防止 OpenGL 缓冲帧

Posted

技术标签:

【中文标题】防止 OpenGL 缓冲帧【英文标题】:Prevent OpenGL from Buffering Frames 【发布时间】:2018-05-21 00:53:27 【问题描述】:

我正在编写一个程序,该程序需要极低的延迟纹理来进行屏幕流式传输(低于 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 【参考方案1】:

我找到了答案,有一个鲜为人知的OpenGL扩展名为SGI_video_sync,使用它可以等待下一帧。

即:

glFlush();
uint remainder;
glXWaitVideoSyncSGI(1, 0, &remainder);

【讨论】:

以上是关于防止 OpenGL 缓冲帧的主要内容,如果未能解决你的问题,请参考以下文章

◮OpenGL-帧缓冲

在 OpenGL 中显示帧缓冲区

如何定义 QT Opengl 帧缓冲区的大小

OpenGL 帧缓冲区缺失面

将负值混合到帧缓冲区 0 opengl

快速交换帧缓冲区 OpenGL