docs(render): V11 closeout — register, architecture, code structure, issues

Retires the GL framing from the documents that described a two-backend,
two-UI-stack client, and files what the deletion left behind.

Divergence register:
  * AD-46 (anisotropic tap pattern in dense alpha scenery) is REFRAMED rather
    than retired. Its substance survives -- distant foliage may read denser
    than retail's -- but it was measured GL-vs-Vulkan, and with GL gone it is
    a Vulkan-vs-retail question against the D3D oracle it already cited. The
    measurement is kept as the evidence that the residual is a driver tap
    pattern; the row now records that it is no longer falsifiable by
    self-differential, which is a real loss the deletion causes.
  * AD-47 and AD-48 are NEW, and the campaign's own risk register scheduled
    them here: MSAA sample positions (measured at 8.83% of the frame at 4x,
    which is why every strict gate runs MSAA off -- and therefore why a
    regression confined to the multisample path would not be caught) and
    present pacing (#235 is the live instance).
  * AD-17's justification moves from a GL clip-plane citation to Vulkan's
    maxClipDistances floor, which is the same 8, so the divergence is
    unchanged and only its authority moves.
  * AP-92 keeps IUiViewportRenderer.TextureIsBottomUp rather than folding it
    flat, because it is what let the origin question be answered by data.

Architecture and code structure: the layer diagram, the frame order, the
residency vocabulary and the reference table all said OpenGL. The UI section
said two stacks. Rule 3's rationale is rewritten around what actually
happened -- ImGui was deleted and not one panel, ViewModel or command had to
change, because none of them had ever imported ImGuiNET. That is the rule
paying for itself, so it is recorded as evidence rather than removed as
obsolete.

Issues: #258 files the dev-panel host as a decision rather than an accident,
and #255 is REOPENED. Its TaskCreationOptions.LongRunning fix asks the
scheduler for a thread but does not promise two callbacks overlap; under nine
concurrent test assemblies it still failed 2 of 5 whole-suite runs. The
earlier evidence tested a narrower pool, not a contended one. The fix it
needs is a rendezvous inside the read stub -- not a weakened assertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-29 03:20:04 +02:00
parent 5852bdb877
commit c265b52d4b
5 changed files with 143 additions and 62 deletions

View file

@ -18,7 +18,7 @@ from WB vs port ourselves).
## 1. The structural problem we're solving
The layered architecture works: `AcDream.Core` is GL-free, the network
The layered architecture works: `AcDream.Core` is backend-free, the network
layer is wire-compatible, the UI has a stable contract, plugins load.
The structural debt is concentrated in **one file**:
@ -42,7 +42,7 @@ after Slice 8 checkpoint K 1,622 lines / canonical soak shell
At the campaign baseline, `GameWindow` was the single object that:
- Owns the GL context, the window, input, and shaders.
- Owns the Vulkan device, the window, input, and shaders.
- Reads ~40 different environment variables across its lifetime.
- Composes the shipped `LiveSessionController`/host/router boundary; it no
longer owns a parallel session, command bus, subscription lifetime, connect,
@ -90,34 +90,40 @@ you find yourself adding a 200-line method to `GameWindow`, stop and
extract.
**Exemption:** Trivial wiring that *must* stay in `GameWindow` because
it touches GL state during `OnLoad` is acceptable, but should still
it touches device state during `OnLoad` is acceptable, but should still
delegate to a collaborator for the substance.
### Rule 2: `AcDream.Core` must not depend on window / GL / backend projects
### Rule 2: `AcDream.Core` must not depend on window / backend projects
**Why:** Core is the GL-free, testable layer. The moment Core imports
a GL or windowing namespace, we've lost the ability to test it without
a graphics context, and the layer split becomes fiction.
**Why:** Core is the backend-free, testable layer. The moment Core imports
a graphics or windowing namespace, we've lost the ability to test it without
a device, and the layer split becomes fiction.
**How to apply:** Phase O removed both external WorldBuilder/backend project
references. The only currently allowed seams are the GL-free helpers owned in
references. The only currently allowed seams are the backend-free helpers owned in
our tree under `src/AcDream.Core/Rendering/Wb/`: `TerrainUtils`,
`TerrainEntry`, `RegionInfo`, `SceneryHelpers`, and `TextureHelpers`.
`ObjectMeshManager` and every GL resource owner remain in App. If Core needs a
`ObjectMeshManager` and every GPU resource owner remain in App. If Core needs a
new capability, define a narrow Core interface and implement it in App; adding
a new project reference requires an inventory-doc update explaining why.
### Rule 3: UI panels target `AcDream.UI.Abstractions` only
**Why:** This is the one rule that keeps D.2b (the future retail-look
backend) viable. Every panel that imports `ImGuiNET` directly is a panel
we'd have to rewrite when the backend swaps.
**Why:** The rule was written to keep D.2b (the retail-look backend)
viable while ImGui was still the developer stack, and **it paid off**: when
Campaign V slice V11 deleted ImGui on 2026-07-29, not one panel contract,
ViewModel or command had to change, because none of them had ever imported
`ImGuiNET`. `AcDream.UI.Abstractions` survived a backend deletion intact.
**How to apply:** A panel's `using` block must mention
`AcDream.UI.Abstractions.*` and nothing from `AcDream.UI.ImGui`. The
panel writes against `IPanelRenderer`. The `ImGuiPanelRenderer`
translates those calls to ImGui at runtime. Plugin-facing UI follows the
same rule.
`AcDream.UI.Abstractions.*` and nothing from any backend assembly. The panel
writes against `IPanelRenderer`; a renderer implementation translates those
calls at runtime. Plugin-facing UI follows the same rule.
**Status:** there is currently no `IPanelRenderer` implementation in the tree —
the ImGui one went with V11 and the replacement is issue **#258**. The contract
is kept rather than deleted precisely because this rule proved its worth; a new
host binds to it without touching a single panel.
### Rule 4: Startup env vars enter through `RuntimeOptions`
@ -173,7 +179,7 @@ Today:
`tests/AcDream.App.Tests/` now exists and owns App-layer controller, streaming,
render-resource lifetime, retained-UI, and `RuntimeOptions` tests. New App tests
belong there; do not place GL-free Core behavior in that project merely because
belong there; do not place backend-free Core behavior in that project merely because
App currently wires it.
---
@ -228,7 +234,7 @@ src/AcDream.App/
├── Program.cs # parse args + env → RuntimeOptions, build GameWindow
├── RuntimeOptions.cs # typed startup options (Rule 4)
├── Rendering/
│ ├── GameWindow.cs # thin: GL/window lifecycle + delegates per-frame to RenderFrameOrchestrator
│ ├── GameWindow.cs # thin: device/window lifecycle + delegates per-frame to RenderFrameOrchestrator
│ ├── RenderFrameOrchestrator.cs # GPU-flight boundary + typed world/private/UI render phases
│ ├── LiveEntityAnimationScheduler.cs # shipped: ordinary live-object update workset
│ ├── LiveEntityAnimationPresenter.cs # final part-pose/mesh/effect composition after scheduler output
@ -284,10 +290,10 @@ src/AcDream.App/
What `GameWindow` keeps:
- `IWindow` / `GL` / `IInputContext` lifecycle (constructor + `OnLoad` +
- `IWindow` / device / `IInputContext` lifecycle (constructor + `OnLoad` +
`Run` + `OnClosing`).
- `RuntimeOptions` reference (the typed startup config).
- GL resource construction and top-level collaborator composition. Construction
- GPU resource construction and top-level collaborator composition. Construction
is allowed here; feature algorithms and mutable subsystem state are not.
- One field per top-level collaborator (`_liveSessionController`,
`_liveEntityRuntime`, `_selectionInteraction`, `_streamingPresentation`,
@ -480,7 +486,7 @@ useful ordering seam, but its ownership status is **partial**.
| Landblock presentation | **Complete** | `LandblockBuildFactory` owns the captured-origin DAT transaction; concrete render/physics/DAT-static publishers and `LandblockPresentationPipeline` own typed-meter publication and exact retryable retirement. `StreamingController` owns stable destination/control/unload/Near/Far queues and destination reservation. CPU mesh-cache restaging requires an exact live owner. `StreamingOriginRecenterCoordinator` serializes old-window retirement with teleport/session origin lifetimes. `GameWindow` retains construction and one pipeline field only (`c79d0a49`, closeout `4a205a3e`; Slice E closeout `91e82c3c`). |
| Render-frame orchestration | **Complete** | `RenderFrameOrchestrator` owns the GPU-flight, resource, world/PView/shared-alpha, private-presentation, diagnostics, screenshot, and recovery graph. `GameWindow.OnRender` takes one logical window-size snapshot and performs one immutable handoff (`9d7df1bf`). |
| Unified `GameEntity` | **Slice J complete** | Canonical identity, retained-object lifetime, direct views, ordered entity/object deltas, gameplay state, action/combat/magic/movement/physics/remote/projectile simulation, world environment, reveal/transit truth, and host acknowledgement share failure-safe Runtime owners while exact graphical sidecars stay in App. One `GameRuntime` composes the graph. `RuntimeGenerationReset` is the sole retryable canonical-generation reset for graphical and no-window hosts; the deterministic direct host proves lifecycle, commands, portal, reconnect, GUID reuse, fault recovery, isolation, and terminal convergence without presentation assemblies (`a9a822f2`). |
| Headless host | **Slice K complete** | `AcDream.Headless` references only Runtime and loads no App/UI/GL/window/audio assembly. Portable paths/config/credentials, deterministic command/event scheduling, shared immutable content, exact per-session identity, failure quarantine, reconnect, resource telemetry, 1/5/10/30-session isolation, two-hour simulated endurance, and the exact two-account native-Linux connected soak pass through `776482da`. |
| Headless host | **Slice K complete** | `AcDream.Headless` references only Runtime and loads no App/UI/graphics/window/audio assembly. Portable paths/config/credentials, deterministic command/event scheduling, shared immutable content, exact per-session identity, failure quarantine, reconnect, resource telemetry, 1/5/10/30-session isolation, two-hour simulated endurance, and the exact two-account native-Linux connected soak pass through `776482da`. |
### 4.3 Revised extraction sequence
@ -687,7 +693,7 @@ Detailed execution ledger:
(complete).
Move the complete draw graph and its reusable frame-local scratch state into a
GL-owning App collaborator. Preserve the exact modern pipeline order, clip
GPU-owning App collaborator. Preserve the exact modern pipeline order, clip
routing, PView flood, landscape/opaque/shared-alpha flush boundaries,
particles, debug draw, paperdoll, retained UI, and frame fences. Do not pass a
hundred individual delegates or let the orchestrator reach back into
@ -715,7 +721,7 @@ residency without weakening leak detection.
Detailed execution ledger:
[`docs/plans/2026-07-22-gamewindow-slice-8-composition-lifecycle.md`](../plans/2026-07-22-gamewindow-slice-8-composition-lifecycle.md).
Keep GL/window construction in `GameWindow.OnLoad`, but group creation into
Keep device/window construction in `GameWindow.OnLoad`, but group creation into
small composition functions and delete feature state left behind by prior
slices. `OnClosing` delegates to the existing retryable shutdown transaction.
Silk callbacks become narrow calls into the input, update, render, resize,
@ -745,14 +751,14 @@ Gameplay draft fields when combat preferences change. `GameWindow` is now 3,663
raw lines / 162 fields / 37 methods at G. H adds sole lifetime roots for the
terrain atlas and dedicated sky shader, one retained Host/runtime lease, an
atomic update/render frame-root slot, and a prepare-aware portal fallback and
transfer slot. GL construction and state mutations now use checked commit
transfer slot. GPU construction and state mutations now use checked commit
boundaries with exact retry ownership for failed names, bindless residency,
and texture-binding restoration. `GameWindow` is 3,689 raw lines / 162 fields /
37 methods at H. Checkpoint I.1I.5 now provide the executable nine-phase
oracle, platform/host/content/settings phases, and the production world/render
phase. `WorldRenderCompositionPhase` owns Region/environment, the mandatory
modern-renderer foundation, immutable terrain-worker inputs, and WB/texture/
sampler construction; every Phase-4 GL constructor has retryable prefix
sampler construction; every Phase-4 GPU constructor has retryable prefix
ownership. `GameWindow` is 3,522 raw lines after I.5. I.6 moves interaction,
retained UI, live presentation, and landblock publication into ordered
composition phases. Typed exact-owner sources bridge later session,