streaming: early-admission + apply-cap experiment controls, off by default; forward-cone metric (L157)

30 m/s UE, 5 pairs: near coverage 36.1 -> 48.6% but 2/5 runs had p99 15.8/18.2 ms (worst 19.9 ms), so controls stay
off. Measured: only ~23% of desired LOD0-2 tiles lie in the 55 deg forward cone; forward readiness is 12.1% (base) /
16.9%, vs 50.9/68.5% behind. Slow frames are dominated by desired-set rebuild/UpdateChunks, not apply. Source/:
VoxelWorld.cpp (default behaviour unchanged).

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-11-02 03:21:19 +01:00
1 parent eb47d72258
commit 323fbe3736
3 files changed
+541 -5

No files matched your search

+103 -5
View File
@@ -262,6 +262,12 @@ namespace
GVoxelForgeCoreRegionConcurrentAdmission,
TEXT("Allow tiles independent of a pending Core region compile to proceed; 0 restores the global streaming stop."));
int32 GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles = 1;
FAutoConsoleVariableRef CVarVoxelForgeStreamingFastTravelWaitForAllCriticalTiles(
TEXT("voxel.StreamingFastTravelWaitForAllCriticalTiles"),
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles,
TEXT("Wait for the expanded critical tile set before sharing fast-travel admissions with near/far work; 0 keeps the walkable ring first and admits the normal shares."));
int32 GVoxelForgeStreamingResultBacklogCap = 256;
FAutoConsoleVariableRef CVarVoxelForgeStreamingResultBacklogCap(
TEXT("voxel.StreamingResultBacklogCap"),
@@ -355,6 +361,11 @@ namespace
TEXT("voxel.StreamingStartupApplyBoost"),
GVoxelForgeStreamingStartupApplyBoost,
TEXT("Bounded cold-view upload budget (default on): 1 allows a 14 ms / 24-mesh cap until the initial desired set and walkable ring are ready; 0 uses the authored per-frame budget."));
float GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds = 0.0f;
FAutoConsoleVariableRef CVarVoxelForgeStreamingFastTravelApplyBudgetMilliseconds(
TEXT("voxel.StreamingFastTravelApplyBudgetMilliseconds"),
GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds,
TEXT("Optional visible-result apply-time cap during speed-aware fast travel; 0 keeps the configured budget."));
constexpr int32 StreamingStartupMaxMeshApplies = 24;
constexpr float StreamingStartupApplyBudgetMilliseconds = 14.0f;
constexpr double StreamingStartupApplyMaxSeconds = 30.0;
@@ -2257,6 +2268,18 @@ void AVoxelWorld::BeginPlay()
GVoxelForgeCoreRegionConcurrentAdmission =
CommandLineCoreRegionConcurrentAdmission != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingFastTravelWaitForAllCriticalTiles="),
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles))
{
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles =
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles != 0 ? 1 : 0;
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingFastTravelApplyBudgetMilliseconds="),
GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds))
{
GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds = FMath::Max(
0.0f, GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds);
}
if (FParse::Value(FCommandLine::Get(), TEXT("voxel.StreamingResultBacklogCap="),
CommandLineStreamingResultBacklogCap))
{
@@ -2750,6 +2773,8 @@ void AVoxelWorld::BeginPlay()
"\"collision_gate\":%d,"
"\"streaming_result_backlog_cap\":%d,\"streaming_startup_apply_boost\":%d,"
"\"streaming_far_apply_supplement\":%d,"
"\"streaming_fast_travel_wait_for_all_critical_tiles\":%d,"
"\"streaming_fast_travel_apply_budget_ms\":%.3f,"
"\"streaming_background_worker_reserve\":%d,\"core_parallel_for_background_priority\":%d,"
"\"streaming_tile_background_low\":%d,\"streaming_tile_background_normal\":%d,"
"\"core_column_cache_direct_mapped\":%d,"
@@ -2772,6 +2797,8 @@ void AVoxelWorld::BeginPlay()
GVoxelForgeCollisionGate,
GVoxelForgeStreamingResultBacklogCap, GVoxelForgeStreamingStartupApplyBoost,
GVoxelForgeStreamingFarApplySupplement,
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles,
GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds,
GVoxelForgeStreamingBackgroundWorkerReserve,
GVoxelForgeCoreParallelForBackgroundPriority,
GVoxelForgeStreamingTileBackgroundLow,
@@ -9889,9 +9916,16 @@ void AVoxelWorld::ProcessPendingChunks()
const int32 MaxApplies = GVoxelForgeStep1MaxMeshApplies > 0
? GVoxelForgeStep1MaxMeshApplies
: (bUseStartupApplyBoost ? StreamingStartupMaxMeshApplies : ConfiguredMaxApplies);
const float ApplyBudgetMilliseconds = bUseStartupApplyBoost
float ApplyBudgetMilliseconds = bUseStartupApplyBoost
? StreamingStartupApplyBudgetMilliseconds
: (Settings ? FMath::Max(Settings->MaxMeshApplyMilliseconds, 0.0f) : 2.0f);
const bool bFastTravelApplyBudgetActive = bStreamingPlayerMoving && bSpeedAwareFastMode
&& GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds > 0.0f;
if (bFastTravelApplyBudgetActive)
{
ApplyBudgetMilliseconds = FMath::Min(
ApplyBudgetMilliseconds, GVoxelForgeStreamingFastTravelApplyBudgetMilliseconds);
}
const double ApplyBudgetSeconds =
static_cast<double>(ApplyBudgetMilliseconds) * 0.001;
int32 MeshesApplied = 0;
@@ -13231,7 +13265,10 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
// Policy 0 reconstructs L77. Policy 3 enters that order only after sustained fast travel.
if (bPolicy3FastTravel)
{
if (bWalkableRingReadyForReserve && AreCriticalTilesReady())
const bool bWaitForExpandedCriticalSet =
GVoxelForgeStreamingFastTravelWaitForAllCriticalTiles != 0;
if (bWalkableRingReadyForReserve
&& (!bWaitForExpandedCriticalSet || AreCriticalTilesReady()))
{
const int32 ShareAdmissionCap = FastTravelTotalCap;
const int32 StartingAdmissions = GetGenerationAdmissionCount();
@@ -13451,7 +13488,24 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
int32 SettledByLevel[9] = {};
int32 CoveredByLevel[9] = {};
int32 PendingByLevel[9] = {};
int32 NearAheadDesired = 0;
int32 NearAheadResident = 0;
int32 NearBehindDesired = 0;
int32 NearBehindResident = 0;
int32 NearForwardConeDesired = 0;
int32 NearForwardConeResident = 0;
double NearForwardWeightedDesired = 0.0;
double NearForwardWeightedResident = 0.0;
int32 TraceMaxDesiredLevel = 0;
const FVector LocalPawn = WorldToLocalCm(CenterPosition);
FVector TraceHeading = GetActorTransform().InverseTransformVectorNoScale(PlayerHeading)
.GetSafeNormal();
if (TraceHeading.IsNearlyZero() && IsValid(PlayerPawn))
{
TraceHeading = GetActorTransform().InverseTransformVectorNoScale(
PlayerPawn->GetActorForwardVector()).GetSafeNormal();
}
constexpr double ForwardConeCosine = 0.573576436351046; // cos(55 degrees)
for (const FVoxelTileKey& Tile : DesiredSorted)
{
TraceMaxDesiredLevel = FMath::Max(TraceMaxDesiredLevel, Tile.Level);
@@ -13460,10 +13514,43 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
{
if (Tile.Level < 0 || Tile.Level > 8) continue;
++DesiredByLevel[Tile.Level];
if (LoadedTiles.Contains(Tile)) ++ResidentByLevel[Tile.Level];
const bool bResident = LoadedTiles.Contains(Tile);
if (bResident) ++ResidentByLevel[Tile.Level];
if (LoadedTiles.Contains(Tile) || CollisionNotRequiredTiles.Contains(Tile))
++SettledByLevel[Tile.Level];
if (PendingTiles.Contains(Tile)) ++PendingByLevel[Tile.Level];
if (Tile.Level <= 2 && !TraceHeading.IsNearlyZero())
{
const double TileExtentCm = static_cast<double>(
VF_ClipLevelExtentVoxels(Tile.Level)) * GetActiveVoxelSizeCm();
const FVector TileCenter(
(static_cast<double>(Tile.Coord.X) + 0.5) * TileExtentCm,
(static_cast<double>(Tile.Coord.Y) + 0.5) * TileExtentCm,
(static_cast<double>(Tile.Coord.Z) + 0.5) * TileExtentCm);
const FVector Offset = TileCenter - LocalPawn;
const double Distance = Offset.Size();
const double Projection = FVector::DotProduct(Offset, TraceHeading);
const double DirectionCosine = Distance > 0.0 ? Projection / Distance : 0.0;
if (Projection > 0.0)
{
++NearAheadDesired;
if (bResident) ++NearAheadResident;
}
else if (Projection < 0.0)
{
++NearBehindDesired;
if (bResident) ++NearBehindResident;
}
if (DirectionCosine >= ForwardConeCosine)
{
++NearForwardConeDesired;
if (bResident) ++NearForwardConeResident;
}
const double Weight = FMath::Max(0.0, DirectionCosine);
NearForwardWeightedDesired += Weight;
if (bResident) NearForwardWeightedResident += Weight;
}
bool bCovered = LoadedTiles.Contains(Tile);
for (int32 AncestorLevel = Tile.Level + 1;
!bCovered && AncestorLevel <= TraceMaxDesiredLevel && AncestorLevel <= 8;
@@ -13503,12 +13590,17 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
SettledCounts += TEXT("]");
CoveredCounts += TEXT("]");
PendingCounts += TEXT("]");
const FVector LocalPawn = WorldToLocalCm(CenterPosition);
const double StreamingUpdateMilliseconds = (TraceNow - StreamingUpdateStartSeconds) * 1000.0;
VoxelForgeStartupTrace::RecordEvent(TEXT("streaming_sample"), FString::Printf(
TEXT("\"scope\":\"desired_residency_not_visual_enclosure\",\"center\":[%d,%d,%d],"
"\"position_cm\":[%s,%s,%s],\"speed_cm_s\":%s,\"walkable_ready\":%d,"
"\"desired_by_lod\":%s,\"resident_by_lod\":%s,\"settled_by_lod\":%s,"
"\"near_ahead_desired\":%d,\"near_ahead_resident\":%d,"
"\"near_behind_desired\":%d,\"near_behind_resident\":%d,"
"\"near_forward_cone_half_angle_deg\":55,"
"\"near_forward_cone_desired\":%d,\"near_forward_cone_resident\":%d,"
"\"near_forward_weighted_desired\":%s,"
"\"near_forward_weighted_resident\":%s,\"near_direction_valid\":%d,"
"\"pending_by_lod\":%s,"
"\"covered_by_lod\":%s,"
"\"walkable_ready_tiles\":%d,\"walkable_required_tiles\":9,"
@@ -13522,7 +13614,13 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
*FString::SanitizeFloat(LocalPawn.Z),
*FString::SanitizeFloat(PlayerHeading.Size()),
bWalkableRingReadyForReserve ? 1 : 0,
*DesiredCounts, *ResidentCounts, *SettledCounts, *PendingCounts, *CoveredCounts,
*DesiredCounts, *ResidentCounts, *SettledCounts,
NearAheadDesired, NearAheadResident, NearBehindDesired, NearBehindResident,
NearForwardConeDesired, NearForwardConeResident,
*FString::SanitizeFloat(static_cast<float>(NearForwardWeightedDesired)),
*FString::SanitizeFloat(static_cast<float>(NearForwardWeightedResident)),
TraceHeading.IsNearlyZero() ? 0 : 1,
*PendingCounts, *CoveredCounts,
WalkableRingReadyCount,
GetActiveGenerationTaskCount(), GetGenerationAdmissionCount(), MaxTasks, NearTaskReserve,
GVoxelForgeStreamingCoarseFirst, GVoxelForgeStreamingDynamicNearReserve,