DescriptorSet.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. // Copyright (C) 2009-2019, Panagiotis Christopoulos Charitos and contributors.
  2. // All rights reserved.
  3. // Code licensed under the BSD License.
  4. // http://www.anki3d.org/LICENSE
  5. #include <anki/gr/vulkan/DescriptorSet.h>
  6. #include <anki/gr/Buffer.h>
  7. #include <anki/gr/vulkan/BufferImpl.h>
  8. #include <anki/util/List.h>
  9. #include <anki/util/HashMap.h>
  10. #include <anki/core/Trace.h>
  11. #include <algorithm>
  12. namespace anki
  13. {
  14. /// Descriptor set internal class.
  15. class DS : public IntrusiveListEnabled<DS>
  16. {
  17. public:
  18. VkDescriptorSet m_handle = {};
  19. U64 m_lastFrameUsed = MAX_U64;
  20. U64 m_hash;
  21. };
  22. /// Per thread allocator.
  23. class alignas(ANKI_CACHE_LINE_SIZE) DSThreadAllocator : public NonCopyable
  24. {
  25. public:
  26. const DSLayoutCacheEntry* m_layoutEntry; ///< Know your father.
  27. ThreadId m_tid;
  28. DynamicArray<VkDescriptorPool> m_pools;
  29. U32 m_lastPoolDSCount = 0;
  30. U32 m_lastPoolFreeDSCount = 0;
  31. IntrusiveList<DS> m_list; ///< At the left of the list are the least used sets.
  32. HashMap<U64, DS*> m_hashmap;
  33. DSThreadAllocator(const DSLayoutCacheEntry* layout, ThreadId tid)
  34. : m_layoutEntry(layout)
  35. , m_tid(tid)
  36. {
  37. ANKI_ASSERT(m_layoutEntry);
  38. }
  39. ~DSThreadAllocator();
  40. ANKI_USE_RESULT Error init();
  41. ANKI_USE_RESULT Error createNewPool();
  42. ANKI_USE_RESULT Error getOrCreateSet(
  43. U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out)
  44. {
  45. out = tryFindSet(hash);
  46. if(out == nullptr)
  47. {
  48. ANKI_CHECK(newSet(hash, bindings, out));
  49. }
  50. return Error::NONE;
  51. }
  52. private:
  53. ANKI_USE_RESULT const DS* tryFindSet(U64 hash);
  54. ANKI_USE_RESULT Error newSet(
  55. U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out);
  56. void writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS& set);
  57. };
  58. /// Cache entry. It's built around a specific descriptor set layout.
  59. class DSLayoutCacheEntry
  60. {
  61. public:
  62. DescriptorSetFactory* m_factory;
  63. U64 m_hash = 0; ///< Layout hash.
  64. VkDescriptorSetLayout m_layoutHandle = {};
  65. BitSet<MAX_BINDINGS_PER_DESCRIPTOR_SET, U8> m_activeBindings = {false};
  66. Array<DescriptorType, MAX_BINDINGS_PER_DESCRIPTOR_SET> m_bindingType = {};
  67. U32 m_minBinding = MAX_U32;
  68. U32 m_maxBinding = 0;
  69. // Cache the create info
  70. Array<VkDescriptorPoolSize, U(DescriptorType::COUNT)> m_poolSizesCreateInf = {};
  71. VkDescriptorPoolCreateInfo m_poolCreateInf = {};
  72. DynamicArray<DSThreadAllocator*> m_threadAllocs;
  73. SpinLock m_threadAllocsMtx;
  74. DSLayoutCacheEntry(DescriptorSetFactory* factory)
  75. : m_factory(factory)
  76. {
  77. }
  78. ~DSLayoutCacheEntry();
  79. ANKI_USE_RESULT Error init(const DescriptorBinding* bindings, U bindingCount, U64 hash);
  80. ANKI_USE_RESULT Error getOrCreateThreadAllocator(ThreadId tid, DSThreadAllocator*& alloc);
  81. };
  82. DSThreadAllocator::~DSThreadAllocator()
  83. {
  84. auto alloc = m_layoutEntry->m_factory->m_alloc;
  85. while(!m_list.isEmpty())
  86. {
  87. DS* ds = &m_list.getFront();
  88. m_list.popFront();
  89. alloc.deleteInstance(ds);
  90. }
  91. for(VkDescriptorPool pool : m_pools)
  92. {
  93. vkDestroyDescriptorPool(m_layoutEntry->m_factory->m_dev, pool, nullptr);
  94. }
  95. m_pools.destroy(alloc);
  96. m_hashmap.destroy(alloc);
  97. }
  98. Error DSThreadAllocator::init()
  99. {
  100. ANKI_CHECK(createNewPool());
  101. return Error::NONE;
  102. }
  103. Error DSThreadAllocator::createNewPool()
  104. {
  105. m_lastPoolDSCount =
  106. (m_lastPoolDSCount != 0) ? (m_lastPoolDSCount * DESCRIPTOR_POOL_SIZE_SCALE) : DESCRIPTOR_POOL_INITIAL_SIZE;
  107. m_lastPoolFreeDSCount = m_lastPoolDSCount;
  108. // Set the create info
  109. Array<VkDescriptorPoolSize, U(DescriptorType::COUNT)> poolSizes;
  110. memcpy(&poolSizes[0],
  111. &m_layoutEntry->m_poolSizesCreateInf[0],
  112. sizeof(poolSizes[0]) * m_layoutEntry->m_poolCreateInf.poolSizeCount);
  113. for(U i = 0; i < m_layoutEntry->m_poolCreateInf.poolSizeCount; ++i)
  114. {
  115. poolSizes[i].descriptorCount *= m_lastPoolDSCount;
  116. ANKI_ASSERT(poolSizes[i].descriptorCount > 0);
  117. }
  118. VkDescriptorPoolCreateInfo ci = m_layoutEntry->m_poolCreateInf;
  119. ci.pPoolSizes = &poolSizes[0];
  120. ci.maxSets = m_lastPoolDSCount;
  121. // Create
  122. VkDescriptorPool pool;
  123. ANKI_VK_CHECK(vkCreateDescriptorPool(m_layoutEntry->m_factory->m_dev, &ci, nullptr, &pool));
  124. ANKI_TRACE_INC_COUNTER(VK_DESCRIPTOR_POOL_CREATE, 1);
  125. // Push back
  126. m_pools.resize(m_layoutEntry->m_factory->m_alloc, m_pools.getSize() + 1);
  127. m_pools[m_pools.getSize() - 1] = pool;
  128. return Error::NONE;
  129. }
  130. const DS* DSThreadAllocator::tryFindSet(U64 hash)
  131. {
  132. ANKI_ASSERT(hash > 0);
  133. auto it = m_hashmap.find(hash);
  134. if(it == m_hashmap.getEnd())
  135. {
  136. return nullptr;
  137. }
  138. else
  139. {
  140. DS* ds = *it;
  141. // Remove from the list and place at the end of the list
  142. m_list.erase(ds);
  143. m_list.pushBack(ds);
  144. ds->m_lastFrameUsed = m_layoutEntry->m_factory->m_frameCount;
  145. return ds;
  146. }
  147. }
  148. Error DSThreadAllocator::newSet(
  149. U64 hash, const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS*& out_)
  150. {
  151. DS* out = nullptr;
  152. // First try to see if there are unused to recycle
  153. const U64 crntFrame = m_layoutEntry->m_factory->m_frameCount;
  154. auto it = m_list.getBegin();
  155. const auto end = m_list.getEnd();
  156. while(it != end)
  157. {
  158. DS* set = &(*it);
  159. U64 frameDiff = crntFrame - set->m_lastFrameUsed;
  160. if(frameDiff > DESCRIPTOR_FRAME_BUFFERING)
  161. {
  162. // Found something, recycle
  163. auto it2 = m_hashmap.find(set->m_hash);
  164. ANKI_ASSERT(it2 != m_hashmap.getEnd());
  165. m_hashmap.erase(m_layoutEntry->m_factory->m_alloc, it2);
  166. m_list.erase(set);
  167. m_list.pushBack(set);
  168. m_hashmap.emplace(m_layoutEntry->m_factory->m_alloc, hash, set);
  169. out = set;
  170. break;
  171. }
  172. ++it;
  173. }
  174. if(out == nullptr)
  175. {
  176. // Need to allocate one
  177. if(m_lastPoolFreeDSCount == 0)
  178. {
  179. // Can't allocate one from the current pool, create new
  180. ANKI_CHECK(createNewPool());
  181. }
  182. --m_lastPoolFreeDSCount;
  183. VkDescriptorSetAllocateInfo ci = {};
  184. ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  185. ci.descriptorPool = m_pools.getBack();
  186. ci.pSetLayouts = &m_layoutEntry->m_layoutHandle;
  187. ci.descriptorSetCount = 1;
  188. VkDescriptorSet handle;
  189. VkResult rez = vkAllocateDescriptorSets(m_layoutEntry->m_factory->m_dev, &ci, &handle);
  190. (void)rez;
  191. ANKI_ASSERT(rez == VK_SUCCESS && "That allocation can't fail");
  192. ANKI_TRACE_INC_COUNTER(VK_DESCRIPTOR_SET_CREATE, 1);
  193. out = m_layoutEntry->m_factory->m_alloc.newInstance<DS>();
  194. out->m_handle = handle;
  195. m_hashmap.emplace(m_layoutEntry->m_factory->m_alloc, hash, out);
  196. m_list.pushBack(out);
  197. }
  198. ANKI_ASSERT(out);
  199. out->m_lastFrameUsed = crntFrame;
  200. out->m_hash = hash;
  201. // Finally, write it
  202. writeSet(bindings, *out);
  203. out_ = out;
  204. return Error::NONE;
  205. }
  206. void DSThreadAllocator::writeSet(const Array<AnyBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET>& bindings, const DS& set)
  207. {
  208. Array<VkWriteDescriptorSet, MAX_BINDINGS_PER_DESCRIPTOR_SET> writes;
  209. U writeCount = 0;
  210. Array<VkDescriptorImageInfo, MAX_BINDINGS_PER_DESCRIPTOR_SET> tex;
  211. U texCount = 0;
  212. Array<VkDescriptorBufferInfo, MAX_BINDINGS_PER_DESCRIPTOR_SET> buff;
  213. U buffCount = 0;
  214. VkWriteDescriptorSet writeTemplate = {};
  215. writeTemplate.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  216. writeTemplate.pNext = nullptr;
  217. writeTemplate.dstSet = set.m_handle;
  218. writeTemplate.descriptorCount = 1;
  219. for(U i = m_layoutEntry->m_minBinding; i <= m_layoutEntry->m_maxBinding; ++i)
  220. {
  221. if(m_layoutEntry->m_activeBindings.get(i))
  222. {
  223. const AnyBinding& b = bindings[i];
  224. VkWriteDescriptorSet& w = writes[writeCount++];
  225. w = writeTemplate;
  226. w.dstBinding = i;
  227. w.descriptorType = convertDescriptorType(b.m_type);
  228. switch(b.m_type)
  229. {
  230. case DescriptorType::COMBINED_TEXTURE_SAMPLER:
  231. tex[texCount].sampler = b.m_texAndSampler.m_sampler->getHandle();
  232. tex[texCount].imageView = b.m_texAndSampler.m_texView->m_handle;
  233. tex[texCount].imageLayout = b.m_texAndSampler.m_layout;
  234. w.pImageInfo = &tex[texCount];
  235. ++texCount;
  236. break;
  237. case DescriptorType::TEXTURE:
  238. tex[texCount].sampler = VK_NULL_HANDLE;
  239. tex[texCount].imageView = b.m_tex.m_texView->m_handle;
  240. tex[texCount].imageLayout = b.m_tex.m_layout;
  241. w.pImageInfo = &tex[texCount];
  242. ++texCount;
  243. break;
  244. case DescriptorType::SAMPLER:
  245. tex[texCount].sampler = b.m_sampler.m_sampler->getHandle();
  246. tex[texCount].imageView = VK_NULL_HANDLE;
  247. tex[texCount].imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
  248. w.pImageInfo = &tex[texCount];
  249. ++texCount;
  250. break;
  251. case DescriptorType::UNIFORM_BUFFER:
  252. case DescriptorType::STORAGE_BUFFER:
  253. buff[buffCount].buffer = b.m_buff.m_buff->getHandle();
  254. buff[buffCount].offset = 0;
  255. buff[buffCount].range = (b.m_buff.m_range == MAX_PTR_SIZE) ? VK_WHOLE_SIZE : b.m_buff.m_range;
  256. w.pBufferInfo = &buff[buffCount];
  257. ++buffCount;
  258. break;
  259. case DescriptorType::IMAGE:
  260. tex[texCount].sampler = VK_NULL_HANDLE;
  261. tex[texCount].imageView = b.m_image.m_texView->m_handle;
  262. tex[texCount].imageLayout = VK_IMAGE_LAYOUT_GENERAL;
  263. w.pImageInfo = &tex[texCount];
  264. ++texCount;
  265. break;
  266. default:
  267. ANKI_ASSERT(0);
  268. }
  269. }
  270. }
  271. vkUpdateDescriptorSets(m_layoutEntry->m_factory->m_dev, writeCount, &writes[0], 0, nullptr);
  272. }
  273. DSLayoutCacheEntry::~DSLayoutCacheEntry()
  274. {
  275. auto alloc = m_factory->m_alloc;
  276. for(DSThreadAllocator* a : m_threadAllocs)
  277. {
  278. alloc.deleteInstance(a);
  279. }
  280. m_threadAllocs.destroy(alloc);
  281. if(m_layoutHandle)
  282. {
  283. vkDestroyDescriptorSetLayout(m_factory->m_dev, m_layoutHandle, nullptr);
  284. }
  285. }
  286. Error DSLayoutCacheEntry::init(const DescriptorBinding* bindings, U bindingCount, U64 hash)
  287. {
  288. ANKI_ASSERT(bindings);
  289. ANKI_ASSERT(hash > 0);
  290. m_hash = hash;
  291. // Create the VK layout
  292. Array<VkDescriptorSetLayoutBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> vkBindings;
  293. VkDescriptorSetLayoutCreateInfo ci = {};
  294. ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  295. for(U i = 0; i < bindingCount; ++i)
  296. {
  297. VkDescriptorSetLayoutBinding& vk = vkBindings[i];
  298. const DescriptorBinding& ak = bindings[i];
  299. vk.binding = ak.m_binding;
  300. vk.descriptorCount = 1;
  301. vk.descriptorType = convertDescriptorType(ak.m_type);
  302. vk.pImmutableSamplers = nullptr;
  303. vk.stageFlags = convertShaderTypeBit(ak.m_stageMask);
  304. ANKI_ASSERT(m_activeBindings.get(ak.m_binding) == false);
  305. m_activeBindings.set(ak.m_binding);
  306. m_bindingType[ak.m_binding] = ak.m_type;
  307. m_minBinding = min<U32>(m_minBinding, ak.m_binding);
  308. m_maxBinding = max<U32>(m_maxBinding, ak.m_binding);
  309. }
  310. ci.bindingCount = bindingCount;
  311. ci.pBindings = &vkBindings[0];
  312. ANKI_VK_CHECK(vkCreateDescriptorSetLayout(m_factory->m_dev, &ci, nullptr, &m_layoutHandle));
  313. // Create the pool info
  314. U poolSizeCount = 0;
  315. for(U i = 0; i < bindingCount; ++i)
  316. {
  317. U j;
  318. for(j = 0; j < poolSizeCount; ++j)
  319. {
  320. if(m_poolSizesCreateInf[j].type == convertDescriptorType(bindings[i].m_type))
  321. {
  322. ++m_poolSizesCreateInf[j].descriptorCount;
  323. break;
  324. }
  325. }
  326. if(j == poolSizeCount)
  327. {
  328. m_poolSizesCreateInf[poolSizeCount].type = convertDescriptorType(bindings[i].m_type);
  329. m_poolSizesCreateInf[poolSizeCount].descriptorCount = 1;
  330. ++poolSizeCount;
  331. }
  332. }
  333. if(poolSizeCount == 0)
  334. {
  335. // If the poolSizeCount it means that the DS layout has 0 descriptors. Since the pool sizes can't be zero put
  336. // something in them
  337. m_poolSizesCreateInf[0].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  338. m_poolSizesCreateInf[0].descriptorCount = 1;
  339. ++poolSizeCount;
  340. }
  341. ANKI_ASSERT(poolSizeCount > 0);
  342. m_poolCreateInf.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  343. m_poolCreateInf.poolSizeCount = poolSizeCount;
  344. return Error::NONE;
  345. }
  346. Error DSLayoutCacheEntry::getOrCreateThreadAllocator(ThreadId tid, DSThreadAllocator*& alloc)
  347. {
  348. alloc = nullptr;
  349. LockGuard<SpinLock> lock(m_threadAllocsMtx);
  350. class Comp
  351. {
  352. public:
  353. Bool operator()(const DSThreadAllocator* a, ThreadId tid) const
  354. {
  355. return a->m_tid < tid;
  356. }
  357. Bool operator()(ThreadId tid, const DSThreadAllocator* a) const
  358. {
  359. return tid < a->m_tid;
  360. }
  361. };
  362. // Find using binary search
  363. auto it = binarySearch(m_threadAllocs.getBegin(), m_threadAllocs.getEnd(), tid, Comp());
  364. if(it != m_threadAllocs.getEnd())
  365. {
  366. ANKI_ASSERT((*it)->m_tid == tid);
  367. alloc = *it;
  368. }
  369. else
  370. {
  371. // Need to create one
  372. alloc = m_factory->m_alloc.newInstance<DSThreadAllocator>(this, tid);
  373. ANKI_CHECK(alloc->init());
  374. m_threadAllocs.resize(m_factory->m_alloc, m_threadAllocs.getSize() + 1);
  375. m_threadAllocs[m_threadAllocs.getSize() - 1] = alloc;
  376. // Sort for fast find
  377. std::sort(m_threadAllocs.getBegin(),
  378. m_threadAllocs.getEnd(),
  379. [](const DSThreadAllocator* a, const DSThreadAllocator* b) { return a->m_tid < b->m_tid; });
  380. }
  381. ANKI_ASSERT(alloc);
  382. return Error::NONE;
  383. }
  384. void DescriptorSetState::flush(
  385. Bool& stateDirty, U64& hash, Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets, U& dynamicOffsetCount)
  386. {
  387. dynamicOffsetCount = 0;
  388. // Get cache entry
  389. ANKI_ASSERT(m_layout.m_entry);
  390. const DSLayoutCacheEntry& entry = *m_layout.m_entry;
  391. // Early out if nothing happened
  392. if(!m_anyBindingDirty && !m_layoutDirty)
  393. {
  394. stateDirty = false;
  395. return;
  396. }
  397. Bool dynamicOffsetsDirty = false;
  398. // Compute the hash
  399. Array<U64, MAX_BINDINGS_PER_DESCRIPTOR_SET * 2 * 2> toHash;
  400. U toHashCount = 0;
  401. const U minBinding = entry.m_minBinding;
  402. const U maxBinding = entry.m_maxBinding;
  403. for(U i = minBinding; i <= maxBinding; ++i)
  404. {
  405. if(entry.m_activeBindings.get(i))
  406. {
  407. toHash[toHashCount++] = m_bindings[i].m_uuids[0];
  408. switch(entry.m_bindingType[i])
  409. {
  410. case DescriptorType::COMBINED_TEXTURE_SAMPLER:
  411. ANKI_ASSERT(
  412. m_bindings[i].m_type == DescriptorType::COMBINED_TEXTURE_SAMPLER && "Have bound the wrong type");
  413. toHash[toHashCount++] = m_bindings[i].m_uuids[1];
  414. toHash[toHashCount++] = U64(m_bindings[i].m_texAndSampler.m_layout);
  415. break;
  416. case DescriptorType::TEXTURE:
  417. ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::TEXTURE && "Have bound the wrong type");
  418. toHash[toHashCount] = U64(m_bindings[i].m_tex.m_layout);
  419. break;
  420. case DescriptorType::SAMPLER:
  421. ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::SAMPLER && "Have bound the wrong type");
  422. break;
  423. case DescriptorType::UNIFORM_BUFFER:
  424. ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::UNIFORM_BUFFER && "Have bound the wrong type");
  425. toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
  426. dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
  427. dynamicOffsetsDirty = dynamicOffsetsDirty || m_dynamicOffsetDirty.get(i);
  428. break;
  429. case DescriptorType::STORAGE_BUFFER:
  430. ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::STORAGE_BUFFER && "Have bound the wrong type");
  431. toHash[toHashCount++] = m_bindings[i].m_buff.m_range;
  432. dynamicOffsets[dynamicOffsetCount++] = m_bindings[i].m_buff.m_offset;
  433. dynamicOffsetsDirty = dynamicOffsetsDirty || m_dynamicOffsetDirty.get(i);
  434. break;
  435. case DescriptorType::IMAGE:
  436. ANKI_ASSERT(m_bindings[i].m_type == DescriptorType::IMAGE && "Have bound the wrong type");
  437. break;
  438. default:
  439. ANKI_ASSERT(0);
  440. }
  441. }
  442. }
  443. hash = (toHashCount == 1) ? toHash[0] : computeHash(&toHash[0], toHashCount * sizeof(U64));
  444. if(hash != m_lastHash || dynamicOffsetsDirty || m_layoutDirty)
  445. {
  446. m_lastHash = hash;
  447. stateDirty = true;
  448. }
  449. else
  450. {
  451. stateDirty = false;
  452. }
  453. m_anyBindingDirty = false;
  454. m_layoutDirty = false;
  455. m_dynamicOffsetDirty.unsetAll();
  456. }
  457. DescriptorSetFactory::~DescriptorSetFactory()
  458. {
  459. }
  460. void DescriptorSetFactory::init(const GrAllocator<U8>& alloc, VkDevice dev)
  461. {
  462. m_alloc = alloc;
  463. m_dev = dev;
  464. }
  465. void DescriptorSetFactory::destroy()
  466. {
  467. for(DSLayoutCacheEntry* l : m_caches)
  468. {
  469. m_alloc.deleteInstance(l);
  470. }
  471. m_caches.destroy(m_alloc);
  472. }
  473. Error DescriptorSetFactory::newDescriptorSetLayout(const DescriptorSetLayoutInitInfo& init, DescriptorSetLayout& layout)
  474. {
  475. // Compute the hash for the layout
  476. Array<DescriptorBinding, MAX_BINDINGS_PER_DESCRIPTOR_SET> bindings;
  477. U bindingCount = init.m_bindings.getSize();
  478. U64 hash;
  479. if(init.m_bindings.getSize() > 0)
  480. {
  481. memcpy(&bindings[0], &init.m_bindings[0], init.m_bindings.getSizeInBytes());
  482. std::sort(&bindings[0],
  483. &bindings[0] + bindingCount,
  484. [](const DescriptorBinding& a, const DescriptorBinding& b) { return a.m_binding < b.m_binding; });
  485. hash = computeHash(&bindings[0], init.m_bindings.getSizeInBytes());
  486. ANKI_ASSERT(hash != 1);
  487. }
  488. else
  489. {
  490. hash = 1;
  491. }
  492. // Find or create the cache entry
  493. LockGuard<SpinLock> lock(m_cachesMtx);
  494. DSLayoutCacheEntry* cache = nullptr;
  495. U count = 0;
  496. for(DSLayoutCacheEntry* it : m_caches)
  497. {
  498. if(it->m_hash == hash)
  499. {
  500. cache = it;
  501. break;
  502. }
  503. ++count;
  504. }
  505. if(cache == nullptr)
  506. {
  507. cache = m_alloc.newInstance<DSLayoutCacheEntry>(this);
  508. ANKI_CHECK(cache->init(&bindings[0], bindingCount, hash));
  509. m_caches.resize(m_alloc, m_caches.getSize() + 1);
  510. m_caches[m_caches.getSize() - 1] = cache;
  511. }
  512. // Set the layout
  513. layout.m_handle = cache->m_layoutHandle;
  514. layout.m_entry = cache;
  515. return Error::NONE;
  516. }
  517. Error DescriptorSetFactory::newDescriptorSet(ThreadId tid,
  518. DescriptorSetState& state,
  519. DescriptorSet& set,
  520. Bool& dirty,
  521. Array<U32, MAX_BINDINGS_PER_DESCRIPTOR_SET>& dynamicOffsets,
  522. U& dynamicOffsetCount)
  523. {
  524. ANKI_TRACE_SCOPED_EVENT(VK_DESCRIPTOR_SET_GET_OR_CREATE);
  525. U64 hash;
  526. state.flush(dirty, hash, dynamicOffsets, dynamicOffsetCount);
  527. if(!dirty)
  528. {
  529. return Error::NONE;
  530. }
  531. DescriptorSetLayout layout = state.m_layout;
  532. DSLayoutCacheEntry& entry = *layout.m_entry;
  533. // Get thread allocator
  534. DSThreadAllocator* alloc;
  535. ANKI_CHECK(entry.getOrCreateThreadAllocator(tid, alloc));
  536. // Finally, allocate
  537. const DS* s;
  538. ANKI_CHECK(alloc->getOrCreateSet(hash, state.m_bindings, s));
  539. set.m_handle = s->m_handle;
  540. ANKI_ASSERT(set.m_handle != VK_NULL_HANDLE);
  541. return Error::NONE;
  542. }
  543. BindlessDescriptorSet::~BindlessDescriptorSet()
  544. {
  545. ANKI_ASSERT(m_dset == VK_NULL_HANDLE);
  546. ANKI_ASSERT(m_layout == VK_NULL_HANDLE);
  547. ANKI_ASSERT(m_pool == VK_NULL_HANDLE);
  548. }
  549. Error BindlessDescriptorSet::init(const GrAllocator<U8>& alloc, VkDevice dev)
  550. {
  551. ANKI_ASSERT(dev);
  552. m_alloc = alloc;
  553. m_dev = dev;
  554. // Create the layout
  555. {
  556. Array<VkDescriptorSetLayoutBinding, 2> bindings = {};
  557. bindings[0].binding = 0;
  558. bindings[0].stageFlags = VK_SHADER_STAGE_ALL;
  559. bindings[0].descriptorCount = MAX_BINDLESS_TEXTURES;
  560. bindings[0].descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
  561. bindings[1].binding = 1;
  562. bindings[1].stageFlags = VK_SHADER_STAGE_ALL;
  563. bindings[1].descriptorCount = MAX_BINDLESS_IMAGES;
  564. bindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  565. Array<VkDescriptorBindingFlagsEXT, 2> bindingFlags = {};
  566. bindingFlags[0] = VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
  567. | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT
  568. | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT;
  569. bindingFlags[1] = bindingFlags[0];
  570. VkDescriptorSetLayoutBindingFlagsCreateInfoEXT extraInfos = {};
  571. extraInfos.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT;
  572. extraInfos.bindingCount = bindingFlags.getSize();
  573. extraInfos.pBindingFlags = &bindingFlags[0];
  574. VkDescriptorSetLayoutCreateInfo ci = {};
  575. ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  576. ci.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT;
  577. ci.bindingCount = bindings.getSize();
  578. ci.pBindings = &bindings[0];
  579. ci.pNext = &extraInfos;
  580. ANKI_VK_CHECK(vkCreateDescriptorSetLayout(m_dev, &ci, nullptr, &m_layout));
  581. }
  582. // Create the pool
  583. {
  584. Array<VkDescriptorPoolSize, 2> sizes = {};
  585. sizes[0].type = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
  586. sizes[0].descriptorCount = MAX_BINDLESS_TEXTURES;
  587. sizes[1].type = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  588. sizes[1].descriptorCount = MAX_BINDLESS_IMAGES;
  589. VkDescriptorPoolCreateInfo ci = {};
  590. ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
  591. ci.maxSets = 1;
  592. ci.poolSizeCount = sizes.getSize();
  593. ci.pPoolSizes = &sizes[0];
  594. ci.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT;
  595. ANKI_VK_CHECK(vkCreateDescriptorPool(m_dev, &ci, nullptr, &m_pool));
  596. }
  597. // Create the descriptor set
  598. {
  599. VkDescriptorSetAllocateInfo ci = {};
  600. ci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
  601. ci.descriptorPool = m_pool;
  602. ci.descriptorSetCount = 1;
  603. ci.pSetLayouts = &m_layout;
  604. ANKI_VK_CHECK(vkAllocateDescriptorSets(m_dev, &ci, &m_dset));
  605. }
  606. // Init the free arrays
  607. {
  608. m_freeTexIndices.create(m_alloc, MAX_BINDLESS_TEXTURES);
  609. m_freeTexIndexCount = m_freeTexIndices.getSize();
  610. for(U i = 0; i < m_freeTexIndices.getSize(); ++i)
  611. {
  612. m_freeTexIndices[i] = m_freeTexIndices.getSize() - i - 1;
  613. }
  614. m_freeImgIndices.create(m_alloc, MAX_BINDLESS_IMAGES);
  615. m_freeImgIndexCount = m_freeImgIndices.getSize();
  616. for(U i = 0; i < m_freeImgIndices.getSize(); ++i)
  617. {
  618. m_freeImgIndices[i] = m_freeImgIndices.getSize() - i - 1;
  619. }
  620. }
  621. return Error::NONE;
  622. }
  623. void BindlessDescriptorSet::destroy()
  624. {
  625. if(m_pool)
  626. {
  627. vkDestroyDescriptorPool(m_dev, m_pool, nullptr);
  628. m_pool = VK_NULL_HANDLE;
  629. m_dset = VK_NULL_HANDLE;
  630. }
  631. if(m_layout)
  632. {
  633. vkDestroyDescriptorSetLayout(m_dev, m_layout, nullptr);
  634. m_layout = VK_NULL_HANDLE;
  635. }
  636. m_freeImgIndices.destroy(m_alloc);
  637. m_freeTexIndices.destroy(m_alloc);
  638. }
  639. U32 BindlessDescriptorSet::bindTexture(const VkImageView view, const VkImageLayout layout)
  640. {
  641. ANKI_ASSERT(view);
  642. LockGuard<Mutex> lock(m_mtx);
  643. ANKI_ASSERT(m_freeTexIndexCount > 0 && "Out of indices");
  644. // Get the index
  645. --m_freeTexIndexCount;
  646. const U idx = m_freeTexIndices[m_freeTexIndexCount];
  647. ANKI_ASSERT(idx < MAX_BINDLESS_TEXTURES);
  648. // Update the set
  649. VkDescriptorImageInfo imageInf = {};
  650. imageInf.imageView = view;
  651. imageInf.imageLayout = layout;
  652. VkWriteDescriptorSet write = {};
  653. write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  654. write.pNext = nullptr;
  655. write.dstSet = m_dset;
  656. write.descriptorCount = 1;
  657. write.descriptorType = VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE;
  658. write.dstArrayElement = idx;
  659. write.pImageInfo = &imageInf;
  660. vkUpdateDescriptorSets(m_dev, 1, &write, 0, nullptr);
  661. return idx;
  662. }
  663. U32 BindlessDescriptorSet::bindImage(const VkImageView view)
  664. {
  665. ANKI_ASSERT(view);
  666. LockGuard<Mutex> lock(m_mtx);
  667. ANKI_ASSERT(m_freeImgIndexCount > 0 && "Out of indices");
  668. // Get the index
  669. --m_freeImgIndexCount;
  670. const U idx = m_freeImgIndices[m_freeImgIndexCount];
  671. ANKI_ASSERT(idx < MAX_BINDLESS_IMAGES);
  672. // Update the set
  673. VkDescriptorImageInfo imageInf = {};
  674. imageInf.imageView = view;
  675. imageInf.imageLayout = VK_IMAGE_LAYOUT_GENERAL; // Storage images are always in general.
  676. VkWriteDescriptorSet write = {};
  677. write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
  678. write.pNext = nullptr;
  679. write.dstSet = m_dset;
  680. write.descriptorCount = 1;
  681. write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
  682. write.dstArrayElement = idx;
  683. write.pImageInfo = &imageInf;
  684. vkUpdateDescriptorSets(m_dev, 1, &write, 0, nullptr);
  685. return idx;
  686. }
  687. void BindlessDescriptorSet::unbindCommon(U32 idx, DynamicArray<U16>& freeIndices, U16& freeIndexCount)
  688. {
  689. ANKI_ASSERT(idx < freeIndices.getSize());
  690. LockGuard<Mutex> lock(m_mtx);
  691. ANKI_ASSERT(freeIndexCount < freeIndices.getSize());
  692. freeIndices[freeIndexCount] = idx;
  693. ++freeIndexCount;
  694. // Sort the free indices to minimize fragmentation
  695. std::sort(&freeIndices[0], &freeIndices[0] + freeIndexCount, std::greater<U16>());
  696. // Make sure there are no duplicates
  697. for(U i = 1; i < freeIndexCount; ++i)
  698. {
  699. ANKI_ASSERT(freeIndices[i] != freeIndices[i - 1]);
  700. }
  701. }
  702. Error BindlessDescriptorSet::initDeviceFeatures(
  703. VkPhysicalDevice pdev, VkPhysicalDeviceDescriptorIndexingFeaturesEXT& indexingFeatures)
  704. {
  705. indexingFeatures = {};
  706. indexingFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
  707. VkPhysicalDeviceFeatures2 features = {};
  708. features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
  709. features.pNext = &indexingFeatures;
  710. vkGetPhysicalDeviceFeatures2(pdev, &features);
  711. if(!indexingFeatures.descriptorBindingSampledImageUpdateAfterBind
  712. || !indexingFeatures.descriptorBindingStorageImageUpdateAfterBind)
  713. {
  714. ANKI_VK_LOGE("Update descriptors after bind is not supported by the device");
  715. return Error::FUNCTION_FAILED;
  716. }
  717. if(!indexingFeatures.descriptorBindingUpdateUnusedWhilePending)
  718. {
  719. ANKI_VK_LOGE("Update descriptors while cmd buffer is pending is not supported by the device");
  720. return Error::FUNCTION_FAILED;
  721. }
  722. return Error::NONE;
  723. }
  724. } // end namespace anki