2
0
Эх сурвалжийг харах

Textures are now properly hot-loaded and their changes will be immediately reflected in scene after reimport

BearishSun 8 жил өмнө
parent
commit
cdc8db06bc

+ 17 - 10
Source/BansheeCore/Include/BsMaterial.h

@@ -40,6 +40,13 @@ namespace bs
 	template<> struct TGpuParamsSetType < false > { typedef GpuParamsSet Type; };
 	template<> struct TGpuParamsSetType < true > { typedef ct::GpuParamsSet Type; };
 
+	/** Flags that signal in what way did the Material change. */
+	enum class MaterialDirtyFlags
+	{
+		Normal,
+		ResourceChanged
+	};
+
 	/**
 	 * Material that controls how objects are rendered. It is represented by a shader and parameters used to set up that
 	 * shader. It provides a simple interface for manipulating the parameters.
@@ -80,15 +87,15 @@ namespace bs
 		 */
 
 		/** Marks the contents of the sim thread object as dirty, causing it to sync with its core thread counterpart. */
-		virtual void _markCoreDirty() { }
+		virtual void _markCoreDirty(MaterialDirtyFlags flags = MaterialDirtyFlags::Normal) { }
 
-		/** @} */
-	protected:
 		/** @copydoc CoreObject::markDependenciesDirty */
 		virtual void _markDependenciesDirty() { }
 
 		/** @copydoc IResourceListener::markListenerResourcesDirty */
 		virtual void _markResourcesDirty() { }
+
+		/** @} */
 	};
 
 	/** @copydoc MaterialBase */
@@ -593,7 +600,13 @@ namespace bs
 		 * Marks the core data as dirty. This causes the syncToCore() method to trigger the next time objects are synced 
 		 * between core and sim threads. 
 		 */
-		void _markCoreDirty() override;
+		void _markCoreDirty(MaterialDirtyFlags flags = MaterialDirtyFlags::Normal) override;
+
+		/** @copydoc CoreObject::markDependenciesDirty */
+		void _markDependenciesDirty() override;
+
+		/** @copydoc IResourceListener::markResourcesDirty */
+		void _markResourcesDirty() override;
 
 		/** @} */
 	private:
@@ -611,12 +624,6 @@ namespace bs
 		/** @copydoc CoreObject::getCoreDependencies */
 		void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
 
-		/** @copydoc CoreObject::markDependenciesDirty */
-		void _markDependenciesDirty() override;
-
-		/** @copydoc IResourceListener::markResourcesDirty */
-		void _markResourcesDirty() override;
-
 		/** @copydoc IResourceListener::getListenerResources */
 		void getListenerResources(Vector<HResource>& resources) override;
 

+ 9 - 1
Source/BansheeCore/Include/BsMaterialParams.h

@@ -591,8 +591,16 @@ namespace bs
 		 *								of the required buffer.
 		 * @param[in, out]	size		Size of the provided allocated buffer. Or if the buffer is null, this parameter will
 		 *								contain the required buffer size when the method executes.
+		 * @param[in]		forceAll	If false, only the parameters that were changed since the last call will be synced.
+		 *								Otherwise all parameters will be synced.
 		 */
-		void getSyncData(UINT8* buffer, UINT32& size);
+		void getSyncData(UINT8* buffer, UINT32& size, bool forceAll);
+
+		/** Appends any resources stored by this object to the provided vector. */
+		void getResourceDependencies(Vector<HResource>& resources);
+
+		/** Appends any core objects stored by this object to the provided vector. */
+		void getCoreObjectDependencies(Vector<CoreObject*>& coreObjects);
 
 	private:
 		friend class ct::MaterialParams;

+ 14 - 8
Source/BansheeCore/Source/BsCoreObjectManager.cpp

@@ -108,6 +108,8 @@ namespace bs
 
 				mDependants.erase(iterFind);
 			}
+
+			mDependencies.erase(internalId);
 		}
 	}
 
@@ -151,11 +153,11 @@ namespace bs
 
 					if (dependencies != nullptr)
 					{
-						std::set_difference(dependencies->begin(), dependencies->end(),
-							dependencies->begin(), dependencies->end(), toRemove.begin());
-
 						std::set_difference(oldDependencies.begin(), oldDependencies.end(),
-							oldDependencies.begin(), oldDependencies.end(), toAdd.begin());
+							dependencies->begin(), dependencies->end(), std::inserter(toRemove, toRemove.begin()));
+
+						std::set_difference(dependencies->begin(), dependencies->end(),
+							oldDependencies.begin(), oldDependencies.end(), std::inserter(toAdd, toAdd.begin()));
 					}
 					else
 					{
@@ -178,18 +180,22 @@ namespace bs
 								mDependants.erase(iterFind2);
 						}
 					}
+
+					if (dependencies != nullptr && dependencies->size() > 0)
+						mDependencies[id] = *dependencies;
+					else
+						mDependencies.erase(id);
 				}
 				else
 				{
-					if (dependencies != nullptr)
+					if (dependencies != nullptr && dependencies->size() > 0)
 					{
 						for (auto& dependency : *dependencies)
 							toAdd.push_back(dependency);
+
+						mDependencies[id] = *dependencies;
 					}
 				}
-
-				if (dependencies != nullptr)
-					mDependencies[id] = *dependencies;
 			}
 
 			// Register dependants

+ 26 - 7
Source/BansheeCore/Source/BsMaterial.cpp

@@ -389,9 +389,9 @@ namespace bs
 		initializeIfLoaded();
 	}
 
-	void Material::_markCoreDirty()
+	void Material::_markCoreDirty(MaterialDirtyFlags flags)
 	{
-		markCoreDirty();
+		markCoreDirty((UINT32)flags);
 	}
 
 	void Material::_markDependenciesDirty()
@@ -438,9 +438,11 @@ namespace bs
 
 	CoreSyncData Material::syncToCore(FrameAlloc* allocator)
 	{
+		bool syncAllParams = getCoreDirtyFlags() == (UINT32)MaterialDirtyFlags::ResourceChanged;
+
 		UINT32 paramsSize = 0;
 		if (mParams != nullptr)
-			mParams->getSyncData(nullptr, paramsSize);
+			mParams->getSyncData(nullptr, paramsSize, syncAllParams);
 
 		UINT32 numTechniques = (UINT32)mTechniques.size();
 		UINT32 size = sizeof(UINT32) * 2 + sizeof(SPtr<ct::Shader>) + 
@@ -468,7 +470,7 @@ namespace bs
 
 		dataPtr = rttiWriteElem(paramsSize, dataPtr);
 		if (mParams != nullptr)
-			mParams->getSyncData((UINT8*)dataPtr, paramsSize);
+			mParams->getSyncData((UINT8*)dataPtr, paramsSize, syncAllParams);
 
 		dataPtr += paramsSize;
 
@@ -479,12 +481,18 @@ namespace bs
 	{
 		if (mShader.isLoaded())
 			dependencies.push_back(mShader.get());
+
+		if(mParams != nullptr)
+			mParams->getCoreObjectDependencies(dependencies);
 	}
 
 	void Material::getListenerResources(Vector<HResource>& resources)
 	{
 		if (mShader != nullptr)
 			resources.push_back(mShader);
+
+		if (mParams != nullptr)
+			mParams->getResourceDependencies(resources);
 	}
 
 	void Material::getResourceDependencies(FrameVector<HResource>& dependencies) const
@@ -525,13 +533,24 @@ namespace bs
 
 	void Material::notifyResourceLoaded(const HResource& resource)
 	{
-		initializeIfLoaded();
+		// Ready to initialize as soon as shader loads
+		if (resource->getRTTI()->getRTTIId() == TID_Shader)
+			initializeIfLoaded();
 	}
 
 	void Material::notifyResourceChanged(const HResource& resource)
 	{
-		mLoadFlags = Load_None;
-		initializeIfLoaded();
+		// Need full rebuild if shader changed
+		if (resource->getRTTI()->getRTTIId() == TID_Shader)
+		{
+			mLoadFlags = Load_None;
+			initializeIfLoaded();
+		}
+		else
+		{
+			// Otherwise just sync changes (most likely just a texture got reimported)
+			_markCoreDirty(MaterialDirtyFlags::ResourceChanged);
+		}
 	}
 
 	HMaterial Material::clone()

+ 6 - 0
Source/BansheeCore/Source/BsMaterialParam.cpp

@@ -172,6 +172,8 @@ namespace bs
 
 		params->setTexture(*data, newValue, surface);
 		mMaterial->_markCoreDirty();
+		mMaterial->_markDependenciesDirty();
+		mMaterial->_markResourcesDirty();
 	}
 
 	template<bool Core>
@@ -223,6 +225,8 @@ namespace bs
 
 		params->setLoadStoreTexture(*data, texture, surface);
 		mMaterial->_markCoreDirty();
+		mMaterial->_markDependenciesDirty();
+		mMaterial->_markResourcesDirty();
 	}
 
 	template<bool Core>
@@ -274,6 +278,7 @@ namespace bs
 
 		params->setBuffer(*data, buffer);
 		mMaterial->_markCoreDirty();
+		mMaterial->_markDependenciesDirty();
 	}
 
 	template<bool Core>
@@ -327,6 +332,7 @@ namespace bs
 
 		params->setSamplerState(*data, newValue);
 		mMaterial->_markCoreDirty();
+		mMaterial->_markDependenciesDirty();
 	}
 
 	template<bool Core>

+ 54 - 3
Source/BansheeCore/Source/BsMaterialParams.cpp

@@ -553,7 +553,7 @@ namespace bs
 		:TMaterialParams(shader), mLastSyncVersion(1)
 	{ }
 
-	void MaterialParams::getSyncData(UINT8* buffer, UINT32& size)
+	void MaterialParams::getSyncData(UINT8* buffer, UINT32& size, bool forceAll)
 	{
 		// Note: Not syncing struct data
 
@@ -565,7 +565,7 @@ namespace bs
 		UINT32 dataParamSize = 0;
 		for(auto& param : mParams)
 		{
-			if (param.version <= mLastSyncVersion)
+			if (param.version <= mLastSyncVersion && !forceAll)
 				continue;
 
 			switch(param.type)
@@ -630,7 +630,7 @@ namespace bs
 		for(UINT32 i = 0; i < (UINT32)mParams.size(); i++)
 		{
 			ParamData& param = mParams[i];
-			if (param.version <= mLastSyncVersion)
+			if (param.version <= mLastSyncVersion && !forceAll)
 				continue;
 
 			switch (param.type)
@@ -705,6 +705,57 @@ namespace bs
 		mLastSyncVersion = mParamVersion;
 	}
 
+	void MaterialParams::getResourceDependencies(Vector<HResource>& resources)
+	{
+		for (UINT32 i = 0; i < (UINT32)mParams.size(); i++)
+		{
+			ParamData& param = mParams[i];
+			if (param.type != ParamType::Texture)
+				continue;
+
+			const MaterialParamTextureData& textureData = mTextureParams[param.index];
+			if (textureData.value != nullptr)
+				resources.push_back(textureData.value);
+		}
+	}
+
+	void MaterialParams::getCoreObjectDependencies(Vector<CoreObject*>& coreObjects)
+	{
+		for (UINT32 i = 0; i < (UINT32)mParams.size(); i++)
+		{
+			ParamData& param = mParams[i];
+
+			switch (param.type)
+			{
+			case ParamType::Texture:
+			{
+				const MaterialParamTextureData& textureData = mTextureParams[param.index];
+
+				if (textureData.value.isLoaded())
+					coreObjects.push_back(textureData.value.get());
+			}
+			break;
+			case ParamType::Buffer:
+			{
+				const MaterialParamBufferData& bufferData = mBufferParams[param.index];
+
+				if (bufferData.value != nullptr)
+					coreObjects.push_back(bufferData.value.get());
+			}
+			break;
+			case ParamType::Sampler:
+			{
+
+				const MaterialParamSamplerStateData& samplerData = mSamplerStateParams[param.index];
+
+				if (samplerData.value != nullptr)
+					coreObjects.push_back(samplerData.value.get());
+			}
+			break;
+			}
+		}
+	}
+
 	RTTITypeBase* MaterialParams::getRTTIStatic()
 	{
 		return MaterialParamsRTTI::instance();