phase(N.5): roadmap — N.5 shipped, N.6 next

Moves N.5 from in-flight to Shipped (2026-05-08). N.6 (retire
InstancedMeshRenderer + perf polish) becomes the in-flight phase.
CLAUDE.md in-flight pointer updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-08 21:13:49 +02:00
parent 38eb999f2c
commit 77e619d48a
2 changed files with 38 additions and 31 deletions

View file

@ -500,14 +500,17 @@ acdream's plan lives in two files committed to the repo:
acceptance criteria. Do not drift from the spec without explicit user acceptance criteria. Do not drift from the spec without explicit user
approval. approval.
**Currently in flight: Phase N.5 — Modern Rendering Path.** Roadmap entry **Currently in flight: Phase N.6 — Retire legacy renderers + perf polish.**
at [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md). Roadmap entry at [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md).
Builds on N.4's `WbDrawDispatcher` to adopt WB's modern rendering primitives: Builds on N.5. Retires `InstancedMeshRenderer` + `StaticMeshRenderer` entirely.
bindless textures (eliminate `glBindTexture` calls) and Optional candidates: WB atlas adoption, persistent-mapped buffers, GPU-side
`glMultiDrawElementsIndirect` (one GL call per pass instead of one per culling via compute pre-pass, GL_TIME_ELAPSED query double-buffering, direct
group). Together these target a 2-5× CPU win on draw-heavy scenes by N.4 vs N.5 perf measurement. Plan + spec written when work begins.
eliminating the remaining per-group state changes. Plan + spec to be
written when work begins. **Phase N.5 (Modern Rendering Path) shipped 2026-05-08.** `WbDrawDispatcher`
on bindless textures + `glMultiDrawElementsIndirect`. CPU dispatcher 1.23ms/frame
at Holtburg (~810 fps). Plan archived at
[`docs/superpowers/plans/2026-05-08-phase-n5-modern-rendering.md`](docs/superpowers/plans/2026-05-08-phase-n5-modern-rendering.md).
**Phase N.4 (Rendering Pipeline Foundation) shipped 2026-05-08.** WB's **Phase N.4 (Rendering Pipeline Foundation) shipped 2026-05-08.** WB's
`ObjectMeshManager` is integrated and is the default rendering path `ObjectMeshManager` is integrated and is the default rendering path

View file

@ -1,6 +1,6 @@
# acdream — strategic roadmap # acdream — strategic roadmap
**Status:** Living document. Updated 2026-05-08 for Phase N.4 shipping (`WbMeshAdapter` + `WbDrawDispatcher` + `ACDREAM_USE_WB_FOUNDATION` default-on) + N.5 rebranded to "Modern rendering path" (bindless + multi-draw indirect on top of N.4's foundation). **Status:** Living document. Updated 2026-05-08 for Phase N.5 shipping (bindless textures + `glMultiDrawElementsIndirect` on top of N.4's foundation; CPU dispatcher 1.23ms/frame at Holtburg, ~810 fps) + N.6 becomes the new in-flight phase (retire legacy renderers + perf polish).
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file. **Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
--- ---
@ -60,6 +60,7 @@
| N.1 | WorldBuilder-backed scenery (Chorizite/WorldBuilder fork as submodule, SceneryHelpers + TerrainUtils replace our inline ports) | Live ✓ | | N.1 | WorldBuilder-backed scenery (Chorizite/WorldBuilder fork as submodule, SceneryHelpers + TerrainUtils replace our inline ports) | Live ✓ |
| N.3 | WorldBuilder-backed texture decode — `SurfaceDecoder` delegates INDEX16 / P8 / A8R8G8B8 / R8G8B8 / A8(+Additive) to `TextureHelpers.Fill*`; `isAdditive` threaded through (terrain alpha → `FillA8Additive`, non-additive entity surfaces → `FillA8`). R5G6B5 + A4R4G4B4 newly handled (previously magenta). X8R8G8B8, DXT1/3/5, SolidColor remain ours (no WB equivalent). 9 conformance tests prove byte-identical equivalence per format. | Live ✓ | | N.3 | WorldBuilder-backed texture decode — `SurfaceDecoder` delegates INDEX16 / P8 / A8R8G8B8 / R8G8B8 / A8(+Additive) to `TextureHelpers.Fill*`; `isAdditive` threaded through (terrain alpha → `FillA8Additive`, non-additive entity surfaces → `FillA8`). R5G6B5 + A4R4G4B4 newly handled (previously magenta). X8R8G8B8, DXT1/3/5, SolidColor remain ours (no WB equivalent). 9 conformance tests prove byte-identical equivalence per format. | Live ✓ |
| N.4 | Rendering pipeline foundation — adopted WB's `ObjectMeshManager` as the production mesh pipeline behind `ACDREAM_USE_WB_FOUNDATION` (default-on). `WbMeshAdapter` is the single seam (owns `ObjectMeshManager`, drains the staged-upload queue per frame, populates `AcSurfaceMetadataTable` with per-batch translucency / luminosity / fog metadata). `WbDrawDispatcher` is the production draw path: groups all visible (entity, batch) pairs, single-uploads the matrix buffer, fires one `glDrawElementsInstancedBaseVertexBaseInstance` per group with `BaseInstance` slicing into the shared instance VBO. `LandblockSpawnAdapter` + `EntitySpawnAdapter` bridge spawn lifecycle to WB ref-counts (atlas tier vs per-instance). Perf wins shipped as part of N.4: per-entity frustum cull, opaque front-to-back sort, palette-hash memoization (compute once per entity, reuse across batches). Visual verification at Holtburg passed: scenery + connected characters with full close-detail geometry (Issue #47 regression resolved). Legacy `InstancedMeshRenderer` retained as `ACDREAM_USE_WB_FOUNDATION=0` escape hatch until N.6. | Live ✓ | | N.4 | Rendering pipeline foundation — adopted WB's `ObjectMeshManager` as the production mesh pipeline behind `ACDREAM_USE_WB_FOUNDATION` (default-on). `WbMeshAdapter` is the single seam (owns `ObjectMeshManager`, drains the staged-upload queue per frame, populates `AcSurfaceMetadataTable` with per-batch translucency / luminosity / fog metadata). `WbDrawDispatcher` is the production draw path: groups all visible (entity, batch) pairs, single-uploads the matrix buffer, fires one `glDrawElementsInstancedBaseVertexBaseInstance` per group with `BaseInstance` slicing into the shared instance VBO. `LandblockSpawnAdapter` + `EntitySpawnAdapter` bridge spawn lifecycle to WB ref-counts (atlas tier vs per-instance). Perf wins shipped as part of N.4: per-entity frustum cull, opaque front-to-back sort, palette-hash memoization (compute once per entity, reuse across batches). Visual verification at Holtburg passed: scenery + connected characters with full close-detail geometry (Issue #47 regression resolved). Legacy `InstancedMeshRenderer` retained as `ACDREAM_USE_WB_FOUNDATION=0` escape hatch until N.6. | Live ✓ |
| N.5 | Modern rendering path — lifted `WbDrawDispatcher` onto bindless textures (`GL_ARB_bindless_texture`) + `glMultiDrawElementsIndirect`. Per-frame entity rendering: 3 SSBO uploads (instance matrices @ binding=0, batch data @ binding=1, indirect commands) + 2 indirect draw calls (opaque + transparent). ~12-15 GL calls per frame regardless of group count, down from hundreds-of-per-group in N.4. CPU dispatcher: 1.23 ms/frame median at Holtburg courtyard (1662 groups, ~810 fps sustained). All textures on the WB modern path use 1-layer `Texture2DArray` + `sampler2DArray`. Legacy callers keep `Texture2D` / `sampler2D` via the parallel `TextureCache` path until N.6 retires them. Three gotchas captured in memory: texture target lock-in, bindless Dispose order (two-phase non-resident before delete), GL_TIME_ELAPSED double-buffering. Plan archived at `docs/superpowers/plans/2026-05-08-phase-n5-modern-rendering.md`. | Live ✓ |
Plus polish that doesn't get its own phase number: Plus polish that doesn't get its own phase number:
- FlyCamera default speed lowered + Shift-to-boost - FlyCamera default speed lowered + Shift-to-boost
@ -624,22 +625,21 @@ for our deletions/additions; merge upstream `master` periodically.
memoization. Legacy `InstancedMeshRenderer` retained as flag-off memoization. Legacy `InstancedMeshRenderer` retained as flag-off
fallback until N.6 fully retires it. Plan archived at fallback until N.6 fully retires it. Plan archived at
`docs/superpowers/plans/2026-05-08-phase-n4-rendering-foundation.md`. `docs/superpowers/plans/2026-05-08-phase-n4-rendering-foundation.md`.
- **N.5 — Modern rendering path.** **Rebranded from "Terrain rendering" - **✓ SHIPPED — N.5 — Modern rendering path.** Shipped 2026-05-08.
2026-05-08 after N.4 perf review.** N.4 left two big remaining wins **Rebranded from "Terrain rendering" 2026-05-08 after N.4 perf
on the table that pair naturally: (1) bindless textures via review.** Lifted `WbDrawDispatcher` onto bindless textures
`GL_ARB_bindless_texture` (WB already populates (`GL_ARB_bindless_texture`) + `glMultiDrawElementsIndirect`. Per-frame
`ObjectRenderBatch.BindlessTextureHandle`; switch our shader to entity rendering: 3 SSBO uploads (instance matrices @ binding=0, batch
consume per-instance handles, eliminate 100% of `glBindTexture` data @ binding=1, indirect commands) + 2 indirect calls (opaque +
calls), and (2) `glMultiDrawElementsIndirect` (one GL call per pass transparent). ~12-15 GL calls per frame regardless of group count, down
instead of one per group; build a `DrawElementsIndirectCommand` from hundreds-of-per-group in N.4. CPU dispatcher: 1.23 ms/frame median
buffer, fire one indirect draw, the driver pulls everything). Both at Holtburg (1662 groups, ~810 fps). All textures on the modern path use
require shader changes (same shader, in fact — bindless + indirect 1-layer `Texture2DArray` + `sampler2DArray`; legacy callers retain
are the same modern path WB uses internally). Together they target a `Texture2D` via the parallel `TextureCache` path until N.6 retires them.
2-5× CPU win on draw-heavy scenes (Holtburg courtyard, Foundry, Three gotchas in memory (`project_phase_n5_state.md`): texture target
dense dungeons). Also folds in: persistent-mapped instance VBO lock-in, bindless Dispose two-phase order, GL_TIME_ELAPSED double-
(`glBufferStorage` + `MAP_PERSISTENT_BIT | MAP_COHERENT_BIT` + ring buffering. Plan archived at
buffer + sync) and texture pre-warm at landblock load (smooths `docs/superpowers/plans/2026-05-08-phase-n5-modern-rendering.md`.
streaming-boundary hitches). **Estimate: 2-3 weeks.**
- **N.5b — Terrain rendering on N.5 path.** Wire WB's - **N.5b — Terrain rendering on N.5 path.** Wire WB's
`TerrainRenderManager` + `LandSurfaceManager` + `TerrainGeometryGenerator` `TerrainRenderManager` + `LandSurfaceManager` + `TerrainGeometryGenerator`
onto the modern rendering path. Closes N.2's deferred terrain math onto the modern rendering path. Closes N.2's deferred terrain math
@ -647,12 +647,16 @@ for our deletions/additions; merge upstream `master` periodically.
`CalculateSplitDirection` + `GetHeight` + `GetNormal` in lockstep, `CalculateSplitDirection` + `GetHeight` + `GetNormal` in lockstep,
resolving ISSUE #51. **Estimate: 1-2 weeks** (was 2-3 — modern path resolving ISSUE #51. **Estimate: 1-2 weeks** (was 2-3 — modern path
primitives already in place from N.5). primitives already in place from N.5).
- **N.6 — Static objects rendering.** Wire WB's - **N.6 — Retire legacy renderers + perf polish.** **Currently in flight.**
`StaticObjectRenderManager` onto the modern rendering path; **fully Builds on N.5. Retires `InstancedMeshRenderer` + `StaticMeshRenderer`
delete** legacy `StaticMeshRenderer` + `InstancedMeshRenderer` (they entirely — they remain as `ACDREAM_USE_WB_FOUNDATION=0` escape hatches
remain as `ACDREAM_USE_WB_FOUNDATION=0` escape hatches through N.5). through N.5 but are deleted when N.6 ships. Optional N.6 candidates: WB
Mostly draw orchestration at this point — most of the substance atlas adoption for memory savings on shared content, persistent-mapped
landed in N.4 + N.5. **Estimate: 1-2 weeks** (was 2-3). buffers if `glBufferData` shows up in profiling, GPU-side culling via
compute pre-pass, GL_TIME_ELAPSED query double-buffering (deferred from
N.5 — diagnostic shows `gpu_us=0/0` under `ACDREAM_WB_DIAG=1`), direct
N.4 vs N.5 perf measurement. Plan + spec written when work begins.
**Estimate: 1-2 weeks** (was 2-3).
- **N.7 — EnvCells / dungeons.** Replace EnvCell rendering with WB's - **N.7 — EnvCells / dungeons.** Replace EnvCell rendering with WB's
`EnvCellRenderManager` + `PortalRenderManager` on top of N.4's `EnvCellRenderManager` + `PortalRenderManager` on top of N.4's
foundation. **Estimate: 1-2 weeks** (was 2-3 — naturally smaller now foundation. **Estimate: 1-2 weeks** (was 2-3 — naturally smaller now