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)。因此,调整前后肩或同步脉冲宽度,会直接改变刷新率与消隐时间。

一帧扫描输出的时序结构(以 1920×1080 为例) 水平方向(一行) 前肩 HFP HSYNC 后肩 HBP 有效像素 1920 HTotal = HFP + HSYNC + HBP + 1920 垂直方向(一帧) 前肩 VFP VSYNC 后肩 VBP 有效行 1080 VTotal = VFP + VSYNC + VBP + 1080 消隐区(Blanking) · 水平消隐 = HFP + HSYNC + HBP · 垂直消隐 = VFP + VSYNC + VBP · VBlank 中断通常由 VSYNC 触发 有效显示区域(Active Area) · 可见像素:1920 × 1080 · 硬件光标叠加在有效区域内 · 刷新率 = PCLK / (HTotal × VTotal)

二、方法流程:如何计算与配置一组显示时序

在 DRM 驱动中,显示时序通常通过 drm_display_mode 结构体描述,并写入 CRTC 的 mode 配置。配置流程可以概括为以下步骤:

  1. 确定目标分辨率与刷新率,例如 1920×1080@60Hz。
  2. 根据显示器 EDID 或标准 CEA 时序,获取 PCLK、HTotal、VTotal、前后肩与同步脉冲宽度。
  3. 计算 HTotal 与 VTotal,验证刷新率是否匹配。
  4. 将时序参数填入 drm_display_mode,并设置 DRM_MODE_FLAG_PHSYNC、DRM_MODE_FLAG_PVSYNC 等极性标志。
  5. 通过 drm_mode_setcrtc() 或原子提交接口下发到硬件。
  6. 使能 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
注意:消隐区不是“浪费的时间”,而是显示管线完成回扫、寄存器更新和同步锁定的必要窗口。VBlank 同步、硬件光标更新、page flip 提交都依赖这段窗口,配置时不可随意压缩。

总结来看,像素时钟决定输出速度,扫描线与行场同步定义节奏,前后肩与消隐区提供安全窗口,有效显示区域承载最终画面。只有把这组参数作为一个整体来理解和配置,才能在 DRM 驱动中实现稳定的扫描输出,并为后续的 VBlank 同步与硬件光标叠加打下可靠基础。