DRM显示驱动开发:硬件光标与VBlank同步 - 第3节
3.1 VBlank 定义与垂直消隐期
VBlank(Vertical Blanking Interval,垂直消隐期)是显示系统中一个基础且关键的时间窗口。在光栅扫描显示设备(如 LCD、OLED 屏幕)中,图像是从左到右、从上到下逐行扫描显示的。当扫描完一帧的最后一行后,电子枪(或等效的像素更新逻辑)需要从屏幕右下角回到左上角,开始下一帧的扫描。这个回扫过程所对应的时间段,就是 VBlank。
3.1.1 垂直消隐期的物理意义
在 CRT 显示器时代,VBlank 是电子枪回扫的物理必需。在 LCD 等现代显示设备中,虽然不再有电子枪,但 VBlank 的概念被保留并扩展为一种重要的同步机制:
- 帧缓冲切换安全窗口: 在 VBlank 期间切换显示缓冲区(Page Flip),可以避免用户看到撕裂(Tearing)的画面。
- 显示控制器状态重置: 为下一帧的扫描线输出准备行指针、时钟等硬件状态。
- 低功耗模式入口: 部分显示控制器在 VBlank 期间可进入低功耗状态。
3.1.2 VBlank 与 VSync 的关系
VBlank 是时间段,VSync(垂直同步)是信号。VSync 信号通常在每个 VBlank 开始时由显示控制器硬件产生,用于通知 GPU 或驱动:现在可以安全更新帧缓冲区了。
| 概念 | 类型 | 作用 |
|---|---|---|
| VBlank | 时间段 | 两帧之间的消隐窗口,持续若干微秒到毫秒 |
| VSync | 硬件信号/中断 | VBlank 开始时刻的触发信号,驱动据此调度操作 |
| VBlank 周期 | 时间间隔 | 从一次 VBlank 开始到下一次 VBlank 开始的时间 |
3.2 刷新率与 VBlank 周期
刷新率(Refresh Rate)是显示器每秒更新完整画面的次数,单位是 Hz。常见的刷新率有 60Hz、120Hz、144Hz 等。VBlank 周期与刷新率直接相关:
例如,60Hz 显示器的 VBlank 周期约为 16.67ms,120Hz 约为 8.33ms。但 VBlank 本身只是这个周期中的一小部分。
3.2.1 帧周期构成
一个完整的帧周期由两部分组成:
- 有效显示时间(Active Area): 实际扫描并显示像素数据的时间。
- 垂直消隐时间(VBlank): 回扫或等待时间。
| 刷新率 | 帧周期 | 典型 VBlank 时长 | VBlank 占比 |
|---|---|---|---|
| 60 Hz | 16.67 ms | ~1.5 ms | ~9% |
| 120 Hz | 8.33 ms | ~0.8 ms | ~9.6% |
| 144 Hz | 6.94 ms | ~0.7 ms | ~10% |
| 240 Hz | 4.17 ms | ~0.4 ms | ~9.6% |
3.3 VBlank 在显示流水线中的作用
在 DRM 显示驱动中,VBlank 是连接显示控制器、GPU 渲染和用户空间应用程序的同步枢纽。它在显示流水线中扮演以下关键角色:
3.3.1 帧缓冲切换(Page Flip)
当应用程序更新画面时,驱动需要在 VBlank 期间切换显示控制器读取的帧缓冲地址。如果切换发生在有效显示区,用户将看到屏幕上半部分显示旧帧、下半部分显示新帧的撕裂现象。
- 应用程序提交新的帧缓冲(FB)到 DRM。
- 驱动等待下一个 VBlank 中断。
- 在 VBlank 中断服务程序中,更新显示控制器的帧缓冲基址寄存器。
- 显示控制器从下一帧开始读取新的 FB,用户看到完整的新画面。
3.3.2 硬件光标更新
硬件光标(Hardware Cursor)是显示控制器内置的叠加层,独立于主帧缓冲。更新光标位置或图像时,同样需要在 VBlank 期间进行,以避免光标闪烁或撕裂。
- 光标位置更新: 修改光标位置寄存器,需在 VBlank 窗口内完成。
- 光标图像切换: 更新光标缓冲区指针,需与帧同步对齐。
- 光标使能/禁用: 状态切换也应在 VBlank 期间执行。
3.3.3 VBlank 中断与驱动调度
显示控制器在每次 VBlank 开始时触发硬件中断。DRM 驱动注册中断处理函数,在中断上下文中执行时间敏感操作:
// 简化的 VBlank 中断处理流程(伪代码)
static irqreturn_t display_vblank_handler(int irq, void *dev_id)
{
struct drm_device *dev = dev_id;
struct drm_crtc *crtc = ...;
// 1. 更新 VBlank 计数器
drm_crtc_handle_vblank(crtc);
// 2. 检查是否有等待的 Page Flip
if (crtc->state->pending_page_flip)
commit_pending_flip(crtc);
// 3. 更新硬件光标位置(如果需要)
if (crtc->cursor_needs_update)
update_hw_cursor(crtc);
// 4. 唤醒等待 VBlank 的用户空间进程
wake_up(&crtc->vblank_wait_queue);
return IRQ_HANDLED;
}
3.3.4 用户空间 VBlank 等待
DRM 提供了 DRM_IOCTL_WAIT_VBLANK 等 ioctl,允许用户空间应用程序主动等待 VBlank 事件。这在以下场景中非常有用:
- 游戏渲染循环: 等待 VBlank 后再提交新帧,实现垂直同步。
- 视频播放: 与显示器刷新率对齐,避免丢帧或重复帧。
- 合成器(Compositor): 在 VBlank 期间执行合成操作,减少延迟。
3.4 本章小结
VBlank 是显示驱动开发中不可回避的核心概念。理解 VBlank 的定义、周期构成以及在显示流水线中的多重作用,是后续学习硬件光标同步、Page Flip 优化和 VBlank 控制的基础。关键要点:
- VBlank 是两帧之间的安全切换窗口,由显示控制器硬件保证。
- VBlank 周期 = 1 / 刷新率,高刷新率下 VBlank 窗口极短。
- VBlank 中断是驱动调度帧缓冲切换、光标更新等操作的同步锚点。
- 用户空间通过 DRM ioctl 等待 VBlank,实现应用层垂直同步。