2011-12-08 27 views
0

我有一個關於修復FPS而不使用VSYNC的快速問題。想寫沒有VSYNC的固定幀率繪製循環

我目前有一個繪製循環,計算兩次繪製之間的時間, 並減去繪製試圖和穩定幀率所需的時間。

這就是我現在所擁有的:

static clock_t dt = clock(); 
static clock_t startDraw; 
static clock_t endDraw; 

while (_running) 
{ 
    update(); 

    // Draw after desired elapsed time 
    if (clock() - dt >= _timestep) 
    { 
     startDraw = clock(); 
     draw(); 
     _window->SwapBuffer(); 
     endDraw = clock(); 
     dt = clock() - (endDraw- startDraw); 
    } 
} 

_timeStep目前16代表60fps的,但我可能要稍後就改變以30fps的。

沒有VSYNC這個波動在40~62fps之間,所以我不知道這種方法是錯誤的,或者如果我忽略了一些東西。

我的目標是爲VSYNC切換,所以我真的想要添加此功能。

注:我使用OpenGL進行渲染,最多OpenGL_2.0。

回答

0

我注意到這個代碼有幾件事。

首先,你的最後一行:

endDraw = clock() 
dt = clock() - (endDraw - startDraw); 

是一樣的:

endDraw = clock(); 
dt = startDraw; 

所以你當前的測量是自上次名爲draw()僅僅是時間。你實際上並沒有減去繪製所需的時間。

現在,至於爲什麼它波動很大,這是由於一些原因。在您的計時代碼中,您將累計調用update()的時間,以及每次評估時調用draw()的時間。這意味着您的測量粒度受到運行update()+ draw()所花費的時間的限制。實際上,您的fps限制循環僅在60fps的最大fps上設置了一個上限,但運行速度可能遠遠低於60fps,具體取決於要完成多少工作。這就解釋了爲什麼在某些情況下你會看到40fps。你看到的62fps可能只是舍入誤差,或者由於你如何測量fps。

例如,update()+ draw()需要4ms。您當前的「clock() - dt」評估時間爲自上次繪製後的15ms,那麼下一次通過該評估時,它將自上次繪製後的時間爲19ms。意思是這個幀將以較慢的fps運行。

通過在單獨的線程上運行draw()邏輯,可以使其稍微更穩定。這意味着update()的成本不會包含在渲染循環中。但是,這會增加其他複雜性,例如同步更新,以便在身體位置尚未更新時不會繪製人頭部的更新位置。

我給你的問題是,你爲什麼要限制幀率爲60fps?是否減少CPU使用率?如果你不關心CPU的使用情況,你可以使用三屏緩衝系統。儘可能頻繁地運行draw(),只需在60fps的單獨線程上調用SwapBuffer()(當然要小心同步)。由於SwapBuffer比draw()或update()重量輕得多,因此您將擁有相當穩定的fps。

+0

嗯,我主要關心的是cpu使用情況。我的目標是通過NDK添加對Android的支持。我目前正在使用SwapBuffer的雙緩衝。 – redsting

+0

你可以考慮的一件事是在draw()之前做SwapBuffer。這樣,你的顯示器將首先刷新(所以你的計時代碼不會產生draw()的代價)。這會給你稍微更穩定的刷新率。唯一需要注意的是,您的屏幕刷新總是會落後1幀,但是在正常的30fps或60fps應用程序中應該不會有太大影響。 – Skyd