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

+67 -39
View File
@@ -206,7 +206,7 @@ namespace
FAutoConsoleVariableRef CVarVoxelForgeStreamingCoarseFirst(
TEXT("voxel.StreamingCoarseFirst"),
GVoxelForgeStreamingCoarseFirst,
TEXT("Prioritize current walkable tiles, then far coarse clipmap levels, then near refinement; 0 restores legacy LOD order."));
TEXT("Prioritize walkable tiles, then finish LOD0-2 before far clipmap work; controls far-level order."));
int32 GVoxelForgeStreamingDynamicNearReserve = 1;
FAutoConsoleVariableRef CVarVoxelForgeStreamingDynamicNearReserve(
@@ -11631,7 +11631,8 @@ void AVoxelWorld::EnqueueStreamingResult(FChunkResult&& Result)
{
EditedProcessQueue.Enqueue(MoveTemp(Result));
}
else if (Result.WorkPriority == EVoxelTileWorkPriority::LOD0)
else if (Result.WorkPriority == EVoxelTileWorkPriority::LOD0
|| Result.Tile.Level <= 2)
{
NearProcessQueue.Enqueue(MoveTemp(Result));
}
@@ -11947,8 +11948,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
const int32 NearTaskReserve = EffectiveNearTaskReserve;
const int32 NearAdmissionCap = bPawnMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearTaskReserve) + ReadyQueueDepth;
const int32 FirstCoarseLevel = FMath::Max(
2, Settings ? Settings->FullResClipLevels : 2);
constexpr int32 FirstFarLevel = 3;
const bool bUseCoarseFirstOrder = GVoxelForgeStreamingCoarseFirst != 0
&& bWalkableRingReadyForReserve;
int32 SchedulerSubmittedByLevel[9] = {};
@@ -12425,43 +12425,65 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
}
};
// Coarse-first gives the far shell the first non-critical admissions. Keep the current
// collision-ready 3x3 ring above it, then spend the remaining slots on full-resolution
// refinement. The opt-out reproduces the S4 LOD0-to-LOD8 submission order for a control.
// Le shell lointain passe apres l'anneau de collision, puis le raffinement fin. L'option
// inverse restaure l'ordre LOD0-vers-LOD8 de S4 comme controle negatif.
// Keep the walkable ring on the legacy near-first path; only spend its reserved task slots
// on coarse work after all nine collision gates are ready.
// Garder l'anneau praticable en priorite ; les taches grossieres commencent apres ses neuf collisions.
if (bUseCoarseFirstOrder)
const auto AreCriticalTilesReady = [this]()
{
for (int32 Level = MaxDesiredLevel; Level >= FirstCoarseLevel; --Level)
for (const FVoxelTileKey& Tile : CriticalDesiredTiles)
{
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
CoarseTaskCap, true);
if (!LoadedTiles.Contains(Tile) && !CollisionNotRequiredTiles.Contains(Tile))
{
return false;
}
}
for (int32 Level = 0; Level < FirstCoarseLevel && Level <= MaxDesiredLevel; ++Level)
return true;
};
const auto AreNearLODTilesReady = [this]()
{
for (const FVoxelTileKey& Tile : DesiredSorted)
{
if (Tile.Level <= 2 && !LoadedTiles.Contains(Tile)
&& !CollisionNotRequiredTiles.Contains(Tile))
{
return false;
}
}
return true;
};
// The support and collision-critical set drains first. Then LOD0, LOD1, and LOD2
// use the near lane. Far tiles are not admitted until every requested near tile is ready.
if (AreCriticalTilesReady() && bWalkableRingReadyForReserve)
{
for (int32 Level = 0; Level <= 2 && Level <= MaxDesiredLevel; ++Level)
{
const EVoxelTileWorkPriority Priority = Level == 0
? EVoxelTileWorkPriority::LOD0 : EVoxelTileWorkPriority::Horizon;
const int32 LevelAdmissionCap = Priority == EVoxelTileWorkPriority::Horizon
? CoarseTaskCap : NearAdmissionCap;
SubmitLevel(Level, Priority, LevelAdmissionCap, true);
SubmitLevel(Level, Priority, NearAdmissionCap, true);
}
}
else
if (AreNearLODTilesReady())
{
SubmitLevel(0, EVoxelTileWorkPriority::LOD0, NearAdmissionCap, false);
for (int32 Level = 1; Level <= MaxDesiredLevel; ++Level)
if (bUseCoarseFirstOrder)
{
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
CoarseTaskCap, false);
if (GetGenerationAdmissionCount() >= CoarseTaskCap)
for (int32 Level = MaxDesiredLevel; Level >= FirstFarLevel; --Level)
{
if (Level >= 0 && Level < 9) { ++SchedulerLevelCapBreaks[Level]; }
SchedulerOrderStopLevel = Level;
SchedulerOrderStopCap = CoarseTaskCap;
break;
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
CoarseTaskCap, true);
}
}
else
{
for (int32 Level = FirstFarLevel; Level <= MaxDesiredLevel; ++Level)
{
SubmitLevel(Level, EVoxelTileWorkPriority::Horizon,
CoarseTaskCap, false);
if (GetGenerationAdmissionCount() >= CoarseTaskCap)
{
if (Level >= 0 && Level < 9) { ++SchedulerLevelCapBreaks[Level]; }
SchedulerOrderStopLevel = Level;
SchedulerOrderStopCap = CoarseTaskCap;
break;
}
}
}
}
@@ -12621,9 +12643,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
> ResultBacklogCapStopsAtUpdateEntry;
for (int32 Level = 0; Level < 9; ++Level)
{
AdmissionCapByLevel[Level] = bUseCoarseFirstOrder
? (Level >= FirstCoarseLevel || Level > 0 ? CoarseTaskCap : NearAdmissionCap)
: (Level == 0 ? NearAdmissionCap : CoarseTaskCap);
AdmissionCapByLevel[Level] = Level <= 2 ? NearAdmissionCap : CoarseTaskCap;
if (DesiredMissingByLevel[Level] <= 0) continue;
if (bAllChunksLoaded)
@@ -12711,7 +12731,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
"\"max_tasks\":%d,\"ready_queue_depth\":%d,"
"\"total_admission_cap\":%d,\"near_admission_cap\":%d,"
"\"near_reserve\":%d,"
"\"coarse_cap\":%d,\"first_coarse_level\":%d,"
"\"coarse_cap\":%d,\"first_far_level\":%d,"
"\"submission_stop_level\":%d,\"submission_stop_cap\":%d,"
"\"pending_entry\":%d,\"pending_after\":%d,\"admission_occupancy\":%d,"
"\"active_task_guard\":%d,\"running_workers\":%d,\"pending_results_estimate\":%d,"
@@ -12734,7 +12754,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
GVoxelForgeStreamingCoarseFirst, GVoxelForgeStreamingDynamicNearReserve,
GVoxelForgeStreamingLegacyPendingResultCap,
GVoxelForgeCoreRegionConcurrentAdmission, MaxTasks, ReadyQueueDepth,
TotalAdmissionCap, NearAdmissionCap, NearTaskReserve, CoarseTaskCap, FirstCoarseLevel,
TotalAdmissionCap, NearAdmissionCap, NearTaskReserve, CoarseTaskCap, FirstFarLevel,
SchedulerOrderStopLevel, SchedulerOrderStopCap,
PendingTilesAtUpdateEntry, PendingTiles.Num(), AdmissionOccupancy, ActiveTaskGuard,
ActiveGenerationWorkerCount.load(std::memory_order_relaxed), PendingResultsEstimate,
@@ -12789,15 +12809,19 @@ void AVoxelWorld::LoadTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority Wor
const int32 ReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon
|| Tile.Level <= 2;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
? FMath::Clamp(EffectiveNearTaskReserve, 0, FMath::Max(0, MaxTasks - 1))
: GetNearTaskReserve(MaxTasks);
const int32 NearAdmissionCap = bStreamingPlayerMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 AdmissionCap = WorkPriority == EVoxelTileWorkPriority::Horizon
&& Tile.Level > 2
? CoarseTaskCap
: (WorkPriority == EVoxelTileWorkPriority::LOD0 ? NearAdmissionCap : TotalAdmissionCap);
: ((WorkPriority == EVoxelTileWorkPriority::LOD0
|| (WorkPriority == EVoxelTileWorkPriority::Horizon && Tile.Level <= 2))
? NearAdmissionCap : TotalAdmissionCap);
if (GetGenerationAdmissionCount() >= AdmissionCap)
{
if (GVoxelForgeProfileTileGeneration != 0
@@ -13132,15 +13156,19 @@ void AVoxelWorld::LoadCoreTile(const FVoxelTileKey& Tile, EVoxelTileWorkPriority
const int32 ReadyQueueDepth = FMath::Clamp(
GVoxelForgeStreamingReadyQueueDepth, 0, FMath::Min(64, FMath::Max(1, MaxTasks) * 4));
const int32 TotalAdmissionCap = MaxTasks + ReadyQueueDepth;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon;
const bool bNearPriority = WorkPriority != EVoxelTileWorkPriority::Horizon
|| Tile.Level <= 2;
const int32 NearReserve = EffectiveNearTaskReserve >= 0
? FMath::Clamp(EffectiveNearTaskReserve, 0, FMath::Max(0, MaxTasks - 1))
: GetNearTaskReserve(MaxTasks);
const int32 NearAdmissionCap = bStreamingPlayerMoving ? MaxTasks : TotalAdmissionCap;
const int32 CoarseTaskCap = FMath::Max(1, MaxTasks - NearReserve) + ReadyQueueDepth;
const int32 AdmissionCap = WorkPriority == EVoxelTileWorkPriority::Horizon
&& Tile.Level > 2
? CoarseTaskCap
: (WorkPriority == EVoxelTileWorkPriority::LOD0 ? NearAdmissionCap : TotalAdmissionCap);
: ((WorkPriority == EVoxelTileWorkPriority::LOD0
|| (WorkPriority == EVoxelTileWorkPriority::Horizon && Tile.Level <= 2))
? NearAdmissionCap : TotalAdmissionCap);
if (GetGenerationAdmissionCount() >= AdmissionCap) return;
PendingTiles.Add(Tile);