3. 显示管线与像素格式

在 DRM 显示驱动开发中,显示管线最终要把一块内存中的像素数据,经过格式解释、色彩空间转换、缩放、合成、Gamma/色彩管理,再送入显示控制器扫描输出。像素格式决定了“内存里的二进制如何被解释成颜色”,而显示管线决定了“这些颜色如何被搬运、转换和最终点亮屏幕”。理解 RGB、YUV、色深以及 DRM 中的格式表示,是排查花屏、偏色、绿屏、颜色错位等问题的基本功。

一、核心原理:像素格式是内存与显示控制器之间的契约

一个像素格式至少包含四类信息:颜色模型(RGB 还是 YUV)、分量排列(如 ARGB、BGRA、NV12)、每分量位宽(8bit、10bit、16bit)、采样与存储方式(打包 packed 还是平面 planar,是否半平面 semi-planar)。DRM 用 fourcc 四字符码统一表示这些格式,例如 DRM_FORMAT_XRGB8888、DRM_FORMAT_ARGB8888、DRM_FORMAT_NV12、DRM_FORMAT_P010。

RGB 是显示器的原生驱动空间,每个像素独立存储 R、G、B 分量,适合 UI、文字、合成。YUV 则把亮度 Y 与色度 UV 分离,利用人眼对色度不敏感的特性进行色度下采样,常见 4:4:4、4:2:2、4:2:0。视频解码、摄像头输出通常是 YUV,而显示控制器最终需要 RGB 或经过 CSC 转换后输出。色深则决定每个分量的量化精度:8bit 每通道 256 级,10bit 每通道 1024 级,能显著减少渐变条带。

关键结论:像素格式不是“颜色本身”,而是“内存布局 + 颜色模型 + 位宽 + 采样方式”的组合契约。驱动、GPU、显示控制器、应用必须对同一个 fourcc 达成一致,否则就会出现颜色通道错位或花屏。

二、DRM 中的表示:fourcc、modifier 与 plane 属性

在 DRM 中,格式通过 drm_fourcc.h 定义,驱动在 drm_plane 的 format_types 中声明支持的格式。用户态通过 DRM_IOCTL_MODE_ADDFB2 或 ATOMIC 提交 framebuffer,其中包含 pixel_format、width、height、pitches、offsets、modifier。modifier 用于描述平铺、压缩等内存布局,例如 DRM_FORMAT_MOD_LINEAR 或厂商私有压缩格式。

struct drm_mode_fb_cmd2 {
    __u32 fb_id;
    __u32 width;
    __u32 height;
    __u32 pixel_format;   /* DRM_FORMAT_* */
    __u32 flags;
    __u32 handles[4];
    __u32 pitches[4];
    __u32 offsets[4];
    __u64 modifier[4];
};

对于 NV12,通常有 2 个 plane:Y 平面和交错 UV 平面;对于 P010,则是 10bit 存储在 16bit 容器中。驱动需要根据 fourcc 计算 pitch、offset 和 plane 数量,并配置显示控制器的 CSC、DMA 和格式转换单元。

三、转换流程:从应用缓冲到屏幕像素

典型转换链路如下:应用或视频解码器产生 YUV 缓冲,GPU 或显示控制器进行 CSC 转 RGB,合成器进行 alpha 混合,色彩管理模块做 Gamma/3D LUT,最后输出到面板。若显示控制器不支持某格式,驱动可能通过 GPU 做中间转换,或让用户态选择支持的格式。

DRM 显示管线:像素格式表示与转换 应用/解码器 NV12 / P010 / ARGB DRM Framebuffer fourcc + modifier Plane / CSC YUV → RGB 合成 / 色彩管理 Alpha / Gamma / LUT 面板 RGB 格式关键属性对照 RGB:XRGB8888 / ARGB8888 / ABGR2101010,每像素打包,适合 UI 与合成 YUV:NV12(4:2:0 半平面)、YUYV(4:2:2 打包)、P010(10bit 半平面) 色深:8bit 易条带,10bit 需 P010/RGB10,注意 pitch 与对齐 转换:CSC 矩阵、有限/全范围、Gamma 与色彩管理链路必须匹配

四、案例与场景:NV12 视频叠加 UI 的典型问题

假设一个播放器用 NV12 输出视频,UI 用 ARGB8888。合成器把两个 plane 交给显示控制器:视频 plane 配置 NV12,UI plane 配置 ARGB8888。若驱动把 NV12 的 UV 平面 offset 算错,画面会出现绿色或紫色;若 CSC 矩阵把有限范围当成全范围,黑色会发灰;若 10bit P010 被当成 8bit 解释,亮度会整体偏移。

排查时可按以下清单逐项核对:

  • 确认 pixel_format 与用户态实际填充一致,特别是 XRGB 与 ARGB 的 alpha 语义。
  • 检查 pitches 与 offsets 是否按 plane 正确计算,NV12 的 UV offset 通常等于 Y pitch × height。
  • 确认 CSC 的输入范围:视频通常 limited range,UI 通常 full range。
  • 确认色深与容器:P010 是 10bit 有效位存在 16bit 容器中,不能按 8bit 读取。
  • 用 modetest 或 kmscube 验证格式支持列表与 modifier。
# 查看 plane 支持的格式
modetest -M rockchip -p
# 典型输出片段
Planes:
  id  format  modifier
  35  XRGB8888  LINEAR
  35  ARGB8888  LINEAR
  35  NV12      LINEAR
  35  P010      LINEAR

五、误区与复盘

常见误区一:认为“支持 NV12”就等于支持所有 YUV 格式。实际上 4:2:0、4:2:2、4:4:4 的采样和内存布局完全不同,驱动必须逐项声明。误区二:忽略 modifier,把压缩平铺缓冲当线性缓冲读取,导致花屏。误区三:只改 fourcc 不改 CSC 和范围,导致偏色。误区四:10bit 只改格式不改带宽与时钟,导致欠载闪烁。

复盘时建议建立“格式—plane—CSC—范围—色深”五维检查表,把每次花屏、偏色、条带问题都归因到具体维度。只有把像素格式当作显示管线中的一等公民,才能在 DRM 驱动开发中稳定地支撑视频、UI、游戏和色彩管理等多种场景。