Vulkan 1.4 Real-Time Path Tracing with Autonomous Device-Generated Commands, Wavefront Microkernels, and Multi-GPU Scaling
- Engine Baseline: Vulkan Core 1.4 (1.4.341+)
- Primary Hardware Targets: AMD RDNA 4 (
gfx1201/ Radeon AI PRO R9700) and RDNA 3 architectures - Design Philosophy: GPU-autonomous Device-Generated Commands (DGC), decoupled wavefront microkernels, zero-copy host memory multi-GPU scaling, and standard cross-vendor Vulkan 1.4 without proprietary vendor extensions.
Real-time path tracing at 4K (3840×2160) within an interactive 8.33 ms (120 FPS) or 16.66 ms (60 FPS) frame budget requires structured pipeline design and register management. Traditional real-time renderers deploy monolithic megakernels that package ray generation, BVH traversal, material evaluation, light sampling, and secondary ray recursion into a single execution unit.
While conceptually straightforward, monolithic ray tracing pipelines encounter several hardware bottlenecks on modern wide SIMD architectures:
- Intra-Wave Branch & Path-Length Divergence: SIMD execution units serialize across divergent execution paths when adjacent lanes evaluate differing materials or terminate at differing path lengths.
- Vector General-Purpose Register (VGPR) Bloat: Monolithic shaders must preserve registers and samplers for all supported BSDFs simultaneously, demanding 72–128+ VGPRs per thread and capping hardware wave occupancy to 25%–50%.
- Cache Locality Thrashing: Adjacent threads access disparate textures, material buffers, and BVH nodes, degrading L0/L1 vector cache hit rates.
Pathways replaces the monolithic megakernel approach with a GPU-driven Wavefront Architecture using standard Vulkan 1.4 Device Generated Commands (VK_EXT_device_generated_commands).
┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ PATHWAYS WAVEFRONT PIPELINE STAGES │
└────────────────────────────────────────────────────────────────────────────────────────────────────────┘
[ Primary Ray Generation ]
│
▼
[ Hardware BVH Traversal ] ──► VK_KHR_ray_query / VK_KHR_ray_tracing_pipeline
│
▼
[ Ray Classification & Binning ] ──► 3D Spatial Morton + Material Composite Binning
│
▼
[ GPU-Autonomous DGC Dispatch ] ──► vkCmdExecuteGeneratedCommandsEXT
├──────────────────────┬──────────────────────┬──────────────────────┐
▼ ▼ ▼ ▼
[ shade_diffuse ] [ shade_dielectric ] [ shade_conductor ] [ shade_complex ]
(24 VGPRs, 100% Occ) (40 VGPRs, 100% Occ) (48 VGPRs, 100% Occ) (64 VGPRs, 50% Occ)
│ │ │ │
└──────────────────────┴──────────────────────┴──────────────────────┘
│
▼
[ Shadow Occlusion Test ] ──► Inline Ray Query
│
▼
[ Progressive Accumulation ] ──► Online Running Mean
│
▼
[ (Experimental Upscalers — see §5) ]
Pathways decomposes light transport into decoupled, specialized compute microkernels:
- Ray Classification (
shaders/compute/wavefront_classify.comp):- Inspects surface intersection records produced by BVH traversal.
- Evaluates surface material archetype (Diffuse, Dielectric, Conductor, Complex, Emissive, Passthrough) directly via the 4-byte scalar
materialArchetypesbuffer (binding 34), bypassing full material structure loads into VGPRs. - Computes 16-bit composite sorting keys combining material archetype and quantized 3D Morton spatial codes.
- Atomically stages rays into dedicated Structure-of-Arrays (SoA) ray queues via 64-bit Buffer Device Addresses (BDA).
- Ray Traversal & Intersection (
shaders/compute/wavefront_intersect.comp):- Evaluates fixed-function hardware BVH traversal using inline ray queries (
rayQueryEXT). - Retrieves triangle shading attributes from the 64-byte cache-line-packed
TriangleShadeGPUbuffer (binding 2; 2 triangles per 128-byte RDNA 4 vector cache line). - Conditionally evaluates tangent frames and object-to-world transforms exclusively for
COMPLEX,CONDUCTOR, andDIELECTRICarchetypes, skipping tangent attribute loads and matrix math for diffuse and emissive surfaces.
- Evaluates fixed-function hardware BVH traversal using inline ray queries (
- GPU-Autonomous Command Synthesis (
shaders/compute/wavefront_classify.comp):- The classifier kernel synthesizes dual execution command streams into device-local memory without host readbacks:
- A standard
VkDispatchIndirectCommandstream (16-byte stride per archetype) consumed by the hardware Command Processor's native multi-dispatch loop (vkCmdDispatchIndirect). This production path achieves maximum throughput (+22.3% faster) with zero driver preprocessing latency and hardware 0-workgroup dispatch skipping. - A 16-byte
DGCCommandstream (ExecutionSettoken +Dispatchtoken) forVkIndirectExecutionSetEXTexecution sets when--dgc-execsetis selected.
- A standard
- The classifier kernel synthesizes dual execution command streams into device-local memory without host readbacks:
- Material Microkernel Dispatch (
vkCmdDispatchIndirect/vkCmdExecuteGeneratedCommandsEXT):- Dispatches only the exact workgroup counts needed for each material queue.
- High-frequency diffuse and primary shading kernels query the compact 64-byte
ShadeMaterialGPUbuffer (binding 35), fetching packed albedo, emissive/specular, PBR parameters, and texture flags at 2 materials per 128B vector cache line. - Secondary diffuse shading (
#if !IS_SECONDARY_BOUNCE) bypasses normal map texture sampling and TBN perturbation, preserving vector registers and memory bandwidth for indirect diffuse GI. - Vector register pressure is tailored to each physical lobe:
shade_diffuse.comp: Lambertian diffuse reflection. Operates at 24–32 VGPRs (up to 100% Wave32 hardware occupancy in pure shading mode; 52 VGPRs / 56.2% occupancy on secondary bounces).shade_dielectric.comp: Snell's law refraction, Total Internal Reflection (TIR), and volumetric Beer-Lambert absorption. Operates at 40–42 VGPRs with up to 100% occupancy (62.5% with dispersion).shade_conductor.comp: Anisotropic GGX specular microfacets with Fresnel-Conductor physics. Operates at 48 VGPRs with 100% occupancy.shade_complex.comp: Layered clearcoat, transmission, and sheen BSDFs. Operates at 61–64 VGPRs with 50% occupancy.
- Shadow Occlusion (
shaders/compute/wavefront_shadow.comp):- Evaluates direct lighting visibility using binary inline ray queries (
rayQueryConfirmIntersectionEXT), bypassing hit shader overhead.
- Evaluates direct lighting visibility using binary inline ray queries (
- Accumulation Resolve (
shaders/compute/accum_running_avg.comp):- Numerically stable progressive HDR accumulation using an online running-mean update (
x̄_N = mix(x̄_{N-1}, x_N, 1/N)— note: an online mean, not Welford's variance algorithm), preventing highlight blowout and floating-point accumulation drift.
- Numerically stable progressive HDR accumulation using an online running-mean update (
Staging all ray queues simultaneously across a native 4K UHD viewport (
Pathways solves this with GPU-Autonomous Coarse-Batch Wavefront Partitioning:
-
Target Batch Pixel Budget: Ray queues are sized strictly for an on-chip pixel budget (
$2.0\text{M pixels}$ on APU/UMA platforms,$1.0\text{M pixels}$ on discrete GPUs) viagetTargetBatchPixels(). -
2D Aspect-Ratio Grid Decomposition: Rather than 1D horizontal strips (which sever vertical spatial neighbors and cause up to a 35% cache-locality regression on textured assets), the viewport is partitioned into a 2D tile grid (
$2 \times 1, 2 \times 2, 4 \times 2, 3 \times 3$ ) matching screen aspect ratio:$$\text{TileWidth} = \left\lceil \frac{W}{G_x} \right\rceil, \quad \text{TileHeight} = \left\lceil \frac{H}{G_y} \right\rceil$$ This preserves 2D spatial texture and BVH cache locality across both primary and secondary rays. -
Adaptive Secondary Ray CU Occupancy Capping: In multi-bounce diffuse GI scenes (
max_bounces > 2), dividing the screen into too many batches causes Compute Unit starvation on Bounces 2–3 due to diminishing active ray counts. Pathways dynamically caps auto-batches to$\le 4$ , ensuring sufficient ray volume to saturate all SIMD execution units while keeping queue memory locked at ~699 MB at 4K (-74.3% reduction). -
True
$O(1)$ Memory Scaling: Rendering at 8K ($7680 \times 4320$ ) simply schedules a$4 \times 4$ macro-tile grid without expanding ray queue memory beyond the configured batch budget.
Configurable via --macro-tiles <count> (or --batches <count>). For empirical SPM cache analysis, see docs/reports/wavefront_batching_head_to_head.md.
To preserve cache locality across secondary ray bounces:
Sorting rays purely by material restores ALU wave efficiency but disperses spatial locality across scene geometry. Pathways uses a dual-binning key: $$\text{Key}{16} = \big(\text{ArchetypeID} \ll 12\big) ;\vert; \text{Morton3D}(x, y, z){12}$$ This clusters rays by material archetype while preserving spatial L0/L1 cache locality for texture and geometry fetches.
Secondary rays scattered by rough surfaces are partitioned at emission time across 8 directional octant bins using Wave32 ballot leader-election loops:
// Subgroup ballot leader election for octant binning
uint octant = (rayDir.x >= 0.0 ? 1 : 0) |
(rayDir.y >= 0.0 ? 2 : 0) |
(rayDir.z >= 0.0 ? 4 : 0);
uvec4 ballot = subgroupBallot(true);Rays traversing downstream BVHs share coherent ray frustums, boosting BVH node hit rates and eliminating post-hoc sort passes.
To eliminate high-energy Monte Carlo fireflies caused by specular-diffuse-specular paths, secondary rays enforce scene-invariant radiance clamping:
$$\mathbf{L}{\text{clamped}} = \min\left(\mathbf{L}{\text{secondary}}, \frac{L_{\text{max}}}{\max(1.0, |\mathbf{p} - \mathbf{x}|)}\right)$$
Configurable via --indirect-clamp (default 10.0), suppressing caustic fireflies with zero energy loss on primary surfaces.
Pathways provides unlinked multi-GPU scaling across dual discrete GPUs (e.g. 2x AMD Radeon AI PRO R9700 32GB) over standard PCIe slots without requiring proprietary hardware bridges.
┌────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ZERO-COPY HOST MEMORY MULTI-GPU TOPOLOGY │
└────────────────────────────────────────────────────────────────────────────────────────────────────────┘
[ Secondary GPU (GPU 1) ]
│
▼ Renders Alternate 64x64 Checkerboard Tiles
[ Device VRAM ]
│
▼ CP DMA High-Speed Posted Writes (~25 GB/s PCIe Bus Line Rate)
[ Pinned Host RAM ] ──► VK_EXT_external_memory_host
│
▼ GPU-Autonomous DMA / Pinned Host Buffering
[ Primary GPU (GPU 0) ]
│
▼ Direct Import & Tile Composite (<0.12 ms)
[ Final 4K Swapchain Presentation ]
-
Push Model: The primary GPU allocates the merge buffer in its own device-local VRAM and exports it via
VK_EXT_external_memory_dma_buf+VK_KHR_external_memory_fd; the secondary GPU imports the handle and binds it to its own buffer object. -
Posted Writes Only: The secondary streams completed
$64\times 64$ checkerboard tiles into the imported buffer via CP DMA posted writes at PCIe 4.0/5.0 bus line rate (~25 GB/s, latency <0.5 ms). The primary then merges from local VRAM at full memory bandwidth — no shader-driven non-posted PCIe reads on the frame-critical path. - Auto-Fallback: Falls back to host zero-copy automatically when DMA-BUF export is unavailable or the BAR aperture is small ($\le$256 MB).
- Secondary GPU streams completed tiles into pinned host memory via CP DMA posted writes; the primary imports the host pointer and composites alternate tiles in ~0.12 ms without PCIe bus contention.
- Optimal on UMA (Strix Halo, where "host memory" is the shared LPDDR5X) and the safe fallback on discrete PCIe.
Screen space is subdivided into
Pathways contains experimental reconstruction and super-resolution code paths (src/rt/Fsr3Upscaler.*,
src/rt/UpwaysPipeline.*, shaders/compute/fsr3_*.comp, shaders/compute/upways_*.comp). These are
experimental at best and are intentionally excluded from user-facing documentation and the GUI. They
are reachable only via hidden CLI flags (--scaler, --denoiser, --upways*) and carry no performance or
quality guarantee.
Accuracy note: the
fsr3/fsr1passes are Pathways-authored custom filters, not the official AMD FidelityFX SDK techniques. A feasibility study for integrating the genuine AMD FSR 3.1 Vulkan Upscaler (FidelityFX-SDKv1.1.x) is recorded indocs/reports/codebase_review_2026_10_07.md(finding A3); the integration was descoped by the project owner. Until then, no AMD/FSR branding is claimed anywhere user-facing.
Pathways implements a unified ReSTIR PT path-space reservoir resampling pipeline (see docs/RESTIR_PT_DESIGN.md).
All resampling runs inline in the wavefront shade passes (shaders/compute/restir_common.glsl,
used by wavefront_shade_diffuse/complex.comp); src/rt/ReSTIRManager.cpp is a lean owner
of the per-pixel reservoir grids (lazy allocation, zero-fill on (re)alloc). Enabled via --restir.
- Direct Lighting Resampling: 28 B direct reservoir (light index + M, weight sum, scalar target p̂, age/valid/lobe flags, oct-encoded x1 & light normals, 8-bit-per-channel light UV, fp16 cosine & primary distance) — every field is read back during reuse.
- Temporal Reservoir Reuse: The previous frame's grid is sampled at the
MV-reprojected pixel; stored samples are reconnected to the current surface, re-weighted
with the correct solid-angle measure ratio (
q_src/q_currfor area lights, 1.0 for point-like lights), M-truncated by--restir-m-cap, and gated by stored x1 normal/depth disocclusion checks plus a max-age cutoff. - Spatial Reservoir Reuse: Four additional taps read the previous frame's grid at a per-pixel randomly rotated cross offset (±2 px). Buffer-based taps keep reuse legal under the wavefront's divergent per-material control flow.
- Finalization: Full GGX + diffuse BRDF evaluation of the winning light with a single inline shadow ray; an occluded winner zeroes its reservoir so bad history dies immediately.
- Indirect Path-Space Resampling (Secondary-Vertex Reconnection): The indirect path term
is estimated by resampling cached secondary vertices at the primary hit x1. A 24 B per-pixel
X1Context(normal, albedo, wo, F0) is written at bounce 0; a 32 BGiReservoir(x2 world position, shadowed L̂2 radiance, weight sum, p̂, d_src, age/M) is double-buffered. Taps reconnect neighbors' x2 to the current x1 with the(d_src/d_new)²solid-angle Jacobian; the winner gets one replay visibility ray (skipped when the path's own candidate wins). - Debug views (
--debug-view, also a GUI combo): a post pass overwrites the output image with live reservoir state — Direct/Indirect sample-count M (log heatmap), finalized weight w = wSum/(p̂·M) (log scale, firefly hunting), winner light index (golden-ratio hue), and a validity coverage map (R = Direct valid, G = Indirect valid, B = X1 context valid). Runs after accumulation & tonemap so the state is never temporal-blurred; seeshaders/compute/restir_debug_view.comp.
Pathways ingests complex VFX and CAD production assets via OpenUSD (UsdLoader.cpp):
- High-Density Point Instancing (
UsdGeomPointInstancer): Evaluates scenes with tens of thousands of instances and tens of millions of expanded triangles (e.g.PointInstancedMedCity.usdwith 40,001 instances and ~49M triangles) without geometry flattening. - Prototype BLAS Deduplication: Instanced geometries reference compact deduplicated prototype BLAS acceleration structures, reducing VRAM footprint by up to 90%.
- Dynamic Real-Time TLAS Build: Builds top-level acceleration structures in <2.0 ms per frame on RDNA 4 hardware.
On modern GPU architectures such as AMD RDNA 4 (gfx1201), vector cache lines (
In traditional rasterization and path tracing engines, triangle vertex positions, normals, texture coordinates, and tangents are interleaved into a single fat vertex structure (e.g. 160+ bytes per triangle). In a wavefront path tracer, however:
-
Hardware BVH Traversal requires only vertex positions during acceleration structure building (
VkAccelerationStructureGeometryTrianglesDataKHR). Traversal itself runs in fixed-function ray tracing hardware. -
Shading Kernels need surface normals, texture coordinates, tangents, and material IDs to evaluate BSDFs and sample textures; they do not require vertex positions because world-space hit points are computed from ray origins, direction, and ray query hit distances
$t$ ($\mathbf{p} = \mathbf{o} + t \cdot \mathbf{d}$ ).
Pathways segregates positions from shading geometry into two decoupled buffers:
m_positionBuffer: A contiguous array of 16-byteglm::vec4(x, y, z, 1.0f)positions used strictly for hardware BLAS builds.m_triangleShadeBuffer(TriangleShadeGPU): An aligned 64-byte structure containing exclusively the attributes required during shading — 2 triangles per 128-byte RDNA 4 vector cache line, so consecutive triangle fetches never straddle a cache-line boundary. Normals and tangents are octahedrally encoded (4 bytes each instead of 16) and UVs are packed as half-float pairs:
| Field | GLSL / C++ Type | Byte Size | Description |
|---|---|---|---|
octNormal0/1/2 |
uint32_t × 3 |
12 | Per-vertex normals, octahedral 32-bit encoding (unpackOct32) |
octTan0/1/2 |
uint32_t × 3 |
12 | Per-vertex tangents, octahedral 32-bit encoding |
uv0/1/2 |
uint32_t × 3 |
12 | Per-vertex UVs, packed half2 (unpackHalf2x16) |
tanSigns |
uint32_t |
4 | Tangent handedness signs (bit-packed) |
materialId |
uint32_t |
4 | Scene material index |
padding0 + reserved[4] |
uint32_t[5] |
20 | Alignment / forward-compatibility padding |
| Total | 64 Bytes | 2 triangles per 128B Vector Cache Line (0 Split Cache-Line Penalty) |
struct alignas(16) TriangleShadeGPU {
uint32_t octNormal0 = 0; // oct-encoded normal, vertex 0
uint32_t octNormal1 = 0;
uint32_t octNormal2 = 0;
uint32_t octTan0 = 0; // oct-encoded tangent, vertex 0
uint32_t octTan1 = 0;
uint32_t octTan2 = 0;
uint32_t uv0 = 0; // packed half2 UV, vertex 0
uint32_t uv1 = 0;
uint32_t uv2 = 0;
uint32_t tanSigns = 0;
uint32_t materialId = 0;
uint32_t padding0 = 0;
uint32_t reserved[4] = {0, 0, 0, 0};
};
static_assert(sizeof(TriangleShadeGPU) == 64, "TriangleShadeGPU must be exactly 64 bytes (2 triangles per 128B cache line)");Full physical material descriptions (MaterialGPU, 208 bytes) contain extended parameters for clearcoat, transmission, dispersion, sheen, and thin-film iridescence. In high-frequency shading (diffuse, primary ray dispatch, and shadow queries), the vast majority of hits require only core albedo, emissive, metallic-roughness, IOR, and texture handles.
Pathways introduces a compact 64-byte material representation (ShadeMaterialGPU) bound at descriptor binding 35:
- Cache Packing: Exactly two
ShadeMaterialGPUentries fit into a single 128-byte vector cache line. - Bandwidth Reduction: Accessing material state incurs 64 bytes instead of 208 bytes—a 69.2% reduction in material read bandwidth.
| Field | Type | Size | Packed Contents |
|---|---|---|---|
albedo |
vec4 |
16 | Base color factor (linear RGBA) |
emissive_spec |
vec4 |
16 | xyz: Emissive factor (linear RGB), w: Specular factor |
pbrParams |
vec4 |
16 | x: Roughness, y: Metallic, z: IOR, w: Diffuse transmission factor |
tex_flags |
uvec4 |
16 | x: albedoTex | (normalTex << 16)y: mrTex | (emissiveTex << 16)z: diffTransTex | (specularTex << 16)w: (matType & 0xFFFF) | (packHalf16(normalScale) << 16) |
| Total | 64 Bytes | Packs 2 materials per 128B cache line (alignas(16)) |
During ray classification (wavefront_classify.comp) and ray intersection (wavefront_intersect.comp), the engine must identify each surface hit's BSDF archetype to route the ray to the correct queue or decide whether to evaluate tangents:
uint materialArchetypes[]) at binding 34:
- Direct index lookup:
uint archetype = materialArchetypes[matId]; - Zero Structure Cache Bloat: Keeps classification and intersection inner loops lean, saving 60–204 bytes of memory fetch per ray hit and preserving VGPR registers.
Secondary indirect bounces in diffuse environments carry low-frequency global illumination. Evaluating high-frequency normal maps and loading tangent frames on secondary diffuse bounces introduces significant ALU and memory overhead for imperceptible visual difference.
Pathways deploys a two-tier tangent bypass:
-
Intersection Bypass (
wavefront_intersect.comp): Tangent vectors (tan0_v0,tan1_v1,tan2_v2,tanSigns) and object-to-world tangent matrix multiplications are executed only if the hit archetype isCOMPLEX,CONDUCTOR, orDIELECTRIC:Diffuse and emissive hits bypass all 4 tangentif (archetype == MATERIAL_ARCHETYPE_COMPLEX || archetype == MATERIAL_ARCHETYPE_CONDUCTOR || archetype == MATERIAL_ARCHETYPE_DIELECTRIC) { tanDir = getTriangleTangent(tri, closestBary); tanDir = normalize(mat3(hitO2w) * tanDir); tanSign = getTriangleTangentSign(tri); }
vec4loads and$3\times 3$ matrix transforms. -
Shading Bypass (
wavefront_shade_diffuse.comp): Compile-time specialization (#if !IS_SECONDARY_BOUNCE) strips normal map texture reads, unpack half operations, and TBN orthonormalization from secondary bounce shaders:This drops secondary diffuse shader register pressure from 85 VGPRs to 52 VGPRs, lifting occupancy to 56.2% (9 waves/SIMD) on RDNA 4 hardware.#if !IS_SECONDARY_BOUNCE if (hitType == 0u && normalTex > 0u && normalTex <= 512u) { vec3 normalMap = SAMPLE_SCENE_TEXTURE(normalTex, hitUv).rgb * 2.0 - 1.0; normalMap.xy *= normalScale; normalMap = normalize(normalMap); geomTan = normalize(geomTan - dot(geomTan, hitNormal) * hitNormal); vec3 geomBitangent = cross(hitNormal, geomTan) * tanSign; mat3 tbn = mat3(geomTan, geomBitangent, hitNormal); hitNormal = normalize(tbn * normalMap); } #endif
The primary wavefront and compute pipelines bind scene data through descriptor set 0:
| Binding | Resource Type | Name | Stride / Size | Purpose |
|---|---|---|---|---|
| 0 | storageImage |
accumImage |
RGBA32F / RGBA16F | Progressive accumulation & render target |
| 1 | uniformBuffer |
cameraUBO |
320 B | Camera projection, view matrices, unjittered VP, jitter offset, resolution |
| 2 | storageBuffer |
triangles |
64 B | Cache-line-packed shading geometry (TriangleShadeGPU, 2 triangles per 128 B vector cache line) |
| 3 | storageBuffer |
spheres |
32 B | Procedural analytic spheres (SphereGPU) |
| 4 | storageBuffer |
materials |
208 B | Full glTF 2.0 extended PBR materials (MaterialGPU) |
| 5 | storageBuffer |
lights |
128 B | Analytical & emissive scene lights (1 cache line per light) |
| 6 | accelerationStructure |
topLevelAS |
— | Hardware Top-Level Acceleration Structure (TLAS) |
| 7 | combinedSampler |
environmentMap |
— | HDR/EXR equirectangular environment texture |
| 8 | combinedSampler[512] |
sceneTextures |
— | Bindless/descriptor array of glTF/USD textures |
| 9 | storageBuffer |
inStates |
16 B | Input ray state queue (throughput, seed, pixel index, flags) |
| 10 | storageBuffer |
outStates |
16 B | Output ray state queue for next bounce |
| 11 | storageBuffer |
queueCounters |
256 B | Atomic workgroup and ray queue counters |
| 20–22 | storageBuffer |
nrcQueue/Counters |
Variable | Neural direct-light caching query, train, and counter buffers |
| 23–24 | storageImage |
motionVectors / normalDepth |
RG16F / RGBA16F | Temporal motion vectors and G-Buffer normal/depth |
| 25 | storageBuffer |
lightTree |
Variable | Hierarchical 3D Light Tree nodes |
| 26–29 | storageImage |
albedoRough / specMetal / mlDiff / mlSpec |
RGBA16F | Denoising feature maps & separated diffuse/specular buffers |
| 30 | storageBuffer |
instances |
64 B | Scene mesh instance transforms and material offsets |
| 31 | storageImage |
causticImage |
RGBA16F | Forward photon-traced caustic splat target |
| 32 | storageBuffer |
restirReservoirs |
28 B/px | ReSTIR DI reservoirs, current frame slot (write) |
| 34 | storageBuffer |
materialArchetypes |
4 B | Compact scalar BSDF archetype lookup buffer |
| 35 | storageBuffer |
shadeMaterials |
64 B | Compact cache-line aligned shading material buffer |
| 36 | storageBuffer |
restirHistory |
28 B/px | ReSTIR DI reservoirs, previous frame slot (temporal/spatial taps, read-only) |
| 37 | storageBuffer |
x1Contexts |
24 B/px | ReSTIR GI: BRDF context at primary hit (written bounce 0, read bounce 1, single-buffered) |
| 38 | storageBuffer |
giReservoirs |
32 B/px | ReSTIR GI reservoirs, current frame slot (write) |
| 39 | storageBuffer |
giHistory |
32 B/px | ReSTIR GI reservoirs, previous frame slot (taps, read-only) |
| 40 | storageBuffer |
positions |
48 B/tri | Segregated vertex positions (3 x vec4) for triangle reconstruction |
| 41–45 | storageBuffer |
ptReservoirs / pathSamples / shadeReq |
32–144 B/px | ReSTIR PT path reservoirs, path samples, and reconnection request/result buffers |
| 47 | storageImage |
prevNormalDepthImage |
RGBA16F | Previous frame G-Buffer normal/depth for temporal reprojection |