wip(assembler): round S14 -- 4-way column cache + memoized MC gradients (output unchanged)

Worker-local XY column cache uses deterministic 4-way sets at LOD3-8: LOD4
misses 8,224 -> 1,437, conflicts 7,407 -> 0 (direct-map control: 6.62 s /
43.5 worker-s vs 4.24 s / 21.7). Exact LOD0 lattice gradients memoized per
tile: MC-exclusive 242 -> 201 ns/sample, two-pass loop unchanged. Hashes
identical, no recipe bump. Primary cold trace 4.24 s full set, ring 0.45 s,
75/75 at 40 m/s; a repeat ran uniformly ~40% slower on every LOD (machine
contention suspected); tick p95 to re-check on an idle machine. CVars
voxel.CoreColumnCacheDirectMapped / voxel.CoreMCGradientMemoization.
Report: Standalone/Research/WorldAssemblerM3/Round18.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 17:58:54 +02:00
1 parent bd5e38594f
commit ec2afe9c93
11 files changed
+769 -50

No files matched your search

@@ -120,13 +120,16 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
int64* OutDensitySampleCount,
FVoxelSharedDensityGrid* OutPreEditDensityGrid,
const FVoxelSharedDensityGrid* InSharedDensityGrid,
std::vector<float>* OutDebugDensitySamples)
std::vector<float>* OutDebugDensitySamples,
FVoxelMarchingCubesStageTimings* OutStageTimings)
{
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_MesherGenerateMesh);
const uint64 StageMesherStartCycles=OutStageTimings?FPlatformTime::Cycles64():0;
FVoxelMeshData MeshData;
if (OutCaptureGrid) { OutCaptureGrid->Reset(); }
if (OutPreEditDensityGrid) { OutPreEditDensityGrid->Reset(); }
if (OutDensitySampleCount) { *OutDensitySampleCount = 0; }
if (OutStageTimings) { *OutStageTimings = FVoxelMarchingCubesStageTimings{}; }
if (OutDebugDensitySamples) { OutDebugDensitySamples->clear(); }
if (!Generator) return MeshData;
const bool bEmitUV = !bStandaloneSkipUvAndColors && !bStandaloneSkipUV;
@@ -851,6 +854,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
// Bande de strate : seules les rangées Z réellement lues (cellules CzLo..CzHi + marges de
// gradient) sont échantillonnées — le reste du tampon reste non initialisé et non lu.
const uint64 StageDensityGridStartCycles=OutStageTimings?FPlatformTime::Cycles64():0;
VoxelDensityProfile::FScopedTimer MesherDensityGridTimer(
VoxelDensityProfile::EBucket::MesherDensityGrid);
#if WITH_EDITOR
@@ -1250,6 +1254,10 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
}
MesherDensityGridTimer.End();
if(OutStageTimings)
OutStageTimings->DensityGridMilliseconds=static_cast<double>(
FPlatformTime::Cycles64()-StageDensityGridStartCycles)
*FPlatformTime::GetSecondsPerCycle64()*1000.0;
if (bUseProofBlocks)
{
@@ -1345,6 +1353,22 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
{
return DensityGrid[((gz + 1) * MDim + (gy + 1)) * MDim + (gx + 1)];
};
// Reuse exact grid-corner gradients between incident cells within this tile.
// Reutiliser les gradients exacts des coins entre cellules voisines de cette tuile.
static thread_local TArray<FVector> GradientMemo;
static thread_local TArray<uint8> GradientMemoValid;
const bool bUseGradientMemo=bStandaloneEnableGradientMemoization
&&ShapeWorldContext!=nullptr&&Step==1;
if(bUseGradientMemo)
{
GradientMemo.SetNumUninitialized(DensityGrid.Num());
GradientMemoValid.SetNumUninitialized(DensityGrid.Num());
// Clear every tile even when the reused TArray keeps the same length.
// Effacer chaque tuile meme si le TArray reutilise conserve la meme taille.
if(GradientMemoValid.Num()>0)
FMemory::Memzero(GradientMemoValid.GetData(),
static_cast<SIZE_T>(GradientMemoValid.Num())*sizeof(uint8));
}
auto SampleGradientG = [&](int32 gx, int32 gy, int32 gz) -> float
{
const float Cached = SampleG(gx, gy, gz);
@@ -1353,6 +1377,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
{
return Cached;
}
if(OutStageTimings)++OutStageTimings->GradientFallbackDensityCalls;
return ShapeWorldContext->DensityAtUnclamped(
static_cast<float>(OriginVoxels.X + gx * Step),
static_cast<float>(OriginVoxels.Y + gy * Step),
@@ -1360,11 +1385,23 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
};
auto GradAt = [&](int32 gx, int32 gy, int32 gz) -> FVector
{
const int32 CacheIndex=((gz+1)*MDim+(gy+1))*MDim+(gx+1);
if(bUseGradientMemo&&GradientMemoValid[CacheIndex]!=0)
{
if(OutStageTimings)++OutStageTimings->GradientMemoHits;
return GradientMemo[CacheIndex];
}
// Densité négative=solide, positive=air → le gradient pointe vers l'air (sortant).
return FVector(
const FVector Gradient(
SampleGradientG(gx + 1, gy, gz) - SampleGradientG(gx - 1, gy, gz),
SampleGradientG(gx, gy + 1, gz) - SampleGradientG(gx, gy - 1, gz),
SampleGradientG(gx, gy, gz + 1) - SampleGradientG(gx, gy, gz - 1));
if(bUseGradientMemo)
{
GradientMemo[CacheIndex]=Gradient;
GradientMemoValid[CacheIndex]=1;
}
return Gradient;
};
// DC is limited to tagged LOD0 patches. Coarse tiles and a connected patch that reaches a
@@ -1401,8 +1438,12 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
GroundTris.Reset();
CapTris.Reset();
const bool bProfileMesher = VoxelDensityProfile::IsCycleTimingEnabled();
const bool bAuditMesherStages=OutStageTimings!=nullptr;
uint64 CellClassificationCalls = 0;
uint64 SurfaceCellCalls = 0;
uint64 AuditCellClassificationCycles=0,AuditGradientCycles=0;
uint64 AuditInterpolationCycles=0,AuditDedupStreamCycles=0;
uint64 AuditGradientSamples=0,AuditInterpolationSamples=0,AuditDedupStreamSamples=0;
uint8 CaseIndexRow[CHUNK_SIZE]{};
uint8 SurfaceRow[CHUNK_SIZE]{};
uint8 SampleClassificationRow[CHUNK_SIZE]{};
@@ -1413,7 +1454,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
{
if (ShouldAbortWork()) return FVoxelMeshData();
FMemory::Memzero(SampleClassificationRow, sizeof(SampleClassificationRow));
const uint64 ClassificationRowStart = bProfileMesher
const uint64 ClassificationRowStart = (bProfileMesher||bAuditMesherStages)
? FPlatformTime::Cycles64() : 0;
int32 ClassificationRowCalls = 0;
for (int32 GroupX = 0; GroupX < CellsPerAxis; GroupX += 8)
@@ -1454,9 +1495,10 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
CaseIndexRow[CellX] = static_cast<uint8>(CaseIndex);
SurfaceRow[CellX] = MCEdgeTable[CaseIndex] != 0;
SampleClassificationRow[CellX] = bProfileMesher
&& VoxelDensityProfile::ShouldSample(
VoxelDensityProfile::EBucket::MesherCellClassification);
SampleClassificationRow[CellX] =
(bProfileMesher&&VoxelDensityProfile::ShouldSample(
VoxelDensityProfile::EBucket::MesherCellClassification))
||(bAuditMesherStages&&(CellClassificationCalls%8u)==0u);
++ClassificationRowCalls;
++CellClassificationCalls;
}
@@ -1477,26 +1519,31 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
CaseIndexRow[CellX] = static_cast<uint8>(CaseIndex);
SurfaceRow[CellX] = MCEdgeTable[CaseIndex] != 0;
SampleClassificationRow[CellX] = bProfileMesher
&& VoxelDensityProfile::ShouldSample(
VoxelDensityProfile::EBucket::MesherCellClassification);
SampleClassificationRow[CellX] =
(bProfileMesher&&VoxelDensityProfile::ShouldSample(
VoxelDensityProfile::EBucket::MesherCellClassification))
||(bAuditMesherStages&&(CellClassificationCalls%8u)==0u);
++ClassificationRowCalls;
++CellClassificationCalls;
}
}
}
if (bProfileMesher && ClassificationRowCalls > 0)
if ((bProfileMesher||bAuditMesherStages) && ClassificationRowCalls > 0)
{
const uint64 RowCycles = FPlatformTime::Cycles64() - ClassificationRowStart;
const uint64 PerCellCycles = RowCycles
/ static_cast<uint64>(ClassificationRowCalls);
for (int32 cx = 0; cx < CellsPerAxis; ++cx)
if(bAuditMesherStages)AuditCellClassificationCycles+=RowCycles;
if(bProfileMesher)
{
if (SampleClassificationRow[cx])
const uint64 PerCellCycles = RowCycles
/ static_cast<uint64>(ClassificationRowCalls);
for (int32 cx = 0; cx < CellsPerAxis; ++cx)
{
VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherCellClassification,
PerCellCycles);
if (SampleClassificationRow[cx])
{
VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherCellClassification,
PerCellCycles);
}
}
}
}
@@ -1537,9 +1584,11 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
if (bSampleCell)
{
VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherGradientNormals,
FPlatformTime::Cycles64() - GradientStart);
const uint64 StageCycles=FPlatformTime::Cycles64()-GradientStart;
if(bProfileMesher)VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherGradientNormals,StageCycles);
if(bAuditMesherStages)
{AuditGradientCycles+=StageCycles;++AuditGradientSamples;}
}
// Interpolation des positions + normales sur les arêtes traversées. t = point de
@@ -1563,6 +1612,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
if(ShapeWorldContext&&Step==1&&T>=0.375f&&T<=0.625f)
{
const FVector Midpoint=(Positions[A]+Positions[B])*0.5f;
if(OutStageTimings)++OutStageTimings->EdgeMidpointDensityCalls;
const float MidDensity=ShapeWorldContext->DensityAtUnclamped(
Midpoint.X/GeometryVoxelSize,Midpoint.Y/GeometryVoxelSize,
Midpoint.Z/GeometryVoxelSize);
@@ -1611,9 +1661,11 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
if (bSampleCell)
{
VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherVertexInterpolation,
FPlatformTime::Cycles64() - VertexInterpolationStart);
const uint64 StageCycles=FPlatformTime::Cycles64()-VertexInterpolationStart;
if(bProfileMesher)VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherVertexInterpolation,StageCycles);
if(bAuditMesherStages)
{AuditInterpolationCycles+=StageCycles;++AuditInterpolationSamples;}
}
// Génère les triangles avec vertices dédupliqués.
@@ -1651,9 +1703,11 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
if (bSampleCell)
{
VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherStreamBuilding,
FPlatformTime::Cycles64() - StreamBuildingStart);
const uint64 StageCycles=FPlatformTime::Cycles64()-StreamBuildingStart;
if(bProfileMesher)VoxelDensityProfile::AddSampledMeasurement(
VoxelDensityProfile::EBucket::MesherStreamBuilding,StageCycles);
if(bAuditMesherStages)
{AuditDedupStreamCycles+=StageCycles;++AuditDedupStreamSamples;}
}
}
}
@@ -1989,5 +2043,31 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
OutputAllocatedBytes);
}
if(OutStageTimings)
{
const double CycleToMs=FPlatformTime::GetSecondsPerCycle64()*1000.0;
const auto ScaleSampledCycles=[CycleToMs](uint64 Cycles,uint64 Samples,uint64 Calls)
{
return Samples>0?static_cast<double>(Cycles)*static_cast<double>(Calls)
/static_cast<double>(Samples)*CycleToMs:0.0;
};
OutStageTimings->CellClassificationMilliseconds=
static_cast<double>(AuditCellClassificationCycles)*CycleToMs;
OutStageTimings->GradientNormalsMilliseconds=ScaleSampledCycles(
AuditGradientCycles,AuditGradientSamples,SurfaceCellCalls);
OutStageTimings->EdgeInterpolationMilliseconds=ScaleSampledCycles(
AuditInterpolationCycles,AuditInterpolationSamples,SurfaceCellCalls);
OutStageTimings->VertexDedupStreamMilliseconds=ScaleSampledCycles(
AuditDedupStreamCycles,AuditDedupStreamSamples,SurfaceCellCalls);
const double TotalMilliseconds=static_cast<double>(
FPlatformTime::Cycles64()-StageMesherStartCycles)*CycleToMs;
OutStageTimings->OtherMilliseconds=FMath::Max(0.0,TotalMilliseconds
-OutStageTimings->DensityGridMilliseconds
-OutStageTimings->CellClassificationMilliseconds
-OutStageTimings->GradientNormalsMilliseconds
-OutStageTimings->EdgeInterpolationMilliseconds
-OutStageTimings->VertexDedupStreamMilliseconds);
}
return MeshData;
}
@@ -41,6 +41,21 @@ struct FVoxelSharedDensityGrid
}
};
// Optional, sampled timing output for the research audit; null in production calls.
// Mesures echantillonnees facultatives pour l'audit; pointeur nul en production.
struct FVoxelMarchingCubesStageTimings
{
double DensityGridMilliseconds = 0.0;
double CellClassificationMilliseconds = 0.0;
double GradientNormalsMilliseconds = 0.0;
double EdgeInterpolationMilliseconds = 0.0;
double VertexDedupStreamMilliseconds = 0.0;
double OtherMilliseconds = 0.0;
uint64 GradientFallbackDensityCalls = 0;
uint64 EdgeMidpointDensityCalls = 0;
uint64 GradientMemoHits = 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
@@ -91,7 +106,8 @@ public:
int64* OutDensitySampleCount = nullptr,
FVoxelSharedDensityGrid* OutPreEditDensityGrid = nullptr,
const FVoxelSharedDensityGrid* InSharedDensityGrid = nullptr,
std::vector<float>* OutDebugDensitySamples = nullptr);
std::vector<float>* OutDebugDensitySamples = nullptr,
FVoxelMarchingCubesStageTimings* OutStageTimings = nullptr);
//=========================================================================
// SERVICES (injectés par AVoxelWorld)
@@ -161,6 +177,7 @@ public:
bool bStandaloneSkipUV = false;
bool bStandaloneSkipColors = false;
bool bStandaloneSkipMaterialGroups = false;
bool bStandaloneEnableGradientMemoization = true;
// Seuil de l'isosurface dans le champ de densité.
// Convention MC: densité < IsoLevel = solide, >= = air.