window 显示驱动开发-GPU 抢占(三)

实现中的内存映射注意事项

  1. 按照本指南创建支持 Windows 8 GPU 抢占模型的可靠驱动程序,并提供高质量的用户体验:
  2. 当 Dxgkrnl 计划程序发送抢占命令时,请求抢占 GPU 中的中间DMA缓冲区。 具有更精细粒度 DMA 中间缓冲区抢占的硬件设备有望提供更好的客户体验。
  3. 允许分页命令围栏ID重复使用:如果抢占请求导致硬件队列中的分页命令被抢占,Dxgkrnl 计划程序将重新提交使用原始围栏ID的被抢占分页命令,并且这些分页命令将在该引擎的任何其他命令之前安排执行。 将使用新分配的围栏 ID 重新提交非分页命令。
  4. 提供拆分 DMA 缓冲区的补丁位置列表。 有关详细信息,请参阅 拆分 DMA 缓冲区。
  5. 可以使用称为绑定泄漏检测的验证模式。 此验证模式遍历修补位置列表,并拒绝未解除绑定或未重新编程为每个拆分数据包分配的数据包。 某些硬件支持虚拟地址,允许额外的间接级别,使这种验证不必要。 在这种情况下,若要指示驱动程序选择退出验证模式,请将 NoDmaPatchingDXGK_VIDSCHCAPS 结构的成员设置为 1。
  6. 在 Windows 7 中,Dxgkrnl 计划程序保证按顺序执行与同一呈现命令对应的所有拆分 DMA 数据包,而无需切换到另一个呈现上下文。 在 Windows 8 抢占模型中,调度程序可以在两个拆分数据包之间执行渲染数据包,这两个拆分数据包对应于同一渲染命令,并可能来自不同的上下文。 因此,意识到抢占的驱动程序应以与常规完整数据包提交相同的方式处理拆分/部分 DMA 数据包提交。 具体而言,必须在此类提交的边界处保存或还原 GPU 状态。
  7. 在链接显示适配器 (LDA) 模式下广播到多个适配器时,抢占感知驱动程序不得更改拆分 DMA 缓冲区的内容,其中多个物理 GPU 链接到单个、更快、虚拟 GPU。 在 Windows 8 抢占模型中,Dxgkrnl 计划程序不再保证同步执行拆分数据包序列,而无需切换到另一个上下文。 更改拆分 DMA 数据包内容的驱动程序会损害数据包数据的完整性。 具体而言,如果数据包在另一个引擎上执行,它将对 DMA 缓冲区数据的同一副本进行操作。
  8. 在 Windows 8 GPU 抢先模型中,Dxgkrnl 调度程序为具有关联“提交时信号”同步基元的数据包启用抢先。 如果设备使用具有基于硬件的等待状态的“提交信号”同步基元,则必须支持在满足等待条件之前抢占等待指令的能力。

1. DMA 缓冲区抢占的精细粒度处理

硬件要求:支持在 DMA 缓冲区执行中间(而非仅边界)被抢占的设备,需提供更优用户体验(如减少 UI 延迟)。

驱动实现:

// 在 DxgkDdiSubmitCommand 中处理部分提交的 DMA 缓冲区
if (pSubmitCmd->Flags.PreemptionPending) {
    SaveGpuState();  // 保存当前 GPU 寄存器/上下文状态
    PartialDmaBuffer = SplitDmaBuffer(pSubmitCmd->pDmaBuffer, CurrentOffset);
    SubmitPartialBuffer(PartialDmaBuffer);
}

2. 分页命令围栏 ID 重用规则

抢占后行为:

  • 分页命令:使用原始围栏 ID 重新提交,优先执行。
  • 非分页命令:分配新围栏 ID,按常规队列处理。

驱动注意事项:需区分分页与非分页命令(通过 DXGK_DMAFLAGS_PAGING 标志)。

3. 拆分 DMA 缓冲区的修补列表

验证模式(绑定泄漏检测):

默认检查修补列表中的资源绑定完整性,拒绝未正确解绑的包。

硬件优化:若支持虚拟地址间接访问(如 GPU VA 空间),可禁用验证:

DXGK_VIDSCHCAPS VidSchCaps = {0};
VidSchCaps.NoDmaPatching = 1;  // 跳过验证

4. 抢占下的 GPU 状态管理

关键变更(vs Windows 7):

Windows 8 允许 高优先级任务插入拆分 DMA 包之间,驱动必须:

  • 在拆分包边界保存/恢复 GPU 状态。
  • 确保状态一致性(如着色器寄存器、渲染目标绑定)。

示例流程:

void HandleSplitDmaBuffer(DXGKARG_SUBMITCOMMAND* pCmd) {
    if (IsPreemptionPoint(pCmd->pDmaBuffer)) {
        SaveGpuContext();  // 保存当前状态
    }
    SubmitToGpu(pCmd->pDmaBuffer);
    if (IsPreemptionPoint(pCmd->pDmaBuffer)) {
        RestoreGpuContext();  // 恢复下一个包所需状态
    }
}

5. 链接显示适配器 (LDA) 的特殊处理

约束条件:在 LDA 模式下,多个物理 GPU 共享同一 DMA 缓冲区副本,驱动禁止修改拆分包内容。

驱动要求:

  • 将 DMA 缓冲区视为 只读,依赖硬件同步机制(如 GPU 原子操作)。
  • 若必须修改,需为每个物理 GPU 创建独立副本。

6. 提交时信号同步基元的抢占支持

硬件协作:若使用基于硬件的等待(如 DXGK_INTERRUPT_TYPE_WAIT),必须支持 在条件未满足时抢占等待指令。

实现示例:

NTSTATUS DxgkDdiInterruptRoutine(DXGKARG_INTERRUPT* pArgs) {
    if (pArgs->InterruptType == DXGK_INTERRUPT_TYPE_PREEMPTION) {
        if (IsGpuWaiting()) {
            ForceCancelWait();  // 中断硬件等待
        }
        TriggerPreemption();
    }
    return STATUS_SUCCESS;
}

 7. 关键验证与调试

场景 验证方法 调试工具
拆分 DMA 状态一致性 注入抢占请求,检查渲染结果是否正确。 GPU 调试器(如 NVIDIA Nsight、PIX)
LDA 数据完整性 多 GPU 环境下验证帧数据一致性。 WHCK LDA 测试套件
围栏 ID 重用 监控分页命令是否优先执行。 ETW 事件 DXGKRNL_PAGING_FENCE

你可能感兴趣的:(windows图形显示驱动开发,驱动开发,单片机,嵌入式硬件)