perf(generation): field-exact LOD0 overhead removal; the unknown bucket is Core.dll
Field-preserving floor round (Codex; reviewed by me against the code):
- exact per-(sample, passage) caching of native/generic floor projections and walkable-air
checks, behind voxel.FloorRound1PassageProjectionCache
- a zero-work disabled path for VoxelDensityProfile::FScopedTimer, unchanged when enabled
- pointer / range-for iteration in the proven-hot tunnel, passage, spatial and candidate loops
(TArray RangeCheck was ~6.5% of LOD0 samples on the Development binaries the owner plays on)
- FVector2D temporaries replaced with scalar doubles, same operations in the same order
- FSurfaceColumn made trivial, so thread-local construction does no work. Verified safe:
ComputeSurfaceColumn writes all five outputs unconditionally before any branch, and every read
of Box.Cols is gated by Box.Computed
Verified: export OBJ byte-identical (b3e5f4c3..9b377); capability 20,830 / 10,909; all 8
interleaved game runs gave identical totals (841 tiles / 669,834 triangles static, 2,348 /
1,985,216 moving, the same as previous rounds). Per-tile identity for the always-on changes still
needs a check against a stored trace; that is queued first in the next round.
Game path (sampler off, two interleaved runs each):
projection-cache switch alone: neutral (static worker +0.41%, moving -0.05%)
vs the previous round (cfad3d1, same harness; cross-round numbers reproduced within ~1% here):
LOD0 generation p50 static 76.6 -> 65.8 ms (-14%), moving 72.4 -> 59.5 ms (-18%)
LOD0 request p50/p95 moving 79.4/158.5 -> 67.6/137.6 ms
worker seconds static 39.2 -> 33.4, moving 113.7 -> 97.9
The always-on changes carry the gain; they have no switch, so this is a cross-round comparison.
The sampler's ~12.9% "unknown" LOD0 leaf is engine code: UnrealEditor-Core.dll + RVA 0xC080,
without a Core PDB. The old FSurfaceColumn label is gone. Next round names it by its callers.
PERF-SAMPLED.md: corrected a sentence that repeated my false "daytime use" explanation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TaFdXhTdYMkW1xrV6ApT6Y
This commit is contained in:
1 parent
b839edd3a3
commit
ab4bbe3680
9 files changed
+629
-170
No files matched your search
@@ -302,35 +302,48 @@ namespace VoxelPassageGeometry
|
||||
return false;
|
||||
}
|
||||
|
||||
const FVector2D QueryXY(Position.X, Position.Y);
|
||||
const double QueryX = Position.X;
|
||||
const double QueryY = Position.Y;
|
||||
const int32 ControlPointCount = ControlPoints.Num();
|
||||
const FVector* ControlPointData = ControlPoints.GetData();
|
||||
const float* ControlRadiusData = ControlRadii.GetData();
|
||||
float BestDistanceSquared = FLT_MAX;
|
||||
bool bFoundSegment = false;
|
||||
for (int32 SegmentIndex = 0;
|
||||
SegmentIndex + 1 < ControlPoints.Num();
|
||||
SegmentIndex + 1 < ControlPointCount;
|
||||
++SegmentIndex)
|
||||
{
|
||||
const FVector& A = ControlPoints[SegmentIndex];
|
||||
const FVector& B = ControlPoints[SegmentIndex + 1];
|
||||
const FVector2D AXY(A.X, A.Y);
|
||||
const FVector2D Delta = FVector2D(B.X, B.Y) - AXY;
|
||||
const float LengthSquared = Delta.SizeSquared();
|
||||
const FVector& A = ControlPointData[SegmentIndex];
|
||||
const FVector& B = ControlPointData[SegmentIndex + 1];
|
||||
const double AXY_X = A.X;
|
||||
const double AXY_Y = A.Y;
|
||||
const double DeltaX = B.X - AXY_X;
|
||||
const double DeltaY = B.Y - AXY_Y;
|
||||
const float LengthSquared = static_cast<float>(
|
||||
DeltaX * DeltaX + DeltaY * DeltaY);
|
||||
if (LengthSquared <= KINDA_SMALL_NUMBER)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const double Dot = (QueryX - AXY_X) * DeltaX
|
||||
+ (QueryY - AXY_Y) * DeltaY;
|
||||
const float T = FMath::Clamp(
|
||||
FVector2D::DotProduct(QueryXY - AXY, Delta) / LengthSquared,
|
||||
Dot / LengthSquared,
|
||||
0.0f, 1.0f);
|
||||
const FVector2D ClosestXY = AXY + Delta * T;
|
||||
const float DistanceSquared = (QueryXY - ClosestXY).SizeSquared();
|
||||
const double ClosestX = AXY_X + DeltaX * T;
|
||||
const double ClosestY = AXY_Y + DeltaY * T;
|
||||
const double DistanceX = QueryX - ClosestX;
|
||||
const double DistanceY = QueryY - ClosestY;
|
||||
const float DistanceSquared = static_cast<float>(
|
||||
DistanceX * DistanceX + DistanceY * DistanceY);
|
||||
if (DistanceSquared >= BestDistanceSquared)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const float StartRadius = FMath::Abs(ControlRadii[SegmentIndex]);
|
||||
const float EndRadius = FMath::Abs(ControlRadii[SegmentIndex + 1]);
|
||||
const float StartRadius = FMath::Abs(ControlRadiusData[SegmentIndex]);
|
||||
const float EndRadius = FMath::Abs(ControlRadiusData[SegmentIndex + 1]);
|
||||
OutFloorZ = FMath::Lerp(
|
||||
TunnelFloorZ(A, StartRadius),
|
||||
TunnelFloorZ(B, EndRadius),
|
||||
|
||||
Reference in new issue
Block a user