streaming: split dense passage-junction grid fills; heavy-first order + far-parent deferral in Unreal (L85)

Tiles with passage-overlap score >= 9 split grid fill over up to 4 helper lanes (disjoint rows,
same per-sample order, join before MC) when workers are idle. FI junction tile fill 173 -> 99 ms;
estimated serial floor ~0.55-0.60 s. Readiness essentially unchanged (FI/TN LOD0-2 ~2.15 s @W12):
the limit is now aggregate work, not single tiles.
Unreal: LOD0-2 ordered by passage overlap before travel/distance (L80 modes kept); far parents
built after LOD0-1, LOD2 gated on them; helper budget via ParallelFor. Unreal null-RHI FI
arrival: LOD0-2 resident at 3.65 s.
All tile hashes identical to L84 (four whole views). Fast tier PASS; Linux UE host builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-28 02:02:32 +01:00
1 parent 0a98da6fd0
commit 06f558dc91
17 files changed
+1561 -54

No files matched your search

@@ -15,9 +15,73 @@
#include "HAL/IConsoleManager.h"
#include "Misc/CommandLine.h"
#include <atomic>
#include <array>
namespace
{
struct FVoxelMesherThreadState
{
int32 OctaveBias=0,SampleStep=1,TileCells=0,TileReachBlocks=0,TileReachBlockIndex=INDEX_NONE;
FIntVector TileOrigin=FIntVector::ZeroValue;
uint8 TilePostReachFlags=VoxelGenLOD::AllTileReach;
bool bTilePostReachDebug=false,bTilePostReachBypass=false;
bool bTileReachDiagnosticTile=false,bTileCoreReachProofEnabled=false;
bool bTileCoreReachDecisionRecorded=false,bTileBlockReachValid=false;
float TileReachScale=1.0f;
std::array<uint8,VoxelGenLOD::TileReachMaxBlockCount> TileBlockReachFlags{};
static FVoxelMesherThreadState Capture()
{
FVoxelMesherThreadState State;
State.OctaveBias=VoxelGenLOD::OctaveBias;
State.SampleStep=VoxelGenLOD::SampleStep;
State.TileOrigin=VoxelGenLOD::TileOriginVoxels;
State.TileCells=VoxelGenLOD::TileCellsPerAxis;
State.TilePostReachFlags=VoxelGenLOD::TilePostReachFlags;
State.bTilePostReachDebug=VoxelGenLOD::bTilePostReachDebug;
State.bTilePostReachBypass=VoxelGenLOD::bTilePostReachBypass;
State.bTileReachDiagnosticTile=VoxelGenLOD::bTileReachDiagnosticTile;
State.bTileCoreReachProofEnabled=VoxelGenLOD::bTileCoreReachProofEnabled;
State.bTileCoreReachDecisionRecorded=VoxelGenLOD::bTileCoreReachDecisionRecorded;
State.bTileBlockReachValid=VoxelGenLOD::bTileBlockReachValid;
State.TileReachScale=VoxelGenLOD::TileReachScale;
State.TileReachBlocks=VoxelGenLOD::TileReachBlocksPerAxis;
State.TileReachBlockIndex=VoxelGenLOD::TileReachBlockIndex;
std::copy(std::begin(VoxelGenLOD::TileBlockReachFlags),
std::end(VoxelGenLOD::TileBlockReachFlags),State.TileBlockReachFlags.begin());
return State;
}
void Apply() const
{
VoxelGenLOD::OctaveBias=OctaveBias;
VoxelGenLOD::SampleStep=SampleStep;
VoxelGenLOD::TileOriginVoxels=TileOrigin;
VoxelGenLOD::TileCellsPerAxis=TileCells;
VoxelGenLOD::TilePostReachFlags=TilePostReachFlags;
VoxelGenLOD::bTilePostReachDebug=bTilePostReachDebug;
VoxelGenLOD::bTilePostReachBypass=bTilePostReachBypass;
VoxelGenLOD::bTileReachDiagnosticTile=bTileReachDiagnosticTile;
VoxelGenLOD::bTileCoreReachProofEnabled=bTileCoreReachProofEnabled;
VoxelGenLOD::bTileCoreReachDecisionRecorded=bTileCoreReachDecisionRecorded;
VoxelGenLOD::bTileBlockReachValid=bTileBlockReachValid;
VoxelGenLOD::TileReachScale=TileReachScale;
VoxelGenLOD::TileReachBlocksPerAxis=TileReachBlocks;
VoxelGenLOD::TileReachBlockIndex=TileReachBlockIndex;
std::copy(TileBlockReachFlags.begin(),TileBlockReachFlags.end(),
std::begin(VoxelGenLOD::TileBlockReachFlags));
}
};
struct FVoxelMesherThreadStateScope
{
explicit FVoxelMesherThreadStateScope(const FVoxelMesherThreadState& InTarget)
:Previous(FVoxelMesherThreadState::Capture())
{ InTarget.Apply(); }
~FVoxelMesherThreadStateScope(){Previous.Apply();}
FVoxelMesherThreadState Previous;
};
int32 GVoxelForgeUseOperatorBlock = 1;
FAutoConsoleVariableRef CVarVoxelForgeUseOperatorBlock(
TEXT("voxel.UseOperatorBlock"),
@@ -692,6 +756,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
// capacité, donc plus de malloc/free de ~170 Ko (35³ floats) par tuile.
static thread_local TArray<float> DensityGrid;
DensityGrid.SetNumUninitialized(MDim * MDim * MDim);
float* const DensityGridData=DensityGrid.GetData();
const FVoxelSharedDensityGrid* ReuseGrid = InSharedDensityGrid != nullptr
? InSharedDensityGrid : SharedDensityGrid;
const int32 SharedDeltaX = ReuseGrid
@@ -739,7 +804,15 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
const bool bUseOperatorBlock = !bUseSharedDensityGrid
&& !bUseParameterizedBrickEvaluator
&& GVoxelForgeUseOperatorBlock != 0;
if (bUseOperatorBlock)
const int32 GridZSampleCount=GzHi-GzLo+1;
const std::size_t GridFillLaneCount=std::min<std::size_t>({
GridFillExecution.WorkerLimit,16,
static_cast<std::size_t>(FMath::Max(0,GridZSampleCount))});
const bool bUseParallelDensityGrid=GridFillExecution.ParallelFor!=nullptr
&&GridFillLaneCount>1&&GridFillExecution.BeginWorkerContext!=nullptr
&&GridFillExecution.EndWorkerContext!=nullptr&&!bUseSharedDensityGrid
&&!bUseParameterizedBrickEvaluator&&OutCaptureGrid==nullptr;
if (bUseOperatorBlock&&!bUseParallelDensityGrid)
{
// The grid includes one sample of halo on every side. The generator groups these exact
// lattice points by chunk key and lets the prepared op stack fill each group once.
@@ -889,6 +962,80 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
}
#endif
}
else if(bUseParallelDensityGrid)
{
const FVoxelMesherThreadState TileThreadState=FVoxelMesherThreadState::Capture();
std::array<int64,16> LaneSampleCounts{};
std::atomic<bool> bAborted{false};
auto RunLane=[&](std::size_t Lane,std::size_t Worker)
{
void* WorkerState=GridFillExecution.BeginWorkerContext(
GridFillExecution.WorkerContext,Worker);
int64 LaneSamples=0;
{
FVoxelMesherThreadStateScope ThreadStateScope(TileThreadState);
const int32 FirstGz=GzLo+static_cast<int32>(
(static_cast<std::size_t>(GridZSampleCount)*Lane)/GridFillLaneCount);
const int32 EndGz=GzLo+static_cast<int32>(
(static_cast<std::size_t>(GridZSampleCount)*(Lane+1))/GridFillLaneCount);
if(bUseOperatorBlock)
{
Generator->BeginDensityBlock(
OriginVoxels+FIntVector(-Step,-Step,FirstGz*Step),Step,
MDim,MDim,EndGz-FirstGz);
}
for(int32 gz=FirstGz;gz<EndGz;++gz)
{
if(ShouldAbortWork())
{ bAborted.store(true,std::memory_order_relaxed);break; }
for(int32 gy=-1;gy<=GridDim;++gy)
{
if(ShouldAbortWork())
{ bAborted.store(true,std::memory_order_relaxed);break; }
for(int32 gx=-1;gx<=GridDim;++gx)
{
const int32 LocalIndex=((gz+1)*MDim+(gy+1))*MDim+(gx+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;
float PreEditDensity=0.0f;
DensityGridData[LocalIndex]=Generator->GetDensityAt(
OriginVoxels.X+gx*Step,OriginVoxels.Y+gy*Step,
OriginVoxels.Z+gz*Step,
bCapturePreEditGrid?&PreEditDensity:nullptr);
if(bCapturePreEditGrid)
OutPreEditDensityGrid->Samples[LocalIndex]=PreEditDensity;
++LaneSamples;
}
}
if(bAborted.load(std::memory_order_relaxed))break;
}
if(bUseOperatorBlock)Generator->EndDensityBlock();
}
LaneSampleCounts[Lane]=LaneSamples;
GridFillExecution.EndWorkerContext(
GridFillExecution.WorkerContext,WorkerState,Worker);
};
struct FDispatchContext{decltype(RunLane)* Run=nullptr;};
FDispatchContext DispatchContext{&RunLane};
const auto DispatchLane=[](void* RawContext,std::size_t Lane,std::size_t Worker)
{
auto& Context=*static_cast<FDispatchContext*>(RawContext);
(*Context.Run)(Lane,Worker);
};
GridFillExecution.ParallelFor(GridFillExecution.SchedulerContext,
GridFillLaneCount,GridFillLaneCount,&DispatchContext,DispatchLane);
if(OutDensitySampleCount)
for(std::size_t Lane=0;Lane<GridFillLaneCount;++Lane)
*OutDensitySampleCount+=LaneSampleCounts[Lane];
if(bAborted.load(std::memory_order_relaxed))return FVoxelMeshData();
}
else for (int32 gz = GzLo; gz <= GzHi; gz++)
{
if (ShouldAbortWork())
@@ -959,7 +1106,7 @@ FVoxelMeshData UVoxelMarchingCubesMesher::GenerateMesh(FIntVector OriginVoxels,
GridSampleCount * sizeof(float));
}
}
if (bUseOperatorBlock)
if (bUseOperatorBlock&&!bUseParallelDensityGrid)
{
Generator->EndDensityBlock();
}