3. 常见渲染故障现象:屏幕撕裂、卡顿、黑屏/花屏与渲染延迟
在 DRM 驱动开发与调试中,渲染故障是用户最直观感知到的异常。本章聚焦四种核心故障现象:屏幕撕裂(Tearing)、画面卡顿(Jank)、黑屏/花屏以及渲染延迟过高。理解这些现象背后的 DRM 机制(如 VBlank、Buffer Flip、Fence 同步)是精准定位问题的前提。
3.1 屏幕撕裂(Tearing)
现象描述:画面在水平方向出现错位或断裂,通常发生在快速移动的场景中。根本原因是 GPU 在显示器刷新(VBlank)期间更新了帧缓冲区(Front Buffer),导致显示器在一帧内同时显示了新旧两帧的内容。
核心机制:DRM 的 Page Flip 操作若未与 VBlank 同步(即未使用 VBlank 等待或 Atomic Commit 的垂直同步标志),则会产生 Tearing。
3.1.1 撕裂产生的时序图
下图展示了未同步的 Buffer Flip 如何导致撕裂:
3.1.2 排查清单
| 排查项 | 检查方法 | 典型根因 |
|---|---|---|
| VBlank 等待 | 检查 DRM_IOCTL_MODE_PAGE_FLIP 是否设置 DRM_MODE_PAGE_FLIP_EVENT | 用户态未等待 VBlank 事件 |
| Atomic Commit 标志 | 检查 CRTC 属性 "vrr_enabled" 或 "VRR" 是否误开启 | 可变刷新率(VRR)范围配置错误 |
| 双缓冲 vs 三缓冲 | 查看 /sys/kernel/debug/dri/0/state 中的 fb_id 切换频率 | 单缓冲模式或 Buffer 数量不足 |
| 驱动层面 | dmesg 搜索 "tearing" 或 "page flip timeout" | GPU 调度器延迟导致 Flip 错过 VBlank |
快速验证:在 weston 或 kmscube 中启用
--fullscreen --vsync 参数,若撕裂消失,则确认是用户态同步缺失。
3.2 画面卡顿(Jank)
现象描述:画面出现不连续的停顿或跳跃,帧率不稳定。Jank 通常由渲染管线中的某个环节超时导致,例如 GPU 提交延迟、Fence 等待超时或 DRM 的 Atomic Commit 被阻塞。
3.2.1 Jank 的典型流程
3.2.2 Jank 分类与定位
| Jank 类型 | 特征 | DRM 相关工具 |
|---|---|---|
| 提交延迟 Jank | drm_atomic_commit 返回 -EBUSY 或 -ETIMEDOUT | perf trace -e drm:* |
| 渲染超时 Jank | GPU 作业在调度器中等待超过 2 个 VBlank 周期 | drm_info + /sys/kernel/debug/dri/*/gpu_busy |
| Fence 饥饿 Jank | dma_fence_wait_timeout 返回 0 | ftrace filter: dma_fence_signaled |
| VBlank 错过 Jank | CRTC 的 vblank_count 出现跳变或停滞 | cat /sys/kernel/debug/dri/*/vblank_count |
注意:Jank 与 Tearing 有时同时出现。若 VBlank 同步开启但仍卡顿,优先检查 GPU 频率是否被限制(如
devfreq 策略导致降频)。
3.3 黑屏/花屏
现象描述:显示器无信号(黑屏)或显示随机像素/色块(花屏)。黑屏通常意味着 CRTC 或 Encoder 未正确使能;花屏则多与帧缓冲区数据损坏或格式不匹配有关。
3.3.1 黑屏/花屏根因对比
| 现象 | 可能根因 | DRM 状态检查 |
|---|---|---|
| 黑屏(无背光) | Backlight 属性未设置或 PWM 驱动异常 | cat /sys/class/backlight/*/brightness |
| 黑屏(有背光) | CRTC 未使能或 Connector 状态为 disconnected | drmModeGetConnector 返回的连接状态 |
| 花屏(水平条纹) | Fence 未等待,GPU 写入未完成即翻转 | 检查 Atomic Commit 中 in_fence_fd 是否有效 |
| 花屏(随机色块) | 帧缓冲区 stride 或 pixel_format 不匹配 | drmModeAddFB2 的 pitch 与硬件要求对齐 |
| 花屏(全屏绿色/紫色) | 色彩空间转换错误(如 YUV 误传为 RGB) | 检查 plane 的 color_encoding 属性 |
3.3.2 花屏排查流程图
调试命令:使用
modetest -M -p 查看当前 plane 的 fb_id 和 format,对比硬件支持的格式列表(通常位于 /sys/kernel/debug/dri/*/framebuffer)。
3.4 渲染延迟过高
现象描述:从用户输入到画面更新之间的延迟明显增加(如触控笔延迟 > 50ms)。渲染延迟通常由管线中的排队、等待或缓冲区复制引起。
3.4.1 延迟构成分析
| 延迟阶段 | 典型耗时 | DRM 相关因素 |
|---|---|---|
| 用户态提交 | 0.5 – 2 ms | drmModeAtomicCommit 的 ioctl 开销 |
| 内核排队 | 1 – 8 ms | 调度器等待 GPU 空闲;drm_sched 队列深度 |
| GPU 渲染 | 2 – 16 ms | 着色器复杂度;显存带宽瓶颈 |
| Fence 等待 | 0 – 16 ms | 等待前一帧完成;out_fence 未及时 signaled |
| VBlank 翻转 | 0 – 16.7 ms | 等待下一个 VBlank 窗口(60Hz 显示器) |
3.4.2 延迟优化方向
- 减少排队深度:通过
drm_sched的num_jobs参数控制 GPU 队列中的最大作业数,避免过度缓冲。 - 使用 Direct Flip:在 Atomic Commit 中设置
DRM_MODE_ATOMIC_NONBLOCK并结合in_fence_fd,减少内核态阻塞。 - 启用 VRR(可变刷新率):在支持 FreeSync 或 HDMI-VRR 的显示器上,允许显示器在帧就绪后立即刷新,而非等待固定 VBlank。
- 避免隐式同步:使用
dma-buf的显式同步(Explicit Sync)替代隐式 dma_fence 等待,减少不必要的同步点。
延迟测量方法:在用户态记录
clock_gettime(CLOCK_MONOTONIC) 在 Atomic Commit 前后,结合 drm_wait_vblank 的返回时间,可精确计算端到端延迟。使用 perf record -e drm:drm_vblank_event 可捕获内核态 VBlank 事件时间戳。
3.5 故障现象总结表
| 故障现象 | 主要根因 | 首要排查方向 | 典型 DRM 调试接口 |
|---|---|---|---|
| 屏幕撕裂 | Page Flip 未同步 VBlank | 检查 DRM_MODE_PAGE_FLIP_EVENT 标志 | drm_wait_vblank |
| 画面卡顿 | Fence 等待超时 / 提交阻塞 | 检查 Atomic Commit 返回码与 Fence 状态 | drm_atomic_state_dump |
| 黑屏 | CRTC/Encoder 未使能 | 检查 Connector 状态与 CRTC 激活属性 | modetest -c |
| 花屏 | 帧缓冲区格式/stride 不匹配 | 验证 fb 的 pixel_format 与硬件兼容性 | drmModeGetFB |
| 渲染延迟高 | 管线排队深 / VBlank 等待 | 测量各阶段耗时,优化队列深度 | perf trace + drm:* 事件 |