2. Linux图形显示基础
要理解 DRM 与 Wayland 的集成,必须先建立一条完整的“像素从内存到屏幕”的链路认知。Linux 图形栈并不是单一组件,而是由帧缓冲、显示控制器、GPU、KMS、GEM 等多个层次协作构成的系统。本节从最底层的帧缓冲概念出发,逐层向上梳理各组件职责,并回顾 DRM 的历史演进,为后续深入 KMS 与 GEM 打下基础。
一、核心原理:从帧缓冲到显示控制器
帧缓冲(Framebuffer)是一块内存区域,保存了一帧图像中每个像素的颜色值。显示控制器(Display Controller)会周期性地从帧缓冲中读取像素数据,按照扫描顺序输出到显示接口(如 HDMI、DP、MIPI DSI),最终在屏幕上呈现图像。帧缓冲的关键参数包括:
- 分辨率:宽 × 高,例如 1920×1080。
- 像素格式:如 XRGB8888、ARGB8888、NV12,决定每个像素占用的字节数与通道排列。
- stride(行跨距):每行像素在内存中占用的字节数,通常大于“宽度 × 每像素字节数”,用于对齐。
- 修饰符(modifier):描述内存布局,如线性、平铺(tiled)、压缩等,影响 GPU 与显示控制器的读取效率。
显示控制器内部通常包含扫描引擎、图层合成器(Blender)、色彩管理单元和输出编码器。它支持多个图层(Plane)叠加,例如主图层显示桌面、叠加图层显示鼠标光标或视频,从而减少 GPU 的合成负担。
二、GPU 与显示控制器的分工
GPU 负责图形渲染与计算,显示控制器负责扫描输出。两者通过内存中的缓冲区交换数据。典型流程是:GPU 将渲染结果写入缓冲区,然后通过 KMS 将该缓冲区设置为扫描输出源,显示控制器在下一个垂直同步(VBlank)时切换过去,避免画面撕裂。
三、KMS 与 GEM:DRM 的两大子系统
KMS(Kernel Mode Setting)负责显示模式设置与图层管理,核心对象包括:
- CRTC:显示控制器实例,代表一条扫描输出通道。
- Encoder:将 CRTC 的像素流转换为显示接口信号。
- Connector:物理连接器,如 HDMI-A-1,负责探测连接状态与 EDID。
- Plane:图层,用于叠加多个帧缓冲。
- Framebuffer:与具体缓冲区绑定的帧缓冲对象。
GEM(Graphics Execution Manager)负责显存与缓冲区管理,提供缓冲对象的创建、映射、共享和同步机制。GEM 对象可以被 GPU 渲染、被 KMS 扫描输出,也可以导出为 dma-buf 在进程间共享。
# 查看当前 DRM 设备与连接器状态
ls /dev/dri/
cat /sys/class/drm/card0-HDMI-A-1/status
# 输出示例:connected
# 使用 modetest 查看 KMS 资源
modetest -M i915 -c
四、DRM 的历史与演进
在 DRM 出现之前,用户空间通过 FBDEV(framebuffer device)直接操作 /dev/fb0。FBDEV 接口简单,但只支持单图层、无模式设置、无 GPU 同步,无法满足现代合成需求。随着 X11 和 GPU 的发展,内核需要一套统一的图形子系统,DRM 应运而生。
| 阶段 | 代表技术 | 主要能力 | 局限 |
|---|---|---|---|
| 早期 | FBDEV | 直接映射帧缓冲,简单显示 | 无模式设置、无多图层、无 GPU 同步 |
| DRM 初期 | DRM legacy | GPU 命令提交、显存管理 | 模式设置仍在用户态,接口不统一 |
| KMS 引入 | DRM + KMS | 内核态模式设置、多图层、原子提交 | 早期驱动适配复杂 |
| 现代 | Atomic KMS + GEM + dma-buf | 原子提交、跨设备共享、Wayland 原生支持 | 驱动实现门槛高 |
DRM 的演进可以概括为三个阶段:从 FBDEV 的简单帧缓冲,到 DRM legacy 的 GPU 管理,再到 KMS/GEM 的现代显示与内存管理。原子提交(Atomic Commit)的引入,使得多个图层的状态可以在一次系统调用中整体生效,避免了中间状态导致的闪烁。
五、案例场景:一次页面翻转的完整路径
假设一个 Wayland 合成器要显示新一帧画面,典型路径如下:
- 合成器通过 EGL/GLES 调用 GPU 渲染到 GEM 缓冲区。
- 渲染完成后,合成器通过 DRM ioctl 将缓冲区绑定为 Framebuffer。
- 合成器提交 Atomic Commit,设置 CRTC 的扫描输出源为新 Framebuffer。
- 内核在 VBlank 时切换扫描源,显示控制器开始读取新缓冲区。
- 旧缓冲区通过 dma-fence 同步后释放或复用。
六、常见误区与复盘
误区二:认为“GPU 直接驱动屏幕”。GPU 只负责渲染到内存,真正驱动屏幕的是显示控制器。
误区三:忽略 stride 与 modifier。错误的 stride 会导致图像错位,错误的 modifier 会导致显示花屏或性能下降。
复盘建议:调试显示问题时,先确认 Connector 状态,再检查 CRTC 是否绑定正确的 Framebuffer,最后核对像素格式与 stride。使用 modetest、drm_info 等工具可以快速定位问题所在层次。