Many stupid changes

This commit is contained in:
Dynamitos
2024-10-18 19:01:04 +02:00
parent 7623d647ee
commit 1193406dd8
13 changed files with 419 additions and 117 deletions
+1 -1
View File
@@ -41,7 +41,7 @@ void Split(uint dispatchID : SV_DispatchThreadID)
uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + dispatchID];
// Split the element
SplitElement(currentID, pParams.geometry.baseDepth);
SplitElement(currentID, pParams.geometry.baseDepth, dispatchID);
}
[numthreads(1, 1, 1)]
+203 -26
View File
@@ -1,4 +1,65 @@
// Pointer to an invalid neighbor or index
const static int INVALID_POINTER = 4294967295;
// Possible culling state
const static int BACK_FACE_CULLED = -3;
const static int FRUSTUM_CULLED = -2;
const static int TOO_SMALL = -1;
const static int UNCHANGED_ELEMENT = 0;
const static int BISECT_ELEMENT = 1;
const static int SIMPLIFY_ELEMENT = 2;
const static int MERGED_ELEMENT = 3;
// Bisector flags
const static int VISIBLE_BISECTOR = 0x1;
const static int MODIFIED_BISECTOR = 0x2;
// Possible splits
static const uint64_t NO_SPLIT = 0x00;
static const uint64_t CENTER_SPLIT = 0x01;
static const uint64_t RIGHT_SPLIT = 0x02;
static const uint64_t LEFT_SPLIT = 0x04;
static const uint64_t RIGHT_DOUBLE_SPLIT = (CENTER_SPLIT | RIGHT_SPLIT);
static const uint64_t LEFT_DOUBLE_SPLIT = (CENTER_SPLIT | LEFT_SPLIT);
static const uint64_t TRIPLE_SPLIT = (CENTER_SPLIT | RIGHT_SPLIT | LEFT_SPLIT);
// Split buffer slots
static const uint64_t SPLIT_COUNTER = 0;
static const uint64_t SIMPLIFY_COUNTER = 1;
static const uint64_t CLASSIFY_COUNTER_OFFSET = 2;
struct BisectorData
{
// Allocated indices for this bisector
uint32_t indices[3];
// Subvision that should be applied to this bisector
uint32_t subdivisionPattern;
// Neighbor that should be processed
uint32_t problematicNeighbor;
// State of this bisector (split, merge, etc)
uint32_t bisectorState;
// Visibility and modification flags of a bisector
uint32_t flags;
// ID used for the propagation
uint32_t propagationID;
};
uint HeapIDDepth(uint64_t x)
{
uint depth = 0;
while (x > 0u) {
++depth;
x >>= 1u;
}
return depth;
}
struct ComputeParams
{
RWStructuredBuffer<uint> indirectDrawBuffer;
@@ -6,45 +67,161 @@ struct ComputeParams
RWStructuredBuffer<uint> classificationBuffer;
RWStructuredBuffer<int> allocateBuffer;
RWStructuredBuffer<int> memoryBuffer;
RWStructuredBuffer<uint4> neighboursBuffer;
RWStructuredBuffer<BisectorData> bisectorDataBuffer;
RWStructuredBuffer<int> propagateBuffer;
RWStructuredBuffer<uint> simplifyBuffer;
RWStructuredBuffer<uint32_t> bitFieldBuffer;
};
ParameterBlock<ComputeParams> pParams;
// Split buffer slots
static const uint64_t SPLIT_COUNTER = 0;
static const uint64_t SIMPLIFY_COUNTER = 1;
static const uint64_t CLASSIFY_COUNTER_OFFSET = 2;
void ResetBuffers()
void SplitElement(uint currentID, uint baseDepth, uint dispatchID)
{
pParams.memoryBuffer[0] = 0;
pParams.memoryBuffer[1] = 0;
// Get the neighbors information
uint4 cNeighbors = pParams.neighboursBuffer[currentID];
pParams.classificationBuffer[SPLIT_COUNTER] = 0;
pParams.classificationBuffer[SIMPLIFY_COUNTER] = 0;
// If there is a neighbor X
if (cNeighbors.x != INVALID_POINTER)
{
// This is on the path of it's neighbor X
uint4 xNeighbors = pParams.neighboursBuffer[cNeighbors.x];
if (xNeighbors.z == currentID && pParams.bisectorDataBuffer[cNeighbors.x].bisectorState != UNCHANGED_ELEMENT)
return;
}
pParams.allocateBuffer[0] = 0;
// If there is a neighbor Y
if (cNeighbors.y != INVALID_POINTER)
{
// This is on the path of it's neighbor Y
uint4 yNeighbors = pParams.neighboursBuffer[cNeighbors.y];
if (yNeighbors.z == currentID && pParams.bisectorDataBuffer[cNeighbors.y].bisectorState != UNCHANGED_ELEMENT)
return;
}
pParams.propagateBuffer[0] = 0;
pParams.propagateBuffer[1] = 0;
// Depth of the current triangle
uint64_t heapID = pParams.heapIDBuffer[currentID];
uint currentDepth = HeapIDDepth(heapID);
pParams.simplifyBuffer[0] = 0;
// Compute the maximal required memory for this subdivision
int maxRequiredMemory = 2 * (currentDepth - baseDepth) - 1;
pParams.indirectDrawBuffer[0] = 0;
pParams.indirectDrawBuffer[1] = 1;
pParams.indirectDrawBuffer[2] = 0;
pParams.indirectDrawBuffer[3] = 0;
// Get the twin information
uint twinID = cNeighbors.z;
pParams.indirectDrawBuffer[4] = 0;
pParams.indirectDrawBuffer[5] = 1;
pParams.indirectDrawBuffer[6] = 0;
pParams.indirectDrawBuffer[7] = 0;
// This avoid the massive over-reservation and saves a bunch of artifacts
if (twinID == INVALID_POINTER)
maxRequiredMemory = 1;
else if (pParams.neighboursBuffer[twinID].z == currentID)
maxRequiredMemory = 2;
pParams.indirectDrawBuffer[8] = 0;
// Try to reserve
int remainingMemory;
InterlockedAdd(pParams.memoryBuffer[1], -maxRequiredMemory, remainingMemory);
// Did someone manage to sneak-in while we were trying to pick the memory, add it back and try again
if (remainingMemory < maxRequiredMemory)
{
// Then add back the required memory and stop
InterlockedAdd(pParams.memoryBuffer[1], maxRequiredMemory, remainingMemory);
return;
}
// Let's actually count the memory that we will be using
uint usedMemory = 1;
uint prevPattern;
InterlockedOr(pParams.bisectorDataBuffer[currentID].subdivisionPattern, CENTER_SPLIT, prevPattern);
// If this is not zero, it means an other neighbor went faster than us, we restore the memory and leave.
if (prevPattern != 0)
{
InterlockedAdd(pParams.memoryBuffer[1], maxRequiredMemory, remainingMemory);
return;
}
// Mark this for allocation
uint targetLocation = 0;
InterlockedAdd(pParams.allocateBuffer[0], 1, targetLocation);
pParams.allocateBuffer[1 + targetLocation] = currentID;
// While we're not done (up the tree or everything is subdivided properly)
bool done = false;
while (!done)
{
// If this neighbor is not allocated, we're done.
if (twinID == INVALID_POINTER)
break;
// Grab the bisector of the neighbor
uint64_t nHeapID = pParams.heapIDBuffer[twinID];
BisectorData nBisectorData = pParams.bisectorDataBuffer[twinID];
uint nDepth = HeapIDDepth(nHeapID);
uint4 nNeighbors = pParams.neighboursBuffer[twinID];
// If both triangles have the same depth
if (nDepth == currentDepth)
{
// Raised the center split
InterlockedOr(pParams.bisectorDataBuffer[twinID].subdivisionPattern, CENTER_SPLIT, prevPattern);
// Only account for it if it was not raised before.
if (prevPattern == 0)
{
// Mark this for allocation
uint targetLocation = 0;
InterlockedAdd(pParams.allocateBuffer[0], 1, targetLocation);
pParams.allocateBuffer[1 + targetLocation] = twinID;
usedMemory++;
}
// And we're done
done = true;
}
// If this node has already been subdivided, it means that we need to add the third subdivision and we're done
else
{
if (nNeighbors[0] == currentID)
InterlockedOr(pParams.bisectorDataBuffer[twinID].subdivisionPattern, RIGHT_DOUBLE_SPLIT, prevPattern);
else // if (nNeighbors[1] == currentID)
InterlockedOr(pParams.bisectorDataBuffer[twinID].subdivisionPattern, LEFT_DOUBLE_SPLIT, prevPattern);
if (prevPattern != 0)
{
usedMemory++;
done = true;
}
else
{
// Mark this for allocation
uint targetLocation = 0;
InterlockedAdd(pParams.allocateBuffer[0], 1, targetLocation);
pParams.allocateBuffer[1 + targetLocation] = twinID;
// Account for two splits
usedMemory += 2;
// the new bisector that needs to be propagated
currentID = twinID;
currentDepth = nDepth;
twinID = pParams.neighboursBuffer[currentID].z;
}
}
}
int change = maxRequiredMemory - usedMemory;
if(change > 0)
{
// Add back the unused memory (in case)
InterlockedAdd(pParams.memoryBuffer[1], change, remainingMemory);
}
}
[numthreads(1, 1, 1)]
void Reset()
[numthreads(64, 1, 1)]
void Split(uint dispatchID : SV_DispatchThreadID)
{
ResetBuffers();
}
if (dispatchID >= pParams.classificationBuffer[SPLIT_COUNTER])
return;
// Grab the real elementID
uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + dispatchID];
// Split the element
SplitElement(currentID, 7, dispatchID);
}
+7 -4
View File
@@ -29,9 +29,12 @@ struct UpdateCB
struct DebugStruct
{
uint3 neighbours;
int status;
}
int maxRequiredMemory;
int usedMemory;
uint memoryChange;
uint twinID;
};
struct ComputeParams
{
@@ -59,6 +62,6 @@ struct ComputeParams
RWStructuredBuffer<uint> modifiedBisectorIndices;
RWStructuredBuffer<float4> lebPositionBuffer;
StructuredBuffer<float3x3> lebMatrixCache;
RWStructuredBuffer<DebugStruct> debugBuffer;
globallycoherent RWStructuredBuffer<DebugStruct> debugBuffer;
};
ParameterBlock<ComputeParams> pParams;
+64 -34
View File
@@ -23,13 +23,30 @@ static const uint64_t SPLIT_COUNTER = 0;
static const uint64_t SIMPLIFY_COUNTER = 1;
static const uint64_t CLASSIFY_COUNTER_OFFSET = 2;
bool FrustumAABBIntersect(in Frustum frustum, float3 aabbMin, float3 aabbMax)
{
float3 center = (aabbMax + aabbMin) * 0.5;
float3 extents = (aabbMax - aabbMin) * 0.5;
for (int i = 0; i < 4; i++)
{
Plane plane = frustum.sides[i];
float3 normal_sign = sign(plane.n);
float3 test_point = center + extents * normal_sign;
float dotProd = dot(test_point, plane.n);
if (dotProd + plane.d < 0)
return false;
}
return true;
}
int ClassifyBisector(in BisectorGeometry tri, uint depth)
{
// Check the triangle's visibility
float3 triNormal = normalize(cross(tri.p[2] - tri.p[1], tri.p[0] - tri.p[1]));
float3 triCenter = (tri.p[0] + tri.p[1] + tri.p[2]) / 3.0;
float3 viewDir = normalize(-triCenter);
float FdotV = dot(viewDir, pViewParams.cameraForward_WS.xyz);
float FdotV = dot(viewDir, -pViewParams.cameraForward_WS.xyz);
float VdotN = dot(viewDir, triNormal);
// Here we don't use 0 as it introduces stability issues at grazing angles
@@ -41,11 +58,11 @@ int ClassifyBisector(in BisectorGeometry tri, uint depth)
float3 aabbMax = float3(max(max(tri.p[0].x, tri.p[1].x), tri.p[2].x), max(max(tri.p[0].y, tri.p[1].y), tri.p[2].y), max(max(tri.p[0].z, tri.p[1].z), tri.p[2].z));
// First we do a frustum culling pass
//if (!FrustumAABBIntersect(_FrustumPlanes, aabbMin, aabbMax))
// return FRUSTUM_CULLED;
if (!FrustumAABBIntersect(pViewParams.viewFrustum, aabbMin, aabbMax))
return FRUSTUM_CULLED;
// Project the points on screen
float4x4 viewProjectionMatrix = mul(pViewParams.projectionMatrix, pViewParams.viewMatrix);
float4x4 viewProjectionMatrix = pParams.update.viewProjectionMatrix;//mul(pViewParams.projectionMatrix, pViewParams.viewMatrix);
float4 p0P = mul(viewProjectionMatrix, float4(tri.p[0], 1.0));
p0P.xy = p0P.xy / p0P.w;
p0P.xy = (p0P.xy * 0.5 + 0.5);
@@ -166,16 +183,20 @@ void ClassifyElement(uint currentID, BisectorGeometry bis, uint totalNumElements
pParams.bisectorDataBuffer[currentID] = cbisectorData;
}
void SplitElement(uint currentID, uint baseDepth)
void SplitElement(uint currentID, uint baseDepth, uint dispatchID)
{
DebugStruct debug;
debug.maxRequiredMemory = 0;
debug.usedMemory = 0;
debug.memoryChange = 0;
// Get the neighbors information
uint3 cNeighbors = pParams.neighboursBuffer[currentID].xyz;
uint4 cNeighbors = pParams.neighboursBuffer[currentID];
// If there is a neighbor X
if (cNeighbors.x != INVALID_POINTER)
{
// This is on the path of it's neighbor X
uint3 xNeighbors = pParams.neighboursBuffer[cNeighbors.x].xyz;
uint4 xNeighbors = pParams.neighboursBuffer[cNeighbors.x];
if (xNeighbors.z == currentID && pParams.bisectorDataBuffer[cNeighbors.x].bisectorState != UNCHANGED_ELEMENT)
return;
}
@@ -184,7 +205,7 @@ void SplitElement(uint currentID, uint baseDepth)
if (cNeighbors.y != INVALID_POINTER)
{
// This is on the path of it's neighbor Y
uint3 yNeighbors = pParams.neighboursBuffer[cNeighbors.y].xyz;
uint4 yNeighbors = pParams.neighboursBuffer[cNeighbors.y];
if (yNeighbors.z == currentID && pParams.bisectorDataBuffer[cNeighbors.y].bisectorState != UNCHANGED_ELEMENT)
return;
}
@@ -205,10 +226,13 @@ void SplitElement(uint currentID, uint baseDepth)
else if (pParams.neighboursBuffer[twinID].z == currentID)
maxRequiredMemory = 2;
debug.maxRequiredMemory = maxRequiredMemory;
debug.twinID = twinID;
// Try to reserve
int remainingMemory;
InterlockedAdd(pParams.memoryBuffer[1], -maxRequiredMemory, remainingMemory);
debug.memoryChange = -maxRequiredMemory;
// Did someone manage to sneak-in while we were trying to pick the memory, add it back and try again
if (remainingMemory < maxRequiredMemory)
{
@@ -218,7 +242,7 @@ void SplitElement(uint currentID, uint baseDepth)
}
// Let's actually count the memory that we will be using
uint usedMemory = 1;
int usedMemory = 1;
uint prevPattern;
InterlockedOr(pParams.bisectorDataBuffer[currentID].subdivisionPattern, CENTER_SPLIT, prevPattern);
@@ -246,7 +270,7 @@ void SplitElement(uint currentID, uint baseDepth)
uint64_t nHeapID = pParams.heapIDBuffer[twinID];
BisectorData nBisectorData = pParams.bisectorDataBuffer[twinID];
uint nDepth = HeapIDDepth(nHeapID);
uint3 nNeighbors = pParams.neighboursBuffer[twinID].xyz;
uint4 nNeighbors = pParams.neighboursBuffer[twinID];
// If both triangles have the same depth
if (nDepth == currentDepth)
@@ -297,9 +321,13 @@ void SplitElement(uint currentID, uint baseDepth)
}
}
}
int change = maxRequiredMemory - usedMemory;
// Add back the unused memory (in case)
InterlockedAdd(pParams.memoryBuffer[1], max(maxRequiredMemory - usedMemory, 0), remainingMemory);
InterlockedAdd(pParams.memoryBuffer[1], change, remainingMemory);
debug.memoryChange += change;
debug.usedMemory = usedMemory;
pParams.debugBuffer[dispatchID] = debug;
}
void AllocateElement(uint currentID)
@@ -335,7 +363,7 @@ void AllocateElement(uint currentID)
void evaluate_neighbors(uint currentID, uint bisectorID, out uint resX, out uint resY)
{
BisectorData nBisectorData = pParams.bisectorDataBuffer[bisectorID];
uint3 nNeighbors = pParams.neighboursBuffer[bisectorID].xyz;
uint4 nNeighbors = pParams.neighboursBuffer[bisectorID];
if (nBisectorData.subdivisionPattern == 0x01)
{
resX = nBisectorData.indices[SUBLING0_ID];
@@ -399,7 +427,7 @@ void BisectElement(uint currentID)
uint currentSubdiv = cBisectorData.subdivisionPattern;
// neighbors of the parent
uint3 cNeighbors = pParams.neighboursBuffer[currentID].xyz;
uint4 cNeighbors = pParams.neighboursBuffer[currentID];
uint p_n0 = cNeighbors[0];
uint p_n1 = cNeighbors[1];
uint p_n2 = cNeighbors[2];
@@ -421,15 +449,15 @@ void BisectElement(uint currentID)
pParams.heapIDBuffer[siblingID0] = 2 * baseHeapID + 1;
// Update the neighbors
uint3 modifiedNeighbors;
uint4 modifiedNeighbors;
modifiedNeighbors[0] = siblingID0;
modifiedNeighbors[1] = resX;
modifiedNeighbors[2] = p_n0;
pParams.neighboursOutputBuffer[currentID] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[currentID] = modifiedNeighbors;
modifiedNeighbors[0] = resY;
modifiedNeighbors[1] = currentID;
modifiedNeighbors[2] = p_n1;
pParams.neighboursOutputBuffer[siblingID0] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID0] = modifiedNeighbors;
// Keep track of the parent
BisectorData modifiedBisector = cBisectorData;
@@ -444,7 +472,7 @@ void BisectElement(uint currentID)
pParams.bisectorDataBuffer[siblingID0] = modifiedBisector;
// Mark this for propagation
uint targetLocation = 0;
uint targetLocation;
InterlockedAdd(pParams.propagateBuffer[0], 1, targetLocation);
pParams.propagateBuffer[2 + targetLocation] = siblingID0;
}
@@ -463,19 +491,19 @@ void BisectElement(uint currentID)
pParams.heapIDBuffer[siblingID0] = 2 * baseHeapID + 1;
pParams.heapIDBuffer[siblingID1] = 4 * baseHeapID + 1;
uint3 modifiedNeighbors;
uint4 modifiedNeighbors;
modifiedNeighbors[0] = siblingID1;
modifiedNeighbors[1] = res0X;
modifiedNeighbors[2] = siblingID0;
pParams.neighboursOutputBuffer[currentID] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[currentID] = modifiedNeighbors;
modifiedNeighbors[0] = res1Y;
modifiedNeighbors[1] = currentID;
modifiedNeighbors[2] = p_n1;
pParams.neighboursOutputBuffer[siblingID0] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID0] = modifiedNeighbors;
modifiedNeighbors[0] = res0Y;
modifiedNeighbors[1] = currentID;
modifiedNeighbors[2] = res1X;
pParams.neighboursOutputBuffer[siblingID1] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID1] = modifiedNeighbors;
// Keep track of the parent
BisectorData modifiedBisector = cBisectorData;
@@ -497,7 +525,7 @@ void BisectElement(uint currentID)
pParams.bisectorDataBuffer[siblingID1] = modifiedBisector;
// Mark this for propagation
uint targetLocation = 0;
uint targetLocation;
InterlockedAdd(pParams.propagateBuffer[0], 1, targetLocation);
pParams.propagateBuffer[2 + targetLocation] = siblingID0;
}
@@ -516,19 +544,19 @@ void BisectElement(uint currentID)
pParams.heapIDBuffer[siblingID0] = 4 * baseHeapID + 2;
pParams.heapIDBuffer[siblingID1] = 4 * baseHeapID + 3;
uint3 modifiedNeighbors;
uint4 modifiedNeighbors;
modifiedNeighbors[0] = siblingID1;
modifiedNeighbors[1] = res1X;
modifiedNeighbors[2] = p_n0;
pParams.neighboursOutputBuffer[currentID] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[currentID] = modifiedNeighbors;
modifiedNeighbors[0] = siblingID1;
modifiedNeighbors[1] = res0X;
modifiedNeighbors[2] = res1Y;
pParams.neighboursOutputBuffer[siblingID0] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID0] = modifiedNeighbors;
modifiedNeighbors[0] = res0Y;
modifiedNeighbors[1] = siblingID0;
modifiedNeighbors[2] = currentID;
pParams.neighboursOutputBuffer[siblingID1] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID1] = modifiedNeighbors;
// Keep track of the parent
BisectorData modifiedBisector = cBisectorData;
@@ -568,23 +596,23 @@ void BisectElement(uint currentID)
pParams.heapIDBuffer[siblingID1] = 4 * baseHeapID + 1;
pParams.heapIDBuffer[siblingID2] = 4 * baseHeapID + 3;
uint3 modifiedNeighbors;
uint4 modifiedNeighbors;
modifiedNeighbors[0] = siblingID1;
modifiedNeighbors[1] = res0X;
modifiedNeighbors[2] = siblingID2;
pParams.neighboursOutputBuffer[currentID] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[currentID] = modifiedNeighbors;
modifiedNeighbors[0] = siblingID2;
modifiedNeighbors[1] = res1X;
modifiedNeighbors[2] = res2Y;
pParams.neighboursOutputBuffer[siblingID0] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID0] = modifiedNeighbors;
modifiedNeighbors[0] = res0Y;
modifiedNeighbors[1] = currentID;
modifiedNeighbors[2] = res2X;
pParams.neighboursOutputBuffer[siblingID1] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID1] = modifiedNeighbors;
modifiedNeighbors[0] = res1Y;
modifiedNeighbors[1] = siblingID0;
modifiedNeighbors[2] = currentID;
pParams.neighboursOutputBuffer[siblingID2] = uint4(modifiedNeighbors, 0);
pParams.neighboursOutputBuffer[siblingID2] = modifiedNeighbors;
// Keep track of the parent
BisectorData modifiedBisector = cBisectorData;
@@ -930,7 +958,8 @@ void ValidateBisector(uint currentID)
return;
// Load the bisector data of the target element
uint3 cNeighbors = pParams.neighboursBuffer[currentID].xyz;
uint4 cNeighbors = pParams.neighboursBuffer[currentID];
uint4 tempnNeighbours[3];
bool failed = false;
uint targetNeighbor = INVALID_POINTER;
@@ -941,7 +970,8 @@ void ValidateBisector(uint currentID)
if (neighborID != INVALID_POINTER)
{
bool found = false;
uint3 nNeighbors = pParams.neighboursBuffer[neighborID].xyz;
uint4 nNeighbors = pParams.neighboursBuffer[neighborID];
tempnNeighbours[i] = nNeighbors;
for (uint j = 0; j < 3; ++j)
{
if (nNeighbors[j] == currentID)