streaming: deeper ready queue + startup apply cap; tile-local mouth-support culling (L72)

- Unreal: ready queue depth 8 -> 16 (cap 4 worker-sets / 64), startup mesh-apply cap
  12 -> 24 within the unchanged 14 ms budget. Owner SW arrival, same 2,850 keys:
  initial set ready 4.78 -> 3.74 s, queue p95 123 -> 35 ms, request-to-apply p95
  139 -> 45 ms; walkable gate 1.07 -> 1.11 s; per-frame apply p95 0.73 ms.
- Core composer: mouth-support segments filtered by tile bounds, mouth relief result reused
  (route checks -80/-87% in passage tiles). Hashes identical W1/W8/W12, Clang and GCC.
- Opt-in per-tile composer counters. Verify control meshes stored as .xz (78.5 -> 18.4 MB).
- Fast tier 269 PASS.

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-27 08:25:14 +01:00
1 parent 971206c2ea
commit d970d75be8
26 files changed
+383 -82

No files matched your search

+12 -12
View File
@@ -238,11 +238,11 @@ namespace
GVoxelForgeStreamingResultBacklogCap,
TEXT("Maximum queued results plus admitted tile tasks; 0 disables the safety cap. This is separate from the worker-slot cap."));
int32 GVoxelForgeStreamingReadyQueueDepth = 8;
int32 GVoxelForgeStreamingReadyQueueDepth = 16;
FAutoConsoleVariableRef CVarVoxelForgeStreamingReadyQueueDepth(
TEXT("voxel.StreamingReadyQueueDepth"),
GVoxelForgeStreamingReadyQueueDepth,
TEXT("Extra admitted tile tasks kept ready beyond the worker slots, up to one worker-set; 0 disables the refill queue."));
TEXT("Extra admitted tile tasks kept ready beyond worker slots, up to four worker-sets/64 tasks; 0 disables the refill queue."));
int32 GVoxelForgeStreamingBackgroundWorkerCap = 1;
FAutoConsoleVariableRef CVarVoxelForgeStreamingBackgroundWorkerCap(
@@ -312,8 +312,8 @@ namespace
FAutoConsoleVariableRef CVarVoxelForgeStreamingStartupApplyBoost(
TEXT("voxel.StreamingStartupApplyBoost"),
GVoxelForgeStreamingStartupApplyBoost,
TEXT("Bounded cold-view upload budget (default on): 1 allows a 14 ms / 12-mesh budget until the initial desired set and walkable ring are ready; 0 uses the authored per-frame budget."));
constexpr int32 StreamingStartupMaxMeshApplies = 12;
TEXT("Bounded cold-view upload budget (default on): 1 allows a 14 ms / 24-mesh cap until the initial desired set and walkable ring are ready; 0 uses the authored per-frame budget."));
constexpr int32 StreamingStartupMaxMeshApplies = 24;
constexpr float StreamingStartupApplyBudgetMilliseconds = 14.0f;
constexpr double StreamingStartupApplyMaxSeconds = 30.0;
@@ -2207,7 +2207,7 @@ void AVoxelWorld::BeginPlay()
CommandLineStreamingReadyQueueDepth))
{
GVoxelForgeStreamingReadyQueueDepth = FMath::Clamp(
CommandLineStreamingReadyQueueDepth, 0, 32);
CommandLineStreamingReadyQueueDepth, 0, 64);
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingBackgroundWorkerCap="),
CommandLineStreamingBackgroundWorkerCap))
@@ -2634,7 +2634,8 @@ void AVoxelWorld::BeginPlay()
FTaskGraphInterface& TaskGraph = FTaskGraphInterface::Get();
LowLevelTasks::FScheduler& TaskScheduler = LowLevelTasks::FScheduler::Get();
const int32 QueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, GetMaxConcurrentStreamingTasks());
GVoxelForgeStreamingReadyQueueDepth, 0,
FMath::Min(64, FMath::Max(1, GetMaxConcurrentStreamingTasks()) * 4));
VoxelForgeStartupTrace::RecordEvent(TEXT("worker_backend_config"), FString::Printf(
TEXT("\"logical_cores\":%d,\"effective_tile_slots\":%d,"
"\"task_api\":\"UE::Tasks::Launch\",\"task_scheduler_workers\":%u,"
@@ -11873,11 +11874,10 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
}
}
const int32 MaxTasks = GetMaxConcurrentStreamingTasks();
// Keep at most one worker-set of ready work so an admission pass can feed idle slots
// without letting far work consume the near reserve. / Garder une file d'un ensemble
// de workers pour nourrir les slots sans consommer la reserve proche.
// Keep several bounded worker-sets ready so frame-paced admission can feed the
// background lane continuously without moving mesh application onto the game thread.
const int32 ReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, MaxTasks);
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const int32 AuthoredNearTaskReserve = GetNearTaskReserve(MaxTasks);
const FIntVector CenterChunk = GetTileCoordAtLocalCm(WorldToLocalCm(CenterPosition));
@@ -12787,7 +12787,7 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
const int32 MaxTasks = GetMaxConcurrentStreamingTasks(); // Core and worker lane clamped. / Core et voie worker plafonnes.
const int32 ReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, MaxTasks);
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
@@ -13130,7 +13130,7 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
const int32 MaxTasks = GetMaxConcurrentStreamingTasks();
const int32 ReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, MaxTasks);
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
@@ -131,6 +131,31 @@ namespace VoxelForgeCore
std::uint64_t mixedBoxes = 0;
std::uint64_t unknownBoxes = 0;
std::uint64_t fieldCalls = 0;
// Opt-in composer diagnostics. These stay zero during ordinary generation.
bool passageComposerProfiled = false;
std::uint64_t passageTileFeatureCount = 0;
std::uint64_t passageTileRouteSegmentCandidates = 0;
std::uint64_t passageTileMouthSegmentCandidates = 0;
std::uint64_t passageComposerQueries = 0;
std::uint64_t passageIterations = 0;
std::uint64_t passageUpperMouthFilterChecks = 0;
std::uint64_t passageColumnCandidates = 0;
std::uint64_t passageColumnDistanceCalls = 0;
std::uint64_t passageNegativeBoundChecks = 0;
std::uint64_t passageNegativeBoundRejects = 0;
std::uint64_t passagePositiveBoundChecks = 0;
std::uint64_t passagePositiveBoundRejects = 0;
std::uint64_t passageCarveSegmentVisits = 0;
std::uint64_t passageSmoothCarveJoins = 0;
std::uint64_t passageSupportSegmentVisits = 0;
std::uint64_t passageSmoothSupportJoins = 0;
std::uint64_t passageSupportCapsuleChecks = 0;
std::uint64_t passageLaterBoreChecks = 0;
std::uint64_t passageOtherCapsuleChecks = 0;
std::uint64_t passageMouthSupportCalls = 0;
std::uint64_t passageMouthRouteSegmentChecks = 0;
std::uint64_t passageReliefFieldCalls = 0;
std::uint64_t passageSmoothstepEvaluations = 0;
std::uint64_t floatFieldCalls = 0;
std::uint64_t latticeFieldCalls = 0;
std::uint64_t unclampedFieldCalls = 0;
@@ -1745,6 +1770,8 @@ 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;
// Research-only: count passage-composer work per generated tile.
bool profilePassageComposer = false;
// Research-only: collect tile-drain kernel counters and floating-island cache metrics.
// Inactive on ordinary generation so the hot path only pays the option check.
bool instrumentTileDrain = false;
+201 -60
View File
@@ -172,11 +172,19 @@ public:
class FScopedPassageTileQueries
{
public:
struct FCandidateSegment
{
std::size_t segmentIndex=0;
std::array<std::int64_t,3> minimumSubvoxels{},maximumSubvoxels{};
};
FScopedPassageTileQueries(const FStandaloneShapeWorld& shape,
const std::array<std::int64_t,3>& minimumSubvoxels,
const std::array<std::int64_t,3>& maximumSubvoxels)
const std::array<std::int64_t,3>& maximumSubvoxels,
VoxelForgeCore::TileGenerationStats* profileStats=nullptr)
:shape_(&shape),minimumSubvoxels_(minimumSubvoxels),
maximumSubvoxels_(maximumSubvoxels),previous_(ActivePassageTileQueries)
maximumSubvoxels_(maximumSubvoxels),previous_(ActivePassageTileQueries),
profileStats_(profileStats)
{
mayContainResolvedBoundaryBand_=shape.ResolvedBoundaryBandsIntersectSubvoxelRange(
minimumSubvoxels_[2],maximumSubvoxels_[2]);
@@ -190,6 +198,7 @@ public:
passageRoutes_.assign(shape.ResolvedLayout?shape.ResolvedLayout->passages.size():0,0);
passageColumns_=passageRoutes_;
passageMouthSupports_=passageRoutes_;
passageMouthSupportSegments_.resize(passageRoutes_.size());
for(const auto& crossing:shape.PassageVoidCrossings)
if(crossing.needsColumn
&&crossing.bottomZSubvoxels<=maximumSubvoxels_[2]
@@ -200,14 +209,27 @@ public:
if(featureIndex>=shape.PassageTileFeatures.size())continue;
const auto& feature=shape.PassageTileFeatures[featureIndex];
if(feature.passageIndex>=passageRoutes_.size())continue;
const auto& featureBounds=shape.PassageFeatureBounds[featureIndex];
const FCandidateSegment candidate{feature.segmentIndex,
featureBounds.minimumSubvoxels,featureBounds.maximumSubvoxels};
if(feature.bColumn)passageColumns_[feature.passageIndex]=1;
else if(feature.bMouthSupport)passageMouthSupports_[feature.passageIndex]=1;
else if(feature.bMouthSupport)
{
passageMouthSupports_[feature.passageIndex]=1;
passageMouthSupportSegments_[feature.passageIndex].push_back(candidate);
}
else
{
passageRoutes_[feature.passageIndex]=1;
++routeSegmentCandidateCount_;
routeFeatureOverlap_=true;
}
}
for(auto& values:passageMouthSupportSegments_)
{
std::sort(values.begin(),values.end(),[](const auto& a,const auto& b)
{return a.segmentIndex<b.segmentIndex;});
}
ActivePassageTileQueries=this;
}
~FScopedPassageTileQueries(){ActivePassageTileQueries=previous_;}
@@ -220,6 +242,12 @@ public:
const auto& candidates=columnFeature?passageColumns_:passageRoutes_;
return passageIndex<candidates.size()&&candidates[passageIndex]!=0;
}
const std::vector<FCandidateSegment>& mouthSupportSegments(std::size_t passageIndex) const
{
static const std::vector<FCandidateSegment> Empty;
return passageIndex<passageMouthSupportSegments_.size()
?passageMouthSupportSegments_[passageIndex]:Empty;
}
bool hasMouthSupport(std::size_t passageIndex) const
{return passageIndex<passageMouthSupports_.size()&&passageMouthSupports_[passageIndex]!=0;}
bool hasAnyMouthSupport() const
@@ -235,6 +263,9 @@ public:
&&shape_->ResolvedBoundaryBandMayAffectAtZMicrometres(zMicrometres);
}
std::size_t featureCount() const{return featureIndices_.size();}
std::size_t routeSegmentCandidateCount() const{return routeSegmentCandidateCount_;}
VoxelForgeCore::TileGenerationStats* profileStats() const noexcept
{return profileStats_;}
bool hasStampCandidates() const{return !stampIndices_.empty();}
const std::vector<std::uint32_t>& stampCandidates() const{return stampIndices_;}
bool hasCavernCandidates() const{return !cavernFeatureIndices_.empty();}
@@ -248,10 +279,13 @@ public:
std::vector<std::uint32_t> stampIndices_;
std::vector<std::uint32_t> cavernFeatureIndices_;
std::vector<std::uint8_t> passageRoutes_,passageColumns_,passageMouthSupports_;
std::vector<std::vector<FCandidateSegment>> passageMouthSupportSegments_;
std::size_t routeSegmentCandidateCount_=0;
bool routeFeatureOverlap_=false,columnZOverlap_=false;
bool mayContainResolvedBoundaryBand_=true;
bool mayContainTransitionPassageFade_=true;
const FScopedPassageTileQueries* previous_;
VoxelForgeCore::TileGenerationStats* profileStats_=nullptr;
};
bool IsResolvedPassageColumnSample(std::size_t PassageIndex,std::size_t SegmentIndex,
@@ -953,9 +987,13 @@ public:
const auto* passageTileQueries=ActivePassageTileQueries;
const bool passageTileScopeMatches=passageTileQueries
&&passageTileQueries->matches(*this);
auto* passageProfile=passageTileScopeMatches
?passageTileQueries->profileStats():nullptr;
if(passageProfile)++passageProfile->passageComposerQueries;
bool queryNearUpperMouthSupport=false;
for(const auto& passage:ResolvedLayout->passages)
{
if(passageProfile)++passageProfile->passageUpperMouthFilterChecks;
const double dx=qx-static_cast<double>(passage.upperMouthSubvoxels[0]);
const double dy=qy-static_cast<double>(passage.upperMouthSubvoxels[1]);
const double dz=qz-static_cast<double>(passage.upperMouthSubvoxels[2]);
@@ -972,26 +1010,20 @@ public:
const double playerCenterAboveFloorQ=1.13*qPerMetre;
float composed=density;
float deferredSupportDensity=std::numeric_limits<float>::infinity();
const auto composeRouteMouthSupport=[&](std::int32_t strateIndex,
const std::array<std::int64_t,3>& mouth)
const auto composeRouteMouthSupport=[&](std::size_t passageIndex)
{
// Surface-route treads may reinforce native solid terrain only.
if(!(density<0.0f))return;
if(passageIndex>=ResolvedLayout->passages.size()
||passageIndex>=PassageMouthSupportRoutes.size())return;
const auto& passage=ResolvedLayout->passages[passageIndex];
const auto& mouth=passage.upperMouthSubvoxels;
const double mouthDx=qx-static_cast<double>(mouth[0]);
const double mouthDy=qy-static_cast<double>(mouth[1]);
const double routeSupportReach=13.0*qPerMetre;
if(mouthDx*mouthDx+mouthDy*mouthDy>routeSupportReach*routeSupportReach)return;
const auto stratum=std::find_if(ResolvedLayout->strates.begin(),
ResolvedLayout->strates.end(),[strateIndex](const auto& value)
{return value.strateIndex==strateIndex;});
if(stratum==ResolvedLayout->strates.end())return;
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> route;
route.reserve(stratum->anchors.size());
for(const auto& anchor:stratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
route.push_back(&anchor);
if(route.size()<2)return;
const std::size_t lastSegment=route.size()-1;
const auto& route=PassageMouthSupportRoutes[passageIndex];
if(route.empty())return;
constexpr double MouthSupportBlendMetres=0.45;
// Route anchors encode the player center at half the authored capsule
// height above the tread. Keep the support deck below that same foot
@@ -999,18 +1031,21 @@ public:
constexpr double RouteCenterAboveFootMetres=0.88;
const double mouthBlendWidth=MouthSupportBlendMetres*qPerMetre;
double mouthSupportDistance=std::numeric_limits<double>::infinity();
for(std::size_t index=0;index<lastSegment;++index)
const auto evaluateSegment=[&](std::size_t index)
{
const auto& a=*route[index];const auto& b=*route[index+1];
const double dx=static_cast<double>(b.values[0]-a.values[0]);
const double dy=static_cast<double>(b.values[1]-a.values[1]);
if(index>=route.size())return;
if(passageProfile)++passageProfile->passageMouthRouteSegmentChecks;
const auto& segment=route[index];
const double dx=static_cast<double>(segment.b[0]-segment.a[0]);
const double dy=static_cast<double>(segment.b[1]-segment.a[1]);
const double lengthSq=dx*dx+dy*dy;
const double t=lengthSq>0.0?std::clamp(((qx-a.values[0])*dx
+(qy-a.values[1])*dy)/lengthSq,0.0,1.0):0.0;
const double centerX=a.values[0]+t*dx,centerY=a.values[1]+t*dy;
const double centerZ=a.values[2]+t*(static_cast<double>(b.values[2])-a.values[2]);
const double routeRadius=a.values.size()>=4
?a.values[3]+t*(static_cast<double>(b.values[3])-a.values[3]):0.0;
const double t=lengthSq>0.0?std::clamp(((qx-segment.a[0])*dx
+(qy-segment.a[1])*dy)/lengthSq,0.0,1.0):0.0;
const double centerX=segment.a[0]+t*dx,centerY=segment.a[1]+t*dy;
const double centerZ=segment.a[2]
+t*(static_cast<double>(segment.b[2])-segment.a[2]);
const double routeRadius=segment.hasRadius
?segment.a[3]+t*(static_cast<double>(segment.b[3])-segment.a[3]):0.0;
const double halfWidth=std::clamp(routeRadius,
0.42*qPerMetre,0.56*qPerMetre);
const double horizontalX=qx-centerX,horizontalY=qy-centerY;
@@ -1022,12 +1057,29 @@ public:
const double topDistance=qz-floorQ;
const double bottomDistance=floorQ-qPerMetre-qz;
const double verticalDistance=std::max(topDistance,bottomDistance);
if(sideDistance>mouthBlendWidth||verticalDistance>mouthBlendWidth)continue;
if(sideDistance>mouthBlendWidth||verticalDistance>mouthBlendWidth)return;
const double outside=DeterministicSqrt(
std::max(sideDistance,0.0)*std::max(sideDistance,0.0)
+std::max(verticalDistance,0.0)*std::max(verticalDistance,0.0));
const double inside=std::min(std::max(sideDistance,verticalDistance),0.0);
mouthSupportDistance=std::min(mouthSupportDistance,outside+inside);
};
if(passageTileScopeMatches)
{
for(const auto& candidate:passageTileQueries->mouthSupportSegments(passageIndex))
{
const bool containsPoint=qx>=candidate.minimumSubvoxels[0]
&&qx<=candidate.maximumSubvoxels[0]
&&qy>=candidate.minimumSubvoxels[1]
&&qy<=candidate.maximumSubvoxels[1]
&&qz>=candidate.minimumSubvoxels[2]
&&qz<=candidate.maximumSubvoxels[2];
if(containsPoint)evaluateSegment(candidate.segmentIndex);
}
}
else
{
for(std::size_t index=0;index<route.size();++index)evaluateSegment(index);
}
if(std::isfinite(mouthSupportDistance))
composed=SmoothMinDistance(composed,
@@ -1037,6 +1089,7 @@ public:
// The connected passage tread continues the surface route into the tunnel.
for(std::size_t passageIndex=0;passageIndex<ResolvedLayout->passages.size();++passageIndex)
{
if(passageProfile)++passageProfile->passageIterations;
const auto& passage=ResolvedLayout->passages[passageIndex];
if(passage.controlPoints.size()<2)continue;
const auto supportStratum=[&](std::int32_t strateIndex)
@@ -1071,6 +1124,7 @@ public:
const auto laterPassageMayCarve=[&](std::ptrdiff_t supportSegment,
double sampleX,double sampleY,double sampleZ)
{
if(passageProfile)++passageProfile->passageLaterBoreChecks;
return PassageSupportMayBeCarvedByLaterBore(passageIndex,
supportSegment,sampleX,sampleY,sampleZ,0.35*qPerMetre);
};
@@ -1086,6 +1140,7 @@ public:
{
if(!crossing.needsColumn||crossing.passageIndex!=passageIndex
||qz>crossing.topZSubvoxels||qz<crossing.bottomZSubvoxels)continue;
if(passageProfile)++passageProfile->passageColumnCandidates;
#if defined(VF_L30_ENABLE_COST_COUNTERS)
++ThreadClassificationStats().ColumnZOverlapCalls;
#endif
@@ -1120,6 +1175,7 @@ public:
#else
if(horizontalSquared>exteriorLimit*exteriorLimit)continue;
#endif
if(passageProfile)++passageProfile->passageColumnDistanceCalls;
columnDistance=PassageColumnSignedDistance(crossing,X,Y,Z);
}
else
@@ -1127,6 +1183,7 @@ public:
#if defined(VF_L30_ENABLE_COST_COUNTERS)
++ThreadClassificationStats().ColumnSignedDistanceCalls;
#endif
if(passageProfile)++passageProfile->passageColumnDistanceCalls;
columnDistance=PassageColumnSignedDistance(crossing,X,Y,Z);
}
composed=std::min(composed,static_cast<float>(columnDistance/Q));
@@ -1166,12 +1223,16 @@ public:
const std::ptrdiff_t mouthSearchBegin=std::max<std::ptrdiff_t>(0,lowerMouthIndex-8);
const std::ptrdiff_t mouthSearchEnd=std::min<std::ptrdiff_t>(lastIndex,
lowerMouthIndex+8);
if(density<0.0f&&tilePassageFree
&&!PassageMayAffectDensity(passageIndex,carveBegin,carveEnd,
if(density<0.0f&&tilePassageFree)
{
if(passageProfile)++passageProfile->passageNegativeBoundChecks;
if(!PassageMayAffectDensity(passageIndex,carveBegin,carveEnd,
lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,lastIndex,qx,qy,qz,
-static_cast<double>(composed)*Q+0.24*qPerMetre))
{
continue;
{
if(passageProfile)++passageProfile->passageNegativeBoundRejects;
continue;
}
}
// For a positive source sample, the tube can only change it within relief reach;
// the supported column tread is within 2.25 m of its centerline. A short-span
@@ -1181,10 +1242,18 @@ public:
// n'a pas cette borne, donc sa requête complète est conservée.
const bool canCullPositiveRoute=passageTileScopeMatches&&density>=0.0f
&&!PassageHasShortSpanSegments(passageIndex);
if(canCullPositiveRoute&&!PassageMayAffectDensity(passageIndex,carveBegin,carveEnd,
lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,lastIndex,qx,qy,qz,
std::max(2.25*qPerMetre,-static_cast<double>(composed)*Q
+0.24*qPerMetre)))continue;
if(canCullPositiveRoute)
{
if(passageProfile)++passageProfile->passagePositiveBoundChecks;
if(!PassageMayAffectDensity(passageIndex,carveBegin,carveEnd,
lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,lastIndex,qx,qy,qz,
std::max(2.25*qPerMetre,-static_cast<double>(composed)*Q
+0.24*qPerMetre)))
{
if(passageProfile)++passageProfile->passagePositiveBoundRejects;
continue;
}
}
double bestSignedDistance=std::numeric_limits<double>::infinity();
double bestPlayerCapsuleSignedDistance=std::numeric_limits<double>::infinity();
double bestT=0.0;
@@ -1208,10 +1277,12 @@ public:
lowerMouthDx*lowerMouthDx+lowerMouthDy*lowerMouthDy
+lowerMouthDz*lowerMouthDz)/qPerMetre;
const double lowerMouthT=std::clamp((20.0-lowerMouthDistance)/12.0,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
const double lowerMouthBlend=lowerMouthT*lowerMouthT
*(3.0-2.0*lowerMouthT);
const auto considerCarveSegment=[&](std::size_t segmentIndex,int scanPhase)
{
if(passageProfile)++passageProfile->passageCarveSegmentVisits;
const std::ptrdiff_t index=static_cast<std::ptrdiff_t>(segmentIndex);
const auto& a=passage.controlPoints[static_cast<std::size_t>(index)];
const auto& b=passage.controlPoints[static_cast<std::size_t>(index+1)];
@@ -1249,6 +1320,7 @@ public:
&&!IsPassageShortSpanSegment(passageIndex,segmentIndex+1);
if(smoothCarveJoin)
{
if(passageProfile)++passageProfile->passageSmoothCarveJoins;
const auto& p0=passage.controlPoints[static_cast<std::size_t>(index-1)];
const auto& p3=passage.controlPoints[static_cast<std::size_t>(index+2)];
constexpr double SmoothJoinWeight=1.0;
@@ -1326,12 +1398,11 @@ public:
const float mouthSurfaceRelief=VF_FieldSurfaceRelief(static_cast<float>(X)*1.5f,
static_cast<float>(Y)*1.5f,static_cast<float>(Z)*1.5f,
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x4D4F5554u);
const float mouthTerrainRelief=VF_FieldSurfaceRelief(static_cast<float>(X)*1.5f,
static_cast<float>(Y)*1.5f,static_cast<float>(Z)*1.5f,
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x4D4F5554u);
const float mouthTerrainRelief=mouthSurfaceRelief;
const float mouthTreadFieldRelief=VF_FieldSurfaceRelief(static_cast<float>(X)*0.75f,
static_cast<float>(Y)*0.75f,static_cast<float>(Z)*0.75f,
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x54485244u);
if(passageProfile)passageProfile->passageReliefFieldCalls+=3;
const auto routeSegmentLengthMetres=[&](std::ptrdiff_t routeIndex)
{
const auto& before=passage.controlPoints[static_cast<std::size_t>(routeIndex)];
@@ -1381,6 +1452,7 @@ public:
for(std::ptrdiff_t routeIndex=0;
routeIndex<std::min<std::ptrdiff_t>(3,lowerMouthIndex);++routeIndex)
{
if(passageProfile)++passageProfile->passageMouthRouteSegmentChecks;
const auto& before=passage.controlPoints[static_cast<std::size_t>(routeIndex)];
const auto& after=passage.controlPoints[static_cast<std::size_t>(routeIndex+1)];
const double ax=static_cast<double>(before.positionSubvoxels[0]);
@@ -1402,6 +1474,7 @@ public:
static_cast<float>((az+t*dz)/qPerMetre*1.5),
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x4D4F5554u)),
-1.0,1.0);
if(passageProfile)++passageProfile->passageReliefFieldCalls;
const double lateralOffset=pathRelief*0.18*qPerMetre;
projectedX-=dy/horizontalLength*lateralOffset;
projectedY+=dx/horizontalLength*lateralOffset;
@@ -1437,10 +1510,12 @@ public:
if(std::isfinite(distanceFromOpenMouth))
{
const double fade=std::clamp(distanceFromOpenMouth/11.0,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
const double smooth=fade*fade*(3.0-2.0*fade);
mouthFloorBlend=1.0-smooth;
}
const double floorReliefT=std::clamp((verticalWallAlignment-0.55)/0.45,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
const double floorReliefWeight=floorReliefT*floorReliefT
*(3.0-2.0*floorReliefT);
const double floorReliefOffset=std::clamp(
@@ -1466,6 +1541,7 @@ public:
constexpr double mouthCarveFadeMetres=8.0;
mouthCarveFade=std::clamp(distanceFromOpenMouth/mouthCarveFadeMetres,
0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
mouthCarveFade=mouthCarveFade*mouthCarveFade*(3.0-2.0*mouthCarveFade);
}
const double floorAlignment=std::max(verticalWallAlignment,
@@ -1477,6 +1553,7 @@ public:
const double belowFloor=(mouthEntryFloorQ-qz)/qPerMetre;
const double supportRamp=std::clamp(belowFloor/0.15,0.0,1.0);
const double supportFade=std::clamp((1.0-belowFloor)/0.35,0.0,1.0);
if(passageProfile)passageProfile->passageSmoothstepEvaluations+=2;
const double rampSmooth=supportRamp*supportRamp*(3.0-2.0*supportRamp);
const double fadeSmooth=supportFade*supportFade*(3.0-2.0*supportFade);
floorBelowWeight=rampSmooth*fadeSmooth;
@@ -1485,6 +1562,7 @@ public:
// former bore-wide alignment feather left a straight platform-width
// bridge across the FI mouth.
double mouthWalkLaneT=std::clamp((1.05-mouthEntryPlanDistance)/0.60,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
mouthWalkLaneT=mouthWalkLaneT*mouthWalkLaneT*(3.0-2.0*mouthWalkLaneT);
const double mouthWalkLaneWeight=upperMouthFloorFade?mouthWalkLaneT:0.0;
const double floorCarveWeight=1.0-(1.0-mouthCarveFade)
@@ -1496,6 +1574,7 @@ public:
const float composedAfterCarve=composed;
const auto considerSupportSegment=[&](std::ptrdiff_t index)
{
if(passageProfile)++passageProfile->passageSupportSegmentVisits;
const auto& segmentA=passage.controlPoints[static_cast<std::size_t>(index)];
const auto& segmentB=passage.controlPoints[static_cast<std::size_t>(index+1)];
const double dx=static_cast<double>(segmentB.positionSubvoxels[0])-segmentA.positionSubvoxels[0];
@@ -1538,6 +1617,7 @@ public:
static_cast<double>(segmentB.radiusSubvoxels)-segmentA.radiusSubvoxels);
if(smoothSupportJoin)
{
if(passageProfile)++passageProfile->passageSmoothSupportJoins;
const auto& p0=passage.controlPoints[static_cast<std::size_t>(index-1)];
const auto& p3=passage.controlPoints[static_cast<std::size_t>(index+2)];
const double t2=supportT*supportT,t3=t2*supportT;
@@ -1568,6 +1648,7 @@ public:
static_cast<float>(centerZ/qPerMetre*1.5),
static_cast<std::uint32_t>(Owner?Owner->Seed:0)^0x4D4F5554u)),
-1.0,1.0);
if(passageProfile)++passageProfile->passageReliefFieldCalls;
treadRelief=pathRelief;
const double lateralOffset=pathRelief*0.18*qPerMetre;
centerX-=dy/horizontalLength*lateralOffset;
@@ -1660,8 +1741,10 @@ public:
suffixMetres+(1.0-supportT)*supportSegmentLength);
}
double mouthReliefT=std::clamp(distanceFromMouthMetres/8.0,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
mouthReliefT=mouthReliefT*mouthReliefT*(3.0-2.0*mouthReliefT);
double mouthSupportT=std::clamp((distanceFromMouthMetres-0.25)/4.0,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
mouthSupportT=mouthSupportT*mouthSupportT*(3.0-2.0*mouthSupportT);
const double mouthSupportWidth=std::lerp(0.82,1.00,mouthSupportT);
const double supportHalfWidthMetres=mouthTread?mouthSupportWidth
@@ -1687,6 +1770,7 @@ public:
?std::clamp((horizontalDistance
-(supportHalfWidth-supportEdgeBlendMetres*qPerMetre))
/(supportEdgeBlendMetres*qPerMetre),0.0,1.0):0.0;
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
const double supportEdgeSmooth=supportEdgeT*supportEdgeT
*(3.0-2.0*supportEdgeT);
const double mouthSupportThicknessVoxels=std::lerp(
@@ -1700,6 +1784,7 @@ public:
{
const double mouthBlendT=std::clamp(
distanceFromMouthMetres/0.75,0.0,1.0);
if(passageProfile)++passageProfile->passageSmoothstepEvaluations;
mouthSupportBlend=0.75+0.25*mouthBlendT*mouthBlendT
*(3.0-2.0*mouthBlendT);
}
@@ -1802,12 +1887,17 @@ public:
const double capsuleQueryZ=bestSupportUsesSignedDistance?bestSupportFloorQ:qz;
const bool supportCapsuleProfileAvailable=passageIndex<PassageNearestNodes.size()
&&!PassageNearestNodes[passageIndex].empty();
const bool capsuleAllowsSupport=(passageTileScopeMatches
bool capsuleAllowsSupport;
if(passageTileScopeMatches
||(bestSupportUsesSignedDistance&&supportCapsuleProfileAvailable))
?!PassagePlayerCapsuleBlocksSupport(passageIndex,carveBegin,carveEnd,
lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,lastIndex,qx,qy,
capsuleQueryZ,qPerMetre,capsuleClearanceMetres)
:bestPlayerCapsuleSignedDistance>=capsuleClearanceMetres*qPerMetre;
{
if(passageProfile)++passageProfile->passageSupportCapsuleChecks;
capsuleAllowsSupport=!PassagePlayerCapsuleBlocksSupport(passageIndex,
carveBegin,carveEnd,lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,
lastIndex,qx,qy,capsuleQueryZ,qPerMetre,capsuleClearanceMetres);
}
else capsuleAllowsSupport=
bestPlayerCapsuleSignedDistance>=capsuleClearanceMetres*qPerMetre;
bool supportApplied=false;
bool supportNeedsDeferral=false;
// Outside bridge and short-span segments, add the tread only where the
@@ -1826,9 +1916,12 @@ public:
// and noise. The capsule test keeps neighbouring coils open.
const bool nativeRestoreCapsuleClear=density<0.0f
&&bestSupportNativeBlend>0.0&&capsuleAllowsSupport
&&!PassagePlayerCapsuleBlocksSupport(passageIndex,carveBegin,
carveEnd,lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,
lastIndex,qx,qy,qz,qPerMetre,capsuleClearanceMetres);
&&([&](){
if(passageProfile)++passageProfile->passageSupportCapsuleChecks;
return !PassagePlayerCapsuleBlocksSupport(passageIndex,carveBegin,
carveEnd,lowerMouthIndex,mouthSearchBegin,mouthSearchEnd,
lastIndex,qx,qy,qz,qPerMetre,capsuleClearanceMetres);
})();
if(nativeRestoreCapsuleClear)
{
const double nativeSurfaceDetail=std::clamp(
@@ -1851,6 +1944,7 @@ public:
}
if(supportApplied)
{
if(passageProfile)++passageProfile->passageOtherCapsuleChecks;
if(PassageOtherCapsuleBlocksSupport(passageIndex,
bestSupportSegmentIndex,qx,qy,qz,qPerMetre,capsuleClearanceMetres))
{
@@ -1875,8 +1969,10 @@ public:
const bool tileHasSupport=passageTileScopeMatches;
if(!tileHasSupport
||ActivePassageTileQueries->hasMouthSupport(passageIndex))
composeRouteMouthSupport(passage.upperStrateIndex,
passage.upperMouthSubvoxels);
{
if(passageProfile)++passageProfile->passageMouthSupportCalls;
composeRouteMouthSupport(passageIndex);
}
}
composed=std::min(composed,deferredSupportDensity);
return composed;
@@ -3332,6 +3428,11 @@ private:
std::size_t passageIndex=0,segmentIndex=0;
bool bColumn=false,bMouthSupport=false;
};
struct FPassageMouthSupportSegment
{
std::array<std::int64_t,4> a{},b{};
bool hasRadius=false;
};
struct FPassageNearestNode
{
std::array<double,3> minimum{},maximum{};
@@ -4309,6 +4410,8 @@ private:
PassageNearestNodes.clear();
PassageProofBounds.clear();PassageProofNodes.clear();
PassageNearestNodes.resize(ResolvedLayout?ResolvedLayout->passages.size():0);
PassageMouthSupportRoutes.clear();
PassageMouthSupportRoutes.resize(ResolvedLayout?ResolvedLayout->passages.size():0);
PassageLaterBoreSources.clear();
PassageColumnSegmentFlags.clear();PassageShortSpanSegmentFlags.clear();
PassageHasShortSpanFlags.clear();
@@ -4316,6 +4419,7 @@ private:
constexpr double Q=static_cast<double>(VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel);
const double voxelsPerMetre=Owner&&Owner->CoreVoxelSizeMicrons>0
?1000000.0/Owner->CoreVoxelSizeMicrons:4.0;
const double qPerMetre=Q*voxelsPerMetre;
const double bridgeHalfWidthVoxels=3.5*voxelsPerMetre;
const double bridgeFootDepthVoxels=(5.0-0.13)*voxelsPerMetre;
PassageColumnSegmentFlags.resize(ResolvedLayout->passages.size());
@@ -4367,9 +4471,12 @@ private:
{
std::array<const VoxelForgeCore::ResolvedLayoutAnchorV2*,5> route{};
std::size_t routeCount=0;
std::vector<const VoxelForgeCore::ResolvedLayoutAnchorV2*> allRoutePoints;
allRoutePoints.reserve(upperStratum->anchors.size());
for(const auto& anchor:upperStratum->anchors)
if(anchor.kind=="route_point"&&anchor.values.size()>=3)
{
allRoutePoints.push_back(&anchor);
if(routeCount<route.size())route[routeCount++]=&anchor;
else
{
@@ -4379,6 +4486,25 @@ private:
}
if(routeCount>=2)
{
auto& supportRoutes=PassageMouthSupportRoutes[passageIndex];
supportRoutes.reserve(allRoutePoints.size()-1);
for(std::size_t index=0;index+1<allRoutePoints.size();++index)
{
FPassageMouthSupportSegment segment;
for(std::size_t axis=0;axis<3;++axis)
{
segment.a[axis]=allRoutePoints[index]->values[axis];
segment.b[axis]=allRoutePoints[index+1]->values[axis];
}
segment.hasRadius=allRoutePoints[index]->values.size()>=4
&&allRoutePoints[index+1]->values.size()>=4;
if(segment.hasRadius)
{
segment.a[3]=allRoutePoints[index]->values[3];
segment.b[3]=allRoutePoints[index+1]->values[3];
}
supportRoutes.push_back(segment);
}
const double mouthReach=13.0*voxelsPerMetre*Q;
double minimumZ=std::numeric_limits<double>::infinity();
double maximumZ=-std::numeric_limits<double>::infinity();
@@ -4395,17 +4521,32 @@ private:
supportProof.maximum={(mouthX+mouthReach)/Q,(mouthY+mouthReach)/Q,
(maximumZ+3.0*voxelsPerMetre*Q)/Q};
PassageProofBounds.push_back(supportProof);
const std::array<std::int64_t,3> featureMin={
static_cast<std::int64_t>(std::floor(supportProof.minimum[0]*Q)),
static_cast<std::int64_t>(std::floor(supportProof.minimum[1]*Q)),
static_cast<std::int64_t>(std::floor(supportProof.minimum[2]*Q))};
const std::array<std::int64_t,3> featureMax={
static_cast<std::int64_t>(std::ceil(supportProof.maximum[0]*Q)),
static_cast<std::int64_t>(std::ceil(supportProof.maximum[1]*Q)),
static_cast<std::int64_t>(std::ceil(supportProof.maximum[2]*Q))};
PassageFeatureBounds.push_back({static_cast<std::uint64_t>(PassageTileFeatures.size()),
featureMin,featureMax});
PassageTileFeatures.push_back({passageIndex,0,false,true});
for(std::size_t index=0;index<supportRoutes.size();++index)
{
const auto& segment=supportRoutes[index];
constexpr double HorizontalReachMetres=1.01;
constexpr double MouthSupportTopOffsetMetres=0.68;
constexpr double MouthSupportBottomOffsetMetres=2.58;
const std::array<std::int64_t,3> featureMinimum={
std::min(segment.a[0],segment.b[0])-static_cast<std::int64_t>(
std::ceil(HorizontalReachMetres*qPerMetre)),
std::min(segment.a[1],segment.b[1])-static_cast<std::int64_t>(
std::ceil(HorizontalReachMetres*qPerMetre)),
static_cast<std::int64_t>(std::floor(
std::min(segment.a[2],segment.b[2])
-MouthSupportBottomOffsetMetres*qPerMetre))};
const std::array<std::int64_t,3> featureMaximum={
std::max(segment.a[0],segment.b[0])+static_cast<std::int64_t>(
std::ceil(HorizontalReachMetres*qPerMetre)),
std::max(segment.a[1],segment.b[1])+static_cast<std::int64_t>(
std::ceil(HorizontalReachMetres*qPerMetre)),
static_cast<std::int64_t>(std::ceil(
std::max(segment.a[2],segment.b[2])
-MouthSupportTopOffsetMetres*qPerMetre))};
PassageFeatureBounds.push_back({static_cast<std::uint64_t>(
PassageTileFeatures.size()),featureMinimum,featureMaximum});
PassageTileFeatures.push_back({passageIndex,index,false,true});
}
}
}
}
@@ -4414,7 +4555,6 @@ private:
// hot query can test a short list of physical bounds instead of walking a
// full spatial tree for every density sample.
PassageLaterBoreSources.resize(ResolvedLayout->passages.size());
const double qPerMetre=Q*voxelsPerMetre;
for(std::size_t sourcePassageIndex=0;
sourcePassageIndex<ResolvedLayout->passages.size();++sourcePassageIndex)
{
@@ -11170,6 +11310,7 @@ private:
std::vector<FPassageFeatureNode> PassageFeatureNodes;
bool PassageFeatureBoundsFailOpen=false;
std::vector<std::vector<FPassageNearestNode>> PassageNearestNodes;
std::vector<std::vector<FPassageMouthSupportSegment>> PassageMouthSupportRoutes;
std::vector<std::vector<FPassageLaterBoreSource>> PassageLaterBoreSources;
std::vector<FPassageProofBound> PassageProofBounds;
std::vector<FPassageProofNode> PassageProofNodes;
+16 -1
View File
@@ -2620,7 +2620,22 @@ namespace VoxelForgeCore
// GenerateMesh n'échantillonne que origin..origin+extent et la marge de normale d'un pas ;
// queryMinimum/queryMaximum ci-dessus couvrent exactement ce domaine inclusif.
const FStandaloneShapeWorld::FScopedPassageTileQueries passageFeatureScope(
tileShape,queryMinimum,queryMaximum);
tileShape,queryMinimum,queryMaximum,
options.profilePassageComposer?&out.diagnostics:nullptr);
if(options.profilePassageComposer)
{
out.diagnostics.passageComposerProfiled=true;
out.diagnostics.passageTileFeatureCount=passageFeatureScope.featureCount();
if(impl_->resolvedLayout)
{
out.diagnostics.passageTileRouteSegmentCandidates=
passageFeatureScope.routeSegmentCandidateCount();
for(std::size_t passageIndex=0;
passageIndex<impl_->resolvedLayout->passages.size();++passageIndex)
out.diagnostics.passageTileMouthSegmentCandidates+=
passageFeatureScope.mouthSupportSegments(passageIndex).size();
}
}
const bool bDiagnosticColumnSampling=options.diagnosticGlobalOctaveDrop!=0
||options.diagnosticColumnInterpolationStride>1;
const std::uint32_t PreviousOctaveDrop=bDiagnosticColumnSampling
@@ -4,10 +4,11 @@ import argparse
import importlib.util
import math
from collections import defaultdict, deque
import os
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
BASELINES = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37")) / "baselines"
PROFILE_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py"
SPEC = importlib.util.spec_from_file_location("ring_profile_l37", PROFILE_PATH)
PROFILE = importlib.util.module_from_spec(SPEC)
@@ -13,9 +13,9 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
OUT = Path(os.environ.get("VOXELFORGE_L37_OUT",
os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37")))
BASELINES = OUT / "baselines"
BIN = OUT / "bin"
CAPTURES = Path(os.environ.get("VOXELFORGE_L37_CAPTURE_DIR",
OUT / "captures"))
@@ -8,10 +8,11 @@ import json
import math
import re
import argparse
import os
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
BASELINES = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37")) / "baselines"
BASE_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux37/RunMouthFragmentAuditL37.py"
SPEC = importlib.util.spec_from_file_location("mouth_fragment_l37", BASE_PATH)
BASE = importlib.util.module_from_spec(SPEC)
@@ -10,8 +10,8 @@ import os
from pathlib import Path
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
OUT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l37"))
BASELINES = OUT / "baselines"
BIN = Path(os.environ.get("VOXELFORGE_VERIFY_HEADLESS",
OUT / "bin/VoxelForgeCoreHeadless-l37-final-clang"))
OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA",
@@ -14,7 +14,7 @@ import time
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
BASELINES = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l47")) / "baselines"
VERIFY = ROOT / "Standalone/Tools/verify"
LINUX37 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux37"
sys.path.insert(0, str(VERIFY))
@@ -6,12 +6,13 @@ import importlib.util
import argparse
import json
import math
import os
from pathlib import Path
import sys
ROOT = Path(__file__).resolve().parents[4]
BASELINES = ROOT / "Standalone/Tools/verify/baselines"
BASELINES = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l47")) / "baselines"
PROFILE_PATH = ROOT / "Standalone/Research/WorldAssemblerM3/Linux32/AuditRingTerraceL32.py"
spec = importlib.util.spec_from_file_location("ring_profile", PROFILE_PATH)
if spec is None or spec.loader is None:
@@ -0,0 +1,61 @@
# Linux 72 report
## Unreal timeline
Three L71 and three L72 traces used the same 2,850 tile keys. The readback value `streaming_background_worker_cap=1` selects the TaskGraph background lane; Unreal reported eight background workers and eight effective tile slots. The delay was queue admission and result draining, not RMC construction. Raising ready queue depth from 8 to 16 and the startup apply count cap from 12 to 24 moved readiness forward. The hard game-thread apply budget stays 14 ms, and the moving-player admission cap still prevents a ready backlog during fast travel.
| Median milestone | L71 | L72 |
|---|---:|---:|
| Last tile requested | 4.577 s | 3.680 s |
| Last worker started | 4.583 s | 3.696 s |
| Last worker finished | 4.597 s | 3.712 s |
| Last tile applied | 4.754 s | 3.724 s |
| Initial set ready | 4.775 s | 3.741 s |
| Walkable gate ready | 1.068 s | 1.107 s |
| Queue p95 | 122.7 ms | 34.8 ms |
| Request-to-apply p95 | 139.1 ms | 45.3 ms |
The worker-finish-to-last-apply tail fell from 157 ms to 11 ms. L72 per-frame apply work was p95 0.73 ms, max 6.26 ms, below the 14 ms cap; the cap was not hit. Commandlet frame interval p95 was 18.85 ms. Initial-set readiness still takes 3.74 s (about 199 p95 frame intervals), so the roughly 1 s target is not met. Against the 2.41 s headless stride-0 whole-view median, about 1.33 s remains in the Unreal path. RMC build p95 was 0.32 ms.
Headless whole-view timing used three interleaved before/after pairs per stratum:
| Stratum | Tiles | Before median | After median |
|---|---:|---:|---:|
| 0 | 2,850 | 2.538 s | 2.412 s |
| 1 | 2,249 | 6.382 s | 6.343 s |
| 2 | 2,233 | 5.718 s | 5.443 s |
| 3 | 2,329 | 2.661 s | 2.624 s |
## Passage composer
The L71 40× compares 18.8 ms for nonempty passage tiles with 0.5 ms across all LOD0 tiles; 441 of 512 LOD0 tiles were empty. Empty tiles can stop after classification, while a nonempty passage tile fills and meshes a density grid. It is not a matched per-sample comparison. These profiles do not isolate the passage-specific share of total tile time: passage controls have about twice the samples of the terrain control, and no matched nonempty terrain control was profiled. Native calls were 27,367 for terrain (17,680 samples) and 43,243/44,767 for passage tiles (36,439/37,975 samples).
Within the composer, route-mouth checks were a large avoidable scan. The shared composer now filters mouth-support segments against per-tile bounds and reuses the identical mouth relief result. Passage carve/support visits and smoothstep counts stayed the same. The exact counters are below; they show reduced work, but do not identify the dominant timed composer term.
| Tile (LOD0) | Samples | Native calls before/after | Mouth route checks before → after | Relief calls before → after |
|---|---:|---:|---:|---:|
| Terrain `(5,-2,-47)` | 17,680 | 27,367 | — | — |
| Passage `(1,0,-47)` | 36,439 | 43,243 | 612,242 → 123,090 | 384,444 → 343,414 |
| Passage `(0,1,-47)` | 37,975 | 44,767 | 1,042,612 → 131,334 | 407,910 → 364,554 |
Field calls and world hashes are unchanged. The two passage samples reduced route checks by 80% and 87%. A single instrumented worker-time comparison was mixed (100.0→91.8 ms and 155.2→157.1 ms), so it does not establish a stable per-tile wall-time gain. L71 identified near-field density-grid sampling and meshing as the largest cost; L72 does not isolate which composer term takes the most time.
## Integrity and housekeeping
- Hashes matched before/after at W1, W8, and W12 with Clang and GCC: all 2,850 keys and density, mesh, payload, and topology hashes matched.
- Fast tier passed in 270.2 s (269 PASS, 5 DIAGNOSTIC); gates and thresholds are unchanged.
- Compressed all 11 verification meshes with Python `lzma`: 78.54 MB → 18.37 MB (23.4% of original). `verify.py` expands them into its output baselines folder before use.
## Source changes
- `Source/VoxelForge/Private/VoxelWorld.cpp`: queue depth and startup apply count tuning, retaining the 14 ms hard budget and moving-player admission behavior.
- `Standalone/Core/src/ShapeWorldInternal.h`: tile-local passage support segment filtering and reused mouth relief evaluation.
- `Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h`, `Standalone/Core/src/VoxelForgeCore.cpp`, `Standalone/Source/StreamingWorld.h`, `Standalone/Source/StreamBenchmarkPipeline.h`, `Standalone/Source/StreamBenchmarkHeadless.cpp`: opt-in per-tile composer counters.
- `Standalone/Tools/verify/verify.py` and the Linux37/Linux47 audit scripts: decompressed baseline path handling.
## Failed and rejected runs
- The first Unreal build referenced unavailable .NET 8.0.300; retry with installed 8.0.412 succeeded.
- An initial hash invocation omitted `--stream-hash-tiles` and emitted no hash rows; corrected six-config matrix passed.
- The first fast-tier attempt lacked built executables, then an audit helper still read the compressed baseline path. Both were corrected; the rerun passed.
- A no-feature passage cull changed density hashes in 433 tiles and was reverted. A point-bound trial rejected no negative LOD0 samples, and a carve-seed trial added one candidate visit per query; both were dropped. A depth-32 queue probe worsened LOD0 request-to-apply p95 (102.6 ms) and walkable readiness (1.204 s), so depth 16 was retained.
@@ -46,6 +46,7 @@ namespace
bool ScreenSpaceGate=false;
bool AuditUniformBlockProofs=false;
bool ProfileLodWork=false;
bool ProfilePassageComposer=false;
bool InstrumentTileDrain=false;
bool ExactMidpointDensityMemo=false;
bool ActiveLaneBatching=false;
@@ -1439,6 +1440,7 @@ namespace
" --audit-uniform-block-proofs (fill and check every interval-certified block)\n"
" --profile-lod-work (report per-LOD density sample counts)\n"
" --instrument-tile-drain (opt-in CpuTileTimeline and per-tile stages/counters)\n"
" --profile-passage-composer (emit per-tile passage work counters)\n"
" --exact-midpoint-density-memo (exact-input midpoint query memo A/B)\n"
" --active-lane-batching --proof-block-cells=N (proof-masked density fill A/B)\n"
" --parallel-sign-edge-repair --serial-sign-edge-repair\n"
@@ -1494,6 +1496,8 @@ namespace
else if(arg=="--audit-uniform-block-proofs")options.AuditUniformBlockProofs=true;
else if(arg=="--profile-lod-work")options.ProfileLodWork=true;
else if(arg=="--instrument-tile-drain")options.InstrumentTileDrain=true;
else if(arg=="--profile-passage-composer")
{options.ProfilePassageComposer=true;options.InstrumentTileDrain=true;}
else if(arg=="--exact-midpoint-density-memo")options.ExactMidpointDensityMemo=true;
else if(arg=="--active-lane-batching")options.ActiveLaneBatching=true;
else if(arg=="--parallel-sign-edge-repair")
@@ -2214,5 +2218,5 @@ int main(int argc,char** argv)
options.ProofBlockCells,options.HasSignEdgeRepairOverride
?options.ParallelSignEdgeRepair:options.FloatingIslandsRecipe,
options.AuditNativeLattice,options.LatticeOrphanControl,
options.CaptureSkipWalkability);
options.CaptureSkipWalkability,options.ProfilePassageComposer);
}
+3 -1
View File
@@ -1872,7 +1872,8 @@ namespace StandaloneStreamBenchmark
bool bExactMidpointDensityMemo=false,
bool bActiveLaneBatching=false,int32 ProofBlockCells=8,
bool bParallelSignEdgeRepair=false,bool bAuditNativeLattice=false,
bool bLatticeOrphanControl=false,bool bCaptureSkipWalkability=false)
bool bLatticeOrphanControl=false,bool bCaptureSkipWalkability=false,
bool bProfilePassageComposer=false)
{
using Clock=std::chrono::steady_clock;
FStandaloneOwnerWorld& World=*OwnerWorld;
@@ -2037,6 +2038,7 @@ namespace StandaloneStreamBenchmark
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache);
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
Streamer.SetTileDrainInstrumentationEnabled(bInstrumentTileDrain);
Streamer.SetPassageComposerProfilingEnabled(bProfilePassageComposer);
Streamer.SetExactMidpointDensityMemoEnabled(bExactMidpointDensityMemo);
Streamer.SetActiveLaneBatchingEnabled(bActiveLaneBatching);
Streamer.SetProofBlockCells(ProofBlockCells);
+32
View File
@@ -710,6 +710,8 @@ public:
{bProfileMesherStages=Enabled;}
void SetTileDrainInstrumentationEnabled(bool Enabled)
{bInstrumentTileDrain=Enabled;}
void SetPassageComposerProfilingEnabled(bool Enabled)
{bProfilePassageComposer=Enabled;}
void SetExactMidpointDensityMemoEnabled(bool Enabled)
{bExactMidpointDensityMemo=Enabled;}
void SetActiveLaneBatchingEnabled(bool Enabled)
@@ -890,6 +892,7 @@ private:
Options.useSharedColumnCache=bSharedColumnCache;
Options.lod8HorizonInteriorStepVoxels=Lod8HorizonInteriorStepVoxels;
Options.profileMesherStages=(bProfileMesherStages||bInstrumentTileDrain)&&!ForceGenerate;
Options.profilePassageComposer=bProfilePassageComposer;
Options.instrumentTileDrain=bInstrumentTileDrain&&!ForceGenerate;
Options.exactMidpointDensityMemo=bExactMidpointDensityMemo&&!ForceGenerate;
Options.activeLaneBatching=bActiveLaneBatching&&!ForceGenerate;
@@ -1100,6 +1103,34 @@ private:
static_cast<unsigned long long>(D.islandSharedCacheComputes),
static_cast<unsigned long long>(D.islandSharedCacheConflictReplacements),
static_cast<double>(D.islandSharedCacheLockWaitNanoseconds)/1000.0);
if(D.passageComposerProfiled)
std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu mouth_candidates=%llu queries=%llu passage_iterations=%llu upper_mouth_checks=%llu column_candidates=%llu column_distance_calls=%llu negative_bounds=%llu negative_rejects=%llu positive_bounds=%llu positive_rejects=%llu carve_segment_visits=%llu smooth_carve_joins=%llu support_segment_visits=%llu smooth_support_joins=%llu support_capsule_checks=%llu later_bore_checks=%llu other_capsule_checks=%llu mouth_support_calls=%llu mouth_route_segment_checks=%llu relief_field_calls=%llu smoothstep_evaluations=%llu\n",
Event.Key.Coord.X,Event.Key.Coord.Y,Event.Key.Coord.Z,Event.Key.Level,
Event.WorkerMilliseconds,static_cast<unsigned long long>(Event.DensitySamples),
static_cast<unsigned long long>(D.fieldCalls),
static_cast<unsigned long long>(D.passageTileFeatureCount),
static_cast<unsigned long long>(D.passageTileRouteSegmentCandidates),
static_cast<unsigned long long>(D.passageTileMouthSegmentCandidates),
static_cast<unsigned long long>(D.passageComposerQueries),
static_cast<unsigned long long>(D.passageIterations),
static_cast<unsigned long long>(D.passageUpperMouthFilterChecks),
static_cast<unsigned long long>(D.passageColumnCandidates),
static_cast<unsigned long long>(D.passageColumnDistanceCalls),
static_cast<unsigned long long>(D.passageNegativeBoundChecks),
static_cast<unsigned long long>(D.passageNegativeBoundRejects),
static_cast<unsigned long long>(D.passagePositiveBoundChecks),
static_cast<unsigned long long>(D.passagePositiveBoundRejects),
static_cast<unsigned long long>(D.passageCarveSegmentVisits),
static_cast<unsigned long long>(D.passageSmoothCarveJoins),
static_cast<unsigned long long>(D.passageSupportSegmentVisits),
static_cast<unsigned long long>(D.passageSmoothSupportJoins),
static_cast<unsigned long long>(D.passageSupportCapsuleChecks),
static_cast<unsigned long long>(D.passageLaterBoreChecks),
static_cast<unsigned long long>(D.passageOtherCapsuleChecks),
static_cast<unsigned long long>(D.passageMouthSupportCalls),
static_cast<unsigned long long>(D.passageMouthRouteSegmentChecks),
static_cast<unsigned long long>(D.passageReliefFieldCalls),
static_cast<unsigned long long>(D.passageSmoothstepEvaluations));
}
void RecordTimelineEvent(FStandaloneCpuTileTimelineEvent::EType Type,
const FVoxelTileKey& Key,int32 WorkerId,size_t QueueDepth,size_t ActiveWorkers,
@@ -1138,6 +1169,7 @@ private:
int32 Lod8HorizonInteriorStepVoxels=0;
bool bProfileMesherStages=false;
bool bInstrumentTileDrain=false;
bool bProfilePassageComposer=false;
bool bExactMidpointDensityMemo=false;
bool bActiveLaneBatching=false;
int32 ProofBlockCells=8;
+17 -1
View File
@@ -6,6 +6,7 @@ import argparse
import atexit
import hashlib
import json
import lzma
import math
import os
from pathlib import Path
@@ -22,7 +23,8 @@ import zlib
ROOT = Path(__file__).resolve().parents[3]
VERIFY_DIR = ROOT / "Standalone/Tools/verify"
BASELINES = VERIFY_DIR / "baselines"
BASELINE_SOURCE = VERIFY_DIR / "baselines"
BASELINES = BASELINE_SOURCE
LINUX37 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux37"
LINUX47 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux47"
LINUX53 = ROOT / "Standalone/Research/WorldAssemblerM3/Linux53"
@@ -54,11 +56,25 @@ ARGS = PARSER.parse_args()
if ARGS.sanitize and ARGS.tier != "full":
PARSER.error("--sanitize is available only with the full tier; use the sanitize tier on its own")
OUT = ARGS.out.resolve()
BASELINES = OUT / "baselines"
ROUND_NAME = OUT.name
os.environ["VOXELFORGE_VERIFY_OUT"] = str(OUT)
os.environ["PYTHONDONTWRITEBYTECODE"] = "1"
sys.dont_write_bytecode = True
def prepare_baselines() -> None:
"""Copy pinned inputs into the output tree and expand compressed mesh fixtures."""
shutil.copytree(BASELINE_SOURCE, BASELINES, dirs_exist_ok=True)
for compressed in sorted(BASELINES.rglob("*.vfmesh.xz")):
expanded = compressed.with_suffix("")
expanded.parent.mkdir(parents=True, exist_ok=True)
with lzma.open(compressed, "rb") as source, expanded.open("wb") as target:
shutil.copyfileobj(source, target, 1024 * 1024)
prepare_baselines()
sys.path.insert(0, str(VERIFY_DIR))
from owner_step import measure as measure_owner_step
from runner import VerificationFailure, VerificationRunner, bounded_run