From 65062874747be33009121e96732fa3e551b2223c Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Mon, 21 Oct 2024 16:49:58 +0200 Subject: [PATCH] Pinning down the issue --- res/shaders/WaterPass.slang | 23 +- res/shaders/terrain/CBT.slang | 22 +- res/shaders/terrain/CBTCompute.slang | 171 ++-- res/shaders/terrain/CompileTest.glsl | 1114 +++++++++-------------- res/shaders/terrain/CompileTest.slang | 136 ++- res/shaders/terrain/CompileTest.spv | 455 +++++++++ res/shaders/terrain/CompileTest.spv-asm | Bin 0 -> 31528 bytes 7 files changed, 1136 insertions(+), 785 deletions(-) create mode 100644 res/shaders/terrain/CompileTest.spv create mode 100644 res/shaders/terrain/CompileTest.spv-asm diff --git a/res/shaders/WaterPass.slang b/res/shaders/WaterPass.slang index bb5741f..3e988ca 100644 --- a/res/shaders/WaterPass.slang +++ b/res/shaders/WaterPass.slang @@ -9,6 +9,11 @@ struct WaterPayload uint numMeshes; }; +//struct WaterPayload +//{ +// TileDescriptor descriptors[BLOCK_SIZE]; +//} + struct WaterTile { int2 location; @@ -75,12 +80,24 @@ struct MaterialParams layout(set = 1) ParameterBlock pWaterMaterial; -[numthreads(1, 1, 1)] +//groupshared WaterPayload waterPayload; +//groupshared uint head; + +[numthreads(BLOCK_SIZE, 1, 1)] [shader("amplification")] void taskMain( uint threadID: SV_GroupThreadID, uint3 groupID: SV_GroupID + // uint dispatchID: SV_DispatchThreadID, ) { + //if(threadID == 0) + //{ + // head = 0; + //} + //if(dispatchID >= 1600) + //{ + // return; + //} WaterTile tile = pWaterMaterial.tiles[groupID.x]; GroupMemoryBarrierWithGroupSync(); AABB bounding; @@ -111,6 +128,10 @@ void taskMain( payload.offset = bounding.minCorner; payload.extent = tile.extent / numMeshes; payload.numMeshes = numMeshes; + //uint index = 0; + //InterlockedAdd(head, 1, index); + //waterPayload.descriptors[index] = payload; + //GroupMemoryBarrierWithGroupSync(); DispatchMesh(numMeshes, numMeshes, 1, payload); } diff --git a/res/shaders/terrain/CBT.slang b/res/shaders/terrain/CBT.slang index c545613..43fceb9 100644 --- a/res/shaders/terrain/CBT.slang +++ b/res/shaders/terrain/CBT.slang @@ -108,7 +108,7 @@ static const uint32_t OCBT_bit_count[18] = { 32, // Root 17 #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)) +#define WAVE_TREE_DEPTH uint(17) uint32_t cbt_size() { @@ -174,9 +174,7 @@ uint get_heap_element(uint id) 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); + return countbits(uint(target_bits >> 32)) + countbits(uint(target_bits)); } } @@ -298,15 +296,11 @@ void reduce_prepass(uint dispatchThreadID) { // First element of the pair uint64_t target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx]; - uint32_t high = uint(target_bits >> 32); - uint32_t low = uint(target_bits); - uint elementC = countbits(high) + countbits(low); + uint elementC = countbits(uint(target_bits >> 32)) + countbits(uint(target_bits)); // Second element of the pair target_bits = pParams.bitFieldBuffer[dispatchThreadID * 8 + 2 * pairIdx + 1]; - high = uint(target_bits >> 32); - low = uint(target_bits); - elementC += countbits(high) + countbits(low); + elementC += countbits(uint(target_bits >> 32)) + countbits(uint(target_bits)); // Store in the right bits packedSum |= (elementC << pairIdx * 8); @@ -396,9 +390,11 @@ void reduce_second_pass(uint groupIndex) GroupMemoryBarrierWithGroupSync(); // Load the bitfield to the LDS - for (uint i = groupIndex; i < 319; i+=WORKGROUP_SIZE) + for (uint e = 0; e < 5; ++e) { - pParams.cbtBuffer[i] = gs_cbtTree[i]; + uint target_element = 5 * groupIndex + e; + if (target_element < 319) + pParams.cbtBuffer[target_element] = gs_cbtTree[target_element]; } } @@ -494,4 +490,4 @@ void set_bit_atomic_buffer(uint bitID, bool state) uint32_t bit_count_buffer() { return pParams.cbtBuffer[0]; -} \ No newline at end of file +} diff --git a/res/shaders/terrain/CBTCompute.slang b/res/shaders/terrain/CBTCompute.slang index e76da52..3faf50e 100644 --- a/res/shaders/terrain/CBTCompute.slang +++ b/res/shaders/terrain/CBTCompute.slang @@ -10,38 +10,48 @@ void Reset() ResetBuffers(); } -[numthreads(WORKGROUP_SIZE, 1, 1)] -void Classify(uint currentID : SV_DispatchThreadID) +[numthreads(1, 1, 1)] +void Classify(uint dispatchID : SV_DispatchThreadID) { - // This thread doesn't have any work to do, we're done - if (currentID >= pParams.indirectDrawBuffer[9]) + if(dispatchID > 0) return; + for(uint i = 0; i < pParams.indirectDrawBuffer[9]; ++i) + { + // This thread doesn't have any work to do, we're done + //if (currentID >= pParams.indirectDrawBuffer[9]) + // return; - // Operate the indirection - currentID = pParams.indexedBisectorBuffer[currentID]; + // Operate the indirection + uint currentID = pParams.indexedBisectorBuffer[i]; - // Read the current geometry data - BisectorGeometry bis; - bis.p[0] = pParams.currentVertexBuffer[3 * currentID].xyz; - bis.p[1] = pParams.currentVertexBuffer[3 * currentID + 1].xyz; - bis.p[2] = pParams.currentVertexBuffer[3 * currentID + 2].xyz; - bis.p[3] = pParams.currentVertexBuffer[3 * pParams.geometry.totalNumElements + currentID].xyz; + // Read the current geometry data + BisectorGeometry bis; + bis.p[0] = pParams.currentVertexBuffer[3 * currentID].xyz; + bis.p[1] = pParams.currentVertexBuffer[3 * currentID + 1].xyz; + bis.p[2] = pParams.currentVertexBuffer[3 * currentID + 2].xyz; + bis.p[3] = pParams.currentVertexBuffer[3 * pParams.geometry.totalNumElements + currentID].xyz; - // Classify the element - ClassifyElement(currentID, bis, pParams.geometry.totalNumElements, pParams.geometry.baseDepth); + // Classify the element + ClassifyElement(currentID, bis, pParams.geometry.totalNumElements, pParams.geometry.baseDepth); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void Split(uint dispatchID : SV_DispatchThreadID) { - if (dispatchID >= pParams.classificationBuffer[SPLIT_COUNTER]) + if(dispatchID > 0) return; + for(dispatchID = 0; dispatchID < pParams.classificationBuffer[SPLIT_COUNTER]; ++dispatchID) + { + //if (dispatchID >= pParams.classificationBuffer[SPLIT_COUNTER]) + // return; - // Grab the real elementID - uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + dispatchID]; + // Grab the real elementID + uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + dispatchID]; - // Split the element - SplitElement(currentID, pParams.geometry.baseDepth); + // Split the element + SplitElement(currentID, pParams.geometry.baseDepth); + } } [numthreads(1, 1, 1)] @@ -52,74 +62,102 @@ void PrepareIndirect(uint currentID : SV_DispatchThreadID) pParams.indirectDispatchBuffer[currentID * 3 + 2] = 1; } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void Allocate(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThreadID) { - // Load the CBT to the LDS - load_buffer_to_shared_memory(groupIndex); - - // If this element doesn't need to be processed, we're done - if (dispatchID >= pParams.allocateBuffer[0]) + if(dispatchID > 0) return; - // Allocate the required bits - AllocateElement(pParams.allocateBuffer[1 + dispatchID]); + for(uint i = 0; i < 64; ++i) + { + // Load the CBT to the LDS + load_buffer_to_shared_memory(i); + } + + // If this element doesn't need to be processed, we're done + //if (dispatchID >= pParams.allocateBuffer[0]) + // return; + for(uint i = 0; i < pParams.allocateBuffer[0]; ++i) + { + // Allocate the required bits + AllocateElement(pParams.allocateBuffer[1 + i]); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void Bisect(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThreadID) { - // If this element doesn't need to be processed, we're done - if (dispatchID >= pParams.allocateBuffer[0]) + if(dispatchID > 0) return; - - // Operation the bisection of this element - BisectElement(pParams.allocateBuffer[1 + dispatchID], dispatchID); + // If this element doesn't need to be processed, we're done + //if (dispatchID >= pParams.allocateBuffer[0]) + // return; + for(uint i = 0; i < pParams.allocateBuffer[0]; ++i) + { + // Operation the bisection of this element + BisectElement(pParams.allocateBuffer[1 + i], i); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void PropagateBisect(uint dispatchID : SV_DispatchThreadID) { - // If this element doesn't need to be processed, we're done - if (dispatchID >= pParams.propagateBuffer[0]) + if(dispatchID > 0) return; - - PropagateBisectElement(pParams.propagateBuffer[2 + dispatchID]); + // If this element doesn't need to be processed, we're done + //if (dispatchID >= pParams.propagateBuffer[0]) + // return; + for(uint i = 0; i < pParams.propagateBuffer[0]; ++i) + { + PropagateBisectElement(pParams.propagateBuffer[2 + i]); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void PrepareSimplify(uint dispatchID : SV_DispatchThreadID) { + if(dispatchID > 0) + return; // If this element doesn't need to be processed, we're done - if (dispatchID >= pParams.classificationBuffer[SIMPLIFY_COUNTER]) - return; + //if (dispatchID >= pParams.classificationBuffer[SIMPLIFY_COUNTER]) + // return; + for(uint i = 0; i < pParams.classificationBuffer[SIMPLIFY_COUNTER]; ++i) + { + // Grab the real elementID + uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + pParams.geometry.totalNumElements + i]; - // Grab the real elementID - uint currentID = pParams.classificationBuffer[CLASSIFY_COUNTER_OFFSET + pParams.geometry.totalNumElements + dispatchID]; - - // Simplify an element - PrepareSimplifyElement(currentID); + // Simplify an element + PrepareSimplifyElement(currentID); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] -void Simplify(uint currentID : SV_DispatchThreadID) +[numthreads(1, 1, 1)] +void Simplify(uint dispatchID : SV_DispatchThreadID) { - // This thread doesn't have any work to do, we're done - if (currentID >= pParams.simplifyBuffer[0]) + if(dispatchID > 0) return; - - // Simplify an element - SimplifyElement(pParams.simplifyBuffer[1 + currentID]); + // This thread doesn't have any work to do, we're done + //if (currentID >= pParams.simplifyBuffer[0]) + // return; + for(uint i = 0; i < pParams.simplifyBuffer[0]; ++i) + { + // Simplify an element + SimplifyElement(pParams.simplifyBuffer[1 + i]); + } } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void PropagateSimplify(uint dispatchID : SV_DispatchThreadID) { - // If this element doesn't need to be processed, we're done - if (dispatchID >= pParams.propagateBuffer[1]) + if(dispatchID > 0) return; - - PropagateElementSimplify(pParams.propagateBuffer[2 + dispatchID]); + // If this element doesn't need to be processed, we're done + //if (dispatchID >= pParams.propagateBuffer[1]) + // return; + for(uint i = 0; i < pParams.propagateBuffer[1]; ++i) + { + PropagateElementSimplify(pParams.propagateBuffer[2 + i]); + } } [numthreads(WORKGROUP_SIZE, 1, 1)] @@ -142,15 +180,20 @@ void ReduceSecondPass(uint groupIndex : SV_GroupIndex) reduce_second_pass(groupIndex); } -[numthreads(WORKGROUP_SIZE, 1, 1)] +[numthreads(1, 1, 1)] void BisectorIndexation(uint currentID : SV_DispatchThreadID) { - // This thread doesn't have any work to do, we're done - if (currentID >= pParams.geometry.totalNumElements) + if(currentID > 0) return; + // This thread doesn't have any work to do, we're done + //if (currentID >= pParams.geometry.totalNumElements) + // return; - // Indexate this bisector - BisectorElementIndexation(currentID); + for(uint i = 0; i < pParams.geometry.totalNumElements; ++i) + { + // Indexate this bisector + BisectorElementIndexation(i); + } } [numthreads(1, 1, 1)] diff --git a/res/shaders/terrain/CompileTest.glsl b/res/shaders/terrain/CompileTest.glsl index 244c87d..75d9078 100644 --- a/res/shaders/terrain/CompileTest.glsl +++ b/res/shaders/terrain/CompileTest.glsl @@ -1,753 +1,455 @@ #version 450 #extension GL_EXT_shader_explicit_arithmetic_types_int64 : require +#extension GL_KHR_memory_scope_semantics : require layout(row_major) uniform; layout(row_major) buffer; -#line 8 0 -struct GeometryCB_std140_0 -{ - uint totalNumElements_0; - uint baseDepth_0; - uint totalNumVertices_0; -}; - - -#line 8 -layout(binding = 0, set = 1) -layout(std140) uniform block_GeometryCB_std140_0 -{ - uint totalNumElements_0; - uint baseDepth_0; - uint totalNumVertices_0; -}pParams_geometry_0; - -#line 1334 1 -struct _MatrixStorage_float4x4_ColMajorstd140_0 -{ - vec4 data_0[4]; -}; - - -#line 27 0 -struct UpdateCB_std140_0 -{ - _MatrixStorage_float4x4_ColMajorstd140_0 viewProjectionMatrix_0; - float triangleSize_0; - uint maxSubdivisionDepth_0; - float fov_0; - float farPlaneDistance_0; -}; - - -#line 27 -layout(binding = 1, set = 1) -layout(std140) uniform block_UpdateCB_std140_0 -{ - _MatrixStorage_float4x4_ColMajorstd140_0 viewProjectionMatrix_0; - float triangleSize_0; - uint maxSubdivisionDepth_0; - float fov_0; - float farPlaneDistance_0; -}pParams_update_0; - -#line 40 -layout(std430, binding = 2, set = 1) buffer StructuredBuffer_vectorx3Cfloatx2C4x3E_t_0 { - vec4 _data[]; -} pParams_currentVertexBuffer_0; - -#line 40 -layout(std430, binding = 3, set = 1) readonly buffer StructuredBuffer_uint_t_0 { - uint _data[]; -} pParams_indexedBisectorBuffer_0; - -#line 40 -layout(std430, binding = 4, set = 1) buffer StructuredBuffer_uint_t_1 { - uint _data[]; -} pParams_indirectDrawBuffer_0; - -#line 40 -layout(std430, binding = 5, set = 1) buffer StructuredBuffer_uint64_t_0 { - uint64_t _data[]; -} pParams_heapIDBuffer_0; - -#line 20 2 -struct _Array_std430_uint3_0 -{ - uint data_1[3]; -}; - - -#line 35 -struct BisectorData_std430_0 -{ - _Array_std430_uint3_0 indices_0; - uint subdivisionPattern_0; - uint problematicNeighbor_0; - uint bisectorState_0; - uint flags_0; - uint propagationID_0; -}; - - -#line 35 -layout(std430, binding = 6, set = 1) buffer StructuredBuffer_BisectorData_std430_t_0 { - BisectorData_std430_0 _data[]; -} pParams_bisectorDataBuffer_0; - -#line 35 -layout(std430, binding = 7, set = 1) buffer StructuredBuffer_uint_t_2 { +#line 178 0 +layout(std430, binding = 2) buffer StructuredBuffer_uint_t_0 { uint _data[]; } pParams_classificationBuffer_0; -#line 102 3 -struct Plane_std140_0 -{ - vec3 n_0; - float d_0; -}; +#line 178 +layout(std430, binding = 9) buffer StructuredBuffer_uint_t_1 { + uint _data[]; +} pParams_cbtBuffer_0; +#line 63 +layout(std430, binding = 10) buffer StructuredBuffer_uint64_t_0 { + uint64_t _data[]; +} pParams_bitFieldBuffer_0; -#line 102 -struct _Array_std140_Plane4_0 -{ - Plane_std140_0 data_2[4]; -}; +#line 119 +const uint64_t OCBT_bit_mask_0[18] = { 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 65535UL, 65535UL, 65535UL, 255UL, 18446744073709551615UL, 18446744073709551615UL, 65535UL, 255UL, 15UL, 3UL, 1UL }; - -#line 102 -struct Frustum_std140_0 -{ - _Array_std140_Plane4_0 sides_0; -}; - - -#line 19 -struct ViewParameter_std140_0 -{ - Frustum_std140_0 viewFrustum_0; - _MatrixStorage_float4x4_ColMajorstd140_0 viewMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 inverseViewMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 projectionMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 inverseProjection_0; - vec4 cameraPosition_WS_0; - vec4 cameraForward_WS_0; - vec2 screenDimensions_0; - vec2 invScreenDimensions_0; - uint frameIndex_0; - float time_0; -}; - - -#line 22 -layout(binding = 0) -layout(std140) uniform block_ViewParameter_std140_0 -{ - Frustum_std140_0 viewFrustum_0; - _MatrixStorage_float4x4_ColMajorstd140_0 viewMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 inverseViewMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 projectionMatrix_0; - _MatrixStorage_float4x4_ColMajorstd140_0 inverseProjection_0; - vec4 cameraPosition_WS_0; - vec4 cameraForward_WS_0; - vec2 screenDimensions_0; - vec2 invScreenDimensions_0; - uint frameIndex_0; - float time_0; -}pViewParams_0; - -#line 22 -mat4x4 unpackStorage_0(_MatrixStorage_float4x4_ColMajorstd140_0 _S1) -{ - -#line 22 - return mat4x4(_S1.data_0[0][0], _S1.data_0[1][0], _S1.data_0[2][0], _S1.data_0[3][0], _S1.data_0[0][1], _S1.data_0[1][1], _S1.data_0[2][1], _S1.data_0[3][1], _S1.data_0[0][2], _S1.data_0[1][2], _S1.data_0[2][2], _S1.data_0[3][2], _S1.data_0[0][3], _S1.data_0[1][3], _S1.data_0[2][3], _S1.data_0[3][3]); -} - - -#line 99 -struct Plane_0 -{ - vec3 n_0; - float d_0; -}; - - -#line 109 -Plane_0 unpackStorage_1(Plane_std140_0 _S2) -{ - -#line 109 - Plane_0 _S3 = { _S2.n_0, _S2.d_0 }; - -#line 109 - return _S3; -} - - -#line 109 -void unpackStorage_2(_Array_std140_Plane4_0 _S4, out Plane_0 _S5[4]) -{ - -#line 109 - Plane_0 _S6 = unpackStorage_1(_S4.data_2[1]); - -#line 109 - Plane_0 _S7 = unpackStorage_1(_S4.data_2[2]); - -#line 109 - Plane_0 _S8 = unpackStorage_1(_S4.data_2[3]); - -#line 109 - _S5[0] = unpackStorage_1(_S4.data_2[0]); - -#line 109 - _S5[1] = _S6; - -#line 109 - _S5[2] = _S7; - -#line 109 - _S5[3] = _S8; - -#line 109 - return; -} - - -#line 17 2 -_Array_std430_uint3_0 packStorage_0(uint _S9[3]) -{ - -#line 17 - uint _S10[3] = { _S9[0], _S9[1], _S9[2] }; - -#line 17 - _Array_std430_uint3_0 _S11 = { _S10 }; - -#line 17 - return _S11; -} - - -#line 17 -void unpackStorage_3(_Array_std430_uint3_0 _S12, out uint _S13[3]) -{ - -#line 17 - _S13[0] = _S12.data_1[0]; - -#line 17 - _S13[1] = _S12.data_1[1]; - -#line 17 - _S13[2] = _S12.data_1[2]; - -#line 17 - return; -} - - -#line 17 -struct BisectorData_0 -{ - uint indices_0[3]; - uint subdivisionPattern_0; - uint problematicNeighbor_0; - uint bisectorState_0; - uint flags_0; - uint propagationID_0; -}; - - -#line 17 -BisectorData_0 unpackStorage_4(BisectorData_std430_0 _S14) -{ - -#line 17 - uint _S15[3]; - -#line 17 - unpackStorage_3(_S14.indices_0, _S15); - -#line 17 - BisectorData_0 _S16 = { _S15, _S14.subdivisionPattern_0, _S14.problematicNeighbor_0, _S14.bisectorState_0, _S14.flags_0, _S14.propagationID_0 }; - -#line 17 - return _S16; -} - - -#line 17 -BisectorData_std430_0 packStorage_1(BisectorData_0 _S17) -{ - -#line 17 - BisectorData_std430_0 _S18 = { packStorage_0(_S17.indices_0), _S17.subdivisionPattern_0, _S17.problematicNeighbor_0, _S17.bisectorState_0, _S17.flags_0, _S17.propagationID_0 }; - -#line 17 - return _S18; -} - - -#line 38 -uint HeapIDDepth_0(uint64_t x_0) -{ - -#line 38 - uint64_t _S19 = x_0; - -#line 38 - uint depth_0 = 0U; - - - for(;;) - { - -#line 41 - if(_S19 > 0UL) - { - } - else - { - -#line 41 - break; - } - -#line 42 - uint depth_1 = depth_0 + 1U; - -#line 42 - _S19 = _S19 >> 1U; - -#line 42 - depth_0 = depth_1; - -#line 41 - } - - - - return depth_0; -} - - -#line 109 3 -struct Frustum_0 -{ - Plane_0 sides_0[4]; -}; - - -#line 109 -Frustum_0 unpackStorage_5(Frustum_std140_0 _S20) -{ - -#line 109 - Plane_0 _S21[4]; - -#line 109 - unpackStorage_2(_S20.sides_0, _S21); - -#line 109 - Frustum_0 _S22 = { _S21 }; - -#line 109 - return _S22; -} - - -#line 26 4 -bool FrustumAABBIntersect_0(Frustum_0 frustum_0, vec3 aabbMin_0, vec3 aabbMax_0) -{ - vec3 _S23 = (aabbMax_0 + aabbMin_0) * 0.5; - vec3 _S24 = (aabbMax_0 - aabbMin_0) * 0.5; - -#line 29 - int i_0 = 0; - for(;;) - { - -#line 30 - if(i_0 < 4) - { - } - else - { - -#line 30 - break; - } - -#line 37 - if(dot(_S23 + _S24 * vec3((ivec3(sign((frustum_0.sides_0[i_0].n_0))))), frustum_0.sides_0[i_0].n_0) + frustum_0.sides_0[i_0].d_0 < 0.0) - { - -#line 38 - return false; - } - -#line 30 - i_0 = i_0 + 1; - -#line 30 - } - -#line 40 - return true; -} - - -#line 7 -struct BisectorGeometry_0 -{ - vec3 p_0[4]; -}; - - -#line 43 -int ClassifyBisector_0(BisectorGeometry_0 tri_0, uint depth_2) -{ - - - - vec3 viewDir_0 = normalize(- ((tri_0.p_0[0] + tri_0.p_0[1] + tri_0.p_0[2]) / 3.0)); - - float VdotN_0 = dot(viewDir_0, normalize(cross(tri_0.p_0[2] - tri_0.p_0[1], tri_0.p_0[0] - tri_0.p_0[1]))); - -#line 50 - bool _S25; - - - if(dot(viewDir_0, pViewParams_0.cameraForward_WS_0.xyz) < 0.0) - { - -#line 53 - _S25 = VdotN_0 < -0.00100000004749745; - -#line 53 - } - else - { - -#line 53 - _S25 = false; - -#line 53 - } - -#line 53 - if(_S25) - { - -#line 54 - return -3; - } - - float _S26 = tri_0.p_0[0].x; - -#line 57 - float _S27 = tri_0.p_0[1].x; - -#line 57 - float _S28 = tri_0.p_0[2].x; - -#line 57 - float _S29 = tri_0.p_0[0].y; - -#line 57 - float _S30 = tri_0.p_0[1].y; - -#line 57 - float _S31 = tri_0.p_0[2].y; - -#line 57 - float _S32 = tri_0.p_0[0].z; - -#line 57 - float _S33 = tri_0.p_0[1].z; - -#line 57 - float _S34 = tri_0.p_0[2].z; - - - - if(!FrustumAABBIntersect_0(unpackStorage_5(pViewParams_0.viewFrustum_0), vec3(min(min(_S26, _S27), _S28), min(min(_S29, _S30), _S31), min(min(_S32, _S33), _S34)), vec3(max(max(_S26, _S27), _S28), max(max(_S29, _S30), _S31), max(max(_S32, _S33), _S34)))) - { - -#line 62 - return -2; - } - -#line 62 - mat4x4 _S35 = unpackStorage_0(pParams_update_0.viewProjectionMatrix_0); - - - - vec4 _S36 = (((vec4(tri_0.p_0[0], 1.0)) * (_S35))); - -#line 66 - vec4 p0P_0 = _S36; - p0P_0.xy = _S36.xy / _S36.w; - p0P_0.xy = p0P_0.xy * 0.5 + 0.5; - - vec4 _S37 = (((vec4(tri_0.p_0[1], 1.0)) * (_S35))); - -#line 70 - vec4 p1P_0 = _S37; - p1P_0.xy = _S37.xy / _S37.w; - p1P_0.xy = p1P_0.xy * 0.5 + 0.5; - - vec4 _S38 = (((vec4(tri_0.p_0[2], 1.0)) * (_S35))); - -#line 74 - vec4 p2P_0 = _S38; - p2P_0.xy = _S38.xy / _S38.w; - p2P_0.xy = p2P_0.xy * 0.5 + 0.5; - -#line 85 - float areaOverestimation_0 = mix(2.0, 1.0, pow(VdotN_0, 0.20000000298023224)); - float area_0 = 0.5 * abs(p0P_0.x * (p2P_0.y - p1P_0.y) + p1P_0.x * (p0P_0.y - p2P_0.y) + p2P_0.x * (p1P_0.y - p0P_0.y)) * (pViewParams_0.screenDimensions_0.x * pViewParams_0.screenDimensions_0.y) * areaOverestimation_0; - - - if(pParams_update_0.triangleSize_0 < area_0) - { - -#line 89 - _S25 = depth_2 < pParams_update_0.maxSubdivisionDepth_0; - -#line 89 - } - else - { - -#line 89 - _S25 = false; - -#line 89 - } - -#line 89 - if(_S25) - { - - return 1; - } - else - { - -#line 94 - if(pParams_update_0.triangleSize_0 * 0.5 > area_0) - { - -#line 94 - _S25 = true; - -#line 94 - } - else - { - -#line 94 - _S25 = depth_2 > pParams_update_0.maxSubdivisionDepth_0; - -#line 94 - } - -#line 94 - if(_S25) - { - - vec4 _S39 = (((vec4(tri_0.p_0[3], 1.0)) * (_S35))); +#line 141 +const uint OCBT_bit_count_0[18] = { 32U, 32U, 32U, 32U, 32U, 32U, 32U, 16U, 16U, 16U, 8U, 64U, 32U, 16U, 8U, 4U, 2U, 1U }; #line 97 - vec4 p3P_0 = _S39; - p3P_0.xy = _S39.xy / _S39.w; - p3P_0.xy = p3P_0.xy * 0.5 + 0.5; +const uint OCBT_depth_offset_0[18] = { 0U, 32U, 96U, 224U, 480U, 992U, 2016U, 4064U, 6112U, 10208U, 18400U, 0U, 0U, 0U, 0U, 0U, 0U, 0U }; -#line 107 - if(pParams_update_0.triangleSize_0 >= 0.5 * abs(p0P_0.x * (p2P_0.y - p3P_0.y) + p3P_0.x * (p0P_0.y - p2P_0.y) + p2P_0.x * (p3P_0.y - p0P_0.y)) * (pViewParams_0.screenDimensions_0.x * pViewParams_0.screenDimensions_0.y) * areaOverestimation_0) - { - -#line 107 - _S25 = true; - -#line 107 - } - else - { - -#line 107 - _S25 = depth_2 > pParams_update_0.maxSubdivisionDepth_0; - -#line 107 - } - -#line 107 - int _S40; - -#line 107 - if(_S25) - { - -#line 107 - _S40 = -1; - -#line 107 - } - else - { - -#line 107 - _S40 = 0; - -#line 107 - } - -#line 107 - return _S40; - } - -#line 89 - } - -#line 109 - return 0; -} +#line 163 +shared uint gs_cbtTree_0[831]; -#line 140 -void ClassifyElement_0(uint currentID_0, BisectorGeometry_0 bis_0, uint totalNumElements_1, uint baseDepth_1) +#line 171 +void load_buffer_to_shared_memory_0(uint groupIndex_0) { - uint64_t heapID_0 = pParams_heapIDBuffer_0._data[uint(currentID_0)]; - uint depth_3 = HeapIDDepth_0(pParams_heapIDBuffer_0._data[uint(currentID_0)]); - BisectorData_0 cbisectorData_0 = unpackStorage_4(pParams_bisectorDataBuffer_0._data[uint(currentID_0)]); +#line 171 + uint e_0 = 0U; - cbisectorData_0.subdivisionPattern_0 = 0U; - cbisectorData_0.bisectorState_0 = 0U; - cbisectorData_0.problematicNeighbor_0 = 4294967295U; - cbisectorData_0.flags_0 = 1U; - - - int currentValidity_0 = ClassifyBisector_0(bis_0, depth_3); - if(currentValidity_0 > 0) + for(;;) { - - cbisectorData_0.bisectorState_0 = 1U; - uint targetSlot_0 = atomicAdd(pParams_classificationBuffer_0._data[uint(0UL)], 1U); - pParams_classificationBuffer_0._data[uint(2UL + uint64_t(targetSlot_0))] = currentID_0; - -#line 155 - } - else - { - -#line 155 - int _S41; - -#line 165 - if(currentValidity_0 >= -1) +#line 174 + if(int(e_0) < 13) { - -#line 165 - _S41 = 1; - -#line 165 } else { -#line 165 - _S41 = 0; - -#line 165 +#line 174 + break; } - -#line 165 - cbisectorData_0.flags_0 = uint(_S41); - -#line 155 - } - -#line 155 - bool _S42; - -#line 168 - if(baseDepth_1 != depth_3) - { - -#line 168 - _S42 = currentValidity_0 < 0; - -#line 168 - } - else - { - -#line 168 - _S42 = false; - -#line 168 - } - -#line 168 - if(_S42) - { - - cbisectorData_0.bisectorState_0 = 2U; - - - if(heapID_0 % 2UL == 0UL) + uint target_element_0 = uint(13 * int(groupIndex_0) + int(e_0)); + if(int(target_element_0) < 831) { - uint targetSlot_1 = atomicAdd(pParams_classificationBuffer_0._data[uint(1UL)], 1U); - pParams_classificationBuffer_0._data[uint(2UL + uint64_t(totalNumElements_1) + uint64_t(targetSlot_1))] = currentID_0; +#line 178 + gs_cbtTree_0[target_element_0] = pParams_cbtBuffer_0._data[uint(target_element_0)]; -#line 174 +#line 177 } -#line 168 +#line 174 + e_0 = e_0 + 1U; + +#line 174 } -#line 183 - pParams_bisectorDataBuffer_0._data[uint(currentID_0)] = packStorage_1(cbisectorData_0); +#line 180 + controlBarrier(gl_ScopeWorkgroup, gl_ScopeWorkgroup, gl_StorageSemanticsShared, gl_SemanticsAcquireRelease); return; } -#line 14 5 +#line 183 +uint get_heap_element_0(uint id_0) +{ + + uint real_heap_id_0 = id_0 - 1U; + uint depth_0 = uint(log2(float(real_heap_id_0 + 1U))); + + + uint first_bit_0 = OCBT_depth_offset_0[depth_0] + OCBT_bit_count_0[depth_0] * (real_heap_id_0 - ((1U << depth_0) - 1U)); + if(depth_0 < 11U) + { + + + + return gs_cbtTree_0[first_bit_0 / 32U] >> first_bit_0 % 32U & uint(OCBT_bit_mask_0[depth_0]); + } + else + { + + + uint64_t target_bits_0 = pParams_bitFieldBuffer_0._data[uint(first_bit_0 / 64U)] >> first_bit_0 % 64U & OCBT_bit_mask_0[depth_0]; + + + return bitCount(uint(target_bits_0 >> 32)) + bitCount(uint(target_bits_0)); + } + +#line 205 +} + + + + +uint decode_bit_0(uint handle_0) +{ + +#line 210 + uint b_0; + +#line 210 + uint heapElementID_0 = 1U; + +#line 210 + uint currentDepth_0 = 0U; + +#line 210 + uint bitCount_0 = handle_0; + +#line 227 + for(;;) + { + +#line 227 + if(currentDepth_0 < 11U) + { + } + else + { + +#line 227 + break; + } + + uint heapValue_0 = get_heap_element_0(2U * heapElementID_0); + + + if(bitCount_0 < heapValue_0) + { + +#line 233 + b_0 = 0U; + +#line 233 + } + else + { + +#line 233 + b_0 = 1U; + +#line 233 + } + + + uint _S1 = 2U * heapElementID_0 + b_0; + + + uint _S2 = bitCount_0 - heapValue_0 * b_0; + +#line 227 + uint currentDepth_1 = currentDepth_0 + 1U; + +#line 227 + heapElementID_0 = _S1; + +#line 227 + currentDepth_0 = currentDepth_1; + +#line 227 + bitCount_0 = _S2; + +#line 227 + } + +#line 243 + uint _S3 = currentDepth_0 + 1U; + + + uint64_t _S4 = pParams_bitFieldBuffer_0._data[uint(int(heapElementID_0) - 2048)]; + +#line 210 + uint _S5 = bitCount_0; + +#line 210 + uint64_t mask_0 = 18446744073709551615UL; + +#line 210 + currentDepth_0 = _S3; + +#line 210 + bitCount_0 = 32U; + +#line 210 + uint _S6 = _S5; + +#line 249 + for(;;) + { + +#line 249 + if(currentDepth_0 < uint(log2(1.31072e+05)) + 1U) + { + } + else + { + +#line 249 + break; + } + +#line 257 + uint64_t target_bits_1 = _S4 >> bitCount_0 * (2U * heapElementID_0 - 1U - ((1U << currentDepth_0) - 1U)) % 64U & mask_0; + uint heapValue_1 = bitCount(uint(target_bits_1 >> 32)) + bitCount(uint(target_bits_1)); + + + if(_S6 < heapValue_1) + { + +#line 261 + b_0 = 0U; + +#line 261 + } + else + { + +#line 261 + b_0 = 1U; + +#line 261 + } + + + uint _S7 = 2U * heapElementID_0 + b_0; + + + uint _S8 = _S6 - heapValue_1 * b_0; + + + uint bitCount_1 = bitCount_0 / 2U; + uint64_t _S9 = mask_0 >> bitCount_1; + +#line 249 + uint currentDepth_2 = currentDepth_0 + 1U; + +#line 249 + heapElementID_0 = _S7; + +#line 249 + mask_0 = _S9; + +#line 249 + currentDepth_0 = currentDepth_2; + +#line 249 + bitCount_0 = bitCount_1; + +#line 249 + _S6 = _S8; + +#line 249 + } + +#line 273 + return heapElementID_0 ^ 131072U; +} + + + +uint decode_bit_complement_0(uint handle_1) +{ + +#line 278 + uint b_1; + +#line 278 + uint heapElementID_1 = 1U; + +#line 278 + uint currentDepth_3 = 0U; + +#line 278 + uint c_0 = 65536U; + +#line 278 + uint bitCount_2 = handle_1; + +#line 299 + for(;;) + { + +#line 299 + if(currentDepth_3 < 11U) + { + } + else + { + +#line 299 + break; + } + uint heapValue_2 = c_0 - get_heap_element_0(2U * heapElementID_1); + if(bitCount_2 < heapValue_2) + { + +#line 302 + b_1 = 0U; + +#line 302 + } + else + { + +#line 302 + b_1 = 1U; + +#line 302 + } + + uint _S10 = 2U * heapElementID_1 + b_1; + uint _S11 = bitCount_2 - heapValue_2 * b_1; + uint c_1 = c_0 / 2U; + +#line 299 + uint currentDepth_4 = currentDepth_3 + 1U; + +#line 299 + heapElementID_1 = _S10; + +#line 299 + currentDepth_3 = currentDepth_4; + +#line 299 + c_0 = c_1; + +#line 299 + bitCount_2 = _S11; + +#line 299 + } + +#line 310 + uint _S12 = currentDepth_3 + 1U; + + + uint64_t _S13 = pParams_bitFieldBuffer_0._data[uint(int(heapElementID_1) - 2048)]; + +#line 278 + uint _S14 = bitCount_2; + +#line 278 + uint64_t mask_1 = 18446744073709551615UL; + +#line 278 + currentDepth_3 = _S12; + +#line 278 + bitCount_2 = 32U; + +#line 278 + uint _S15 = _S14; + +#line 316 + for(;;) + { + +#line 316 + if(currentDepth_3 < uint(log2(1.31072e+05)) + 1U) + { + } + else + { + +#line 316 + break; + } + +#line 324 + uint64_t target_bits_2 = _S13 >> bitCount_2 * (2U * heapElementID_1 - 1U - ((1U << currentDepth_3) - 1U)) % 64U & mask_1; + uint heapValue_3 = c_0 - bitCount(uint(target_bits_2 >> 32)) + bitCount(uint(target_bits_2)); + + if(_S15 < heapValue_3) + { + +#line 327 + b_1 = 0U; + +#line 327 + } + else + { + +#line 327 + b_1 = 1U; + +#line 327 + } + + uint _S16 = 2U * heapElementID_1 + b_1; + uint _S17 = _S15 - heapValue_3 * b_1; + uint c_2 = c_0 / 2U; + + + uint bitCount_3 = bitCount_2 / 2U; + uint64_t _S18 = mask_1 >> bitCount_3; + +#line 316 + uint currentDepth_5 = currentDepth_3 + 1U; + +#line 316 + heapElementID_1 = _S16; + +#line 316 + mask_1 = _S18; + +#line 316 + currentDepth_3 = currentDepth_5; + +#line 316 + bitCount_2 = bitCount_3; + +#line 316 + c_0 = c_2; + +#line 316 + _S15 = _S17; + +#line 316 + } + +#line 338 + return heapElementID_1 ^ 131072U; +} + + + layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; void main() { -#line 14 - uint _S43 = gl_GlobalInvocationID.x; +#line 343 + uint _S19 = gl_GlobalInvocationID.x; - - if(_S43 >= pParams_indirectDrawBuffer_0._data[uint(9)]) - { - -#line 18 - return; - } - - uint _S44 = pParams_indexedBisectorBuffer_0._data[uint(_S43)]; - - - BisectorGeometry_0 bis_1; - uint _S45 = 3U * _S44; - -#line 25 - bis_1.p_0[0] = pParams_currentVertexBuffer_0._data[uint(_S45)].xyz; - bis_1.p_0[1] = pParams_currentVertexBuffer_0._data[uint(_S45 + 1U)].xyz; - bis_1.p_0[2] = pParams_currentVertexBuffer_0._data[uint(_S45 + 2U)].xyz; - bis_1.p_0[3] = pParams_currentVertexBuffer_0._data[uint(3U * pParams_geometry_0.totalNumElements_0 + _S44)].xyz; - - - ClassifyElement_0(_S44, bis_1, pParams_geometry_0.totalNumElements_0, pParams_geometry_0.baseDepth_0); + load_buffer_to_shared_memory_0(gl_LocalInvocationIndex); + pParams_classificationBuffer_0._data[uint(_S19)] = decode_bit_0(_S19); + pParams_classificationBuffer_0._data[uint(_S19 * 2U)] = decode_bit_complement_0(_S19); return; } diff --git a/res/shaders/terrain/CompileTest.slang b/res/shaders/terrain/CompileTest.slang index ecde828..05ed6aa 100644 --- a/res/shaders/terrain/CompileTest.slang +++ b/res/shaders/terrain/CompileTest.slang @@ -206,9 +206,143 @@ uint get_heap_element(uint id) } } +// 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 +} + [numthreads(64, 1, 1)] void GetHeap(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThreadID) { load_buffer_to_shared_memory(groupIndex); - pParams.classificationBuffer[dispatchID] = get_heap_element(dispatchID); + pParams.classificationBuffer[dispatchID] = decode_bit(dispatchID); + pParams.classificationBuffer[dispatchID * 2] = decode_bit_complement(dispatchID); } \ No newline at end of file diff --git a/res/shaders/terrain/CompileTest.spv b/res/shaders/terrain/CompileTest.spv new file mode 100644 index 0000000..75d9078 --- /dev/null +++ b/res/shaders/terrain/CompileTest.spv @@ -0,0 +1,455 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : require +#extension GL_KHR_memory_scope_semantics : require +layout(row_major) uniform; +layout(row_major) buffer; + +#line 178 0 +layout(std430, binding = 2) buffer StructuredBuffer_uint_t_0 { + uint _data[]; +} pParams_classificationBuffer_0; + +#line 178 +layout(std430, binding = 9) buffer StructuredBuffer_uint_t_1 { + uint _data[]; +} pParams_cbtBuffer_0; + +#line 63 +layout(std430, binding = 10) buffer StructuredBuffer_uint64_t_0 { + uint64_t _data[]; +} pParams_bitFieldBuffer_0; + +#line 119 +const uint64_t OCBT_bit_mask_0[18] = { 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 18446744073709551615UL, 65535UL, 65535UL, 65535UL, 255UL, 18446744073709551615UL, 18446744073709551615UL, 65535UL, 255UL, 15UL, 3UL, 1UL }; + +#line 141 +const uint OCBT_bit_count_0[18] = { 32U, 32U, 32U, 32U, 32U, 32U, 32U, 16U, 16U, 16U, 8U, 64U, 32U, 16U, 8U, 4U, 2U, 1U }; + +#line 97 +const uint OCBT_depth_offset_0[18] = { 0U, 32U, 96U, 224U, 480U, 992U, 2016U, 4064U, 6112U, 10208U, 18400U, 0U, 0U, 0U, 0U, 0U, 0U, 0U }; + +#line 163 +shared uint gs_cbtTree_0[831]; + + +#line 171 +void load_buffer_to_shared_memory_0(uint groupIndex_0) +{ + +#line 171 + uint e_0 = 0U; + + + for(;;) + { + +#line 174 + if(int(e_0) < 13) + { + } + else + { + +#line 174 + break; + } + uint target_element_0 = uint(13 * int(groupIndex_0) + int(e_0)); + if(int(target_element_0) < 831) + { + +#line 178 + gs_cbtTree_0[target_element_0] = pParams_cbtBuffer_0._data[uint(target_element_0)]; + +#line 177 + } + +#line 174 + e_0 = e_0 + 1U; + +#line 174 + } + +#line 180 + controlBarrier(gl_ScopeWorkgroup, gl_ScopeWorkgroup, gl_StorageSemanticsShared, gl_SemanticsAcquireRelease); + return; +} + + +#line 183 +uint get_heap_element_0(uint id_0) +{ + + uint real_heap_id_0 = id_0 - 1U; + uint depth_0 = uint(log2(float(real_heap_id_0 + 1U))); + + + uint first_bit_0 = OCBT_depth_offset_0[depth_0] + OCBT_bit_count_0[depth_0] * (real_heap_id_0 - ((1U << depth_0) - 1U)); + if(depth_0 < 11U) + { + + + + return gs_cbtTree_0[first_bit_0 / 32U] >> first_bit_0 % 32U & uint(OCBT_bit_mask_0[depth_0]); + } + else + { + + + uint64_t target_bits_0 = pParams_bitFieldBuffer_0._data[uint(first_bit_0 / 64U)] >> first_bit_0 % 64U & OCBT_bit_mask_0[depth_0]; + + + return bitCount(uint(target_bits_0 >> 32)) + bitCount(uint(target_bits_0)); + } + +#line 205 +} + + + + +uint decode_bit_0(uint handle_0) +{ + +#line 210 + uint b_0; + +#line 210 + uint heapElementID_0 = 1U; + +#line 210 + uint currentDepth_0 = 0U; + +#line 210 + uint bitCount_0 = handle_0; + +#line 227 + for(;;) + { + +#line 227 + if(currentDepth_0 < 11U) + { + } + else + { + +#line 227 + break; + } + + uint heapValue_0 = get_heap_element_0(2U * heapElementID_0); + + + if(bitCount_0 < heapValue_0) + { + +#line 233 + b_0 = 0U; + +#line 233 + } + else + { + +#line 233 + b_0 = 1U; + +#line 233 + } + + + uint _S1 = 2U * heapElementID_0 + b_0; + + + uint _S2 = bitCount_0 - heapValue_0 * b_0; + +#line 227 + uint currentDepth_1 = currentDepth_0 + 1U; + +#line 227 + heapElementID_0 = _S1; + +#line 227 + currentDepth_0 = currentDepth_1; + +#line 227 + bitCount_0 = _S2; + +#line 227 + } + +#line 243 + uint _S3 = currentDepth_0 + 1U; + + + uint64_t _S4 = pParams_bitFieldBuffer_0._data[uint(int(heapElementID_0) - 2048)]; + +#line 210 + uint _S5 = bitCount_0; + +#line 210 + uint64_t mask_0 = 18446744073709551615UL; + +#line 210 + currentDepth_0 = _S3; + +#line 210 + bitCount_0 = 32U; + +#line 210 + uint _S6 = _S5; + +#line 249 + for(;;) + { + +#line 249 + if(currentDepth_0 < uint(log2(1.31072e+05)) + 1U) + { + } + else + { + +#line 249 + break; + } + +#line 257 + uint64_t target_bits_1 = _S4 >> bitCount_0 * (2U * heapElementID_0 - 1U - ((1U << currentDepth_0) - 1U)) % 64U & mask_0; + uint heapValue_1 = bitCount(uint(target_bits_1 >> 32)) + bitCount(uint(target_bits_1)); + + + if(_S6 < heapValue_1) + { + +#line 261 + b_0 = 0U; + +#line 261 + } + else + { + +#line 261 + b_0 = 1U; + +#line 261 + } + + + uint _S7 = 2U * heapElementID_0 + b_0; + + + uint _S8 = _S6 - heapValue_1 * b_0; + + + uint bitCount_1 = bitCount_0 / 2U; + uint64_t _S9 = mask_0 >> bitCount_1; + +#line 249 + uint currentDepth_2 = currentDepth_0 + 1U; + +#line 249 + heapElementID_0 = _S7; + +#line 249 + mask_0 = _S9; + +#line 249 + currentDepth_0 = currentDepth_2; + +#line 249 + bitCount_0 = bitCount_1; + +#line 249 + _S6 = _S8; + +#line 249 + } + +#line 273 + return heapElementID_0 ^ 131072U; +} + + + +uint decode_bit_complement_0(uint handle_1) +{ + +#line 278 + uint b_1; + +#line 278 + uint heapElementID_1 = 1U; + +#line 278 + uint currentDepth_3 = 0U; + +#line 278 + uint c_0 = 65536U; + +#line 278 + uint bitCount_2 = handle_1; + +#line 299 + for(;;) + { + +#line 299 + if(currentDepth_3 < 11U) + { + } + else + { + +#line 299 + break; + } + uint heapValue_2 = c_0 - get_heap_element_0(2U * heapElementID_1); + if(bitCount_2 < heapValue_2) + { + +#line 302 + b_1 = 0U; + +#line 302 + } + else + { + +#line 302 + b_1 = 1U; + +#line 302 + } + + uint _S10 = 2U * heapElementID_1 + b_1; + uint _S11 = bitCount_2 - heapValue_2 * b_1; + uint c_1 = c_0 / 2U; + +#line 299 + uint currentDepth_4 = currentDepth_3 + 1U; + +#line 299 + heapElementID_1 = _S10; + +#line 299 + currentDepth_3 = currentDepth_4; + +#line 299 + c_0 = c_1; + +#line 299 + bitCount_2 = _S11; + +#line 299 + } + +#line 310 + uint _S12 = currentDepth_3 + 1U; + + + uint64_t _S13 = pParams_bitFieldBuffer_0._data[uint(int(heapElementID_1) - 2048)]; + +#line 278 + uint _S14 = bitCount_2; + +#line 278 + uint64_t mask_1 = 18446744073709551615UL; + +#line 278 + currentDepth_3 = _S12; + +#line 278 + bitCount_2 = 32U; + +#line 278 + uint _S15 = _S14; + +#line 316 + for(;;) + { + +#line 316 + if(currentDepth_3 < uint(log2(1.31072e+05)) + 1U) + { + } + else + { + +#line 316 + break; + } + +#line 324 + uint64_t target_bits_2 = _S13 >> bitCount_2 * (2U * heapElementID_1 - 1U - ((1U << currentDepth_3) - 1U)) % 64U & mask_1; + uint heapValue_3 = c_0 - bitCount(uint(target_bits_2 >> 32)) + bitCount(uint(target_bits_2)); + + if(_S15 < heapValue_3) + { + +#line 327 + b_1 = 0U; + +#line 327 + } + else + { + +#line 327 + b_1 = 1U; + +#line 327 + } + + uint _S16 = 2U * heapElementID_1 + b_1; + uint _S17 = _S15 - heapValue_3 * b_1; + uint c_2 = c_0 / 2U; + + + uint bitCount_3 = bitCount_2 / 2U; + uint64_t _S18 = mask_1 >> bitCount_3; + +#line 316 + uint currentDepth_5 = currentDepth_3 + 1U; + +#line 316 + heapElementID_1 = _S16; + +#line 316 + mask_1 = _S18; + +#line 316 + currentDepth_3 = currentDepth_5; + +#line 316 + bitCount_2 = bitCount_3; + +#line 316 + c_0 = c_2; + +#line 316 + _S15 = _S17; + +#line 316 + } + +#line 338 + return heapElementID_1 ^ 131072U; +} + + + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; +void main() +{ + +#line 343 + uint _S19 = gl_GlobalInvocationID.x; + + load_buffer_to_shared_memory_0(gl_LocalInvocationIndex); + pParams_classificationBuffer_0._data[uint(_S19)] = decode_bit_0(_S19); + pParams_classificationBuffer_0._data[uint(_S19 * 2U)] = decode_bit_complement_0(_S19); + return; +} + diff --git a/res/shaders/terrain/CompileTest.spv-asm b/res/shaders/terrain/CompileTest.spv-asm new file mode 100644 index 0000000000000000000000000000000000000000..c5c0feb3db0801ec8eddcf1406e279625f925538 GIT binary patch literal 31528 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