BsCoreObject.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. #pragma once
  2. #include "BsCorePrerequisites.h"
  3. #include "BsCoreObjectCore.h"
  4. #include "BsAsyncOp.h"
  5. namespace BansheeEngine
  6. {
  7. /**
  8. * @brief This class provides some common functionality that all low-level objects
  9. * used on the core thread need to implement.
  10. *
  11. * @note This involves initializing, keeping track of, and releasing GPU resources.
  12. * All core GPU objects are initialized on the core thread, and destroyed on the core thread,
  13. * so majority of these methods will just schedule object initialization/destruction.
  14. * Non-GPU core objects can normally be initialized on the caller thread.
  15. */
  16. class BS_CORE_EXPORT CoreObject
  17. {
  18. protected:
  19. /**
  20. * @brief Values that represent current state of the object
  21. */
  22. enum Flags
  23. {
  24. CGO_DESTROYED = 0x01, /**< Object has been destroyed and shouldn't be used. */
  25. CGO_INIT_ON_CORE_THREAD = 0x02 /**< Object requires initialization on core thread. */
  26. };
  27. public:
  28. /**
  29. * @brief Constructs a new core object.
  30. *
  31. * @param requiresGpuInit (optional) If true the objects initialize_internal and destroy_internal methods
  32. * will be called from the core thread asynchronously. Otherwise they will be called
  33. * by the caller thread synchronously.
  34. */
  35. CoreObject(bool requiresGpuInit = true);
  36. virtual ~CoreObject();
  37. /**
  38. * @brief Frees all the data held by this object.
  39. *
  40. * @note If is created with "CGO_INIT_ON_CORE_THREAD" flag destruction is not done immediately,
  41. * and is instead just scheduled on the core thread.
  42. * Unless called from core thread in which case it is executed immediately.
  43. * Objects without "CGO_INIT_ON_CORE_THREAD" flag are destructed immediately.
  44. */
  45. virtual void destroy();
  46. /**
  47. * @brief Initializes all the internal resources of this object. Should be called by the
  48. * factory creation methods automatically after construction and not by user directly.
  49. *
  50. * @note If is created with "CGO_INIT_ON_CORE_THREAD" flag initialization is not done immediately,
  51. * and is instead just scheduled on the core thread.
  52. * Unless called from core thread in which case it is executed immediately.
  53. * Objects without "CGO_INIT_ON_CORE_THREAD" flag are initialized immediately.
  54. */
  55. virtual void initialize();
  56. /**
  57. * @brief Returns true if the object has been destroyed. Destroyed object should not be used.
  58. */
  59. bool isDestroyed() const { return (mFlags & CGO_DESTROYED) != 0; }
  60. /**
  61. * @brief Blocks the current thread until the resource is fully initialized.
  62. *
  63. * @note If you call this without calling initialize first a deadlock will occur.
  64. * You should not call this from core thread.
  65. */
  66. void blockUntilCoreInitialized();
  67. /**
  68. * @brief Internal method. Sets a shared this pointer to this object. This MUST be called immediately after construction.
  69. *
  70. * @note Called automatically by the factory creation methods so user should not call this manually.
  71. */
  72. void _setThisPtr(std::shared_ptr<CoreObject> ptrThis);
  73. /**
  74. * @brief Returns an unique identifier for this object.
  75. */
  76. UINT64 getInternalID() const { return mInternalID; }
  77. /**
  78. * @brief Internal method. Schedules the object to be destroyed, and then deleted.
  79. */
  80. template<class T, class MemAlloc>
  81. static void _delete(CoreObject* obj)
  82. {
  83. if (!obj->isDestroyed())
  84. obj->destroy();
  85. bs_delete<T, MemAlloc>((T*)obj);
  86. }
  87. /**
  88. * @brief Returns a shared_ptr version of "this" pointer.
  89. */
  90. SPtr<CoreObject> getThisPtr() const { return mThis.lock(); }
  91. /**
  92. * @brief Returns an object that contains a core thread specific implementation
  93. * of this CoreObject.
  94. *
  95. * @note Thread safe to retrieve, but its data is only valid on the core thread.
  96. */
  97. SPtr<CoreObjectCore> getCore() const { return mCoreSpecific; }
  98. /**
  99. * @brief Ensures all dirty syncable data is send to the core thread variant of this object.
  100. *
  101. * @note Call this if you have modified the object and need to make sure core thread has an up
  102. * to date version. Normally this is done automatically at the end of a frame.
  103. */
  104. void syncToCore(CoreAccessor& accessor);
  105. protected:
  106. /**
  107. * @brief Queues a command to be executed on the core thread, without a return value.
  108. *
  109. * @note Requires a shared pointer to the object this function will be executed on, in order to
  110. * make sure the object is not deleted before the command executes. Can be null if the
  111. * function is static or global.
  112. */
  113. static void queueGpuCommand(const SPtr<CoreObjectCore>& obj, std::function<void()> func);
  114. /**
  115. * @brief Queues a command to be executed on the core thread, with a return value in the form of AsyncOp.
  116. *
  117. * @see AsyncOp
  118. *
  119. * @note Requires a shared pointer to the object this function will be executed on, in order to
  120. * make sure the object is not deleted before the command executes. Can be null if the
  121. * function is static or global.
  122. */
  123. static AsyncOp queueReturnGpuCommand(const SPtr<CoreObjectCore>& obj, std::function<void(AsyncOp&)> func);
  124. bool requiresInitOnCoreThread() const { return (mFlags & CGO_INIT_ON_CORE_THREAD) != 0; }
  125. void setIsDestroyed(bool destroyed) { mFlags = destroyed ? mFlags | CGO_DESTROYED : mFlags & ~CGO_DESTROYED; }
  126. private:
  127. friend class CoreObjectManager;
  128. volatile UINT8 mFlags;
  129. UINT32 mCoreDirtyFlags;
  130. UINT64 mInternalID; // ID == 0 is not a valid ID
  131. std::weak_ptr<CoreObject> mThis;
  132. /**
  133. * @brief Queues object initialization command on the core thread. The command is added to the
  134. * primary core thread queue and will be executed as soon as the core thread is ready.
  135. */
  136. static void queueInitializeGpuCommand(const SPtr<CoreObjectCore>& obj);
  137. /**
  138. * @brief Queues object destruction command on the core thread. The command is added to the
  139. * core thread accessor of this thread and will be executed after accessor commands
  140. * are submitted and any previously queued commands are executed.
  141. *
  142. * @note It is up to the caller to ensure no other accessors attempt to use this object.
  143. */
  144. static void queueDestroyGpuCommand(const SPtr<CoreObjectCore>& obj);
  145. /**
  146. * @brief Helper wrapper method used for queuing commands with no return value on the core thread.
  147. */
  148. static void executeGpuCommand(const SPtr<CoreObjectCore>& obj, std::function<void()> func);
  149. /**
  150. * @brief Helper wrapper method used for queuing commands with a return value on the core thread.
  151. */
  152. static void executeReturnGpuCommand(const SPtr<CoreObjectCore>& obj, std::function<void(AsyncOp&)> func, AsyncOp& op);
  153. protected:
  154. /************************************************************************/
  155. /* CORE OBJECT SYNC */
  156. /************************************************************************/
  157. /**
  158. * @brief Creates an object that contains core thread specific data and methods
  159. * for this CoreObject. Can be null if such object is not required.
  160. */
  161. virtual SPtr<CoreObjectCore> createCore() const { return nullptr; }
  162. /**
  163. * @brief Marks the core data as dirty. This causes the syncToCore()
  164. * method to trigger the next time objects are synced between core and sim threads.
  165. *
  166. * @param flags Optional flags in case you want to signal that only part of the
  167. * internal data is dirty. syncToCore() will be called regardless
  168. * and it's up to the implementation to read the flags value if needed.
  169. */
  170. void markCoreDirty(UINT32 flags = 0xFFFFFFFF) { mCoreDirtyFlags |= flags; }
  171. /**
  172. * @brief Marks the core data as clean. Normally called right after syncToCore()
  173. * has been called.
  174. */
  175. void markCoreClean() { mCoreDirtyFlags = 0; }
  176. /**
  177. * @brief Checks is the core dirty flag set. This is used by external systems
  178. * to know when internal data has changed and core thread potentially needs to be notified.
  179. */
  180. bool isCoreDirty() const { return mCoreDirtyFlags != 0; }
  181. /**
  182. * @brief Returns the exact value of the internal flag that signals whether an object needs to be
  183. * synced with the core thread.
  184. */
  185. UINT32 getCoreDirtyFlags() const { return mCoreDirtyFlags; }
  186. /**
  187. * @brief Copy internal dirty data to a memory buffer that will be used
  188. * for updating core thread version of that data.
  189. *
  190. * @note This generally happens at the end of every sim thread frame. Synced data becomes
  191. * available to the core thread the start of the next core thread frame.
  192. */
  193. virtual CoreSyncData syncToCore(FrameAlloc* allocator) { return CoreSyncData(); }
  194. /**
  195. * @brief Populates the provided array with all core objects that this core object depends upon.
  196. */
  197. virtual void getCoreDependencies(Vector<SPtr<CoreObject>>& dependencies) { }
  198. protected:
  199. SPtr<CoreObjectCore> mCoreSpecific;
  200. };
  201. /**
  202. * @brief Creates a new core object using the specified allocators and returns a shared pointer to it.
  203. *
  204. * @note All core thread object shared pointers must be created using this method or its overloads
  205. * and you should not create them manually.
  206. */
  207. template<class Type, class MainAlloc, class PtrDataAlloc, class... Args>
  208. std::shared_ptr<Type> bs_core_ptr_new(Args &&...args)
  209. {
  210. return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
  211. &CoreObject::_delete<Type, MainAlloc>, StdAlloc<Type, PtrDataAlloc>());
  212. }
  213. /**
  214. * @brief Creates a new core object using the specified allocator and returns a shared pointer to it.
  215. *
  216. * @note All core thread object shared pointers must be created using this method or its overloads
  217. * and you should not create them manually.
  218. */
  219. template<class Type, class MainAlloc, class... Args>
  220. std::shared_ptr<Type> bs_core_ptr_new(Args &&...args)
  221. {
  222. return std::shared_ptr<Type>(bs_new<Type, MainAlloc>(std::forward<Args>(args)...),
  223. &CoreObject::_delete<Type, MainAlloc>, StdAlloc<Type, GenAlloc>());
  224. }
  225. /**
  226. * @brief Creates a new core object and returns a shared pointer to it.
  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... Args>
  232. std::shared_ptr<Type> bs_core_ptr_new(Args &&...args)
  233. {
  234. return std::shared_ptr<Type>(bs_new<Type, GenAlloc>(std::forward<Args>(args)...),
  235. &CoreObject::_delete<Type, GenAlloc>, StdAlloc<Type, GenAlloc>());
  236. }
  237. /**
  238. * @brief Creates a core object shared pointer using a previously constructed object.
  239. *
  240. * @note All core thread object shared pointers must be created using this method or its overloads
  241. * and you should not create them manually.
  242. */
  243. template<class Type, class MainAlloc = GenAlloc, class PtrDataAlloc = GenAlloc>
  244. std::shared_ptr<Type> bs_core_ptr(Type* data)
  245. {
  246. return std::shared_ptr<Type>(data, &CoreObject::_delete<Type, MainAlloc>, StdAlloc<Type, PtrDataAlloc>());
  247. }
  248. }