core: stamp passage route slabs into the tile cache (L125, evaluator v225)
Conservative route slabs with an outside sentinel, tight expanded segment bounds; DensityGrid exact fallbacks 479k -> 0 per run. Near-ready 2-14% faster than L119, still +4.7..+10.2% vs L109; whole view within -0.5..+8%. Same look (floor offset 7.884 mm, captures checked), seam audit bit-identical, fast tier + walk audits, Clang/GCC W1/W8/W12 determinism green. BVH and 25 cm tolerance trials rejected. Not for merge yet. 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
103fa75e1c
commit
4111b967bd
40 files changed
+2748
-28
No files matched your search
@@ -155,11 +155,27 @@ namespace VoxelForgeCore
|
||||
std::uint64_t passageSweepDetailShellSamples = 0;
|
||||
std::uint64_t passageSweepGridSamples = 0;
|
||||
std::uint64_t passageSweepNoInfluenceGridSamples = 0;
|
||||
std::uint64_t passageSweepTouchedSamples = 0;
|
||||
std::uint64_t passageSweepStampedOutsideSamples = 0;
|
||||
std::uint64_t passageSweepCacheValidSamples = 0;
|
||||
std::uint64_t passageSweepCacheValidUniqueSamples = 0;
|
||||
std::uint64_t passageSweepUniqueTouchedSamples = 0;
|
||||
std::uint64_t passageSweepBodyBandSamples = 0;
|
||||
std::uint64_t passageSweepShellBandSamples = 0;
|
||||
std::uint64_t passageSweepUniqueBandSamples = 0;
|
||||
std::uint64_t passageSweepOverlapPairs = 0;
|
||||
std::uint64_t passageSweepContributingPairs = 0;
|
||||
std::uint64_t passageSweepCrossPassageOverlaps = 0;
|
||||
std::uint64_t passageSweepFloorProfileCalls = 0;
|
||||
std::uint64_t passageSweepAllocatedBytes = 0;
|
||||
std::uint64_t passageSweepPrepareScratchBytes = 0;
|
||||
std::uint64_t passageSweepLookups = 0;
|
||||
std::uint64_t passageSweepCacheHits = 0;
|
||||
std::uint64_t passageSweepBaseInfluenceHits = 0;
|
||||
std::uint64_t passageSweepOutOfInfluenceHits = 0;
|
||||
std::uint64_t passageSweepMissingSamples = 0;
|
||||
std::uint64_t passageSweepOffGridMisses = 0;
|
||||
std::uint64_t passageSweepUnpreparedMisses = 0;
|
||||
std::array<std::uint64_t,12> passageSweepMissingLookupsByCaller{};
|
||||
std::array<std::uint64_t,12> passageSweepExactRouteFallbacksByCaller{};
|
||||
std::array<std::uint64_t,12> passageSweepFeatureBoundSkipsByCaller{};
|
||||
@@ -478,7 +494,7 @@ namespace VoxelForgeCore
|
||||
// Version 223 projects the floor onto one continuous arc-length profile and groups
|
||||
// dense passage samples into coarse tile candidates. Version 224 keeps the same
|
||||
// continuous floor while relaxing the spline chord tolerance and bounding shell work.
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 224;
|
||||
inline constexpr std::uint32_t WorldAssemblyEvaluatorVersion = 225;
|
||||
|
||||
enum class FieldChannel : std::uint32_t
|
||||
{
|
||||
|
||||
@@ -272,7 +272,7 @@ public:
|
||||
std::uint32_t segmentIndex=std::numeric_limits<std::uint32_t>::max();
|
||||
std::uint32_t floorSegmentIndex=std::numeric_limits<std::uint32_t>::max();
|
||||
float wallRelief=0.0f;
|
||||
bool valid=false,hasWallRelief=false;
|
||||
bool valid=false,hasWallRelief=false,hasExactContribution=false;
|
||||
};
|
||||
struct FPassageTileSweepData
|
||||
{
|
||||
@@ -288,7 +288,8 @@ public:
|
||||
std::vector<std::int32_t> passageToSweep;
|
||||
std::vector<FPassageSamples> passages;
|
||||
std::atomic<std::uint64_t> lookups{0},cacheHits{0},baseInfluenceHits{0},
|
||||
outOfInfluenceHits{0},missingSamples{0};
|
||||
outOfInfluenceHits{0},missingSamples{0},offGridMisses{0},
|
||||
unpreparedMisses{0};
|
||||
std::array<std::atomic<std::uint64_t>,PassageDensityQueryCallerCount>
|
||||
missingLookupsByCaller{},exactRouteFallbacksByCaller{},
|
||||
featureBoundSkipsByCaller{},tileFreeSkipsByCaller{},
|
||||
@@ -389,6 +390,10 @@ public:
|
||||
passageSweepData_->outOfInfluenceHits.load(std::memory_order_relaxed);
|
||||
profileStats_->passageSweepMissingSamples=passageSweepData_->missingSamples.load(
|
||||
std::memory_order_relaxed);
|
||||
profileStats_->passageSweepOffGridMisses=passageSweepData_->offGridMisses.load(
|
||||
std::memory_order_relaxed);
|
||||
profileStats_->passageSweepUnpreparedMisses=
|
||||
passageSweepData_->unpreparedMisses.load(std::memory_order_relaxed);
|
||||
for(std::size_t caller=0;caller<PassageDensityQueryCallerCount;++caller)
|
||||
{
|
||||
profileStats_->passageSweepMissingLookupsByCaller[caller]=
|
||||
@@ -11459,10 +11464,17 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
||||
sweep->passageToSweep.assign(passageRouteSegments_.size(),-1);
|
||||
std::vector<std::uint8_t> anyPassageInfluence(gridSampleCount,0);
|
||||
std::vector<std::uint8_t> anyPreparedSample(profile?gridSampleCount:0,0);
|
||||
std::vector<std::uint8_t> anyCacheValidSample(profile?gridSampleCount:0,0);
|
||||
std::vector<std::uint8_t> anyExactBandSample(profile?gridSampleCount:0,0);
|
||||
std::uint64_t preparedSampleCount=0,stampedOutsideSampleCount=0,
|
||||
cacheValidSampleCount=0,contributingPairCount=0,
|
||||
bodyBandSampleCount=0,shellBandSampleCount=0;
|
||||
const double qPerMetre=static_cast<double>(Q)*1000000.0/
|
||||
std::max<std::uint32_t>(1,shape_->ResolvedLayout
|
||||
?shape_->ResolvedLayout->coreVoxelSizeMicrometres:250000);
|
||||
const double shellThickness=0.75*qPerMetre;
|
||||
const double stampedOutsideDistance=sweep->influenceSubvoxels+1.0;
|
||||
constexpr double MouthShellBlendMetres=5.0;
|
||||
const double wallReliefShell=0.41*qPerMetre;
|
||||
const double floorDetailShell=1.0*qPerMetre;
|
||||
@@ -11507,28 +11519,73 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
candidate.sweepMaximumSubvoxels[axis],first[axis],last[axis]);
|
||||
if(first[0]>last[0]||first[1]>last[1]||first[2]>last[2])continue;
|
||||
|
||||
// Stamp the conservative route feature slab once. Segment geometry below
|
||||
// visits its own tight expanded bounds, avoiding the old feature-box x
|
||||
// segment-count scan.
|
||||
for(std::int32_t gz=first[2];gz<=last[2];++gz)
|
||||
{
|
||||
for(std::int32_t gy=first[1];gy<=last[1];++gy)
|
||||
for(std::int32_t gx=first[0];gx<=last[0];++gx)
|
||||
{
|
||||
const double qz=static_cast<double>(sweep->gridMinimumSubvoxels[2]
|
||||
+static_cast<std::int64_t>(gz)*sweep->stepSubvoxels);
|
||||
const std::size_t sampleIndex=(static_cast<std::size_t>(gz)
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gy))
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gx);
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
// Every grid sample inside a conservative feature slab has a known
|
||||
// outside value unless a segment contributes within the prepared
|
||||
// influence. This makes slab gaps cheap rock instead of cache misses.
|
||||
if(!sample.valid)
|
||||
{
|
||||
sample.signedDistance=stampedOutsideDistance;
|
||||
sample.shellSignedDistance=stampedOutsideDistance;
|
||||
sample.roundSignedDistance=stampedOutsideDistance;
|
||||
sample.centerZSubvoxels=qz;
|
||||
sample.floorCenterZSubvoxels=qz;
|
||||
sample.radiusSubvoxels=0.0;
|
||||
sample.floorDepthSubvoxels=0.0;
|
||||
sample.floorCenterDistanceSq=std::numeric_limits<double>::infinity();
|
||||
sample.t=0.0;
|
||||
sample.floorT=0.0;
|
||||
sample.segmentIndex=static_cast<std::uint32_t>(candidate.segmentIndex);
|
||||
sample.floorSegmentIndex=static_cast<std::uint32_t>(candidate.segmentIndex);
|
||||
sample.wallRelief=0.0f;
|
||||
sample.valid=true;
|
||||
sample.hasWallRelief=false;
|
||||
sample.hasExactContribution=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(std::size_t segmentIndex=candidate.segmentIndex;
|
||||
segmentIndex<segmentEndIndex;++segmentIndex)
|
||||
{
|
||||
const auto& segment=segments[segmentIndex];
|
||||
if(segment.lengthSq<=0.0)continue;
|
||||
std::array<std::int32_t,3> segmentFirst{},segmentLast{};
|
||||
for(std::size_t axis=0;axis<3;++axis)
|
||||
gridRange(axis,segment.sweepMinimumSubvoxels[axis],
|
||||
segment.sweepMaximumSubvoxels[axis],
|
||||
segmentFirst[axis],segmentLast[axis]);
|
||||
if(segmentFirst[0]>segmentLast[0]
|
||||
||segmentFirst[1]>segmentLast[1]
|
||||
||segmentFirst[2]>segmentLast[2])continue;
|
||||
for(std::int32_t gz=segmentFirst[2];gz<=segmentLast[2];++gz)
|
||||
{
|
||||
for(std::int32_t gy=segmentFirst[1];gy<=segmentLast[1];++gy)
|
||||
for(std::int32_t gx=segmentFirst[0];gx<=segmentLast[0];++gx)
|
||||
{
|
||||
const double qx=static_cast<double>(sweep->gridMinimumSubvoxels[0]
|
||||
+static_cast<std::int64_t>(gx)*sweep->stepSubvoxels);
|
||||
const double qy=static_cast<double>(sweep->gridMinimumSubvoxels[1]
|
||||
+static_cast<std::int64_t>(gy)*sweep->stepSubvoxels);
|
||||
const double qz=static_cast<double>(sweep->gridMinimumSubvoxels[2]
|
||||
+static_cast<std::int64_t>(gz)*sweep->stepSubvoxels);
|
||||
for(std::size_t segmentIndex=candidate.segmentIndex;
|
||||
segmentIndex<segmentEndIndex;++segmentIndex)
|
||||
{
|
||||
const auto& segment=segments[segmentIndex];
|
||||
if(segment.lengthSq<=0.0
|
||||
||qx<segment.sweepMinimumSubvoxels[0]
|
||||
||qx>segment.sweepMaximumSubvoxels[0]
|
||||
||qy<segment.sweepMinimumSubvoxels[1]
|
||||
||qy>segment.sweepMaximumSubvoxels[1]
|
||||
||qz<segment.sweepMinimumSubvoxels[2]
|
||||
||qz>segment.sweepMaximumSubvoxels[2])continue;
|
||||
const std::size_t sampleIndex=(static_cast<std::size_t>(gz)
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gy))
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gx);
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
const double projectionXY=(qx-segment.a[0])*segment.delta[0]
|
||||
+(qy-segment.a[1])*segment.delta[1];
|
||||
const double t=std::clamp((projectionXY
|
||||
@@ -11540,6 +11597,8 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
const double ex=qx-cx,ey=qy-cy,ez=qz-cz;
|
||||
const double signedDistance=FStandaloneShapeWorld::DeterministicSqrt(
|
||||
ex*ex+ey*ey+ez*ez)-radius;
|
||||
if(profile&&signedDistance<sweep->influenceSubvoxels+1.0)
|
||||
++contributingPairCount;
|
||||
const double floorT=segment.horizontalLengthSq>1.0e-12
|
||||
?projectionXY/segment.horizontalLengthSq:t;
|
||||
const double floorTClamped=std::clamp(floorT,0.0,1.0);
|
||||
@@ -11557,10 +11616,6 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
{
|
||||
if(profile)++profileStats_->passageSweepOutsideInfluencePairs;
|
||||
}
|
||||
const std::size_t sampleIndex=(static_cast<std::size_t>(gz)
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gy))
|
||||
*static_cast<std::size_t>(sweep->dimension)+static_cast<std::size_t>(gx);
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
if(floorCenterDistanceSq<sample.floorCenterDistanceSq
|
||||
||(floorCenterDistanceSq==sample.floorCenterDistanceSq
|
||||
&&segmentIndex<sample.floorSegmentIndex))
|
||||
@@ -11637,9 +11692,11 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
++profileStats_->passageSweepShellSupportSkips;
|
||||
// Rank the tube body by round SDF. Its floor plane is selected
|
||||
// independently above from the nearest centerline position.
|
||||
if(!sample.valid||signedDistance<sample.roundSignedDistance
|
||||
||(signedDistance==sample.roundSignedDistance
|
||||
&&segmentIndex<sample.segmentIndex))
|
||||
if(signedDistance<stampedOutsideDistance
|
||||
&&(!sample.hasExactContribution
|
||||
||signedDistance<sample.roundSignedDistance
|
||||
||(signedDistance==sample.roundSignedDistance
|
||||
&&segmentIndex<sample.segmentIndex)))
|
||||
{
|
||||
sample.roundSignedDistance=signedDistance;
|
||||
sample.centerZSubvoxels=cz;
|
||||
@@ -11648,9 +11705,10 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
sample.segmentIndex=static_cast<std::uint32_t>(segmentIndex);
|
||||
sample.valid=true;
|
||||
sample.hasWallRelief=false;
|
||||
sample.hasExactContribution=true;
|
||||
if(profile)++profileStats_->passageSweepMinimumUpdates;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11665,6 +11723,23 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
{
|
||||
auto& sample=passageSamples.samples[sampleIndex];
|
||||
if(!sample.valid)continue;
|
||||
if(profile)
|
||||
{
|
||||
++cacheValidSampleCount;
|
||||
anyCacheValidSample[sampleIndex]=1;
|
||||
}
|
||||
if(!sample.hasExactContribution)
|
||||
{
|
||||
if(profile)++stampedOutsideSampleCount;
|
||||
sample.signedDistance=stampedOutsideDistance;
|
||||
sample.shellSignedDistance=stampedOutsideDistance;
|
||||
continue;
|
||||
}
|
||||
if(profile)
|
||||
{
|
||||
++preparedSampleCount;
|
||||
anyPreparedSample[sampleIndex]=1;
|
||||
}
|
||||
const std::int32_t gx=static_cast<std::int32_t>(sampleIndex
|
||||
%static_cast<std::size_t>(sweep->dimension));
|
||||
const std::int32_t gy=static_cast<std::int32_t>((sampleIndex
|
||||
@@ -11682,6 +11757,17 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
sample.signedDistance=FStandaloneShapeWorld::PassageFlatBottomDistance(
|
||||
static_cast<float>(sample.roundSignedDistance),
|
||||
sample.floorCenterZSubvoxels,qz,sample.floorDepthSubvoxels,qPerMetre);
|
||||
if(profile&&std::abs(sample.signedDistance)<=sweep->stepSubvoxels)
|
||||
{
|
||||
++bodyBandSampleCount;
|
||||
anyExactBandSample[sampleIndex]=1;
|
||||
}
|
||||
if(profile&&std::isfinite(sample.shellSignedDistance)
|
||||
&&std::abs(sample.shellSignedDistance)<=sweep->stepSubvoxels)
|
||||
{
|
||||
++shellBandSampleCount;
|
||||
anyExactBandSample[sampleIndex]=1;
|
||||
}
|
||||
const double radius=sample.radiusSubvoxels;
|
||||
const double centerZ=sample.centerZSubvoxels;
|
||||
if(sample.signedDistance<=sweep->influenceSubvoxels)
|
||||
@@ -11710,6 +11796,38 @@ inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBa
|
||||
profileStats_->passageSweepNoInfluenceGridSamples=
|
||||
static_cast<std::uint64_t>(std::count(anyPassageInfluence.begin(),
|
||||
anyPassageInfluence.end(),static_cast<std::uint8_t>(0)));
|
||||
profileStats_->passageSweepTouchedSamples=preparedSampleCount;
|
||||
profileStats_->passageSweepStampedOutsideSamples=stampedOutsideSampleCount;
|
||||
profileStats_->passageSweepCacheValidSamples=cacheValidSampleCount;
|
||||
profileStats_->passageSweepCacheValidUniqueSamples=
|
||||
static_cast<std::uint64_t>(std::count(anyCacheValidSample.begin(),
|
||||
anyCacheValidSample.end(),static_cast<std::uint8_t>(1)));
|
||||
profileStats_->passageSweepUniqueTouchedSamples=
|
||||
static_cast<std::uint64_t>(std::count(anyPreparedSample.begin(),
|
||||
anyPreparedSample.end(),static_cast<std::uint8_t>(1)));
|
||||
profileStats_->passageSweepBodyBandSamples=bodyBandSampleCount;
|
||||
profileStats_->passageSweepShellBandSamples=shellBandSampleCount;
|
||||
profileStats_->passageSweepUniqueBandSamples=
|
||||
static_cast<std::uint64_t>(std::count(anyExactBandSample.begin(),
|
||||
anyExactBandSample.end(),static_cast<std::uint8_t>(1)));
|
||||
profileStats_->passageSweepContributingPairs=contributingPairCount;
|
||||
profileStats_->passageSweepOverlapPairs=contributingPairCount
|
||||
>=preparedSampleCount
|
||||
?contributingPairCount-preparedSampleCount:0;
|
||||
profileStats_->passageSweepCrossPassageOverlaps=preparedSampleCount
|
||||
>=profileStats_->passageSweepUniqueTouchedSamples
|
||||
?preparedSampleCount-profileStats_->passageSweepUniqueTouchedSamples:0;
|
||||
profileStats_->passageSweepFloorProfileCalls=
|
||||
profileStats_->passageSweepSegmentSamplePairs;
|
||||
std::uint64_t allocatedBytes=sizeof(*sweep)
|
||||
+sweep->passageToSweep.capacity()*sizeof(std::int32_t)
|
||||
+sweep->passages.capacity()*sizeof(FPassageTileSweepData::FPassageSamples);
|
||||
for(const auto& passageSamples:sweep->passages)
|
||||
allocatedBytes+=passageSamples.samples.capacity()
|
||||
*sizeof(FPassageSweepSample);
|
||||
profileStats_->passageSweepAllocatedBytes=allocatedBytes;
|
||||
profileStats_->passageSweepPrepareScratchBytes=gridSampleCount
|
||||
*(sizeof(std::uint8_t)*4);
|
||||
profileStats_->passageSweepPrepareNanoseconds+=static_cast<std::uint64_t>(
|
||||
std::max<std::int64_t>(0,std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now()-prepareStart).count()));
|
||||
@@ -11735,12 +11853,14 @@ FStandaloneShapeWorld::FScopedPassageTileQueries::sweptSample(
|
||||
};
|
||||
if(passageIndex>=sweep->passageToSweep.size())
|
||||
{
|
||||
sweep->unpreparedMisses.fetch_add(1,std::memory_order_relaxed);
|
||||
recordMissing();
|
||||
return nullptr;
|
||||
}
|
||||
const std::int32_t passageSweepIndex=sweep->passageToSweep[passageIndex];
|
||||
if(passageSweepIndex<0||static_cast<std::size_t>(passageSweepIndex)>=sweep->passages.size())
|
||||
{
|
||||
sweep->unpreparedMisses.fetch_add(1,std::memory_order_relaxed);
|
||||
recordMissing();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -11754,6 +11874,7 @@ FStandaloneShapeWorld::FScopedPassageTileQueries::sweptSample(
|
||||
if(rounded<0||rounded>=sweep->dimension
|
||||
||std::abs(coordinate-static_cast<double>(rounded))>1.0e-5)
|
||||
{
|
||||
sweep->offGridMisses.fetch_add(1,std::memory_order_relaxed);
|
||||
recordMissing();
|
||||
return nullptr;
|
||||
}
|
||||
@@ -11765,6 +11886,7 @@ FStandaloneShapeWorld::FScopedPassageTileQueries::sweptSample(
|
||||
const auto& samples=sweep->passages[static_cast<std::size_t>(passageSweepIndex)].samples;
|
||||
if(index>=samples.size()||!samples[index].valid)
|
||||
{
|
||||
sweep->unpreparedMisses.fetch_add(1,std::memory_order_relaxed);
|
||||
recordMissing();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user