2012-08-27 21 views
6

DirectX tabanlı bir uygulamaya sahibim. Son zamanlarda, grafik motorumun ana döngüsünde çağrıldığında, Now() işlevinin yanlış bir değer döndürdüğünü buldum. Grafik başlatıldığında uygulamamda çağrıldığında, motor başlatılmadan ve farklı bir taneden önce (genellikle 2-3 dakika geri veya ileride farklılık gösterir) bir değer verilir. Delphi Now() işlevi yanlış bir değer döndürüyor

Ben Now() işlevi Windows API GetLocalTime() işlevi için bir sarıcı olduğunu gördük. Herkes bu işlevin geri dönüş değerini nasıl etkileyebileceğine işaret edebilir mi? Uygulamamın ana döngüsünde timeGetTime() işlevini çok kullanırım, sorun kaynağı olabilir mi? Ayrıca ben ... ana döngüde

Herhangi fikirleri CheckSyncronize() fonksiyonunu kullanmak gerekir? Şimdi

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() işlevinde bir yere denir

+0

tüm makinelerde yaramazlık mı Geçersiz kayan nokta operasyonu? Bunu küçük bir örnek programda yeniden üretebilir misiniz? –

+0

Evet. Aslında bu hatayı bir hata raporu olarak aldım. Sanırım küçük bir program yapabilirim ama grafik motorumun bağlanmasını içerecek ... –

+0

En büyük mesajda bir ana döngü kodu gönderdim. –

cevap

11

Sonunda çözümü buldum. D3D.CreateDevice tarafından D3D cihazı oluştururken D3DCREATE_FPU_PRESERVE bayrağını belirtmem gerekiyordu.

Aksi takdirde, o bayrağı olmadan, tüm kayan nokta işlemi tek hassasiyetle yapılmaktadır. TDateTime basit Double ve Now() fonksiyonları zaman değerine tarih değeri basit eklenmesi oluşur olduğundan, tüm DirectX "akıllı" geçersiz kılma tarafından berbat.

Sorun çözüldü. Gerçekten zor bir şeydi. :)

2

Bunları sorunları çalıştırmak için kullanın: Ben ana döngünün :(

kodu ... ipuçları bitti. . OpenGL ve simülatör ve MapObjects ile zamanlama dizisi ekipmanı arasındaki farklar olduğu bulunmuştur Burada konu üzerine biraz ışık tutabilecek iki bağlantı olduğunu.

http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm Zarko Gajic makalesi yardım Seri arayüz için oluşturmam gereken zamanlayıcı ile. Bir tank sensörü için veri çekmek için bu kod örneğinin bir varyasyonunu kullandım.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx Bu, yazılımınızdaki üst düzey zamanlayıcıları kullanmanın microsoft bilgisidir. Genellikle zamanlayıcılar döngüden çıkar ve senkronizasyondan çıkar. Bu makalede iki zamanlayıcı, Yüksek Çözünürlüklü Zamanlayıcı ve Bekleyen Zamanlayıcı Nesneleri gider. Yüksek Çözünürlük simülatör için kullandığım zamanlayıcı varyantıdır.

   f_DeltaTicks := timeGetTime - f_Time0; 

f_Time0 değişkeni

+3

Bu daha ince ayar yapılması gerektiğinden, ilgili görünmüyor. Soru 'SYSTEMTIME' farklı çağrılar arasında kayar şikayet ediyor. Ardışık çağrılar ile farklı fiş kullanmaz. Ya da belki de ben bu soruyu anlamadım .. –

+0

Bu bağlantıların bitişik değerlerle 'Now' değerlerini birbirinden ayıran bitişik çağrılarla nasıl ilişkili olabileceğini göremiyorum. –

1

Bildiğim kadarıyla kodundan anladığını, sen yapıyoruz kararlar döngüde daha sonraki bir aşamada başlatılır.

   f_Time0 := timeGetTime; 

f_Time0 Eğer döngüye ilk girişinde/gerektiriyor istediğiniz şekilde başlatıldı olmadığını, basit bir hata olabilir.

+0

Aslında, hayır. Hata yok. Aşağıda bulduğum bir çözüm yolladım. Ama yardım için teşekkürler! :) –

0

Eğer DirectX kullanıyorsanız, o gerektiğinde matematik doğruluk açmak ve gerek olduğu zaman bunu kapatmak için daha iyidir.

uses Math; 


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

Direct X ve bazı ekran kartı sürücüleri bu ihtiyaç ve hata atmak olabilir :

İlgili konular