目录
- 一、Android 图形显示系统
- 1. 从下层往上层理解
一、Android 图形显示系统
1. 从下层往上层理解
1.1 显示屏
显示屏上的内容,是从硬件帧缓冲区的,大致读取过程为:从Buffer的起始地址开始,从上往下,从左往右(一行一行读取)扫描整个Buffer,将内容映射到显示屏上。扫描一行显示一行
如果同时读写会引起屏幕的撕裂,该如何解决?
答:方式一:加锁
,在写入的时候对其进行加锁,写完之后才对锁的释放,读取的时候也是一样,只要读取完毕之后才能进行写入。但是该方式的缺点就是加锁会造成性能的浪费
方式二:增加缓冲区
,用来显示内容到屏幕的帧缓冲区叫前缓冲区,增加一个后缓冲区
,用于后台合成下一帧图形的帧缓冲区,这样可以同时的进行写和读,而且不是对同一块资源进行增强。这样既能够解决掉同时增强资源引起的屏幕撕裂问题,也能避免对资源的浪费。
其中,前缓冲区和后缓冲区可以进行交换(地址进行更换就好),前缓冲区变成后缓冲区,后缓冲区变成前缓冲区。
增加双缓冲区的好处:
① 避免资源的争抢
② 避免性能的浪费
然而,上面假设“当前一帧显示完毕,后一帧准备好了”的情况,在现实中这两个事件并非同时完成,那么屏幕扫描缓冲区的速度和系统合成帧的速度之间有什么关系呢?
屏幕刷新率(HZ)
:代表屏幕在一秒内刷新屏幕的次数,Android手机一般为60HZ(也就是1秒刷新60帧,大约16.67毫秒刷新1帧)
系统帧速率(FPS)
:代表了系统在一秒内合成的帧数,该值的大小由系统算法和硬件决定。
我们用以下两个假设来分析两者的关系:
①屏幕刷新速率比系统帧速率快
此时,在前缓冲区内容全部映射到屏幕之后,后缓冲区尚未准备好下一帧,屏幕将无法读取下一帧,所以只能继续显示当前一帧的图形,造成一帧显示多次,也就是卡顿。
②系统帧速率比屏幕刷新速率快
此时,屏幕未完全把前缓冲区的一帧映射到屏幕,而系统已经在后缓冲区准备好了下一帧,并要求读取下一帧到屏幕,将会导致屏幕上半部分是上一帧的图形,而下半部分是下一帧的图形,造成屏幕上显示多帧,也就是屏幕撕裂。
上面两中情况,都会导致问题,根本原因就是两个缓冲区的操作速率不一致,解决办法就是让屏幕控制前后缓冲区的切换,让系统帧速率配合屏幕刷新率的节奏。
Drawing with VSYNC
Time:从左到右流动变化
CPU:生成图片
GPU:合成图片
Display:显示图片,那一行上的数字表示第几帧,比如0表示第0帧,在第0帧上CPU、GPU在生成合成第一帧的内容。合成完成VSync信号来了就显示第一帧的内容。
但这种模式有一定的缺点:
Display上的数字是逐步增长的,这些数据都是要放在一个个缓存buffer上,这样开辟的控件就越多,旧的没有进行回收复用,这样就浪费性能
Parallel Processing and Double Buffering
好处
:在整个过程中只有A、B两个Buffer,不会再去开辟新的空间,对以前空间进行了很好的利用,减少CPU计算性能的浪费,减少了内存的开辟。
Jank:表示一帧显示了多次,造成了卡顿
,
造成卡顿原因
:从上图可以看出,GPU在合同B或者A的时候超出了一帧的时间,一帧内没有合成完,只能复用上一帧的内容,具体原因可能是主线程里面做了耗时工作
从上图可以看出,CPU和GPU流程过程中其实是很多空闲时间给浪费掉了,从而延申出三缓冲的思想。
谷歌文档中,给出了这样的解释:假如缓冲区B的处理需要较长时间,并且A正在使用中显示当前帧。此时引入第三个缓冲区,则CPU与GPU不会空等,而是系统创建C缓冲区,可以避免下一次jank,从而让系统变得流畅,通俗来讲就是减少红绿灯的等待。
Parallel Processing and Triple Buffering
三缓存与双缓存的区别就是利用卡顿的时间即在CPU或者GPU空闲的时候进行第三个缓存的生成与合成操作,减少后续卡顿事件
一个window对应一个surface(一个window对应一个图层),一个surface对应三个buffer
如果说SurfaceFlinger是图形的合成者,那么图形的提供者就是上层。图形的传递是通过Buffer作为载体,Surface是对Buffer的进一步封装,也就是说Surface内部具有多个Buffer供上层使用,如何管理这些Buffer呢?请看下面这个模型:
surface内部提供了一个BufferQueue,与上层和SurfaceFlinger形成一个生产者消费者模型,上层对应Producer,SurfaceFlinger对应Consumer。三者通过Buffer产生联系,每个Buffer都有四种状态:
- Free:可被上层使用
- Dequeued:出列,正在被上层使用
- Queued:入列,已完成上层绘制,等待SurfaceFlinger合成
- Acquired:被获取,SurfaceFlinger正持有该Buffer进行合成
不能直接对BufferQueue进行操作,从而出于安全考虑弄了一个生产者和消费者。