diff --git a/Standalone/Research/WorldAssemblerM3/Astra1/BRIEF.md b/Standalone/Research/WorldAssemblerM3/Astra1/BRIEF.md new file mode 100644 index 0000000..9de8b1f --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Astra1/BRIEF.md @@ -0,0 +1,133 @@ +# VoxelForge — design review: how do we get a cold whole view from ~2.5–4.6 s to ~1 s? + +You're reviewing a voxel terrain generator's performance architecture. **Read and reason only.** Don't edit, +build, run tests, commit or stash. You may read any file in this repository and search the web. + +We've spent about 15 rounds finding and fixing hot spots, and the gains are shrinking. We want fresh eyes on the +*approach*, not another micro-optimisation. Question our framing where it's wrong. + +## The system (summary, so you don't have to rediscover it) + +**VoxelForge** is a UE5 plugin for underground density-field terrain. Generation lives in a standalone C++ +library, "Core" (`Standalone/Core/`), that Unreal calls through an adapter +(`Source/VoxelForge/Private/VoxelForgeCoreAdapter.cpp`). +- **The field.** Density is a *function*, not stored data: negative = solid. Core voxels are 25 cm. Tiles hold + 32³ voxels. +- **Clipmap.** LOD0–8; each LOD doubles the voxel step. A "whole view" is about 2,250–2,850 tiles across all LODs + around one camera. +- **Meshing.** Marching cubes per tile (about 35³ samples per LOD0/1 tile with borders), plus normals and skirts. +- **The world is a vertical stack of "strates".** Each is ceiling → content → bedrock, with its own generator: + - SurfaceWorld (SW): heightfield, native path; + - FloatingIslands (FI), TunnelNetwork (TN) and VerticalShafts (VS): the "legacy compiled-analytic" path. +- **The owner's test world** stacks four of them: SW 512 m, FI 240 m, TN 128 m, VS 128 m tall. +- **Passages.** Walkable, winding, natural-looking tunnels near (0,0) connect each strate to the next. They're + carved by a shared "composer" that also adds support treads, boundary bands and mouth shaping. +- **Multiplayer.** No geometry is replicated. Every peer regenerates from the seed, the layout and a diff of + player edits. That's why peer determinism is mandatory. + +## The goal and constraints + +- **Goal:** about 1 s cold whole view at any strate arrival on the owner's PC (Ryzen 5800X3D, 8 cores/16 threads, + 7900 XTX). Streaming must stay smooth in VR (Quest 3) and at high travel speed. +- **Must hold:** + - peer determinism (same inputs → same world on every machine); + - no visible quality regression; + - passages stay walkable from arrival mouth to departure mouth (capsule, support and grade audits exist); + - no game-thread hitches. +- **Not required:** byte-identical output with earlier versions. The owner accepts that perf passes change the + world's shape slightly, as long as every peer gets the same result and quality holds. (We have tended to treat + hash equality as a gate anyway; it's a convenience, not a rule.) +- **On the shelf, not a speed excuse:** a disk mesh cache is an accepted feature, but perf is judged cold. + +## Measurements (owner world, measured on an i9-12900H with 8 workers, headless unless stated) + +**Whole view now** (it was 2.6 / 7.2 / 6.0 / 2.7 s a week ago): + +| Strate | Whole view | +|---|---:| +| SW | 2.4 s | +| FI | 4.6 s | +| TN | 4.3 s | +| VS | 2.5 s | + +**In Unreal (SW arrival):** +- Core work equals headless; +- initial set ready at 3.74 s vs headless 2.41 s, the extra being scheduling; +- walkable ring 0.4–1.8 s. + +**Where the time goes:** +- **L73:** field evaluation inside grid fill is about 40 of FI's 46 worker-seconds (TN 33 of 39). LOD0/1 tiles + evaluate about 44k density samples each. +- **L74/L75:** sound whole-tile skip proofs now certify about 22–26% of tile visits. + - Ceiling: 46–82% of LOD0–2 tiles are truly uniform, and 90–97% of samples lie in uniform 8³ blocks. + - Dominant remaining veto: tiles crossing a strate boundary. + - Legacy sub-tile (block) proofs were unsound once (missed passage wall/floor relief), then sound but slower + than they saved. +- **L76, per legacy sample:** + - passage/support composer ≈ **1.05 µs**; + - primitive scan ≈ 0.19 µs (0.25 primitive distance evaluations per sample, binned); + - boundary band ≈ 0.06 µs; + - noise ≈ 0.01 µs. + + **About 75% of field time is the passage composer, even far from passages.** + - Per-tile passage culling was tried and changed 612 density samples / 24 mesh tiles. It was rejected only for + breaking hash equality, which is a convenience, not a rule; nobody checked whether that change was harmless. + +**Tried and rejected:** +- the native FI generator (fails passage walk audits on this plan); +- deeper Unreal queues (done: 4.78 → 3.74 s). + +**Trap we fell into once:** a diagnostic hash mode silently disabled the skips and doubled the timings. Measure the +production path. + +## What to reason about (open; don't limit yourself to these) + +1. **Is "evaluate a density function at ~44k points per tile, then march cubes" the right shape** for this world? + Consider, for example: + - sparse/hierarchical evaluation (octree or brick refinement driven by interval or Lipschitz bounds, as in + libfive/Fidget/MPR-style implicit rendering); + - reusing samples across nested clipmap LODs; + - evaluating smooth large-scale terms coarsely and interpolating; + - narrow-band evaluation near the surface only. +2. **The passages are a few winding tubes.** Why does every sample pay 1 µs for them? What representation would + make "far from any passage" free and "near a passage" cheap? For example: + - bake each passage once at plan time into a sparse distance/brick structure; + - a spatial index of segments with a conservative distance early-out; + - a per-tile passage candidate list built once. + + What would a correct per-tile culling need so that it doesn't change the result? And if it changes the result, + how should we judge whether that change is acceptable? +3. **Which work is needed for "ready in 1 s"?** Maybe the target should be redefined: walkable ring first, + progressive LOD refinement, far LODs from cheaper representations or impostors, fewer tiles. What do comparable + engines do (Voxel Plugin, Teardown, Dreams, No Man's Sky, Minecraft-style streaming, Nanite-era voxel work)? +4. **Hardware.** 8 CPU cores plus a 7900 XTX that's mostly idle during load. An earlier GPU port was closed, and + determinism across GPU vendors is a concern. Is there a deterministic way to use it, e.g. integer/fixed-point + evaluation or a CPU-authoritative plus GPU-display split? Is SIMD (AVX2) evaluation of the legacy field + realistic? +5. **Anything in our process or measurement** that hides the real bottleneck. + +## How to work efficiently + +- **Trust the numbers above; don't re-measure or re-derive them.** Spend your effort on thinking. +- **Read code only to check whether a specific idea fits.** Entry points: + - `CODEMAP.md` (navigation) and `ARCHITECTURE.md` §8.10 (performance invariants); + - `Standalone/Core/src/ShapeWorldInternal.h`: composer, `AnalyticDensityAt`, `ClassifyBoxDetailed`, passage + terms; + - `Standalone/Core/src/VoxelForgeCore.cpp`: tile generation and skips; + - reports in `Standalone/Research/WorldAssemblerM3/`: `Linux73`–`Linux76`, `Research36`, and R38–R40 notes + inside `Linux73/` and `Linux76/`. +- **Use the web** for prior art and techniques, and cite them. +- **Go broad first** (many approaches, one or two lines each), then deep on the best three. + +## Output + +At most ~2,500 words, plain language, **ranked recommendations first**. For each of the top three: +- what changes, and where in this codebase (file and function); +- expected gain, with arithmetic from the numbers above; +- what it risks: determinism, quality, walkability; +- effort; +- **a cheap experiment that would prove it wrong** before anyone builds it fully. + +Then the shorter list of other ideas, then any questions only the owner can answer (e.g. what "ready" must mean). +Mark claims as [CODE] (read in this repo), [MEASURED] (from the numbers above), [PRIOR ART] (cited) or +[INFERENCE]. diff --git a/Standalone/Research/WorldAssemblerM3/Astra1/REPORT.md b/Standalone/Research/WorldAssemblerM3/Astra1/REPORT.md new file mode 100644 index 0000000..ca46fdd --- /dev/null +++ b/Standalone/Research/WorldAssemblerM3/Astra1/REPORT.md @@ -0,0 +1,137 @@ +# Astra 1 — design review (gpt-6-astra, effort low, read-only), 2026-10-27 + +Brief: see BRIEF.md. Note from Claude: the brief's "~75% of field time is the passage composer" was WRONG — L76's term profiler covered ~6.0M of ~52M density calls per view (FI); measured passage cost is ~6.5 of ~40 worker-s (~15%). Astra flagged the scope mismatch itself. Its gain arithmetic in rec. 1 inherits the wrong share. + +**[INFERENCE] Ranked recommendations:** + +1. **Compile passages into spatially local operations.** Make most samples bypass the composer entirely; simplify the remaining work. +2. **Replace repeated block classification with a retained hierarchy of proofs and local field programs.** Keep marching cubes; stop densely evaluating regions that cannot produce geometry. +3. **Give arrival readiness its own deadline-driven pipeline.** Preserve whole-view completion as a separate benchmark; scheduling improvements alone cannot meet it. + +**[INFERENCE]** These are complementary. Passage localization is the strongest first investment, but does not plausibly deliver one second alone. A wholesale mesher replacement, GPU rewrite, or native-generator migration is premature. + +### 1. Make passage influence local by construction + +**[CODE]** There is already a spatial index: `BuildPassageFeatureTileList` queries passage feature bounds. `FScopedPassageTileQueries` turns route candidates into per-passage flags, while retaining segment lists for mouth support. Nevertheless, `ApplyResolvedStratePassageCarves` still iterates all passages and scans crossings. After finding a route distance, it calculates relief and mouth-related terms. See [ShapeWorldInternal.h](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:989). + +**[INFERENCE] What changes:** compile a small, immutable passage program for each spatial region: + +- Empty region: no passage invocation. +- Route region: ordered candidate segments, precomputed geometry and distances along the route. +- Mouth/support region: explicit support, transition-fade and later-bore dependencies. +- Overlapping features: retain the original composition order. + +Use `BuildPassageComposerConstants`, `BuildPassageFeatureTileList`, `FScopedPassageTileQueries`, and `ApplyResolvedStratePassageCarves`; connect the result through `World::generateTile` in [VoxelForgeCore.cpp](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/VoxelForgeCore.cpp:1997). This is stronger than filtering one loop: the region program should remove entire categories of work. + +**[INFERENCE] Exact culling requires an identity proof**, not merely “the tube does not intersect this tile.” For every omitted operation, prove that it leaves the incoming density unchanged over the query domain. Include: + +- Spline extrema, variable radius, wall/floor relief and smooth-blend reach. +- Mouth shaping, support treads, columns, boundary fade and dependencies on other passages. +- All sample positions used by normals, borders and skirts. +- Deterministic ordering and tie-breaking among retained features. + +A feature can leave density signs unchanged while altering marching-cubes interpolation or normals. Conversely, changing far-away density magnitudes may be harmless. These are different correctness claims. + +**[CODE]** L75 already corrected bounds for passage relief and spline extrema. The composer also conditionally restores support and defers support composition. Therefore, baking one distance to the nearest tube would not reproduce its semantics. [L75 report](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux75/REPORT.md:22) + +**[INFERENCE]** If exact influence is awkward or effectively nonlocal, introduce a versioned, compact-support passage operator: identical in the protected walkable corridor and mouth regions, smoothly becoming identity outside an explicit envelope. That is a legitimate world-generation change under your constraints. + +**[MEASURED → INFERENCE] Expected gain:** passage work is approximately `0.75 × 40 = 30` of FI’s 46 worker-seconds, and `0.75 × 33 = 24.75` of TN’s 39. Removing 80–90% gives proportional wall-time scenarios: + +| View | 80% passage reduction | 90% passage reduction | +|---|---:|---:| +| FI | `4.6 × (46−24)/46 = 2.20 s` | `4.6 × (46−27)/46 = 1.90 s` | +| TN | `4.3 × (39−19.8)/39 = 2.12 s` | `4.3 × (39−22.275)/39 = 1.84 s` | + +These assume critical-path time follows work reduction; they are not predictions for the Ryzen. Even eliminating passage cost entirely leaves approximately **1.6 seconds** in both views. + +**[INFERENCE] Risks and effort:** medium effort for regional programs; larger for a new passage representation. Stable candidate ordering and versioned arithmetic protect determinism. Underestimated envelopes threaten clearance and support; overly generous envelopes merely lose speed. Run capsule, grade and support audits across entire passages, including landings and seams. + +**[INFERENCE] Cheap falsifier:** resurrect the rejected culling candidate as an experiment. First inspect all 612 changed samples and 24 changed mesh tiles: location, zero crossings, surface displacement, normals, support and audit outcomes. Then time the production path including candidate construction. Reject this implementation if conservative lists remain large or composer savings are small. Hash differences alone are neither acceptance nor rejection. + +### 2. Retain spatial proofs and simplify the field inside each region + +**[INFERENCE]** A continuous density function remains a good world definition. Evaluating its complete program at every lattice point is the questionable implementation. Marching cubes is not currently the dominant problem. + +**[CODE]** `ClassifyBoxDetailed` delegates to `ClassifyBoundsDetailed`. The latter already performs conditional strate slicing, but combines slices into a whole-box verdict and abandons the skip when a slice is unknown or has a different sign. L75’s legacy block certificates became audit-only after timing regressions. Simply enabling more block checks repeats a failed approach. [Classifier](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Core/src/ShapeWorldInternal.h:6385), [L75 final disposition](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux75/REPORT.md:64) + +**[INFERENCE] What changes:** introduce a compact region tree or brick table whose entries retain: + +- A solid/air certificate, or an unresolved range. +- Relevant primitive and passage candidates. +- Terms proven inactive or dominated. +- Child regions requiring further evaluation. + +Split first at known strate and transition-band boundaries, then refine unresolved regions spatially. Keep successful proofs even if a neighboring slice fails. Share candidate filtering and bounds down the hierarchy; do not repeatedly invoke the full classifier from scratch. + +Start tile-local and retain the regular marching-cubes lattice. Extend `ClassifyBoundsDetailed`, the evaluation feeding `AnalyticDensityAt`, `World::generateTile`, and the grid/proof path in `UVoxelMarchingCubesMesher::GenerateMesh` in [VoxelMarchingCubesMesher.cpp](/home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelMarchingCubesMesher.cpp:102). + +**[PRIOR ART]** Fidget combines interval evaluation with regional expression simplification: even unresolved regions can use shorter programs. That second benefit matters here as much as empty-space skipping. It also supports bulk SIMD evaluation. [Fidget’s author documentation](https://www.mattkeeter.com/projects/fidget/) + +**[INFERENCE]** Do not assume the composed density is a signed distance field with Lipschitz constant one. Warps, blends and relief require their actual bounds. Uniform corners do not prove a uniform interior. + +Similarly, do not fill certified interiors with arbitrary constants and then use those constants at surface edges or in normal stencils. Evaluate the exact endpoint and halo values wherever geometry or gradients consume them. A narrow band must be *discovered conservatively*, not guessed from sparse signs. + +**[MEASURED → INFERENCE] Expected gain:** the 90–97% uniform-block sample census is an opportunity ceiling, not a realizable skip rate. A useful experiment target is **50–70% reduction of remaining field work, net of classification cost**. + +After a 90% passage reduction, FI has approximately 13 field-work units plus 6 others. Reducing those 13 by 50–70% gives: + +`4.6 × [6 + 13 × (0.5 to 0.3)] / 46 = 1.25 to 0.99 s`. + +TN similarly gives approximately **1.25–1.02 seconds**. Thus the combination approaches the headless target, with little budget left for Unreal overhead. Do not multiply independent headline speedups: both techniques remove overlapping work. + +**[INFERENCE] Risks and effort:** medium-to-large effort, substantially less than adaptive meshing with new topology. Incorrect proofs can silently delete geometry; edits must invalidate affected certificates, including their dependency halos. Quality and walkability can remain unchanged if surface samples and stencils remain exact. Unknown bounds must fall back. + +**[INFERENCE] Cheap falsifier:** implement one tile-local hierarchy for representative boundary-crossing and passage-adjacent tiles, retaining the existing mesher. Compare total classification-plus-fill cost against dense evaluation, after passage localization. Reject expansion if net field savings fall well below 50%, or bookkeeping and conservative halos consume the benefit. The prior slow block experiment makes this an essential early gate. + +### 3. Schedule for an explicit arrival deadline + +**[MEASURED]** SW’s Unreal overhead is `3.74−2.41 = 1.33 s`; walkable readiness ranges from 0.4 to 1.8 seconds. + +**[INFERENCE]** Keep two separate commitments: + +- **Arrival ready:** safe collision and sufficient visible terrain for immediate movement. +- **Whole view complete:** the full requested set at final quality. + +If the owner insists both happen within one second, say so explicitly. Progressive refinement cannot be counted as meeting the second commitment. + +**[CODE]** §8.10 already specifies occupied/support-tile priority, heading priority, dynamic near reserve, independent region admission, cancellation, bounded result backlog and hot-swap. “Make nearby tiles higher priority” is therefore not a new recommendation. [Performance invariants](/home/jahni/VoxelM/Plugins/VoxelForge/ARCHITECTURE.md:572) + +**[INFERENCE] What changes:** make readiness a dependency graph with deadlines: required region compilation → field/mesh → collision preparation → bounded publication. Prioritize prerequisites of the arrival set, not just its tile jobs. Reserve capacity through publication, and schedule travel-ahead work by time-to-arrival. + +Inspect and change `AVoxelWorld::UpdateChunksAroundPosition`, `LoadTile`, and `ProcessPendingChunks` in [VoxelWorld.cpp](/home/jahni/VoxelM/Plugins/VoxelForge/Source/VoxelForge/Private/VoxelWorld.cpp:9400). Preserve the existing epoch, cancellation and collision-handoff rules. Refinement should retain covering geometry until replacements are ready. + +**[PRIOR ART]** Voxel Plugin separates collision/navmesh demand through invokers. Geometry clipmaps use incremental updates, coarse-to-fine processing and continuity between levels. These support separate readiness domains, not a universal one-second guarantee. [Voxel Plugin](https://docs.voxelplugin.com/2.0p6/knowledgebase/blueprints/collision-navmesh-and-invokers), [Geometry clipmaps](https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry) + +**[MEASURED → INFERENCE] Expected gain:** removing half the observed scheduling gap saves about **0.67 seconds**; removing all of it still leaves SW at 2.41 seconds before Core changes. Improving a 1.8-second walkable arrival to one second requires eliminating or deferring 0.8 seconds from that critical path. + +**[INFERENCE] Risks and effort:** small-to-medium for dependency scheduling; larger for new far representations. Timing must never change generation inputs. Coarse collision can violate walkability; coarse visuals can pop, particularly in VR. Preserve authoritative near collision and accept temporary visual substitutes only if they satisfy the owner’s quality criterion. + +**[INFERENCE] Cheap falsifier:** first replay existing job timings against the dependency graph, then try an arrival-only admission experiment. If prerequisites plus bounded publication already exceed one second without competing work, scheduling cannot solve arrival latency. If the coarse cover visibly degrades the arrival, it cannot redefine “ready.” + +**Other approaches, in priority order** + +- **[INFERENCE] Bake passage geometry, not necessarily final density.** Precompute spline coefficients, arc lengths, frames and conservative segment bounds first. Sparse sampled bricks are a later option; retain separate carve/support operands and conditions. Count baking in cold latency. Interpolated distance alone can erase treads or alter mouths. +- **[INFERENCE] SIMD after localization.** AVX2 evaluation of batches sharing a local program is realistic; divergent all-passage loops are a poor starting point. Eight lanes do not imply eightfold speedup. Specify arithmetic and reduction order across scalar/vector paths. +- **[INFERENCE] Sample sharing.** Share same-LOD borders first; cross-LOD reuse requires identical coordinates *and field semantics*. Nested lattices overlap, but clipmap shells need not cover the same volume. Compare synchronization cost against duplicate evaluation before building a global cache. +- **[INFERENCE] Coarse smooth terms.** Interpolate bounded macro terms while evaluating fine relief near surfaces. Density error does not imply equal position error where gradients are weak. L76’s 0.01-µs noise row is too small to justify making noise approximation the main project. +- **[INFERENCE] GPU.** A specified integer/fixed-point evaluator can be deterministic: define rounding, overflow, square roots, interpolation and stable emission order. Quantizing floating-point results afterward is insufficient. CPU-authoritative collision plus GPU display is easier, provided visual disagreement is bounded and display results never affect gameplay. GPU readbacks and VR contention can erase gains. +- **[PRIOR ART → INFERENCE]** HLSL `precise` controls arithmetic refactoring; it is not a complete cross-vendor world-generation specification. Prototype one bounded integer passage kernel before reopening a full port. [Microsoft documentation](https://learn.microsoft.com/en-us/windows/win32/direct3dhlsl/precise) +- **[PRIOR ART → INFERENCE] Alternative renderers.** Dreams’ published architecture evaluates CSG into multiresolution point clouds; Teardown uses a voxel renderer without polygons. These demonstrate representation choices, not transferable cold-generation timings. Nanite addresses rendering downstream of field generation. [Dreams presentation](https://www.advances.realtimerendering.com/s2015/index.html), [Teardown FAQ](https://www.teardowngame.com/faq.html) +- **[PRIOR ART → INFERENCE] Continuous streaming.** No Man’s Sky’s architecture is explicitly organized around continuous generation. That supports travel-ahead planning, but does not prove cold teleport latency. Disk caching likewise remains useful without counting toward this target. [Hello Games’ GDC talk](https://www.youtube.com/watch?v=sCRzxEEcO2Y) + +**Process changes that matter** + +**[INFERENCE]** Separate three gates: peer determinism for the *new version*; gameplay/visual acceptance against the previous version; and performance on the production path. Old-version hash identity should only gate changes advertised as exact. + +**[CODE]** L76’s term profiler covers selected legacy evaluations; its passage total is about 6.3 worker-seconds, whereas L73 reports broader grid-field totals. Those scopes must not be silently equated. The arithmetic above uses your supplied aggregate attribution as a scenario, not reconciled absolute profiling data. [L76 profiler scope](/home/jahni/VoxelM/Plugins/VoxelForge/Standalone/Research/WorldAssemblerM3/Linux76/REPORT.md:5) + +**[INFERENCE]** Report cold-start boundaries, critical-path stages, worker occupancy, publication latency and worst frame time alongside whole-view time. Include plan compilation and fresh in-memory structures. Validate the winning prototype on the 5800X3D; no reliable conversion follows from the laptop measurements alone. + +**Questions only the owner can settle** + +- Must every final-quality tile exist at one second, or can safe arrival precede complete refinement? +- What travel speed, teleport distance and VR frame budget must streaming sustain? +- Does “cold” include world planning, and must supported peers reproduce density bits, mesh bits, or an explicitly defined gameplay representation? + +Read-only review completed; no edits, builds, tests, commits or stashes. \ No newline at end of file