From 07dad4641dce0d980537d0f0a8c4635bd74aed75 Mon Sep 17 00:00:00 2001 From: Dynamitos Date: Mon, 21 Oct 2024 11:13:26 +0200 Subject: [PATCH] Idk what is still missing --- res/shaders/terrain/CBT.slang | 6 +- res/shaders/terrain/CompileTest.glsl | 753 ++++++++++++++++++ res/shaders/terrain/CompileTest.slang | 265 +++--- res/shaders/terrain/generate.py | 13 + res/shaders/terrain/update_utils.slang | 18 +- .../Graphics/RenderPass/TerrainRenderer.cpp | 4 +- src/Engine/Graphics/Vulkan/Buffer.cpp | 2 +- src/Engine/Graphics/Vulkan/Graphics.cpp | 1 + src/Engine/Graphics/slang-compile.cpp | 4 +- 9 files changed, 909 insertions(+), 157 deletions(-) create mode 100644 res/shaders/terrain/CompileTest.glsl create mode 100644 res/shaders/terrain/generate.py diff --git a/res/shaders/terrain/CBT.slang b/res/shaders/terrain/CBT.slang index e1932ca..c545613 100644 --- a/res/shaders/terrain/CBT.slang +++ b/res/shaders/terrain/CBT.slang @@ -396,11 +396,9 @@ void reduce_second_pass(uint groupIndex) GroupMemoryBarrierWithGroupSync(); // Load the bitfield to the LDS - for (uint e = 0; e < 5; ++e) + for (uint i = groupIndex; i < 319; i+=WORKGROUP_SIZE) { - uint target_element = 5 * groupIndex + e; - if (target_element < 319) - pParams.cbtBuffer[target_element] = gs_cbtTree[target_element]; + pParams.cbtBuffer[i] = gs_cbtTree[i]; } } diff --git a/res/shaders/terrain/CompileTest.glsl b/res/shaders/terrain/CompileTest.glsl new file mode 100644 index 0000000..244c87d --- /dev/null +++ b/res/shaders/terrain/CompileTest.glsl @@ -0,0 +1,753 @@ +#version 450 +#extension GL_EXT_shader_explicit_arithmetic_types_int64 : 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 { + uint _data[]; +} pParams_classificationBuffer_0; + +#line 102 3 +struct Plane_std140_0 +{ + vec3 n_0; + float d_0; +}; + + +#line 102 +struct _Array_std140_Plane4_0 +{ + Plane_std140_0 data_2[4]; +}; + + +#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 97 + vec4 p3P_0 = _S39; + p3P_0.xy = _S39.xy / _S39.w; + p3P_0.xy = p3P_0.xy * 0.5 + 0.5; + +#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 140 +void ClassifyElement_0(uint currentID_0, BisectorGeometry_0 bis_0, uint totalNumElements_1, uint baseDepth_1) +{ + + 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)]); + + + 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) + { + + + 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 165 + _S41 = 1; + +#line 165 + } + else + { + +#line 165 + _S41 = 0; + +#line 165 + } + +#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 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 174 + } + +#line 168 + } + +#line 183 + pParams_bisectorDataBuffer_0._data[uint(currentID_0)] = packStorage_1(cbisectorData_0); + return; +} + + +#line 14 5 +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; +void main() +{ + +#line 14 + uint _S43 = 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); + return; +} + diff --git a/res/shaders/terrain/CompileTest.slang b/res/shaders/terrain/CompileTest.slang index b38cdcc..ecde828 100644 --- a/res/shaders/terrain/CompileTest.slang +++ b/res/shaders/terrain/CompileTest.slang @@ -71,157 +71,144 @@ struct ComputeParams RWStructuredBuffer bisectorDataBuffer; RWStructuredBuffer propagateBuffer; RWStructuredBuffer simplifyBuffer; - RWStructuredBuffer bitFieldBuffer; + RWStructuredBuffer cbtBuffer; + RWStructuredBuffer bitFieldBuffer; }; ParameterBlock pParams; -void SplitElement(uint currentID, uint baseDepth, uint dispatchID) +#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) { - // Get the neighbors information - uint4 cNeighbors = pParams.neighboursBuffer[currentID]; - - // If there is a neighbor X - if (cNeighbors.x != INVALID_POINTER) + // Load the bitfield to the LDS + for (uint e = 0; e < BUFFER_ELEMENT_PER_LANE; ++e) { - // 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; + uint target_element = BUFFER_ELEMENT_PER_LANE * groupIndex + e; + if (target_element < OCBT_TREE_NUM_SLOTS) + gs_cbtTree[target_element] = pParams.cbtBuffer[target_element]; } + GroupMemoryBarrierWithGroupSync(); +} - // If there is a neighbor Y - if (cNeighbors.y != INVALID_POINTER) +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) { - // 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; + 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]); } - - // Depth of the current triangle - uint64_t heapID = pParams.heapIDBuffer[currentID]; - uint currentDepth = HeapIDDepth(heapID); - - // Compute the maximal required memory for this subdivision - int maxRequiredMemory = 2 * (currentDepth - baseDepth) - 1; - - // Get the twin information - uint twinID = cNeighbors.z; - - // 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; - - // 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) + else { - // 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); + 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); } } [numthreads(64, 1, 1)] -void Split(uint dispatchID : SV_DispatchThreadID) +void GetHeap(uint groupIndex : SV_GroupIndex, uint dispatchID : SV_DispatchThreadID) { - 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); -} + load_buffer_to_shared_memory(groupIndex); + pParams.classificationBuffer[dispatchID] = get_heap_element(dispatchID); +} \ No newline at end of file diff --git a/res/shaders/terrain/generate.py b/res/shaders/terrain/generate.py new file mode 100644 index 0000000..b991596 --- /dev/null +++ b/res/shaders/terrain/generate.py @@ -0,0 +1,13 @@ +import subprocess + +e = ['Reset', 'Classify', 'Split', 'PrepareIndirect', 'Allocate', 'Bisect', 'PropagateBisect', 'PrepareSimplify', 'Simplify', 'PropagateSimplify', 'ReducePrePass', 'ReduceFirstPass', 'ReduceSecondPass', 'BisectorIndexation', 'PrepareBisectorIndirect', 'Validate'] + +def generate(entry: list[str], file: str): + for point in entry: + subprocess.run(['C:/Users/Dynamitos/slang/build/Release/bin/slangc', '-I', '../lib', f'{file}.slang', '-profile', 'spirv_1_6', '-stage', 'compute', '-target','spirv', '-entry', f'{point}', '-o', f'{point}.spv', '-emit-spirv-via-glsl']) + +generate(e, 'CBTCompute') + +e = ['ClearBuffer', 'EvaluateLEB'] + +generate(e, 'LEB') \ No newline at end of file diff --git a/res/shaders/terrain/update_utils.slang b/res/shaders/terrain/update_utils.slang index 8751e95..c7ee4a3 100644 --- a/res/shaders/terrain/update_utils.slang +++ b/res/shaders/terrain/update_utils.slang @@ -19,9 +19,9 @@ 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; +static const uint32_t SPLIT_COUNTER = 0; +static const uint32_t SIMPLIFY_COUNTER = 1; +static const uint32_t CLASSIFY_COUNTER_OFFSET = 2; bool FrustumAABBIntersect(in Frustum frustum, float3 aabbMin, float3 aabbMax) { @@ -330,14 +330,13 @@ void AllocateElement(uint currentID) int numSlots = countbits(bisectorData.subdivisionPattern); // Request the number of bits we need using an interlock add - uint firstBitIndex = 0; + int firstBitIndex = 0; InterlockedAdd(pParams.memoryBuffer[0], numSlots, firstBitIndex); // llocate the bits we need for (uint bitId = 0; bitId < numSlots; ++bitId) { - uint index = decode_bit_complement(firstBitIndex + bitId); - bisectorData.indices[bitId] = index; + bisectorData.indices[bitId] = decode_bit_complement(firstBitIndex + bitId); } // Output @@ -664,7 +663,7 @@ void BisectElement(uint currentID, uint dispatchID) pParams.debugBuffer[dispatchID] = debug; for (uint siblingIdx = 0; siblingIdx < numSiblings; ++siblingIdx) { - set_bit_atomic_buffer(cBisectorData.indices[siblingIdx], true); + set_bit_atomic(cBisectorData.indices[siblingIdx], true); } } @@ -709,8 +708,9 @@ void PropagateBisectElement(uint currentID) } // Reset the problematic neighbor and the bisection state - pParams.bisectorDataBuffer[currentID].problematicNeighbor = INVALID_POINTER; - pParams.bisectorDataBuffer[currentID].bisectorState = UNCHANGED_ELEMENT; + cBisectorData.problematicNeighbor = INVALID_POINTER; + cBisectorData.bisectorState = UNCHANGED_ELEMENT; + pParams.bisectorDataBuffer[currentID] = cBisectorData; } void PrepareSimplifyElement(uint currentID) diff --git a/src/Engine/Graphics/RenderPass/TerrainRenderer.cpp b/src/Engine/Graphics/RenderPass/TerrainRenderer.cpp index 69d8745..1c9d95f 100644 --- a/src/Engine/Graphics/RenderPass/TerrainRenderer.cpp +++ b/src/Engine/Graphics/RenderPass/TerrainRenderer.cpp @@ -13,7 +13,7 @@ TerrainRenderer::TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDe Gfx::OPipelineLayout test = graphics->createPipelineLayout(); graphics->beginShaderCompilation(ShaderCompilationInfo{ .modules = {"CompileTest"}, - .entryPoints = {{"Split", "CompileTest"}}, + .entryPoints = {{"GetHeap", "CompileTest"}}, .rootSignature = test, }); graphics->createComputeShader({0}); @@ -32,7 +32,7 @@ TerrainRenderer::TerrainRenderer(Gfx::PGraphics graphics, PScene scene, Gfx::PDe .size = bufferSize, .data = (uint8*)cbt.rawBuffer(i), }, - .name = "GPUCBT", + .name = fmt::format("GPUCBT{0}", i).c_str(), }); plainMesh.gpuCBT.bufferArray[i]->pipelineBarrier(Gfx::SE_ACCESS_TRANSFER_WRITE_BIT, Gfx::SE_PIPELINE_STAGE_TRANSFER_BIT, Gfx::SE_ACCESS_SHADER_READ_BIT | Gfx::SE_ACCESS_SHADER_WRITE_BIT, diff --git a/src/Engine/Graphics/Vulkan/Buffer.cpp b/src/Engine/Graphics/Vulkan/Buffer.cpp index dba604b..9986710 100644 --- a/src/Engine/Graphics/Vulkan/Buffer.cpp +++ b/src/Engine/Graphics/Vulkan/Buffer.cpp @@ -313,7 +313,7 @@ void Buffer::createBuffer(uint64 size, uint32 destIndex) { PCommand command = graphics->getQueueCommands(initialOwner)->getCommands(); command->bindResource(PBufferAllocation(buffers[destIndex])); vkCmdFillBuffer(command->getHandle(), buffers[destIndex]->buffer, 0, VK_WHOLE_SIZE, clearValue); - pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, + buffers[destIndex]->pipelineBarrier(VK_ACCESS_TRANSFER_WRITE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); } } diff --git a/src/Engine/Graphics/Vulkan/Graphics.cpp b/src/Engine/Graphics/Vulkan/Graphics.cpp index c8849a4..caec4d7 100644 --- a/src/Engine/Graphics/Vulkan/Graphics.cpp +++ b/src/Engine/Graphics/Vulkan/Graphics.cpp @@ -792,6 +792,7 @@ void Graphics::pickPhysicalDevice() { .pNext = &meshShaderFeatures, .storageBuffer8BitAccess = true, .uniformAndStorageBuffer8BitAccess = true, + .shaderBufferInt64Atomics = true, .shaderFloat16 = true, .shaderInt8 = true, .shaderUniformBufferArrayNonUniformIndexing = true, diff --git a/src/Engine/Graphics/slang-compile.cpp b/src/Engine/Graphics/slang-compile.cpp index 821be5e..61de6ff 100644 --- a/src/Engine/Graphics/slang-compile.cpp +++ b/src/Engine/Graphics/slang-compile.cpp @@ -42,7 +42,7 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg // }, //}, { - .name = slang::CompilerOptionName::EmitSpirvDirectly, + .name = slang::CompilerOptionName::EmitSpirvViaGLSL, .value = { .kind = slang::CompilerOptionValueKind::Int, @@ -88,7 +88,7 @@ void Seele::beginCompilation(const ShaderCompilationInfo& info, SlangCompileTarg sessionDesc.preprocessorMacroCount = macros.size(); sessionDesc.preprocessorMacros = macros.data(); slang::TargetDesc targetDesc; - targetDesc.profile = globalSession->findProfile("spirv_1_6"); + targetDesc.profile = globalSession->findProfile("glsl_450"); targetDesc.format = target; sessionDesc.targetCount = 1; sessionDesc.targets = &targetDesc;