BsResourceHandle.h 11 KB

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