DRM显示驱动开发:硬件光标与VBlank同步 - 第2节
2.1 硬件光标 vs 软件光标:性能与机制的根本差异
在图形显示系统中,光标(Cursor / Pointer)的呈现方式直接决定了交互流畅度与驱动实现的复杂度。硬件光标与软件光标在渲染路径、内存带宽消耗、同步机制上存在本质区别。
核心结论:硬件光标由显示控制器(Display Controller)独立合成,不占用主图层 Framebuffer 的渲染带宽;软件光标由 CPU 或 GPU 在帧缓冲区中手动绘制,每次移动都需要重绘部分或全部画面。
2.1.1 对比表格:硬件光标 vs 软件光标
| 对比维度 | 硬件光标 | 软件光标 |
|---|---|---|
| 合成方式 | 显示控制器独立硬件合成 | CPU/GPU 写入 Framebuffer |
| 内存带宽 | 极低(仅光标图像,通常 64×64 或 128×128) | 高(每次移动需重绘整个光标区域,甚至全屏) |
| 移动延迟 | 纳秒级(寄存器更新后下一行扫描即生效) | 毫秒级(依赖帧刷新周期) |
| VBlank 依赖 | 弱(可异步更新,但建议同步避免撕裂) | 强(必须在 VBlank 窗口内更新,否则撕裂) |
| 光标形状 | 受硬件限制(固定尺寸、颜色格式、热区) | 任意(可绘制任意复杂图形) |
| 功耗 | 低(专用硬件单元) | 高(频繁唤醒 CPU/GPU) |
2.1.2 软件光标的典型问题
- 光标闪烁:当光标移动频率高于帧率时,部分帧中光标被擦除但未重绘,导致光标短暂消失。
- 画面撕裂:光标更新与扫描线输出不同步,光标区域出现上下半帧错位。
- 性能开销:高分辨率下(如 4K),软件光标每次移动需要读写数 MB 的帧缓冲数据。
驱动开发避坑:在 DRM 驱动中,如果硬件不支持光标平面,不要尝试用软件光标模拟硬件光标行为。应直接返回 -EOPNOTSUPP,让用户空间(如 Wayland compositor)自行决定是否使用软件光标。
2.2 硬件光标寄存器模型:从物理到逻辑
硬件光标在显示控制器中通常对应一组专用寄存器,驱动通过读写这些寄存器来控制光标的位置、形状、可见性。不同厂商(Intel、AMD、NVIDIA、Rockchip、Allwinner)的寄存器布局不同,但逻辑模型高度一致。
2.2.1 通用寄存器模型
| 寄存器名称 | 功能描述 | 典型位宽 |
|---|---|---|
| CURSOR_CTRL | 光标使能、格式选择、热区偏移 | 32 bit |
| CURSOR_POS | 光标在屏幕上的 X/Y 坐标(左上角或热区) | 32 bit(X:16, Y:16) |
| CURSOR_BASE | 光标图像在显存中的物理基地址 | 32/64 bit |
| CURSOR_SIZE | 光标图像尺寸(如 64×64, 128×128) | 32 bit |
| CURSOR_PALETTE | (可选)颜色查找表,用于 2-bit 或 4-bit 光标 | 多组 32 bit |
2.2.2 寄存器更新时序要求
硬件光标寄存器通常支持两种更新模式:
- 立即更新:写入寄存器后,下一行扫描即生效。适用于位置频繁移动的场景。
- VBlank 同步更新:写入寄存器后,硬件在下一个 VBlank 期间 latch 新值。适用于光标图像切换或使能/禁能操作。
最佳实践:位置寄存器使用立即更新模式,图像基地址和使能位使用 VBlank 同步更新模式。这样可以兼顾低延迟与画面完整性。
2.3 光标平面(Cursor Plane)在 DRM 中的位置
在 DRM 子系统中,光标平面被抽象为 DRM_PLANE_TYPE_CURSOR 类型的 plane。它与 primary plane(主平面)和 overlay plane(覆盖平面)共同构成显示流水线。
2.3.1 DRM 平面架构图
2.3.2 DRM 中光标平面的关键数据结构
// 注册光标平面
struct drm_plane *cursor_plane;
cursor_plane = drm_universal_plane_init(
drm_dev,
&cursor_plane_funcs, // 回调函数: .update_plane, .disable_plane, .destroy
possible_crtcs, // 位掩码,表示该平面可绑定到哪些 CRTC
&cursor_plane_helper_funcs, // 辅助函数: .prepare_fb, .cleanup_fb, .atomic_check
DRM_PLANE_TYPE_CURSOR, // 平面类型
NULL); // 私有数据
// 设置光标位置 (IOCTL 路径)
int drm_mode_cursor_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
struct drm_mode_cursor *req = data;
struct drm_crtc *crtc = drm_crtc_find(dev, file_priv, req->crtc_id);
if (!crtc) return -ENOENT;
// 调用 CRTC 的 cursor_set/cursor_move 回调
if (req->flags & DRM_MODE_CURSOR_BO)
return crtc->funcs->cursor_set(crtc, file_priv, req->handle, req->width, req->height);
else if (req->flags & DRM_MODE_CURSOR_MOVE)
return crtc->funcs->cursor_move(crtc, req->x, req->y);
return -EINVAL;
}
2.3.3 光标平面的硬件合成流程
- 用户空间通过 DRM IOCTL
DRM_IOCTL_MODE_CURSOR或DRM_IOCTL_MODE_CURSOR2设置光标图像和位置。 - DRM Core 将请求路由到对应 CRTC 的
cursor_set/cursor_move回调。 - 驱动层将光标图像 DMA 到显存中的固定区域,更新光标寄存器(BASE、POS、CTRL)。
- 显示控制器在每帧扫描输出时,从光标平面读取像素,与主图层进行 alpha 混合(通常使用 1-bit 或 2-bit 透明度)。
- 最终输出:光标像素覆盖在主图层之上,形成用户可见的鼠标指针。
关键约束:光标平面通常不支持缩放、旋转、色彩空间转换。其图像格式固定为 ARGB8888 或 2-bit 索引色。驱动在
atomic_check 阶段必须验证用户提交的 framebuffer 是否符合硬件限制。
2.4 本章小结
- 硬件光标通过专用硬件单元合成,具有低延迟、低带宽、低功耗的优势,是桌面和嵌入式系统的首选方案。
- 硬件光标寄存器模型包含控制、位置、基地址、尺寸等核心寄存器,驱动需区分立即更新与 VBlank 同步更新两种模式。
- 在 DRM 架构中,光标平面作为
DRM_PLANE_TYPE_CURSOR独立存在,与主平面和覆盖平面并行输入到 CRTC 进行硬件合成。 - 驱动开发者应优先实现硬件光标支持,仅在硬件不支持时回退到软件光标方案。