docs(runtime): approve render scene program
This commit is contained in:
parent
e7d9d6fa7d
commit
5ecaa5612d
8 changed files with 662 additions and 31 deletions
|
|
@ -150,9 +150,11 @@ and receive retail's centered wait cue instead of forced early reveal. E6
|
|||
deterministic/resource suites, Release build, complete tests, capped/uncapped
|
||||
nine-stop routes, and pinned dense Arwic pass on exact binary `91e82c3c`.
|
||||
Every checkpoint converged without pending publication, retirement, upload,
|
||||
warmup, or class backlog. Slices F/G
|
||||
remain behind the explicit ECS decision gate and Slice J behind its separate
|
||||
gameplay-owner gate. Evidence:
|
||||
warmup, or class backlog. The user explicitly approved Slices F–L, including
|
||||
the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active
|
||||
from pre-runtime rollback anchor `e7d9d6fa`. The implementation-ready F/G
|
||||
ownership, shadow-scene, cutover, and acceptance contract is
|
||||
`docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`. Evidence:
|
||||
`docs/research/2026-07-24-slice-c-prepared-asset-cutover-report.md` and
|
||||
`docs/research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`.
|
||||
|
||||
|
|
|
|||
|
|
@ -148,9 +148,11 @@ and receive retail's centered wait cue instead of forced early reveal. E6
|
|||
deterministic/resource suites, Release build, complete tests, capped/uncapped
|
||||
nine-stop routes, and pinned dense Arwic pass on exact binary `91e82c3c`.
|
||||
Every checkpoint converged without pending publication, retirement, upload,
|
||||
warmup, or class backlog. Slices F/G
|
||||
remain behind the explicit ECS decision gate and Slice J behind its separate
|
||||
gameplay-owner gate. Evidence:
|
||||
warmup, or class backlog. The user explicitly approved Slices F–L, including
|
||||
the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active
|
||||
from pre-runtime rollback anchor `e7d9d6fa`. The implementation-ready F/G
|
||||
ownership, shadow-scene, cutover, and acceptance contract is
|
||||
`docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`. Evidence:
|
||||
`docs/research/2026-07-24-slice-c-prepared-asset-cutover-report.md` and
|
||||
`docs/research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`.
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,12 @@ What does NOT go here:
|
|||
every typed budget dimension; incomplete worlds remain in portal space with
|
||||
retail's centered wait cue. E6 deterministic/resource suites and all three
|
||||
physical-local connected routes pass with zero stranded work/resource
|
||||
backlog. Slices F/G retain their explicit approval gate. Evidence:
|
||||
backlog. Slices F–L, including the former F/G and J gates, were explicitly
|
||||
approved 2026-07-24. Slice F now executes from the pre-runtime rollback
|
||||
anchor `e7d9d6fa`; its ownership, shadow-scene, cutover, and acceptance
|
||||
contract is
|
||||
[`plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md`](plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md).
|
||||
Evidence:
|
||||
[`research/2026-07-24-slice-e-cost-budgeted-streaming-report.md`](research/2026-07-24-slice-e-cost-budgeted-streaming-report.md).
|
||||
|
||||
The [documentation map](README.md) defines how this tactical ledger relates to
|
||||
|
|
|
|||
|
|
@ -25,16 +25,21 @@ banner cannot silently override the current program state.
|
|||
typed budget dimension; incomplete destinations remain in portal space and
|
||||
receive retail's centered wait cue instead of forced early reveal. E6's
|
||||
deterministic/resource gates and capped, uncapped, and dense-Arwic
|
||||
physical-local routes pass. Slices F/G await their explicit approval gate.
|
||||
See the [Slice E streaming report](research/2026-07-24-slice-e-cost-budgeted-streaming-report.md).
|
||||
physical-local routes pass. Slices F–L, including the F/G and J approval
|
||||
gates, were explicitly authorized 2026-07-24; Slice F is active.
|
||||
Their post-E evidence, ownership map, shadow-comparison design, cutover
|
||||
sequence, and acceptance matrix are implementation-ready in the
|
||||
[F/G render-scene plan](plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md).
|
||||
See also the [Slice E streaming report](research/2026-07-24-slice-e-cost-budgeted-streaming-report.md).
|
||||
- **Completed gates:** R6 locomotion/collision/projectile/teleport/radar and
|
||||
the final two-client portal-out/materialization observer comparison (`#218`).
|
||||
- **Separate visual verification:** the shared-alpha lifestone/particle result
|
||||
in `#225`; its connected resource-lifetime and performance routes pass.
|
||||
- **Carried behavior debt:** `#153` (far teleport onto an unstreamed edge),
|
||||
`#116` (two narrowed slide-response cases), and divergence rows TS-50/TS-51.
|
||||
- **Deferred engineering tracks:** render ECS/MP3 remains behind its explicit
|
||||
user decision gate; Linux/headless automation (Track LH) remains future work.
|
||||
- **Active engineering track:** render ECS/MP3 is executing from the
|
||||
implementation-ready F/G plan, followed by the approved Linux/headless
|
||||
automation slices. The pre-F/G runtime rollback anchor is `e7d9d6fa`.
|
||||
- **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,164 tests pass and
|
||||
|
|
|
|||
|
|
@ -1625,8 +1625,13 @@ port in any phase — no separate listing here.
|
|||
> retirement, upload, warmup, or class backlog. Capped/uncapped CPU p99 improved
|
||||
> 34.7%/30.4% from Slice A and maximum frame allocation fell 84.7%/82.2%.
|
||||
> [Streaming report](../research/2026-07-24-slice-e-cost-budgeted-streaming-report.md).
|
||||
> F/G and J
|
||||
> retain their explicit approval gates.
|
||||
> Dense Arwic already meets the provisional 3.33 ms median target; CPU tail
|
||||
> cost remains above GPU cost. The implementation-ready
|
||||
> [F/G render-scene plan](2026-07-24-modern-runtime-slices-f-g-render-scene.md)
|
||||
> records the post-E decision evidence, exact owner boundary, non-drawing
|
||||
> shadow referee, production cutover, and acceptance matrix. The user
|
||||
> explicitly approved Slices F–L, including the F/G and J gates, on
|
||||
> 2026-07-24. Slice F is active from pre-runtime rollback anchor `e7d9d6fa`.
|
||||
|
||||
**Spec:** `docs/superpowers/specs/2026-07-05-modern-pipeline-design.md` (the
|
||||
umbrella design — read it first). **Goal:** smoothness first (no frame over
|
||||
|
|
|
|||
|
|
@ -106,9 +106,11 @@ complete tests, capped/uncapped nine-stop routes, and pinned dense Arwic pass
|
|||
on exact binary `91e82c3c`; all checkpoints converge with no stranded
|
||||
publication, retirement, upload, warmup, or resource backlog. Capped/uncapped
|
||||
CPU p99 is 34.7%/30.4% below Slice A and maximum frame allocation is
|
||||
84.7%/82.2% lower. Slices F/G remain behind their explicit ECS approval gate,
|
||||
and Slice J
|
||||
remains behind its gameplay-owner approval gate.
|
||||
84.7%/82.2% lower. The user explicitly approved Slices F–L, including both
|
||||
the F/G ECS and Slice J gameplay-owner gates, on 2026-07-24. Slice F is active
|
||||
from rollback anchor `e7d9d6fa`, using the implementation-ready post-E
|
||||
ownership, shadow-comparison, cutover, and acceptance contract in
|
||||
[`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md).
|
||||
|
||||
Slice 1's 18-cell favorite-spell overflow bar is user-accepted. Slice 2's
|
||||
status hand selected-object availability and existing
|
||||
|
|
|
|||
|
|
@ -2,7 +2,8 @@
|
|||
|
||||
**Date:** 2026-07-24
|
||||
|
||||
**Status:** Slices A–E complete. Slices F/G await their explicit approval gate.
|
||||
**Status:** Slices A–E complete. Slices F–L explicitly approved 2026-07-24;
|
||||
Slice F is active.
|
||||
|
||||
**Scope:** Reconcile and sequence the existing Modern Pipeline (`MP`) and
|
||||
Linux/headless (`LH`) tracks using the 2026-07-24 connected performance audit.
|
||||
|
|
@ -34,7 +35,10 @@ section 13.
|
|||
do not touch that deferral. **Slices F and G resume the deferred MP3
|
||||
work and MUST NOT start without explicit user approval recorded against
|
||||
this section**, taken on the post-Slice-E corrected uncapped-local
|
||||
profile (does partition/submission cost still dominate?). Note the prior
|
||||
profile (does partition/submission cost still dominate?).
|
||||
**Approval recorded 2026-07-24:** after reviewing the post-E result and
|
||||
rewrite risk, the user authorized "all slices." F/G may proceed from the
|
||||
pre-runtime rollback anchor `e7d9d6fa`. Note the prior
|
||||
"GPU-bound at ~200 FPS" Sawato reading is itself invalidated by the
|
||||
`GpuFrameTimer` boundary artifact this plan's Slice A corrects — the
|
||||
question is genuinely open until re-measured.
|
||||
|
|
@ -45,9 +49,10 @@ section 13.
|
|||
covers streaming and WB rendering only. Slice H's network-I/O item and
|
||||
Slice J's gameplay-owner moves touch otherwise-frozen subsystems
|
||||
(network, chat, input) and each requires its own recorded user
|
||||
authorization before starting. (The 2026-07-24 receive-thread robustness
|
||||
fix was separately reviewed and user-approved as a bug fix, not a
|
||||
rework.)
|
||||
authorization before starting. **Approval recorded 2026-07-24:** the
|
||||
user's authorization for "all slices" lifts the Slice J gate as well.
|
||||
(The 2026-07-24 receive-thread robustness fix was separately reviewed and
|
||||
user-approved as a bug fix, not a rework.)
|
||||
4. **Evidence-base corrections.** The §1 exception-traffic row previously
|
||||
cited "4,520 + 1,168" — figures with no derivation in the audit or its
|
||||
committed artifacts; the verifiable figures are the focused-trace 1,587
|
||||
|
|
@ -799,6 +804,8 @@ Slices G and H.
|
|||
|
||||
### Slice F — Incremental render scene foundation
|
||||
|
||||
**Prepared plan:** [`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md).
|
||||
|
||||
**Purpose:** Stop rebuilding/partitioning the world each frame.
|
||||
|
||||
- Add acdream-owned `IRenderScene`, identifiers, components, and delta journal.
|
||||
|
|
@ -1170,14 +1177,21 @@ an improvement" carries the same evidence burden as a regression claim.
|
|||
|
||||
## 14. Current execution point
|
||||
|
||||
Slices A–C are complete. Slice C replaced production live-DAT world-mesh
|
||||
extraction with the validated prepared source and passed all connected,
|
||||
performance, lifetime, automated, and user-visual gates. Its physical
|
||||
uncapped result is CPU p50/p95/p99 1.409/4.909/6.496 ms, GPU
|
||||
0.832/2.510/2.706 ms, a 39.9 MiB largest frame allocation, zero invalid Setup
|
||||
probe exceptions, and a passing warm repeated-Caul memory assertion. Slice D
|
||||
is the next execution point; it unifies accounting and policy around the
|
||||
specialized caches that remain, rather than replacing their working storage.
|
||||
Slices A–E are complete. Slice E's exact physical-local Release binary
|
||||
produced uncapped CPU p50/p95/p99 1.216/4.216/5.450 ms and GPU
|
||||
0.725/2.486/2.666 ms across the nine-stop route. Dense Arwic, with 15,530
|
||||
entities and 111 animated entities, produced CPU 2.652/4.153/5.736 ms and GPU
|
||||
1.576/2.504/2.662 ms. Every stable checkpoint converged without pending
|
||||
publication, retirement, upload, warmup, or resource backlog.
|
||||
|
||||
The dense median already satisfies the provisional 3.33 ms / 300 FPS target.
|
||||
CPU tail cost remains above GPU cost and the normal draw path still scans and
|
||||
partitions resident entities, so F/G can improve CPU utilization, scaling, and
|
||||
tail behavior, but a dramatic average-FPS gain is not promised. The
|
||||
implementation-ready F/G contract and ownership map are
|
||||
[`2026-07-24-modern-runtime-slices-f-g-render-scene.md`](2026-07-24-modern-runtime-slices-f-g-render-scene.md).
|
||||
The §0.1 and §0.3 gates were explicitly lifted 2026-07-24. Slice F is the
|
||||
current execution point; `e7d9d6fa` is the pre-runtime rollback anchor.
|
||||
|
||||
The intended order is therefore:
|
||||
|
||||
|
|
@ -1186,8 +1200,8 @@ honest metrics + committed baselines (A — exit criteria block C)
|
|||
-> prepared content (B, C)
|
||||
-> typed residence (D — unify/retune, not rebuild)
|
||||
-> cost-budgeted streaming (E)
|
||||
-> [user decision gate: lift the ECS deferral? §0.1]
|
||||
-> incremental render scene (F — referee sub-slice first)
|
||||
-> [APPROVED 2026-07-24: ECS deferral lifted under §0.1]
|
||||
-> incremental render scene (F — CURRENT; referee first)
|
||||
-> delta GPU submission (G)
|
||||
-> residual frame cleanup (H-a, H-b, H-c)
|
||||
-> flat collision assets (I — floats; depends only on B)
|
||||
|
|
|
|||
596
docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md
Normal file
596
docs/plans/2026-07-24-modern-runtime-slices-f-g-render-scene.md
Normal file
|
|
@ -0,0 +1,596 @@
|
|||
# Modern Runtime Slices F/G — Incremental Render Scene and Delta Submission
|
||||
|
||||
**Date:** 2026-07-24
|
||||
|
||||
**Status:** approved 2026-07-24; Slice F active
|
||||
|
||||
**Program:** `docs/plans/2026-07-24-modern-runtime-architecture.md`
|
||||
|
||||
**Baseline:** Slice E closeout commits `91e82c3c` and `e7d9d6fa`
|
||||
|
||||
**Behavior contract:** no change to pixels, view distance, particles, PView
|
||||
visibility, clipping, draw order, selection, lighting, animation, or
|
||||
retail-faithful gameplay
|
||||
|
||||
## 1. Decision record
|
||||
|
||||
### 1.1 Why this work has a separate approval gate
|
||||
|
||||
Slices A–E optimized measurement, prepared content, residency, streaming, and
|
||||
retirement without replacing the renderer's scene model. Slices F/G resume the
|
||||
MP3 work that the user explicitly deferred on 2026-07-05:
|
||||
|
||||
- Slice F introduces a second, render-only projection in non-drawing shadow
|
||||
mode.
|
||||
- Slice G makes that projection the renderer's production input and removes the
|
||||
old whole-world enumeration/partition path.
|
||||
|
||||
This is a materially larger regression surface than changing an isolated
|
||||
scheduler or cache. A wrong cell bucket, incarnation, transform, material
|
||||
variant, or draw-order classification can produce the historical
|
||||
stairs/doorway/player-vanish bug classes while still compiling and appearing
|
||||
faster. The approval gate therefore remains binding.
|
||||
|
||||
Approval had to be explicit and recorded as:
|
||||
|
||||
> Approved — continue with all slices.
|
||||
|
||||
The user supplied that approval on 2026-07-24 after reviewing the post-E
|
||||
evidence and rewrite risk. Runtime work therefore proceeds from the exact
|
||||
pre-F/G anchor `e7d9d6fa`.
|
||||
|
||||
### 1.2 Post-Slice-E evidence
|
||||
|
||||
Physical-local Release captures on exact binary
|
||||
`91e82c3c6850fcedbf20322b2ecf4fdcd11a2b2a` produced:
|
||||
|
||||
| Capture | CPU p50 / p95 / p99 | GPU p50 / p95 / p99 |
|
||||
|---|---:|---:|
|
||||
| Uncapped nine-stop | 1.216 / 4.216 / 5.450 ms | 0.725 / 2.486 / 2.666 ms |
|
||||
| Dense Arwic uncapped | 2.652 / 4.153 / 5.736 ms | 1.576 / 2.504 / 2.662 ms |
|
||||
|
||||
Dense Arwic exercised 15,530 entities and 111 animated entities. Its CPU
|
||||
median is already below the provisional 3.33 ms / 300 FPS target. Therefore:
|
||||
|
||||
- F/G is not needed to claim that one provisional median target.
|
||||
- CPU p95/p99 still exceed GPU p95/p99, leaving measurable CPU headroom.
|
||||
- The current path still scales with the resident entity population rather
|
||||
than only with scene changes and visible buckets.
|
||||
- The expected win is lower CPU utilization, better dense-scene scaling,
|
||||
lower tail cost, and a clean future snapshot/headless seam.
|
||||
- A dramatic average-FPS increase is possible but is not promised.
|
||||
|
||||
The go/no-go decision is consequently about accepting architectural rewrite
|
||||
risk for throughput headroom and a cleaner long-term runtime boundary, not
|
||||
about repairing an existing visual or stability failure.
|
||||
|
||||
## 2. Current owner map
|
||||
|
||||
| Concern | Current owner | Current cost/contract | F/G treatment |
|
||||
|---|---|---|---|
|
||||
| Logical live identity and accepted state | `LiveEntityRuntime` | sole GUID/incarnation authority | unchanged; emits exact projection facts only |
|
||||
| Spatial landblock membership | `GpuWorldState` | sole loaded/pending bucket authority | unchanged; journals committed render projection deltas |
|
||||
| Static publication/retirement | `LandblockPresentationPipeline` and retirement coordinator | retained exact Slice-E receipts | append render deltas at existing committed receipt boundaries |
|
||||
| Live presentation resources | `EntitySpawnAdapter` | exact per-incarnation mesh/composite ownership | unchanged; appearance facts copied into render projection |
|
||||
| Equipped-child presentation | `EquippedChildRenderController` | final current transform and visibility | copied into equipped projection archetype |
|
||||
| Static animation | `RetailStaticAnimatingObjectScheduler` | final root transform for active animated statics | active-only synchronization into dynamic transform components |
|
||||
| Frame camera/root/building facts | `WorldRenderFrameBuilder` | borrowed one-frame facts | retained |
|
||||
| Retail cell visibility | `PortalVisibilityBuilder` / `RetailPViewRenderer` | retail PView and viewcone oracle | retained without algorithm changes |
|
||||
| Per-frame entity split | `InteriorEntityPartition` | scans every resident `WorldEntity` | replaced by incremental scene indices in G |
|
||||
| Visibility walk/classification | `WbDrawDispatcher` | walks entity/mesh pairs and rebuilds instance groups | consumes packed frame candidates and dirty instance ranges in G |
|
||||
| Alpha order | `RetailAlphaQueue` | shared stable far-to-near ordering | retained |
|
||||
| Selection | retail selection scene/sink | visible part publication and lighting | same accepted parts and transforms from frame view |
|
||||
| Lighting | `LightManager` plus dispatcher selection | per-object retail light set | same algorithm over packed bounds |
|
||||
| GL ownership | `WbMeshAdapter`, texture/residency owners, dispatcher buffers | render-thread only | unchanged |
|
||||
|
||||
`GpuWorldState` remains the canonical spatial projection. The new render scene
|
||||
is a derived, disposable presentation index. It cannot answer gameplay,
|
||||
network, collision, inventory, interaction, radar, target, or persistence
|
||||
questions.
|
||||
|
||||
## 3. Target boundary
|
||||
|
||||
### 3.1 Acdream-owned API
|
||||
|
||||
Arch is an implementation detail in `AcDream.App`. No Arch type crosses an
|
||||
acdream interface, enters Core, or appears in a test fixture outside App.
|
||||
|
||||
The boundary is equivalent to:
|
||||
|
||||
```csharp
|
||||
internal interface IRenderScene
|
||||
{
|
||||
RenderSceneGeneration Generation { get; }
|
||||
RenderProjectionCounts Counts { get; }
|
||||
|
||||
RenderDeltaApplyResult Apply(ReadOnlySpan<RenderProjectionDelta> deltas);
|
||||
void SynchronizeDynamicSources(in DynamicProjectionSyncInput input);
|
||||
RenderSceneDigest BuildDigest(RenderSceneDigestBuffer reuse);
|
||||
RenderSceneQuery OpenQuery();
|
||||
void Clear(RenderSceneGeneration replacementGeneration);
|
||||
}
|
||||
```
|
||||
|
||||
The exact API may split mutation, query, and diagnostics into narrower
|
||||
interfaces, but these rules are fixed:
|
||||
|
||||
- mutation is update-thread only;
|
||||
- draw receives only a borrowed read/query surface;
|
||||
- draw cannot call `LiveEntityRuntime`, `GpuWorldState`, or `WorldEntity`
|
||||
dictionaries;
|
||||
- Arch entities and `.Value` primitives stay inside the scene implementation;
|
||||
- all external identities are acdream-owned wrapper types;
|
||||
- session/world generations are explicit;
|
||||
- stale incarnation deltas are rejected rather than applied to a reused slot.
|
||||
|
||||
### 3.2 Identity
|
||||
|
||||
Use distinct wrapper identities:
|
||||
|
||||
```text
|
||||
RenderProjectionId
|
||||
RenderOwnerIncarnation
|
||||
RenderSceneGeneration
|
||||
RenderSpatialBucket
|
||||
RenderAssetHandle
|
||||
```
|
||||
|
||||
Projection keys are derived presentation identities, not a second gameplay
|
||||
GUID map:
|
||||
|
||||
- static: world generation + canonical landblock + current static entity id;
|
||||
- live root: current local `WorldEntity.Id` + accepted instance sequence;
|
||||
- equipped child: parent local id + attachment slot/child local id +
|
||||
incarnation;
|
||||
- EnvCell: world generation + cell id.
|
||||
|
||||
The scene may keep a source-key-to-projection lookup solely to apply deltas. It
|
||||
may not expose that lookup as object identity to gameplay consumers.
|
||||
|
||||
### 3.3 Component set
|
||||
|
||||
Initial packed components:
|
||||
|
||||
```text
|
||||
RenderTransform
|
||||
PreviousRenderTransform
|
||||
RenderMeshSet
|
||||
RenderMaterialVariant
|
||||
RenderSpatialResidency
|
||||
RenderWorldBounds
|
||||
RenderFlags
|
||||
RenderDegradeState
|
||||
RenderSortKey
|
||||
RenderOwnerIncarnation
|
||||
RenderDirtyMask
|
||||
```
|
||||
|
||||
Archetypes remain narrow:
|
||||
|
||||
- outdoor static;
|
||||
- indoor-cell static;
|
||||
- live/dynamic root;
|
||||
- active animated static;
|
||||
- equipped child;
|
||||
- translucent/light-bearing variants only where query density justifies them.
|
||||
|
||||
Do not attach every component to every projection. Effects, particles, and
|
||||
lights remain in their existing owners during F/G unless a measured query
|
||||
benefit and an exact parity fixture justify a packed reference.
|
||||
|
||||
### 3.4 Delta journal
|
||||
|
||||
One update-thread-owned `RenderProjectionJournal` receives:
|
||||
|
||||
```text
|
||||
Register
|
||||
UpdateTransform
|
||||
UpdateAppearance
|
||||
UpdateFlags
|
||||
Rebucket
|
||||
Unregister
|
||||
ClearGeneration
|
||||
```
|
||||
|
||||
Each delta carries:
|
||||
|
||||
- scene generation;
|
||||
- projection source key;
|
||||
- exact owner incarnation;
|
||||
- monotonically increasing journal sequence;
|
||||
- complete payload for the changed channel.
|
||||
|
||||
Rules:
|
||||
|
||||
- structural order is exact;
|
||||
- updates may coalesce only within one host tick, after the most recent
|
||||
structural edge for the same projection/incarnation;
|
||||
- register/unregister and generation boundaries never coalesce away;
|
||||
- unregister of an old incarnation cannot remove its replacement;
|
||||
- a journal drains fully at the update-to-render boundary;
|
||||
- any carry-over at frame publication is an invariant failure;
|
||||
- callback reentrancy appends after the current sequence and cannot invalidate
|
||||
active iteration;
|
||||
- no bounded queue or worker thread is introduced in F/G—the accepted host
|
||||
thread remains the only writer.
|
||||
|
||||
### 3.5 Static versus dynamic synchronization
|
||||
|
||||
Static projections are change-driven:
|
||||
|
||||
- landblock spatial publication registers them once;
|
||||
- appearance or static-animation membership changes issue explicit deltas;
|
||||
- rebucket/retirement removes them once.
|
||||
|
||||
Dynamic root and equipped-child transforms are synchronized after animation,
|
||||
physics, remote motion, local-player projection, and attachment transforms
|
||||
have reached their existing final frame state. The synchronizer walks only
|
||||
the scene's dynamic/active-animated source registry, compares packed final
|
||||
facts, and emits updates for changed records. It never scans all resident
|
||||
statics.
|
||||
|
||||
This active-only synchronization is deliberate. Retrofitting presentation
|
||||
version counters into every simulation setter during F would broaden the
|
||||
change into gameplay/physics ownership. A later measured slice may replace
|
||||
the comparison with versioned producers without changing `IRenderScene`.
|
||||
|
||||
## 4. Referee before the match
|
||||
|
||||
The comparison oracle lands before Arch or shadow storage.
|
||||
|
||||
`CurrentRenderSceneOracle` captures the current accepted render input after
|
||||
PView construction and before dispatcher classification. Its deterministic
|
||||
digest contains, in stable sort order:
|
||||
|
||||
- source/projection identity and incarnation;
|
||||
- spatial class: outdoor static, cell static, dynamic, equipped;
|
||||
- canonical landblock and full cell;
|
||||
- root transform and world bounds;
|
||||
- mesh ids and part transforms in order;
|
||||
- material/palette/texture replacement identity;
|
||||
- draw/ancestor/hidden/translucency/degrade flags;
|
||||
- active-animation classification;
|
||||
- PView survivor class and clip-route identity;
|
||||
- expected selection part ids;
|
||||
- opaque/alpha classification identity.
|
||||
|
||||
The oracle is validated on the current production path first. It must be:
|
||||
|
||||
- deterministic across repeated unchanged frames;
|
||||
- allocation-free when disabled;
|
||||
- bounded and reusable when enabled;
|
||||
- independent of dictionary enumeration order;
|
||||
- continuously sampled during login, portal transit, reveal, movement,
|
||||
animation, appearance change, and teardown—not only at stable checkpoints.
|
||||
|
||||
The oracle does not decide what retail should draw. It records what the
|
||||
already accepted current path supplies, so F/G cannot silently redefine
|
||||
parity in favor of the new implementation.
|
||||
|
||||
## 5. Slice F — Non-drawing shadow render scene
|
||||
|
||||
### F0 — Current-path oracle
|
||||
|
||||
1. Add acdream-owned digest/value types and reusable buffers.
|
||||
2. Capture the current partition and dispatcher candidate identity without
|
||||
changing draw behavior.
|
||||
3. Add deterministic unit fixtures for static, dynamic, animated, equipped,
|
||||
translucent, hidden, duplicate ids across landblocks, and GUID reuse.
|
||||
4. Extend canonical lifecycle artifacts with digest generation, counts,
|
||||
mismatch count, journal depth, and scene bytes.
|
||||
5. Run the current pipeline alone through the canonical route and establish
|
||||
the referee's own stability.
|
||||
|
||||
**Commit gate:** no Arch dependency; identical screenshots; no material
|
||||
performance regression with comparison disabled.
|
||||
|
||||
### F1 — Scene types and contained Arch adapter
|
||||
|
||||
1. Verify Arch's current license and selected package API; pin one exact
|
||||
version in `AcDream.App` only.
|
||||
2. Add `IRenderScene`, wrapper ids, component structs, query contracts, and
|
||||
`ArchRenderScene`.
|
||||
3. Add an architecture test preventing Arch namespaces outside the allowed App
|
||||
folder and preventing primitive id extraction outside the owner assembly.
|
||||
4. Add memory accounting for chunks, lookup/index storage, journal buffers,
|
||||
and retained synchronization sources.
|
||||
5. Prove create/update/remove/clear and stale-incarnation rejection in pure App
|
||||
tests.
|
||||
|
||||
**Commit gate:** the scene is unbound and non-drawing; full suite green.
|
||||
|
||||
### F2 — Static projection journal
|
||||
|
||||
1. Append Register deltas from the existing final landblock spatial publication
|
||||
receipt.
|
||||
2. Append Unregister deltas from the exact retirement/demotion receipt.
|
||||
3. Preserve owner landblock identity independently of the caller's current
|
||||
draw landblock—the #119 cache lesson.
|
||||
4. Mirror indoor cell statics, outdoor statics, scenery, building shells, and
|
||||
EnvCell projection identity without changing their resource ownership.
|
||||
5. Make same-landblock rehydrate a reconcile operation: retained identities
|
||||
update, omitted identities unregister, and new identities register.
|
||||
6. Clear by exact world generation on login, portal supersession, session
|
||||
reset, and graceful shutdown.
|
||||
|
||||
**Commit gate:** shadow static digest equals the referee over deterministic
|
||||
publication/retirement permutations.
|
||||
|
||||
### F3 — Live and equipped projection journal
|
||||
|
||||
1. Register only after the current live record, materialized projection, and
|
||||
presentation resources have committed.
|
||||
2. Use exact local id + instance sequence; never server GUID alone.
|
||||
3. Journal loaded/pending visibility edges without treating rebucket as
|
||||
logical recreate.
|
||||
4. Mirror appearance, mesh refs, palette/material variants, draw flags,
|
||||
ancestor visibility, full cell, and bounds.
|
||||
5. Mirror equipped children after their current attachment transform update.
|
||||
6. Unregister exactly once on pickup/parenting/withdraw/delete/session reset,
|
||||
rejecting callbacks from displaced generations.
|
||||
|
||||
**Commit gate:** duplicate CreateObject, reentrant callback, pending-to-loaded,
|
||||
loaded-to-loaded, hidden, parent/child, delete/recreate, and GUID-reuse tests
|
||||
have zero leaked or stale projections.
|
||||
|
||||
### F4 — Dynamic synchronization and incremental indices
|
||||
|
||||
1. Synchronize final current-frame transforms for live roots, active animated
|
||||
statics, and equipped children.
|
||||
2. Maintain outdoor-static, per-cell-static, dynamic, translucent, selectable,
|
||||
light-candidate, and dirty-record indices incrementally.
|
||||
3. Preserve `InteriorEntityPartition.IsIndoorCellId` semantics.
|
||||
4. Preserve retail's special dynamic routing:
|
||||
- outdoor dynamics under an interior root enter the outside stage;
|
||||
- exit-portal-straddling dynamics may enter both stages;
|
||||
- out-of-flood indoor dynamics remain members but fail the per-dynamic
|
||||
viewcone cull.
|
||||
5. Assert index counts and membership against the current partition every
|
||||
sampled frame.
|
||||
|
||||
**Commit gate:** no whole-static-world synchronization in a steady frame;
|
||||
unchanged dynamic records emit no update.
|
||||
|
||||
### F5 — Continuous shadow comparison
|
||||
|
||||
1. Apply the journal and build the shadow digest at the update/render boundary.
|
||||
2. Compare continuously at a fixed diagnostic cadence and at every canonical
|
||||
checkpoint.
|
||||
3. Record the first exact mismatch with both projections and source channel;
|
||||
never log an unbounded mismatch storm.
|
||||
4. Run deterministic portal, churn, animation, appearance, hidden, selection,
|
||||
and teardown tests.
|
||||
5. Run capped and uncapped nine-stop routes plus dense Arwic on the physical
|
||||
display.
|
||||
6. Prove:
|
||||
- zero mismatches;
|
||||
- zero stale delta applications;
|
||||
- zero journal carry-over;
|
||||
- zero retained old-generation scene state;
|
||||
- bounded shadow memory;
|
||||
- no pixel changes because the shadow does not draw.
|
||||
|
||||
**Slice F gate:** all evidence above passes before any production consumer is
|
||||
switched. F may temporarily cost memory and a small amount of CPU in diagnostic
|
||||
mode; those costs are reported separately and shadow comparison is disabled by
|
||||
default after its gate.
|
||||
|
||||
## 6. Slice G — Frame product and production cutover
|
||||
|
||||
### G0 — Borrowed double-buffered frame product
|
||||
|
||||
Add two reusable `RenderFrameArena` instances. Building frame N writes the
|
||||
arena not borrowed by draw N-1 and publishes a generation-stamped
|
||||
`RenderFrameView`.
|
||||
|
||||
The view contains spans/ranges for:
|
||||
|
||||
- visible outdoor static candidates;
|
||||
- visible per-cell static candidates keyed by PView order;
|
||||
- dynamic candidates;
|
||||
- final root/part transforms;
|
||||
- opaque and alpha classification records;
|
||||
- per-object light sets;
|
||||
- selection parts and lighting;
|
||||
- existing PView/clip products by borrowed reference;
|
||||
- diagnostic counts and source digest.
|
||||
|
||||
Rules:
|
||||
|
||||
- no extra frame of latency;
|
||||
- no render thread is introduced;
|
||||
- a view is invalid after its arena is reused;
|
||||
- no consumer retains spans across frame completion;
|
||||
- abort recycles the incomplete arena without publishing it;
|
||||
- world generation and frame sequence must match at draw.
|
||||
|
||||
### G1 — Replace whole-world partition with scene queries
|
||||
|
||||
1. Query outdoor statics directly.
|
||||
2. Query each PView-visible cell bucket in the exact existing far-to-near order.
|
||||
3. Query the dynamic set once, then apply the existing per-dynamic viewcone and
|
||||
outside-stage/straddle rules.
|
||||
4. Preserve look-in cells as a distinct landscape-stage source.
|
||||
5. Preserve particle-owner filtering against the exact mesh survivor set.
|
||||
6. Compare the new candidate digest with the old partition without drawing
|
||||
twice.
|
||||
|
||||
**Commit gate:** exact candidate parity through indoor/outdoor transitions,
|
||||
door apertures, look-ins, non-flooded rooms, and portal straddles.
|
||||
|
||||
### G2 — Packed dispatcher input
|
||||
|
||||
1. Introduce an acdream-owned `RenderInstanceCandidate` consumed by
|
||||
`WbDrawDispatcher`.
|
||||
2. Copy every current `WorldEntity` fact the dispatcher actually uses:
|
||||
- mesh refs and ordered part transforms;
|
||||
- root transform;
|
||||
- owner landblock/cell;
|
||||
- palette and texture replacement identity;
|
||||
- hidden/draw/ancestor flags;
|
||||
- scale, bounds, source setup/gfx id;
|
||||
- selection owner identity;
|
||||
- translucency/degrade state.
|
||||
3. Preserve cache key and invalidation semantics, especially owner landblock
|
||||
identity and incomplete-mesh retry.
|
||||
4. Keep Wb/texture/selection/light/alpha owners unchanged.
|
||||
5. Add old-input/new-input instance-set comparison at the dispatcher boundary.
|
||||
|
||||
**Commit gate:** identical instance keys, model matrices, material identities,
|
||||
clip slots, light sets, selection parts, alpha records, and draw counts.
|
||||
|
||||
### G3 — Dirty instance ranges and reusable command storage
|
||||
|
||||
1. Retain persistent instance records keyed by projection + mesh part + batch.
|
||||
2. Rebuild classification only for Register, Appearance, Material, Mesh,
|
||||
Degrade, or relevant Flags dirtiness.
|
||||
3. Update transform/light/selection fields through dirty ranges.
|
||||
4. Reuse MDI command, batch, sort, and alpha scratch storage.
|
||||
5. Cache static command templates by scene generation and visible-cell set only
|
||||
after parity proves the simpler indexed path.
|
||||
6. Keep resource upload and GL retirement on the accepted render thread.
|
||||
7. Do not add GPU culling, GPU particles, or render-worker jobs in G.
|
||||
|
||||
**Commit gate:** warm unchanged frames rebuild no static classification and
|
||||
allocate no core scene/dispatcher memory.
|
||||
|
||||
### G4 — Cutover
|
||||
|
||||
1. Run old and new input construction in compare-only mode; draw only the old
|
||||
path.
|
||||
2. Fix every mismatch at its source.
|
||||
3. Switch the single production draw input to `RenderFrameView`.
|
||||
4. Run instance-set and fixed-camera image comparisons.
|
||||
5. Obtain the user's connected visual confirmation.
|
||||
6. Delete:
|
||||
- production `InteriorEntityPartition` use;
|
||||
- full `LandblockEntries` walk from normal world draw;
|
||||
- transition flags and dual-input compare code;
|
||||
- obsolete static classification rebuild paths.
|
||||
7. Keep only reusable oracle tooling behind diagnostics/tests.
|
||||
|
||||
There is no permanent runtime fallback. A failed gate reverts the cutover
|
||||
commit; it does not ship a hidden old/new switch.
|
||||
|
||||
### G5 — Physical performance and lifecycle gate
|
||||
|
||||
Run the exact Slice-E reference matrix:
|
||||
|
||||
- capped physical-local nine-stop;
|
||||
- uncapped physical-local nine-stop;
|
||||
- pinned dense-Arwic uncapped with stationary turn;
|
||||
- fresh login, portal/dungeon, same-location revisit, world edge;
|
||||
- appearance, hidden/unhide, equipped-child changes;
|
||||
- graceful logout/reconnect;
|
||||
- rapid generation replacement and GUID reuse.
|
||||
|
||||
Report, without changing thresholds:
|
||||
|
||||
- CPU/GPU p50/p95/p99/p99.9 and maximum;
|
||||
- update, PView, scene query, frame build, dispatcher, alpha, and GL stages;
|
||||
- frame-thread and process allocation;
|
||||
- scene/chunk/index/journal bytes;
|
||||
- managed heap, LOH/POH fragmentation, GC pauses;
|
||||
- tracked CPU/GPU/staging/retiring bytes;
|
||||
- instance/draw/triangle counts;
|
||||
- screenshot and instance-set comparison.
|
||||
|
||||
## 7. Acceptance matrix
|
||||
|
||||
### 7.1 Correctness
|
||||
|
||||
- Exact static/live/equipped projection count and digest.
|
||||
- Exact PView cell order and viewcone behavior.
|
||||
- Exact outside-stage and portal-straddling dynamic behavior.
|
||||
- Exact opaque/clip-map/alpha classification and stable alpha order.
|
||||
- Exact root and part transforms with no one-frame lag.
|
||||
- Exact hidden, NoDraw, ancestor visibility, and translucency behavior.
|
||||
- Exact material/palette/texture replacement identity.
|
||||
- Exact light sets and selection-part placement.
|
||||
- Exact incarnation behavior across stale updates and GUID reuse.
|
||||
- Zero replay of logical create/default script/effect work on rebucket.
|
||||
- Zero draw calls into gameplay/spatial dictionaries.
|
||||
|
||||
### 7.2 Resource and lifecycle
|
||||
|
||||
- Journal empty at every frame publication.
|
||||
- No old world generation in scene after replacement converges.
|
||||
- Scene memory plateaus on third location visit.
|
||||
- No stale Arch entity handle after removal/reuse.
|
||||
- No extra mesh/texture/composite owner.
|
||||
- No unbalanced reference, staged upload, dynamic light, effect, or alpha
|
||||
record.
|
||||
- Graceful shutdown drains scene and GL retirement exactly once.
|
||||
|
||||
### 7.3 Performance
|
||||
|
||||
The program goals remain:
|
||||
|
||||
- dense uncapped p50 at or below 3.33 ms, or a newly attributed blocker;
|
||||
- traversal p99 at or below 16.67 ms;
|
||||
- no post-warm frame above 33.3 ms without an attributed indivisible/OS event;
|
||||
- steady update p95 at or below 2 ms;
|
||||
- core render-scene/dispatcher allocation p50 of zero;
|
||||
- whole-client steady allocation initially at or below 4 KiB/frame;
|
||||
- no known exception-as-control-flow site.
|
||||
|
||||
Because Slice E already satisfies the dense median target, G must additionally
|
||||
show one of:
|
||||
|
||||
- a statistically meaningful CPU p95/p99 reduction;
|
||||
- lower CPU utilization at equal uncapped throughput;
|
||||
- materially improved resident-entity scaling;
|
||||
- or a documented result that the removed scan was no longer dominant and the
|
||||
next measured bottleneck belongs to Slice H.
|
||||
|
||||
No visual-quality reduction is an acceptable way to pass.
|
||||
|
||||
## 8. Commit and review sequence
|
||||
|
||||
Each sub-slice is one or more bisectable commits, but a commit may not mix
|
||||
shadow storage, production cutover, and old-path deletion.
|
||||
|
||||
For every commit:
|
||||
|
||||
1. inspect the complete diff for authority leakage, stale identity, lifecycle
|
||||
asymmetry, and allocations;
|
||||
2. run focused App tests;
|
||||
3. run `dotnet build AcDream.slnx -c Release`;
|
||||
4. run the complete Release solution tests before a sub-slice gate;
|
||||
5. update architecture, roadmap, issues, divergence register, and memory in the
|
||||
same commit when their truth changes;
|
||||
6. introduce no retail-divergence row—F/G is performance-only and any visible
|
||||
difference is a bug.
|
||||
|
||||
No substantial feature body enters `GameWindow`. Composition changes live in
|
||||
`FrameRootComposition`; scene, journal, oracle, synchronization, and frame
|
||||
product owners live under focused `AcDream.App/Rendering` namespaces.
|
||||
|
||||
## 9. Stop/rollback conditions
|
||||
|
||||
Stop the current sub-slice and fix the root cause when:
|
||||
|
||||
- the shadow digest differs;
|
||||
- source identity requires a second authoritative GUID map;
|
||||
- a draw consumer must call back into `LiveEntityRuntime` or `GpuWorldState`;
|
||||
- delta order cannot represent a reentrant lifecycle edge;
|
||||
- the new path needs a timer, suppression flag, or retry workaround;
|
||||
- a screenshot/instance difference cannot be explained;
|
||||
- the frame product adds a frame of latency;
|
||||
- memory fails to plateau;
|
||||
- F/G performance is worse outside explicitly enabled shadow comparison.
|
||||
|
||||
The rollback unit is the failing sub-slice commit. Do not retain a permanent
|
||||
legacy fallback, dual draw, or user-facing renderer switch.
|
||||
|
||||
## 10. Approval and rollback state
|
||||
|
||||
This plan is approved and active.
|
||||
|
||||
- Pre-F/G runtime rollback anchor: `e7d9d6fa`.
|
||||
- Every production cutover commit is added here and to
|
||||
`claude-memory/project_render_pipeline_digest.md`.
|
||||
- Shadow/referee commits precede the production switch and need not be reverted
|
||||
for a visual mismatch unless they independently change runtime behavior.
|
||||
- A failed visual gate reverts the exact cutover commit(s); it does not use
|
||||
`git reset`, discard later evidence, or enable a permanent fallback.
|
||||
Loading…
Add table
Add a link
Reference in a new issue