How RTVs Direct Pixel Shader Output in DirectX
In DirectX rendering pipelines, pixel shaders compute per-pixel color and numerical data that must be committed to GPU memory. Render Target Views (RTVs) act as the binding mechanism that bridges pixel shader outputs to specific memory resources, such as textures or swap chain buffers. By defining resource formats, subresource ranges, and array slots at the Output Merger stage, RTVs inform the hardware precisely where and how each pixel shader output value is written.
The Purpose of a Render Target View
Raw GPU resources, such as textures, are allocated as blocks of memory. A raw resource alone does not specify how the pipeline should interpret its memory during a write operation. An RTV provides the necessary metadata, including:
- Data Format: Interpreting typeless resources into
concrete formats (e.g., converting a typeless resource into
DXGI_FORMAT_R8G8B8A8_UNORM). - Resource Dimension: Identifying whether the target is a 1D, 2D, 3D texture, or a texture array.
- Subresource Allocation: Specifying the exact mip level or array slice that receives the output, preventing accidental writes to other mip levels.
Binding to the Output Merger
The pixel shader does not write to memory directly. Instead, it outputs data to the Output Merger (OM) stage of the DirectX pipeline.
Developers bind RTVs to the Output Merger using API-specific commands:
- In DirectX 11, using
ID3D11DeviceContext::OMSetRenderTargets. - In DirectX 12, using
ID3D12GraphicsCommandList::OMSetRenderTargetsalongside CPU descriptor handles.
When calling these functions, the application passes an array of RTV descriptors. The position of an RTV in this array defines its render target slot index (from 0 to 7 in standard configurations).
Mapping Shader Outputs to Render Targets
In High-Level Shader Language (HLSL), pixel shaders designate their
outputs using system-value semantics. The primary semantic used is
SV_Target[n], where [n] represents the
zero-based target index.
struct PixelOutput
{
float4 Color : SV_Target0;
float4 Normal : SV_Target1;
};
PixelOutput PSMain(PixelInput input)
{
PixelOutput output;
output.Color = float4(1.0, 0.0, 0.0, 1.0); // Routes to RTV at slot 0
output.Normal = float4(0.0, 1.0, 0.0, 0.0); // Routes to RTV at slot 1
return output;
}
The hardware maps these semantics directly to the active RTV array:
SV_Target0routes output data to the RTV bound at slot 0.SV_Target1routes output data to the RTV bound at slot 1.- Additional semantics (
SV_Target2throughSV_Target7) correspond sequentially to their respective slots for Multiple Render Target (MRT) setups.
Final Output Execution
Once the pixel shader generates its values:
- The values leave the shader execution units tagged with their
SV_Targetdesignations. - The Output Merger checks the RTV bound to the corresponding slot index.
- The Output Merger applies any configured blend states, format conversions, or masking defined by the pipeline state.
- The processed pixel data is written to the specific subresource and memory addresses defined by the active RTV.