分配列表消失后,视频内存管理器(VidMm)不再能够查看特定命令缓冲区中引用的分配。 因此,VidMm 不再能够跟踪分配使用情况并处理相关同步。 此责任现在属于用户模式驱动程序(UMD)。 具体而言,UMD 需要处理与直接 CPU 访问分配和重命名相关的同步。
VidMm 以安全的方式异步延迟销毁分配,对调用线程非阻塞且性能良好。 因此,UMD 不必担心必须延迟分配销毁。 当 VidMm 收到分配销毁请求时,默认认为在销毁请求之前已排队的命令可能会访问正在被销毁的分配。 因此,VidMm 将销毁操作推迟到排队命令完成之后。 如果 UMD 知道挂起的命令无法访问被销毁的分配,它可以指示 VidMm 在调用 Deallocate2 或 DestroyAllocation2 时设置 AssumeNotInUse 标志来处理请求,而无需等待。
Lock2
UMD 负责处理与直接 CPU 访问相关的正确同步。 具体而言,UMD 需要做到以下几点:
支持无覆盖和放弃锁语义,这意味着 UMD 需要实现自己的重命名方案。
对于需要同步的映射操作(即不是上述的无覆盖或放弃):
- 如果尝试访问当前正忙的分配,并且调用方请求锁定操作不阻止调用线程(D3D11_MAP_FLAG_DO_NOT_WAIT),则返回WasStillDrawing。
- 或者,如果未设置 D3D11_MAP_FLAG_DO_NOT_WAIT 标志,请等待分配可供 CPU 访问。 UMD 需要实现非轮询等待。 UMD 将使用新的上下文监视机制。
目前,UMD 仍需要调用 LockCb 和 UnlockCb,以要求 VidMm 为 CPU 访问设置分配。 在大多数情况下,UMD 能够在整个生存期内保留分配映射。 但是,将来, LockCb 和 UnlockCb 将弃用,以支持新的 Lock2Cb 和 Unlock2Cb 调用。 这些较新的回调的目标是使用一组全新的参数和标志提供一种全新的、清晰的实现。
从 WDDM 版本 2 中删除 swizzling 范围。 驱动程序开发人员有责任删除对 LockCb 调用时重排范围的依赖关系,因为他们正在转向基于 Lock2Cb 的实现。
Lock2Cb 公开为获取分配虚拟地址的简单方法。 根据分配类型和当前所处的段,有一些限制。
驱动程序指示某个段是否可通过 CpuVisible 标志(位于DXGK_SEGMENTDESCRIPTOR结构的 Flags 成员中)访问 CPU。
对于 CPU 可访问的分配:
- CPU 可访问的缓存分配必须驻留在一个光圈段中,或者不驻留,以便被锁定。 我们无法保证 CPU 与图形处理单元(GPU)上的内存段之间的缓存一致性。
- CPU 可访问的分配位于完全可由 CPU 访问的内存段(使用可调整大小的 BAR 调整大小)中,保证能够锁定并返回虚拟地址。 此方案中不需要任何特殊约束。
- 位于非 CPU 可访问内存段的 CPU 可访问内存分配(无论是否能访问 CpuHostAperture)可能由于各种原因而无法映射到 CPU 虚拟地址。 如果 CpuHostAperture 空间不足或分配未指定光圈段,则无法获取虚拟地址。 因此,在非 CPU 可访问的内存段中,所有 CPU 可访问的分配必须在其支持的段集中包含一个孔径段。 此要求保证 VidMm 能够在系统内存中放置分配并提供虚拟地址。
- 保证 CPU 可访问的分配已位于系统内存(和/或已映射到光圈段)内,并确保其正常运行。
对于不可访问的 CPU 分配:
- CPU 可访问的分配由不能直接指向 GPU 帧缓冲区的部分对象支持。 若要锁定无法被 CPU 访问的分配,分配必须支持段集中支持的某个孔径段,或已位于系统内存中(不能驻留于设备上)。
如果在某个分配尚未驻留于设备上时成功锁定分配,而该分配又不支持光圈段,则在锁定期间不得将该分配提交到内存段。
Lock2 当前不包含任何标志, 保留 标志位必须全部为 0。
CpuHostAperture
为了更好地支持在调整 BAR 失败时使用无法被 CPU 访问的内存段进行锁定,CpuHostAperture 已在 PCI 区间中提供。 CpuHostAperture 充当基于页面的管理器,然后可以通过 DxgkDdiMapCpuHostAperture设备驱动程序接口 (DDI) 函数直接映射到视频内存区域。 然后,VidMm 可以将一系列虚拟地址空间直接映射到 CpuHostAperture 的非连续范围,并让 CpuHostAperture 映射到视频内存,而无需重排范围。
CPU 可以在不可 CPU 访问的内存段内引用的最大可锁定内存量限制为 CpuHostAperture 的大小。 有关向 DirectX 图形内核公开 CpuHostAperture 的详细信息,请参阅 CPU 主机光圈。
I/O 一致性
在目前 x86/x64 上,所有 GPU 都必须支持基于 PCIe 的 I/O 一致性,以便 GPU 能够读取或写入可缓存的系统内存图面,并保持与 CPU 的一致性。 从 GPU 的角度将图面映射为缓存一致时,GPU 需要在访问图面时窥探 CPU 缓存。 这种形式的内存一致性通常用于需要 CPU 读取的资源,例如某些缓存表面。
在某些 Arm 平台上,硬件中不支持 I/O 一致性。 在这些平台上,需要通过手动使 CPU 缓存层次结构失效来模拟 I/O 一致性。 VidMm 通过跟踪来自 GPU(分配列表的读写操作)和 CPU(映射操作、读写)的分配活动来执行此操作。 VidMm 在确定缓存可能包含以下任一内容时发出缓存失效:
- 需要写回的数据(CPU 写入、GPU 读取)
- 需要被无效化的过时数据(GPU 写入,CPU 读取)。
在没有 I/O 一致性的平台上,跟踪分配的 CPU 和 GPU 访问的责任由 UMD 负责。 图形内核提供了一个新的 Invalidate CacheDDI,供 UMD 用于将可缓存分配关联的虚拟地址范围写回并使其失效。 在不支持 I/O 一致性的平台上,需要 UMD 在 CPU 写入后、GPU 读取之前以及写入后和 CPU 读取之前调用此函数。 后者起初似乎不合时宜。 但是,由于 CPU 在 GPU 写入到内存之前可能具有推测性读取数据,因此有必要使所有 CPU 缓存失效,以确保 CPU 从 RAM 重新读取数据。