wip(standalone): GPU step 28 -- skirted near tiles on GPU (correct, but SLOWER); 16 shape workers

Luna: near skirts were CPU-only by implementation gap, not correctness. Ported with
near-resolution refinement and overflow fallback; near-probe preparation split out so
the skirt kernels no longer inline the near field (first attempt: two fxc /O3 compiles
ran 10.5 h and were stopped). Shape compile proven identical at W1/W8/W16.
-SkipCpuDetailBand retired (154/640 skirt audit failures, +174 ms planning).
Audits: hashes W1/W8/W16, walk 5,642/5,642, whole-near 960 tiles + 640 skirt faces
0 sign/topology diffs (one 0.001 cm vertex-key delta), far/thin 0 diffs, both
survivals pass with 2,074 candidates at 7.00 / 7.02 GiB (was ~6.2), ten captures pass.

My runs outside the sandbox (Step28.exe). NOTE the machine was ~25% slower than last
night for every build (step 27 CPU full machine 0.97-1.02 s at night, 1.22-1.29 s now):
  0xFF00: CPU 1.337 / 1.291 / 1.295 s; GPU miss 1.337 s;
          GPU cached 1.663 / 1.424 / 1.617 s (GPU tiles 1,427 / 2,072 / 1,222)
  0xFFFF: CPU 1.221 / 1.231 / 1.236 s (step 27 same session 1.285 / 1.222 s)
          GPU cached 1.582 / 1.550 / 1.416, 1.635 / 1.441 / 1.470 / 1.445 s
          (GPU tiles vary 593-2,074; timestamps up to ~470 ms)
=> GPU route now slower than the CPU route measured alongside it. Step 27 GPU control
   was not clean (both exes load the same precompiled .cso files).

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-08 17:07:40 +02:00
1 parent 7d1808fdf2
commit 5aa285c3ef
26 files changed
+1536 -400

No files matched your search

@@ -32,6 +32,11 @@ cbuffer TileConstants : register(b0)
uint3 TileConstantsPadding;
};
uint FarSkirtNearProbeSurfaceCapacity()
{
return TileConstantsPadding.x;
}
cbuffer FarFieldConstants : register(b1)
{
float FarStrataLo;
@@ -62,7 +67,7 @@ cbuffer FarConnectorConstants : register(b2)
uint FarShapeCount;
uint FarSkirtFaceMask;
float FarSkirtDepthVoxels;
uint FarConnectorPadding;
uint FarConnectorOutputBaseVertex;
};
static const int3 CornerOffset[8] = {
@@ -448,6 +453,7 @@ NearFieldBaseData NearFieldBaseAt(float3 position,out uint distanceEvaluations)
const FarFieldSpatialBin range=FarFieldFindBin(position);
float cave=100000.0f,overlay=-100000.0f;
float caveFloorInfluence=0.0f,cavePassageInfluence=0.0f;
bool criticalAir=false;
distanceEvaluations=0;
[loop]
for(uint item=0;item<range.count;++item)
@@ -455,6 +461,22 @@ NearFieldBaseData NearFieldBaseAt(float3 position,out uint distanceEvaluations)
const VF_FieldPrimitive shape=FarShapes[FarSpatialBinShapeIds[range.offset+item]];
if((shape.flags&VF_FIELD_PRIMITIVE_CARVE)!=0)
{
if((shape.flags&VF_FIELD_PRIMITIVE_CRITICAL)!=0
&&all(position>=float3(shape.minVoxel[0],shape.minVoxel[1],shape.minVoxel[2]))
&&all(position<=float3(shape.maxVoxel[0],shape.maxVoxel[1],shape.maxVoxel[2])))
{
const int3 decidedPosition=int3(position);
float decidedDistance=VF_FieldPrimitiveDistance(shape,
(float)decidedPosition.x,(float)decidedPosition.y,(float)decidedPosition.z);
if((shape.flags&VF_FIELD_PRIMITIVE_HAS_FLOOR)!=0)
{
const float decidedFloor=VF_FieldPrimitiveFloorAt(shape,
(float)decidedPosition.x,(float)decidedPosition.y);
decidedDistance=VF_FieldSmoothMax(decidedDistance,
decidedFloor-(float)decidedPosition.z,shape.floorBlendRadius);
}
criticalAir=criticalAir||decidedDistance<=0.0f;
}
if(position.x<shape.minVoxel[0]-6||position.x>shape.maxVoxel[0]+6
||position.y<shape.minVoxel[1]-6||position.y>shape.maxVoxel[1]+6
||position.z<shape.minVoxel[2]-6||position.z>shape.maxVoxel[2]+6)continue;
@@ -495,7 +517,7 @@ NearFieldBaseData NearFieldBaseAt(float3 position,out uint distanceEvaluations)
const float rockDistance=VF_FieldSmoothMin(base,carveOrOverlay,FarStrataBlend);
NearFieldBaseData result;
result.geometry=float4(rockDistance,surfaceSdf,caveInfluence,floorInfluence);
result.influences=float4(passageInfluence,0,0,0);
result.influences=float4(passageInfluence,criticalAir?1.0f:0.0f,0,0);
return result;
}
@@ -567,10 +589,12 @@ float NearFieldDetailRockDistance(float3 position,NearFieldBaseData baseData)
return rockDistance;
}
[noinline]
float NearFieldDensityAt(float3 position,uint clampNearZero,out uint distanceEvaluations)
{
const NearFieldBaseData baseData=NearFieldBaseAt(position,distanceEvaluations);
const float rockDistance=NearFieldDetailRockDistance(position,baseData);
float rockDistance=NearFieldDetailRockDistance(position,baseData);
if(baseData.influences.y!=0.0f)rockDistance=min(rockDistance,-1.0f/16.0f);
float density=-rockDistance;
if(clampNearZero!=0&&abs(density)<0.05f)
density=rockDistance>=0.0f?-0.05f:0.05f;
@@ -757,6 +781,48 @@ struct FarSkirtCachedSamples
StructuredBuffer<FarSkirtCachedSamples> FarSkirtCachedProbeInput : register(t21);
RWStructuredBuffer<FarSkirtCachedSamples> FarSkirtCachedProbeOutput : register(u2);
StructuredBuffer<float4> FarSkirtNearProbeInput : register(t22);
ByteAddressBuffer FarSkirtNearProbeCounterInput : register(t23);
RWStructuredBuffer<float4> FarSkirtNearProbeOutput : register(u3);
RWByteAddressBuffer FarSkirtNearProbeCounter : register(u5);
RWByteAddressBuffer FarSkirtNearProbeDispatchArgs : register(u6);
static const uint FarSkirtNearRootProbeStride=11u;
static const uint FarSkirtNearChildProbeFanStride=4u;
static const uint FarSkirtNearChildProbeFanLimit=8u;
static const uint FarSkirtNearRootLimit=6u;
static const uint FarSkirtNearProbeStride=FarSkirtNearRootProbeStride
+FarSkirtNearChildProbeFanStride*FarSkirtNearChildProbeFanLimit;
static const float FarSkirtUnusedNearProbeDensity=-3.402823e+38f;
[noinline]
float NearSkirtDensityAtVoxel(float3 position)
{
uint ignoredEvaluations=0;
float density=NearFieldDensityAt(position,1,ignoredEvaluations);
const float3 latticePosition=(position-float3(OriginX,OriginY,OriginZ))/StepVoxels;
const int3 lattice=int3(round(latticePosition));
if(all(abs(latticePosition-float3(lattice))<=1.0e-4f)
&&all(lattice>=-1)&&all(lattice<=int(CellsPerAxis)+1))
{
const uint sample=SampleIndex(lattice);
const uint packedProxy=FarNearPackedProxy[sample];
if(packedProxy!=0xffffffffu)
{
const bool packedSignOverride=(packedProxy&0x40000000u)!=0u;
const bool packedRockSign=(packedProxy&0x80000000u)!=0u;
const uint magnitudeQ=packedProxy&0x3fffffffu;
const float magnitude=magnitudeQ==0u?4.125f:(float)magnitudeQ*(1.0f/256.0f);
const bool negative=packedSignOverride?packedRockSign:(density<=0.0f);
density=negative?-magnitude:magnitude;
}
const uint protectedAir=(FarProtectedAir[sample>>5]>>(sample&31u))&1u;
const uint protectedSolid=(FarProtectedSolid[sample>>5]>>(sample&31u))&1u;
if(protectedAir!=0u)density=max(abs(density),1.0f/256.0f);
else if(protectedSolid!=0u)density=-max(abs(density),1.0f/256.0f);
}
return density;
}
float FarSkirtDensityAtVoxel(float3 position)
{
@@ -783,8 +849,8 @@ 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));
// Clipping only uses the interpolated position and normal after insertion.
// Its density is never fed back into an edge decision or emitted vertex.
// Clipping uses the interpolated density only to find this root. Later near
// refinement reads its exact probe from FarSkirtNearProbeInput.
result.density=lerp(a.density,b.density,t);
return result;
}
@@ -812,8 +878,221 @@ void FarSkirtClipTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
}
}
void FarSkirtStoreNearRootProbePositions(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,uint probeBase)
{
const FarSkirtVertex midpoint01=FarSkirtInterpolate(a,b,0.5f);
const FarSkirtVertex midpoint12=FarSkirtInterpolate(b,c,0.5f);
const FarSkirtVertex midpoint20=FarSkirtInterpolate(c,a,0.5f);
FarSkirtNearProbeOutput[probeBase]=float4(a.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+1]=float4(b.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+2]=float4(c.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+3]=float4(
(a.position+b.position+c.position)/(3.0f*VoxelSizeCm),0.0f);
FarSkirtNearProbeOutput[probeBase+4]=float4(midpoint01.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+5]=float4(midpoint12.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+6]=float4(midpoint20.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[probeBase+7]=float4(
(a.position+midpoint01.position+midpoint20.position)/(3.0f*VoxelSizeCm),0.0f);
FarSkirtNearProbeOutput[probeBase+8]=float4(
(midpoint01.position+b.position+midpoint12.position)/(3.0f*VoxelSizeCm),0.0f);
FarSkirtNearProbeOutput[probeBase+9]=float4(
(midpoint20.position+midpoint12.position+c.position)/(3.0f*VoxelSizeCm),0.0f);
FarSkirtNearProbeOutput[probeBase+10]=float4(
(midpoint01.position+midpoint12.position+midpoint20.position)/(3.0f*VoxelSizeCm),0.0f);
[unroll]
for(uint childProbe=FarSkirtNearRootProbeStride;
childProbe<FarSkirtNearProbeStride;++childProbe)
FarSkirtNearProbeOutput[probeBase+childProbe]=float4(0.0f,0.0f,0.0f,
FarSkirtUnusedNearProbeDensity);
}
void FarSkirtPrepareNearSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,uint probeBase,inout uint rootIndex)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
if(polygonCount<3)return;
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
if(rootIndex<FarSkirtNearRootLimit)
FarSkirtStoreNearRootProbePositions(polygon[0],polygon[fan],polygon[fan+1],
probeBase+rootIndex*FarSkirtNearProbeStride);
++rootIndex;
}
}
FarSkirtVertex FarSkirtNearRootVertex(FarSkirtVertex vertex,float exactDensity,
FarSkirtVertex sourceA,FarSkirtVertex sourceB)
{
vertex.density=all(vertex.position==sourceA.position)||all(vertex.position==sourceB.position)
?0.0f:exactDensity;
return vertex;
}
void FarSkirtNearBuildChildTriangleOutput(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,uint probeBase,uint rootIndex,FarSkirtVertex sourceA,
FarSkirtVertex sourceB,uint childIndex,out FarSkirtVertex childA,
out FarSkirtVertex childB,out FarSkirtVertex childC)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride;
a=FarSkirtNearRootVertex(a,FarSkirtNearProbeOutput[base].w,sourceA,sourceB);
b=FarSkirtNearRootVertex(b,FarSkirtNearProbeOutput[base+1].w,sourceA,sourceB);
c=FarSkirtNearRootVertex(c,FarSkirtNearProbeOutput[base+2].w,sourceA,sourceB);
FarSkirtVertex midpoint01=FarSkirtInterpolate(a,b,0.5f);
FarSkirtVertex midpoint12=FarSkirtInterpolate(b,c,0.5f);
FarSkirtVertex midpoint20=FarSkirtInterpolate(c,a,0.5f);
midpoint01.density=FarSkirtNearProbeOutput[base+4].w;
midpoint12.density=FarSkirtNearProbeOutput[base+5].w;
midpoint20.density=FarSkirtNearProbeOutput[base+6].w;
if(childIndex==0){childA=a;childB=midpoint01;childC=midpoint20;}
else if(childIndex==1){childA=midpoint01;childB=b;childC=midpoint12;}
else if(childIndex==2){childA=midpoint20;childB=midpoint12;childC=c;}
else {childA=midpoint01;childB=midpoint12;childC=midpoint20;}
}
void FarSkirtStoreNearChildFanProbePositions(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,uint probeBase,uint rootIndex,uint childFanIndex)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride
+FarSkirtNearRootProbeStride+childFanIndex*FarSkirtNearChildProbeFanStride;
FarSkirtNearProbeOutput[base]=float4(a.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[base+1]=float4(b.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[base+2]=float4(c.position/VoxelSizeCm,0.0f);
FarSkirtNearProbeOutput[base+3]=float4(
(a.position+b.position+c.position)/(3.0f*VoxelSizeCm),0.0f);
}
float FarSkirtNearRootMaximumOutput(uint probeBase,uint rootIndex)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride;
float maximumDensity=FarSkirtNearProbeOutput[base].w;
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+1].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+2].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+3].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+4].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+5].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeOutput[base+6].w);
return maximumDensity;
}
void FarSkirtPrepareNearChildRoot(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
uint probeBase,uint rootIndex,FarSkirtVertex sourceA,FarSkirtVertex sourceB)
{
if(FarSkirtNearRootMaximumOutput(probeBase,rootIndex)<=0.25f)return;
uint childFanIndex=0;
[unroll]
for(uint child=0;child<4;++child)
{
FarSkirtVertex childA,childB,childC;
FarSkirtNearBuildChildTriangleOutput(a,b,c,probeBase,rootIndex,sourceA,sourceB,
child,childA,childB,childC);
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(childA,childB,childC,polygon,polygonCount);
if(polygonCount<3)continue;
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
FarSkirtStoreNearChildFanProbePositions(polygon[0],polygon[fan],polygon[fan+1],
probeBase,rootIndex,childFanIndex++);
}
}
void FarSkirtPrepareNearChildSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,FarSkirtVertex sourceA,FarSkirtVertex sourceB,uint probeBase,
inout uint rootIndex)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
if(polygonCount<3)return;
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
if(rootIndex<FarSkirtNearRootLimit)
FarSkirtPrepareNearChildRoot(polygon[0],polygon[fan],polygon[fan+1],
probeBase,rootIndex,sourceA,sourceB);
++rootIndex;
}
}
uint FarSkirtCountNearSourceTriangleRoots(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
return polygonCount<3?0:polygonCount-2;
}
float FarSkirtNearRootMaximum(uint probeBase,uint rootIndex)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride;
float maximumDensity=FarSkirtNearProbeInput[base].w;
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+1].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+2].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+3].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+4].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+5].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+6].w);
return maximumDensity;
}
void FarSkirtNearBuildChildTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
uint probeBase,uint rootIndex,FarSkirtVertex sourceA,FarSkirtVertex sourceB,
uint childIndex,out FarSkirtVertex childA,out FarSkirtVertex childB,
out FarSkirtVertex childC)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride;
a=FarSkirtNearRootVertex(a,FarSkirtNearProbeInput[base].w,sourceA,sourceB);
b=FarSkirtNearRootVertex(b,FarSkirtNearProbeInput[base+1].w,sourceA,sourceB);
c=FarSkirtNearRootVertex(c,FarSkirtNearProbeInput[base+2].w,sourceA,sourceB);
FarSkirtVertex midpoint01=FarSkirtInterpolate(a,b,0.5f);
FarSkirtVertex midpoint12=FarSkirtInterpolate(b,c,0.5f);
FarSkirtVertex midpoint20=FarSkirtInterpolate(c,a,0.5f);
midpoint01.density=FarSkirtNearProbeInput[base+4].w;
midpoint12.density=FarSkirtNearProbeInput[base+5].w;
midpoint20.density=FarSkirtNearProbeInput[base+6].w;
if(childIndex==0){childA=a;childB=midpoint01;childC=midpoint20;}
else if(childIndex==1){childA=midpoint01;childB=b;childC=midpoint12;}
else if(childIndex==2){childA=midpoint20;childB=midpoint12;childC=c;}
else {childA=midpoint01;childB=midpoint12;childC=midpoint20;}
}
uint FarSkirtNearChildFanOutputCount(uint probeBase,uint rootIndex,uint childFanIndex)
{
const uint base=probeBase+rootIndex*FarSkirtNearProbeStride
+FarSkirtNearRootProbeStride+childFanIndex*FarSkirtNearChildProbeFanStride;
float maximumDensity=FarSkirtNearProbeInput[base].w;
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+1].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+2].w);
maximumDensity=max(maximumDensity,FarSkirtNearProbeInput[base+3].w);
return maximumDensity<=0.25f?6u:0u;
}
uint FarSkirtNearResolutionTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,uint probeBase,uint rootIndex,FarSkirtVertex sourceA,
FarSkirtVertex sourceB)
{
if(FarSkirtNearRootMaximum(probeBase,rootIndex)<=0.25f)return 6;
uint vertexCount=0,childFanIndex=0;
[unroll]
for(uint child=0;child<4;++child)
{
FarSkirtVertex childA,childB,childC;
FarSkirtNearBuildChildTriangle(a,b,c,probeBase,rootIndex,sourceA,sourceB,
child,childA,childB,childC);
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(childA,childB,childC,polygon,polygonCount);
if(polygonCount<3)continue;
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
vertexCount+=FarSkirtNearChildFanOutputCount(probeBase,rootIndex,childFanIndex++);
}
return vertexCount;
}
uint FarSkirtSourceTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
inout FarSkirtCachedSamples cached)
inout FarSkirtCachedSamples cached,uint nearProbeBase,inout uint nearRootIndex,
FarSkirtVertex sourceA,FarSkirtVertex sourceB)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
@@ -822,6 +1101,14 @@ uint FarSkirtSourceTriangleOutputCount(FarSkirtVertex a,FarSkirtVertex b,FarSkir
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
if(StepVoxels<=2)
{
if(nearRootIndex<FarSkirtNearRootLimit)
vertexCount+=FarSkirtNearResolutionTriangleOutputCount(polygon[0],
polygon[fan],polygon[fan+1],nearProbeBase,nearRootIndex,sourceA,sourceB);
++nearRootIndex;
continue;
}
const float3 centerVoxel=(polygon[0].position+polygon[fan].position
+polygon[fan+1].position)/(3.0f*VoxelSizeCm);
const float centerDensity=FarSkirtDensityAtVoxel(centerVoxel);
@@ -878,9 +1165,15 @@ FarSkirtVertex FarSkirtExtrudedVertexCached(FarSkirtVertex source,float density)
uint FarSkirtEdgeOutputCount(uint edgeVertexId,out FarSkirtCachedSamples cached)
{
cached.endpointDensities=0.0f;
cached.centerDensities=0.0f;
cached.metadata=0;
if(StepVoxels<=2)
cached=FarSkirtCachedProbeInput[edgeVertexId];
else
{
cached.endpointDensities=0.0f;
cached.centerDensities=0.0f;
cached.metadata=0;
}
if(StepVoxels<=2&&cached.metadata.w!=0u)return 0;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),OutputVertexCapacity);
if(edgeVertexId>=surfaceVertexCount)return 0;
const uint triangleBase=edgeVertexId-(edgeVertexId%3);
@@ -888,11 +1181,21 @@ uint FarSkirtEdgeOutputCount(uint edgeVertexId,out FarSkirtCachedSamples cached)
const FarSkirtVertex a=FarSkirtSurfaceVertex(triangleBase+edge);
const FarSkirtVertex b=FarSkirtSurfaceVertex(triangleBase+(edge+1)%3);
if((FarSkirtBoundaryFaceMask(a.position,b.position)&FarSkirtFaceMask)==0)return 0;
const FarSkirtVertex a2=FarSkirtExtrudedVertex(a);
const FarSkirtVertex b2=FarSkirtExtrudedVertex(b);
cached.endpointDensities=float2(a2.density,b2.density);
return FarSkirtSourceTriangleOutputCount(a,b,b2,cached)
+FarSkirtSourceTriangleOutputCount(a,b2,a2,cached);
FarSkirtVertex a2,b2;
if(StepVoxels<=2)
{
a2=FarSkirtExtrudedVertexCached(a,cached.endpointDensities.x);
b2=FarSkirtExtrudedVertexCached(b,cached.endpointDensities.y);
}
else
{
a2=FarSkirtExtrudedVertex(a);
b2=FarSkirtExtrudedVertex(b);
cached.endpointDensities=float2(a2.density,b2.density);
}
uint nearRootIndex=0;
return FarSkirtSourceTriangleOutputCount(a,b,b2,cached,cached.metadata.y,nearRootIndex,a,b)
+FarSkirtSourceTriangleOutputCount(a,b2,a2,cached,cached.metadata.y,nearRootIndex,a,b);
}
void FarSkirtStoreVertex(uint outputId,FarSkirtVertex vertex,uint panelBaseVertex)
@@ -920,9 +1223,40 @@ void FarSkirtEmitTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
FarSkirtStoreVertex(edgeBase+edgeCursor++,b,panelBaseVertex);
}
void FarSkirtEmitNearResolutionTriangle(FarSkirtVertex a,FarSkirtVertex b,
FarSkirtVertex c,FarSkirtVertex sourceA,FarSkirtVertex sourceB,uint probeBase,
uint rootIndex,uint panelBaseVertex,uint edgeBase,inout uint edgeCursor)
{
if(FarSkirtNearRootMaximum(probeBase,rootIndex)<=0.25f)
{
FarSkirtEmitTriangle(a,b,c,panelBaseVertex,edgeBase,edgeCursor);
return;
}
uint childFanIndex=0;
[unroll]
for(uint child=0;child<4;++child)
{
FarSkirtVertex childA,childB,childC;
FarSkirtNearBuildChildTriangle(a,b,c,probeBase,rootIndex,sourceA,sourceB,
child,childA,childB,childC);
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(childA,childB,childC,polygon,polygonCount);
if(polygonCount<3)continue;
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
if(FarSkirtNearChildFanOutputCount(probeBase,rootIndex,childFanIndex)!=0)
FarSkirtEmitTriangle(polygon[0],polygon[fan],polygon[fan+1],
panelBaseVertex,edgeBase,edgeCursor);
++childFanIndex;
}
}
}
void FarSkirtEmitSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex c,
float4 centerDensities,inout uint centerIndex,
uint panelBaseVertex,uint edgeBase,inout uint edgeCursor)
float4 centerDensities,inout uint centerIndex,uint nearProbeBase,inout uint nearRootIndex,
FarSkirtVertex sourceA,FarSkirtVertex sourceB,uint panelBaseVertex,uint edgeBase,
inout uint edgeCursor)
{
FarSkirtVertex polygon[5];uint polygonCount=0;
FarSkirtClipTriangle(a,b,c,polygon,polygonCount);
@@ -930,6 +1264,14 @@ void FarSkirtEmitSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex
[loop]
for(uint fan=1;fan+1<polygonCount;++fan)
{
if(StepVoxels<=2)
{
if(nearRootIndex<FarSkirtNearRootLimit)
FarSkirtEmitNearResolutionTriangle(polygon[0],polygon[fan],polygon[fan+1],
sourceA,sourceB,nearProbeBase,nearRootIndex,panelBaseVertex,edgeBase,edgeCursor);
++nearRootIndex;
continue;
}
const uint index=centerIndex++;
const float centerDensity=index==0?centerDensities.x:index==1?centerDensities.y:
index==2?centerDensities.z:centerDensities.w;
@@ -939,6 +1281,142 @@ void FarSkirtEmitSourceTriangle(FarSkirtVertex a,FarSkirtVertex b,FarSkirtVertex
}
}
[numthreads(64,1,1)]
void EvaluateFarSkirtEndpointsCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint edgeVertexId=dispatchId.x;
if(edgeVertexId>=OutputVertexCapacity||StepVoxels>2)return;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),
OutputVertexCapacity);
FarSkirtCachedSamples cached;
cached.endpointDensities=0.0f;cached.centerDensities=0.0f;cached.metadata=0;
if(edgeVertexId<surfaceVertexCount)
{
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)
{
const FarSkirtVertex a2=FarSkirtExtrudedVertexCached(a,0.0f);
const FarSkirtVertex b2=FarSkirtExtrudedVertexCached(b,0.0f);
float endpointDensities[2];
[loop]
for(uint endpoint=0;endpoint<2;++endpoint)
{
const float3 position=endpoint==0?a2.position:b2.position;
endpointDensities[endpoint]=NearSkirtDensityAtVoxel(position/VoxelSizeCm);
}
cached.endpointDensities=float2(endpointDensities[0],endpointDensities[1]);
}
}
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
}
[numthreads(64,1,1)]
void PrepareFarSkirtNearProbesCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint edgeVertexId=dispatchId.x;
if(edgeVertexId>=OutputVertexCapacity||StepVoxels>2)return;
FarSkirtCachedSamples cached;
cached.endpointDensities=0.0f;cached.centerDensities=0.0f;cached.metadata=0;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),
OutputVertexCapacity);
if(edgeVertexId>=surfaceVertexCount)
{
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
return;
}
if(edgeVertexId>=FarSkirtNearProbeSurfaceCapacity())
{
cached.metadata.w=1u;
uint previousStatus=0u;
FarConnectorDrawArgs.InterlockedOr(OutputArgsByteOffset+40,1u,previousStatus);
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
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)
{
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
return;
}
const FarSkirtCachedSamples endpoints=FarSkirtCachedProbeInput[edgeVertexId];
cached.endpointDensities=endpoints.endpointDensities;
const FarSkirtVertex a2=FarSkirtExtrudedVertexCached(a,cached.endpointDensities.x);
const FarSkirtVertex b2=FarSkirtExtrudedVertexCached(b,cached.endpointDensities.y);
const uint rootCount=FarSkirtCountNearSourceTriangleRoots(a,b,b2)
+FarSkirtCountNearSourceTriangleRoots(a,b2,a2);
uint probeBase=0;
if(rootCount!=0)
FarSkirtNearProbeCounter.InterlockedAdd(0,rootCount*FarSkirtNearProbeStride,probeBase);
uint rootIndex=0;
FarSkirtPrepareNearSourceTriangle(a,b,b2,probeBase,rootIndex);
FarSkirtPrepareNearSourceTriangle(a,b2,a2,probeBase,rootIndex);
cached.metadata.y=probeBase;
cached.metadata.z=rootIndex;
FarSkirtCachedProbeOutput[edgeVertexId]=cached;
}
[numthreads(1,1,1)]
void FinalizeFarSkirtNearProbeDispatchCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint probeCount=FarSkirtNearProbeCounterInput.Load(0);
FarSkirtNearProbeDispatchArgs.Store(0,(probeCount+63u)/64u);
FarSkirtNearProbeDispatchArgs.Store(4,1u);
FarSkirtNearProbeDispatchArgs.Store(8,1u);
}
[numthreads(64,1,1)]
void EvaluateFarSkirtNearProbesCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint probeIndex=dispatchId.x;
if(probeIndex>=FarSkirtNearProbeCounterInput.Load(0))return;
if(probeIndex%FarSkirtNearProbeStride>=FarSkirtNearRootProbeStride)return;
float4 probe=FarSkirtNearProbeOutput[probeIndex];
probe.w=NearSkirtDensityAtVoxel(probe.xyz);
FarSkirtNearProbeOutput[probeIndex]=probe;
}
[numthreads(64,1,1)]
void PrepareFarSkirtNearChildProbesCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint edgeVertexId=dispatchId.x;
if(edgeVertexId>=OutputVertexCapacity||StepVoxels>2)return;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),
OutputVertexCapacity);
if(edgeVertexId==0u)FarSkirtNearProbeOutput[0].z=(float)surfaceVertexCount;
if(edgeVertexId>=surfaceVertexCount)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 FarSkirtCachedSamples cached=FarSkirtCachedProbeInput[edgeVertexId];
if(cached.metadata.w!=0u)return;
const FarSkirtVertex a2=FarSkirtExtrudedVertexCached(a,cached.endpointDensities.x);
const FarSkirtVertex b2=FarSkirtExtrudedVertexCached(b,cached.endpointDensities.y);
uint rootIndex=0;
FarSkirtPrepareNearChildSourceTriangle(a,b,b2,a,b,cached.metadata.y,rootIndex);
FarSkirtPrepareNearChildSourceTriangle(a,b2,a2,a,b,cached.metadata.y,rootIndex);
}
[numthreads(64,1,1)]
void EvaluateFarSkirtNearChildProbesCS(uint3 dispatchId : SV_DispatchThreadID)
{
const uint probeIndex=dispatchId.x;
if(probeIndex>=FarSkirtNearProbeCounterInput.Load(0))return;
const uint probeInRoot=probeIndex%FarSkirtNearProbeStride;
if(probeInRoot<FarSkirtNearRootProbeStride)return;
float4 probe=FarSkirtNearProbeOutput[probeIndex];
if(probe.w< -1.0e30f)return;
probe.w=NearSkirtDensityAtVoxel(probe.xyz);
FarSkirtNearProbeOutput[probeIndex]=probe;
}
float FarConnectorRadius(float3 center, float3 direction, float nominalRadius)
{
const float3 nominalPosition=center+direction*nominalRadius;
@@ -1097,9 +1575,7 @@ void BuildFarConnectorRingsCS(uint3 groupId : SV_GroupID,
}
if (ringId == 0)
{
const uint slot = OutputVertexCapacity > 0
? OutputBaseVertex / OutputVertexCapacity : 0;
const uint panelBaseVertex = slot * FarConnectorPanelVertexCapacity;
const uint panelBaseVertex = FarConnectorOutputBaseVertex;
FarConnectorDrawArgs.Store(OutputArgsByteOffset + 20, FarConnectorVertexCount);
FarConnectorDrawArgs.Store(OutputArgsByteOffset + 24, FarConnectorVertexCount > 0 ? 1 : 0);
FarConnectorDrawArgs.Store(OutputArgsByteOffset + 28, panelBaseVertex);
@@ -1175,9 +1651,7 @@ void EmitFarConnectorPanelsCS(uint3 dispatchId : SV_DispatchThreadID)
vertex.normal = ring.normals[cornerIndex].xyz;
const float connectorLength = length(connector.end - connector.start);
vertex.uv = float2(ring.t * connectorLength / 256.0f, (float)side / 4.0f);
const uint slot = OutputVertexCapacity > 0
? OutputBaseVertex / OutputVertexCapacity : 0;
const uint base = slot * FarConnectorPanelVertexCapacity;
const uint base = FarConnectorOutputBaseVertex;
const uint byteAddress = (base + vertexId) * 32;
FarConnectorVertexBytes.Store3(byteAddress, asuint(vertex.position));
FarConnectorVertexBytes.Store3(byteAddress + 12, asuint(vertex.normal));
@@ -1382,6 +1856,7 @@ void ClassifyFarSkirtsCS(uint3 dispatchId : SV_DispatchThreadID)
[numthreads(1,1,1)]
void ScanFarSkirtsCS(uint3 dispatchId : SV_DispatchThreadID)
{
if(FarConnectorDrawArgs.Load(OutputArgsByteOffset+40)!=0u)return;
const uint surfaceVertexCount=min(FarConnectorDrawArgs.Load(OutputArgsByteOffset),
OutputVertexCapacity);
uint totalSkirtVertices=0;
@@ -1419,14 +1894,18 @@ void EmitFarSkirtsCS(uint3 dispatchId : SV_DispatchThreadID)
const FarSkirtVertex b=FarSkirtSurfaceVertex(triangleBase+(edge+1)%3);
if((FarSkirtBoundaryFaceMask(a.position,b.position)&FarSkirtFaceMask)==0)return;
const FarSkirtCachedSamples cached=FarSkirtCachedProbeInput[edgeVertexId];
if(cached.metadata.w!=0u)return;
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,centerIndex=0;
uint nearRootIndex=0;
FarSkirtEmitSourceTriangle(a,b,b2,cached.centerDensities,centerIndex,
cached.metadata.y,nearRootIndex,a,b,
panelBaseVertex,edgeBase,edgeCursor);
FarSkirtEmitSourceTriangle(a,b2,a2,cached.centerDensities,centerIndex,
cached.metadata.y,nearRootIndex,a,b,
panelBaseVertex,edgeBase,edgeCursor);
}