1. DRM 子系统概述:架构演进、核心组件与对比
Direct Rendering Manager(DRM)是 Linux 内核中负责图形显示与渲染管理的核心框架。自 Linux 2.4.0 引入以来,DRM 从最初仅支持直接渲染的简单接口,演进为涵盖显示模式设置(KMS)、显存管理(GEM)、多图层合成与色彩管理的完整显示子系统。本章从架构演进、核心组件以及与传统 FBDev 的对比三个维度,帮助开发者建立对 DRM 子系统的全局认知。
1.1 DRM 架构演进:从 DRI 到现代 DRM/KMS
DRM 的演进经历了三个主要阶段,每个阶段都解决了当时图形显示栈的核心痛点:
| 阶段 | 时间 | 核心改进 | 关键驱动 |
|---|---|---|---|
| DRI 时代 | 1999–2004 | 用户态直接访问 GPU,避免内核切换开销 | DRI (Direct Rendering Infrastructure) |
| DRM 独立 | 2004–2012 | 从 DRI 中分离,成为独立内核子系统;引入 GEM 显存管理器 | DRM Core + GEM |
| KMS 成熟 | 2012–至今 | KMS 完全替代 FBDev;原子化 API;多图层合成;色彩管理 | DRM Core + KMS + GEM |
演进关键点: 2012 年 Linux 3.9 内核正式弃用 FBDev 的旧模式设置接口,KMS 成为唯一标准。原子化 API(Atomic Modesetting)在 Linux 4.0 后逐步稳定,为多图层无撕裂合成奠定基础。
1.2 核心组件:DRM Core、KMS、GEM
现代 DRM 子系统由三个核心组件构成,它们分工明确、协同工作:
- DRM Core:提供基础框架,包括设备注册、文件操作接口、ioctl 分发、缓冲区对象抽象、驱动模型。所有 DRM 驱动都基于 DRM Core 实现。
- KMS (Kernel Mode Setting):负责显示模式管理,包括分辨率、刷新率、图层合成、色彩空间、连接器检测。KMS 是显示输出的核心。
- GEM (Graphics Execution Manager):负责显存分配、共享、同步。提供缓冲区对象(BO)、句柄(Handle)、文件描述符(FD)传递机制,是 GPU 与显示引擎之间的数据桥梁。
组件关系: DRM Core 是骨架,KMS 是显示策略层,GEM 是显存管理层。用户态通过 /dev/dri/card0 访问 DRM Core,通过 /dev/dri/card0 的 KMS ioctl 配置显示,通过 GEM 接口分配和共享显存。
1.3 DRM 与 FBDev 的对比
Frame Buffer Device(FBDev)是 Linux 传统的显示框架,在 DRM/KMS 成熟之前被广泛使用。两者在架构设计、功能特性、性能表现上存在显著差异:
| 对比维度 | FBDev | DRM/KMS |
|---|---|---|
| 架构层次 | 单一帧缓冲,所有合成由用户态完成 | 多图层硬件合成,内核态管理显示流水线 |
| 模式设置 | 通过 FBIO 系列 ioctl,不支持原子切换 | KMS 提供完整模式设置,支持原子提交 |
| 多图层 | 不支持硬件图层,需用户态合成 | 支持多个硬件 plane,零拷贝合成 |
| 色彩管理 | 无原生支持,依赖应用层 | 内置 LUT、CTM、HDR 元数据接口 |
| 显存管理 | 固定帧缓冲,不支持 GPU 共享 | GEM/DMA-BUF 实现零拷贝共享 |
| 性能 | 高 CPU 开销,撕裂常见 | 硬件加速,VBlank 同步,无撕裂 |
| 设备节点 | /dev/fb0 | /dev/dri/card0, /dev/dri/renderD128 |
迁移建议: 新开发显示驱动应直接使用 DRM/KMS 框架。FBDev 在 Linux 主线中已被标记为“过时”(Deprecated),部分架构(如 ARM64)已不再支持 FBDev 驱动。DRM/KMS 是未来显示开发的唯一标准。
1.4 DRM 设备模型与用户态接口
DRM 在内核中遵循标准设备驱动模型,通过字符设备暴露给用户态:
- 主设备号 226:所有 DRM 设备共享主设备号,次设备号区分不同功能。
- 设备节点:
/dev/dri/card0:主显示设备,支持 KMS 和 GEM 操作。/dev/dri/controlD64:控制设备,用于显示服务器(如 Wayland)的权限分离。/dev/dri/renderD128:渲染设备,仅支持 GEM 操作,用于 GPU 计算。
- ioctl 接口:用户态通过
drmIoctl()调用,核心 ioctl 包括:DRM_IOCTL_MODE_GETRESOURCES:获取 CRTC、Encoder、Connector、Plane 资源。DRM_IOCTL_MODE_ATOMIC:原子提交模式设置和图层配置。DRM_IOCTL_GEM_OPEN/DRM_IOCTL_GEM_CLOSE:GEM 句柄管理。
// 用户态打开 DRM 设备示例
int fd = open("/dev/dri/card0", O_RDWR | O_CLOEXEC);
if (fd < 0) {
perror("open /dev/dri/card0 failed");
return -1;
}
// 查询资源
struct drm_mode_card_res res = {0};
res.count_fb_ptr = (uint64_t)&res.count_fbs;
// ... 填充其他 count 指针
drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res);
// 分配 GEM 对象
struct drm_gem_create gem_create = {
.size = 1920 * 1080 * 4,
.handle = 0
};
drmIoctl(fd, DRM_IOCTL_GEM_CREATE, &gem_create);
printf("GEM handle: %u\n", gem_create.handle);
开发提示: 用户态通常使用 libdrm 库封装 ioctl 调用,避免直接操作原始 ioctl。libdrm 提供了
drmModeGetResources()、drmModeAtomicCommit() 等高级 API,降低开发难度。
1.5 本章小结
DRM 子系统经过二十余年演进,从 DRI 到现代 DRM/KMS,已成为 Linux 显示领域的基石。其核心组件 DRM Core、KMS、GEM 分别承担框架、显示策略、显存管理的职责,三者协同实现高效、灵活的多图层合成与色彩管理。与 FBDev 相比,DRM/KMS 在架构先进性、功能完备性、性能表现上具有压倒性优势,是当前和未来显示驱动开发的唯一选择。