Geo*_*rey 5 c linux opengl amd nvidia
我正在编写一个程序,需要极低延迟的纹理来屏幕流(10ms以下),我已经实现了这个使用GL_ARB_buffer_storage,它非常适合流式传输,而vsync则可以防止撕裂.
但是我发现NVidia管道在阻塞之前调用交换缓冲区时会缓冲2到8帧,我需要防止这种情况.
我所做的是以下内容:
uint64_t detectPresentTime()
{
// warm up first as the GPU driver may have multiple buffers
for(int i = 0; i < 10; ++i)
glxSwapBuffers(state.renderer);
// time 10 iterations and compute the average
const uint64_t start = microtime();
for(int i = 0; i < 10; ++i)
glxSwapBuffers(state.renderer);
const uint64_t t = (microtime() - start) / 10;
// ensure all buffers are flushed
glFinish();
DEBUG_INFO("detected: %lu (%f Hz)", t, 1000000.0f / t);
return t;
}
Run Code Online (Sandbox Code Playgroud)
然后在绘制线程中我执行以下操作:
uint64_t presentTime = detectPresentTime();
if (presentTime > 1000)
presentTime -= 1000;
while(running)
{
const uint64_t start = microtime();
glClear();
// copy the texture to the screen
glxSwapBuffers();
const uint64_t delta = microtime() - start;
if (delta < presentTime)
{
glFlush();
usleep(delta);
glFinish();
}
}
Run Code Online (Sandbox Code Playgroud)
该解决方案在NVidia硬件上运行良好,但据报道不能在AMD GPU上计算正确的当前时间.
有一个更好的方法吗?我知道glFinish通常不应该在应用程序中使用除了分析,但我找不到另一种方法来确保GPU管道不缓冲帧.
编辑:对于那些感兴趣的人,这有效地模拟了Linux下的FastSync,但没有禁用vsync.
Edit2:也许现在的时间函数应该有点不同:
uint64_t detectPresentTime()
{
glFinish();
// time 10 iterations and compute the average
const uint64_t start = microtime();
for(int i = 0; i < 10; ++i)
{
glxSwapBuffers(state.renderer);
glFinish();
}
const uint64_t t = (microtime() - start) / 10;
DEBUG_INFO("detected: %lu (%f Hz)", t, 1000000.0f / t);
return t;
}
Run Code Online (Sandbox Code Playgroud)
我找到了答案,有一个鲜为人知的 OpenGL 扩展名为SGI_video_sync,使用它可以等待下一帧。
IE:
glFlush();
uint remainder;
glXWaitVideoSyncSGI(1, 0, &remainder);
Run Code Online (Sandbox Code Playgroud)