Record the clean Release, lifecycle, soak, and framebuffer gates for Slice 7, advance the structural program to Slice 8, and preserve the observed process-residency diagnostic gap as issue 232 rather than weakening its leak threshold.\n\nCo-authored-by: Codex <codex@openai.com>
602 lines
32 KiB
Markdown
602 lines
32 KiB
Markdown
# GameWindow Slice 7 — render-frame orchestration
|
||
|
||
**Status:** Complete 2026-07-22.
|
||
**Parent program:** [`docs/architecture/code-structure.md`](../architecture/code-structure.md), Slice 7.
|
||
**Baseline:** `9512404e`; `GameWindow.cs` is 7,026 raw lines, 241 fields, and
|
||
108 methods. The Release suite passes 7,182 tests / 5 fixture or environment
|
||
skips. The 314-second lifecycle/reconnect gate and 394-second synchronized
|
||
nine-stop resource soak pass.
|
||
**Behavior rule:** This is an ownership extraction. Preserve every accepted
|
||
world/PView/alpha/private-viewport/UI draw edge, render-thread publication
|
||
edge, GL-state boundary, and GPU-flight failure contract. Do not combine the
|
||
extraction with a render-quality change, visibility correction, frame-order
|
||
port, or resource-lifetime redesign.
|
||
|
||
## Progress ledger
|
||
|
||
- [x] A — freeze the complete render graph, correct the architecture SSOT, and
|
||
introduce data-only frame contracts plus deterministic order/failure tests.
|
||
- [x] B — extract paperdoll, panel-layout/devtools, and render-diagnostics leaf
|
||
owners while `GameWindow` still orders the frame.
|
||
- [x] C — extract frame-resource begin/upload/publication and live display,
|
||
and weather/display foundations that do not depend on camera/root
|
||
classification.
|
||
- [x] D — extract frame-data classification and reusable world scratch without
|
||
duplicating live identity, spatial, visibility, or resource ownership; then
|
||
run the dependent audio, sky, lighting, and listener preparation.
|
||
- [x] E — replace `RetailPViewDrawContext`'s callback bag with a typed
|
||
`RetailPViewPassExecutor` and data-only inputs.
|
||
- [x] F — extract `WorldSceneRenderer`, including both shared-alpha scopes,
|
||
PView/fallback world branches, particles, debug world draw, and completion.
|
||
- [x] G — compose `RenderFrameOrchestrator`, cut `GameWindow.OnRender` to one
|
||
handoff, and delete obsolete frame bodies, fields, helpers, and callbacks.
|
||
- [x] H — corrected-diff reviews, full Release suite, connected lifecycle and
|
||
soak gates, framebuffer comparison, documentation, memory, and metrics.
|
||
|
||
Every checked checkpoint is one bisectable architectural commit. A checkpoint
|
||
does not complete while a new owner merely delegates a substantial body back to
|
||
`GameWindow`.
|
||
|
||
## 1. Outcome and non-goals
|
||
|
||
At slice exit, `GameWindow.OnRender` supplies one immutable delta/viewport input
|
||
to `RenderFrameOrchestrator`. The orchestrator owns the GPU-flight transaction
|
||
and composes focused frame-resource, world-scene, private-presentation, and
|
||
diagnostic phases. `GameWindow` remains the construction and shutdown shell; it
|
||
does not keep the draw graph, PView pass callbacks, frame scratch, paperdoll
|
||
assembly, or performance-title body.
|
||
|
||
The target ownership graph is:
|
||
|
||
```text
|
||
RenderFrameOrchestrator
|
||
├── RenderFrameResourceController GPU slot + resource BeginFrame/upload
|
||
├── WorldRenderFrameBuilder camera/root/light/classification facts
|
||
├── WorldSceneRenderer accepted world draw graph
|
||
│ ├── RetailPViewRenderer visibility/order owner
|
||
│ ├── RetailPViewPassExecutor concrete GL pass implementation
|
||
│ └── WorldRenderDiagnostics probes/debug counters/signatures
|
||
├── PrivatePresentationRenderer portal + paperdoll + retained UI + ImGui
|
||
│ ├── PaperdollFramePresenter
|
||
│ └── DevToolsFramePresenter
|
||
└── RenderFrameDiagnosticsController title/resource/frame snapshots
|
||
```
|
||
|
||
Names may narrow as code lands, but the ownership boundaries do not collapse
|
||
into one replacement god object. No new owner may receive `GameWindow`, a broad
|
||
service locator, or an anonymous list of callbacks into the window.
|
||
|
||
This slice does **not** change:
|
||
|
||
- the viewer-cell render root or player-cell lighting root;
|
||
- synthetic outdoor-cell behavior or the null-root safety path;
|
||
- portal flood, building pre-gates, clip-plane/scissor limits, punch/seal
|
||
depth behavior, shell lift, viewcone culling, or draw distances;
|
||
- shared-alpha sort keys, scope boundaries, blend/cull behavior, or immediate
|
||
EnvCell/private alpha;
|
||
- weather, fog, point-light selection, particle visibility/range, terrain
|
||
quality, FOV, frame pacing, or audio-listener formulas;
|
||
- portal-space, paperdoll, retained gameplay UI, ImGui, or screenshot visuals;
|
||
- resource ownership, shutdown/disposal order, or three-frame GPU retirement;
|
||
- TS-53's retained-UI time placement on the render seam.
|
||
|
||
Issue #225's translucent lifestone/particle comparison remains a separate user
|
||
visual gate. Passing this structural slice must not mark it resolved.
|
||
|
||
## 2. Retail oracle and accepted adaptations
|
||
|
||
This extraction reuses the existing named-retail research rather than
|
||
reinterpreting the draw algorithms:
|
||
|
||
- `SceneTool::BeginScene @ 0x0043DAD0` establishes the black scene-clear
|
||
baseline used by portal CreatureMode replacement;
|
||
- `SmartBox::DrawNoBlit @ 0x00454C20` updates the viewer and invokes the normal
|
||
world render before post-world selection work;
|
||
- `SmartBox::RenderNormalMode @ 0x00453AA0` owns landscape/inside dispatch and
|
||
the final retail alpha flush;
|
||
- `RenderDeviceD3D::DrawInside @ 0x0059F0D0`,
|
||
`PView::DrawInside @ 0x005A5860`, and
|
||
`PView::ConstructView @ 0x005A57B0` own the portal traversal;
|
||
- `PView::DrawCells @ 0x005A4840` fixes the outside-landscape → alpha flush →
|
||
conditional depth clear → exit masks → shells → object-list order;
|
||
- `LScape::draw @ 0x00506330`, `GameSky::Draw @ 0x00506FF0`,
|
||
`DrawBuilding @ 0x0059F2A0`, `DrawBlock @ 0x005A17C0`, and
|
||
`DrawObjCellForDummies @ 0x005A0760` constrain the landscape/building/cell
|
||
phases;
|
||
- `AddMeshToAlphaList @ 0x0059C230` and
|
||
`FlushAlphaList @ 0x0059D2E0` constrain alpha submission/flush boundaries;
|
||
- `CPhysicsPart::UpdateViewerDistance @ 0x0050E030` and
|
||
`CShadowPart::insertion_sort @ 0x006B5130` constrain transformed DAT
|
||
SortCenter/CYpt and stable far-to-near ordering;
|
||
- `CreatureMode::Render @ 0x004529D0` constrains portal and paperdoll private
|
||
viewports;
|
||
- `SceneTool::EndFrame @ 0x0043FB30` proves retail gameplay UI precedes retail
|
||
profiler/debug overlays; placing ImGui above gameplay UI is acdream's IA-12
|
||
modern coexistence adaptation, not literal Keystone parity.
|
||
|
||
The readable pseudocode oracle is
|
||
[`docs/research/2026-06-05-retail-pview-indoor-render-pseudocode.md`](../research/2026-06-05-retail-pview-indoor-render-pseudocode.md),
|
||
with the current full reference in
|
||
[`docs/research/2026-06-02-retail-render-pipeline-full-reference.md`](../research/2026-06-02-retail-render-pipeline-full-reference.md).
|
||
Shared-alpha ordering is pinned separately by
|
||
[`docs/research/2026-07-18-retail-shared-alpha-list-pseudocode.md`](../research/2026-07-18-retail-shared-alpha-list-pseudocode.md).
|
||
|
||
This slice preserves, rather than retires, the registered modern adaptations:
|
||
IA-8/9/10/12/14/15; AD-16/17/19/24;
|
||
AP-21/32/33/34/35/85/92/115/116/117;
|
||
TS-6/7; and TS-53. Source pointers move with ownership in the same commit, but
|
||
mechanism/risk language changes only if behavior actually changes.
|
||
|
||
## 3. Frozen production render order
|
||
|
||
The complete accepted order is:
|
||
|
||
1. call `GpuFrameFlightController.BeginFrame` outside the render `try`;
|
||
2. begin the composite-texture frame and cache tick;
|
||
3. begin, in order, dispatcher, EnvCell, portal depth, world text, retained-UI
|
||
text, clip, terrain, lighting UBO, then profiler frame state for the current
|
||
GPU slot;
|
||
4. select the portal replacement viewport; reset particle visibility when it
|
||
is active;
|
||
5. choose portal black or normal fog clear color, force depth writes, clear
|
||
color/depth/stencil, and establish CW/back-face frame-global state;
|
||
6. run GL-state/surface diagnostics;
|
||
7. advance render-thread publication in order: `WbMeshAdapter.Tick`, destination
|
||
reveal preparation/evaluation, then `ParticleRenderer.BeginFrame`;
|
||
8. begin ImGui, tick weather, and begin retail selection-scene accumulation;
|
||
9. when a normal camera/world viewport is active:
|
||
- begin the one frame-scoped `RetailAlphaQueue` collection; its landscape
|
||
`Flush` drains the first sub-scope and `EndFrame` later drains the final
|
||
world sub-scope without a second begin;
|
||
- resolve camera/projection/frustum and begin particle/terrain visibility;
|
||
- publish world-reveal visibility/completion;
|
||
- preview audio/display settings and publish the listener;
|
||
- resolve player lighting cell and collided viewer render cell;
|
||
- build prior-visible-cell point-light candidacy, sun/fog/lighting UBO, and
|
||
animated/equipped classification;
|
||
- construct the synthetic outdoor root/building candidates when required;
|
||
- run the null-root safety world or the one `RetailPViewRenderer.DrawInside`
|
||
graph;
|
||
- draw the post-world Scene particles/weather fallback and debug geometry;
|
||
- sample current-frame DebugVM visible-landblock and nearest-collision facts
|
||
before the developer UI can consume them;
|
||
- close the final shared-alpha scope and publish terrain/cell particle
|
||
visibility;
|
||
10. complete retail selection-scene accumulation;
|
||
11. draw the portal CreatureMode replacement viewport;
|
||
12. render the private paperdoll FBO before its 2-D widget blit;
|
||
13. tick/update-cursor/draw retained gameplay UI;
|
||
14. render ImGui menus and developer panels above gameplay UI;
|
||
15. capture a requested default-framebuffer screenshot;
|
||
16. publish window-title, resource-dump, and frame-profile diagnostics;
|
||
17. close the exact GPU frame once in `finally`.
|
||
|
||
Within `RetailPViewRenderer.DrawInside`:
|
||
|
||
1. construct the main PView; merge per-building exterior floods only for the
|
||
synthetic outdoor root and build separate look-in frames for interior roots;
|
||
2. assemble/upload the one clip arena, prepare EnvCell batches, partition
|
||
statics/dynamics, and classify outside-stage dynamics;
|
||
3. draw each outside slice early: sky, terrain, and outdoor statics;
|
||
4. draw building look-ins: all far-Z punches, opaque shells, then transparent
|
||
shells plus statics/dynamics/emitters;
|
||
5. draw outside-stage dynamic meshes, Scene particles, and weather late;
|
||
6. draw one interior-root unattached Scene-particle pass;
|
||
7. flush the **landscape** shared-alpha scope;
|
||
8. for an interior root, perform the full depth clear, then write true-depth
|
||
exit seals; for an outdoor root, retain world depth and use far-Z entry
|
||
punches;
|
||
9. draw opaque EnvCell shells once, then transparent shell cells immediate
|
||
far-to-near;
|
||
10. draw cell statics as one cross-cell batch, then their particles;
|
||
11. draw the surviving main-flood dynamics last, then their particles; look-in
|
||
and outside-stage dynamics remain in their earlier landscape phases.
|
||
|
||
The landscape alpha flush must never move across the depth clear. The final
|
||
world alpha close must never move after portal/paperdoll private viewports.
|
||
|
||
## 4. Architecture and interfaces
|
||
|
||
### 4.1 Frame transaction
|
||
|
||
Use immutable values equivalent to:
|
||
|
||
```csharp
|
||
internal readonly record struct RenderFrameInput(
|
||
double DeltaSeconds,
|
||
int ViewportWidth,
|
||
int ViewportHeight);
|
||
|
||
internal readonly record struct WorldRenderFrameOutcome(
|
||
int VisibleLandblocks,
|
||
int TotalLandblocks,
|
||
bool NormalWorldDrawn);
|
||
```
|
||
|
||
Portal-viewport selection and drawing belong to `PrivatePresentationRenderer`,
|
||
which runs after the world phase. If a combined public outcome becomes useful,
|
||
the top-level orchestrator composes it only after private presentation; the
|
||
world owner never claims that a later viewport was drawn.
|
||
|
||
`RenderFrameOrchestrator` receives a small fixed set of typed phase owners. It
|
||
does not receive every renderer separately, a mutable frame-services bag, or
|
||
`GameWindow`.
|
||
|
||
`BeginFrame` remains outside the `try`: if it fails, no `EndFrame` is attempted.
|
||
After begin succeeds, every failure closes exactly once. Render failure plus
|
||
close failure becomes the current explicit `AggregateException`; close-only
|
||
failure propagates directly. Alpha, particle-visibility, and selection-scene
|
||
completion retain their current non-finally behavior; changing that recovery
|
||
contract requires separate approval and evidence.
|
||
|
||
### 4.2 Borrowed resources and shutdown
|
||
|
||
The frame orchestrator and phase owners borrow the already-created GL/render
|
||
owners and do not dispose them. The developer-tools backend is itself the
|
||
canonical owner of its ImGui bootstrap and disposes that bootstrap when the
|
||
existing retryable shutdown transaction retires the backend; the frame
|
||
presenter only borrows it. Shutdown keeps its proven dependency order: wait for
|
||
submitted work; withdraw UI/render publications; release textures and mesh
|
||
owners; then dispose GL backing stores, with `GpuFrameFlightController` last
|
||
among render resources. Slice 8 may group construction/disposal after the
|
||
render cutover is stable.
|
||
|
||
`DisplayFramePacingController` is the focused shared owner for requested VSync,
|
||
live display preview, monitor/window callbacks, and the separate
|
||
`OnFrameRendered` pacing event. Render preparation and window lifecycle wiring
|
||
invoke that typed owner directly; neither calls back into a substantial
|
||
`GameWindow` method. Its existing disposal remains in the Slice 7 shutdown
|
||
transaction.
|
||
|
||
### 4.3 World frame data
|
||
|
||
`WorldRenderFrameBuilder` owns reusable classification scratch:
|
||
|
||
- animated/equipped entity IDs;
|
||
- synthetic outdoor node and candidate building cells;
|
||
- previous-frame drawable cells used by point-light candidacy;
|
||
- camera/root/classification facts with one-frame borrowed lifetime.
|
||
|
||
The builder owns only facts available before PView execution. Slice-local
|
||
visible/outdoor/unattached particle-owner IDs belong to
|
||
`RetailPViewPassExecutor`. The current interior partition is produced by
|
||
`RetailPViewRenderer.DrawInside` and remains in its borrowed result/diagnostic
|
||
snapshot; it is never stored as stale pre-draw builder state.
|
||
|
||
It queries canonical `LiveEntityRuntime`, `GpuWorldState`, player-mode/camera,
|
||
physics cell graph, cell visibility, and landblock presentation sources. It
|
||
does not copy their dictionaries or create a second visibility computation.
|
||
Returned collections are borrowed until the next build; tests pin this
|
||
lifetime and consumers cannot retain them.
|
||
|
||
### 4.4 PView pass execution
|
||
|
||
Replace the current `RetailPViewDrawContext` callback bag with a data-only
|
||
`RetailPViewFrameInput`, a typed cell-visibility source, and one explicit
|
||
`IRetailPViewPassExecutor`/`RetailPViewPassExecutor`. The executor owns the GL
|
||
resources needed for these named operations:
|
||
|
||
```text
|
||
SetTerrainClip
|
||
DrawLandscapeSlice
|
||
DrawLandscapeSliceLate
|
||
ClearInteriorDepth
|
||
DrawExitPortalMask
|
||
DrawLookInPortalPunch
|
||
DrawUnattachedSceneParticles
|
||
FlushLandscapeAlpha
|
||
DrawCellParticles
|
||
DrawDynamicsParticles
|
||
EmitDiagnostics
|
||
```
|
||
|
||
`RetailPViewRenderer` remains the retail ordering owner and calls these typed
|
||
operations. The executor may not call `GameWindow` or make independent
|
||
visibility/order decisions. Existing borrowed `RetailPViewFrameResult` scratch
|
||
semantics remain explicit.
|
||
|
||
### 4.5 Presentation and diagnostics
|
||
|
||
`PaperdollFramePresenter` owns dirty state, DAT-backed clone/re-dress, pose
|
||
selection/application, and FBO rendering. Inventory/session paths call
|
||
`MarkDirty`; they do not mutate its internals.
|
||
|
||
`PrivatePresentationRenderer` owns portal viewport, paperdoll, retained UI,
|
||
ImGui, and screenshot order. A focused panel-layout/devtools owner handles menu
|
||
actions and is also reused by framebuffer resize; it cannot call a substantial
|
||
window method.
|
||
|
||
`WorldRenderDiagnostics` owns pass-local PView/GL/scissor state, render
|
||
signatures, and world-pass timings. `RenderFrameDiagnosticsController` owns
|
||
FPS/frame-time accumulation, final visible-landblock counters, performance
|
||
title/resource publication, and the public render-frame snapshot. Only
|
||
render-derived DebugVM providers move in Slice 7. Update/session/streaming
|
||
providers and the cross-domain world-lifecycle resource sampler stay at the
|
||
composition boundary until Slice 8 rather than turning either diagnostics
|
||
owner into a replacement service locator. Diagnostics observe the frame; they
|
||
never choose a draw branch or mutate canonical world ownership.
|
||
|
||
## 5. Implementation checkpoints
|
||
|
||
### A — contracts, architecture, and oracles
|
||
|
||
- correct the stale render-pipeline and per-frame architecture sections;
|
||
- add `RenderFrameInput`, phase interfaces, and a recording orchestrator;
|
||
- pin the outer resource/world/private/diagnostic order across normal,
|
||
portal-replacement, login-wait, and screenshot outcome shapes; defer the
|
||
concrete indoor/outdoor/null-root branch tests to the world builder and scene
|
||
owner in D/F; camera is an initialized runtime invariant, so the slice does
|
||
not invent a new graceful missing-camera path;
|
||
- pin the exact GPU begin/end exception matrix;
|
||
- add source guards against `GameWindow` back-references, mega contexts, and a
|
||
new PView delegate bag;
|
||
- capture the current connected framebuffer/resource baseline.
|
||
|
||
Completed 2026-07-22. `RenderFrameOrchestrator` now owns the inert five-owner
|
||
outer transaction contract; `GpuFrameFlightController` implements its narrow
|
||
lifetime seam. Twenty-six focused render/GPU tests pin value-only contracts,
|
||
required-owner construction, exact phase prefixes, per-phase input propagation,
|
||
and every begin/render/close failure combination. Release build and the full
|
||
suite pass (7,199 passed / 5 skipped after adding 17 tests). All three
|
||
corrected-diff reviews are clean; production `GameWindow.OnRender` is unchanged.
|
||
|
||
### B — leaf presentation and diagnostics
|
||
|
||
- extract paperdoll refresh/pose/dirty/FBO ownership;
|
||
- extract panel-layout reuse and devtools menu/panel rendering;
|
||
- extract pass-local render signature, PView/GL/scissor probes, and timing state
|
||
into `WorldRenderDiagnostics`; extract FPS, final counts, title/resource
|
||
publication, and the public render snapshot into
|
||
`RenderFrameDiagnosticsController`;
|
||
- preserve the pre-presentation render-derived DebugVM sampling site separately
|
||
from the post-screenshot title/resource publication site; leave non-render
|
||
DebugVM providers and cross-domain world-lifecycle sampling at composition;
|
||
- keep call sites in their current `GameWindow.OnRender` positions.
|
||
|
||
Completed 2026-07-22. Paperdoll clone/re-dress/pose/FBO work now belongs to
|
||
`PaperdollFramePresenter`; retained surfaces are narrow and optional, while
|
||
live identity and DAT pose application resolve through focused adapters.
|
||
`DevToolsFramePresenter` owns the ImGui frame, menus, panels, layout, and input
|
||
actions while borrowing the bootstrap; `ImGuiDevToolsFrameBackend` explicitly
|
||
owns and disposes that bootstrap at shutdown.
|
||
`WorldRenderDiagnostics`, `DebugVmRenderFactsPublisher`, and
|
||
`RenderFrameDiagnosticsController` own the former render probes, debug facts,
|
||
title/resource cadence, and public snapshot. The production handoff now reports
|
||
the observed login/world and screenshot outcomes, preserves the original shared
|
||
TERRAIN→FRAME diagnostic transaction, and keeps the devtools-off scan path
|
||
allocation-free. `GameWindow.cs` is 6,270 raw lines, 60.1% below the 15,723-line
|
||
campaign baseline. Sixty-two focused tests, the Release build, and the complete
|
||
suite pass (7,255 passed / 5 skipped). Retail, architecture, and adversarial
|
||
corrected-diff reviews are clean.
|
||
|
||
### C — frame resources and live preparation
|
||
|
||
- extract ordered per-resource `BeginFrame` calls, clear/state establishment,
|
||
histogram probe, mesh upload, reveal evaluation, and particle begin;
|
||
- extract weather accumulation and display foundations that do not consume the
|
||
camera/root classification, preserving their current render-time positions;
|
||
- consolidate requested-VSync/live-preview, monitor callbacks, and
|
||
`OnFrameRendered` pacing through `DisplayFramePacingController`, while
|
||
leaving its disposal in the existing shutdown transaction;
|
||
- prove `WbMeshAdapter.Tick` remains before reveal evaluation and drawing;
|
||
- prove dispatcher begin occurs once for the whole world/paperdoll frame.
|
||
|
||
Completed 2026-07-22. `RenderFrameResourceController` now owns the exact
|
||
resource-begin → atmosphere/GL-clear → live-upload/reveal/particle transaction,
|
||
with a single captured GPU slot shared by every phase. Focused sources own the
|
||
login reveal cell, teleport render state, upload timing, and render-time weather
|
||
clock. `DisplayFramePacingController` owns requested VSync, the event-refreshed
|
||
monitor-rate cache, software pacing, and the post-render callback without adding
|
||
a monitor query to the frame hot path. Borrowed frame owners are withdrawn before
|
||
render teardown; portal fallback ownership transfers before the throwable sink
|
||
bind; pacing releases its borrowed surface/profiler before their owners close.
|
||
`GameWindow.cs` is 6,181 raw lines, 60.7% below the 15,723-line campaign
|
||
baseline. Twenty-one focused tests, the Release build, and the complete suite
|
||
pass (7,269 passed / 5 skipped). Retail, architecture, and adversarial
|
||
corrected-diff reviews are clean.
|
||
|
||
### D — world frame builder
|
||
|
||
- move animated/equipped classification, camera/root selection, outdoor-node
|
||
building gather, and prior-visible-cell light scratch out of the window;
|
||
- after those facts exist, run focused audio/listener, live preview, sky PES,
|
||
sun/fog/point-light, and lighting-UBO preparation; do not build an interim
|
||
`GameWindow` mega-context;
|
||
- keep PView-generated particle-owner sets in `RetailPViewPassExecutor` and the
|
||
post-draw partition in the borrowed PView result/diagnostic snapshot;
|
||
- pin viewer-cell versus player-cell roles, portal replacement, login wait,
|
||
fallback/null-root, sealed/SeenOutside, and borrowed scratch reset;
|
||
- preserve allocation-free warmed frames and hysteretic scratch retention.
|
||
|
||
Completed 2026-07-22. `WorldRenderFrameBuilder` now owns the ordered camera,
|
||
visibility, live settings/listener, player-lighting versus collided-viewer root,
|
||
sky/lighting/fog, animated-ID, and building-candidate preparation. Reusable
|
||
animated/building/light-cell collections retain their explicit one-frame
|
||
borrowed lifetime; PView drawable-cell feedback returns through the builder and
|
||
is copied before the renderer reuses its own scratch. The diagnostic sky-PES
|
||
experiment moved to `SkyPesFrameController`, and fog startup overrides now enter
|
||
through typed `RuntimeOptions`. The frame graph is withdrawn before its borrowed
|
||
equipped/effect/audio owners during shutdown. `GameWindow.cs` is 5,715 raw
|
||
lines, 63.6% below the 15,723-line campaign baseline. Twenty-nine focused tests,
|
||
the Release build, and the complete suite pass (7,281 passed / 5 skipped).
|
||
Retail, architecture, and adversarial corrected-diff reviews are clean.
|
||
|
||
### E — typed PView pass executor
|
||
|
||
- replace `Action`/`Func` draw callbacks in `RetailPViewDrawContext`;
|
||
- move landscape early/late, scissor/clip, depth seal/punch, particle passes,
|
||
landscape alpha flush, and PView diagnostics to the executor;
|
||
- add a recording executor test for the complete `DrawInside` call sequence;
|
||
- verify no executor operation rebuilds portal visibility or retains a borrowed
|
||
frame result across calls.
|
||
|
||
Completed 2026-07-22. `RetailPViewRenderer` is now the retail visibility and
|
||
ordering owner only; `RetailPViewPassExecutor` owns the concrete clip upload,
|
||
EnvCell/entity, landscape, portal depth, particle, alpha, and diagnostic pass
|
||
implementations. The old callback bag and broad window closures are gone.
|
||
`WorldRenderDiagnostics` now owns every PView print-on-change signature and
|
||
probe sink, while a focused terrain-diagnostics controller preserves the
|
||
shared five-second terrain/frame publication transaction across fallback and
|
||
PView draws. Real `DrawInside` fixtures cover outdoor, interior-exit,
|
||
no-outside, entity/static/dynamic particle, transparent-shell, look-in, and
|
||
second-call scratch-reset behavior; structural tests pin concrete forwarding,
|
||
no delegate/back-reference leakage, no borrowed frame/result retention, and
|
||
early shutdown withdrawal. `GameWindow.cs` is 5,303 raw lines, 66.3% below the
|
||
15,723-line campaign baseline. Release build and the complete suite pass
|
||
(7,295 passed / 5 skipped). Retail, architecture, and adversarial
|
||
corrected-diff reviews are clean.
|
||
|
||
### F — world scene owner
|
||
|
||
- extract alpha/selection/particle-visibility begin/end and the normal-world
|
||
conditional;
|
||
- extract sky/terrain/null-root fallback and unified PView branches;
|
||
- extract post-world particles/weather and debug collision drawing;
|
||
- return a small `WorldRenderFrameOutcome` for diagnostics/presentation;
|
||
- delete the world draw body and helper closure from `GameWindow`.
|
||
|
||
Completed 2026-07-22. `WorldSceneRenderer` now owns the normal-world
|
||
transaction, one shared-alpha frame, retail selection accumulation, PView versus
|
||
null-root fallback branching, post-world particles/weather, visibility
|
||
publication, and world diagnostics. `WorldScenePassExecutor`, focused runtime
|
||
sources, and `WorldSceneDiagnosticsController` carry the concrete GL and data
|
||
seams without retaining `GameWindow`, delegates, or borrowed PView products.
|
||
Failed frames abort PView, pass routing, particle visibility, alpha, and
|
||
selection in reverse ownership order; one shared `RenderFrameGlStateController`
|
||
restores scissor/stencil/blend/clip/mask/depth/cull/program/buffer state before
|
||
the next clear. Normal portal-depth exits now restore the same cull-off
|
||
convention, and alpha cleanup preserves the original draw failure while
|
||
attempting every source reset. `GameWindow.cs` is 4,765 raw lines, 69.7% below
|
||
the 15,723-line campaign baseline. Release build and the complete suite pass
|
||
(7,313 passed / 5 skipped). Retail, architecture, and adversarial
|
||
corrected-diff reviews are clean.
|
||
|
||
### G — final orchestration cutover
|
||
|
||
- compose concrete resource, world, private-presentation, and diagnostic owners;
|
||
- replace `OnRender` with one `RenderFrameOrchestrator.Render` handoff;
|
||
- remove obsolete fields/helpers/callbacks; prove immediate frame owners retain
|
||
no direct `GameWindow`/anonymous-delegate back-reference, and document rather
|
||
than deny recursive paths through borrowed canonical UI/input owners;
|
||
- preserve the existing shutdown dependency order while making the
|
||
developer-tools backend's pre-existing bootstrap ownership explicit;
|
||
- measure line/field/method counts. Ownership decides completion; the expected
|
||
signal is roughly 5,000–5,500 lines before Slice 8 composition cleanup.
|
||
|
||
Completed 2026-07-22. `GameWindow.OnRender` now creates one value-only
|
||
`RenderFrameInput` and hands the complete frame to `RenderFrameOrchestrator`.
|
||
Focused preparation, world-scene, private-presentation, and diagnostic owners
|
||
preserve the accepted resource → ImGui begin → weather → world → portal →
|
||
paperdoll → retained UI → ImGui submit → screenshot → diagnostics → GPU close
|
||
order. Recovery now closes an active ImGui frame through the owning Silk
|
||
controller and restores the exact text-render GL state after success or
|
||
failure. Screenshot dimensions travel in the frame input rather than through a
|
||
window callback, and immediate frame owners have no direct `GameWindow` or
|
||
anonymous-delegate back-reference. `GameWindow.cs` is 4,666 raw lines / 196
|
||
fields / 70 methods: 11,057 lines (70.3%) below the 15,723-line campaign
|
||
baseline. The Release build and complete suite pass (7,341 passed / 5 skipped),
|
||
and retail-conformance, architecture, and adversarial corrected-diff reviews
|
||
are clean.
|
||
|
||
### H — release and connected gates
|
||
|
||
After three clean corrected-diff reviews:
|
||
|
||
1. run focused App/Core render, PView, alpha, portal, screenshot, and resource
|
||
tests;
|
||
2. run `dotnet build AcDream.slnx -c Release`;
|
||
3. run the complete Release suite;
|
||
4. run `tools/run-connected-world-lifecycle-gate.ps1 -SkipBuild`;
|
||
5. run `tools/run-connected-r6-soak.ps1 -SkipBuild`;
|
||
6. require code-zero graceful exits, exact lifecycle checkpoints/PNGs, no
|
||
fatal/invariant/reveal/pending-resource failures, and unchanged same-location
|
||
resource tolerances;
|
||
7. compare the six existing lifecycle/reconnect PNGs (`capped_login`,
|
||
`aerlinthe_first`, `facility_hub`, `holtburg_after_dungeon`,
|
||
`aerlinthe_revisit`, and `uncapped_reconnect`) with the Slice 6 baseline;
|
||
8. audit architecture, divergence pointers, roadmap, milestones, issues,
|
||
`AGENTS.md`, `CLAUDE.md`, and durable memory.
|
||
|
||
Completed 2026-07-22. The 315.6-second lifecycle/reconnect gate passed at
|
||
`9d7df1bf` with six valid PNG checkpoints, code-zero graceful capped exit, and
|
||
fresh-process uncapped reconnect. Side-by-side comparison with the Slice 6
|
||
artifacts preserved world geometry, UI/paperdoll layering, private viewports,
|
||
and depth/presentation; only live weather, particle timing, authoritative
|
||
vitals, and small scripted camera-settling differences changed. The unchanged
|
||
nine-stop gate then passed in 395.2 seconds with nine materializations, all
|
||
Caul/Holtburg movement exercises, code-zero graceful shutdown, update p95 at
|
||
or below 0.8 ms, and same-location Caul plateau deltas of +85.7 MiB working set
|
||
and +59.3 MiB private memory. Two immediately preceding identical-binary runs
|
||
crossed the coarse process-residency limit while every other deterministic
|
||
lifecycle, timing, and shutdown check passed; #232 records the need to add
|
||
canonical managed/GPU/cache owner snapshots to that gate instead of weakening
|
||
its leak threshold. Release build and the complete suite remain green at 7,341
|
||
passed / 5 skipped. Slice 7 is closed with no new retail divergence.
|
||
|
||
The accepted baseline at docs-only commit `9512404e` is behavior-equivalent to
|
||
production cutover `e91f3102`: 7,182 passed / 5 skipped, 314.195-second
|
||
lifecycle/reconnect, and 393.581-second soak. Exact counters are recorded in
|
||
`memory/project_gamewindow_decomposition.md` and the Slice 6 closeout ledger.
|
||
Building/doorway poses, an open paperdoll, transient portal-exit visuals, and
|
||
#225 remain user visual gates; the stable post-materialization PNGs do not
|
||
overclaim them.
|
||
|
||
## 6. Mandatory review gate
|
||
|
||
After every implementation checkpoint, three read-only reviews run:
|
||
|
||
1. **Retail conformance:** named anchors, PView/alpha/depth/private-viewport/UI
|
||
order, and registered adaptation boundaries.
|
||
2. **Architecture/integration:** focused owner scope, no replacement god object,
|
||
no service locator/back-callback, render-thread mutation, borrowed lifetime,
|
||
GL-state symmetry, and shutdown dependency direction.
|
||
3. **Adversarial:** begin/end failures, missing resources, portal/login
|
||
branches, stale borrowed scratch, callback reentrancy, frame spikes,
|
||
mid-frame resource churn, and GUID/session replacement.
|
||
|
||
The primary agent fixes confirmed findings at their root, then requests
|
||
corrected-diff re-review until clean. Each checkpoint then runs focused tests,
|
||
Release build/full suite, divergence/doc audit, and lands as one commit.
|
||
|
||
## 7. Final acceptance matrix
|
||
|
||
### Automated
|
||
|
||
- exact orchestrator order for normal, login, portal, indoor, outdoor, and
|
||
fallback frames, plus construction-time rejection of missing required phase
|
||
owners;
|
||
- exact GPU begin/end/aggregate failure behavior;
|
||
- PView landscape/look-in/flush/clear/seal/shell/static/dynamics ordering;
|
||
- screenshot after retained UI/ImGui, before title/resource/frame-profile
|
||
diagnostics, and before GPU `EndFrame`;
|
||
- dispatcher frame begin once across world and paperdoll scopes;
|
||
- frame scratch reset/reuse after skipped, portal, normal, and failed frames;
|
||
- no `GameWindow` reference or anonymous draw delegate bag in extracted owners;
|
||
- existing PView replay, shared-alpha, particle visibility, portal, paperdoll,
|
||
GPU-fence, screenshot, resource, and structural suites remain green;
|
||
- Release build and all tests green;
|
||
- connected lifecycle/reconnect and synchronized soak reports pass.
|
||
|
||
### In-client campaign gate
|
||
|
||
- outdoor dense scenes, terrain, sky, weather, particles, and selection match;
|
||
- buildings, doorway look-in/out, depth seals/punches, and dynamics stay stable;
|
||
- sealed dungeons keep correct visibility and lighting;
|
||
- portal replacement and destination reveal preserve the accepted flow;
|
||
- paperdoll, retained gameplay UI, cursor, and ImGui layering are unchanged;
|
||
- no resource growth, GPU reset, render exception, or shutdown regression.
|
||
|
||
## 8. Fixed assumptions
|
||
|
||
- all render/GL mutation remains on the existing render thread;
|
||
- `DatCollection` remains the only DAT reader;
|
||
- `LiveEntityRuntime`, `GpuWorldState`, cell visibility, session, and resource
|
||
owners remain canonical and are not copied;
|
||
- existing render resources are borrowed through Slice 7 and disposed by the
|
||
current shutdown transaction;
|
||
- frame-local results and scratch collections are borrowed until the next
|
||
frame/call unless explicitly copied;
|
||
- no quality/range/performance tradeoff is introduced to make the extraction
|
||
easier;
|
||
- missing optional diagnostic/UI owners skip only their own presentation and
|
||
never suppress world drawing or GPU frame closure.
|