measure(step2c): setup once per chunk, still 1.6 us/sample -- exact per-sample density misses 600 ms
Editor-only, default off. 259^3 ring split into 1,000 aligned 32^3 chunks; cache/index builds bounded by chunks (948 room/SDF caches, 800 active-op lists, 8,532 index tables); 800 block setups + 201,243 scalar fallback points (1.16%); no per-point GetDensityAt on supported routes. Six workers: live 7.07 s wall / 1.678 us per sample; prepared 7.92 s / 1.595 us. Candidate visits 21.2 -> 15.8 per sample, evaluations 6.31 -> 5.75; room / tunnel / tunnel-core evaluations unchanged (48.1 M / 5.0 M / 38.4 M for 17.4 M samples). Passage evals 18.1 M -> 8.4 M. Exact: 0 Q16/sign disagreements, five seeds, same hash on 1 and 6 workers, reach shrink caught. Luna's verdict: 600 ms is not reachable while every lattice point evaluates the exact current density; 27.7 worker-CPU seconds need >= 7.7x less work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
1 parent
fd9f809c1c
commit
43c11ccaa8
9 files changed
+484
-143
No files matched your search
@@ -1416,6 +1416,11 @@ namespace
|
||||
static void VF_BuildSpatialIndex(
|
||||
FChunkSDFSpatialIndex& OutIndex, int32 ItemCount, FGetBounds&& GetBounds)
|
||||
{
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::SdfSpatialIndexBuild);
|
||||
}
|
||||
OutIndex.Reset();
|
||||
if (ItemCount <= 0)
|
||||
{
|
||||
@@ -1811,6 +1816,11 @@ namespace
|
||||
static void VF_BuildBrickIndex(
|
||||
FChunkSDFBrickIndex& OutIndex, int32 ItemCount, FGetBounds&& GetBounds)
|
||||
{
|
||||
if (VoxelDensityProfile::AreCountersEnabled())
|
||||
{
|
||||
VoxelDensityProfile::AddCounter(
|
||||
VoxelDensityProfile::ECounter::SdfBrickIndexBuild);
|
||||
}
|
||||
OutIndex.Reset();
|
||||
if (ItemCount <= 0)
|
||||
{
|
||||
|
||||
@@ -640,6 +640,8 @@ namespace VoxelDensityProfile
|
||||
case ECounter::TunnelCacheHit: return TEXT("TunnelCacheHit");
|
||||
case ECounter::TunnelCacheMiss: return TEXT("TunnelCacheMiss");
|
||||
case ECounter::SdfCacheBuild: return TEXT("SdfCacheBuild");
|
||||
case ECounter::SdfSpatialIndexBuild: return TEXT("SdfSpatialIndexBuild");
|
||||
case ECounter::SdfBrickIndexBuild: return TEXT("SdfBrickIndexBuild");
|
||||
case ECounter::RoomGraphBuildGeneratorTile: return TEXT("RoomGraphBuildGeneratorTile");
|
||||
case ECounter::RoomGraphBuildGeneratorTunnelCore: return TEXT("RoomGraphBuildGeneratorTunnelCore");
|
||||
case ECounter::RoomGraphBuildOpShared: return TEXT("RoomGraphBuildOpShared");
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace VoxelMath
|
||||
|
||||
namespace
|
||||
{
|
||||
#if WITH_EDITOR
|
||||
thread_local bool GVoxelResearchRegionCacheWindowEnabled = false;
|
||||
#endif
|
||||
// The default-on branch uses VoxelMath::IsFiniteFast, while 0 retains the original
|
||||
// FMath::IsFinite call for a real within-round A/B and sampler comparison.
|
||||
FAutoConsoleVariableRef CVarVoxelForgeFastIsFinite(
|
||||
@@ -884,6 +887,12 @@ bool VoxelGenLOD::IsTileCacheWindowEnabled(bool bFusedPath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#if WITH_EDITOR
|
||||
if (GVoxelResearchRegionCacheWindowEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
const int32 RequiredMinLOD = bFusedPath
|
||||
? GVoxelForgeTileCacheWindowMinLOD
|
||||
: GVoxelForgeTileCacheWindowOpStackMinLOD;
|
||||
@@ -891,6 +900,13 @@ bool VoxelGenLOD::IsTileCacheWindowEnabled(bool bFusedPath)
|
||||
return FMath::Max(SampleStep, 1) >= RequiredStep;
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
void VoxelGenLOD::SetResearchRegionCacheWindowEnabled(bool bEnabled)
|
||||
{
|
||||
GVoxelResearchRegionCacheWindowEnabled = bEnabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool VoxelGenLOD::GetThreadTileCacheWindow(
|
||||
FIntVector& OutOriginVoxels, int32& OutStep, int32& OutCellsPerAxis)
|
||||
{
|
||||
@@ -2722,15 +2738,19 @@ void UVoxelGenerator::EndDensityBlock() const
|
||||
}
|
||||
|
||||
#if WITH_EDITOR
|
||||
bool UVoxelGenerator::EvaluateDensityBrick(
|
||||
bool UVoxelGenerator::EvaluateDensityChunk(
|
||||
FIntVector OriginVoxels, int32 SizeX, int32 SizeY, int32 SizeZ,
|
||||
TArray<float>& OutDensities, int32& OutFallbackSamples) const
|
||||
TArray<float>& OutDensities, int32& OutFallbackSamples,
|
||||
uint64& OutGeneralPathEntries, uint64& OutSupportedBlockSetupEntries) const
|
||||
{
|
||||
OutDensities.Reset();
|
||||
OutFallbackSamples = 0;
|
||||
OutGeneralPathEntries = 0;
|
||||
OutSupportedBlockSetupEntries = 0;
|
||||
const int64 SampleCount64 = static_cast<int64>(SizeX) * SizeY * SizeZ;
|
||||
if (SizeX <= 0 || SizeY <= 0 || SizeZ <= 0
|
||||
|| SizeX > 8 || SizeY > 8 || SizeZ > 8 || SampleCount64 > 512)
|
||||
|| SizeX > CHUNK_SIZE || SizeY > CHUNK_SIZE || SizeZ > CHUNK_SIZE
|
||||
|| SampleCount64 > static_cast<int64>(CHUNK_SIZE) * CHUNK_SIZE * CHUNK_SIZE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -2741,10 +2761,7 @@ bool UVoxelGenerator::EvaluateDensityBrick(
|
||||
return FMath::FloorToInt(static_cast<float>(A) / static_cast<float>(CellSize))
|
||||
== FMath::FloorToInt(static_cast<float>(B) / static_cast<float>(CellSize));
|
||||
};
|
||||
if (!SameCell(OriginVoxels.X, Last.X, 8)
|
||||
|| !SameCell(OriginVoxels.Y, Last.Y, 8)
|
||||
|| !SameCell(OriginVoxels.Z, Last.Z, 8)
|
||||
|| !SameCell(OriginVoxels.X, Last.X, CHUNK_SIZE)
|
||||
if (!SameCell(OriginVoxels.X, Last.X, CHUNK_SIZE)
|
||||
|| !SameCell(OriginVoxels.Y, Last.Y, CHUNK_SIZE)
|
||||
|| !SameCell(OriginVoxels.Z, Last.Z, CHUNK_SIZE))
|
||||
{
|
||||
@@ -2761,17 +2778,19 @@ bool UVoxelGenerator::EvaluateDensityBrick(
|
||||
static_cast<float>(OriginVoxels.X),
|
||||
static_cast<float>(OriginVoxels.Y),
|
||||
static_cast<float>(OriginVoxels.Z));
|
||||
OutGeneralPathEntries = 1;
|
||||
if (GVoxelDensityBlockSession.bBatchSucceeded)
|
||||
{
|
||||
OutDensities.SetNumUninitialized(SampleCount);
|
||||
FMemory::Memcpy(
|
||||
OutDensities.GetData(), GVoxelDensityBlockSession.BatchResults.GetData(),
|
||||
static_cast<SIZE_T>(SampleCount) * sizeof(float));
|
||||
OutSupportedBlockSetupEntries = 1;
|
||||
EndDensityBlock();
|
||||
return OutDensities.Num() == SampleCount;
|
||||
}
|
||||
|
||||
// Recipes without the editor brick port retain the canonical point evaluator. The first
|
||||
// Routes without the editor block program retain the canonical point evaluator. The first
|
||||
// call already produced point zero; the remaining samples are explicit counted fallbacks.
|
||||
GVoxelDensityBlockSession.bBatchRequested = false;
|
||||
OutDensities.SetNumUninitialized(SampleCount);
|
||||
@@ -2787,6 +2806,7 @@ bool UVoxelGenerator::EvaluateDensityBrick(
|
||||
static_cast<float>(OriginVoxels.Z + Z));
|
||||
}
|
||||
OutFallbackSamples = SampleCount;
|
||||
OutGeneralPathEntries = static_cast<uint64>(SampleCount);
|
||||
EndDensityBlock();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -106,6 +106,8 @@ namespace VoxelDensityProfile
|
||||
TunnelCacheHit,
|
||||
TunnelCacheMiss,
|
||||
SdfCacheBuild,
|
||||
SdfSpatialIndexBuild,
|
||||
SdfBrickIndexBuild,
|
||||
RoomGraphBuildGeneratorTile,
|
||||
RoomGraphBuildGeneratorTunnelCore,
|
||||
RoomGraphBuildOpShared,
|
||||
|
||||
@@ -77,6 +77,10 @@ namespace VoxelGenLOD
|
||||
// Called by the module's game-thread startup before any worker can enter GetDensityAt.
|
||||
VOXELFORGE_API void InitializeConsoleSwitches();
|
||||
VOXELFORGE_API bool IsTileCacheWindowEnabled(bool bFusedPath = true);
|
||||
#if WITH_EDITOR
|
||||
/** Research-only override for the bounded editor region evaluator; default false per thread. */
|
||||
VOXELFORGE_API void SetResearchRegionCacheWindowEnabled(bool bEnabled);
|
||||
#endif
|
||||
VOXELFORGE_API bool GetThreadTileCacheWindow(
|
||||
FIntVector& OutOriginVoxels, int32& OutStep, int32& OutCellsPerAxis);
|
||||
VOXELFORGE_API void SetThreadTileContext(
|
||||
@@ -181,10 +185,11 @@ public:
|
||||
void EndDensityBlock() const;
|
||||
|
||||
#if WITH_EDITOR
|
||||
/** Editor-only region-program entry point; unsupported routes report live point fallbacks. */
|
||||
bool EvaluateDensityBrick(FIntVector OriginVoxels, int32 SizeX, int32 SizeY, int32 SizeZ,
|
||||
TArray<float>& OutDensities,
|
||||
int32& OutFallbackSamples) const;
|
||||
/** Editor-only chunk program; supported routes enter GetDensityAt once to seed a whole block. */
|
||||
bool EvaluateDensityChunk(FIntVector OriginVoxels, int32 SizeX, int32 SizeY, int32 SizeZ,
|
||||
TArray<float>& OutDensities, int32& OutFallbackSamples,
|
||||
uint64& OutGeneralPathEntries,
|
||||
uint64& OutSupportedBlockSetupEntries) const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user