本文讲解 VSync 产生的原因及其作用。内容涉及如下方面:
即 Frame Rate,单位 fps,是指 gpu 生成帧的速率,如 33 fps,60fps,越高越好。
即 Refresh Rate 或 Scanning Frequency,单位赫兹/Hz,是指设备刷新屏幕的频率,该值对于特定的设备来说是个常量,如 60hz。
如下图,屏幕的刷新过程是每一行从左到右(行刷新,水平刷新,Horizontal Scanning),从上到下(屏幕刷新,垂直刷新,Vertical Scanning)。当整个屏幕刷新完毕,即一个垂直刷新周期完成,会有短暂的空白期,此时发出 VSync 信号。所以,VSync 中的 V 指的是垂直刷新中的垂直/Vertical。
对于一个特定的设备,帧率和刷新频率没有必然的大小关系。
安卓系统中有 2 种 VSync 信号:屏幕产生的硬件 VSync 和由 SurfaceFlinger 将其转成的软件 Vsync 信号。后者经由 Binder 传递给 Choreographer。
硬件 VSync 是一个脉冲信号,起到开关或触发某种操作的作用。
更多信息请自行复习《计算机组成原理》或《数字电路与逻辑设计》等大学教材(就像考研备考的时候研友感慨的:出来混,迟早要还的,当时没学好,现在还得接着学)。
在第一章我们讲到,帧率和刷新频率没有必然的大小关系。先记住这一点。
首先,我们来看下,没有引入 VSync 时,屏幕显示图像的工作流程。
注意,此处的“双缓冲”和计算机组成原理中的“二级缓存”是两回事。三重缓存也是如此。
为了解决单缓存的“tearing”问题,双重缓存和 VSync 应运而生。双重缓存模型如下图:
双缓冲的模型下,工作流程这样的:
在某个时间点,一个屏幕刷新周期完成,进入短暂的刷新空白期。此时,VSync 信号产生,先完成复制操作,然后通知 CPU/GPU 绘制下一帧图像。复制操作完成后屏幕开始下一个刷新周期,即将刚复制到 Frame Buffer 的数据显示到屏幕上。
在这种模型下,只有当 VSync 信号产生时,CPU/GPU 才会开始绘制。这样,当帧率大于刷新频率时,帧率就会被迫跟刷新频率保持同步,从而避免“tearing”现象。
注意,当 VSync 信号发出时,如果 GPU/CPU 正在生产帧数据,此时不会发生复制操作。屏幕进入下一个刷新周期时,从 Frame Buffer 中取出的是“老”数据,而非正在产生的帧数据,即两个刷新周期显示的是同一帧数据。这是我们称发生了“掉帧”(Dropped Frame,Skipped Frame,Jank)现象。
双重缓存的缺陷在于:当 CPU/GPU 绘制一帧的时间超过 16 ms 时,会产生 Jank。更要命的是,产生 Jank 的那一帧的显示期间,GPU/CPU 都是在闲置的。
如下图,A、B 和 C 都是 Buffer。蓝色代表 CPU 生成 Display List,绿色代表 GPU 执行 Display List 中的命令从而生成帧,黄色代表生成帧完成。
如果有第三个 Buffer 能让 CPU/GPU 在这个时候继续工作,那就完全可以避免第二个 Jank 的发生了!
于是就有了三缓存:
需要注意的是,第三个缓存并不是总是存在的,只要当需要的时候才会创建。之所以这样,是因为三缓存会显著增加用户输入到显示的延迟时间。如上图,帧 C 是在第 2 个刷新周期产生的,但却是在第 4 个周期显示的。最坏的情况下,你会同时遇到输入延迟和卡顿现象。
写博客的初衷不是分享,而是帮助自己总结整理、深化记忆。
也许本文不值一看,但是下面这些文章则不然: