BsCoreObject.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #pragma once
  2. #include "BsCorePrerequisites.h"
  3. #include "BsAsyncOp.h"
  4. namespace BansheeEngine
  5. {
  6. /**
  7. * @brief This class provides some common functionality that all low-level objects
  8. * used on the core thread need to implement.
  9. *
  10. * @note This involves initializing, keeping track of, and releasing GPU resources.
  11. * All core GPU objects are initialized on the core thread, and destroyed on the core thread,
  12. * so majority of these methods will just schedule object initialization/destruction.
  13. * Non-GPU core objects can normally be initialized on the caller thread.
  14. */
  15. class BS_CORE_EXPORT CoreObject
  16. {
  17. protected:
  18. /**
  19. * @brief Values that represent current state of the object
  20. */
  21. enum Flags
  22. {
  23. CGO_INITIALIZED = 0x01, /**< Object has been fully initialized and may be used. */
  24. CGO_INIT_ON_CORE_THREAD = 0x02, /**< Object requires initialization on core thread. */
  25. CGO_SCHEDULED_FOR_INIT = 0x04, /**< Object has been scheduled for initialization but core thread has not completed it yet. */
  26. CGO_SCHEDULED_FOR_DELETE = 0x08 /**< Object has been scheduled for deletion but core thread has not completed it yet. */
  27. };
  28. public:
  29. /**
  30. * @brief Constructs a new core object.
  31. *
  32. * @param requiresGpuInit (optional) If true the objects initialize_internal and destroy_internal methods
  33. * will be called from the core thread asynchronously. Otherwise they will be called
  34. * by the caller thread synchronously.
  35. */
  36. CoreObject(bool requiresGpuInit = true);
  37. virtual ~CoreObject();
  38. /**
  39. * @brief Destroys all GPU resources of this object.
  40. *
  41. * @note If is created with "CGO_INIT_ON_CORE_THREAD" flag destruction is not done immediately,
  42. * and is instead just scheduled on the core thread.
  43. * Unless called from core thread in which case it is executed immediately.
  44. * Objects without "CGO_INIT_ON_CORE_THREAD" flag are destructed immediately.
  45. */
  46. virtual void destroy();
  47. /**
  48. * @brief Initializes all the internal resources of this object. Should be called by the
  49. * factory creation methods automatically after construction and not by user directly.
  50. *
  51. * @note If is created with "CGO_INIT_ON_CORE_THREAD" flag initialization is not done immediately,
  52. * and is instead just scheduled on the core thread.
  53. * Unless called from core thread in which case it is executed immediately.
  54. * Objects without "CGO_INIT_ON_CORE_THREAD" flag are initialized immediately.
  55. */
  56. virtual void initialize();
  57. /**
  58. * @brief Returns true if the object has been properly initialized. You are not
  59. * allowed to call any methods on the resource until you are sure resource is initialized.
  60. *
  61. * @note Normally CPU objects are initialized on creation and this will never be false, and GPU
  62. * objects are initialized when the core thread processes them.
  63. */
  64. bool isInitialized() const { return (mFlags & CGO_INITIALIZED) != 0; }
  65. /**
  66. * @brief Blocks the current thread until the resource is fully initialized.
  67. *
  68. * @note If you call this without calling initialize first a deadlock will occur.
  69. * You should not call this from core thread.
  70. */
  71. void synchronize();
  72. /**
  73. * @brief Internal method. Sets a shared this pointer to this object. This MUST be called immediately after construction.
  74. *
  75. * @note Called automatically by the factory creation methods so user should not call this manually.
  76. */
  77. void _setThisPtr(std::shared_ptr<CoreObject> ptrThis);
  78. /**
  79. * @brief Returns an unique identifier for this object.
  80. */
  81. UINT64 getInternalID() const { return mInternalID; }
  82. /**
  83. * @brief Internal method. Schedules the object to be destroyed, and then deleted.
  84. */
  85. template<class T, class MemAlloc>
  86. static void _deleteDelayed(CoreObject* obj)
  87. {
  88. _deleteDelayedInternal(obj);
  89. if(obj->isInitialized())
  90. {
  91. std::shared_ptr<CoreObject> thisPtr(obj);
  92. obj->_setThisPtr(thisPtr);
  93. obj->destroy();
  94. }
  95. else
  96. {
  97. bs_delete<MemAlloc, T>((T*)obj);
  98. }
  99. }
  100. /**
  101. * @brief Returns a shared_ptr version of "this" pointer.
  102. */
  103. std::shared_ptr<CoreObject> getThisPtr() const { return mThis.lock(); }
  104. protected:
  105. /**
  106. * @brief Frees all of the objects dynamically allocated memory. All derived classes that have something to free
  107. * should do it here instead of their destructor. All derived classes need to call this base method when they're done.
  108. *
  109. * @note For objects with "CGO_INIT_ON_CORE_THREAD" flag this is scheduled to be executed on the core thread,
  110. * so normally you want to destroy all GPU specific resources here.
  111. */
  112. virtual void destroy_internal();
  113. /**
  114. * @brief Initializes all the internal resources of this object. Needs to be called before doing
  115. * any operations with the object. All derived classes also need to call this base method.
  116. *
  117. * @note For objects with "CGO_INIT_ON_CORE_THREAD" flag this is scheduled to be executed on the core thread,
  118. * so normally you want to initialize all GPU specific resources here.
  119. */
  120. virtual void initialize_internal();
  121. /**
  122. * @brief Performs some internal checks when an object is being deleted.
  123. */
  124. static void _deleteDelayedInternal(CoreObject* obj);
  125. /**
  126. * @brief Queues a command to be executed on the core thread, without a return value.
  127. *
  128. * @note Requires a shared pointer to the object this function will be executed on, in order to
  129. * make sure the object is not deleted before the command executes. Can be null if the
  130. * function is static or global.
  131. */
  132. static void queueGpuCommand(std::shared_ptr<CoreObject>& obj, std::function<void()> func);
  133. /**
  134. * @brief Queues a command to be executed on the core thread, with a return value in the form of AsyncOp.
  135. *
  136. * @see AsyncOp
  137. *
  138. * @note Requires a shared pointer to the object this function will be executed on, in order to
  139. * make sure the object is not deleted before the command executes. Can be null if the
  140. * function is static or global.
  141. */
  142. static AsyncOp queueReturnGpuCommand(std::shared_ptr<CoreObject>& obj, std::function<void(AsyncOp&)> func);
  143. bool isScheduledToBeInitialized() const { return (mFlags & CGO_SCHEDULED_FOR_INIT) != 0; }
  144. bool isScheduledToBeDeleted() const { return (mFlags & CGO_SCHEDULED_FOR_DELETE) != 0; }
  145. bool requiresInitOnCoreThread() const { return (mFlags & CGO_INIT_ON_CORE_THREAD) != 0; }
  146. void setIsInitialized(bool initialized) { mFlags = initialized ? mFlags | CGO_INITIALIZED : mFlags & ~CGO_INITIALIZED; }
  147. void setScheduledToBeInitialized(bool scheduled) { mFlags = scheduled ? mFlags | CGO_SCHEDULED_FOR_INIT : mFlags & ~CGO_SCHEDULED_FOR_INIT; }
  148. void setScheduledToBeDeleted(bool scheduled) { mFlags = scheduled ? mFlags | CGO_SCHEDULED_FOR_DELETE : mFlags & ~CGO_SCHEDULED_FOR_DELETE; }
  149. private:
  150. friend class CoreObjectManager;
  151. volatile UINT8 mFlags;
  152. UINT64 mInternalID; // ID == 0 is not a valid ID
  153. std::weak_ptr<CoreObject> mThis;
  154. BS_STATIC_THREAD_SYNCHRONISER(mCoreGpuObjectLoadedCondition)
  155. BS_STATIC_MUTEX(mCoreGpuObjectLoadedMutex)
  156. /**
  157. * @brief Queues object initialization command on the core thread. The command is added to the
  158. * primary core thread queue and will be executed as soon as the core thread is ready.
  159. */
  160. static void queueInitializeGpuCommand(std::shared_ptr<CoreObject>& obj);
  161. /**
  162. * @brief Queues object destruction command on the core thread. The command is added to the
  163. * core thread accessor of this thread and will be executed after accessor commands
  164. * are submitted and any previously queued commands are executed.
  165. *
  166. * @note It is up to the caller to ensure no other accessors attempt to use this object.
  167. */
  168. static void queueDestroyGpuCommand(std::shared_ptr<CoreObject>& obj);
  169. /**
  170. * @brief Helper wrapper method used for queuing commands with no return value on the core thread.
  171. */
  172. static void executeGpuCommand(std::shared_ptr<CoreObject> obj, std::function<void()> func);
  173. /**
  174. * @brief Helper wrapper method used for queuing commands with a return value on the core thread.
  175. */
  176. static void executeReturnGpuCommand(std::shared_ptr<CoreObject> obj, std::function<void(AsyncOp&)> func, AsyncOp& op);
  177. };
  178. /**
  179. * @brief Creates a new core object using the specified allocators and returns a shared pointer to it.
  180. *
  181. * @note All core thread object shared pointers must be created using this method or its overloads
  182. * and you should not create them manually.
  183. */
  184. template<class Type, class MainAlloc, class PtrDataAlloc, class... Args>
  185. std::shared_ptr<Type> bs_core_ptr(Args &&...args)
  186. {
  187. return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
  188. &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<PtrDataAlloc>());
  189. }
  190. /**
  191. * @brief Creates a new core object using the specified allocator and returns a shared pointer to it.
  192. *
  193. * @note All core thread object shared pointers must be created using this method or its overloads
  194. * and you should not create them manually.
  195. */
  196. template<class Type, class MainAlloc, class... Args>
  197. std::shared_ptr<Type> bs_core_ptr(Args &&...args)
  198. {
  199. return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
  200. &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<GenAlloc>());
  201. }
  202. /**
  203. * @brief Creates a new core object and returns a shared pointer to it.
  204. *
  205. * @note All core thread object shared pointers must be created using this method or its overloads
  206. * and you should not create them manually.
  207. */
  208. template<class Type, class... Args>
  209. std::shared_ptr<Type> bs_core_ptr(Args &&...args)
  210. {
  211. return std::shared_ptr<Type>(bs_new<Type, GenAlloc>(std::forward<Args>(args)...),
  212. &CoreObject::_deleteDelayed<Type, GenAlloc>, StdAlloc<GenAlloc>());
  213. }
  214. /**
  215. * @brief Creates a core object shared pointer using a previously constructed object.
  216. *
  217. * @note All core thread object shared pointers must be created using this method or its overloads
  218. * and you should not create them manually.
  219. */
  220. template<class Type, class MainAlloc>
  221. std::shared_ptr<Type> bs_core_ptr(Type* data)
  222. {
  223. return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<GenAlloc>());
  224. }
  225. /**
  226. * @brief Creates a core object shared pointer using a previously constructed object.
  227. *
  228. * @note All core thread object shared pointers must be created using this method or its overloads
  229. * and you should not create them manually.
  230. */
  231. template<class Type, class MainAlloc, class PtrDataAlloc>
  232. std::shared_ptr<Type> bs_core_ptr(Type* data)
  233. {
  234. return std::shared_ptr<Type>(data, &CoreObject::_deleteDelayed<Type, MainAlloc>, StdAlloc<PtrDataAlloc>());
  235. }
  236. }