DirectX 12 Global Barriers vs Resource Transitions
DirectX 12 Enhanced Barriers modernize synchronization by replacing legacy resource transitions with explicit, fine-grained controls, including global barriers. While traditional resource transitions tightly couple execution synchronization, cache management, and memory layout modifications on a per-resource basis, global barrier synchronization decouples these operations, allowing developers to synchronize execution stages and memory access across all GPU resources simultaneously without altering physical layouts.
The Legacy Model: Individual Resource Transitions
In the legacy DirectX 12 synchronization model, developers control
synchronization primarily through
D3D12_RESOURCE_BARRIER_TYPE_TRANSITION. This approach
requires assigning specific resources or subresources from a defined
D3D12_RESOURCE_STATES state before an operation to a state
after.
- Coupled Responsibilities: An individual transition bundles three operations into a single command: waiting for previous GPU pipeline stages to complete (execution barrier), flushing and invalidating caches (memory barrier), and altering the underlying data layout if necessary (layout transition).
- Per-Resource Overhead: If multiple textures or buffers require cache flushing or pipeline synchronization, each must be individually declared. The GPU driver must iterate through these arrays of barriers, leading to increased CPU-side validation overhead and potential GPU stalls caused by conservative, redundant cache flushes.
The Updated Model: Global Barrier Synchronization
The Enhanced Barriers framework introduces
D3D12_GLOBAL_BARRIER, offering a broader, unified mechanism
to coordinate work between pipeline stages and memory caches without
specifying individual resources.
- Scope and Granularity: A global barrier applies to all memory access within the command stream. Instead of issuing dozens of individual barriers for multiple resources, a single global barrier synchronizes the pipeline and flushes appropriate caches across the entire device.
- Separation of Concerns: Global barriers separate
execution and memory synchronization from layout transitions:
- Synchronization Stages (
SyncBefore/SyncAfter): Explicitly states which pipeline stages must complete before subsequent stages begin (e.g., waiting for all compute shader writes to finish before starting a pixel shader). - Access Types (
AccessBefore/AccessAfter): Explicitly dictates what cache operations must occur, such as making unordered access writes visible to shader read operations.
- Synchronization Stages (
- No Layout Modification: Unlike resource
transitions, global barriers cannot change the layout of a texture (for
example, transitioning from a render target to a shader-readable
format). Layout transitions remain exclusively within dedicated texture
barriers (
D3D12_TEXTURE_BARRIER).
Key Differences
| Feature | Legacy Resource Transitions | Global Barriers |
|---|---|---|
| Target Scope | Individual resource or subresource | Entire GPU memory and pipeline |
| Layout Changes | Combined with execution and memory sync | Not supported; execution and memory sync only |
| State Tracking | Implicit; manages transitions between rigid states | Explicit; controls specific sync stages and cache visibilities |
| Batch Efficiency | Declaring multiple resources scales CPU and driver work | Synchronizes all resources in a single, high-efficiency call |
When to Use Each Approach
Global barrier synchronization is ideal for compute-to-compute or general resource dependencies where data layouts do not change, such as when numerous unordered access views (UAVs) written by one dispatch are immediately read by another. Instead of declaring a UAV barrier or transition for every buffer and texture, a single global barrier handles execution synchronization and cache visibility simultaneously.
Individual resource transitions—now handled via explicit texture barriers—are reserved strictly for cases where a resource must physically reconfigure its memory format or tiling arrangement to be consumed by different hardware units, such as transitioning a depth-stencil buffer to a readable texture.