4. CRTC 与 Plane 模型:时序生成、图层叠加与硬件差异
CRTC(Cathode Ray Tube Controller)与 Plane(图层)是 DRM/KMS 框架中负责显示时序生成与像素数据合成的核心硬件抽象层。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 |
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);
4.2 Plane 图层叠加模型
Plane 是 DRM 中表示独立图层的抽象。每个 Plane 拥有自己的 framebuffer、位置、尺寸、透明度(alpha)和颜色转换矩阵。CRTC 从多个 Plane 读取像素数据,按照 Z-order 顺序混合后输出到显示器。
4.2.1 图层叠加流程
- Primary Plane:作为背景层,通常包含完整的桌面或游戏画面。
- Overlay Plane:叠加在 Primary 之上,用于视频播放、UI 弹窗等,支持缩放与颜色空间转换。
- Cursor Plane:硬件光标层,具有最低延迟,通常只支持小尺寸(64×64 或 128×128)且无需 framebuffer 切换。
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 弹窗 |
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 刷新率,驱动会重复显示最后一帧,导致视觉卡顿。
drmModePageFlip 配合 DRM_MODE_PAGE_FLIP_EVENT 标志监听 VBlank 完成事件,精确控制帧交付节奏。