同步
图形处理器旨在并行执行尽可能多的工作。 任何依赖于先前 GPU 工作的 GPU 工作都必须在访问相关数据之前同步。
增强型屏障接口使用显式 SyncBefore 和 SyncAfter 值作为逻辑位字段掩码。 在执行屏障之前,屏障必须等待所有前面的命令 SyncBefore 范围完成。 同样,屏障必须阻止所有后续的 SyncAfter 范围,直到屏障完成。 D3D12DDI_BARRIER_SYNC 指定 GPU 工作相对于屏障的同步范围。
布局转换
纹理子资源可以为各种访问方法使用不同的布局。 例如,当用作呈现目标或深度模具时,纹理通常会被压缩;对于着色器读取或复制命令,纹理通常不会被压缩。 纹理屏障使用 LayoutBefore 和 LayoutAfter D3D12DDI_BARRIER_LAYOUT 值来描述布局转换。
布局转换仅适用于纹理,因此它们仅在 D3D12DDI_TEXTURE_BARRIER 数据结构中表示。
LayoutBefore 和 LayoutAfter 都必须与执行屏障的队列类型兼容。 例如,计算队列无法将子资源转换到或转换出 D3D12DDI_BARRIER_LAYOUT_RENDER_TARGET。
为了提供定义完善的屏障排序,在完成一系列屏障后,子资源的布局是序列中的最终 LayoutAfter。
访问转换
由于许多 GPU 写入操作都是缓存的,因此从写入访问到另一个写入访问或只读访问的任何障碍都可能需要缓存刷新。 增强型屏障 API 使用访问转换来指示子资源的内存需要对特定的新访问类型可见。 与布局转换一样,如果已知相关子资源的内存已经可用于所需用途,则可能不需要一些访问转换。
访问转换表示如下:
- 对于纹理,作为 D3D12DDI_TEXTURE_BARRIER 结构的一部分。
- 对于缓冲区,作为 D3D12DDI_BUFFER_BARRIER 结构的一部分。
访问转换不执行同步。 预计依赖访问之间的同步将使用屏障中适当的 SyncBefore 和 SyncAfter 值来处理。
AccessBefore 对于指定的 AccessAfter 可见,并不能保证资源内存对于不同的访问类型也是可见的。 例如:
MyTexBarrier.AccessBefore=D3D12DDI_BARRIER_ACCESS_UNORDERED_ACCESS;
MyTexBarrier.AccessAfter=D3D12DDI_BARRIER_ACCESS_SHADER_RESOURCE;
此访问转换表示后续着色器读取访问依赖于前面的无序访问写入。 但是,如果硬件能够直接从 UAV 缓存读取着色器资源,则驱动程序可能实际上不会刷新 UAV 缓存。
D3D12DDI_BARRIER_ACCESS_COMMON
D3D12DDI_BARRIER_ACCESS_COMMON 是一种特殊的访问类型,表示任何布局兼容的访问。 转换为 D3D12DDI_BARRIER_ACCESS_COMMON 意味着子资源数据必须可用于屏障后的任何布局兼容访问。 由于缓冲区没有布局,因此 D3D12DDI_BARRIER_ACCESS_COMMON 仅表示任何与缓冲区兼容的访问。
在屏障中将 D3D12DDI_BARRIER_ACCESS_COMMON 指定为 AccessBefore 表示所有写入访问类型的集合。 不建议将 D3D12DDI_BARRIER_ACCESS_COMMON 用作 AccessBefore,因为这可能会导致代价高昂的意外缓存刷新。 而是鼓励开发人员只使用最严格要求的写入访问位,以适当地约束屏障开销。 当 AccessBefore 设置为 D3D12DDI_BARRIER_ACCESS_COMMON 时,将发出调试层警告。
单队列同时访问
增强型屏障允许对同一缓冲区进行并发读/写操作,或在同一命令队列中同时访问纹理。
缓冲区和同时访问资源始终支持来自一个队列的写入访问,以及来自一个或多个其他队列的并发、非依赖、读取访问。 这种支持是因为此类资源始终使用 COMMON 布局,并且没有读/写危险,因为读取不能依赖于并发写入。 旧资源屏障规则禁止将写入状态位与任何其他状态位组合在一起。因此,使用旧资源屏障不能在同一队列中同时读取和写入资源。
一次一个写入策略仍然适用,因为两个看似不重叠的写入区域可能仍然有重叠的缓存行。
子资源范围
开发人员通常希望转换一系列子资源。 一个例子是为给定的纹理数组转换完整的 mip 链,或为所有数组切片转换单个 mip 级别。 增强型屏障允许开发人员使用 D3D12DDI_BARRIER_SUBRESOURCE_RANGE 结构转换逻辑上相邻的子资源范围。 旧资源状态转换屏障仅为开发人员提供了以原子方式转换所有子资源状态或单个子资源状态的选项。