CommandBufferImpl.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. // Copyright (C) 2009-2021, 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/CommandBuffer.h>
  7. #include <AnKi/Gr/Vulkan/VulkanObject.h>
  8. #include <AnKi/Gr/Vulkan/CommandBufferFactory.h>
  9. #include <AnKi/Gr/CommandBuffer.h>
  10. #include <AnKi/Gr/Texture.h>
  11. #include <AnKi/Gr/Buffer.h>
  12. #include <AnKi/Gr/Shader.h>
  13. #include <AnKi/Gr/Vulkan/BufferImpl.h>
  14. #include <AnKi/Gr/Vulkan/TextureImpl.h>
  15. #include <AnKi/Gr/Vulkan/Pipeline.h>
  16. #include <AnKi/Gr/Vulkan/GrManagerImpl.h>
  17. #include <AnKi/Util/List.h>
  18. namespace anki
  19. {
  20. #define ANKI_BATCH_COMMANDS 1
  21. // Forward
  22. class CommandBufferInitInfo;
  23. /// @addtogroup vulkan
  24. /// @{
  25. #define ANKI_CMD(x_, t_) \
  26. flushBatches(CommandBufferCommandType::t_); \
  27. x_;
  28. /// List the commands that can be batched.
  29. enum class CommandBufferCommandType : U8
  30. {
  31. SET_BARRIER,
  32. RESET_QUERY,
  33. WRITE_QUERY_RESULT,
  34. PUSH_SECOND_LEVEL,
  35. ANY_OTHER_COMMAND
  36. };
  37. /// Command buffer implementation.
  38. class CommandBufferImpl final : public CommandBuffer, public VulkanObject<CommandBuffer, CommandBufferImpl>
  39. {
  40. public:
  41. /// Default constructor
  42. CommandBufferImpl(GrManager* manager, CString name)
  43. : CommandBuffer(manager, name)
  44. , m_renderedToDefaultFb(false)
  45. , m_finalized(false)
  46. , m_empty(false)
  47. , m_beganRecording(false)
  48. {
  49. }
  50. ~CommandBufferImpl();
  51. ANKI_USE_RESULT Error init(const CommandBufferInitInfo& init);
  52. void setFence(MicroFencePtr& fence)
  53. {
  54. m_microCmdb->setFence(fence);
  55. }
  56. const MicroCommandBufferPtr& getMicroCommandBuffer()
  57. {
  58. return m_microCmdb;
  59. }
  60. VkCommandBuffer getHandle() const
  61. {
  62. ANKI_ASSERT(m_handle);
  63. return m_handle;
  64. }
  65. Bool renderedToDefaultFramebuffer() const
  66. {
  67. return m_renderedToDefaultFb;
  68. }
  69. Bool isEmpty() const
  70. {
  71. return m_empty;
  72. }
  73. Bool isSecondLevel() const
  74. {
  75. return !!(m_flags & CommandBufferFlag::SECOND_LEVEL);
  76. }
  77. void bindVertexBuffer(U32 binding, BufferPtr buff, PtrSize offset, PtrSize stride, VertexStepRate stepRate)
  78. {
  79. commandCommon();
  80. m_state.bindVertexBuffer(binding, stride, stepRate);
  81. VkBuffer vkbuff = static_cast<const BufferImpl&>(*buff).getHandle();
  82. ANKI_CMD(vkCmdBindVertexBuffers(m_handle, binding, 1, &vkbuff, &offset), ANY_OTHER_COMMAND);
  83. m_microCmdb->pushObjectRef(buff);
  84. }
  85. void setVertexAttribute(U32 location, U32 buffBinding, const Format fmt, PtrSize relativeOffset)
  86. {
  87. commandCommon();
  88. m_state.setVertexAttribute(location, buffBinding, fmt, relativeOffset);
  89. }
  90. void bindIndexBuffer(BufferPtr buff, PtrSize offset, IndexType type)
  91. {
  92. commandCommon();
  93. ANKI_CMD(vkCmdBindIndexBuffer(m_handle, static_cast<const BufferImpl&>(*buff).getHandle(), offset,
  94. convertIndexType(type)),
  95. ANY_OTHER_COMMAND);
  96. m_microCmdb->pushObjectRef(buff);
  97. }
  98. void setPrimitiveRestart(Bool enable)
  99. {
  100. commandCommon();
  101. m_state.setPrimitiveRestart(enable);
  102. }
  103. void setFillMode(FillMode mode)
  104. {
  105. commandCommon();
  106. m_state.setFillMode(mode);
  107. }
  108. void setCullMode(FaceSelectionBit mode)
  109. {
  110. commandCommon();
  111. m_state.setCullMode(mode);
  112. }
  113. void setViewport(U32 minx, U32 miny, U32 width, U32 height)
  114. {
  115. ANKI_ASSERT(width > 0 && height > 0);
  116. commandCommon();
  117. if(m_viewport[0] != minx || m_viewport[1] != miny || m_viewport[2] != width || m_viewport[3] != height)
  118. {
  119. m_viewportDirty = true;
  120. m_viewport[0] = minx;
  121. m_viewport[1] = miny;
  122. m_viewport[2] = width;
  123. m_viewport[3] = height;
  124. }
  125. }
  126. void setScissor(U32 minx, U32 miny, U32 width, U32 height)
  127. {
  128. ANKI_ASSERT(width > 0 && height > 0);
  129. commandCommon();
  130. if(m_scissor[0] != minx || m_scissor[1] != miny || m_scissor[2] != width || m_scissor[3] != height)
  131. {
  132. m_scissorDirty = true;
  133. m_scissor[0] = minx;
  134. m_scissor[1] = miny;
  135. m_scissor[2] = width;
  136. m_scissor[3] = height;
  137. }
  138. }
  139. void setPolygonOffset(F32 factor, F32 units)
  140. {
  141. commandCommon();
  142. m_state.setPolygonOffset(factor, units);
  143. }
  144. void setStencilOperations(FaceSelectionBit face, StencilOperation stencilFail,
  145. StencilOperation stencilPassDepthFail, StencilOperation stencilPassDepthPass)
  146. {
  147. commandCommon();
  148. m_state.setStencilOperations(face, stencilFail, stencilPassDepthFail, stencilPassDepthPass);
  149. }
  150. void setStencilCompareOperation(FaceSelectionBit face, CompareOperation comp)
  151. {
  152. commandCommon();
  153. m_state.setStencilCompareOperation(face, comp);
  154. }
  155. void setStencilCompareMask(FaceSelectionBit face, U32 mask);
  156. void setStencilWriteMask(FaceSelectionBit face, U32 mask);
  157. void setStencilReference(FaceSelectionBit face, U32 ref);
  158. void setDepthWrite(Bool enable)
  159. {
  160. commandCommon();
  161. m_state.setDepthWrite(enable);
  162. }
  163. void setDepthCompareOperation(CompareOperation op)
  164. {
  165. commandCommon();
  166. m_state.setDepthCompareOperation(op);
  167. }
  168. void setAlphaToCoverage(Bool enable)
  169. {
  170. commandCommon();
  171. m_state.setAlphaToCoverage(enable);
  172. }
  173. void setColorChannelWriteMask(U32 attachment, ColorBit mask)
  174. {
  175. commandCommon();
  176. m_state.setColorChannelWriteMask(attachment, mask);
  177. }
  178. void setBlendFactors(U32 attachment, BlendFactor srcRgb, BlendFactor dstRgb, BlendFactor srcA, BlendFactor dstA)
  179. {
  180. commandCommon();
  181. m_state.setBlendFactors(attachment, srcRgb, dstRgb, srcA, dstA);
  182. }
  183. void setBlendOperation(U32 attachment, BlendOperation funcRgb, BlendOperation funcA)
  184. {
  185. commandCommon();
  186. m_state.setBlendOperation(attachment, funcRgb, funcA);
  187. }
  188. void bindTextureAndSamplerInternal(U32 set, U32 binding, TextureViewPtr& texView, SamplerPtr sampler,
  189. TextureUsageBit usage, U32 arrayIdx)
  190. {
  191. commandCommon();
  192. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
  193. const TextureImpl& tex = view.getTextureImpl();
  194. ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
  195. const VkImageLayout lay = tex.computeLayout(usage, 0);
  196. m_dsetState[set].bindTextureAndSampler(binding, arrayIdx, &view, sampler.get(), lay);
  197. m_microCmdb->pushObjectRef(texView);
  198. m_microCmdb->pushObjectRef(sampler);
  199. }
  200. void bindTextureInternal(U32 set, U32 binding, TextureViewPtr& texView, TextureUsageBit usage, U32 arrayIdx)
  201. {
  202. commandCommon();
  203. const TextureViewImpl& view = static_cast<const TextureViewImpl&>(*texView);
  204. const TextureImpl& tex = view.getTextureImpl();
  205. ANKI_ASSERT(tex.isSubresourceGoodForSampling(view.getSubresource()));
  206. const VkImageLayout lay = tex.computeLayout(usage, 0);
  207. m_dsetState[set].bindTexture(binding, arrayIdx, &view, lay);
  208. m_microCmdb->pushObjectRef(texView);
  209. }
  210. void bindSamplerInternal(U32 set, U32 binding, SamplerPtr& sampler, U32 arrayIdx)
  211. {
  212. commandCommon();
  213. m_dsetState[set].bindSampler(binding, arrayIdx, sampler.get());
  214. m_microCmdb->pushObjectRef(sampler);
  215. }
  216. void bindImageInternal(U32 set, U32 binding, TextureViewPtr& img, U32 arrayIdx)
  217. {
  218. commandCommon();
  219. m_dsetState[set].bindImage(binding, arrayIdx, img.get());
  220. const Bool isPresentable =
  221. !!(static_cast<const TextureViewImpl&>(*img).getTextureImpl().getTextureUsage() & TextureUsageBit::PRESENT);
  222. if(isPresentable)
  223. {
  224. m_renderedToDefaultFb = true;
  225. }
  226. m_microCmdb->pushObjectRef(img);
  227. }
  228. void bindAccelerationStructureInternal(U32 set, U32 binding, AccelerationStructurePtr& as, U32 arrayIdx)
  229. {
  230. commandCommon();
  231. m_dsetState[set].bindAccelerationStructure(binding, arrayIdx, as.get());
  232. m_microCmdb->pushObjectRef(as);
  233. }
  234. void bindAllBindlessInternal(U32 set)
  235. {
  236. commandCommon();
  237. m_dsetState[set].bindBindlessDescriptorSet();
  238. }
  239. void beginRenderPass(FramebufferPtr fb, const Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS>& colorAttachmentUsages,
  240. TextureUsageBit depthStencilAttachmentUsage, U32 minx, U32 miny, U32 width, U32 height);
  241. void endRenderPass();
  242. void drawArrays(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 first, U32 baseInstance);
  243. void drawElements(PrimitiveTopology topology, U32 count, U32 instanceCount, U32 firstIndex, U32 baseVertex,
  244. U32 baseInstance);
  245. void drawArraysIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr& buff);
  246. void drawElementsIndirect(PrimitiveTopology topology, U32 drawCount, PtrSize offset, BufferPtr& buff);
  247. void dispatchCompute(U32 groupCountX, U32 groupCountY, U32 groupCountZ);
  248. void traceRaysInternal(BufferPtr& sbtBuffer, PtrSize sbtBufferOffset, U32 sbtRecordSize, U32 hitGroupSbtRecordCount,
  249. U32 rayTypeCount, U32 width, U32 height, U32 depth);
  250. void resetOcclusionQuery(OcclusionQueryPtr query);
  251. void beginOcclusionQuery(OcclusionQueryPtr query);
  252. void endOcclusionQuery(OcclusionQueryPtr query);
  253. void resetTimestampQueryInternal(TimestampQueryPtr& query);
  254. void writeTimestampInternal(TimestampQueryPtr& query);
  255. void generateMipmaps2d(TextureViewPtr texView);
  256. void clearTextureView(TextureViewPtr texView, const ClearValue& clearValue);
  257. void pushSecondLevelCommandBuffer(CommandBufferPtr cmdb);
  258. void endRecording();
  259. void setTextureBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
  260. const TextureSubresourceInfo& subresource);
  261. void setTextureSurfaceBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
  262. const TextureSurfaceInfo& surf);
  263. void setTextureVolumeBarrier(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
  264. const TextureVolumeInfo& vol);
  265. void setTextureBarrierRange(TexturePtr tex, TextureUsageBit prevUsage, TextureUsageBit nextUsage,
  266. const VkImageSubresourceRange& range);
  267. void setBufferBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess, VkPipelineStageFlags dstStage,
  268. VkAccessFlags dstAccess, PtrSize offset, PtrSize size, VkBuffer buff);
  269. void setBufferBarrier(BufferPtr& buff, BufferUsageBit before, BufferUsageBit after, PtrSize offset, PtrSize size);
  270. void setAccelerationStructureBarrierInternal(AccelerationStructurePtr& as, AccelerationStructureUsageBit prevUsage,
  271. AccelerationStructureUsageBit nextUsage);
  272. void fillBuffer(BufferPtr buff, PtrSize offset, PtrSize size, U32 value);
  273. void writeOcclusionQueryResultToBuffer(OcclusionQueryPtr query, PtrSize offset, BufferPtr buff);
  274. void bindShaderProgram(ShaderProgramPtr& prog);
  275. void bindUniformBufferInternal(U32 set, U32 binding, BufferPtr& buff, PtrSize offset, PtrSize range, U32 arrayIdx)
  276. {
  277. commandCommon();
  278. m_dsetState[set].bindUniformBuffer(binding, arrayIdx, buff.get(), offset, range);
  279. m_microCmdb->pushObjectRef(buff);
  280. }
  281. void bindStorageBufferInternal(U32 set, U32 binding, BufferPtr& buff, PtrSize offset, PtrSize range, U32 arrayIdx)
  282. {
  283. commandCommon();
  284. m_dsetState[set].bindStorageBuffer(binding, arrayIdx, buff.get(), offset, range);
  285. m_microCmdb->pushObjectRef(buff);
  286. }
  287. void copyBufferToTextureViewInternal(BufferPtr buff, PtrSize offset, PtrSize range, TextureViewPtr texView);
  288. void copyBufferToBuffer(BufferPtr& src, PtrSize srcOffset, BufferPtr& dst, PtrSize dstOffset, PtrSize range);
  289. void buildAccelerationStructureInternal(AccelerationStructurePtr& as);
  290. void setPushConstants(const void* data, U32 dataSize);
  291. void setRasterizationOrder(RasterizationOrder order);
  292. void setLineWidth(F32 width);
  293. void addReference(GrObjectPtr& ptr)
  294. {
  295. m_microCmdb->pushObjectRef(ptr);
  296. }
  297. private:
  298. StackAllocator<U8> m_alloc;
  299. MicroCommandBufferPtr m_microCmdb;
  300. VkCommandBuffer m_handle = VK_NULL_HANDLE;
  301. ThreadId m_tid = ~ThreadId(0);
  302. CommandBufferFlag m_flags = CommandBufferFlag::NONE;
  303. Bool m_renderedToDefaultFb : 1;
  304. Bool m_finalized : 1;
  305. Bool m_empty : 1;
  306. Bool m_beganRecording : 1;
  307. #if ANKI_EXTRA_CHECKS
  308. U32 m_commandCount = 0;
  309. U32 m_setPushConstantsSize = 0;
  310. #endif
  311. FramebufferPtr m_activeFb;
  312. Array<U32, 4> m_renderArea = {0, 0, MAX_U32, MAX_U32};
  313. Array<U32, 2> m_fbSize = {0, 0};
  314. U32 m_rpCommandCount = 0; ///< Number of drawcalls or pushed cmdbs in rp.
  315. Array<TextureUsageBit, MAX_COLOR_ATTACHMENTS> m_colorAttachmentUsages = {};
  316. TextureUsageBit m_depthStencilAttachmentUsage = TextureUsageBit::NONE;
  317. PipelineStateTracker m_state;
  318. Array<DescriptorSetState, MAX_DESCRIPTOR_SETS> m_dsetState;
  319. ShaderProgramImpl* m_graphicsProg ANKI_DEBUG_CODE(= nullptr); ///< Last bound graphics program
  320. ShaderProgramImpl* m_computeProg ANKI_DEBUG_CODE(= nullptr);
  321. ShaderProgramImpl* m_rtProg ANKI_DEBUG_CODE(= nullptr);
  322. VkSubpassContents m_subpassContents = VK_SUBPASS_CONTENTS_MAX_ENUM;
  323. CommandBufferCommandType m_lastCmdType = CommandBufferCommandType::ANY_OTHER_COMMAND;
  324. /// @name state_opts
  325. /// @{
  326. Array<U32, 4> m_viewport = {0, 0, 0, 0};
  327. Array<U32, 4> m_scissor = {0, 0, MAX_U32, MAX_U32};
  328. Bool m_viewportDirty = true;
  329. VkViewport m_lastViewport = {};
  330. Bool m_scissorDirty = true;
  331. VkRect2D m_lastScissor = {{-1, -1}, {MAX_U32, MAX_U32}};
  332. Array<U32, 2> m_stencilCompareMasks = {0x5A5A5A5A, 0x5A5A5A5A}; ///< Use a stupid number to initialize.
  333. Array<U32, 2> m_stencilWriteMasks = {0x5A5A5A5A, 0x5A5A5A5A};
  334. Array<U32, 2> m_stencilReferenceMasks = {0x5A5A5A5A, 0x5A5A5A5A};
  335. #if ANKI_ENABLE_ASSERTIONS
  336. Bool m_lineWidthSet = false;
  337. #endif
  338. /// Rebind the above dynamic state. Needed after pushing secondary command buffers (they dirty the state).
  339. void rebindDynamicState();
  340. /// @}
  341. /// @name barrier_batch
  342. /// @{
  343. DynamicArray<VkImageMemoryBarrier> m_imgBarriers;
  344. DynamicArray<VkBufferMemoryBarrier> m_buffBarriers;
  345. DynamicArray<VkMemoryBarrier> m_memBarriers;
  346. U16 m_imgBarrierCount = 0;
  347. U16 m_buffBarrierCount = 0;
  348. U16 m_memBarrierCount = 0;
  349. VkPipelineStageFlags m_srcStageMask = 0;
  350. VkPipelineStageFlags m_dstStageMask = 0;
  351. /// @}
  352. /// @name reset_query_batch
  353. /// @{
  354. class QueryResetAtom
  355. {
  356. public:
  357. VkQueryPool m_pool;
  358. U32 m_queryIdx;
  359. };
  360. DynamicArray<QueryResetAtom> m_queryResetAtoms;
  361. /// @}
  362. /// @name write_query_result_batch
  363. /// @{
  364. class WriteQueryAtom
  365. {
  366. public:
  367. VkQueryPool m_pool;
  368. U32 m_queryIdx;
  369. VkBuffer m_buffer;
  370. PtrSize m_offset;
  371. };
  372. DynamicArray<WriteQueryAtom> m_writeQueryAtoms;
  373. /// @}
  374. /// @name push_second_level_batch
  375. /// @{
  376. DynamicArray<VkCommandBuffer> m_secondLevelAtoms;
  377. U16 m_secondLevelAtomCount = 0;
  378. /// @}
  379. /// Some common operations per command.
  380. void commandCommon();
  381. /// Flush batches. Use ANKI_CMD on every vkCmdXXX to do that automatically and call it manually before adding to a
  382. /// batch.
  383. void flushBatches(CommandBufferCommandType type);
  384. void drawcallCommon();
  385. Bool insideRenderPass() const
  386. {
  387. return m_activeFb.isCreated();
  388. }
  389. void beginRenderPassInternal();
  390. Bool secondLevel() const
  391. {
  392. return !!(m_flags & CommandBufferFlag::SECOND_LEVEL);
  393. }
  394. /// Flush batched image and buffer barriers.
  395. void flushBarriers();
  396. void flushQueryResets();
  397. void flushWriteQueryResults();
  398. void setImageBarrier(VkPipelineStageFlags srcStage, VkAccessFlags srcAccess, VkImageLayout prevLayout,
  399. VkPipelineStageFlags dstStage, VkAccessFlags dstAccess, VkImageLayout newLayout, VkImage img,
  400. const VkImageSubresourceRange& range);
  401. void beginRecording();
  402. Bool flipViewport() const;
  403. static VkViewport computeViewport(U32* viewport, U32 fbWidth, U32 fbHeight, Bool flipvp)
  404. {
  405. const U32 minx = viewport[0];
  406. const U32 miny = viewport[1];
  407. const U32 width = min<U32>(fbWidth, viewport[2]);
  408. const U32 height = min<U32>(fbHeight, viewport[3]);
  409. ANKI_ASSERT(width > 0 && height > 0);
  410. ANKI_ASSERT(minx + width <= fbWidth);
  411. ANKI_ASSERT(miny + height <= fbHeight);
  412. VkViewport s = {};
  413. s.x = F32(minx);
  414. s.y = (flipvp) ? F32(fbHeight - miny) : F32(miny); // Move to the bottom;
  415. s.width = F32(width);
  416. s.height = (flipvp) ? -F32(height) : F32(height);
  417. s.minDepth = 0.0f;
  418. s.maxDepth = 1.0f;
  419. return s;
  420. }
  421. static VkRect2D computeScissor(U32* scissor, U32 fbWidth, U32 fbHeight, Bool flipvp)
  422. {
  423. const U32 minx = scissor[0];
  424. const U32 miny = scissor[1];
  425. const U32 width = min<U32>(fbWidth, scissor[2]);
  426. const U32 height = min<U32>(fbHeight, scissor[3]);
  427. ANKI_ASSERT(minx + width <= fbWidth);
  428. ANKI_ASSERT(miny + height <= fbHeight);
  429. VkRect2D out = {};
  430. out.extent.width = width;
  431. out.extent.height = height;
  432. out.offset.x = minx;
  433. out.offset.y = (flipvp) ? (fbHeight - (miny + height)) : miny;
  434. return out;
  435. }
  436. const ShaderProgramImpl& getBoundProgram()
  437. {
  438. if(m_graphicsProg)
  439. {
  440. ANKI_ASSERT(m_computeProg == nullptr && m_rtProg == nullptr);
  441. return *m_graphicsProg;
  442. }
  443. else if(m_computeProg)
  444. {
  445. ANKI_ASSERT(m_graphicsProg == nullptr && m_rtProg == nullptr);
  446. return *m_computeProg;
  447. }
  448. else
  449. {
  450. ANKI_ASSERT(m_graphicsProg == nullptr && m_computeProg == nullptr && m_rtProg != nullptr);
  451. return *m_rtProg;
  452. }
  453. }
  454. };
  455. /// @}
  456. } // end namespace anki
  457. #include <AnKi/Gr/Vulkan/CommandBufferImpl.inl.h>