4. CRTC 与 Plane 模型:时序生成、图层叠加与硬件差异

CRTC(Cathode Ray Tube Controller)与 Plane(图层)是 DRM/KMS 框架中负责显示时序生成与像素数据合成的核心硬件抽象层。CRTC 控制扫描时序与刷新率,Plane 管理图层叠加与透明度混合。理解两者的协作模型是进行帧率配置与显示性能调优的基础。

核心概念速览: CRTC 决定“何时”将像素数据发送到显示器;Plane 决定“哪些”像素数据被发送,以及它们如何叠加。

4.1 CRTC 时序生成模型

CRTC 模拟传统 CRT 显示器的扫描过程,生成精确的像素时钟、水平同步(HSync)、垂直同步(VSync)以及消隐区间(Blanking)。这些时序参数共同决定了显示器的刷新率与分辨率。

4.1.1 时序参数与帧率计算

帧率(刷新率)由以下公式计算:

Pixel Clock (MHz) = Horizontal Total (pixels) × Vertical Total (lines) × Refresh Rate (Hz)

Refresh Rate = Pixel Clock / (HTOTAL × VTOTAL)

其中 HTOTAL = HActive + HFrontPorch + HSyncWidth + HBackPorch,VTOTAL 同理。

参数 说明 典型值(1920×1080@60Hz)
Pixel Clock 像素时钟频率 148.5 MHz
HActive 水平有效像素 1920
HFP / HSync / HBP 水平前肩、同步、后肩 88 / 44 / 148
VActive 垂直有效行数 1080
VFP / VSync / VBP 垂直前肩、同步、后肩 4 / 5 / 36
调优提示: 调整 CRTC 时序中的消隐区间(Blanking)可以微调实际刷新率,但必须确保在显示器支持的 VESA 标准范围内,否则会导致画面撕裂或黑屏。

4.1.2 CRTC 状态机与 VBlank

CRTC 在扫描过程中会进入 VBlank(垂直消隐)区间,这是驱动更新帧缓冲(Flip)的安全窗口。在 VBlank 期间更新 Plane 的 framebuffer 可以避免撕裂(Tearing)。

// 等待 VBlank 的典型用户态调用
int fd = open("/dev/dri/card0", O_RDWR);
drm_wait_vblank_t vblank;
memset(&vblank, 0, sizeof(vblank));
vblank.request.type = DRM_VBLANK_RELATIVE;
vblank.request.sequence = 1;
ioctl(fd, DRM_IOCTL_WAIT_VBLANK, &vblank);
CRTC 扫描时序与 VBlank 窗口 有效显示区域(Active Area) HBlank HBlank VBlank 区间(安全帧缓冲更新窗口) HSync VSync

4.2 Plane 图层叠加模型

Plane 是 DRM 中表示独立图层的抽象。每个 Plane 拥有自己的 framebuffer、位置、尺寸、透明度(alpha)和颜色转换矩阵。CRTC 从多个 Plane 读取像素数据,按照 Z-order 顺序混合后输出到显示器。

4.2.1 图层叠加流程

  1. Primary Plane:作为背景层,通常包含完整的桌面或游戏画面。
  2. Overlay Plane:叠加在 Primary 之上,用于视频播放、UI 弹窗等,支持缩放与颜色空间转换。
  3. Cursor Plane:硬件光标层,具有最低延迟,通常只支持小尺寸(64×64 或 128×128)且无需 framebuffer 切换。
Plane 图层叠加与 CRTC 合成流程 Cursor Plane 硬件光标,小尺寸,低延迟 Overlay Plane 视频/UI 弹窗,支持缩放 Primary Plane 背景层,完整桌面画面 CRTC Z-order 混合 + 时序生成 Alpha 合成 / 颜色转换 显示 Plane 的 Z-order 由 DRM 驱动固定:Cursor > Overlay > Primary

4.3 Primary / Cursor / Overlay Plane 的区别

三种 Plane 在硬件能力、使用场景和性能特性上存在显著差异。驱动通过 drm_plane 结构体暴露这些能力,用户态通过 DRM_IOCTL_MODE_GETPLANERESOURCES 查询。

特性 Primary Plane Cursor Plane Overlay Plane
数量 每个 CRTC 至少 1 个 每个 CRTC 最多 1 个 0 到多个(取决于硬件)
尺寸限制 通常等于 CRTC 分辨率 固定小尺寸(如 64×64) 可缩放,最大可达 CRTC 分辨率
Alpha 支持 通常不支持全局 Alpha 支持硬件光标 Alpha 支持全局 Alpha 与 per-pixel Alpha
颜色空间 RGB 为主 RGB RGB 或 YUV(视频硬件加速)
帧缓冲更新 需要 VBlank 同步 可异步更新(无撕裂) 需要 VBlank 同步
性能开销 低(直接扫描) 极低(专用硬件) 中(需要合成与缩放)
典型用途 桌面背景、游戏画面 鼠标指针 视频播放、画中画、UI 弹窗
性能陷阱: 如果 Overlay Plane 数量不足,用户态合成(如 Weston 或 Xorg 的 composite 重定向)会将所有图层合并到 Primary Plane,这会增加 GPU 渲染负载并可能降低帧率。优先使用硬件 Overlay Plane 进行视频叠加。

4.4 Plane 与 CRTC 的绑定关系

在 DRM 中,Plane 必须绑定到特定的 CRTC 才能生效。绑定操作通过 drmModeSetPlane 或 atomic commit 完成。一个 CRTC 可以绑定多个 Plane,但每个 Plane 同一时刻只能绑定到一个 CRTC。

// 使用 atomic API 将 Overlay Plane 绑定到 CRTC
struct drm_mode_atomic atomic;
struct drm_atomic_state *state;

state->planes[overlay_plane_id].fb_id = fb_id;
state->planes[overlay_plane_id].crtc_id = crtc_id;
state->planes[overlay_plane_id].src_x = 0;
state->planes[overlay_plane_id].src_y = 0;
state->planes[overlay_plane_id].src_w = 1920 << 16;
state->planes[overlay_plane_id].src_h = 1080 << 16;
state->planes[overlay_plane_id].crtc_x = 0;
state->planes[overlay_plane_id].crtc_y = 0;
state->planes[overlay_plane_id].crtc_w = 1920;
state->planes[overlay_plane_id].crtc_h = 1080;

drmModeAtomicCommit(fd, &atomic, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);

4.5 帧率配置与 Plane 的协同

帧率配置不仅依赖 CRTC 的时序参数,还受 Plane 更新频率的影响。当 Overlay Plane 频繁更新 framebuffer(如 60fps 视频)时,CRTC 的 VBlank 中断频率决定了实际交付帧率。

  • 同步更新: 所有 Plane 在 VBlank 中断中同时切换 framebuffer,保证画面一致性。
  • 异步更新: Cursor Plane 可以绕过 VBlank 直接更新,适用于高 DPI 鼠标移动。
  • 帧率降级: 如果 Overlay Plane 的 framebuffer 更新速度低于 CRTC 刷新率,驱动会重复显示最后一帧,导致视觉卡顿。
实战建议: 在视频播放场景中,将视频帧直接提交到 Overlay Plane 并启用硬件缩放,可以避免 GPU 合成开销,将帧率提升 20%-30%。使用 drmModePageFlip 配合 DRM_MODE_PAGE_FLIP_EVENT 标志监听 VBlank 完成事件,精确控制帧交付节奏。