簡體   English   中英

如何減少OpenGL CPU使用率和/或如何正確使用OpenGL

[英]How to reduce OpenGL CPU usage and/or how to use OpenGL properly

我正在使用OpenGL構建的Micromouse模擬應用程序上工作,我有一種直覺,認為我做的事情做得不好。 尤其是,我對以近乎恆定的幀速率(60 FPS)刷新(大部分為靜態)圖形的方式感到懷疑。 我的方法如下:

1)啟動計時器
2)畫出我的形狀和文字(大約一千個):

glBegin(GL_POLYGON);
for (Cartesian vertex : polygon.getVertices()) {
    std::pair<float, float> coordinates = getOpenGlCoordinates(vertex);
    glVertex2f(coordinates.first, coordinates.second);
}   
glEnd();

glPushMatrix();
glScalef(scaleX, scaleY, 0);
glTranslatef(coordinates.first * 1.0/scaleX, coordinates.second * 1.0/scaleY, 0);
for (int i = 0; i < text.size(); i += 1) {
    glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, text.at(i));
}
glPopMatrix();

3)致電

glFlush();

4)停止計時器
5)睡眠(1 / FPS-持續時間)秒
6)致電

glutPostRedisplay();

“問題”是上述方法確實占用了我的CPU-進程正在使用96-100%的東西。 我知道,有沒有什么內在的錯誤使用大量的CPU,但我覺得我不應該用那么多所有的時間

更重要的是, 大多數圖形在不同的幀之間都不會改變。 實際上,這只是一個移動(覆蓋)靜態形狀的多邊形。 是否有任何方法告訴OpenGL僅重繪自上一幀以來發生的變化(希望它會減少glxxx調用的次數,我認為這是“問題”的根源)? 或者,更好的是,我刷新圖形的方法是否正確?

首先,使用OpenGL的最大CPU消耗是即時模式 …並且您正在使用它(glBegin,glEnd)。 IM的問題是,每個單個頂點都需要進行完整的OpenGL調用。 並且由於OpenGL使用線程本地狀態,這意味着每個OpenGL調用都必須經過某種間接調用。 因此,第一步就是要擺脫它。

下一個問題是如何安排顯示時間。 如果用戶輸入和顯示之間的低延遲不是您的最終目標,則標准方法將設置窗口進行雙緩沖,啟用glutSwapBuffers同步,將交換間隔設置為1,並在渲染幀后進行緩沖區交換( glutSwapBuffers )。 不幸的是,什么以及在什么地方阻塞的確切時間取決於實現(不幸的是),但是只要您的渲染器能夠跟上(即渲染一幀需要更少的時間),您或多或少就可以保證達到屏幕刷新頻率。屏幕刷新間隔)。

glutPostRedisplay僅在沒有其他事件掛起時為主循環設置一個標志,以調用顯示函數,因此定時重新繪制幀的時間不是很准確。

最后但並非最不重要的一點是,您可能會簡單地嘲笑Windows占用CPU時間的方式(在驅動程序上下文中花費的時間,包括阻止,等待V-Sync)將消耗到所消耗的CPU時間中,而實際上這是可中斷的睡眠。 無論您寫了什么,您都已經在代碼中進行了睡眠,這可以排除這種情況,因為要獲得更合理的記賬的首選方法是在緩沖區交換之前或之后添加Sleep(1)

我發現通過將渲染線程置於睡眠狀態有助於將cpu使用率從(我的情況)降低26%到大約8%

#include <chrono>
#include <thread>

void render_loop(){
  ...
  auto const start_time = std::chrono::steady_clock::now();
  auto const wait_time = std::chrono::milliseconds{ 17 };
  auto next_time = start_time + wait_time;
  while(true){
    ...
    // execute once after thread wakes up every 17ms which is theoretically 60 frames per 
    // second
    auto then = std::chrono::high_resolution_clock::now();
    std::this_thread::sleep_until(next_time);

    ...rendering jobs

    auto elasped_time = 
    std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::high_resolution_clock::now() - then);
    std::cout << "ms: " << elasped_time.count() << '\n';
    next_time += wait_time;
  }
}

我考慮過在線程處於睡眠狀態時嘗試測量幀速率,但是我的用例沒有任何理由嘗試這樣做。 結果平均約為16ms,所以我認為它足夠好

受此職位啟發

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM