我有基于DirectX的应用程序。最近我发现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()
函数中的某处调用Now()。
答案 0 :(得分:12)
最后,我找到了解决方案。在D3DCREATE_FPU_PRESERVE
创建D3D设备时,我需要指定D3D.CreateDevice
标志。
否则,如果没有该标志,则以单精度执行所有浮点运算。由于TDateTime
是一个简单的Double
,而Now()
函数由简单的日期值添加到时间值组成,所有这些都被DirectX&#34; smart&#34;覆盖。
问题解决了。确实这是一个棘手的问题。 :)
答案 1 :(得分: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 这是有关在软件中使用高端计时器的Microsoft信息。通常,计时器会循环并且不同步。本文分为两个定时器,高分辨率定时器和等待定时器对象。高分辨率是我用于模拟器的计时器变体。
答案 2 :(得分:1)
据我从代码中了解到,你正在做决定
f_DeltaTicks := timeGetTime - f_Time0;
f_Time0变量在循环的后期初始化。
f_Time0 := timeGetTime;
可能存在一个简单的错误,即f_Time0没有按照第一次进入循环的方式进行初始化。
答案 3 :(得分:0)
如果您使用的是DirectX,最好在需要时打开数学精度,并在不需要时将其关闭。
uses Math;
var pm: TFPUPrecisionMode;
begin
pm: = GetPrecisionMode;
try
SetPrecisionMode (pmExtended)
.
.
.
finally
SetPrecisionMode (pm);
end
end;
Direct X和某些显卡驱动程序需要这个并且可能会抛出错误:无效的浮点操作