1. DRM 框架概述

DRM(Direct Rendering Manager)是 Linux 内核中负责图形显示与渲染管理的核心框架。它最初诞生于 1999 年,作为 XFree86 加速架构(DRI)的一部分,旨在为 3D 加速提供安全的用户空间内核接口。经过二十多年的演进,DRM 已从单一的渲染管理器发展为涵盖显示控制、内存管理、编解码加速的完整显示子系统,是当前 Linux 图形栈的基石。

1.1 DRM 在 Linux 图形栈中的位置

下图展示了 DRM 在 Linux 图形栈中的层级关系:

Linux 图形栈架构图 Linux 图形栈架构 用户空间应用(Wayland/Weston、Xorg、Qt、Flutter、游戏引擎) 用户空间图形库(libdrm、Mesa 3D、EGL、GBM、Vulkan) 系统调用接口(ioctl、mmap、poll) 内核空间 DRM 核心框架 KMS(内核模式设置) | GEM(图形执行管理器) | FB(帧缓冲) DRM 调度器 | DRM 连接器/编码器/桥接抽象 硬件驱动层(i915、msm、vc4、panfrost、mediatek-drm 等) 物理硬件(GPU、Display Controller、DSI/HDMI/DP 接口)
关键理解:DRM 是内核空间与用户空间图形栈之间的桥梁。用户空间的图形库(如 Mesa)通过 libdrm 封装的 ioctl 调用与 DRM 核心交互,而 DRM 核心则通过驱动层控制具体的显示硬件。Wayland/Weston 等现代显示服务器直接使用 DRM 的 KMS 接口进行页面合成与显示输出。

1.2 DRM 的发展历史

时间 里程碑 关键变化
1999 DRI 项目启动 XFree86 引入 DRI(Direct Rendering Infrastructure),DRM 作为内核组件诞生
2004 DRM 进入主线内核 2.6.x DRM 成为 Linux 内核官方子系统,支持 i810、radeon 等早期 GPU
2008 KMS 引入 内核模式设置(Kernel Mode Setting)合并,将显示模式管理从 X Server 移入内核
2012 GEM 与 TTM 成熟 图形执行管理器(GEM)成为主流内存管理方案,TTM 用于专业显卡
2015 Atomic API 稳定 DRM 原子操作接口合并,支持无撕裂的原子化显示更新
2018+ 显示子框架扩展 DRM 桥接框架、MIPI DSI 支持、HDMI/DP 驱动框架持续完善

1.3 DRM 核心组件

DRM 框架由三个核心子系统构成,它们协同工作以实现完整的显示功能:

1.3.1 KMS — 内核模式设置

KMS(Kernel Mode Setting)负责显示管线的配置与管理,包括分辨率、刷新率、图层叠加、色彩空间等。KMS 将显示硬件抽象为以下对象:

  • CRTC(Cathode Ray Tube Controller):显示控制器,负责从内存读取像素数据并生成视频时序信号。每个 CRTC 对应一个独立的显示通道。
  • Encoder(编码器):将 CRTC 输出的像素流编码为特定接口格式(如 MIPI DSI、HDMI、DisplayPort)。
  • Connector(连接器):代表物理显示接口(如 HDMI 插座、DSI 排线),负责检测显示器连接状态和 EDID 信息。
  • Plane(图层):硬件叠加层,允许将多个帧缓冲叠加合成后输出,减少 CPU 合成负担。
  • Bridge(桥接):用于连接不同显示接口的转换芯片(如 DSI 转 eDP、LVDS 转 HDMI)。
KMS 对象关系图 KMS 核心对象关系 Framebuffer Plane(图层) CRTC Encoder Connector Bridge 数据流方向 Framebuffer → Plane → CRTC → Encoder → Connector/Bridge CRTC 从 Framebuffer 读取像素数据 Encoder 将像素流编码为接口信号 Connector/Bridge 连接物理显示设备

1.3.2 GEM — 图形执行管理器

GEM(Graphics Execution Manager)是 DRM 的内存管理子系统,负责管理 GPU 和显示控制器使用的缓冲区对象。GEM 提供以下核心能力:

  • 缓冲区分配与释放:通过 drm_gem_object_init() 创建 GEM 对象,支持连续内存、分散内存等多种分配策略。
  • 内存共享与映射:支持通过 drm_gem_handle_create() 导出句柄,实现进程间共享;通过 mmap 将 GPU 内存映射到用户空间。
  • 同步与栅栏:提供 dma_fence 机制,确保 GPU 渲染完成后再进行显示扫描。
  • 驱动适配层:每个 DRM 驱动可以实现自己的 GEM 后端(如 i915 的 shmem、msm 的 ion 封装)。
GEM vs TTM:GEM 是 DRM 推荐的内存管理框架,适用于大多数嵌入式 GPU 和集成显卡。TTM(Translation Table Manager)是更底层的内存管理方案,主要用于需要复杂显存管理的独立显卡(如 AMDGPU、Nouveau)。现代驱动倾向于使用 GEM 加驱动私有后端的组合方式。

1.3.3 Framebuffer — 帧缓冲

Framebuffer 是 DRM 中表示显示缓冲区的基本对象。它封装了像素数据的格式、尺寸、行宽和内存地址。KMS 通过 Framebuffer 对象告诉 CRTC 从哪里读取显示数据。

属性 说明 典型值
width / height 帧缓冲的像素尺寸 1920 x 1080
pixel_format 像素格式(DRM 四码标识) DRM_FORMAT_XRGB8888
pitches[4] 每行字节数(可能包含对齐填充) 7680(1920 * 4)
offsets[4] 各颜色平面的字节偏移 0(单平面格式)
modifier 内存布局修饰符(压缩、分块等) DRM_FORMAT_MOD_LINEAR
Framebuffer 内存布局 Framebuffer 内存布局(XRGB8888 格式) Framebuffer 内存区域 width = 1920 像素 height = 1080 行 pitch = 1920 × 4 = 7680 字节/行 像素 XRGB 8888 4 字节

1.4 DRM 驱动注册流程

一个典型的 DRM 驱动在 probe 阶段的注册流程如下:

  1. 分配 DRM 设备:调用 drm_dev_alloc() 分配 struct drm_device 结构体。
  2. 设置驱动信息:填充 struct drm_driver,包括 driver_features、fops、gem_create_object 等回调。
  3. 注册 DRM 设备:调用 drm_dev_register() 将设备注册到内核,创建设备节点 /dev/dri/card0。
  4. 初始化 KMS 组件:调用 drm_mode_config_init(),注册 CRTC、Encoder、Connector、Plane。
  5. 初始化 GEM 后端:调用 drm_gem_object_init() 或驱动私有的 GEM 初始化函数。
  6. 创建初始 Framebuffer:为启动 Logo 或控制台创建默认帧缓冲。
// DRM 驱动 probe 函数示例(简化)
static int my_drm_probe(struct platform_device *pdev)
{
    struct drm_device *drm;
    int ret;

    // 1. 分配 DRM 设备
    drm = drm_dev_alloc(&my_drm_driver, &pdev->dev);
    if (IS_ERR(drm))
        return PTR_ERR(drm);

    platform_set_drvdata(pdev, drm);

    // 2. 初始化模式配置
    ret = drm_mode_config_init(drm);
    if (ret)
        goto err_free;

    // 3. 初始化显示管线组件
    ret = my_drm_crtc_init(drm);
    if (ret)
        goto err_config;

    ret = my_drm_encoder_init(drm);
    if (ret)
        goto err_config;

    ret = my_drm_connector_init(drm);
    if (ret)
        goto err_config;

    // 4. 注册 DRM 设备
    ret = drm_dev_register(drm, 0);
    if (ret)
        goto err_config;

    drm_fbdev_generic_setup(drm, 32);
    return 0;

err_config:
    drm_mode_config_cleanup(drm);
err_free:
    drm_dev_put(drm);
    return ret;
}
注意事项:DRM 驱动的注册顺序非常重要。必须先初始化所有 KMS 组件(CRTC、Encoder、Connector),再调用 drm_dev_register()。如果组件未就绪就注册设备,用户空间可能在设备节点出现后立即尝试配置显示,导致竞态条件。

1.5 本章小结

DRM 框架是 Linux 显示子系统的核心,它通过 KMS、GEM、Framebuffer 三大组件实现了显示管线的完整管理。KMS 负责显示模式与图层配置,GEM 管理 GPU 与显示内存,Framebuffer 提供像素数据的标准表示。理解这三者的关系与协作方式,是后续学习 MIPI DSI 驱动开发和调试的基础。