BsResourceHandle.h 9.6 KB

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