1. DRM 子系统概述:DRM 架构、GEM 与 KMS 核心组件、显示驱动栈全景图
DRM(Direct Rendering Manager)是 Linux 内核中负责图形显示与渲染管理的核心子系统。它向上为用户空间提供统一的显示与渲染接口,向下抽象了 GPU、Display Controller、Encoder、Connector 等硬件差异。理解 DRM 的架构分层、GEM/KMS 两大核心组件以及完整的显示驱动栈,是进行 drm_info 解析与性能调优的基础。
关键认知: DRM 并非一个单一的驱动,而是一个框架。它通过
drm_device 管理显示状态,通过 GEM 管理显存,通过 KMS 管理显示模式与合成。调试时,drm_info 输出的所有信息都源自这三个核心模块的数据结构。
1.1 DRM 架构分层
DRM 子系统在内核中分为三层:
- DRM Core(核心层): 提供设备注册、文件操作、ioctl 分发、缓冲区管理(GEM)和模式设置(KMS)的通用框架。所有 DRM 驱动都基于此层。
- DRM Helper(辅助层): 提供通用实现,如
drm_fb_helper(帧缓冲模拟)、drm_atomic_helper(原子提交辅助函数)、drm_bridge(桥接芯片驱动框架)。 - Driver Layer(驱动层): 具体硬件厂商的实现,如
i915(Intel)、amdgpu(AMD)、msm(Qualcomm)、panfrost(Arm Mali)等。驱动层填充drm_driver结构体中的回调函数。
1.2 GEM 核心组件
GEM(Graphics Execution Manager)是 DRM 的显存管理框架,负责分配、映射、共享 GPU 缓冲区。drm_info 中关于 buffer objects、handles、size 的信息均来自 GEM 层。
| GEM 概念 | 内核数据结构 | 说明 |
|---|---|---|
| GEM Object | struct drm_gem_object |
代表一个显存缓冲区,包含 size、handle count、dma_buf 等字段。 |
| GEM Handle | u32 (用户空间句柄) |
用户空间通过 handle 引用 GEM Object,每个进程有独立的 handle 空间。 |
| GEM VMA | struct drm_vma_offset_node |
管理 GEM Object 在进程地址空间中的映射。 |
| DMA-BUF | struct dma_buf |
用于跨设备、跨驱动共享 GEM 缓冲区,如 GPU 与 Display Controller 共享。 |
| GEM Prime | 扩展接口 | 提供 drm_gem_prime_export / drm_gem_prime_import 实现 DMA-BUF 导出导入。 |
调试提示: 使用
drm_info 查看 GEM Objects 列表时,关注 size 和 handle count。如果某个 BO 的 handle count 异常高,可能存在用户空间未关闭 handle 导致的内存泄漏。
1.3 KMS 核心组件
KMS(Kernel Mode Setting)是 DRM 中负责显示模式设置、合成和输出的框架。drm_info 中关于 CRTC、Encoder、Connector、Plane 的信息全部来自 KMS 组件。
| KMS 组件 | 内核结构体 | 功能描述 |
|---|---|---|
| CRTC | struct drm_crtc |
代表显示控制器,负责扫描输出、生成时序信号。一个 CRTC 对应一个显示管道。 |
| Encoder | struct drm_encoder |
将 CRTC 输出的像素数据编码为特定接口信号(如 HDMI、DP、LVDS)。 |
| Connector | struct drm_connector |
代表物理显示接口(HDMI 端口、DP 端口、eDP 面板),检测显示器热插拔与 EDID。 |
| Plane | struct drm_plane |
代表硬件图层(Overlay/Primary/Cursor),支持独立缩放、色彩转换和合成。 |
| Bridge | struct drm_bridge |
代表外部桥接芯片(如 HDMI 转 DP、MIPI 桥接),用于扩展显示输出路径。 |
常见误区: CRTC 不是指显示器刷新率,而是指显示控制器的扫描输出管道。一个 CRTC 可以连接多个 Encoder,但同一时刻只能激活一条显示链路。drm_info 中
crtc 的 mode 字段显示的是当前激活的显示时序。
1.4 显示驱动栈全景图
从用户空间应用程序到最终显示像素,完整的显示驱动栈涉及多个层次。理解每一层的职责和交互接口,有助于在调试时快速定位问题发生在哪个环节。
- 应用程序层: 使用 Wayland/Weston、Xorg、Android HWC 或直接调用 libdrm 的 ioctl。
- 用户空间库: libdrm 封装内核 ioctl,Mesa 提供 OpenGL/Vulkan 渲染,Wayland 合成器管理显示合成。
- 系统调用层: 通过
drm_ioctl进入内核,分发到 DRM Core 的处理函数。 - DRM Core: 解析 ioctl 命令,调用 GEM 或 KMS 框架的通用实现。
- DRM Helper: 提供原子提交、帧缓冲模拟、桥接管理等辅助功能。
- 驱动层: 硬件厂商驱动实现具体的寄存器操作、中断处理、DMA 传输。
- 硬件层: GPU 渲染、Display Controller 扫描、Encoder 编码、Connector 输出到显示器。
1.5 原子提交与性能计数器
现代 DRM 驱动使用 Atomic Mode Setting(原子模式设置)来管理显示状态更新。原子提交允许在一个事务中同时更新多个 KMS 对象(CRTC、Plane、Connector),避免中间状态导致的闪烁或撕裂。
性能计数器(Performance Counters)是 drm_info 调试的重要输出,通常包括:
- vblank 计数: 垂直消隐中断次数,用于衡量显示刷新周期。
- page flip 计数: 缓冲区交换次数,反映合成器或游戏的帧率。
- atomic commit 计数: 原子提交成功/失败次数,用于诊断显示配置变更问题。
- GPU 引擎占用: 渲染引擎、拷贝引擎、视频编解码引擎的利用率。
调试实战: 使用
drm_info 的 -p 或 --properties 参数可以查看每个 KMS 对象的属性值,包括 CRTC_ACTIVE、mode、FB_ID 等。结合 perf 工具统计 vblank 中断频率,可以快速判断显示输出是否稳定。