wip(standalone): GPU step 6 -- near field on GPU, exact; cold start still slower than CPU

Near LOD0/1 (detail band, relief, root refinement, normals) now evaluated and
meshed on the GPU. 960 near tiles: zero sign/topology differences vs CPU and
WARP, vertex max 0.0049 mm (was 15 cm); far survival audit passes; CPU hashes
44/44 unchanged. Far connector-panel outlier (64.56 cm, LOD8) remains a
tessellation difference, and remote captures show missing far geometry on GPU.

Cold readiness (viewer clock, my interleaved runs): CPU 2.51/2.49/2.40 s,
GPU 5.05/2.68/2.80 s. The ~2.1 s Present stall hit only the first GPU launch.
Viewer spends ~1.13 s before shape compile starts (startup checks), which is
the gap between the 0.95 s benchmark and ~2.4 s on-screen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MmSoF64BbRFmk9C3p1VsBJ
This commit is contained in:
Fr0zkaandClaude Opus 5.5 committed 2026-10-06 20:03:10 +02:00
1 parent 0e730cdbba
commit b0a14262b1
50 files changed
+1681 -236

No files matched your search

@@ -204,10 +204,25 @@ namespace VoxelForgeCore
};
static_assert(sizeof(FarFieldSpatialBin) == 24);
// Layer-local detail parameters for the shared coherent near field. This record stays
// float-only so the same values bind to an HLSL StructuredBuffer.
struct FarFieldDetailLayerGpu
{
std::int32_t lo = 0, hi = -1;
float surfaceRoughness = 0.0f, roughnessFrequency = 0.0f;
float verticalScale = 1.0f, domainWarpStrength = 0.0f;
float domainWarpFrequency = 0.0f;
std::uint32_t roughnessNoiseType = 0;
};
static_assert(sizeof(FarFieldDetailLayerGpu) == 32);
struct FarFieldWorldInput
{
std::uint32_t spatialBinSize = 32, spatialBinMask = 0;
std::uint32_t fieldSeed = 0;
std::int32_t detailMinVoxel[3]{}, detailMaxVoxel[3]{};
std::vector<FarFieldPrimitiveGpu> shapes;
std::vector<FarFieldDetailLayerGpu> detailLayers;
// Open-addressed table. count == 0 denotes an empty slot; mask is capacity - 1.
std::vector<FarFieldSpatialBin> spatialBins;
std::vector<std::uint32_t> spatialBinShapeIds;
@@ -236,6 +251,7 @@ namespace VoxelForgeCore
{
Vec3i origin{};
std::int32_t cells = 0, step = 0, sampleDim = 0;
bool nearDetailEnabled = false;
float strataLo = 0.0f, strataHi = 0.0f, strataBlend = 12.0f;
std::shared_ptr<const FarFieldWorldInput> worldInput;
// Sparse exception bitset: bit 1 forces route-protected air. Ordinary rock/air
@@ -244,6 +260,11 @@ namespace VoxelForgeCore
// Sparse exception bitset for exact solid overlays/thin route-adjacent features.
std::vector<std::uint32_t> protectedSolid;
std::vector<std::uint32_t> protectedThin;
// Near tiles mirror the CPU's sparse interpolation proxy cache. UINT_MAX
// means analytic-only; zero means the packed fixed fallback; low values
// store |SurfaceDistanceQ|. For Q==1 only, bit 30 marks the ambiguous
// packed-sign exception and bit 31 carries its CPU rock sign.
std::vector<std::uint32_t> nearPackedProxy;
std::vector<FarFieldStratumBoundary> stratumBoundaries;
std::vector<FarFieldConnectorPanel> connectorPanels;
std::uint32_t connectorRingCount = 0, connectorVertexCount = 0;
@@ -343,6 +364,8 @@ namespace VoxelForgeCore
std::vector<std::uint32_t> farConnectorCandidates(Vec3i minVoxel, Vec3i maxVoxel) const;
std::optional<FarFieldTileInput> exportFarFieldTile(const TileKey& key,
std::string& error) const;
std::optional<FarFieldTileInput> exportGpuFieldTile(const TileKey& key,
std::string& error) const;
bool isFarFieldTileEligible(const TileKey& key) const;
bool auditDetailPassing() const;
+53 -66
View File
@@ -526,9 +526,20 @@ public:
auto Data=std::make_shared<VoxelForgeCore::FarFieldWorldInput>();
Data->spatialBinSize=static_cast<uint32>(ActiveSpatialBinSize);
Data->spatialBinMask=static_cast<uint32>(TableCapacity-1);
Data->fieldSeed=static_cast<uint32>(Owner?Owner->Seed:0);
for(int32 Axis=0;Axis<3;++Axis)
{Data->detailMinVoxel[Axis]=Min[Axis];Data->detailMaxVoxel[Axis]=Max[Axis];}
Data->shapes.reserve(SharedFieldPrimitives.size());
for(const VF_FieldPrimitive& Shape:SharedFieldPrimitives)
Data->shapes.push_back(ToFarFieldGpuPrimitive(Shape));
Data->detailLayers.reserve(LayerFields.size());
for(const FLayerField& Field:LayerFields)
{
const FStrateGenerationParams& Params=Field.Params;
Data->detailLayers.push_back({Field.Lo,Field.Hi,Params.SurfaceRoughness,
Params.RoughnessFrequency,Params.VerticalScale,Params.DomainWarpStrength,
Params.DomainWarpFrequency,static_cast<uint32>(Params.RoughnessNoiseType)});
}
Data->spatialBins.resize(TableCapacity);
size_t ReferenceCount=0;
for(const auto& Bin:SpatialBins)ReferenceCount+=Bin.second.size();
@@ -551,20 +562,22 @@ public:
const double UploadMiB=(G.shapes.size()*sizeof(VoxelForgeCore::FarFieldPrimitiveGpu)
+G.spatialBins.size()*sizeof(VoxelForgeCore::FarFieldSpatialBin)
+G.spatialBinShapeIds.size()*sizeof(uint32))/1048576.0;
std::printf("[FarGpuWorldData] shapes=%zu spatial_bins=%zu hash_slots=%zu bin_shape_ids=%zu bin_size=%d bytes=%.3fMiB upload_scope=once_per_world\n",
std::printf("[FarGpuWorldData] shapes=%zu spatial_bins=%zu hash_slots=%zu bin_shape_ids=%zu bin_size=%d detail_min=(%d,%d,%d) detail_max=(%d,%d,%d) bytes=%.3fMiB upload_scope=once_per_world\n",
G.shapes.size(),SpatialBins.size(),G.spatialBins.size(),G.spatialBinShapeIds.size(),
ActiveSpatialBinSize,UploadMiB);
ActiveSpatialBinSize,G.detailMinVoxel[0],G.detailMinVoxel[1],G.detailMinVoxel[2],
G.detailMaxVoxel[0],G.detailMaxVoxel[1],G.detailMaxVoxel[2],UploadMiB);
return CachedFarFieldGpuInput;
}
bool ExportFarFieldTileInput(const FIntVector& Origin,int32 Cells,int32 Step,
VoxelForgeCore::FarFieldTileInput& Out,std::string& Error) const
bool bNearDetail,VoxelForgeCore::FarFieldTileInput& Out,std::string& Error) const
{
if(!FarBuilt||Cells<=0||Cells>32||Step<=0)
{Error="far field export requires a built far world and a bounded coarse tile";return false;}
const int32 Dim=Cells+3;
const size_t SampleCount=static_cast<size_t>(Dim)*Dim*Dim;
Out={};Error.clear();Out.origin={Origin.X,Origin.Y,Origin.Z};Out.cells=Cells;Out.step=Step;Out.sampleDim=Dim;
Out.nearDetailEnabled=bNearDetail;
Out.worldInput=GetFarFieldWorldInput(Error);
if(!Out.worldInput)return false;
if(LayerRanges.empty())
@@ -596,6 +609,8 @@ public:
Out.protectedAir.assign((SampleCount+31u)/32u,0u);
Out.protectedSolid.assign((SampleCount+31u)/32u,0u);
Out.protectedThin.assign((SampleCount+31u)/32u,0u);
if(bNearDetail)
Out.nearPackedProxy.assign(SampleCount,std::numeric_limits<uint32>::max());
const int32 LatticeMin[3]={Origin.X-Step,Origin.Y-Step,Origin.Z-Step};
const int32 LatticeMax[3]={Origin.X+(Cells+1)*Step,Origin.Y+(Cells+1)*Step,
@@ -723,7 +738,34 @@ public:
for(int32 X=-1;X<=Cells+1;++X,++SampleIndex)
{
const int32 WX=Origin.X+X*Step,WY=Origin.Y+Y*Step,WZ=Origin.Z+Z*Step;
if(WX>=Min[0]&&WX<=Max[0]&&WY>=Min[1]&&WY<=Max[1]&&WZ>=Min[2]&&WZ<=Max[2])
if(bNearDetail&&!bAnalyticOnly&&Contains(WX,WY,WZ))
{
const size_t Column=static_cast<size_t>(WY-Min[1])*Size[0]
+static_cast<size_t>(WX-Min[0]);
const size_t Zi=static_cast<size_t>(WZ-Min[2]);
const size_t Word=Column*WordsPerZ+(Zi>>6);
const uint64 Mask=uint64{1}<<(Zi&63u);
if((CandidateWords[Word]&Mask)==0)
Out.nearPackedProxy[SampleIndex]=0u;
else
{
const size_t Node=Zi*static_cast<size_t>(Size[1])*Size[0]+Column;
const int32 Q=std::abs(static_cast<int32>(SurfaceDistanceQ[Node]));
const uint32 Magnitude=static_cast<uint32>(std::clamp(Q,1,32767));
if(Magnitude==1u)
{
// At the minimum quantization step a one-ULP GPU sign flip
// can change an entire marching-cubes cell. Keep this sparse
// ambiguous boundary decision aligned with the packed cache.
const bool bRock=(RockWords[Word]&Mask)!=0;
Out.nearPackedProxy[SampleIndex]=0x40000000u
|(bRock?0x80000000u:0u)|Magnitude;
}
else Out.nearPackedProxy[SampleIndex]=Magnitude;
}
}
if(!bNearDetail&&WX>=Min[0]&&WX<=Max[0]&&WY>=Min[1]&&WY<=Max[1]
&&WZ>=Min[2]&&WZ<=Max[2])
{Error="tile lattice intersects the near analytic/detail region; this export is far-field only";return false;}
if(InsideCritical(WX,WY,WZ))
{
@@ -1746,6 +1788,7 @@ private:
if(P.bCurvedFloorClip)Out.flags|=VF_FIELD_PRIMITIVE_CURVED_FLOOR;
if(P.bCarve)Out.flags|=VF_FIELD_PRIMITIVE_CARVE;
if(P.bCritical)Out.flags|=VF_FIELD_PRIMITIVE_CRITICAL;
if(P.bPassageSurface)Out.flags|=VF_FIELD_PRIMITIVE_PASSAGE;
for(int32 A=0;A<3;++A)
{
Out.minVoxel[A]=P.Min[A];Out.maxVoxel[A]=P.Max[A];
@@ -4081,68 +4124,12 @@ private:
float OwnerCaveRoughnessCore(double X,double Y,double Z,
const FStrateGenerationParams& Params) const
{
const uint32 Seed=static_cast<uint32>(Owner->Seed);
const float RF=Params.RoughnessFrequency;
const float NoiseX=static_cast<float>(X);
const float NoiseY=static_cast<float>(Y);
const float EffectiveZ=(Params.VerticalScale>0.0f&&Params.VerticalScale!=1.0f)
?static_cast<float>(Z)/Params.VerticalScale:static_cast<float>(Z);
FVector3f Main(NoiseX*RF+VoxelHash::SeedOffset(Seed,11.3f),
NoiseY*RF+VoxelHash::SeedOffset(Seed,13.7f),
EffectiveZ*RF+VoxelHash::SeedOffset(Seed,17.1f));
FVector3f Fine(NoiseX*RF*3.0f+VoxelHash::SeedOffset(Seed,19.1f)+2000.0f,
NoiseY*RF*3.0f+VoxelHash::SeedOffset(Seed,23.7f)+2500.0f,
EffectiveZ*RF*3.0f+VoxelHash::SeedOffset(Seed,29.3f)+3000.0f);
if(Params.DomainWarpStrength>0.0f)
{
const float WF=Params.DomainWarpFrequency,WS=Params.DomainWarpStrength;
float WX=0.0f,WY=0.0f,WZ=0.0f;
VoxelNoise::Perlin3D_x3(
NoiseX*WF+VoxelHash::SeedOffset(Seed,5.2f),
NoiseY*WF+VoxelHash::SeedOffset(Seed,1.3f),
EffectiveZ*WF+VoxelHash::SeedOffset(Seed,9.7f),
NoiseX*WF+100.0f+VoxelHash::SeedOffset(Seed,7.7f),
NoiseY*WF+200.0f+VoxelHash::SeedOffset(Seed,3.1f),
EffectiveZ*WF+300.0f,
NoiseX*WF+400.0f,
NoiseY*WF+500.0f+VoxelHash::SeedOffset(Seed,11.9f),
EffectiveZ*WF+600.0f+VoxelHash::SeedOffset(Seed,13.3f),WX,WY,WZ);
WX*=VOXEL_NOISE_SCALE*WS;WY*=VOXEL_NOISE_SCALE*WS;WZ*=VOXEL_NOISE_SCALE*WS;
Main+=FVector3f(WX,WY,WZ);Fine+=FVector3f(WX,WY,WZ);
}
float Rough=0.0f,FineValue=0.0f;
switch(Params.RoughnessNoiseType)
{
case EVoxelNoiseType::Ridged:
{
float MainFBM=0.0f,MainRidged=0.0f,FineFBM=0.0f,FineRidged=0.0f;
VoxelNoise::FractalPair<false,true>(Main.X,Main.Y,Main.Z,3,
Fine.X,Fine.Y,Fine.Z,2,MainFBM,MainRidged,FineFBM,FineRidged);
Rough=MainRidged;FineValue=FineRidged;
break;
}
case EVoxelNoiseType::Mixed:
{
float MainFBM=0.0f,MainRidged=0.0f,FineFBM=0.0f,FineRidged=0.0f;
VoxelNoise::FractalPair<true,true>(Main.X,Main.Y,Main.Z,3,
Fine.X,Fine.Y,Fine.Z,2,MainFBM,MainRidged,FineFBM,FineRidged);
Rough=MainFBM*0.5f+MainRidged*0.5f;
FineValue=FineFBM*0.5f+FineRidged*0.5f;
break;
}
case EVoxelNoiseType::Cellular:
Rough=VoxelNoise::Cellular3D(Main);FineValue=VoxelNoise::Cellular3D(Fine);break;
case EVoxelNoiseType::FBM:
default:
{
float MainFBM=0.0f,MainRidged=0.0f,FineFBM=0.0f,FineRidged=0.0f;
VoxelNoise::FractalPair<true,false>(Main.X,Main.Y,Main.Z,3,
Fine.X,Fine.Y,Fine.Z,2,MainFBM,MainRidged,FineFBM,FineRidged);
Rough=MainFBM;FineValue=FineFBM;
break;
}
}
return (Rough+FineValue*0.4f)*VOXEL_NOISE_SCALE*Params.SurfaceRoughness;
// Keep CPU prediction and the near-field HLSL on one scalar source. The helper
// preserves the legacy seed offsets, octave order, and roughness families.
return VF_FieldOwnerRoughnessCore(static_cast<float>(X),static_cast<float>(Y),
static_cast<float>(Z),static_cast<uint32>(Owner->Seed),Params.SurfaceRoughness,
Params.RoughnessFrequency,Params.VerticalScale,Params.DomainWarpStrength,
Params.DomainWarpFrequency,static_cast<uint32>(Params.RoughnessNoiseType));
}
float OwnerCaveRoughness(double X,double Y,double Z,float SurfaceSDF,
+20 -1
View File
@@ -746,11 +746,30 @@ namespace VoxelForgeCore
const int32 cells=std::max(1,impl_->owner->CoarseTileCells);
const int32 step=std::max(1,extent/cells);
FarFieldTileInput result;
if(!impl_->shape->ExportFarFieldTileInput(ToNative(key).OriginVoxels(),cells,step,result,error))
if(!impl_->shape->ExportFarFieldTileInput(ToNative(key).OriginVoxels(),cells,step,false,result,error))
return std::nullopt;
return result;
}
std::optional<FarFieldTileInput> World::exportGpuFieldTile(const TileKey& key,
std::string& error) const
{
if(!impl_||!impl_->owner||!impl_->shape||!impl_->shape->IsBuilt())
{error="world must be compiled before exporting a GPU field tile";return std::nullopt;}
if(key.lod<0||key.lod>8)
{error="GPU field export accepts LOD0 through LOD8";return std::nullopt;}
if(!impl_->shape->HasFarWorld())
{error="world must include the far parent/connector shapes before export";return std::nullopt;}
const int32 extent=CHUNK_SIZE<<key.lod;
const bool nearDetail=key.lod<impl_->configuration.fullResolutionLodCount;
const int32 cells=nearDetail?CHUNK_SIZE:std::max(1,impl_->owner->CoarseTileCells);
const int32 step=std::max(1,extent/cells);
FarFieldTileInput result;
if(!impl_->shape->ExportFarFieldTileInput(ToNative(key).OriginVoxels(),cells,step,
nearDetail,result,error))return std::nullopt;
return result;
}
bool World::isFarFieldTileEligible(const TileKey& key) const
{
if(!impl_||!impl_->owner||!impl_->shape||!impl_->shape->IsBuilt()
+188
View File
@@ -68,6 +68,7 @@ static const VF_FieldI32 VF_FIELD_PRIMITIVE_HAS_FLOOR = 8;
static const VF_FieldI32 VF_FIELD_PRIMITIVE_CURVED_FLOOR = 16;
static const VF_FieldI32 VF_FIELD_PRIMITIVE_CARVE = 32;
static const VF_FieldI32 VF_FIELD_PRIMITIVE_CRITICAL = 64;
static const VF_FieldI32 VF_FIELD_PRIMITIVE_PASSAGE = 128;
VF_FIELD_INLINE VF_FieldReal VF_FieldEvaluateFloorProfile(VF_FieldReal a, VF_FieldReal b,
VF_FieldReal tangentA, VF_FieldReal tangentB, VF_FieldReal length,
@@ -249,6 +250,193 @@ VF_FIELD_INLINE float VF_FieldSurfaceRelief(float x, float y, float z, VF_FieldU
return 1.20f * macro + (0.80f + 0.25f * macro) * (0.40f * mid + 0.60f * fine);
}
// Scalar version of VoxelNoise::Perlin3D and its owner-world roughness variant.
// The integer hash and operation order are shared so the standalone field and HLSL
// evaluate the same authored detail from the same world parameters.
VF_FIELD_INLINE VF_FieldU32 VF_FieldVoxelHashMix(VF_FieldU32 x)
{
x ^= x >> 16; x *= 0x45d9f3bu;
x ^= x >> 16; x *= 0x45d9f3bu;
x ^= x >> 16;
return x;
}
VF_FIELD_INLINE float VF_FieldVoxelSeedOffset(VF_FieldU32 seed,float siteKey)
{
const VF_FieldU32 site=VF_FIELD_CAST_U32(siteKey*100.0f+0.5f);
return VF_FIELD_CAST_F32(VF_FieldVoxelHashMix(seed^(site*2654435761u))&0x3FFFu);
}
VF_FIELD_INLINE VF_FieldU32 VF_FieldPerlinHash(VF_FieldI32 x,VF_FieldI32 y,VF_FieldI32 z)
{
VF_FieldU32 h=VF_FIELD_CAST_U32(x)*0x9E3779B1u
^VF_FIELD_CAST_U32(y)*0x85EBCA77u
^VF_FIELD_CAST_U32(z)*0xC2B2AE3Du;
h^=h>>15;h*=0x2C1B3C6Du;
h^=h>>12;h*=0x297A2D39u;
h^=h>>15;
return h;
}
VF_FIELD_INLINE float VF_FieldPerlinFade(float t)
{
const float inner=t*(t*6.0f-15.0f)+10.0f;
const float t3=t*t*t;
return t3*inner;
}
VF_FIELD_INLINE float VF_FieldPerlinGrad(VF_FieldU32 hash,float x,float y,float z)
{
const VF_FieldU32 h=hash&15u;
const float u=(h&8u)==0u?x:y;
float v;
if((h&12u)==0u)v=y;
else if((h&13u)==12u)v=x;
else v=z;
const float ru=(h&1u)==0u?u:-u;
const float rv=(h&2u)==0u?v:-v;
return ru+rv;
}
VF_FIELD_INLINE float VF_FieldPerlinLerp(float a,float b,float t)
{ return a+t*(b-a); }
VF_FIELD_INLINE float VF_FieldPerlin3D(float x,float y,float z)
{
const float xf=VF_FIELD_FLOOR(x),yf=VF_FIELD_FLOOR(y),zf=VF_FIELD_FLOOR(z);
const VF_FieldI32 X=VF_FIELD_CAST_I32(xf),Y=VF_FIELD_CAST_I32(yf),Z=VF_FIELD_CAST_I32(zf);
const float fx=x-xf,fy=y-yf,fz=z-zf;
const float su=VF_FieldPerlinFade(fx),sv=VF_FieldPerlinFade(fy),sw=VF_FieldPerlinFade(fz);
const VF_FieldU32 h000=VF_FieldPerlinHash(X,Y,Z),h100=VF_FieldPerlinHash(X+1,Y,Z);
const VF_FieldU32 h010=VF_FieldPerlinHash(X,Y+1,Z),h110=VF_FieldPerlinHash(X+1,Y+1,Z);
const VF_FieldU32 h001=VF_FieldPerlinHash(X,Y,Z+1),h101=VF_FieldPerlinHash(X+1,Y,Z+1);
const VF_FieldU32 h011=VF_FieldPerlinHash(X,Y+1,Z+1),h111=VF_FieldPerlinHash(X+1,Y+1,Z+1);
const float fx1=fx-1.0f,fy1=fy-1.0f,fz1=fz-1.0f;
const float n000=VF_FieldPerlinGrad(h000,fx,fy,fz);
const float n100=VF_FieldPerlinGrad(h100,fx1,fy,fz);
const float n010=VF_FieldPerlinGrad(h010,fx,fy1,fz);
const float n110=VF_FieldPerlinGrad(h110,fx1,fy1,fz);
const float n001=VF_FieldPerlinGrad(h001,fx,fy,fz1);
const float n101=VF_FieldPerlinGrad(h101,fx1,fy,fz1);
const float n011=VF_FieldPerlinGrad(h011,fx,fy1,fz1);
const float n111=VF_FieldPerlinGrad(h111,fx1,fy1,fz1);
const float x00=VF_FieldPerlinLerp(n000,n100,su);
const float x10=VF_FieldPerlinLerp(n010,n110,su);
const float x01=VF_FieldPerlinLerp(n001,n101,su);
const float x11=VF_FieldPerlinLerp(n011,n111,su);
const float y0=VF_FieldPerlinLerp(x00,x10,sv);
const float y1=VF_FieldPerlinLerp(x01,x11,sv);
return VF_FieldPerlinLerp(y0,y1,sw);
}
VF_FIELD_INLINE float VF_FieldOwnerFractal(float x,float y,float z,VF_FieldI32 octaves,
VF_FieldI32 mode)
{
float total=0.0f,maxValue=0.0f,frequency=1.0f,amplitude=1.0f,weight=1.0f;
for(VF_FieldI32 i=0;i<octaves;++i)
{
const float noise=VF_FieldPerlin3D(x*frequency,y*frequency,z*frequency);
if(mode==0)total+=noise*amplitude;
else
{
float ridge=noise*1.25f;
ridge=1.0f-VF_FIELD_ABS(ridge);
ridge=ridge*ridge;
ridge*=weight;
weight=VF_FIELD_CLAMP(ridge*2.0f,0.0f,1.0f);
total+=ridge*amplitude;
}
maxValue+=amplitude;
amplitude*=0.5f;
frequency*=2.0f;
}
const float result=total/maxValue;
return mode==0?result:result*2.0f-1.0f;
}
VF_FIELD_INLINE float VF_FieldOwnerCellular(float x,float y,float z)
{
const VF_FieldI32 cellX=VF_FIELD_CAST_I32(VF_FIELD_FLOOR(x));
const VF_FieldI32 cellY=VF_FIELD_CAST_I32(VF_FIELD_FLOOR(y));
const VF_FieldI32 cellZ=VF_FIELD_CAST_I32(VF_FIELD_FLOOR(z));
const float fracX=x-VF_FIELD_CAST_F32(cellX),fracY=y-VF_FIELD_CAST_F32(cellY),
fracZ=z-VF_FIELD_CAST_F32(cellZ);
float first=3.402823466e+38f,second=3.402823466e+38f;
for(VF_FieldI32 dz=-1;dz<=1;++dz)
for(VF_FieldI32 dy=-1;dy<=1;++dy)
for(VF_FieldI32 dx=-1;dx<=1;++dx)
{
const VF_FieldI32 nx=cellX+dx,ny=cellY+dy,nz=cellZ+dz;
const VF_FieldU32 h=VF_FieldVoxelHashMix(
VF_FIELD_CAST_U32(nx+0x7FFFFFFF)
^VF_FieldVoxelHashMix(VF_FIELD_CAST_U32(ny+0x7FFFFFFF)*2654435761u)
^VF_FieldVoxelHashMix(VF_FIELD_CAST_U32(nz+0x7FFFFFFF)*374761393u));
const float fpx=VF_FIELD_CAST_F32(dx)
+VF_FIELD_CAST_F32(h&0xFFFFFFu)*(1.0f/16777216.0f)-fracX;
const VF_FieldU32 hy=VF_FieldVoxelHashMix(h^0x12345678u);
const VF_FieldU32 hz=VF_FieldVoxelHashMix(h^0x9ABCDEF0u);
const float fpy=VF_FIELD_CAST_F32(dy)
+VF_FIELD_CAST_F32(hy&0xFFFFFFu)*(1.0f/16777216.0f)-fracY;
const float fpz=VF_FIELD_CAST_F32(dz)
+VF_FIELD_CAST_F32(hz&0xFFFFFFu)*(1.0f/16777216.0f)-fracZ;
const float distanceSquared=fpx*fpx+fpy*fpy+fpz*fpz;
if(distanceSquared<first){second=first;first=distanceSquared;}
else if(distanceSquared<second)second=distanceSquared;
}
return (VF_FIELD_SQRT(second)-VF_FIELD_SQRT(first))*2.0f-1.0f;
}
VF_FIELD_INLINE float VF_FieldOwnerRoughnessCore(float x,float y,float z,
VF_FieldU32 seed,float surfaceRoughness,float roughnessFrequency,float verticalScale,
float domainWarpStrength,float domainWarpFrequency,VF_FieldU32 noiseType)
{
if(!(roughnessFrequency>0.0f))return 0.0f;
const float effectiveZ=verticalScale>0.0f&&verticalScale!=1.0f?z/verticalScale:z;
const float mainX=x*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,11.3f);
const float mainY=y*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,13.7f);
const float mainZ=effectiveZ*roughnessFrequency+VF_FieldVoxelSeedOffset(seed,17.1f);
float fineX=x*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,19.1f)+2000.0f;
float fineY=y*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,23.7f)+2500.0f;
float fineZ=effectiveZ*roughnessFrequency*3.0f+VF_FieldVoxelSeedOffset(seed,29.3f)+3000.0f;
float mx=mainX,my=mainY,mz=mainZ;
if(domainWarpStrength>0.0f)
{
const float wf=domainWarpFrequency,ws=domainWarpStrength;
float wx=VF_FieldPerlin3D(x*wf+VF_FieldVoxelSeedOffset(seed,5.2f),
y*wf+VF_FieldVoxelSeedOffset(seed,1.3f),
effectiveZ*wf+VF_FieldVoxelSeedOffset(seed,9.7f));
float wy=VF_FieldPerlin3D(x*wf+100.0f+VF_FieldVoxelSeedOffset(seed,7.7f),
y*wf+200.0f+VF_FieldVoxelSeedOffset(seed,3.1f),effectiveZ*wf+300.0f);
float wz=VF_FieldPerlin3D(x*wf+400.0f,y*wf+500.0f+VF_FieldVoxelSeedOffset(seed,11.9f),
effectiveZ*wf+600.0f+VF_FieldVoxelSeedOffset(seed,13.3f));
wx*=1.25f*ws;wy*=1.25f*ws;wz*=1.25f*ws;
mx+=wx;my+=wy;mz+=wz;
fineX+=wx;fineY+=wy;fineZ+=wz;
}
float rough=0.0f,fine=0.0f;
if(noiseType==1u)
{
rough=VF_FieldOwnerFractal(mx,my,mz,3,1);
fine=VF_FieldOwnerFractal(fineX,fineY,fineZ,2,1);
}
else if(noiseType==2u)
{
rough=(VF_FieldOwnerFractal(mx,my,mz,3,0)+VF_FieldOwnerFractal(mx,my,mz,3,1))*0.5f;
fine=(VF_FieldOwnerFractal(fineX,fineY,fineZ,2,0)+VF_FieldOwnerFractal(fineX,fineY,fineZ,2,1))*0.5f;
}
else if(noiseType==3u)
{
rough=VF_FieldOwnerCellular(mx,my,mz);
fine=VF_FieldOwnerCellular(fineX,fineY,fineZ);
}
else
{
rough=VF_FieldOwnerFractal(mx,my,mz,3,0);
fine=VF_FieldOwnerFractal(fineX,fineY,fineZ,2,0);
}
return (rough+fine*0.4f)*1.25f*surfaceRoughness;
}
VF_FIELD_INLINE float VF_FieldSmoothUnit(float value)
{
#if defined(VF_FIELD_HLSL)
@@ -0,0 +1,51 @@
[CmdletBinding()]
param()
$ErrorActionPreference = 'Stop'
$HostProcess = Get-Process -Id $PID
$HostProcess.PriorityClass = 'BelowNormal'
$HostProcess.ProcessorAffinity = [IntPtr]0xFF00
$Standalone = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\..'))
$Executable = Join-Path $Standalone 'bin\VoxelForgeGpuFieldStep6NearProbe.exe'
$Stdout = Join-Path $PSScriptRoot 'step6_cpu_hash_fresh_w8.stdout.log'
$Stderr = Join-Path $PSScriptRoot 'step6_cpu_hash_fresh_w8.stderr.log'
$Arguments = @('--stream-benchmark','--shape-world','--force-generate','--stream-hash','--workers=8','--clip-radius=3')
if (-not (Test-Path -LiteralPath $Executable -PathType Leaf)) { throw "Executable not found: $Executable" }
for ($Attempt = 0; $Attempt -lt 2; ++$Attempt) {
if ($Attempt -eq 1) {
Write-Output '0xC0000142 encountered; waiting 60 seconds before the permitted retry.'
Start-Sleep -Seconds 60
}
$Child = Start-Process -FilePath $Executable -ArgumentList $Arguments -WorkingDirectory $Standalone `
-WindowStyle Hidden -PassThru -RedirectStandardOutput $Stdout -RedirectStandardError $Stderr
$PeakWorkingSet = 0L
$PeakPrivate = 0L
$OverLimit = $false
while (-not $Child.HasExited) {
$Child.Refresh()
if ($Child.HasExited) { break }
$Child.PriorityClass = 'BelowNormal'
$Child.ProcessorAffinity = [IntPtr]0xFF00
$PeakWorkingSet = [Math]::Max($PeakWorkingSet,$Child.WorkingSet64)
$PeakPrivate = [Math]::Max($PeakPrivate,$Child.PrivateMemorySize64)
if ($Child.PrivateMemorySize64 -ge 8GB) {
$OverLimit = $true
$Child.Kill()
$Child.WaitForExit()
break
}
Start-Sleep -Milliseconds 100
}
$Child.WaitForExit()
$Child.Refresh()
if ($Child.ExitCode -eq -1073741502 -and $Attempt -eq 0) { continue }
if ($Child.ExitCode -eq -1073741502) { throw '0xC0000142 repeated after the one retry; stopping.' }
if ($OverLimit) { throw 'CPU hash run stopped at the 8 GB process memory limit.' }
$Log = Get-Content -LiteralPath $Stdout -Raw
if ($Child.ExitCode -ne 0 -or -not $Log.Contains('[StreamFullClipmap]')) {
throw "Hash run failed; exit=$($Child.ExitCode) stdout=$Stdout stderr=$Stderr"
}
Write-Output "RUN_EXIT pid=$($Child.Id) priority=BelowNormal affinity=0xFF00 peak_working_set_gb=$([Math]::Round($PeakWorkingSet/1GB,2)) peak_private_gb=$([Math]::Round($PeakPrivate/1GB,2)) exit_code=$($Child.ExitCode) stdout=$Stdout stderr=$Stderr"
exit 0
}