Files
VoxelForge/Standalone/Research/WorldAssemblerM3/Linux106/patches/band-column-cache-not-merged.patch
T
Fr0zkaandClaude Opus 5.5 20f1b35967 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
2026-10-28 22:18:17 +01:00

273 lines
18 KiB
Diff

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),