很多朋友在玩游戏的时候都可能遇到过下图这种画面撕裂的情况。尤其是对于FPS玩家,这种撕裂在迅速转动镜头时非常明显。

077045fc81b62743820621bf36c294b3.png

不过通常游戏设置里面都会有相应的选项来进行调整,比如是否开启垂直同步,是否启用三级缓冲等,打开之后画面撕裂的问题就会有明显的改善。

除了垂直同步以外,我们在购买的显示器和显卡的时候也可能听说过G-Sync、FreeSync等相关的技术,那么这些概念到底是什么意思?他们又是如何解决画面撕裂的问题呢?

0b94e9b66b87e0af2ab8923b07eb8122.jpeg

撕裂原因

首先我们需要先从画面刷新的基本原理讲起。对于任何一个显示器,其屏幕画面的更新都不是瞬间完成的,而是要从上到下进行逐行扫描刷新,整个屏幕刷新一次是需要一定时间的。

华为手机支持960fps录制,本地显示器录了一段,可以明显看到逐行更新。

我们常说的60HZ显示器其实表示的是屏幕刷新率,也就是显示器每秒可以更新60次。但单次从第一行扫描到最后一行时间并不需要16.6ms(1s/60),也许5ms就可以搞定。

另一方面,屏幕要显示的画面数据其实来源于GPU的Buffer,而GPU往buffer里面写数据的速度与显示器是无关的。GPU产生帧率与显示器帧率往往不一致,如果不加以同步就必然产生撕裂,简单来说,GPU会在显示器读取buffer时把buffer改成下一帧内容,导致显示器上半屏是后一帧图像,下半屏是前一帧图像。

下面是在apex中关闭垂直同步录的,

可以看到其中有撕裂

3be5578275b26fcc5018514f96e4f2ca.png

双缓冲

双缓冲是显卡的渲染基本特性,GPU会使用两个buffer,每次渲染完后都把画面写入backbuffer。而显示器只从frontbuffer读取画面,通过交换指针来交换两个buffer,这个操作可认为是瞬间完成的。

6bf53b5b78124090d0348c79e91d14cf.png不过swapbuffer时,显示器还没读取完frontbuffer,依然会产生撕裂。

1dac4837393c19337825a9e4dd0f5923.png

垂直同步

双缓冲下,想要不撕裂,就需要保证显示器在显示完一个buffer后,再去swapbuffer,这就是垂直同步。简单讲,就是显示器在显示完后会向显卡发送一个v-sync信号。

不过垂直同步有两个明显的的缺点:

1.锁帧,这会把游戏帧率限制到显示器帧率。比如你使用的是60帧的显示器,那么无论你使用的是I9的CPU还是4090的显卡,在fps游戏中,玩家操作依然会有明显的延迟。比如下面情况(使用unrealInsight工具进行性能分析),开垂直同步锁了60帧之后,会发现CPU一直都在idle。

16db64f244df157c6154d43223640269.png

2.降帧。当GPU帧率低于60帧,或突然下降时,比如45帧,最终显示的帧率会变成30帧。

关于第2点,我们再进一步分析一下

理想情况:GPU输出帧率高于60帧,输出一帧画面后等v-sync信号,最终显示器顺序输出每帧图像

23818b21fe3a212a9098c2f4cd1fe07a.png

帧率低的时候:当游戏卡了一下,GPU不能在16.6ms内完成一帧时,显示器产生v-sync信号后,发现没新数据,下一帧就继续使用老数据,导致两次显示了同一帧。再等到下一个v-sync信号,GPU输出了第三帧画面,正常显示,我们会发现中间的第二帧画面丢失了。

6f8d0d4d0f007bff5a827d29ee33e107.png

另外考虑如果GPU稳定以45帧输出画面,那么每两个v-sync信号只有一个会显示新画面,最终显示器输出的是30帧。

三缓冲

对于低帧率和帧率波动情况,可以用三缓冲来缓解,当帧率高于显示器帧率时,依然是垂直同步锁帧方案。

728d7897b8944a07e3091fddf3542e8d.png

可以再加一个backbuffer,让GPU在完成一帧后不等垂直同步信号,接着运行,把数据写入另一个backbuffer。当swapbuffer时,顺序选取下一个buffer,相当于多了一个蓄水池。

d324e3446c974ee0d6226cefb40b2e06.png

b7cbc3bb7fe285f1095b6f007de23c6e.png

比如上图,GPU错过了第二个v-sync信号,就把图像缓存起来,第三个v-sync信号时就能显示第二帧图像了。

这里注意,注意GPU每帧输出的图像都必须顺序显示,中间不能丢。而且第一次GPU遇到卡顿的时候是无法避免丢失的,因为那个时候另一个backbuffer里面还没有东西。

这样偶尔有一帧卡,因为多了个缓冲,依然能以60hz输出图像给显示器。当GPU稳定45帧运行时,显示器也能以45帧输出图像,而不是30帧。

但这样也存在问题,帧的逻辑时间可能长短不一,但最终都以16.6ms间隔显示在屏幕上,想象一个匀速直线运动物体,前一帧移动了16ms的距离,后一帧移动了26ms的距离,那么反映到显示器上物体移动就不匀速了。目前看,这种情况无法避免,因为GPU输出的画面是对游戏世界的离散采样,只有让帧率足够高,才能缓解这种问题。

Apex里的垂直同步选项里可选双缓冲和三缓冲,而且解释也比较清楚。

23c91d3573601a41666cafc1463c6ecf.png

另外三缓冲不是游戏独有的技术,普通软件也能使用。安卓早期UI不流畅,因此在Project Butter中引入了vsync和三缓冲,app都可以使用该特性,也可以用开关mLayerTripleBufferingDisabled进行控制。

Android 之 Project Butter 详细介绍

https://www.jianshu.com/p/aea19baa3608

可变帧率显示器 G-sync Freesync

可变帧率显示器就是freesync和G-Sync技术,分别是AMD和英伟达的技术,要有对应显卡来让显示器帧率与GPU输出画面帧率同步。比如GPU在某段时刻的帧率分别是50,51,57,那么显示器也会立刻改变自己的显示帧率。这样可以做到延迟最低,也不会撕裂。那这个时候是不是还需要开启垂直同步呢?

开垂直同步

帧率依然会限制在屏幕最高帧率,只是GPU画面不需要等v-sync信号,显示延迟更低。

关垂直同步

不锁帧,GPU帧率低于显示器最高帧率时,也不会撕裂,GPU帧率高于显示器帧率,还会撕裂。

因此只要GPU帧率低于显示器帧率,垂直同步开关没影响,都是不撕裂+立即显示,就看游戏能不能跑到更高帧率了。

找了一台支持G-Sync的144hz显示器,关闭垂直同步,游戏稳定100hz左右,确实一直处于流畅状态,也没有撕裂。

3677118057625c364bda9e8e8bf45ece.png

FastSync/EnhancedSync

有没有办法在普通显示器上也实现既高帧率,又不撕裂?可以,回顾三缓冲方案,如果GPU帧率很高,可以在两次v-sync间输出两帧,那么就写入两个backbuffer,下一次v-sync来时,选取最新的backbuffer即可,另一个丢弃。这样就既开启了垂直同步,又不锁60帧,能尽快显示最新的画面。这种方式不妨称为FastSync。

cf271cb1a050d113dddc284af615c68d.png

这么做输入延迟高于关掉v-sync,但低于开v-sync,很适合fps游戏。

不过依然有最高帧率限制,在两次v-sync间如果把backbuffer都写满了,还是要等,最高帧率为(backbuffer数*显示器帧率)。假如一个游戏backbuffer开了3个,对于普通玩家的60帧显示器,最高帧率可以到达180,也基本够用了。

在虚幻引擎中,r.D3D12.UseAllowTearing和r.D3D12.SwapChainBufferCount分别控制了是否开启FastSync和backbuffer的数量。

863c0aab4ec5d23b37e1506e770bafc7.png

映射到对DX接口的操作在这里

8a48cf2fdbbf3e6b0bb81d578eaf46ca.png

如果使用了这种方式,注意开启防撕裂时要关闭垂直同步。

建议

  • 如果只是普通显示器,而且GPU帧率是显示器帧率的2倍或3倍,就使用FastSync/EnhancedSync。

  • 如果显示器支持freesync或G-Sync,fps游戏就不开垂直同步了。

  • 尽量不要使用双缓冲的v-sync,用三缓冲的。

参考:
Android 之 Project Butter 详细介绍:https://www.jianshu.com/p/aea19baa3608
什么是画面撕裂?垂直同步,G-sync,Freesync到底有啥用?:https://zhuanlan.zhihu.com/p/41848908
AMD:https://www.hardwaretimes.com/what-is-v-sync-should-you-turn-it-on-or-off/
垂直同步到底要不要开?:https://www.bilibili.com/video/BV16x411e7bp/

 往期文章推荐 

612a4367b41112bc892f9ce8da1b98d6.png

游戏开发技术系列【想做游戏开发,我应该会点啥?】

8da1b15cc432c3632b355c0f4ef13444.png

虚幻引擎技术系列【使用虚幻引擎4年,我想再谈谈他的网络架构】

98ccbc394a45d4163ae34e13eed8e53e.jpeg

游戏科普系列【盘点游戏中那些“欺骗玩家眼睛的开发技巧”】

d745300efd2109b98dcf778afd24caa5.jpeg

C++面试系列【史上最全的C++/游戏开发面试经验总结】

我是Jerish,网易游戏工程师,6年从业经验。该公众号会定期输出技术干货和游戏科普的文章,关注我回复关键字可以获取游戏开发、操作系统、面试、C++、游戏设计等相关书籍和参考资料。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐