android屏幕刷新和缓存机制
1 基本概念
-
帧率frame rate:单位fps,指gpu生成帧的速率,可以理解为每秒钟gpu渲染图像的次数
gpu会获取图形数据并进行渲染,然后硬件将渲染后的内容呈现在屏幕上
-
屏幕刷新频率:单位hz,指的是设备刷新屏幕的频率,一般来说对于一个特定的设备这个数值是一个常量,比如说80hz 60hz,越高越好,但随着技术的发展,现在许多设备可以根据需要自动改变屏幕刷新率
注意:一般来说 帧率和刷新率是不一致的。但如果出现不一致会引起画面撕裂的现象,此时就需要vsync机制。从android4.1开始,谷歌致力于解决android一直以来的画面不过流畅的问题,因此引入了一个project butter。黄油计划包括三个部分:vsync、triple buffer、choreographer
2 屏幕刷新机制大致流程:
image
首先应用程序向系统服务申请一块缓存,系统服务返回buff,应用程序接收到之后开始进行绘制工作,等到绘制结束后再提交给系统服务。系统服务将这个buff写到屏幕的一个缓存区中。屏幕会以一定的刷新率刷新。
屏幕的图像缓存一般不止一个,如果只有一个缓存,屏幕在读图片缓存的时候系统服务在写缓存,此时就会出现冲突,可能会出现一半显示第一帧的图像,一半显示第二帧的图像的情况。为了避免这种事情发生,一般有多个缓存,屏幕读缓存a,系统写缓存b,当屏幕要显示下一帧的时候,换一下就好了。
3 Vsync(垂直同步信号量)机制
Android系统每隔16ms发出VSYNC信号(1000ms/60=16.66ms),触发对UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps。
屏幕的刷新过程:每一行从左到右成为行刷新,再从上到下刷新,类似于“z”字型。当整个屏幕刷新完成,即一个垂直刷新周期完成,会有短暂的空白时间,此时会发出一个vsync信号
3.1 然而vsync是什么呢?
VSync是Vertical Synchronization(垂直同步)的缩写,是一种在PC上很早就广泛使用的技术,可以简单的把它认为是一种定时中断。而在Android 4.1(JB)中已经开始引入VSync机制,用来同步渲染,让AppUI和SurfaceFlinger可以按硬件产生的VSync节奏进行工作。
- 安卓系统中有两种vsync信号:屏幕产生的硬件 VSync 和由 SurfaceFlinger 将其转成的软件 Vsync 信号。后者经由 Binder 传递给 Choreographer 。
3.1.2 垂直同步有什么用呢?
当帧率和刷新率出现偏差的时候,如果帧率大于刷新率,那么会出现产生帧的速度快展示帧的速度慢的问题,会出现漏帧的问题。这种情况下采用垂直同步,那么显卡会在收到vsync信号时开始渲染,在下一个信号之前完成渲染工作,此时不会继续处理下一帧的渲染,而是等到下一个信号到来才开始渲染下一帧。
3.2 当没有使用VSYNC时
image
在第一个时间间隔的时候,cpu正常执行帧1,gpu渲染帧1,屏幕正常展示帧1;第二个时间间隔的时候,cpu由于被占用,推迟执行了帧2,导致了只能展示上一帧,即帧2。这时就需要vsync信号
注:jank指的是一种卡顿的表现,android团队将滞缓、不流畅的动画定义为jank(延误机),如果渲染的内容在16ms内不能完成就会出现jank。
3.3 当使用vsync信号
image
在第一个时间间隔的时候,cpu正常执行帧1,gpu渲染帧1,屏幕正常展示帧1;第二个时间间隔的时候,vsync立即通知cpu,cpu执行帧2,gpu渲染帧2,屏幕展示帧2。使用vsync机制后有效的减少了丢帧,卡顿的问题。
但这种情况是在cpu/gpu帧率大于刷新率的情况下
3.4 如果cpu/gpu的帧率小于刷新率
image
在第二个时间间隔的时候,屏幕本应该展示b帧,但由于gpu还在处理帧b,导致帧a被重复展示。并且在第二个时间间隔里,cpu没有工作,因为buffer中存有帧a。此时就引入了triple buffer
4 Triple Buffer
一般来说在绘制ui的时候会用到双重缓存技术。ui在back buffer上进行绘制,然后再和font buffer交换,渲染到屏幕上。
在android4.1之前,在上图的第二个时间间隔里,cpu处于空闲状态,因为back buffer被gpu占用,font buffer屏幕在使用。因此cpu只有等到gpu使用之后,并且屏幕给cpu发出vsync信号之后才能写入。因此如果有3个buffer,那么cpu就不至于空闲。
image
图中,第二个时间间隔开始的时候,屏幕给cpu发信号,但此时buffer b被使用了,因此cpu使用buffer c写入数据。虽然屏幕会重复执行两次帧a,但后续的展示是连贯的。
buffer并不是越多越好,从图中可以看出来cpu使用buffer c写入的帧c要等到第四个时间间隔才能展示,因此会比双重缓冲的时候延迟16ms。并且大量的缓存会导致内存增加等问题,因此并不是越多越好,3个正好。