Graphics: per-feature rendering toggles + quality presets (wire up graphics.quality)
Part of #158.
Problem
The renderer has no quality dial at all.
ProjectSettings.graphics.quality (low/medium/high/ultra) is persisted, serialized, and editable in the Project Settings Inspector — and no code in subsystems/render/ ever reads it. The only references outside the settings struct are the Inspector editor and its own tests.
Meanwhile every expensive choice is hardcoded:
pipeline.pickSampleCountreturnsSAMPLECOUNT_4whenever the device supports the format, with no override anywhere.- SSAO: 24 hemisphere taps at full resolution, plus a blur pass.
- SSR: a 32-step march at full resolution.
- 4 cascades at 2048²,
NUM_CASCADESfixed atcomptime. - No render-scale option.
So there is no way for a user — or for us, while optimizing — to trade quality for speed, and no way to find out which feature is actually costing the frame.
Scope
A render.Features struct in state.zig with one toggle or value per feature, applied through render.setFeatures():
| toggle | today | note |
|---|---|---|
msaa |
forced 4× | pipelines bake in the sample count, so changing it must rebuild the scene pipeline cache |
render_scale |
1.0 | render at a fraction, upsample in the composite pass |
ssao, ssao_half_res, ssao_samples |
on, full, 24 | |
ssr, ssr_half_res, ssr_steps |
on, full, 32 | |
shadows, shadow_dim, cascade_count |
on, 2048, 4 | NUM_CASCADES is comptime today; needs a runtime bound, max 4 — FragUB packs the splits into one vec4 |
reflection_probes |
on | |
bloom |
on | already per-volume; surface a global kill switch |
lod_bias |
— | placeholder until #39 lands |
Surfaced two ways:
1. A Studio "Rendering" control group, alongside the Profiler panel's existing vsync / fps-cap / detailed-GPU-timing controls: one checkbox or slider per feature, applied live with no restart. This is what makes the rest of #158 observable — flip one toggle, watch the frame chart move. It is also how we ground the presets in real hardware instead of guessing.
2. ProjectSettings.graphics.quality presets seeding the toggle set, finally giving that field meaning. The shipped game applies it at startup.
Suggested starting presets, to be re-grounded against #159 (closed)'s baseline numbers:
low— no MSAA, 0.75 render scale, half-res SSAO at 8 taps, SSR off, 1024 shadow map, 2 cascadesmedium— no MSAA, 1.0 scale, half-res SSAO + SSRhigh— today's behaviourultra— high + 4096 shadow map
Files
subsystems/render/{state,pipeline,ssao,ssr,shadow,postprocess,root}.zig, studio/main-window/ProfilerPanel.zig, engine/assets/ProjectSettings.zig, engine/Application.zig
Acceptance
- Every feature above can be toggled live in Studio with no restart
-
graphics.qualityseeds the toggles and is honoured by the shipped game - Changing MSAA correctly rebuilds the scene pipeline cache (pipelines bake in the sample count)
-
--featureson #159 (closed)'s benchmark harness can drive a toggle set headlessly - Each toggle's measured fps delta on Bistro recorded in the baseline doc