Cluster LOD: event-driven upkeep (weld pairs once; audit per-frame classify / RT select / alpha order) #826

Open
opened 2026-10-17 20:48:04 +00:00 by sky_line · 0 comments
Owner

Cluster LOD's per-frame upkeep costs more GPU time than cluster rendering saves on the current path. Measured on an RTX 5090 at 4K, fully serial (async compute, all overlaps and probe-early off), same scene:

GPU ms/frame
Cluster LOD on 17.2-17.6
Cluster LOD off (legacy rigged/static path) 15.85-15.95
Cluster upkeep alone (on) ~5.7

So cluster rendering saves ~4.2 ms over legacy, and its upkeep spends ~5.7 ms. Making the upkeep event-driven should put cluster-on around 12-13 ms, i.e. ~3-4 ms faster than legacy instead of ~1.5 ms slower.

Upkeep breakdown (cluster on, serial): c_cl_sk_weld 1.29, c_cl_rig_clas 1.20, c_cl_rt_select 1.12, c_cluster_preskin 0.81, c_cl_alpha_order 0.70, c_cl_sk_apply 0.60, c_cl_blas_build 0.58, c_blas_build 0.45, c_cl_sk_skin 0.14.

1. Rigged weld: pair once, apply per frame

clean_cluster_preskin_weld.comp re-searches pairs every frame (insert every boundary vertex of the cut into a spatial hash, search in rest-pose space, then apply). The design note says this is because a cluster vertex has no stable LOD0 vertex id, so stored pairs would need a hash lookup anyway.

But the weld candidates are the original face's open-boundary vertices, which simplification locks at their LOD0 positions in every LOD (1a). The same physical vertex exists in every cut, so it can carry a stable id assigned at cluster build time. With that:

  • Pair once per avatar on the rest-table triggers (outfit / shape / joint-override / attachment changes), storing pairs keyed by stable id, as the legacy mode-1 weld does.
  • Per frame: only APPLY, and only for slots re-skinned this frame (held-pose reuse already skips unchanged slots' skinning). No hash insert, no search.

Expected: most of the 1.29 ms search and the insert gone; the 0.60 ms apply limited to re-skinned slots.

2. Audit the other per-frame passes for unchanged work

Not yet read; check each for recomputation of inputs that did not change since the last frame:

  • c_cl_rig_clas (rigged classification, 1.20 ms)
  • c_cl_rt_select (cluster RT selection, 1.12 ms)
  • c_cl_alpha_order (0.70 ms)
  • c_cluster_preskin / c_cl_blas_build / c_blas_build

Same pattern as #825 (shadow cascades re-rendered for unchanged content): track what changed, and do the work only for those slots and instances.

Measure

Per-frame counters first: slots re-skinned vs welded vs classified vs RT-selected, against how many actually changed. Then A/B serial on the 5090 (cluster on before/after, plus cluster off) and check pacing (worst / p99) as well as the average.

Cluster LOD's per-frame upkeep costs more GPU time than cluster rendering saves on the current path. Measured on an RTX 5090 at 4K, fully serial (async compute, all overlaps and probe-early off), same scene: | | GPU ms/frame | |---|---| | Cluster LOD on | 17.2-17.6 | | Cluster LOD off (legacy rigged/static path) | 15.85-15.95 | | Cluster upkeep alone (on) | ~5.7 | So cluster rendering saves ~4.2 ms over legacy, and its upkeep spends ~5.7 ms. Making the upkeep event-driven should put cluster-on around 12-13 ms, i.e. ~3-4 ms *faster* than legacy instead of ~1.5 ms slower. **Upkeep breakdown (cluster on, serial):** `c_cl_sk_weld` 1.29, `c_cl_rig_clas` 1.20, `c_cl_rt_select` 1.12, `c_cluster_preskin` 0.81, `c_cl_alpha_order` 0.70, `c_cl_sk_apply` 0.60, `c_cl_blas_build` 0.58, `c_blas_build` 0.45, `c_cl_sk_skin` 0.14. ### 1. Rigged weld: pair once, apply per frame `clean_cluster_preskin_weld.comp` re-searches pairs every frame (insert every boundary vertex of the cut into a spatial hash, search in rest-pose space, then apply). The design note says this is because a cluster vertex has no stable LOD0 vertex id, so stored pairs would need a hash lookup anyway. But the weld candidates are the original face's open-boundary vertices, which simplification **locks at their LOD0 positions in every LOD** (1a). The same physical vertex exists in every cut, so it can carry a stable id assigned at cluster build time. With that: - Pair once per avatar on the rest-table triggers (outfit / shape / joint-override / attachment changes), storing pairs keyed by stable id, as the legacy mode-1 weld does. - Per frame: only APPLY, and only for slots re-skinned this frame (held-pose reuse already skips unchanged slots' skinning). No hash insert, no search. Expected: most of the 1.29 ms search and the insert gone; the 0.60 ms apply limited to re-skinned slots. ### 2. Audit the other per-frame passes for unchanged work Not yet read; check each for recomputation of inputs that did not change since the last frame: - `c_cl_rig_clas` (rigged classification, 1.20 ms) - `c_cl_rt_select` (cluster RT selection, 1.12 ms) - `c_cl_alpha_order` (0.70 ms) - `c_cluster_preskin` / `c_cl_blas_build` / `c_blas_build` Same pattern as #825 (shadow cascades re-rendered for unchanged content): track what changed, and do the work only for those slots and instances. ### Measure Per-frame counters first: slots re-skinned vs welded vs classified vs RT-selected, against how many actually changed. Then A/B serial on the 5090 (cluster on before/after, plus cluster off) and check pacing (worst / p99) as well as the average.
sky_line added this to the Slipstream project 2026-10-17 20:48:04 +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#826
No description provided.