2012-08-27 38 views
6

Tôi có ứng dụng dựa trên DirectX. Và gần đây tôi thấy rằng hàm Now() trả về một giá trị sai khi được gọi từ bên trong vòng lặp chính của công cụ đồ họa của tôi. Nó cung cấp cho một giá trị được gọi trước khi khởi động động cơ và một giá trị khác (thường khác 2-3 phút trở lại hoặc chuyển tiếp) khi được gọi trong ứng dụng của tôi khi đồ họa được khởi động.Hàm Delphi Now() trả về một giá trị sai

Tôi thấy rằng Now() chức năng là trình bao bọc cho chức năng Windows API GetLocalTime(). Bất cứ ai cũng có thể chỉ ra những gì có thể ảnh hưởng đến giá trị trả về của chức năng này? Tôi sử dụng nhiều chức năng timeGetTime() trong vòng lặp chính của ứng dụng của tôi, nó có thể là nguồn gốc của vấn đề không? Ngoài ra, tôi cần phải sử dụng chức năng CheckSyncronize() trong vòng lặp chính ...

Bất kỳ ý tưởng nào? Tôi ra khỏi manh mối ... :(

mã của vòng lặp chính:

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; 

Bây giờ() được gọi ở đâu đó trong f_OnFrame() chức năng

+0

Liệu nó misbehave trên tất cả các máy? Bạn có thể tái tạo điều này trong một chương trình mẫu nhỏ không? –

+0

Có. Thực ra tôi đã nhận được lỗi này dưới dạng báo cáo lỗi. Tôi nghĩ rằng tôi có thể làm một chương trình nhỏ nhưng nó sẽ liên quan đến liên kết của công cụ đồ họa của tôi ... –

+0

Tôi đã đăng một mã vòng lặp chính trong thông báo trên cùng. –

Trả lời

11

Cuối cùng tôi đã tìm được giải pháp. Tôi cần chỉ định cờ thứ D3DCREATE_FPU_PRESERVE khi tạo thiết bị D3D theo số D3D.CreateDevice.

Nếu không, không có cờ đó, tất cả các hoạt động điểm động được thực hiện với độ chính xác đơn. Khi TDateTime là một đơn giản Double và các chức năng Now() bao gồm việc thêm đơn giản giá trị ngày vào giá trị thời gian, tất cả sẽ bị sai lệch bởi ghi đè DirectX "thông minh".

Sự cố được giải quyết. Đó thực sự là một điều khó khăn. :)

2

tôi sử dụng để chạy vào những vấn đề này. với OpenGL và trình mô phỏng và MapObjects, trình tự thời gian được tìm thấy là sự khác biệt giữa thiết bị. Dưới đây là hai liên kết có thể làm sáng tỏ một số chủ đề:

http://delphi.about.com/od/windowsshellapi/a/delphi-high-performance-timer-tstopwatch.htm Bài viết của Zarko Gajic đã giúp với bộ hẹn giờ mà tôi phải tạo cho một giao diện nối tiếp. Tôi đã sử dụng một biến thể của ví dụ mã này để lấy dữ liệu cho cảm biến bể.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms644900%28v=vs.85%29.aspx Đây là thông tin microsoft về sử dụng bộ tính giờ cao cấp trong phần mềm của bạn. Thông thường, bộ hẹn giờ sẽ chu kỳ và tắt đồng bộ hóa. Bài viết này đi vào hai bộ hẹn giờ, Bộ định thời Độ phân giải cao và Các đối tượng hẹn giờ có thể đợi. Độ phân giải cao là biến thể hẹn giờ mà tôi đã sử dụng cho trình mô phỏng.

+3

Trong khi điều này có thể được yêu cầu như điều chỉnh tốt hơn nữa, nó không có vẻ là có liên quan. Câu hỏi này phàn nàn rằng 'SYSTEMTIME' trượt giữa các cuộc gọi khác nhau. Nó sẽ không sử dụng chip khác nhau thông qua các cuộc gọi liên tiếp. Hoặc có thể tôi không hiểu câu hỏi .. –

+0

Tôi không thể thấy các liên kết này có thể liên quan đến các cuộc gọi lân cận tới 'Now' trở về giá trị cách nhau vài phút. –

1

quyết định Như xa như tôi đã hiểu từ mã, bạn đang làm trên

   f_DeltaTicks := timeGetTime - f_Time0; 

f_Time0 biến được khởi tạo ở giai đoạn sau trong vòng lặp.

   f_Time0 := timeGetTime; 

có thể có một lỗi đơn giản, rằng f_Time0 không được khởi tạo theo cách bạn muốn/yêu cầu trên lối vào đầu tiên vào vòng lặp.

+0

Thực tế là không. Không có lỗi. Dưới đây tôi đã đăng một giải pháp tôi tìm thấy. Nhưng nhờ giúp đỡ! :) –

0

Nếu bạn đang sử dụng DirectX, tốt hơn nên bật tính chính xác của toán khi cần và tắt khi không cần.

uses Math; 


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

Direct X và một số trình điều khiển card đồ họa đòi hỏi này và có thể ném ra một lỗi: không hợp lệ nổi hoạt động điểm

Các vấn đề liên quan