Investigate: particle FPS cost in its various forms (count, overdraw, glow, textures, shadows, crowds) -- measure, then file fixes #435

Closed
opened 2026-10-05 12:26:26 +00:00 by sky_line · 3 comments
Owner

Investigation: measure how particles affect frame rate (CPU and GPU) in the different forms they take in SL, find the expensive cases, and file targeted fixes.

Where particles live in Slipstream

  • LL simulation (CPU): llviewerpartsim.cpp / llviewerpartsource.cpp handle sources (llParticleSystem), per-particle updates, lifetime, and the RenderMaxPartCount cap (the quality slider sets it, 0-8192).
  • VK side: llcleanparticlestore.cpp (GPU particle pools: the part VRAM category; the "emit live/peak/4096" store in the VKMem log), particle compute + indirect draws (recordParticleCompute, releaseParticles, RenderVKOverlapParticles async/overlap), particle shadow casters, and particle coverage written into the TAA reactive / coverage mask.
  • The particle editor (alfloaterparticleeditor.cpp), for building test emitters.

Cases to measure

For each case, record CPU frame time (main thread), GPU time per pass (the particle compute, particle draw, shadows, TAA/FSR, post), particle count / emitter count, and overdraw:

  1. Many small particles (rain, snow, sparkles): high count, small screen size → CPU sim + per-particle upload / compute cost.
  2. Few huge particles (smoke, fog, clouds, light shafts, "glow" planes covering the screen): overdraw / fill rate → GPU-bound, worst at high resolution.
  3. Additive / glow / emissive particles (club lights, lasers): blending + glow + bloom cost; HDR interaction.
  4. Textured vs untextured, animated textures (flipbook): texture fetch / residency / bindless churn.
  5. Particles with shadows (if particles cast shadows): shadow-pass cost per cascade / RT.
  6. Particles bouncing / following / target-pos / wind-affected (flags that add per-particle CPU work).
  7. Avatar-attached emitters (worn bling, effects), many avatars in a club: emitter count scaling.
  8. Selection beams / the "show selection beam" particles (the ShowSelectionBeam / EnableSelectionHints paths).
  9. Interaction with TAA / FSR: particle ghosting / reactive mask cost; motion-vector handling for particles.
  10. Interaction with the VRAM ladder / budget: particle pools sized sensibly (high-water vs live), freed when idle.

Method

  • Build repeatable test scenes with the particle editor (one emitter per case; adjustable counts) plus real-world busy spots (a club with light shows, a weather region).
  • Compare particles on / off (RenderMaxPartCount 0 vs default vs max) and resolution 1080p vs 4K (for fill rate).
  • Use the existing GPU pass timers and CPU perf / Tracy zones (add zones around the part sim update and the particle upload if missing).
  • Compare with Firestorm on the same scenes (CPU sim cost is LL-shared; GPU path differs).

Likely fixes to evaluate (file separately once measured)

  • Move simulation to the GPU (compute-driven emitters: the CPU only spawns, the GPU updates). This fits the GPU-driven architecture and removes per-particle CPU cost.
  • Overdraw control: half-resolution particle rendering for big translucent particles, composited with depth-aware upsampling; screen-size / overdraw budgets.
  • Distance / LOD: fade or cull particles by distance and screen size; per-avatar emitter budgets in crowds.
  • Batching: one draw (or a few) for all particles (indirect), sorted where needed.
  • Sensible defaults for RenderMaxPartCount per quality level; maybe a ladder step under GPU pressure (#422 auto-tuner, #405).

Done when

  • A measured cost table per case (CPU ms, GPU ms per pass, VRAM) at 1080p / 4K.
  • The top 2-3 problems identified, with follow-up tickets.
**Investigation:** measure how particles affect frame rate (CPU and GPU) in the different forms they take in SL, find the expensive cases, and file targeted fixes. ## Where particles live in Slipstream - **LL simulation (CPU):** `llviewerpartsim.cpp` / `llviewerpartsource.cpp` handle sources (`llParticleSystem`), per-particle updates, lifetime, and the `RenderMaxPartCount` cap (the quality slider sets it, 0-8192). - **VK side:** `llcleanparticlestore.cpp` (GPU particle pools: the `part` VRAM category; the "emit live/peak/4096" store in the VKMem log), particle **compute** + indirect draws (`recordParticleCompute`, `releaseParticles`, `RenderVKOverlapParticles` async/overlap), particle **shadow casters**, and particle coverage written into the TAA reactive / coverage mask. - The particle editor (`alfloaterparticleeditor.cpp`), for building test emitters. ## Cases to measure For each case, record CPU frame time (main thread), GPU time per pass (the particle compute, particle draw, shadows, TAA/FSR, post), particle count / emitter count, and overdraw: 1. **Many small particles** (rain, snow, sparkles): high count, small screen size → CPU sim + per-particle upload / compute cost. 2. **Few huge particles** (smoke, fog, clouds, light shafts, "glow" planes covering the screen): **overdraw / fill rate** → GPU-bound, worst at high resolution. 3. **Additive / glow / emissive particles** (club lights, lasers): blending + glow + bloom cost; HDR interaction. 4. **Textured vs untextured, animated textures** (flipbook): texture fetch / residency / bindless churn. 5. **Particles with shadows** (if particles cast shadows): shadow-pass cost per cascade / RT. 6. **Particles bouncing / following / target-pos / wind-affected** (flags that add per-particle CPU work). 7. **Avatar-attached emitters** (worn bling, effects), many avatars in a club: emitter count scaling. 8. **Selection beams** / the "show selection beam" particles (the `ShowSelectionBeam` / `EnableSelectionHints` paths). 9. **Interaction with TAA / FSR:** particle ghosting / reactive mask cost; motion-vector handling for particles. 10. **Interaction with the VRAM ladder / budget:** particle pools sized sensibly (high-water vs live), freed when idle. ## Method - Build repeatable test scenes with the particle editor (one emitter per case; adjustable counts) plus real-world busy spots (a club with light shows, a weather region). - Compare particles on / off (`RenderMaxPartCount` 0 vs default vs max) and resolution 1080p vs 4K (for fill rate). - Use the existing GPU pass timers and CPU `perf` / Tracy zones (add zones around the part sim update and the particle upload if missing). - Compare with Firestorm on the same scenes (CPU sim cost is LL-shared; GPU path differs). ## Likely fixes to evaluate (file separately once measured) - **Move simulation to the GPU** (compute-driven emitters: the CPU only spawns, the GPU updates). This fits the GPU-driven architecture and removes per-particle CPU cost. - **Overdraw control:** half-resolution particle rendering for big translucent particles, composited with depth-aware upsampling; screen-size / overdraw budgets. - **Distance / LOD:** fade or cull particles by distance and screen size; per-avatar emitter budgets in crowds. - **Batching:** one draw (or a few) for all particles (indirect), sorted where needed. - **Sensible defaults** for `RenderMaxPartCount` per quality level; maybe a ladder step under GPU pressure (#422 auto-tuner, #405). ## Done when - [ ] A measured cost table per case (CPU ms, GPU ms per pass, VRAM) at 1080p / 4K. - [ ] The top 2-3 problems identified, with follow-up tickets.
sky_line added this to the Slipstream project 2026-10-06 15:04:14 +00:00
Author
Owner

Started 2026-10-10. Measured in a busy scene (RTX 5090, 3840x2088): particle pass 29.3 ms of a 44 ms GPU frame, ~12 fragment-shader invocations per pixel from ~4.8k particle triangles (682 emitters, ~5.4k live particles). Both overdraw and per-fragment cost are high. In progress: per-vertex particle lighting, a half-resolution particle path with depth-aware upsample, and near-camera fade for screen-filling sprites.

Started 2026-10-10. Measured in a busy scene (RTX 5090, 3840x2088): particle pass 29.3 ms of a 44 ms GPU frame, ~12 fragment-shader invocations per pixel from ~4.8k particle triangles (682 emitters, ~5.4k live particles). Both overdraw and per-fragment cost are high. In progress: per-vertex particle lighting, a half-resolution particle path with depth-aware upsample, and near-camera fade for screen-filling sprites.
Author
Owner

Pushed to main at 07c8a3ac73. Per-particle lighting in a compute pass (RenderVKParticleLighting), coarse shading on particles (RenderVKParticleShadingRate), adaptive half-resolution particles with depth-aware upsample (RenderVKParticleLowRes, auto at about 2 layers per pixel) and near-camera fade. Same busy sim: particle pass 29.3 ms -> about 0.6 ms, frame 44 ms -> 12.3 ms (22 -> 81 FPS). To test: particle looks (glow, underwater, mirror, snapshot) and a window resize.

Pushed to main at 07c8a3ac73. Per-particle lighting in a compute pass (`RenderVKParticleLighting`), coarse shading on particles (`RenderVKParticleShadingRate`), adaptive half-resolution particles with depth-aware upsample (`RenderVKParticleLowRes`, auto at about 2 layers per pixel) and near-camera fade. Same busy sim: particle pass 29.3 ms -> about 0.6 ms, frame 44 ms -> 12.3 ms (22 -> 81 FPS). To test: particle looks (glow, underwater, mirror, snapshot) and a window resize.
Author
Owner

Particle pass 29.3 ms -> ~0.6 ms in the measured busy sim (lighting compute pass, shading rate, adaptive low-res); shipped in v1.3.0-beta.1. Closing.

Particle pass 29.3 ms -> ~0.6 ms in the measured busy sim (lighting compute pass, shading rate, adaptive low-res); shipped in v1.3.0-beta.1. Closing.
sky_line 2026-10-11 13:25:06 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#435
No description provided.