Files
Seele/res/shaders/terrain/CompileTest.slang
T

348 lines
12 KiB
Plaintext
Raw Normal View History

2024-10-18 19:01:04 +02:00
// Pointer to an invalid neighbor or index
const static int INVALID_POINTER = 4294967295;
2024-10-15 21:35:52 +02:00
2024-10-18 19:01:04 +02:00
// 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;
}
2024-10-15 21:35:52 +02:00
struct ComputeParams
{
RWStructuredBuffer<uint> indirectDrawBuffer;
RWStructuredBuffer<uint64_t> heapIDBuffer;
RWStructuredBuffer<uint> classificationBuffer;
RWStructuredBuffer<int> allocateBuffer;
RWStructuredBuffer<int> memoryBuffer;
2024-10-18 19:01:04 +02:00
RWStructuredBuffer<uint4> neighboursBuffer;
RWStructuredBuffer<BisectorData> bisectorDataBuffer;
2024-10-15 21:35:52 +02:00
RWStructuredBuffer<int> propagateBuffer;
RWStructuredBuffer<uint> simplifyBuffer;
2024-10-21 11:13:26 +02:00
RWStructuredBuffer<uint> cbtBuffer;
RWStructuredBuffer<uint64_t> bitFieldBuffer;
2024-10-15 21:35:52 +02:00
};
ParameterBlock<ComputeParams> pParams;
2024-10-21 11:13:26 +02:00
#define WORKGROUP_SIZE 64
// Num elements
#define OCBT_NUM_ELEMENTS 131072
// Tree sizes
#define OCBT_TREE_SIZE_BITS (32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512 + 8 * 1024)
#define OCBT_TREE_NUM_SLOTS (OCBT_TREE_SIZE_BITS / 32)
#define OCBT_BITFIELD_NUM_SLOTS (OCBT_NUM_ELEMENTS / 64)
#define OCBT_LAST_LEVEL_SIZE 1024
// Tree last level
#define TREE_LAST_LEVEL 10
// First virtual level
#define FIRST_VIRTUAL_LEVEL 11
// Leaf level
#define LEAF_LEVEL 17
// per level offset
static const uint32_t OCBT_depth_offset[18] = { 0, // Level 0
32 * 1, // level 1
32 * 1 + 32 * 2, // level 2
32 * 1 + 32 * 2 + 32 * 4, // level 3
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8, // Level 4
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16, // Level 5
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32, // Level 6
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64, // Level 7
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128, // Level 8
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256, // Level 9
32 * 1 + 32 * 2 + 32 * 4 + 32 * 8 + 32 * 16 + 32 * 32 + 32 * 64 + 16 * 128 + 16 * 256 + 16 * 512, // Level 10
0, // Level 12
0, // Level 13
0, // Level 14
0, // Level 15
0, // Level 16
0, // Level 17
0, // Level 18
};
static const uint64_t OCBT_bit_mask[18] = { 0xffffffff, // Root 17
0xffffffff, // Level 16
0xffffffff, // level 15
0xffffffff, // level 14
0xffffffff, // level 13
0xffffffff, // level 12
0xffffffff, // level 11
0xffff, // level 10
0xffff, // level 9
0xffff, // level 8
0xff, // level 8
0xffffffffffffffff, // level 7
0xffffffff, // Level 6
0xffff, // level 5
0xff, // level 4
0xf, // level 3
0x3, // level 2
0x1, // level 1
};
static const uint32_t OCBT_bit_count[18] = { 32, // Root 17
32, // Level 16
32, // level 15
32, // level 14
32, // level 13
32, // level 12
32, // level 11
16, // level 10
16, // level 9
16, // level 8
8, // level 8
64, // Level 5
32, // Level 5
16, // Level 4
8, // level 3
4, // level 2
2, // level 1
1, // level 0
};
groupshared uint gs_cbtTree[OCBT_TREE_NUM_SLOTS];
// Define the remaining values
#define BUFFER_ELEMENT_PER_LANE ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BUFFER_ELEMENT_PER_LANE_NO_BITFIELD ((OCBT_TREE_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define BITFIELD_ELEMENT_PER_LANE ((OCBT_BITFIELD_NUM_SLOTS + WORKGROUP_SIZE - 1) / WORKGROUP_SIZE)
#define WAVE_TREE_DEPTH uint(log2(OCBT_NUM_ELEMENTS))
void load_buffer_to_shared_memory(uint groupIndex)
2024-10-15 21:35:52 +02:00
{
2024-10-21 11:13:26 +02:00
// Load the bitfield to the LDS
for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e)
2024-10-18 19:01:04 +02:00
{
2024-10-21 11:13:26 +02:00
uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e;
if (target_element < OCBT_TREE_NUM_SLOTS)
gs_cbtTree[target_element] = pParams.cbtBuffer[target_element];
2024-10-18 19:01:04 +02:00
}
2024-10-21 11:13:26 +02:00
GroupMemoryBarrierWithGroupSync();
}
2024-10-15 21:35:52 +02:00
2024-10-21 11:13:26 +02:00
uint get_heap_element(uint id)
{
// Figure out the location of the first bit of this element
uint32_t real_heap_id = id - 1;
uint32_t depth = uint32_t(log2(real_heap_id + 1));
uint32_t level_first_element = (1u << depth) - 1;
uint32_t id_in_level = real_heap_id - level_first_element;
uint32_t first_bit = OCBT_depth_offset[depth] + OCBT_bit_count[depth] * id_in_level;
if (depth < FIRST_VIRTUAL_LEVEL)
2024-10-18 19:01:04 +02:00
{
2024-10-21 11:13:26 +02:00
uint32_t slot = first_bit / 32;
uint32_t local_id = first_bit % 32;
uint32_t target_bits = (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
return (gs_cbtTree[slot] >> local_id) & uint32_t(OCBT_bit_mask[depth]);
2024-10-18 19:01:04 +02:00
}
2024-10-21 11:13:26 +02:00
else
2024-10-18 19:01:04 +02:00
{
2024-10-21 11:13:26 +02:00
uint32_t slot = first_bit / 64;
uint32_t local_id = first_bit % 64;
uint64_t target_bits = (pParams.bitFieldBuffer[slot] >> local_id) & OCBT_bit_mask[depth];
uint32_t high = uint(target_bits >> 32);
uint32_t low = uint(target_bits);
return countbits(high) + countbits(low);
2024-10-18 19:01:04 +02:00
}
2024-10-15 21:35:52 +02:00
}
2024-10-21 16:49:58 +02:00
// decodes the position of the i-th one in the bitfield
uint decode_bit(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1;
for (uint currentDepth = 0; currentDepth < WAVE_TREE_DEPTH; ++currentDepth)
{
uint heapValue = get_heap_element(2 * bitID);
uint b = handle < heapValue ? 0 : 1;
bitID = 2 * bitID + b;
handle -= heapValue * b;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint currentDepth = 0;
uint heapElementID = 1u;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
// Read the left element
uint heapValue = get_heap_element(2u * heapElementID);
// Does it fall in the right or left subtree?
uint b = handle < heapValue ? 0u : 1u;
// Pick a subtree
heapElementID = 2u * heapElementID + b;
// Move the iterator to exclude the right subtree if required
handle -= heapValue * b;
}
// Align with the internal depth
currentDepth++;
// Ok we have our subtree, now we need to pick the right bit
uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint heapValue = countbits(uint(target_bits >> 32)) + countbits(uint(target_bits));
// Does it fall in the right or left subtree?
uint b = handle < heapValue ? 0u : 1u;
// Pick a subtree
heapElementID = 2u * heapElementID + b;
// Move the iterator to exclude the right subtree if required
handle -= heapValue * b;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
// decodes the position of the i-th zero in the bitfield
uint decode_bit_complement(uint handle)
{
#if defined(NAIVE_DECODE)
uint bitID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
while (bitID < OCBT_NUM_ELEMENTS) {
uint heapValue = c - get_heap_element(2u * bitID);
uint b = handle < heapValue ? 0u : 1u;
bitID = 2u * bitID + b;
handle -= heapValue * b;
c /= 2u;
}
return (bitID ^ OCBT_NUM_ELEMENTS);
#else
uint heapElementID = 1u;
uint c = OCBT_NUM_ELEMENTS / 2u;
uint currentDepth = 0;
for (currentDepth = 0; currentDepth < FIRST_VIRTUAL_LEVEL; ++currentDepth)
{
uint heapValue = c - get_heap_element(2u * heapElementID);
uint b = handle < heapValue ? 0u : 1u;
heapElementID = 2u * heapElementID + b;
handle -= heapValue * b;
c /= 2u;
}
// Align with the internal depth
currentDepth++;
// Ok we have our subtree, now we need to pick the right bit
uint64_t heapValue = pParams.bitFieldBuffer[heapElementID - OCBT_LAST_LEVEL_SIZE * 2];
uint64_t mask = 0xffffffff;
uint32_t bitCount = 32;
for (; currentDepth < (WAVE_TREE_DEPTH + 1); ++currentDepth)
{
// Figure out the location of the first bit of this element
uint real_heap_id = 2 * heapElementID - 1;
uint level_first_element = (1u << currentDepth) - 1;
uint id_in_level = real_heap_id - level_first_element;
uint first_bit = bitCount * id_in_level;
uint local_id = first_bit % 64;
uint64_t target_bits = (heapValue >> local_id) & mask;
uint heapValue = c - countbits(uint(target_bits >> 32)) + countbits(uint(target_bits));;
uint b = handle < heapValue ? 0u : 1u;
heapElementID = 2u * heapElementID + b;
handle -= heapValue * b;
c /= 2u;
// Adjust the mask and bitcount
bitCount /= 2;
mask = mask >> bitCount;
}
return (heapElementID ^ OCBT_NUM_ELEMENTS);
#endif
}
2024-10-18 19:01:04 +02:00
[numthreads(64, 1, 1)]
2024-10-21 11:13:26 +02:00
void GetHeap(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThreadID)
2024-10-15 21:35:52 +02:00
{
2024-10-21 11:13:26 +02:00
load_buffer_to_shared_memory(groupIndex);
2024-10-21 16:49:58 +02:00
pParams.classificationBuffer[dispatchID] = decode_bit(dispatchID);
pParams.classificationBuffer[dispatchID * 2] = decode_bit_complement(dispatchID);
2024-10-21 11:13:26 +02:00
}