2012-08-27 21 views
6

मेरे पास डायरेक्टएक्स-आधारित एप्लिकेशन है। और हाल ही में मैंने पाया कि Now() फ़ंक्शन मेरे ग्राफिक्स इंजन के मुख्य पाश के भीतर से कॉल होने पर गलत मान देता है। ग्राफिक्स शुरू होने पर मेरे एप्लिकेशन में कॉल होने पर इसे इंजन शुरू करने से पहले एक मूल्य कहा जाता है और अलग-अलग (आमतौर पर 2-3 मिनट पहले या आगे अलग होता है)।डेल्फी अब() फ़ंक्शन एक गलत मान देता है

मुझे पता चला कि Now() फ़ंक्शन Windows API GetLocalTime() फ़ंक्शन के लिए एक रैपर है। कोई भी इस बात के बारे में बता सकता है कि इस समारोह के वापसी मूल्य को क्या प्रभावित कर सकता है? मैं अपने ऐप के मुख्य पाश में timeGetTime() फ़ंक्शन का भारी उपयोग करता हूं, क्या यह समस्या का स्रोत हो सकता है? इसके अलावा मुझे मुख्य लूप में CheckSyncronize() फ़ंक्शन का उपयोग करने की आवश्यकता है ...

कोई विचार? मैं सुराग से बाहर कर रहा हूँ ... :(मुख्य पाश की

कोड:

procedure Td2dCore.System_Run; 
    var 
     l_Msg: TMsg; 
     l_Point: TPoint; 
     l_Rect : TRect; 
     l_Finish: Boolean; 
    begin 
     if f_WHandle = 0 then 
     begin 
      System_Log('Engine was not started!'); 
      Exit; 
     end; 

     if not Assigned(f_OnFrame) then 
     begin 
      System_Log('Frame function is not assigned!'); 
      Exit; 
     end; 

     // MAIN LOOP 
     l_Finish := False; 
     while not l_Finish do 
     begin 
      // dispatch messages 
      if PeekMessage(l_Msg, 0, 0, 0, PM_REMOVE) then 
      begin 
       if l_Msg.message = WM_QUIT then 
        l_Finish := True; 
       DispatchMessage(l_Msg); 
       Continue; 
      end; 

      GetCursorPos(l_Point); 
      GetClientRect(f_WHandle, l_Rect); 
      MapWindowPoints(f_WHandle, 0, l_Rect, 2); 
      f_MouseOver := f_MouseCaptured or (PtInRect(l_Rect, l_Point) and (WindowFromPoint(l_Point) = f_WHandle)); 
      if f_Active or f_DontSuspend then 
      begin 
       repeat 
        f_DeltaTicks := timeGetTime - f_Time0; 
        if f_DeltaTicks <= f_FixedDelta then 
         Sleep(1); 
       until f_DeltaTicks > f_FixedDelta; 
       //if f_DeltaTicks >= f_FixedDelta then 
       begin 
        f_DeltaTime := f_DeltaTicks/1000.0; 

        // if delay was too big, count it as if where was no delay 
        // (return from suspended state for instance) 
        if f_DeltaTime > 0.2 then 
         if f_FixedDelta > 0 then 
          f_DeltaTime := f_FixedDelta/1000.0 
         else 
          f_DeltaTime := 0.01; 

        f_Time := f_Time + f_DeltaTime; 

        f_Time0 := timeGetTime; 

        if(f_Time0 - f_Time0FPS < 1000) then 
         Inc(f_FPSCount) 
        else 
        begin 
         f_FPS := f_FPSCount; 
         f_FPSCount := 0; 
         f_Time0FPS := f_Time0; 
        end; 

        f_OnFrame(f_DeltaTime, l_Finish); 
        if Assigned(f_OnRender) then 
         f_OnRender(); 
        ClearQueue; 
        { 
        if (not f_Windowed) and (f_FixedFPS = D2D_FPS_VSYNC) then 
         Sleep(1); 
        } 
       end; 
       { 
       else 
        if (f_FixedDelta > 0) and (f_DeltaTicks+3 < f_FixedDelta) then 
         Sleep(1); 
       } 
      end 
      else 
       Sleep(1); 
      CheckSynchronize; 
     end; 
    end; 

अब() f_OnFrame() समारोह में कहीं भी कहा जाता है

+0

यह सब मशीनों पर दुर्व्यवहार करता है? क्या आप इसे एक छोटे नमूना कार्यक्रम में पुन: पेश कर सकते हैं? –

+0

हां। असल में मुझे यह त्रुटि एक बग रिपोर्ट के रूप में मिली। मुझे लगता है कि मैं एक छोटा प्रोग्राम बना सकता हूं लेकिन इसमें मेरे ग्राफिक इंजन को जोड़ने में शामिल होगा ... –

+0

मैंने शीर्ष संदेश में एक मुख्य लूप कोड पोस्ट किया है। –

उत्तर

11

अंततः मुझे समाधान मिला है। D3D.CreateDevice द्वारा डी 3 डी डिवाइस बनाते समय मुझे D3DCREATE_FPU_PRESERVE ध्वज निर्दिष्ट करने की आवश्यकता थी।

अन्यथा, उस ध्वज के बिना, सभी फ़्लोटिंग पॉइंट ऑपरेशंस एकल परिशुद्धता के साथ किए जाते हैं। चूंकि TDateTime एक साधारण Double है, और Now() फ़ंक्शंस में समय मूल्य के लिए दिनांक मूल्य का सरल जोड़ा शामिल है, यह सभी DirectX "smart" ओवरराइड द्वारा गड़बड़ हो जाता है।

समस्या हल हो गई। यह वास्तव में एक मुश्किल था। :)

2

मैं इन मुद्दों में चलाने के लिए इस्तेमाल करते हैं। । ओपन और सिम्युलेटर और MapObjects साथ समय अनुक्रम उपकरण के बीच मतभेद हो पाया था यहाँ दो लिंक है कि इस विषय पर कुछ प्रकाश डाला सकता है:।

http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm Zarko Gajic के लेख में मदद की टाइमर के साथ जो मुझे सीरियल इंटरफ़ेस के लिए बनाना था। मैंने टैंक सेंसर के लिए डेटा खींचने के लिए इस कोड उदाहरण की विविधता का उपयोग किया।

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx यह आपके सॉफ़्टवेयर में उच्च अंत टाइमर का उपयोग करने पर माइक्रोसॉफ्ट जानकारी है। आम तौर पर टाइमर चक्र से बाहर हो जाते हैं और सिंक बंद हो जाते हैं। यह आलेख दो टाइमर, उच्च-रिज़ॉल्यूशन टाइमर और प्रतीक्षा करने योग्य टाइमर ऑब्जेक्ट्स में जाता है। हाई-रेज़ोल्यूशन टाइमर संस्करण है जिसे मैंने सिम्युलेटर के लिए उपयोग किया था।

+3

हालांकि इसे और अधिक ठीक ट्यूनिंग के रूप में आवश्यक हो सकता है, यह प्रासंगिक नहीं प्रतीत होता है। सवाल शिकायत करता है कि 'सिस्टम' के माध्यम से विभिन्न कॉल के बीच फिसल जाता है। यह लगातार कॉल के माध्यम से विभिन्न चिप्स का उपयोग नहीं करेगा। या संभवतः मुझे प्रश्न समझ में नहीं आया .. –

+0

मैं नहीं देख सकता कि ये लिंक आसन्न कॉल से संबंधित कैसे हो सकते हैं 'अब' वापस आने वाले मानों को अलग-अलग करें। –

1

   f_DeltaTicks := timeGetTime - f_Time0; 

f_Time0 चर पर जहाँ तक मेरा कोड से समझ लिया है, आप कर रहे हैं निर्णय पाश में बाद के चरणों में आरंभ नहीं हो जाता।

   f_Time0 := timeGetTime; 

एक सरल बग वहाँ हो सकता है, कि जिस तरह से आप f_Time0 लूप में पहले प्रवेश द्वार पर की आवश्यकता होती है चाहता हूँ/आरंभ नहीं किया है।

+0

वास्तव में, नहीं। कोई बग नहीं है नीचे मैंने एक समाधान पोस्ट किया है जो मैंने पाया था। लेकिन मदद के लिए धन्यवाद! :) –

0

यदि आप डायरेक्टएक्स का उपयोग कर रहे हैं, तो आवश्यकता होने पर गणित सटीकता को चालू करना बेहतर है और आवश्यकता होने पर इसे बंद कर दें।

uses Math; 


var pm: TFPUPrecisionMode; 
begin 
   pm: = GetPrecisionMode; 
   try 
     SetPrecisionMode (pmExtended) 
. 
. 
. 
   finally 
     SetPrecisionMode (pm); 
   end 
end; 

डायरेक्ट एक्स और कुछ ग्राफ़िक्स कार्ड ड्राइवर इस आवश्यकता होती है और एक त्रुटि फेंक सकता है: अमान्य चल बिन्दु आपरेशन

संबंधित मुद्दे