BsResourceHandle.h 11 KB

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