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
@@ -86,6 +86,11 @@ namespace
|
||||
bool HasCameraStep=false;
|
||||
bool AutoSurfaceCamera=false;
|
||||
bool CaptureSkipWalkability=false;
|
||||
int StreamingSchedulerPolicy=-1;
|
||||
bool MovingCameraTrace=false;
|
||||
double MovingCameraSpeedMetersPerSecond=0.0;
|
||||
double MovingCameraDurationSeconds=12.0;
|
||||
double MovingCameraDwellSeconds=5.0;
|
||||
FVector CameraMeters=FVector::ZeroVector;
|
||||
FVector CameraStepMeters=FVector::ZeroVector;
|
||||
float CameraYawDegrees=0.0f;
|
||||
@@ -1409,6 +1414,8 @@ namespace
|
||||
std::printf("Usage: %s [owner_world.json] --world-assembler-prototype --stream-benchmark --stream-pipeline [options]\n"
|
||||
" --workers=N --clip-radius=N --max-clip-level=N --max-level=N\n"
|
||||
" --camera=X,Y,Z,YAW,PITCH (position in metres) --stream-hash\n"
|
||||
" --stream-scheduler-policy=0|1|2 (L77 coarse, L78 near, L79 fair share)\n"
|
||||
" --moving-camera-speed-mps=N [--moving-camera-duration-s=N] [--moving-camera-dwell-s=N]\n"
|
||||
" --stream-hash-tiles (print per-tile hashes; implies --stream-hash)\n"
|
||||
" --stream-hash-tiles-allow-skips (mesh/topology falsifier with proven uniform skips)\n"
|
||||
" --camera-step=X,Y,Z (optional second view step in metres)\n"
|
||||
@@ -1590,6 +1597,37 @@ namespace
|
||||
{std::fprintf(stderr,"Invalid --camera-step value: %.*s\n",static_cast<int>(arg.size()),arg.data());return false;}
|
||||
options.HasCameraStep=true;
|
||||
}
|
||||
else if(arg.starts_with("--stream-scheduler-policy="))
|
||||
{
|
||||
if(!readInt("--stream-scheduler-policy=",options.StreamingSchedulerPolicy)
|
||||
||options.StreamingSchedulerPolicy<0||options.StreamingSchedulerPolicy>2)
|
||||
{std::fprintf(stderr,"Invalid --stream-scheduler-policy (expected 0..2).\n");return false;}
|
||||
}
|
||||
else if(arg.starts_with("--moving-camera-speed-mps="))
|
||||
{
|
||||
const std::string value(arg.substr(std::string_view("--moving-camera-speed-mps=").size()));
|
||||
char* end=nullptr;options.MovingCameraSpeedMetersPerSecond=std::strtod(value.c_str(),&end);
|
||||
if(end==value.c_str()||*end!='\0'||!std::isfinite(options.MovingCameraSpeedMetersPerSecond)
|
||||
||options.MovingCameraSpeedMetersPerSecond<=0.0)
|
||||
{std::fprintf(stderr,"Invalid --moving-camera-speed-mps (expected positive finite value).\n");return false;}
|
||||
options.MovingCameraTrace=true;
|
||||
}
|
||||
else if(arg.starts_with("--moving-camera-duration-s="))
|
||||
{
|
||||
const std::string value(arg.substr(std::string_view("--moving-camera-duration-s=").size()));
|
||||
char* end=nullptr;options.MovingCameraDurationSeconds=std::strtod(value.c_str(),&end);
|
||||
if(end==value.c_str()||*end!='\0'||!std::isfinite(options.MovingCameraDurationSeconds)
|
||||
||options.MovingCameraDurationSeconds<=0.0)
|
||||
{std::fprintf(stderr,"Invalid --moving-camera-duration-s (expected positive finite value).\n");return false;}
|
||||
}
|
||||
else if(arg.starts_with("--moving-camera-dwell-s="))
|
||||
{
|
||||
const std::string value(arg.substr(std::string_view("--moving-camera-dwell-s=").size()));
|
||||
char* end=nullptr;options.MovingCameraDwellSeconds=std::strtod(value.c_str(),&end);
|
||||
if(end==value.c_str()||*end!='\0'||!std::isfinite(options.MovingCameraDwellSeconds)
|
||||
||options.MovingCameraDwellSeconds<0.0)
|
||||
{std::fprintf(stderr,"Invalid --moving-camera-dwell-s (expected nonnegative finite value).\n");return false;}
|
||||
}
|
||||
else if(arg.starts_with("--column-cache="))
|
||||
{
|
||||
const std::string_view mode=arg.substr(std::string_view("--column-cache=").size());
|
||||
@@ -1635,6 +1673,10 @@ namespace
|
||||
{std::fprintf(stderr,"--tls-probe-touch requires --tls-probe=N\n");return false;}
|
||||
if(options.RegionCrossing&&!options.HasCameraStep)
|
||||
{std::fprintf(stderr,"--region-crossing requires --camera-step=X,Y,Z\n");return false;}
|
||||
if(options.MovingCameraTrace&&(!options.StreamPipeline||!options.WorldAssemblerPrototype))
|
||||
{std::fprintf(stderr,"--moving-camera-speed-mps requires --world-assembler-prototype --stream-pipeline\n");return false;}
|
||||
if(options.MovingCameraTrace&&options.StreamingSchedulerPolicy<0)
|
||||
{std::fprintf(stderr,"--moving-camera-speed-mps requires --stream-scheduler-policy=0|1|2\n");return false;}
|
||||
if(options.LandmarkL45RampControl&&!options.LandmarkChamberDemo)
|
||||
{std::fprintf(stderr,"--landmark-l45-ramp-control requires --landmark-chamber-demo\n");return false;}
|
||||
if(options.AuditOreVeinYield&&!options.OreVeinsDemo)
|
||||
@@ -2228,5 +2270,8 @@ int main(int argc,char** argv)
|
||||
?options.ParallelSignEdgeRepair:options.FloatingIslandsRecipe,
|
||||
options.AuditNativeLattice,options.LatticeOrphanControl,
|
||||
options.CaptureSkipWalkability,options.ProfilePassageComposer,
|
||||
options.StreamHashAllowUniformSkips,options.Linux77Profile);
|
||||
options.StreamHashAllowUniformSkips,options.Linux77Profile,
|
||||
options.StreamingSchedulerPolicy,options.MovingCameraTrace,
|
||||
options.MovingCameraSpeedMetersPerSecond,options.MovingCameraDurationSeconds,
|
||||
options.MovingCameraDwellSeconds);
|
||||
}
|
||||
@@ -1874,7 +1874,9 @@ namespace StandaloneStreamBenchmark
|
||||
bool bParallelSignEdgeRepair=false,bool bAuditNativeLattice=false,
|
||||
bool bLatticeOrphanControl=false,bool bCaptureSkipWalkability=false,
|
||||
bool bProfilePassageComposer=false,bool bAllowUniformSkipsWhenHashing=false,
|
||||
bool bLinux77Profile=false)
|
||||
bool bLinux77Profile=false,int32 SchedulerPolicy=-1,
|
||||
bool bMovingCameraTrace=false,double MovingCameraSpeedMetersPerSecond=0.0,
|
||||
double MovingCameraDurationSeconds=12.0,double MovingCameraDwellSeconds=5.0)
|
||||
{
|
||||
using Clock=std::chrono::steady_clock;
|
||||
FStandaloneOwnerWorld& World=*OwnerWorld;
|
||||
@@ -2038,6 +2040,7 @@ namespace StandaloneStreamBenchmark
|
||||
bSkipUvAndColors,bSkipMaterialGroups,bSkipUV,bSkipColors,&Shape,bProfileColumnOverlap,
|
||||
FarHorizonLOD8InteriorStepVoxels,bUseSharedColumnCache,
|
||||
bAllowUniformSkipsWhenHashing);
|
||||
Streamer.SetSchedulerPolicy(SchedulerPolicy);
|
||||
Streamer.SetUniformBlockProofAuditEnabled(bAuditUniformBlockProofs);
|
||||
Streamer.SetTileDrainInstrumentationEnabled(bInstrumentTileDrain);
|
||||
Streamer.SetLinux77ProfileEnabled(bLinux77Profile);
|
||||
@@ -4975,6 +4978,152 @@ namespace StandaloneStreamBenchmark
|
||||
std::fprintf(stderr,"[StreamPipeline] expected %zu tiles after shape publication but queued %d.\n",
|
||||
Desired.Tiles.size(),Update.DesiredTiles);return 7;
|
||||
}
|
||||
if(bMovingCameraTrace)
|
||||
{
|
||||
constexpr double SamplePeriodSeconds=0.25;
|
||||
using FTileSet=std::unordered_set<FVoxelTileKey,FStandaloneTileKeyHash>;
|
||||
FTileSet Resident;
|
||||
std::unordered_map<FVoxelTileKey,Clock::time_point,FStandaloneTileKeyHash> FarMissingSince;
|
||||
const double VoxelMetres=static_cast<double>(World.CoreVoxelSizeMicrons)/1000000.0;
|
||||
const auto TotalSeconds=MovingCameraDurationSeconds+MovingCameraDwellSeconds;
|
||||
const auto TraceStart=Clock::now();
|
||||
int32 SampleIndex=0;
|
||||
int32 GenerationFailures=0;
|
||||
double FirstAllFarReadySeconds=-1.0;
|
||||
int32 Samples=0;
|
||||
std::printf("[L79MovingCheckpoint] stage=start desired=%zu policy=%d speed_mps=%.3f\n",
|
||||
Desired.Tiles.size(),SchedulerPolicy,MovingCameraSpeedMetersPerSecond);
|
||||
std::fflush(stdout);
|
||||
auto DrainReady=[&]()
|
||||
{
|
||||
std::vector<FStandaloneCpuTile> Ready=Streamer.TakeReady();
|
||||
for(const FStandaloneCpuTile& Tile:Ready)
|
||||
{
|
||||
if(Tile.bGenerationFailed)++GenerationFailures;
|
||||
else Resident.insert(Tile.Key);
|
||||
}
|
||||
};
|
||||
for(;;++SampleIndex)
|
||||
{
|
||||
const double ScheduledSeconds=std::min(TotalSeconds,
|
||||
static_cast<double>(SampleIndex)*SamplePeriodSeconds);
|
||||
std::this_thread::sleep_until(TraceStart+std::chrono::duration<double>(ScheduledSeconds));
|
||||
const auto SampleAt=Clock::now();
|
||||
const double ElapsedSeconds=std::min(TotalSeconds,
|
||||
std::chrono::duration<double>(SampleAt-TraceStart).count());
|
||||
const double MovingSeconds=std::min(MovingCameraDurationSeconds,ElapsedSeconds);
|
||||
FVector Camera=CameraPositionVoxels;
|
||||
Camera.X+=static_cast<float>(MovingCameraSpeedMetersPerSecond*MovingSeconds/VoxelMetres);
|
||||
DrainReady();
|
||||
if(SampleIndex==0)
|
||||
{
|
||||
std::printf("[L79MovingCheckpoint] stage=drained resident=%zu failures=%d\n",
|
||||
Resident.size(),GenerationFailures);
|
||||
std::fflush(stdout);
|
||||
}
|
||||
FStandaloneDesiredTileSet CurrentDesired=Desired;
|
||||
CurrentDesired.CenterChunk=FIntVector(
|
||||
static_cast<int32>(std::floor(Camera.X/CHUNK_SIZE)),
|
||||
static_cast<int32>(std::floor(Camera.Y/CHUNK_SIZE)),
|
||||
static_cast<int32>(std::floor(Camera.Z/CHUNK_SIZE)));
|
||||
const auto CoreDesired=Shape.desiredTiles({Camera.X,Camera.Y,Camera.Z});
|
||||
CurrentDesired.Tiles.clear();CurrentDesired.Tiles.reserve(CoreDesired.size());
|
||||
for(const auto& Key:CoreDesired)
|
||||
{
|
||||
if(MaxLevel>=0&&Key.lod>MaxLevel)continue;
|
||||
CurrentDesired.Tiles.emplace_back(
|
||||
FIntVector(Key.coordinate.x,Key.coordinate.y,Key.coordinate.z),Key.lod);
|
||||
}
|
||||
const auto BeforeUpdate=Clock::now();
|
||||
const std::vector<FVoxelTileKey> ResidentKeys(Resident.begin(),Resident.end());
|
||||
const FStandaloneStreamingUpdate MovingUpdate=Streamer.UpdateDesiredWithSet(
|
||||
CurrentDesired,ResidentKeys,static_cast<uint64>(SampleIndex),Camera);
|
||||
if(SampleIndex==0)
|
||||
{
|
||||
std::printf("[L79MovingCheckpoint] stage=updated desired=%d new_jobs=%d\n",
|
||||
MovingUpdate.DesiredTiles,MovingUpdate.NewJobs);
|
||||
std::fflush(stdout);
|
||||
}
|
||||
const double UpdateMilliseconds=std::chrono::duration<double,std::milli>(
|
||||
Clock::now()-BeforeUpdate).count();
|
||||
if(MovingUpdate.DesiredTiles!=static_cast<int32>(CurrentDesired.Tiles.size()))
|
||||
{
|
||||
Streamer.Stop();
|
||||
std::fprintf(stderr,"[MovingCameraTrace] desired-set mismatch expected=%zu actual=%d\n",
|
||||
CurrentDesired.Tiles.size(),MovingUpdate.DesiredTiles);
|
||||
return 9;
|
||||
}
|
||||
std::size_t NearDesired=0,NearResident=0,FarDesired=0,FarResident=0,FarCovered=0;
|
||||
double FarStaleAgeSum=0.0,FarStaleAgeMax=0.0;
|
||||
const auto FloorDiv=[](int32 Value,int32 Divisor)
|
||||
{
|
||||
const int32 Quotient=Value/Divisor, Remainder=Value%Divisor;
|
||||
return Quotient-((Remainder!=0&&Remainder<0)?1:0);
|
||||
};
|
||||
std::unordered_map<FVoxelTileKey,Clock::time_point,FStandaloneTileKeyHash> CurrentFarMissing;
|
||||
for(const FVoxelTileKey& Key:CurrentDesired.Tiles)
|
||||
{
|
||||
const bool bResident=Resident.contains(Key);
|
||||
if(Key.Level<=2)
|
||||
{
|
||||
++NearDesired;
|
||||
NearResident+=bResident?1u:0u;
|
||||
}
|
||||
else
|
||||
{
|
||||
++FarDesired;
|
||||
FarResident+=bResident?1u:0u;
|
||||
bool bFarCovered=bResident;
|
||||
for(int32 ParentLOD=Key.Level+1;
|
||||
!bFarCovered&&ParentLOD<=World.MaxClipLevel;++ParentLOD)
|
||||
{
|
||||
const int32 Scale=1<<(ParentLOD-Key.Level);
|
||||
const FVoxelTileKey Parent(FIntVector(
|
||||
FloorDiv(Key.Coord.X,Scale),FloorDiv(Key.Coord.Y,Scale),
|
||||
FloorDiv(Key.Coord.Z,Scale)),ParentLOD);
|
||||
bFarCovered=Resident.contains(Parent);
|
||||
}
|
||||
FarCovered+=bFarCovered?1u:0u;
|
||||
if(!bResident)
|
||||
{
|
||||
auto [It,bInserted]=FarMissingSince.try_emplace(Key,SampleAt);
|
||||
(void)bInserted;
|
||||
const double Age=std::chrono::duration<double>(SampleAt-It->second).count();
|
||||
FarStaleAgeSum+=Age;
|
||||
FarStaleAgeMax=std::max(FarStaleAgeMax,Age);
|
||||
CurrentFarMissing.emplace(Key,It->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
FarMissingSince.swap(CurrentFarMissing);
|
||||
const double NearReadyPercent=100.0*static_cast<double>(NearResident)
|
||||
/static_cast<double>(std::max<std::size_t>(1,NearDesired));
|
||||
const double FarMissingPercent=100.0*static_cast<double>(FarDesired-FarResident)
|
||||
/static_cast<double>(std::max<std::size_t>(1,FarDesired));
|
||||
const double FarHolePercent=100.0*static_cast<double>(FarDesired-FarCovered)
|
||||
/static_cast<double>(std::max<std::size_t>(1,FarDesired));
|
||||
const double FarStaleAgeMean=FarDesired>FarResident
|
||||
?FarStaleAgeSum/static_cast<double>(FarDesired-FarResident):0.0;
|
||||
if(FarDesired>0&&FarDesired==FarResident&&FirstAllFarReadySeconds<0.0)
|
||||
FirstAllFarReadySeconds=ElapsedSeconds;
|
||||
const char* Phase=ElapsedSeconds<MovingCameraDurationSeconds?"move":"dwell";
|
||||
std::printf("[L79MovingSample] policy=%d speed_mps=%.3f t_s=%.3f phase=%s x_m=%.3f near=%zu/%zu near_ready_pct=%.3f far=%zu/%zu far_missing_pct=%.3f far_covered=%zu/%zu far_hole_pct=%.3f far_stale_mean_s=%.3f far_stale_max_s=%.3f queued_jobs=%d queue_update_ms=%.3f generation_failures=%d\n",
|
||||
SchedulerPolicy,MovingCameraSpeedMetersPerSecond,ElapsedSeconds,Phase,
|
||||
Camera.X*VoxelMetres,NearResident,NearDesired,NearReadyPercent,
|
||||
FarResident,FarDesired,FarMissingPercent,FarCovered,FarDesired,
|
||||
FarHolePercent,FarStaleAgeMean,FarStaleAgeMax,
|
||||
MovingUpdate.NewJobs,UpdateMilliseconds,GenerationFailures);
|
||||
std::fflush(stdout);
|
||||
++Samples;
|
||||
if(ElapsedSeconds>=TotalSeconds)break;
|
||||
}
|
||||
std::printf("[L79MovingSummary] policy=%d speed_mps=%.3f move_s=%.3f dwell_s=%.3f samples=%d resident_tiles=%zu first_all_far_ready_s=%.3f generation_failures=%d priority=background_workers_only status=%s\n",
|
||||
SchedulerPolicy,MovingCameraSpeedMetersPerSecond,MovingCameraDurationSeconds,
|
||||
MovingCameraDwellSeconds,Samples,Resident.size(),FirstAllFarReadySeconds,
|
||||
GenerationFailures,GenerationFailures==0?"PASS":"FAIL");
|
||||
Streamer.Stop();
|
||||
return GenerationFailures==0?0:9;
|
||||
}
|
||||
FSceneExportWriter SceneExport;
|
||||
const bool bExportRequested=!MeshExportPath.empty();
|
||||
bool bSceneExportPassing=true;
|
||||
|
||||
@@ -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