2. 显示基础
在把嵌入式 Linux 显示驱动从 FBDEV 迁移到 DRM/KMS 之前,必须先建立一套“显示链路”的底层认知。DRM 并不是凭空出现的抽象层,它只是把传统显示控制器中本来就存在的像素格式、时序、显存、扫描输出等概念,用更规范的对象模型重新组织了一遍。理解这些基础概念,后续看 drm_mode、drm_framebuffer、drm_crtc 等结构体时才不会觉得突兀。
一、像素格式:显存里每个像素如何被解释
像素格式(Pixel Format / DRM_FORMAT_*)描述的是“显存中的一段二进制数据,如何被解释成颜色”。它至少包含三个维度:颜色分量排列顺序、每个分量的位宽、以及是否带 Alpha 通道。例如 DRM_FORMAT_XRGB8888 表示每像素 32 位,其中 R/G/B 各 8 位,高 8 位忽略;DRM_FORMAT_ARGB8888 则把高 8 位用作 Alpha。
嵌入式平台常见的格式还有 RGB565(16bpp,适合低带宽屏)、YUV420 系列(视频层常用,带色度抽样)、以及带预乘 Alpha 的 ARGB8888。像素格式选错,最直观的现象就是颜色偏色、红蓝互换或整屏发绿,而不是“黑屏”。
pixel_format 与显示控制器输出格式是否一致,再检查是否发生了 RGB/BGR 字节序交换。二、分辨率、刷新率与显存带宽
分辨率指一帧图像的有效像素行列数,如 1920×1080。刷新率(Refresh Rate)指显示控制器每秒向屏幕输出完整帧的次数,单位 Hz。二者与像素格式共同决定了扫描输出所需的显存带宽:
带宽 ≈ 水平总像素 × 垂直总行数 × 刷新率 × 每像素字节数
例:1920×1080@60Hz,ARGB8888(4B/px)
有效像素带宽 = 1920 × 1080 × 60 × 4 ≈ 497 MB/s
若含消隐区(2200×1125),则 ≈ 594 MB/s
注意公式里用的是“总像素”而非“有效像素”,因为消隐区同样要占用扫描时间。嵌入式 SoC 的显示控制器、DDR 控制器和总线带宽有限,高分辨率 + 高刷新率 + 多图层叠加时,带宽很容易成为瓶颈,表现为撕裂、闪烁或掉帧。
三、时序参数:让屏幕“对上拍”
并行 RGB、MIPI DSI、LVDS 等接口都依赖一套时序参数来同步扫描。核心参数包括:
- Hactive / Vactive:有效显示区域的行像素数与行数。
- HFP / HBP / HSYNC:水平前肩、后肩、同步脉冲宽度。
- VFP / VBP / VSYNC:垂直前肩、后肩、同步脉冲宽度。
- Pixel Clock:像素时钟频率,决定每个像素的输出节奏。
这些参数通常来自屏幕数据手册(Datasheet)的 Timing Table。DRM 中用 struct drm_display_mode 描述,字段名如 hdisplay、hsync_start、hsync_end、htotal 等。时序不匹配时,屏幕可能黑屏、偏移、抖动或出现彩色条纹。
四、显存、扫描输出与 DRM 对象映射
显存(Framebuffer)是扫描输出的数据源。传统 FBDEV 用 /dev/fb0 暴露一块连续显存,应用直接 mmap 后写像素;而 DRM/KMS 把显存抽象为 drm_framebuffer,并引入 GEM/DMA-BUF 来管理缓冲区生命周期。扫描输出(Scanout)则是 CRTC 按当前 mode 从 framebuffer 中逐行读取并送往编码器/连接器的过程。
在 DRM 中,这条链路被拆成清晰的对象:
| 概念 | DRM 对象 | 职责 |
|---|---|---|
| 显存缓冲 | drm_framebuffer + GEM object |
存放像素数据,描述格式、宽高、stride、修饰符 |
| 扫描控制器 | drm_crtc |
按 mode 读取 framebuffer,产生时序信号 |
| 显示模式 | drm_display_mode |
分辨率、刷新率、H/V 前后肩与同步宽度 |
| 图层 | drm_plane |
把 framebuffer 叠加、缩放、裁剪后送入 CRTC |
| 物理接口 | drm_encoder + drm_connector |
把并行信号转换为 MIPI/LVDS/HDMI 并连接面板 |
五、案例:一次“颜色发绿”的排查
某嵌入式板卡从 FBDEV 切到 DRM 后,屏幕能亮但整体偏绿。排查步骤如下:
- 用
modetest -M xxx -p查看当前 CRTC 绑定的 framebuffer 格式,发现是DRM_FORMAT_RGB565。 - 检查应用侧写入的像素格式,实际按
ARGB8888填充,导致高低字节错位。 - 确认显示控制器输出格式寄存器配置为 RGB565,与 framebuffer 一致。
- 修正应用侧格式或改用
DRM_FORMAT_XRGB8888,颜色恢复正常。
六、常见误区与复盘
- 只看有效分辨率,忽略消隐区:带宽和 Pixel Clock 计算必须用 Htotal/Vtotal,否则会低估负载。
- 把刷新率当成“应用帧率”:刷新率是扫描输出的固定节奏,应用帧率受 VSYNC 和合成能力约束。
- 认为 stride 等于 width×bpp:很多控制器要求行对齐,stride 可能大于理论值,必须按驱动返回的 pitch 使用。
- 忽略显存对齐与缓存一致性:DMA 扫描输出要求物理连续或 IOMMU 映射,CPU 写入后需正确 flush/sync。
把像素格式、分辨率、刷新率、时序参数、显存与扫描输出这六个概念串成一条链路,就得到了 DRM/KMS 的“物理底座”。后续配置 drm_mode、提交 atomic commit、调试 panel 时序时,所有问题几乎都能回溯到这条链路上的某一环。