c – 防止OpenGL缓冲帧

我正在编写一个程序,需要极低延迟的纹理到屏幕流(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;
}

然后在绘制线程中我执行以下操作:

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)",1000000.0f / t); 
  return t;
}
最佳答案
我找到了答案,有一个鲜为人知的名为SGI_video_sync的OpenGL扩展,使用它可以等待下一帧.

即:

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

相关文章

文章浏览阅读1.8k次,点赞63次,收藏54次。Linux下的目录权限...
文章浏览阅读1.6k次,点赞44次,收藏38次。关于Qt的安装、Wi...
本文介绍了使用shell脚本编写一个 Hello
文章浏览阅读1.5k次,点赞37次,收藏43次。【Linux】初识Lin...
文章浏览阅读3k次,点赞34次,收藏156次。Linux超详细笔记,...
文章浏览阅读6.8k次,点赞109次,收藏114次。【Linux】 Open...