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:
1 parent
9c70053543
commit
c6357b573f
4 files changed
+1300
-42
No files matched your search
@@ -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),
|
||||
|
||||
Reference in new issue
Block a user