KMS(Kernel Mode Setting,内核模式设置)是 Linux DRM 中让内核负责显示模式配置的机制,包括分辨率、刷新率、显示接口、扫描输出、显示平面和页面翻转。
它解决的是“谁有权、在什么时候、用什么硬件状态把哪张图像送到哪个屏幕上”的问题。
核心问题
显示输出不是普通文件写入。屏幕需要稳定的像素时序,显卡或 显示控制器 要按固定节奏从内存中读取图像,再通过 HDMI、DisplayPort、eDP、MIPI DSI 等接口送出去。
如果显示模式由用户态程序随意切换,会带来几个问题:
- 系统启动、登录界面、桌面会话和崩溃恢复之间很难交接屏幕控制权。
- 多个程序可能同时想改分辨率、刷新率或显示缓冲。
- GPU 渲染和扫描输出之间需要同步,否则会撕裂或显示半成品。
- 热插拔、休眠恢复和多显示器布局需要内核级状态管理。
KMS 把显示硬件状态放在内核的 DRM 驱动里,由拥有显示权限的合成器或显示服务器通过受控接口提交变更。
核心对象
| 对象 | 含义 | 关注点 |
|---|---|---|
| connector | 物理或逻辑显示接口 | HDMI、DP、eDP、DSI、是否连接、EDID |
| encoder | 像素流到接口信号的编码单元 | 哪些 connector 可用、硬件路由限制 |
| CRTC | 产生扫描时序的显示控制器 | 分辨率、刷新率、vblank、扫描位置 |
| plane | 可叠加 [[DRM Plane | 显示平面]] |
| framebuffer | 被扫描输出的图像描述 | 指向 帧缓冲、像素格式、stride、尺寸 |
| mode | 显示模式 | 宽高、刷新率、时钟、同步参数 |
| atomic commit | 原子提交显示状态 | 一次性验证和应用多对象状态 |
核心机制
KMS 的现代用法通常是 atomic modesetting:用户态先构造一组“新显示状态”,内核先验证,再在安全时机一次性应用。
典型流程如下:
- 枚举资源:用户态读取 connector、CRTC、plane、encoder 和 mode 列表。
- 选择显示路径:选择哪个 connector 接到哪个 CRTC,选择主 plane 和目标 framebuffer。
- 构造属性集合:设置 connector 的 CRTC、CRTC 的 mode、plane 的源矩形和目标矩形。
- test-only 验证:内核检查硬件是否支持这组组合,例如格式、缩放、带宽和路由限制。
- atomic commit:验证通过后提交真实变更。
- 等待 vblank / page flip:在合适 扫描输出 周期切换 framebuffer,减少撕裂。
- 释放旧缓冲:收到 flip 完成事件后,旧 framebuffer 可以被复用或销毁。
可以把页面翻转理解为:
display_state.framebuffer = next_framebuffer
apply_at_next_vblank(display_state)next_framebuffer是下一帧要显示的图像。vblank是垂直消隐期,屏幕刚扫完一帧、尚未开始下一帧的时间窗口。apply_at_next_vblank不是普通赋值,而是让硬件在不撕裂的时机切换扫描源。
工程用途
- Linux 桌面合成器用 KMS 控制显示器、光标、overlay 和页面翻转。
- 嵌入式设备用 KMS 调试屏幕 bring-up、MIPI DSI/eDP 面板、背光和显示时序。
- 游戏或 kiosk 系统可以绕过传统窗口系统,直接使用 DRM/KMS 全屏输出。
- 显示调试工具
modetest可以列出 KMS 对象并尝试设置模式。
调试 KMS 时常看 connector 是否 connected、EDID 是否读到、CRTC 是否绑定、plane 是否支持目标格式、framebuffer stride 是否正确,以及 dmesg 中的带宽或模式验证失败信息。
边界与常见坑
- KMS 不是密钥管理服务:本文的 KMS 是 Kernel Mode Setting;云安全里的 KMS 是 KMS(密钥管理服务)。
- KMS 只负责显示模式和扫描输出:GPU 渲染命令、着色器执行和显存调度属于 DRM 的渲染路径或用户态驱动。
- 设置成功不等于有画面:背光、电源、面板 init 序列、像素格式和线缆连接都可能导致黑屏。
- legacy modesetting 和 atomic modesetting 不是同一套模型:现代合成器更依赖 atomic commit,因为它能一次验证整组状态。
- vblank 同步不正确会出现撕裂或卡顿:页面翻转太早、太晚或没等 fence 都可能造成可见异常。