用户模式工作提交的 DDI
KMD 实现的 DDI
为 KMD 添加了以下内核模式 DDI,以实现对用户模式工作提交的支持。
- DxgkDdiCreateDoorbell。 当 UMD 调用 D3DKMTCreateDoorbell 为 HWQueue 创建Ring时, Dxgkrnl 会对此函数进行相应的调用,以便 KMD 可以初始化其Ring结构。
- DxgkDdiConnectDoorbell。 当 UMD 调用 D3DKMTConnectDoorbell 时,Dxgkrnl 会对该函数进行相应调用,以便 KMD 可以提供映射到物理Ring位置的 CPUVA,并在 HWQueue 对象、Ring对象、Ring物理地址、GPU 计划程序等之间进行所需连接。
- DxgkDdiDisconnectDoorbell。 当 OS 想要断开特定Ring的连接时,会使用此 DDI 调用 KMD。
- DxgkDdiDestroyDoorbell。 当 UMD 调用 D3DKMTDestroyDoorbell 时,Dxgkrnl 对此函数进行相应的调用,以便 KMD 可以销毁其Ring结构。
- DxgkDdiNotifyWorkSubmission。 当 UMD 调用 D3DKMTNotifyWorkSubmission 时,Dxgkrnl 对此函数进行相应的调用,以便 KMD 可以收到新工作提交的通知。
Dxgkrnl 实现的 DDI
DxgkCbDisconnectDoorbell 回调由 Dxgkrnl 实现。 KMD 可以调用此函数来通知 Dxgkrnl KMD 需要断开特定Ring的连接。
HW 队列进度围栏更改
在 UM 工作提交模型中运行的硬件队列仍有一个单调递增的进度围栏值的概念,UMD 在命令缓冲区完成后生成和写入该值。 为了使 Dxgkrnl 知道特定硬件队列是否具有挂起的工作,UMD 需要在将新的命令缓冲区追加到环形缓冲区并使其对 GPU 可见之前更新排队进度围栏值。 CreateDoorbell.HwQueueProgressFenceLastQueuedValueCPUVirtualAddress 是最新排队值读取/写入用户模式进程映射。
UMD 必须确保在新提交对 GPU 可见之前立即更新排队值。 以下步骤是推荐的操作顺序。 它们假定 HW 队列处于空闲状态,最后一个完成的缓冲区的进度围栏值为 N。
- 生成一个新的进度围栏值 N+1。
- 填写命令缓冲区。 命令缓冲区的最后一个指令是写入 N+1 的进度围栏值。
- 通过将 (HwQueueProgressFenceLastQueuedValueCPUVirtualAddress) 设置为 N+1,通知 OS 新排队的值。
- 通过将命令缓冲区添加到环形缓冲区,使命令缓冲区对 GPU 可见。
- 触发Ring。
正常和异常进程终止
以下事件序列发生在正常进程终止期间。
对于设备/上下文的每个 HWQueue:
- Dxgkrnl 调用 DxgkDdiDisconnectDoorbell 以断开Ring的连接。
- Dxgkrnl 等待最后一个排队的 HwQueueProgressFenceLastQueuedValueCPUVirtualAddress 在 GPU 上完成。 环形缓冲区/环形缓冲区控制分配保持驻留。
- Dxgkrnl 的等待已得到满足,现在可以销毁环形缓冲区/环缓冲区控制分配以及Ring和 HWQueue 对象。
以下事件序列发生在异常进程终止期间。
- Dxgkrnl 将设备标记为出错。
- 对于每个设备上下文,Dxgkrnl 调用 DxgkddiSuspendContext 以挂起上下文。 环形缓冲区/环形缓冲区控制分配仍然驻留。 KMD 抢占上下文,并将其从其 HW 运行列表中删除。
- 对于上下文的每个 HWQueue,Dxglrnl:
- 调用 DxgkDdiDisconnectDoorbell 以断开Ring的连接。
- 销毁环形缓冲区/环形缓冲区控制分配,以及Ring和 HWQueue 对象。