BsVulkanResource.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  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 "Allocators/BsStaticAlloc.h"
  6. namespace bs { namespace ct
  7. {
  8. /** @addtogroup Vulkan
  9. * @{
  10. */
  11. /** Flags that determine how is a resource being used by the GPU. */
  12. enum class VulkanUseFlag
  13. {
  14. None = 0,
  15. Read = 0x1,
  16. Write = 0x2
  17. };
  18. class VulkanResourceManager;
  19. typedef Flags<VulkanUseFlag> VulkanUseFlags;
  20. BS_FLAGS_OPERATORS(VulkanUseFlag);
  21. /**
  22. * Wraps one or multiple native Vulkan objects. Allows the object usage to be tracked in command buffers, handles
  23. * ownership transitions between different queues, and handles delayed object destruction.
  24. *
  25. * @note Thread safe
  26. */
  27. class VulkanResource
  28. {
  29. public:
  30. VulkanResource(VulkanResourceManager* owner, bool concurrency);
  31. virtual ~VulkanResource();
  32. /**
  33. * Notifies the resource that it is currently bound to a command buffer. Buffer hasn't yet been submitted so the
  34. * resource isn't being used on the GPU yet.
  35. *
  36. * Must eventually be followed by a notifyUsed() or notifyUnbound().
  37. */
  38. void notifyBound();
  39. /**
  40. * Notifies the resource that it is currently being used on the provided command buffer. This means the command
  41. * buffer has actually been submitted to the queue and the resource is used by the GPU.
  42. *
  43. * A resource can only be used by a single command buffer at a time unless resource concurrency is enabled.
  44. *
  45. * Must follow a notifyBound(). Must eventually be followed by a notifyDone().
  46. *
  47. * @param[in] globalQueueIdx Global index of the queue the resource is being used in.
  48. * @param[in] queueFamily Family of the queue the resource is being used in.
  49. * @param[in] useFlags Flags that determine in what way is the resource being used.
  50. */
  51. void notifyUsed(UINT32 globalQueueIdx, UINT32 queueFamily, VulkanUseFlags useFlags);
  52. /**
  53. * Notifies the resource that it is no longer used by on the GPU. This makes the resource usable on other command
  54. * buffers again.
  55. *
  56. * Must follow a notifyUsed().
  57. *
  58. * @param[in] globalQueueIdx Global index of the queue that finished using the resource.
  59. * @param[in] useFlags Use flags that specify how was the resource being used.
  60. */
  61. void notifyDone(UINT32 globalQueueIdx, VulkanUseFlags useFlags);
  62. /**
  63. * Notifies the resource that it is no longer queued on the command buffer. This is similar to notifyDone(), but
  64. * should only be called if resource never got submitted to the GPU (e.g. command buffer was destroyed before
  65. * being submitted).
  66. *
  67. * Must follow a notifyBound() if notifyUsed() wasn't called.
  68. */
  69. void notifyUnbound();
  70. /**
  71. * Checks is the resource currently used on a device.
  72. *
  73. * @note Resource usage is only checked at certain points of the program. This means the resource could be
  74. * done on the device but this method may still report true. If you need to know the latest state
  75. * call VulkanCommandBufferManager::refreshStates() before checking for usage.
  76. */
  77. bool isUsed() const { Lock(mMutex); return mNumUsedHandles > 0; }
  78. /**
  79. * Checks is the resource currently bound to any command buffer.
  80. *
  81. * @note Resource usage is only checked at certain points of the program. This means the resource could be
  82. * done on the device but this method may still report true. If you need to know the latest state
  83. * call VulkanCommandBufferManager::refreshStates() before checking for usage.
  84. */
  85. bool isBound() const { Lock(mMutex); return mNumBoundHandles > 0; }
  86. /**
  87. * Returns the queue family the resource is currently owned by. Returns -1 if owned by no queue.
  88. *
  89. * @note If resource concurrency is enabled, then this value has no meaning as the resource can be used on
  90. * multiple queue families at once.
  91. */
  92. UINT32 getQueueFamily() const { Lock(mMutex); return mQueueFamily; }
  93. /**
  94. * Returns a mask that has bits set for every queue that the resource is currently used (read or written) by.
  95. *
  96. * @param[in] useFlags Flags for which to check use information (e.g. read only, write only, or both).
  97. * @return Bitmask of which queues is the resource used on. This has the same format as sync mask
  98. * created by CommandSyncMask.
  99. */
  100. UINT32 getUseInfo(VulkanUseFlags useFlags) const;
  101. /** Returns on how many command buffers is the buffer currently used on. */
  102. UINT32 getUseCount() const { return mNumUsedHandles; }
  103. /** Returns on how many command buffers is the buffer currently bound on. */
  104. UINT32 getBoundCount() const { return mNumBoundHandles; }
  105. /** Returns true if the resource is only allowed to be used by a single queue family at once. */
  106. bool isExclusive() const { Lock(mMutex); return mState != State::Shared; }
  107. /**
  108. * Destroys the resource and frees its memory. If the resource is currently being used on a device, the
  109. * destruction is delayed until the device is done with it.
  110. */
  111. void destroy();
  112. protected:
  113. /** Possible states of this object. */
  114. enum class State
  115. {
  116. Normal,
  117. Shared,
  118. Destroyed
  119. };
  120. static const UINT32 MAX_UNIQUE_QUEUES = BS_MAX_QUEUES_PER_TYPE * GQT_COUNT;
  121. VulkanResourceManager* mOwner;
  122. UINT32 mQueueFamily;
  123. State mState;
  124. UINT8 mReadUses[MAX_UNIQUE_QUEUES];
  125. UINT8 mWriteUses[MAX_UNIQUE_QUEUES];
  126. UINT32 mNumUsedHandles;
  127. UINT32 mNumBoundHandles;
  128. Mutex mMutex;
  129. };
  130. /**
  131. * Creates and destroys annd VulkanResource%s on a single device.
  132. *
  133. * @note Thread safe
  134. */
  135. class VulkanResourceManager
  136. {
  137. public:
  138. VulkanResourceManager(VulkanDevice& device);
  139. ~VulkanResourceManager();
  140. /**
  141. * Creates a new Vulkan resource of the specified type. User must call VulkanResource::destroy() when done using
  142. * the resource.
  143. */
  144. template<class Type, class... Args>
  145. Type* create(Args &&...args)
  146. {
  147. Type* resource = new (bs_alloc(sizeof(Type))) Type(this, std::forward<Args>(args)...);
  148. #if BS_DEBUG_MODE
  149. Lock lock(mMutex);
  150. mResources.insert(resource);
  151. #endif
  152. return resource;
  153. }
  154. /** Returns the device that owns this manager. */
  155. VulkanDevice& getDevice() const { return mDevice; }
  156. private:
  157. friend VulkanResource;
  158. /**
  159. * Destroys a previously created Vulkan resource. Caller must ensure the resource is not currently being used
  160. * on the device.
  161. */
  162. void destroy(VulkanResource* resource);
  163. VulkanDevice& mDevice;
  164. #if BS_DEBUG_MODE
  165. UnorderedSet<VulkanResource*> mResources;
  166. Mutex mMutex;
  167. #endif
  168. };
  169. /** @} */
  170. }}