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:
1 parent
5e091d254c
commit
ec20994a8e
10 files changed
+718
-52
No files matched your search
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user