Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Research23/first-pass.md
T
Fr0zkaandClaude Opus 5.5 9458217d34 feat(core): native Core caves generator, slice 1 -- spine + room, whole view 0.73 s (L54); research R23
Core.Caves.PrimitiveField v1, opt-in per strate (legacy TunnelNetwork assets stay legacy): solid host rock
and one smooth union of two elliptical spine tubes and an ellipsoid room, each intersected with its rising
floor by cubic smooth-max (W 2.4 m, measured fillet 0.70 m, no trailing floor cap). Bound in the L40 field
table and L42 capabilities, BVH feature candidates, isTileShapeFree aware, exact interval boxes (0 misses).
Capsule flood fill arrival -> departure passes (headroom >= 0.3 m, grade <= 15 deg); the generalized
whole-surface audit passes with its controls failing. Cold whole view 0.727 s, near ring 0.19 s. Graph
ordering/serialization changes are scoped to native caves (the flagged L47 demo is unchanged); verify
tiers write captures under --out only. fast/medium/full PASS, Clang and GCC.
Research R23 (deepened): per-tile LOD0 kernel speed plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
2026-10-25 04:10:19 +01:00

11 KiB
Raw Blame History

VoxelForge — Research R23: making each tile cheaper

Stage model

World::generateTile sets the shape and optional shared-cache scope, classifies the tile, calls the mesher, then copies mesh data into the tile payload. The LOD0 mesher path is GenerateMesh.

LOD0 uses a 32³ cell tile and a 35³ density grid: 42,875 samples per fully sampled tile. FI sampled 17.883M points across 512 LOD0 jobs, an average of 34,928 per job (81.5% of the full grid); SW sampled all 21.952M. FI’s proof mask marks active cells and their one-sample gradient halo. Proof-mask construction is outside the density-grid timer, in the residual work.

The density fill, proof mask and X-batch gates are in VoxelMarchingCubesMesher.cpp. The cell loop classifies eight X-adjacent cells with AVX2, then computes gradients, interpolation, deduplication and streams triangles for surface cells. The mesher reads gradients from the density grid and memoizes them; it re-queries only for proxy-band fallback samples. Edge interpolation can re-query at the midpoint when T is between 0.375 and 0.625. The skirt pass clips and emits boundary geometry; final triangle and skirt-mask assembly follows. These stages are in VoxelMarchingCubesMesher.cpp. Round18 found only 35 midpoint probes in its audit, so that re-query has little measured headroom.

The table shows L52 totals for 512 LOD0 jobs. Shares use each recipe’s worker_sum_s as denominator. Grid and skirt timers are direct; some mesher substage buckets are sampled or extrapolated. Those buckets exceed the outer mesher timer by about 17 ms in both recipes, so treat shares as approximate.

Stage Code SW total / share FI total / share
Density grid GenerateMesh, fill and grid timer 608.641 ms / 30.0% 26,703.171 ms / 93.3%
Cell-case classification AVX2 X rows 131.076 ms / 6.45% 104.673 ms / 0.37%
Gradients and normals central differences, memo 49.508 ms / 2.44% 24.732 ms / 0.09%
Edge interpolation edge crossings and midpoint probes 370.383 ms / 18.23% 30.921 ms / 0.11%
Vertex dedup and stream vertex maps, triangle bins 95.139 ms / 4.68% 66.466 ms / 0.23%
Other mesher work setup, proof-mask work, finalization residual 47.487 ms / 2.34% 106.111 ms / 0.37%
Skirts boundary scan, clipping, emission 650.112 ms / 32.0% 1,094.614 ms / 3.82%
Core mesh assembly mesh-to-payload copy 10.458 ms / 0.51% 13.247 ms / 0.05%

The LOD0 worker sums are 2.032 seconds for SW and 28.633 seconds for FI. With 12 workers, their ideal drains are 0.169 and 2.386 seconds. SW’s LOD0 work alone cannot close R22’s roughly 0.72-second whole-view gap to one second; the shared kernel needs to carry into other LODs as well.

Tile and block classification is separate from the cell-case stage. L52’s final logs report classification_worker_ms=0.622 for SW and 22.465 for FI across 960 full-detail tiles, with no LOD0 split. ClassifyBoxDetailed records milliseconds. The Linux52 report’s prose calls the FI figure 22.47 worker-seconds; that conflicts with the final log field and source units, so I have not counted it as seconds.

The X8 density API is not generally eight-lane SIMD: its native-only route loops over scalar DensityAtLattice calls. FI’s proof-masked fill disables the X-batch route. The cell classifier is genuine AVX2; a separate primitive Z-run helper uses four double lanes. The relevant code is ShapeWorldInternal.h and ShapeWorldInternal.h.

The world-level shared column cache is scoped in VoxelForgeCore.cpp and used by Heightfield2D::point in WorldAssemblerInternal.h. L52’s LOD0 heightfield-column counters are zero. FI also has an island XY column cache in FloatingIslandsInternal.h; its hit rate and cost are not reported. An optional shared 3D density grid exists, but Core passes null, and using it disables proof-mask sampling.

Techniques and evidence

  • SIMD field evaluation: both the i9-12900H and Ryzen 7 5800X3D list AVX2 support; the AVX2 width is eight floats, so X16 means two vectors rather than a wider instruction. Intel specs, AMD specs. FastNoise2 reports 494.49M 3D value samples/s with AVX2 versus 64.13M for FastNoiseLite on an i7-7820X; this is an illustration, not a VoxelForge forecast. FastNoise2 benchmark. An earlier in-repo packed X-row path reduced its LOD0 grid timer 62.4% with matching W1/W8 hashes; its workload differs from L52. Round9 report.

  • Sparse sampling: refine the existing conservative 8³ block proofs to smaller mixed blocks, retaining exact fallback for unknown blocks and the gradient halo. The method is already proven for the current block sizes: L52’s brute-force audit checked 36.9M samples with zero violations under Clang and GCC. Linux52 report. Generic Lipschitz pruning assumes a valid field bound; use VoxelForge’s exact box proofs rather than assuming every field is a unit-distance SDF. NVIDIA Warp sparse MC design.

  • Alternative extraction: Flying Edges’ four-pass structure intersects each edge once and preallocates output; its paper reports up to 5.22× serial and 8.26× at 36 threads versus its optimized MC baseline on CT angiography data. VTK warns that its output may include degenerate triangles and differ from MC. These are much larger workloads than a 32³ tile. Paper, VTK documentation. Surface Nets and dual contouring change vertex placement and mesh topology. On an RTX 5090 sphere benchmark at 512³, uniform MC took 5.4 ms, Surface Nets 6.9 ms and dual contouring 7.0 ms. Isoext performance. Transvoxel solves 2:1 LOD seams using nine high-resolution samples and 512 cases in 73 classes; it does not reduce interior LOD0 sampling. Transvoxel.

  • Reuse and layout: density, proof-mask and gradient arrays, vertex maps and triangle bins already retain worker-local capacity. The grid is X-fast and cell traversal follows X rows. The visible per-tile scratch allocation is SurfaceVertexDensitySamples; allocation time is not isolated. The viewer already computes visible skirt faces, but generation currently emits all skirt faces. Viewer mask.

Exactness

Technique Bit-identical? Conditions
AVX2 arithmetic batches Yes, conditionally Preserve each lane’s operation order; keep contraction off; avoid approximate math.
Grid-derived gradients and memoization Yes; already implemented Preserve central differences and the proxy-band fallback.
Finer proof blocks Yes, conditionally Use conservative proofs, exact fallback and the same halo.
Scratch reuse and cache changes Yes Reset all validity and key state; cache replacement must affect residency only.
Vectorized sin/cos Not guaranteed SIMD math can shift bits. Pin the implementation and compare Clang/GCC peers.
Hidden skirt-face omission Mesh output changes Rendered output can match for a fixed neighbor mask, but hashes and cache identity change.
Flying Edges, Surface Nets, dual contouring or Transvoxel No Geometry or topology changes; peer determinism is possible with a fixed implementation and version bump.

VoxelForge already disables FP contraction for Core; GCC and Clang document that contraction controls FMA formation. Those flags do not fix libm or vector-trig results across implementations. GCC, Clang, FastNoise2 reproducibility notes.

Ranked plan

Savings are scenarios in worker-seconds across the same 512 LOD0 jobs. Divide by 12 for ideal-drain wall time. They are not additive.

Rank Change and code location SW / FI scenario Risk and measurement
1 Add mask-aware AVX2 field batches in mesher fill and field evaluators: VoxelMarchingCubesMesher.cpp, ShapeWorldInternal.h, FI IslandDensity. If grid fill speeds up 1.25–1.5×: 0.12–0.20 / 5.34–8.90 s Current X8 API and FI proof mask fall back to scalar work. Preserve lane operation order first; pin vector math if trig is vectorized. Count active lanes and compare grid timers, then paired unprofiled medians and hashes under Clang/GCC on both CPUs.
2 Refine 8³ proofs to 4³ in mixed blocks; retain unknown fallback and halo. If FI grid work falls another 5–15%: ≈0 / 1.3–4.0 s Sensitivity range only; finer proofs may cost more than they save. Measure samples and classifier time, then repeat the brute-force proof audit and hash matrix.
3 Pass the viewer’s visible-face mask into GenerateMesh and skip hidden skirt emission. h×0.650 / h×1.095 s, where h is the hidden fraction L52 has no hidden-face histogram. Measure mask fractions and skirt time under fixed adjacency; include the mask in any mesh-cache key.
4 Prototype Flying Edges after grid fill. If the post-grid MC work became 2.5× faster: ≈0.41 / 0.19 s Literature results may not transfer to 32³ tiles; output ordering and degenerates differ. Benchmark prefilled grids and whole tiles; version the changed mesh.
5 Instrument and reuse remaining scratch; add FI island-cache hit/miss timing. Unmeasured / unmeasured Existing buffers already retain capacity. Count allocations and cache hits before selecting a change; compare output hashes after any scratch reuse.

Read-only pass complete. No source edits, scripts, tests, builds or binaries were run.