Bläddra i källkod

Resource handle refactor (part 2)
- Added separate normal & weak handles

BearishSun 10 år sedan
förälder
incheckning
8e23f57d9d

+ 2 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -358,7 +358,8 @@ namespace BansheeEngine
 		TID_StringTable = 1083,
 		TID_LanguageData = 1084,
 		TID_LocalizedStringData = 1085,
-		TID_MaterialParamColor = 1086
+		TID_MaterialParamColor = 1086,
+		TID_WeakResourceHandle = 1087,
 	};
 }
 

+ 91 - 51
BansheeCore/Include/BsResourceHandle.h

@@ -4,9 +4,6 @@
 
 namespace BansheeEngine
 {
-	template <typename T>
-	class ResourceHandle;
-
 	/**
 	 * @brief	Data that is shared between all resource handles.
 	 */
@@ -83,11 +80,56 @@ namespace BansheeEngine
 
 	protected:
 		inline void throwIfNotLoaded() const;
+	};
+
+	/**
+	 * @copydoc	ResourceHandleBase
+	 *
+	 * Handles differences in reference counting depending if the handle is normal or weak.
+	 */
+	template <bool WeakHandle>
+	class BS_CORE_EXPORT TResourceHandleBase : public ResourceHandleBase { };
+
+	/**
+	 * @brief	Specialization of TResourceHandleBase for weak handles. Weak handles do no reference counting.
+	 */
+	template<>
+	class BS_CORE_EXPORT TResourceHandleBase<true> : public ResourceHandleBase
+	{
+	public:
+		virtual ~TResourceHandleBase() { }
+
+	protected:
+		void addRef() { };
+		void releaseRef() { };
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
 		/************************************************************************/
 	public:
+		friend class WeakResourceHandleRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const override;
+	};
+
+	/**
+	 * @brief	Specialization of TResourceHandleBase for normal (non-weak) handles.
+	 */
+	template<>
+	class BS_CORE_EXPORT TResourceHandleBase<false> : public ResourceHandleBase
+	{
+	public:
+		virtual ~TResourceHandleBase() { }
+
+	protected:
+		void addRef() { if (mData) mData->mRefCount++; };
+		void releaseRef() { if (mData) mData->mRefCount--; };
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class WeakResourceHandleRTTI;
 		friend class ResourceHandleRTTI;
 		static RTTITypeBase* getRTTIStatic();
 		virtual RTTITypeBase* getRTTI() const override;
@@ -101,38 +143,36 @@ namespace BansheeEngine
 	 *				- Handles can be serialized and deserialized, therefore saving/restoring references
 	 *				  to their original resource.
 	 */
-	template <typename T>
-	class ResourceHandle : public ResourceHandleBase
+	template <typename T, bool WeakHandle>
+	class TResourceHandle : public TResourceHandleBase<WeakHandle>
 	{
 	public:
-		ResourceHandle()
-			:ResourceHandleBase()
+		TResourceHandle()
+			:TResourceHandleBase()
 		{ }
 
 		/**
 		 * @brief	Copy constructor.
 		 */
-		ResourceHandle(const ResourceHandle<T>& ptr)
-			:ResourceHandleBase()
+		TResourceHandle(const TResourceHandle<T, WeakHandle>& ptr)
+			:TResourceHandleBase()
 		{
 			mData = ptr.getHandleData();
 
-			if (mData != nullptr)
-				mData->mRefCount++;
+			addRef();
 		}
 
-		~ResourceHandle()
+		virtual ~TResourceHandle()
 		{
-			if (mData != nullptr)
-				mData->mRefCount--;
+			releaseRef();
 		}
 
 		/**
 		 * @brief	Converts a specific handle to generic Resource handle.
 		 */
-		operator ResourceHandle<Resource>() const
+		operator TResourceHandle<Resource, WeakHandle>() const
 		{
-			ResourceHandle<Resource> handle;
+			TResourceHandle<Resource, WeakHandle> handle;
 			handle.setHandleData(getHandleData());
 
 			return handle;
@@ -156,10 +196,9 @@ namespace BansheeEngine
 		 * @brief	Clears the handle making it invalid and releases any references
 		 *			held to the resource.
 		 */
-		ResourceHandle<T>& operator=(std::nullptr_t ptr)
+		TResourceHandle<T, WeakHandle>& operator=(std::nullptr_t ptr)
 		{ 	
-			if (mData != nullptr)
-				mData->mRefCount--;
+			releaseRef();
 
 			mData = nullptr;
 			return *this;
@@ -206,12 +245,12 @@ namespace BansheeEngine
 			return std::static_pointer_cast<T>(mData->mPtr); 
 		}
 
-	private:
-		friend class Resources;
-		template<class _Ty1>
-		friend class ResourceHandle;
-		template<class _Ty1, class _Ty2>
-		friend ResourceHandle<_Ty1> static_resource_cast(const ResourceHandle<_Ty2>& other);
+	protected:
+		friend Resources;
+		template<class _T, bool _Weak>
+		friend class TResourceHandle;
+		template<class _Ty1, class _Ty2, bool Weak>
+		friend TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other);
 
 		/**
 		 * @brief	Constructs a new valid handle for the provided resource with the provided UUID.
@@ -219,11 +258,11 @@ namespace BansheeEngine
 		 * @note	Handle will take ownership of the provided resource pointer, so make sure you don't
 		 *			delete it elsewhere.
 		 */
-		explicit ResourceHandle(T* ptr, const String& uuid)
-			:ResourceHandleBase()
+		explicit TResourceHandle(T* ptr, const String& uuid)
+			:TResourceHandleBase()
 		{
 			mData = bs_shared_ptr_new<ResourceHandleData>();
-			mData->mRefCount++;
+			addRef();
 
 			setHandleData(std::shared_ptr<Resource>(ptr, uuid));
 		}
@@ -232,52 +271,53 @@ namespace BansheeEngine
 		 * @brief	Constructs an invalid handle with the specified UUID. You must call setHandleData
 		 *			with the actual resource pointer to make the handle valid.
 		 */
-		ResourceHandle(const String& uuid)
-			:ResourceHandleBase()
+		TResourceHandle(const String& uuid)
+			:TResourceHandleBase()
 		{
 			mData = bs_shared_ptr_new<ResourceHandleData>();
-			mData->mRefCount++;
 			mData->mUUID = uuid;
+
+			addRef();
 		}
 
 		/**
 		 * @brief	Constructs a new valid handle for the provided resource with the provided UUID.
 		 */
-		ResourceHandle(std::shared_ptr<T> ptr, const String& uuid)
-			:ResourceHandleBase()
+		TResourceHandle(const SPtr<T> ptr, const String& uuid)
+			:TResourceHandleBase()
 		{
 			mData = bs_shared_ptr_new<ResourceHandleData>();
-			mData->mRefCount++;
+			addRef();
 
 			setHandleData(ptr, uuid);
 		}
 
 		/**
-		 * @brief	Sets the internal handle data to another previously created data.
-		 *
-		 * @note	Internal method.
+		 * @brief	Replaces the internal handle data pointer, effectively transforming the handle into a different handle.
 		 */
 		void setHandleData(const SPtr<ResourceHandleData>& data)
 		{
-			if (mData != nullptr)
-				mData->mRefCount--;
-
+			releaseRef();
 			mData = data;
-
-			if (mData != nullptr)
-				mData->mRefCount++;
+			addRef();
 		}
 
-		using ResourceHandleBase::setHandleData;
+		using TResourceHandleBase::setHandleData;
 	};
 
+	template <typename T>
+	using ResourceHandle = TResourceHandle<T, false>;
+
+	template <typename T>
+	using WeakResourceHandle = TResourceHandle<T, true>;
+	
 	/**
 	 * @brief	Casts one resource handle to another.
 	 */
-	template<class _Ty1, class _Ty2>
-		ResourceHandle<_Ty1> static_resource_cast(const ResourceHandle<_Ty2>& other)
+	template<class _Ty1, class _Ty2, bool Weak>
+	TResourceHandle<_Ty1, Weak> static_resource_cast(const TResourceHandle<_Ty2, Weak>& other)
 	{	
-		ResourceHandle<_Ty1> handle;
+		TResourceHandle<_Ty1, Weak> handle;
 		handle.setHandleData(other.getHandleData());
 
 		return handle;
@@ -286,8 +326,8 @@ namespace BansheeEngine
 	/**
 	 * @brief	Checks if two handles point to the same resource.
 	 */
-	template<class _Ty1, class _Ty2>
-	bool operator==(const ResourceHandle<_Ty1>& _Left, const ResourceHandle<_Ty2>& _Right)
+	template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
+	bool operator==(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
 	{	
 		if(_Left.getHandleData() != nullptr && _Right.getHandleData() != nullptr)
 			return _Left.getHandleData()->mPtr == _Right.getHandleData()->mPtr;
@@ -295,8 +335,8 @@ namespace BansheeEngine
 		return _Left.getHandleData() == _Right.getHandleData();
 	}
 
-	template<class _Ty1, class _Ty2>
-	bool operator!=(const ResourceHandle<_Ty1>& _Left, const ResourceHandle<_Ty2>& _Right)
+	template<class _Ty1, bool _Weak1, class _Ty2, bool _Weak2>
+	bool operator!=(const TResourceHandle<_Ty1, _Weak1>& _Left, const TResourceHandle<_Ty2, _Weak2>& _Right)
 	{	
 		return (!(_Left == _Right));
 	}

+ 57 - 11
BansheeCore/Include/BsResourceHandleRTTI.h

@@ -7,17 +7,17 @@
 
 namespace BansheeEngine
 {
-	class BS_CORE_EXPORT ResourceHandleRTTI : public RTTIType<ResourceHandleBase, IReflectable, ResourceHandleRTTI>
+	class BS_CORE_EXPORT ResourceHandleRTTI : public RTTIType<TResourceHandleBase<false>, IReflectable, ResourceHandleRTTI>
 	{
 	private:
-		String& getUUID(ResourceHandleBase* obj) 
+		String& getUUID(TResourceHandleBase<false>* obj)
 		{ 
 			static String Blank = "";
 
 			return obj->mData != nullptr ? obj->mData->mUUID : Blank; 
 		}
 
-		void setUUID(ResourceHandleBase* obj, String& uuid) { obj->mData->mUUID = uuid; } 
+		void setUUID(TResourceHandleBase<false>* obj, String& uuid) { obj->mData->mUUID = uuid; }
 	public:
 		ResourceHandleRTTI()
 		{
@@ -26,19 +26,15 @@ namespace BansheeEngine
 
 		void onDeserializationEnded(IReflectable* obj) override
 		{
-			ResourceHandleBase* resourceHandle = static_cast<ResourceHandleBase*>(obj);
+			TResourceHandleBase<false>* resourceHandle = static_cast<TResourceHandleBase<false>*>(obj);
 
 			if(resourceHandle->mData && resourceHandle->mData->mUUID != "")
 			{
 				HResource loadedResource = gResources()._createResourceHandle(resourceHandle->mData->mUUID);
 
-				if (resourceHandle->mData != nullptr)
-					resourceHandle->mData->mRefCount--;
-
+				resourceHandle->releaseRef();
 				resourceHandle->mData = loadedResource.mData;
-
-				if (resourceHandle->mData != nullptr)
-					resourceHandle->mData->mRefCount++;
+				resourceHandle->addRef();
 			}
 		}
 
@@ -55,11 +51,61 @@ namespace BansheeEngine
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() override
 		{
-			std::shared_ptr<ResourceHandleBase> obj = bs_shared_ptr<ResourceHandleBase>(new (bs_alloc<ResourceHandleBase>()) ResourceHandleBase());
+			SPtr<TResourceHandleBase<false>> obj = bs_shared_ptr<TResourceHandleBase<false>>
+				(new (bs_alloc<TResourceHandleBase<false>>()) TResourceHandleBase<false>());
 			obj->mData = bs_shared_ptr_new<ResourceHandleData>();
 			obj->mData->mRefCount++;
 
 			return obj;
 		}
 	};
+
+	class BS_CORE_EXPORT WeakResourceHandleRTTI : public RTTIType<TResourceHandleBase<true>, IReflectable, WeakResourceHandleRTTI>
+	{
+	private:
+		String& getUUID(TResourceHandleBase<true>* obj)
+		{
+			static String Blank = "";
+
+			return obj->mData != nullptr ? obj->mData->mUUID : Blank;
+		}
+
+		void setUUID(TResourceHandleBase<true>* obj, String& uuid) { obj->mData->mUUID = uuid; }
+	public:
+		WeakResourceHandleRTTI()
+		{
+			addPlainField("mUUID", 0, &WeakResourceHandleRTTI::getUUID, &WeakResourceHandleRTTI::setUUID);
+		}
+
+		void onDeserializationEnded(IReflectable* obj) override
+		{
+			TResourceHandleBase<true>* resourceHandle = static_cast<TResourceHandleBase<true>*>(obj);
+
+			if (resourceHandle->mData && resourceHandle->mData->mUUID != "")
+			{
+				HResource loadedResource = gResources()._createResourceHandle(resourceHandle->mData->mUUID);
+				resourceHandle->mData = loadedResource.mData;
+			}
+		}
+
+		virtual const String& getRTTIName() override
+		{
+			static String name = "WeakResourceHandleBase";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId() override
+		{
+			return TID_WeakResourceHandle;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() override
+		{
+			SPtr<TResourceHandleBase<true>> obj = bs_shared_ptr<TResourceHandleBase<true>>
+				(new (bs_alloc<TResourceHandleBase<true>>()) TResourceHandleBase<true>());
+			obj->mData = bs_shared_ptr_new<ResourceHandleData>();
+
+			return obj;
+		}
+	};
 }

+ 16 - 3
BansheeCore/Source/BsResourceHandle.cpp

@@ -94,13 +94,26 @@ namespace BansheeEngine
 #endif
 	}
 
-	RTTITypeBase* ResourceHandleBase::getRTTIStatic()
+	template class TResourceHandleBase<true>;
+	template class TResourceHandleBase<false>;
+
+	RTTITypeBase* TResourceHandleBase<true>::getRTTIStatic()
+	{
+		return WeakResourceHandleRTTI::instance();
+	}
+
+	RTTITypeBase* TResourceHandleBase<true>::getRTTI() const
+	{
+		return getRTTIStatic();
+	}
+
+	RTTITypeBase* TResourceHandleBase<false>::getRTTIStatic()
 	{
 		return ResourceHandleRTTI::instance();
 	}
 
-	RTTITypeBase* ResourceHandleBase::getRTTI() const
+	RTTITypeBase* TResourceHandleBase<false>::getRTTI() const
 	{
-		return ResourceHandleBase::getRTTIStatic();
+		return getRTTIStatic();
 	}
 }