我知道,如果您打开vsync,它将使渲染与垂直重绘周期同步,以防止撕裂,并且这样做可以将渲染速率(FPS)限制为监视器刷新速率,通常为60hz / 60 fps,尽管存在其他速率以及。

但是,当您未以60fps的全速运行时,vsync对帧速率有何影响?我听说有人说您将被限制为60fps的倍数(好吧,精确到〜16ms),但是从观察的角度来看,fps会剧烈波动。

#1 楼

简短的答案是It's Complicated™。 :)

很多因素都可能影响帧计时(以及由于游戏的动画增量时间与实际帧交付时间不匹配而导致的动画颤抖相关问题)。其中一些因素是:游戏的CPU限制与GPU限制如何,游戏的代码如何测量时间,CPU和GPU上的帧时间有多少可变性,CPU提前多少帧

关于特定的问题,即是否将锁定到60 fps(30、20、15等)的除数,这似乎允许主要取决于应用程序受GPU限制还是CPU限制。如果您受GPU限制,那么假设应用程序稳定运行(本身不会产生任何故障或性能快速变化),它将确实锁定在其可以维持的vsync速率的最高除数上。此时序图显示了它的工作方式:



时间从左到右运行,每个块的宽度代表一帧的工作时间。在开始的几帧之后,系统进入稳定的状态,即帧以稳定的速率输出,每两个垂直同步周期间隔一次(即,如果垂直同步为60 Hz,则游戏将以30 fps的速度运行)。 >
请注意CPU和GPU行中的空白(空闲时间)。这表示如果关闭vsync,游戏可能会运行得更快。但是,在启用vsync的情况下,交换链给GPU施加了背压-在vsync释放供其渲染的后缓冲之前,GPU才能开始渲染下一帧。由于驱动程序直到GPU开始渲染下一帧之前不会从Present() / SwapBuffers()返回,因此GPU会通过命令队列对CPU施加反压,并打开队列插槽供CPU继续发出命令。结果就是一切都以稳定的30 fps速率运行,并且每个人都很高兴(也许60 fps的纯粹游戏玩家r除外)。

将此与应用程序受限于CPU的情况进行比较:



这次,我们最终以36 fps的速度运行了游戏,在给定CPU的情况下可能达到的最大速度在这种情况下加载。但这不是刷新率的除数,因此我们无法均匀地将帧传输到显示器,其中一些帧显示了两个垂直同步周期,而另一些帧仅显示了一个。这将导致抖动。

GPU处于空闲状态是因为它在等待CPU进行更多工作,而不是因为它在等待可用于渲染的后缓冲。因此,交换链不会对GPU施加背压(或至少不会一直如此),GPU也不会对CPU施加背压。因此,CPU会尽可能快地运行,而不会出现在显示器上出现不规则的帧时间。

可以“修复”此问题,以便即使在游戏中,游戏仍会离散化为vsync友好的速率CPU限制的情况。游戏代码可以尝试识别这种情况,并通过使其CPU线程休眠以人为地将其自身锁定为30 fps或将其交换间隔增大为2来进行补偿。或者,驱动程序可以通过在Present() / SwapBuffers()中插入额外的睡眠来执行相同的操作(NVIDIA驱动程序确实将其作为控制面板选项;我不知道其他人)。但是无论如何,都必须有人发现问题并采取措施。在GPU受限的情况下,游戏自然不会以与vsync友好的速度稳定下来。

这都是简化的情况,CPU和GPU的工作负载都非常稳定。当然,在现实生活中,工作负载和帧时间会有变化,这可能导致发生更多有趣的事情。这样,CPU提前渲染队列和三重缓冲就可以发挥作用了。

评论


$ \ begingroup $
很好的答案,这个值得一提!
$ \ endgroup $
–尼古拉斯·米勒(Nicholas Miller)
18年4月21日在23:13

#2 楼

这取决于驱动程序如何处理丢失的帧。

一个选项是仅等待下一个vsync,导致出现32毫秒的中断,并且应用程序仅处于16毫秒的限制可能会引起波动。

下一个选项是将帧排队显示下一个帧,但不要等待。这仍然会导致视觉障碍,但是应用程序可以立即在下一帧开始,而不必被迫等待16 ms。如果下一帧的处理速度更快,那么甚至可能永远都不会显示后一帧。

最后的选择是不阻挡并立即将后帧推入显示屏,这可能会导致撕裂。

评论


$ \ begingroup $
将帧排入队列但不等待的选项是否会被视为三倍(或更高)缓冲?
$ \ endgroup $
–艾伦·沃尔夫(Alan Wolfe)
16 Mar 10 '16 at 14:19

$ \ begingroup $
@AlanWolfe可能需要至少3个缓冲区才能显示不撕裂且不阻塞的视图,一个要显示,另一个要显示,另一个要渲染。
$ \ endgroup $
–棘轮怪胎
16 Mar 10 '16 at 14:21