资源生存期和同步

与 Direct3D 12 一样,DirectML 应用程序必须(为了避免未定义的行为)正确管理对象生存期和 CPU 与 GPU 之间的同步。 DirectML 遵循与 Direct3D 12 相同的资源生存期模型。

  • DirectML 使用强引用计数维护两个 CPU 对象的生存期依赖关系。 应用程序不需要手动管理 CPU 生存期依赖项。 例如,每个子设备包含对其父设备的强引用。
  • GPU 对象之间的生存期依赖关系(或跨 CPU 和 GPU 的依赖项)不会自动管理。 应用程序负责确保 GPU 资源的生存期至少延续至 GPU 上使用该资源的所有作业完成执行。

DirectML 设备

DirectML 设备是线程安全的无状态工厂对象。 每个子设备(见 IDMLDeviceChild)都对其父 DirectML 设备(见 IDMLDevice)具有强引用。 这意味着,始终可以从任何设备子接口检索父设备接口。

相应地,DirectML 设备包含对用于创建它的 Direct3D 12 设备的强引用(请参阅 ID3D12Device 和派生接口)。

由于 DirectML 设备是无状态的,因此它是隐式线程安全的。 可以在 DirectML 设备上同时从多个线程调用方法,而无需外部同步。

但是,不同于 Direct3D 12 设备的是,DirectML 设备不是单一实例对象。 你可以根据需要创建任意数量的 DirectML 设备。 不过,你不能混合和匹配属于不同设备的子设备。 例如, IDMLBindingTableIDMLCompiledOperator 是两种类型的设备子级(两种接口都直接或间接派生自 IDMLDeviceChild)。 如果运算符和绑定表属于不同的 DirectML 设备实例,则不能使用绑定表(IDMLBindingTable)绑定运算符(IDMLCompiledOperator)。

由于 DirectML 设备不是单一实例对象,因此要基于每台设备执行设备删除,而非如同使用 Direct3D 12 设备时那样作为进程范围事件执行删除。 有关详细信息,请参阅 在 DirectML 中处理错误和设备删除

GPU 资源的生存期要求

与 Direct3D 12 一样,DirectML 不会在 CPU 和 GPU 之间自动同步;它也不会在 GPU 使用资源时自动保持活动状态。 相反,这些是你的应用程序的责任。

执行包含 DirectML 调度的命令列表时,应用程序必须确保 GPU 资源保持活动状态,直到使用这些资源的所有工作都已完成 GPU 上的执行。

对于 DirectML 运算符的 IDMLCommandRecorder::RecordDispatch,其中包含以下对象。

并非所有 DirectML 接口都表示 GPU 资源。 例如,绑定 表不需要保持 活动状态,直到使用绑定表的所有调度在 GPU 上完成执行。 这是因为绑定表本身不拥有任何 GPU 资源。 而描述符堆拥有这些。 因此,基础 描述符堆 是必须保持活动状态的对象,直到执行完成,而不是绑定表本身。

Direct3D 12 中存在类似的概念。 命令 分配器 必须保持活动状态,直到使用命令的所有执行已在 GPU 上完成;因为它拥有 GPU 内存。 但是,命令 列表 不具有 GPU 内存,因此可以在提交执行后立即重置或释放它。

在 DirectML 中,编译的运算符(IDMLCompiledOperator)和运算符初始值设定项(IDMLOperatorInitializer)都直接拥有 GPU 资源,因此必须在使用它们的所有调度完成 GPU 上的执行之前保持活动状态。 此外,正在使用的任何 Direct3D 12 资源(如命令分配器、描述符堆、缓冲区等)都必须同样由您的应用程序保持活动状态。

如果在 GPU 仍在使用对象时过早释放对象,则结果为未定义行为,这可能导致设备删除或其他错误。

CPU 和 GPU 同步

DirectML 本身不会提交任何工作以在 GPU 上执行。 相反,IDMLCommandRecorder::RecordDispatch 方法会将该工作的调度记录到命令列表中,以供以后执行。 然后,应用程序必须关闭并提交其命令列表以供执行,方法是调用 ID3D12CommandQueue::ExecuteCommandLists,就像任何 Direct3D 12 命令列表一样。

由于 DirectML 本身不会提交任何工作以在 GPU 上执行,因此也不会创建任何围栏,也不会代表你执行任何形式的 CPU/GPU 同步。 应用程序有责任使用适当的 Direct3D 12 基元来等待提交的工作在 GPU 上完成执行(如有必要)。 有关详细信息,请参阅 ID3D12FenceID3D12CommandQueue::Signal

另请参阅