# GameWindow Slice 7 — render-frame orchestration **Status:** Active 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. - [ ] C — extract frame-resource begin/upload/publication and live display, and weather/display foundations that do not depend on camera/root classification. - [ ] 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. - [ ] E — replace `RetailPViewDrawContext`'s callback bag with a typed `RetailPViewPassExecutor` and data-only inputs. - [ ] F — extract `WorldSceneRenderer`, including both shared-alpha scopes, PView/fallback world branches, particles, debug world draw, and completion. - [ ] G — compose `RenderFrameOrchestrator`, cut `GameWindow.OnRender` to one handoff, and delete obsolete frame bodies, fields, helpers, and callbacks. - [ ] 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 Slice 7 collaborators borrow the already-created GL/render owners. They do not dispose them. The existing retryable shutdown transaction 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 without taking shutdown ownership of the borrowed bootstrap. `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. ### 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. ### 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`. ### 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 and prove the transitive render graph has no substantial path back to `GameWindow`; - preserve the existing shutdown resource list without transferring disposal; - measure line/field/method counts. Ownership decides completion; the expected signal is roughly 5,000–5,500 lines before Slice 8 composition cleanup. ### 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. 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.