BsVulkanCommandBuffer.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. #define BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY BS_MAX_QUEUES_PER_TYPE * 32
  16. // Maximum number of command buffers that another command buffer can be dependant on (via a sync mask)
  17. #define BS_MAX_VULKAN_CB_DEPENDENCIES 2
  18. /** Wrapper around a Vulkan semaphore object that manages its usage and lifetime. */
  19. class VulkanSemaphore : public VulkanResource
  20. {
  21. public:
  22. VulkanSemaphore(VulkanResourceManager* owner);
  23. ~VulkanSemaphore();
  24. /** Returns the internal handle to the Vulkan object. */
  25. VkSemaphore getHandle() const { return mSemaphore; }
  26. private:
  27. VkSemaphore mSemaphore;
  28. };
  29. class VulkanCmdBuffer;
  30. /** Pool that allocates and distributes Vulkan command buffers. */
  31. class VulkanCmdBufferPool
  32. {
  33. public:
  34. VulkanCmdBufferPool(VulkanDevice& device);
  35. ~VulkanCmdBufferPool();
  36. /**
  37. * Attempts to find a free command buffer, or creates a new one if not found. Caller must guarantee the provided
  38. * queue family is valid.
  39. */
  40. VulkanCmdBuffer* getBuffer(UINT32 queueFamily, bool secondary);
  41. private:
  42. /** Command buffer pool and related information. */
  43. struct PoolInfo
  44. {
  45. VkCommandPool pool = VK_NULL_HANDLE;
  46. VulkanCmdBuffer* buffers[BS_MAX_VULKAN_CB_PER_QUEUE_FAMILY];
  47. UINT32 queueFamily = -1;
  48. };
  49. /** Creates a new command buffer. */
  50. VulkanCmdBuffer* createBuffer(UINT32 queueFamily, bool secondary);
  51. VulkanDevice& mDevice;
  52. UnorderedMap<UINT32, PoolInfo> mPools;
  53. UINT32 mNextId;
  54. };
  55. /** Determines where are the current descriptor sets bound to. */
  56. enum class DescriptorSetBindFlag
  57. {
  58. None = 0,
  59. Graphics = 1 << 0,
  60. Compute = 1 << 1
  61. };
  62. typedef Flags<DescriptorSetBindFlag> DescriptorSetBindFlags;
  63. BS_FLAGS_OPERATORS(DescriptorSetBindFlag)
  64. /**
  65. * Represents a direct wrapper over an internal Vulkan command buffer. This is unlike VulkanCommandBuffer which is a
  66. * higher level class, and it allows for re-use by internally using multiple low-level command buffers.
  67. */
  68. class VulkanCmdBuffer
  69. {
  70. /** Possible states a command buffer can be in. */
  71. enum class State
  72. {
  73. /** Buffer is ready to be re-used. */
  74. Ready,
  75. /** Buffer is currently recording commands, but isn't recording a render pass. */
  76. Recording,
  77. /** Buffer is currently recording render pass commands. */
  78. RecordingRenderPass,
  79. /** Buffer is done recording but hasn't been submitted. */
  80. RecordingDone,
  81. /** Buffer is done recording and is currently submitted on a queue. */
  82. Submitted
  83. };
  84. public:
  85. VulkanCmdBuffer(VulkanDevice& device, UINT32 id, VkCommandPool pool, UINT32 queueFamily, bool secondary);
  86. ~VulkanCmdBuffer();
  87. /** Returns an unique identifier of this command buffer. */
  88. UINT32 getId() const { return mId; }
  89. /** Returns the index of the queue family this command buffer is executing on. */
  90. UINT32 getQueueFamily() const { return mQueueFamily; }
  91. /** Returns the index of the device this command buffer will execute on. */
  92. UINT32 getDeviceIdx() const;
  93. /** Makes the command buffer ready to start recording commands. */
  94. void begin();
  95. /** Ends command buffer command recording (as started with begin()). */
  96. void end();
  97. /** Begins render pass recording. Must be called within begin()/end() calls. */
  98. void beginRenderPass();
  99. /** Ends render pass recording (as started with beginRenderPass(). */
  100. void endRenderPass();
  101. /**
  102. * Submits the command buffer for execution.
  103. *
  104. * @param[in] queue Queue to submit the command buffer on.
  105. * @param[in] queueIdx Index of the queue the command buffer was submitted on. Note that this may be different
  106. * from the actual VulkanQueue index since multiple command buffer queue indices can map
  107. * to the same queue.
  108. * @param[in] syncMask Mask that controls which other command buffers does this command buffer depend upon
  109. * (if any). See description of @p syncMask parameter in RenderAPICore::executeCommands().
  110. */
  111. void submit(VulkanQueue* queue, UINT32 queueIdx, UINT32 syncMask);
  112. /** Returns the handle to the internal Vulkan command buffer wrapped by this object. */
  113. VkCommandBuffer getHandle() const { return mCmdBuffer; }
  114. /** Returns a fence that can be used for tracking when the command buffer is done executing. */
  115. VkFence getFence() const { return mFence; }
  116. /**
  117. * Returns a semaphore that may be used for synchronizing execution between command buffers executing on the same
  118. * queue.
  119. */
  120. VulkanSemaphore* getIntraQueueSemaphore() const { return mIntraQueueSemaphore; }
  121. /**
  122. * Returns a semaphore that may be used for synchronizing execution between command buffers executing on different
  123. * queues. Note that these semaphores get used each time they are requested, and there is only a fixed number
  124. * available. If all are used up, null will be returned. New semaphores are generated when allocateSemaphores()
  125. * is called.
  126. */
  127. VulkanSemaphore* requestInterQueueSemaphore() const;
  128. /**
  129. * Allocates a new set of semaphores that may be used for synchronizing execution between different command buffers.
  130. * Releases the previously allocated semaphores, if they exist. Use getIntraQueueSemaphore() &
  131. * requestInterQueueSemaphore() to retrieve latest allocated semaphores.
  132. */
  133. void allocateSemaphores();
  134. /** Returns true if the command buffer is currently being processed by the device. */
  135. bool isSubmitted() const { return mState == State::Submitted; }
  136. /** Returns true if the command buffer is currently recording (but not within a render pass). */
  137. bool isRecording() const { return mState == State::Recording; }
  138. /** Returns true if the command buffer is ready to be submitted to a queue. */
  139. bool isReadyForSubmit() const { return mState == State::RecordingDone; }
  140. /** Returns true if the command buffer is currently recording a render pass. */
  141. bool isInRenderPass() const { return mState == State::RecordingRenderPass; }
  142. /** Checks the internal fence if done executing. */
  143. bool checkFenceStatus() const;
  144. /**
  145. * Resets the command buffer back in Ready state. Should be called when command buffer is done executing on a
  146. * queue.
  147. */
  148. void reset();
  149. /**
  150. * Lets the command buffer know that the provided resource has been queued on it, and will be used by the
  151. * device when the command buffer is submitted. If a resource is an image or a buffer use the more specific
  152. * registerResource() overload.
  153. */
  154. void registerResource(VulkanResource* res, VulkanUseFlags flags);
  155. /**
  156. * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
  157. * device when the command buffer is submitted. Executes a layout transition to @p newLayout (if needed), and
  158. * updates the externally visible image layout field to @p finalLayout (once submitted).
  159. *
  160. * @param[in] res Image to register with the command buffer.
  161. * @param[in] newLayout Layout the image needs to be transitioned in before use. Set to undefined
  162. * layout if no transition is required.
  163. * @param[in] finalLayout Determines what value the externally visible image layout will be set after
  164. * submit() is called. Normally this will be same as @p newLayout, but can be
  165. * different if some form of automatic layout transitions are happening.
  166. * @param[in] flags Flags that determine how will be command buffer be using the buffer.
  167. * @param[in] isFBAttachment Determines if the image is being used as a framebuffer attachment (if true),
  168. * or just as regular shader input (if false).
  169. */
  170. void registerResource(VulkanImage* res, VkImageLayout newLayout, VkImageLayout finalLayout, VulkanUseFlags flags,
  171. bool isFBAttachment = false);
  172. /**
  173. * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
  174. * device when the command buffer is submitted. Performs no layout transitions on the image, they must be performed
  175. * by the caller, or not required at all.
  176. */
  177. void registerResource(VulkanImage* res, VulkanUseFlags flags);
  178. /**
  179. * Lets the command buffer know that the provided image resource has been queued on it, and will be used by the
  180. * device when the command buffer is submitted.
  181. */
  182. void registerResource(VulkanBuffer* res, VkAccessFlags accessFlags, VulkanUseFlags flags);
  183. /**
  184. * Lets the command buffer know that the provided framebuffer resource has been queued on it, and will be used by
  185. * the device when the command buffer is submitted.
  186. */
  187. void registerResource(VulkanFramebuffer* res, RenderSurfaceMask loadMask, VulkanUseFlags flags);
  188. /************************************************************************/
  189. /* COMMANDS */
  190. /************************************************************************/
  191. /**
  192. * Assigns a render target the the command buffer. This render target's framebuffer and render pass will be used
  193. * when beginRenderPass() is called. Command buffer must not be currently recording a render pass.
  194. */
  195. void setRenderTarget(const SPtr<RenderTargetCore>& rt, bool readOnlyDepthStencil, RenderSurfaceMask loadMask);
  196. /** Clears the entirety currently bound render target. */
  197. void clearRenderTarget(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
  198. /** Clears the viewport portion of the currently bound render target. */
  199. void clearViewport(UINT32 buffers, const Color& color, float depth, UINT16 stencil, UINT8 targetMask);
  200. /** Assigns a pipeline state to use for subsequent draw commands. */
  201. void setPipelineState(const SPtr<GraphicsPipelineStateCore>& state);
  202. /** Assigns a pipeline state to use for subsequent dispatch commands. */
  203. void setPipelineState(const SPtr<ComputePipelineStateCore>& state);
  204. /** Assign GPU params to the GPU programs bound by the pipeline state. */
  205. void setGpuParams(const SPtr<GpuParamsCore>& gpuParams);
  206. /** Sets the current viewport which determine to which portion of the render target to render to. */
  207. void setViewport(const Rect2& area);
  208. /**
  209. * Sets the scissor rectangle area which determines in which area if the viewport are the fragments allowed to be
  210. * generated. Only relevant if enabled on the pipeline state.
  211. */
  212. void setScissorRect(const Rect2I& area);
  213. /** Sets a stencil reference value that will be used for comparisons in stencil operations, if enabled. */
  214. void setStencilRef(UINT32 value);
  215. /** Changes how are primitives interpreted as during rendering. */
  216. void setDrawOp(DrawOperationType drawOp);
  217. /** Sets one or multiple vertex buffers that will be used for subsequent draw() or drawIndexed() calls. */
  218. void setVertexBuffers(UINT32 index, SPtr<VertexBufferCore>* buffers, UINT32 numBuffers);
  219. /** Sets an index buffer that will be used for subsequent drawIndexed() calls. */
  220. void setIndexBuffer(const SPtr<IndexBufferCore>& buffer);
  221. /** Sets a declaration that determines how are vertex buffer contents interpreted. */
  222. void setVertexDeclaration(const SPtr<VertexDeclarationCore>& decl);
  223. /** Executes a draw command using the currently bound graphics pipeline, vertex buffer and render target. */
  224. void draw(UINT32 vertexOffset, UINT32 vertexCount, UINT32 instanceCount);
  225. /** Executes a draw command using the currently bound graphics pipeline, index & vertex buffer and render target. */
  226. void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 instanceCount);
  227. /** Executes a dispatch command using the currently bound compute pipeline. */
  228. void dispatch(UINT32 numGroupsX, UINT32 numGroupsY, UINT32 numGroupsZ);
  229. /**
  230. * Registers a command that signals the event when executed. Will be delayed until the end of the current
  231. * render pass, if any.
  232. */
  233. void setEvent(VulkanEvent* event);
  234. /**
  235. * Registers a command that resets the query. The command will be delayed until the next submit() if a render
  236. * pass is currently in progress, but is guaranteed to execute before this command buffer is submitted.
  237. */
  238. void resetQuery(VulkanQuery* query);
  239. private:
  240. friend class VulkanCmdBufferPool;
  241. friend class VulkanCommandBuffer;
  242. friend class VulkanQueue;
  243. /** Contains information about a single Vulkan resource bound/used on this command buffer. */
  244. struct ResourceUseHandle
  245. {
  246. bool used;
  247. VulkanUseFlags flags;
  248. };
  249. /** Contains information about a single Vulkan buffer resource bound/used on this command buffer. */
  250. struct BufferInfo
  251. {
  252. VkAccessFlags accessFlags;
  253. ResourceUseHandle useHandle;
  254. };
  255. /** Contains information about a single Vulkan image resource bound/used on this command buffer. */
  256. struct ImageInfo
  257. {
  258. VkImageSubresourceRange range;
  259. ResourceUseHandle useHandle;
  260. // Only relevant for layout transitions
  261. VkImageLayout initialLayout;
  262. VkImageLayout currentLayout;
  263. VkImageLayout requiredLayout;
  264. VkImageLayout finalLayout;
  265. bool isFBAttachment : 1;
  266. bool isShaderInput : 1;
  267. bool hasTransitioned : 1;
  268. bool isReadOnly : 1;
  269. bool isInitialReadOnly : 1;
  270. };
  271. /** Checks if all the prerequisites for rendering have been made (e.g. render target and pipeline state are set. */
  272. bool isReadyForRender();
  273. /** Marks the command buffer as submitted on a queue. */
  274. void setIsSubmitted() { mState = State::Submitted; }
  275. /** Binds the current graphics pipeline to the command buffer. Returns true if bind was successful. */
  276. bool bindGraphicsPipeline();
  277. /**
  278. * Binds any dynamic states to the pipeline, as required.
  279. *
  280. * @param[in] forceAll If true all states will be bound. If false only states marked as dirty will be bound.
  281. */
  282. void bindDynamicStates(bool forceAll);
  283. /** Binds the currently stored GPU parameters object, if dirty. */
  284. void bindGpuParams();
  285. /** Clears the specified area of the currently bound render target. */
  286. void clearViewport(const Rect2I& area, UINT32 buffers, const Color& color, float depth, UINT16 stencil,
  287. UINT8 targetMask);
  288. /** Starts and ends a render pass, intended only for a clear operation. */
  289. void executeClearPass();
  290. /** Executes any queued layout transitions by issuing a pipeline barrier. */
  291. void executeLayoutTransitions();
  292. /**
  293. * Updates final layouts for images used by the current framebuffer, reflecting layout changes performed by render
  294. * pass' automatic layout transitions.
  295. */
  296. void updateFinalLayouts();
  297. UINT32 mId;
  298. UINT32 mQueueFamily;
  299. State mState;
  300. VulkanDevice& mDevice;
  301. VkCommandPool mPool;
  302. VkCommandBuffer mCmdBuffer;
  303. VkFence mFence;
  304. VulkanSemaphore* mIntraQueueSemaphore;
  305. VulkanSemaphore* mInterQueueSemaphores[BS_MAX_VULKAN_CB_DEPENDENCIES];
  306. mutable UINT32 mNumUsedInterQueueSemaphores;
  307. VulkanFramebuffer* mFramebuffer;
  308. UINT32 mRenderTargetWidth;
  309. UINT32 mRenderTargetHeight;
  310. bool mRenderTargetDepthReadOnly;
  311. RenderSurfaceMask mRenderTargetLoadMask;
  312. UnorderedMap<VulkanResource*, ResourceUseHandle> mResources;
  313. UnorderedMap<VulkanResource*, UINT32> mImages;
  314. UnorderedMap<VulkanResource*, BufferInfo> mBuffers;
  315. Vector<ImageInfo> mImageInfos;
  316. UINT32 mGlobalQueueIdx;
  317. SPtr<VulkanGraphicsPipelineStateCore> mGraphicsPipeline;
  318. SPtr<VulkanComputePipelineStateCore> mComputePipeline;
  319. SPtr<VertexDeclarationCore> mVertexDecl;
  320. Rect2 mViewport;
  321. Rect2I mScissor;
  322. UINT32 mStencilRef;
  323. DrawOperationType mDrawOp;
  324. UINT32 mNumBoundDescriptorSets;
  325. bool mGfxPipelineRequiresBind : 1;
  326. bool mCmpPipelineRequiresBind : 1;
  327. bool mViewportRequiresBind : 1;
  328. bool mStencilRefRequiresBind : 1;
  329. bool mScissorRequiresBind : 1;
  330. bool mBoundParamsDirty : 1;
  331. DescriptorSetBindFlags mDescriptorSetsBindState;
  332. SPtr<VulkanGpuParams> mBoundParams;
  333. std::array<VkClearValue, BS_MAX_MULTIPLE_RENDER_TARGETS + 1> mClearValues;
  334. ClearMask mClearMask;
  335. Rect2I mClearArea;
  336. VulkanSemaphore* mSemaphoresTemp[BS_MAX_UNIQUE_QUEUES];
  337. VkBuffer mVertexBuffersTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
  338. VkDeviceSize mVertexBufferOffsetsTemp[BS_MAX_BOUND_VERTEX_BUFFERS];
  339. VkDescriptorSet* mDescriptorSetsTemp;
  340. UnorderedMap<UINT32, TransitionInfo> mTransitionInfoTemp;
  341. Vector<VkImageMemoryBarrier> mLayoutTransitionBarriersTemp;
  342. UnorderedMap<VulkanImage*, UINT32> mQueuedLayoutTransitions;
  343. Vector<VulkanEvent*> mQueuedEvents;
  344. Vector<VulkanQuery*> mQueuedQueryResets;
  345. };
  346. /** CommandBuffer implementation for Vulkan. */
  347. class VulkanCommandBuffer : public CommandBuffer
  348. {
  349. public:
  350. /**
  351. * Submits the command buffer for execution.
  352. *
  353. * @param[in] syncMask Mask that controls which other command buffers does this command buffer depend upon
  354. * (if any). See description of @p syncMask parameter in RenderAPICore::executeCommands().
  355. */
  356. void submit(UINT32 syncMask);
  357. /**
  358. * Returns the internal command buffer.
  359. *
  360. * @note This buffer will change after a submit() call.
  361. */
  362. VulkanCmdBuffer* getInternal() const { return mBuffer; }
  363. private:
  364. friend class VulkanCommandBufferManager;
  365. VulkanCommandBuffer(VulkanDevice& device, GpuQueueType type, UINT32 deviceIdx, UINT32 queueIdx,
  366. bool secondary);
  367. /**
  368. * Tasks the command buffer to find a new internal command buffer. Call this after the command buffer has been
  369. * submitted to a queue (it's not allowed to be used until the queue is done with it).
  370. */
  371. void acquireNewBuffer();
  372. VulkanCmdBuffer* mBuffer;
  373. VulkanDevice& mDevice;
  374. VulkanQueue* mQueue;
  375. UINT32 mIdMask;
  376. };
  377. /** @} */
  378. }