perf(tunnels): memoise the room mouth -- room ownership now cheaper than before the change
The room-wins rule cost +55% static / +36% moving worker CPU because every sample re-answered the room-mouth question. A bounded exact memo around BuildRoomMouth (4096 sets x 4 ways, 7.49 MiB, keyed on every geometry-affecting room/tunnel input) removes that: hit rate 99.91% static / 99.89% moving, and VF_FindRoomFloorCrossingWorld (19.5%/17.1% inclusive), VF_FindRoomMouthBoundary (16.0%/14.0%) and VF_EvaluateRoomLandingDensity leave the sampler's top 30 entirely.
vs the tip DLL (bf9384a runtime), same staged owner map: worker sum 29.003 s vs 30.749 s static (-5.7%), 57.232 s vs 60.923 s moving (-6.1%), request p95 -3.3% / -8.4%. Geometry unchanged by construction: canonical hash 86A99075, 64/64 tile hashes, OBJ SHA 7E0D8109..C543, identical across a repeat run and with -voxel.CrtFma3=0. Walk Connected 42,870 / 17,413; tunnel-attributed solid inside rooms 0; mouth amplitude 1.4903 cm; TilePostReachProof and DetSinCos pass. The crossing test was not rerun (the memo returns the same values; its PASS stands at 248.43 m / 26.584 s).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
76bc8bce97
commit
1c642fd182
5 files changed
+954
-135
No files matched your search
File diff suppressed because it is too large.
Load diff
@@ -3747,6 +3747,8 @@ namespace
|
||||
FTunnelCoreWorldEvaluation LastTunnelCoreWorldEvaluation;
|
||||
FVector LastTunnelCoreEvaluationPosition = FVector::ZeroVector;
|
||||
bool bLastTunnelCoreWorldEvaluationValid = false;
|
||||
bool bLastRoomOwnsBottom = false;
|
||||
bool bLastRoomOwnsBottomValid = false;
|
||||
|
||||
/** ÉTAPE C1 — les params de la strate avec l'op de CETTE salle appliqué par-dessus.
|
||||
* Mémo par voxel : invalidé au début de chaque `Eval`, calculé au PREMIER modificateur
|
||||
@@ -3800,6 +3802,7 @@ namespace
|
||||
S.ActiveCache = Sample.RoomCache;
|
||||
S.NearestRoom = Sample.NearestRoomIndex;
|
||||
S.bLocalParamsValid = false;
|
||||
S.bLastRoomOwnsBottomValid = false;
|
||||
}
|
||||
|
||||
bool TryGetLastTunnelCoreWorldEvaluation(
|
||||
@@ -3827,7 +3830,8 @@ namespace
|
||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
Position.X, Position.Y, Position.Z, GetCache(), nullptr,
|
||||
VoxelGenLOD::ShouldUseSpatialIndex(false),
|
||||
&S.LastWarpedPosition);
|
||||
&S.LastWarpedPosition,
|
||||
S.bLastRoomOwnsBottomValid ? &S.bLastRoomOwnsBottom : nullptr);
|
||||
S.LastTunnelCoreEvaluationPosition = Position;
|
||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||
}
|
||||
@@ -3922,6 +3926,7 @@ namespace
|
||||
FState& S = State();
|
||||
S.LastWorldPosition = FVector(WorldX, WorldY, WorldZ);
|
||||
S.bLastTunnelCoreWorldEvaluationValid = false;
|
||||
S.bLastRoomOwnsBottomValid = false;
|
||||
|
||||
// ⚠️ REMIS À -1 INCONDITIONNELLEMENT, ce que l'original ne fait pas : chez lui
|
||||
// `NearestRoomIdx` est un `thread_local` qui, quand `RoomDensity <= 0`, garde la valeur
|
||||
@@ -4184,7 +4189,9 @@ namespace
|
||||
const FVector WorldTunnelPosition(WorldX, WorldY, WorldZ);
|
||||
float CaveSDF = VoxelCaveMorphology::EvaluateSDFCached(
|
||||
WarpedX, WarpedY, WarpedZ, GetCache(), P.SDFBlendRadius,
|
||||
&S.NearestRoom, bUseSpatialIndex, &WorldTunnelPosition);
|
||||
&S.NearestRoom, bUseSpatialIndex, &WorldTunnelPosition,
|
||||
&S.bLastRoomOwnsBottom);
|
||||
S.bLastRoomOwnsBottomValid = true;
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// PITS & CHEMINÉES — coordonnées RÉELLES, SmoothMin dans le même canal SDF
|
||||
@@ -4275,7 +4282,8 @@ namespace
|
||||
{
|
||||
S.LastTunnelCoreWorldEvaluation = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, GetCache(), nullptr,
|
||||
bUseSpatialIndex, &S.LastWarpedPosition);
|
||||
bUseSpatialIndex, &S.LastWarpedPosition,
|
||||
&S.bLastRoomOwnsBottom);
|
||||
S.LastTunnelCoreEvaluationPosition = S.LastWorldPosition;
|
||||
S.bLastTunnelCoreWorldEvaluationValid = true;
|
||||
|
||||
|
||||
@@ -3294,6 +3294,10 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
float BlockTunnelCoreSweptFloorRadius = 0.0f;
|
||||
bool bUsedFusedEvaluator = false;
|
||||
FTunnelCoreWorldEvaluation FusedTunnelCore;
|
||||
bool bRoomOwnsBottom = false;
|
||||
bool bRoomOwnsBottomValid = false;
|
||||
FVector NativeWarpedPosition = FVector::ZeroVector;
|
||||
bool bNativeWarpedPositionValid = false;
|
||||
|
||||
// Le seul point d'entrée de la pile dans le chemin de production. Elle rend la convention
|
||||
// MC (négatif = solide) comme les fonctions d'archétype, donc les disturbances et la couche
|
||||
@@ -3322,7 +3326,9 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
WorldX, WorldY, WorldZ, CP_Tunnel, CP_TunnelFP, LayoutVersion,
|
||||
/*bApplyLegacyStructuralPosts=*/false,
|
||||
&FusedTunnelCore,
|
||||
/*bCollectFusedDiagnostics=*/true);
|
||||
/*bCollectFusedDiagnostics=*/true,
|
||||
&bRoomOwnsBottom);
|
||||
bRoomOwnsBottomValid = true;
|
||||
}
|
||||
|
||||
const bool bIntegerLatticePoint =
|
||||
@@ -3432,9 +3438,14 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
case ECaveGeneratorType::TunnelNetwork:
|
||||
default:
|
||||
// Underwater shares tunnel rock (water table is a render-side overlay).
|
||||
Result = GetDensityWithParams(WorldX, WorldY, WorldZ, CP_Tunnel,
|
||||
Result = GetDensityWithParams(WorldX, WorldY, WorldZ, CP_Tunnel,
|
||||
CP_TunnelFP, LayoutVersion,
|
||||
/*bApplyLegacyStructuralPosts=*/false); break;
|
||||
/*bApplyLegacyStructuralPosts=*/false,
|
||||
nullptr, false, &bRoomOwnsBottom,
|
||||
&NativeWarpedPosition);
|
||||
bRoomOwnsBottomValid = true;
|
||||
bNativeWarpedPositionValid = true;
|
||||
break;
|
||||
}
|
||||
DensityCoreTimer.End();
|
||||
|
||||
@@ -3475,18 +3486,27 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
{
|
||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
||||
FVector RoomQueryPosition(WorldX, WorldY, WorldZ);
|
||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||
FVector RoomQueryPosition;
|
||||
if (bNativeWarpedPositionValid)
|
||||
{
|
||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||
RoomQueryPosition = NativeWarpedPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
RoomQueryPosition = FVector(WorldX, WorldY, WorldZ);
|
||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||
{
|
||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||
}
|
||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||
}
|
||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||
PreDisturbanceTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache, nullptr,
|
||||
VoxelGenLOD::ShouldUseSpatialIndex(
|
||||
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
||||
&RoomQueryPosition);
|
||||
&RoomQueryPosition,
|
||||
bRoomOwnsBottomValid ? &bRoomOwnsBottom : nullptr);
|
||||
bHavePreDisturbanceTunnelCore = true;
|
||||
}
|
||||
|
||||
@@ -3679,19 +3699,28 @@ float UVoxelGenerator::GetDensityAt(float WorldX, float WorldY, float WorldZ) co
|
||||
{
|
||||
VoxelDensityProfile::FScopedTimer ProfileTimer(
|
||||
VoxelDensityProfile::EBucket::TunnelCorePosts);
|
||||
FVector RoomQueryPosition(WorldX, WorldY, WorldZ);
|
||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||
FVector RoomQueryPosition;
|
||||
if (bNativeWarpedPositionValid)
|
||||
{
|
||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||
RoomQueryPosition = NativeWarpedPosition;
|
||||
}
|
||||
else
|
||||
{
|
||||
RoomQueryPosition = FVector(WorldX, WorldY, WorldZ);
|
||||
if (CP_Tunnel.VerticalScale != 1.0f && CP_Tunnel.VerticalScale > 0.0f)
|
||||
{
|
||||
RoomQueryPosition.Z = WorldZ / CP_Tunnel.VerticalScale;
|
||||
}
|
||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||
}
|
||||
RoomQueryPosition = VoxelCaveMorphology::ApplyCaveWarp(
|
||||
RoomQueryPosition, CP_Tunnel, static_cast<uint32>(Seed));
|
||||
TunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, ActiveTunnelCoreCache->Cache,
|
||||
nullptr,
|
||||
VoxelGenLOD::ShouldUseSpatialIndex(
|
||||
CP_UseOpStack ? bUsedFusedEvaluator : true),
|
||||
&RoomQueryPosition);
|
||||
&RoomQueryPosition,
|
||||
bRoomOwnsBottomValid ? &bRoomOwnsBottom : nullptr);
|
||||
bHaveTunnelCore = true;
|
||||
}
|
||||
if (bHaveTunnelCore)
|
||||
@@ -3828,7 +3857,9 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
||||
uint32 ParamsFingerprint, uint32 LayoutVersion,
|
||||
bool bApplyLegacyStructuralPosts,
|
||||
FTunnelCoreWorldEvaluation* OutTunnelCore,
|
||||
bool bCollectFusedDiagnostics) const
|
||||
bool bCollectFusedDiagnostics,
|
||||
bool* OutRoomOwnsBottom,
|
||||
FVector* OutWarpedPosition) const
|
||||
{
|
||||
//=========================================================================
|
||||
// STRATE DENSITY FUNCTION (Morphology Pipeline)
|
||||
@@ -3859,6 +3890,14 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
||||
{
|
||||
*OutTunnelCore = FTunnelCoreWorldEvaluation();
|
||||
}
|
||||
if (OutRoomOwnsBottom != nullptr)
|
||||
{
|
||||
*OutRoomOwnsBottom = false;
|
||||
}
|
||||
if (OutWarpedPosition != nullptr)
|
||||
{
|
||||
*OutWarpedPosition = FVector::ZeroVector;
|
||||
}
|
||||
if (bCollectFusedDiagnostics && VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
@@ -3930,6 +3969,10 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
||||
WarpedY += WarpY * VOXEL_NOISE_SCALE * WS;
|
||||
WarpedZ += WarpZ * VOXEL_NOISE_SCALE * WS;
|
||||
}
|
||||
if (OutWarpedPosition != nullptr)
|
||||
{
|
||||
*OutWarpedPosition = FVector(WarpedX, WarpedY, WarpedZ);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// STEP 4: SDF MORPHOLOGY (rooms + tunnels) — CACHED PER CHUNK
|
||||
@@ -4187,7 +4230,8 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
||||
SDFCache, Params.SDFBlendRadius,
|
||||
&NearestRoomIdx,
|
||||
bUseSpatialIndex,
|
||||
&WorldTunnelPosition
|
||||
&WorldTunnelPosition,
|
||||
OutRoomOwnsBottom
|
||||
);
|
||||
|
||||
// ── PIT & CHIMNEY SDF INTEGRATION ──
|
||||
@@ -4307,7 +4351,7 @@ float UVoxelGenerator::GetDensityWithParams(float WorldX, float WorldY, float Wo
|
||||
const FVector RoomQueryPosition(WarpedX, WarpedY, WarpedZ);
|
||||
*OutTunnelCore = VoxelCaveMorphology::EvaluateTunnelCoreWorld(
|
||||
WorldX, WorldY, WorldZ, SDFCache, nullptr, bUseSpatialIndex,
|
||||
&RoomQueryPosition);
|
||||
&RoomQueryPosition, OutRoomOwnsBottom);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -1049,6 +1049,10 @@ namespace VoxelCaveMorphology
|
||||
// supplied, rooms remain at the query position but the tunnel
|
||||
// uses its authored world chain. Null preserves the legacy
|
||||
// all-query behavior.
|
||||
// @param OutRoomOwnsBottom — optional out: true when the query position is inside any
|
||||
// cached room's raw authored shape. When the caller evaluates
|
||||
// the tunnel core for this same sample, pass this result back
|
||||
// to EvaluateTunnelCoreWorld to avoid a second room query.
|
||||
// (Room shape variety is baked into FCachedRoom by BuildChunkCache — no per-voxel roll.)
|
||||
// @return negative = inside cave, positive = solid rock
|
||||
VOXELFORGE_API float EvaluateSDFCached(
|
||||
@@ -1057,7 +1061,8 @@ namespace VoxelCaveMorphology
|
||||
float SDFBlendRadius,
|
||||
int32* OutNearestRoomIdx = nullptr,
|
||||
bool bUseSpatialIndex = true,
|
||||
const FVector* WorldTunnelPosition = nullptr
|
||||
const FVector* WorldTunnelPosition = nullptr,
|
||||
bool* OutRoomOwnsBottom = nullptr
|
||||
);
|
||||
|
||||
// Evaluate the raw union of cached graph-tunnel capsules. This is intentionally separate from
|
||||
@@ -1087,7 +1092,10 @@ namespace VoxelCaveMorphology
|
||||
// The room graph is evaluated in warped coordinates while the tunnel core is evaluated in
|
||||
// the authored world frame. Pass the former when available so room ownership is tested in
|
||||
// the same domain as the generic room field.
|
||||
const FVector* RoomQueryPosition = nullptr
|
||||
const FVector* RoomQueryPosition = nullptr,
|
||||
// Optional result from EvaluateSDFCached for this exact sample. When supplied, it avoids
|
||||
// repeating the room-shape containment query; null preserves standalone-call behavior.
|
||||
const bool* CachedRoomOwnsBottom = nullptr
|
||||
);
|
||||
|
||||
// Per-tile broad reach for the world-space core/floor post. The bound includes the swept
|
||||
|
||||
@@ -240,7 +240,14 @@ public:
|
||||
FTunnelCoreWorldEvaluation* OutTunnelCore = nullptr,
|
||||
// Diagnostics are opt-in so ordinary/reference calls do not pay
|
||||
// for fused-path counters.
|
||||
bool bCollectFusedDiagnostics = false) const;
|
||||
bool bCollectFusedDiagnostics = false,
|
||||
// Optional same-sample hand-off from EvaluateSDFCached. This is
|
||||
// only a room-shape ownership bit; it does not alter the scalar
|
||||
// result and avoids a duplicate room-index query in native paths.
|
||||
bool* OutRoomOwnsBottom = nullptr,
|
||||
// Optional same-sample warped position. Native GetDensityAt uses
|
||||
// this to feed the core post without applying the cave warp twice.
|
||||
FVector* OutWarpedPosition = nullptr) const;
|
||||
|
||||
/**
|
||||
* Densité pour une strate Slab (FlatPlain / CrystalChamber).
|
||||
|
||||
Reference in new issue
Block a user