前言我在带妹子刷分,团战又卡了,怎么跟妹子解释?在线等待。“卡”的含义无论是端游还是手游,我们都会不时遇到“卡”。这张卡一般有两种意思:丢帧和画面撕裂那么问题来了,这些情况是什么原因造成的呢??如何解决?掉帧首先,你需要知道什么是帧,什么是帧率。帧是图像动画中单个图像帧的最小单位,相当于电影胶片上的每一帧。一帧是静止画面,连续的帧构成动画,如电视画面。帧率(framespersecond),简单的说就是1秒内传输图片的帧数,也可以理解为图形处理器每秒可以刷新多少次,通常以fps(FramesPerSecond)表示现在大家应该都知道了,一帧就是一张静止的图片,很多帧加在一起就构成了视频、电影、游戏的画面。帧率就是我们游戏中常见的fps,指的是一秒钟内绘制的帧数,单位是“赫兹”(Hz)。这里做一个简单的科普。如果一般要求连贯性,当帧速率至少高于每秒约10到12帧时,人眼会认为它是连贯的。这种现象称为“视觉暂留”。生物结构决定的。通过这种现象,早期的无声电影都是用手驱动来快速播放画面,让人感觉是在播放一个完整的、连续的视频。按照我们的理解,帧率越大,越连贯,越不容易卡顿。但同时带来的消费也越多,比如电影需要更多的胶片,电脑需要更好的硬件支持。所以电影的帧率一般是24Hz,而电脑和手机的帧率一般是60Hz,这样人们在正常情况下才能舒服地观看和使用。丢帧的意义显而易见。本来游戏的fps是60,突然降到20,也就是每秒只有20帧。能不卡吗?那么,掉帧的原因是什么?其实我知道的原因大家都知道,不信请继续往下看……硬件原因是“我的手机玩游戏卡死了”“你这破手机,快换吧~”这种对话应该经常发生,所以大家都知道硬件是好的。在一定程度上决定了游戏是否“卡”,用高配置的硬件玩游戏才能保证游戏的流畅性。软件原因“你玩什么app,做什么游戏,这么卡,我手机配置那么高,我就玩你的卡”“嗯,可能是游戏优化没做得好,”第二个原因是因为游戏/软件本身的优化没有做好,图片太大,布局嵌套太深,那么帧的计算和渲染会花费更多的时间,这可能会导致掉帧。网络原因是“太差了,太慢了,我的ping都快1000了,怎么玩?”“赶紧换流量,团战快输了,人少怎么打”是的,第三个原因是网络原因,这也是最常见的原因。网络的波动会影响画面的传输,所以会掉帧。屏幕刷新机制以上三个原因其实涉及到屏幕刷新的基本机制。在一个典型的显示系统中,无论是手机还是电脑,一般都会涉及到三个部分:CPU和中央处理器。用于计算数据、信息处理。GPU,图形处理单元。用于处理图像图形,俗称显卡。显示,显示屏。它是用来显示图像的,也就是我们的手机屏幕和电脑显示器。整个显示过程是:CPU计算出屏幕需要的数据,然后交给GPU处理。GPU处理并绘制图像,然后将其存储在缓冲区中。display然后从这个缓冲区中读取数据并显示它。每一帧都要重复这项工作,即1秒内需要进行60次这样的循环操作,每次操作所需时间约等于16.6ms。也就是说,在我们常说的Android系统中,屏幕每16.6ms就会刷新一次。关于屏幕刷新机制,有一张很经典的图:可以看到,一到16.6ms,系统就发出一个VSync信号,然后屏幕从缓冲区中获取一帧新的图像并显示出来。与此同时,CPU也开始计算下一帧数据,然后将计算交给GPU,最后放入缓冲区,等待下一个VSync信号。什么是垂直同步信号?暂且按下去,以后再说。你可以先把它理解为一个同步刷新信号,同步CPU和屏幕。信号来了,屏幕开始切换画面,CPU开始计算下一帧。为了方便理解,我做了一个小动画:通过上面的解释,我们知道一帧的显示时间是16.6ms。在这段时间里,CPU和GPU必须对数据进行处理,并将它们放入缓冲区(buffer)中。如果CPU和GPU在某个16.6ms内没有绘制下一帧数据,那么显示器就无法更新下一帧数据,这就是丢帧。这就是为什么以上三个原因会导致掉帧的原因,我们来回顾一下:1.硬件原因。硬件比较差,就是CPU和GPU计算不给力,导致一帧数据没有准备好,所以掉帧。2、软件原因。在硬件充足的情况下,一帧App或游戏数据计算复杂,嵌套过多或图过大,也会导致下一帧数据在16.6ms内没有准备好,导致帧降低。3.网络原因。在硬件和软件都正常的情况下,由于网络波动,导致CPU的计算数据无法从网络获取,这势必会造成CPU数据准备延迟,最终导致掉帧。那么丢帧之后,屏幕刷新机制会如何处理后续的帧呢?如果是游戏的话,因为更看重即时性,所以丢帧就不用管了,直接准备当前时间应该显示的内容。终于显示在屏幕上。所以这种情况下掉帧是真的丢了。如果是应用程序,可能更看重数据的完整性,所以如果丢掉第二帧,那么屏幕会继续显示第一帧,而CPU和GPU继续准备第二帧的数据frame,如果能在接下来的16.6ms内完成第二帧数据,那么屏幕就会显示第二帧。比如有时候手机卡顿的时候,我们操作App的时候,操作会出现延迟,也就是掉帧。在这种情况下,帧并没有真正被丢弃,而是被延迟了。屏幕撕裂接下来,让我们看看屏幕撕裂。为什么一帧出现两帧?先了解一个概念:“逐行扫描”、“逐行扫描”是指显示屏不是“刮花”一次显示一张图片,而是从上到下逐行显示,只是显示速度较快所以无法用肉眼看到。前面说过屏幕的数据是从缓冲区Buffer中取出来的。如果在从屏幕取数据,逐行扫描显示屏的过程中,Buffer中的数据发生变化,可能会导致屏幕撕裂。最明显的例子就是:显卡的fps是180,而显示器的fps是60。也就是说显卡每秒可以生成180帧,而显示器每秒只能读取60帧。那么在显示器从Buffer中读取数据逐行扫描的过程中,显示??一张图片需要1/60秒,但是在1/180的时候,显卡会保存下一张图片的数据到缓冲区。结果,显示器的下半部分显示了第二张图片的内容。这也导致屏幕撕裂。这里再用一个动图来解释一下:所以为了防止这种情况,一般的显示系统都会加一个双缓冲+垂直同步的概念:首先,当开启垂直同步时,GPU的fps会被限制在相同的作为显示器的fps。系统会在显示器绘制完一帧后发送一个垂直同步信号,然后CPU和GPU准备下一帧的内容,等待显示器绘制完下一帧,再发送一个垂直同步信号。如此反复,显卡的fps有限,按照显示器的标准绘制图像。该垂直同步信号称为VSync信号。玩游戏的朋友应该知道,很多游戏内的设置页面都有开启垂直同步的选项,目的是让显卡的fps适应显示器的fps,防止画面撕裂。其次,通过双缓冲来保证一帧数据的一致性。1、缓冲区backBuffer用于CPU/GPU图形处理。2、缓冲区frameBuffer用于监控显示。这样分工明确后,屏幕只会读取framebuffer的内容,也就是一个完整的帧。CPU/GPU计算出的新帧的内容将被放入后台缓冲区,而不会影响帧缓冲区的内容。只有在屏幕绘制完一帧内容后,CPU/GPU计算出的新帧内容,即backbuffer内容,才会与framebuffer进行交换。这确保了数据帧的完全连贯性。总结就是:当屏幕扫描到第一帧时,系统发出VSync信号,此时会发生三件事:1.交换两个缓冲区(framebuffer,backbuffer)的内容。2、显示器开始显示第二帧的内容,即交换后的framebuffer的内容。3、CPU/GPU开始计算处理第三帧的内容,处理完内容后放入backbuffer。另一个动画:AndroidProjectButter(黄油计划)问题解决了吗?No.加入VSync信号后,丢帧问题变得更加严重:可以发现,加入VSync信号后,虽然CPU处理时间统一了,但是丢帧问题可能会再次放大,从直接丢一帧到帧继续下降。因为第二个16.6ms被浪费了,CPU必须等到第三个16.6ms才开始新一帧的数据处理,直接影响到后面所有帧的进度。我应该怎么办?是否可以在保留VSync信号的同时最大限度地利用CPU/GPU?这里有三个缓存:1.缓冲区backBuffer用于CPU/GPU图形处理。2.缓冲区TripleBuffer用于CPU/GPU图形处理。31.缓冲区frameBuffer是用来显示刚才说的情况的。原因是当第二个VSync信号到来时,由于backBuffer被GPU占用,CPU无法开始新一帧的计算。增加了第三个缓冲区,这样当第二个VSync信号到来时,CPU可以使用TripleBuffer开始计算新的一帧,而忽略backBuffer被GPU占用的情况。你可以理解为CPU、GPU、Display各有一个缓存区,这样三者可以同时做自己的事情,互不影响,最大限度的发挥各个模块的作用。上面提到的三个buffer和Vsync同步信号都是在Android4.1发布的ProjectButter(黄油计划)中提出的,目的是让Android像黄油/奶油一样顺滑。最后贴一张三缓存机制下的刷新机制图:小结今天学习了下Android系统的刷新机制。虽然没有代码,但是面试的时候经常会被问到。再总结一下:1、提供垂直同步信号VSync信号和双缓冲。每次VSync信号到来,画面切换,CPU/GPU开始为下一帧做准备。CPU/GPU每次准备好数据后,放入一个单独的buffer缓冲区backBuffer中。当屏幕就绪后,交换backBuffer数据和frameBuffer数据,屏幕只读取frameBuffer缓冲缓冲区中的数据,保证数据的完整连续性。.2、为了解决CPU/GPU在VSync信号下无法最大化的问题,引入了三个缓存。当VSync信号到来时,即使GPU还没有处理完上一帧数据,backBuffer也没有空闲,CPU也可以利用第三缓冲区正常开始处理下一帧数据,最大限度的利用CPU/GPU以保证垂直同步机制同时不浪费资源。3、丢帧的根本原因是CPU/GPU无法在一帧时间内(一般为16.6ms)准备好下一帧的数据。即使使用三重缓冲和垂直同步,帧丢失仍然会发生。作为App软件开发者,我们能做的就是尽可能优化布局,减少嵌套,减少CPU/GPU计算屏幕数据的时间。让下一帧的图像数据在每一帧时间内正常准备好。至于刷新机制在Android源码中是如何实现的?下一期带来Choreographer的解析。参考https://www.jianshu.com/p/0d00cb85fdf3https://www.zhihu.com/question/49764664/answer/469342536https://blog.csdn.net/yangwen123/article/details/16344375
