perf(streaming): cursor publication across frame budgets

This commit is contained in:
Erik 2026-07-24 19:10:18 +02:00
parent bb16f74fd4
commit 98f1ac8934
32 changed files with 2215 additions and 823 deletions

View file

@ -44,11 +44,12 @@ What does NOT go here:
smooth and physics, collision, and wire state remain correct.
- **Build hygiene:** `#228` records 17 clean-Release test-project warnings;
production compilation and all tests pass.
- **Performance side track:** Slices AD and Slice E0E3 are complete. Typed
- **Performance side track:** Slices AD and Slice E0E4 are complete. Typed
completion admission, immediate generation-scoped old-world quiescence, and
budgeted full-window/recenter retirement are live; E4 cursor-budgeted
publication is next. Physical performance/visual evidence is paused while
the desktop is RDP. Evidence:
budgeted full-window/recenter retirement are live. Publication now advances
from retained render/physics/static/building/EnvCell cursors without replay;
E5 destination reservation/reveal joining is next. The physical console is
available and remains reserved for the E6 connected gate. Evidence:
[`research/2026-07-24-slice-d-unified-residency-report.md`](research/2026-07-24-slice-d-unified-residency-report.md).
The [documentation map](README.md) defines how this tactical ledger relates to

View file

@ -14,13 +14,15 @@ banner cannot silently override the current program state.
[`plans/2026-07-23-world-interaction-completion.md`](plans/2026-07-23-world-interaction-completion.md).
The eight-slice `GameWindow` decomposition and its connected visual matrix
are complete.
- **Current active engineering program:** Slices AD and Slice E0E3 of
- **Current active engineering program:** Slices AD and Slice E0E4 of
[`plans/2026-07-24-modern-runtime-architecture.md`](plans/2026-07-24-modern-runtime-architecture.md)
are complete. Production world-mesh streaming consumes the validated
prepared package, typed residency is bounded/accounted, and streaming now
has typed admission plus immediate old-generation quiescence and metered
retirement cursors. E4 cursor-budgeted publication is next. Physical
GPU/FPS gates wait for the physical console because the desktop is RDP. See
has typed admission plus immediate old-generation quiescence, metered
retirement, and retained cursor-budgeted publication across render, physics,
statics, building registries, collision/reflood, and EnvCells. E5 destination
reservation/reveal joining is next. The physical console is available; its
connected performance and visual evidence remains the E6 gate. See
the [Slice D residency report](research/2026-07-24-slice-d-unified-residency-report.md).
- **Completed gates:** R6 locomotion/collision/projectile/teleport/radar and
the final two-client portal-out/materialization observer comparison (`#218`).
@ -32,7 +34,7 @@ banner cannot silently override the current program state.
user decision gate; Linux/headless automation (Track LH) remains future work.
- **Divergence audit:** 178 active rows — IA 17, AD 37, AP 85, TS 34,
and UN 5 — plus the retained retired TS-37 history note.
- **Latest automated baseline:** Release build succeeds; 8,148 tests pass and
- **Latest automated baseline:** Release build succeeds; 8,152 tests pass and
five are intentionally skipped. The capped, uncapped, and dense-Arwic
physical prepared-asset routes all completed their portal/input/lifetime
assertions and disconnected gracefully.

View file

@ -731,8 +731,18 @@ readiness continue. Canonical live records remain retained until physical
teardown converges, so quiescence neither reconstructs server identity nor
invents Hidden/UnHide transitions. Full-window and shared-origin retirement
advance only from `StreamingController.Tick` through stable resident and
per-owner entity/stage cursors on the frame's one meter. Publication remains
transaction-atomic until Slice E4.
per-owner entity/stage cursors on the frame's one meter.
Accepted publication is likewise retained at its exact priority-queue head.
`LandblockPresentationPipeline` meters render, physics, static, building, and
EnvCell receipts one operation at a time; each owner captures stable ordered
inputs once and retries only its unfinished cursor. Building and EnvCell
replacements are constructed off-side and atomically replace their complete
owner snapshots. The final `GpuWorldState.MutationBatch` is intentionally one
observer-atomic boundary so bucket identity, render pins, activation, and the
outer visibility notice cannot be observed partially. Settings and native
callbacks may defer policy changes, but cannot bypass the frame meter to drain
pending publication.
### World-reveal readiness ownership

View file

@ -68,7 +68,7 @@ accepted-divergence entries (#96, #49, #50).
|---|---|---|---|---|---|
| AD-38 | Outgoing teleport viewports retire when retail's quantized animation level exceeds the last captured visible level 1022 (index 96), suppressing levels 1023/1024 up to 20.2 ms before retail's literal `elapsed >= 1.0` state edge. Incoming fades retain the exact timer. | `src/AcDream.Core/World/TeleportAnimSequencer.cs` (`OutgoingViewportReachedTerminalProjection`) | An uncapped 2000 FPS pass can publish the finite tunnel at levels 1023/1024 even though the paired 2013 retail capture switches viewports after 1022. The table-level cutover preserves the captured visible viewport ordering without throttling the application. | Exit sound, viewport replacement, and logout tunnel entry can occur at most two easing-table quanta (about 20.2 ms) earlier than retail's logical timer. | `UIGlobals::GetAnimLevel @ 0x004EE540`; `gmSmartBoxUI::UseTime @ 0x004D6E30`; paired retail/acdream captures documented in `docs/research/2026-07-15-retail-portal-space-pseudocode.md` |
| AD-1 | Lost-cell machinery replaced by recoverable outdoor demote (**#107** safety net) + outdoor-restore `max(terrainZ, z)` under-terrain lift; retail goes `GotoLostCell` | `src/AcDream.Core/Physics/PhysicsEngine.cs:553` (+ :808) | acdream has no lost-cell state machine; outdoor landcell is the recoverable equivalent; the #107 auto-entry hold should make the demote branch unreachable | Gap in the hold → player committed to outdoor terrain inside/under a building (fake-grounded spawn, fall-through); a legit below-heightmap server restore is silently lifted — upward warp vs server | `GotoLostCell` pc:283418; `SetPositionInternal` 0x00515bd0, pc:283892-283945 |
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. **Slice E3 refinement (2026-07-24):** the same generation now publishes an immediate `WorldGenerationQuiescence` edge: old-world drawing/spatial queries, simulation/effect clocks, reconciliation, targeting, and 3-D audio stop while retained physical teardown advances through metered cursors and destination network/UI/streaming/readiness remain live. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldGenerationQuiescence.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Streaming/StreamingOriginRecenterCoordinator.cs`; `src/AcDream.App/Streaming/LandblockPresentationPipeline.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal or continue simulating an old/partial collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, missing scenery, or a still-active old generation; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
| AD-2 | Async readiness gates replace retail's synchronous destination cell load. **#229 refinement (2026-07-20):** login and F751 portal-space exit now share `WorldRevealReadinessBarrier`, so neither path can expose the normal viewport until the same render-publication, composite-texture, and collision domains converge. A hydratable indoor claim requires its owning Near-tier static/EnvCell mesh set, destination composites, and exact EnvCell physics (`IsSpawnCellReady`); an outdoor claim requires those render domains plus terrain/collision residency for the priority near ring. Hard-recenter generations and tier-aware completion application prevent stale overlapping loads/unloads or Far/Near jobs from opening or erasing the gate; mesh upload remains separate from balanced landblock ownership. Claims beyond NumCells still take the loud forced-placement path. `WorldRevealCoordinator` owns this shared lifetime; diagnostic telemetry observes its generation without defining another readiness path. **Slice E3 refinement (2026-07-24):** the same generation now publishes an immediate `WorldGenerationQuiescence` edge: old-world drawing/spatial queries, simulation/effect clocks, reconciliation, targeting, and 3-D audio stop while retained physical teardown advances through metered cursors and destination network/UI/streaming/readiness remain live. **Slice E4 refinement (2026-07-24):** accepted render/physics/static publication may span update frames through retained exact cursors, but reveal still consumes only the completed spatial/render-ready generation; building and EnvCell snapshots remain invisible until complete and the final spatial identity swap stays observer-atomic. The portal hold→materialize→regain-control lifecycle remains owned by `TeleportAnimSequencer`. | `src/AcDream.App/Streaming/WorldRevealCoordinator.cs`; `src/AcDream.App/Streaming/WorldGenerationQuiescence.cs`; `src/AcDream.App/Streaming/WorldRevealReadinessBarrier.cs`; `src/AcDream.App/Streaming/StreamingOriginRecenterCoordinator.cs`; `src/AcDream.App/Streaming/LandblockPresentationPipeline.cs`; `src/AcDream.App/Rendering/GameWindow.cs` (owner wiring + draw eligibility); `src/AcDream.App/Streaming/StreamingController.cs` (`IsRenderNeighborhoodResident`); `src/AcDream.App/Streaming/GpuWorldState.cs` (`IsRenderReady`); `src/AcDream.App/Rendering/Wb/LandblockSpawnAdapter.cs`; `src/AcDream.Core/Physics/PhysicsEngine.cs` (`IsSpawnCellReady`, `IsNeighborhoodTerrainResident`) | This is the asynchronous equivalent of retail leaving `SmartBox::position_update_complete` false while `CellManager::blocking_for_cells` is set: neither initial login nor portal arrival may reveal or continue simulating an old/partial collision world, a terrain-only Far shell, or a published-but-not-drawable GPU landblock. Indoor does not require a terrain heightmap, only the owning render landblock and exact EnvCell. | Gate opens early → grey/untextured first login or portal reveal, free-fall, wrong-cell rooting, missing scenery, or a still-active old generation; predicate never satisfies (streamer/DAT/upload failure) → login remains behind the world render gate, while portal transit reaches its existing loud timeout/forced-placement diagnostic. | `SmartBox::UseTime` 0x00455410; `gmSmartBoxUI::EndTeleportAnimation` 0x004D65A0 |
| AD-3 | Outdoor seeds always walk the transit array (retail skips the walk when the seed CLandCell is null/unloaded); per-cell lookups no-op on unhydrated data | `src/AcDream.Core/Physics/CellTransit.cs:503` | Equivalence argument: with nothing hydrated every lookup inside the walk no-ops, so the result matches retail's skipped walk | Near partially-streamed landblocks, building-transit promotion silently can't fire until structs hydrate — membership stays outdoor while the player is inside a building | `CObjCell::find_cell_list` 0052b535-0052b56c (null-CLandCell case) |
| AD-4 | `point_in_cell` against an unhydrated CellBSP returns false (skip) rather than the null-node "inside" default; retail never queries unloaded cells | `src/AcDream.Core/Physics/CellTransit.cs:588` | The null-node default would make an unhydrated cell spuriously claim every point; skipping is the conservative streaming-safe choice | During hydration, a point genuinely inside a not-yet-loaded cell resolves outdoor/stale — transient membership misclassification driving wrong collision set and render root | `CEnvCell::find_visible_child_cell` :311397; cell-BSP vtable[0x84] |
| AD-5 | Outdoor `point_in_cell` is an identity compare against the global XY-column cell from `LandDefs.AdjustToOutside` (no per-cell containment test) | `src/AcDream.Core/Physics/CellTransit.cs:865` | Landcells are disjoint 24 m columns — identity-compare against the column under the sphere centre is exactly equivalent to retail's per-candidate test | If block-origin/lcoord math is wrong at a landblock seam, the compare silently never matches — outdoor membership freezes at boundaries (the pre-#106 symptom) | `find_cell_list` pick pc:308788-308825; `CLandCell::point_in_cell` (get_block_offset pc:308804) |

View file

@ -1613,7 +1613,10 @@ port in any phase — no separate listing here.
> generation unavailable at the hard reveal edge and freezes its world
> simulation/audio while full-window and shared-origin teardown advance through
> metered resident, entity, and owner-stage cursors with exact retry receipts.
> E4 cursor-budgets publication next. F/G and J retain their explicit approval
> E4 now retains the exact accepted queue head and cursor-budgets render,
> physics, static, building-registry, EnvCell, collision, and reflood
> publication before one observer-atomic spatial swap. E5 destination
> reservation/reveal joining is next. F/G and J retain their explicit approval
> gates.
**Spec:** `docs/superpowers/specs/2026-07-05-modern-pipeline-design.md` (the

View file

@ -93,12 +93,14 @@ The separately authorized modern-runtime performance program has completed
Slices AD: corrected measurement, prepared-package bake/dedup, package-only
production streaming, and typed unified residency. Its physical capped,
uncapped, and dense connected gates pass without a visual-quality change.
Slice E0E3 now define and enforce typed completion admission through explicit
Slice E0E4 now define and enforce typed completion admission through explicit
stable priority queues, publish an immediate generation-scoped old-world
quiesce at login/portal boundaries, and advance full-window/recenter teardown
through exact metered retirement cursors. E4 next makes publication itself
cursor-budgeted. Slices F/G remain behind their explicit ECS approval gate, and
Slice J remains behind its gameplay-owner approval gate.
through exact metered retirement cursors. Render, physics, static, building,
and EnvCell publication now resume from retained exact cursors under the same
frame budget. E5 destination reservation and reveal-generation joining is
next. Slices F/G remain behind their explicit ECS approval gate, and Slice J
remains behind its gameplay-owner approval gate.
Slice 1's 18-cell favorite-spell overflow bar is user-accepted. Slice 2's
status hand selected-object availability and existing

View file

@ -2,7 +2,7 @@
**Date:** 2026-07-24
**Status:** Slices AD complete. Slice E is active (E0E3 complete).
**Status:** Slices AD complete. Slice E is active (E0E4 complete).
**Scope:** Reconcile and sequence the existing Modern Pipeline (`MP`) and
Linux/headless (`LH`) tracks using the 2026-07-24 connected performance audit.
@ -728,9 +728,10 @@ checkpoint retained staged or retiring bytes. Evidence:
**Checkpoint 2026-07-24:** E0 fixed the retail/adaptation contract and current
owner inventory. E1 landed the validated work profile, deterministic meter and
completion charge model, plus lifecycle-artifact shadow diagnostics while
preserving the prior scheduler's execution. E2 is the first enforcement
cutover.
completion charge model. E2 cut execution over to stable priority FIFOs. E3
added immediate generation quiescence and cursored retirement. E4 now advances
render/physics/static publication from retained exact receipts; E5 destination
reservation and reveal-generation joining is next.
**Purpose:** Remove update-thread portal transactions.

View file

@ -1,6 +1,6 @@
# Modern Runtime Slice E — Cost-budgeted streaming and retirement
**Status:** active — E0/E1/E2/E3 complete; E4 cursor-budgeted publication next
**Status:** active — E0/E1/E2/E3/E4 complete; E5 destination reservation next
**Program:** `docs/plans/2026-07-24-modern-runtime-architecture.md`
**Baseline:** Slice D closeout commit `66690805`
**Behavior contract:** no visual-quality or retail-behavior reduction
@ -325,6 +325,29 @@ valid GPU/FPS evidence.
- Feed GPU requested-byte and retirement-operation facts from renderer owners.
- Prove every failure resumes the exact unfinished operation without replay.
**Complete 2026-07-24.** One accepted completion now remains at the exact queue
head while `LandblockPresentationPipeline` advances retained render, physics,
and static receipts through the frame's single meter. Stable entity/Gfx/building
and prior-owner arrays are captured once. Terrain upload bytes are charged at
the render owner; physics cells/buildings, static collision/light/plugin work,
prior static teardown, shadow reflood, building-registry construction, and
EnvCell shell construction advance one bounded operation at a time. Building
and EnvCell replacements are prepared off-side and become visible only when
complete. Failures retain the unfinished cursor and never replay a committed
prefix. Settings/native callbacks can defer policy changes but cannot drain
publication outside `StreamingController.Tick`.
The final `GpuWorldState.MutationBatch` remains one deliberate observer-atomic
operation: bucket mutation, render-id ownership, activation, and the outer
visibility notification cannot span frames without exposing a partial spatial
identity. It is time-metered and named for E6 overrun evidence; all iterable
owner work now occurs before it.
Validation: focused render/building/publication/controller tests passed; the
complete App suite passed 3,669 / 3 skipped; the complete Release solution
passed 8,152 / 5 skipped; Release solution build green. Physical connected
performance and visual evidence remains an E6 gate.
### E5 — Destination reservation and reveal generation
- Replace eager `PriorityRadius` execution with destination reservations.