Windows 图形显示驱动开发-WDDM 3.0功能- 硬件翻转队列(三)
DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 重试和失败案例
由于挂起的翻转,无法将请求排队到硬件
有几个特殊情况可能会阻止 KMD 在挂起其他翻转请求时对翻转请求进行排队。 在这种情况下,KMD 应从 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 返回 STATUS_RETRY,并将HwFlipQueueDrainNeeded 设置为 1。 OS 将尝试在完成受翻转影响的平面上所有挂起的翻转后再次提交翻转请求,并在达到目标时间后提交翻转请求。
在某些情况下,显示硬件可能需要在所有平面上完成挂起的翻转,而不仅仅是传入翻转请求引用的翻转。 在这种情况下,HwFlipQueueDrainNeeded 和 HwFlipQueueDrainAllPlanes 标志都应设置为 1,并且 KMD 应返回 STATUS_RETRY。
同样,显示硬件可能需要在所有 VidPn 源上完成挂起的翻转才能重新分配内部资源,在这种情况下,必须设置 HwFlipQueueDrainNeeded 标志,KMD 应返回STATUS_RETRY。
此外,KMD 可以向 OS 指示是否应在设备 IRQL(PrePresentNeeded 设置为 0)上完成重新提交,或者 OS 是否应在 PASSIVE_LEVEL(PrePresentNeeded 设置为 1)执行此调用。 如果 KMD 仍然返回STATUS_RETRY,即使该 VidPnSourceId 上没有更多挂起的翻转,则此条件被视为 无效的参数失败。
重要的是 MaxHwQueuedFlips 的值仍反映可排队到 MPO 平面的简单仅地址更改翻转的最大数量。 STATUS_RETRY 机制应用于无法深度排队的更复杂的翻转请求,例如平面配置更改。
无效参数失败
在硬件翻转队列模型中,OS 对失败的翻转请求的处理被重新设计,以实现更好的可调试性。 当 KMD 无法处理翻转请求时,则会从 DxgkDdiSetVidPnSourceAddressWithMultiPlaneOverlay3 返回 STATUS_INVALID_PARAMETER。 根据 OS 设置,OS 将执行以下操作之一:
- 内核调试器中断和 bug 检查:通常在开发/预发布版本上启用此行为,以便在故障情况发生时更好地进行可调试性。
- 实时内核转储后跟 TDR:零售最终用户行为。
指定 VSync 中断行为
为了在排队翻转方案中实现节能,OS 通常会暂停常规 VSync 中断,使 CPU 保持低功率状态。 但是,某些翻转被标记为需要引发中断,以便应用程序观察已完成的演示批次并排队进一步工作。 在某些情况下,应用程序请求在每个 VSync 中断时唤醒,而不考虑是否有挂起的翻转请求。 相反,在完全空闲的系统上,VSync 中断将挂起,直到出现新的演示活动或 VSync 侦听器。
- 为了处理所有这些情况,引入了以下驱动程序回调和回调结构:DXGKDDI_SETINTERRUPTTARGETPRESENTID
- DXGKARG_SETINTERRUPTTARGETPRESENTID
KMD 在 DRIVER_INITIALIZATION_DATA 中提供一个指向其 DxgkDdiSetInterruptTargetPresentId 函数的指针OS 调用 DxgkDdiSetInterruptTargetPresentId 来指定目标 PresentId,该目标 PresentId 会在相应翻转完成后引发 VSync 中断。 此函数在设备中断级别(DIRQL)调用,以便与 DxgkDdiSetVidPnSourceAddress 和 VSync 中断同步。
与 DxgkDdiControlInterrupt 交互
当 VSync 中断通过 DxgkDdiControlInterrupt/DxgkDdiControlInterrupt2/DxgkDdiControlInterrupt3 完全禁用时,无论中断目标 PresentId 值如何,它们都将保持禁用状态。 KMD 需要存储最新的中断目标 PresentId,以便在再次启用 VSync 后可以遵循该 ID。
通过 DxgkDdiControlInterruptXxx 启用 VSync 中断时,中断目标 PresentId (pSetInterruptTargetPresentId) 提供精细的控制,如下所示:
- 当目标 PresentId 设置为 UINT64_MAX 时,在再次更改目标 PresentId 之前,不需要任何 VSync 中断。 VSync 中断已禁用,但需要 KMD 来实现 DXGK_VSYNC_DISABLE_KEEP_PHASE 行为才能重新启用中断。
- 当目标 PresentId 设置为 0 时,每个 VSync 都需要中断。
- 对于任何其他 PresentId 值,如果当前扫描的 PresentId >= InterruptTargetPresentId,则会引发中断。
当多个 MPO 平面可用时,如果任何平面需要 VSync 中断,则应引发 VSync 中断.