上下文监视

本文提供有关上下文监视的信息,该监视允许在 GPU 引擎之间或跨 CPU 核心和 GPU 引擎灵活同步。 受监视围栏对象是隔离同步的高级形式,它允许 CPU 核心或 GPU 引擎向特定围栏对象发出信号或等待。

受监视围栏创建

Direct3D 运行时使用 D3DDDI_MONITORED_FENCE 同步对象类型调用用户模式驱动程序的 (UMD) CreateSynchronizationObjectCb 回调来创建受监视的围栏对象。

将创建受监视围栏对象以及以下属性:

  • 初始值
  • (指定其等待和信号行为的标志)

创建后,图形内核将返回由以下项组成的围栏对象:

说明
hSyncObject 同步对象的句柄。 用于在调用图形内核时引用它。
FenceValueCPUVirtualAddress 隔离值的只读映射 (CPU) 64 位。 从支持 I/O 一致性、UC (其他平台上的未缓存) 的平台上的 CPU 的角度来看,此地址映射为 WB (可缓存) 。 允许 CPU 通过仅读取此内存位置来跟踪围栏进度。 不允许 CPU 写入此内存位置。 若要发出围栏信号,需要 CPU 调用 SignalSynchronizationObjectFromCpuCb。 支持 IoMmu 的适配器应使用此地址进行 GPU 访问。 在这种情况下,地址映射为读写。
FenceValueGPUVirtualAddress gpu 的围栏值的读/写映射 (64 位) 。 此地址映射为在支持它的平台上需要 I/O 一致性。 为了发出围栏信号,允许 GPU 直接写入此 GPU 虚拟地址。 IoMmu GPU 不应使用此地址。

围栏值是一个 64 位值,其各自的虚拟地址在 64 位边界上对齐。 GPU 应声明它们是否能够通过添加的 DXGK_VIDSCHCAPS::No64BitAtomics 标志以原子方式更新 CPU 可见的 64 位值。 如果 GPU 只能以原子方式更新 32 位值,则 OS 会自动处理围栏环绕情况。 但是,它存在一个限制,即未完成的等待和信号围栏值不能超过 最后一个信号围栏值UINT_MAX/2。

GPU 信号

如果 GPU 引擎无法使用其虚拟地址写入受监视围栏,则用户模式驱动程序 (UMD) 使用 SignalSynchronizationObjectFromGpuCb 回调将软件信号数据包排队到 GPU 上下文。

为了从 GPU 发出围栏信号,UMD 直接在上下文命令流中插入围栏写入命令,而无需通过内核模式。 内核监视围栏进度的机制因特定 GPU 引擎是支持受监视围栏的基本实现还是高级实现而异。

当命令缓冲区在 GPU 上完成执行时,图形内核:

  • 浏览具有挂起等待的围栏对象列表,这些等待可针对此过程发出信号
  • 读取其当前围栏值
  • 确定是否有任何需要取消的等待。

GPU 等待

若要在 GPU 引擎上等待受监视的围栏,UMD 首先需要刷新其挂起的命令缓冲区,然后调用 WaitForSynchronizationObjectFromGpuCb ,指定 (hSyncObject) 和正在等待的围栏值。 图形内核将依赖项排队到其内部数据库,然后立即返回到 UMD,以便它可以继续在等待操作后面排队工作。 在满足等待操作之前,不会计划执行等待操作后提交的命令缓冲区。

CPU 信号

添加了 SignalSynchronizationObjectFromCpuCb 回调,以允许 CPU 向受监视围栏对象发出信号。 当 CPU 向受监视围栏对象发出信号时,图形内核会使用信号值更新围栏内存位置。 此值立即对任何用户模式读取器可见,并立即取消任何满意的等待。

CPU 等待

添加了 WaitForSynchronizationObjectFromCpuCb 回调,以允许 CPU 等待受监视的围栏对象。 可以使用两种形式的等待操作。 在第一种形式中, WaitForSynchronizationObjectFromCpuCb 将阻止,直到满足等待。 在第二种形式中, WaitForSynchronizationObjectFromCpuCb 采用 CPU 事件的句柄,该事件在满足等待条件后发出信号。