3. 显示与图形系统:SurfaceFlinger/WindowManager架构、多屏显示策略与GPU调优

座舱开发里,显示和图形系统是用户第一眼就能感知的部分。说白了,屏幕亮不亮、动画顺不顺、多屏切换卡不卡,全看这一层的功底。8155 的显示架构继承自 Android,但针对多屏场景做了大量定制。我刚开始接触时也被 SurfaceFlinger 和 WindowManager 的关系绕晕过,后来拆了几个 dump 才理清楚。

3.1 SurfaceFlinger 与 WindowManager 的协作关系

WindowManager(WMS)管“逻辑”,SurfaceFlinger(SF)管“合成”。WMS 决定窗口该多大、在哪层、是否可见;SF 则把各应用的 Surface 合成一帧,送给 Display。你可以把 WMS 当成导演,SF 是剪辑师。

核心流程:

  1. App 通过 Surface 向 BufferQueue 提交图像数据。
  2. WMS 计算窗口 Z-order 和可见区域,通知 SF 更新 Layer 状态。
  3. SF 在 V-Sync 周期内合成所有 Layer,输出到 HWC(硬件合成器)或 GPU。
  4. HWC 直接送显,或 GPU 做 OpenGL ES 合成后再送显。

我在项目中遇到过一个问题:中控屏切应用时出现黑边。查了半天,发现是 WMS 的窗口裁剪区域没及时同步给 SF。嗯,这里要注意——WMS 和 SF 之间是异步通信,状态不一致就会闪。

3.2 多屏显示策略:仪表、中控、HUD

8155 最多支持 4 路独立显示输出。仪表、中控、HUD 这三块屏幕,各有各的脾气。

屏幕 分辨率 刷新率 关键要求
仪表 1920x720 60fps 低延迟、无撕裂、安全关键
中控 1920x1080 60fps 高帧率、触控响应、多窗口
HUD 1280x480 30fps 高亮度、畸变校正、动态对齐

多屏策略的核心是 Display 分组。每个 Display 有独立的 SurfaceFlinger 实例(或虚拟 Display),WMS 通过 DisplayManager 分配窗口到不同屏幕。仪表屏通常独占一个物理 Display,中控和 HUD 可以共享或独立。

我的经验:仪表屏一定要用 HWC 直接合成,别走 GPU 绕一圈。我曾经试过让仪表走 GPU 合成,结果帧率掉到 45fps,指针动画肉眼可见的卡。后来强制走 HWC bypass,稳在 60fps。

3.3 GPU 渲染管线与性能调优

8155 集成的 Adreno 640 GPU,渲染管线分三个阶段:

  • 应用端渲染:App 通过 OpenGL ES/Vulkan 绘制到 Surface。
  • 合成阶段:SF 把多个 Surface 合成到 Framebuffer。
  • 显示输出:Framebuffer 通过 DSI/DP 接口送显。

性能瓶颈通常出现在合成阶段。我常用的调优手段:

  1. 减少 Layer 数量:每多一个 Layer,SF 就多一次合成开销。能合并的 Surface 尽量合并。
  2. 使用 Hardware Composer:HWC 能直接合成 overlay,不占用 GPU 资源。用 dumpsys SurfaceFlinger 查看 HWC 是否生效。
  3. 控制帧率:仪表用 60fps,HUD 用 30fps,别让 GPU 做无用功。
  4. GPU 频率调节:通过 /sys/class/kgsl/kgsl-3d0 调节频率,避免过热降频。

避坑指南:我曾经在 HUD 上叠加了一个半透明遮罩层,结果 GPU 负载飙升 30%。后来发现是 SF 把遮罩当成独立 Layer 合成,改成在 App 内预合成后,负载降下来了。记住——透明层越多,合成越重。

3.4 多屏显示架构总览

下面这张图展示了 8155 座舱的显示系统整体架构,从 App 到屏幕的完整链路。

8155 多屏显示架构图 8155 座舱多屏显示架构 应用层(仪表App / 中控App / HUD App) Surface · BufferQueue · OpenGL ES / Vulkan WindowManager(WMS) 窗口策略 · Z-order · 可见性 SurfaceFlinger(SF) Layer合成 · HWC · GPU合成 HWC / GPU 合成 Overlay · OpenGL ES · Framebuffer 仪表屏 DSI · 60fps · HWC直出 中控屏 DSI · 60fps · 触控 HUD DP · 30fps · 畸变校正 说明: 仪表屏走 HWC bypass 保证低延迟;中控和 HUD 可走 GPU 合成,但需控制 Layer 数量。 WMS 和 SF 通过异步通信协作,状态不一致可能导致闪屏或黑边。

3.5 性能调优实战清单

调优不是玄学,是数据驱动。我每次调优都按这个清单来:

步骤 操作 工具/命令 预期效果
1 检查 Layer 数量 dumpsys SurfaceFlinger Layer 数 < 8
2 确认 HWC 生效 dumpsys SurfaceFlinger --hwclayers HWC 合成占比 > 80%
3 测量 GPU 负载 cat /sys/class/kgsl/kgsl-3d0/gpu_busy_percentage 负载 < 70%
4 检查帧率 dumpsys gfxinfo 仪表 60fps,HUD 30fps
5 验证 V-Sync 对齐 dumpsys SurfaceFlinger --vsync 无 jitter

小技巧:用 adb shell dumpsys SurfaceFlinger 看每一帧的合成耗时。如果某个 Layer 的合成时间超过 5ms,优先检查它是不是透明层或尺寸过大。

嗯,显示系统这块内容比较多,但核心就三件事:理解 WMS 和 SF 怎么配合、针对不同屏幕选对策略、用数据驱动 GPU 调优。你在实际开发中遇到闪屏、卡顿、黑边,八成都能在这三个方向找到根因。