我有一个带有 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(),如下所示:
我通过读取 GL_BACK 或 GL_FRONT 尝试了一些变化,结果相同。
我还尝试在窗口交换之前和之后阅读。
但CPU使用率始终处于100%水平。
-
平台:乌班图18.04.1
-
SDL:版本2.0.8
-
CPU:英特尔哈斯韦尔
-
GPU:英伟达 GTX750Ti
-
GL_版本:3.2.0 英伟达 390.87
UPDATE
在 Intel HD Graphics 上,CPU 不自旋锁。
glReadPixels 仍然很慢,但与 nVidia 驱动程序上完全 100% 加载的 CPU 相比,CPU 的占空比较低 (1%) 左右。
我也尝试过通过 PBO 异步读取像素 http://www.songho.ca/opengl/gl_pbo.html(像素缓冲区对象)但仅适用于 RGBA 值,不适用于 DEPTH 值。