Skip to content

CommonStates

Chuck Walbourn edited this page Apr 21, 2023 · 33 revisions
DirectXTK

CommonStates is a class which defines the most common combinations of Direct3D rendering states. This is simliar to the XNA Game Studio 4 (Microsoft.Xna.Framework.Graphics.BlendState, DepthStencilState, RasterizerState, SamplerState) design.

Related tutorials: Sprites and textures

Header

#include <CommonStates.h>

Initialization

The CommonStates constructor requires a Direct3D 12 device.

std::unique_ptr<CommonStates> states;
states = std::make_unique<CommonStates>(device);

For exception safety, it is recommended you make use of the C++ RAII pattern and use a std::unique_ptr or std::shared_ptr

Many methods of this class are static. You do not need to create an instance of CommonStates to use them.

Usage

The static methods provide a D3D12_*_DESC structure which can be used to create a Pipeline State Object (PSO):

D3D12_GRAPHICS_PIPELINE_STATE_DESC psoDesc = {};
psoDesc.RasterizerState = CommonStates::CullNone;
psoDesc.BlendState = CommonStates::Opaque;
psoDesc.DepthStencilState = CommonStates::DepthDefault;

...

DX::ThrowIfFailed(
    device->CreateGraphicsPipelineState(&psoDesc,
        IID_PPV_ARGS(m_pipelineState.ReleaseAndGetAddressOf())));

They are typically used with EffectPipelineStateDescription:

RenderTargetState rtState(m_deviceResources->GetBackBufferFormat(),
    m_deviceResources->GetDepthBufferFormat());

EffectPipelineStateDescription pd(
    &VertexPositionColor::InputLayout,
    CommonStates::Opaque,
    CommonStates::DepthDefault,
    CommonStates::CullNone,
    rtState);

Blending State

  • static const D3D12_BLEND_DESC Opaque;
  • static const D3D12_BLEND_DESC AlphaBlend;
  • static const D3D12_BLEND_DESC Additive;
  • static const D3D12_BLEND_DESC NonPremultiplied;

Typical usage

For standard drawing, typically you should make use of Opaque.

For drawing alpha-blended objects, you should use AlphaBlend if using premultiplied alpha, or NonPremultiplied if using 'straight' alpha.

For multipass rendering, you'd typically use Additive.

Depth/Stencil State

  • static const D3D12_DEPTH_STENCIL_DESC DepthNone;
  • static const D3D12_DEPTH_STENCIL_DESC DepthDefault;
  • static const D3D12_DEPTH_STENCIL_DESC DepthRead;
  • static const D3D12_DEPTH_STENCIL_DESC DepthReverseZ;
  • static const D3D12_DEPTH_STENCIL_DESC DepthReadReverseZ;

Typical usage

For standard rendering with a z-buffer, you should use DepthDefault. If using a reverse z-buffer, then you should use DepthReverseZ.

For drawing alpha blended objects (which is typically done after all opaque objects have been drawn), use DepthRead which will respect the existing z-buffer values, but will not update them with 'closer' pixels.

For drawing objects without any depth-sort at all, use DepthNone.

Rasterizer State

  • static const D3D12_RASTERIZER_DESC CullNone;
  • static const D3D12_RASTERIZER_DESC CullClockwise;
  • static const D3D12_RASTERIZER_DESC CullCounterClockwise;
  • static const D3D12_RASTERIZER_DESC Wireframe;

Typical usage

For default geometry winding use CullCounterClockwise. For inverted winding (typically when using assets designed for left-handed coordinates but rendering with right-handed coordinates or vice-versa), use CullClockwise.

For "double-sided" geometry, use CullNone. Keep in mind this is a potentially large performance hit, so use it sparingly.

Wireframe is a wireframe rendering mode and shows both sides of the geometry.

Static Sampler State

Each of these takes a shaderRegister, a shaderVisibility which defaults to D3D12_SHADER_VISIBILITY_ALL, and registerSpace which defaults to 0.

  • static const D3D12_STATIC_SAMPLER_DESC StaticPointWrap(shaderRegister, shaderVisbility, registerSpace);
  • static const D3D12_STATIC_SAMPLER_DESC StaticPointClamp(shaderRegister, shaderVisbility, registerSpace);
  • static const D3D12_STATIC_SAMPLER_DESC StaticLinearWrap(shaderRegister, shaderVisbility, registerSpace);
  • static const D3D12_STATIC_SAMPLER_DESC StaticLinearClamp(shaderRegister, shaderVisbility, registerSpace);
  • static const D3D12_STATIC_SAMPLER_DESC StaticAnisotropicWrap(shaderRegister, shaderVisbility, registerSpace);
  • static const D3D12_STATIC_SAMPLER_DESC StaticAnisotropicClamp(shaderRegister, shaderVisbility, registerSpace);

Typical usage

The static sampler used by SpriteBatch if you don't provide an explicit sampler descriptor is StaticLinearClamp.

StaticAnisotropicWrap is the default static sampler in DirectX 12.

Sampler descriptor

This class also provides heap-based descriptors for use with Effects and to override the default SpriteBatch static sampler.

  • D3D12_GPU_DESCRIPTOR_HANDLE PointWrap() const;
  • D3D12_GPU_DESCRIPTOR_HANDLE PointClamp() const;
  • D3D12_GPU_DESCRIPTOR_HANDLE LinearWrap() const;
  • D3D12_GPU_DESCRIPTOR_HANDLE LinearClamp() const;
  • D3D12_GPU_DESCRIPTOR_HANDLE AnisotropicWrap() const;
  • D3D12_GPU_DESCRIPTOR_HANDLE AnisotropicClamp() const;

To use these you must provide the CommonStates Heap to the command-list. Usage for the built-in shaders is typically in conjunction with a DescriptorHeap of texture descriptors as follows:

ID3D12DescriptorHeap* heaps[] = { resourceDescriptors->Heap(), states->Heap() };
commandList->SetDescriptorHeaps(static_cast<UINT>(std::size(heaps)), heaps);

You can also refer to these heap sampler descriptors by index using SamplerIndex

  • PointWrap
  • PointClamp
  • LinearWrap
  • LinearClamp
  • AnisotropicWrap
  • AnisotropicClamp

Because SamplerIndex is strongly-named enum to avoid conflicts with the method names, to use it as an integer requires an explicit cast: static_cast<int>( SamplerIndex::AnisotropicWrap )

To provide flexibility, setting the proper descriptor heaps to render with via SetDescriptorHeaps is left to the caller. You can create as many heaps as you wish in your application, but remember that you can have only a single texture descriptor heap and a single sampler descriptor heap active at a given time.

Remarks

These common states are equivalent to using the following descriptors:

Blend states

CD3DX12_DEFAULT def;

// Opaque
CD3DX12_BLEND_DESC desc(def);

// AlphaBlend
CD3DX12_BLEND_DESC desc(def);
desc.RenderTarget[0].BlendEnable = TRUE;
desc.RenderTarget[0].SrcBlend =
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
desc.RenderTarget[0].DestBlend =
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;

// Additive
CD3DX12_BLEND_DESC desc(def);
desc.RenderTarget[0].BlendEnable = TRUE;
desc.RenderTarget[0].SrcBlend =
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend =
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;

// NonPremultiplied
CD3DX12_BLEND_DESC desc(def);
desc.RenderTarget[0].BlendEnable = TRUE;
desc.RenderTarget[0].SrcBlend =
desc.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend =
desc.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;

Depth/Stencil states

CD3DX12_DEFAULT def;

// DepthNone
CD3DX12_DEPTH_STENCIL_DESC desc(def);
desc.DepthEnable = FALSE;
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;

// DepthDefault
CD3DX12_DEPTH_STENCIL_DESC desc(def);
desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;

// DepthRead
CD3DX12_DEPTH_STENCIL_DESC desc(def);
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
desc.DepthFunc = D3D12_COMPARISON_FUNC_LESS_EQUAL;

// DepthReverseZ
CD3DX12_DEPTH_STENCIL_DESC desc(def);
desc.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;

// DepthReadReverseZ
CD3DX12_DEPTH_STENCIL_DESC desc(def);
desc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ZERO;
desc.DepthFunc = D3D12_COMPARISON_FUNC_GREATER_EQUAL;

Rasterizer states

// CullNone
CD3DX12_RASTERIZER_DESC desc(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_NONE,
    FALSE /* FrontCounterClockwise */,
    D3D12_DEFAULT_DEPTH_BIAS,
    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
    TRUE /* DepthClipEnable */,
    TRUE /* MultisampleEnable */,
    FALSE /* AntialiasedLineEnable */,
    0 /* ForceSampleCount */,
    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF);

// CullClockwise
CD3DX12_RASTERIZER_DESC desc(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_FRONT,
    FALSE /* FrontCounterClockwise */,
    D3D12_DEFAULT_DEPTH_BIAS,
    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
    TRUE /* DepthClipEnable */,
    TRUE /* MultisampleEnable */,
    FALSE /* AntialiasedLineEnable */,
    0 /* ForceSampleCount */,
    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF);

// CullCounterClockwise
CD3DX12_RASTERIZER_DESC desc(D3D12_FILL_MODE_SOLID, D3D12_CULL_MODE_BACK,
    FALSE /* FrontCounterClockwise */,
    D3D12_DEFAULT_DEPTH_BIAS,
    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
    TRUE /* DepthClipEnable */,
    TRUE /* MultisampleEnable */,
    FALSE /* AntialiasedLineEnable */,
    0 /* ForceSampleCount */,
    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF);

// Wireframe
CD3DX12_RASTERIZER_DESC desc(D3D12_FILL_MODE_WIREFRAME, D3D12_CULL_MODE_NONE,
    FALSE /* FrontCounterClockwise */,
    D3D12_DEFAULT_DEPTH_BIAS,
    D3D12_DEFAULT_DEPTH_BIAS_CLAMP,
    D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS,
    TRUE /* DepthClipEnable */,
    TRUE /* MultisampleEnable */,
    FALSE /* AntialiasedLineEnable */,
    0 /* ForceSampleCount */,
    D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF);

Sampler states

// PointWrap
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_POINT,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

// PointClamp
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_POINT,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

// LinearWrap
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_LINEAR,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

// LinearClamp
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_MIN_MAG_MIP_LINEAR,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

// AnisotropicWrap
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_ANISOTROPIC,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    D3D12_TEXTURE_ADDRESS_MODE_WRAP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

// AnisotropicClamp
D3D12_SAMPLER_DESC desc = { D3D12_FILTER_ANISOTROPIC,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    D3D12_TEXTURE_ADDRESS_MODE_CLAMP,
    0, D3D12_MAX_MAXANISOTROPY, D3D12_COMPARISON_FUNC_NEVER,
    { 0, 0, 0, 0 }, 0, D3D12_FLOAT32_MAX };

Further reading

PSOs, Shaders, and Signatures

Managing Graphics Pipeline State in Direct3D 12

State objects in XNA Game Studio 4.0

Premultiplied alpha
Premultiplied alpha and image composition
Premultiplied alpha in XNA Game Studio 4.0

Depth sorting alpha blended objects

For Use

  • Universal Windows Platform apps
  • Windows desktop apps
  • Windows 11
  • Windows 10
  • Xbox One
  • Xbox Series X|S

Architecture

  • x86
  • x64
  • ARM64

For Development

  • Visual Studio 2022
  • Visual Studio 2019 (16.11)
  • clang/LLVM v12 - v18
  • MinGW 12.2, 13.2
  • CMake 3.20

Related Projects

DirectX Tool Kit for DirectX 11

DirectXMesh

DirectXTex

DirectXMath

Tools

Test Suite

Model Viewer

Content Exporter

DxCapsViewer

See also

DirectX Landing Page

Clone this wiki locally