perf(rendering): retain synchronous frame scratch

Reuse the PView frame input, publish mutation-invalidated landblock views, and avoid constructing optional shadow iterators while preserving title and lifecycle visibility facts.
This commit is contained in:
Erik 2026-07-25 05:28:30 +02:00
parent b9cbf5e040
commit b3427554c3
10 changed files with 397 additions and 129 deletions

View file

@ -80,21 +80,26 @@ subtree-withdrawal suites preserve exact event and resource counts.
Landed evidence:
[`../research/2026-07-25-slice-h-a3-attached-pose-reconcile.md`](../research/2026-07-25-slice-h-a3-attached-pose-reconcile.md).
### H-a4 — diagnostics and frame scratch
### H-a4 — diagnostics and frame scratch — COMPLETE
1. Reuse one synchronous `RetailPViewFrameInput` owned by
`WorldSceneRenderer`; reset every field before each draw.
2. Expose stable borrowed landblock entry/bounds views instead of creating
iterator state in each frame.
3. Consumer-gate diagnostic landblock visibility counting and shadow
enumeration. When no DebugVM/collision/probe consumer exists, publish a
neutral diagnostic outcome without scanning resident landblocks.
3. Consumer-gate optional shadow enumeration. Preserve landblock visibility
counting because the normal title and lifecycle checkpoints are active
consumers of `lb V/T`; neutralizing it would be a visible/automation
behavior change.
4. Do not rework `InteriorEntityPartition` while the G4 referee remains.
Issue #241 closes with G5 old-route deletion, not by editing the fallback.
5. Profile capped and uncapped production paths and retain evidence.
Gate: identical framebuffer/scene digest, no per-frame PView input allocation,
and no diagnostic world traversal with all consumers disabled.
no iterator allocation for stable landblock views, and no shadow traversal
with all optional consumers disabled.
Landed evidence:
[`../research/2026-07-25-slice-h-a4-frame-scratch.md`](../research/2026-07-25-slice-h-a4-frame-scratch.md).
## 3. H-b — exact light top-k

View file

@ -0,0 +1,69 @@
# Slice H-a4 — retained frame scratch and diagnostic traversal
## Scope
This is a behavior-preserving ownership/allocation correction. It does not
change retail visibility, PView construction, spatial ordering, collision
debug drawing, title facts, or lifecycle checkpoint facts.
## Findings
Three independent steady-frame allocation sources remained:
1. `WorldSceneRenderer` constructed one `RetailPViewFrameInput` reference
object for every PView frame even though `DrawInside` consumes it
synchronously.
2. `GpuWorldState.LandblockEntries` and `LandblockBounds` were C# iterator
methods, so merely obtaining each sequence constructed fresh iterator
state. The underlying spatial membership changed only at update-thread
publication boundaries.
3. `WorldSceneDiagnosticsController` passed
`ShadowObjectRegistry.AllEntriesForDebug()` to the DebugVM publisher even
when no developer UI consumer existed. The publisher correctly avoided
enumeration, but the yield sequence itself had already been constructed.
The execution plan initially described landblock visibility counting as an
unconsumed diagnostic. That was incorrect in the current application:
`WorldRenderFrameOutcome` feeds the always-visible FPS/title `lb V/T` values
and connected lifecycle snapshots. Returning a neutral count would therefore
change observable behavior and invalidate lifecycle evidence. The count is
retained; only its iterator allocation is removed.
## Implementation
- `WorldSceneRenderer` owns one `RetailPViewFrameInput` and resets every field
before the synchronous `DrawInside` call. The input is publicly read-only
and internally mutable so downstream render owners cannot change borrowed
frame facts.
- `GpuWorldState` exposes retained entry, no-animated-index entry, and bounds
lists. They rebuild only after landblock membership, resident entity-list,
animated-index, or AABB changes. Existing render-traversal slot order is
preserved exactly.
- Landblock diagnostic counting uses indexed access over the retained bounds
view.
- Shadow enumeration is constructed only when the DebugVM is mounted. The
independent collision-wireframe switch keeps its existing enumeration.
- `InteriorEntityPartition` remains untouched while the G4 referee is still
retained. Its removal and issue #241 close remain G5 work after the user
accepts the G4 visual gate.
## Conformance
- Stable retained render-view getters allocate zero bytes over 1,000 polls.
- A spatial mutation refreshes the same borrowed list identity and publishes
the new count.
- Two successive PView frames receive the same input object, reset with the
current frame values.
- Existing quiescence, render traversal, animated-index, PView executor,
abort/recovery, and DebugVM tests remain unchanged in behavior.
## Rollback boundary
This work is independent of the G4 production-source cutover. If tomorrow's
visual gate rejects G4, use:
```text
git revert ef1d263337997bb030eadb7b8e71d73dc659907a
```
Do not revert this Slice H-a4 commit, G3, or the portal-warmup corrections.