Replace over-cap full sorting with a retained exact top-k heap while preserving the accepted tie-order fallback. Differential tests lock randomized and Town Network-scale output, and the measured 463-light path cuts selector CPU by 29 percent without warmed allocations.
2.3 KiB
Slice H-b — exact bounded point-light selection
Result
LightManager.BuildPointLightSnapshot no longer sorts every qualifying light
when more than 128 lights are eligible. It keeps the best 128 in a retained
worst-first heap, sorts only those 128 for submission, and performs no
allocation after warm-up.
The optimization preserves the accepted pre-slice output exactly:
- dynamic lights still precede static lights;
- each pool is still ordered by squared player distance;
- the visible-cell, lit-state, and directional-light filters are unchanged;
- in-budget snapshots remain in registration order;
- equal-rank overflow frames which could expose .NET's unstable sort retain the previous complete-sort path and exact object-reference order.
The retail oracle and readable pseudocode are in
2026-07-25-slice-h-b-light-top-k-pseudocode.md. Retail's own selector is a
bounded ordered insertion into separate static and dynamic pools. This slice
ports the bounded-work principle without claiming to close AP-85's larger
pool/cap/lifecycle divergence.
Evidence
Focused conformance covers:
- exact randomized differential comparison against the previous full-sort oracle;
- equal-distance overflow and cap-boundary behavior;
- lit, directional, dynamic, static, and visible-cell filtering;
- a deterministic 463-light Town Network-scale candidate set;
- zero warmed allocations on both bounded and equal-rank fallback routes.
A Release diagnostic microbenchmark ran 100,000 snapshot builds with 463 eligible uniquely ranked lights:
| Route | Elapsed | Managed allocation |
|---|---|---|
| previous complete sort | 1,377.578 ms | 0 bytes |
| retained bounded selector | 976.993 ms | 0 bytes |
That sample is a 1.410x throughput improvement, or about 29.1% less CPU time inside selection. It is a narrow microbenchmark rather than a whole-frame FPS claim; its purpose is to prove that the replacement removes work rather than merely moving it.
Safety boundary
No shader, light parameters, candidate membership, draw order, or production scene ownership changed. AP-85 remains open because retail's exact 7-dynamic/40-static pools and DBObj-resident cell lifecycle are outside this performance-only slice.
G4's independent visual rollback remains:
git revert ef1d263337997bb030eadb7b8e71d73dc659907a