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

+22 -1
View File
@@ -271,11 +271,32 @@ public:
}
ActivePassageTileQueries=this;
}
// Duplicate the immutable per-tile masks onto a density-grid helper worker. Mutable
// segment-range caches remain lane-local so helpers never race with the parent query.
explicit FScopedPassageTileQueries(const FScopedPassageTileQueries& source)
:shape_(source.shape_),minimumSubvoxels_(source.minimumSubvoxels_),
maximumSubvoxels_(source.maximumSubvoxels_),featureIndices_(source.featureIndices_),
stampIndices_(source.stampIndices_),cavernFeatureIndices_(source.cavernFeatureIndices_),
passageRoutes_(source.passageRoutes_),passageColumns_(source.passageColumns_),
passageMouthSupports_(source.passageMouthSupports_),
passageMouthSupportSegments_(source.passageMouthSupportSegments_),
passageSegmentRangeCaches_(source.passageSegmentRangeCaches_.size()),
upperMouthSupportPassages_(source.upperMouthSupportPassages_),
routeSegmentCandidateCount_(source.routeSegmentCandidateCount_),
routeFeatureOverlap_(source.routeFeatureOverlap_),columnZOverlap_(source.columnZOverlap_),
mayContainResolvedBoundaryBand_(source.mayContainResolvedBoundaryBand_),
mayContainTransitionPassageFade_(source.mayContainTransitionPassageFade_),
previous_(ActivePassageTileQueries)
{ ActivePassageTileQueries=this; }
~FScopedPassageTileQueries(){ActivePassageTileQueries=previous_;}
FScopedPassageTileQueries(const FScopedPassageTileQueries&)=delete;
FScopedPassageTileQueries& operator=(const FScopedPassageTileQueries&)=delete;
bool matches(const FStandaloneShapeWorld& shape) const{return shape_==&shape;}
static const FScopedPassageTileQueries* CurrentFor(const FStandaloneShapeWorld& shape)
{
const FScopedPassageTileQueries* current=ActivePassageTileQueries;
return current&&current->shape_==&shape?current:nullptr;
}
bool hasFeature(std::size_t passageIndex,bool columnFeature) const
{
const auto& candidates=columnFeature?passageColumns_:passageRoutes_;
+115 -2
View File
@@ -1084,6 +1084,51 @@ namespace VoxelForgeCore
bool bEnabled=false;
};
struct FGridFillWorkerContext
{
FScopedSharedColumnCaches::FHeightfieldCache* HeightfieldCache=nullptr;
FScopedSharedColumnCaches::FIslandCache* IslandCache=nullptr;
const FStandaloneShapeWorld::FScopedPassageTileQueries* PassageQueries=nullptr;
int32 Lod=0;
bool bLegacyDirectMapped=false;
};
struct FGridFillWorkerState
{
bool bPreviousLegacyDirectMapped=false;
std::unique_ptr<FScopedSharedColumnCaches> SharedCaches;
std::unique_ptr<FStandaloneShapeWorld::FScopedPassageTileQueries> PassageQueries;
std::unique_ptr<VoxelForgeCore::Linux77Profiler::FScopedLod> Lod;
~FGridFillWorkerState()
{
Lod.reset();
PassageQueries.reset();
SharedCaches.reset();
Heightfield2D::setThreadColumnCacheLegacyDirectMapped(
bPreviousLegacyDirectMapped);
}
};
void* BeginGridFillWorkerContext(void* rawContext,std::size_t)
{
const auto& context=*static_cast<FGridFillWorkerContext*>(rawContext);
auto state=std::make_unique<FGridFillWorkerState>();
state->bPreviousLegacyDirectMapped=
Heightfield2D::threadColumnCacheLegacyDirectMapped();
Heightfield2D::setThreadColumnCacheLegacyDirectMapped(context.bLegacyDirectMapped);
state->SharedCaches=std::make_unique<FScopedSharedColumnCaches>(
context.HeightfieldCache,context.IslandCache);
if(context.PassageQueries)
state->PassageQueries=
std::make_unique<FStandaloneShapeWorld::FScopedPassageTileQueries>(
*context.PassageQueries);
state->Lod=std::make_unique<VoxelForgeCore::Linux77Profiler::FScopedLod>(context.Lod);
return state.release();
}
void EndGridFillWorkerContext(void*,void* rawState,std::size_t)
{ delete static_cast<FGridFillWorkerState*>(rawState); }
World::World(ResolvedWorldSnapshot snapshot):impl_(std::make_unique<Impl>())
{
if(snapshot.data_)
@@ -1737,8 +1782,13 @@ namespace VoxelForgeCore
impl_->tileRegionCount.store(impl_->tileRegions.size(),std::memory_order_release);
}
void World::buildFarWorld()
{ if(impl_&&impl_->shapeReady.load(std::memory_order_acquire)&&impl_->shape)impl_->shape->BuildFarWorld(); }
bool World::buildFarWorld()
{
if(!impl_||!impl_->shapeReady.load(std::memory_order_acquire)||!impl_->shape)
return false;
if(!impl_->shape->HasFarWorld())impl_->shape->BuildFarWorld();
return impl_->shape->HasFarWorld();
}
bool World::isCompiled() const noexcept
{ return impl_&&impl_->shapeReady.load(std::memory_order_acquire); }
bool World::hasFarWorld() const noexcept
@@ -1914,6 +1964,41 @@ namespace VoxelForgeCore
return output;
}
std::uint32_t World::passageOverlapScore(const TileKey& key) const noexcept
{
if(!impl_||!impl_->resolvedLayout||key.lod<0||key.lod>30)return 0;
constexpr std::int64_t SubvoxelsPerVoxel=WorldAssemblySubvoxelsPerVoxel;
constexpr std::int64_t ExtraInfluenceVoxels=32;
const std::int64_t Extent=static_cast<std::int64_t>(CoreTileVoxelCount)<<key.lod;
const std::int64_t TileMinimum[3]={
static_cast<std::int64_t>(key.coordinate.x)*Extent,
static_cast<std::int64_t>(key.coordinate.y)*Extent,
static_cast<std::int64_t>(key.coordinate.z)*Extent};
const std::int64_t TileMaximum[3]={TileMinimum[0]+Extent,
TileMinimum[1]+Extent,TileMinimum[2]+Extent};
std::uint32_t Score=0;
for(const auto& Passage:impl_->resolvedLayout->passages)
for(std::size_t Index=1;Index<Passage.controlPoints.size();++Index)
{
const auto& A=Passage.controlPoints[Index-1];
const auto& B=Passage.controlPoints[Index];
const std::int64_t Radius=std::max(A.radiusSubvoxels,B.radiusSubvoxels)
/SubvoxelsPerVoxel+ExtraInfluenceVoxels;
bool bOverlap=true;
for(std::size_t Axis=0;Axis<3;++Axis)
{
const std::int64_t AVoxel=A.positionSubvoxels[Axis]/SubvoxelsPerVoxel;
const std::int64_t BVoxel=B.positionSubvoxels[Axis]/SubvoxelsPerVoxel;
const std::int64_t Minimum=std::min(AVoxel,BVoxel)-Radius;
const std::int64_t Maximum=std::max(AVoxel,BVoxel)+Radius;
bOverlap=bOverlap&&Maximum>=TileMinimum[Axis]
&&Minimum<=TileMaximum[Axis];
}
if(bOverlap)++Score;
}
return Score;
}
std::vector<TileKey> World::desiredTiles(Vec3d cameraPosition) const
{
if(!impl_||!impl_->owner)return {};
@@ -2724,6 +2809,33 @@ namespace VoxelForgeCore
passageFeatureScope.mouthSupportSegments(passageIndex).size();
}
}
FGridFillWorkerContext GridFillWorkerContext;
if(options.gridFillScheduler&&options.gridFillWorkerLimit>1)
{
GridFillWorkerContext.HeightfieldCache=options.useSharedColumnCache
?impl_->sharedHeightfieldColumns.get():nullptr;
GridFillWorkerContext.IslandCache=options.useSharedColumnCache
?impl_->sharedIslandColumns.get():nullptr;
GridFillWorkerContext.PassageQueries=
FStandaloneShapeWorld::FScopedPassageTileQueries::CurrentFor(tileShape);
GridFillWorkerContext.Lod=key.lod;
GridFillWorkerContext.bLegacyDirectMapped=
options.legacyDirectMappedColumnCache||key.lod<=2;
FVoxelGridFillExecution Execution;
Execution.SchedulerContext=const_cast<JobScheduler*>(options.gridFillScheduler);
Execution.ParallelFor=[](void* RawScheduler,std::size_t Count,
std::size_t WorkerLimit,void* TaskContext,FVoxelGridFillExecution::FTask Task)
{
return static_cast<const JobScheduler*>(RawScheduler)->parallel_for(
Count,1,WorkerLimit,TaskContext,Task,nullptr,0);
};
Execution.WorkerLimit=std::clamp<std::size_t>(
options.gridFillWorkerLimit,2,16);
Execution.WorkerContext=&GridFillWorkerContext;
Execution.BeginWorkerContext=&BeginGridFillWorkerContext;
Execution.EndWorkerContext=&EndGridFillWorkerContext;
mesher.SetGridFillExecution(Execution);
}
const bool bDiagnosticColumnSampling=options.diagnosticGlobalOctaveDrop!=0
||options.diagnosticColumnInterpolationStride>1;
const std::uint32_t PreviousOctaveDrop=bDiagnosticColumnSampling
@@ -2781,6 +2893,7 @@ namespace VoxelForgeCore
out.diagnostics.marchingCubesExclusiveMilliseconds
-out.diagnostics.marchingCubesSkirtMilliseconds);
out.diagnostics.marchingCubesDensityGridMilliseconds=McStageTimings.DensityGridMilliseconds;
out.diagnostics.marchingCubesGridFillWorkers=McStageTimings.GridFillWorkerCount;
out.diagnostics.marchingCubesCellClassificationMilliseconds=
McStageTimings.CellClassificationMilliseconds;
out.diagnostics.marchingCubesGradientNormalsMilliseconds=
@@ -2653,6 +2653,9 @@ void Heightfield2D::setThreadColumnCaptureBounds(std::int64_t minimumXSubvoxels,
void Heightfield2D::setThreadColumnCacheLegacyDirectMapped(bool enabled) noexcept
{ world_assembly_detail::HeightfieldColumnCacheLegacyDirectMapped=enabled; }
bool Heightfield2D::threadColumnCacheLegacyDirectMapped() noexcept
{ return world_assembly_detail::HeightfieldColumnCacheLegacyDirectMapped; }
void Heightfield2D::setThreadColumnOctaveDrop(std::uint32_t octaveDrop) noexcept
{ world_assembly_detail::HeightfieldColumnOctaveDrop=octaveDrop; }