ReSTIR Integration in DirectX Raytracing (DXR)
Reservoir-based Spatio-Temporal Importance Resampling (ReSTIR) dramatically improves real-time ray tracing performance by enabling the sampling of millions of dynamic lights with minimal noise and overhead. Integrating ReSTIR into DirectX Raytracing (DXR) involves coupling compute-driven importance resampling passes with hardware-accelerated ray tracing to resolve visibility. By maintaining compact data structures called reservoirs across space and time, the pipeline limits expensive DXR shadow ray evaluations to only the most promising light candidates, making path tracing and complex direct illumination practical in modern real-time rendering.
The Reservoir Data Structure and Buffer Allocation
At the core of ReSTIR is the reservoir, a lightweight structure that tracks candidate samples using streaming importance sampling (RIS). In DirectX 12, each reservoir is represented as a structured data element containing:
- The selected sample (such as a light index or radiance sample).
- The sum of candidate weights (\(w_{sum}\)).
- The number of processed candidates (\(M\)).
- The final normalization weight (\(W\)).
These structures are stored in GPU memory using 2D or structured
RWStructuredBuffer (Unordered Access Views / Shader
Resource Views). Because temporal reuse requires reading the previous
frame’s results and writing the current frame’s state, developers
implement ping-pong double buffering for the reservoir data alongside
standard G-buffer data (world normals, linear depth, and motion
vectors).
The ReSTIR Execution Pipeline in DXR
A typical ReSTIR direct illumination (ReSTIR DI) integration divides the frame into distinct compute and raytracing stages:
Initial Candidate Generation (Compute or RayGen Shader): The GPU generates an initial set of light candidates per pixel. This is typically implemented in a standard compute shader or a DXR Ray Generation shader. Light sources are sampled proportionally to their unshadowed contribution using light grids or bounding volume hierarchies (BVHs). A reservoir is filled for each pixel without performing visibility tests.
Temporal Resampling: A compute shader reprojects the current pixel to the previous frame using motion vectors. If the history sample passes geometric validation tests (depth and normal thresholds), the previous frame's reservoir is combined with the current reservoir. This combines history weights without tracing rays, rapidly boosting sample counts (\(M\)).
Spatial Resampling: To further reduce variance, neighboring screen-space reservoirs are gathered and combined. A compute shader iterates over a random set of neighboring pixels, checking depth and normal similarity to prevent light leaking across geometry boundaries. Reservoirs from valid neighbors are merged mathematically.
Visibility Determination using DXR: Evaluating visibility is the most expensive operation in ray tracing. The key advantage of ReSTIR is that visibility (shadow rays) only needs to be evaluated for the final selected light sample after resampling, rather than for every initial candidate.
Under DXR, visibility is resolved in one of two ways:
- DXR 1.0 (
DispatchRays): A Ray Generation shader callsTraceRay()with a simple payload and ray flags likeRAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_SKIP_CLOSEST_HIT_SHADERagainst the Top-Level Acceleration Structure (TLAS). - DXR 1.1 (Inline Raytracing via
RayQuery): Modern implementations frequently utilizeRayQuerydirectly within compute shaders. This avoids the overhead of separate Ray Generation pipelines and shader table dispatches, allowing candidate generation, spatial merging, and shadow testing to occur within a unified compute pass.
- DXR 1.0 (
Final Shading: Pixels that pass the visibility check calculate the final direct lighting contribution by multiplying the light's evaluated radiance, the material's Bidirectional Reflectance Distribution Function (BRDF), and the reservoir’s final weight (\(W\)).
Performance Considerations
Integrating ReSTIR into DXR requires careful management of ray
tracing divergence and register pressure. Inline raytracing
(RayQuery) minimizes pipeline state object (PSO) switching
overhead and simplifies debugging in tools like PIX. Additionally,
limiting spatial reuse sample counts and applying temporal clamping
prevents historical bias, fireflies, and ghosting artifacts during rapid
camera or light movements.