CommandBufferImpl.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789
  1. // Copyright (C) 2009-2022, 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/CommandBufferImpl.h>
  6. #include <AnKi/Gr/GrManager.h>
  7. #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
  8. #include <AnKi/Gr/Framebuffer.h>
  9. #include <AnKi/Gr/Vulkan/FramebufferImpl.h>
  10. #include <AnKi/Gr/Vulkan/AccelerationStructureImpl.h>
  11. #include <algorithm>
  12. namespace anki {
  13. CommandBufferImpl::~CommandBufferImpl()
  14. {
  15. if(m_empty)
  16. {
  17. ANKI_VK_LOGW("Command buffer was empty");
  18. }
  19. if(!m_finalized)
  20. {
  21. ANKI_VK_LOGW("Command buffer was not flushed");
  22. }
  23. m_imgBarriers.destroy(m_alloc);
  24. m_buffBarriers.destroy(m_alloc);
  25. m_memBarriers.destroy(m_alloc);
  26. m_queryResetAtoms.destroy(m_alloc);
  27. m_writeQueryAtoms.destroy(m_alloc);
  28. m_secondLevelAtoms.destroy(m_alloc);
  29. }
  30. Error CommandBufferImpl::init(const CommandBufferInitInfo& init)
  31. {
  32. m_tid = Thread::getCurrentThreadId();
  33. m_flags = init.m_flags;
  34. ANKI_CHECK(getGrManagerImpl().getCommandBufferFactory().newCommandBuffer(m_tid, m_flags, m_microCmdb));
  35. m_handle = m_microCmdb->getHandle();
  36. m_alloc = m_microCmdb->getFastAllocator();
  37. // Store some of the init info for later
  38. if(!!(m_flags & CommandBufferFlag::SECOND_LEVEL))
  39. {
  40. m_activeFb = init.m_framebuffer;
  41. m_colorAttachmentUsages = init.m_colorAttachmentUsages;
  42. m_depthStencilAttachmentUsage = init.m_depthStencilAttachmentUsage;
  43. m_state.beginRenderPass(static_cast<FramebufferImpl*>(m_activeFb.get()));
  44. m_microCmdb->pushObjectRef(m_activeFb);
  45. }
  46. for(DescriptorSetState& state : m_dsetState)
  47. {
  48. state.init(m_alloc);
  49. }
  50. return Error::NONE;
  51. }
  52. void CommandBufferImpl::beginRecording()
  53. {
  54. // Do the begin
  55. VkCommandBufferInheritanceInfo inheritance = {};
  56. inheritance.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO;
  57. VkCommandBufferBeginInfo begin = {};
  58. begin.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  59. begin.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  60. begin.pInheritanceInfo = &inheritance;
  61. if(!!(m_flags & CommandBufferFlag::SECOND_LEVEL))
  62. {
  63. FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_activeFb);
  64. // Calc the layouts
  65. Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
  66. for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
  67. {
  68. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*impl.getColorAttachment(i));
  69. colAttLayouts[i] = view.getTextureImpl().computeLayout(m_colorAttachmentUsages[i], 0);
  70. }
  71. VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
  72. if(impl.hasDepthStencil())
  73. {
  74. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*impl.getDepthStencilAttachment());
  75. dsAttLayout = view.getTextureImpl().computeLayout(m_depthStencilAttachmentUsage, 0);
  76. }
  77. VkImageLayout sriAttachmentLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
  78. if(impl.hasSri())
  79. {
  80. // Technically it's possible for SRI to be in other layout. Don't bother though
  81. sriAttachmentLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
  82. }
  83. inheritance.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout, sriAttachmentLayout);
  84. inheritance.subpass = 0;
  85. inheritance.framebuffer = impl.getFramebufferHandle();
  86. begin.flags |= VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT;
  87. }
  88. vkBeginCommandBuffer(m_handle, &begin);
  89. // Stats
  90. if(!!(getGrManagerImpl().getExtensions() & VulkanExtensions::KHR_PIPELINE_EXECUTABLE_PROPERTIES))
  91. {
  92. m_state.setEnablePipelineStatistics(true);
  93. }
  94. }
  95. void CommandBufferImpl::beginRenderPassInternal(
  96. const FramebufferPtr& fb, const Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS>& colorAttachmentUsages,
  97. TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height)
  98. {
  99. commandCommon();
  100. ANKI_ASSERT(!insideRenderPass());
  101. m_rpCommandCount = 0;
  102. m_activeFb = fb;
  103. FramebufferImpl& fbimpl = static_cast<FramebufferImpl&>(*fb);
  104. U32 fbWidth, fbHeight;
  105. fbimpl.getAttachmentsSize(fbWidth, fbHeight);
  106. m_fbSize[0] = fbWidth;
  107. m_fbSize[1] = fbHeight;
  108. ANKI_ASSERT(minx < fbWidth && miny < fbHeight);
  109. const U32 maxx = min<U32>(minx + width, fbWidth);
  110. const U32 maxy = min<U32>(miny + height, fbHeight);
  111. width = maxx - minx;
  112. height = maxy - miny;
  113. ANKI_ASSERT(minx + width <= fbWidth && miny + height <= fbHeight);
  114. m_renderArea[0] = minx;
  115. m_renderArea[1] = miny;
  116. m_renderArea[2] = width;
  117. m_renderArea[3] = height;
  118. m_colorAttachmentUsages = colorAttachmentUsages;
  119. m_depthStencilAttachmentUsage = depthStencilAttachmentUsage;
  120. m_microCmdb->pushObjectRef(fb);
  121. m_subpassContents = VK_SUBPASS_CONTENTS_MAX_ENUM;
  122. // Re-set the viewport and scissor because sometimes they are set clamped
  123. m_viewportDirty = true;
  124. m_scissorDirty = true;
  125. }
  126. void CommandBufferImpl::beginRenderPassInternal()
  127. {
  128. FramebufferImpl& impl = static_cast<FramebufferImpl&>(*m_activeFb);
  129. flushBatches(CommandBufferCommandType::ANY_OTHER_COMMAND); // Flush before the marker
  130. m_state.beginRenderPass(&impl);
  131. VkRenderPassBeginInfo bi = {};
  132. bi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
  133. bi.clearValueCount = impl.getAttachmentCount();
  134. bi.pClearValues = impl.getClearValues();
  135. bi.framebuffer = impl.getFramebufferHandle();
  136. // Calc the layouts
  137. Array<VkImageLayout, MAX_COLOR_ATTACHMENTS> colAttLayouts;
  138. for(U i = 0; i < impl.getColorAttachmentCount(); ++i)
  139. {
  140. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*impl.getColorAttachment(i));
  141. colAttLayouts[i] = view.getTextureImpl().computeLayout(m_colorAttachmentUsages[i], 0);
  142. }
  143. VkImageLayout dsAttLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
  144. if(impl.hasDepthStencil())
  145. {
  146. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*impl.getDepthStencilAttachment());
  147. dsAttLayout = view.getTextureImpl().computeLayout(m_depthStencilAttachmentUsage, 0);
  148. }
  149. VkImageLayout sriAttachmentLayout = VK_IMAGE_LAYOUT_MAX_ENUM;
  150. if(impl.hasSri())
  151. {
  152. // Technically it's possible for SRI to be in other layout. Don't bother though
  153. sriAttachmentLayout = VK_IMAGE_LAYOUT_FRAGMENT_SHADING_RATE_ATTACHMENT_OPTIMAL_KHR;
  154. }
  155. bi.renderPass = impl.getRenderPassHandle(colAttLayouts, dsAttLayout, sriAttachmentLayout);
  156. const Bool flipvp = flipViewport();
  157. bi.renderArea.offset.x = m_renderArea[0];
  158. if(flipvp)
  159. {
  160. ANKI_ASSERT(m_renderArea[3] <= m_fbSize[1]);
  161. }
  162. bi.renderArea.offset.y = (flipvp) ? m_fbSize[1] - (m_renderArea[1] + m_renderArea[3]) : m_renderArea[1];
  163. bi.renderArea.extent.width = m_renderArea[2];
  164. bi.renderArea.extent.height = m_renderArea[3];
  165. getGrManagerImpl().beginMarker(m_handle, impl.getName(), Vec3(0.0f, 1.0f, 0.0f));
  166. #if !ANKI_PLATFORM_MOBILE
  167. // nVidia SRI cache workaround
  168. if(impl.hasSri())
  169. {
  170. VkMemoryBarrier memBarrier = {};
  171. memBarrier.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER;
  172. memBarrier.dstAccessMask = VK_ACCESS_FRAGMENT_SHADING_RATE_ATTACHMENT_READ_BIT_KHR;
  173. const VkPipelineStageFlags srcStages = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
  174. const VkPipelineStageFlags dstStages = VK_PIPELINE_STAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR;
  175. vkCmdPipelineBarrier(m_handle, srcStages, dstStages, 0, 1, &memBarrier, 0, nullptr, 0, nullptr);
  176. }
  177. #endif
  178. VkSubpassBeginInfo subpassBeginInfo = {};
  179. subpassBeginInfo.sType = VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO;
  180. subpassBeginInfo.contents = m_subpassContents;
  181. vkCmdBeginRenderPass2KHR(m_handle, &bi, &subpassBeginInfo);
  182. m_renderedToDefaultFb = m_renderedToDefaultFb || impl.hasPresentableTexture();
  183. }
  184. void CommandBufferImpl::endRenderPassInternal()
  185. {
  186. commandCommon();
  187. ANKI_ASSERT(insideRenderPass());
  188. if(m_rpCommandCount == 0)
  189. {
  190. // Empty pass
  191. m_subpassContents = VK_SUBPASS_CONTENTS_INLINE;
  192. beginRenderPassInternal();
  193. }
  194. VkSubpassEndInfo subpassEndInfo = {};
  195. subpassEndInfo.sType = VK_STRUCTURE_TYPE_SUBPASS_END_INFO;
  196. ANKI_CMD(vkCmdEndRenderPass2KHR(m_handle, &subpassEndInfo), ANY_OTHER_COMMAND);
  197. getGrManagerImpl().endMarker(m_handle);
  198. m_activeFb.reset(nullptr);
  199. m_state.endRenderPass();
  200. // After pushing second level command buffers the state is undefined. Reset the tracker and rebind the dynamic state
  201. if(m_subpassContents == VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS)
  202. {
  203. m_state.reset();
  204. rebindDynamicState();
  205. }
  206. }
  207. void CommandBufferImpl::endRecording()
  208. {
  209. commandCommon();
  210. ANKI_ASSERT(!m_finalized);
  211. ANKI_ASSERT(!m_empty);
  212. ANKI_CMD(ANKI_VK_CHECKF(vkEndCommandBuffer(m_handle)), ANY_OTHER_COMMAND);
  213. m_finalized = true;
  214. #if ANKI_EXTRA_CHECKS
  215. static Atomic<U32> messagePrintCount(0);
  216. constexpr U32 MAX_PRINT_COUNT = 10;
  217. CString message;
  218. if(!!(m_flags & CommandBufferFlag::SMALL_BATCH))
  219. {
  220. if(m_commandCount > COMMAND_BUFFER_SMALL_BATCH_MAX_COMMANDS * 4)
  221. {
  222. message = "Command buffer has too many commands%s: %u";
  223. }
  224. }
  225. else
  226. {
  227. if(m_commandCount <= COMMAND_BUFFER_SMALL_BATCH_MAX_COMMANDS / 4)
  228. {
  229. message = "Command buffer has too few commands%s: %u";
  230. }
  231. }
  232. if(!message.isEmpty())
  233. {
  234. const U32 count = messagePrintCount.fetchAdd(1) + 1;
  235. if(count < MAX_PRINT_COUNT)
  236. {
  237. ANKI_VK_LOGW(message.cstr(), "", m_commandCount);
  238. }
  239. else if(count == MAX_PRINT_COUNT)
  240. {
  241. ANKI_VK_LOGW(message.cstr(), " (will ignore further warnings)", m_commandCount);
  242. }
  243. }
  244. #endif
  245. }
  246. void CommandBufferImpl::generateMipmaps2dInternal(const TextureViewPtr& texView)
  247. {
  248. commandCommon();
  249. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
  250. const TextureImpl& tex = view.getTextureImpl();
  251. ANKI_ASSERT(tex.getTextureType() != TextureType::_3D && "Not for 3D");
  252. ANKI_ASSERT(tex.isSubresourceGoodForMipmapGeneration(view.getSubresource()));
  253. const U32 blitCount = tex.getMipmapCount() - 1u;
  254. if(blitCount == 0)
  255. {
  256. // Nothing to be done, flush the previous commands though because you may batch (and sort) things you shouldn't
  257. flushBatches(CommandBufferCommandType::ANY_OTHER_COMMAND);
  258. return;
  259. }
  260. const DepthStencilAspectBit aspect = view.getSubresource().m_depthStencilAspect;
  261. const U32 face = view.getSubresource().m_firstFace;
  262. const U32 layer = view.getSubresource().m_firstLayer;
  263. for(U32 i = 0; i < blitCount; ++i)
  264. {
  265. // Transition source
  266. if(i > 0)
  267. {
  268. VkImageSubresourceRange range;
  269. tex.computeVkImageSubresourceRange(TextureSubresourceInfo(TextureSurfaceInfo(i, 0, face, layer), aspect),
  270. range);
  271. setImageBarrier(VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
  272. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_PIPELINE_STAGE_TRANSFER_BIT,
  273. VK_ACCESS_TRANSFER_READ_BIT, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
  274. range);
  275. }
  276. // Transition destination
  277. {
  278. VkImageSubresourceRange range;
  279. tex.computeVkImageSubresourceRange(
  280. TextureSubresourceInfo(TextureSurfaceInfo(i + 1, 0, face, layer), aspect), range);
  281. setImageBarrier(VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, VK_IMAGE_LAYOUT_UNDEFINED,
  282. VK_PIPELINE_STAGE_TRANSFER_BIT, VK_ACCESS_TRANSFER_WRITE_BIT,
  283. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, tex.m_imageHandle, range);
  284. }
  285. // Setup the blit struct
  286. I32 srcWidth = tex.getWidth() >> i;
  287. I32 srcHeight = tex.getHeight() >> i;
  288. I32 dstWidth = tex.getWidth() >> (i + 1);
  289. I32 dstHeight = tex.getHeight() >> (i + 1);
  290. ANKI_ASSERT(srcWidth > 0 && srcHeight > 0 && dstWidth > 0 && dstHeight > 0);
  291. U32 vkLayer = 0;
  292. switch(tex.getTextureType())
  293. {
  294. case TextureType::_2D:
  295. case TextureType::_2D_ARRAY:
  296. break;
  297. case TextureType::CUBE:
  298. vkLayer = face;
  299. break;
  300. case TextureType::CUBE_ARRAY:
  301. vkLayer = layer * 6 + face;
  302. break;
  303. default:
  304. ANKI_ASSERT(0);
  305. break;
  306. }
  307. VkImageBlit blit;
  308. blit.srcSubresource.aspectMask = convertImageAspect(aspect);
  309. blit.srcSubresource.baseArrayLayer = vkLayer;
  310. blit.srcSubresource.layerCount = 1;
  311. blit.srcSubresource.mipLevel = i;
  312. blit.srcOffsets[0] = {0, 0, 0};
  313. blit.srcOffsets[1] = {srcWidth, srcHeight, 1};
  314. blit.dstSubresource.aspectMask = convertImageAspect(aspect);
  315. blit.dstSubresource.baseArrayLayer = vkLayer;
  316. blit.dstSubresource.layerCount = 1;
  317. blit.dstSubresource.mipLevel = i + 1;
  318. blit.dstOffsets[0] = {0, 0, 0};
  319. blit.dstOffsets[1] = {dstWidth, dstHeight, 1};
  320. ANKI_CMD(vkCmdBlitImage(m_handle, tex.m_imageHandle, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, tex.m_imageHandle,
  321. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
  322. (!!aspect) ? VK_FILTER_NEAREST : VK_FILTER_LINEAR),
  323. ANY_OTHER_COMMAND);
  324. }
  325. // Hold the reference
  326. m_microCmdb->pushObjectRef(texView);
  327. }
  328. void CommandBufferImpl::flushBarriers()
  329. {
  330. if(m_imgBarrierCount == 0 && m_buffBarrierCount == 0 && m_memBarrierCount == 0)
  331. {
  332. return;
  333. }
  334. // Sort
  335. //
  336. if(m_imgBarrierCount > 0)
  337. {
  338. std::sort(&m_imgBarriers[0], &m_imgBarriers[0] + m_imgBarrierCount,
  339. [](const VkImageMemoryBarrier& a, const VkImageMemoryBarrier& b) -> Bool {
  340. if(a.image != b.image)
  341. {
  342. return a.image < b.image;
  343. }
  344. if(a.subresourceRange.aspectMask != b.subresourceRange.aspectMask)
  345. {
  346. return a.subresourceRange.aspectMask < b.subresourceRange.aspectMask;
  347. }
  348. if(a.oldLayout != b.oldLayout)
  349. {
  350. return a.oldLayout < b.oldLayout;
  351. }
  352. if(a.newLayout != b.newLayout)
  353. {
  354. return a.newLayout < b.newLayout;
  355. }
  356. if(a.subresourceRange.baseArrayLayer != b.subresourceRange.baseArrayLayer)
  357. {
  358. return a.subresourceRange.baseArrayLayer < b.subresourceRange.baseArrayLayer;
  359. }
  360. if(a.subresourceRange.baseMipLevel != b.subresourceRange.baseMipLevel)
  361. {
  362. return a.subresourceRange.baseMipLevel < b.subresourceRange.baseMipLevel;
  363. }
  364. return false;
  365. });
  366. }
  367. // Batch
  368. //
  369. DynamicArrayAuto<VkImageMemoryBarrier> finalImgBarriers(m_alloc);
  370. U32 finalImgBarrierCount = 0;
  371. if(m_imgBarrierCount > 0)
  372. {
  373. DynamicArrayAuto<VkImageMemoryBarrier> squashedBarriers(m_alloc);
  374. U32 squashedBarrierCount = 0;
  375. squashedBarriers.create(m_imgBarrierCount);
  376. // Squash the mips by reducing the barriers
  377. for(U32 i = 0; i < m_imgBarrierCount; ++i)
  378. {
  379. const VkImageMemoryBarrier* prev = (i > 0) ? &m_imgBarriers[i - 1] : nullptr;
  380. const VkImageMemoryBarrier& crnt = m_imgBarriers[i];
  381. if(prev && prev->image == crnt.image
  382. && prev->subresourceRange.aspectMask == crnt.subresourceRange.aspectMask
  383. && prev->oldLayout == crnt.oldLayout && prev->newLayout == crnt.newLayout
  384. && prev->srcAccessMask == crnt.srcAccessMask && prev->dstAccessMask == crnt.dstAccessMask
  385. && prev->subresourceRange.baseMipLevel + prev->subresourceRange.levelCount
  386. == crnt.subresourceRange.baseMipLevel
  387. && prev->subresourceRange.baseArrayLayer == crnt.subresourceRange.baseArrayLayer
  388. && prev->subresourceRange.layerCount == crnt.subresourceRange.layerCount)
  389. {
  390. // Can batch
  391. squashedBarriers[squashedBarrierCount - 1].subresourceRange.levelCount +=
  392. crnt.subresourceRange.levelCount;
  393. }
  394. else
  395. {
  396. // Can't batch, create new barrier
  397. squashedBarriers[squashedBarrierCount++] = crnt;
  398. }
  399. }
  400. ANKI_ASSERT(squashedBarrierCount);
  401. // Squash the layers
  402. finalImgBarriers.create(squashedBarrierCount);
  403. for(U32 i = 0; i < squashedBarrierCount; ++i)
  404. {
  405. const VkImageMemoryBarrier* prev = (i > 0) ? &squashedBarriers[i - 1] : nullptr;
  406. const VkImageMemoryBarrier& crnt = squashedBarriers[i];
  407. if(prev && prev->image == crnt.image
  408. && prev->subresourceRange.aspectMask == crnt.subresourceRange.aspectMask
  409. && prev->oldLayout == crnt.oldLayout && prev->newLayout == crnt.newLayout
  410. && prev->srcAccessMask == crnt.srcAccessMask && prev->dstAccessMask == crnt.dstAccessMask
  411. && prev->subresourceRange.baseMipLevel == crnt.subresourceRange.baseMipLevel
  412. && prev->subresourceRange.levelCount == crnt.subresourceRange.levelCount
  413. && prev->subresourceRange.baseArrayLayer + prev->subresourceRange.layerCount
  414. == crnt.subresourceRange.baseArrayLayer)
  415. {
  416. // Can batch
  417. finalImgBarriers[finalImgBarrierCount - 1].subresourceRange.layerCount +=
  418. crnt.subresourceRange.layerCount;
  419. }
  420. else
  421. {
  422. // Can't batch, create new barrier
  423. finalImgBarriers[finalImgBarrierCount++] = crnt;
  424. }
  425. }
  426. ANKI_ASSERT(finalImgBarrierCount);
  427. }
  428. // Finish the job
  429. //
  430. vkCmdPipelineBarrier(m_handle, m_srcStageMask, m_dstStageMask, 0, m_memBarrierCount,
  431. (m_memBarrierCount) ? &m_memBarriers[0] : nullptr, m_buffBarrierCount,
  432. (m_buffBarrierCount) ? &m_buffBarriers[0] : nullptr, finalImgBarrierCount,
  433. (finalImgBarrierCount) ? &finalImgBarriers[0] : nullptr);
  434. ANKI_TRACE_INC_COUNTER(VK_PIPELINE_BARRIERS, 1);
  435. m_imgBarrierCount = 0;
  436. m_buffBarrierCount = 0;
  437. m_memBarrierCount = 0;
  438. m_srcStageMask = 0;
  439. m_dstStageMask = 0;
  440. }
  441. void CommandBufferImpl::flushQueryResets()
  442. {
  443. if(m_queryResetAtoms.getSize() == 0)
  444. {
  445. return;
  446. }
  447. std::sort(m_queryResetAtoms.getBegin(), m_queryResetAtoms.getEnd(),
  448. [](const QueryResetAtom& a, const QueryResetAtom& b) -> Bool {
  449. if(a.m_pool != b.m_pool)
  450. {
  451. return a.m_pool < b.m_pool;
  452. }
  453. ANKI_ASSERT(a.m_queryIdx != b.m_queryIdx && "Tried to reset the same query more than once");
  454. return a.m_queryIdx < b.m_queryIdx;
  455. });
  456. U32 firstQuery = m_queryResetAtoms[0].m_queryIdx;
  457. U32 queryCount = 1;
  458. VkQueryPool pool = m_queryResetAtoms[0].m_pool;
  459. for(U32 i = 1; i < m_queryResetAtoms.getSize(); ++i)
  460. {
  461. const QueryResetAtom& crnt = m_queryResetAtoms[i];
  462. const QueryResetAtom& prev = m_queryResetAtoms[i - 1];
  463. if(crnt.m_pool == prev.m_pool && crnt.m_queryIdx == prev.m_queryIdx + 1)
  464. {
  465. // Can batch
  466. ++queryCount;
  467. }
  468. else
  469. {
  470. // Flush batch
  471. vkCmdResetQueryPool(m_handle, pool, firstQuery, queryCount);
  472. // New batch
  473. firstQuery = crnt.m_queryIdx;
  474. queryCount = 1;
  475. pool = crnt.m_pool;
  476. }
  477. }
  478. vkCmdResetQueryPool(m_handle, pool, firstQuery, queryCount);
  479. m_queryResetAtoms.destroy(m_alloc);
  480. }
  481. void CommandBufferImpl::flushWriteQueryResults()
  482. {
  483. if(m_writeQueryAtoms.getSize() == 0)
  484. {
  485. return;
  486. }
  487. std::sort(&m_writeQueryAtoms[0], &m_writeQueryAtoms[0] + m_writeQueryAtoms.getSize(),
  488. [](const WriteQueryAtom& a, const WriteQueryAtom& b) -> Bool {
  489. if(a.m_pool != b.m_pool)
  490. {
  491. return a.m_pool < b.m_pool;
  492. }
  493. if(a.m_buffer != b.m_buffer)
  494. {
  495. return a.m_buffer < b.m_buffer;
  496. }
  497. if(a.m_offset != b.m_offset)
  498. {
  499. return a.m_offset < b.m_offset;
  500. }
  501. ANKI_ASSERT(a.m_queryIdx != b.m_queryIdx && "Tried to write the same query more than once");
  502. return a.m_queryIdx < b.m_queryIdx;
  503. });
  504. U32 firstQuery = m_writeQueryAtoms[0].m_queryIdx;
  505. U32 queryCount = 1;
  506. VkQueryPool pool = m_writeQueryAtoms[0].m_pool;
  507. PtrSize offset = m_writeQueryAtoms[0].m_offset;
  508. VkBuffer buff = m_writeQueryAtoms[0].m_buffer;
  509. for(U32 i = 1; i < m_writeQueryAtoms.getSize(); ++i)
  510. {
  511. const WriteQueryAtom& crnt = m_writeQueryAtoms[i];
  512. const WriteQueryAtom& prev = m_writeQueryAtoms[i - 1];
  513. if(crnt.m_pool == prev.m_pool && crnt.m_buffer == prev.m_buffer && prev.m_queryIdx + 1 == crnt.m_queryIdx
  514. && prev.m_offset + sizeof(U32) == crnt.m_offset)
  515. {
  516. // Can batch
  517. ++queryCount;
  518. }
  519. else
  520. {
  521. // Flush batch
  522. vkCmdCopyQueryPoolResults(m_handle, pool, firstQuery, queryCount, buff, offset, sizeof(U32),
  523. VK_QUERY_RESULT_PARTIAL_BIT);
  524. // New batch
  525. firstQuery = crnt.m_queryIdx;
  526. queryCount = 1;
  527. pool = crnt.m_pool;
  528. buff = crnt.m_buffer;
  529. }
  530. }
  531. vkCmdCopyQueryPoolResults(m_handle, pool, firstQuery, queryCount, buff, offset, sizeof(U32),
  532. VK_QUERY_RESULT_PARTIAL_BIT);
  533. m_writeQueryAtoms.resize(m_alloc, 0);
  534. }
  535. void CommandBufferImpl::copyBufferToTextureViewInternal(const BufferPtr& buff, PtrSize offset,
  536. [[maybe_unused]] PtrSize range, const TextureViewPtr& texView)
  537. {
  538. commandCommon();
  539. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
  540. const TextureImpl& tex = view.getTextureImpl();
  541. ANKI_ASSERT(tex.usageValid(TextureUsageBit::TRANSFER_DESTINATION));
  542. ANKI_ASSERT(tex.isSubresourceGoodForCopyFromBuffer(view.getSubresource()));
  543. const VkImageLayout layout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
  544. const Bool is3D = tex.getTextureType() == TextureType::_3D;
  545. const VkImageAspectFlags aspect = convertImageAspect(view.getSubresource().m_depthStencilAspect);
  546. const TextureSurfaceInfo surf(view.getSubresource().m_firstMipmap, view.getSubresource().m_firstFace, 0,
  547. view.getSubresource().m_firstLayer);
  548. const TextureVolumeInfo vol(view.getSubresource().m_firstMipmap);
  549. // Compute the sizes of the mip
  550. const U32 width = tex.getWidth() >> surf.m_level;
  551. const U32 height = tex.getHeight() >> surf.m_level;
  552. ANKI_ASSERT(width && height);
  553. const U32 depth = (is3D) ? (tex.getDepth() >> surf.m_level) : 1u;
  554. if(!is3D)
  555. {
  556. ANKI_ASSERT(range == computeSurfaceSize(width, height, tex.getFormat()));
  557. }
  558. else
  559. {
  560. ANKI_ASSERT(range == computeVolumeSize(width, height, depth, tex.getFormat()));
  561. }
  562. // Copy
  563. VkBufferImageCopy region;
  564. region.imageSubresource.aspectMask = aspect;
  565. region.imageSubresource.baseArrayLayer = (is3D) ? tex.computeVkArrayLayer(vol) : tex.computeVkArrayLayer(surf);
  566. region.imageSubresource.layerCount = 1;
  567. region.imageSubresource.mipLevel = surf.m_level;
  568. region.imageOffset = {0, 0, 0};
  569. region.imageExtent.width = width;
  570. region.imageExtent.height = height;
  571. region.imageExtent.depth = depth;
  572. region.bufferOffset = offset;
  573. region.bufferImageHeight = 0;
  574. region.bufferRowLength = 0;
  575. ANKI_CMD(vkCmdCopyBufferToImage(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), tex.m_imageHandle,
  576. layout, 1, &region),
  577. ANY_OTHER_COMMAND);
  578. m_microCmdb->pushObjectRef(texView);
  579. m_microCmdb->pushObjectRef(buff);
  580. }
  581. void CommandBufferImpl::rebindDynamicState()
  582. {
  583. m_viewportDirty = true;
  584. m_lastViewport = {};
  585. m_scissorDirty = true;
  586. m_lastScissor = {};
  587. m_vrsRateDirty = true;
  588. m_vrsRate = VrsRate::_1x1;
  589. // Rebind the stencil compare mask
  590. if(m_stencilCompareMasks[0] == m_stencilCompareMasks[1])
  591. {
  592. ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
  593. m_stencilCompareMasks[0]),
  594. ANY_OTHER_COMMAND);
  595. }
  596. else
  597. {
  598. ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilCompareMasks[0]),
  599. ANY_OTHER_COMMAND);
  600. ANKI_CMD(vkCmdSetStencilCompareMask(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilCompareMasks[1]),
  601. ANY_OTHER_COMMAND);
  602. }
  603. // Rebind the stencil write mask
  604. if(m_stencilWriteMasks[0] == m_stencilWriteMasks[1])
  605. {
  606. ANKI_CMD(vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
  607. m_stencilWriteMasks[0]),
  608. ANY_OTHER_COMMAND);
  609. }
  610. else
  611. {
  612. ANKI_CMD(vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilWriteMasks[0]),
  613. ANY_OTHER_COMMAND);
  614. ANKI_CMD(vkCmdSetStencilWriteMask(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilWriteMasks[1]),
  615. ANY_OTHER_COMMAND);
  616. }
  617. // Rebind the stencil reference
  618. if(m_stencilReferenceMasks[0] == m_stencilReferenceMasks[1])
  619. {
  620. ANKI_CMD(vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT,
  621. m_stencilReferenceMasks[0]),
  622. ANY_OTHER_COMMAND);
  623. }
  624. else
  625. {
  626. ANKI_CMD(vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_FRONT_BIT, m_stencilReferenceMasks[0]),
  627. ANY_OTHER_COMMAND);
  628. ANKI_CMD(vkCmdSetStencilReference(m_handle, VK_STENCIL_FACE_BACK_BIT, m_stencilReferenceMasks[1]),
  629. ANY_OTHER_COMMAND);
  630. }
  631. }
  632. void CommandBufferImpl::buildAccelerationStructureInternal(const AccelerationStructurePtr& as)
  633. {
  634. commandCommon();
  635. // Get objects
  636. const AccelerationStructureImpl& asImpl = static_cast<AccelerationStructureImpl&>(*as);
  637. // Create the scrach buffer
  638. BufferInitInfo bufferInit;
  639. bufferInit.m_usage = PrivateBufferUsageBit::ACCELERATION_STRUCTURE_BUILD_SCRATCH;
  640. bufferInit.m_size = asImpl.getBuildScratchBufferSize();
  641. BufferPtr scratchBuff = getManager().newBuffer(bufferInit);
  642. // Create the build info
  643. VkAccelerationStructureBuildGeometryInfoKHR buildInfo;
  644. VkAccelerationStructureBuildRangeInfoKHR rangeInfo;
  645. asImpl.generateBuildInfo(scratchBuff->getGpuAddress(), buildInfo, rangeInfo);
  646. // Do the command
  647. Array<const VkAccelerationStructureBuildRangeInfoKHR*, 1> pRangeInfos = {&rangeInfo};
  648. ANKI_CMD(vkCmdBuildAccelerationStructuresKHR(m_handle, 1, &buildInfo, &pRangeInfos[0]), ANY_OTHER_COMMAND);
  649. // Push refs
  650. m_microCmdb->pushObjectRef(as);
  651. m_microCmdb->pushObjectRef(scratchBuff);
  652. }
  653. } // end namespace anki