window 显示驱动开发-线程同步和 TDR

下图显示了 Windows 显示驱动程序模型 (WDDM) 中显示微型端口驱动程序的线程同步的工作原理

如果发生硬件超时,则会启动 超时检测和恢复 (TDR) 进程。 GPU 计划程序调用驱动程序的 DxgkDdiResetFromTimeout 函数,这将重置 GPU。 DxgkDdiResetFromTimeout 与任何其他显示微型端口驱动程序函数同步调用,运行时电源管理功能 DxgkDdiSetPowerComponentFState 和 DxgkDdiPowerRuntimeControlRequest 除外。 也就是说, 在 DxgkDdiResetFromTimeout 线程运行时,驱动程序中没有其他线程运行。 操作系统还保证在调用 DxgkDdiResetFromTimeout 期间,任何应用程序都无法访问帧缓冲区;因此,驱动程序可以重置内存控制器相位锁定循环 (PLL) 等。

当恢复线程执行 DxgkDdiResetFromTimeout 时,可以继续调用中断和延迟过程调用 (DPC) 。 KeSynchronizeExecution 函数可用于将重置过程的某些部分与设备中断同步。

驱动程序从 DxgkDdiResetFromTimeout 返回后,可以再次调用大多数驱动程序函数,并且操作系统开始清理不再需要的资源。 在清理期间,出于指示的原因调用以下驱动程序函数:

  • 调用驱动程序以通知正在逐出分配。

例如,如果分配是在内存段中分页的,则会调用驱动程序的 DxgkDdiBuildPagingBuffer 函数,并将 DXGKARG_BUILDPAGINGBUFFER 结构的 Operation 成员设置为 DXGK_OPERATION_TRANSFER,Transfer.Size 成员设置为零,以通知驱动程序有关逐出的信息。 请注意,由于内容在重置期间丢失,因此不涉及内容传输。

如果分配是在光圈段中分页的,则会调用驱动程序的 DxgkDdiBuildPagingBuffer 函数,并将 DXGKARG_BUILDPAGINGBUFFER 的 Operation 成员设置为 DXGK_OPERATION_UNMAP_APERTURE_SEGMENT,以通知驱动程序取消映射光圈中的分配。

  • 调用驱动程序的 DxgkDdiReleaseSwizzlingRange 函数来释放不重排光圈和段光圈范围。

除非绝对必要,否则驱动程序不应在上述调用期间访问 GPU。

清理期结束后,操作系统调用驱动程序的 DxgkDdiRestartFromTimeout 函数,以通知驱动程序清理已完成,操作系统将恢复使用适配器进行呈现。

1. TDR 触发条件

  • GPU 长时间未响应(通常由于 命令队列卡死、硬件故障 或 驱动死锁)。
  • Windows GPU 调度器检测到超时,并启动恢复流程。

2. TDR 核心流程

(1) 调用 DxgkDdiResetFromTimeout(GPU 重置)

同步性:

  • 此函数是 完全同步调用,即在执行期间:
  • 禁止其他任何驱动线程运行(除了 DxgkDdiSetPowerComponentFState 和 DxgkDdiPowerRuntimeControlRequest)。
  • 应用程序无法访问帧缓冲区(确保内存安全)。
  • 操作系统保证 GPU 处于 可安全重置 的状态。

驱动职责:

  • 重置 GPU 硬件(如寄存器、PLL、内存控制器等)。
  • 清理 GPU 内部状态(如命令队列、缓存)。

可调用 KeSynchronizeExecution 与设备中断同步(避免竞争条件)。

(2) 中断和 DPC 处理

中断和 DPC(延迟过程调用)仍可继续执行,但驱动程序需确保:

  • 不会与 DxgkDdiResetFromTimeout 冲突(如使用自旋锁保护关键代码)。

(3) 重置完成后的资源清理

在 DxgkDdiResetFromTimeout 返回后,操作系统开始 清理无效资源,并调用以下驱动函数:

驱动函数 调用原因 参数说明
DxgkDdiBuildPagingBuffer 通知分配被逐出 - Operation = DXGK_OPERATION_TRANSFERTransfer.Size = 0):表示内存段分配被逐出(无数据传输,因内容已丢失)。 - Operation = DXGK_OPERATION_UNMAP_APERTURE_SEGMENT:取消映射光圈段(Aperture Segment)中的分配。
DxgkDdiReleaseSwizzlingRange 释放 Swizzling Range 清理所有不再需要的重排范围(Swizzling Range)。

关键注意事项:

  • 驱动程序应避免访问 GPU,除非绝对必要(如释放硬件资源)。
  • 不涉及数据传输(因为 GPU 重置后显存内容已丢失)。

(4) 调用 DxgkDdiRestartFromTimeout(恢复呈现)

清理完成后,操作系统调用 DxgkDdiRestartFromTimeout,通知驱动:

  • TDR 恢复流程结束。
  • GPU 可以重新用于图形渲染。

驱动应:

  • 重新初始化必要的硬件状态(如默认分辨率、颜色格式)。
  • 恢复 GPU 调度器工作(允许提交新命令)。

3. 驱动开发注意事项

(1) 线程安全性

DxgkDdiResetFromTimeout 运行期间,禁止其他驱动线程运行,但仍需:

  • 保护共享硬件资源(如 MMIO 寄存器)。
  • 避免死锁(如不等待可能被阻塞的锁)。

(2) 内存管理

显存内容在重置后丢失,因此:

  • 驱动不应尝试恢复旧数据。
  • 应用程序需重新提交丢失的资源(如纹理、缓冲区)。

(3) 错误恢复

如果 DxgkDdiResetFromTimeout 失败:

  • 系统可能 完全禁用 GPU(降级到基本显示模式)。
  • 用户可能需要 重启系统 恢复功能。

(4) 调试支持

在 DxgkDdiCollectDbgInfo(Reason = VIDEO_TDR_TIMEOUT_DETECTED)中:

  • 记录足够信息(如最后提交的命令、GPU 状态)。
  • 确保代码可分页(PASSIVE_LEVEL)。

4. 典型 TDR 时序图

复制代码
1. GPU 超时发生
   │
2. WDDM 检测超时,暂停 GPU 调度
   │
3. 调用 DxgkDdiResetFromTimeout (同步执行)
   │   ├─ 重置 GPU 硬件
   │   └─ 清理内部状态
   │
4. 操作系统清理资源:
   │   ├─ DxgkDdiBuildPagingBuffer (逐出分配)
   │   └─ DxgkDdiReleaseSwizzlingRange (释放范围)
   │
5. 调用 DxgkDdiRestartFromTimeout
   │
6. GPU 恢复工作,应用程序重新提交命令

5. 总结

阶段 关键动作 驱动职责
检测超时 GPU 无响应 无(系统自动触发)
重置 GPU DxgkDdiResetFromTimeout 重置硬件,避免竞争
清理资源 BuildPagingBuffer / ReleaseSwizzlingRange 释放无效分配
恢复工作 DxgkDdiRestartFromTimeout 重新初始化 GPU

TDR 是 Windows 图形稳定性的关键机制,驱动程序需正确处理重置和资源清理,以避免系统崩溃或图形异常

相关推荐
VernonJsn8 小时前
visual studio 2022的windows驱动开发
ide·驱动开发·visual studio
嵌入式郑工14 小时前
RK3566 LubanCat 开发板 USB Gadget 配置完整复盘
linux·驱动开发·ubuntu
雾削木2 天前
树莓派 ESPHome 固件编译与烧录全攻略(解决超时与串口识别问题)
驱动开发
春日见3 天前
win11 分屏设置
java·开发语言·驱动开发·docker·单例模式·计算机外设
DarkAthena3 天前
【GaussDB】手动编译不同python版本的psycopg2驱动以适配airflow
驱动开发·python·gaussdb
松涛和鸣3 天前
DAY66 SPI Driver for ADXL345 Accelerometer
linux·网络·arm开发·数据库·驱动开发
嵌入式郑工4 天前
# RK3576 平台 RTC 时钟调试全过程
linux·驱动开发·ubuntu
GS8FG4 天前
针对Linux,RK3568平台下,I2C驱动的一点小小的领悟
linux·驱动开发
一路往蓝-Anbo4 天前
第 4 篇:策略模式 (Strategy) —— 算法的热插拔艺术
网络·驱动开发·stm32·嵌入式硬件·算法·系统架构·策略模式
A-花开堪折4 天前
RK3568 Android 11 驱动开发(五):串口驱动适配
驱动开发