撰写了文章 更新于 2017-12-15 18:04:24
【弹幕程序科普计划】 第六篇 垂直同步与全屏模式
【垂直同步与全屏模式】
上次文章在介绍绝对帧率控制法的时候提了一句,在没有垂直同步的情况下画面会产生缺陷。今天就主要来介绍一下这种缺陷的由来和解决方法。
首先,先来理解一下画面刷新的过程。对于一幅画面来说,刷新时总是要从上到下逐行刷新的,如果这个刷新过程给用户看到,用户肯定会感觉到画面在刷,这个缺陷无法忍受。
为了缓解这个缺陷,在老电视上出现过一种隔行扫描技术,并不把一幅画面逐行刷新,而是先刷新奇数行,再刷新偶数行,这样将一帧画面分成了两场,奇数场和偶数场。这样就大大缓解了逐行刷新的缺陷,并且有近似刷新率翻倍的效果,但是当画面大幅度变换时,奇场与偶场可能相差过大,造成画面隔行交错现象。虽然存在一定缺陷,但是这种视频信号到现在依然有很多设备采用,比如一些安防摄像头、工业摄像头之类的。
我们现在用的显示器,在解决逐行刷新的问题上也是有典型方法的。这种方法称为乒乓操作。具体做法是,准备两块缓存,其中A缓存显示到屏幕,B缓存用于更新画面,当B缓存更新完成后,AB缓存互换,变成B缓存显示到屏幕,A缓存更新,如此交替。这样,用户在屏幕上看到的画面并没有在刷新状态,也就不会有上述缺陷,而在刷新的是后面那块看不到的缓存。这里就引出了一个问题,就是应该在后面那块缓存刷新完的时候进行AB互换。如果在没有刷新完的情况下进行互换,用户就会看到一幅刷新到一半的画面,这就是画面撕裂现象。当画面内容变化幅度较大时(比如版面背景大幅运动或者存在很多运动特效时),这种现象会更加明显。以下给出一幅示例画面。可以看到画面上方的特效部分出现了明显的断层,而始终不变的界面部分则看不出异样。
不过要说明一下,画面撕裂现象只在全屏模式下才会出现,并且不可能被截图截到,这幅图是为了示例而做出来的。DirectX本身的全屏方法,是专门开设显示缓存用于显示到屏幕,只有这这种情况下,缓存刷新不完全的缺陷才会显示到屏幕上,这种全屏模式又称为全屏独占模式。
要消除画面撕裂现象,就应该在缓存画面完全更新完以后,再进行AB缓存互换。如何知道它是否更新完毕,就是通过同步信号来判断了,这也就是常说的垂直同步。但是,一方面上次文章也说到,要使用绝对帧率控制法就不能开启垂直同步,另一方面,垂直同步有时也会存在一些缺陷,比如开启垂直同步会在很多电脑上产生显示延时,其现象是玩家发现从自己按键输入到游戏画面反应之间存在一个延时。很多人会误以为这是操作延时,输入延时,但其实延时发生在画面显示环节,是等待同步信号过程中产生了延时。
由于垂直同步或多或少存在缺陷,因此很多时候会选择关掉垂直同步。那么在不使用垂直同步的情况下,如何处理画面撕裂现象呢?主要有两种方法:三重缓冲方法和伪全屏方法
1. 三重缓冲
之前说乒乓操作时用了两块缓存,一块用于显示,一块用于刷新,但是可能产生画面撕裂现象。但是如果缓存数量增加到3,那就绝对不可能看到撕裂了。ABC三块缓存,A显示到屏幕,B等待显示,C用于更新。下一帧的时候,B用于显示,C等待,A用于更新,以此类推。这样不管在更新的那块缓存有没有更新完,等待显示的那块缓存总是更新完的,因此没有同步信号也不会有画面撕裂现象。不过这种方法显而易见的,会带来了一帧画面延时。
据说三重缓冲只对OpenGL游戏起作用,我自己也并没有调通这个方法,因此我对它的认识也只停留在理论层面。倒是比起三重缓冲,有一种更加简单易行的伪全屏方法可以应对画面撕裂。
2. 伪全屏
由于画面撕裂现象仅存在于全屏独占模式,在Windows窗体显示时,窗体会有其它的缓存,因此不会看到撕裂现象。由此就产生了一种简单直观的应对撕裂现象的方法,就是将窗口拉伸放大到全屏,然后让窗口边框、标题栏不要显示,窗体背景弄成全黑,这样显示效果与全屏独占模式几乎相同,如果再给窗体加个保持前端显示什么的,绝对以假乱真。
除了可以消除画面撕裂现象外,伪全屏还有一些其它优势,比如在切换全屏和窗口模式时,全屏独占模式相当于要切换显示设备,这个过程会存在延时,同时在程序里还必须要处理设备丢失及设备找回等比较烦人的问题,比较麻烦;而对于伪全屏来说,切换全屏仅仅是在调整窗口大小和显示样式,几乎不存在延时,非常便捷。因为具有这些优势,有越来越多的游戏使用了伪全屏方法,比如东方VP补丁,近年来也有不少GalGame开始使用伪全屏模式,我在制作《弹幕音乐绘》剧情篇时也开始采用这种方法,因此也有一些使用心得。
不过伪全屏还是存在一些缺陷。与全屏独占相比,全屏独占模式是开设专门的缓存用于显示到屏幕,因此效率更高。假设游戏分辨率为640×480,显示器的分辨率是1920×1080,如果使用全屏独占模式的话,那显示缓存的大小就是640×480,而如果使用伪全屏的话,相当于在刷新一块1920×1080的屏幕,当然效率会低。但是,这里的效率仅仅是屏幕刷新效率,和游戏帧率无关。实际测试发现,使用伪全屏时,如果画面存在大幅度刷新,可能会出现画面刷新率跟不上游戏帧率的情况。虽然游戏帧率保持在60fps,但却会出现画面稍许不连贯的现象。由于存在这种缺陷,因此伪全屏并不能完全替代全屏独占模式。同时也发现一些电脑上,使用全屏独占时延时较小,使用窗口模式或伪全屏则延时较大,这种现象原因还不清楚。
此外,关于全屏独占模式和伪全屏模式对游戏效率的影响,我测试的结果是影响很小。甚至我在一台8年前的笔记本上看到了如下现象:游戏在窗口状态下帧率难以达到60fps,但是全屏状态可以稳在60fps,即使这种全屏是伪全屏。这种现象我还不能解释,如果有哪位神能理解这种现象的话请务必教教我。。。不过,不管怎样,至少对我那台笔记本而言,游戏在伪全屏状态的效率和全屏独占状态的效率都高于窗口模式的效率。
那么以上就是本期关于垂直同步和全屏模式的科普。