wip(assembler): rounds L5+L6 -- Linux far-terrain captures and screen-space gate (world unchanged)

Linux offscreen capture (EGL/GLES pbuffer; llvmpipe in the sandbox) and an opt-in screen-space gate
for LOD>=3 (normal distance projected at each LOD's closest display distance, 1 px at 1440p =
0.61 mrad). The gate rejects the S13 octave-drop and stride-2 controls, fault injections, and a
vertical-vs-screen control. Finding: today's far meshes differ from the field by up to 92 px, and
LOD swaps snap mesa rims by tens of px (p50 0 px), a silhouette effect of plain LOD switching. The
octave cutoff was dropped: nothing qualified, and octaves are a small share of far time. Off-path
cost: reviewer interleaved W12 within noise vs L4 (+0.6% median). Hashes = L4.
Largest far lever measured: column work outside noise, 34% of far worker time (duplicate XY across tiles).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ED33VnqepD4YY6gDAAA832
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-19 21:10:08 +02:00
1 parent 7770074503
commit 9898e057fd
36 files changed
+1821 -11

No files matched your search

@@ -137,6 +137,7 @@ namespace VoxelForgeCore
double marchingCubesGradientNormalsMilliseconds = 0.0;
double marchingCubesEdgeInterpolationMilliseconds = 0.0;
double marchingCubesVertexDedupStreamMilliseconds = 0.0;
double marchingCubesSkirtMilliseconds = 0.0;
double marchingCubesOtherMilliseconds = 0.0;
std::uint64_t marchingCubesGradientFallbackDensityCalls = 0;
std::uint64_t marchingCubesEdgeMidpointDensityCalls = 0;
@@ -704,6 +705,10 @@ namespace VoxelForgeCore
std::int64_t maximumZSubvoxels, std::int32_t stepVoxels) const noexcept;
static void resetThreadColumnCacheStats(bool captureCoordinates = false,
bool clearCache = false, std::uint32_t octaveDrop = 0) noexcept;
static void setThreadColumnOctaveDrop(std::uint32_t octaveDrop) noexcept;
static std::uint32_t threadColumnOctaveDrop() noexcept;
static void setThreadColumnInterpolationStrideSubvoxels(std::int64_t stride) noexcept;
static std::int64_t threadColumnInterpolationStrideSubvoxels() noexcept;
static void setThreadColumnCacheLegacyDirectMapped(bool enabled) noexcept;
static const HeightfieldColumnCacheStats& threadColumnCacheStats() noexcept;
FieldInterval interval(std::int64_t minimumXSubvoxels,
@@ -1050,6 +1055,10 @@ namespace VoxelForgeCore
// Incremente quand le plafond lointain change. Les hashes LOD4-8 incluent cette version;
// densite et hashes LOD0-3 restent inchanges.
std::uint32_t farHorizonVersion = 3;
// Linux research controls for reproducing L5 negative controls. Defaults preserve output.
std::uint32_t diagnosticGlobalOctaveDrop = 0;
std::uint32_t diagnosticCellStride = 1;
std::uint32_t diagnosticColumnInterpolationStride = 1;
};
class VFCORE_API World
+32 -1
View File
@@ -1446,6 +1446,14 @@ namespace VoxelForgeCore
}
}
}
int32 MeshCells=cells,MeshStep=step;
if(options.diagnosticCellStride>1&&level>=3)
{
const int32 Stride=static_cast<int32>(std::min<std::uint32_t>(
options.diagnosticCellStride,static_cast<std::uint32_t>(std::max(1,cells))));
MeshCells=FMath::Max(1,cells/Stride);
MeshStep=FMath::Max(1,extent/MeshCells);
}
int64 sampleCount=0;std::vector<float> densityValues;
FVoxelMarchingCubesStageTimings McStageTimings;
TileMesh out;out.key=key;
@@ -1678,13 +1686,32 @@ namespace VoxelForgeCore
out.diagnostics.featureListMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-FeatureListStart).count();
const ScopedWorldAssemblyFeatureQueriesV1 featureScope(featureQueries);
const bool bDiagnosticColumnSampling=options.diagnosticGlobalOctaveDrop!=0
||options.diagnosticColumnInterpolationStride>1;
const std::uint32_t PreviousOctaveDrop=bDiagnosticColumnSampling
?Heightfield2D::threadColumnOctaveDrop():0;
const std::int64_t PreviousInterpolationStride=bDiagnosticColumnSampling
?Heightfield2D::threadColumnInterpolationStrideSubvoxels():0;
if(bDiagnosticColumnSampling)
{
Heightfield2D::setThreadColumnOctaveDrop(options.diagnosticGlobalOctaveDrop);
Heightfield2D::setThreadColumnInterpolationStrideSubvoxels(
options.diagnosticColumnInterpolationStride>1&&level>=3
?static_cast<std::int64_t>(MeshStep)*WorldAssemblySubvoxelsPerVoxel
*options.diagnosticColumnInterpolationStride:0);
}
const double ColumnMillisecondsBeforeMeshing=
VoxelForgeCore::Heightfield2D::threadColumnCacheStats().columnComputeMilliseconds;
const auto MarchingCubesStart=std::chrono::steady_clock::now();
FVoxelMeshData mesh=mesher.GenerateMesh(origin,step,cells,nullptr,
FVoxelMeshData mesh=mesher.GenerateMesh(origin,MeshStep,MeshCells,nullptr,
MeshBandMinZVoxel,MeshBandMaxZVoxel,&sampleCount,nullptr,nullptr,
(options.hashDensity||options.captureDensitySamples)?&densityValues:nullptr,
options.profileMesherStages?&McStageTimings:nullptr);
if(bDiagnosticColumnSampling)
{
Heightfield2D::setThreadColumnOctaveDrop(PreviousOctaveDrop);
Heightfield2D::setThreadColumnInterpolationStrideSubvoxels(PreviousInterpolationStride);
}
const double MarchingCubesWallMilliseconds=std::chrono::duration<double,std::milli>(
std::chrono::steady_clock::now()-MarchingCubesStart).count();
const double ColumnMillisecondsAfterMeshing=
@@ -1695,6 +1722,10 @@ namespace VoxelForgeCore
ColumnMillisecondsAfterMeshing-ColumnMillisecondsBeforeMeshing);
if(options.profileMesherStages)
{
out.diagnostics.marchingCubesSkirtMilliseconds=McStageTimings.SkirtMilliseconds;
out.diagnostics.marchingCubesExclusiveMilliseconds=std::max(0.0,
out.diagnostics.marchingCubesExclusiveMilliseconds
-out.diagnostics.marchingCubesSkirtMilliseconds);
out.diagnostics.marchingCubesDensityGridMilliseconds=McStageTimings.DensityGridMilliseconds;
out.diagnostics.marchingCubesCellClassificationMilliseconds=
McStageTimings.CellClassificationMilliseconds;
@@ -1031,6 +1031,7 @@ namespace world_assembly_detail
// Audit-only override; normal tile generation resets this to zero before evaluating a recipe.
// Surcharge reservee aux mesures; la generation remet zero avant d'evaluer une recette.
inline thread_local std::uint32_t HeightfieldColumnOctaveDrop = 0;
inline thread_local std::int64_t HeightfieldColumnInterpolationStrideSubvoxels = 0;
inline std::int32_t FractalNoiseQ16(std::int64_t xQ16, std::int64_t yQ16,
std::int64_t zQ16, std::uint32_t octaves, bool ridged = false)
@@ -1506,6 +1507,43 @@ namespace world_assembly_detail
inline HeightfieldPointSample CachedColumn(const WorldAssemblyRecipeV1& recipe,
const WorldAssemblyStratumPlanV1& plan,std::int64_t x,std::int64_t y)
{
const std::int64_t InterpolationStride=HeightfieldColumnInterpolationStrideSubvoxels;
if(InterpolationStride>0)
{
const std::int64_t X0=FloorDiv(x,InterpolationStride)*InterpolationStride;
const std::int64_t Y0=FloorDiv(y,InterpolationStride)*InterpolationStride;
const std::int64_t X1=X0+InterpolationStride,Y1=Y0+InterpolationStride;
const std::int64_t Fx=x-X0,Fy=y-Y0;
struct FScopedInterpolationSampling
{
std::int64_t Previous=HeightfieldColumnInterpolationStrideSubvoxels;
~FScopedInterpolationSampling()
{HeightfieldColumnInterpolationStrideSubvoxels=Previous;}
} SamplingScope;
HeightfieldColumnInterpolationStrideSubvoxels=0;
const HeightfieldPointSample C00=CachedColumn(recipe,plan,X0,Y0);
const HeightfieldPointSample C10=CachedColumn(recipe,plan,X1,Y0);
const HeightfieldPointSample C01=CachedColumn(recipe,plan,X0,Y1);
const HeightfieldPointSample C11=CachedColumn(recipe,plan,X1,Y1);
const auto Lerp=[&](std::int64_t A,std::int64_t B,std::int64_t T)
{return A+((B-A)*T)/InterpolationStride;};
const auto Bilinear=[&](std::int64_t A,std::int64_t B,
std::int64_t C,std::int64_t D)
{
const std::int64_t Top=Lerp(A,B,Fx),Bottom=Lerp(C,D,Fx);
return Lerp(Top,Bottom,Fy);
};
HeightfieldPointSample Out=C00;
Out.groundHeightSubvoxels=Bilinear(C00.groundHeightSubvoxels,
C10.groundHeightSubvoxels,C01.groundHeightSubvoxels,
C11.groundHeightSubvoxels);
Out.capHeightSubvoxels=Bilinear(C00.capHeightSubvoxels,
C10.capHeightSubvoxels,C01.capHeightSubvoxels,
C11.capHeightSubvoxels);
return Out;
}
if(HeightfieldColumnOctaveDrop!=0)
return EvaluateColumn(recipe,plan,x,y);
auto& cache=HeightfieldColumnCache.Get();
auto& nextWay=HeightfieldColumnCacheNextWay.Get();
HeightfieldColumnCacheEntry* replacement=nullptr;
@@ -2058,6 +2096,19 @@ void Heightfield2D::resetThreadColumnCacheStats(bool captureCoordinates, bool cl
void Heightfield2D::setThreadColumnCacheLegacyDirectMapped(bool enabled) noexcept
{ world_assembly_detail::HeightfieldColumnCacheLegacyDirectMapped=enabled; }
void Heightfield2D::setThreadColumnOctaveDrop(std::uint32_t octaveDrop) noexcept
{ world_assembly_detail::HeightfieldColumnOctaveDrop=octaveDrop; }
std::uint32_t Heightfield2D::threadColumnOctaveDrop() noexcept
{ return world_assembly_detail::HeightfieldColumnOctaveDrop; }
void Heightfield2D::setThreadColumnInterpolationStrideSubvoxels(std::int64_t stride) noexcept
{ world_assembly_detail::HeightfieldColumnInterpolationStrideSubvoxels=std::max<std::int64_t>(0,stride); }
std::int64_t Heightfield2D::threadColumnInterpolationStrideSubvoxels() noexcept
{ return world_assembly_detail::HeightfieldColumnInterpolationStrideSubvoxels; }
const HeightfieldColumnCacheStats& Heightfield2D::threadColumnCacheStats() noexcept
{ return world_assembly_detail::HeightfieldColumnStats; }