Android 渲染机制与图形栈深入理解(3):从 GPU 到屏幕:缓冲区、合成与 SurfaceFlinger
本文是「Android 渲染机制与图形栈深入理解」系列的第 3 篇,共 4 篇。在上一篇中,我们探讨了「View 树遍历:performTraversals() 的三大乐章」的相关内容。
五、从 GPU 到屏幕:缓冲区、合成与 SurfaceFlinger
GPU 渲染完成后,像素数据需要经过一系列处理才能最终显示在屏幕上。
1. 图形缓冲区(Graphic Buffer)
GPU 的渲染结果被写入一块内存缓冲区中。这块内存通常通过 Gralloc HAL(Graphics Allocator HAL)进行分配和管理,以确保最高效的内存访问(例如,可能直接在 GPU 内存中)。
2. BufferQueue:缓冲区管道
- 机制: 一个用于在图形数据生产者和消费者之间传递图形缓冲区的同步队列机制。它通常包含多个缓冲区槽位(如 3 个,实现三缓冲)。
- 生产者(Producer): 通常是应用程序(由 RenderThread/HWUI 代表)。它向 BufferQueue 请求一个空闲缓冲区(
dequeueBuffer),将渲染内容写入其中,然后将填充好的缓冲区排入队列(queueBuffer)。 - 消费者(Consumer): 通常是 SurfaceFlinger。它从 BufferQueue 中获取已填充的缓冲区(
acquireBuffer)进行处理(合成),处理完毕后释放回队列(releaseBuffer),让生产者可以再次使用。
3. Surface:应用窗口的画布代理
每个应用窗口在 WMS 中注册时,WMS 会为其创建一个 SurfaceControl,这个 SurfaceControl 内部包含了一个 Surface 对象(代表 BufferQueue 的生产者端)。这个 Surface 对象通过 Binder 传递给应用程序进程。应用程序(通过 RenderThread/HWUI)最终将渲染结果画到与这个 Surface 关联的 BufferQueue 中的缓冲区里。
4. SurfaceFlinger:系统级图形合成器
- 角色: 运行在一个独立的高优先级进程(surfaceflinger)中的系统服务。它是 Android 图形栈的「最终汇聚点」。
- 职责:
- 收集图层: 从所有当前可见的窗口(每个窗口对应一个 BufferQueue/Surface)以及系统 UI 元素(状态栏、导航栏等,它们也有自己的 Surface)获取它们最新渲染完成的图形缓冲区(称为「图层」)。
- 图形合成(Composition): 计算这些图层如何组合在一起形成最终的屏幕画面。这包括处理它们的位置、Z 轴顺序(谁在上面)、透明度、旋转、裁剪以及可能的特效。
- 硬件合成优先(HWC): SurfaceFlinger 会优先尝试使用 Hardware Composer(HWC)HAL。HWC 是显示硬件驱动提供的一个接口,允许 SurfaceFlinger 告诉硬件直接读取多个图层缓冲区并进行合成,无需 GPU 再次介入。这非常高效,尤其对于全屏视频播放等场景。
- GPU 合成回退: 如果图层过于复杂(数量太多、有不支持的变换或特效),或者 HWC 不支持,SurfaceFlinger 会回退到使用 GPU(通过 OpenGL ES)进行合成,这会增加 GPU 的负载。
- 提交屏幕: 将最终合成好的帧缓冲区提交给显示硬件进行显示。
- VSYNC 同步: SurfaceFlinger 的合成工作也严格按照 VSYNC 信号进行。在每个 VSYNC 周期,它会检查所有可见的 BufferQueue 是否有新的缓冲区准备好(
latchBuffer),然后进行合成并提交。
5. 多缓冲机制(Double/Triple Buffering)
- 目的: 为了避免渲染流水线的停顿(Stall),即防止生产者(App)等待消费者(SurfaceFlinger),或者反之。
- 双缓冲: App 渲染 Buffer A,提交给 SF。同时 App 开始渲染 Buffer B。SF 合成并显示 A。下一帧,SF 合成并显示 B,App 渲染 A。如果某一方处理过快,可能需要等待另一方。
- 三缓冲(更常见): App 渲染 A,提交。App 渲染 B,提交。App 渲染 C。SF 合成 A。下一帧,SF 合成 B,App 可以继续渲染 A(如果 A 已被 SF 释放)。这提供了更大的缓冲空间,进一步减少了等待的可能性,提高了吞吐量,但代价是增加了一帧的延迟。
(图示:BufferQueue 与 SurfaceFlinger 合成流程)
+-------------------------------------+ +-------------------------------------+
| App Process | | SurfaceFlinger Process |
|-------------------------------------| |-------------------------------------|
| RenderThread (Producer) | | SurfaceFlinger (Consumer) |
| 1. dequeueBuffer() from BufferQueue| | |
| 2. Render frame into Buffer N | | |
| 3. queueBuffer(N) to BufferQueue | ----> | |
| | | |
| | | 4. on VSYNC: |
| +-------------+ | | - latchBuffer(N) from BufferQueue|
| | BufferQueue | <---------------- | - Collect layers from all apps |
| | [B0][B1][B2]| | | |
| +-------------+ | | 5. Composition: |
| ^ | | | - Try HWC HAL (Hardware) |
| | | releaseBuffer | | - Fallback to GPU (OpenGL ES) |
| `---------------------` | |
| | | 6. Submit Frame Buffer to Display HAL|
+-------------------------------------+ +----------------------+--------------+
|
V
+-----------------+
| Display Panel |
+-----------------+
下一篇我们将探讨「特殊视图辨析:SurfaceView vs TextureView vs SurfaceControlViewHost」,敬请关注本系列。
「Android 渲染机制与图形栈深入理解」系列目录
- 引言:打造流畅体验的基石
- View 树遍历:performTraversals() 的三大乐章
- 从 GPU 到屏幕:缓冲区、合成与 SurfaceFlinger(本文)
- 特殊视图辨析:SurfaceView vs TextureView vs SurfaceControlViewHost