安卓一帧图像的渲染过程

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


一、显示一帧流程概览

在这里插入图片描述

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 交互图

在这里插入图片描述

  1. App 通过bind 向SF dequeuebuffer 进行buffer申请
  2. SF 对端完成对bufferQueue 的dequeuebuffer的申请
  3. App 处理合成完后,通过binder向SF queuebuffer 申请buffer 入队。
  4. 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。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值