research: floor-ribbon falsifier and band column cache (L106, no code merged)
A route-only floor profile cannot reproduce current support semantics: support is gated per sample by native density < 0, player-capsule clearance, later-bore deferral and neighbouring- passage capsule checks (the overlapping-coil tile exercises all of them). The exact per-tile boundary-band XY column cache matched all 24 hashes but showed no consistent readiness gain, so it is kept as a patch only (patches/band-column-cache-not-merged.patch), not merged. 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
f228d6319f
commit
20f1b35967
27 files changed
+1860
No files matched your search
+272
@@ -0,0 +1,272 @@
|
||||
diff --git a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
|
||||
index 972aaf8..94ec19b 100644
|
||||
--- a/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
|
||||
+++ b/Standalone/Core/include/VoxelForgeCore/VoxelForgeCore.h
|
||||
@@ -139,6 +139,9 @@ namespace VoxelForgeCore
|
||||
std::uint64_t passageTileRouteSegmentCandidates = 0;
|
||||
std::uint64_t passageTileMouthSegmentCandidates = 0;
|
||||
std::uint64_t resolvedBoundaryBandQueries = 0;
|
||||
+ std::uint64_t resolvedBoundaryBandColumnEvaluations = 0;
|
||||
+ std::uint64_t resolvedBoundaryBandColumnCacheHits = 0;
|
||||
+ std::uint64_t resolvedBoundaryBandColumnOffGridFallbacks = 0;
|
||||
std::uint64_t passageComposerQueries = 0;
|
||||
std::uint64_t passageIterations = 0;
|
||||
std::uint64_t passageTileBoundChecks = 0;
|
||||
diff --git a/Standalone/Core/src/ShapeWorldInternal.h b/Standalone/Core/src/ShapeWorldInternal.h
|
||||
index 8626d7e..2c53c35 100644
|
||||
--- a/Standalone/Core/src/ShapeWorldInternal.h
|
||||
+++ b/Standalone/Core/src/ShapeWorldInternal.h
|
||||
@@ -339,6 +339,15 @@ public:
|
||||
verticalBoundSkipsByCaller{},negativeReachSkipsByCaller{},
|
||||
positiveReachSkipsByCaller{};
|
||||
};
|
||||
+ struct FResolvedBoundaryColumnData
|
||||
+ {
|
||||
+ std::int32_t minimumXVoxel=0,minimumYVoxel=0,stepVoxel=0,dimension=0;
|
||||
+ std::size_t pairCount=0;
|
||||
+ std::vector<std::uint8_t> pairReady;
|
||||
+ std::vector<VoxelForgeCore::ResolvedLayoutTransitionBandsV1> bands;
|
||||
+ std::uint64_t evaluations=0;
|
||||
+ mutable std::atomic<std::uint64_t> cacheHits{0},offGridFallbacks{0};
|
||||
+ };
|
||||
FScopedPassageTileQueries(const FStandaloneShapeWorld& shape,
|
||||
const std::array<std::int64_t,3>& minimumSubvoxels,
|
||||
const std::array<std::int64_t,3>& maximumSubvoxels,
|
||||
@@ -502,6 +511,8 @@ public:
|
||||
passageCarveReachMetres_(source.passageCarveReachMetres_),
|
||||
passageSweepData_(source.passageSweepData_),
|
||||
ownsPassageSweepDiagnostics_(false),
|
||||
+ resolvedBoundaryColumnData_(source.resolvedBoundaryColumnData_),
|
||||
+ ownsResolvedBoundaryColumnDiagnostics_(false),
|
||||
clampCounters_(source.clampCounters_),ownsClampCounters_(false),
|
||||
projectionCacheSize_(source.projectionCacheSize_),
|
||||
reuseCounters_(source.reuseCounters_),ownsReuseCounters_(false)
|
||||
@@ -546,6 +557,7 @@ public:
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
}
|
||||
+ copyResolvedBoundaryColumnDiagnostics();
|
||||
if(ownsReuseCounters_&&reuseCounters_)
|
||||
std::printf("[L98PassageReuseTile] lod=%d projection_columns=%llu projection_computes=%llu projection_hits=%llu floor_profile_reads=%llu carve_prepared=%llu support_prepared=%llu capsule_prepared=%llu mouth_prepared=%llu\n",
|
||||
profileLod_,
|
||||
@@ -626,6 +638,23 @@ public:
|
||||
bool capturesCallerDiagnostics() const noexcept{return profileStats_!=nullptr;}
|
||||
void prepareSweptTubeBase(const FIntVector& origin,std::int32_t step,
|
||||
std::int32_t cells,std::uint32_t seed);
|
||||
+ void prepareResolvedBoundaryColumns(const FIntVector& origin,
|
||||
+ std::int32_t step,std::int32_t cells);
|
||||
+ const VoxelForgeCore::ResolvedLayoutTransitionBandsV1* cachedTransitionBands(
|
||||
+ float X,float Y,const VoxelForgeCore::ResolvedLayoutStratumV2& upper,
|
||||
+ const VoxelForgeCore::ResolvedLayoutStratumV2& lower) const noexcept;
|
||||
+ void copyResolvedBoundaryColumnDiagnostics() const noexcept
|
||||
+ {
|
||||
+ if(!ownsResolvedBoundaryColumnDiagnostics_||!profileStats_
|
||||
+ ||!resolvedBoundaryColumnData_)return;
|
||||
+ profileStats_->resolvedBoundaryBandColumnEvaluations=
|
||||
+ resolvedBoundaryColumnData_->evaluations;
|
||||
+ profileStats_->resolvedBoundaryBandColumnCacheHits=
|
||||
+ resolvedBoundaryColumnData_->cacheHits.load(std::memory_order_relaxed);
|
||||
+ profileStats_->resolvedBoundaryBandColumnOffGridFallbacks=
|
||||
+ resolvedBoundaryColumnData_->offGridFallbacks.load(
|
||||
+ std::memory_order_relaxed);
|
||||
+ }
|
||||
const FPassageSweepSample* sweptSample(std::size_t passageIndex,
|
||||
double qx,double qy,double qz) const;
|
||||
bool hasSweptTubeBase() const noexcept{return passageSweepData_!=nullptr;}
|
||||
@@ -917,6 +946,8 @@ public:
|
||||
double passageCarveReachMetres_=0.0;
|
||||
std::shared_ptr<FPassageTileSweepData> passageSweepData_;
|
||||
bool ownsPassageSweepDiagnostics_=true;
|
||||
+ std::shared_ptr<FResolvedBoundaryColumnData> resolvedBoundaryColumnData_;
|
||||
+ bool ownsResolvedBoundaryColumnDiagnostics_=true;
|
||||
mutable std::shared_ptr<FPassageSourceClampCounters> clampCounters_;
|
||||
bool ownsClampCounters_=true;
|
||||
std::size_t projectionCacheSize_=0;
|
||||
@@ -1546,8 +1577,12 @@ public:
|
||||
static_cast<double>(X)*Owner->CoreVoxelSizeMicrons));
|
||||
const auto yMicrometres=static_cast<std::int64_t>(std::llround(
|
||||
static_cast<double>(Y)*Owner->CoreVoxelSizeMicrons));
|
||||
- const auto bands=ResolvedTransitionBandsAtXY(*transitionUpper,
|
||||
- *transitionLower,xMicrometres,yMicrometres,skipPassageFade);
|
||||
+ const auto* cachedBands=tileQueries&&tileQueries->matches(*this)
|
||||
+ ?tileQueries->cachedTransitionBands(X,Y,*transitionUpper,
|
||||
+ *transitionLower):nullptr;
|
||||
+ const auto bands=cachedBands?*cachedBands:ResolvedTransitionBandsAtXY(
|
||||
+ *transitionUpper,*transitionLower,xMicrometres,yMicrometres,
|
||||
+ skipPassageFade);
|
||||
const std::int64_t solidBottom=std::min(
|
||||
bands.upperBedrockBottomMicrometres,bands.lowerCeilingBottomMicrometres);
|
||||
const std::int64_t solidTop=std::max(
|
||||
@@ -1609,8 +1644,11 @@ public:
|
||||
#if defined(VF_L30_ENABLE_COST_COUNTERS)
|
||||
if(skipPassageFade)++ThreadClassificationStats().TransitionPassageTileSkips;
|
||||
#endif
|
||||
- const auto resolvedBands=ResolvedTransitionBandsAtXY(*upper,*lower,
|
||||
- xMicrometres,yMicrometres,skipPassageFade);
|
||||
+ const auto* cachedBands=tileQueries&&tileQueries->matches(*this)
|
||||
+ ?tileQueries->cachedTransitionBands(X,Y,*upper,*lower):nullptr;
|
||||
+ const auto resolvedBands=cachedBands?*cachedBands:
|
||||
+ ResolvedTransitionBandsAtXY(*upper,*lower,xMicrometres,yMicrometres,
|
||||
+ skipPassageFade);
|
||||
// Treat the two authored bands as one continuous solid interval. Its
|
||||
// exterior faces remain the lower ceiling bottom and upper bedrock top;
|
||||
// measuring signed distance from those faces also clears native generator
|
||||
@@ -14424,6 +14462,115 @@ private:
|
||||
inline static thread_local const FPassageCandidateBrick* ActivePassageCandidateBrick=nullptr;
|
||||
};
|
||||
|
||||
+inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareResolvedBoundaryColumns(
|
||||
+ const FIntVector& origin,std::int32_t step,std::int32_t cells)
|
||||
+{
|
||||
+ if(!shape_||!mayContainResolvedBoundaryBand_||step<=0||cells<=0
|
||||
+ ||!shape_->ResolvedLayout||!shape_->Owner
|
||||
+ ||shape_->Owner->CoreVoxelSizeMicrons==0)return;
|
||||
+
|
||||
+ constexpr std::int64_t Q=VoxelForgeCore::WorldAssemblySubvoxelsPerVoxel;
|
||||
+ const auto& layout=*shape_->ResolvedLayout;
|
||||
+ auto data=std::make_shared<FResolvedBoundaryColumnData>();
|
||||
+ data->minimumXVoxel=origin.X-step;
|
||||
+ data->minimumYVoxel=origin.Y-step;
|
||||
+ data->stepVoxel=step;
|
||||
+ data->dimension=cells+3;
|
||||
+ for(const auto& stratum:layout.strates)
|
||||
+ if(stratum.order>=0)
|
||||
+ data->pairCount=std::max(data->pairCount,
|
||||
+ static_cast<std::size_t>(stratum.order)+1);
|
||||
+ if(data->pairCount==0)return;
|
||||
+ data->pairReady.assign(data->pairCount,0);
|
||||
+ const double minimumZMicrometres=static_cast<double>(minimumSubvoxels_[2])
|
||||
+ *shape_->Owner->CoreVoxelSizeMicrons/Q;
|
||||
+ const double maximumZMicrometres=static_cast<double>(maximumSubvoxels_[2])
|
||||
+ *shape_->Owner->CoreVoxelSizeMicrons/Q;
|
||||
+ std::size_t activePairCount=0;
|
||||
+ for(const auto& upper:layout.strates)
|
||||
+ {
|
||||
+ if(upper.order<0||static_cast<std::size_t>(upper.order)>=data->pairCount
|
||||
+ ||!shape_->IsResolvedLayoutTransitionActive(upper))continue;
|
||||
+ const auto* lower=shape_->FindResolvedLayoutStratumByOrder(upper.order+1);
|
||||
+ if(!lower)continue;
|
||||
+ const auto maximumDisplacement=
|
||||
+ shape_->ResolvedTransitionMaximumFaceDisplacementMicrometres(upper,*lower);
|
||||
+ const double transitionMinimum=std::min(upper.bedrock.bottomMicrometres,
|
||||
+ lower->ceiling.bottomMicrometres)-maximumDisplacement;
|
||||
+ const double transitionMaximum=std::max(upper.bedrock.topMicrometres,
|
||||
+ lower->ceiling.topMicrometres)+maximumDisplacement;
|
||||
+ if(maximumZMicrometres<transitionMinimum
|
||||
+ ||minimumZMicrometres>=transitionMaximum)continue;
|
||||
+ data->pairReady[static_cast<std::size_t>(upper.order)]=1;
|
||||
+ ++activePairCount;
|
||||
+ }
|
||||
+ if(activePairCount==0)return;
|
||||
+
|
||||
+ const std::size_t columnCount=static_cast<std::size_t>(data->dimension)
|
||||
+ *static_cast<std::size_t>(data->dimension);
|
||||
+ if(columnCount>std::numeric_limits<std::size_t>::max()/data->pairCount)return;
|
||||
+ data->bands.resize(columnCount*data->pairCount);
|
||||
+ data->evaluations=static_cast<std::uint64_t>(columnCount)*activePairCount;
|
||||
+ const bool skipPassageFade=!mayContainTransitionPassageFade_;
|
||||
+ for(std::int32_t gy=0;gy<data->dimension;++gy)
|
||||
+ for(std::int32_t gx=0;gx<data->dimension;++gx)
|
||||
+ {
|
||||
+ const float x=static_cast<float>(static_cast<std::int64_t>(data->minimumXVoxel)
|
||||
+ +static_cast<std::int64_t>(gx)*data->stepVoxel);
|
||||
+ const float y=static_cast<float>(static_cast<std::int64_t>(data->minimumYVoxel)
|
||||
+ +static_cast<std::int64_t>(gy)*data->stepVoxel);
|
||||
+ const std::int64_t xMicrometres=static_cast<std::int64_t>(std::llround(
|
||||
+ static_cast<double>(x)*shape_->Owner->CoreVoxelSizeMicrons));
|
||||
+ const std::int64_t yMicrometres=static_cast<std::int64_t>(std::llround(
|
||||
+ static_cast<double>(y)*shape_->Owner->CoreVoxelSizeMicrons));
|
||||
+ const std::size_t column=static_cast<std::size_t>(gy)
|
||||
+ *static_cast<std::size_t>(data->dimension)+static_cast<std::size_t>(gx);
|
||||
+ for(const auto& upper:layout.strates)
|
||||
+ {
|
||||
+ if(upper.order<0||static_cast<std::size_t>(upper.order)>=data->pairCount
|
||||
+ ||!data->pairReady[static_cast<std::size_t>(upper.order)])continue;
|
||||
+ const auto* lower=shape_->FindResolvedLayoutStratumByOrder(upper.order+1);
|
||||
+ if(!lower)continue;
|
||||
+ data->bands[column*data->pairCount+static_cast<std::size_t>(upper.order)]=
|
||||
+ shape_->ResolvedTransitionBandsAtXY(upper,*lower,xMicrometres,
|
||||
+ yMicrometres,skipPassageFade);
|
||||
+ }
|
||||
+ }
|
||||
+ resolvedBoundaryColumnData_=std::move(data);
|
||||
+}
|
||||
+
|
||||
+inline const VoxelForgeCore::ResolvedLayoutTransitionBandsV1*
|
||||
+FStandaloneShapeWorld::FScopedPassageTileQueries::cachedTransitionBands(
|
||||
+ float X,float Y,const VoxelForgeCore::ResolvedLayoutStratumV2& upper,
|
||||
+ const VoxelForgeCore::ResolvedLayoutStratumV2& lower) const noexcept
|
||||
+{
|
||||
+ const auto* data=resolvedBoundaryColumnData_.get();
|
||||
+ if(!data||upper.order<0||lower.order!=upper.order+1
|
||||
+ ||static_cast<std::size_t>(upper.order)>=data->pairCount
|
||||
+ ||!data->pairReady[static_cast<std::size_t>(upper.order)])return nullptr;
|
||||
+ const double xCoordinate=(static_cast<double>(X)-data->minimumXVoxel)/data->stepVoxel;
|
||||
+ const double yCoordinate=(static_cast<double>(Y)-data->minimumYVoxel)/data->stepVoxel;
|
||||
+ const auto gx=static_cast<std::int64_t>(std::llround(xCoordinate));
|
||||
+ const auto gy=static_cast<std::int64_t>(std::llround(yCoordinate));
|
||||
+ if(gx<0||gy<0||gx>=data->dimension||gy>=data->dimension
|
||||
+ ||static_cast<float>(static_cast<std::int64_t>(data->minimumXVoxel)
|
||||
+ +gx*data->stepVoxel)!=X
|
||||
+ ||static_cast<float>(static_cast<std::int64_t>(data->minimumYVoxel)
|
||||
+ +gy*data->stepVoxel)!=Y)
|
||||
+ {
|
||||
+ if(profileStats_)
|
||||
+ data->offGridFallbacks.fetch_add(1,std::memory_order_relaxed);
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+ const std::size_t column=static_cast<std::size_t>(gy)
|
||||
+ *static_cast<std::size_t>(data->dimension)+static_cast<std::size_t>(gx);
|
||||
+ const std::size_t index=column*data->pairCount
|
||||
+ +static_cast<std::size_t>(upper.order);
|
||||
+ if(index>=data->bands.size())return nullptr;
|
||||
+ if(profileStats_)data->cacheHits.fetch_add(1,std::memory_order_relaxed);
|
||||
+ return &data->bands[index];
|
||||
+}
|
||||
+
|
||||
inline void FStandaloneShapeWorld::FScopedPassageTileQueries::prepareSweptTubeBase(
|
||||
const FIntVector& origin,std::int32_t step,std::int32_t cells,std::uint32_t seed)
|
||||
{
|
||||
diff --git a/Standalone/Core/src/VoxelForgeCore.cpp b/Standalone/Core/src/VoxelForgeCore.cpp
|
||||
index 0a5d451..81a04b1 100644
|
||||
--- a/Standalone/Core/src/VoxelForgeCore.cpp
|
||||
+++ b/Standalone/Core/src/VoxelForgeCore.cpp
|
||||
@@ -2806,6 +2806,7 @@ namespace VoxelForgeCore
|
||||
options.profilePassageComposer?&out.diagnostics:nullptr,key.lod,
|
||||
options.diagnosticPassageSourceFloorVoxels,
|
||||
options.diagnosticPassageCarveReachMetres);
|
||||
+ passageFeatureScope.prepareResolvedBoundaryColumns(origin,MeshStep,MeshCells);
|
||||
passageFeatureScope.prepareSweptTubeBase(origin,MeshStep,MeshCells,
|
||||
static_cast<std::uint32_t>(world.Seed));
|
||||
static std::atomic<bool> l98ProjectionProbeStarted{false};
|
||||
@@ -3367,6 +3368,7 @@ namespace VoxelForgeCore
|
||||
out.diagnostics.meshAssemblyMilliseconds=std::chrono::duration<double,std::milli>(
|
||||
std::chrono::steady_clock::now()-MeshAssemblyStart).count();
|
||||
CopyIslandCacheMetrics();
|
||||
+ passageFeatureScope.copyResolvedBoundaryColumnDiagnostics();
|
||||
return out;
|
||||
}
|
||||
|
||||
diff --git a/Standalone/Source/StreamingWorld.h b/Standalone/Source/StreamingWorld.h
|
||||
index 3019e39..3f706f9 100644
|
||||
--- a/Standalone/Source/StreamingWorld.h
|
||||
+++ b/Standalone/Source/StreamingWorld.h
|
||||
@@ -1538,7 +1538,7 @@ private:
|
||||
static_cast<unsigned long long>(D.islandSharedCacheConflictReplacements),
|
||||
static_cast<double>(D.islandSharedCacheLockWaitNanoseconds)/1000.0);
|
||||
if(D.passageComposerProfiled)
|
||||
- std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu mouth_candidates=%llu boundary_band_queries=%llu queries=%llu passage_iterations=%llu tile_bound_checks=%llu tile_bound_rejects=%llu tile_bound_skipped_iterations=%llu upper_mouth_checks=%llu column_candidates=%llu column_distance_calls=%llu negative_bounds=%llu negative_rejects=%llu positive_bounds=%llu positive_rejects=%llu carve_segment_visits=%llu smooth_carve_joins=%llu support_segment_visits=%llu smooth_support_joins=%llu support_capsule_checks=%llu later_bore_checks=%llu other_capsule_checks=%llu mouth_support_calls=%llu mouth_route_segment_checks=%llu relief_field_calls=%llu smoothstep_evaluations=%llu sweep_segments=%llu sweep_pairs=%llu sweep_outside_pairs=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n",
|
||||
+ std::printf("[PassageComposerTile] key=(%d,%d,%d,lod%d) worker_ms=%.3f samples=%llu native_field_calls=%llu features=%llu route_candidates=%llu mouth_candidates=%llu boundary_band_queries=%llu boundary_column_evaluations=%llu boundary_column_hits=%llu boundary_column_offgrid=%llu queries=%llu passage_iterations=%llu tile_bound_checks=%llu tile_bound_rejects=%llu tile_bound_skipped_iterations=%llu upper_mouth_checks=%llu column_candidates=%llu column_distance_calls=%llu negative_bounds=%llu negative_rejects=%llu positive_bounds=%llu positive_rejects=%llu carve_segment_visits=%llu smooth_carve_joins=%llu support_segment_visits=%llu smooth_support_joins=%llu support_capsule_checks=%llu later_bore_checks=%llu other_capsule_checks=%llu mouth_support_calls=%llu mouth_route_segment_checks=%llu relief_field_calls=%llu smoothstep_evaluations=%llu sweep_segments=%llu sweep_pairs=%llu sweep_outside_pairs=%llu sweep_min_updates=%llu sweep_base_samples=%llu sweep_detail_samples=%llu sweep_grid_samples=%llu sweep_no_influence_samples=%llu sweep_lookups=%llu sweep_cache_hits=%llu sweep_base_hits=%llu sweep_outside_hits=%llu sweep_missing=%llu\n",
|
||||
Event.Key.Coord.X,Event.Key.Coord.Y,Event.Key.Coord.Z,Event.Key.Level,
|
||||
Event.WorkerMilliseconds,static_cast<unsigned long long>(Event.DensitySamples),
|
||||
static_cast<unsigned long long>(D.fieldCalls),
|
||||
@@ -1546,6 +1546,9 @@ private:
|
||||
static_cast<unsigned long long>(D.passageTileRouteSegmentCandidates),
|
||||
static_cast<unsigned long long>(D.passageTileMouthSegmentCandidates),
|
||||
static_cast<unsigned long long>(D.resolvedBoundaryBandQueries),
|
||||
+ static_cast<unsigned long long>(D.resolvedBoundaryBandColumnEvaluations),
|
||||
+ static_cast<unsigned long long>(D.resolvedBoundaryBandColumnCacheHits),
|
||||
+ static_cast<unsigned long long>(D.resolvedBoundaryBandColumnOffGridFallbacks),
|
||||
static_cast<unsigned long long>(D.passageComposerQueries),
|
||||
static_cast<unsigned long long>(D.passageIterations),
|
||||
static_cast<unsigned long long>(D.passageTileBoundChecks),
|
||||
Reference in new issue
Block a user