2014-09-25 152 views
0

所以現在在我的OpenGL遊戲引擎中,當我的渲染線程幾乎沒有任何關係時,它佔用了我的CPU可以給它的最大值。 Windows任務管理器顯示我的應用程序佔用了25%的處理量(我有4個硬件線程,因此25%是一個線程可以使用的最大值)。當我根本沒有啓動渲染線程時,我得到0-2%(這是它自己的擔心,因爲它所做的全部都是運行SDL輸入循環)。爲什麼我的渲染線程佔用100%cpu?

那麼,我的渲染線程究竟做了什麼?這裏有一些代碼:

Timer timer; 

while (gVar.running) 
{ 
    timer.frequencyCap(60.0); 

    beginFrame(); 
    drawFrame(); 
    endFrame(); 
} 

讓我們來看看其中的每一個。 Timer是我使用SDL_GetPerformanceCounter製作的定製計時器類。 timer.frequencyCap(60.0);旨在確保循環每秒不會運行超過60次。下面的代碼爲Timer::frequencyCap()

double Timer::frequencyCap(double maxFrequency) 
{ 
    double duration; 

    update(); 
    duration = _deltaTime; 
    if (duration < (1.0/maxFrequency)) 
    { 
     double dur = ((1.0/maxFrequency) - duration) * 1000000.0; 
     this_thread::sleep_for(chrono::microseconds((int64)dur)); 
     update(); 
    } 

    return duration; 
} 

void Timer::update(void) 
{ 
    if (_freq == 0) 
     return; 

    _prevTicks = _currentTicks; 
    _currentTicks = SDL_GetPerformanceCounter(); 

     // Some sanity checking here. // 
     // The only way _currentTicks can be less than _prevTicks is if we've wrapped around to 0. // 
     // So, we need some other way of calculating the difference. 
    if (_currentTicks < _prevTicks) 
    { 
     // If we take difference between UINT64_MAX and _prevTicks, then add that to _currentTicks, we get the proper difference between _currentTicks and _prevTicks. // 
     uint64 dif = UINT64_MAX - _prevTicks; 

     // The +1 here prvents an off-by-1 error. In truth, the error would be pretty much indistinguishable, but we might as well be correct. // 
     _deltaTime = (double)(_currentTicks + dif + 1)/(double)_freq; 
    } 
    else 
     _deltaTime = (double)(_currentTicks - _prevTicks)/(double)_freq; 
} 

接下來的3個功能是相當簡單的(在此階段):

void Renderer::beginFrame() 
{ 
     // Perform a resize if we need to. // 
    if (_needResize) 
    { 
     gWindow.getDrawableSize(&_width, &_height); 
     glViewport(0, 0, _width, _height); 
     _needResize = false; 
    } 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 
} 

void Renderer::endFrame() 
{ 
    gWindow.swapBuffers(); 
} 

void Renderer::drawFrame() 
{ 
} 

渲染線程使用的std ::線程創建。我能想到的唯一解釋是timer.frequencyCap以某種方式不起作用,除非我在主線程中使用完全相同的功能,並且我在0-2%空閒。

我在這裏做錯了什麼?

+3

添加日誌記錄,直到您明白髮生了什麼。 – 2014-09-25 06:05:09

+1

強烈建議您廢除自己的計時器控制並使用圖形驅動程序提供的[交換間隔控制](http://www.opengl.org/wiki/Swap_Interval)。 – starrify 2014-09-25 06:23:31

+0

任何sleep_for調用保證低於100%的CPU負載。檢查這個條件if(duration <(1.0/maxFrequency))' – 9dan 2014-09-25 06:30:29

回答

1

如果你有一個複雜的現場或非優化渲染

  • 命中瓶頸的地方,或者在GL代碼
  • 然後幀率通常下降到約20 fps的(至少在英偉達)無論錯誤現場
  • 對非常複雜場景的複雜性甚至吼叫是

試試這個:

  1. 嘗試測量時需要這種處理

    beginFrame(); 
    drawFrame(); 
    endFrame(); 
    
    • 在那裏你會看到你的FPS上限
    • 把它比作場景複雜度/ HW能力
    • ,並決定如果它是一個錯誤或過於複雜的場景
    • 試圖關閉一些GL的東西
    • 例如上週我發現如果我把CU LL_FACE關閉它實際上加速了我的一個非優化渲染約10-100倍,我不知道爲什麼直到今天(老東西GL代碼)
  2. 檢查GL錯誤

  3. 我在您的代碼中看不到任何glFlush()/ glFinish()

    • 嘗試使用glFinish();
  4. 如果您不能排序了這一點,你仍然可以使用骯髒的伎倆像

    • 添加Sleep(1);到您的代碼
    • 這將迫使睡你的線程所以它不會使用100%的功率
    • 它睡覺的時間爲1ms +調度粒度,因此也限制了目標FPS
    • 您使用this_thread::sleep_for(chrono::microseconds((int64)dur));
    • 不知道這個功能,你真的確定它是做你的想法嗎?
+0

現在,'drawFrame()'完全沒有做任何事情。場景並不複雜或簡單,因爲場景不存在。我打電話的是「glClear」和「SDL_GL_SwapWindow」。這就是爲什麼我很困惑。添加'glFinish()'到代碼實際上使它變得更糟* - 我從25%的使用率降到45-50%! 'glFlush'沒有這個問題,但也沒有幫助。 – 2014-09-26 04:21:18

+0

@ HaydnV.Harach不測量CPU使用情況,而是測量代碼花費的時間。只有這樣你才能發現問題所在。 – Spektre 2014-09-26 07:07:24

4

如果V-Sync啓用和程序榮譽的交換間隔,那麼你看到你的程序佔用了100%,實際上是一種假象Windows如何衡量CPU時間。這是一個長期以來已知的問題,但是,無論何時,當程序在驅動程序上下文中阻塞時(這是在OpenGL在V-Sync上阻塞時發生的情況)窗口將記錄實際耗用CPU時間的程序,而實際上它只是空閒。

如果您在交換緩衝區之後添加一個Sleep(1),它將使Windows陷入更爲理智的會計;在一些系統上,即使是一個Sleep(0)也能做到這一點。

無論如何,大多數情況下,100%只是一個美容問題。


在過去的幾周我已經做了低延遲渲染一些詳盡的研究(即減少了用戶的輸入,並走出顯示相應的光子之間的時間),因爲我很快就得到一個VR耳機。下面是關於定時SwapBuffers的發現:解決這個問題的理想方案實際上是定時幀渲染時間,並在SwapBuffers之前添加仿真睡眠,以便在V-Sync之前幾秒鐘喚醒。然而,說起來容易做起來難,因爲OpenGL是高度異步的,顯式添加同步會降低吞吐量。

+0

+1這也可以解釋我在過去反擊的一些GL怪異 – Spektre 2014-09-25 10:14:53

+0

@Spektre:等到你開始分析各種OpenGL相關調用的時間線。在SwapBuffers和改變OpenGL調用的第一個幀緩衝區內容之間發生的事情真的很奇怪......並且不一致。我發現,如果在* static *場景中啓用了V-Sync,則流水線失速會偏離幾ms。你會期望這樣的測試有一些非常一致的值。顯然,OS進程調度器,GPU和OpenGL驅動程序之間正在發生一些非常奇怪的事情。我還沒有試驗當我更改調度器參數時會發生什麼。 – datenwolf 2014-09-25 10:28:20

+0

來自XP +的Windows任務調度程序很奇怪...我在慢速機器上(即使是2核心)和少量線程(〜3不要求)(與OpenGL無關)有問題,從哪一個機器訪問asynchro USB傳輸,並定期掛斷幾秒到幾秒。這讓我對W7瘋狂,它在W2K上更糟。它只發生在低端硬件(就像一些CELERON筆記本...),即使CPU足夠處理它......我懷疑它有訪問驅動程序層(這也適用於GL的東西)的東西。這甚至凍結一切甚至不相關... – Spektre 2014-09-25 10:53:47

相關問題