From a28a5b75832fbdd09f30411d70ad8ddc5fddbca2 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 10 May 2026 10:06:26 +0200 Subject: [PATCH] docs(A.5 T27): spec + plan amendments for T22.5 + ship MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spec (2026-05-09-phase-a5-two-tier-streaming-design.md): - §2 acceptance metrics reshaped from absolute 240 FPS to refresh-rate-relative + per-preset (95th-pct ≤ 1000ms/refresh standstill; ≤ 1.5× walking) to match the Quality Preset reality. - New §4.10 Quality Preset System (T22.5): enum Low/Medium/High/Ultra, QualitySettings schema, canonical preset values table, env-var override table, wiring notes (GameWindow.OnLoad + ReapplyQualityPreset), MSAA mid-session unsupported caveat, file list, test count (12). - New §11 What was deferred: 8 items (Tier 1 cache, lifestone, JobKind plumbing, Tier 2/3, ToEntries alloc, InvalidateEntity wiring, High preset retest). Former §11 References renumbered to §12. Plan (2026-05-09-phase-a5-two-tier-streaming.md): - New Task 22.5 section inserted between T22 and T23: full inline spec with schema, preset table, env-var list, wiring steps, acceptance criteria, deferred items, commit SHAs. Includes file-name corrections (SettingsState → DisplaySettings, DisplayTab → SettingsPanel). - Self-review cross-check table: new §4.10 row pointing at T22.5. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-09-phase-a5-two-tier-streaming.md | 70 ++++++++ ...5-09-phase-a5-two-tier-streaming-design.md | 166 ++++++++++++++++-- 2 files changed, 224 insertions(+), 12 deletions(-) diff --git a/docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md b/docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md index 275b0cf..a53d596 100644 --- a/docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md +++ b/docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md @@ -2046,6 +2046,75 @@ git commit -m "feat(A.5 T22): fog params wired from N₁/N₂ + ACDREAM_FOG_*_MU --- +## Task 22.5 (NEW — Quality Preset System) + +**Inserted between T22 (fog wiring) and T23 (DIAG budgets). Added mid-execution at user's direction. Estimate: ~1 day.** + +**Background:** User added this task between T22 and T23 with a complete inline spec. Shipped as commits `afa4200` (schema + tests) and `28d2c60` (wiring). Design spec at §4.10 of the A.5 spec doc. + +**Files:** +- Create: `src/AcDream.UI.Abstractions/Settings/QualityPreset.cs` +- Modify: `src/AcDream.UI.Abstractions/Settings/DisplaySettings.cs` (add `Quality` field) + - NOTE: `SettingsState.cs` (from the original inline spec) did not exist; `Quality` went onto `DisplaySettings` instead — the natural home for display-related settings. +- Modify: `src/AcDream.UI.Abstractions/Panels/Settings/SettingsPanel.cs` (Display tab Quality dropdown) + - NOTE: the original inline spec named `DisplayTab.cs`; the actual file is `SettingsPanel.cs` with a `RenderDisplayTab` method. Same intent, different file name. +- Modify: `src/AcDream.App/Rendering/GameWindow.cs` (apply preset on launch + on mid-session change via `ReapplyQualityPreset`) +- Create: `tests/AcDream.UI.Abstractions.Tests/Settings/QualityPresetTests.cs` + +**Schema:** + +```csharp +public enum QualityPreset { Low, Medium, High, Ultra } + +public readonly record struct QualitySettings( + int NearRadius, int FarRadius, + int MsaaSamples, int AnisotropicLevel, + bool AlphaToCoverage, + int MaxCompletionsPerFrame); +``` + +`QualitySettings.From(preset)` returns canonical values per preset: + +| Preset | NearRadius | FarRadius | MsaaSamples | AnisotropicLevel | AlphaToCoverage | MaxCompletionsPerFrame | +|---|---|---|---|---|---|---| +| Low | 2 | 5 | 0 | 4 | false | 2 | +| Medium | 3 | 8 | 2 | 8 | false | 3 | +| High | 4 | 12 | 4 | 16 | true | 4 | +| Ultra | 5 | 15 | 4 | 16 | true | 6 | + +`QualitySettings.WithEnvOverrides(baseSettings)` applies per-field env-var overrides: +`ACDREAM_NEAR_RADIUS`, `ACDREAM_FAR_RADIUS`, `ACDREAM_MSAA_SAMPLES`, +`ACDREAM_ANISOTROPIC`, `ACDREAM_A2C`, `ACDREAM_MAX_COMPLETIONS_PER_FRAME`. + +**Wiring:** + +1. `DisplaySettings.Quality` persists via the existing `settings.json` infrastructure (Phase L.0). +2. `SettingsPanel.RenderDisplayTab` Combo widget for Quality dropdown. +3. `GameWindow.OnLoad` applies preset: streamer + controller built with preset's + `NearRadius`/`FarRadius`; `TerrainAtlas.SetAnisotropic` from preset; `WindowOptions.Samples` + from preset (window creation time only); `WbDrawDispatcher.AlphaToCoverage` from preset; + `StreamingController.MaxCompletionsPerFrame` from preset. +4. Env-var overrides applied per field via `WithEnvOverrides`; logged at startup. +5. Mid-session change via F11 → Quality dropdown → `ReapplyQualityPreset` rebuilds the + streaming pipeline. MSAA samples mid-session change is structurally unsupported + (OpenGL requires window recreation); logs a warning. + +**Acceptance criteria (as shipped):** + +- Standstill: at user's selected preset, 95% of frames hit ≤ (1000ms / monitor refresh). +- Walking: 95% ≤ 1.5× (1000ms / monitor refresh). +- Visual gate: same on all presets. + +**Out of scope (deferred):** + +- Auto-detect first-launch preset (Phase A.6 / N.6.5). +- Adaptive runtime preset drop on budget miss. +- Per-feature toggles below preset level. + +**Commits:** `afa4200` (schema + tests), `28d2c60` (wiring). + +--- + ## Task 23: Per-subsystem regression budget logging in DIAG output **Files:** @@ -2429,6 +2498,7 @@ Spec coverage cross-check: | §4.6 Bucketing Change #3 (sub-LB cull) | conditional — added as T18.5 only if Tasks 17+18 don't hit 2.0ms budget | | §4.7 TerrainModernRenderer | T15 (AddLandblockWithMesh entry); no structural change | | §4.8 Fog tuning | T22 | +| §4.10 Quality Preset System (NEW — mid-execution addition) | T22.5 | | §4.9.1 Mipmaps | T19 | | §4.9.2 A2C with MSAA | T20 | | §4.9.3 Depth-write audit | T21 | diff --git a/docs/superpowers/specs/2026-05-09-phase-a5-two-tier-streaming-design.md b/docs/superpowers/specs/2026-05-09-phase-a5-two-tier-streaming-design.md index 44ed02a..eaf92ca 100644 --- a/docs/superpowers/specs/2026-05-09-phase-a5-two-tier-streaming-design.md +++ b/docs/superpowers/specs/2026-05-09-phase-a5-two-tier-streaming-design.md @@ -37,21 +37,21 @@ The headline win: walking around Holtburg, the user sees a real horizon - 240 Hz @ 2560×1440 (verified via `Get-CimInstance Win32_VideoController`). - Frame budget: **4.166 ms** at vsync. -### Acceptance metrics (Q9 Option B — tiered) +### Acceptance metrics (as shipped — revised with Quality Preset system) 1. **Build green; existing tests still green.** N.5b conformance sentinel passes (visual mesh Z = TerrainSurface.SampleZ within 1 mm). -2. **Standstill at Holtburg dueling field, 30 s with `[WB-DIAG]` and `[TERRAIN-DIAG]`:** - - Median frame time ≤ 4.166 ms (240 FPS sustained). - - p99 ≤ 4.5 ms (no vsync misses). -3. **Walking Holtburg → North Yanshi at run speed, 60 s trace:** - - Median ≥ 144 FPS (≤ 6.94 ms). - - p95 ≥ 120 FPS (≤ 8.33 ms). +2. **Standstill at user's selected preset on user's hardware:** + - 95% of frames hit ≤ (1000ms / monitor refresh rate). + - No absolute FPS number is required — the Quality Preset system (§4.10) + is the user's knob for trading quality vs frame budget. +3. **Walking at user's selected preset:** + - 95% of frames hit ≤ 1.5× (1000ms / monitor refresh rate). 4. **First traversal into virgin region (cold mesh cache):** - - Render thread frame time stays ≤ 8.33 ms throughout while the worker - fills the far-tier horizon (~2.7 s of "horizon filling in" is OK). -5. **Visual gate (user-driven):** user launches the client, walks - Holtburg → North Yanshi, and confirms: + - Render thread frame time stays within 2× the standstill budget while + the worker fills the far-tier horizon (~2.7 s of "horizon filling in" is OK). +5. **Visual gate (user-driven, same on all presets):** user launches the + client, walks Holtburg → North Yanshi, and confirms: - Horizon visible at ~2.3 km. - Fog blend at N₁ smooths the scenery boundary (no harsh cliff). - Distant terrain does not shimmer (mipmaps work). @@ -433,6 +433,106 @@ pass (it is, per `IsOpaque` returning true for ClipMap at line 738). If audit finds nothing wrong, ship a comment + a unit test that locks in the partition. Cheap insurance against future regression. +### 4.10 Quality Preset System (T22.5 — added mid-execution) + +**Background:** Added between T22 (fog wiring) and T23 (DIAG budgets) at +user's direction. The original spec had no preset concept; §2 was written +against absolute 240 FPS on fixed N₁/N₂. T22.5 makes both radii and every +quality knob user-controllable via a single enum. §2 was amended above to +reflect the per-preset, refresh-rate-relative acceptance criteria. + +#### Schema + +```csharp +public enum QualityPreset { Low, Medium, High, Ultra } + +public readonly record struct QualitySettings( + int NearRadius, + int FarRadius, + int MsaaSamples, + int AnisotropicLevel, + bool AlphaToCoverage, + int MaxCompletionsPerFrame); +``` + +`QualitySettings.From(preset)` returns the canonical values: + +| Preset | NearRadius | FarRadius | MsaaSamples | AnisotropicLevel | AlphaToCoverage | MaxCompletionsPerFrame | +|---|---|---|---|---|---|---| +| Low | 2 | 5 | 0 | 4 | false | 2 | +| Medium | 3 | 8 | 2 | 8 | false | 3 | +| High | 4 | 12 | 4 | 16 | true | 4 | +| Ultra | 5 | 15 | 4 | 16 | true | 6 | + +`QualitySettings.WithEnvOverrides(baseSettings)` applies per-field env-var +overrides (see §4.10.3). + +#### Persistence and UI + +`DisplaySettings.Quality` (type `QualityPreset`) persists via the existing +`settings.json` infrastructure (Phase L.0). The Settings panel (F11) exposes +a Quality dropdown in its Display tab (`SettingsPanel.RenderDisplayTab`). + +#### Wiring (GameWindow.OnLoad + ReapplyQualityPreset) + +1. `GameWindow.OnLoad` resolves the active `QualitySettings`: + `QualitySettings.From(displaySettings.Quality).WithEnvOverrides(...)`. +2. `StreamingController` and `LandblockStreamer` are built with the preset's + `NearRadius` / `FarRadius`. +3. `TerrainAtlas.SetAnisotropic(settings.AnisotropicLevel)` called once at + load and again on reapply. +4. `WindowOptions.Samples = settings.MsaaSamples` applied at window creation + time only (MSAA mid-session change is structurally unsupported by OpenGL). +5. `WbDrawDispatcher.AlphaToCoverage = settings.AlphaToCoverage`. +6. `StreamingController.MaxCompletionsPerFrame = settings.MaxCompletionsPerFrame`. + +Mid-session quality change (F11 dropdown change → Save): + +- `GameWindow.ReapplyQualityPreset` rebuilds `StreamingController` + + `LandblockStreamer` with the new radii, re-applies anisotropic and + AlphaToCoverage. +- If `MsaaSamples` changed, logs a warning that MSAA sample count cannot be + changed mid-session; requires restart. + +#### Env-var overrides (§4.10.3) + +Applied by `QualitySettings.WithEnvOverrides` after the base preset is resolved. +Each field has one env var; all are optional. Logged at startup. + +| Env var | Field overridden | +|---|---| +| `ACDREAM_NEAR_RADIUS` | `NearRadius` | +| `ACDREAM_FAR_RADIUS` | `FarRadius` | +| `ACDREAM_MSAA_SAMPLES` | `MsaaSamples` | +| `ACDREAM_ANISOTROPIC` | `AnisotropicLevel` | +| `ACDREAM_A2C` | `AlphaToCoverage` (1/0/true/false) | +| `ACDREAM_MAX_COMPLETIONS_PER_FRAME` | `MaxCompletionsPerFrame` | + +#### Tests + +12 tests in `tests/AcDream.UI.Abstractions.Tests/Settings/QualityPresetTests.cs` +cover: canonical preset values per enum member; `WithEnvOverrides` no-op when +no env vars set; `WithEnvOverrides` each override individually; invalid env-var +value falls back to base setting. + +#### Files + +- `src/AcDream.UI.Abstractions/Settings/QualityPreset.cs` — new +- `src/AcDream.UI.Abstractions/Settings/DisplaySettings.cs` — `Quality` field added +- `src/AcDream.UI.Abstractions/Panels/Settings/SettingsPanel.cs` — Display tab + Quality dropdown (`RenderDisplayTab` method) +- `src/AcDream.App/Rendering/GameWindow.cs` — `ReapplyQualityPreset`, + `OnLoad` preset wiring +- `tests/AcDream.UI.Abstractions.Tests/Settings/QualityPresetTests.cs` — new (12 tests) + +#### Out of scope (deferred) + +- Auto-detect preset on first launch (Phase A.6 / N.6.5). +- Adaptive runtime preset drop on budget miss. +- Per-feature toggles below preset level. + +Commits: `afa4200` (schema + tests), `28d2c60` (wiring). + --- ## 5. Data flow @@ -668,7 +768,49 @@ Per the brainstorm Q10 confirmation: --- -## 11. References +## 11. What was deferred (post-A.5) + +The following items were identified during A.5 development but deferred to +post-A.5 phases. They are tracked as OPEN issues in `docs/ISSUES.md`. + +1. **Tier 1 entity-classification cache** (commit `3639a6f` reverted at + `9b49009`): First attempt cached `meshRef.PartTransform` which is mutated + per frame for animated entities (skeletal pose). Next attempt needs: + (a) audit AnimationSequencer + AnimationHookRouter to identify ALL + per-frame mutations of MeshRef state; (b) redesign cache to bypass + animated entities OR cache only the animation-invariant subset; (c) test + specifically with a moving animated NPC on screen. (`docs/ISSUES.md` #53) + +2. **Lifestone missing visual**: The Holtburg lifestone has not rendered since + earlier in A.5 development. Possibly Bug A's far-tier strip incorrectly + catching a near-tier entity, or a separate earlier regression. + (`docs/ISSUES.md` #52) + +3. **Plumb JobKind through BuildLandblockForStreaming**: Bug A's fix (commit + `9217fd9`) strips entities post-load in the worker. Proper fix: skip the + `LandBlockInfo` + scenery load entirely for far-tier jobs. ~30 min. + (`docs/ISSUES.md` #54) + +4. **Tier 2 — Static/dynamic split with persistent groups**: ~2-week phase. + Avoids per-frame entity re-classification by maintaining stable groups + keyed at spawn time. Roadmap doc at + `docs/plans/2026-05-10-perf-tiers-2-3-roadmap.md`. + +5. **Tier 3 — GPU-side culling via compute pre-pass**: ~1-month phase. + Same roadmap doc. + +6. **Eliminate ToEntries adapter allocation**: tiny win (~25 KB/frame). + +7. **InvalidateEntity wiring on palette/ObjDesc events**: needed by the + Tier 1 retry. + +8. **Visual gate at full High preset**: never validated due to the + GPU+CPU stack-up OS crash earlier in A.5. With Bug A fixed the crash + likely won't recur; defer retest to post-A.5 perf polish. + +--- + +## 12. References (formerly §11) - **Handoff (cold-start):** [`docs/research/2026-05-10-phase-a5-handoff.md`](../../research/2026-05-10-phase-a5-handoff.md) - **N.5b handoff (predecessor):** [`docs/research/2026-05-09-phase-n5b-handoff.md`](../../research/2026-05-09-phase-n5b-handoff.md)