BsResourceHandle.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. //********************************** Banshee Engine (www.banshee3d.com) **************************************************//
  2. //**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
  3. #pragma once
  4. #include "BsIReflectable.h"
  5. namespace BansheeEngine
  6. {
  7. /** @addtogroup Implementation
  8. * @{
  9. */
  10. /** Data that is shared between all resource handles. */
  11. struct BS_CORE_EXPORT ResourceHandleData
  12. {
  13. ResourceHandleData()
  14. :mIsCreated(false), mRefCount(0)
  15. { }
  16. SPtr<Resource> mPtr;
  17. String mUUID;
  18. bool mIsCreated;
  19. UINT32 mRefCount;
  20. };
  21. /**
  22. * Represents a handle to a resource. Handles are similar to a smart pointers, but they have two advantages:
  23. * - When loading a resource asynchronously you can be immediately returned the handle that you may use throughout
  24. * the engine. The handle will be made valid as soon as the resource is loaded.
  25. * - Handles can be serialized and deserialized, therefore saving/restoring references to their original resource.
  26. */
  27. class BS_CORE_EXPORT ResourceHandleBase : public IReflectable
  28. {
  29. public:
  30. virtual ~ResourceHandleBase();
  31. /**
  32. * Checks if the resource is loaded. Until resource is loaded this handle is invalid and you may not get the
  33. * internal resource from it.
  34. *
  35. * @param[in] checkDependencies If true, and if resource has any dependencies, this method will also check if
  36. * they are loaded.
  37. */
  38. bool isLoaded(bool checkDependencies = true) const;
  39. /**
  40. * Blocks the current thread until the resource is fully loaded.
  41. *
  42. * @note Careful not to call this on the thread that does the loading.
  43. */
  44. void blockUntilLoaded(bool waitForDependencies = true) const;
  45. /**
  46. * Releases an internal reference to this resource held by the resources system, if there is one.
  47. *
  48. * @see Resources::release(ResourceHandleBase&)
  49. */
  50. void release();
  51. /** Returns the UUID of the resource the handle is referring to. */
  52. const String& getUUID() const { return mData != nullptr ? mData->mUUID : StringUtil::BLANK; }
  53. public: // ***** INTERNAL ******
  54. /** @name Internal
  55. * @{
  56. */
  57. /** Gets the handle data. For internal use only. */
  58. const SPtr<ResourceHandleData>& getHandleData() const { return mData; }
  59. /** @} */
  60. protected:
  61. ResourceHandleBase();
  62. /** Destroys the resource the handle is pointing to. */
  63. void destroy();
  64. /**
  65. * Sets the created flag to true and assigns the resource pointer. Called by the constructors, or if you
  66. * constructed just using a UUID, then you need to call this manually before you can access the resource from
  67. * this handle.
  68. *
  69. * @note
  70. * This is needed because two part construction is required due to multithreaded nature of resource loading.
  71. * @note
  72. * Internal method.
  73. */
  74. void setHandleData(const SPtr<Resource>& ptr, const String& uuid);
  75. /** Increments the reference count of the handle. Only to be used by Resources for keeping internal references. */
  76. void addInternalRef();
  77. /** Decrements the reference count of the handle. Only to be used by ::Resources for keeping internal references. */
  78. void removeInternalRef();
  79. /**
  80. * @note
  81. * All handles to the same source must share this same handle data. Otherwise things like counting number of
  82. * references or replacing pointed to resource become impossible without additional logic. */
  83. SPtr<ResourceHandleData> mData;
  84. private:
  85. friend class Resources;
  86. BS_STATIC_THREAD_SYNCHRONISER(mResourceCreatedCondition)
  87. BS_STATIC_MUTEX(mResourceCreatedMutex)
  88. protected:
  89. inline void throwIfNotLoaded() const;
  90. };
  91. /**
  92. * @copydoc ResourceHandleBase
  93. *
  94. * Handles differences in reference counting depending if the handle is normal or weak.
  95. */
  96. template <bool WeakHandle>
  97. class BS_CORE_EXPORT TResourceHandleBase : public ResourceHandleBase { };
  98. /** Specialization of TResourceHandleBase for weak handles. Weak handles do no reference counting. */
  99. template<>
  100. class BS_CORE_EXPORT TResourceHandleBase<true> : public ResourceHandleBase
  101. {
  102. public:
  103. virtual ~TResourceHandleBase() { }
  104. protected:
  105. void addRef() { };
  106. void releaseRef() { };
  107. /************************************************************************/
  108. /* RTTI */
  109. /************************************************************************/
  110. public:
  111. friend class WeakResourceHandleRTTI;
  112. static RTTITypeBase* getRTTIStatic();
  113. virtual RTTITypeBase* getRTTI() const override;
  114. };
  115. /** Specialization of TResourceHandleBase for normal (non-weak) handles. */
  116. template<>
  117. class BS_CORE_EXPORT TResourceHandleBase<false> : public ResourceHandleBase
  118. {
  119. public:
  120. virtual ~TResourceHandleBase() { }
  121. protected:
  122. void addRef() { if (mData) mData->mRefCount++; };
  123. void releaseRef()
  124. {
  125. if (mData)
  126. {
  127. mData->mRefCount--;
  128. if (mData->mRefCount == 0)
  129. destroy();
  130. }
  131. };
  132. /************************************************************************/
  133. /* RTTI */
  134. /************************************************************************/
  135. public:
  136. friend class WeakResourceHandleRTTI;
  137. friend class ResourceHandleRTTI;
  138. static RTTITypeBase* getRTTIStatic();
  139. virtual RTTITypeBase* getRTTI() const override;
  140. };
  141. /** @copydoc ResourceHandleBase */
  142. template <typename T, bool WeakHandle>
  143. class TResourceHandle : public TResourceHandleBase<WeakHandle>
  144. {
  145. public:
  146. TResourceHandle()
  147. :TResourceHandleBase()
  148. { }
  149. /** Copy constructor. */
  150. TResourceHandle(const TResourceHandle<T, WeakHandle>& ptr)
  151. :TResourceHandleBase()
  152. {
  153. mData = ptr.getHandleData();
  154. addRef();
  155. }
  156. virtual ~TResourceHandle()
  157. {
  158. releaseRef();
  159. }
  160. /** Converts a specific handle to generic Resource handle. */
  161. operator TResourceHandle<Resource, WeakHandle>() const
  162. {
  163. TResourceHandle<Resource, WeakHandle> handle;
  164. handle.setHandleData(getHandleData());
  165. return handle;
  166. }
  167. /**
  168. * Returns internal resource pointer.
  169. *
  170. * @note Throws exception if handle is invalid.
  171. */
  172. T* operator->() const { return get(); }
  173. /**
  174. * Returns internal resource pointer and dereferences it.
  175. *
  176. * @note Throws exception if handle is invalid.
  177. */
  178. T& operator*() const { return *get(); }
  179. /** Clears the handle making it invalid and releases any references held to the resource. */
  180. TResourceHandle<T, WeakHandle>& operator=(std::nullptr_t ptr)
  181. {
  182. releaseRef();
  183. mData = nullptr;
  184. return *this;
  185. }
  186. /** Normal assignment operator. */
  187. TResourceHandle<T, WeakHandle>& operator=(const TResourceHandle<T, WeakHandle>& rhs)
  188. {
  189. setHandleData(rhs.getHandleData());
  190. return *this;
  191. }
  192. template<class _Ty>
  193. struct Bool_struct
  194. {
  195. int _Member;
  196. };
  197. /**
  198. * Allows direct conversion of handle to bool.
  199. *
  200. * @note This is needed because we can't directly convert to bool since then we can assign pointer to bool and
  201. * that's weird.
  202. */
  203. operator int Bool_struct<T>::*() const
  204. {
  205. return ((mData != nullptr && !mData->mUUID.empty()) ? &Bool_struct<T>::_Member : 0);
  206. }
  207. /**
  208. * Returns internal resource pointer and dereferences it.
  209. *
  210. * @note Throws exception if handle is invalid.
  211. */
  212. T* get() const
  213. {
  214. throwIfNotLoaded();
  215. return reinterpret_cast<T*>(mData->mPtr.get());
  216. }
  217. /**
  218. * Returns the internal shared pointer to the resource.
  219. *
  220. * @note Throws exception if handle is invalid.
  221. */
  222. SPtr<T> getInternalPtr() const
  223. {
  224. throwIfNotLoaded();
  225. return std::static_pointer_cast<T>(mData->mPtr);
  226. }
  227. /** Converts a handle into a weak handle. */
  228. TResourceHandle<T, true> getWeak() const
  229. {
  230. TResourceHandle<T, true> handle;
  231. handle.setHandleData(getHandleData());
  232. return handle;
  233. }
  234. protected:
  235. friend Resources;
  236. template<class _T, bool _Weak>
  237. friend class TResourceHandle;
  238. template<class _Ty1, class _Ty2, bool Weak>
  239. friend TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other);
  240. /**
  241. * Constructs a new valid handle for the provided resource with the provided UUID.
  242. *
  243. * @note Handle will take ownership of the provided resource pointer, so make sure you don't delete it elsewhere.
  244. */
  245. explicit TResourceHandle(T* ptr, const String& uuid)
  246. :TResourceHandleBase()
  247. {
  248. mData = bs_shared_ptr_new<ResourceHandleData>();
  249. addRef();
  250. setHandleData(std::shared_ptr<Resource>(ptr, uuid));
  251. }
  252. /**
  253. * Constructs an invalid handle with the specified UUID. You must call setHandleData() with the actual resource
  254. * pointer to make the handle valid.
  255. */
  256. TResourceHandle(const String& uuid)
  257. :TResourceHandleBase()
  258. {
  259. mData = bs_shared_ptr_new<ResourceHandleData>();
  260. mData->mUUID = uuid;
  261. addRef();
  262. }
  263. /** Constructs a new valid handle for the provided resource with the provided UUID. */
  264. TResourceHandle(const SPtr<T> ptr, const String& uuid)
  265. :TResourceHandleBase()
  266. {
  267. mData = bs_shared_ptr_new<ResourceHandleData>();
  268. addRef();
  269. setHandleData(ptr, uuid);
  270. }
  271. /** Replaces the internal handle data pointer, effectively transforming the handle into a different handle. */
  272. void setHandleData(const SPtr<ResourceHandleData>& data)
  273. {
  274. releaseRef();
  275. mData = data;
  276. addRef();
  277. }
  278. /** Converts a weak handle into a normal handle. */
  279. TResourceHandle<T, false> lock() const
  280. {
  281. TResourceHandle<Resource, false> handle;
  282. handle.setHandleData(getHandleData());
  283. return handle;
  284. }
  285. using TResourceHandleBase::setHandleData;
  286. };
  287. /** Checks if two handles point to the same resource. */
  288. template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
  289. bool operator==(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
  290. {
  291. if(_Left.getHandleData() != nullptr && _Right.getHandleData() != nullptr)
  292. return _Left.getHandleData()->mPtr == _Right.getHandleData()->mPtr;
  293. return _Left.getHandleData() == _Right.getHandleData();
  294. }
  295. /** Checks if a handle is null. */
  296. template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
  297. bool operator==(const TResourceHandle<_Ty1, _Weak1>& _Left, std::nullptr_t _Right)
  298. {
  299. return _Left.getHandleData() == nullptr || _Left.getHandleData()->mUUID.empty();
  300. }
  301. template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
  302. bool operator!=(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
  303. {
  304. return (!(_Left == _Right));
  305. }
  306. /** @} */
  307. /** @addtogroup Resources
  308. * @{
  309. */
  310. /** @copydoc ResourceHandleBase */
  311. template <typename T>
  312. using ResourceHandle = TResourceHandle<T, false>;
  313. /**
  314. * @copydoc ResourceHandleBase
  315. *
  316. * Weak handles don't prevent the resource from being unloaded.
  317. */
  318. template <typename T>
  319. using WeakResourceHandle = TResourceHandle<T, true>;
  320. /** Casts one resource handle to another. */
  321. template<class _Ty1, class _Ty2, bool Weak>
  322. TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other)
  323. {
  324. TResourceHandle<_Ty1, Weak> handle;
  325. handle.setHandleData(other.getHandleData());
  326. return handle;
  327. }
  328. /** @} */
  329. }