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

Opengl glReadPixels()消耗单个内核的所有CPU周期,opengl,nvidia,cpu-usage,sdl-2,glreadpixels,Opengl,Nvidia,Cpu Usage,Sdl 2,Glreadpixels,我有一个带有OpenGL窗口的SDL2应用程序,它表现良好:当它运行时,应用程序与我的60Hz显示器同步,我看到应用程序的CPU使用率为12% 到目前为止还不错。 但是,当我通过从深度缓冲区(绘制后)读取单个(!)深度值来添加3D拾取时,会发生以下情况: FPS仍为60 主线程的CPU使用率达到100% 如果不使用glReadPixels,CPU使用率将再次下降到12%。为什么从深度缓冲区读取单个值会导致CPU耗尽所有周期 我的窗口是通过以下方式创建的: SDL_GL_SetAttribut

我有一个带有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." );
}
int rv=SDL\u GL\u SetSwapInterval(-1);
如果(rv<0)
{
LOGI(“延迟交换不可用。使用与显示器的硬v同步”);
rv=SDL_GL_SetSwapInterval(1);
如果(rv<0)LOGE(“SDL_GL_SetSwapInterval()失败”);
}
其他的
{
LOGI(“可以使用后期vsync交换”);
}
使用“perf”进行的调查显示,nVidia的驱动程序会不断地进行系统调用,其中一个是sys_clock_gettime(),如下所示:

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

  • 平台:Ubuntu 18.04.1
  • SDL:2.0.8版
  • CPU:Intel Haswell
  • GPU:nVidia GTX750Ti
  • GL_版本:3.2.0 NVIDIA 390.87
更新

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


我也尝试过(像素缓冲区对象),但这只适用于RGBA值,而不适用于深度值。

如何/何时读取深度?从哪个缓冲区?当你这么做的时候,怎么没有vsync的FPS掉下来?看起来您强制驱动程序进行同步,因为请求的深度尚未渲染。从逻辑上讲,您可能需要上一帧的深度,而不是当前渲染的深度。@keltar谢谢。我用GL_FRONT和GL_BACK尝试了glReadBuffer(),结果相同。100%的CPU使用率。没有VSYNC到300 FPS,但仍然有很多循环被烧毁,所有都在GLADEXPLICALL()中。英伟达驱动程序在使用CPU-GPU同步时使用繁忙等待。事实上,这并没有什么错,因为这是最有效的选择。真正的问题是,您正在强制执行同步,而您应该执行的当然是异步回读。绝对没有理由不使用深度缓冲区内容,您应该真正修复代码。@derhass我认为我的代码是正确的:我在读取RGBA时获得非阻塞readpixels,而不是读取深度时。代码如下: