2012-08-27 25 views
6

私はDirectXベースのアプリケーションを持っています。そして、最近私は、Now()関数は、私のグラフィックスエンジンのメインループ内から呼び出されたときに間違った値を返すことを発見しました。これは、エンジンが初期化される前に呼び出される1つの値と、グラフィックスが開始されたときにアプリケーションで呼び出されるときに異なる値(通常、2-3分前または前に異なる)を与えます。Delphi Now()関数が間違った値を返します

私は、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でD3Dデバイスを作成するときに、D3DCREATE_FPU_PRESERVEフラグを指定する必要がありました。

このフラグを指定しないと、すべての浮動小数点演算が単精度で実行されます。 TDateTimeは単純なDoubleであり、Now()の機能は日付値と時間値を単純に加算したもので構成されているため、DirectXの「スマート」オーバーライドによってすべてが崩れてしまいます。

問題を解決しました。それは確かに難しいものでした。 :)

2

私はこれらの問題に実行するために使用します。私は、メインループの:(

コードが...手がかりの外です。 。OpenGLとシミュレータと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 これはソフトウェアでハイエンドタイマを使用するためのマイクロソフトの情報です。一般的に、タイマーはサイクルアウトして同期を外します。この記事では、高解像度タイマーと待機可能タイマーオブジェクトの2つのタイマーについて説明します。高解像度は、私がシミュレータに使用したタイマーの変形です。

+3

さらに細かいチューニングが必要な場合もありますが、関連性がないようです。質問は、 'SYSTEMTIME'が異なる呼び出しの間に伝わることを訴える。それは連続した呼び出しによって異なるチップを使用することはありません。または、おそらく私は質問を理解していませんでした。 –

+0

これらのリンクが「Now」の値を分単位で返す隣接呼び出しとどのように関係しているのか分かりません。 –

1

私の知る限り、コードからわかるてきたように、あなたが

   f_DeltaTicks := timeGetTime - f_Time0; 

上の意思決定をしているf_Time0変数はループの後の段階で初期化されます。

   f_Time0 := timeGetTime; 

f_Time0は、あなたが/ループへの最初の入り口に必要と望むように初期化されていないことを、簡単なバグがあるかもしれません。

+0

実際、いいえ。バグはありません。以下、私が見つけた解決策を掲載しました。しかし、助けてくれてありがとう! :) –

0

DirectXを使用している場合は、必要なときに数学の精度をオンにし、必要がない場合はオフにする方がよいでしょう。

uses Math; 


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

ダイレクトXと一部のグラフィックスカードドライバがこれを必要とし、エラーをスローすることがあります。無効な浮動小数点演算

関連する問題