MeshletsCompute.azsl 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #pragma once
  2. #include <Atom/Features/SrgSemantics.azsli>
  3. //------------------------------------------------------------------------------
  4. ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
  5. { // [To Do] No needto use StructuredBuffer - change to buffer and test
  6. RWStructuredBuffer<int> m_meshletsSharedBuffer;
  7. }
  8. //------------------------------------------------------------------------------
  9. //! The following meshlet descriptor structure must reflect the structure as
  10. //! appeared in MeshletsData.h
  11. struct MeshletDescriptor
  12. {
  13. //! Offset into the indirect indices array representing the global index of
  14. //! all the meshlet vertices.
  15. //! The Indirect vertices array is built as follows:
  16. //! std::vector<uint32_t> indirectIndices;
  17. //! indirectIndices = { { meshlet 1 vertex indices }, { meshlet 2 }, .. { meshlet n} }
  18. uint vertexOffset; // In uint32_t steps
  19. //! Offset into the global meshlets triangleIndices array represented as:
  20. //! std::vector<uint8_t> triangleIndices;
  21. //! triangleIndices = { {meshlet 1 local indices group}, ... { meshlet n} }
  22. //! The local indices are an 8 bits index that can represent up to 256 entries.
  23. uint triangleOffset; // In bytes from the start of the array
  24. //! Finding a vertex within the meshlet is done like that:
  25. //! triangleOffset = currentMeshlet.triangleOffset + meshletTrIndex * 3;
  26. //! localIndex_i = meshletTriangles[triangleOffset + i]; // i = triangle vertex index 0..2
  27. //! vertexIndex_i = indirectIndices[currentMeshlet.vertexOffset + localIndex_i];
  28. //! Amount of vertices and triangle for the meshlet - based on this the arrays
  29. //! indirectIndices and triangleIndices are created per meshlet.
  30. uint vertexCount;
  31. uint triangleCount;
  32. };
  33. //------------------------------------------------------------------------------
  34. // This structure is used per mesh (object) and represents the meshlets data
  35. // for this mesh.
  36. // This is not the instance data but rather the object data that can be used
  37. // across instances of the same mesh.
  38. ShaderResourceGroup MeshletsDataSrg : SRG_PerObject
  39. {
  40. // Shared buffer offset in uint to be used when using the shared buffer when
  41. // addressing the properties
  42. uint m_indicesOffset;
  43. uint m_texCoordsOffset;
  44. uint2 padding;
  45. // For the next array review the structuee 'MeshletDescriptor'.
  46. // The array holds the offsets and amount of vertices and triangles per
  47. // meshlet.
  48. StructuredBuffer<MeshletDescriptor> m_meshletsDescriptors;
  49. // The following array consistes of sub arrays of triangles - one per meshlet.
  50. // Each uint (32 bits) represents 3 x 8 bits indices into the meshlet indices
  51. // lookup array (the top byte is unused).
  52. Buffer<uint> m_meshletsTriangles;
  53. // Array of sub-tables, each one represents lookup table for a meshlet that
  54. // maps between a meshlet local vertex index and its global index in the mesh.
  55. Buffer<uint> m_meshletsIndicesLookup;
  56. // ---------------------------------------------
  57. // The following two buffers are in fact buffer views into the shared buffer
  58. // so that the GPU memory can be synchronized via the pass system using only
  59. // a single buffer and barier between passes.
  60. // ---------------------------------------------
  61. // Index buffer of the mesh comprised of meshlets
  62. // Meshlets Compute threads will write the calculated indices per meshlet and
  63. // store it in the array if the meshlets are not culled.
  64. RWBuffer<uint> m_indices;
  65. // Mesh texture coordinates - will be used for debug purposes to color meshlets
  66. RWBuffer<float2> m_uvs;
  67. //--------------------------------------------------------------------------
  68. uint GetVertexIndex(uint index)
  69. {
  70. return PassSrg::m_meshletsSharedBuffer[m_indicesOffset + index];
  71. }
  72. void SetVertexIndex(uint index, uint vertexIndex )
  73. {
  74. PassSrg::m_meshletsSharedBuffer[m_indicesOffset + index] = vertexIndex;
  75. }
  76. void SetTriangleIndices(uint index, uint3 triIndices)
  77. {
  78. uint indexOffset = m_indicesOffset + index;
  79. PassSrg::m_meshletsSharedBuffer[indexOffset] = triIndices.x;
  80. PassSrg::m_meshletsSharedBuffer[indexOffset+1] = triIndices.y;
  81. PassSrg::m_meshletsSharedBuffer[indexOffset+2] = triIndices.z;
  82. }
  83. void SetUVs(uint index, float2 texCoords)
  84. {
  85. // index multiplied by 2 since we have two coordinates
  86. uint texCoordIndex = m_texCoordsOffset + (index << 1);
  87. PassSrg::m_meshletsSharedBuffer[texCoordIndex] = asint(texCoords.x);
  88. PassSrg::m_meshletsSharedBuffer[texCoordIndex+1] = asint(texCoords.y);
  89. }
  90. };
  91. //------------------------------------------------------------------------------
  92. // Given the local meshlet's triangle index and the meshlet, the function calculates
  93. // the global triangle's vertex indices and returns them along with the global
  94. // triangle offset.
  95. //------------------------------------------------------------------------------
  96. uint4 GetGlobalVertexIndicesAndTriOffset(MeshletDescriptor meshlet, uint localTriangleIdx)
  97. {
  98. uint globalTriangleIndex = meshlet.triangleOffset + localTriangleIdx;
  99. uint encodedTri = MeshletsDataSrg::m_meshletsTriangles[globalTriangleIndex];
  100. uint3 localIndices = uint3(
  101. (encodedTri) & 0xff,
  102. (encodedTri >> 8) & 0xff,
  103. (encodedTri >> 16) & 0xff
  104. );
  105. uint3 globalIndirection = meshlet.vertexOffset + localIndices;
  106. uint4 globalVertexIndicesAndTriOffset = uint4(
  107. MeshletsDataSrg::m_meshletsIndicesLookup[globalIndirection.x],
  108. MeshletsDataSrg::m_meshletsIndicesLookup[globalIndirection.y],
  109. MeshletsDataSrg::m_meshletsIndicesLookup[globalIndirection.z],
  110. globalTriangleIndex * 3
  111. );
  112. return globalVertexIndicesAndTriOffset;
  113. }
  114. /*
  115. * Modifications Copyright (c) Contributors to the Open 3D Engine Project.
  116. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  117. *
  118. * SPDX-License-Identifier: Apache-2.0 OR MIT
  119. *
  120. */
  121. //------------------------------------------------------------------------------
  122. //! The group's threads count should match either Meshlets::maxVerticesPerMeshlet
  123. //! or Meshlets::maxTrianglesPerMeshlet depending on our algorithm for minimizing
  124. //! amount of work per thread and achieving max parallelizm.
  125. //------------------------------------------------------------------------------
  126. #define THREADS_COUNT 64
  127. //------------------------------------------------------------------------------
  128. // The following method demonstartes the usage of the meshlets data buffers to
  129. // create the index buffer content on the fly and as debug display it also
  130. // generates the meshlets color in the UV channel.
  131. // A future step should be to run a culling compute before this and generate
  132. // a visibility list of the meshlets. This visibility list will be used to
  133. // generate the dispatch groups per the visible meshlets and populate the index
  134. // buffer accordingly hence saving most of the rasterization of culled meshlets.
  135. // Care should be taken for synchronizing between threads for the location of
  136. // the indices to be written - possibly single thread per mesh can be used to
  137. // prepare the look up table for writing the indices by each thread in a unique
  138. // location.
  139. //------------------------------------------------------------------------------
  140. [numthreads(THREADS_COUNT, 1, 1)]
  141. void ComputeMeshletsIndexBuffer(
  142. uint groupIndex : SV_GroupIndex,
  143. uint3 groupId : SV_GroupID,
  144. uint3 dispatchThreadId : SV_DispatchThreadID)
  145. {
  146. uint meshletId = groupId.x;
  147. MeshletDescriptor meshlet = MeshletsDataSrg::m_meshletsDescriptors[meshletId];
  148. uint uvDebugIndex = meshletId + 7; // to start off with some interesting color
  149. float2 debugUVs = float2( (uvDebugIndex % 3), ((uvDebugIndex / 3) % 3) ) * 0.5;
  150. //#define _DEBUG_TEST_CONTENT_
  151. #ifdef _DEBUG_TEST_CONTENT_
  152. ///////////////////////// Start - Test Debug Only ////////////////////////////
  153. // Simple test of the first entries of each meshlet - this will test writing
  154. // Tests writing data and data validity using both direct and indirect approach
  155. if ((groupIndex < meshlet.triangleCount) && (groupIndex < 4))
  156. {
  157. uint4 vtxGlobalVerticesAndTriOffset = GetGlobalVertexIndicesAndTriOffset(meshlet, groupIndex);
  158. // Both method work!!!
  159. if (groupIndex < 2)
  160. { // Sub-Buffers address
  161. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w] = 555;
  162. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w + 1] = meshletId;
  163. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w + 2] = groupIndex;
  164. // Notice that writing to address is writing float2! (not a single element)
  165. // This is ok for testing, but wrong in general since there is no 1:1 correlation
  166. // between vertices and indices.
  167. MeshletsDataSrg::m_uvs[vtxGlobalVerticesAndTriOffset.w].x = 555;
  168. MeshletsDataSrg::m_uvs[vtxGlobalVerticesAndTriOffset.w].y = groupIndex;
  169. // This is the indirection in into the vertex pointed by the Index Buffer but since it
  170. // can be located anywhere, it is harder to verify
  171. // MeshletsDataSrg::m_uvs[MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w]].x = 555;
  172. // MeshletsDataSrg::m_uvs[MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w]].y = meshletId;
  173. }
  174. else
  175. { // Shared Buffer using offsets
  176. uint3 testIndex = uint3(22,meshletId,groupIndex);
  177. MeshletsDataSrg::SetTriangleIndices(vtxGlobalVerticesAndTriOffset.w, testIndex);
  178. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.w, groupIndex);
  179. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.w + 1, groupIndex);
  180. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.w + 2, groupIndex);
  181. }
  182. return;
  183. }
  184. ///////////////////////// End - Test Debug Only ////////////////////////////
  185. #endif
  186. if (groupIndex < meshlet.triangleCount)
  187. { // groupIndex is used here as the index of the triangle we process
  188. uint4 vtxGlobalVerticesAndTriOffset = GetGlobalVertexIndicesAndTriOffset(meshlet, groupIndex);
  189. //#define _USE_SHARED_BUFFER_OFFSET_
  190. #ifdef _USE_SHARED_BUFFER_OFFSET_
  191. //// Setting the various properties via usage of the shared buffer with offsets
  192. // Construct the triangles using the meshlets data
  193. MeshletsDataSrg::SetTriangleIndices(vtxGlobalVerticesAndTriOffset.w, vtxGlobalVerticesAndTriOffset.xyz);
  194. // Mark the triangles based on the meshlets Id.
  195. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.x, debugUVs);
  196. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.y, debugUVs);
  197. MeshletsDataSrg::SetUVs(vtxGlobalVerticesAndTriOffset.z, debugUVs);
  198. #else
  199. // Setting the properties directly through the buffer views that represent areas
  200. // in the memory of the shared buffer.
  201. // Set the global mesh index buffer for this meshlet triangle
  202. // Future progress will require meshlets as visible or not and accordingly write this data
  203. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w] = vtxGlobalVerticesAndTriOffset.x;
  204. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w + 1] = vtxGlobalVerticesAndTriOffset.y;
  205. MeshletsDataSrg::m_indices[vtxGlobalVerticesAndTriOffset.w + 2] = vtxGlobalVerticesAndTriOffset.z;
  206. // Set the vertices UV according to the meshlet Id as a debug indication
  207. // This is for testing only and should not be touched in the actual PBR render
  208. MeshletsDataSrg::m_uvs[vtxGlobalVerticesAndTriOffset.x] = debugUVs;
  209. MeshletsDataSrg::m_uvs[vtxGlobalVerticesAndTriOffset.y] = debugUVs;
  210. MeshletsDataSrg::m_uvs[vtxGlobalVerticesAndTriOffset.z] = debugUVs;
  211. #endif
  212. }
  213. }