这个问题挺好的。

为了理解这个问题,首先需要了解什么是垂直同步。

Analog television?

en.wikipedia.org图标

早在CRT(显像管)时代,电视机的画面是由热电子撞击涂在显像管上的荧光粉发光来进行显示的。在显像管的背面,有一把热电子「枪」,发射出电子束。在电子束和屏幕之间,有电磁线圈,左右一对,上下一对,分别控制电子束的水平偏转和垂直偏转。

Cathode-ray tube?

en.wikipedia.org图标

为了显示一幅画面,控制电路通过控制流过线圈当中的电流,改变磁场的强弱和极性,从而改变电子束在水平方向和垂直方向的偏转角度。就如同我们写文章一样,从屏幕的左上角开始,从左到右从上到下一行一行地扫过屏幕的整个显示区域,激发荧光粉发光,显示一幅完整的图像。

图片来源:维基百科(https://en.wikipedia.org/wiki/Analog_television#/media/File:Raster-scan.svg)

在上图当中,我们可以看到有两种虚线。一种是在一行扫描完成之后,从右边回到左边的虚线;另外一种是在最后一行扫描完成之后,从右下方回到左上方的虚线。

第一种就被称为水平同步,而第二种就被称为垂直同步。在模拟信号时代,它们都有专门的信号与其对应,分别标志著一行的结束和一帧的结束。

虽然在如今的数字液晶屏(或者等离子、OLED)时代,显示的原理已经有很大的不同,但是水平同步和垂直同步的概念仍然被保留了下来。我们依然可以认为画面是这样一行一行一帧一帧显示出来的。

而游戏当中的所谓开启垂直同步,就是CPU(或者GPU)必须等待上一帧的垂直同步信号,才开始在屏幕上更新显示下一帧的画面。这样做的目的是确保在任何时候,画面上显示的所有行都是属于同一帧的,也就是不会出现前面几行是上一帧而后面几行是下一帧的情况,就是平常所说的画面割裂。

但是仅仅是开启垂直同步的话,只是限制了CPU/GPU可以向显示设备推送画面的时机,其本身并不一定会限制游戏逻辑(游戏主循环)的循环频率。比如,游戏依然可以跑在120fps,也就是每秒渲染120幅画面。只不过,最终显示在屏幕上的只是其中的一部分(60帧),其他的我们看不到而已。

当然,这种情况对于大多数游戏来说,显然是没有意义的,平白浪费了很多计算资源。于是,大多数游戏引擎当中,会进一步让CPU/GPU等待第N帧的垂直同步信号之后,才开始N+2帧(此时,N+1帧需要输出给显示器进行显示了)的准备和渲染工作。也就是说,在屏幕显示第N帧的时候,CPU/GPU在绘制的是第N+1帧(绘制到内存当中的一块缓冲区,也称为back buffer);而当显示器显示第N+1帧的时候,CPU/GPU在绘制的是第N+2帧。

这就是所谓的双缓冲机制。我们在玩很多游戏的时候,会有一个选项,问我们是否要开启双缓冲,甚至是三缓冲(CPU/GPU与显示的内容差2帧)。

在这种情况下,开了垂直同步,其实也就是将游戏锁定在了屏幕刷新率上。

而如果不开启垂直同步,直接锁游戏的帧率,那么更多的只是在游戏的主循环加个限制,让其按照这个帧率运行。这个时候,CPU/GPU对画面的更新与屏幕的刷新可能不同步,也就是屏幕的上半部和下半部可能是显示了两个相邻帧的一部分,画面就会出现割裂。但是这样做的优点是CPU/GPU可以不必等待外部的垂直同步信号才开始工作,对于帧与帧之间计算量波动较大的情况,对于复杂的帧可以花费更多的CPU/GPU时间来计算,导致的后果可能是画面撕裂,但是总比跳帧强(在开启垂直同步的情况下,如果计算不能在下一个垂直同步信号到来之前完成,那么这帧就可能面临著被丢弃,也就是跳帧的后果)。


最重要的区别在于:是游戏自己的代码在等待,还是驱动在等待。

垂直同步的情况下,游戏的渲染循环走到Present()的时候,是会跳到游戏之外的代码之中,由系统和驱动进行等待,等待完毕再回到渲染循环。这个等待的时间里面,游戏代码本身不能进行任何操作。如果是多线程代码,呼叫了Present()的线程,通常也就是渲染线程也是无法进行任何其他操作的。什么时候能返回游戏也说了不算,只能等待系统结束等待并返回。

游戏自己锁60fps的情况,则是游戏在自己的代码之中主动等待,等到固定的时间之后再推送Present()或者进入下一个循环(取决于你在哪里等)。在等待的途中游戏代码可以去干点别的,如果是多线程的话,渲染线程可以主动睡下,并设定一个定时器唤醒,或者由其他线程计时并唤醒。

游戏自己锁帧的好处是可以避免驱动一下子吃进太多Present()提前缓存多帧导致的输入延迟。

不过锁帧和垂直同步并不冲突,可以在锁帧的前提下开启垂直同步,系统的垂直同步通常是只要内部渲染队列没有填满,就不会进行等待并立即返回。显示的时候则会忠实的去「同步」显示。只要掌握好Timing,游戏是可以掌握一定的控制权的。不过Windows 8之后有了更好的方法,很少有游戏单纯为了「低延迟」和「掌握控制权」而锁帧了。


游戏锁60fps,照样发生画面撕裂

60Hz开V-Sync,画面完整


做个实验就好了,我的实验结果是:

以60HZ屏幕为基础:

开垂直同步,只要垂直同步不出BUG,画面绝对不可能出现任何撕裂

关垂直同步,用锁帧工具把游戏锁死为60帧,画面该撕裂还是撕裂。

这就是区别,但是原理我讲不出来,网路上对于VSYNC的定义非常迷糊,就是英伟达也没说出来个死理。

我想垂直同步绝非仅仅是个限帧工具而已,不然怎么解释同是锁帧不开垂直同步就会画面撕裂呢


区别在于 垂直同步6060hz的帧生成时间是稳定一致的16.666ms

而锁60帧的话 帧生成时间可能不一致 有大有小 可能前一帧的生成时间是20ms 后一帧的生成时间可能就是10ms 与显示器的刷新率就会不一致 依然会有撕裂


锁帧60:GPU监视帧时,帧时小于1/60秒则暂停渲染,等待到1/60再继续。大于1/60秒则不涉及。相当于帧数曲线砍掉高频。

垂直同步:等待屏幕刷新结束再开始渲染,渲染完重复等待。


推荐阅读:
相关文章