拆分 DMA 缓冲区

视频内存管理器使用拆分点将显示微型端口驱动程序提交的大型工作项划分为需要较少 GPU 资源执行的较小工作项。 例如,大型 DMA 缓冲区可能引用一组可能不适合本地视频内存或非本地内存的分配。 处理此类工作项的唯一方法是将其划分为多个需要较少 GPU 资源的较小工作项。

注意 DMA 缓冲区拆分和 DMA 缓冲区抢占是不同的独立概念。 即使在无法抢占 DMA 缓冲区的 GPU 系统上,显示微型端口驱动程序也必须始终支持 DMA 缓冲区拆分。 在具有无法保存和还原上下文的 GPU 的系统上,GPU 计划程序将 DMA 缓冲区的拆分部分安排回背对背,确保拆分部分不会与来自不同 GPU 上下文的另一个 DMA 缓冲区交错。 但是,应在拆分的 DMA 缓冲区的各部分之间提交分页缓冲区,因为在 DMA 缓冲区的拆分部分之间需要进行分页操作。 驱动程序用于生成应用程序 DMA 流的每个拆分点都由视频内存管理器使用。 提交的 DMA 缓冲区应在每个拆分点后重新编程足够的 GPU 状态,以考虑可能插入到该位置的潜在分页缓冲区。

若要指定拆分点,显示微型端口驱动程序为D3DDDI_PATCHLOCATIONLIST的 AllocationIndex 成员中引用的每个分配指定D3DDDI_PATCHLOCATIONLIST结构的 SplitOffsetSlotId 成员中的值。 为了跟踪特定 DMA 缓冲区中的分配使用情况,视频内存管理器使用驱动程序通过调用 DxgkDdiQueryAdapterInfo 函数提供的 DXGK_DRIVERCAPS 结构的 MaxAllocationListSlotId 成员创建数组的所需维度。 此数组在零处初始化,并在处理修补程序位置列表的拆分部分条目时填充。 修补程序位置的 D3DDDI_PATCHLOCATIONLISTSlotId 成员指示必须更新资源表的哪一行,而 SplitOffset 成员指示需要分配的 DMA 缓冲区中的偏移量。 DMA 缓冲区可以运行到 SplitOffset 指定的点,而无需 GPU 访问资源。 同样,如果新的补丁位置拆分部分条目引用相同的 SlotId,则以前的分配将替换为新的分配,并且不再需要以前的分配 (即,以前的分配可以分页) 。

在 DMA 缓冲区所需的资源中分页时,视频内存管理器通过从第一个元素开始并向下移动到最后一个元素来处理补丁位置列表。 驱动程序填充 的D3DDDI_PATCHLOCATIONLIST 元素在其 SplitOffset 成员中必须包含值;元素严格增加 (也就是说,分配必须按照它们在流) 中的使用顺序显示。 分配中的视频内存管理器页,这些页面按照提供的顺序在修补程序位置列表中引用。 当到达某个点时,视频内存管理器由于内存不足而无法再分页分配,视频内存管理器会将正在准备的 DMA 缓冲区的当前部分提交到 GPU 计划程序执行。 DMA 缓冲区从上一个拆分点的开头一直运行到为无法引入的分配指定的 SplitOffset 值。 提交后,视频内存管理器将使用资源表确定 DMA 流中当前拆分偏移量处所需的分配列表。 表上的所有分配都保留在其当前物理位置,而不再使用的其他分配可能会被逐出。 然后,视频内存管理器继续处理修补程序位置列表,可能会再次拆分多次。

每次绑定或取消分配时,驱动程序都应指定拆分点。 若要指定未绑定分配,驱动程序可以在 DXGK_ALLOCATIONLIST 结构的 hDeviceSpecificAllocation 成员中指定 NULL 分配句柄,并在关联的D3DDDI_PATCHLOCATIONLISTSlotId 成员中指定适当的值。 驱动程序应取消绑定大型资源,以增加视频内存管理器解决复杂内存放置问题的可能性。

同样,驱动程序应在每个拆分点重新编程大型资源。 获取拆分点时,视频内存管理器被迫将以前绑定的分配留给以前的分配。 这会导致内存碎片,导致无法解决复杂的内存放置问题,如果不是以前绑定的分配限制,则可能已经解决了这些问题。 在计算拆分点的状态时,视频内存管理器将确定正在该拆分点重新编程的槽标识符 (SlotId) , (即,每个与) 的其他元素共享相同 SplitOffset 值的修补程序位置列表元素,并忽略此拆分点上的放置限制。 例如,如果驱动程序使用 64 MB 纹理,则在每个拆分点重新编程该纹理可让视频内存管理器在必要时在拆分点之间灵活地在内存中移动该纹理。