-
Notifications
You must be signed in to change notification settings - Fork 411
PSOs, Shaders, and Signatures
In order to render using DirectX 12, the complete description of the render state needs to be captured in a ID3D12PipelineState
interface object (PSO). Compiled shaders for all stages you use are bound to the PSO at creation time. In order to share data between the HLSL shader and the CPU, the ID3D12RootSignature
interface object describes how the shader expects parameters to be bound and is also part of the PSO.
Root signature management is one of the more challenging aspects of using DirectX 12. In Direct3D 11, you can think of every shader using the same 'mega signature', but in DirectX 12 you rarely need anything like the 128+ slots per stage that DirectX 11 provides. In DirectX Tool Kit for DirectX 12 we have a dozen or so different root signatures used internally used in different aspects.
Here's a basic root signature we use for BasicEffect
when texturing using the D3DX12 utility library and DirectXHelpers function CreateRootSignature
which combines the underlying D3D12SerializeRootSignature
and ID3D12Device::CreateRootSignature
calls:
// Create root signature.
enum RootParameterIndex
{
ConstantBuffer,
TextureSRV,
TextureSampler,
RootParameterCount
};
Microsoft::WRL::ComPtr<ID3D12RootSignature> rootSig;
{
D3D12_ROOT_SIGNATURE_FLAGS rootSignatureFlags =
D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |
D3D12_ROOT_SIGNATURE_FLAG_DENY_DOMAIN_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_GEOMETRY_SHADER_ROOT_ACCESS |
D3D12_ROOT_SIGNATURE_FLAG_DENY_HULL_SHADER_ROOT_ACCESS;
// Create root parameters and initialize first (constants)
CD3DX12_ROOT_PARAMETER rootParameters[RootParameterIndex::RootParameterCount] = {};
rootParameters[RootParameterIndex::ConstantBuffer].InitAsConstantBufferView(0, 0, D3D12_SHADER_VISIBILITY_ALL);
// Root parameter descriptor
CD3DX12_ROOT_SIGNATURE_DESC rsigDesc = {};
// Include texture and srv
CD3DX12_DESCRIPTOR_RANGE textureSRV(D3D12_DESCRIPTOR_RANGE_TYPE_SRV, 1, 0);
CD3DX12_DESCRIPTOR_RANGE textureSampler(D3D12_DESCRIPTOR_RANGE_TYPE_SAMPLER, 1, 0);
rootParameters[RootParameterIndex::TextureSRV].InitAsDescriptorTable(1, &textureSRV, D3D12_SHADER_VISIBILITY_PIXEL);
rootParameters[RootParameterIndex::TextureSampler].InitAsDescriptorTable(1, &textureSampler, D3D12_SHADER_VISIBILITY_PIXEL);
// use all parameters
rsigDesc.Init(_countof(rootParameters), rootParameters, 0, nullptr, rootSignatureFlags);
DX::ThrowIfFailed(CreateRootSignature(device, &rsigDesc, rootSig.GetAddressOf()));
}
In addition to programmatically building root signatures, they can also be declared in HLSL. The root signature above is described as:
#define RootSig \
"RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
" DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
" DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
" DENY_HULL_SHADER_ROOT_ACCESS )," \
"CBV(b0),"\
"DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
"DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
[RootSignature(RootSig)]
VSOutput VertexShader(VSInput vin)
{
...
}
On the Xbox One platform, it's best practice to do both programmatic root signatures and have matching HLSL root signatures to avoid triggering a second-phase compilation at runtime. On the PC/UWP platform, if you provide a programmatic root signature then any HLSL declared root signature is ignored.
Shaders are typically built offline at build time and loaded as binary blobs, or they can be compiled 'on-the-fly' from HLSL source files. The process of building these shaders is the same as it was in DirectX 11--see Writing custom shaders for a quick tutorial.
Using the ReadData.h helper, we can load these blobs at runtime:
auto vertexShaderBlob = DX::ReadData(L"VertexShader.cso");
auto pixelShaderBlob = DX::ReadData(L"PixelShader.cso");
The built-in shaders used by DirectX Tool Kit are included as headers containing C++ arrays to avoid the need to ship binary blobs as individual files.
UNDER DEVELOPMENT
UNDER DEVELOPMENT
In DirectX Tool Kit for DirectX 12, the individual Effects objects include per-device root signature and a per-instance pipeline state object. These are bound when the Apply method is invoked.
SimpleTriangle12 sample for PC, UWP, Xbox One XDK
All content and source code for this package are subject to the terms of the MIT License.
This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.
- Universal Windows Platform apps
- Windows desktop apps
- Windows 11
- Windows 10
- Xbox One
- Xbox Series X|S
- x86
- x64
- ARM64
- Visual Studio 2022
- Visual Studio 2019 (16.11)
- clang/LLVM v12 - v18
- MinGW 12.2, 13.2
- CMake 3.20