3. 软件架构
在 SA8155 这类高通座舱平台上,显示链路并不是单一驱动,而是一条从应用层一直贯穿到硬件显示控制器的纵向软件栈。理解这条栈的分层职责与数据流向,是后续调试黑屏、撕裂、掉帧、多屏不同步等问题的前提。本节从 Android 显示框架出发,逐层向下梳理 SurfaceFlinger、HWC、DRM/KMS、GPU 驱动栈以及内核模块之间的关系。
一、整体分层与数据流
Android 显示系统的核心思想是“合成与提交分离”:应用只负责把内容画到自己的图形缓冲区(GraphicBuffer),由系统统一决定这些缓冲区如何被合成、在哪个显示设备上、以什么时序呈现。SA8155 上这条链路大致分为五层:应用与图形 API 层、SurfaceFlinger 合成层、HWC 硬件抽象层、DRM/KMS 内核显示框架、以及 MSM 显示控制器与 GPU 硬件。
二、各层核心职责
SurfaceFlinger 是 Android 显示的中枢,运行在 system_server 进程中。它维护所有 Layer 的 Z 序、可见性、裁剪与变换,接收应用通过 BufferQueue 提交的图形缓冲区,并在每个 VSYNC 周期决定如何合成。合成方式有两种:Client 合成由 GPU 把多个 Layer 渲染到一个缓冲区,Device 合成则把 Layer 直接交给 HWC 硬件叠加。SA8155 的 DPU 支持多层硬件叠加,因此优先走 Device 合成以降低 GPU 负载与功耗。
HWC(Hardware Composer) 是 SurfaceFlinger 与内核显示驱动之间的 HAL。它向上暴露 validate、present、getDisplayConfigs 等接口,向下通过 DRM/KMS ioctl 提交图层。HWC 的关键能力是“能力查询”:告诉 SurfaceFlinger 当前显示设备能同时叠加多少层、支持哪些格式与缩放。若图层数超过硬件能力,SurfaceFlinger 会回退到 GPU 合成。
DRM/KMS 是 Linux 内核的标准显示框架。KMS 把显示管线抽象为 CRTC(扫描输出控制器)、Plane(图层)、Encoder(编码器)、Connector(物理接口)四类对象。高通在此基础上实现了 msm_atomic、sde_crtc、sde_plane 等驱动,通过 Atomic Modeset 一次性提交整帧配置,保证多图层切换的原子性。
GPU 驱动栈 由内核态 KGSL(Kernel Graphics Support Layer)与用户态 Adreno 驱动组成。KGSL 负责 GPU 命令提交、内存管理、电源与频率调节;用户态驱动把 OpenGL ES / Vulkan 命令翻译为 Adreno 微码。当 SurfaceFlinger 选择 Client 合成时,正是通过 EGL 调用这条栈完成渲染。
三、关键内核模块与设备节点
| 模块/节点 | 所属层 | 作用 |
|---|---|---|
| msm_drm.ko | DRM/KMS | 高通 DRM 显示驱动主体,注册 card0 |
| msm_atomic.c | DRM/KMS | Atomic 提交路径,处理 plane/crtc 状态 |
| sde_crtc.c | DRM/KMS | SDE/DPU 扫描输出与混合配置 |
| dsi_display.ko | 显示输出 | MIPI DSI 面板初始化与时序 |
| kgsl.ko | GPU | Adreno GPU 内核驱动,/dev/kgsl-3d0 |
| /dev/dri/card0 | 用户接口 | DRM 主设备节点,HWC 通过它提交 |
| /sys/class/drm | 用户接口 | 查看 connector、CRTC 状态与 EDID |
四、典型场景:一帧从应用到屏幕
- 应用在 UI 线程完成绘制,通过 EGL 把内容渲染到 BufferQueue 的 GraphicBuffer,并 queue 给 SurfaceFlinger。
- SurfaceFlinger 收到 VSYNC 信号后,遍历所有可见 Layer,调用 HWC 的 validate 询问硬件能否直接叠加。
- HWC 返回每个 Layer 的合成方式;若可 Device 合成,则把 Layer 的 buffer handle 与位置信息打包。
- HWC 通过 DRM Atomic ioctl 提交 plane 更新,内核 msm_atomic 校验后写入 SDE 寄存器。
- DPU 在下一个 VSYNC 扫描输出,把混合结果经 DSI/DP 送到屏幕。
dumpsys SurfaceFlinger 查看合成方式与 Layer 数量,再用 dmesg | grep sde 确认内核是否报 plane 分配失败,最后用 modetest -M msm_drm 验证 CRTC/Connector 状态。
五、常见误区与复盘
误区二:把 HWC 当成独立进程。HWC 是加载进 SurfaceFlinger 进程的 HAL 库,崩溃会直接导致显示服务重启。
误区三:忽略 DRM 的原子性。多图层必须通过一次 Atomic 提交,分多次提交会造成中间态闪烁。
# 查看当前显示管线状态
adb shell dumpsys SurfaceFlinger --display-id
adb shell dumpsys SurfaceFlinger | grep -A5 "Composition"
# 查看 DRM 设备与连接器
adb shell ls /dev/dri/
adb shell cat /sys/class/drm/card0-DSI-1/status
# 查看 GPU 驱动加载情况
adb shell dmesg | grep -i kgsl