1. 课程导入

在嵌入式 Linux、桌面 Linux 以及 Android 设备中,屏幕能够点亮、窗口能够流畅合成、视频能够无撕裂播放,背后依赖的并不是某一个单独驱动,而是一整套被称为“显示子系统”的软件与硬件协同体系。对开发者而言,如果只停留在 framebuffer 的认知层面,往往会在多图层合成、分辨率切换、热插拔、页面翻转、垂直同步等问题上陷入困境。本课程围绕 Linux 显示子系统的核心——DRM(Direct Rendering Manager)框架与 KMS(Kernel Mode Setting)组件展开,从架构到初始化流程逐层拆解,帮助你建立完整的显示链路认知。

一、显示子系统到底解决什么问题

显示子系统的本质任务,是把应用或图形库生成的像素数据,经过内存管理、格式转换、图层合成、时序控制,最终稳定地送到显示控制器,并由显示控制器驱动屏幕面板或显示器输出。它需要同时解决四类问题:

  • 缓冲区管理:谁分配显存或系统内存,如何共享、同步与回收。
  • 模式设置:分辨率、刷新率、像素时钟、前后肩、同步极性等时序参数如何确定。
  • 图层合成:多个平面(plane)如何叠加,由 GPU 合成还是由显示控制器硬件合成。
  • 同步与事件:页面翻转、垂直同步、帧完成事件如何通知用户态。

在 Linux 中,这些职责主要由 DRM/KMS 承担。用户态图形栈(如 X11、Wayland 合成器、Android SurfaceFlinger)通过 DRM 接口与内核交互,内核再通过具体显示控制器驱动(如 i915、amdgpu、msm、rockchip、sun4i 等)操作硬件。

二、DRM 与 KMS 在 Linux 图形栈中的位置

理解位置关系比记忆名词更重要。下面这张结构关系图展示了从应用到硬件的典型分层:应用与图形库位于最上层,Wayland/X11/Android 合成器负责窗口与图层策略,libdrm 提供用户态 ioctl 封装,内核 DRM 核心提供统一对象模型,KMS 负责模式设置与显示管线,具体驱动最终操作显示控制器与面板。

Linux 图形栈中的 DRM / KMS 位置 应用 / 图形库 OpenGL ES · Vulkan · EGL · 视频播放器 · 相机预览 显示合成器 / 窗口系统 Wayland Compositor · X11 · Android SurfaceFlinger 用户态 DRM 接口 libdrm · ioctl · dumb buffer · atomic API · GEM handle 内核 DRM 核心 drm_device · drm_file · GEM · 对象管理 · 事件分发 KMS 显示管线 CRTC · Encoder · Connector · Plane · Mode · Atomic State 显示控制器驱动与硬件 i915 · amdgpu · msm · rockchip · sun4i · MIPI DSI · HDMI · Panel 用户态 → 内核态 → 硬件

从图中可以看出,DRM 是内核中承上启下的统一框架,而 KMS 是 DRM 内部专门负责“显示模式设置与显示管线管理”的子系统。用户态并不直接操作寄存器,而是通过 DRM 对象模型间接控制硬件。

三、核心对象模型速览

KMS 把显示管线抽象为若干可枚举、可配置的对象。理解这些对象,是后续初始化流程分析的基础。

对象 职责 典型关注点
CRTC 代表一个显示控制器通道,负责扫描输出与时序生成 mode、fb、位置、gamma、page flip
Encoder 把 CRTC 的像素流转换为连接器可接受的信号 DSI、HDMI、DP、LVDS 编码方式
Connector 代表物理输出接口或面板,负责连接状态检测 connected、modes、EDID、热插拔
Plane 代表一个图层,可叠加到 CRTC 上参与合成 格式、缩放、混合、zpos
Framebuffer 描述一块可扫描输出的像素缓冲区 宽高、像素格式、pitch、GEM 对象

四、一个典型场景:从应用提交到屏幕显示

假设一个 Wayland 合成器需要把桌面画面显示到 MIPI DSI 屏幕上,典型路径如下:

  1. 合成器通过 EGL/GBM 分配图形缓冲区,得到 GEM handle 与 framebuffer ID。
  2. 合成器使用 atomic API 提交一次显示请求,设置 CRTC 的 mode、connector 与 plane 属性。
  3. 内核 DRM 核心校验 atomic state,调用具体驱动的 atomic_check 与 atomic_commit。
  4. 驱动配置显示控制器寄存器,启动扫描输出,并在垂直同步时产生 page flip 事件。
  5. 合成器收到事件后,提交下一帧,形成稳定的帧循环。
# 查看当前 DRM 设备与连接器状态(调试常用)
ls /dev/dri/
cat /sys/class/drm/card0-DSI-1/status
modetest -M msm -c

# 典型输出片段
Connectors:
id  encoder status      name        size (mm)  modes  encoders
42  41      connected   DSI-1       68x121     1      41
  modes:
    index name refresh (Hz) hdisp hss hse htot vdisp vss vse vtot
    0     1080x2340 60 1080 1092 1096 1120 2340 2344 2348 2360
学习建议:不要一开始就陷入寄存器细节。先建立“对象—关系—流程”的三层认知:有哪些对象,它们如何连接,初始化时按什么顺序被创建和注册。这样再看驱动代码时,才能快速定位关键路径。

五、常见误区与复盘

  • 误区一:把 framebuffer 等同于 DRM。framebuffer 只是 DRM 中的一个对象,现代显示还涉及 plane、atomic、fence 等机制。
  • 误区二:认为 KMS 只负责“设置分辨率”。KMS 还管理图层、页面翻转、连接器状态与显示管线资源。
  • 误区三:忽略用户态与内核态的边界。很多显示问题其实出在缓冲区格式、fence 同步或 atomic 提交时机,而非驱动寄存器。
  • 误区四:调试时只看 dmesg。应结合 modetest、sysfs、debugfs 与 DRM trace 综合判断。
本章小结:显示子系统是应用、合成器、DRM/KMS 与显示控制器协同工作的结果。DRM 提供统一对象模型与用户态接口,KMS 负责模式设置与显示管线管理。后续章节将沿着“对象创建—驱动注册—管线初始化—提交与翻转”的主线,逐步深入 DRM 框架与 KMS 组件的初始化过程。