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对象之间的典型拓扑与数据流方向。

KMS 对象拓扑与数据流 Framebuffer 格式 / modifier / pitch GEM 句柄 Plane Primary / Overlay / Cursor 缩放 / 混合 / 色彩属性 CRTC mode / ACTIVE / VBlank OUT_FENCE_PTR Encoder TMDS / DP / DSI 信号编码 Connector HDMI-A-1 / DP-1 / eDP-1 EDID / HDR metadata 扫描 合成 编码 输出 Atomic 提交:一次 ioctl 原子更新整条链路 drmModeAtomicReq 添加对象属性 ATOMIC_TEST_ONLY 校验可行性 ATOMIC_COMMIT 提交并生效 Page Flip VBlank 完成 所有对象属性在同一提交中生效,避免中间态撕裂;失败时整批回滚

二、Atomic模式设置的核心流程

传统drmModeSetCrtc是“立即生效”的旧接口,容易出现中间态闪烁。Atomic模式设置把一次显示变更拆成“构建请求—测试—提交—等待完成”四步,保证整条链路要么全部生效,要么全部不生效。

  1. 获取资源:通过drmModeGetResources枚举CRTC、Encoder、Connector、Plane,并读取每个对象的属性ID。
  2. 构建请求:用drmModeAtomicReq依次添加属性,例如把Connector的CRTC_ID指向目标CRTC,把CRTC的MODE_ID指向新建的blob,把Plane的FB_ID指向目标Framebuffer。
  3. 测试提交:带DRM_MODE_ATOMIC_TEST_ONLY调用drmModeAtomicCommit,内核只做校验不真正改硬件,便于提前发现带宽、格式或时序冲突。
  4. 正式提交:去掉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日志结合使用,快速定位是对象绑定错误、属性取值越界,还是硬件带宽不足。