Bläddra i källkod

Material refactor WIP - Added GpuParamsSet update method and parameter meta-data

BearishSun 9 år sedan
förälder
incheckning
0fcb499f43

+ 80 - 12
Source/BansheeCore/Include/BsGpuParamsSet.h

@@ -24,6 +24,9 @@ namespace BansheeEngine
 		typedef typename TPassType<Core>::Type PassType;
 		typedef typename TPassType<Core>::Type PassType;
 		typedef typename TGpuProgramType<Core>::Type GpuProgramPtrType;
 		typedef typename TGpuProgramType<Core>::Type GpuProgramPtrType;
 		typedef typename TGpuParamBlockBufferType<Core>::Type ParamBlockType;
 		typedef typename TGpuParamBlockBufferType<Core>::Type ParamBlockType;
+		typedef typename TGpuParamTextureType<Core>::Type TextureType;
+		typedef typename TGpuBufferType<Core>::Type BufferType;
+		typedef typename TGpuParamSamplerStateType<Core>::Type SamplerStateType;
 
 
 		/** Contains all parameters for a single pass. */
 		/** Contains all parameters for a single pass. */
 		struct PassParams
 		struct PassParams
@@ -36,45 +39,94 @@ namespace BansheeEngine
 			GpuParamsType compute;
 			GpuParamsType compute;
 		};
 		};
 
 
+		/** Information about a parameter block buffer. */
+		struct BlockInfo
+		{
+			BlockInfo(const String& name, const ParamBlockPtrType& buffer, bool shareable)
+				:name(name), buffer(buffer), shareable(shareable)
+			{ }
+
+			String name;
+			ParamBlockPtrType buffer;
+			bool shareable;
+		};
+
+		/** Information about how a data parameter maps from a material parameter into a parameter block buffer. */
+		struct DataParamInfo
+		{
+			UINT32 paramIdx;
+			UINT32 blockIdx;
+			UINT32 offset;
+			UINT32 size;
+		};
+
+		/** Information about how an object parameter maps from a material parameter to a GPU stage slot. */
+		struct ObjectParamInfo
+		{
+			UINT32 paramIdx;
+			UINT32 slotIdx;
+		};
+
+		/** Information about all object parameters for a specific GPU programmable stage. */
+		struct StageParamInfo
+		{
+			ObjectParamInfo* textures;
+			UINT32 numTextures;
+			ObjectParamInfo* loadStoreTextures;
+			UINT32 numLoadStoreTextures;
+			ObjectParamInfo* buffers;
+			UINT32 numBuffers;
+			ObjectParamInfo* samplerStates;
+			UINT32 numSamplerStates;
+		};
+
+		/** Information about all object parameters for a specific pass. */
+		struct PassParamInfo
+		{
+			StageParamInfo stages[6];
+		};
+
 	public:
 	public:
 		TGpuParamsSet() {}
 		TGpuParamsSet() {}
-		TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader);
+		TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader, UINT32 techniqueIdx, 
+			const SPtr<MaterialParamsType>& params);
+		~TGpuParamsSet();
 
 
 		/**
 		/**
 		 * Returns a GPU parameters for a specific shader stage and pass.
 		 * Returns a GPU parameters for a specific shader stage and pass.
 		 *
 		 *
-		 * @param[in]	idx			Sequential index of the shader stage to retrieve the parameters for.
+		 * @param[in]	stageidx	Sequential index of the shader stage to retrieve the parameters for.
 		 * @param[in]	passIdx		Pass for which to retrieve the parameters for.
 		 * @param[in]	passIdx		Pass for which to retrieve the parameters for.
 		 * @return					GPU parameters object that can be used for setting parameters of a GPU program 
 		 * @return					GPU parameters object that can be used for setting parameters of a GPU program 
 		 *							individually.
 		 *							individually.
 		 *
 		 *
 		 * @note	Useful when needing to iterate over all sets of GPU parameters.
 		 * @note	Useful when needing to iterate over all sets of GPU parameters.
 		 */
 		 */
-		GpuParamsType getParamByIdx(UINT32 idx, UINT32 passIdx = 0)
+		GpuParamsType getParamByIdx(UINT32 stageidx, UINT32 passIdx = 0)
 		{
 		{
 			GpuParamsType* paramArray[] = { &mPassParams[passIdx].vertex, &mPassParams[passIdx].fragment,
 			GpuParamsType* paramArray[] = { &mPassParams[passIdx].vertex, &mPassParams[passIdx].fragment,
 				&mPassParams[passIdx].geometry, &mPassParams[passIdx].hull, &mPassParams[passIdx].domain, 
 				&mPassParams[passIdx].geometry, &mPassParams[passIdx].hull, &mPassParams[passIdx].domain, 
 				&mPassParams[passIdx].compute };
 				&mPassParams[passIdx].compute };
 
 
-			return *paramArray[idx];
+			return *paramArray[stageidx];
 		}
 		}
 
 
 		/**
 		/**
 		 * Sets GPU parameters for a specific shader stage and pass.
 		 * Sets GPU parameters for a specific shader stage and pass.
 		 *
 		 *
-		 * @param[in]	idx			Sequential index of the shader stage to set the parameters for.
+		 * @param[in]	stageidx	Sequential index of the shader stage to set the parameters for.
 		 * @param[in]	params		GPU parameters object to assign.
 		 * @param[in]	params		GPU parameters object to assign.
 		 * @param[in]	passIdx		Pass for which to set the parameters for.
 		 * @param[in]	passIdx		Pass for which to set the parameters for.
 		 *
 		 *
 		 * @note	Useful when needing to iterate over all sets of GPU parameters.
 		 * @note	Useful when needing to iterate over all sets of GPU parameters.
 		 */
 		 */
-		void setParamByIdx(UINT32 idx, const GpuParamsType& params, UINT32 passIdx = 0)
+		void setParamByIdx(UINT32 stageidx, const GpuParamsType& params, UINT32 passIdx = 0)
 		{
 		{
 			GpuParamsType* paramArray[] = { &mPassParams[passIdx].vertex, &mPassParams[passIdx].fragment,
 			GpuParamsType* paramArray[] = { &mPassParams[passIdx].vertex, &mPassParams[passIdx].fragment,
 				&mPassParams[passIdx].geometry, &mPassParams[passIdx].hull, &mPassParams[passIdx].domain,
 				&mPassParams[passIdx].geometry, &mPassParams[passIdx].hull, &mPassParams[passIdx].domain,
 				&mPassParams[passIdx].compute };
 				&mPassParams[passIdx].compute };
 
 
-			(*paramArray[idx]) = params;
+			(*paramArray[stageidx]) = params;
 		}
 		}
 
 
 		/** 
 		/** 
@@ -101,11 +153,25 @@ namespace BansheeEngine
 		/** Returns the number of passes the set contains the parameters for. */
 		/** Returns the number of passes the set contains the parameters for. */
 		UINT32 getNumPasses() const { return (UINT32)mPassParams.size(); }
 		UINT32 getNumPasses() const { return (UINT32)mPassParams.size(); }
 
 
-		static const UINT32 NUM_PARAMS;
+		/**
+		 * Updates internal GPU params for all passes and stages from the provided material parameters object.
+		 *
+		 * @param[in]	params		Object containing the parameter data to update from. Layout of the object must match the
+		 *							object used for creating this object (be created for the same shader).
+		 * @param[in]	updateAll	By default the system will only update parameters marked as dirty in @p params. If this
+		 *							is set to true, all parameters will be updated instead.
+		 */
+		void update(const SPtr<MaterialParamsType>& params, bool updateAll = false);
+
+		static const UINT32 NUM_STAGES;
 	private:
 	private:
 		template<bool Core2> friend class TMaterial;
 		template<bool Core2> friend class TMaterial;
 
 
+		UINT32 mTechniqueIdx;
 		Vector<PassParams> mPassParams;
 		Vector<PassParams> mPassParams;
+		Vector<BlockInfo> mBlocks;
+		Vector<DataParamInfo> mDataParamInfos;
+		PassParamInfo* mPassParamInfos;
 	};
 	};
 
 
 	/** Sim thread version of TGpuParamsSet<Core>. */
 	/** Sim thread version of TGpuParamsSet<Core>. */
@@ -113,8 +179,9 @@ namespace BansheeEngine
 	{
 	{
 	public:
 	public:
 		GpuParamsSet() { }
 		GpuParamsSet() { }
-		GpuParamsSet(const SPtr<Technique>& technique, const HShader& shader)
-			:TGpuParamsSet(technique, shader)
+		GpuParamsSet(const SPtr<Technique>& technique, const HShader& shader, UINT32 techniqueIdx, 
+			const SPtr<MaterialParams>& params)
+			:TGpuParamsSet(technique, shader, techniqueIdx, params)
 		{ }
 		{ }
 	};
 	};
 
 
@@ -123,8 +190,9 @@ namespace BansheeEngine
 	{
 	{
 	public:
 	public:
 		GpuParamsSetCore() { }
 		GpuParamsSetCore() { }
-		GpuParamsSetCore(const SPtr<TechniqueCore>& technique, const SPtr<ShaderCore>& shader)
-			:TGpuParamsSet(technique, shader)
+		GpuParamsSetCore(const SPtr<TechniqueCore>& technique, const SPtr<ShaderCore>& shader, UINT32 techniqueIdx,
+			const SPtr<MaterialParamsCore>& params)
+			:TGpuParamsSet(technique, shader, techniqueIdx, params)
 		{ }
 		{ }
 	};
 	};
 
 

+ 1 - 3
Source/BansheeCore/Include/BsMaterial.h

@@ -147,12 +147,10 @@ namespace BansheeEngine
 		 * will not be able to track which parameters were updated since the last call.
 		 * will not be able to track which parameters were updated since the last call.
 		 *
 		 *
 		 * @param[in]	paramsSet		Parameter set to update.
 		 * @param[in]	paramsSet		Parameter set to update.
-		 * @param[in]	technique		Technique to update the parameters for. The parameter set provided must have been
-		 *								created using createParamsSet() using this same technique index.
 		 * @param[in]	forceRefresh	If true all material parameters will be assigned to the params set, regardless if
 		 * @param[in]	forceRefresh	If true all material parameters will be assigned to the params set, regardless if
 		 *								they are marked dirty or not.
 		 *								they are marked dirty or not.
 		 */
 		 */
-		void updateParamsSet(const SPtr<GpuParamsSetType>& paramsSet, UINT32 techniqueIdx = 0, bool forceRefresh = false);
+		void updateParamsSet(const SPtr<GpuParamsSetType>& paramsSet, bool forceRefresh = false);
 
 
 		/**   
 		/**   
 		 * Assigns a float value to the shader parameter with the specified name. 
 		 * Assigns a float value to the shader parameter with the specified name. 

+ 15 - 0
Source/BansheeCore/Include/BsMaterialParams.h

@@ -113,6 +113,9 @@ namespace BansheeEngine
 			memcpy(&mDataParamsBuffer[param->index + arrayIdx * paramTypeSize], input, sizeof(paramTypeSize));
 			memcpy(&mDataParamsBuffer[param->index + arrayIdx * paramTypeSize], input, sizeof(paramTypeSize));
 		}
 		}
 
 
+		/** Returns an index of the parameter with the specified name. Returns -1 if parameter cannot be found. */
+		UINT32 getParamIndex(const String& name) const;
+
 		/**
 		/**
 		 * Returns data about a parameter and reports an error if there is a type or size mismatch, or if the parameter
 		 * Returns data about a parameter and reports an error if there is a type or size mismatch, or if the parameter
 		 * does exist.
 		 * does exist.
@@ -132,6 +135,12 @@ namespace BansheeEngine
 		GetParamResult getParamData(const String& name, ParamType type, GpuParamDataType dataType, UINT32 arrayIdx,
 		GetParamResult getParamData(const String& name, ParamType type, GpuParamDataType dataType, UINT32 arrayIdx,
 			const ParamData** output) const;
 			const ParamData** output) const;
 
 
+		/**
+		 * Returns information about a parameter at the specified global index, as retrieved by getParamIndex(). Returns
+		 * null if the index is out of range.
+		 */
+		const ParamData* getParamData(UINT32 index) const;
+
 		/**
 		/**
 		 * Logs an error that was reported by getParamData().
 		 * Logs an error that was reported by getParamData().
 		 *
 		 *
@@ -173,6 +182,12 @@ namespace BansheeEngine
 			memcpy(&mDataParamsBuffer[index + arrayIdx * paramTypeSize], &input, paramTypeSize);
 			memcpy(&mDataParamsBuffer[index + arrayIdx * paramTypeSize], &input, paramTypeSize);
 		}
 		}
 
 
+		/** Returns pointer to the internal data buffer for a data parameter at the specified index. */
+		UINT8* getData(UINT32 index) const
+		{
+			return &mDataParamsBuffer[index];
+		}
+
 	protected:
 	protected:
 		const static UINT32 STATIC_BUFFER_SIZE = 256;
 		const static UINT32 STATIC_BUFFER_SIZE = 256;
 
 

+ 499 - 8
Source/BansheeCore/Source/BsGpuParamsSet.cpp

@@ -5,6 +5,7 @@
 #include "BsTechnique.h"
 #include "BsTechnique.h"
 #include "BsPass.h"
 #include "BsPass.h"
 #include "BsGpuProgram.h"
 #include "BsGpuProgram.h"
+#include "BsMaterialParams.h"
 #include "BsGpuParamDesc.h"
 #include "BsGpuParamDesc.h"
 #include "BsGpuParamBlockBuffer.h"
 #include "BsGpuParamBlockBuffer.h"
 
 
@@ -16,6 +17,7 @@ namespace BansheeEngine
 		GpuParamBlockUsage usage;
 		GpuParamBlockUsage usage;
 		int size;
 		int size;
 		bool external;
 		bool external;
+		UINT32 sequentialIdx;
 	};
 	};
 
 
 	Vector<SPtr<GpuParamDesc>> getAllParamDescs(const SPtr<Technique>& technique)
 	Vector<SPtr<GpuParamDesc>> getAllParamDescs(const SPtr<Technique>& technique)
@@ -233,12 +235,188 @@ namespace BansheeEngine
 		return output;
 		return output;
 	}
 	}
 
 
+	Map<String, const GpuParamDataDesc*> determineValidDataParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs)
+	{
+		Map<String, const GpuParamDataDesc*> foundDataParams;
+		Map<String, bool> validParams;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+
+			// Check regular data params
+			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
+			{
+				const GpuParamDataDesc& curParam = iter2->second;
+
+				auto dataFindIter = validParams.find(iter2->first);
+				if (dataFindIter == validParams.end())
+				{
+					validParams[iter2->first] = true;
+					foundDataParams[iter2->first] = &curParam;
+				}
+				else
+				{
+					if (validParams[iter2->first])
+					{
+						auto dataFindIter2 = foundDataParams.find(iter2->first);
+
+						const GpuParamDataDesc* otherParam = dataFindIter2->second;
+						if (!areParamsEqual(curParam, *otherParam, true))
+						{
+							validParams[iter2->first] = false;
+							foundDataParams.erase(dataFindIter2);
+						}
+					}
+				}
+			}
+		}
+
+		return foundDataParams;
+	}
+
+	Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs)
+	{
+		Vector<const GpuParamObjectDesc*> validParams;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+
+			// Check sampler params
+			for (auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
+			// Check texture params
+			for (auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
+			// Check load-store texture params
+			for (auto iter2 = curDesc.loadStoreTextures.begin(); iter2 != curDesc.loadStoreTextures.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+
+			// Check buffer params
+			for (auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
+			{
+				validParams.push_back(&iter2->second);
+			}
+		}
+
+		return validParams;
+	}
+
+	Map<String, String> determineParameterToBlockMapping(const Vector<SPtr<GpuParamDesc>>& paramDescs)
+	{
+		Map<String, String> paramToParamBlock;
+
+		for (auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
+		{
+			const GpuParamDesc& curDesc = **iter;
+			for (auto iter2 = curDesc.params.begin(); iter2 != curDesc.params.end(); ++iter2)
+			{
+				const GpuParamDataDesc& curParam = iter2->second;
+
+				auto iterFind = paramToParamBlock.find(curParam.name);
+				if (iterFind != paramToParamBlock.end())
+					continue;
+
+				for (auto iterBlock = curDesc.paramBlocks.begin(); iterBlock != curDesc.paramBlocks.end(); ++iterBlock)
+				{
+					if (iterBlock->second.slot == curParam.paramBlockSlot)
+					{
+						paramToParamBlock[curParam.name] = iterBlock->second.name;
+						break;
+					}
+				}
+			}
+		}
+
+		return paramToParamBlock;
+	}
+
+	UnorderedSet<String> determineValidParameters(const Vector<SPtr<GpuParamDesc>>& paramDescs,
+		const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferParams,
+		const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams)
+	{
+		UnorderedSet<String> validParams;
+
+		Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(paramDescs);
+		Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(paramDescs);
+		Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(paramDescs);
+
+		// Create data param mappings
+		for (auto iter = dataParams.begin(); iter != dataParams.end(); ++iter)
+		{
+			auto findIter = validDataParameters.find(iter->second.gpuVariableName);
+
+			// Not valid so we skip it
+			if (findIter == validDataParameters.end())
+				continue;
+
+			if (findIter->second->type != iter->second.type && !(iter->second.type == GPDT_COLOR && findIter->second->type == GPDT_FLOAT4))
+			{
+				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Type doesn't match the one defined in the gpu program. "
+					+ "Shader defined type: " + toString(iter->second.type) + " - Gpu program defined type: " + toString(findIter->second->type));
+				continue;
+			}
+
+			if (findIter->second->arraySize != iter->second.arraySize)
+			{
+				LOGWRN("Ignoring shader parameter \"" + iter->first + "\". Array size doesn't match the one defined in the gpu program."
+					+ "Shader defined array size: " + toString(iter->second.arraySize) + " - Gpu program defined array size: " + toString(findIter->second->arraySize));
+				continue;
+			}
+
+			auto findBlockIter = paramToParamBlockMap.find(iter->second.gpuVariableName);
+
+			if (findBlockIter == paramToParamBlockMap.end())
+				BS_EXCEPT(InternalErrorException, "Parameter doesn't exist in param to param block map but exists in valid param map.");
+
+			validParams.insert(iter->first);
+		}
+
+		// Create object param mappings
+		auto determineObjectMappings = [&](const Map<String, SHADER_OBJECT_PARAM_DESC>& params)
+		{
+			for (auto iter = params.begin(); iter != params.end(); ++iter)
+			{
+				const Vector<String>& gpuVariableNames = iter->second.gpuVariableNames;
+				for (auto iter2 = gpuVariableNames.begin(); iter2 != gpuVariableNames.end(); ++iter2)
+				{
+					for (auto iter3 = validObjectParameters.begin(); iter3 != validObjectParameters.end(); ++iter3)
+					{
+						if ((*iter3)->name == (*iter2) && (*iter3)->type == iter->second.type)
+						{
+							validParams.insert(iter->first);
+							break;
+						}
+					}
+				}
+			}
+		};
+
+		determineObjectMappings(textureParams);
+		determineObjectMappings(samplerParams);
+		determineObjectMappings(bufferParams);
+
+		return validParams;
+	}
+
 	template<bool Core>
 	template<bool Core>
-	const UINT32 TGpuParamsSet<Core>::NUM_PARAMS = 6;
+	const UINT32 TGpuParamsSet<Core>::NUM_STAGES = 6;
 
 
 	template<bool Core>
 	template<bool Core>
-	TGpuParamsSet<Core>::TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader)
-		:mPassParams(technique->getNumPasses())
+	TGpuParamsSet<Core>::TGpuParamsSet(const SPtr<TechniqueType>& technique, const ShaderType& shader, UINT32 techniqueIdx,
+		const SPtr<MaterialParamsType>& params)
+		:mPassParams(technique->getNumPasses()), mTechniqueIdx(techniqueIdx)
 	{
 	{
 		UINT32 numPasses = technique->getNumPasses();
 		UINT32 numPasses = technique->getNumPasses();
 
 
@@ -277,6 +455,12 @@ namespace BansheeEngine
 
 
 		//// Fill out various helper structures
 		//// Fill out various helper structures
 		Vector<ShaderBlockDesc> paramBlockData = determineValidShareableParamBlocks(allParamDescs, shader->getParamBlocks());
 		Vector<ShaderBlockDesc> paramBlockData = determineValidShareableParamBlocks(allParamDescs, shader->getParamBlocks());
+		UnorderedSet<String> validParams = determineValidParameters(
+			allParamDescs, 
+			shader->getDataParams(), 
+			shader->getTextureParams(), 
+			shader->getBufferParams(), 
+			shader->getSamplerParams());
 
 
 		Map<String, ParamBlockPtrType> paramBlockBuffers;
 		Map<String, ParamBlockPtrType> paramBlockBuffers;
 
 
@@ -287,18 +471,22 @@ namespace BansheeEngine
 			if (!paramBlock.external)
 			if (!paramBlock.external)
 				newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
 				newParamBlockBuffer = ParamBlockType::create(paramBlock.size, paramBlock.usage);
 
 
+			paramBlock.sequentialIdx = (UINT32)mBlocks.size();
+
 			paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
 			paramBlockBuffers[paramBlock.name] = newParamBlockBuffer;
+			mBlocks.push_back(BlockInfo(paramBlock.name, newParamBlockBuffer, true));
 		}
 		}
 
 
-		//// Assign param block buffers
+		//// Assign param block buffers and generate information about data parameters
 		for (UINT32 i = 0; i < numPasses; i++)
 		for (UINT32 i = 0; i < numPasses; i++)
 		{
 		{
-			for (UINT32 j = 0; j < NUM_PARAMS; j++)
+			for (UINT32 j = 0; j < NUM_STAGES; j++)
 			{
 			{
 				GpuParamsType paramPtr = getParamByIdx(j, i);
 				GpuParamsType paramPtr = getParamByIdx(j, i);
 				if (paramPtr != nullptr)
 				if (paramPtr != nullptr)
 				{
 				{
 					// Assign shareable buffers
 					// Assign shareable buffers
+					UINT32 paramBlockIdx = 0;
 					for (auto& block : paramBlockData)
 					for (auto& block : paramBlockData)
 					{
 					{
 						const String& paramBlockName = block.name;
 						const String& paramBlockName = block.name;
@@ -308,22 +496,199 @@ namespace BansheeEngine
 
 
 							paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
 							paramPtr->setParamBlockBuffer(paramBlockName, blockBuffer);
 						}
 						}
+
+						paramBlockIdx++;
 					}
 					}
 
 
 					// Create non-shareable ones (these are buffers defined by default by the RHI usually)
 					// Create non-shareable ones (these are buffers defined by default by the RHI usually)
 					const GpuParamDesc& desc = paramPtr->getParamDesc();
 					const GpuParamDesc& desc = paramPtr->getParamDesc();
 					for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
 					for (auto iterBlockDesc = desc.paramBlocks.begin(); iterBlockDesc != desc.paramBlocks.end(); ++iterBlockDesc)
 					{
 					{
-						if (!iterBlockDesc->second.isShareable)
+						const GpuParamBlockDesc& blockDesc = iterBlockDesc->second;
+
+						UINT32 globalBlockIdx = (UINT32)-1;
+						if (!blockDesc.isShareable)
 						{
 						{
-							ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(iterBlockDesc->second.blockSize * sizeof(UINT32));
+							ParamBlockPtrType newParamBlockBuffer = ParamBlockType::create(blockDesc.blockSize * sizeof(UINT32));
+
+							globalBlockIdx = (UINT32)mBlocks.size();
 
 
 							paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
 							paramPtr->setParamBlockBuffer(iterBlockDesc->first, newParamBlockBuffer);
+							mBlocks.push_back(BlockInfo(iterBlockDesc->first, newParamBlockBuffer, false));
+						}
+						else
+						{
+							auto iterFind = std::find_if(paramBlockData.begin(), paramBlockData.end(), [&](const auto& x)
+							{
+								return x.name == iterBlockDesc->first;
+							});
+
+							if(iterFind != paramBlockData.end())
+								globalBlockIdx = iterFind->sequentialIdx;
+						}
+
+						// If this parameter block is valid, create data/struct mappings for it
+						if (globalBlockIdx == (UINT32)-1)
+							continue;
+
+						for(auto& dataParam : desc.params)
+						{
+							if (dataParam.second.paramBlockSlot != blockDesc.slot)
+								continue;
+
+							if (validParams.count(dataParam.first) == 0)
+								continue;
+
+							UINT32 paramIdx = params->getParamIndex(dataParam.first);
+
+							// Parameter shouldn't be in the valid parameter list if it cannot be found
+							assert(paramIdx != (UINT32)-1);
+
+							mDataParamInfos.push_back(DataParamInfo());
+							DataParamInfo& paramInfo = mDataParamInfos.back();
+							paramInfo.paramIdx = paramIdx;
+							paramInfo.blockIdx = globalBlockIdx;
+							paramInfo.offset = dataParam.second.cpuMemOffset;
+
+							const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)dataParam.second.type];
+							UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
+
+							paramInfo.size = paramSize * dataParam.second.arraySize;
 						}
 						}
 					}
 					}
 				}
 				}
 			}
 			}
 		}
 		}
+
+		// Generate information about object parameters
+		bs_frame_mark();
+		{
+			FrameVector<ObjectParamInfo> objParamInfos;
+
+			UINT32 offsetsSize = numPasses * NUM_STAGES * 4 * sizeof(UINT32);
+			UINT32* offsets = (UINT32*)bs_frame_alloc(offsetsSize);
+			memset(offsets, 0, offsetsSize);
+
+			// First store all objects in temporary arrays since we don't know how many of them are
+			UINT32 totalNumObjects = 0;
+			UINT32* stageOffsets = offsets;
+			for (UINT32 i = 0; i < numPasses; i++)
+			{
+				for (UINT32 j = 0; j < NUM_STAGES; j++)
+				{
+					GpuParamsType paramPtr = getParamByIdx(j, i);
+					if (paramPtr == nullptr)
+					{
+						stageOffsets += sizeof(UINT32) * 4;
+						continue;
+					}
+
+					auto processObjectParams = [&](const Map<String, GpuParamObjectDesc>& gpuParams, 
+						UINT32 stageIdx, MaterialParams::ParamType paramType)
+					{
+						for (auto& param : gpuParams)
+						{
+							if (validParams.count(param.first) == 0)
+								continue;
+
+							UINT32 paramIdx = params->getParamIndex(param.first);
+
+							// Parameter shouldn't be in the valid parameter list if it cannot be found
+							assert(paramIdx != (UINT32)-1);
+
+							objParamInfos.push_back(ObjectParamInfo());
+							ObjectParamInfo& paramInfo = objParamInfos.back();
+							paramInfo.paramIdx = paramIdx;
+							paramInfo.slotIdx = param.second.slot;
+
+							offsets[stageIdx]++;
+							totalNumObjects++;
+						}
+					};
+
+					const GpuParamDesc& desc = paramPtr->getParamDesc();
+					processObjectParams(desc.textures, 0, MaterialParams::ParamType::Texture);
+					processObjectParams(desc.loadStoreTextures, 1, MaterialParams::ParamType::Texture);
+					processObjectParams(desc.buffers, 2, MaterialParams::ParamType::Buffer);
+					processObjectParams(desc.samplers, 3, MaterialParams::ParamType::Sampler);
+
+					stageOffsets += sizeof(UINT32) * 4;
+				}
+			}
+
+			// Transfer all objects into their permanent storage
+			UINT32 objectParamInfosSize = totalNumObjects * sizeof(ObjectParamInfo) + numPasses * sizeof(PassParamInfo);
+			mPassParamInfos = (PassParamInfo*)bs_alloc(objectParamInfosSize);
+			memset(mPassParamInfos, 0, objectParamInfosSize);
+
+			StageParamInfo* stageInfos = (StageParamInfo*)mPassParamInfos;
+
+			ObjectParamInfo* objInfos = (ObjectParamInfo*)(mPassParamInfos + numPasses);
+			memcpy(objInfos, objParamInfos.data(), totalNumObjects * sizeof(ObjectParamInfo));
+
+			UINT32 objInfoOffset = 0;
+
+			stageOffsets = offsets;
+			for (UINT32 i = 0; i < numPasses; i++)
+			{
+				for (UINT32 j = 0; j < NUM_STAGES; j++)
+				{
+					StageParamInfo& stage = stageInfos[i * NUM_STAGES + j];
+
+					if(stageOffsets[0] > 0)
+					{
+						UINT32 numEntries = stageOffsets[0];
+
+						stage.textures = objInfos + objInfoOffset;
+						stage.numTextures = numEntries;
+
+						objInfoOffset += numEntries;
+					}
+
+					if (stageOffsets[1] > 0)
+					{
+						UINT32 numEntries = stageOffsets[1];
+
+						stage.loadStoreTextures = objInfos + objInfoOffset;
+						stage.numLoadStoreTextures = numEntries;
+
+						objInfoOffset += numEntries;
+					}
+
+					if (stageOffsets[2] > 0)
+					{
+						UINT32 numEntries = stageOffsets[2];
+
+						stage.buffers = objInfos + objInfoOffset;
+						stage.numBuffers = numEntries;
+
+						objInfoOffset += numEntries;
+					}
+
+					if (stageOffsets[3] > 0)
+					{
+						UINT32 numEntries = stageOffsets[3];
+
+						stage.samplerStates = objInfos + objInfoOffset;
+						stage.numSamplerStates = numEntries;
+
+						objInfoOffset += numEntries;
+					}
+
+					stageOffsets += sizeof(UINT32) * 4;
+				}
+			}
+
+			bs_frame_free(offsets);
+		}
+		bs_frame_clear();
+	}
+
+	template<bool Core>
+	TGpuParamsSet<Core>::~TGpuParamsSet()
+	{
+		// All allocations share the same memory, so we just clear it all at once
+		bs_free(mPassParamInfos);
 	}
 	}
 
 
 	template<bool Core>
 	template<bool Core>
@@ -354,10 +719,34 @@ namespace BansheeEngine
 	template<bool Core>
 	template<bool Core>
 	void TGpuParamsSet<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
 	void TGpuParamsSet<Core>::setParamBlockBuffer(const String& name, const ParamBlockPtrType& paramBlock)
 	{
 	{
+		UINT32 foundIdx = (UINT32)-1;
+		for(UINT32 i = 0; i < (UINT32)mBlocks.size(); i++)
+		{
+			BlockInfo& block = mBlocks[i];
+			if(block.name == name)
+			{
+				if (!block.shareable)
+				{
+					LOGERR("Cannot set parameter block buffer with the name \"" + name + "\". Buffer is not assignable. ");
+					return;
+				}
+
+				foundIdx = i;
+			}
+		}
+
+		if(foundIdx == (UINT32)-1)
+		{
+			LOGERR("Cannot set parameter block buffer with the name \"" + name + "\". Buffer name not found. ");
+			return;
+		}
+
+		mBlocks[foundIdx].buffer = paramBlock;
+
 		UINT32 numPasses = (UINT32)mPassParams.size();
 		UINT32 numPasses = (UINT32)mPassParams.size();
 		for (UINT32 j = 0; j < numPasses; j++)
 		for (UINT32 j = 0; j < numPasses; j++)
 		{
 		{
-			for (UINT32 i = 0; i < NUM_PARAMS; i++)
+			for (UINT32 i = 0; i < NUM_STAGES; i++)
 			{
 			{
 				GpuParamsType paramPtr = getParamByIdx(i);
 				GpuParamsType paramPtr = getParamByIdx(i);
 				if (paramPtr != nullptr)
 				if (paramPtr != nullptr)
@@ -369,6 +758,108 @@ namespace BansheeEngine
 		}
 		}
 	}
 	}
 
 
+	template<bool Core>
+	void TGpuParamsSet<Core>::update(const SPtr<MaterialParamsType>& params, bool updateAll)
+	{
+		// Note: Instead of iterating over every single parameter, it might be more efficient for @p params to keep
+		// a ring buffer and a version number. Then we could just iterate over the ring buffer and only access dirty
+		// parameters. If the version number is too high (larger than ring buffer can store), then we force update for all.
+
+		// Maximum of 31 techniques are supported. Bit 32 is reserved.
+		assert(mTechniqueIdx < 31);
+		UINT32 dirtyFlagCheck = 1 << mTechniqueIdx;
+
+		// Update data params
+		for(auto& paramInfo : mDataParamInfos)
+		{
+			ParamBlockPtrType paramBlock = mBlocks[paramInfo.blockIdx].buffer;
+			if (paramBlock != nullptr)
+				continue;
+
+			const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
+			if ((materialParamInfo->dirtyFlags & dirtyFlagCheck) == 0 && !updateAll)
+				continue;
+
+			// TODO - Handle transposing matrices (POTENTIALLY add this to Material setters directly)
+			UINT8* data = params->getData(materialParamInfo->index);
+			paramBlock->write(paramInfo.offset, data, paramInfo.size);
+		}
+
+		// Update object params
+		UINT32 numPasses = (UINT32)mPassParams.size();
+
+		for(UINT32 i = 0; i < numPasses; i++)
+		{
+			for(UINT32 j = 0; j < NUM_STAGES; j++)
+			{
+				GpuParamsType paramsPtr = getParamByIdx(j, i);
+				if(paramsPtr != nullptr)
+				{
+					const StageParamInfo& stageInfo = mPassParamInfos[i].stages[j];
+
+					for(UINT32 k = 0; k < stageInfo.numTextures; k++)
+					{
+						const ObjectParamInfo& paramInfo = stageInfo.textures[k];
+
+						const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
+						if ((materialParamInfo->dirtyFlags & dirtyFlagCheck) == 0 && !updateAll)
+							continue;
+
+						TextureType texture;
+						params->getTexture(materialParamInfo->index, texture);
+
+						paramsPtr->setTexture(paramInfo.slotIdx, texture);
+					}
+
+					for (UINT32 k = 0; k < stageInfo.numLoadStoreTextures; k++)
+					{
+						const ObjectParamInfo& paramInfo = stageInfo.loadStoreTextures[k];
+
+						const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
+						if ((materialParamInfo->dirtyFlags & dirtyFlagCheck) == 0 && !updateAll)
+							continue;
+
+						TextureSurface surface;
+						TextureType texture;
+						params->getLoadStoreTexture(materialParamInfo->index, texture, surface);
+
+						paramsPtr->setLoadStoreTexture(paramInfo.slotIdx, texture, surface);
+					}
+
+					for (UINT32 k = 0; k < stageInfo.numBuffers; k++)
+					{
+						const ObjectParamInfo& paramInfo = stageInfo.buffers[k];
+
+						const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
+						if ((materialParamInfo->dirtyFlags & dirtyFlagCheck) == 0 && !updateAll)
+							continue;
+
+						BufferType buffer;
+						params->getBuffer(materialParamInfo->index, buffer);
+
+						paramsPtr->setBuffer(paramInfo.slotIdx, buffer);
+					}
+
+					for (UINT32 k = 0; k < stageInfo.numSamplerStates; k++)
+					{
+						const ObjectParamInfo& paramInfo = stageInfo.samplerStates[k];
+
+						const MaterialParams::ParamData* materialParamInfo = params->getParamData(paramInfo.paramIdx);
+						if ((materialParamInfo->dirtyFlags & dirtyFlagCheck) == 0 && !updateAll)
+							continue;
+
+						SamplerStateType samplerState;
+						params->getSamplerState(materialParamInfo->index, samplerState);
+
+						paramsPtr->setSamplerState(paramInfo.slotIdx, samplerState);
+					}
+
+					paramsPtr->_markCoreDirty();
+				}
+			}
+		}
+	}
+
 	template class TGpuParamsSet <false>;
 	template class TGpuParamsSet <false>;
 	template class TGpuParamsSet <true>;
 	template class TGpuParamsSet <true>;
 }
 }

+ 5 - 3
Source/BansheeCore/Source/BsMaterial.cpp

@@ -40,13 +40,15 @@ namespace BansheeEngine
 			return nullptr;
 			return nullptr;
 
 
 		SPtr<TechniqueType> technique = mTechniques[techniqueIdx];
 		SPtr<TechniqueType> technique = mTechniques[techniqueIdx];
-		return bs_shared_ptr_new<GpuParamsSetType>(technique, mShader);
+		return bs_shared_ptr_new<GpuParamsSetType>(technique, mShader, techniqueIdx, mParams);
 	}
 	}
 
 
 	template<bool Core>
 	template<bool Core>
-	void TMaterial<Core>::updateParamsSet(const SPtr<GpuParamsSetType>& paramsSet, UINT32 techniqueIdx, bool forceRefresh)
+	void TMaterial<Core>::updateParamsSet(const SPtr<GpuParamsSetType>& paramsSet, bool forceRefresh)
 	{
 	{
-		// TODO
+		paramsSet->update(mParams, forceRefresh);
+
+		// TODO - Clear dirty flags
 	}
 	}
 
 
 	template<bool Core>
 	template<bool Core>

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

@@ -118,14 +118,23 @@ namespace BansheeEngine
 		mAlloc.clear();
 		mAlloc.clear();
 	}
 	}
 
 
-	MaterialParamsBase::GetParamResult MaterialParamsBase::getParamData(const String& name, ParamType type, GpuParamDataType dataType,
-		UINT32 arrayIdx, const ParamData** output) const
+	UINT32 MaterialParamsBase::getParamIndex(const String& name) const
 	{
 	{
 		auto iterFind = mParamLookup.find(name);
 		auto iterFind = mParamLookup.find(name);
 		if (iterFind == mParamLookup.end())
 		if (iterFind == mParamLookup.end())
+			return (UINT32)-1;
+
+		return iterFind->second;
+	}
+
+	MaterialParamsBase::GetParamResult MaterialParamsBase::getParamData(const String& name, ParamType type, 
+		GpuParamDataType dataType, UINT32 arrayIdx, const ParamData** output) const
+	{
+		UINT32 index = getParamIndex(name);
+		if(index == -1)
 			return GetParamResult::NotFound;
 			return GetParamResult::NotFound;
 
 
-		const ParamData& param = mParams[iterFind->second];
+		const ParamData& param = mParams[index];
 		*output = &param;
 		*output = &param;
 
 
 		if (param.type != type || (type == ParamType::Data && param.dataType != dataType))
 		if (param.type != type || (type == ParamType::Data && param.dataType != dataType))
@@ -137,6 +146,15 @@ namespace BansheeEngine
 		return GetParamResult::Success;
 		return GetParamResult::Success;
 	}
 	}
 
 
+	const MaterialParamsBase::ParamData* MaterialParamsBase::getParamData(UINT32 index) const
+	{
+		if (index == -1)
+			return nullptr;
+
+		const ParamData& param = mParams[index];
+		return &param;
+	}
+
 	void MaterialParamsBase::reportGetParamError(GetParamResult errorCode, const String& name, UINT32 arrayIdx) const
 	void MaterialParamsBase::reportGetParamError(GetParamResult errorCode, const String& name, UINT32 arrayIdx) const
 	{
 	{
 		switch (errorCode)
 		switch (errorCode)

+ 4 - 4
Source/RenderBeast/Source/BsRenderBeast.cpp

@@ -183,7 +183,7 @@ namespace BansheeEngine
 					matInfo.params[0] = renElement.material->createParamsSet(0);
 					matInfo.params[0] = renElement.material->createParamsSet(0);
 					matInfo.matVersion = renElement.material->getVersion();
 					matInfo.matVersion = renElement.material->getVersion();
 
 
-					renElement.material->updateParamsSet(matInfo.params[0], 0, true);
+					renElement.material->updateParamsSet(matInfo.params[0], true);
 					renElement.material->setRendererData(matInfo);
 					renElement.material->setRendererData(matInfo);
 					renElement.params = matInfo.params[0];
 					renElement.params = matInfo.params[0];
 				}
 				}
@@ -198,7 +198,7 @@ namespace BansheeEngine
 						matInfo.params[0] = renElement.material->createParamsSet(0);
 						matInfo.params[0] = renElement.material->createParamsSet(0);
 						matInfo.matVersion = renElement.material->getVersion();
 						matInfo.matVersion = renElement.material->getVersion();
 
 
-						renElement.material->updateParamsSet(matInfo.params[0], 0, true);
+						renElement.material->updateParamsSet(matInfo.params[0], true);
 					}
 					}
 
 
 					renElement.params = matInfo.params[0];
 					renElement.params = matInfo.params[0];
@@ -801,7 +801,7 @@ namespace BansheeEngine
 	{
 	{
 		for (auto& entry : mSamplerOverrides)
 		for (auto& entry : mSamplerOverrides)
 		{
 		{
-			SPtr<GpuParamsSetCore> paramsSet = entry.first;
+			SPtr<GpuParamsSetCore> paramsSet = nullptr;// entry.first;
 
 
 			if (force)
 			if (force)
 			{
 			{
@@ -818,7 +818,7 @@ namespace BansheeEngine
 				{
 				{
 					PassSamplerOverrides& passOverrides = materialOverrides->passes[i];
 					PassSamplerOverrides& passOverrides = materialOverrides->passes[i];
 
 
-					for (UINT32 j = 0; j < GpuParamsSetCore::NUM_PARAMS; j++)
+					for (UINT32 j = 0; j < GpuParamsSetCore::NUM_STAGES; j++)
 					{
 					{
 						StageSamplerOverrides& stageOverrides = passOverrides.stages[j];
 						StageSamplerOverrides& stageOverrides = passOverrides.stages[j];
 
 

+ 4 - 4
Source/RenderBeast/Source/BsSamplerOverrides.cpp

@@ -21,7 +21,7 @@ namespace BansheeEngine
 		{
 		{
 			UINT32 maxSamplerSlot = 0;
 			UINT32 maxSamplerSlot = 0;
 
 
-			for (UINT32 j = 0; j < GpuParamsSetCore::NUM_PARAMS; j++)
+			for (UINT32 j = 0; j < GpuParamsSetCore::NUM_STAGES; j++)
 			{
 			{
 				SPtr<GpuParamsCore> params = paramsSet->getParamByIdx(j, i);
 				SPtr<GpuParamsCore> params = paramsSet->getParamByIdx(j, i);
 				if (params == nullptr)
 				if (params == nullptr)
@@ -40,7 +40,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		UINT32 outputSize = sizeof(MaterialSamplerOverrides) +
 		UINT32 outputSize = sizeof(MaterialSamplerOverrides) +
-			numPasses * (sizeof(PassSamplerOverrides) + GpuParamsSetCore::NUM_PARAMS * sizeof(StageSamplerOverrides)) +
+			numPasses * (sizeof(PassSamplerOverrides) + GpuParamsSetCore::NUM_STAGES * sizeof(StageSamplerOverrides)) +
 			totalNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 			totalNumSamplerStates * sizeof(SPtr<SamplerStateCore>);
 
 
 		UINT8* outputData = (UINT8*)bs_alloc(outputSize);
 		UINT8* outputData = (UINT8*)bs_alloc(outputSize);
@@ -59,9 +59,9 @@ namespace BansheeEngine
 			for (UINT32 i = 0; i < numPasses; i++)
 			for (UINT32 i = 0; i < numPasses; i++)
 			{
 			{
 				PassSamplerOverrides& passOverrides = output->passes[i];
 				PassSamplerOverrides& passOverrides = output->passes[i];
-				passOverrides.numStages = GpuParamsSetCore::NUM_PARAMS;
+				passOverrides.numStages = GpuParamsSetCore::NUM_STAGES;
 				passOverrides.stages = (StageSamplerOverrides*)outputData;
 				passOverrides.stages = (StageSamplerOverrides*)outputData;
-				outputData += sizeof(StageSamplerOverrides) * GpuParamsSetCore::NUM_PARAMS;
+				outputData += sizeof(StageSamplerOverrides) * GpuParamsSetCore::NUM_STAGES;
 
 
 				for (UINT32 j = 0; j < passOverrides.numStages; j++)
 				for (UINT32 j = 0; j < passOverrides.numStages; j++)
 				{
 				{