streaming: near LODs first (walkable ring, LOD0, LOD1, LOD2, then far); exact passage trims (L78)

- Headless and Unreal schedulers drain the collision-critical ring, then LOD0-2, then far LODs
  at low priority. LOD0-2 ready (W8 medians): SW 4.36->1.76, FI 6.89->5.26, TN 4.88->3.22,
  VS 2.71->1.56 s. Whole view roughly unchanged (FI/VS slightly later).
  KNOWN RISK: far tiles wait until every near tile is ready, so far LODs may starve while
  moving fast (to address next).
- Exact composer trims: tile-level upper-mouth candidate list, segment-index min/max rejection
  before lower_bound, 64-entry thread-local value-noise corner cache. Passage share 65 -> 63%.
- World exact: 24/24 hash matrix + pinned L75 owner hash. 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-27 19:13:45 +01:00
1 parent 5e091d254c
commit ec20994a8e
10 files changed
+718 -52

No files matched your search

+16 -7
View File
@@ -581,6 +581,7 @@ public:
Workers.clear();
std::lock_guard<std::mutex> Lock(Mutex);
Ready.clear();Outstanding.clear();Desired.clear();Running.clear();
NearOutstandingJobs=0;
}
FStandaloneStreamingUpdate UpdateDesired(
@@ -680,6 +681,7 @@ public:
{
if(Desired.contains(Job.Key))return false;
Outstanding.erase(Job.Key);++Stats.CancelledQueuedJobs;
if(Job.Key.Level<=2&&NearOutstandingJobs>0)--NearOutstandingJobs;
++CancelledByCrossing[Job.RequestedCrossing];return true;
});
Queue.erase(QueueEnd,Queue.end());
@@ -774,15 +776,14 @@ private:
std::vector<FVoxelTileKey> Prioritized=NewDesired.Tiles;
if(IsCoarseFirstSchedulingEnabled())
{
// The local walkable ring leads, the coarse enclosure follows, then target-detail work.
// L'anneau praticable local passe d'abord, puis l'enveloppe grossiere, puis le detail cible.
const int32 FirstCoarseLevel=FMath::Max(2,World->FullResClipLevels);
// Finish the local walkable ring, then all near LODs, before admitting far work.
// Terminer l'anneau praticable, puis tous les LOD proches avant le champ lointain.
auto Tier=[&](const FVoxelTileKey& Key)
{
if(Key.Level==0&&std::abs(Key.Coord.X-NewDesired.CenterChunk.X)<=1
&&std::abs(Key.Coord.Y-NewDesired.CenterChunk.Y)<=1
&&std::abs(Key.Coord.Z-NewDesired.CenterChunk.Z)<=1)return 0;
return Key.Level>=FirstCoarseLevel?1:2;
return Key.Level<=2?1:2;
};
auto IsAhead=[&](const FVoxelTileKey& Key)
{
@@ -797,7 +798,8 @@ private:
{
const int32 TierA=Tier(A),TierB=Tier(B);
if(TierA!=TierB)return TierA<TierB;
if(TierA==1&&A.Level!=B.Level)return A.Level>B.Level;
if(TierA==1&&A.Level!=B.Level)return A.Level<B.Level;
if(TierA==2&&A.Level!=B.Level)return A.Level>B.Level;
const bool bAheadA=IsAhead(A),bAheadB=IsAhead(B);
if(bAheadA!=bAheadB)return bAheadA;
const double DA=StandaloneWorldMesher::TileDistanceSquaredChunks(A,NewDesired.CenterChunk);
@@ -844,6 +846,7 @@ private:
RecordTimelineEvent(FStandaloneCpuTileTimelineEvent::EType::Queued,Key,-1,
Queue.size(),Running.size(),Job.PriorityRank,Job.QueuedAt,Job.QueuedAt);
Outstanding.insert(Key);++Stats.NewJobs;
if(Key.Level<=2)++NearOutstandingJobs;
}
CurrentDesired=std::move(NewDesired);
std::make_heap(Queue.begin(),Queue.end(),FStandaloneTileJobHeapOrder{});
@@ -1025,10 +1028,13 @@ private:
size_t DispatchQueueDepth=0,DispatchActiveWorkers=0;
{
std::unique_lock<std::mutex> Lock(Mutex);
Wake.wait(Lock,[&](){return bStop||!PriorityTasks.empty()||!Queue.empty();});
Wake.wait(Lock,[&](){return bStop||!PriorityTasks.empty()
||(!Queue.empty()&&(NearOutstandingJobs==0||Queue.front().Key.Level<=2));});
if(bStop)return;
const bool bNearTileEligible=!Queue.empty()
&&(NearOutstandingJobs==0||Queue.front().Key.Level<=2);
const bool bPreferPriority=!PriorityTasks.empty()
&&(Queue.empty()||ConsecutivePriorityTasks<PriorityTaskBurst);
&&(!bNearTileEligible||ConsecutivePriorityTasks<PriorityTaskBurst);
if(bPreferPriority)
{
PriorityTask=std::move(PriorityTasks.front());PriorityTasks.pop_front();
@@ -1057,6 +1063,7 @@ private:
std::lock_guard<std::mutex> Lock(Mutex);
if(bStop)return;
Running.erase(Tile.Key);
if(Tile.Key.Level<=2&&NearOutstandingJobs>0)--NearOutstandingJobs;
if(bColdTimelineTrace)
RecordTimelineEvent(FStandaloneCpuTileTimelineEvent::EType::Finish,Tile.Key,
WorkerId,Queue.size(),Running.size(),Job.PriorityRank,Tile.CompletedAt,
@@ -1065,6 +1072,7 @@ private:
Tile.PayloadBuildMilliseconds);
Ready.push_back(std::move(Tile));
}
Wake.notify_all();
}
}
@@ -1208,6 +1216,7 @@ private:
mutable std::mutex Mutex;
std::condition_variable Wake;
bool bStop=true;
size_t NearOutstandingJobs=0;
std::vector<FStandaloneWorkerThread> Workers;
std::deque<std::function<void()>> PriorityTasks;
std::vector<FStandaloneTileJob> Queue;