diff --git a/CLAUDE.md b/CLAUDE.md index e54d0fb..e6d0b27 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -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 approval. -**Currently in flight: Phase N.5 — Modern Rendering Path.** 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: -bindless textures (eliminate `glBindTexture` calls) and -`glMultiDrawElementsIndirect` (one GL call per pass instead of one per -group). Together these target a 2-5× CPU win on draw-heavy scenes by -eliminating the remaining per-group state changes. Plan + spec to be -written when work begins. +**Currently in flight: Phase N.6 — Retire legacy renderers + perf polish.** +Roadmap entry at [`docs/plans/2026-04-11-roadmap.md`](docs/plans/2026-04-11-roadmap.md). +Builds on N.5. Retires `InstancedMeshRenderer` + `StaticMeshRenderer` entirely. +Optional candidates: WB atlas adoption, persistent-mapped buffers, GPU-side +culling via compute pre-pass, GL_TIME_ELAPSED query double-buffering, direct +N.4 vs N.5 perf measurement. Plan + spec 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 `ObjectMeshManager` is integrated and is the default rendering path diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index 8fc303d..43623cf 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -1,6 +1,6 @@ # 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. --- @@ -60,6 +60,7 @@ | 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.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: - 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 fallback until N.6 fully retires it. Plan archived at `docs/superpowers/plans/2026-05-08-phase-n4-rendering-foundation.md`. -- **N.5 — Modern rendering path.** **Rebranded from "Terrain rendering" - 2026-05-08 after N.4 perf review.** N.4 left two big remaining wins - on the table that pair naturally: (1) bindless textures via - `GL_ARB_bindless_texture` (WB already populates - `ObjectRenderBatch.BindlessTextureHandle`; switch our shader to - consume per-instance handles, eliminate 100% of `glBindTexture` - calls), and (2) `glMultiDrawElementsIndirect` (one GL call per pass - instead of one per group; build a `DrawElementsIndirectCommand` - buffer, fire one indirect draw, the driver pulls everything). Both - require shader changes (same shader, in fact — bindless + indirect - are the same modern path WB uses internally). Together they target a - 2-5× CPU win on draw-heavy scenes (Holtburg courtyard, Foundry, - dense dungeons). Also folds in: persistent-mapped instance VBO - (`glBufferStorage` + `MAP_PERSISTENT_BIT | MAP_COHERENT_BIT` + ring - buffer + sync) and texture pre-warm at landblock load (smooths - streaming-boundary hitches). **Estimate: 2-3 weeks.** +- **✓ SHIPPED — N.5 — Modern rendering path.** Shipped 2026-05-08. + **Rebranded from "Terrain rendering" 2026-05-08 after N.4 perf + review.** 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 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 (1662 groups, ~810 fps). All textures on the modern path use + 1-layer `Texture2DArray` + `sampler2DArray`; legacy callers retain + `Texture2D` via the parallel `TextureCache` path until N.6 retires them. + Three gotchas in memory (`project_phase_n5_state.md`): texture target + lock-in, bindless Dispose two-phase order, GL_TIME_ELAPSED double- + buffering. Plan archived at + `docs/superpowers/plans/2026-05-08-phase-n5-modern-rendering.md`. - **N.5b — Terrain rendering on N.5 path.** Wire WB's `TerrainRenderManager` + `LandSurfaceManager` + `TerrainGeometryGenerator` 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, resolving ISSUE #51. **Estimate: 1-2 weeks** (was 2-3 — modern path primitives already in place from N.5). -- **N.6 — Static objects rendering.** Wire WB's - `StaticObjectRenderManager` onto the modern rendering path; **fully - delete** legacy `StaticMeshRenderer` + `InstancedMeshRenderer` (they - remain as `ACDREAM_USE_WB_FOUNDATION=0` escape hatches through N.5). - Mostly draw orchestration at this point — most of the substance - landed in N.4 + N.5. **Estimate: 1-2 weeks** (was 2-3). +- **N.6 — Retire legacy renderers + perf polish.** **Currently in flight.** + Builds on N.5. Retires `InstancedMeshRenderer` + `StaticMeshRenderer` + entirely — they remain as `ACDREAM_USE_WB_FOUNDATION=0` escape hatches + through N.5 but are deleted when N.6 ships. Optional N.6 candidates: WB + atlas adoption for memory savings on shared content, persistent-mapped + 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 `EnvCellRenderManager` + `PortalRenderManager` on top of N.4's foundation. **Estimate: 1-2 weeks** (was 2-3 — naturally smaller now