1. 课程导入
在嵌入式Linux设备中,“把画面显示出来”看似是一件理所当然的事情,但在这背后,内核需要完成显存管理、图层合成、时序控制、背光调节、格式转换等一系列复杂工作。早期方案以 FBDEV(Framebuffer Device) 为主,它用一块线性帧缓冲描述屏幕,简单直接;而现代方案则普遍转向 DRM/KMS(Direct Rendering Manager / Kernel Mode Setting),用更结构化的对象模型管理显示管线。理解这两者的定位差异,是后续驱动移植工作的起点。
一、显示子系统的演进脉络
嵌入式Linux显示子系统大致经历了三个阶段。第一阶段是裸帧缓冲阶段,应用直接操作 /dev/fb0,通过 mmap 映射显存后写入像素数据,内核只负责把这块内存扫描输出到屏幕。第二阶段是FBDEV 多图层扩展阶段,部分 SoC 厂商在 FBDEV 框架上增加 ioctl 来支持硬件叠加层(Overlay)、YUV 图层和色彩键,但这些扩展缺乏统一标准,移植性差。第三阶段是DRM/KMS 统一阶段,内核用 CRTC、Encoder、Connector、Plane 等抽象描述显示硬件,用户态通过 libdrm 或 Wayland 合成器统一管理,支持原子提交、多平面合成和动态模式设置。
这一演进并非单纯“新替代旧”,而是显示需求从“能显示”走向“高效、可组合、可扩展”的必然结果。尤其在多屏、高分辨率、视频播放和 GPU 合成场景下,FBDEV 的线性模型逐渐力不从心。
二、FBDEV 与 DRM/KMS 的核心差异
从驱动开发者视角看,两者最本质的差异在于抽象层次。FBDEV 把显示硬件抽象成“一块可写的帧缓冲”,驱动只需实现 fb_ops 中的 fb_fillrect、fb_copyarea、fb_imageblit 等回调,以及 fb_check_var、fb_set_par 等模式设置接口。而 DRM/KMS 把显示硬件拆解为多个可独立配置的对象,驱动需要分别实现 Plane、CRTC、Encoder、Connector 的初始化与状态提交。
下表从多个维度对比两者的定位差异,便于在移植前建立整体判断。
| 对比维度 | FBDEV | DRM/KMS |
|---|---|---|
| 核心抽象 | 单块线性帧缓冲 | Plane / CRTC / Encoder / Connector |
| 用户态接口 | /dev/fbX + ioctl + mmap | /dev/dri/cardX + libdrm / atomic ioctl |
| 多图层支持 | 厂商私有扩展,不统一 | Plane 原生支持,可叠加合成 |
| 模式设置 | fb_set_par,粒度粗 | Atomic Commit,状态一致 |
| 与 GPU 协同 | 弱,通常各管各的 | 强,GEM/DMA-BUF 共享缓冲 |
| 典型场景 | 简单 UI、低分辨率、老平台 | 多屏、视频、Wayland、现代 SoC |
三、一个典型场景:从 FBDEV 到 DRM 的切换动因
假设你在一款 i.MX6 平台上维护旧产品,系统使用 FBDEV 显示 Qt 界面,运行稳定。现在产品升级到 i.MX8,需要支持双屏异显、视频播放和 GPU 合成。此时若继续沿用 FBDEV,会遇到几个硬伤:双屏需要两套独立帧缓冲和私有 ioctl;视频图层无法与 UI 图层统一合成;GPU 渲染结果难以直接送入显示管线。而 DRM/KMS 天然支持多 CRTC、多 Plane 和 DMA-BUF 共享,能够把 GPU、VPU 和显示控制器串联成一条完整管线。
四、常见误区与复盘
- 误区一:DRM 只是“更复杂的 FBDEV”。实际上 DRM 的对象模型和提交机制与 FBDEV 有本质区别,不能简单套用 fb_ops 的思路。
- 误区二:移植就是改设备树。设备树只描述硬件连接,驱动中的 CRTC/Plane 初始化、时钟、电源域、桥接芯片配置都需要逐一适配。
- 误区三:用户态不用改。从 /dev/fb0 切换到 /dev/dri/card0,Qt、SDL、GStreamer 的显示后端都需要重新配置或替换。
- 误区四:忽略原子提交的异步性。DRM 的 atomic commit 是异步生效的,调试时要关注 flip 完成事件和 fence,而不是写完寄存器就认为已经生效。
五、本课程整体框架与学习目标
本课程围绕“从 FBDEV 到 KMS 切换”这一主线展开,整体分为四个部分。第一部分是基础认知,包括显示子系统演进、FBDEV 与 DRM/KMS 定位差异、DRM 对象模型与数据流。第二部分是驱动移植实操,涵盖设备树配置、CRTC/Encoder/Connector 驱动适配、Plane 与格式协商、时钟与电源管理。第三部分是用户态切换,包括 libdrm 编程、Qt/SDL 显示后端替换、Wayland 合成器对接。第四部分是调试与优化,涉及 dmesg 日志分析、modetest 验证、性能调优和常见故障排查。
完成本课程后,你应该能够:读懂一个 SoC 的 DRM 驱动结构;根据硬件手册完成显示管线适配;把原有 FBDEV 应用迁移到 DRM/KMS;并使用标准工具验证显示状态和排查问题。
# 后续章节会反复用到的验证命令示例
modetest -M imx-drm -c # 查看 Connector 状态
modetest -M imx-drm -p # 查看 CRTC 与 Plane 能力
cat /sys/kernel/debug/dri/0/state # 查看当前原子状态
dmesg | grep -i drm # 查看 DRM 驱动初始化日志
显示子系统的切换不是一次简单的 API 替换,而是从“写显存”到“管理管线”的思维转变。理解 FBDEV 与 DRM/KMS 各自的定位,明确移植的动因与边界,才能在实际项目中做出合理的技术选型,并为后续的驱动适配和用户态迁移打下坚实基础。