wip(assembler): round L9 -- LOD1 skips proven-uniform blocks: 95% fewer samples, view ~2% faster

Step-2 (LOD1) tiles of native SurfaceWorld now prove 8-cell blocks uniform from exact heightfield
column extrema over the padded block (cells + normal halo) and skip their density fill; features,
edits, mixed strata and Unknown verdicts still fill. LOD1 samples 42,875 -> 2,063 per tile.
Audit: 80,502 skipped blocks (3 seeds) + 9,216 island blocks force-filled, 0 violations. All
SurfaceWorld and FloatingIslands hashes unchanged at W1/W8/W12, Clang off and GCC default.
Reviewer interleaved W12, no hashing: whole view 1.439 -> 1.409 s. L8 phase probes removed;
--profile-lod-work and --audit-uniform-block-proofs are opt-in.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CSFYgsdW8ejZSyiMf4qRSX
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 23:14:16 +02:00
1 parent 82813fb13b
commit 7650abb755
10 files changed
+439 -48

No files matched your search

+10
View File
@@ -1118,6 +1118,16 @@ restores the S13 path for the negative control. Runtime CVar capture lives in
cold-path decision are in
[`Standalone/Research/WorldAssemblerM3/Round18/REPORT.md`](Standalone/Research/WorldAssemblerM3/Round18/REPORT.md).
### 3.21 LOD1 uniform-block proof — World Assembler M3 Linux9
`FStandaloneShapeWorld::IsNativeSurfaceBox` gates the step-2 proof to a single native SurfaceWorld
stratum. `ClassifyBoxDetailed(..., bUseNativeLatticeProof)` delegates to
`Heightfield2D::classifyLatticeBox`, whose ground/cap extrema cover the MC lattice and normal halo.
`UVoxelMarchingCubesMesher::GenerateMesh` sparsely fills only Mixed blocks and their sample halo;
Mixed/Unknown remains on the fill path. The headless `--audit-uniform-block-proofs` forces sample
verification, while `--profile-lod-work` reports per-LOD filled samples; both are off by default.
Implementation and evidence: [`Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md`](Standalone/Research/WorldAssemblerM3/Linux9/REPORT.md).
## 4. The density pipeline (most-edited hot path)
### 4.1 `GetDensityWithParams` (TunnelNetwork) — VoxelGenerator.cpp:3749
@@ -133,6 +133,11 @@ namespace VoxelForgeCore
std::uint64_t columnCacheConflictMisses = 0;
std::uint64_t sharedColumnCacheHits = 0;
std::uint64_t columnEvaluations = 0;
std::uint64_t uniformBlockProofsChecked = 0;
std::uint64_t uniformBlockProofSamplesChecked = 0;
std::uint64_t uniformBlockProofFallbackBlocks = 0;
std::uint64_t uniformBlockProofUnknownBlocks = 0;
std::uint64_t uniformBlockProofViolations = 0;
double classificationMilliseconds = 0.0;
double columnComputeMilliseconds = 0.0;
double columnEvaluationExclusiveMilliseconds = 0.0;
@@ -1056,6 +1061,9 @@ namespace VoxelForgeCore
// Separate cold pass only; samples the MC inner stages without changing output.
// Passe froide separee seulement; mesure les etapes internes MC sans changer la sortie.
bool profileMesherStages = false;
// Diagnostic only; fills and checks every lattice sample in blocks certified uniform.
// Diagnostic seulement; evalue et verifie tous les echantillons des blocs uniformes.
bool auditUniformBlockProofs = false;
// Negative control for the shared XY-column cache; 1 restores the old direct-map indexing.
// Controle negatif du cache XY partage; 1 restaure l'ancien indexage direct.
bool legacyDirectMappedColumnCache = false;
+51 -14
View File
@@ -1227,7 +1227,34 @@ public:
EVoxelTileClass ClassifyBox(const FIntVector& Origin,int32 Step,int32 Cells) const
{ return ClassifyBoxDetailed(Origin,Step,Cells).Verdict; }
FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells) const
bool IsNativeSurfaceBox(const FIntVector& Origin,int32 Step,int32 Cells) const
{
if(!WorldAssembly||!Owner||!Owner->Manager||Step<=0||Cells<=0)return false;
const int32 Pad=std::max(Step,1);
const int32 BMin=Origin.Z-Pad;
const int32 BMax=Origin.Z+(Cells+1)*Step;
const int32 FirstChunk=FMath::FloorToInt(static_cast<float>(BMin)
/static_cast<float>(CHUNK_SIZE));
const int32 LastChunk=FMath::FloorToInt(static_cast<float>(BMax)
/static_cast<float>(CHUNK_SIZE));
const VoxelForgeCore::WorldAssemblyStratumPlanV1* Plan=nullptr;
for(int32 ChunkZ=FirstChunk;ChunkZ<=LastChunk;++ChunkZ)
{
const auto It=std::find_if(WorldAssembly->plan.strates.begin(),
WorldAssembly->plan.strates.end(),[ChunkZ](const auto& Entry)
{return ChunkZ<=Entry.topChunkZ&&ChunkZ>=Entry.bottomChunkZ;});
if(It==WorldAssembly->plan.strates.end())return false;
const auto* Candidate=&*It;
if(Plan&&Plan!=Candidate)return false;
if(Owner->Manager->GetGeneratorTypeForChunk(FIntVector(0,0,ChunkZ))
!=ECaveGeneratorType::SurfaceWorld)return false;
Plan=Candidate;
}
return Plan!=nullptr;
}
FBoxClassification ClassifyBoxDetailed(const FIntVector& Origin,int32 Step,int32 Cells,
bool bUseNativeLatticeProof=false) const
{
using Clock=std::chrono::steady_clock;
const auto Start=Clock::now();
@@ -1310,27 +1337,37 @@ public:
&&EditBoundsMin.Y<=BMax[1]&&EditBoundsMax.Y>=BMin[1]
&&EditBoundsMin.Z<=BMax[2]&&EditBoundsMax.Z>=BMin[2])
return Finish(EVoxelTileClass::Mixed,true);
for(int32 BZ=FloorDiv(BMin[2],ActiveSpatialBinSize);BZ<=FloorDiv(BMax[2],ActiveSpatialBinSize);++BZ)
for(int32 BY=FloorDiv(BMin[1],ActiveSpatialBinSize);BY<=FloorDiv(BMax[1],ActiveSpatialBinSize);++BY)
for(int32 BX=FloorDiv(BMin[0],ActiveSpatialBinSize);BX<=FloorDiv(BMax[0],ActiveSpatialBinSize);++BX)
// The native interval path below is the exact field selected first by DensityAtLattice
// for SurfaceWorld and FloatingIslands. Legacy analytic primitives/layer bounds cannot
// modify that field; only the explicit edit transaction above can. Keep their guards on
// the legacy classifier path, where those overlays do participate in density.
if(!bUseNativeLatticeProof||(!bSurfaceOverlap&&!bIslandOverlap))
{
const auto It=SpatialBins.find({BX,BY,BZ});if(It==SpatialBins.end())continue;
for(uint32 Id:It->second)
for(int32 BZ=FloorDiv(BMin[2],ActiveSpatialBinSize);BZ<=FloorDiv(BMax[2],ActiveSpatialBinSize);++BZ)
for(int32 BY=FloorDiv(BMin[1],ActiveSpatialBinSize);BY<=FloorDiv(BMax[1],ActiveSpatialBinSize);++BY)
for(int32 BX=FloorDiv(BMin[0],ActiveSpatialBinSize);BX<=FloorDiv(BMax[0],ActiveSpatialBinSize);++BX)
{
const FPrimitive& P=Primitives[Id];bool Overlap=true;
for(int32 A=0;A<3;++A)
Overlap &= P.Max[A]+DetailBand>=BMin[A]&&P.Min[A]-DetailBand<=BMax[A];
if(Overlap)return Finish(EVoxelTileClass::Mixed);
const auto It=SpatialBins.find({BX,BY,BZ});if(It==SpatialBins.end())continue;
for(uint32 Id:It->second)
{
const FPrimitive& P=Primitives[Id];bool Overlap=true;
for(int32 A=0;A<3;++A)
Overlap &= P.Max[A]+DetailBand>=BMin[A]&&P.Min[A]-DetailBand<=BMax[A];
if(Overlap)return Finish(EVoxelTileClass::Mixed);
}
}
for(const FInterval& R:LayerRanges)
if(R.Lo<=BMax[2]&&R.Hi>=BMin[2]
&&(R.Lo>=BMin[2]||R.Hi<=BMax[2]))
return Finish(EVoxelTileClass::Mixed);
}
for(const FInterval& R:LayerRanges)
if(R.Lo<=BMax[2]&&R.Hi>=BMin[2]
&&(R.Lo>=BMin[2]||R.Hi<=BMax[2]))
return Finish(EVoxelTileClass::Mixed);
if(bSurfaceOverlap)
{
if(!WorldAssembly||!SurfacePlan)return Finish(EVoxelTileClass::Mixed,true);
const VoxelForgeCore::Heightfield2D Block(WorldAssembly->recipe,*SurfacePlan);
// classifyLatticeBox takes the exact extrema of ground/cap columns at every
// MC lattice XY in this box. Since density is min(z-ground, cap-z), those extrema
// bound every lattice sample in Z without a noise amplitude guess.
const auto Verdict=Block.classifyLatticeBox(
static_cast<int64>(BMin[0])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
static_cast<int64>(BMin[1])*VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel,
+13 -2
View File
@@ -1570,7 +1570,8 @@ namespace VoxelForgeCore
}
if((out.diagnostics.tileClass==TileClass::allSolid
||out.diagnostics.tileClass==TileClass::allAir)
&&!options.hashDensity&&!options.captureDensitySamples&&!bNeedsFarShell)
&&!options.hashDensity&&!options.captureDensitySamples&&!bNeedsFarShell
&&!options.auditUniformBlockProofs)
{
out.diagnostics.meshingSkipped=true;
const auto Counts=FStandaloneShapeWorld::GetThreadClassificationStats();
@@ -1747,10 +1748,20 @@ namespace VoxelForgeCore
const double ColumnMillisecondsBeforeMeshing=
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
const auto MarchingCubesStart=std::chrono::steady_clock::now();
FVoxelUniformBlockProofAuditStats BlockProofAudit;
FVoxelMeshData mesh=mesher.GenerateMesh(origin,MeshStep,MeshCells,nullptr,
MeshBandMinZVoxel,MeshBandMaxZVoxel,&sampleCount,nullptr,nullptr,
(options.hashDensity||options.captureDensitySamples)?&densityValues:nullptr,
options.profileMesherStages?&McStageTimings:nullptr);
options.profileMesherStages?&McStageTimings:nullptr,
options.auditUniformBlockProofs?&BlockProofAudit:nullptr);
if(options.auditUniformBlockProofs)
{
out.diagnostics.uniformBlockProofsChecked=BlockProofAudit.CheckedBlocks;
out.diagnostics.uniformBlockProofSamplesChecked=BlockProofAudit.CheckedSamples;
out.diagnostics.uniformBlockProofFallbackBlocks=BlockProofAudit.FallbackBlocks;
out.diagnostics.uniformBlockProofUnknownBlocks=BlockProofAudit.UnknownBlocks;
out.diagnostics.uniformBlockProofViolations=BlockProofAudit.Violations;
}
if(bDiagnosticColumnSampling)
{
Heightfield2D::setThreadColumnOctaveDrop(PreviousOctaveDrop);
@@ -0,0 +1,149 @@
# Linux9: LOD1 uniform-block proof
LOD1 now omits density fills only for 8-cell blocks proved uniform by the Core SurfaceWorld heightfield. It fills 924,232 samples across the 448 tiles (2,063 per tile), down from 19,208,000 (42,875 per tile): 95.2% fewer. All output hashes match the `4b1108b` baseline.
## Why the old gate excluded steps
`git blame` points to the original mesher gate: steps 2, 16 and 32 were disabled because the per-block classifier was expected to cost more than the smaller grids saved, and to preserve the old coarse-LOD latency. It gives no correctness reason at step 2; the history does not cite block edges, normal halos or skirts. Step 1 and step 8 were already enabled (step 8 is LOD2). This round enables step 2 for native SurfaceWorld tiles; steps 16/32 remain off pending a separate cost profile.
## Proof and fallback
The tile and each proof box must stay inside one native SurfaceWorld stratum, with no overlapping edit. For every XY lattice point in the padded 8-cell box, `Heightfield2D::classifyLatticeBox` evaluates the exact ground and cap columns at the step-2 stride. For density `min(z-ground, cap-z)`, `minZ > maxGround && maxZ < minCap` proves air; `maxZ < minGround || minZ > maxCap` proves solid. These extrema bound every discrete MC density sample; the box includes the cell samples and the one-sample normal halo (`-1..+9`). No nominal noise parameter is used as a bound.
Feature boxes that can add volume, edits, invalid input, mixed strata, and any Mixed/Unknown verdict stay on the exact fill path. The default FloatingIslands view does not use this Step-2 tile gate; its Unknown whole boxes (1,635) remain filled. The native classifier path is shared, and a W12 island audit also forced 9,216 uniform Step-2 candidates through fill-and-check.
The generic `Heightfield2D::interval` was sound but too broad here: it gave bounds `[-2,883,809, 1,032,090]` subvoxels around z=-2,114, so all 28,672 Step-2 blocks were Mixed. The exact lattice-column extrema produced useful verdicts instead.
## Soundness sweep
The audit bypassed block skipping and explicitly evaluated every density sample in each candidate's padded block, asserting that none contradicted the verdict. It covered three SurfaceWorld seeds and one FloatingIslands audit:
| Recipe / seed | Blocks checked | Density samples checked | Mixed fallbacks | Unknown | Violations |
|---|---:|---:|---:|---:|---:|
| SurfaceWorld 0 | 27,479 | 36,574,549 | 1,193 | 0 | 0 |
| SurfaceWorld 1 | 26,069 | 34,697,839 | 1,451 | 0 | 0 |
| SurfaceWorld 17 | 26,954 | 35,875,774 | 1,718 | 0 | 0 |
| SurfaceWorld total | 80,502 | 107,148,162 | 4,362 | 0 | 0 |
| FloatingIslands 0 | 9,216 | 12,266,496 | 0 | 0 | 0 |
A violation would be possible if the native density dispatch or `point()` stopped matching this column formula, if a new volume/edit overlay bypassed the Mixed guard, or if the padded lattice/normal halo changed without updating the proof bounds. Zero density is treated as Mixed by the audit.
## W12 samples and worker time
Sample counts compare L8's SurfaceWorld profile with the final L9 profile. Worker seconds are medians of five W12 no-hash runs against `linux7shared` and the Clang candidate. They are per-LOD sums across workers.
| LOD | L9 filled samples | Worker seconds baseline → L9 | Change |
|---:|---:|---:|---:|
| 0 | 5,316,500 | 2.398 → 2.395 | -0.1% |
| 1 | 924,232 | 1.213 → 0.920 | -24.1% |
| 2 | 932,824 | 0.452 → 0.456 | +0.8% |
| 3 | 1,858,789 | 0.540 → 0.549 | +1.6% |
| 4 | 2,085,136 | 1.535 → 1.545 | +0.6% |
| 5 | 987,696 | 1.378 → 1.395 | +1.2% |
| 6 | 658,464 | 2.559 → 2.564 | +0.2% |
| 7 | 329,232 | 1.134 → 1.139 | +0.4% |
| 8 | 1,049,427 | 2.055 → 2.082 | +1.3% |
LOD1 per tile is 42,875 → 2,063 samples.
LOD0 and LOD2–8 stayed within 1.6% of baseline worker time. LOD1's 4.064 worker-seconds in the L8 profile did not reproduce in the specified `linux7shared` binary's worker diagnostics: the five-run median there was 1.213 seconds. The exact-binary interleaved timing below is the comparable whole-view measure.
## W12 interleaved stream time
Baseline is `Standalone/bin/linux/VoxelForgeCoreHeadless-linux7shared`, SHA256 `fbbd468e351c8a0e00c903a7988a3765158e9400ed6a0111898da4d7f5ae6c85`. Each pair used the same seed, camera, 2,553 tiles and W12 settings.
| Pair | Baseline | Clang `-ffp-contract=off` | Delta |
|---:|---:|---:|---:|
| 1 | 1.079 s | 1.066 s | -1.2% |
| 2 | 1.109 s | 1.083 s | -2.3% |
| 3 | 1.145 s | 1.100 s | -3.9% |
| 4 | 1.125 s | 1.099 s | -2.3% |
| 5 | 1.126 s | 1.113 s | -1.2% |
| Median | 1.125 s | 1.099 s | -2.3% |
| Pair | Baseline | GCC 14 default | Delta |
|---:|---:|---:|---:|
| 1 | 1.073 s | 1.100 s | +2.5% |
| 2 | 1.091 s | 1.136 s | +4.1% |
| 3 | 1.104 s | 1.129 s | +2.3% |
| 4 | 1.123 s | 1.140 s | +1.5% |
| 5 | 1.123 s | 1.150 s | +2.4% |
| Median | 1.104 s | 1.136 s | +2.9% |
The baseline ELF contains GCC 14 and Clang 19 objects; the candidate GCC binary is GCC-only. As a compiler-matched control, five W12 pairs against the GCC-only `linux7gcc` baseline measured 1.154 s → 1.116 s (-3.3%). Thus the specified-binary GCC comparison is slower, while the matched GCC control is faster; the mixed-toolchain delta cannot be attributed to this change. The Clang candidate is faster than the specified binary.
FloatingIslands seed 0 hashes match at W1/W12 for both compilers. Five W12 no-hash pairs against `linux7shared` gave Clang 10.836 → 11.005 s (+1.6%, pair range -0.5% to +3.0%). GCC was 11.223 → 12.618 s (+12.4%), while five compiler-matched GCC pairs against `linux7gcc` were 12.498 → 12.529 s (+0.25%, pair range -0.5% to +1.3%). The default island path has no measurable same-compiler slowdown; the large `linux7shared` GCC delta is the same toolchain mismatch.
## Hashes
Every SurfaceWorld hash below matched the baseline at W1/W8/W12 for both compilers; W12 was repeated five times per compiler. FloatingIslands seed 0 matched at W1/W12 for both compilers. Per-LOD tuples are density / mesh / payload / topology.
SurfaceWorld full detail: density `0x0ee0579bd15cbbe4`, mesh `0x32e5d4964d610fee`, payload `0x1932b96ee4b1d910`, topology `0x69743c6bad3447dc`.
SurfaceWorld whole view: density `0xc10697a8f48380c7`, mesh `0xe75c9119a1498cd5`, payload `0x49a9a8d1835a6c8c`, topology `0xedcb23288b5e8724`.
SurfaceWorld exact queries (9 probes): density/unclamped `0xe4d4a8eb95b35933`, detail `0xefcba20c0c70c415`, collision `0xe604823a249029bf`.
| LOD | Density | Mesh | Payload | Topology |
|---:|---|---|---|---|
| 0 | `0x769f2a706d585a72` | `0x33eeeb39fa443816` | `0x645621a1d968983f` | `0xc2457ed905036c9d` |
| 1 | `0x69cc5a5c0a2c60af` | `0xb48335f5410c57d5` | `0xd15c5480162ab8ba` | `0xfeca1bd025823604` |
| 2 | `0x85deed5683a77202` | `0x53469895987aeea2` | `0xe55f8ae7e1532033` | `0xd5feb12a0e85c09b` |
| 3 | `0x6518caefb3be7e7f` | `0xec513c90b853a614` | `0xf62fa1137ff17f82` | `0xccf1dcf681965816` |
| 4 | `0x62d4be96021992f4` | `0xf1e4c6efcc2615a9` | `0x9dc5f9c88be02f33` | `0xfe6f55125a07c3bf` |
| 5 | `0x5e4a8c38b8cea6fc` | `0x08ee56998aaf21e5` | `0x541eea8558f26cc8` | `0x6539374a8b3336d8` |
| 6 | `0xe036e95b9006945b` | `0x624a33f941a99b02` | `0x81b73e14f68bdf86` | `0x4de4c63ce1f80a56` |
| 7 | `0x8ee358af56a30d8d` | `0x46ab3c6184048b7c` | `0x0a6164b7e68e80c5` | `0x0c26b85bb03bc831` |
| 8 | `0xc3458e1cbdb9c471` | `0x46c03d0994d75192` | `0x8f89fc5bde12d230` | `0xd16dc0cf62031898` |
FloatingIslands full detail: density `0x6d842d2878b08ef6`, mesh `0x4b868a3184f08035`, payload `0x2cedf2236788752d`, topology `0xeac17d5e0cb5044a`.
FloatingIslands whole view: density `0x5be4d8cde79b2a76`, mesh `0x96f75041f6861b3a`, payload `0x3700a516cc89d50c`, topology `0x6b99948d6eab4f21`.
FloatingIslands exact queries (9 probes): density/unclamped `0x61daded9c303becb`, detail `0xefcba20c0c70c415`, collision `0x84d37463be9b0573`.
| LOD | Density | Mesh | Payload | Topology |
|---:|---|---|---|---|
| 0 | `0xf2524906044ef994` | `0x15b2828701a06591` | `0x4cbbf7ade54321f7` | `0x2c0382f590d69610` |
| 1 | `0x71b4c8327ad91da7` | `0xfd2280177adb70c9` | `0xc6f695b969ca8573` | `0xb7b026366bc5b627` |
| 2 | `0x23925de354d86f14` | `0xd4b470b6aae75cab` | `0x38c39feddc72ca0c` | `0x8496f76d94d0e578` |
| 3 | `0x4cb68a60bc8a5103` | `0x30514ad73d41fd87` | `0x39a209d2ec7695b1` | `0xa2ffa199ba1e1215` |
| 4 | `0x0e95c8abbcf6fb37` | `0x966b891fbe67794a` | `0xf01627522109d362` | `0xd7bfb2fea0137c0c` |
| 5 | `0xf444ffed34a1bd20` | `0x7f3073ed3a711113` | `0xad32e4ea4a1b4d50` | `0x6fdba8d6e549193c` |
| 6 | `0x6a6b4f75b9583ec7` | `0xdbb540e17a46b981` | `0xe2374a66e9d12b22` | `0xd384b7c0c0247982` |
| 7 | `0x5c4e824aaa7e5f73` | `0x44857e6de8e89645` | `0xa4ac0bf1da59e406` | `0x94f425b0d77004c8` |
| 8 | `0x8ce5f96cb24bc365` | `0xa1406a9a6dcae02b` | `0x8b5e182d38fe352b` | `0x098f65c1a8cde739` |
## Instrumentation, builds and limits
Removed the L8 phase/stage probes from the normal path. Kept `--profile-lod-work` for per-LOD density sample counts and added `--audit-uniform-block-proofs`; both are off by default. Normal runs do not perform the audit fill-and-check pass or sample-count aggregation. The optional LOD0 MC (1.348 worker-s) and shape compile (215 ms) were counted in L8 and not changed.
No async task or epoch path changed. The L3 FP-contract preamble/self-test, L4 `FLazy`, L7 shared cache, ARCHITECTURE §8.10 two-pass MC/SSE noise/clipmap-streaming invariants, and generator density output remain unchanged.
Clang 19 (`-ffp-contract=off`) and GCC 14 default builds used `-j12`; SHA256s are `0cd3f0ef993ced2c615418c6e2b37b83f57eff6d024d7d1568c30ea51490384a` and `23fe40de558b1b6931469cc5e976a0e4f2ed5fb6c362bc746dcc64a38fa40e08`. Peak build RSS was 901,940 KiB; highest measured runtime RSS was 623,928 KiB. Runs used CPUs 0–11, a 6 GiB address-space limit, normal priority, and the unchanged `powersave` governor. No run exceeded 30 minutes or remained stuck for 15 minutes.
## Failed and retried runs
- The first build wrapper failed because `/usr/bin/time` is absent; direct builds succeeded. One RSS sampling wrapper hung on zombie handling and was interrupted; later measurements used a corrected monitor.
- Initial proof-audit commands exited 2 because the positional data file and required stream modes were missing. Corrected commands completed. The first broad global interval returned Mixed for all 28,672 blocks and was replaced by the exact lattice-column proof.
- An early all-step audit found two legacy step-8 uniform candidates whose exact filled-grid signs disagreed; the existing post-fill validator cleared them before skip. The new audit is scoped to the native step-2 proof; step 8 is unchanged.
- The first Clang retry failed to compile because `SampleGridPoint` was outside its lambda scope; it was corrected to call `DensityAtLattice` directly and rebuilt.
- The first hash comparison differed because a uniform-tile early return bypassed debug density capture. Step-2 hash runs now refill omitted samples after exercising sparse MC. A separate FloatingIslands mismatch came from changing `>= 0` to `> 0`; the legacy `>= 0` comparison was restored and both compiler hashes then matched.
**Owner note:** LOD1 now fills 95% fewer samples with zero proof violations, and all SurfaceWorld and FloatingIslands hashes match. The GCC W12 comparison against `linux7shared` is toolchain-confounded; GCC-to-GCC controls are flat or faster, while the Clang candidate is faster than the requested baseline.
## Orchestrator review (Claude)
- **Re-run by me, 5 interleaved W12 pairs, L1 view.** Without `--stream-hash` (game-like):
whole view L7 1.379/1.485/1.430/1.439/1.449 s vs L9 1.390/1.409/1.401/1.423/1.429 s (median
1.439 → 1.409 s, −2.1%); stream wall 1.140 → 1.112 s (−2.5%). With hashing on, the difference is
inside noise (1.748 vs 1.744 s), because hashing adds ~0.3 s. The whole-view hash is identical in
all runs.
- **The L8 lever was inflated by L8's own instrumentation.** L8's profile build reported LOD1 at
4.06 worker-s; the plain `linux7shared` binary spends 1.21. Per-LOD shares from instrumented builds
must be re-checked on a plain build before they're ranked.
- The "baseline ELF contains GCC and Clang objects" remark is expected: crt/libstdc++ objects always
come from GCC. The compiler-matched controls are the right comparison, as Luna did.
- Proof read: for native SurfaceWorld step-2 tiles the verdict uses exact column extrema over the
padded block (cells plus the −1..+9 normal halo) for density `min(z−ground, cap−z)`. Features, edits,
mixed strata and Unknown verdicts all fill. The 80,502-block audit found 0 violations.
@@ -39,6 +39,8 @@ namespace
bool ForceGenerate=false;
bool MeshCoverage=false;
bool ScreenSpaceGate=false;
bool AuditUniformBlockProofs=false;
bool ProfileLodWork=false;
bool HasSeedOverride=false;
int SeedOverride=0;
bool HasRenderDistanceOverride=false;
@@ -111,6 +113,8 @@ namespace
" --auto-surface-camera (place the 27-tile cube on this seed's surface)\n"
" --mesh-coverage (report non-empty tiles and indexed triangles)\n"
" --screen-space-gate (measure display error and historical negative controls)\n"
" --audit-uniform-block-proofs (fill and check every interval-certified block)\n"
" --profile-lod-work (report per-LOD density sample counts)\n"
" --render-distance-chunks=N (0 disables the extra far ring)\n"
" --tls-probe=N (Linux worker TLS/stack measurement; N=0..12)\n"
" --tls-probe-touch=none|surface-world|floating-islands (first-use probe)\n"
@@ -126,6 +130,8 @@ namespace
else if(arg=="--force-generate")options.ForceGenerate=true;
else if(arg=="--mesh-coverage")options.MeshCoverage=true;
else if(arg=="--screen-space-gate")options.ScreenSpaceGate=true;
else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true;
else if(arg=="--profile-lod-work")options.ProfileLodWork=true;
else if(arg=="--auto-surface-camera")options.AutoSurfaceCamera=true;
else if(arg.starts_with("--recipe="))
{
@@ -348,5 +354,5 @@ int main(int argc,char** argv)
options.ProfileColumnOverlap,options.FarHorizonLOD8InteriorStepVoxels,
options.MeshCoverage,options.MeshExportPath,options.CameraYawDegrees,
options.CameraPitchDegrees,options.ScreenSpaceGate,options.UseSharedColumnCache,
cameraStepVoxels);
cameraStepVoxels,options.AuditUniformBlockProofs,options.ProfileLodWork);
}
+31 -2
View File
@@ -138,7 +138,8 @@ namespace StandaloneStreamBenchmark
int32 FarHorizonLOD8InteriorStepVoxels,bool bReportMeshCoverage=false,
const std::filesystem::path& MeshExportPath={},float CameraYawDegrees=0.0f,
float CameraPitchDegrees=0.0f,bool bScreenSpaceGate=false,
bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector)
bool bUseSharedColumnCache=true,FVector CameraStepVoxels=FVector::ZeroVector,
bool bAuditUniformBlockProofs=false,bool bReportLodWorkProfile=false)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
@@ -264,6 +265,7 @@ namespace StandaloneStreamBenchmark
FStandaloneStreamingGenerator Streamer(World,WorkerCount,bHashDensity,nullptr,MaxLevel,
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache);
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
if(bScreenSpaceGate)Streamer.SetMesherStageProfilingEnabled(true);
const auto StreamStart=Clock::now();
const FStandaloneStreamingUpdate Update=Streamer.StartWithDesired(Desired);
@@ -330,6 +332,7 @@ namespace StandaloneStreamBenchmark
std::array<double,9> GroundRefineExclusiveMsByLOD{},CapRefineExclusiveMsByLOD{};
std::array<double,9> MeshAssemblyMsByLOD{};
std::array<double,9> SkirtMsByLOD{};
std::array<std::uint64_t,9> DensitySamplesByLOD{};
std::array<std::uint64_t,9> SkirtTrianglesByLOD{};
std::array<std::uint64_t,9> TileCountByLOD{};
for(const FVoxelTileKey& Tile:Desired.Tiles)
@@ -354,6 +357,8 @@ namespace StandaloneStreamBenchmark
GateSampleDistances.fill(std::numeric_limits<double>::infinity());
Clock::time_point NeighborhoodReady{},FullDetailReady{},WholeViewReady{};
bool bNeighborhoodReported=false,bFullDetailReported=false;
uint64 BlockProofBlocksChecked=0,BlockProofSamplesChecked=0;
uint64 BlockProofFallbackBlocks=0,BlockProofUnknownBlocks=0,BlockProofViolations=0;
while(Finished<Update.DesiredTiles)
{
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
@@ -379,7 +384,16 @@ namespace StandaloneStreamBenchmark
CapRefineExclusiveMsByLOD[LOD]+=Tile.CoreDiagnostics.capRefinementExclusiveMilliseconds;
MeshAssemblyMsByLOD[LOD]+=Tile.CoreDiagnostics.meshAssemblyMilliseconds;
SkirtMsByLOD[LOD]+=Tile.CoreDiagnostics.marchingCubesSkirtMilliseconds;
if(bReportLodWorkProfile)DensitySamplesByLOD[LOD]+=Tile.DensitySamples;
SkirtTrianglesByLOD[LOD]+=Tile.SkirtTriangleCount;
if(bAuditUniformBlockProofs)
{
BlockProofBlocksChecked+=Tile.CoreDiagnostics.uniformBlockProofsChecked;
BlockProofSamplesChecked+=Tile.CoreDiagnostics.uniformBlockProofSamplesChecked;
BlockProofFallbackBlocks+=Tile.CoreDiagnostics.uniformBlockProofFallbackBlocks;
BlockProofUnknownBlocks+=Tile.CoreDiagnostics.uniformBlockProofUnknownBlocks;
BlockProofViolations+=Tile.CoreDiagnostics.uniformBlockProofViolations;
}
if(bScreenSpaceGate&&Assembly&&Tile.Key.Level>=3&&Tile.Key.Level<9
&&!Tile.Vertices.empty()
&&StandaloneScreenSpaceGate::TileHasNativeSurface(Tile.Key,*Assembly,
@@ -600,6 +614,13 @@ namespace StandaloneStreamBenchmark
GroundRefineExclusiveMsByLOD[LOD],CapRefineExclusiveMsByLOD[LOD],
SkirtMsByLOD[LOD],static_cast<unsigned long long>(SkirtTrianglesByLOD[LOD]),
MeshAssemblyMsByLOD[LOD]);
if(bReportLodWorkProfile)
{
const double SamplesPerTile=TileCountByLOD[LOD]
?static_cast<double>(DensitySamplesByLOD[LOD])/TileCountByLOD[LOD]:0.0;
std::printf("[WorldAssemblerLODSamples] lod=%zu samples=%llu samples_per_tile=%.1f\n",
LOD,static_cast<unsigned long long>(DensitySamplesByLOD[LOD]),SamplesPerTile);
}
}
const double NeighborhoodSeconds=std::chrono::duration<double>(NeighborhoodReady-ColdStart).count();
const double NeighborhoodMeshSeconds=std::chrono::duration<double>(NeighborhoodReady-ShapeReady).count();
@@ -625,6 +646,13 @@ namespace StandaloneStreamBenchmark
static_cast<unsigned long long>(NativeColumnMisses),
NativeColumnComputeMilliseconds,NativeClassificationMilliseconds,
NativeMeshingMilliseconds);
if(bAuditUniformBlockProofs)
std::printf("[UniformBlockProofAudit] checked_blocks=%llu checked_samples=%llu fallback_blocks=%llu unknown_blocks=%llu violations=%llu\n",
static_cast<unsigned long long>(BlockProofBlocksChecked),
static_cast<unsigned long long>(BlockProofSamplesChecked),
static_cast<unsigned long long>(BlockProofFallbackBlocks),
static_cast<unsigned long long>(BlockProofUnknownBlocks),
static_cast<unsigned long long>(BlockProofViolations));
bool bHashesPassing=true;
if(bHashDensity)
@@ -701,6 +729,7 @@ namespace StandaloneStreamBenchmark
return NeighborhoodFinished==static_cast<int32>(Neighborhood.size())
&&FullDetailFinished==FullDetailExpected&&Finished==Update.DesiredTiles&&bHashesPassing
&&(!bProfileColumnOverlap||bColumnOverlapCapturePassing)
&&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing?0:6;
&&(!bExportRequested||bSceneExportPassing)&&bScreenSpaceGatePassing
&&(!bAuditUniformBlockProofs||BlockProofViolations==0)?0:6;
}
} // namespace StandaloneStreamBenchmark
+4
View File
@@ -650,6 +650,8 @@ public:
void SetMesherStageProfilingEnabled(bool Enabled)
{bProfileMesherStages=Enabled;}
void SetUniformBlockProofAuditEnabled(bool Enabled)
{bAuditUniformBlockProofs=Enabled;}
FStandaloneCpuTile GenerateDiagnostic(const FVoxelTileKey& Key,
std::uint32_t GlobalOctaveDrop=0,std::uint32_t CellStride=1,
bool ForceGenerate=false)
@@ -821,6 +823,7 @@ private:
Options.useSharedColumnCache=bSharedColumnCache;
Options.lod8HorizonInteriorStepVoxels=Lod8HorizonInteriorStepVoxels;
Options.profileMesherStages=bProfileMesherStages&&!ForceGenerate;
Options.auditUniformBlockProofs=bAuditUniformBlockProofs&&!ForceGenerate;
Options.diagnosticGlobalOctaveDrop=DiagnosticGlobalOctaveDrop;
Options.diagnosticCellStride=std::max<std::uint32_t>(1,DiagnosticCellStride);
Options.diagnosticColumnInterpolationStride=
@@ -999,6 +1002,7 @@ private:
bool bSharedColumnCache=true;
int32 Lod8HorizonInteriorStepVoxels=0;
bool bProfileMesherStages=false;
bool bAuditUniformBlockProofs=false;
std::atomic<uint64> CacheHitCount{0};
mutable std::mutex Mutex;
std::condition_variable Wake;
@@ -121,7 +121,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
FVoxelSharedDensityGrid* OutPreEditDensityGrid,
const FVoxelSharedDensityGrid* InSharedDensityGrid,
std::vector<float>* OutDebugDensitySamples,
FVoxelMarchingCubesStageTimings* OutStageTimings)
FVoxelMarchingCubesStageTimings* OutStageTimings,
FVoxelUniformBlockProofAuditStats* OutBlockProofAudit)
{
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_MesherGenerateMesh);
const uint64 StageMesherStartCycles=OutStageTimings?FPlatformTime::Cycles64():0;
@@ -130,6 +131,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
if (OutPreEditDensityGrid) { OutPreEditDensityGrid->Reset(); }
if (OutDensitySampleCount) { *OutDensitySampleCount = 0; }
if (OutStageTimings) { *OutStageTimings = FVoxelMarchingCubesStageTimings{}; }
if (OutBlockProofAudit) { *OutBlockProofAudit = FVoxelUniformBlockProofAuditStats{}; }
if (OutDebugDensitySamples) { OutDebugDensitySamples->clear(); }
if (!Generator) return MeshData;
const bool bEmitUV = !bStandaloneSkipUvAndColors && !bStandaloneSkipUV;
@@ -550,22 +552,19 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
MesherSetupTimer.End();
// Optional 8x8x8-cell block proof. The tile classifier has already returned Mixed, but
// that is a conservative answer over the whole tile. A tile can still be uniformly solid
// (or uniformly air) when its smaller blocks are each provable. Do this before allocating
// or filling the density grid: the grid is only needed when at least one block can contain
// a surface. A whole-tile early return is allowed only when every relevant block has the
// SAME verdict; adjacent uniform blocks with opposite signs can contain a surface between
// them. This is a proof-only optimization: ClassifyTile is conservative and no samples or
// resolution are removed from a tile that reaches the mesher.
// Optional 8x8x8-cell block proof. Mixed/Unknown blocks always fall back to exact density
// sampling. The Core SurfaceWorld column-range proof at Step 2 can also omit evaluations
// outside active blocks and their one-sample normal halo.
TArray<uint8> BlockSkip;
int32 BlocksPerAxis = 0;
// LOD2's 16-cell tile is the remaining false-Mixed empty case in the streamed game path.
// Its step-8 lattice can use the same proof-only 8-cell block partition as LOD0. Keep the
// gate off for steps 2/16/32: their meshing work is already smaller than repeating a full
// tile classifier per block, and this preserves the established coarse-LOD latency profile.
// Step 2 is enabled only for a tile wholly inside one native SurfaceWorld stratum. Steps
// 16/32 keep the historical gate off because their smaller grids do not amortize per-block queries.
const bool bNativeSurfaceTileProof = Step == 2 && ShapeWorldContext != nullptr
&& ShapeWorldContext->IsNativeSurfaceBox(OriginVoxels,Step,CellsPerAxis);
const bool bUseProofBlocks = bUseBlockEarlyOut && !OutCaptureGrid
&& (Step == 1 || Step == 8);
&& (Step == 1 || Step == 8 || (Step == 2
&& (bNativeSurfaceTileProof || OutBlockProofAudit != nullptr)));
bool bCanSkipProofBlockGrid = bNativeSurfaceTileProof;
if (bUseProofBlocks)
{
constexpr int32 BlockCells = 8;
@@ -613,18 +612,27 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
VoxelDensityProfile::RecordClassifierCall(bSampleClassifier);
}
EVoxelTileClass Verdict;
bool bBlockUnknown = false;
bool bBlockNative = false;
if(ShapeWorldContext&&Step<=2)
{
const auto ShapeVerdict=ShapeWorldContext->ClassifyBox(
BlockOrigin,Step,BlockCells);
Verdict=ShapeVerdict==EVoxelTileClass::AllSolid
const auto ShapeVerdict=ShapeWorldContext->ClassifyBoxDetailed(
BlockOrigin,Step,BlockCells,Step==2);
Verdict=ShapeVerdict.Verdict==EVoxelTileClass::AllSolid
?EVoxelTileClass::AllSolid
:ShapeVerdict==EVoxelTileClass::AllAir
:ShapeVerdict.Verdict==EVoxelTileClass::AllAir
?EVoxelTileClass::AllAir:EVoxelTileClass::Mixed;
bBlockUnknown=ShapeVerdict.bUnknown;
bBlockNative=ShapeVerdict.bNativeSurface;
if(Step==2&&!ShapeVerdict.bNativeSurface)
bCanSkipProofBlockGrid=false;
}
else
{
if(Step==2)bCanSkipProofBlockGrid=false;
Verdict=Generator->ClassifyTile(BlockOrigin,Step,BlockCells,
bSampleClassifier ? &ClassifierStats : nullptr);
}
if (bSampleClassifier)
{
VoxelDensityProfile::AddSampledMeasurement(
@@ -699,20 +707,70 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
ClassifierStats.RoomTailCycles);
}
}
if (Verdict == EVoxelTileClass::AllSolid
|| Verdict == EVoxelTileClass::AllAir)
{
if(OutBlockProofAudit&&Step==2&&bBlockNative)
{
++OutBlockProofAudit->CheckedBlocks;
const int32 ProofMinX=BlockX*BlockCells-1;
const int32 ProofMinY=BlockY*BlockCells-1;
const int32 ProofMinZ=BlockZ*BlockCells-1;
const int32 ProofMaxX=BlockX*BlockCells+BlockCells+1;
const int32 ProofMaxY=BlockY*BlockCells+BlockCells+1;
const int32 ProofMaxZ=BlockZ*BlockCells+BlockCells+1;
bool bUniform=true;
for(int32 Z=ProofMinZ;Z<=ProofMaxZ&&bUniform;++Z)
for(int32 Y=ProofMinY;Y<=ProofMaxY&&bUniform;++Y)
for(int32 X=ProofMinX;X<=ProofMaxX;++X)
{
++OutBlockProofAudit->CheckedSamples;
const float Density=ShapeWorldContext
?ShapeWorldContext->DensityAtLattice(
OriginVoxels.X+X*Step,
OriginVoxels.Y+Y*Step,
OriginVoxels.Z+Z*Step)
:Generator->GetDensityAtLattice(
OriginVoxels.X+X*Step,
OriginVoxels.Y+Y*Step,
OriginVoxels.Z+Z*Step);
if(!VoxelMath::IsFinite(Density)||Density==0.0f
||(Verdict==EVoxelTileClass::AllSolid
?Density>=0.0f:Density<=0.0f))
{
std::printf("[UniformBlockProofViolation] tile_origin=(%d,%d,%d) step=%d cells=%d block=(%d,%d,%d) sample=(%d,%d,%d) expected=%s density=%.9g native=%d unknown=%d\n",
OriginVoxels.X,OriginVoxels.Y,OriginVoxels.Z,Step,
CellsPerAxis,BlockX,BlockY,BlockZ,
OriginVoxels.X+X*Step,OriginVoxels.Y+Y*Step,
OriginVoxels.Z+Z*Step,
Verdict==EVoxelTileClass::AllSolid?"solid":"air",
Density,bBlockNative?1:0,bBlockUnknown?1:0);
bUniform=false;
break;
}
}
if(!bUniform)
{
++OutBlockProofAudit->Violations;
Verdict=EVoxelTileClass::Mixed;
}
}
}
if (Verdict == EVoxelTileClass::Mixed)
{
if(OutBlockProofAudit&&Step==2)
{
++OutBlockProofAudit->FallbackBlocks;
if(bBlockUnknown)++OutBlockProofAudit->UnknownBlocks;
}
MixedBlockIndices.Add(
((BlockZ * BlocksPerAxis) + BlockY) * BlocksPerAxis + BlockX);
}
if (Verdict == EVoxelTileClass::AllSolid
|| Verdict == EVoxelTileClass::AllAir)
{
// Keep the classifier result as a candidate until the exact density grid
// used by this mesher has been filled. ClassifyTile is conservative by
// contract, but its proof and the mesher share worker-local caches; a
// cache replacement must never turn that contract into a cell skip by
// itself. The post-grid sign check below is the final proof consumed by
// the cell loop and clears any candidate whose actual MC vertices disagree.
// In the ordinary path, candidates are checked against the filled grid.
// The Step-2 supremum interval path is itself the proof used to omit fills.
BlockSkip[((BlockZ * BlocksPerAxis) + BlockY) * BlocksPerAxis + BlockX] =
Verdict == EVoxelTileClass::AllSolid ? 1 : 2;
if (!bHaveUniformBlock)
@@ -806,7 +864,8 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
// ClassifyTile path already relies on this same non-Mixed proof contract. Return before
// allocating the density grid; no samples are skipped for a tile that can contain
// geometry, and the final geometry remains byte-identical because this path emits none.
if (bHaveUniformBlock && bAllRelevantBlocksSame && bAllRelevantBlocksUniform)
if (bHaveUniformBlock && bAllRelevantBlocksSame && bAllRelevantBlocksUniform
&& !(Step == 2 && OutDebugDensitySamples != nullptr))
{
return MeshData;
}
@@ -841,6 +900,43 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
&& SharedDeltaX + GridDim < ReuseGrid->Dim
&& SharedDeltaY + GridDim < ReuseGrid->Dim
&& SharedDeltaZ + GridDim < ReuseGrid->Dim;
const bool bSkipProofBlockGrid = bUseProofBlocks && bCanSkipProofBlockGrid
&& OutBlockProofAudit == nullptr && OutPreEditDensityGrid == nullptr
&& !bUseSharedDensityGrid;
static thread_local TArray<uint8> RequiredGridSamples;
if(bSkipProofBlockGrid)
{
RequiredGridSamples.SetNumUninitialized(MDim*MDim*MDim);
FMemory::Memzero(RequiredGridSamples.GetData(),
static_cast<SIZE_T>(RequiredGridSamples.Num())*sizeof(uint8));
constexpr int32 BlockCells=8;
for(int32 BlockZ=0;BlockZ<BlocksPerAxis;++BlockZ)
{
const int32 BlockMinZ=BlockZ*BlockCells;
const int32 BlockMaxZ=FMath::Min(CellsPerAxis-1,BlockMinZ+BlockCells-1);
if(BlockMaxZ<CzLo||BlockMinZ>CzHi)continue;
for(int32 BlockY=0;BlockY<BlocksPerAxis;++BlockY)
for(int32 BlockX=0;BlockX<BlocksPerAxis;++BlockX)
{
const int32 BlockIndex=((BlockZ*BlocksPerAxis)+BlockY)*BlocksPerAxis+BlockX;
if(BlockSkip[BlockIndex]!=0)continue;
const int32 CellMinX=BlockX*BlockCells;
const int32 CellMinY=BlockY*BlockCells;
const int32 CellMaxX=FMath::Min(CellsPerAxis-1,CellMinX+BlockCells-1);
const int32 CellMaxY=FMath::Min(CellsPerAxis-1,CellMinY+BlockCells-1);
const int32 SampleMinX=FMath::Max(-1,CellMinX-1);
const int32 SampleMaxX=FMath::Min(GridDim,CellMaxX+2);
const int32 SampleMinY=FMath::Max(-1,CellMinY-1);
const int32 SampleMaxY=FMath::Min(GridDim,CellMaxY+2);
const int32 SampleMinZ=FMath::Max(GzLo,FMath::Max(CzLo,BlockMinZ)-1);
const int32 SampleMaxZ=FMath::Min(GzHi,FMath::Min(CzHi,BlockMaxZ)+2);
for(int32 Z=SampleMinZ;Z<=SampleMaxZ;++Z)
for(int32 Y=SampleMinY;Y<=SampleMaxY;++Y)
for(int32 X=SampleMinX;X<=SampleMaxX;++X)
RequiredGridSamples[((Z+1)*MDim+(Y+1))*MDim+(X+1)]=1;
}
}
}
const bool bCapturePreEditGrid = OutPreEditDensityGrid != nullptr
&& !bUseSharedDensityGrid
&& Step == 1 && CellsPerAxis == CHUNK_SIZE
@@ -1046,6 +1142,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
auto SampleGridPoint = [&](int32 gx, int32 gy, int32 gz)
{
const int32 LocalIndex = ((gz + 1) * MDim + (gy + 1)) * MDim + (gx + 1);
if(bSkipProofBlockGrid&&RequiredGridSamples[LocalIndex]==0)return;
if (bUseSharedDensityGrid)
{
const int32 SharedX = SharedDeltaX + gx;
@@ -1092,9 +1189,9 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const FStandaloneShapeWorld* ActiveShapeWorld=ShapeWorldContext;
const bool bUseShapeWorldZBatch=ActiveShapeWorld!=nullptr
&&ActiveShapeWorld->IsAnalyticOnly()
&&!bUseSharedDensityGrid&&!bCapturePreEditGrid;
&&!bUseSharedDensityGrid&&!bCapturePreEditGrid&&!bSkipProofBlockGrid;
const bool bUseShapeWorldXBatch=ActiveShapeWorld!=nullptr
&&!bUseSharedDensityGrid&&!bCapturePreEditGrid;
&&!bUseSharedDensityGrid&&!bCapturePreEditGrid&&!bSkipProofBlockGrid;
if(bUseShapeWorldZBatch&&!bUseVerticalCacheTraversal)
{
for(const std::vector<int32>& YGroup:YGroups)
@@ -1242,6 +1339,34 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
if (OutDebugDensitySamples)
{
// Hash/debug runs need the complete reference density lattice. Let MC exercise the
// sparse block path, then evaluate omitted samples before exporting that lattice.
if(bSkipProofBlockGrid)
{
for(int32 gz=GzLo;gz<=GzHi;++gz)
for(int32 gy=-1;gy<=GridDim;++gy)
for(int32 gx=-1;gx<=GridDim;++gx)
{
const int32 LocalIndex=((gz+1)*MDim+(gy+1))*MDim+(gx+1);
if(RequiredGridSamples[LocalIndex]!=0)continue;
RequiredGridSamples[LocalIndex]=1;
const int32 ReachBlockX=FMath::Clamp(gx,0,CellsPerAxis-1)
/VoxelGenLOD::TileReachBlockCells;
const int32 ReachBlockY=FMath::Clamp(gy,0,CellsPerAxis-1)
/VoxelGenLOD::TileReachBlockCells;
const int32 ReachBlockZ=FMath::Clamp(gz,0,CellsPerAxis-1)
/VoxelGenLOD::TileReachBlockCells;
VoxelGenLOD::TileReachBlockIndex=
((ReachBlockZ*ReachBlocksPerAxis)+ReachBlockY)*ReachBlocksPerAxis+ReachBlockX;
const int32 SampleX=OriginVoxels.X+gx*Step;
const int32 SampleY=OriginVoxels.Y+gy*Step;
const int32 SampleZ=OriginVoxels.Z+gz*Step;
DensityGrid[LocalIndex]=ShapeWorldContext
?ShapeWorldContext->DensityAtLattice(SampleX,SampleY,SampleZ)
:Generator->GetDensityAtLattice(SampleX,SampleY,SampleZ);
if(OutDensitySampleCount)++(*OutDensitySampleCount);
}
}
const size_t SampleCount = static_cast<size_t>(GzHi - GzLo + 1)
* static_cast<size_t>(MDim) * static_cast<size_t>(MDim);
OutDebugDensitySamples->reserve(SampleCount);
@@ -1259,7 +1384,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
FPlatformTime::Cycles64()-StageDensityGridStartCycles)
*FPlatformTime::GetSecondsPerCycle64()*1000.0;
if (bUseProofBlocks)
if (bUseProofBlocks&&(!bSkipProofBlockGrid||OutDebugDensitySamples!=nullptr))
{
// Finalize every block candidate against the exact density samples that the marching-
// cubes loop will consume. This is intentionally redundant with ClassifyTile: it is a
@@ -57,6 +57,17 @@ struct FVoxelMarchingCubesStageTimings
uint64 GradientMemoHits = 0;
};
// Opt-in soundness audit for density blocks which the Core mesher would skip.
// Audit de justesse facultatif pour les blocs de densite que Core sauterait.
struct FVoxelUniformBlockProofAuditStats
{
uint64 CheckedBlocks = 0;
uint64 CheckedSamples = 0;
uint64 FallbackBlocks = 0;
uint64 UnknownBlocks = 0;
uint64 Violations = 0;
};
// Stable plan data copied onto one worker-owned mesher for hybrid LOD0 generation.
// Donnees stables du plan copiees dans un mailleur de worker pour le mode hybride LOD0.
struct FVoxelHybridSharpFeatureBox
@@ -108,7 +119,8 @@ public:
FVoxelSharedDensityGrid* OutPreEditDensityGrid = nullptr,
const FVoxelSharedDensityGrid* InSharedDensityGrid = nullptr,
std::vector<float>* OutDebugDensitySamples = nullptr,
FVoxelMarchingCubesStageTimings* OutStageTimings = nullptr);
FVoxelMarchingCubesStageTimings* OutStageTimings = nullptr,
FVoxelUniformBlockProofAuditStats* OutBlockProofAudit = nullptr);
//=========================================================================
// SERVICES (injectés par AVoxelWorld)