【发布时间】:2014-12-25 12:41:53
【问题描述】:
我似乎无法理解帧绘制如何与缓冲区交换同步。
以下是问题:
1.由于大多数开放式 GL 调用都是非阻塞(或缓冲)的,您如何知道 gpu 是否已完成当前帧?
2.open GL 是否会处理它,以便未完成的帧不会被交换到窗口缓冲区
3.如何计算帧率?我的意思是确定绘制的帧数或每帧花费的时间的依据是什么?
【问题讨论】:
-
@datenwolf 没错!优点
我似乎无法理解帧绘制如何与缓冲区交换同步。
以下是问题:
1.由于大多数开放式 GL 调用都是非阻塞(或缓冲)的,您如何知道 gpu 是否已完成当前帧?
2.open GL 是否会处理它,以便未完成的帧不会被交换到窗口缓冲区
3.如何计算帧率?我的意思是确定绘制的帧数或每帧花费的时间的依据是什么?
【问题讨论】:
与 GL 同步的现代方式是使用 sync objects。使用glFinish()(或其他阻塞GL 调用)的缺点是会使GPU 和CPU(线程)都停顿:CPU 将等到GPU 完成,然后GPU 因为没有新的工作排队而停顿。如果同步对象使用得当,两者都可以完全避免。
您只需在您感兴趣的任何时候将 fence sync 插入到 GL 命令流中,然后可以检查之前是否所有命令都已完成,或者您可以等待完成(同时你仍然可以有更多的命令排队)。
请注意,对于帧速率估计,您不需要任何明确的同步方式。只需使用SwapBuffers() 就足够了。 gpu 可能会提前排队几帧(nvidia 驱动程序甚至对此进行了设置),但这不会干扰 fps 计数,因为只有前 n 帧排队。只需计算每秒发出的SwapBuffer() 呼叫数,您就可以了。如果用户开启了sync to vblank,帧率会被限制为显示器的刷新率,不会出现撕裂现象。
如果您需要更详细的 GPU 计时统计信息(但对于帧速率计数器,您不需要),您应该查看timer queries。
【讨论】:
glFinish() 没有被弃用,它仍然存在于现代核心配置文件中。但应该小心使用。在一个普通的 OpenGL 程序中,很少(而且通常从不)需要它。过去在共享上下文的多线程情况下需要它,但同步对象也是一个更好的选择。
glFinish()而不是glFlush():说明
glFinish 在所有先前调用的 GL 命令的效果完成之前不会返回。此类影响包括对 GL 状态的所有更改、对连接状态的所有更改以及对帧缓冲区内容的所有更改。
Timer,计算一秒钟内对glFinish()的调用次数。【讨论】:
glFinish() 时,可以保证此函数只会在帧成功绘制到屏幕后返回。所以再次回答问题 2,YES。
SwapBuffers 调用,它将保证您在SwapBuffers 调用之前进行的所有调用都将在交换缓冲区之前完成。上面的一些内容被稍微简化了,因为这开辟了一些可能非常广泛的领域。例如,您可以使用计时器查询来测量 GPU 处理给定帧所需的时间。但是你必须小心你从中得出的结论。
作为一个假设示例,假设您以 60 fps 的速度渲染,受垂直同步的限制。您在帧上放置了一个计时器查询,它告诉您 GPU 花了 15 毫秒来渲染该帧。这是否意味着您能够保持 60 fps 的极限是正确的?并且使您的渲染/内容更复杂会使其低于 60 fps?不必要。除非您还跟踪了 GPU 时钟频率,否则您不知道 GPU 是否真的在其极限运行。电源管理可能已将频率/电压降低到处理当前工作负载所需的水平。如果你给它更多的工作,它可能能够很好地处理它,并且仍然以 60 fps 的速度运行。
【讨论】: