How D3D12 Debug Layer Tracks Resource State Decay
The DirectX 12 debug layer tracks resource state decay and implicit
promotion by maintaining a shadow tracking system alongside command list
recording and execution. Because resources such as buffers and
simultaneous-access textures can implicitly transition from
D3D12_RESOURCE_STATE_COMMON to specific access states
during draw calls and eventually decay back to COMMON, the
debug layer monitors per-subresource metadata at every draw, dispatch,
and barrier invocation. This article details the internal tracking
mechanisms, validation rules, and hazard detection logic the debug layer
uses to enforce correct resource usage across draw calls.
Shadow State Representation
At the core of the debug layer's validation architecture is an internal tracking structure instantiated for every created resource. For non-monolithic resources, this tracking occurs per subresource.
The tracking structure maintains:
- Current Known State: The logical state of the resource within the active command list.
- Initial State: The state of the resource prior to command list recording or at the start of an execution boundary.
- Implicit Transition Flags: A boolean or bitflag
denoting whether the resource arrived at its current state via an
explicit
ResourceBarrieror via implicit promotion fromD3D12_RESOURCE_STATE_COMMON. - Resource Classification: Flags identifying if the
resource is a buffer, a non-simultaneous-access texture, or a texture
created with
D3D12_RESOURCE_FLAG_ALLOW_SIMULTANEOUS_ACCESS.
Per-Draw Call State Evaluation
When a draw call (such as DrawInstanced or
DrawIndexedInstanced) is recorded, the debug layer
intercepts the API call and resolves all bound resources. This includes
vertex buffers, index buffers, constant buffer views (CBVs), shader
resource views (SRVs), render target views (RTVs), and unordered access
views (UAVs) bound via the current root signature and descriptor
tables.
For every bound subresource, the debug layer executes the following logic:
- State Compatibility Check: The debug layer
determines the required state for the draw call (e.g.,
D3D12_RESOURCE_STATE_VERTEX_AND_CONSTANT_BUFFERfor an input stream). It checks if the tracked current state matches the required state. - Implicit Promotion Verification: If the states do
not match, the debug layer checks if the resource is currently in
D3D12_RESOURCE_STATE_COMMON. If it is, and the resource type supports promotion (all buffers, or simultaneous-access textures for read/write states, and standard textures for non-depth read states):- The debug layer updates the tracked current state to the required state.
- It marks the resource as "implicitly promoted."
- Hazard Detection: If the resource is not in
COMMONand does not match the required state, the debug layer issues a validation error identifying a state mismatch hazard (such as a Read-After-Write or Write-After-Read conflict) due to a missing explicit barrier.
Persistence Across Draw Calls
Once a resource is implicitly promoted during a draw call:
- Promotion Persistence: The resource retains that promoted state for subsequent draw calls within the same command list.
- State Accumulation: If a subsequent draw call reads the resource via a different read state (for example, switching from a vertex buffer to a pixel shader SRV), the debug layer checks if the promotion rules allow combining read states without an explicit barrier. If permitted, the shadow state updates to a combined read bitmask.
- Promotion Invalidation: If a subsequent draw call
requires a state that cannot be reached via implicit promotion from the
current state (such as attempting an unordered write on an implicitly
read-promoted texture), the debug layer flags a validation failure
because the resource cannot decay back to
COMMONwithin the command list to allow re-promotion.
Decay Resolution Mechanics
Resource decay does not typically execute between consecutive draw calls within the same command list; instead, decay rules determine how states reset across boundaries:
- Buffer Decay at Command List End: Buffers and
simultaneous-access textures automatically decay to
D3D12_RESOURCE_STATE_COMMONwhen anExecuteCommandListscall completes. WhenClose()is called on a command list, the debug layer records the final state of all resources. Upon execution on the command queue, the debug layer validates whether the final state was explicit or implicit, then automatically resets buffer states toD3D12_RESOURCE_STATE_COMMONin its queue-level tracking structure. - Implicit Read Decay: Resources promoted implicitly
to read-only states also decay to
D3D12_RESOURCE_STATE_COMMONacrossExecuteCommandListsboundaries. The debug layer tracks the origin of the state transition; if flagged as implicit, it allows the resource to enter the next command list asCOMMONwithout an explicit barrier back toCOMMON. - Explicit State Retention: If a resource entered a
state via an explicit
ResourceBarrier, the debug layer tracks that it did not decay (unless it is a buffer on a copy/compute/direct list meeting the API decay criteria). It requires the application to maintain that state into subsequent command lists unless explicitly transitioned.
GPU-Based Validation (GBV) Layering
While standard CPU-side debug layer tracking catches mismatched states declared during API command recording, GPU-Based Validation (GBV) extends this tracking to runtime descriptor indices.
GBV modifies shaders to insert inline tracking code that checks descriptor table accesses during the actual execution of the draw call. If a shader indexes into a resource whose tracked state in the GPU-visible state table has decayed or was never promoted to the appropriate read/write state, the patch code generates an error event captured by the debug layer runtime, pin-pointing the exact draw call and resource identifier.