2. 座舱图形系统基础

在座舱量产调优中,几乎所有“卡顿、撕裂、掉帧、花屏、黑屏、延迟高”的问题,最终都会落到 Android 图形栈的某一段链路上。理解这条链路,比记住某个参数更重要。Android 图形栈可以粗略理解为一条从“应用画内容”到“屏幕亮像素”的生产线:应用通过 Canvas、OpenGL ES、Vulkan 或硬件加速渲染生成图形缓冲,SurfaceFlinger 负责合成,HWComposer 负责把合成结果送到显示控制器,Gralloc 负责图形缓冲的分配与跨进程共享,RenderEngine 则在需要时承担 GPU 合成与效果处理。

核心组件与职责

  • 应用渲染层:通过 Skia、OpenGL ES、Vulkan 等把 UI 绘制到 Surface 对应的 BufferQueue 中,产出图形缓冲。
  • BufferQueue:生产者与消费者之间的缓冲队列,是应用与 SurfaceFlinger 解耦的关键,也是排查 dequeueBuffer 超时、Buffer 饥饿的入口。
  • SurfaceFlinger:系统合成服务,决定哪些 Layer 可见、如何叠加、用 GPU 还是 HWC 合成,并控制 VSYNC 节奏。
  • HWComposer(HWC):硬件合成抽象层,把可交给显示控制器直接叠加的 Layer 下发给 DPU/显示驱动,减少 GPU 合成开销。
  • Gralloc:图形内存分配器,负责按用途分配带格式、跨进程可共享的图形缓冲,决定带宽、对齐与缓存属性。
  • RenderEngine:SurfaceFlinger 的 GPU 渲染后端,在 HWC 无法全部接管时执行 GPU 合成、混合、圆角、模糊等效果。

这六个部分不是并列关系,而是有明确的数据流方向。下面这张图把座舱图形栈的核心组件、缓冲流向与合成决策点放在同一条链路上,便于建立整体心智模型。

Android 座舱图形栈:从应用到屏幕的数据流 应用 / UI 渲染 Canvas / OpenGL ES Vulkan / Skia 产出图形缓冲 BufferQueue 生产者 / 消费者 dequeue / queue acquire / release SurfaceFlinger Layer 管理 / 合成决策 VSYNC 节奏控制 GPU 或 HWC 合成 HWComposer HWC / DPU 硬件叠加 送显控制 Gralloc 图形缓冲分配 格式 / 对齐 / 缓存 跨进程共享句柄 RenderEngine GPU 合成后端 混合 / 圆角 / 模糊 HWC 兜底路径 缓冲句柄 关键合成决策点 1. Layer 是否可被 HWC 直接叠加(格式、缩放、旋转、遮挡、数量限制) 2. 若 HWC 无法全部接管,SurfaceFlinger 调用 RenderEngine 做 GPU 合成,再交给 HWC 送显 3. 合成结果最终由显示控制器按 VSYNC 扫描输出,任何一段超时都会表现为掉帧或延迟

数据流:一帧是怎么走到屏幕的

以座舱中常见的“仪表 + 中控 + HUD”多屏场景为例,一帧的典型路径如下:

  1. 应用收到 VSYNC 后开始绘制,通过 Skia 或 GPU 把内容渲染到 Surface 对应的 BufferQueue。
  2. 应用 queueBuffer 后,SurfaceFlinger 在下一个 VSYNC 周期被唤醒,收集所有可见 Layer 的最新缓冲。
  3. SurfaceFlinger 向 HWComposer 查询每个 Layer 的合成方式,HWC 根据硬件能力返回 DEVICE 或 CLIENT 合成。
  4. 可硬件叠加的 Layer 由 DPU 直接读取 Gralloc 缓冲;不可硬件叠加的 Layer 由 RenderEngine 先合成到一张 GPU 目标缓冲。
  5. HWC 把最终显示缓冲提交给显示驱动,在 VSYNC 时刻扫描输出到屏幕。
调优视角:这条链路上任何一段出现“等待”,都会以掉帧或延迟的形式暴露。SurfaceFlinger 的合成耗时、HWC 的叠加能力、Gralloc 的带宽与格式、RenderEngine 的 GPU 负载,是四个最常被追查的方向。

关键参数与排查入口

组件 关键参数 / 观察点 常见问题
BufferQueue buffer count、dequeueBuffer 超时、queueBuffer 耗时 Buffer 饥饿、生产者阻塞、帧率不稳
SurfaceFlinger 合成耗时、Layer 数量、missed frame、GPU 合成占比 合成过重、GPU 抢占、VSYNC 错拍
HWComposer DEVICE/CLIENT 合成比例、叠加层数上限、缩放与旋转能力 HWC 回退 GPU、带宽不足、多屏冲突
Gralloc 像素格式、stride 对齐、缓存属性、内存类型 带宽浪费、格式不匹配、跨进程共享失败
RenderEngine GPU 合成耗时、shader 复杂度、模糊/圆角开销 GPU 负载高、合成延迟、发热降频

案例:多屏座舱的合成回退

某座舱项目在“仪表 + 中控 + 副驾”三屏同时显示时出现周期性掉帧。抓取 SurfaceFlinger 日志发现,中控屏的 HWC 合成层数从 4 层增加到 7 层后,HWC 返回 CLIENT 合成,RenderEngine 的 GPU 合成耗时从 2ms 上升到 9ms,直接吃掉了 VSYNC 预算。进一步排查发现,副驾屏新增的视频 Layer 使用了 HWC 不支持的 YUV 格式,导致整条链路回退到 GPU 合成。

# 典型排查命令
adb shell dumpsys SurfaceFlinger --latency
adb shell dumpsys SurfaceFlinger | grep -i "HWC\|Client\|GPU"
adb shell dumpsys SurfaceFlinger --dispsync
adb shell cat /d/dri/0/summary
遇到掉帧时,先确认是“应用画得慢”还是“合成送得慢”。前者看应用帧耗时与 BufferQueue 状态,后者看 SurfaceFlinger 合成耗时、HWC 合成方式与 RenderEngine 负载。方向错了,调参只会越调越乱。

常见误区与复盘

  • 误区一:只盯应用帧率。应用 60fps 不代表屏幕 60fps,合成与送显链路同样可能成为瓶颈。
  • 误区二:认为 HWC 一定能接管所有 Layer。HWC 有叠加层数、格式、缩放、旋转等限制,超出后必然回退 GPU 合成。
  • 误区三:忽略 Gralloc 的格式与对齐。格式不匹配会导致 HWC 无法直接读取,进而触发 RenderEngine 兜底。
  • 误区四:把 RenderEngine 当成“备用方案”而忽视其开销。GPU 合成在座舱多屏场景下可能成为主路径,必须纳入性能预算。