4. KMS核心概念
从 FrameBuffer 迁移到 DRM 之后,最先遇到的“门槛”不是 API,而是 KMS 的对象模型。FrameBuffer 时代只有“一块显存 + 一个分辨率”,而 KMS 把显示过程拆成了若干可独立配置的对象:Plane 负责图像来源与合成,CRTC 负责扫描时序与像素输出,Encoder 负责把像素流转换成某种物理信号,Connector 负责对接真实显示设备,Mode 描述时序参数,EDID 则是显示器自报的能力清单。理解它们之间的“谁连谁、谁配置谁”,是后续写驱动、调分辨率、做多屏的基础。
一、核心原理:一条显示管线的对象化拆解
KMS 的本质是把“显示”建模为一条从内存到屏幕的管线。用户空间通过 DRM ioctl 或原子提交(Atomic Commit)配置这条管线,内核驱动则把配置翻译成寄存器操作。各对象的职责如下:
- Plane(平面):图像来源。它绑定一个 Framebuffer,描述“从哪块显存、取哪块区域、缩放/裁剪成什么、放在屏幕什么位置”。主平面(Primary)通常承载桌面,叠加平面(Overlay)用于视频层,光标平面(Cursor)用于鼠标。
- CRTC:显示控制器,负责产生扫描时序(行同步、场同步、消隐区),把 Plane 合成后的像素按节拍送出。一个 CRTC 对应一路独立的显示输出通道。
- Encoder:信号编码器,把 CRTC 输出的并行像素流转换为 HDMI、DisplayPort、MIPI DSI、LVDS 等物理接口所需的信号格式。
- Connector:物理连接器抽象,代表一个可插拔的显示端口,负责读取 EDID、检测热插拔(HPD)、维护连接状态。
- Mode:一组完整的时序参数,包括像素时钟、水平/垂直有效像素、前后沿、同步极性等,决定“以什么节奏扫描”。
- EDID:显示器通过 DDC/I2C 上报的 128 字节(或扩展块)能力数据,包含厂商、支持的分辨率列表、物理尺寸、首选时序等。
二、方法流程:从枚举到点亮屏幕
在用户空间,点亮一块屏幕的标准流程是“先枚举、再匹配、后提交”。下面以 libdrm 的典型调用顺序说明:
drmModeRes *res = drmModeGetResources(fd);
// 1. 遍历 Connector,读取连接状态与 EDID
for (int i = 0; i < res->count_connectors; i++) {
drmModeConnector *conn = drmModeGetConnector(fd, res->connectors[i]);
if (conn->connection == DRM_MODE_CONNECTED && conn->count_modes > 0) {
// 2. 选择 Mode(通常取 conn->modes[0] 为首选时序)
drmModeModeInfo mode = conn->modes[0];
// 3. 找到该 Connector 可用的 Encoder 与 CRTC
drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoder_id);
uint32_t crtc_id = enc->crtc_id;
// 4. 创建 Framebuffer 并提交
drmModeSetCrtc(fd, crtc_id, fb_id, 0, 0, &conn->connector_id, 1, &mode);
}
}
在原子模式(Atomic Modesetting)下,上述“设置 CRTC”被替换为一次原子提交:把 Plane 的属性、CRTC 的 Mode、Connector 的 CRTC_ID 打包成一个 drmModeAtomicReq,由内核校验资源是否冲突后统一生效。原子提交的好处是支持回滚、支持多平面同时更新,也是现代 DRM 驱动推荐的方式。
三、案例场景:HDMI 显示器热插拔后的对象匹配
假设一块 HDMI 显示器插入,内核通过 HPD 中断感知,读取 EDID 后生成 Mode 列表。此时用户空间需要完成一次“对象匹配”:
- Connector 状态从 Disconnected 变为 Connected,并携带 EDID 解析出的 Mode 列表。
- 驱动为 Connector 分配可用的 Encoder,并找到该 Encoder 能连接的 CRTC。
- 用户空间选择 Mode(如 1920x1080@60),创建对应尺寸的 Framebuffer。
- 把 Framebuffer 绑定到 Primary Plane,把 Plane 绑定到 CRTC,把 CRTC 绑定到 Connector。
- 提交后 CRTC 按 Mode 产生时序,Encoder 输出 TMDS 信号,屏幕点亮。
modetest -M <driver> 直接枚举所有 CRTC、Encoder、Connector、Plane 及其可用 Mode,是验证对象关系最快的手段。
四、误区与复盘:常见理解偏差
| 常见误区 | 正确理解 |
|---|---|
| CRTC 就是“屏幕” | CRTC 是显示控制器通道,一个 CRTC 可切换连接到不同 Connector,屏幕由 Connector 代表。 |
| Plane 只是图层 | Plane 是图像来源与合成单元,支持裁剪、缩放、格式转换,主平面与叠加平面能力不同。 |
| Mode 由驱动随意决定 | Mode 必须来自 EDID 或驱动内置表,且需满足 CRTC 与 Encoder 的时钟约束。 |
| EDID 只是厂商信息 | EDID 决定可用 Mode 集合、首选时序、物理尺寸与音频能力,是 Connector 的能力来源。 |
| Encoder 可以随便换 | Encoder 与 Connector 的对应关系由硬件拓扑决定,通常一个 Connector 只能接特定 Encoder。 |
复盘时建议画一张自己平台的管线拓扑图:标出每个 CRTC 编号、可接的 Encoder、对应的 Connector、支持的 Plane 类型,以及 EDID 中解析出的首选 Mode。这张图一旦建立,后续排查“无显示”“分辨率不对”“多屏错位”都会快很多。KMS 的对象模型不是抽象概念,而是驱动、用户空间与硬件三者之间的契约,理解契约,迁移就成功了一半。