streaming: incremental overlay materialization and same-center priority merge (L166)

Persistent Core/overlay/candidate sets updated from deltas; same-center priority order merges changed keys (full sort
only on center change). Set and order equality audits 28/28 + 28/28, injected mismatch fails. 30 m/s UE, 7 pairs vs
9c70053: p99 10.52 -> 7.42 ms (all pairs), worst tick 12.98 -> 11.65 ms (6/7), near 42.0 -> 43.7% and forward cone
14.8 -> 16.1% (all pairs), far holes 3.20 -> 2.74% median (4/7), arrival flat. Source/: VoxelWorld.cpp, VoxelWorld.h.

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 13:00:55 +01:00
1 parent 9c70053543
commit c6357b573f
4 files changed
+1300 -42

No files matched your search

+547 -42
View File
@@ -397,6 +397,12 @@ namespace
GVoxelForgeStreamingIncrementalDesiredAuditEvery,
TEXT("Compare the incremental desired set with a full rebuild every N center crossings; 0 disables the debug audit."));
int32 GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery = 0;
FAutoConsoleVariableRef CVarVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery(
TEXT("voxel.StreamingIncrementalDesiredMaterializationAuditEvery"),
GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery,
TEXT("Compare reused same-center desired materialization and priority order with a full rebuild every N cache hits; 0 disables this debug audit."));
int32 GVoxelForgeStreamingIncrementalDesiredAuditInjectMismatch = 0;
FAutoConsoleVariableRef CVarVoxelForgeStreamingIncrementalDesiredAuditInjectMismatch(
TEXT("voxel.StreamingIncrementalDesiredAuditInjectMismatch"),
@@ -1183,7 +1189,17 @@ void AVoxelWorld::RegenerateAllChunks()
CachedCoreDesiredTileSet.Reset();
CachedCoreDesiredCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
bHasCachedCoreDesiredTiles = false;
CachedDesiredCandidateKeys.Reset();
CachedDesiredCandidateSet.Reset();
CachedDesiredBaseVisualTiles.Reset();
CachedDesiredOverlayTiles.Reset();
CachedDesiredMaterializationCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
bHasCachedDesiredMaterialization = false;
CachedDesiredPriorityOrder.Reset();
CachedDesiredPriorityCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
bHasCachedDesiredPriorityOrder = false;
IncrementalDesiredCenterCrossings = 0;
IncrementalDesiredMaterializationUpdates = 0;
++DesiredEpoch;
TransitionHold.Reset();
TransitionHoldQueue.Reset();
@@ -2351,6 +2367,13 @@ void AVoxelWorld::BeginPlay()
GVoxelForgeStreamingIncrementalDesiredAuditEvery = FMath::Clamp(
GVoxelForgeStreamingIncrementalDesiredAuditEvery, 0, 1000000);
}
if (FParse::Value(FCommandLine::Get(),
TEXT("voxel.StreamingIncrementalDesiredMaterializationAuditEvery="),
GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery))
{
GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery = FMath::Clamp(
GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery, 0, 1000000);
}
if (FParse::Value(FCommandLine::Get(),
TEXT("voxel.StreamingIncrementalDesiredAuditInjectMismatch="),
GVoxelForgeStreamingIncrementalDesiredAuditInjectMismatch))
@@ -8163,7 +8186,17 @@ bool AVoxelWorld::InitializeVoxelForgeCoreWorld(FString& OutFailureReason)
CachedCoreDesiredTileSet.Reset();
bHasCachedCoreDesiredTiles = false;
CachedCoreDesiredCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
CachedDesiredCandidateKeys.Reset();
CachedDesiredCandidateSet.Reset();
CachedDesiredBaseVisualTiles.Reset();
CachedDesiredOverlayTiles.Reset();
CachedDesiredMaterializationCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
bHasCachedDesiredMaterialization = false;
CachedDesiredPriorityOrder.Reset();
CachedDesiredPriorityCenter = FIntVector(MAX_int32, MAX_int32, MAX_int32);
bHasCachedDesiredPriorityOrder = false;
IncrementalDesiredCenterCrossings = 0;
IncrementalDesiredMaterializationUpdates = 0;
State->bSnapshotReady.store(true, std::memory_order_release);
ActiveTaskCount.fetch_add(1, std::memory_order_relaxed);
const double CoreCompileLaunchSeconds = bTraceCoreStartup
@@ -11111,6 +11144,9 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
TArray<FVoxelTileKey>& OutLeavers)
{
TRACE_CPUPROFILER_EVENT_SCOPE(VoxelForge_BuildCoreDesiredTiles);
const bool bTraceDesiredBreakdown = VoxelForgeStartupTrace::IsActive();
const double DesiredBreakdownStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
// Capture the resolved floor before rebuilding CollisionDesiredTiles. The gate request set
// drops keys as soon as they have a body, while the pawn-radius set may not include a floor
// tile below a known-empty band. Keeping the active support here prevents that body from
@@ -11145,6 +11181,14 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
TArray<FVoxelTileKey> IncrementalCoreEntering;
TArray<FVoxelTileKey> IncrementalCoreLeaving;
double CoreDesiredQueryMilliseconds = 0.0;
double CoreDesiredPreparationMilliseconds = 0.0;
double CoreDesiredDeltaMilliseconds = 0.0;
double CoreDesiredFullFallbackMilliseconds = 0.0;
double OverlayMaterializationMilliseconds = 0.0;
double PrioritySortMilliseconds = 0.0;
double CriticalAdmissionOrderMilliseconds = 0.0;
int32 IncrementalChangedLod4PlusKeyCount = 0;
int32 IncrementalFallbackReason = 0;
bool bCoreDesiredCacheHit = false;
bool bCoreDesiredIncrementalDelta = false;
bool bCoreDesiredFullFallback = false;
@@ -11161,6 +11205,9 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
&& DesiredAuditInterval > 0
&& (IncrementalDesiredCenterCrossings % DesiredAuditInterval) == 0;
const double CoreDesiredPreparationStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
double CoreDesiredDeltaStartSeconds = 0.0;
if (bIncrementalDesiredSet && bHasCachedCoreDesiredTiles
&& CachedCoreDesiredCenter == Center)
{
@@ -11175,6 +11222,8 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
+ FMath::Abs(static_cast<int64>(Center.Z) - CachedCoreDesiredCenter.Z);
if (CenterDelta == 1)
{
CoreDesiredDeltaStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
TArray<FVoxelTileKey> RingEntering;
TArray<FVoxelTileKey> RingLeaving;
{
@@ -11219,11 +11268,15 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
bool bTouchesCoreSurfaceOverlay = false;
for (const FVoxelTileKey& Key : RingEntering)
{
bTouchesCoreSurfaceOverlay |= Key.Level >= 4;
const bool bTouchesSurfaceOverlay = Key.Level >= 4;
bTouchesCoreSurfaceOverlay |= bTouchesSurfaceOverlay;
IncrementalChangedLod4PlusKeyCount += bTouchesSurfaceOverlay ? 1 : 0;
}
for (const FVoxelTileKey& Key : RingLeaving)
{
bTouchesCoreSurfaceOverlay |= Key.Level >= 4;
const bool bTouchesSurfaceOverlay = Key.Level >= 4;
bTouchesCoreSurfaceOverlay |= bTouchesSurfaceOverlay;
IncrementalChangedLod4PlusKeyCount += bTouchesSurfaceOverlay ? 1 : 0;
}
if (!bTouchesCoreSurfaceOverlay)
{
@@ -11256,11 +11309,18 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
else
{
bCoreDesiredFullFallback = true;
IncrementalFallbackReason = 1;
}
if (CoreDesiredDeltaStartSeconds != 0.0)
{
CoreDesiredDeltaMilliseconds =
(FPlatformTime::Seconds() - CoreDesiredDeltaStartSeconds) * 1000.0;
}
}
else
{
bCoreDesiredFullFallback = true;
IncrementalFallbackReason = 2;
}
}
@@ -11306,21 +11366,49 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
FPlatformTime::Cycles64() - QueryStartCycles) * 1000.0;
}
}
if (CoreDesiredPreparationStartSeconds != 0.0)
{
CoreDesiredPreparationMilliseconds =
(FPlatformTime::Seconds() - CoreDesiredPreparationStartSeconds) * 1000.0;
if (bCoreDesiredFullFallback)
{
CoreDesiredFullFallbackMilliseconds = CoreDesiredPreparationMilliseconds;
}
}
if (VoxelForgeStartupTrace::IsActive())
{
VoxelForgeStartupTrace::RecordEvent(TEXT("core_desired_cache"), FString::Printf(
TEXT("\"frame\":%llu,\"center\":[%d,%d,%d],\"hit\":%d,"
"\"incremental_delta\":%d,\"full_fallback\":%d,"
"\"fallback_reason\":%d,\"changed_lod4plus\":%d,"
"\"crossing_count\":%d,\"audit_due\":%d,\"keys\":%d,"
"\"delta_entering\":%d,\"delta_leaving\":%d,\"query_ms\":%s"),
"\"delta_entering\":%d,\"delta_leaving\":%d,\"query_ms\":%s,"
"\"prepare_ms\":%s,\"delta_ms\":%s,\"fallback_ms\":%s"),
static_cast<unsigned long long>(GFrameCounter), Center.X, Center.Y, Center.Z,
bCoreDesiredCacheHit ? 1 : 0,
bCoreDesiredIncrementalDelta ? 1 : 0, bCoreDesiredFullFallback ? 1 : 0,
IncrementalFallbackReason, IncrementalChangedLod4PlusKeyCount,
IncrementalDesiredCenterCrossings, bShouldAuditIncrementalDesired ? 1 : 0,
CoreDesiredTiles ? CoreDesiredTiles->Num()
: static_cast<int32>(UncachedCoreDesiredTiles.size()),
IncrementalCoreEntering.Num(), IncrementalCoreLeaving.Num(),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredQueryMilliseconds))));
*FString::SanitizeFloat(static_cast<float>(CoreDesiredQueryMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredPreparationMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredDeltaMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredFullFallbackMilliseconds))));
}
// Drop completed collision-gate requests before checking the materialization cache. A gate
// set that changed during this rebuild must invalidate the cached overlay union.
for (auto It = CollisionGateDesiredTiles.CreateIterator(); It; ++It)
{
const FVoxelTileKey& Key = *It;
const TCHAR* UnavailableReason = nullptr;
if (IsTileCollisionReady(Key) || CollisionNotRequiredTiles.Contains(Key)
|| IsCollisionTileUnavailable(Key, UnavailableReason))
{
It.RemoveCurrent();
}
}
const FIntVector LookaheadHeadingStep = GetStreamingHeadingStep(PlayerHeading, PlayerPawn);
@@ -11329,23 +11417,57 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
int32 LookaheadCollisionTilesAdded = 0;
int32 LookaheadDesiredTilesMissing = 0;
TArray<FVoxelTileKey> CandidateKeys;
TSet<FVoxelTileKey> CandidateSet;
TSet<FVoxelTileKey> BaseVisualTiles;
const double OverlayMaterializationStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
const bool bIncrementalMaterializationUpdate = bIncrementalDesiredSet
&& bHasCachedCoreDesiredTiles && CoreDesiredTiles == &CachedCoreDesiredTiles
&& bHasCachedDesiredMaterialization
&& (CachedDesiredMaterializationCenter == Center || bCoreDesiredIncrementalDelta);
if (bIncrementalMaterializationUpdate)
{
++IncrementalDesiredMaterializationUpdates;
}
const int32 MaterializationAuditInterval = FMath::Max(
0, GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery);
const bool bShouldAuditDesiredMaterialization = bIncrementalMaterializationUpdate
&& MaterializationAuditInterval > 0
&& (IncrementalDesiredMaterializationUpdates % MaterializationAuditInterval) == 0;
const bool bShouldRunFullDesiredAudit = bShouldAuditIncrementalDesired
|| bShouldAuditDesiredMaterialization;
TArray<FVoxelTileKey>& CandidateKeys = CachedDesiredCandidateKeys;
TSet<FVoxelTileKey>& CandidateSet = CachedDesiredCandidateSet;
TSet<FVoxelTileKey>& BaseVisualTiles = CachedDesiredBaseVisualTiles;
TSet<FVoxelTileKey> FullVisualAnchorTiles;
TSet<FVoxelTileKey> CollisionAnchorTiles;
TSet<FVoxelTileKey> OverlayDesiredTiles;
TSet<FVoxelTileKey>& OverlayDesiredTiles = CachedDesiredOverlayTiles;
TSet<FVoxelTileKey> CurrentOverlayDesiredTiles;
TArray<FVoxelTileKey> DesiredEnteringTiles;
TArray<FVoxelTileKey> PriorityEnteringTiles;
TArray<FVoxelTileKey> PriorityLeavingTiles;
bool bCandidateKeySetChanged = false;
if (!bIncrementalMaterializationUpdate)
{
CandidateKeys.Reset();
CandidateSet.Reset();
BaseVisualTiles.Reset();
OverlayDesiredTiles.Reset();
CachedDesiredPriorityOrder.Reset();
bHasCachedDesiredPriorityOrder = false;
}
auto AddCandidate = [&](const FVoxelTileKey& Key, bool bOverlay)
{
if (bOverlay)
{
CurrentOverlayDesiredTiles.Add(Key);
if (bIncrementalMaterializationUpdate) return;
OverlayDesiredTiles.Add(Key);
}
if (!CandidateSet.Contains(Key))
{
CandidateSet.Add(Key);
CandidateKeys.Add(Key);
bCandidateKeySetChanged = true;
if (bIncrementalMaterializationUpdate) PriorityEnteringTiles.Add(Key);
const uint32* PreviousStamp = DesiredStamped.Find(Key);
if (bIncrementalDesiredSet
&& (PreviousStamp == nullptr || *PreviousStamp != PreviousDesiredStamp))
@@ -11361,14 +11483,14 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
AddCandidate(RuntimeKey, false);
BaseVisualTiles.Add(RuntimeKey);
};
if (CoreDesiredTiles)
if (!bIncrementalMaterializationUpdate && CoreDesiredTiles)
{
for (const FVoxelTileKey& RuntimeKey : *CoreDesiredTiles)
{
AddCoreDesiredTile(RuntimeKey);
}
}
else
else if (!bIncrementalMaterializationUpdate)
{
for (const VoxelForgeCore::TileKey& Key : UncachedCoreDesiredTiles)
{
@@ -11417,16 +11539,8 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
// Preserve unresolved support requests from the existing collision gate. They remain in Core
// tile coordinates, and level-0 bounds use the Core voxel scale through GetPlayerSupportTile.
for (auto It = CollisionGateDesiredTiles.CreateIterator(); It; ++It)
for (const FVoxelTileKey& Key : CollisionGateDesiredTiles)
{
const FVoxelTileKey& Key = *It;
const TCHAR* UnavailableReason = nullptr;
if (IsTileCollisionReady(Key) || CollisionNotRequiredTiles.Contains(Key)
|| IsCollisionTileUnavailable(Key, UnavailableReason))
{
It.RemoveCurrent();
continue;
}
AddCandidate(Key, true);
CollisionDesiredTiles.Add(Key);
CollisionAnchorTiles.Add(Key);
@@ -11436,13 +11550,101 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
{
AddCandidate(ResolvedSupportTile, true);
CollisionDesiredTiles.Add(ResolvedSupportTile);
if (!BaseVisualTiles.Contains(ResolvedSupportTile)
const bool bResolvedSupportIsCoreDesired = bIncrementalMaterializationUpdate
? CachedCoreDesiredTileSet.Contains(ResolvedSupportTile)
: BaseVisualTiles.Contains(ResolvedSupportTile);
if (!bResolvedSupportIsCoreDesired
&& !FullVisualAnchorTiles.Contains(ResolvedSupportTile))
{
CollisionAnchorTiles.Add(ResolvedSupportTile);
}
}
const auto AddCachedCandidateKey = [this, &CandidateKeys, &CandidateSet,
&DesiredEnteringTiles, &PriorityEnteringTiles,
&PreviousDesiredStamp,
&bCandidateKeySetChanged](
const FVoxelTileKey& Key)
{
if (!CandidateSet.Contains(Key))
{
CandidateSet.Add(Key);
CandidateKeys.Add(Key);
bCandidateKeySetChanged = true;
PriorityEnteringTiles.Add(Key);
const uint32* PreviousStamp = DesiredStamped.Find(Key);
if (GVoxelForgeStreamingIncrementalDesiredSet != 0
&& (PreviousStamp == nullptr || *PreviousStamp != PreviousDesiredStamp))
{
DesiredEnteringTiles.Add(Key);
}
}
DesiredStamped.FindOrAdd(Key) = DesiredStamp;
};
const auto RemoveCachedCandidateKey = [this, &CandidateKeys, &CandidateSet,
&PriorityLeavingTiles,
&bCandidateKeySetChanged](
const FVoxelTileKey& Key)
{
if (CandidateSet.Contains(Key))
{
CandidateSet.Remove(Key);
CandidateKeys.RemoveSingleSwap(Key, EAllowShrinking::No);
bCandidateKeySetChanged = true;
PriorityLeavingTiles.Add(Key);
}
};
if (bIncrementalMaterializationUpdate)
{
for (const FVoxelTileKey& Key : IncrementalCoreLeaving)
{
BaseVisualTiles.Remove(Key);
if (!CurrentOverlayDesiredTiles.Contains(Key))
{
RemoveCachedCandidateKey(Key);
}
}
for (const FVoxelTileKey& Key : IncrementalCoreEntering)
{
BaseVisualTiles.Add(Key);
AddCachedCandidateKey(Key);
}
for (auto It = OverlayDesiredTiles.CreateIterator(); It; ++It)
{
const FVoxelTileKey Key = *It;
if (!CurrentOverlayDesiredTiles.Contains(Key))
{
It.RemoveCurrent();
if (!BaseVisualTiles.Contains(Key))
{
RemoveCachedCandidateKey(Key);
}
}
}
for (const FVoxelTileKey& Key : CurrentOverlayDesiredTiles)
{
if (!OverlayDesiredTiles.Contains(Key))
{
OverlayDesiredTiles.Add(Key);
AddCachedCandidateKey(Key);
}
}
for (const FVoxelTileKey& Key : CandidateKeys)
{
DesiredStamped.FindOrAdd(Key) = DesiredStamp;
}
}
if (bIncrementalDesiredSet)
{
CachedDesiredMaterializationCenter = Center;
bHasCachedDesiredMaterialization = true;
}
else
{
bHasCachedDesiredMaterialization = false;
bHasCachedDesiredPriorityOrder = false;
}
const FVoxelTileKey PlayerTile(GetTileCoordAtLocalCm(WorldToLocalCm(PlayerPosition)), 0);
FVoxelTileKey OccupiedTile = PlayerTile;
FVoxelTileKey SupportTile;
@@ -11493,8 +11695,15 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
CollisionOnlyTiles.Add(Key);
}
}
if (OverlayMaterializationStartSeconds != 0.0)
{
OverlayMaterializationMilliseconds =
(FPlatformTime::Seconds() - OverlayMaterializationStartSeconds) * 1000.0;
}
if (bShouldAuditIncrementalDesired)
TSet<FVoxelTileKey> FullReferenceDesiredSetForOrder;
TArray<FVoxelTileKey> FullReferenceDesiredKeysForOrder;
if (bShouldRunFullDesiredAudit)
{
std::vector<VoxelForgeCore::TileKey> FullReferenceCoreTiles;
const FVector CameraVoxels = WorldToLocalCm(PlayerPosition) / GetActiveVoxelSizeCm();
@@ -11507,30 +11716,60 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
TSet<FVoxelTileKey> FullReferenceCoreSet;
FullReferenceCoreSet.Reserve(static_cast<int32>(FullReferenceCoreTiles.size()));
TSet<FVoxelTileKey> FullReferenceDesiredSet;
FullReferenceDesiredSet.Reserve(
static_cast<int32>(FullReferenceCoreTiles.size()) + OverlayDesiredTiles.Num());
TSet<FVoxelTileKey> FullReferenceOverlayDesiredSet;
for (const FVoxelStreamingAnchor& Anchor : StreamingAnchors)
{
if (!Anchor.Actor.IsValid()) continue;
const FIntVector AnchorCenter = Anchor.LastChunk;
const int32 XYRadius = FMath::Clamp(Anchor.XYRadiusChunks, 0, 4);
const int32 ZBelow = FMath::Clamp(Anchor.ZBelowChunks, 0, 4);
const int32 ZAbove = FMath::Clamp(Anchor.ZAboveChunks, 0, 4);
for (int32 Dz = -ZBelow; Dz <= ZAbove; ++Dz)
for (int32 Dy = -XYRadius; Dy <= XYRadius; ++Dy)
for (int32 Dx = -XYRadius; Dx <= XYRadius; ++Dx)
{
FullReferenceOverlayDesiredSet.Add(
FVoxelTileKey(AnchorCenter + FIntVector(Dx, Dy, Dz), 0));
}
}
for (const FVoxelTileKey& Key : CollisionGateDesiredTiles)
{
FullReferenceOverlayDesiredSet.Add(Key);
}
if (bRetainResolvedSupport)
{
FullReferenceOverlayDesiredSet.Add(ResolvedSupportTile);
}
FullReferenceDesiredSetForOrder.Reserve(
static_cast<int32>(FullReferenceCoreTiles.size())
+ FullReferenceOverlayDesiredSet.Num());
for (const VoxelForgeCore::TileKey& Key : FullReferenceCoreTiles)
{
const FVoxelTileKey RuntimeKey(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
FullReferenceCoreSet.Add(RuntimeKey);
FullReferenceDesiredSet.Add(RuntimeKey);
FullReferenceDesiredSetForOrder.Add(RuntimeKey);
}
for (const FVoxelTileKey& Key : OverlayDesiredTiles)
for (const FVoxelTileKey& Key : FullReferenceOverlayDesiredSet)
{
FullReferenceDesiredSet.Add(Key);
FullReferenceDesiredSetForOrder.Add(Key);
}
FullReferenceDesiredKeysForOrder.Reserve(FullReferenceDesiredSetForOrder.Num());
for (const FVoxelTileKey& Key : FullReferenceDesiredSetForOrder)
{
FullReferenceDesiredKeysForOrder.Add(Key);
}
int32 MissingFromIncrementalDesired = 0;
int32 ExtraInIncrementalDesired = 0;
for (const FVoxelTileKey& Key : FullReferenceDesiredSet)
for (const FVoxelTileKey& Key : FullReferenceDesiredSetForOrder)
{
if (!CandidateSet.Contains(Key)) ++MissingFromIncrementalDesired;
}
for (const FVoxelTileKey& Key : CandidateSet)
{
if (!FullReferenceDesiredSet.Contains(Key)) ++ExtraInIncrementalDesired;
if (!FullReferenceDesiredSetForOrder.Contains(Key)) ++ExtraInIncrementalDesired;
}
TSet<FVoxelTileKey> FullReferenceCollisionOnly;
@@ -11554,7 +11793,7 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
if (GVoxelForgeStreamingIncrementalDesiredAuditInjectMismatch != 0)
{
FullReferenceDesiredSet.Add(
FullReferenceDesiredSetForOrder.Add(
FVoxelTileKey(FIntVector(MAX_int32, MAX_int32, MAX_int32), 8));
++MissingFromIncrementalDesired;
}
@@ -11565,11 +11804,14 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
TEXT("\"frame\":%llu,\"center\":[%d,%d,%d],\"crossing\":%d,"
"\"core_keys\":%d,\"reference_keys\":%d,\"candidate_keys\":%d,"
"\"missing\":%d,\"extra\":%d,\"collision_only_missing\":%d,"
"\"collision_only_extra\":%d,\"pass\":%d"),
"\"collision_only_extra\":%d,\"materialization_update\":%d,"
"\"materialization_audit\":%d,\"pass\":%d"),
static_cast<unsigned long long>(GFrameCounter), Center.X, Center.Y, Center.Z,
IncrementalDesiredCenterCrossings, static_cast<int32>(FullReferenceCoreTiles.size()),
FullReferenceDesiredSet.Num(), CandidateSet.Num(), MissingFromIncrementalDesired,
FullReferenceDesiredSetForOrder.Num(), CandidateSet.Num(), MissingFromIncrementalDesired,
ExtraInIncrementalDesired, MissingCollisionOnly, ExtraCollisionOnly,
bIncrementalMaterializationUpdate ? 1 : 0,
bShouldAuditDesiredMaterialization ? 1 : 0,
bDesiredSetsMatch ? 1 : 0));
if (!bDesiredSetsMatch)
{
@@ -11583,19 +11825,133 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
}
}
std::vector<VoxelForgeCore::TileKey> PriorityInput;
PriorityInput.reserve(static_cast<std::size_t>(CandidateKeys.Num()));
for (const FVoxelTileKey& Key : CandidateKeys)
const double PrioritySortStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
const bool bCanIncrementallyUpdateDesiredPriorityOrder = bIncrementalMaterializationUpdate
&& bHasCachedDesiredPriorityOrder
&& CachedDesiredPriorityCenter == Center
&& CachedDesiredPriorityOrder.Num()
== CandidateSet.Num() - PriorityEnteringTiles.Num() + PriorityLeavingTiles.Num();
bool bPriorityOrderUpdated = false;
bool bReuseDesiredPriorityOrder = false;
if (bCanIncrementallyUpdateDesiredPriorityOrder)
{
PriorityInput.push_back({{Key.Coord.X, Key.Coord.Y, Key.Coord.Z}, Key.Level});
const auto IsPriorityBefore = [Center](const FVoxelTileKey& A, const FVoxelTileKey& B)
{
const auto Tier = [Center](const FVoxelTileKey& Key)
{
if (Key.Level == 0 && FMath::Abs(Key.Coord.X - Center.X) <= 1
&& FMath::Abs(Key.Coord.Y - Center.Y) <= 1
&& FMath::Abs(Key.Coord.Z - Center.Z) <= 1)
{
return 0;
}
return Key.Level <= 2 ? 1 : 2;
};
const int32 TierA = Tier(A);
const int32 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;
const auto DistanceSquared = [Center](const FVoxelTileKey& Key)
{
const double Scale = static_cast<double>(1 << Key.Level);
const double DX = (static_cast<double>(Key.Coord.X) + 0.5) * Scale - Center.X;
const double DY = (static_cast<double>(Key.Coord.Y) + 0.5) * Scale - Center.Y;
const double DZ = (static_cast<double>(Key.Coord.Z) + 0.5) * Scale - Center.Z;
return DX * DX + DY * DY + DZ * DZ;
};
const double DistanceA = DistanceSquared(A);
const double DistanceB = DistanceSquared(B);
if (DistanceA != DistanceB) return DistanceA < DistanceB;
if (A.Level != B.Level) return A.Level < B.Level;
if (A.Coord.Z != B.Coord.Z) return A.Coord.Z < B.Coord.Z;
if (A.Coord.Y != B.Coord.Y) return A.Coord.Y < B.Coord.Y;
return A.Coord.X < B.Coord.X;
};
if (!PriorityLeavingTiles.IsEmpty())
{
TSet<FVoxelTileKey> LeavingSet;
LeavingSet.Reserve(PriorityLeavingTiles.Num());
for (const FVoxelTileKey& Key : PriorityLeavingTiles) LeavingSet.Add(Key);
CachedDesiredPriorityOrder.RemoveAll([&LeavingSet](const FVoxelTileKey& Key)
{
return LeavingSet.Contains(Key);
});
}
if (!PriorityEnteringTiles.IsEmpty())
{
PriorityEnteringTiles.Sort(IsPriorityBefore);
TArray<FVoxelTileKey> MergedOrder;
MergedOrder.Reserve(
CachedDesiredPriorityOrder.Num() + PriorityEnteringTiles.Num());
int32 ExistingIndex = 0;
int32 EnteringIndex = 0;
while (ExistingIndex < CachedDesiredPriorityOrder.Num()
&& EnteringIndex < PriorityEnteringTiles.Num())
{
const FVoxelTileKey& ExistingKey = CachedDesiredPriorityOrder[ExistingIndex];
const FVoxelTileKey& EnteringKey = PriorityEnteringTiles[EnteringIndex];
if (ExistingKey == EnteringKey)
{
MergedOrder.Add(ExistingKey);
++ExistingIndex;
++EnteringIndex;
}
else if (IsPriorityBefore(EnteringKey, ExistingKey))
{
MergedOrder.Add(EnteringKey);
++EnteringIndex;
}
else
{
MergedOrder.Add(ExistingKey);
++ExistingIndex;
}
}
while (ExistingIndex < CachedDesiredPriorityOrder.Num())
{
MergedOrder.Add(CachedDesiredPriorityOrder[ExistingIndex++]);
}
while (EnteringIndex < PriorityEnteringTiles.Num())
{
MergedOrder.Add(PriorityEnteringTiles[EnteringIndex++]);
}
CachedDesiredPriorityOrder = MoveTemp(MergedOrder);
}
CachedDesiredPriorityCenter = Center;
bPriorityOrderUpdated = bCandidateKeySetChanged;
bReuseDesiredPriorityOrder = !bPriorityOrderUpdated;
DesiredSorted = CachedDesiredPriorityOrder;
}
std::vector<VoxelForgeCore::TileKey> PriorityOrder = VoxelForgeCore::World::prioritizeTiles(
PriorityInput, {Center.X, Center.Y, Center.Z});
DesiredSorted.Reserve(static_cast<int32>(PriorityOrder.size()));
for (const VoxelForgeCore::TileKey& Key : PriorityOrder)
else
{
DesiredSorted.Emplace(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
std::vector<VoxelForgeCore::TileKey> PriorityInput;
PriorityInput.reserve(static_cast<std::size_t>(CandidateKeys.Num()));
for (const FVoxelTileKey& Key : CandidateKeys)
{
PriorityInput.push_back({{Key.Coord.X, Key.Coord.Y, Key.Coord.Z}, Key.Level});
}
std::vector<VoxelForgeCore::TileKey> PriorityOrder = VoxelForgeCore::World::prioritizeTiles(
PriorityInput, {Center.X, Center.Y, Center.Z});
DesiredSorted.Reserve(static_cast<int32>(PriorityOrder.size()));
for (const VoxelForgeCore::TileKey& Key : PriorityOrder)
{
DesiredSorted.Emplace(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
}
if (bIncrementalDesiredSet)
{
CachedDesiredPriorityOrder = DesiredSorted;
CachedDesiredPriorityCenter = Center;
bHasCachedDesiredPriorityOrder = true;
}
}
if (PrioritySortStartSeconds != 0.0)
{
PrioritySortMilliseconds =
(FPlatformTime::Seconds() - PrioritySortStartSeconds) * 1000.0;
}
RestoreKnownEmptyCollisionTiles();
@@ -11610,6 +11966,8 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
}
CancelObsoleteTileWork();
const double CriticalAdmissionOrderStartSeconds = bTraceDesiredBreakdown
? FPlatformTime::Seconds() : 0.0;
auto AddCriticalTile = [this](const FVoxelTileKey& Key)
{
if (IsDesired(Key) && !CriticalDesiredTiles.Contains(Key))
@@ -11663,6 +12021,120 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
DesiredSorted.Insert(Key, 0);
}
}
if (CriticalAdmissionOrderStartSeconds != 0.0)
{
CriticalAdmissionOrderMilliseconds =
(FPlatformTime::Seconds() - CriticalAdmissionOrderStartSeconds) * 1000.0;
}
if (bShouldRunFullDesiredAudit)
{
std::vector<VoxelForgeCore::TileKey> FullReferencePriorityInput;
FullReferencePriorityInput.reserve(
static_cast<std::size_t>(FullReferenceDesiredKeysForOrder.Num()));
for (const FVoxelTileKey& Key : FullReferenceDesiredKeysForOrder)
{
FullReferencePriorityInput.push_back(
{{Key.Coord.X, Key.Coord.Y, Key.Coord.Z}, Key.Level});
}
const std::vector<VoxelForgeCore::TileKey> FullReferencePriorityOrder =
VoxelForgeCore::World::prioritizeTiles(
FullReferencePriorityInput, {Center.X, Center.Y, Center.Z});
TArray<FVoxelTileKey> FullReferenceDesiredOrder;
FullReferenceDesiredOrder.Reserve(
static_cast<int32>(FullReferencePriorityOrder.size()));
for (const VoxelForgeCore::TileKey& Key : FullReferencePriorityOrder)
{
FullReferenceDesiredOrder.Emplace(
FIntVector(Key.coordinate.x, Key.coordinate.y, Key.coordinate.z), Key.lod);
}
TArray<FVoxelTileKey> FullReferenceCriticalTiles;
const auto AddReferenceCriticalTile = [&](const FVoxelTileKey& Key)
{
if (FullReferenceDesiredSetForOrder.Contains(Key)
&& !FullReferenceCriticalTiles.Contains(Key))
{
FullReferenceCriticalTiles.Add(Key);
}
};
if (CollisionGateDesiredTiles.Contains(PawnGateRequestedSupportTile))
{
AddReferenceCriticalTile(PawnGateRequestedSupportTile);
}
for (const FVoxelTileKey& Key : FullReferenceDesiredOrder)
{
if (CollisionGateDesiredTiles.Contains(Key)) AddReferenceCriticalTile(Key);
}
AddReferenceCriticalTile(OccupiedTile);
if (HeadingStep != FIntVector::ZeroValue)
{
FVoxelTileKey NextTile = OccupiedTile;
NextTile.Coord += HeadingStep;
AddReferenceCriticalTile(NextTile);
}
AddReferenceCriticalTile(PlayerTile);
for (int32 Dy = -1; Dy <= 1; ++Dy)
for (int32 Dx = -1; Dx <= 1; ++Dx)
{
const FVoxelTileKey WalkableKey(OccupiedTile.Coord + FIntVector(Dx, Dy, 0), 0);
if (CollisionDesiredTiles.Contains(WalkableKey))
{
AddReferenceCriticalTile(WalkableKey);
}
}
for (int32 Ahead = 1; Ahead <= LookaheadTiles; ++Ahead)
{
const FIntVector AheadCenter = OccupiedTile.Coord + HeadingStep * Ahead;
for (int32 Dy = -1; Dy <= 1; ++Dy)
for (int32 Dx = -1; Dx <= 1; ++Dx)
{
const FVoxelTileKey WalkableKey(AheadCenter + FIntVector(Dx, Dy, 0), 0);
if (CollisionDesiredTiles.Contains(WalkableKey))
{
AddReferenceCriticalTile(WalkableKey);
}
}
}
for (int32 Index = FullReferenceCriticalTiles.Num() - 1; Index >= 0; --Index)
{
const int32 ExistingIndex = FullReferenceDesiredOrder.Find(
FullReferenceCriticalTiles[Index]);
if (ExistingIndex > 0)
{
const FVoxelTileKey Key = FullReferenceDesiredOrder[ExistingIndex];
FullReferenceDesiredOrder.RemoveAt(ExistingIndex, 1, EAllowShrinking::No);
FullReferenceDesiredOrder.Insert(Key, 0);
}
}
int32 PriorityOrderMismatches = FMath::Abs(
FullReferenceDesiredOrder.Num() - DesiredSorted.Num());
const int32 CommonOrderLength = FMath::Min(
FullReferenceDesiredOrder.Num(), DesiredSorted.Num());
for (int32 Index = 0; Index < CommonOrderLength; ++Index)
{
if (FullReferenceDesiredOrder[Index] != DesiredSorted[Index])
{
++PriorityOrderMismatches;
}
}
const bool bPriorityOrdersMatch = PriorityOrderMismatches == 0;
VoxelForgeStartupTrace::RecordEvent(TEXT("incremental_desired_order_audit"), FString::Printf(
TEXT("\"frame\":%llu,\"center\":[%d,%d,%d],\"reference_keys\":%d,"
"\"candidate_keys\":%d,\"mismatches\":%d,"
"\"materialization_update\":%d,\"pass\":%d"),
static_cast<unsigned long long>(GFrameCounter), Center.X, Center.Y, Center.Z,
FullReferenceDesiredOrder.Num(), DesiredSorted.Num(), PriorityOrderMismatches,
bIncrementalMaterializationUpdate ? 1 : 0, bPriorityOrdersMatch ? 1 : 0));
if (!bPriorityOrdersMatch)
{
UE_LOG(LogTemp, Error,
TEXT("[VoxelForgeIncrementalDesiredOrderAudit] mismatch keys=%d mismatches=%d reused=%d"),
DesiredSorted.Num(), PriorityOrderMismatches,
bReuseDesiredPriorityOrder ? 1 : 0);
FPlatformMisc::RequestExitWithStatus(
false, 1, TEXT("VoxelForge incremental desired priority-order equality failure"));
checkf(false, TEXT("VoxelForge incremental desired priority-order equality failure"));
}
}
if (bIncrementalDesiredSet && bHadPreviousDesiredSet)
{
constexpr int32 MaxSupportedTileLevel = 8;
@@ -11777,6 +12249,37 @@ void AVoxelWorld::BuildCoreDesiredTiles(const FIntVector& Center, const FVector&
}
StartPendingCoreRegionCompile();
}
if (bTraceDesiredBreakdown)
{
const double TotalMilliseconds =
(FPlatformTime::Seconds() - DesiredBreakdownStartSeconds) * 1000.0;
VoxelForgeStartupTrace::RecordEvent(TEXT("desired_rebuild_breakdown"), FString::Printf(
TEXT("\"frame\":%llu,\"center\":[%d,%d,%d],\"total_ms\":%s,"
"\"core_prepare_ms\":%s,\"core_delta_ms\":%s,\"fallback_ms\":%s,"
"\"overlay_materialize_ms\":%s,\"priority_sort_ms\":%s,"
"\"critical_order_ms\":%s,\"core_keys\":%d,\"candidate_keys\":%d,"
"\"overlay_keys\":%d,\"critical_keys\":%d,\"fallback_reason\":%d,"
"\"changed_lod4plus\":%d,\"materialization_update\":%d,"
"\"priority_order_reused\":%d,\"priority_order_updated\":%d,"
"\"materialization_audit_due\":%d"),
static_cast<unsigned long long>(GFrameCounter), Center.X, Center.Y, Center.Z,
*FString::SanitizeFloat(static_cast<float>(TotalMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredPreparationMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredDeltaMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CoreDesiredFullFallbackMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(OverlayMaterializationMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(PrioritySortMilliseconds)),
*FString::SanitizeFloat(static_cast<float>(CriticalAdmissionOrderMilliseconds)),
CoreDesiredTiles ? CoreDesiredTiles->Num()
: static_cast<int32>(UncachedCoreDesiredTiles.size()),
CandidateKeys.Num(), OverlayDesiredTiles.Num(), CriticalDesiredTiles.Num(),
IncrementalFallbackReason, IncrementalChangedLod4PlusKeyCount,
bIncrementalMaterializationUpdate ? 1 : 0,
bReuseDesiredPriorityOrder ? 1 : 0,
bPriorityOrderUpdated ? 1 : 0,
bShouldAuditDesiredMaterialization ? 1 : 0));
}
}
void AVoxelWorld::StartPendingCoreRegionCompile()
@@ -14353,6 +14856,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
"\"core_desired_cache_by_center\":%d,"
"\"incremental_desired_set\":%d,"
"\"incremental_desired_audit_every\":%d,"
"\"incremental_desired_materialization_audit_every\":%d,"
"\"incremental_desired_audit_inject_mismatch\":%d,"
"\"camera_forward_valid\":%d,"
"\"near_missing_by_direction\":%s,\"near_submitted_by_direction\":%s,"
@@ -14391,6 +14895,7 @@ void AVoxelWorld::UpdateChunksAroundPosition(const FVector& CenterPosition, APaw
GVoxelForgeStreamingCoreDesiredCacheByCenter != 0 ? 1 : 0,
GVoxelForgeStreamingIncrementalDesiredSet != 0 ? 1 : 0,
GVoxelForgeStreamingIncrementalDesiredAuditEvery,
GVoxelForgeStreamingIncrementalDesiredMaterializationAuditEvery,
GVoxelForgeStreamingIncrementalDesiredAuditInjectMismatch,
bCameraForwardValid ? 1 : 0,
*IntArray4Json(DesiredMissingByDirection),