Sample Title: DX12 Compute Shader Sample
Description: This sample demonstrates the fundamental usage of compute shaders within the DirectX 12 API. It covers resource binding, dispatching compute operations, and how to integrate compute shaders into a graphics pipeline for tasks such as data processing, simulations, or general-purpose GPU computing.
Topics Covered: Compute Shaders, UAVs (Unordered Access Views), SRVs (Shader Resource Views), CBVs (Constant Buffer Views), Root Signatures, Pipeline State Objects (PSOs), GPU Compute Operations, DXGI Adapter Enumeration.
Platform: Windows 10 and later
API: DirectX 12
Compute shaders in DirectX 12 provide a powerful mechanism to leverage the parallel processing capabilities of the GPU for tasks that are not strictly rendering-related. This sample provides a practical implementation to get you started with compute shaders, illustrating common patterns and best practices.
RWTexture2D<float4> outputTexture : register(u0);
StructuredBuffer<float> inputBuffer : register(t0);
struct Constants
{
float scale;
uint frameCount;
};
cbuffer ConstantBuffer : register(b0)
{
Constants g_constants;
}
// Define the thread group size
[numthreads(8, 8, 1)]
void CSMain( uint3 dispatchThreadID : SV_DispatchThreadID )
{
// Get dimensions of the output texture
uint2 texDim;
outputTexture.GetDimensions(texDim.x, texDim.y);
// Calculate UV coordinates for the texture
float2 uv = float2(float)dispatchThreadID.x / float(texDim.x),
float(texDim.y) / float(texDim.y));
// Example computation: Use input buffer and constants
float sampledValue = inputBuffer[dispatchThreadID.x % 1024];
float4 outputColor = float4(uv.x, uv.y, sampledValue * g_constants.scale, 1.0f);
// Write to the output texture
outputTexture[uint2(dispatchThreadID.x, dispatchThreadID.y)] = outputColor;
}
{
"RootSignatureVersion": "1.0",
"GlobalRootSignature": null,
"RootParameters": [
{
"ParameterType": "DescriptorTable",
"DescriptorCount": 1,
"ShaderVisibility": "All",
"TableEntries": [
{
"DescriptorType": "UAV",
"RegisterRangeType": "Scalar",
"Offset": 0,
"RangeType": "Sequential"
}
]
},
{
"ParameterType": "DescriptorTable",
"DescriptorCount": 1,
"ShaderVisibility": "All",
"TableEntries": [
{
"DescriptorType": "SRV",
"RegisterRangeType": "Scalar",
"Offset": 0,
"RangeType": "Sequential"
}
]
},
{
"ParameterType": "DescriptorTable",
"DescriptorCount": 1,
"ShaderVisibility": "All",
"TableEntries": [
{
"DescriptorType": "CBuffer",
"RegisterRangeType": "Scalar",
"Offset": 0,
"RangeType": "Sequential"
}
]
}
],
"StaticSamplers": [],
"Constants": []
}
// Assume device, commandList, etc. are initialized
// Create root signature
// ... load root signature from JSON ...
Microsoft::WRL::ComPtr<ID3D12RootSignature> rootSignature;
// D3DCreate... or similar to create from blob
// Create compute shader pipeline state
Microsoft::WRL::ComPtr<ID3DBlob> computeShaderBlob;
// ... load compute shader bytecode ...
D3D12_COMPUTE_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.pRootSignature = rootSignature.Get();
psoDesc.CS.pShaderBytecode = computeShaderBlob.Get();
psoDesc.CS.BytecodeLength = computeShaderBlob.GetSize();
Microsoft::WRL::ComPtr<ID3D12PipelineState> computePSO;
ThrowIfFailed(device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&computePSO));
// Setup descriptors and bind resources
// ... create UAV, SRV, CBV descriptors ...
D3D12_CPU_DESCRIPTOR_HANDLE uavHandle; // Handle to UAV descriptor
D3D12_CPU_DESCRIPTOR_HANDLE srvHandle; // Handle to SRV descriptor
D3D12_CPU_DESCRIPTOR_HANDLE ccbvHandle; // Handle to CBV descriptor
// Record commands
commandList->SetComputeRootSignature(rootSignature.Get());
commandList->SetPipelineState(computePSO.Get());
// Bind descriptors to correct root parameter indices
commandList->SetComputeRootDescriptorTable(0, uavHandle); // UAV is at index 0
commandList->SetComputeRootDescriptorTable(1, srvHandle); // SRV is at index 1
commandList->SetComputeRootDescriptorTable(2, ccbvHandle); // CBV is at index 2
// Dispatch the compute shader
UINT threadGroupCountX = (outputTextureWidth + 7 ) / 8;
UINT threadGroupCountY = (outputTextureHeight + 7 ) / 8;
commandList->Dispatch(threadGroupCountX, threadGroupCountY, 1);
To run this sample, you will need:
Download the complete sample from the DirectX Samples Repository.
This sample serves as a foundational step into the world of DirectX 12 compute shaders. Experiment with the code, modify parameters, and observe the results to gain a deeper understanding of GPU-driven computation.