Windows 8 及更高版本中的 TDR

从Windows 8开始,GPU 超时检测和恢复 (TDR) 行为允许重置各个物理适配器的某些部分,而无需重置适配器范围。

有关 TDR 的详细信息,请参阅 超时检测和恢复 ( TDR) 。

要求

  • 最低 WDDM 版本:1.2
  • 最低 Windows 版本:8
  • 驱动程序实现 - 完整图形和仅呈现:必需
  • WHLK 要求和测试: Device.Graphics...TDRResiliency

DDI) (TDR 设备驱动程序接口

为了适应此行为更改,显示微型端口驱动程序实现以下函数:

显示微型端口驱动程序通过设置 DXGK_DRIVERCAPS来指示对这些函数的支持。SupportPerEngineTDR 成员,在这种情况下,它必须实现上述所有函数。

注意

支持这些函数的驱动程序还必须支持 DxgkDdiCollectDbgInfo 函数的零级同步。 这是为了确保不受重置操作影响的级别零微型端口调用可以继续。 请参阅 DxgkDdiCollectDbgInfo 的备注。

以下结构与上述函数相关联:

Nodes

如上述 TDR 函数中使用的一样, 节点 是单个物理适配器的多个部分之一,可以单独计划。 例如,三维节点、视频解码节点和复制节点都可以存在于同一物理适配器中,并且可以在DXGKARG_QUERYDEPENDENTENGINEGROUP中为每个节点分配单独的序号值。调用 DxgkDdiQueryDependentEngineGroup 中的 NodeOrdinal 成员。

物理适配器中的节点数由 DXGK_DRIVERCAPSNbAsymetricProcessingNodes 成员中的显示微型端口驱动程序报告。GpuEngineTopology

创建上下文时,节点序号值在 DXGKARG_CREATECONTEXT 结构的 NodeOrdinal 成员中传递。

引擎

如上述 TDR 函数中使用的那样, 引擎 是多个物理适配器之一, (或 GPU) 共同充当一个逻辑适配器。 DirectX 图形内核子系统支持此类配置,但要求每个引擎必须具有相同数量的节点。

例如,GPU 计划程序将引擎 0 视为与物理适配器 0 相对应。 引擎 0 的节点数必须与引擎 1 相同,对应于适配器 1。

创建上下文时的引擎序号值

创建上下文时,将在 DXGKARG_CREATECONTEXT 结构的 EngineAffinity 成员中设置对应于引擎序号值的单个位。 此结构和其他计划程序相关结构的 EngineOrdinal 成员是从零开始的索引。 EngineAffinity 的值为 1 <<EngineOrdinal,EngineOrdinalEngineAffinity 中的最高位位置。

不受引擎重置影响的数据包

GPU 计划程序可能会要求驱动程序重新提交提交到引擎硬件队列的数据包太晚,无法在引擎重置完成之前得到完全处理。 驱动程序必须遵循以下准则重新提交此类数据包:

  • 分页数据包:GPU 计划程序将要求驱动程序使用原始围栏 ID 重新提交分页数据包,并按照最初提交的相同顺序重新提交分页数据包。 在将新数据包添加到硬件队列之前,将重新提交任何此类数据包。
  • 呈现数据包:GPU 计划程序将为呈现数据包分配新的围栏 ID,然后重新提交它们。

调用序列以重置引擎

当 DxgkDdiResetEngine 成功时,GPU 计划程序确保从引擎重置调用返回的 LastAbortedFenceId 值对应于硬件队列中的现有围栏 ID 或 GPU 上最后完成的围栏 ID。 当硬件队列在检测到 GPU 超时之后但在调用引擎重置回调之前清空时,可能会出现后一种情况。

GPU 上最后完成的围栏 ID 值必须始终由驱动程序维护,因为它还需要设置DXGKARGCB_NOTIFY_INTERRUPT_DATA抢占中断通知结构的 DmaPreempted.LastCompletedFenceId 成员。 只有在以下情况下,才应提前完成最后一个围栏 ID:

  • 当数据包完成 (未抢占) 时,应将上次完成的围栏 ID 设置为已完成数据包的围栏 ID。
  • 当 DxgkDdiResetEngine 成功时,最后完成的围栏 ID 应设置为引擎重置调用返回的 LastCompletedFenceId 成员的值。
  • 对于适配器范围的重置,所有节点上最后完成的围栏 ID 应提前到重置时最后提交的围栏 ID。

下面是成功重置引擎的时间顺序,如 GPU 计划程序所示:

  1. 发出抢占尝试。

  2. 检测到 GPU 超时。

  3. GPU 计划程序会获取上次提交和已完成围栏 ID 的快照,并忽略来自超时引擎的中断。 这是设备中断级别的一个原子操作。

  4. 如果此时硬件队列中没有数据包,请退出。 如果在步骤 2 和 3 之间的时间范围内完成数据包,则可能会发生这种情况。

  5. 刷新所有排队的 DPC。

  6. 准备引擎重置。

  7. 调用 DxgkDdiResetEngine

  8. 如果 LastAbortedFenceId 成员小于上次完成的围栏 ID 或大于上次提交的围栏 ID,则 DirectX 图形内核子系统将导致发生系统 bug 检查。 在故障转储文件中, BugCheck 0x119消息指出了错误,其中包含以下四个参数:

    • 0xA,这意味着驱动程序报告了无效的中止围栏 ID
    • 驱动程序返回的 LastAbortedFenceId
    • 上次完成的围栏 ID
    • 内部操作系统参数
  9. 如果 LastAbortedFenceId 值有效,请继续执行引擎重置恢复,如下所示。 如果分页数据包受引擎重置的影响,GPU 计划程序将按照适配器范围的重置来重置引擎。 拥有该分页数据包引用的分配的所有设备也会处于错误状态。 但是,系统设备本身不会进入错误状态,并在重置完成后继续执行。

特殊情况

在上述步骤 3 和 7 之间完成 GPU 上的数据包时,可能会出现特殊情况。 在这种情况下,如果从驱动程序的角度来看,如果硬件队列中没有数据包,则驱动程序应将 LastAbortedFenceId 设置为最后一个已完成数据包的围栏 ID。 从计划程序的角度来看,此类数据包似乎已中止,即使数据包最终完成,相应的设备也会进入错误状态。

如果驱动程序由于硬件处于无效状态或硬件无法重置节点而无法执行重置操作,则驱动程序应返回失败状态代码。 如果 GPU 计划程序收到失败状态代码,则会在Windows 8之前按照 TDR 行为执行适配器范围的重置和重启操作。

即使驱动程序已选择加入Windows 8及更高版本的 TDR 行为,GPU 计划程序也会请求重置并重启整个逻辑适配器。 因此,驱动程序仍必须实现 DxgkDdiResetFromTimeoutDxgkDdiRestartFromTimeout 函数,并且其语义与Windows 8之前保持相同。 尝试使用 DxgkDdiResetEngine 重置物理适配器导致逻辑适配器重置时,Windows 调试器的 !analyze 命令显示 TDR 恢复上下文的 TdrReason 值设置为 TdrEngineTimeoutPromotedToAdapterReset = 9 的新值。