streaming: far LODs keep a share while near work is pending (L79); no more horizon starvation
L78's strict near-first order starved far LODs at 30 m/s (100% far holes, never completed). Unreal policy 2: once the collision ring is ready, LOD0-2 keep their reserve and far tiles are admitted as low-priority Horizon work; headless gives far work 1 of every 16 requests. Moving camera, far holes while moving: 1.4 m/s L77 8% / L78 29% / L79 31%; 30 m/s L77 8% / L78 100% / L79 72% (completes on dwell). Near readiness while moving at 30 m/s: 52 / 51 / 67%. Still worse than L77 for fast travel -> speed-adaptive policy next. World unchanged (v213). 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
ec20994a8e
commit
2c8a26c0d0
11 files changed
+833
-30
No files matched your search
@@ -551,6 +551,9 @@ public:
|
||||
bUseTileFilter=true;
|
||||
}
|
||||
|
||||
void SetSchedulerPolicy(int32 Policy)
|
||||
{SchedulerPolicy=std::clamp(Policy,-1,2);}
|
||||
|
||||
bool QueuePriorityTasks(std::vector<std::function<void()>> Tasks)
|
||||
{
|
||||
if(Tasks.empty())return true;
|
||||
@@ -623,6 +626,29 @@ public:
|
||||
return UpdateDesiredSet(std::move(NewDesired),ResidentKeys,CrossingIndex);
|
||||
}
|
||||
|
||||
FStandaloneStreamingUpdate UpdateDesiredWithSet(
|
||||
FStandaloneDesiredTileSet NewDesired,const std::vector<FVoxelTileKey>& ResidentKeys,
|
||||
uint64 CrossingIndex,const FVector& CameraPositionVoxels)
|
||||
{
|
||||
if(bHasLastCameraPosition)
|
||||
{
|
||||
const FVector Delta=CameraPositionVoxels-LastCameraPositionVoxels;
|
||||
const double LengthSquared=static_cast<double>(Delta.X)*Delta.X
|
||||
+static_cast<double>(Delta.Y)*Delta.Y;
|
||||
if(LengthSquared>1.0e-12)
|
||||
{
|
||||
const double InverseLength=1.0/std::sqrt(LengthSquared);
|
||||
TravelDirection=FVector(static_cast<float>(Delta.X*InverseLength),
|
||||
static_cast<float>(Delta.Y*InverseLength),0.0f);
|
||||
}
|
||||
else TravelDirection=FVector::ZeroVector;
|
||||
}
|
||||
else TravelDirection=FVector::ZeroVector;
|
||||
LastCameraPositionVoxels=CameraPositionVoxels;
|
||||
bHasLastCameraPosition=true;
|
||||
return UpdateDesiredSet(std::move(NewDesired),ResidentKeys,CrossingIndex);
|
||||
}
|
||||
|
||||
std::vector<FStandaloneCpuTile> TakeReady()
|
||||
{
|
||||
std::vector<FStandaloneCpuTile> Out;
|
||||
@@ -774,15 +800,18 @@ private:
|
||||
for(const auto& Pair:CancelledByCrossing)Stats.CancelledByCrossing.push_back(Pair);
|
||||
|
||||
std::vector<FVoxelTileKey> Prioritized=NewDesired.Tiles;
|
||||
if(IsCoarseFirstSchedulingEnabled())
|
||||
const int32 ActiveSchedulerPolicy=SchedulerPolicy<0
|
||||
?(IsCoarseFirstSchedulingEnabled()?2:3):SchedulerPolicy;
|
||||
if(ActiveSchedulerPolicy<=2)
|
||||
{
|
||||
// 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.
|
||||
// Policy 0 retains L77 coarse-first ordering after the local support ring.
|
||||
// Policies 1 and 2 prioritize all near LODs before horizon work.
|
||||
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;
|
||||
if(ActiveSchedulerPolicy==0)return Key.Level>=3?1:2;
|
||||
return Key.Level<=2?1:2;
|
||||
};
|
||||
auto IsAhead=[&](const FVoxelTileKey& Key)
|
||||
@@ -798,8 +827,10 @@ 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==2&&A.Level!=B.Level)return A.Level>B.Level;
|
||||
if(TierA==1&&A.Level!=B.Level)
|
||||
return ActiveSchedulerPolicy==0?A.Level>B.Level:A.Level<B.Level;
|
||||
if(TierA==2&&A.Level!=B.Level)
|
||||
return ActiveSchedulerPolicy==0?A.Level<B.Level: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);
|
||||
@@ -810,6 +841,29 @@ private:
|
||||
if(A.Coord.Y!=B.Coord.Y)return A.Coord.Y<B.Coord.Y;
|
||||
return A.Coord.X<B.Coord.X;
|
||||
});
|
||||
|
||||
if(ActiveSchedulerPolicy==2)
|
||||
{
|
||||
// Give far LODs one queued slot per sixteen near requests. The near
|
||||
// prefix is the arrival burst; the recurring slot bounds horizon age.
|
||||
std::vector<FVoxelTileKey> NearTiles,FarTiles,FairOrder;
|
||||
NearTiles.reserve(Prioritized.size());
|
||||
FarTiles.reserve(Prioritized.size());
|
||||
FairOrder.reserve(Prioritized.size());
|
||||
for(const FVoxelTileKey& Key:Prioritized)
|
||||
(Key.Level<=2?NearTiles:FarTiles).push_back(Key);
|
||||
constexpr size_t NearBurstAndShareStride=16;
|
||||
size_t NearIndex=0,FarIndex=0;
|
||||
while(NearIndex<NearTiles.size())
|
||||
{
|
||||
const size_t NearEnd=std::min(NearTiles.size(),NearIndex+NearBurstAndShareStride);
|
||||
FairOrder.insert(FairOrder.end(),NearTiles.begin()+NearIndex,NearTiles.begin()+NearEnd);
|
||||
NearIndex=NearEnd;
|
||||
if(FarIndex<FarTiles.size())FairOrder.push_back(FarTiles[FarIndex++]);
|
||||
}
|
||||
FairOrder.insert(FairOrder.end(),FarTiles.begin()+FarIndex,FarTiles.end());
|
||||
Prioritized.swap(FairOrder);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1028,13 +1082,16 @@ private:
|
||||
size_t DispatchQueueDepth=0,DispatchActiveWorkers=0;
|
||||
{
|
||||
std::unique_lock<std::mutex> Lock(Mutex);
|
||||
Wake.wait(Lock,[&](){return bStop||!PriorityTasks.empty()
|
||||
||(!Queue.empty()&&(NearOutstandingJobs==0||Queue.front().Key.Level<=2));});
|
||||
const auto HasEligibleTile=[&]()
|
||||
{
|
||||
return !Queue.empty()&&(SchedulerPolicy!=1||NearOutstandingJobs==0
|
||||
||Queue.front().Key.Level<=2);
|
||||
};
|
||||
Wake.wait(Lock,[&](){return bStop||!PriorityTasks.empty()||HasEligibleTile();});
|
||||
if(bStop)return;
|
||||
const bool bNearTileEligible=!Queue.empty()
|
||||
&&(NearOutstandingJobs==0||Queue.front().Key.Level<=2);
|
||||
const bool bTileEligible=HasEligibleTile();
|
||||
const bool bPreferPriority=!PriorityTasks.empty()
|
||||
&&(!bNearTileEligible||ConsecutivePriorityTasks<PriorityTaskBurst);
|
||||
&&(!bTileEligible||ConsecutivePriorityTasks<PriorityTaskBurst);
|
||||
if(bPreferPriority)
|
||||
{
|
||||
PriorityTask=std::move(PriorityTasks.front());PriorityTasks.pop_front();
|
||||
@@ -1192,6 +1249,7 @@ private:
|
||||
FVector TravelDirection=FVector::ZeroVector;
|
||||
bool bHasLastCameraPosition=false;
|
||||
int32 WorkerCount=8;
|
||||
int32 SchedulerPolicy=-1;
|
||||
bool bHashDensity=false;
|
||||
const FStandaloneMeshCache* MeshCache=nullptr;
|
||||
int32 MaxLevelFilter=-1;
|
||||
|
||||
Reference in new issue
Block a user