如何减少OpenGL CPU使用率和/或如何正确使用OpenGL

时间:2015-05-21 17:56:20

标签: c++ opengl graphics cpu

我正在使用OpenGL构建Micromouse simulation application,我有一种预感,我没有正确地做事。特别是,我对我的(大多数是静态的)图形以接近恒定的帧速率(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();

&#34;问题&#34;是上面的方法真的占用了我的CPU - 这个过程使用的是96-100%。我知道使用大量CPU并没有任何本质上的错误,但我觉得我不应该一直使用那么多

踢球者是大多数的图形不会在帧与帧之间发生变化。它实际上只是一个多边形移动(并覆盖)一些静态形状。有没有办法告诉OpenGL只重绘自上一帧以来发生了什么变化(希望它会减少glxxx呼叫的数量,我认为这是&#34;问题的来源&#34 ;)?或者,更好的是,我的方法是让我的图形刷新甚至正确吗?

2 个答案:

答案 0 :(得分:2)

首先,OpenGL最大的CPU占用立即模式 ......你正在使用它(glBegin,glEnd)。 IM的问题在于,每个顶点都需要进行一对OpenGL调用;并且因为OpenGL使用线程本地状态,这意味着每个OpenGL调用必须经过一些间接调用。所以第一步就是摆脱它。

下一个问题是如何为显示器计时。如果用户输入和显示之间的低延迟不是您的最终目标,则标准方法将设置双缓冲窗口,启用V-Sync,将swap interval设置为1并执行缓冲交换(glutSwapBuffers )一旦渲染帧。事物将阻止的确切时间取决于实现(不幸的是),但只要您的渲染器能够跟上(即渲染帧花费的时间更少),您或多或少可以保证精确地达到屏幕刷新频率。一个屏幕刷新间隔)。

glutPostRedisplay仅为主循环设置一个标志,以便在没有其他事件未决时调用显示函数,因此对帧重绘的定时不是很准确。

最后但并非最不重要的是,您可能只是被Windows所占用的CPU时间(在驱动程序上下文中花费的时间,其中包括阻塞,等待V-Sync)的方式嘲笑,这将占用消耗的CPU时间,而实际上它是可中断的睡眠。 然而你写道,你已经在你的代码中进行了一次睡眠,这会排除这种情况,因为获得更合理的会计的首选方法是在缓冲区交换之前或之后添加Sleep(1)

答案 1 :(得分:0)

我发现,通过使渲染线程进入睡眠状态有助于将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,所以我认为它足够好

受到this post

的启发