4. 内核图形子系统入门

当图形故障从用户态一路排查到内核时,最先接触到的就是 DRM(Direct Rendering Manager)子系统。它既是显卡驱动的统一入口,也是显示管线在内核中的“总调度台”。理解 DRM 的框架分层、KMS 对象模型以及 Atomic Modesetting 的提交机制,是后续定位黑屏、花屏、刷新异常、分辨率错误等问题的前提。

一、DRM 框架的整体分层

DRM 并不是单一模块,而是一套由字符设备、驱动核心、KMS、GEM 以及各厂商驱动共同组成的框架。用户态通过 /dev/dri/card0 或 renderD128 访问,内核侧则由 drm.ko 提供通用能力,再由 i915、amdgpu、nouveau、msm 等具体驱动实现硬件相关部分。

  • DRM Core:提供 ioctl 分发、对象生命周期管理、事件通知等通用机制。
  • KMS(Kernel Mode Setting):负责显示模式设置,管理 CRTC、Encoder、Connector、Plane 等对象。
  • GEM(Graphics Execution Manager):负责显存/缓冲区对象管理,处理分配、映射与同步。
  • 厂商驱动:实现寄存器操作、时钟、电源域、显示控制器等硬件细节。

下图展示了 DRM 框架中用户态、DRM Core、KMS 对象与硬件之间的数据流关系,也是后续日志定位时最常参照的结构。

DRM / KMS 数据流与对象关系 用户态 libdrm / X / Wayland DRM Core ioctl / 事件 / 对象管理 厂商驱动 i915 / amdgpu / msm KMS 对象模型 Framebuffer 像素数据 + 格式 宽高 / pitch Plane 图层 / 叠加 Primary / Cursor CRTC 扫描输出引擎 时序 / 刷新 Encoder / Connector 编码器 / 物理接口 HDMI / DP / eDP 显示硬件 Display Controller PHY / 时钟 面板 / 显示器

二、KMS 对象模型:谁决定画面如何显示

KMS 把显示过程抽象为若干对象,每个对象都有唯一的 ID,可通过 drmModeGetResources() 或 modetest 枚举。理解它们之间的绑定关系,是判断“为什么没有输出”的关键。

对象 职责 常见故障表现
Framebuffer 描述一块可扫描的像素缓冲区,含格式、宽高、pitch 花屏、颜色错乱、尺寸异常
Plane 图层,负责把 Framebuffer 合成到 CRTC 上 图层缺失、叠加顺序错误
CRTC 扫描输出引擎,产生时序并驱动显示 无扫描输出、刷新率错误
Encoder 把 CRTC 的像素流转换为接口信号 接口无信号、协议不匹配
Connector 代表物理接口,保存连接状态与 EDID 检测不到显示器、EDID 读取失败

典型绑定路径是:Framebuffer → Plane → CRTC → Encoder → Connector → 显示器。任何一环缺失或状态异常,都会导致最终无画面。

三、Atomic Modesetting:一次提交,整体生效

传统 modesetting 是逐步设置,容易出现中间态闪烁或部分生效。Atomic Modesetting 引入“原子提交”概念:先把所有对象的属性变更放入一个 drmModeAtomicReq,检查通过后一次性提交,由内核统一应用。

drmModeAtomicReq *req = drmModeAtomicAlloc();
drmModeAtomicAddProperty(req, plane_id, prop_fb_id, fb_id);
drmModeAtomicAddProperty(req, crtc_id, prop_mode_id, mode_id);
drmModeAtomicAddProperty(req, conn_id, prop_crtc_id, crtc_id);

int ret = drmModeAtomicCommit(fd, req,
             DRM_MODE_ATOMIC_ALLOW_MODESET |
             DRM_MODE_PAGE_FLIP_EVENT, NULL);
if (ret < 0) {
    perror("atomic commit failed");
}
drmModeAtomicFree(req);

提交时常用标志包括 DRM_MODE_ATOMIC_ALLOW_MODESET(允许模式切换)、DRM_MODE_PAGE_FLIP_EVENT(请求翻页事件)以及 DRM_MODE_ATOMIC_TEST_ONLY(只检查不生效)。排查时若看到 -EINVAL,通常意味着属性组合不合法或对象未正确绑定。

提示:使用 modetest -M <driver> -p 可以列出所有 Plane、CRTC、Connector 及其属性,是验证 Atomic 属性是否可用的最快方式。

四、内核日志定位方法

DRM 的日志主要通过 dmesg 输出,驱动通常带有前缀,如 [drm]、[i915]、[amdgpu]。定位时建议按以下顺序进行:

  1. 确认驱动是否加载:dmesg | grep -i drm,查看是否有 Initialized 或 probe success。
  2. 查看 Connector 状态:搜索 connector、EDID、hotplug,判断是否检测到显示器。
  3. 检查模式设置:搜索 mode、atomic、commit,确认是否成功应用。
  4. 关注错误码:-EINVAL、-ENOSPC、timeout 往往指向属性非法、带宽不足或硬件无响应。
# 动态开启 DRM 调试日志
echo 0x1f > /sys/module/drm/parameters/debug
dmesg -w | grep -Ei "drm|atomic|connector|crtc"

# 查看当前显示状态
modetest -M i915 -c
cat /sys/kernel/debug/dri/0/state

五、案例与常见误区

案例:某设备启动后 HDMI 无输出。日志显示 connector HDMI-A-1: EDID read failed,随后 atomic commit failed: -EINVAL。排查发现是 Connector 未正确绑定 CRTC,导致 Atomic 提交时属性缺失。修正绑定关系后,EDID 读取成功,画面恢复。

误区:很多人只盯着用户态日志,却忽略 dmesg 中的 DRM 报错。实际上,Atomic 提交失败、EDID 读取异常、Plane 格式不支持等信息,几乎都只在 kernel log 中体现。

复盘时建议建立固定检查清单:驱动是否 probe、Connector 是否 connected、EDID 是否有效、CRTC 是否绑定、Plane 格式是否匹配、Atomic 提交返回码是否为零。按此顺序排查,能覆盖绝大多数内核图形显示问题。