VkDescriptor.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. // Copyright (C) 2009-present, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #pragma once
  6. #include <AnKi/Gr/Vulkan/VkCommon.h>
  7. #include <AnKi/Util/HashMap.h>
  8. #include <AnKi/Util/WeakArray.h>
  9. namespace anki {
  10. /// @addtogroup vulkan
  11. /// @{
  12. /// Allocates descriptor sets.
  13. class DescriptorAllocator
  14. {
  15. public:
  16. DescriptorAllocator() = default;
  17. ~DescriptorAllocator();
  18. void destroy()
  19. {
  20. for(Block& b : m_blocks)
  21. {
  22. ANKI_ASSERT(b.m_pool != VK_NULL_HANDLE);
  23. vkDestroyDescriptorPool(getVkDevice(), b.m_pool, nullptr);
  24. }
  25. m_blocks.destroy();
  26. m_activeBlock = 0;
  27. }
  28. void allocate(VkDescriptorSetLayout layout, VkDescriptorSet& set);
  29. /// Reset for reuse.
  30. void reset();
  31. private:
  32. class Block
  33. {
  34. public:
  35. VkDescriptorPool m_pool = VK_NULL_HANDLE;
  36. U32 m_dsetsAllocatedCount = 0;
  37. U32 m_maxDsets = 0;
  38. };
  39. static constexpr U32 kDescriptorSetGrowScale = 2;
  40. GrDynamicArray<Block> m_blocks;
  41. U32 m_activeBlock = 0;
  42. void createNewBlock();
  43. };
  44. /// The bindless descriptor set.
  45. class BindlessDescriptorSet : public MakeSingleton<BindlessDescriptorSet>
  46. {
  47. friend class PipelineLayoutFactory2;
  48. friend class DescriptorState;
  49. public:
  50. ~BindlessDescriptorSet();
  51. Error init();
  52. /// Bind a sampled image.
  53. /// @note It's thread-safe.
  54. U32 bindTexture(const VkImageView view, const VkImageLayout layout);
  55. /// @note It's thread-safe.
  56. void unbindTexture(U32 idx);
  57. U32 getMaxTextureCount() const
  58. {
  59. return m_freeTexIndices.getSize();
  60. }
  61. private:
  62. VkDescriptorSetLayout m_layout = VK_NULL_HANDLE;
  63. VkDescriptorPool m_dsPool = VK_NULL_HANDLE;
  64. VkDescriptorSet m_dset = VK_NULL_HANDLE;
  65. Mutex m_mtx;
  66. GrDynamicArray<U16> m_freeTexIndices;
  67. U16 m_freeTexIndexCount = kMaxU16;
  68. };
  69. /// Wrapper over VkPipelineLayout
  70. class PipelineLayout2
  71. {
  72. friend class PipelineLayoutFactory2;
  73. friend class DescriptorState;
  74. public:
  75. VkPipelineLayout getHandle() const
  76. {
  77. ANKI_ASSERT(m_handle);
  78. return m_handle;
  79. }
  80. const ShaderReflectionDescriptorRelated& getReflection() const
  81. {
  82. return m_refl;
  83. }
  84. private:
  85. VkPipelineLayout m_handle = VK_NULL_HANDLE;
  86. ShaderReflectionDescriptorRelated m_refl;
  87. Array<VkDescriptorSetLayout, kMaxRegisterSpaces> m_dsetLayouts = {};
  88. Array<U32, kMaxRegisterSpaces> m_descriptorCounts = {};
  89. U8 m_dsetCount = 0;
  90. };
  91. /// Creator of pipeline layouts.
  92. class PipelineLayoutFactory2 : public MakeSingleton<PipelineLayoutFactory2>
  93. {
  94. public:
  95. PipelineLayoutFactory2() = default;
  96. ~PipelineLayoutFactory2();
  97. /// @note It's thread-safe.
  98. Error getOrCreatePipelineLayout(const ShaderReflectionDescriptorRelated& refl, PipelineLayout2*& layout);
  99. private:
  100. class DescriptorSetLayout
  101. {
  102. public:
  103. VkDescriptorSetLayout m_handle = {};
  104. };
  105. GrHashMap<U64, PipelineLayout2*> m_pplLayouts;
  106. GrHashMap<U64, DescriptorSetLayout*> m_dsLayouts;
  107. Mutex m_mtx;
  108. Error getOrCreateDescriptorSetLayout(ConstWeakArray<ShaderReflectionBinding> bindings, DescriptorSetLayout*& layout);
  109. };
  110. /// Part of the command buffer that deals with descriptors.
  111. class DescriptorState
  112. {
  113. public:
  114. void init(StackMemoryPool* tempPool)
  115. {
  116. for(auto& set : m_sets)
  117. {
  118. set.init(tempPool);
  119. }
  120. }
  121. void setShaderProgram(const PipelineLayout2* layout, U32 shaderProgramUuid, VkPipelineBindPoint bindPoint)
  122. {
  123. ANKI_ASSERT(layout && shaderProgramUuid != 0);
  124. // Make it dirty if the program changed as well. There is a case where 2 different programs end up with the same ppline layout because of
  125. // the binding re-write in SPIR-V
  126. const Bool programChanged = m_shaderProgramUuid != shaderProgramUuid;
  127. if(layout != m_pipelineLayout || bindPoint != m_pipelineBindPoint || programChanged)
  128. {
  129. m_shaderProgramUuid = shaderProgramUuid;
  130. m_pipelineLayout = layout;
  131. m_pipelineBindPoint = bindPoint;
  132. m_pushConstantsDirty = m_pushConstantsDirty || (m_pushConstSize != m_pipelineLayout->m_refl.m_fastConstantsSize);
  133. for(U32 iset = 0; iset < m_pipelineLayout->m_dsetCount; ++iset)
  134. {
  135. if(m_sets[iset].m_dsLayout != m_pipelineLayout->m_dsetLayouts[iset] || programChanged)
  136. {
  137. m_sets[iset].m_dirty = true;
  138. m_sets[iset].m_dsLayout = m_pipelineLayout->m_dsetLayouts[iset];
  139. }
  140. }
  141. }
  142. }
  143. void bindSampledTexture(U32 space, U32 registerBinding, VkImageView view, VkImageLayout layout)
  144. {
  145. ANKI_ASSERT(view != 0 && layout != VK_IMAGE_LAYOUT_UNDEFINED);
  146. Descriptor& desc = getDescriptor(HlslResourceType::kSrv, space, registerBinding);
  147. desc.m_image.imageView = view;
  148. desc.m_image.imageLayout = layout;
  149. desc.m_image.sampler = 0;
  150. #if ANKI_ASSERTIONS_ENABLED
  151. desc.m_type = DescriptorType::kSrvTexture;
  152. #endif
  153. }
  154. void bindStorageTexture(U32 space, U32 registerBinding, VkImageView view)
  155. {
  156. ANKI_ASSERT(view);
  157. Descriptor& desc = getDescriptor(HlslResourceType::kUav, space, registerBinding);
  158. desc.m_image.imageView = view;
  159. desc.m_image.imageLayout = VK_IMAGE_LAYOUT_GENERAL;
  160. desc.m_image.sampler = 0;
  161. #if ANKI_ASSERTIONS_ENABLED
  162. desc.m_type = DescriptorType::kUavTexture;
  163. #endif
  164. }
  165. void bindSampler(U32 space, U32 registerBinding, VkSampler sampler)
  166. {
  167. ANKI_ASSERT(sampler);
  168. Descriptor& desc = getDescriptor(HlslResourceType::kSampler, space, registerBinding);
  169. desc.m_image.imageView = 0;
  170. desc.m_image.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  171. desc.m_image.sampler = sampler;
  172. #if ANKI_ASSERTIONS_ENABLED
  173. desc.m_type = DescriptorType::kSampler;
  174. #endif
  175. }
  176. void bindUniformBuffer(U32 space, U32 registerBinding, VkBuffer buffer, PtrSize offset, PtrSize range)
  177. {
  178. ANKI_ASSERT(buffer && range > 0);
  179. Descriptor& desc = getDescriptor(HlslResourceType::kCbv, space, registerBinding);
  180. desc.m_buffer.buffer = buffer;
  181. desc.m_buffer.offset = offset;
  182. desc.m_buffer.range = range;
  183. #if ANKI_ASSERTIONS_ENABLED
  184. desc.m_type = DescriptorType::kConstantBuffer;
  185. #endif
  186. }
  187. void bindReadStorageBuffer(U32 space, U32 registerBinding, VkBuffer buffer, PtrSize offset, PtrSize range)
  188. {
  189. ANKI_ASSERT(buffer && range > 0);
  190. Descriptor& desc = getDescriptor(HlslResourceType::kSrv, space, registerBinding);
  191. desc.m_buffer.buffer = buffer;
  192. desc.m_buffer.offset = offset;
  193. desc.m_buffer.range = range;
  194. #if ANKI_ASSERTIONS_ENABLED
  195. desc.m_type = DescriptorType::kSrvStructuredBuffer;
  196. #endif
  197. }
  198. void bindReadWriteStorageBuffer(U32 space, U32 registerBinding, VkBuffer buffer, PtrSize offset, PtrSize range)
  199. {
  200. ANKI_ASSERT(buffer && range > 0);
  201. Descriptor& desc = getDescriptor(HlslResourceType::kUav, space, registerBinding);
  202. desc.m_buffer.buffer = buffer;
  203. desc.m_buffer.offset = offset;
  204. desc.m_buffer.range = range;
  205. #if ANKI_ASSERTIONS_ENABLED
  206. desc.m_type = DescriptorType::kUavStructuredBuffer;
  207. #endif
  208. }
  209. void bindReadTexelBuffer(U32 space, U32 registerBinding, VkBufferView bufferView)
  210. {
  211. ANKI_ASSERT(bufferView);
  212. Descriptor& desc = getDescriptor(HlslResourceType::kSrv, space, registerBinding);
  213. desc.m_bufferView = bufferView;
  214. #if ANKI_ASSERTIONS_ENABLED
  215. desc.m_type = DescriptorType::kSrvTexelBuffer;
  216. #endif
  217. }
  218. void bindReadWriteTexelBuffer(U32 space, U32 registerBinding, VkBufferView bufferView)
  219. {
  220. ANKI_ASSERT(bufferView);
  221. Descriptor& desc = getDescriptor(HlslResourceType::kUav, space, registerBinding);
  222. desc.m_bufferView = bufferView;
  223. #if ANKI_ASSERTIONS_ENABLED
  224. desc.m_type = DescriptorType::kUavTexelBuffer;
  225. #endif
  226. }
  227. void bindAccelerationStructure(U32 space, U32 registerBinding, const VkAccelerationStructureKHR* handle)
  228. {
  229. ANKI_ASSERT(handle);
  230. Descriptor& desc = getDescriptor(HlslResourceType::kSrv, space, registerBinding);
  231. desc.m_as.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_KHR;
  232. desc.m_as.pNext = nullptr;
  233. desc.m_as.accelerationStructureCount = 1;
  234. desc.m_as.pAccelerationStructures = handle;
  235. #if ANKI_ASSERTIONS_ENABLED
  236. desc.m_type = DescriptorType::kAccelerationStructure;
  237. #endif
  238. }
  239. void setFastConstants(const void* data, U32 dataSize)
  240. {
  241. ANKI_ASSERT(data && dataSize && dataSize <= kMaxFastConstantsSize);
  242. memcpy(m_pushConsts.getBegin(), data, dataSize);
  243. m_pushConstSize = dataSize;
  244. m_pushConstantsDirty = true;
  245. }
  246. void flush(VkCommandBuffer cmdb, DescriptorAllocator& dalloc);
  247. private:
  248. class Descriptor
  249. {
  250. public:
  251. union
  252. {
  253. VkDescriptorImageInfo m_image;
  254. VkDescriptorBufferInfo m_buffer;
  255. VkWriteDescriptorSetAccelerationStructureKHR m_as;
  256. VkBufferView m_bufferView;
  257. };
  258. #if ANKI_ASSERTIONS_ENABLED
  259. DescriptorType m_type = DescriptorType::kCount;
  260. #endif
  261. };
  262. class DescriptorSet
  263. {
  264. public:
  265. Array<DynamicArray<Descriptor, MemoryPoolPtrWrapper<StackMemoryPool>>, U32(HlslResourceType::kCount)> m_descriptors;
  266. DynamicArray<VkWriteDescriptorSet, MemoryPoolPtrWrapper<StackMemoryPool>> m_writeInfos;
  267. VkDescriptorSetLayout m_dsLayout = VK_NULL_HANDLE;
  268. Bool m_dirty = true; ///< Needs rebuild and rebind
  269. void init(StackMemoryPool* pool)
  270. {
  271. for(auto& dynArr : m_descriptors)
  272. {
  273. dynArr = {pool};
  274. }
  275. m_writeInfos = {pool};
  276. }
  277. };
  278. const PipelineLayout2* m_pipelineLayout = nullptr;
  279. U32 m_shaderProgramUuid = 0;
  280. VkPipelineBindPoint m_pipelineBindPoint = VK_PIPELINE_BIND_POINT_MAX_ENUM;
  281. Array<DescriptorSet, kMaxRegisterSpaces> m_sets;
  282. Array<VkDescriptorSet, kMaxRegisterSpaces> m_vkDsets = {};
  283. Array<U8, kMaxFastConstantsSize> m_pushConsts;
  284. U32 m_pushConstSize = 0;
  285. Bool m_pushConstantsDirty = true;
  286. Descriptor& getDescriptor(HlslResourceType svv, U32 space, U32 registerBinding)
  287. {
  288. if(registerBinding >= m_sets[space].m_descriptors[svv].getSize())
  289. {
  290. m_sets[space].m_descriptors[svv].resize(registerBinding + 1);
  291. }
  292. m_sets[space].m_dirty = true;
  293. return m_sets[space].m_descriptors[svv][registerBinding];
  294. }
  295. };
  296. /// @}
  297. } // end namespace anki