【发布时间】:2023-04-04 04:07:01
【问题描述】:
我正在编写一个程序,该程序需要极低的延迟纹理来进行屏幕流式传输(低于 10 毫秒),我使用 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;
}
然后在绘图线程中我执行以下操作:
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();
}
}
此解决方案在 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;
}
【问题讨论】:
-
OpenGL wiki 有一篇关于此的有趣文章:khronos.org/opengl/wiki/Swap_Interval