2. DRM与CRTC基础

在Linux显示子系统中,DRM(Direct Rendering Manager)是内核态管理显示控制器、显存与渲染任务的核心框架。要理解gamma校正与色彩管理为何必须落在CRTC层,首先需要建立对DRM整体架构、CRTC职责以及显示管线数据流的清晰认知。本节从对象模型出发,逐步展开到像素从帧缓冲到屏幕的完整路径。

一、DRM架构:对象模型与职责分层

DRM并非单一模块,而是一组按职责划分的内核对象集合。用户空间通过libdrm或内核ioctl与这些对象交互,内核驱动则负责将抽象对象映射到具体硬件寄存器。核心对象包括:

  • DRM Device:代表一个显示设备节点(如/dev/dri/card0),承载全局能力与资源管理。
  • Framebuffer(FB):描述一块可被扫描输出的像素缓冲区,包含格式、宽高、pitch与GEM handle。
  • Plane:图层抽象,负责从FB取像素并叠加、缩放、旋转后送入CRTC。分为Primary、Overlay、Cursor三类。
  • CRTC:显示控制器通道,负责时序生成、扫描输出与后处理(gamma、色彩变换等)。
  • Encoder:将CRTC的像素流转换为特定接口信号(HDMI、DP、DSI、eDP等)。
  • Connector:物理输出接口,管理连接状态、EDID与支持的显示模式。

这些对象通过“possible_crtcs”“possible_clones”等位图建立约束关系,形成一张有向的资源拓扑图。驱动在初始化阶段注册对象,用户空间通过Atomic或Legacy API提交配置。

DRM显示管线:从Framebuffer到Connector 用户空间 libdrm / Atomic API DRM Core 对象管理 / 模式设置 显示驱动 寄存器 / 时序 / 后处理 显示硬件 CRTC / Encoder / PHY DRM对象流水线 Framebuffer 像素缓冲 / 格式 GEM handle Plane 叠加 / 缩放 旋转 / 裁剪 CRTC 时序生成 / 扫描输出 Gamma / 色彩变换 背景色 / 模式 Encoder HDMI / DP / DSI 信号编码 Connector EDID / 状态 热插拔 Gamma LUT CRTC后处理阶段 像素数据流:FB → Plane → CRTC → Encoder → Connector → 屏幕 Atomic Commit:一次性校验并提交整条管线配置

二、CRTC的作用:不只是“扫描输出”

CRTC(Cathode Ray Tube Controller)名称源于CRT时代,但在现代DRM中它已演化为一个通用的显示控制器通道。其核心职责可归纳为四类:

  1. 时序生成:根据mode信息产生HSYNC、VSYNC、DE等时序信号,控制像素扫描节奏。
  2. 图层合成:将多个Plane的像素按Z-order、Alpha、Blending规则合成为最终输出画面。
  3. 后处理:在像素输出前执行gamma校正、色彩空间转换、抖动等操作。这是gamma LUT的挂载点。
  4. 状态管理:维护active、mode、gamma_lut、ctm等属性,支持Atomic提交与回滚。

一个DRM设备可能包含多个CRTC,每个CRTC可独立驱动一个显示通道。例如双屏异显场景中,CRTC0驱动eDP,CRTC1驱动HDMI。gamma校正配置必须明确指定目标CRTC,否则会作用到错误的显示通道。

关键理解:CRTC是gamma校正的“执行单元”。Plane负责取像素,Encoder负责编码信号,而gamma LUT位于CRTC的后处理阶段,直接修改即将扫描输出的像素值。

三、显示管线概述:像素的完整旅程

从应用提交画面到屏幕发光,像素经历了一条严格的流水线。以Atomic模式为例:

用户空间:
  drmModeAtomicAddProperty(req, crtc_id, "GAMMA_LUT", blob_id)
  drmModeAtomicCommit(fd, req, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL)

内核DRM Core:
  1. 校验属性合法性(blob大小、LUT点数、CRTC状态)
  2. 调用驱动 atomic_check 回调
  3. 驱动计算硬件寄存器值,检查时序冲突
  4. atomic_commit 提交,更新CRTC状态
  5. 在vblank期间切换gamma LUT,避免撕裂

硬件执行:
  Plane取像素 → 合成 → CRTC后处理(gamma LUT查表)→ Encoder编码 → PHY发送 → 屏幕

这条管线中有两个关键同步点:一是Atomic Commit的“全有或全无”语义,保证配置一致性;二是vblank同步,确保gamma切换发生在消隐期,避免画面闪烁。

四、案例与场景:双屏异显下的gamma配置

假设一台设备同时连接eDP内置屏与HDMI外接屏,两块屏幕的gamma特性不同。工程师需要分别配置:

对象 eDP通道 HDMI通道 说明
CRTC CRTC0 CRTC1 独立控制器
Connector eDP-1 HDMI-A-1 物理接口
Gamma LUT sRGB曲线 BT.709曲线 不同色彩空间
LUT点数 256 1024 硬件能力差异
提交方式 Atomic Atomic 统一API

若错误地将HDMI的gamma LUT提交到CRTC0,eDP画面会偏色,而HDMI无变化。排障时应先通过drmModeGetCrtc确认CRTC与Connector的绑定关系,再检查Atomic请求中的crtc_id字段。

常见误区:认为gamma校正属于Plane或Connector。实际上,Plane的color management属性(如COLOR_ENCODING、COLOR_RANGE)影响的是输入像素的解释方式,而gamma LUT位于CRTC输出级,两者层级不同,不可混淆。

五、复盘:建立对象与数据流的双重认知

掌握DRM与CRTC基础,需要同时建立两套认知:

  • 对象关系认知:FB→Plane→CRTC→Encoder→Connector的绑定与约束,理解possible_crtcs位图的意义。
  • 数据流认知:像素从内存到屏幕的路径,明确gamma LUT在CRTC后处理阶段的位置。

后续配置gamma校正时,所有操作都将围绕CRTC对象展开:获取CRTC能力、构造LUT blob、通过Atomic提交、在vblank中生效。只有先厘清架构与管线,才能避免“配置了但没效果”或“配错通道”的典型问题。