GPU-based validation and the Direct3D 12 Debug Layer

This topic describes how to make best use of the Direct3D 12 Debug Layer. GPU-based validation (GBV) enables validation scenarios on the GPU timeline that are not possible during API calls on the CPU. GBV is available starting with the Graphics Tools for Windows 10 Anniversary Update.

Purpose of GPU-based validation

GPU-based validation helps to identify the following errors:

  • Use of uninitialized or incompatible descriptors in a shader.
  • Use of descriptors referencing deleted Resources in a shader.
  • Validation of promoted resource states and resource state decay.
  • Indexing beyond the end of the descriptor heap in a shader.
  • Shader accesses of resources in incompatible state.
  • Use of uninitialized or incompatible Samplers in a shader.

GBV works by creating patched shaders that have validation added directly to the shader. The patched shaders inspect root arguments and resources accessed during shader execution and report errors to a log buffer. GBV also injects extra operations and Dispatch calls into the application command lists to validate and track changes to resource state imposed by the command list on the GPU-timeline.

Because GBV requires the ability to execute shaders, COPY command lists are emulated by a COMPUTE command list. This may potentially change how hardware performs copies though the end result should not be changed. The application will still perceive these are COPY command lists and the debug layer will validate them as such.

Turning on GPU-based validation

GBV can be forced on using the DirectX Control Panel (DXCPL) by forcing on the Direct3D 12 Debug Layer and additionally forcing on GPU-based validation (new tab in the control panel). Once enabled, GBV will remain enabled until the Direct3D 12 device is released. Alternatively, GBV can be enabled programmatically prior to creating the Direct3D 12 Device:

void EnableShaderBasedValidation()
    CComPtr<ID3D12Debug> spDebugController0;
    CComPtr<ID3D12Debug1> spDebugController1;

Generally, you should run your code with the debug layer enabled most of the time. However, GBV can slow things down a lot. Developers may consider enabling GBV with smaller data sets (for example, engine demos or small game levels with fewer PSO’s and resources) or during early application bring-up to reduce performance problems. With larger content consider turning on GBV on one or two test machines in a nightly test pass.

Debug output

GBV produces debug output after a call to ExecuteCommandLists completes execution on the GPU. Since this is on the GPU-timeline the debug output may be asynchronous with other CPU-timeline validation. Application developers may want to inject their own wait-after-execute to synchronize debug output.

GBV output identifies where in a shader an error occurred, along with the current draw/dispatch count and identities of related objects (e.g. command list, queue, PSO, etc).

Example debug message

The following error message indicates that a resource named “Main Color Buffer” was accessed in a shader as a shader resource but was in the unordered access state when the shader ran on the GPU. Additional information, such as the location in the shader source, the name of the command list and the Draw count (Draw Index), and the names of related D3D interface objects are also provided.

D3D12 ERROR: Incompatible resource state: Resource: 0x0000016F61A6EA80:'Main Color Buffer', 
Subresource Index: [0], 
Descriptor heap index: [0], 
Binding Type In Descriptor: SRV, 
Shader Stage: PIXEL, 
Root Parameter Index: [0], 
Draw Index: [0], 
Shader Code: E:\FileShare\MiniEngine_GitHub_160128\MiniEngine_GitHub\Core\Shaders\SharpeningUpsamplePS.hlsl(37,2-59), 
Asm Instruction Range: [0x138-0x16b], 
Asm Operand Index: [3], 
Command List: 0x0000016F6F75F740:'CommandList', SRV/UAV/CBV Descriptor Heap: 0x0000016F6F76F280:'Unnamed ID3D12DescriptorHeap Object', 
Sampler Descriptor Heap: <not set>, 
Pipeline State: 0x0000016F572C89F0:'Unnamed ID3D12PipelineState Object',  

Debug Layer APIs

To enable the debug layer, call EnableDebugLayer.

To enable GPU-based validation, call SetEnableGPUBasedValidation, and refer to the methods of the following interfaces:

Refer to the following enumerations and structures: