wip(standalone): GPU step 13 -- near base/skirts/connectors cheaper to compile; warm-up still ~2.0 s

Cold first use: near base 4.2 ms, near detail 1,595 ms (the floor), connector
rings 630 -> 409, skirt classify+emit ~1,409 -> 366. Production warm-up is
still ~2.03-2.06 s; whole view median CPU 1.356 s vs hybrid 3.044 s.
Near 960 + far 1,114 tiles: 0 topology/protected/thin diffs vs CPU and WARP;
hashes, walk 5,642/5,642, survival pass.

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-07 07:41:31 +02:00
1 parent 05b1523c54
commit a96fd0b95b
18 files changed
+776 -75

No files matched your search

@@ -334,7 +334,33 @@ float NearOwnerRoughness(float3 position,float surfaceSdf,float caveInfluence,
return (anchoredWeight*anchored+directWeight*direct)*normalization;
}
float NearFieldDensityAt(float3 position,uint clampNearZero,out uint distanceEvaluations)
void NearDetailValueNoise(float3 position,out float macro,out float mid,out float fine)
{
macro=0.0f;mid=0.0f;fine=0.0f;
[loop]
for(uint octave=0;octave<3;++octave)
{
const int wavelength=octave==0?32:(octave==1?16:4);
const uint seedOffset=octave==0?0xB5297A4Du:
(octave==1?0x63D83595u:0xA511E9B3u);
const float value=VF_FieldValueNoise(position.x,position.y,position.z,
wavelength,FarFieldSeed^seedOffset);
if(octave==0)macro=value;
else if(octave==1)mid=value;
else fine=value;
}
}
struct NearFieldBaseData
{
float4 geometry;
float4 influences;
};
StructuredBuffer<NearFieldBaseData> FarNearDetailBaseInput : register(t20);
RWStructuredBuffer<NearFieldBaseData> FarNearDetailBaseOutput : register(u1);
NearFieldBaseData NearFieldBaseAt(float3 position,out uint distanceEvaluations)
{
const FarFieldSpatialBin range=FarFieldFindBin(position);
float cave=100000.0f,overlay=-100000.0f;
@@ -383,18 +409,27 @@ float NearFieldDensityAt(float3 position,uint clampNearZero,out uint distanceEva
const float floorInfluence=caveInfluence*caveFloorInfluence;
const float passageInfluence=caveInfluence*cavePassageInfluence;
const float surfaceSdf=base<=carveOrOverlay?base:(cave>=overlay?cave:overlay);
float rockDistance=VF_FieldSmoothMin(base,carveOrOverlay,FarStrataBlend);
const float rockDistance=VF_FieldSmoothMin(base,carveOrOverlay,FarStrataBlend);
NearFieldBaseData result;
result.geometry=float4(rockDistance,surfaceSdf,caveInfluence,floorInfluence);
result.influences=float4(passageInfluence,0,0,0);
return result;
}
float NearFieldDetailRockDistance(float3 position,NearFieldBaseData baseData)
{
float rockDistance=baseData.geometry.x;
const float surfaceSdf=baseData.geometry.y;
const float caveInfluence=baseData.geometry.z;
const float floorInfluence=baseData.geometry.w;
const float passageInfluence=baseData.influences.x;
if(NearFieldMode!=0
&&all(position>=float3(FarDetailMinVoxel.xyz))
&&all(position<=float3(FarDetailMaxVoxel.xyz))
&&abs(rockDistance)<=4.125f)
{
const float macro=VF_FieldValueNoise(position.x,position.y,position.z,32,
FarFieldSeed^0xB5297A4Du);
const float mid=VF_FieldValueNoise(position.x,position.y,position.z,16,
FarFieldSeed^0x63D83595u);
const float fine=VF_FieldValueNoise(position.x,position.y,position.z,4,
FarFieldSeed^0xA511E9B3u);
float macro,mid,fine;
NearDetailValueNoise(position,macro,mid,fine);
const float relief=1.20f*macro+(0.80f+0.25f*macro)*(0.40f*mid+0.60f*fine);
const float passageBandRelief=1.20f*macro+(0.80f+0.25f*macro)*(0.40f*mid);
float ownerRelief=0.0f;
@@ -446,6 +481,13 @@ float NearFieldDensityAt(float3 position,uint clampNearZero,out uint distanceEva
}
rockDistance+=clamp(detail,-3.9f,3.9f)*fade;
}
return rockDistance;
}
float NearFieldDensityAt(float3 position,uint clampNearZero,out uint distanceEvaluations)
{
const NearFieldBaseData baseData=NearFieldBaseAt(position,distanceEvaluations);
const float rockDistance=NearFieldDetailRockDistance(position,baseData);
float density=-rockDistance;
if(clampNearZero!=0&&abs(density)<0.05f)
density=rockDistance>=0.0f?-0.05f:0.05f;
@@ -517,7 +559,21 @@ void EvaluateNearFieldCS(uint3 dispatchId : SV_DispatchThreadID)
const float3 position=float3(OriginX,OriginY,OriginZ)
+float3(int(x)-1,int(y)-1,int(z)-1)*StepVoxels;
uint distanceEvaluations=0;
const float nearNormalDensity=NearFieldDensityAt(position,0,distanceEvaluations);
FarNearDetailBaseOutput[index]=NearFieldBaseAt(position,distanceEvaluations);
if(FarEvalCounterEnabled!=0)FarFieldEvalCounters[index]=distanceEvaluations;
}
[numthreads(64,1,1)]
void ApplyNearFieldDetailCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint index=dispatchId.x;
if(index>=FarSampleCount)return;
const uint x=index%SampleDim;
const uint y=(index/SampleDim)%SampleDim;
const uint z=index/(SampleDim*SampleDim);
const float3 position=float3(OriginX,OriginY,OriginZ)
+float3(int(x)-1,int(y)-1,int(z)-1)*StepVoxels;
const float nearNormalDensity=-NearFieldDetailRockDistance(position,FarNearDetailBaseInput[index]);
float density=nearNormalDensity;
if(abs(density)<0.05f)
density=density<0.0f?-0.05f:(density>0.0f?0.05f:-0.05f);
@@ -540,7 +596,6 @@ void EvaluateNearFieldCS(uint3 dispatchId : SV_DispatchThreadID)
else if(protectedSolid!=0)density=-max(abs(density),1.0f/256.0f);
FarFieldDensity[index]=density;
FarNearNormalDensityOutput[index]=nearNormalDensity;
if(FarEvalCounterEnabled!=0)FarFieldEvalCounters[index]=distanceEvaluations;
}
float FarRockDistanceAt(float3 position,int3 cachedBinCoord,FarFieldSpatialBin cachedRange)
@@ -610,6 +665,16 @@ struct FarSkirtVertex
float density;
};
struct FarSkirtCachedSamples
{
float2 endpointDensities;
float4 centerDensities;
uint4 metadata;
};
StructuredBuffer<FarSkirtCachedSamples> FarSkirtCachedProbeInput : register(t21);
RWStructuredBuffer<FarSkirtCachedSamples> FarSkirtCachedProbeOutput : register(u2);
float FarSkirtDensityAtVoxel(float3 position)
{
const int3 binCoord=int3(floor(position/max(1.0f,(float)FarSpatialBinSize)));
@@ -635,7 +700,9 @@ FarSkirtVertex FarSkirtInterpolate(FarSkirtVertex a,FarSkirtVertex b,float t)
FarSkirtVertex result;
result.position=lerp(a.position,b.position,t);
result.normal=normalize(lerp(a.normal,b.normal,t));
result.density=FarSkirtDensityAtCm(result.position);
// Clipping only uses the interpolated position and normal after insertion.
// Its density is never fed back into an edge decision or emitted vertex.
result.density=lerp(a.density,b.density,t);
return result;
}
@@ -662,7 +729,8 @@ void FarSkirtClipTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
}
}
uint FarSkirtSourceTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c)
uint FarSkirtSourceTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
inout FarSkirtCachedSamples cached)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
@@ -673,7 +741,13 @@ uint FarSkirtSourceTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,FarSkir
{
const float3 centerVoxel=(polygon[0].position+polygon[fan].position
+polygon[fan+1].position)/(3.0f*VoxelSizeCm);
if(FarSkirtDensityAtVoxel(centerVoxel)<=0.0f)vertexCount+=6;
const float centerDensity=FarSkirtDensityAtVoxel(centerVoxel);
const uint centerIndex=cached.metadata.x++;
if(centerIndex==0)cached.centerDensities.x=centerDensity;
else if(centerIndex==1)cached.centerDensities.y=centerDensity;
else if(centerIndex==2)cached.centerDensities.z=centerDensity;
else cached.centerDensities.w=centerDensity;
if(centerDensity<=0.0f)vertexCount+=6;
}
return vertexCount;
}
@@ -711,8 +785,19 @@ FarSkirtVertex FarSkirtExtrudedVertex(FarSkirtVertex source)
return vertex;
}
uint FarSkirtEdgeOutputCount(uint edgeVertexId)
FarSkirtVertex FarSkirtExtrudedVertexCached(FarSkirtVertex source,float density)
{
FarSkirtVertex vertex=source;
vertex.position-=source.normal*(max(1.0f,FarSkirtDepthVoxels)*VoxelSizeCm);
vertex.density=density;
return vertex;
}
uint FarSkirtEdgeOutputCount(uint edgeVertexId,out FarSkirtCachedSamples cached)
{
cached.endpointDensities=0.0f;
cached.centerDensities=0.0f;
cached.metadata=0;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),OutputVertexCapacity);
if(edgeVertexId>=surfaceVertexCount)return 0;
const uint triangleBase=edgeVertexId-(edgeVertexId%3);
@@ -722,8 +807,9 @@ uint FarSkirtEdgeOutputCount(uint edgeVertexId)
if((FarSkirtBoundaryFaceMask(a.position,b.position)&FarSkirtFaceMask)==0)return 0;
const FarSkirtVertex a2=FarSkirtExtrudedVertex(a);
const FarSkirtVertex b2=FarSkirtExtrudedVertex(b);
return FarSkirtSourceTriangleOutputCount(a,b,b2)
+FarSkirtSourceTriangleOutputCount(a,b2,a2);
cached.endpointDensities=float2(a2.density,b2.density);
return FarSkirtSourceTriangleOutputCount(a,b,b2,cached)
+FarSkirtSourceTriangleOutputCount(a,b2,a2,cached);
}
void FarSkirtStoreVertex(uint outputId,FarSkirtVertex vertex,uint panelBaseVertex)
@@ -752,6 +838,7 @@ void FarSkirtEmitTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
}
void FarSkirtEmitSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
float4 centerDensities,inout uint centerIndex,
uint panelBaseVertex,uint edgeBase,inout uint edgeCursor)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
@@ -760,9 +847,10 @@ void FarSkirtEmitSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
const float3 centerVoxel=(polygon[0].position+polygon[fan].position
+polygon[fan+1].position)/(3.0f*VoxelSizeCm);
if(FarSkirtDensityAtVoxel(centerVoxel)<=0.0f)
const uint index=centerIndex++;
const float centerDensity=index==0?centerDensities.x:index==1?centerDensities.y:
index==2?centerDensities.z:centerDensities.w;
if(centerDensity<=0.0f)
FarSkirtEmitTriangle(polygon[0],polygon[fan],polygon[fan+1],
panelBaseVertex,edgeBase,edgeCursor);
}
@@ -780,24 +868,30 @@ float FarConnectorRadius(float3 center, float3 direction, float nominalRadius)
const float minRadius=max(0.0f,nominalRadius-maxOffset);
const float maxRadius=nominalRadius+maxOffset;
float radius=nominalRadius;
float residual=FarRockDistanceAt(center+direction*radius,cachedBinCoord,cachedRange);
bool converged=abs(residual)<=1.0f;
if(!converged)
{
// Most connector fields are close to a unit-gradient SDF along the
// radial ray. Try that correction first and verify it before accepting.
radius=clamp(radius-residual,minRadius,maxRadius);
residual=FarRockDistanceAt(center+direction*radius,cachedBinCoord,cachedRange);
converged=abs(residual)<=1.0f;
}
float residual=0.0f;
bool converged=false;
// Keep nominal probing, the first correction, and the two refinement
// iterations in one loop body. This gives the compiler one shared field
// probe site for the repeated residual evaluation without changing order.
[loop]
for(uint refine=0;refine<2&&!converged;++refine)
for(uint phase=0;phase<4&&!converged;++phase)
{
const float distance=residual;
const float nextDistance=FarRockDistanceAt(center+direction*(radius+4.0f),cachedBinCoord,cachedRange);
const float slope=(nextDistance-distance)*0.25f;
const float correction=abs(slope)>0.125f?distance/slope:distance;
radius=clamp(radius-correction,minRadius,maxRadius);
if(phase==0)
radius=nominalRadius;
else if(phase==1)
{
// Most connector fields are close to a unit-gradient SDF along the
// radial ray. Try that correction first and verify it before accepting.
radius=clamp(radius-residual,minRadius,maxRadius);
}
else
{
const float distance=residual;
const float nextDistance=FarRockDistanceAt(center+direction*(radius+4.0f),cachedBinCoord,cachedRange);
const float slope=(nextDistance-distance)*0.25f;
const float correction=abs(slope)>0.125f?distance/slope:distance;
radius=clamp(radius-correction,minRadius,maxRadius);
}
residual=FarRockDistanceAt(center+direction*radius,cachedBinCoord,cachedRange);
converged=abs(residual)<=1.0f;
}
@@ -1193,7 +1287,9 @@ void ClassifyFarSkirtsCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint edgeVertexId=dispatchId.x;
if(edgeVertexId>=OutputVertexCapacity)return;
FarSkirtScratch[edgeVertexId]=FarSkirtEdgeOutputCount(edgeVertexId);
FarSkirtCachedSamples cached;
FarSkirtScratch[edgeVertexId]=FarSkirtEdgeOutputCount(edgeVertexId,cached);
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
}
[numthreads(1,1,1)]
@@ -1230,19 +1326,21 @@ void EmitFarSkirtsCS(uint3 dispatchId : SV_DispatchThreadID)
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),
OutputVertexCapacity);
if(edgeVertexId>=surfaceVertexCount)return;
if(FarSkirtEdgeOutputCount(edgeVertexId)==0)return;
const uint triangleBase=edgeVertexId-(edgeVertexId%3);
const uint edge=edgeVertexId%3;
const FarSkirtVertex a=FarSkirtSurfaceVertex(triangleBase+edge);
const FarSkirtVertex b=FarSkirtSurfaceVertex(triangleBase+(edge+1)%3);
if((FarSkirtBoundaryFaceMask(a.position,b.position)&FarSkirtFaceMask)==0)return;
const FarSkirtVertex a2=FarSkirtExtrudedVertex(a);
const FarSkirtVertex b2=FarSkirtExtrudedVertex(b);
const FarSkirtCachedSamples cached=FarSkirtCachedProbeInput[edgeVertexId];
const FarSkirtVertex a2=FarSkirtExtrudedVertexCached(a,cached.endpointDensities.x);
const FarSkirtVertex b2=FarSkirtExtrudedVertexCached(b,cached.endpointDensities.y);
const uint panelBaseVertex=FarConnectorDrawArgs.Load(OutputArgsByteOffset+28);
const uint edgeBase=FarConnectorVertexCount+FarSkirtScratch[edgeVertexId];
uint edgeCursor=0;
FarSkirtEmitSourceTriangle(a,b,b2,panelBaseVertex,edgeBase,edgeCursor);
FarSkirtEmitSourceTriangle(a,b2,a2,panelBaseVertex,edgeBase,edgeCursor);
uint edgeCursor=0,centerIndex=0;
FarSkirtEmitSourceTriangle(a,b,b2,cached.centerDensities,centerIndex,
panelBaseVertex,edgeBase,edgeCursor);
FarSkirtEmitSourceTriangle(a,b2,a2,cached.centerDensities,centerIndex,
panelBaseVertex,edgeBase,edgeCursor);
}
// Smoke probe for the dual-language noise path. This is intentionally separate from the mesh