前言

手机屏幕由许多像素点组成,每个像素点通过显示不同的颜色最终显示各种图像。 由于手机系统类型和手机硬件的不同,用户界面的流动体验不一致。

屏幕上显示的颜色数据

GPU有一个名为Frame Buffer的缓冲区。 这个帧缓冲区可以看作是一个存储像素值的2位数组。

数组中的每个值都对应于需要在手机屏幕的像素点显示的颜色。

由于帧缓冲器中的数值不断变化,只要刷新完屏幕就可以显示不同的图像。

关于更新工作手记的逻辑电路,定期更新Frame Buffer的当前主流的刷新频率以60次/秒换算的话,将以16ms更新1次。

GPU的帧缓冲器数据

GPU除了将帧缓冲器传递给手机屏幕进行绘制外,还传递给另一个名为缓冲器Back Buffer的APP应用,让CPU填充数据。

GPU定期更换后台缓冲器和框架缓冲器。 也就是说,栅格化Back Buffer中的数据,将其传输到Frame Buffer,传递到屏幕进行显示绘制,同时将原始的Frame Buffer设置为Back Buffer,由程序处理。

安卓的16ms

安卓一般说用16ms绘制一次,到底是在那里控制着这个16ms呢?

Choreographer类提供了一种获取屏幕刷新率的方法。

公共金融类choreographer {

私有状态流量评估

displayinfodi=displaymanagerglobal.getinstance ().getDisplayInfo (

Display.DEFAULT_DISPLAY;

return di.refreshRate;

}

}

//*

* describesthecharacteristicsofaparticularlogicaldisplay。

* @hide

*/

publicfinalclassdisplayinfoimplementsparcelable {

//*

* therefreshrateofthisdisplayinframespersecond。

* p

* thevalueofthisfieldisindeterminateifthelogicaldisplayispresentedon

* more than one物理显示器。

* /p

*/

公共浮动刷新速率;

}

finalclassvirtualdisplayadapterextendsdisplayadapter {

privatefinalclassvirtualdisplaydeviceextendsdisplaydeviceimplementsdeathrecipient {

@Override

publicdisplaydeviceinfogetdisplaydeviceinfolocked (

if(minfo==null ) {

mInfo=new DisplayDeviceInfo (;

mInfo.name=mName;

mInfo.uniqueId=getUniqueId (;

mInfo.width=mWidth;

mInfo.height=mHeight;

mInfo.refreshRate=60;

/***部分代码省略**/

}

返回微信息;

}

}

}

每秒60帧,计算约16.7ms毫秒1帧。

屏幕绘制

作为严重影响安卓声誉的问题之一的用户界面不畅问题,首先在安卓4.1版中得到了有效处理。 其解决方法是本文介绍的项目浏览器。

Project Butter重新构建了Android Display系统,并引入了三个核心元素: VSYNC、Triple Buffer和Choreographer。 其中,VSYNC是理解项目

Buffer的核心。VSYNC是Vertical Synchronization(垂直同步)的缩写,是一种在PC上已经很早就广泛使用的技术。 可简单的把它认为是一种定时中断。

接下来,将围绕VSYNC来介绍Android Display系统的工作方式。请注意,后续讨论将以Display为基准,将其划分成16ms长度的时间段, 在每一时间段中,Display显示一帧数据(相当于每秒60帧)。时间段从1开始编号。

没有VSYNC的情况:

由上图可知

1.时间从0开始,进入第一个16ms:Display显示第0帧,CPU处理完第一帧后,GPU紧接其后处理继续第一帧。三者互不干扰,一切正常。 2.时间进入第二个16ms:因为早在上一个16ms时间内,第1帧已经由CPU,GPU处理完毕。故Display可以直接显示第1帧。显示没有问题。但在本16ms期间,CPU和GPU 却并未及时去绘制第2帧数据(注意前面的空白区),而是在本周期快结束时,CPU/GPU才去处理第2帧数据。 3.时间进入第3个16ms,此时Display应该显示第2帧数据,但由于CPU和GPU还没有处理完第2帧数据,故Display只能继续显示第一帧的数据,结果使得第1 帧多画了一次(对应时间段上标注了一个Jank)。 4.通过上述分析可知,此处发生Jank的关键问题在于,为何第1个16ms段内,CPU/GPU没有及时处理第2帧数据?原因很简单,CPU可能是在忙别的事情(比如某个应用通过sleep 固定时间来实现动画的逐帧显示),不知道该到处理UI绘制的时间了。可CPU一旦想起来要去处理第2帧数据,时间又错过了!

NSYNC的出现
为解决这个问题,Project Buffer引入了VSYNC,这类似于时钟中断。结果如图所示:

由图可知,每收到VSYNC中断,CPU就开始处理各帧数据。整个过程非常完美。 不过,仔细琢磨图2却会发现一个新问题:图2中,CPU和GPU处理数据的速度似乎都能在16ms内完成,而且还有时间空余,也就是说,CPU/GPU的FPS(帧率,Frames Per Second)要高于Display的FPS。确实如此。由于CPU/GPU只在收到VSYNC时才开始数据处理,故它们的FPS被拉低到与Display的FPS相同。但这种处理并没有什么问题,因为Android设备的Display FPS一般是60,其对应的显示效果非常平滑。 如果CPU/GPU的FPS小于Display的FPS,会是什么情况呢?请看下图:

由图可知: 1.在第二个16ms时间段,Display本应显示B帧,但却因为GPU还在处理B帧,导致A帧被重复显示。 2.同理,在第二个16ms时间段内,CPU无所事事,因为A Buffer被Display在使用。B Buffer被GPU在使用。注意,一旦过了VSYNC时间点, CPU就不能被触发以处理绘制工作了。

三级缓存
为什么CPU不能在第二个16ms处开始绘制工作呢?原因就是只有两个Buffer。如果有第三个Buffer的存在,CPU就能直接使用它, 而不至于空闲。出于这一思路就引出了Triple Buffer。结果如图所示:

由图可知: 第二个16ms时间段,CPU使用C Buffer绘图。虽然还是会多显示A帧一次,但后续显示就比较顺畅了。 是不是Buffer越多越好呢?回答是否定的。由图4可知,在第二个时间段内,CPU绘制的第C帧数据要到第四个16ms才能显示, 这比双Buffer情况多了16ms延迟。所以,Buffer最好还是两个,三个足矣。

以上对VSYNC进行了理论分析,其实也引出了Project Buffer的三个关键点: 核心关键:需要VSYNC定时中断。 Triple Buffer:当双Buffer不够使用时,该系统可分配第三块Buffer。 另外,还有一个非常隐秘的关键点:即将绘制工作都统一到VSYNC时间点上。这就是Choreographer的作用。在它的统一指挥下,应用的绘制工作都将变得井井有条。
 

二分快三计划ms,此时Display应该显示第2帧数据,但由于CPU和GPU还没有处理完第2帧数据,故Display只能继续显示第一帧的数据,结果使得第1 帧多画了一次(对应时间段上标注了一个Jank)。 4.通过上述分析可知,此处发生Jank的关键问题在于,为何第1个16ms段内,CPU/GPU没有及时处理第2帧数据?原因很简单,CPU可能是在忙别的事情(比如某个应用通过sleep 固定时间来实现动画的逐帧显示),不知道该到处理UI绘制的时间了。可CPU一旦想起来要去处理第2帧数据,时间又错过了!

NSYNC的出现
为解决这个问题,Project Buffer引入了VSYNC,这类似于时钟中断。结果如图所示:

由图可知,每收到VSYNC中断,CPU就开始处理各帧数据。整个过程非常完美。 不过,仔细琢磨图2却会发现一个新问题:图2中,CPU和GPU处理数据的速度似乎都能在16ms内完成,而且还有时间空余,也就是说,CPU/GPU的FPS(帧率,Frames Per Second)要高于Display的FPS。确实如此。由于CPU/GPU只在收到VSYNC时才开始数据处理,故它们的FPS被拉低到与Display的FPS相同。但这种处理并没有什么问题,因为Android设备的Display FPS一般是60,其对应的显示效果非常平滑。 如果CPU/GPU的FPS小于Display的FPS,会是什么情况呢?请看下图:

由图可知: 1.在第二个16ms时间段,Display本应显示B帧,但却因为GPU还在处理B帧,导致A帧被重复显示。 2.同理,在第二个16ms时间段内,CPU无所事事,因为A Buffer被Display在使用。B Buffer被GPU在使用。注意,一旦过了VSYNC时间点, CPU就不能被触发以处理绘制工作了。

三级缓存
为什么CPU不能在第二个16ms处开始绘制工作呢?原因就是只有两个Buffer。如果有第三个Buffer的存在,CPU就能直接使用它, 而不至于空闲。出于这一思路就引出了Triple Buffer。结果如图所示:

由图可知: 第二个16ms时间段,CPU使用C Buffer绘图。虽然还是会多显示A帧一次,但后续显示就比较顺畅了。 是不是Buffer越多越好呢?回答是否定的。由图4可知,在第二个时间段内,CPU绘制的第C帧数据要到第四个16ms才能显示, 这比双Buffer情况多了16ms延迟。所以,Buffer最好还是两个,三个足矣。

以上对VSYNC进行了理论分析,其实也引出了Project Buffer的三个关键点: 核心关键:需要VSYNC定时中断。 Triple Buffer:当双Buffer不够使用时,该系统可分配第三块Buffer。 另外,还有一个非常隐秘的关键点:即将绘制工作都统一到VSYNC时间点上。这就是Choreographer的作用。在它的统一指挥下,应用的绘制工作都将变得井井有条。