OpenGL实际更新屏幕需要多长时间?

时间:2014-01-25 08:53:09

标签: c opengl opengl-es 3d latency

我在C中有一个简单的OpenGL测试应用程序,它根据键输入绘制不同的东西。 (Mesa 8.0.4,在带有NVIDIA GTX650的PC上试用了Mesa-EGL和GLFW,Ubuntu 12.04LTS)。绘制非常简单/快速(旋转三角形类型的东西)。我的测试代码不会故意以任何方式限制帧速率,它看起来像这样:

while (true)
{
    draw();
    swap_buffers();
}

我已经非常仔细地计时了,我发现从一个eglSwapBuffers()(或glfwSwapBuffers)调用到下一个的时间是~16.6毫秒。从调用之后 {<1}}到之前下一次调用之前的时间只是稍微少一点,即使绘制的内容非常简单。交换缓冲区调用的时间远低于1ms。

然而,从应用程序更改其响应按键的绘制时间到实际显示在屏幕上的更改的时间> 150ms (大约8-9帧)。这是通过以60fps的屏幕和键盘的相机记录来测量的。 (注意:确实,我没有办法测量从按键到应用程序获取它需要多长时间。我假设它是<&lt; <150ms)。

因此,问题:

  1. 在调用交换缓冲区和实际显示在屏幕上之间缓冲图形的位置是什么?为何延误?看起来应用程序似乎总是在屏幕前方绘制许多帧。

  2. OpenGL应用程序可以做什么来立即绘制屏幕? (即:没有缓冲,只是阻止直到绘制完成;我不需要高吞吐量,我确实需要低延迟)

  3. 应用程序可以做些什么来尽快实现上述即时抽奖?

  4. 应用程序如何才能知道屏幕上实际显示的内容? (或者,当前缓冲延迟的时间长度/帧数是多少?)

4 个答案:

答案 0 :(得分:1)

啊,是的,你发现OpenGL与显示系统相互作用的特点之一,只有少数人真正理解(坦率地说,直到大约2年前我还没有完全理解它)。那么这里发生了什么:

SwapBuffers做了两件事:

  1. 它将(私有)命令排队到命令队列,该命令队列也用于OpenGL绘图调用,基本上标记缓冲交换到图形系统
  2. 它使OpenGL刷新所有排队的绘图命令(到后台缓冲区)
  3. 除了SwapBuffers本身没有做任何事情。但这两件事都有有趣的后果。一个是,SwapBuffers将立即返回。但是,只要“要交换后缓冲区”标志(通过排队命令),后缓冲区就会被锁定以进行任何会改变其内容的操作。因此,只要不进行会改变后台缓冲区内容的调用,事情就不会阻塞。并且会改变后台缓冲区内容的命令将暂停OpenGL命令队列,直到后台缓冲区被交换并释放以用于进一步的命令。

    现在,OpenGL命令队列的长度是一个抽象的东西。但通常的行为是,其中一个OpenGL绘图命令将阻塞,等待队列刷新以响应已发生的交换缓冲区。

    我建议你使用一些高性能,高分辨率的定时器作为时钟源,用日志语句来编写程序,以查看延迟发生的确切位置。

答案 1 :(得分:1)

  • 在调用交换缓冲区和实际显示在屏幕之间缓冲图形的位置是什么?为何延误?看起来应用程序似乎总是在屏幕前方绘制许多帧。
  

如果设置了swapInterval,则命令排队,无论是否向后备缓冲区提取,等待下一个vsync,在下一个vsync中,应显示此缓冲区。

  • OpenGL应用程序可以做什么来立即绘制屏幕? (即:没有缓冲,只是阻止直到绘制完成;我不需要高吞吐量,我确实需要低延迟)
  

使用glFinish将确保在此API返回之前绘制所有内容,但无法控制实际进入除swapInterval设置之外的屏幕的时间。

  • 应用程序可以做些什么来使上述即时抽奖尽快发生? 应用程序如何才能知道屏幕上实际显示的内容? (或者,当前缓冲延迟有多长/多少帧?)
  

通常,您可以使用同步(类似http://www.khronos.org/registry/egl/extensions/NV/EGL_NV_sync.txt)来查找此内容。

     

您确定测量延迟的方法是否正确?如果键输入实际上在您的PC中有明显延迟怎么办?您是否测量过代码中收到的事件到交换缓冲区之后的延迟?

答案 2 :(得分:0)

您必须了解GPU具有专用内存(板载)。在最基本的级别,此内存用于保存您在屏幕上看到的编码像素(它还用于图形硬件加速和其他内容,但现在这并不重要)。因为从主RAM向GPU RAM加载帧需要花费时间,所以可以获得闪烁效果:在短暂的瞬间,您可以看到背景而不是应该显示的内容。虽然这种复制发生的速度非常快,但是人眼很明显并且很烦人。

为了解决这个问题,我们使用了一种名为 double buffering 的技术。基本上双缓冲通过在GPU RAM中有一个额外的帧缓冲区来工作(这可能是一个或多个,取决于您正在使用的图形库和GPU,但两个足以工作)并使用指针指示哪个帧应该显示。因此,在显示第一帧时,您已经使用主RAM中的图像结构上的某些draw()函数在代码中创建了下一个帧,然后将此图像复制到GPU RAM中(同时仍显示前一帧) )然后在调用eglSwapBuffers()时,指针切换到后台缓冲区(我从你的问题中猜到了,我不熟悉OpenGL,但这是非常普遍的)。你可以想象这个指针开关不需要很多时间。我希望你现在看到直接将图像写入屏幕实际上会导致更多的延迟(并且令人讨厌的闪烁)。

同样~16.6毫秒听起来不那么多。我认为大部分时间都不会创建/设置所需的数据结构,而不是真正在绘图计算本身(你可以通过绘制背景来测试它)。

最后我想补充一点,I / O通常很慢(大多数程序中最慢的部分),而150ms根本不是那么长(仍然是眨眼间的两倍)。

答案 3 :(得分:0)

延迟将由驱动程序和显示器本身决定。即使您直接写入硬件,也会受到后者的限制。

应用程序只能做很多事情(即绘制快速,过程输入尽可能接近或在绘图期间,甚至可能在翻转时修改缓冲区)以减轻这种影响。在那之后,你将受到其他工程师的支配,包括硬件和软件。

如你所知,如果没有外部监控,你无法确定延迟是什么。

此外,不要假设您的输入(键盘到应用程序)也是低延迟!