我有一个带有OpenGL窗口的SDL2应用程序,它表现良好:运行时,该应用程序与我的60Hz显示屏同步,并且我看到该应用程序的CPU使用率为12%。
到目前为止,一切都很好。 但是,当我通过从深度缓冲区读取一个(!)深度值(绘制后)来添加3D拾取时,会发生以下情况:
如果我不执行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%的水平。
更新
在Intel HD Graphics上,CPU不旋转锁定。 glReadPixels仍然很慢,但是与nVidia驱动程序上完全加载100%的CPU相比,CPU的占空比很低(约为1%)。
我还尝试了asynchronous pixel reads via PBO(像素缓冲区对象),但仅适用于RGBA值,而不适用于DEPTH值。