Просмотр исходного кода

Refactor: Resource refs are now cached and offer faster resources access

BearishSun 7 лет назад
Родитель
Сommit
b83d1f3ca1

+ 1 - 2
Source/Scripting/MBansheeEditor/Inspectors/SpriteTextureInspector.cs

@@ -30,8 +30,7 @@ namespace BansheeEditor
 
             textureField.OnChanged += (x) =>
             {
-                Texture texture = Resources.Load<Texture>(x.UUID);
-                spriteTexture.Texture = texture;
+                spriteTexture.Texture = x;
                 EditorApplication.SetDirty(spriteTexture);
             };
 

+ 5 - 5
Source/Scripting/MBansheeEditor/Window/MenuItems.cs

@@ -645,7 +645,7 @@ namespace BansheeEditor
         {
             SceneObject so = UndoRedo.CreateSO("Box", "Created a box");
             Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Box.Ref;
+            renderable.Mesh = Builtin.Box;
 
             Selection.SceneObject = so;
             FocusOnHierarchyOrScene();
@@ -661,7 +661,7 @@ namespace BansheeEditor
         {
             SceneObject so = UndoRedo.CreateSO("Sphere", "Created a sphere");
             Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Sphere.Ref;
+            renderable.Mesh = Builtin.Sphere;
 
             Selection.SceneObject = so;
             FocusOnHierarchyOrScene();
@@ -677,7 +677,7 @@ namespace BansheeEditor
         {
             SceneObject so = UndoRedo.CreateSO("Cone", "Created a cone");
             Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Cone.Ref;
+            renderable.Mesh = Builtin.Cone;
 
             Selection.SceneObject = so;
             FocusOnHierarchyOrScene();
@@ -693,7 +693,7 @@ namespace BansheeEditor
         {
             SceneObject so = UndoRedo.CreateSO("Quad", "Created a quad");
             Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Quad.Ref;
+            renderable.Mesh = Builtin.Quad;
 
             Selection.SceneObject = so;
             FocusOnHierarchyOrScene();
@@ -708,7 +708,7 @@ namespace BansheeEditor
         {
             SceneObject so = UndoRedo.CreateSO("Disc", "Created a disc");
             Renderable renderable = so.AddComponent<Renderable>();
-            renderable.Mesh = Builtin.Disc.Ref;
+            renderable.Mesh = Builtin.Disc;
 
             Selection.SceneObject = so;
             FocusOnHierarchyOrScene();

+ 40 - 3
Source/Scripting/SBansheeEngine/BsScriptResourceManager.cpp

@@ -19,10 +19,12 @@ namespace bs
 	ScriptResourceManager::ScriptResourceManager()
 	{
 		mResourceDestroyedConn = gResources().onResourceDestroyed.connect(std::bind(&ScriptResourceManager::onResourceDestroyed, this, _1));
+		mDomainUnloadedConn = MonoManager::instance().onDomainUnload.connect(std::bind(&ScriptResourceManager::clearRRefs, this));
 	}
 
 	ScriptResourceManager::~ScriptResourceManager()
 	{
+		mDomainUnloadedConn.disconnect();
 		mResourceDestroyedConn.disconnect();
 	}
 
@@ -90,7 +92,15 @@ namespace bs
 
 	ScriptRRefBase* ScriptResourceManager::getScriptRRef(const HResource& resource, ::MonoClass* rrefClass)
 	{
-		return ScriptRRefBase::create(resource, rrefClass);
+		UnorderedMap<UUID, ScriptRRefBase*>& rrefs = mScriptRRefsPerType[rrefClass];
+		const auto iterFind = rrefs.find(resource.getUUID());
+		if (iterFind != rrefs.end())
+			return iterFind->second;
+
+		ScriptRRefBase* newRRef = ScriptRRefBase::create(resource, rrefClass);
+		rrefs[resource.getUUID()] = newRRef;
+
+		return newRRef;
 	}
 
 	void ScriptResourceManager::destroyScriptResource(ScriptResourceBase* resource)
@@ -101,15 +111,37 @@ namespace bs
 		if(uuid.empty())
 			BS_EXCEPT(InvalidParametersException, "Provided resource handle has an undefined resource UUID.");
 
+#if BS_DEBUG_MODE
+		for(auto& kvp : mScriptRRefsPerType)
+		{
+			UnorderedMap<UUID, ScriptRRefBase*>& rrefs = kvp.second;
+
+			// No handles should exist at this point because we only manually free the ScriptResourceBase object if the
+			// native resource is destroyed, which we handle in onResourceDestroyed. And only other destruction should
+			// happen during assembly refresh, which we handled in clearRRefs().
+			const auto iterFind = rrefs.find(uuid);
+			assert(iterFind == rrefs.end());
+		}
+#endif
+
 		(resource)->~ScriptResourceBase();
 		MemoryAllocator<GenAlloc>::free(resource);
 
 		mScriptResources.erase(uuid);
 	}
 
-	void ScriptResourceManager::onResourceDestroyed(const UUID& UUID)
+	void ScriptResourceManager::onResourceDestroyed(const UUID& uuid)
 	{
-		auto findIter = mScriptResources.find(UUID);
+		for(auto& kvp : mScriptRRefsPerType)
+		{
+			UnorderedMap<UUID, ScriptRRefBase*>& rrefs = kvp.second;
+
+			const auto iterFind = rrefs.find(uuid);
+			if (iterFind != rrefs.end())
+				iterFind->second->clearResource();
+		}
+
+		auto findIter = mScriptResources.find(uuid);
 		if (findIter != mScriptResources.end())
 		{
 			findIter->second->notifyResourceDestroyed();
@@ -117,6 +149,11 @@ namespace bs
 		}
 	}
 
+	void ScriptResourceManager::clearRRefs()
+	{
+		mScriptRRefsPerType.clear();
+	}
+
 	void ScriptResourceManager::_throwExceptionIfInvalidOrDuplicate(const UUID& uuid) const
 	{
 		if(uuid.empty())

+ 10 - 1
Source/Scripting/SBansheeEngine/BsScriptResourceManager.h

@@ -63,7 +63,7 @@ namespace bs
 		 * Attempts to find a resource interop object for a resource with the specified UUID. Returns null if the object
 		 * cannot be found.
 		 */
-		ScriptResourceBase* getScriptResource(const UUID& UUID);
+		ScriptResourceBase* getScriptResource(const UUID& uuid);
 
 		/**
 		 * Attempts to find an existing interop object for the specified resource reference, or creates a new object if one
@@ -97,8 +97,17 @@ namespace bs
 		/**	Triggered when the native resource has been unloaded and therefore destroyed. */
 		void onResourceDestroyed(const UUID& UUID);
 
+		/** 
+		 * Clears all cached RRefs. Should be called before assembly refresh since the refs will no longer be valid
+		 * after.
+		 */
+		void clearRRefs();
+
 		UnorderedMap<UUID, ScriptResourceBase*> mScriptResources;
+		UnorderedMap<::MonoClass*, UnorderedMap<UUID, ScriptRRefBase*>> mScriptRRefsPerType;
+
 		HEvent mResourceDestroyedConn;
+		HEvent mDomainUnloadedConn;
 	};
 
 	/** @} */

+ 7 - 5
Source/Scripting/SBansheeEngine/Wrappers/BsScriptRRefBase.cpp

@@ -91,13 +91,15 @@ namespace bs
 
 	MonoObject* ScriptRRefBase::internal_GetResource(ScriptRRefBase* thisPtr)
 	{
+		if(thisPtr->mScriptResource)
+			return thisPtr->mScriptResource->getManagedInstance();
+
 		const HResource resource = thisPtr->getHandle();
 		if(resource == nullptr)
 			return nullptr;
 
-		ScriptResourceBase* scriptResource = nullptr;
 		if(resource.isLoaded(false))
-			scriptResource = ScriptResourceManager::instance().getScriptResource(resource, true);
+			thisPtr->mScriptResource = ScriptResourceManager::instance().getScriptResource(resource, true);
 		else
 		{
 			ResourceLoadFlags loadFlags = ResourceLoadFlag::LoadDependencies;
@@ -106,11 +108,11 @@ namespace bs
 				loadFlags |= ResourceLoadFlag::KeepSourceData;
 
 			const HResource loadedResource = gResources().loadFromUUID(thisPtr->getHandle().getUUID(), loadFlags);
-			scriptResource = ScriptResourceManager::instance().getScriptResource(loadedResource, true);
+			thisPtr->mScriptResource = ScriptResourceManager::instance().getScriptResource(loadedResource, true);
 		}
 
-		if(scriptResource)
-			return scriptResource->getManagedInstance();
+		if(thisPtr->mScriptResource)
+			return thisPtr->mScriptResource->getManagedInstance();
 
 		return nullptr;
 	}

+ 6 - 0
Source/Scripting/SBansheeEngine/Wrappers/BsScriptRRefBase.h

@@ -46,6 +46,8 @@ namespace bs
 		static ::MonoClass* bindGenericParam(::MonoClass* param);
 
 	private:
+		friend class ScriptResourceManager;
+
 		ScriptRRefBase(MonoObject* instance, ResourceHandle<Resource> handle);
 		~ScriptRRefBase();
 
@@ -55,10 +57,14 @@ namespace bs
 		/** @copydoc ScriptObjectBase::_onManagedInstanceDeleted */
 		void _onManagedInstanceDeleted(bool assemblyRefresh) override;
 
+		/** Clears the internal cached ScriptResource reference. Should be called if the resource got destroyed. */
+		void clearResource() { mScriptResource = nullptr; }
+
 		/** @copydoc create() */
 		static ScriptRRefBase* createInternal(const ResourceHandle<Resource>& handle, ::MonoClass* type = nullptr);
 
 		ResourceHandle<Resource> mResource;
+		ScriptResourceBase* mScriptResource = nullptr;
 		UINT32 mGCHandle;
 
 		/************************************************************************/