VSync 全称是Vertical Synchronization(垂直同步),在Android 4.1中引入Android 系统(同时引入的一个概念是Triple Buffering)。
学计算机的经常听到Buffer 的概念(生活中也碰到过很多,比如弹簧),起到的都是一个类似的作用。用来协调两个不同速度的东西工作
假设显示内容和绘制使用的是用一块内存,那可能会出现下面的问题。显示有截断的异常(图中的Tear Point #1和Tear Point #2)。为什么会这样呢?因为cpu/gpu 处理和屏幕展示的速度不一样但是却使用的是同一块内存。
怎么解决呢?可以将cpu/gpu 处理和屏幕展示分开,cpu/gpu 在后台处理,处理完一帧的数据以后才交给屏幕展示(这样可能导致另外的问题是,如果cpu/gpu 处理很慢,那么屏幕可能会一直展示某一帧的数据,下面主要分析这个问题的处理)。
绘制过程中的两个概念。
- 手机屏幕刷新率:手机硬件每秒刷新屏幕的次数,单位HZ。一般是一个固定值,例如60HZ。
- FPS:画面每秒传输帧数,通俗来讲就是指动画或视频的画面数。单位HZ。
手机屏幕刷新率是固定的,FPS 则是一直变化的,怎么才能保证能够运行流畅呢?从几个例子来看吧。
先解释图片代表的意思:最下面黑线代表的是时间,黄色代表屏幕展示,绿色代表GPU 处理,蓝色代表CPU 处理。Jank 代表的是重复展示上一帧的异常。下面会从屏幕展示的每一帧开始分析
没有引入VSync 机制
上图是没有引入VSync 机制的处理流程。
Display 展示第0帧数据,这时cpu/gpu 会去处理第1帧的数据。
Display 展示第1帧数据(此时屏幕显示是正常的),这时cpu/gpu 可能处理其他任务导致很晚才去处理绘制。
因为cpu/gpu 没处理好第2帧的数据,所以Display 还是展示第1帧数据(此时屏幕显示是异常的),cpu/gpu 处理完第2帧没有处理完的数据然后继续处理第3帧的数据。
…
上图中一个很明显的问题是,只要一次cpu/gpu 处理出现异常就可能导致后面的一系列的处理出现异常。
引入VSync 机制
VSync 可以简单的认为是一种定时中断,系统在每次需要绘制的时候都会发送VSync Pulse 信号,cpu/gpu 收到信号后马上处理绘制。
正常情况
在4.1以后引入VSync 机制。在FPS < 手机屏幕刷新率的情况下,一切运行完美。
Double Buffering 异常情况
VSync 机制下Double Buffering 时FPS > 手机屏幕刷新率的情况。
- Display 展示第A 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理B 帧的数据,但是由于计算太多,导致没有在一个VSync 间隔内处理完。
- 由于第B 帧数据没有处理好,Display 继续展示第A 帧数据(此时屏幕显示是异常的)。由于系统中只存在一块内存给cpu/gpu 处理绘制,所以在这个VSync 间隔内cpu 不处理任何事。
- Display 展示第B 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理即将展示A 帧的数据,由于计算太多,导致没有在一个VSync 间隔内处理完。
- 需要展示的A 帧数据没有处理好,Display 继续展示第B 帧数据(此时屏幕显示是异常的)。由于系统中只存在一块内存给cpu/gpu 处理绘制,所以在这个VSync 间隔内cpu 不处理任何事。
…
上图中一个很明显的问题是,只要出现一次Jank 就会影响下一次的VSync(cpu 不能工作)。
Triple Buffering 异常情况
Triple Buffering 的引入。
- Display 展示第A 帧数据,cpu/gpu 收到VSync Pulse 信号马上处理B 帧的数据,但是由于计算太多,导致没有在一个VSync 间隔内处理完。
由于第B 帧数据没有准备好,Display 继续展示第A 帧数据(此时屏幕显示是异常的)。此时虽然B 被gpu 在使用,但是cpu 可以处理Buffer C(因为有3个缓冲)。- Display 展示第B 帧数据,gpu 继续处理上一步骤的C,cpu 则处理A。
后续过程出错的情况被降低了…