Функция Delphi Now () возвращает неверное значение

у меня есть приложение на основе DirectX. И недавно я обнаружил, что Now() функция возвращает неправильное значение при вызове из основного цикла моего графического движка. Он дает одно значение, вызываемое до инициализации движка, и другое (обычно отличается на 2-3 минуты назад или вперед) при вызове в моем приложении при запуске графики.

Я нашел это Now() функция является оболочкой для Windows API . Любой может указать, что может влияет на возвращаемое значение этой функции? Я сильно использую 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;

теперь () называется где-то в

4 ответов


наконец-то я нашел решение. Мне нужно было указать th D3DCREATE_FPU_PRESERVE флаг при создании устройства D3D с помощью D3D.CreateDevice.

в противном случае, без этого флага, все операции с плавающей запятой выполняются с одинарной точностью. Как TDateTime простой Double и Now() функции состоят из простого добавления значения даты к значению времени, все это запутывается DirectX "smart" override.

проблема решена. Это было действительно сложно. :)


Я использую для запуска этих проблем с OpenGL и симулятором и MapObjects. Было установлено, что временной последовательностью являются различия между оборудованием. Вот две ссылки, которые могут пролить свет на эту тему:

http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm Статьи жарко Гаич помог с таймером, который мне пришлось строить последовательный интерфейс. Я использовал вариант этого примера кода для извлечения данных для a датчик бака.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx Это информация microsoft об использовании таймеров высокого класса в вашем программном обеспечении. Как правило, таймеры будут отключены и отключены от синхронизации. В этой статье рассматриваются два таймера: таймер высокого разрешения и объекты таймера ожидания. Высокое разрешение-это вариант таймера, который я использовал для симулятора.


насколько я понял из кода, Вы принимаете решения по

              f_DeltaTicks := timeGetTime - f_Time0;

переменная f_Time0 инициализируется на более позднем этапе цикла.

                f_Time0 := timeGetTime;

может быть простая ошибка, что f_Time0 не инициализируется так, как вы хотите/требуете при первом входе в цикл.


Если вы используете DirectX, лучше включить математическую точность, когда это необходимо, и отключить ее, когда нет необходимости.

uses Math;


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

Direct X и некоторые драйверы видеокарты требуют этого и могут вызвать ошибку: недопустимая операция с плавающей запятой