一文说明白Android 渲染那些事

3 阅读6分钟

Android 渲染管线:Main Thread → RenderThread → SurfaceFlinger

一、整体架构概览

┌─────────────────── App 进程 ────────────────────┐    ┌──── 独立进程 ────┐
│                                                   │    │                  │
│   Main Thread          RenderThread               │    │  SurfaceFlinger  │
│   (UI 线程)            (渲染线程)                   │    │  (合成器进程)     │
│                                                   │    │                  │
│   ┃ measure  ┃         ┃ GPU 渲染    ┃            │    │  ┃ 合成所有     ┃│
│   ┃ layout   ┃  sync   ┃ 生成像素    ┃  
BufferQueue │  ┃ Surface层  ┃│
│   ┃ draw     ┃ ──────→ ┃ 填充 Buffer ┃ ────────→  │    │  ┃ 输出到屏幕  ┃│
│   ┃(记录命令)┃         ┃(执行命令)    ┃            │    │                  │
│                                                   │    │                  │
└───────────────────────────────────────────────────┘    └──────────────────┘
         ↑                      ↑                              ↑
      CPU 操作              GPU 操作                     Hardware Composer

二、三者的角色

┌─────────────────────────────────────────────────────────────────┐
│ Main Thread (UI Thread)                                         │
│ ─────────────────────                                           │
│ • 处理 Input 事件                                                │
│ • 执行动画计算                                                    │
│ • measure / layout / draw (View树遍历)                           │
│ • draw 阶段:不是真正画像素,而是记录 DisplayList (RenderNode)      │
│ • 产出:一棵 DisplayList 树(绘制命令记录)                         │
└─────────────────────────────────────────────────────────────────┘
                            │ sync (同步 DisplayList)
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ RenderThread                                                     │
│ ────────────                                                     │
│ • 接收 DisplayList                                               │
│ • 将 DisplayList 转化为 GPU 指令 (OpenGL ES / Vulkan)             │
│ • 调用 GPU 渲染像素到 GraphicBuffer                               │
│ • 通过 BufferQueue 将渲染好的 Buffer 提交给 SurfaceFlinger         │
│ • 产出:一块填满像素的 GraphicBuffer                               │
└─────────────────────────────────────────────────────────────────┘
                            │ BufferQueue (queueBuffer)
                            ↓
┌─────────────────────────────────────────────────────────────────┐
│ SurfaceFlinger                                                   │
│ ──────────────                                                   │
│ • 接收所有应用窗口的 GraphicBuffer                                 │
│ • 按 Z-order 合成多个 Layer(状态栏、导航栏、App窗口...)           │
│ • 通过 HWC (Hardware Composer) 或 GPU 合成                       │
│ • 将最终画面提交给显示屏                                           │
│ • 产出:屏幕上的最终画面                                           │
└─────────────────────────────────────────────────────────────────┘

三、Main Thread 与 RenderThread 的交互

3.1 交互机制

Main Thread                              RenderThread
    │                                         │
    │  ① VSYNC-app 信号到达                    │
    │  Choreographer.doFrame() 被触发          │
    │                                         │
    ├── input 处理                             │
    ├── animation 计算                         │
    ├── traversal                              │
    │   ├── measure (计算大小)                  │
    │   ├── layout  (计算位置)                  │
    │   └── draw    (记录绘制命令)              │
    │       │                                  │
    │       │  View.draw() 不直接画像素          │
    │       │  而是记录到 DisplayList 中:       │
    │       │  canvas.drawRect(...)             │
    │       │  canvas.drawText(...)             │
    │       │  canvas.drawBitmap(...)           │
    │       ↓                                  │
    │  ② 调用 ThreadedRenderer.draw()          │
    │       │                                  │
    │       │══ syncFrameState ══════════════→ │  ★ 同步点
    │       │   (DisplayList 从主线程            │
    │       │    拷贝/移交到 RenderThread)       │
    │       │                                  │
    │  ③ 主线程被释放                           ├── 接收 DisplayList
    │     可以处理下一帧或其他事务               ├── 转化为 GPU 指令
    │                                         ├── 调用 OpenGL/Vulkan
    │                                         ├── GPU 渲染像素
    │                                         ├── eglSwapBuffers
    │                                         │   (提交 Buffer)
    │                                         │
    │  下一个 VSYNC...                         │

3.2 关键同步点:syncFrameState

// ThreadedRenderer.java (简化)
void draw(View view, AttachInfo attachInfo, DrawCallbacks callbacks) {
    // 1. 更新 DisplayList
    updateRootDisplayList(view, callbacks);
    
    // 2. ★ 同步到 RenderThread(这是阻塞操作)
    //    主线程在这里等待 RenderThread 完成上一帧的 sync
    int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo);
    
    // 3. sync 完成后,主线程被释放
    //    RenderThread 开始独立工作
}

Perfetto 中的表现

Main Thread:
┃ doFrame ─────────────────────────────────────────────┃
┃ inputanimtraversal ──────────────┃ commit ─────┃
┃       ┃      ┃ measurelayoutdraw ──┃│            ┃
┃       ┃      ┃        ┃      ┃ record ┃│syncFrame.. ┃
                                          │  等待sync   │
                                          ↓             │
RenderThread:                                           │
  (上一帧收尾)┃ syncFrameStateissueCommandsswap ┃ │
              ↑                                         │
              └── 这个完成后主线程才能继续 ────────────────┘

3.3 DisplayList 的作用

Main Thread 的 draw 阶段生成 DisplayList(而非像素):

DisplayList 示例:
┌────────────────────────────────────┐
│ Save                               │
│ ClipRect(0, 0, 1080, 1920)        │
│ DrawColor(#FFFFFF)                 │  ← 背景
│ Save                               │
│   Translate(100, 200)              │
│   DrawRoundRect(0, 0, 300, 400)   │  ← 卡片背景
│   DrawText("Hello", 20, 50)       │  ← 文字
│   DrawBitmap(avatar, 200, 10)     │  ← 图片
│ Restore                            │
│ DrawLine(0, 600, 1080, 600)       │  ← 分割线
│ Restore                            │
└────────────────────────────────────┘

这些命令不会在主线程执行,
而是传递给 RenderThread,
由 RenderThread 翻译成 GPU 指令执行。

3.4 为什么要分两个线程?

Android 4.x(无 RenderThread):
Main Thread:  ┃ inputanimmeasurelayoutdraw+GPU渲染 ────────┃
              │←──────────────── 全部在主线程,容易超时 ─────────────────→│


Android 5.0+(有 RenderThread):
Main Thread:  ┃ inputanimmeasurelayoutdrawsync ┃  ← 提前释放!
                                                         │
RenderThread:                                            ┃ GPU渲染 ──────┃
                                                         │←── 与主线程并行 →│

好处:
  - 主线程更快释放,可以处理下一帧的 input
  - GPU 渲染与主线程的下一帧准备可以并行
  - 流水线效率更高

四、RenderThread 与 SurfaceFlinger 的交互

4.1 BufferQueue 机制(核心桥梁)

                    BufferQueue(生产者-消费者模型)
                    
RenderThread                                      SurfaceFlinger
(Producer 生产者)                                   (Consumer 消费者)
     │                                                  │
     │  ① dequeueBuffer()                               │
     │  ──────────────→  ┌──────────┐                   │
     │   获取空闲 Buffer  │ Buffer 0 │ ← FREE            │
     │  ←────────────── └──────────┘                   │
     │                    ┌──────────┐                   │
     │                    │ Buffer 1 │ ← ACQUIRED(SF在用) │
     │                    └──────────┘                   │
     │                    ┌──────────┐                   │
     │                    │ Buffer 2 │ ← QUEUED(等待消费)  │
     │                    └──────────┘                   │
     │                                                  │
     │  ② GPU 渲染到 Buffer 0                            │
     │  (OpenGL/Vulkan 绑定此 Buffer 为 render target)   │
     │                                                  │
     │  ③ queueBuffer()                                 │
     │  ──────────────→  ┌──────────┐                   │
     │   提交渲染完成的    │ Buffer 0 │ → QUEUED           │
     │   Buffer           └──────────┘                   │
     │                                                  │
     │                    ④ acquireBuffer()              │
     │                    ┌──────────┐  ←───────────── │
     │                    │ Buffer 0 │ → ACQUIRED        │
     │                    └──────────┘  SF 取走合成       │
     │                                                  │
     │                    ⑤ releaseBuffer()              │
     │                    ┌──────────┐  ←───────────── │
     │                    │ Buffer 0 │ → FREE            │
     │                    └──────────┘  合成完毕,归还     │

4.2 Buffer 状态流转

           dequeueBuffer()        queueBuffer()
    FREE ──────────────────→ DEQUEUED ──────────────→ QUEUED
     ↑                      (App 渲染中)              (等待SF消费)
     │                                                   │
     │    releaseBuffer()       acquireBuffer()          │
     └──────────────────── ACQUIRED ←───────────────────┘
                           (SF 合成中)

4.3 三重缓冲(Triple Buffering)

时间 

VSYNC:                                          
            
Buffer A:   ┃App渲染  等待SF   SF合成    FREE    App渲染 
Buffer B:    SF合成    FREE   ┃App渲染  等待SF   SF合成  
Buffer C:     FREE   ┃App渲染   FREE   ┃App渲染   FREE   

App:        ┃渲染到A ┃渲染到C ┃渲染到A ┃渲染到C ┃渲染到A 
SF:         ┃合成B    合成A   合成C   合成A   合成C  
Display:    ┃显示B    显示A   显示C   显示A   显示C  

三个 Buffer 轮转,确保 App  SF 永远不需要等待

4.4 eglSwapBuffers 的本质

// RenderThread 渲染完成后调用
eglSwapBuffers(display, surface);

// 内部实际做的事:
//   1. fence sync —— 等待 GPU 真正完成渲染
//   2. queueBuffer() —— 将 Buffer 提交到 BufferQueue
//   3. dequeueBuffer() —— 获取下一个可用 Buffer(为下帧准备)

Perfetto 中的表现

RenderThread:
┃ DrawFrame ──────────────────────────────────────────────────┃
┃ syncFrameState ┃ issueDrawCommands ────────┃ eglSwapBuffers ┃
┃   从主线程同步   ┃  发送 GPU 指令             ┃  提交Buffer    ┃
┃   DisplayList   ┃  (可能等待 GPU fence)      ┃  到 BufferQueue┃
                                                       │
                                                       ↓
                                              BufferQueue.queueBuffer()
                                                       │
                                                       ↓
                                              SurfaceFlinger 被唤醒

五、SurfaceFlinger 的工作

5.1 合成流程

VSYNC-sf 信号到达
       │
       ↓
┌─── SurfaceFlinger ──────────────────────────────────────┐
│                                                          │
│  ① 收集所有 Layer 的 Buffer                               │
│     ├── StatusBar Surface    → acquireBuffer()           │
│     ├── NavigationBar Surface → acquireBuffer()          │
│     ├── App Window Surface   → acquireBuffer()           │
│     ├── Wallpaper Surface    → acquireBuffer()           │
│     └── ...                                              │
│                                                          │
│  ② 计算可见区域、Z-order、透明度                            │
│                                                          │
│  ③ 选择合成方式                                            │
│     ├── HWC 合成(硬件合成器,省电高效)                     │
│     │   → 直接让 Display HAL 硬件叠加各 Layer              │
│     │                                                    │
│     └── GPU 合成(回退方案)                                │
│         → SurfaceFlinger 用 GPU 把各层画到 FrameBuffer    │
│                                                          │
│  ④ 提交到显示屏                                            │
│     → 调用 HWC presentDisplay()                          │
│     → 等待下一个 VSYNC 翻转 Buffer 显示                    │
│                                                          │
└──────────────────────────────────────────────────────────┘

5.2 多 Layer 合成示意

             Z-order 从上到下
        ┌─────────────────────────┐
        │     StatusBar Layer     │  ← Surface 1
        ├─────────────────────────┤
        │                         │
        │                         │
        │     App Window Layer    │  ← Surface 2 (你的应用)
        │                         │
        │                         │
        ├─────────────────────────┤
        │   NavigationBar Layer   │  ← Surface 3
        └─────────────────────────┘
                   ↓ 
          HWC / GPU 合成
                   ↓
        ┌─────────────────────────┐
        │                         │
        │     最终合成画面          │  → 送往 Display
        │                         │
        └─────────────────────────┘

六、完整的一帧渲染时序

时间 

VSYNC-app:                                  
VSYNC-sf:                                         

Main Thread:
┃① Choreographer.doFrame() ─────────────────┃
  input  animation  traversal ───────────┃
                    measure ┃layout┃draw 
                                   rec 
                                   ord 
                                   DL  
                                       
                                ②sync 
                                       
RenderThread:
                               ┃③ DrawFrame ───────────────────┃
                                syncState┃ draw commands ┃swap┃
                                          (GPU 工作)        
                                                           
                                                            
                                                   queueBuffer()
                                                            
                                                            
BufferQueue:                                      QUEUED ───────┃
                                                            
                                                    acquireBuffer()
                                                            
                                                            
SurfaceFlinger:
                                                 ┃⑤ onVsync-sf ────────┃
                                                  latchBuffer          
                                                  calculateLayers      
                                                  composite ──────────┃
                                                  (HWC or GPU)        
                                                  presentDisplay ─────┃
                                                                    
                                                                    
Display:                                                      屏幕显示

各阶段说明

┌────┬─────────────────────┬───────────────────────────────────────┐
│阶段│ 发生位置              │ 做什么                                 │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ①  │ Main Thread          │ 处理输入、动画、measure/layout/draw    │
│    │                      │ draw 只是记录 DisplayList 命令         │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ②  │ Main → Render        │ syncFrameState: 同步 DisplayList      │
│    │                      │ 主线程阻塞等待 RenderThread 就绪        │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ③  │ RenderThread         │ 将 DisplayList 转为 GL/Vulkan 命令    │
│    │                      │ 提交给 GPU 执行                        │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ④  │ Render → BufferQueue │ eglSwapBuffers → queueBuffer          │
│    │                      │ 将渲染好的 Buffer 放入队列              │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ⑤  │ SurfaceFlinger       │ VSYNC-sf 触发,取出 Buffer             │
│    │                      │ 合成所有 Layer,提交到 HWC              │
├────┼─────────────────────┼───────────────────────────────────────┤
│ ⑥  │ Display              │ HWC 在下一个 VSYNC 翻转显示新帧        │
└────┴─────────────────────┴───────────────────────────────────────┘

七、通信机制总结

Main Thread ↔ RenderThread

通信方式:进程内线程间通信

┌───────────────────────────────────────────────────────┐
│ 共享数据:DisplayList / RenderNode 树                   │
│                                                       │
│ 同步机制:                                              │
│   • DrawFrameTask(RenderThread 的任务队列)            │
│   • syncFrameState 时的互斥锁                          │
│   • Fence 信号量                                       │
│                                                       │
│ 交互方式:                                              │
│   Main → Render:                                      │
│     ThreadedRenderer.nSyncAndDrawFrame()               │
│     把 DisplayList 传递给 RenderThread                  │
│                                                       │
│   Render → Main:                                      │
│     通过回调通知帧完成状态                                │
│     FrameCompleteCallback                              │
└───────────────────────────────────────────────────────┘

RenderThread ↔ SurfaceFlinger

通信方式:跨进程 IPC (Binder + 共享内存)

┌───────────────────────────────────────────────────────┐
│ 共享数据:GraphicBuffer(通过共享内存/dmabuf)            │
│                                                       │
│ 控制通道:                                              │
│   • Binder IPC                                        │
│     - dequeueBuffer() → ISurfaceComposer              │
│     - queueBuffer()   → ISurfaceComposer              │
│                                                       │
│ 数据通道:                                              │
│   • GraphicBuffer 基于共享内存 (Gralloc/ION/dmabuf)    │
│   • 零拷贝!Buffer 不需要在进程间复制                     │
│   • App 和 SF 通过 fd 映射同一块物理内存                  │
│                                                       │
│ 同步机制:                                              │
│   • Fence (同步栅栏)                                   │
│     - AcquireFence: 告诉 SF,GPU 何时渲染完成           │
│     - ReleaseFence: 告诉 App,SF 何时用完 Buffer        │
└───────────────────────────────────────────────────────┘

Fence 机制详解

RenderThread                BufferQueue              SurfaceFlinger
     │                          │                          │
     │  queueBuffer(buffer,     │                          │
     │    acquireFence) ──────→ │                          │
     │  "GPU 还没画完,          │                          │
     │   等这个 fence 信号再用"   │                          │
     │                          │                          │
     │                          │  acquireBuffer() ──────→ │
     │                          │  + acquireFence           │
     │                          │                          │
     │                          │              等待 acquireFence 
     │                          │              信号(GPU渲染完成)
     │                          │                          │
     │                          │              fence 触发! │
     │                          │              开始合成     │
     │                          │                          │
     │                          │  releaseBuffer() ←────── │
     │                          │  + releaseFence           │
     │                          │  "我用完了,               │
     │                          │   等这个 fence 再写入"     │
     │                          │                          │
     │  dequeueBuffer() ──────→ │                          │
     │  等待 releaseFence        │                          │
     │  信号后才能写入新帧        │                          │

八、Perfetto 中观察三者交互

Perfetto 时间轴:

▼ com.your.app (pid: 12345)
  ▼ main (tid: 12345)
      Choreographer#doFrame
      ├── input
      ├── animation
      ├── traversal
      │   ├── measure
      │   ├── layout
      │   └── draw (record DisplayList)
      └── commit ← 包含 syncFrameStateRenderThread (tid: 12346)
      DrawFrame
      ├── syncFrameState        ← 从主线程接收 DisplayList
      ├── issueDrawCommands     ← 发送 GPU 指令
      ├── flushDrawingCommands  ← 等待 GPU 完成
      └── eglSwapBuffersqueueBuffer 提交给 SFGPU completionGPU fence 完成时间
      ┃████┃

▼ SurfaceFlinger (pid: xxx)
  ▼ VSYNC-appAppVSYNCVSYNC-sfSFVSYNCDisplay Frames
      ├── Expected Timeline
      └── Actual TimelineonMessageReceivedSF 收到 Buffer 的事件
      ├── latchBuffer
      ├── calculateWorkingSet
      ├── composite
      └── postComposition

九、一图总结

                          Android 渲染管线

    VSYNC-app                                    VSYNC-sf
       ↓                                            ↓
  ┌─────────┐   DisplayList   ┌──────────┐  GraphicBuffer  ┌──────────────┐
  │  Main    │ ──────────────→│  Render  │ ───────────────→│ Surface      │
  │  Thread  │   sync          │  Thread  │   BufferQueue   │ Flinger      │
  │          │                 │          │   (共享内存)      │              │
  │ measure  │                 │ GPU 渲染  │                 │ 多Layer合成   │
  │ layout   │                 │ OpenGL   │                 │ HWC/GPU合成  │
  │ draw(DL) │                 │ Vulkan   │                 │              │
  └─────────┘                 └──────────┘                 └──────┬───────┘
                                                                  │
  进程内                        进程内                      跨进程   │
  线程间通信                    线程间通信                   Binder + │
  (共享内存+锁)                 (共享内存+锁)               共享内存   │
                                                                  ↓
                                                            ┌──────────┐
                                                            │ Display  │
                                                            │ 屏幕显示  │
                                                            └──────────┘