Table of contents
Open Table of contents
一、CPU 与 GPU 的关系是什么?
在渲染链路中,CPU 与 GPU 的关系可以类比为“包工头”与“泥瓦匠”:
1.1 CPU(包工头 / 大脑)
- 负责复杂逻辑、物理引擎、网络请求、文件读取等任务
- 在 UI 渲染中,CPU 决定“要画什么,在哪里画”
- 生成 DisplayList(绘制指令集合)
1.2 GPU(泥瓦匠 / 画师)
- 高度并行,专注底层图形指令(如 OpenGL / Vulkan)
- 接收 DisplayList,进行矩阵变换、光栅化计算
- 最终将像素颜色值填满后台缓冲区(Back Buffer)
二、核心纠错:图纸(DisplayList)与画布(GraphicBuffer)
在 Android 的底层架构中,存在两种完全不同的“载体”:
图纸(DisplayList):
- 由 CPU 生成,存储的是“绘画指令”(如 DrawRect、DrawText 等)
- 存放在普通内存(RAM),体积小
画布(GraphicBuffer / Back Buffer):
- 存储的是像素颜色值(RGBA 数据)
- 位于显存(VRAM)或专用图形内存,体积大(如 1080P 屏幕一张图可达数兆)
三、真实工作流:包工头、画师与画板
用一个形象的比喻来还原整个过程:
1.CPU(包工头)生成施工图(DisplayList)
- 你的代码在主线程执行 onDraw,CPU 计算 View 的大小、位置,并生成绘制指令(DisplayList)
- 此时还未接触画布(Buffer)
2.转交施工图(UI 线程同步给 RenderThread)
- CPU 将“图纸DisplayList”交给系统专门负责渲染的线程(RenderThread)
3.申请空画布(Dequeue Buffer)
- RenderThread 接到图纸后,向系统的图形管家(BufferQueue)申请一块空画布(Back Buffer)
4.GPU(画师)开始工作
- RenderThread 拿到画布后,将其绑定到 GPU,并将 DisplayList 翻译成底层 OpenGL/Vulkan 指令
- GPU 进行矩阵变换、光栅化,把像素颜色填满画布(Back Buffer)
5.提交画布(Queue Buffer)
- GPU 完成绘制后,RenderThread 将画满像素的画布交还给BufferQueue
- 等待 VSYNC 信号到来,屏幕取走显示(变成 Front Buffer)
四、案例分析:为什么 GPU 慢了,CPU 会“没有空 Buffer 可拿”?
在双缓冲机制下,系统只有两块画布(A 和 B):
- 画布 A:正在被屏幕显示(Front Buffer)
- 画布 B:正在被 GPU 绘制(Back Buffer)
如果用户操作触发了新一帧:
- CPU 主线程飞速生成新的“图纸(DisplayList)”,交给 RenderThread
- RenderThread 申请第三块空画布时,BufferQueue 会拒绝(因为只有两块画布,A 在屏幕手里,B 在 GPU 手里没画完)
- 这会导致底层触发 dequeueBuffer 阻塞,RenderThread 被卡死,无法接收新图纸
- 最终,CPU 主线程也会在 syncFrameState 步骤被强行卡死
五、结论 & 三缓冲机制的意义
- CPU 只负责生成轻量级的 DisplayList 图纸,不直接填充像素
- GPU 若画得太慢,霸占 Back Buffer 不释放,RenderThread 申请不到新画布,导致流水线拥堵,最终 CPU 也被阻塞
- 三缓冲(Triple Buffering):安卓双缓冲机制
- 增加一块备用画布(Buffer C)
- 当 GPU 霸占 B 慢慢画时,RenderThread 可以拿到空画布 C,让流水线继续运转