3. Linux显示子系统
在Linux图形栈中,DRM(Direct Rendering Manager)负责GPU与显示控制器的统一管理,而KMS(Kernel Mode Setting)是DRM中专门负责显示模式设置与画面扫描输出的子系统。理解KMS的对象模型,是后续调试HDR元数据传递、VBlank时序、Atomic提交失败等问题的前提。本节围绕KMS的核心对象及其协作关系展开,并给出Atomic模式设置的基本流程与排障思路。
一、KMS对象模型:从Framebuffer到Connector
KMS把一条显示通路抽象为若干可独立配置的对象,它们通过“属性(property)”暴露给用户空间,由Atomic机制统一提交。核心对象包括:
- Framebuffer(FB):描述一块可被扫描输出的像素缓冲,包含格式、宽高、pitch、modifier以及底层GEM对象句柄。HDR场景下,FB的格式(如ARGB2101010、ABGR16161616F)和modifier直接决定色彩精度与带宽。
- Plane:图层,负责把某个FB按源/目标矩形、旋转、缩放、混合方式叠加到CRTC上。分为Primary、Overlay、Cursor三类。HDR调试中常关注Plane的
COLOR_ENCODING、COLOR_RANGE、pixel blend mode等属性。 - CRTC:显示控制器通道,负责从Plane合成画面并按时序扫描输出。它持有mode(分辨率+刷新率)、
ACTIVE、MODE_ID、OUT_FENCE_PTR等属性,是VBlank事件的主要来源。 - Encoder:把CRTC的像素流转换为Connector可接收的信号形式,例如TMDS、DP、DSI、eDP。它决定“用哪种物理编码方式输出”。
- Connector:物理或虚拟输出接口,如HDMI-A-1、DP-1、eDP-1。它持有
CRTC_ID、EDID、link-status、HDR相关的HDR_OUTPUT_METADATA、max bpc等属性。
这些对象并非孤立存在,而是通过“可能连接关系”和“当前绑定关系”组织成一条完整链路。下图展示了KMS对象之间的典型拓扑与数据流方向。
二、Atomic模式设置的核心流程
传统drmModeSetCrtc是“立即生效”的旧接口,容易出现中间态闪烁。Atomic模式设置把一次显示变更拆成“构建请求—测试—提交—等待完成”四步,保证整条链路要么全部生效,要么全部不生效。
- 获取资源:通过
drmModeGetResources枚举CRTC、Encoder、Connector、Plane,并读取每个对象的属性ID。 - 构建请求:用
drmModeAtomicReq依次添加属性,例如把Connector的CRTC_ID指向目标CRTC,把CRTC的MODE_ID指向新建的blob,把Plane的FB_ID指向目标Framebuffer。 - 测试提交:带
DRM_MODE_ATOMIC_TEST_ONLY调用drmModeAtomicCommit,内核只做校验不真正改硬件,便于提前发现带宽、格式或时序冲突。 - 正式提交:去掉TEST_ONLY,加上
DRM_MODE_PAGE_FLIP_EVENT,提交后通过read等待DRM_EVENT_FLIP_COMPLETE,确认本帧已在VBlank点完成切换。
drmModeAtomicReq *req = drmModeAtomicAlloc();
drmModeAtomicAddProperty(req, conn_id, prop_crtc_id, crtc_id);
drmModeAtomicAddProperty(req, crtc_id, prop_mode_id, blob_id);
drmModeAtomicAddProperty(req, plane_id, prop_fb_id, fb_id);
drmModeAtomicAddProperty(req, plane_id, prop_src_w, width << 16);
drmModeAtomicAddProperty(req, plane_id, prop_src_h, height << 16);
/* 先测试,再提交 */
int ret = drmModeAtomicCommit(fd, req,
DRM_MODE_ATOMIC_TEST_ONLY, NULL);
if (ret == 0)
ret = drmModeAtomicCommit(fd, req,
DRM_MODE_ATOMIC_ALLOW_MODESET |
DRM_MODE_PAGE_FLIP_EVENT, NULL);
drmModeAtomicFree(req);
三、典型场景:HDR模式切换时的对象协作
假设要把一个SDR桌面切换到HDR10输出,涉及的对象与属性变化如下表所示。可以看到,HDR并不是某一个对象的“开关”,而是Framebuffer、Plane、Connector三者属性协同的结果。
| 对象 | 关键属性 | SDR 状态 | HDR10 状态 |
|---|---|---|---|
| Framebuffer | DRM_FORMAT / modifier | ARGB8888 / LINEAR | ABGR16161616F / AFBC |
| Plane | COLOR_ENCODING / RANGE | BT709 / Limited | BT2020 / Full |
| CRTC | MODE_ID / ACTIVE | 3840x2160@60 | 3840x2160@60(不变) |
| Connector | HDR_OUTPUT_METADATA / max bpc | 无 / 8 | HDR10 blob / 10 |
调试提示:HDR切换失败时,优先用
drmModeAtomicCommit的TEST_ONLY返回值定位是哪个对象属性不满足约束,再结合dmesg中i915/amdgpu的atomic check日志确认带宽或格式限制。四、常见误区与复盘
- 误区一:把Encoder当成Connector。Encoder描述“怎么编码”,Connector描述“从哪个口出”。一个Encoder可被多个Connector共享,但同一时刻只能绑定一个CRTC。
- 误区二:认为Plane可以脱离CRTC独立生效。Plane必须绑定到某个CRTC上,且其FB格式、缩放比例需满足该CRTC的硬件能力,否则Atomic测试阶段就会失败。
- 误区三:忽略blob属性的生命周期。
MODE_ID、HDR_OUTPUT_METADATA等是blob属性,提交后需在合适时机drmModeDestroyPropertyBlob,否则会造成内存泄漏。 - 误区四:用非Atomic接口混搭Atomic提交。同一CRTC上混用旧接口与Atomic接口,容易导致状态不一致,建议统一走Atomic路径。
排障顺序建议:先确认Connector的
link-status与EDID是否正常,再检查CRTC的mode是否被接受,最后核对Plane与Framebuffer的格式、modifier和带宽是否满足。VBlank超时或Page Flip事件丢失,往往不是显示对象本身的问题,而是提交时序或fence处理有误。掌握KMS对象模型与Atomic提交机制后,后续分析HDR元数据如何随Connector属性下发、VBlank事件如何驱动帧同步,就有了统一的观察坐标。实际调试中,建议把modetest、drm_info与内核atomic check日志结合使用,快速定位是对象绑定错误、属性取值越界,还是硬件带宽不足。