2. 显示子系统基础
在 Linux 显示子系统中,DRM(Direct Rendering Manager)负责 GPU 与显示硬件的统一管理,而 KMS(Kernel Mode Setting)是 DRM 中专门负责显示模式设置与像素流管道的子模块。理解 DRM/KMS 的关键,不是记住一堆结构体名字,而是看清一条“像素数据从内存到屏幕”的完整链路:应用或合成器准备好画面内容,经 Plane 送入 CRTC 扫描输出,再由 Encoder 转换为接口信号,最终通过 Connector 驱动物理显示设备。GPU 驱动与硬件适配工程的核心工作,正是把这条链路中的每个对象正确初始化、连接并配置。
一、核心对象与职责划分
DRM/KMS 将显示硬件抽象为若干可组合对象,每个对象承担明确职责:
- Framebuffer(FB):描述一块可被扫描输出的内存缓冲,包含像素格式、宽高、pitch、修饰符(modifier)以及底层 GEM 对象句柄。它是“画面内容”的载体。
- Plane:图层抽象,负责把某个 Framebuffer 按位置、缩放、旋转、混合方式叠加到 CRTC 上。常见类型有 Primary、Cursor、Overlay。
- CRTC:显示控制器,代表一个扫描输出引擎。它从 Plane 取像素,按模式时序(mode)产生像素流,并决定刷新率、消隐区等。
- Encoder:把 CRTC 输出的并行像素流转换为具体物理接口信号,如 HDMI、DisplayPort、MIPI DSI、eDP。
- Connector:代表物理输出端口及其连接状态,负责 EDID 读取、热插拔检测、链路训练结果上报,并暴露可用 mode 列表。
这些对象之间不是简单包含关系,而是通过“可能连接”和“当前连接”两种关系组织。驱动在初始化阶段枚举硬件能力,建立 possible_crtcs、possible_clones 等约束;在模式设置阶段,用户空间通过原子提交(atomic commit)把 FB、Plane、CRTC、Connector 绑定成一次完整显示配置。
二、模式设置流程与原子提交
传统 KMS 使用“设置 CRTC + 设置 Connector + 设置 Plane”的多步 ioctl,容易出现中间状态撕裂。现代驱动普遍采用 Atomic Modeset:用户空间先创建 property 集合,把 FB、Plane、CRTC、Connector 的目标状态写入 atomic state,再由内核统一校验资源冲突、带宽、格式支持等,最后一次性提交生效。
# 典型原子提交伪代码流程
drmModeAtomicAlloc(&req);
drmModeAtomicAddProperty(req, plane_id, "FB_ID", fb_id);
drmModeAtomicAddProperty(req, plane_id, "CRTC_ID", crtc_id);
drmModeAtomicAddProperty(req, crtc_id, "MODE_ID", mode_blob);
drmModeAtomicAddProperty(req, connector_id, "CRTC_ID", crtc_id);
drmModeAtomicSetCursor(req, 0);
drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);
驱动侧需要实现 atomic_check 与 atomic_commit 回调。atomic_check 阶段不写硬件,只做可行性判断;atomic_commit 阶段才真正配置寄存器、启动扫描输出。这种“先校验后生效”的机制,是 GPU 驱动适配中减少显示异常的关键设计。
三、典型场景:HDMI 热插拔后的显示恢复
当 HDMI 显示器插入时,Connector 的 HPD 中断触发,内核读取 EDID 并更新 mode 列表。用户空间合成器收到 uevent 后,重新选择 mode,创建新的 Framebuffer,并通过 atomic commit 把 Plane 绑定到 CRTC,Encoder 切换到 HDMI 输出路径。若链路训练失败,Connector 状态保持 disconnected,CRTC 进入关闭状态,避免无效扫描。
/sys/class/drm/card0-HDMI-A-1/status 与 modetest -c 输出,确认 Connector 状态与可用 mode 是否同步更新。
四、常见误区与复盘要点
| 误区 | 现象 | 正确做法 |
|---|---|---|
| 把 Connector 当作显示内容来源 | 画面黑屏但 Connector 状态正常 | 检查 Plane 是否绑定 FB,CRTC 是否使能 |
| 忽略 possible_crtcs 约束 | atomic commit 返回 -EINVAL | 确认 Plane 与 CRTC 的硬件连接关系 |
| 在 atomic_check 中写寄存器 | 校验失败后硬件状态被污染 | check 只做判断,commit 才写硬件 |
| 忘记设置 FB modifier | 画面花屏或格式不匹配 | 按驱动支持的 modifier 创建 FB |
总结来看,DRM/KMS 的核心对象构成了一条清晰的显示流水线:Framebuffer 提供内容,Plane 负责图层合成,CRTC 完成扫描输出,Encoder 转换接口信号,Connector 连接物理设备。掌握它们之间的连接约束与原子提交机制,是后续进行 GPU 驱动接口开发和硬件适配的基础。