Fix: Light and shadow optimizations #742

Merged
SakulFlee merged 15 commits from fix_light_optimization into main 2026-08-01 02:08:06 +02:00
Owner

This introduces staggered light and shadow updates.
Instead of recalculating everything every frame, we keep a list of "dirty" items and update one per frame. Say we render at 60 FPS, that would be 60x lighting updates per second. It is near real-time while having an enormous performance save: From ~3500 commands before we are down to ~500 now!

This introduces staggered light and shadow updates. Instead of recalculating everything every frame, we keep a list of "dirty" items and update **one per frame**. Say we render at 60 FPS, that would be 60x lighting updates per second. It is near real-time while having an enormous performance save: From ~3500 commands before we are down to ~500 now!
The pre-allocated light buffer (MAX_LIGHTS=256) caused the PBR shader to
loop 256 times per fragment via arrayLength(&light_store), running the
full BRDF+shadow path 256 times instead of ~6 actual lights. This made
the model render pass ~3x slower (6.8ms→22ms in RenderDoc).

Changes:
- Add binding 13 (light_count uniform) to world bind group layout
- Compute active_light_count from LightDescriptorEcs dense.len() each frame
- Write to a static 16-byte UNIFORM|COPY_DST buffer (LIGHT_COUNT_BUF)
- Shader: loop bound changed from arrayLength(&light_store) to light_count
- Shader: add zero-intensity early continue guard (light.color.w == 0.0)
- Also moved global_model_dirty check before realize_models (Fix B1) to
  catch newly-imported models (e.g. DamagedHelmet) whose ModelDirty flag
  is cleared by realize_models before the check runs
On frame 1 (bootstrap), ensure_cubes(2) was called mid-loop when the
second point light was processed, reallocating the cube depth texture
from 1 to 2 cubes. This dropped the first point light's freshly-rendered
cube-0 depth data into the old (dropped) texture, leaving cube 0 as
uninitialized garbage in the new texture. The shader's textureSampleCompare
for that cube returned shadowed (0) for all fragments, making the Room 4
point light contribute nothing — dark room, no shadows.

Changes:
- Pre-compute needed_cubes (count of enabled point lights) and
  needed_layers (spot/directional cascade sum) BEFORE the render loop
- Call ensure_cubes/ensure_layers up-front to final capacity
- Track grew = cubes_grew || layers_grew; when true, force_all_dirty
  makes all lights re-render this frame so no previously-stored depth
  is silently lost after a texture growth realloc
- Remove redundant mid-loop ensure_cubes and post-loop ensure_layers
Fix round-robin starvation: reserve floor budget for proactive shadow refresh
Some checks failed
ci/woodpecker/pr/linting Pipeline failed
ci/woodpecker/pr/test unknown status
99208c9a99
The dirty-first pass consumed the entire per-frame budget when lights
were constantly dirty (e.g. the temporary LightAnimator marking Room-1
spot dirty every frame), starving the proactive round-robin refresh.
This meant clean shadow maps were never re-rendered, preventing newly
imported models from ever appearing in shadow maps.

Changes:
- Reserve max(1, budget/2) for round-robin when clean casters exist
  (0 reserve when no clean casters — all budget goes to dirty)
- Dirty lights get up to budget - reserve slots (still priority)
- Round-robin uses the remainder, ensuring proactive refresh runs
  even when some lights are always dirty
Merge branch 'main' into fix_light_optimization
Some checks failed
ci/woodpecker/pr/linting Pipeline failed
ci/woodpecker/pr/test unknown status
24c6eeee95
style: auto-format code
Some checks failed
ci/woodpecker/pr/linting Pipeline failed
ci/woodpecker/pr/test unknown status
2c3db63ff8
fix: auto-fix clippy warnings
Some checks failed
ci/woodpecker/pr/linting Pipeline failed
ci/woodpecker/pr/test unknown status
e8304144db
style: auto-format code
All checks were successful
ci/woodpecker/pr/linting Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
a9ee2a44e7
Sign in to join this conversation.
No description provided.