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

@@ -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