Configuring Depth and Stencil Buffers in DirectX
Depth and stencil buffers are essential components of the DirectX graphics pipeline, serving to manage visual occlusion, prevent geometry overlap, and handle complex masking operations like shadows or outlines. This article explains how depth and stencil buffers are set up and configured for depth testing in DirectX, covering resource allocation, view creation, pipeline state definition, and execution at the Output Merger stage.
1. Creating the Depth-Stencil Resource
To perform depth testing, you must first allocate a 2D texture that
supports both depth and stencil data. In DirectX, this requires
selecting an appropriate DXGI_FORMAT:
DXGI_FORMAT_D24_UNORM_S8_UINT: 24 bits allocated for depth precision and 8 bits for the stencil buffer.DXGI_FORMAT_D32_FLOAT: 32-bit floating-point precision dedicated entirely to depth (no stencil).DXGI_FORMAT_D32_FLOAT_S8X24_UINT: 32 bits for depth, 8 bits for stencil, and 24 bits of padding.
In Direct3D 11, the resource is created using
ID3D11Device::CreateTexture2D with the
D3D11_BIND_DEPTH_STENCIL flag. In Direct3D 12, the texture
is committed using ID3D12Device::CreateCommittedResource,
marked with D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL and an
initial state of D3D12_RESOURCE_STATE_DEPTH_WRITE.
2. Creating the Depth-Stencil View (DSV)
The raw texture resource cannot be bound directly to the rendering pipeline; it must be exposed via a Depth-Stencil View (DSV).
- Direct3D 11: Populate a
D3D11_DEPTH_STENCIL_VIEW_DESCstructure matching your texture's format and dimension, then callID3D11Device::CreateDepthStencilView. - Direct3D 12: Allocate a CPU descriptor handle from
a dedicated DSV descriptor heap
(
D3D12_DESCRIPTOR_HEAP_TYPE_DSV), define aD3D12_DEPTH_STENCIL_VIEW_DESC, and callID3D12Device::CreateDepthStencilView.
3. Configuring the Depth-Stencil State
The behavior of the depth and stencil tests is governed by a state
descriptor (D3D11_DEPTH_STENCIL_DESC or
D3D12_DEPTH_STENCIL_DESC).
To configure standard depth testing, specify the following primary fields:
- DepthEnable: Set to
TRUEto activate depth comparisons. - DepthWriteMask: Set to
D3D11_DEPTH_WRITE_MASK_ALL(orD3D12_DEPTH_WRITE_MASK_ALL) to allow pixels that pass the depth test to write their depth value to the buffer. UseZEROfor read-only depth testing (common for transparent objects). - DepthFunc: Specifies the comparison function
evaluating whether a incoming pixel fragment passes. The standard
setting is
D3D11_COMPARISON_LESS(orLESS_EQUAL), meaning incoming fragments closer to the camera replace fragments further away. When using a reverse-Z buffer setup,GREATERorGREATER_EQUALis used instead.
If stencil testing is also required:
- StencilEnable: Set to
TRUE. - StencilReadMask / StencilWriteMask: Bitmasks that govern which bits can be read from or written to.
- FrontFace / BackFace: Define
D3D11_DEPTH_STENCILOP_DESCstructures to specify the operations to perform if the stencil test fails (StencilFailOp), if stencil passes but depth fails (StencilDepthFailOp), or if both pass (StencilPassOp), along with the comparison function (StencilFunc).
In Direct3D 11, call
ID3D11Device::CreateDepthStencilState to generate an
ID3D11DepthStencilState object. In Direct3D 12, this
configuration is assigned directly to the DepthStencilState
member of a D3D12_GRAPHICS_PIPELINE_STATE_DESC.
4. Binding to the Pipeline and Clearing
Before rendering geometry, the views and states must be bound to the Output Merger (OM) stage of the pipeline:
- In Direct3D 11: Call
ID3D11DeviceContext::OMSetDepthStencilStateto set the state, followed byID3D11DeviceContext::OMSetRenderTargets, passing the render target view alongside yourID3D11DepthStencilView. - In Direct3D 12: The state is bound as part of the
Pipeline State Object (PSO) via
ID3D12GraphicsCommandList::SetPipelineState. The DSV descriptor handle is then bound along with render targets usingID3D12GraphicsCommandList::OMSetRenderTargets.
At the start of each frame or render pass, the buffer must be cleared
to a default state using ClearDepthStencilView:
- Standard depth buffers are cleared to
1.0f(representing the far clipping plane). Reverse-Z implementations clear to0.0f. - The stencil buffer is typically cleared to
0.