1. DRM 框架概述

Direct Rendering Manager (DRM) 是 Linux 内核中负责图形显示与渲染的核心子系统。它向上为用户态图形栈(如 Mesa、Wayland、Xorg)提供标准接口,向下抽象 GPU、Display Controller、Encoder、Connector 等硬件资源。理解 DRM 在 Linux 图形栈中的位置及其与 FBDEV、V4L2 的区别,是掌握整个显示子系统的第一步。

1.1 DRM 在 Linux 图形栈中的位置

Linux 图形栈从应用层到内核层通常分为四层:应用/合成器、用户态图形库、内核显示驱动、硬件。DRM 位于内核层,是连接用户态与硬件的桥梁。

关键角色: DRM 是 Linux 图形栈中唯一直接操作 GPU 和显示控制器的内核接口。所有现代显示方案(Wayland、Xorg)最终都通过 DRM 提交帧缓冲和配置显示模式。
Linux 图形栈分层架构 应用层 GUI 应用 · 游戏 · 视频播放器 · 合成器 (Weston / Mutter / KWin) 用户态图形库层 Mesa (OpenGL/Vulkan) · libdrm · Wayland 协议 · Xorg DDX 内核层 — DRM 子系统 DRM Core · KMS (显示模式设置) · GEM (图形内存管理) GPU 驱动 · Display Controller 驱动 · Encoder/Connector 驱动 硬件层 GPU · Display Controller · HDMI/DP Encoder · Panel Connector DRM 是内核中唯一直接管理显示硬件和 GPU 内存的子系统,用户态通过 /dev/dri/card0 节点访问

1.2 DRM 与 FBDEV / V4L2 的区别

Linux 内核中存在多个与显示/图像相关的子系统,初学者容易混淆。下表从核心定位、功能范围、应用场景三个维度进行对比。

对比维度 DRM (Direct Rendering Manager) FBDEV (Frame Buffer Device) V4L2 (Video for Linux 2)
核心定位 现代 GPU 显示与渲染管理 简单帧缓冲输出 视频采集与输出
显示模式设置 支持 (KMS 核心功能) 有限 (通过 FBIO 扩展) 不支持
GPU 加速 原生支持 (GEM/Dumb Buffer) 不支持 不支持
多平面合成 支持 (Overlay/Cursor 平面) 不支持 不支持
视频采集 不支持 不支持 核心功能
典型设备节点 /dev/dri/card0, /dev/dri/renderD128 /dev/fb0 /dev/video0
现代桌面环境 Wayland/Xorg 标准后端 仅用于早期或嵌入式系统 摄像头、电视卡
学习建议: 如果你正在开发现代 Linux 桌面或嵌入式显示系统,请直接学习 DRM/KMS。FBDEV 已被标记为“遗留”接口,新硬件不再推荐使用。V4L2 与 DRM 在视频回放场景中常配合使用(V4L2 采集 → DRM 显示),但两者职责完全不同。

1.3 DRM 核心组件介绍

DRM 子系统由三个核心组件构成:DRM Core(基础框架)、KMS(显示模式设置)、GEM(图形内存管理)。三者协同工作,为上层提供完整的显示服务。

1.3.1 DRM Core — 基础框架

DRM Core 是 DRM 子系统的骨架,负责设备注册、文件操作接口、IOCTL 分发、驱动模型抽象。它定义了 struct drm_driver、struct drm_device、struct drm_file 等核心数据结构,并管理用户态与内核态的交互通道。

// DRM Core 核心数据结构关系(简化)
struct drm_driver {
    const struct file_operations *fops;
    int (*load)(struct drm_device *, unsigned long flags);
    void (*unload)(struct drm_device *);
    // ... 驱动回调函数
};

struct drm_device {
    struct drm_driver *driver;
    struct drm_minor *primary;   // /dev/dri/card0
    struct drm_minor *render;    // /dev/dri/renderD128
    struct drm_mode_config mode_config; // KMS 配置
    // ... 设备状态
};

1.3.2 KMS (Kernel Mode Setting) — 显示模式设置

KMS 是 DRM 中负责显示输出管理的组件。它抽象了显示管线中的硬件单元:CRTC(显示控制器)、Encoder(编码器)、Connector(连接器)、Plane(平面)。KMS 提供原子模式设置(Atomic Modeset)接口,允许用户态在一次原子提交中同时更新多个显示参数,避免撕裂和闪烁。

KMS 显示管线核心组件 Plane (平面) 帧缓冲 + 合成参数 CRTC (控制器) 扫描输出 + 时序生成 Encoder (编码器) 信号编码 (TMDS/DP) Connector (连接器) 物理接口 (HDMI/DP) 一个 CRTC 可以绑定多个 Plane(主平面 + 光标平面 + Overlay 平面),实现硬件合成 原子提交 (Atomic Commit) 确保所有平面更新在同一 VBlank 周期生效 KMS 对象连接关系 • Plane → CRTC:将帧缓冲内容输出到指定 CRTC • CRTC → Encoder:CRTC 生成的像素流送入 Encoder 编码 • Encoder → Connector:编码后的信号通过物理接口发送到显示器

1.3.3 GEM (Graphics Execution Manager) — 图形内存管理

GEM 是 DRM 中负责 GPU 内存分配与管理的组件。它提供统一的 API 来分配、映射、共享 GPU 缓冲区。GEM 的核心概念包括:

  • GEM Object:内核中表示一块 GPU 内存的基本单位,每个对象有唯一的 handle。
  • Handle:用户态通过 handle 引用 GEM Object,handle 是 per-file 的。
  • Flink (GEM Global Name):将 GEM Object 导出为全局名称,用于跨进程共享。
  • DMA-BUF:现代 DRM 中推荐的缓冲区共享机制,支持跨设备(GPU ↔ VPU ↔ Display)共享。
  • Dumb Buffer:用于非 GPU 加速场景的简单帧缓冲,CPU 可直接访问。
// GEM 核心操作示例(用户态通过 libdrm 调用)
// 分配 GEM Object
uint32_t handle;
struct drm_mode_create_dumb create = {
    .width = 1920,
    .height = 1080,
    .bpp = 32,
};
ioctl(fd, DRM_IOCTL_MODE_CREATE_DUMB, &create);
handle = create.handle;

// 映射 GEM Object 到用户态地址空间
struct drm_mode_map_dumb map = {
    .handle = handle,
};
ioctl(fd, DRM_IOCTL_MODE_MAP_DUMB, &map);
void *addr = mmap(NULL, create.size, PROT_READ | PROT_WRITE,
                  MAP_SHARED, fd, map.offset);

// 将 GEM Object 提交为帧缓冲
uint32_t fb_id;
drmModeAddFB(fd, 1920, 1080, 24, 32, create.pitch, handle, &fb_id);
注意事项: GEM 是一个框架性接口,具体的内存分配策略(如 TTM、CMA、SHMEM)由底层 GPU 驱动实现。在嵌入式设备中,通常使用 CMA(Contiguous Memory Allocator)来分配连续物理内存;在独立 GPU 上,则使用 TTM(Translation Table Manager)管理显存。

1.4 本章小结

DRM 是 Linux 内核显示子系统的核心,它通过 DRM Core、KMS、GEM 三个组件分别管理设备框架、显示输出和 GPU 内存。与 FBDEV 相比,DRM 支持 GPU 加速、多平面合成和原子模式设置;与 V4L2 相比,DRM 专注于显示输出而非视频采集。掌握 DRM 在图形栈中的位置及其核心组件,为后续深入学习 KMS 原子接口、GEM 缓冲区共享、驱动开发等内容打下坚实基础。