unreal-rendering-performance

Unreal 5.8 Rendering Performance

Diagnose and optimize Unreal rendering cost

---
name: unreal-rendering-performance
description: Diagnose, budget, scale, and optimize real-time rendering in Unreal Engine 5.8 after profiling identifies a render-thread or GPU bottleneck. Use for GPU Profiler results, draw calls, primitive and material cost, Nanite, Lumen, Lumen Lite, Virtual Shadow Maps, MegaLights, TSR, screen percentage, Dynamic Resolution, translucency, overdraw, culling, LOD/HLOD, GPU memory, Render Resource Viewer, Primitive Debugger, scalability groups, device profiles, or platform rendering tiers.
---

# Unreal 5.8 Rendering Performance

## Start from measured evidence

Use `unreal-insights-profiling` first when no trustworthy bound/pass/capture exists. Read
[`references/diagnostic-selector.md`](references/diagnostic-selector.md) and
[`references/budgets-and-baselines.md`](references/budgets-and-baselines.md).

1. Lock target hardware, renderer, resolution, quality tier, scene/camera, and frame budget.
2. Identify whether the cost is Render/RHI-thread submission, GPU pass time, GPU memory, or a hitch.
3. Name the largest measured pass/resource/submission category and its millisecond or byte cost.
4. Use the subsystem visualization/stats to locate causal content or settings.
5. Choose the least destructive lever that changes the measured cost: visibility, workload count,
   quality, resolution, representation, update frequency, or feature path.
6. Change one lever, capture the identical workload, and compare cost plus visual/gameplay impact.
7. Encode approved changes in scalability/device profiles and test every supported tier.

Load only what applies:

- [`references/resolution-tsr-and-dynamic-resolution.md`](references/resolution-tsr-and-dynamic-resolution.md)
- [`references/nanite-geometry.md`](references/nanite-geometry.md)
- [`references/lumen-and-reflections.md`](references/lumen-and-reflections.md)
- [`references/virtual-shadow-maps.md`](references/virtual-shadow-maps.md)
- [`references/megalights.md`](references/megalights.md)
- [`references/materials-translucency-and-overdraw.md`](references/materials-translucency-and-overdraw.md)
- [`references/submission-culling-and-lods.md`](references/submission-culling-and-lods.md)
- [`references/scalability-and-device-profiles.md`](references/scalability-and-device-profiles.md)
- [`references/gpu-memory-and-resources.md`](references/gpu-memory-and-resources.md)
- [`references/symptom-recipes.md`](references/symptom-recipes.md)

## Required answer format

Return:

1. **Target, renderer, budget, capture, and measured bound**.
2. **Dominant pass/submission/resource** with current cost.
3. **Diagnostic visualization or command** and expected evidence.
4. **Ranked changes**, each with mechanism, quality risk, platform scope, and predicted delta.
5. **Exact property/CVar/scalability/device-profile action** for the chosen experiment.
6. **A/B verification** at the same camera and settings.
7. **Tier and fallback behavior**, including unsupported/experimental paths.

## Hard rules

- Do not prescribe renderer CVars from symptoms alone; require a measured pass or bounded experiment.
- Do not compare GPU captures at different resolution, screen percentage, camera, or warm/cold state.
- Optimize milliseconds, not triangle/draw-call/instruction counts in isolation.
- Treat editor view modes and visualization overlays as diagnostic overhead; disable them for final timing.
- Preserve gameplay readability and fairness across tiers; scalability must not hide actionable content.
- Prefer scalability groups and device profiles over scattered runtime CVars.
- Treat Lumen Lite as Beta in UE 5.8 and Primitive Debugger/Nanite Foliage as Experimental.
- MegaLights is Production Ready in UE 5.8, but its quality still degrades as per-pixel light complexity
  exceeds its fixed sampling budget.
- Nanite does not make materials, masked overdraw, WPO, shadows, streaming, or storage free.
- Dynamic resolution mitigates GPU spikes; it does not repair a CPU/render-thread bottleneck.
- Preserve a supported fallback for target platforms that lack Nanite/Lumen/TSR/hardware ray tracing.

See [`references/sources.md`](references/sources.md) for the UE 5.8 primary-source trail.

## Start from measured evidence

Use `unreal-insights-profiling` first when no trustworthy bound/pass/capture exists. Read
[`references/diagnostic-selector.md`](/unreal/unreal-rendering-performance/diagnostic-selector/) and
[`references/budgets-and-baselines.md`](/unreal/unreal-rendering-performance/budgets-and-baselines/).

1. Lock target hardware, renderer, resolution, quality tier, scene/camera, and frame budget.
2. Identify whether the cost is Render/RHI-thread submission, GPU pass time, GPU memory, or a hitch.
3. Name the largest measured pass/resource/submission category and its millisecond or byte cost.
4. Use the subsystem visualization/stats to locate causal content or settings.
5. Choose the least destructive lever that changes the measured cost: visibility, workload count,
   quality, resolution, representation, update frequency, or feature path.
6. Change one lever, capture the identical workload, and compare cost plus visual/gameplay impact.
7. Encode approved changes in scalability/device profiles and test every supported tier.

Load only what applies:

- [`references/resolution-tsr-and-dynamic-resolution.md`](/unreal/unreal-rendering-performance/resolution-tsr-and-dynamic-resolution/)
- [`references/nanite-geometry.md`](/unreal/unreal-rendering-performance/nanite-geometry/)
- [`references/lumen-and-reflections.md`](/unreal/unreal-rendering-performance/lumen-and-reflections/)
- [`references/virtual-shadow-maps.md`](/unreal/unreal-rendering-performance/virtual-shadow-maps/)
- [`references/megalights.md`](/unreal/unreal-rendering-performance/megalights/)
- [`references/materials-translucency-and-overdraw.md`](/unreal/unreal-rendering-performance/materials-translucency-and-overdraw/)
- [`references/submission-culling-and-lods.md`](/unreal/unreal-rendering-performance/submission-culling-and-lods/)
- [`references/scalability-and-device-profiles.md`](/unreal/unreal-rendering-performance/scalability-and-device-profiles/)
- [`references/gpu-memory-and-resources.md`](/unreal/unreal-rendering-performance/gpu-memory-and-resources/)
- [`references/symptom-recipes.md`](/unreal/unreal-rendering-performance/symptom-recipes/)

## Required answer format

Return:

1. **Target, renderer, budget, capture, and measured bound**.
2. **Dominant pass/submission/resource** with current cost.
3. **Diagnostic visualization or command** and expected evidence.
4. **Ranked changes**, each with mechanism, quality risk, platform scope, and predicted delta.
5. **Exact property/CVar/scalability/device-profile action** for the chosen experiment.
6. **A/B verification** at the same camera and settings.
7. **Tier and fallback behavior**, including unsupported/experimental paths.

## Hard rules

- Do not prescribe renderer CVars from symptoms alone; require a measured pass or bounded experiment.
- Do not compare GPU captures at different resolution, screen percentage, camera, or warm/cold state.
- Optimize milliseconds, not triangle/draw-call/instruction counts in isolation.
- Treat editor view modes and visualization overlays as diagnostic overhead; disable them for final timing.
- Preserve gameplay readability and fairness across tiers; scalability must not hide actionable content.
- Prefer scalability groups and device profiles over scattered runtime CVars.
- Treat Lumen Lite as Beta in UE 5.8 and Primitive Debugger/Nanite Foliage as Experimental.
- MegaLights is Production Ready in UE 5.8, but its quality still degrades as per-pixel light complexity
  exceeds its fixed sampling budget.
- Nanite does not make materials, masked overdraw, WPO, shadows, streaming, or storage free.
- Dynamic resolution mitigates GPU spikes; it does not repair a CPU/render-thread bottleneck.
- Preserve a supported fallback for target platforms that lack Nanite/Lumen/TSR/hardware ray tracing.

See [`references/sources.md`](/unreal/unreal-rendering-performance/sources/) for the UE 5.8 primary-source trail.

unreal 5.8 rendering performance diagnose, budget, scale, and optimize real-time rendering in unreal engine 5.8 after profiling identifies a render-thread or gpu bottleneck. use for gpu profiler results, draw calls, primitive and material cost, nanite, lumen, lumen lite, virtual shadow maps, megalights, tsr, screen percentage, dynamic resolution, translucency, overdraw, culling, lod/hlod, gpu memory, render resource viewer, primitive debugger, scalability groups, device profiles, or platform rendering tiers. budgets and baselines budgets and baselines specify: - target fps and full frame budget; - rendering-thread and gpu sub-budget with safety margin; - output resolution and primary/secondary screen percentage; - renderer path, rhi, shader model, ray-tracing state, upscaler; - device profile and every sg. quality group; - scene, camera, time/weather, dynamic objects/lights/effects; - memory/thermal/power constraints. use milliseconds: | target | whole-frame deadline | |---|---:| | 30 fps | 33.33 ms | | 60 fps | 16.67 ms | | 90 fps | 11.11 ms | | 120 fps | 8.33 ms | keep margin for unsampled combat, traversal, streaming, platform services, and thermal variance. test representative worst cases, not an empty editor viewport. resolution sensitivity test 1. capture at production resolution/screen percentage. 2. lower primary screen percentage while preserving camera/content/quality. 3. compare total gpu and each pass. 4. classify passes that fall with pixel count versus fixed/geometry/submission costs. a resolution response localizes pixel-scaled work; it does not identify the specific effect. a weak response does not by itself prove cpu-bound because some gpu passes are weakly resolution-dependent. diagnostic selector diagnostic selector | measured problem | first inspection | route | |---|---|---| | gpu cost scales strongly with resolution | profilegpu, pass event tree | tsr/resolution, pixel-heavy pass | | draw/render thread dominates | primitive debugger, stat scenerendering, primitive/section counts | submission/culling/lod | | basepass high | shader complexity, material/primitive isolation | materials/overdraw | | translucency/post high | shader complexity, screen coverage, effect toggles | translucency/resolution | | nanite pass/streaming issue | nanite visualization, nanitestats | nanite geometry | | lumen gi/reflection high | lumen overview/visualizations, quality a/b | lumen | | shadow depths/projection high | vsm cache/caster views, light isolation | vsm or megalights | | many local lights/noisy direct light | megalights light/ray/caster visualizers | megalights | | tsr cost or ghosting | temporal upscaler visualization, gpu event | tsr | | gpu memory over budget | render resource viewer, rhi/platform memory stats | resources/streaming | | camera-cut spike | gpu/timing trace, vsm/visibility/streaming evidence | subsystem causing burst | disable diagnostic views before the timed a/b capture. their value is attribution, not the final number. gpu memory and render resources gpu memory and render resources open tools -> render resource viewer. it is a snapshot taken when opened; press refresh for a new snapshot. sort/filter by size, type, owner, resident, streaming, transient, and other flags. audit 1. record platform gpu-memory budget and current resident/allocated metrics. 2. capture the representative map/camera after expected streaming settles. 3. sort the largest resources and map each to an owning asset/lod. 4. separate persistent/resident allocations from transient aliased render-graph resources. 5. compare before/after at the same location and streaming state. common actions: - reduce texture resolution/format or correct texture groups/mips; - correct non-streaming or always-resident resources that do not require it; - reduce oversized render targets, history buffers, shadow pools, or feature buffers only after identifying their owner and quality effect; - review nanite streaming pool versus cache-thrashing tradeoff; - remove duplicate/unused assets and unexpectedly loaded references; - set per-platform lod/texture/device-profile limits. gpu resource allocation is not the same as process ram, package size, or streaming pool occupancy. track each budget with the appropriate tool and avoid summing overlapping categories. lumen gi and reflections lumen gi and reflections select quality by target - high-quality lumen is the modern dynamic gi/reflection path for capable targets. - ue 5.8 lumen lite is beta. medium gi quality (sg.globalilluminationquality 1) selects its irradiance field final gather (r.lumen.finalgathermethod 0) for faster, lower-quality gi. - medium reflection quality (sg.reflectionquality 1) disables lumen reflections, uses ssr on smooth surfaces, and retains rough specular from lumen gi. - below lumen, use the project/platform's supported baked or simpler gi/reflection fallback. start from epic's basescalability.ini and platform device profiles; they coordinate many interdependent settings to preserve a reasonably consistent look. isolate cost 1. confirm lumen passes are material in profilegpu/gpu trace. 2. capture lumen visualization/overview modes to find scene representation, update, reflection, or screen-trace problems. 3. a/b gi and reflection scalability independently. 4. test worst-case dynamic lights, camera motion, emissive content, interiors/exteriors, and distance. 5. validate temporal stability and lighting continuity on every tier. lumen uses async compute on supported consoles and can overlap other work. per-pass timings can include overlap. disable lumen async compute only for isolated profiling, then restore it and judge total frame time; overlap is part of the shipping performance strategy. materials, translucency, and overdraw materials, translucency, and overdraw diagnose 1. confirm basepass, translucency, post, or a material-bound draw is significant in gpu timing. 2. use shader complexity (alt+8 / viewmode shadercomplexity) to locate expensive pixel regions. 3. inspect quad overdraw/other supported view modes when tiny triangles or repeated coverage is suspected. 4. isolate the material/primitive/effect and re-capture the same frame. shader complexity primarily visualizes instruction count. it does not reliably price texture fetches, bandwidth, divergent loops, vertex/wpo work, or platform-specific scheduling. use it to locate suspects, then prove cost with gpu milliseconds. levers - reduce full-screen or large-screen material coverage before micro-optimizing a tiny object. - reduce overlapping translucent/masked layers, particle size, spawn density, and unnecessary sorting. - replace translucent effects with opaque/masked/dithered/mesh alternatives only when the visual result and temporal stability remain acceptable. - remove unused texture samples/features; move invariant work out of per-pixel paths where supported. - bound wpo and stop distant/imperceptible deformation. - reduce unique static-switch combinations/permutations; do not convert runtime decisions to static switches without considering compile/package/pso cost. - reduce material slots/sections when submission evidence supports it; preserve authoring flexibility where the measured cost is elsewhere. optimize the exact platform permutation and worst visible overlap. editor shader stats alone are not a shipping gpu measurement. megalights megalights megalights is production ready in ue 5.8. it replaces several deferred direct-lighting/shadow paths for local lights and supports many dynamic shadowed area lights. hardware ray tracing is recommended; each light can use ray-traced or vsm shadowing. directional light support is opt-in with r.megalights.directionallights 1 and disabled by default. epic recommends deferred lighting with vsm for a strong sun because the megalights path has quality limitations; a dim, soft moonlight can be a better fit. sky light remains outside megalights. understand the budget megalights traces a fixed sample budget per pixel toward important lights. runtime cost is more stable than per-light traditional paths, but quality/noise worsens when too many important lights compete at one pixel. more lights are not free artistically even when the timing remains bounded. diagnose 1. use megalights light finder, ray visualizer, and shadow-caster/mismatch views. 2. compare complete gpu frame time, not only one megalights event; it replaces multiple passes. 3. inspect off-screen and tiny bright lights, huge attenuation radii, overlapping volumes, and shadow methods. 4. test motion/noise at target internal resolution and tsr quality. scale | control | effect | |---|---| | r.megalights.allow 0 | disable per tier/device profile for a fallback path | | r.megalights.downsamplemode | adjust sampling/tracing resolution; stronger downsampling saves work but can reduce quality | | r.megalights.numsamplesperpixel | more samples improve stability/quality and increase gpu cost | | allow megalights per light | remove incompatible/problem lights from the path | | shadow method per light | choose ray tracing or vsm with different quality/cpu/memory/gpu tradeoffs | start from the shadow quality scalability group in basescalability.ini. high-quality translucency, volumetric fog, hair, textured area lights, and soft shadows have their own cost; scale only after the visualizer identifies them. nanite geometry nanite geometry use nanite for supported high-detail static/skeletal content when its virtualized path matches the target. preserve conventional lod/fallback behavior for unsupported platforms and features. diagnose - open view modes -> nanite visualization for triangles/clusters/overdraw/streaming/fallback evidence. - run nanitestats; use nanitestats list and a named view such as nanitestats virtualshadowmaps when applicable. - toggle r.nanite 0 only as a diagnostic/fallback-platform experiment; a scene authored around nanite may explode into conventional draw calls or unusable fallback cost. cost levers | evidence | action | |---|---| | streaming pool thrashes in a static view | increase r.nanite.streaming.streamingpoolsize if memory permits, or reduce resident demand | | gpu memory/storage excess | reduce source detail where imperceptible; review fallback and texture payloads | | masked/stacked surface overdraw | simplify aggregate geometry/material coverage; inspect nanite overdraw | | deformation/wpo cost | bound affected content and distance; remove deformation when imperceptible | | blinking/missing clusters at extreme complexity | inspect clusterssw/clustershw; size candidate/visible limits conservatively in config | | foliage loses area | evaluate preserve area and foliage-specific representation/lod | larger streaming pools reduce io/decompression churn but consume more memory. max edge length factor should remain 0 unless solving observed over-simplification on deforming/spline content; increasing it preserves detail at additional cost. do not use triangle count alone as a performance target. measure nanite passes, material/shadow cost, streaming, storage, and fallback behavior. resolution, tsr, and dynamic resolution resolution, tsr, and dynamic resolution tsr tsr renders at a lower internal resolution and reconstructs the display image. its work includes input-resolution and display-resolution costs, so lowering screen percentage may not reduce the tsr pass itself in direct proportion even when it reduces the rest of the frame. actions: 1. capture gpu cost at the production output resolution. 2. compare controlled primary screen percentages with identical content. 3. set anti-aliasing scalability through sg.antialiasingquality (0 low through 4 cinematic). 4. inspect show -> visualize -> temporal upscaler for velocity, rejection, translucency, exposure, input/output, and active quality information. 5. inspect the scene > postprocessing > temporalsuperresolution event in gpu tools. 6. fix velocity/translucency/material history defects before raising global quality to conceal them. avoid routine input screen percentages below 50%; epic reserves extreme upscaling for exceptional cases such as output beyond 4k or brief dynamic-resolution pressure. dynamic resolution enable through game user settings/c++ for supported targets, then configure: | cvar | effect | |---|---| | r.dynamicres.minscreenpercentage | lower bound; decreasing permits more quality loss to recover gpu time | | r.dynamicres.maxscreenpercentage | allocation/quality ceiling | | r.dynamicres.frametimebudget | gpu-frame target in milliseconds | | r.dynamicres.historysize | larger smooths decisions but reacts more slowly; smaller reacts faster but is noisier | use stat unitgraph, then stat raw, to inspect raw gpu time and selected primary screen percentage. dynamic resolution reacts to prior gpu workload and may panic downward after consecutive over-budget frames. it cannot predict every camera cut/effect burst and cannot recover a cpu-bound frame by doing less gpu pixel work. scalability and device profiles scalability and device profiles ownership - use scalability groups for player-facing quality families. - use device profiles for platform/device defaults, feature support, memory buckets, and overrides. - store project overrides in project config, not edited engine base files. - treat engine/config/basescalability.ini and platform base device profiles as current reference implementations, then override only measured needs. core groups include resolution, view distance, anti-aliasing, shadows, global illumination, reflections, post processing, textures, effects, foliage, and shading. validate the exact ue 5.8 group contents; one sg. value can change many cvars. tier workflow 1. define minimum/recommended target hardware and renderer feature support. 2. establish low/medium/high/epic intent with a stable gameplay-readability floor. 3. begin with engine group defaults; measure every target device. 4. override subsystem controls only when the group misses the budget or quality target. 5. expose settings whose visual/performance trade is meaningful to players. 6. restart/reload when a feature path or shader permutation requires it; label settings accordingly. 7. test saved settings, auto-detection/defaults, upgrades, and unsupported hardware fallback. never let a low tier remove enemies, hazards, navigation cues, competitive visibility, or essential feedback. scale visual richness and representation, not game rules. ue 5.8 primary sources ue 5.8 primary sources - ue 5.8 release notes - optimizing and debugging real-time rendering - scalability reference - setting device profiles - temporal super resolution - temporal upscalers - dynamic resolution - nanite virtualized geometry - working with nanite-enabled content - nanite technical details - lumen performance guide - virtual shadow maps - megalights - viewport modes - visibility and occlusion culling - primitive debugger - render resource viewer pages were checked against ue 5.8 documentation on 2026-07-19. reconfirm feature maturity, renderer/platform support, scalability-group contents, visualization names, and cvars after an engine upgrade. submission, culling, and lods submission, culling, and lods render-thread cost often follows visible primitive/component/section/light counts and state diversity, not raw triangle count alone. inspect - stat unit, stat scenerendering, stat rhi, and timing insights render/rhi tracks. - runtime primitive debugger (primitivedebugger.open) in development/test builds for primitive, draw-call, and lod data. it is experimental in ue 5.8; use it diagnostically, not as shipping logic. - freeze rendering/occlusion and r.visualizeoccludedprimitives 1 to inspect culling behavior. reduce submissions and visibility work - instance repeated meshes when transforms/material requirements permit. - merge actors/sections only when it does not destroy culling granularity, streaming, interaction, or authoring needs. - use hlod for distant groups and conventional skeletal/static lods where nanite is not the path. - set max draw distance or cull distance volumes for content that becomes irrelevant. - keep bounds accurate; oversized bounds harm culling, shadows, and streaming decisions. - avoid thousands of independently ticking/updating render components when a batched representation fits. - remove material slots/sections only when section submission is measured. unreal applies distance, frustum, precomputed visibility, then dynamic occlusion according to method and platform. hardware occlusion queries are enabled by default on supported paths. precomputed visibility trades build/runtime memory for reduced runtime rendering work and best fits constrained, mostly static, small-to-medium environments. test occlusion changes during camera motion. more aggressive culling can add popping or query cost and can be worse than rendering small cheap objects. symptom recipes symptom recipes | symptom | prove first | first bounded experiment | |---|---|---| | slow only at high resolution | pixel-scaled gpu passes | lower screen percentage; compare pass deltas | | slow in dense city/forest | render thread, nanite/material/vsm/visibility | isolate primitive/section, overdraw, caster invalidation | | shadow spike while foliage moves | vsm uncached pages/casters | disable distant wpo/shadows on one foliage class | | camera cuts hitch | visibility/vsm/streaming/upscaler history | marked trace plus cache/streaming views | | many lights stay fast but noisy | megalights sample competition | reduce competing radii/lights or raise samples in controlled a/b | | reflections dominate | lumen reflection pass | compare reflection scalability separately from gi | | translucent combat effect tanks gpu | translucency/overdraw event | cut overlap/coverage for one effect | | render thread slow, gpu has headroom | primitive/section/submission count | instance/cull one high-count category | | gpu memory grows by location | resource snapshot and streaming residency | identify largest new owners and correct residency/lod | | low tier changes nothing | device profile/group not applied or restart needed | display active cvars/profile and verify packaged build | | dynamic resolution bottoms out | sustained gpu cost exceeds minimum-resolution budget or cpu bound | inspect gpu at minimum percentage; optimize dominant pass | for every recipe, restore the toggle, implement the production-quality change through owned settings, and capture the same worst case again. virtual shadow maps virtual shadow maps vsms are designed to pair with nanite and large dynamically lit worlds. if the target does not use nanite, validate whether conventional shadow maps are a better fit. diagnose the two cost buckets - shadow depths: rendering/updating caster depth pages. - shadow projection under lights: sampling/projecting shadows into the frame. use view modes -> virtual shadow map: - cached page: green cached, red uncached, blue static-only cached; - shadow casters: locate invalidators; - nanite overdraw: locate costly caster coverage; - virtual page/clipmap-mip: inspect page demand/resolution. disable visualization before timing. for counters, use trace.enable counters,vsm; csv profiling can enable the vsm category. reduce invalidation largest invalidators commonly include moving lights, moving/added/removed casters, component render- state churn, wpo/pdo, skeletal deformation, large bounds, camera cuts, and rapid disocclusion. actions: - stop needless light/primitive updates; - keep deforming bounds tight; - remove wpo/pdo or shadow casting at distance when visually safe; - use material/mesh lods that disable deformation in the distance; - use contact or distance field shadows where the content/target supports the trade; - use shadow cache invalidation behavior overrides only when the asserted rigidity/static state is true; incorrect suppression produces undefined/stale shadows. r.shadow.virtual.cache 0 is a diagnostic to expose caching benefit, not a shipping optimization. resolution lod bias trades shadow detail for pages/work. moving-light biases exist because moving lights cannot reuse cache like stationary ones. when profiling individual vsm passes, r.rdg.asynccompute 0 can make timings more representative; never ship that profiling-only override.

Budgets and baselines

# Budgets and baselines

Specify:

- target FPS and full frame budget;
- rendering-thread and GPU sub-budget with safety margin;
- output resolution and primary/secondary screen percentage;
- renderer path, RHI, shader model, ray-tracing state, upscaler;
- device profile and every `sg.*` quality group;
- scene, camera, time/weather, dynamic objects/lights/effects;
- memory/thermal/power constraints.

Use milliseconds:

| Target | Whole-frame deadline |
|---|---:|
| 30 fps | 33.33 ms |
| 60 fps | 16.67 ms |
| 90 fps | 11.11 ms |
| 120 fps | 8.33 ms |

Keep margin for unsampled combat, traversal, streaming, platform services, and thermal variance. Test
representative worst cases, not an empty editor viewport.

## Resolution sensitivity test

1. Capture at production resolution/screen percentage.
2. Lower primary screen percentage while preserving camera/content/quality.
3. Compare total GPU and each pass.
4. Classify passes that fall with pixel count versus fixed/geometry/submission costs.

A resolution response localizes pixel-scaled work; it does not identify the specific effect. A weak
response does not by itself prove CPU-bound because some GPU passes are weakly resolution-dependent.

Diagnostic selector

# Diagnostic selector

| Measured problem | First inspection | Route |
|---|---|---|
| GPU cost scales strongly with resolution | `profilegpu`, pass event tree | TSR/resolution, pixel-heavy pass |
| Draw/Render thread dominates | Primitive Debugger, `stat sceneRendering`, primitive/section counts | submission/culling/LOD |
| BasePass high | Shader Complexity, material/primitive isolation | materials/overdraw |
| Translucency/post high | Shader Complexity, screen coverage, effect toggles | translucency/resolution |
| Nanite pass/streaming issue | Nanite visualization, `NaniteStats` | Nanite geometry |
| Lumen GI/reflection high | Lumen overview/visualizations, quality A/B | Lumen |
| Shadow Depths/Projection high | VSM cache/caster views, light isolation | VSM or MegaLights |
| many local lights/noisy direct light | MegaLights light/ray/caster visualizers | MegaLights |
| TSR cost or ghosting | Temporal Upscaler visualization, GPU event | TSR |
| GPU memory over budget | Render Resource Viewer, RHI/platform memory stats | resources/streaming |
| camera-cut spike | GPU/Timing trace, VSM/visibility/streaming evidence | subsystem causing burst |

Disable diagnostic views before the timed A/B capture. Their value is attribution, not the final
number.

GPU memory and render resources

# GPU memory and render resources

Open Tools -> Render Resource Viewer. It is a snapshot taken when opened; press Refresh for a new
snapshot. Sort/filter by size, type, owner, resident, streaming, transient, and other flags.

## Audit

1. Record platform GPU-memory budget and current resident/allocated metrics.
2. Capture the representative map/camera after expected streaming settles.
3. Sort the largest resources and map each to an owning asset/LOD.
4. Separate persistent/resident allocations from transient aliased render-graph resources.
5. Compare before/after at the same location and streaming state.

Common actions:

- reduce texture resolution/format or correct texture groups/mips;
- correct non-streaming or always-resident resources that do not require it;
- reduce oversized render targets, history buffers, shadow pools, or feature buffers only after
  identifying their owner and quality effect;
- review Nanite streaming pool versus cache-thrashing tradeoff;
- remove duplicate/unused assets and unexpectedly loaded references;
- set per-platform LOD/texture/device-profile limits.

GPU resource allocation is not the same as process RAM, package size, or streaming pool occupancy.
Track each budget with the appropriate tool and avoid summing overlapping categories.

Lumen GI and reflections

# Lumen GI and reflections

## Select quality by target

- High-quality Lumen is the modern dynamic GI/reflection path for capable targets.
- UE 5.8 Lumen Lite is **Beta**. Medium GI quality (`sg.GlobalIlluminationQuality 1`) selects its
  Irradiance Field Final Gather (`r.Lumen.FinalGatherMethod 0`) for faster, lower-quality GI.
- Medium reflection quality (`sg.ReflectionQuality 1`) disables Lumen Reflections, uses SSR on smooth
  surfaces, and retains rough specular from Lumen GI.
- Below Lumen, use the project/platform's supported baked or simpler GI/reflection fallback.

Start from Epic's `BaseScalability.ini` and platform device profiles; they coordinate many interdependent
settings to preserve a reasonably consistent look.

## Isolate cost

1. Confirm Lumen passes are material in `profilegpu`/GPU trace.
2. Capture Lumen visualization/overview modes to find scene representation, update, reflection, or
   screen-trace problems.
3. A/B GI and reflection scalability independently.
4. Test worst-case dynamic lights, camera motion, emissive content, interiors/exteriors, and distance.
5. Validate temporal stability and lighting continuity on every tier.

Lumen uses async compute on supported consoles and can overlap other work. Per-pass timings can include
overlap. Disable Lumen async compute only for isolated profiling, then restore it and judge total frame
time; overlap is part of the shipping performance strategy.

Materials, translucency, and overdraw

# Materials, translucency, and overdraw

## Diagnose

1. Confirm BasePass, translucency, post, or a material-bound draw is significant in GPU timing.
2. Use Shader Complexity (`Alt+8` / `viewmode shadercomplexity`) to locate expensive pixel regions.
3. Inspect Quad Overdraw/other supported view modes when tiny triangles or repeated coverage is suspected.
4. Isolate the material/primitive/effect and re-capture the same frame.

Shader Complexity primarily visualizes instruction count. It does not reliably price texture fetches,
bandwidth, divergent loops, vertex/WPO work, or platform-specific scheduling. Use it to locate suspects,
then prove cost with GPU milliseconds.

## Levers

- Reduce full-screen or large-screen material coverage before micro-optimizing a tiny object.
- Reduce overlapping translucent/masked layers, particle size, spawn density, and unnecessary sorting.
- Replace translucent effects with opaque/masked/dithered/mesh alternatives only when the visual result
  and temporal stability remain acceptable.
- Remove unused texture samples/features; move invariant work out of per-pixel paths where supported.
- Bound WPO and stop distant/imperceptible deformation.
- Reduce unique static-switch combinations/permutations; do not convert runtime decisions to static
  switches without considering compile/package/PSO cost.
- Reduce material slots/sections when submission evidence supports it; preserve authoring flexibility
  where the measured cost is elsewhere.

Optimize the exact platform permutation and worst visible overlap. Editor shader stats alone are not a
shipping GPU measurement.

MegaLights

# MegaLights

MegaLights is **Production Ready in UE 5.8**. It replaces several deferred direct-lighting/shadow paths
for local lights and supports many dynamic shadowed area lights. Hardware ray tracing is recommended;
each light can use ray-traced or VSM shadowing.

Directional Light support is opt-in with `r.MegaLights.DirectionalLights 1` and disabled by default.
Epic recommends Deferred Lighting with VSM for a strong sun because the MegaLights path has quality
limitations; a dim, soft moonlight can be a better fit. Sky Light remains outside MegaLights.

## Understand the budget

MegaLights traces a fixed sample budget per pixel toward important lights. Runtime cost is more stable
than per-light traditional paths, but quality/noise worsens when too many important lights compete at
one pixel. More lights are not free artistically even when the timing remains bounded.

## Diagnose

1. Use MegaLights light finder, ray visualizer, and shadow-caster/mismatch views.
2. Compare complete GPU frame time, not only one MegaLights event; it replaces multiple passes.
3. Inspect off-screen and tiny bright lights, huge attenuation radii, overlapping volumes, and shadow
   methods.
4. Test motion/noise at target internal resolution and TSR quality.

## Scale

| Control | Effect |
|---|---|
| `r.MegaLights.Allow 0` | disable per tier/device profile for a fallback path |
| `r.MegaLights.DownsampleMode` | adjust sampling/tracing resolution; stronger downsampling saves work but can reduce quality |
| `r.MegaLights.NumSamplesPerPixel` | more samples improve stability/quality and increase GPU cost |
| Allow MegaLights per light | remove incompatible/problem lights from the path |
| Shadow Method per light | choose ray tracing or VSM with different quality/CPU/memory/GPU tradeoffs |

Start from the Shadow Quality scalability group in `BaseScalability.ini`. High-quality translucency,
volumetric fog, hair, textured area lights, and soft shadows have their own cost; scale only after the
visualizer identifies them.

Nanite geometry

# Nanite geometry

Use Nanite for supported high-detail static/skeletal content when its virtualized path matches the
target. Preserve conventional LOD/fallback behavior for unsupported platforms and features.

## Diagnose

- Open View Modes -> Nanite Visualization for triangles/clusters/overdraw/streaming/fallback evidence.
- Run `NaniteStats`; use `NaniteStats List` and a named view such as
  `NaniteStats VirtualShadowMaps` when applicable.
- Toggle `r.Nanite 0` only as a diagnostic/fallback-platform experiment; a scene authored around
  Nanite may explode into conventional draw calls or unusable fallback cost.

## Cost levers

| Evidence | Action |
|---|---|
| streaming pool thrashes in a static view | increase `r.Nanite.Streaming.StreamingPoolSize` if memory permits, or reduce resident demand |
| GPU memory/storage excess | reduce source detail where imperceptible; review fallback and texture payloads |
| masked/stacked surface overdraw | simplify aggregate geometry/material coverage; inspect Nanite Overdraw |
| deformation/WPO cost | bound affected content and distance; remove deformation when imperceptible |
| blinking/missing clusters at extreme complexity | inspect `ClustersSW`/`ClustersHW`; size candidate/visible limits conservatively in config |
| foliage loses area | evaluate Preserve Area and foliage-specific representation/LOD |

Larger streaming pools reduce IO/decompression churn but consume more memory. `Max Edge Length Factor`
should remain `0` unless solving observed over-simplification on deforming/spline content; increasing
it preserves detail at additional cost.

Do not use triangle count alone as a performance target. Measure Nanite passes, material/shadow cost,
streaming, storage, and fallback behavior.

Resolution, TSR, and Dynamic Resolution

# Resolution, TSR, and Dynamic Resolution

## TSR

TSR renders at a lower internal resolution and reconstructs the display image. Its work includes
input-resolution and display-resolution costs, so lowering screen percentage may not reduce the TSR
pass itself in direct proportion even when it reduces the rest of the frame.

Actions:

1. Capture GPU cost at the production output resolution.
2. Compare controlled primary screen percentages with identical content.
3. Set Anti-Aliasing scalability through `sg.AntiAliasingQuality` (`0` Low through `4` Cinematic).
4. Inspect Show -> Visualize -> Temporal Upscaler for velocity, rejection, translucency, exposure,
   input/output, and active quality information.
5. Inspect the `Scene > PostProcessing > TemporalSuperResolution` event in GPU tools.
6. Fix velocity/translucency/material history defects before raising global quality to conceal them.

Avoid routine input screen percentages below 50%; Epic reserves extreme upscaling for exceptional
cases such as output beyond 4K or brief dynamic-resolution pressure.

## Dynamic Resolution

Enable through Game User Settings/C++ for supported targets, then configure:

| CVar | Effect |
|---|---|
| `r.DynamicRes.MinScreenPercentage` | lower bound; decreasing permits more quality loss to recover GPU time |
| `r.DynamicRes.MaxScreenPercentage` | allocation/quality ceiling |
| `r.DynamicRes.FrameTimeBudget` | GPU-frame target in milliseconds |
| `r.DynamicRes.HistorySize` | larger smooths decisions but reacts more slowly; smaller reacts faster but is noisier |

Use `stat unitgraph`, then `stat raw`, to inspect raw GPU time and selected primary screen percentage.
Dynamic resolution reacts to prior GPU workload and may panic downward after consecutive over-budget
frames. It cannot predict every camera cut/effect burst and cannot recover a CPU-bound frame by doing
less GPU pixel work.

Scalability and device profiles

# Scalability and device profiles

## Ownership

- Use scalability groups for player-facing quality families.
- Use device profiles for platform/device defaults, feature support, memory buckets, and overrides.
- Store project overrides in project `Config`, not edited engine base files.
- Treat `Engine/Config/BaseScalability.ini` and platform base device profiles as current reference
  implementations, then override only measured needs.

Core groups include resolution, view distance, anti-aliasing, shadows, global illumination, reflections,
post processing, textures, effects, foliage, and shading. Validate the exact UE 5.8 group contents;
one `sg.*` value can change many CVars.

## Tier workflow

1. Define minimum/recommended target hardware and renderer feature support.
2. Establish Low/Medium/High/Epic intent with a stable gameplay-readability floor.
3. Begin with engine group defaults; measure every target device.
4. Override subsystem controls only when the group misses the budget or quality target.
5. Expose settings whose visual/performance trade is meaningful to players.
6. Restart/reload when a feature path or shader permutation requires it; label settings accordingly.
7. Test saved settings, auto-detection/defaults, upgrades, and unsupported hardware fallback.

Never let a low tier remove enemies, hazards, navigation cues, competitive visibility, or essential
feedback. Scale visual richness and representation, not game rules.

UE 5.8 primary sources

# UE 5.8 primary sources

- [UE 5.8 Release Notes](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-engine-5-8-release-notes)
- [Optimizing and Debugging Real-Time Rendering](https://dev.epicgames.com/documentation/en-us/unreal-engine/optimizing-and-debugging-projects-for-realtime-rendering-in-unreal-engine)
- [Scalability Reference](https://dev.epicgames.com/documentation/en-us/unreal-engine/scalability-reference-for-unreal-engine)
- [Setting Device Profiles](https://dev.epicgames.com/documentation/en-us/unreal-engine/setting-up-device-profiles-in-unreal-engine)
- [Temporal Super Resolution](https://dev.epicgames.com/documentation/en-us/unreal-engine/temporal-super-resolution-in-unreal-engine)
- [Temporal Upscalers](https://dev.epicgames.com/documentation/en-us/unreal-engine/temporal-upscalers-in-unreal-engine)
- [Dynamic Resolution](https://dev.epicgames.com/documentation/en-us/unreal-engine/dynamic-resolution-in-unreal-engine)
- [Nanite Virtualized Geometry](https://dev.epicgames.com/documentation/en-us/unreal-engine/nanite-virtualized-geometry-in-unreal-engine)
- [Working with Nanite-Enabled Content](https://dev.epicgames.com/documentation/en-us/unreal-engine/working-with-naniteenabled-content)
- [Nanite Technical Details](https://dev.epicgames.com/documentation/en-us/unreal-engine/nanite-technical-details)
- [Lumen Performance Guide](https://dev.epicgames.com/documentation/en-us/unreal-engine/lumen-performance-guide-for-unreal-engine)
- [Virtual Shadow Maps](https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine)
- [MegaLights](https://dev.epicgames.com/documentation/en-us/unreal-engine/megalights-in-unreal-engine)
- [Viewport Modes](https://dev.epicgames.com/documentation/en-us/unreal-engine/viewport-modes-in-unreal-engine)
- [Visibility and Occlusion Culling](https://dev.epicgames.com/documentation/en-us/unreal-engine/visibility-and-occlusion-culling-in-unreal-engine)
- [Primitive Debugger](https://dev.epicgames.com/documentation/en-us/unreal-engine/primitive-debugger-in-unreal-engine)
- [Render Resource Viewer](https://dev.epicgames.com/documentation/en-us/unreal-engine/render-resource-viewer-in-unreal-engine)

Pages were checked against UE 5.8 documentation on 2026-07-19. Reconfirm feature maturity,
renderer/platform support, scalability-group contents, visualization names, and CVars after an engine
upgrade.

Submission, culling, and LODs

# Submission, culling, and LODs

Render-thread cost often follows visible primitive/component/section/light counts and state diversity,
not raw triangle count alone.

## Inspect

- `stat unit`, `stat sceneRendering`, `stat rhi`, and Timing Insights Render/RHI tracks.
- Runtime **Primitive Debugger** (`PrimitiveDebugger.Open`) in Development/Test builds for primitive,
  draw-call, and LOD data. It is Experimental in UE 5.8; use it diagnostically, not as shipping logic.
- Freeze rendering/occlusion and `r.VisualizeOccludedPrimitives 1` to inspect culling behavior.

## Reduce submissions and visibility work

- Instance repeated meshes when transforms/material requirements permit.
- Merge actors/sections only when it does not destroy culling granularity, streaming, interaction, or
  authoring needs.
- Use HLOD for distant groups and conventional skeletal/static LODs where Nanite is not the path.
- Set Max Draw Distance or Cull Distance Volumes for content that becomes irrelevant.
- Keep bounds accurate; oversized bounds harm culling, shadows, and streaming decisions.
- Avoid thousands of independently ticking/updating render components when a batched representation fits.
- Remove material slots/sections only when section submission is measured.

Unreal applies distance, frustum, precomputed visibility, then dynamic occlusion according to method and
platform. Hardware occlusion queries are enabled by default on supported paths. Precomputed Visibility
trades build/runtime memory for reduced runtime rendering work and best fits constrained, mostly static,
small-to-medium environments.

Test occlusion changes during camera motion. More aggressive culling can add popping or query cost and
can be worse than rendering small cheap objects.

Symptom recipes

# Symptom recipes

| Symptom | Prove first | First bounded experiment |
|---|---|---|
| slow only at high resolution | pixel-scaled GPU passes | lower screen percentage; compare pass deltas |
| slow in dense city/forest | Render thread, Nanite/material/VSM/visibility | isolate primitive/section, overdraw, caster invalidation |
| shadow spike while foliage moves | VSM uncached pages/casters | disable distant WPO/shadows on one foliage class |
| camera cuts hitch | visibility/VSM/streaming/upscaler history | marked trace plus cache/streaming views |
| many lights stay fast but noisy | MegaLights sample competition | reduce competing radii/lights or raise samples in controlled A/B |
| reflections dominate | Lumen reflection pass | compare reflection scalability separately from GI |
| translucent combat effect tanks GPU | translucency/overdraw event | cut overlap/coverage for one effect |
| render thread slow, GPU has headroom | primitive/section/submission count | instance/cull one high-count category |
| GPU memory grows by location | resource snapshot and streaming residency | identify largest new owners and correct residency/LOD |
| low tier changes nothing | device profile/group not applied or restart needed | display active CVars/profile and verify packaged build |
| dynamic resolution bottoms out | sustained GPU cost exceeds minimum-resolution budget or CPU bound | inspect GPU at minimum percentage; optimize dominant pass |

For every recipe, restore the toggle, implement the production-quality change through owned settings,
and capture the same worst case again.

Virtual Shadow Maps

# Virtual Shadow Maps

VSMs are designed to pair with Nanite and large dynamically lit worlds. If the target does not use
Nanite, validate whether conventional shadow maps are a better fit.

## Diagnose the two cost buckets

- **Shadow Depths**: rendering/updating caster depth pages.
- **Shadow Projection** under Lights: sampling/projecting shadows into the frame.

Use View Modes -> Virtual Shadow Map:

- Cached Page: green cached, red uncached, blue static-only cached;
- Shadow Casters: locate invalidators;
- Nanite Overdraw: locate costly caster coverage;
- Virtual Page/Clipmap-Mip: inspect page demand/resolution.

Disable visualization before timing. For counters, use `trace.enable counters,vsm`; CSV profiling can
enable the VSM category.

## Reduce invalidation

Largest invalidators commonly include moving lights, moving/added/removed casters, component render-
state churn, WPO/PDO, skeletal deformation, large bounds, camera cuts, and rapid disocclusion.

Actions:

- stop needless light/primitive updates;
- keep deforming bounds tight;
- remove WPO/PDO or shadow casting at distance when visually safe;
- use material/mesh LODs that disable deformation in the distance;
- use Contact or Distance Field shadows where the content/target supports the trade;
- use `Shadow Cache Invalidation Behavior` overrides only when the asserted rigidity/static state is
  true; incorrect suppression produces undefined/stale shadows.

`r.Shadow.Virtual.Cache 0` is a diagnostic to expose caching benefit, not a shipping optimization.
Resolution LOD bias trades shadow detail for pages/work. Moving-light biases exist because moving lights
cannot reuse cache like stationary ones.

When profiling individual VSM passes, `r.RDG.AsyncCompute 0` can make timings more representative;
never ship that profiling-only override.