提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
一、显示一帧流程概览
Android 显示一帧大致分为下面 八步:
1、App 接收到 vsync-app 信号后开始工作。
2、App 主线程被Message唤醒,执行onVsync。
3、App 执行 doFrame ,处理input、animation、traversal、draw等。
4、App UIThread 跟RenderThread sync 数据。
5、App 执行DrawFrame,从SurfaceFlinger(后续简称SF) 的 BufferQueue 中 Dequeue buffer,取出一个bufffer后,执行渲染绘制,接着将绘制好的Buffer 通过queuebuffer 放回到。BufferQueue中给 SF消费。
6、App queuebuffer 后, SF 中对应的 app buffer 会增加 +1。
7、Vsync-sf 到来后,SF 从BufferQueue 中 acquireBuffer一个Buffer 进行消费, 对应SF 中的 app buffer 会减 - 1 , SF 消费处理后,通过 releaseBuffer 将buffer 归还到BufferQueue 中。
8、SF 通过 bind 跟 Hardware Composer HAL(简称HWC) 进行通信,通过一些处理后显示到手机屏幕上。
二、生产者,消费者 BufferQueue 流转图
1、dequeue(生产者发起) :
当生产者需要缓冲区时,它会通过调用 dequeueBuffer() 从 BufferQueue 请求一个可用的缓冲区,并指定缓冲区的宽度、高度、像素格式和使用标记。
2、queue(生产者发起):
生产者填充缓冲区并通过调用 queueBuffer() 将缓冲区返回到队列。
3、acquire(消费者发起) :
消费者通过 acquireBuffer() 获取该缓冲区并使用该缓冲区的内容
4、release(消费者发起) :
当消费者操作完成后,它会通过调用 releaseBuffer() 将该缓冲区返回到队列
BufferQueue 很好理解,就是 Buffer 的 Queue。生产者使用 dequeueBuffer 取出可用的 Buffer,往里面填充图像数据(不论是用 CPU 还是 GPU 生产),然后 queueBuffer 把图像数据放回到 BufferQueue 里;消费者使用 requireBuffer 取出可用于屏幕显示的图像数据,然后用于显示,然后再把 Buffer release 回 BufferQueue。
因此整个渲染流程的核心就是 BufferQueue,要理解好渲染流程,就要了解好谁是生产者(Producer),谁是消费者(Consumer),以及 BufferQueue 是怎么运作的。
- 生产者之一就是你的 App。不论你是使用 Android UI Framework 本身的软硬件绘制,还是使用播放器解码视频文件,还是从摄像头取出摄像数据,你的 App 都是图像数据的生产者。
- 消费者是 SurfaceFlinger 和 HWC(Hardware Composer),对各生产者生产出来 Buffer 进行合成,然后显示到屏幕。
- Surface 对象则是上述 Buffer 的抽象。所以你是用不着 dequeueBuffer 这样的操作的,很多 API 都有 setSurface 的方法。
- 这里生产者和消费者都不是绝对的,看你在怎样参考系来看:即使在上述流程的生产侧,Camera 是一个生产者,对 Camera 产生的图像数据进行进一步加工(比如使用 OpenGL ES 处理)的流程,可以认为是一个消费者。
三、App ,SF Buffer 交互图
- App 通过bind 向SF dequeuebuffer 进行buffer申请
- SF 对端完成对bufferQueue 的dequeuebuffer的申请
- App 处理合成完后,通过binder向SF queuebuffer 申请buffer 入队。
- SF 对端通过queuebuffer 完成buffer 对BufferQueue的入队申请,供SF消费并显示到屏幕上
四、Choreographer 和 Vsync
Choreographer 和 Vsync 共同解决生产者何时生产,消费者何时消费的问题。
Choreographer 协调生产者什么时候去生产——也就是什么时候去绘制一帧。既然要协调,那么肯定是需要有一个协调的依据,这个依据就是 Vsync 信号——也就是垂直同步信号。
Vsync 信号一般是由硬件产生的,每个 Vsync 信号之间的时间,就是每一帧生产 / 消费的间隙。Vsync 有两种,Vsync-app 和 Vsync-sf,前者用于告诉 Choreographer,是时候协调 app 生产了;后者用于告诉 SurfaceFlinger,是时候来消费合成并显示到屏幕了。
从上图可以看到,Vsync-app 和 Vsync-sf 是几乎同时发生的(但因为有 Vsync Offset 的存在,每个手机可能都不一样)——注意,这里使用数字信号的变化来表示 Vsync 的发生,这意味着,从 1 ~ 0 或者从 0 ~ 1 都是发生了 Vsync 信号的意思。
接下来看看 Vsync-app 和 Vsync-sf 发生的时候,Choreographer 是怎么协调工作的。
这里先思考一下,为什么你的 app 需要重绘?既然需要重绘,那么就需要 app 的内容发生变化,这里的内容变化可以由多种情况下发生:
- 用户通过物理按键或者触控的方式,产生了交互,app 需要响应交互做出相应的变化,比如改变按钮的文字,颜色,因为列表滚动了所以显示新的内容等;
- 在一个动画过程里,每隔一段时间触发一次内容的改变,比如改变背景颜色,View 的位置等;
- 播放视频等场景;
举因为用户触控导致重绘的场景做例子,在收到 Vsync-app 信号后,Choreographer 做了以下工作:
- 分派触控事件,此时可能检测到 Click 事件的发生,然后 scheduleTraversals
- 执行 Animation 的回调,比如改变 View 的属性等
- 进行 Traversals,视情况会完整或者不完整地走完我们熟悉的:Measure、Layout 和 Draw
五、SF 跟 HWC 交互图
1、vsync-sf 周期到来,SF 开始绘制准备工作
2、SF 通过 acquirebuffer 从BufferQueue 中取出一帧进行消费
3、App 对应的BufferQueue 在SF acquirebuffer 后对那个的值会 -1
4、App 对应的buffer 值为 2
5、App 对应的buffer值 在SF acquirebuffer 后变为 1
6、SF 跟HWC 通过binder 通信处理完后,通过rleasebuffer将buffer 归还到BufferQueue中,紧接着一帧就可以显示出来
SurfaceFlinger 作为上述过程里的消费者,负责跟 HardwareComposer 打交道,把各个 Layer 的数据进行合成,然后交由 HardwareComposer 来进行显示。
在一帧需要合成的时候,SurfaceFlinger 负责跟 HardwareComposer(HWC) 通讯,把各个 Layer 都输出到显示设备。但是不是所有 Layer 都能直接交给 HWC,对于能直接交给 HWC 合成的,HWC 会告诉 SurfaceFlinger 这个 Layer 类型是 OVERLAY;对于不能直接交给 HWC 合成的多个 Layer(比如 Buffer 里数据类型不支持),HWC 会让 SurfaceFlinger 通过 OpenGL ES 合成一个 Layer,然后再移交给 HWC。