3. 显示管线与扫描输出
在 DRM 显示驱动开发中,理解显示管线的扫描输出机制是掌握 VBlank 同步与硬件光标定位的基础。显示器并非一次性把整帧图像“推”到屏幕上,而是由显示控制器按照严格的时序,逐行、逐像素地扫描输出。像素时钟、扫描线、行场同步信号、前后肩、有效显示区域与消隐区共同构成了这套时序体系。只有把这些参数配置正确,图像才能稳定显示,VBlank 中断才能落在正确的时刻,硬件光标也才能精确叠加在扫描输出的画面上。
一、核心原理:从像素时钟到一帧扫描
显示管线的输出节奏由像素时钟(Pixel Clock,PCLK)驱动。每来一个像素时钟周期,控制器就输出一个像素。一行像素输出完毕后,进入行消隐;一帧所有行输出完毕后,进入场消隐。整个扫描过程可以拆解为以下几个关键量:
- 像素时钟 PCLK:决定像素输出速率,单位 MHz。例如 1920×1080@60Hz 的典型像素时钟约为 148.5 MHz。
- 水平总周期 HTotal:一行从开始到下一行开始的总像素时钟数,等于水平有效像素 + 水平前肩 + 水平同步脉冲 + 水平后肩。
- 垂直总周期 VTotal:一帧从开始到下一帧开始的总行数,等于垂直有效行 + 垂直前肩 + 垂直同步脉冲 + 垂直后肩。
- 行同步(HSYNC)与场同步(VSYNC):告诉显示器“一行开始”和“一帧开始”的基准信号。
- 有效显示区域(Active Area):真正可见的像素区域,如 1920×1080。
- 消隐区(Blanking):同步脉冲与前后肩所在的不可见区域,用于给显示器和控制器留出回扫与准备时间。
刷新率与这些参数的关系为:刷新率 = PCLK / (HTotal × VTotal)。因此,调整前后肩或同步脉冲宽度,会直接改变刷新率与消隐时间。
二、方法流程:如何计算与配置一组显示时序
在 DRM 驱动中,显示时序通常通过 drm_display_mode 结构体描述,并写入 CRTC 的 mode 配置。配置流程可以概括为以下步骤:
- 确定目标分辨率与刷新率,例如 1920×1080@60Hz。
- 根据显示器 EDID 或标准 CEA 时序,获取 PCLK、HTotal、VTotal、前后肩与同步脉冲宽度。
- 计算 HTotal 与 VTotal,验证刷新率是否匹配。
- 将时序参数填入
drm_display_mode,并设置DRM_MODE_FLAG_PHSYNC、DRM_MODE_FLAG_PVSYNC等极性标志。 - 通过
drm_mode_setcrtc()或原子提交接口下发到硬件。 - 使能 CRTC 与扫描输出,等待 VBlank 中断确认时序稳定。
struct drm_display_mode mode = {
.clock = 148500, /* PCLK: 148.5 MHz */
.hdisplay = 1920, /* 水平有效像素 */
.hsync_start= 1920 + 88, /* HFP = 88 */
.hsync_end = 1920 + 88 + 44, /* HSYNC = 44 */
.htotal = 1920 + 88 + 44 + 148, /* HBP = 148 */
.vdisplay = 1080, /* 垂直有效行 */
.vsync_start= 1080 + 4, /* VFP = 4 */
.vsync_end = 1080 + 4 + 5, /* VSYNC = 5 */
.vtotal = 1080 + 4 + 5 + 36, /* VBP = 36 */
.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC,
};
/* 刷新率 = 148500000 / (2200 × 1125) ≈ 60 Hz */
三、案例场景:VBlank 与硬件光标的时序关系
假设我们要在 1920×1080@60Hz 的屏幕上叠加一个硬件光标。光标位置由 CRTC 的 cursor 寄存器控制,而光标更新通常应在 VBlank 期间完成,以避免撕裂。此时,垂直消隐区(VFP + VSYNC + VBP = 45 行)就是安全更新窗口。若在有效行扫描期间更新光标坐标,可能出现光标“跳变”或与画面不同步的现象。
另一个典型场景是模式切换。当驱动从 1080p 切换到 720p 时,PCLK、HTotal、VTotal 全部改变,VBlank 的持续时间和触发频率也随之变化。如果驱动仍按旧时序计算 VBlank 超时,就可能导致 page flip 提交失败或光标闪烁。
modetest 或 drm_info 查看当前 CRTC 的 mode 参数,确认 HTotal、VTotal 与 PCLK 是否与显示器 EDID 一致。
四、误区与复盘:常见时序配置错误
| 误区 | 现象 | 原因与修正 |
|---|---|---|
| 前后肩配置过小 | 图像边缘抖动、显示器无法锁定 | 消隐时间不足,需按 EDID 或标准时序增大 HFP/HBP/VFP/VBP |
| 同步极性错误 | 画面偏移或黑屏 | 检查 DRM_MODE_FLAG_PHSYNC/PVSYNC 是否与显示器要求一致 |
| PCLK 与 HTotal×VTotal 不匹配 | 刷新率异常,VBlank 频率错误 | 重新计算 PCLK = 刷新率 × HTotal × VTotal |
| 在有效区域更新光标 | 光标撕裂、闪烁 | 将光标更新放入 VBlank 中断或原子提交的 flip 回调中 |
| 忽略 VTotal 中的消隐行 | VBlank 时间计算偏短 | VBlank 行数 = VTotal − vdisplay,必须计入前后肩与 VSYNC |
总结来看,像素时钟决定输出速度,扫描线与行场同步定义节奏,前后肩与消隐区提供安全窗口,有效显示区域承载最终画面。只有把这组参数作为一个整体来理解和配置,才能在 DRM 驱动中实现稳定的扫描输出,并为后续的 VBlank 同步与硬件光标叠加打下可靠基础。