glReadPixels()消耗单个内核的所有CPU周期

时间:2018-11-15 02:43:11

标签: opengl nvidia cpu-usage sdl-2 glreadpixels

我有一个带有OpenGL窗口的SDL2应用程序,它表现良好:运行时,该应用程序与我的60Hz显示屏同步,并且我看到该应用程序的CPU使用率为12%。

到目前为止,一切都很好。 但是,当我通过从深度缓冲区读取一个(!)深度值(绘制后)来添加3D拾取时,会发生以下情况:

  • FPS仍为60
  • 主线程的CPU使用率达到100%

如果我不执行glReadPixels,CPU使用率将再次下降到12%。为什么从深度缓冲区读取单个值会导致CPU烧毁所有周期?

我的窗口是通过以下方式创建的:

SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, use_aa ? 1 : 0 );
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, use_aa ? 4 : 0 );
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

window = SDL_CreateWindow
(
            "Fragger",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            fbw, fbh,
            SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
);

我的绘图的结论是:

SDL_GL_SwapWindow( window );

我的深度读取通过以下方式执行:

float depth;
glReadPixels( scrx, scry, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth );

我的显示同步是使用以下配置的:

int rv = SDL_GL_SetSwapInterval( -1 );
if ( rv < 0 )
{
    LOGI( "Late swap tearing not available. Using hard v-sync with display." );
    rv = SDL_GL_SetSwapInterval( 1 );
    if ( rv < 0 ) LOGE( "SDL_GL_SetSwapInterval() failed." );
}
else
{
    LOGI( "Can use late vsync swap." );
}

对“ perf”的调查表明,这些周期已被nVidia的驱动程序烧尽,进行了不懈的系统调用,其中之一是sys_clock_gettime(),如下所示:

flame graph

我通过读取GL_BACK或GL_FRONT尝试了一些变体,结果相同。 我还尝试在窗口交换之前和之后阅读。 但是CPU使用率始终处于100%的水平。

  • 平台: Ubuntu 18.04.1
  • SDL: 2.0.8版
  • CPU:英特尔Haswell
  • GPU :nVidia GTX750Ti
  • GL_VERSION :3.2.0 NVIDIA 390.87

更新

在Intel HD Graphics上,CPU不旋转锁定。 glReadPixels仍然很慢,但是与nVidia驱动程序上完全加载100%的CPU相比,CPU的占空比很低(约为1%)。

我还尝试了asynchronous pixel reads via PBO(像素缓冲区对象),但仅适用于RGBA值,而不适用于DEPTH值。

0 个答案:

没有答案