Video summary
Erik Jansson - GPU driven Rendering with Mesh Shaders in Alan Wake 2
Main summary
Key takeaways
Summary (technological concepts, features, analysis)
Speaker / background
- Edik (Erik) Jansson, Senior Graphics Programmer at Remedy Entertainment, presents GPU-driven rendering as used in Alan Wake 2.
- Focus areas:
- GPU-driven pipeline architecture
- Meshlets
- Mesh shaders
- Talk context: primarily console rendering with performance numbers shown for Xbox Series X.
Why GPU-driven rendering was needed (from Control → Alan Wake 2)
Limitations in Control (earlier Remedy game)
- The pipeline relied on a largely non–GPU-driven approach, with significant CPU-side work:
- CPU-side culling remained expensive (example: ~3 million triangles still present after CPU-side culling in an indoor, flat-geometric scenario).
- Command list recording on previous-gen consoles used multiple CPU cores, but it wasn’t efficient enough for next-gen scaling.
Increased complexity in Alan Wake 2 (Pacific Northwest scene)
- Scene complexity grows sharply:
- ~200M triangles before culling
- Dense vegetation + widespread photogrammetry
- Additional factors:
- Fewer “main occluders” (less wall-like structure)
- Heavy reliance on alpha testing
Resulting motivation
- GPU-driven rendering reduces:
- CPU overhead
- command submission
- This enables the render thread to be ~single-core, freeing CPU time for other systems.
- After GPU-side culling, triangle counts become manageable (~10.6M triangles), making real-time console rendering feasible.
GPU-driven pipeline architecture (high-level)
CPU-to-GPU population model
- Even GPU-driven rendering begins with CPU-side setup:
- CPU streams/updates persistent objects into draw sets
- Objects are organized into buckets based on material properties, e.g.:
- Vegetation with alpha-tested depth-pass bucket
- Rocks / single-sided non-alpha bucket
Per-view visibility construction
- Visible draw sets are created per view, including:
- Camera view
- Shadow map views (e.g., spotlight views)
Incremental GPU updates
- CPU updates the GPU incrementally (only differences), avoiding full rebuilds every frame.
Core geometry passes mentioned
- Skinning pass
- Depth pre-pass
- Shadow maps
- G-buffer pass
Alpha handling strategy
- The G-buffer pass avoids alpha testing because depth pre-pass already handled it.
- The “hard” alpha-tested steps remain:
- Depth pre-pass
- Shadow depth passes
Occlusion culling challenge and “last-frame occluders”
The chicken-and-egg problem
- Occlusion culling needs hierarchical depth structure (e.g., Hi-Z/HZB), but building it normally requires rendering—creating a dependency loop.
Approach: reuse last frame
- Render the previous frame’s occluders
- Build a Hi-Z / HZB-like structure
- Perform occlusion culling using it
Handling correctness gaps
- This introduces gaps, so the fix is:
- Render the missing remainder after the culling decision
Temporal continuity / correctness
- The culling result is carried to the next frame.
- Correctness is maintained by re-drawing previously culled geometry using new-frame meshlet references, which keeps animated/skinned geometry consistent.
Bindless rendering considerations
Why bindless helps
- Uses bindless resources (indexing descriptor heaps rather than binding slots):
- reduces CPU overhead
- increases flexibility
Pitfall: divergent resource access
- Divergent indexing can trigger DXE/driver/compiler issues.
- Mitigation:
- nonuniform resource index
- Warning:
- May hurt performance on AMD due to added control flow.
Alternative: uniform indexing
- Another option is trying to make indices uniform (e.g., wave-lane techniques),
- but only works if truly uniform—otherwise artifacts can occur.
Extending beyond textures
- For Alan Wake 2, the approach expands to:
- Bindless geometry for the meshlets/mesh shader path
Meshlets: generation and bounds
Meshlets as the primitive
- Meshlets are treated as the unit of work for mesh shaders.
Generation process
- They use an open-source meshlet library (described as “excellent”) that largely works out-of-the-box.
- Meshlet generation uses a greedy algorithm, with rare edge cases where bounds may be slightly worse.
Meshlet sizing choice (Alan Wake 2)
- Chosen size: 64 triangles + 64 vertices per meshlet.
- Trade-off noted:
- Larger meshlets can improve performance on some architectures.
- Smaller meshlets can improve culling efficiency.
- Advice: tune for real production scenarios, not only synthetic tests.
Bounds required for culling
- Bounding spheres
- Normal cones:
- cone axis + spread
- spread stored quantized; dequantize in shaders
Dynamic / skinned geometry bounds
- Compute shader updates bounds for skinned instances:
- Sphere update: bounding sphere via wave reductions (min/max/mean) over skinned vertex positions
- Normal cone update: reductions over transformed normals to compute cone axis/spread
- Reported performance on Xbox Series X:
- ~<2ms for sphere updates
- ~+0.1ms for normal cone updates
- (happening over a large meshlet-rich area)
Calling strategy: from “naive rendering” to staged GPU culling + mesh shader execution
Naive scale example
- ~200k instances
- ~4M meshlets
- ~200M triangles
Multi-stage savings pipeline
Key stages:
- Frustum culling
- “Frostum?” / shadow-cascade fitting:
- further-away shadow cascade fitting using frustum plane counts
- mentions using more clipping planes to fit cascades to occluders
- Contribution culling (especially for shadow maps)
- project meshlet bounding sphere into a screen-space rectangle (L-B-R-T concept)
- compare against a minimum contribution threshold
- reported savings: ~2ms in shadow map pass scenarios; tuning is difficult
- Normal cone calling (conceptually backface-ish for meshlets)
- described as existing, but not used for Alan Wake 2 mainly because occlusion culling already rejects many backfacing meshlets
- Occlusion culling (the main “holy grail”)
- Uses HZB
- samples depth at UV corners across an appropriate mip level vs the sphere depth
- requires conservative max-based downsampling (not average)
HZB construction details
- Use max-downsample Hi-Z for conservativeness.
- May pad to power-of-two/parity to avoid edge flicker.
Build method choice
- They use a single-pass downsampler (vs AMD SPD-style reference).
- Reported impact:
- ~2.2ms less rendering time
- improves triangle count down to ~12.3M before later steps
Overall results (core headline)
- After the calling pipeline:
- ~10.6M triangles from ~200M initial
- Shadow + G-buffer times are included in the talk, but the triangle-count reduction is the main headline.
Mesh shader usage and performance characteristics
Execution model
- Mesh shaders are the final draw mechanism after compute-driven culling/calling.
Pipeline simplification
- They describe a mesh-shader-only approach:
- no amplification shaders (mesh shaders only)
Mesh shader example behavior
- Configured like a small compute-style program:
- outputs up to 64 triangles / vertex attributes
- starts from per-meshlet bounds
- does bookkeeping, transforms vertices, outputs triangle indices
Benefit vs classic vertex shader pipeline
- Reported benefit: mesh shader version can be ~2x faster in some cases.
- Attribution: largely due to more precise culling
- “call meshlets instead of full meshes” (not mesh shaders magically reducing all costs)
Per-primitive calling / filtering
- Adds an extra step inside mesh shaders:
- reject triangles that won’t cover required sample points (conceptually linked to SV_Coverage / per-primitive behavior)
- Hardware dependence:
- Some GPUs see benefit; others see wash or loss
- Example outcomes mentioned:
- RDNA2: large win (~1.8ms faster)
- PC (Nvidia): a loss in this specific test
- Console wins reported (e.g., Series X ~8ms, Series S ~1.67ms)
Conclusions / lessons learned
- Alan Wake 2 shipped with mesh shaders, presented as an early production use.
- Remedy’s Northlight engine moved toward a fully GPU-driven rendering engine, improving iteration:
- artists previously experienced “slow” iteration
- now graphics can reflect actual content performance constraints (“your content is slow”)
- Mesh shaders are described as mature enough for flexibility and performance benefits.
- Major takeaway:
- meshlets + mesh shaders dramatically increase the amount of culling/calling possible.
What’s next (future directions)
- Work graphs
- could reduce worst-case allocation costs when using execute indirect
- avoid buffer blow-up
- Micropolygon-style software rasterization / Nanite-like approach
- they already do contribution calling + per-triangle calling
- but may still need rasterization for small triangles
- a classified approach could choose between software rasterization and fixed-function GPU paths
- Reduce alpha-testing overdraw
- alpha testing is costly (especially vegetation)
- propose a classification/draw strategy to reduce alpha-test overdraw
- More seamless meshlet loading
- reduce popping
- Meshlet compression research
- mentioned work reportedly down to ~5 bits per triangle
- performance impact still needs evaluation
Main speakers / sources (as mentioned)
- Primary speaker: Edik (Erik) Jansson, Senior Graphics Programmer, Remedy Entertainment
- Mentioned contributors / teams
- Northlight engine team at Remedy
- T. Alto (lead; key contributor to the GPU-driven rendering pipeline)
- Tools / libraries
- Open-source meshlet generation library (credited to A. Kappulkin per the subtitle)
- Referenced related material
- Prior/related resources: earlier GDC presentation on skinned vegetation meshlets (not fully detailed in the subtitles)
- AMD SPD / SPD-like reference for Hi-Z downsampling
- A named alternative for Hi-Z/HZB downsampling (subtitle suggests a person/approach; partially unclear)
Rate this summary
Your feedback will help improve summaries.
Improve this summary
Reprocess with a stronger model when the summary feels incomplete or inaccurate.
Translate summary in another language
Ask questions to this video
Chat for follow-up questions, clarifications, and source-backed answers.