2
0

BsVulkanCommandBuffer.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsVulkanPrerequisites.h"
  5. #include "BsCommandBuffer.h"
  6. #include "BsVulkanRenderAPI.h"
  7. #include "BsVulkanResource.h"
  8. #include "BsVulkanGpuPipelineState.h"
  9. namespace bs
  10. {
  11. class VulkanImage;
  12. /** @addtogroup Vulkan
  13. * @{
  14. */
  15. class VulkanCmdBuffer;
  16. #define BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY BS_MAX_QUEUES_PER_TYPE * 32
  17. /** Pool that allocates and distributes Vulkan command buffers. */
  18. class VulkanCmdBufferPool
  19. {
  20. public:
  21. VulkanCmdBufferPool(VulkanDevice& device);
  22. ~VulkanCmdBufferPool();
  23. /**
  24. * Attempts to find a free command buffer, or creates a new one if not found. Caller must guarantee the provided
  25. * queue family is valid.
  26. */
  27. VulkanCmdBuffer* getBuffer(UINT32 queueFamily, bool secondary);
  28. private:
  29. /** Command buffer pool and related information. */
  30. struct PoolInfo
  31. {
  32. VkCommandPool pool = VK_NULL_HANDLE;
  33. VulkanCmdBuffer* buffers[BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY];
  34. UINT32 queueFamily = -1;
  35. };
  36. /** Creates a new command buffer. */
  37. VulkanCmdBuffer* createBuffer(UINT32 queueFamily, bool secondary);
  38. VulkanDevice& mDevice;
  39. UnorderedMap<UINT32, PoolInfo> mPools;
  40. UINT32 mNextId;
  41. };
  42. /** Determines where are the current descriptor sets bound to. */
  43. enum class DescriptorSetBindFlag
  44. {
  45. None = 0,
  46. Graphics = 1 << 0,
  47. Compute = 1 << 1
  48. };
  49. typedef Flags<DescriptorSetBindFlag> DescriptorSetBindFlags;
  50. BS_FLAGS_OPERATORS(DescriptorSetBindFlag)
  51. /**
  52. * Represents a direct wrapper over an internal Vulkan command buffer. This is unlike VulkanCommandBuffer which is a
  53. * higher level class, and it allows for re-use by internally using multiple low-level command buffers.
  54. */
  55. class VulkanCmdBuffer
  56. {
  57. /** Possible states a command buffer can be in. */
  58. enum class State
  59. {
  60. /** Buffer is ready to be re-used. */
  61. Ready,
  62. /** Buffer is currently recording commands, but isn't recording a render pass. */
  63. Recording,
  64. /** Buffer is currently recording render pass commands. */
  65. RecordingRenderPass,
  66. /** Buffer is done recording but hasn't been submitted. */
  67. RecordingDone,
  68. /** Buffer is done recording and is currently submitted on a queue. */
  69. Submitted
  70. };
  71. public:
  72. VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary);
  73. ~VulkanCmdBuffer();
  74. /** Returns an unique identifier of this command buffer. */
  75. UINT32 getId() const { return mId; }
  76. /** Returns the index of the queue family this command buffer is executing on. */
  77. UINT32 getQueueFamily() const { return mQueueFamily; }
  78. /** Returns the index of the device this command buffer will execute on. */
  79. UINT32 getDeviceIdx() const;
  80. /** Makes the command buffer ready to start recording commands. */
  81. void begin();
  82. /** Ends command buffer command recording (as started with begin()). */
  83. void end();
  84. /** Begins render pass recording. Must be called within begin()/end() calls. */
  85. void beginRenderPass();
  86. /** Ends render pass recording (as started with beginRenderPass(). */
  87. void endRenderPass();
  88. /**
  89. * Submits the command buffer for execution.
  90. *
  91. * @param[in] queue Queue to submit the command buffer on.
  92. * @param[in] queueIdx Index of the queue the command buffer was submitted on. Note that this may be different
  93. * from the actual VulkanQueue index since multiple command buffer queue indices can map
  94. * to the same queue.
  95. * @param[in] syncMask Mask that controls which other command buffers does this command buffer depend upon
  96. * (if any). See description of @p syncMask parameter in RenderAPICore::executeCommands().
  97. */
  98. void submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask);
  99. /** Returns the handle to the internal Vulkan command buffer wrapped by this object. */
  100. VkCommandBuffer getHandle() const { return mCmdBuffer; }
  101. /** Returns a fence that can be used for tracking when the command buffer is done executing. */
  102. VkFence getFence() const { return mFence; }
  103. /**
  104. * Returns a semaphore that may be used for synchronizing execution between command buffers executing on different
  105. * queues.
  106. */
  107. VkSemaphore getSemaphore() const { return mSemaphore; }
  108. /** Returns true if the command buffer is currently being processed by the device. */
  109. bool isSubmitted() const { return mState == State::Submitted; }
  110. /** Returns true if the command buffer is currently recording (but not within a render pass). */
  111. bool isRecording() const { return mState == State::Recording; }
  112. /** Returns true if the command buffer is ready to be submitted to a queue. */
  113. bool isReadyForSubmit() const { return mState == State::RecordingDone; }
  114. /** Returns true if the command buffer is currently recording a render pass. */
  115. bool isInRenderPass() const { return mState == State::RecordingRenderPass; }
  116. /** Returns a counter that gets incremented whenever the command buffer is done executing. */
  117. UINT32 getFenceCounter() const { return mFenceCounter; }
  118. /** Checks the internal fence and changes command buffer state if done executing. */
  119. void refreshFenceStatus();
  120. /**
  121. * Lets the command buffer know that the provided resource has been queued on it, and will be used by the
  122. * device when the command buffer is submitted. If a resource is an image or a buffer use the more specific
  123. * registerResource() overload.
  124. */
  125. void registerResource(VulkanResource* res, VulkanUseFlags flags);
  126. /**
  127. * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
  128. * device when the command buffer is submitted.
  129. */
  130. void registerResource(VulkanImage* res, VkAccessFlags accessFlags, VkImageLayout layout,
  131. VulkanUseFlags flags, bool isFBAttachment = false);
  132. /**
  133. * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
  134. * device when the command buffer is submitted.
  135. */
  136. void registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags);
  137. /**
  138. * Lets the command buffer know that the provided framebuffer resource has been queued on it, and will be used by
  139. * the device when the command buffer is submitted.
  140. */
  141. void registerResource(VulkanFramebuffer* res, VulkanUseFlags flags);
  142. /************************************************************************/
  143. /* COMMANDS */
  144. /************************************************************************/
  145. /**
  146. * Assigns a render target the the command buffer. This render target's framebuffer and render pass will be used
  147. * when beginRenderPass() is called. Command buffer must not be currently recording a render pass.
  148. */
  149. void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil, RenderSurfaceMask loadMask);
  150. /** Clears the entirety currently bound render target. */
  151. void clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
  152. /** Clears the viewport portion of the currently bound render target. */
  153. void clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
  154. /** Assigns a pipeline state to use for subsequent draw commands. */
  155. void setPipelineState(const SPtr<GraphicsPipelineStateCore>& state);
  156. /** Assigns a pipeline state to use for subsequent dispatch commands. */
  157. void setPipelineState(const SPtr<ComputePipelineStateCore>& state);
  158. /** Assign GPU params to the GPU programs bound by the pipeline state. */
  159. void setGpuParams(const SPtr<GpuParamsCore>& gpuParams);
  160. /** Sets the current viewport which determine to which portion of the render target to render to. */
  161. void setViewport(const Rect2& area);
  162. /**
  163. * Sets the scissor rectangle area which determines in which area if the viewport are the fragments allowed to be
  164. * generated. Only relevant if enabled on the pipeline state.
  165. */
  166. void setScissorRect(const Rect2I& area);
  167. /** Sets a stencil reference value that will be used for comparisons in stencil operations, if enabled. */
  168. void setStencilRef(UINT32 value);
  169. /** Changes how are primitives interpreted as during rendering. */
  170. void setDrawOp(DrawOperationType drawOp);
  171. /** Sets one or multiple vertex buffers that will be used for subsequent draw() or drawIndexed() calls. */
  172. void setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers);
  173. /** Sets an index buffer that will be used for subsequent drawIndexed() calls. */
  174. void setIndexBuffer(const SPtr<IndexBufferCore>& buffer);
  175. /** Sets a declaration that determines how are vertex buffer contents interpreted. */
  176. void setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl);
  177. /** Executes a draw command using the currently bound graphics pipeline, vertex buffer and render target. */
  178. void draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount);
  179. /** Executes a draw command using the currently bound graphics pipeline, index & vertex buffer and render target. */
  180. void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount);
  181. /** Executes a dispatch command using the currently bound compute pipeline. */
  182. void dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ);
  183. private:
  184. friend class VulkanCmdBufferPool;
  185. friend class VulkanCommandBuffer;
  186. /** Contains information about a single Vulkan resource bound/used on this command buffer. */
  187. struct ResourceUseHandle
  188. {
  189. bool used;
  190. VulkanUseFlags flags;
  191. };
  192. /** Contains information about a single Vulkan buffer resource bound/used on this command buffer. */
  193. struct BufferInfo
  194. {
  195. VkAccessFlags accessFlags;
  196. ResourceUseHandle useHandle;
  197. };
  198. /** Contains information about a single Vulkan image resource bound/used on this command buffer. */
  199. struct ImageInfo
  200. {
  201. VkAccessFlags accessFlags;
  202. VkImageSubresourceRange range;
  203. ResourceUseHandle useHandle;
  204. // Only relevant for layout transitions
  205. VkImageLayout currentLayout;
  206. VkImageLayout requiredLayout;
  207. VkImageLayout finalLayout;
  208. bool isFBAttachment : 1;
  209. bool isShaderInput : 1;
  210. };
  211. /** Checks if all the prerequisites for rendering have been made (e.g. render target and pipeline state are set. */
  212. bool isReadyForRender();
  213. /** Binds the current graphics pipeline to the command buffer. Returns true if bind was successful. */
  214. bool bindGraphicsPipeline();
  215. /** Binds any dynamic states to the pipeline, as required.
  216. *
  217. * @param[in] forceAll If true all states will be bound. If false only states marked as dirty will be bound.
  218. */
  219. void bindDynamicStates(bool forceAll);
  220. /** Clears the specified area of the currently bound render target. */
  221. void clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
  222. UINT8 targetMask);
  223. UINT32 mId;
  224. UINT32 mQueueFamily;
  225. State mState;
  226. VulkanDevice& mDevice;
  227. VkCommandPool mPool;
  228. VkCommandBuffer mCmdBuffer;
  229. VkFence mFence;
  230. VkSemaphore mSemaphore;
  231. UINT32 mFenceCounter;
  232. VulkanFramebuffer* mFramebuffer;
  233. VkSemaphore mPresentSemaphore;
  234. UINT32 mRenderTargetWidth;
  235. UINT32 mRenderTargetHeight;
  236. bool mRenderTargetDepthReadOnly;
  237. RenderSurfaceMask mRenderTargetLoadMask;
  238. UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
  239. UnorderedMap<VulkanResource*, UINT32> mImages;
  240. UnorderedMap<VulkanResource*, BufferInfo> mBuffers;
  241. Vector<ImageInfo> mImageInfos;
  242. UINT32 mGlobalQueueIdx;
  243. SPtr<VulkanGraphicsPipelineStateCore> mGraphicsPipeline;
  244. SPtr<VulkanComputePipelineStateCore> mComputePipeline;
  245. SPtr<VertexDeclarationCore> mVertexDecl;
  246. Rect2 mViewport;
  247. Rect2I mScissor;
  248. UINT32 mStencilRef;
  249. DrawOperationType mDrawOp;
  250. UINT32 mNumBoundDescriptorSets;
  251. bool mGfxPipelineRequiresBind : 1;
  252. bool mCmpPipelineRequiresBind : 1;
  253. bool mViewportRequiresBind : 1;
  254. bool mStencilRefRequiresBind : 1;
  255. bool mScissorRequiresBind : 1;
  256. DescriptorSetBindFlags mDescriptorSetsBindState;
  257. VkSemaphore mSemaphoresTemp[BS_MAX_UNIQUE_QUEUES + 1]; // +1 for present semaphore
  258. VkBuffer mVertexBuffersTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
  259. VkDeviceSize mVertexBufferOffsetsTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
  260. VkDescriptorSet* mDescriptorSetsTemp;
  261. UnorderedMap<UINT32, TransitionInfo> mTransitionInfoTemp;
  262. Vector<VkImageMemoryBarrier> mLayoutTransitionBarriersTemp;
  263. UnorderedMap<VulkanImage*, UINT32> mQueuedLayoutTransitions;
  264. };
  265. /** CommandBuffer implementation for Vulkan. */
  266. class VulkanCommandBuffer : public CommandBuffer
  267. {
  268. public:
  269. /**
  270. * Submits the command buffer for execution.
  271. *
  272. * @param[in] syncMask Mask that controls which other command buffers does this command buffer depend upon
  273. * (if any). See description of @p syncMask parameter in RenderAPICore::executeCommands().
  274. */
  275. void submit(UINT32 syncMask);
  276. /**
  277. * Returns the internal command buffer.
  278. *
  279. * @note This buffer will change after a submit() call.
  280. */
  281. VulkanCmdBuffer* getInternal() const { return mBuffer; }
  282. private:
  283. friend class VulkanCommandBufferManager;
  284. VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx, UINT32 queueIdx,
  285. bool secondary);
  286. /**
  287. * Tasks the command buffer to find a new internal command buffer. Call this after the command buffer has been
  288. * submitted to a queue (it's not allowed to be used until the queue is done with it).
  289. */
  290. void acquireNewBuffer();
  291. VulkanCmdBuffer* mBuffer;
  292. VulkanDevice& mDevice;
  293. VulkanQueue* mQueue;
  294. UINT32 mIdMask;
  295. };
  296. /** @} */
  297. }