acdream/docs/research/2026-07-25-slice-h-b-light-top-k-report.md
Erik a2a1e5916d perf(lighting): bound global light selection
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.
2026-07-25 05:40:32 +02:00

61 lines
2.3 KiB
Markdown

# 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:
```text
git revert ef1d263337997bb030eadb7b8e71d73dc659907a
```