Explorar o código

Shader can now have one object parameter reference multiple GPU variables, in case variables have different names across different render systems

Marko Pintera %!s(int64=11) %!d(string=hai) anos
pai
achega
c256b7e5d5

+ 1 - 1
BansheeCore/Include/BsMaterial.h

@@ -521,7 +521,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Constructs a list containing all object parameter (e.g. texture, sampler state) names.
 		 */
-		Set<String> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const;
+		Vector<const GpuParamObjectDesc*> determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const;
 
 		/**
 		 * @brief	Constructs a list containing all shareable parameter block names. Shareable blocks may be shared between

+ 7 - 2
BansheeCore/Include/BsShader.h

@@ -37,7 +37,7 @@ namespace BansheeEngine
 	struct BS_CORE_EXPORT SHADER_OBJECT_PARAM_DESC
 	{
 		String name;
-		String gpuVariableName;
+		Vector<String> gpuVariableNames;
 		UINT32 rendererSemantic;
 		GpuParamObjectType type;
 	};
@@ -168,6 +168,8 @@ namespace BansheeEngine
 		/**
 		 * @brief	Registers a new object (texture, sampler state, etc.) parameter you that you may then use 
 		 *			via Material by providing the parameter name. All parameters internally map to variables defined in GPU programs.
+		 *			Multiple GPU variables may be mapped to a single parameter in which case the first variable actually found in the program
+		 *			will be used while others will be ignored.
 		 *
 		 * @param	name		   	The name of the parameter. Name must be unique between all data and object parameters.
 		 * @param	gpuVariableName	Name of the GPU variable in the GpuProgram that the parameter corresponds with.
@@ -176,6 +178,9 @@ namespace BansheeEngine
 		 *							 depends on the current Renderer and its supported list of semantics. Elements with renderer semantics should not be updated
 		 *							 by the user, and will be updated by the renderer. These semantics will also be used to determine if a shader is compatible
 		 *							 with a specific renderer or not. Value of 0 signifies the parameter is not used by the renderer.
+		 *
+		 * @note	Mapping multiple GPU variables to a single parameter is useful when you are defining a shader that supports techniques across different render
+		 *			systems where GPU variable names for the same parameters might differ.
 		 */
 		void addParameter(const String& name, const String& gpuVariableName, GpuParamObjectType type, UINT32 rendererSemantic = 0);
 
@@ -237,7 +242,7 @@ namespace BansheeEngine
 		const Map<String, SHADER_DATA_PARAM_DESC>& _getDataParams() const { return mDataParams; }
 
 		/** 
-		 * @brief	Returns a map of all object parameters in the shader.
+		 * @brief	Returns a map of all object parameters in the shader. 
 		 * 			
 		 * @note	Internal method.
 		 */

+ 3 - 3
BansheeCore/Include/BsShaderRTTI.h

@@ -74,7 +74,7 @@ namespace BansheeEngine
 			memory = rttiWriteElem(data.rendererSemantic, memory);
 			memory = rttiWriteElem(data.type, memory);
 			memory = rttiWriteElem(data.name, memory);
-			memory = rttiWriteElem(data.gpuVariableName, memory);
+			memory = rttiWriteElem(data.gpuVariableNames, memory);
 		}
 
 		static UINT32 fromMemory(SHADER_OBJECT_PARAM_DESC& data, char* memory)
@@ -86,7 +86,7 @@ namespace BansheeEngine
 			memory = rttiReadElem(data.rendererSemantic, memory);
 			memory = rttiReadElem(data.type, memory);
 			memory = rttiReadElem(data.name, memory);
-			memory = rttiReadElem(data.gpuVariableName, memory);
+			memory = rttiReadElem(data.gpuVariableNames, memory);
 
 			return size;
 		}
@@ -94,7 +94,7 @@ namespace BansheeEngine
 		static UINT32 getDynamicSize(const SHADER_OBJECT_PARAM_DESC& data)	
 		{ 
 			UINT64 dataSize = rttiGetElemSize(data.rendererSemantic) + rttiGetElemSize(data.type) +
-				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableName) + sizeof(UINT32);
+				rttiGetElemSize(data.name) + rttiGetElemSize(data.gpuVariableNames) + sizeof(UINT32);
 
 #if BS_DEBUG_MODE
 			if(dataSize > std::numeric_limits<UINT32>::max())

+ 18 - 16
BansheeCore/Source/BsMaterial.cpp

@@ -101,7 +101,7 @@ namespace BansheeEngine
 
 			// Fill out various helper structures
 			Map<String, const GpuParamDataDesc*> validDataParameters = determineValidDataParameters(allParamDescs);
-			Set<String> validObjectParameters = determineValidObjectParameters(allParamDescs);
+			Vector<const GpuParamObjectDesc*> validObjectParameters = determineValidObjectParameters(allParamDescs);
 
 			Set<String> validShareableParamBlocks = determineValidShareableParamBlocks(allParamDescs);
 			Map<String, String> paramToParamBlockMap = determineParameterToBlockMapping(allParamDescs);
@@ -181,13 +181,18 @@ namespace BansheeEngine
 			const Map<String, SHADER_OBJECT_PARAM_DESC>& objectParamDesc = mShader->_getObjectParams();
 			for(auto iter = objectParamDesc.begin(); iter != objectParamDesc.end(); ++iter)
 			{
-				auto findIter = validObjectParameters.find(iter->second.gpuVariableName);
-
-				// Not valid so we skip it
-				if(findIter == validObjectParameters.end())
-					continue;
-
-				mValidParams[iter->first] = iter->second.gpuVariableName;
+				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)
+						{
+							mValidParams[iter->first] = *iter2;
+							break;
+						}
+					}
+				}
 			}
 
 			for(UINT32 i = 0; i < mBestTechnique->getNumPasses(); i++)
@@ -305,9 +310,9 @@ namespace BansheeEngine
 		return foundDataParams;
 	}
 
-	Set<String> Material::determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const
+	Vector<const GpuParamObjectDesc*> Material::determineValidObjectParameters(const Vector<GpuParamDescPtr>& paramDescs) const
 	{
-		Set<String> validParams;
+		Vector<const GpuParamObjectDesc*> validParams;
 
 		for(auto iter = paramDescs.begin(); iter != paramDescs.end(); ++iter)
 		{
@@ -316,22 +321,19 @@ namespace BansheeEngine
 			// Check sampler params
 			for(auto iter2 = curDesc.samplers.begin(); iter2 != curDesc.samplers.end(); ++iter2)
 			{
-				if(validParams.find(iter2->first) == validParams.end())
-					validParams.insert(iter2->first);
+				validParams.push_back(&iter2->second);
 			}
 
 			// Check texture params
 			for(auto iter2 = curDesc.textures.begin(); iter2 != curDesc.textures.end(); ++iter2)
 			{
-				if(validParams.find(iter2->first) == validParams.end())
-					validParams.insert(iter2->first);
+				validParams.push_back(&iter2->second);
 			}
 
 			// Check buffer params
 			for(auto iter2 = curDesc.buffers.begin(); iter2 != curDesc.buffers.end(); ++iter2)
 			{
-				if(validParams.find(iter2->first) == validParams.end())
-					validParams.insert(iter2->first);
+				validParams.push_back(&iter2->second);
 			}
 		}
 

+ 33 - 6
BansheeCore/Source/BsShader.cpp

@@ -105,13 +105,40 @@ namespace BansheeEngine
 
 	void Shader::addParameter(const String& name, const String& gpuVariableName, GpuParamObjectType type, UINT32 rendererSemantic)
 	{
-		SHADER_OBJECT_PARAM_DESC desc;
-		desc.name = name;
-		desc.gpuVariableName = gpuVariableName;
-		desc.type = type;
-		desc.rendererSemantic = rendererSemantic;
+		auto iterFind = mObjectParams.find(name);
+
+		if (iterFind == mObjectParams.end())
+		{
+			SHADER_OBJECT_PARAM_DESC desc;
+			desc.name = name;
+			desc.type = type;
+			desc.rendererSemantic = rendererSemantic;
+			desc.gpuVariableNames.push_back(gpuVariableName);
+
+			mObjectParams[name] = desc;
+		}
+		else
+		{
+			SHADER_OBJECT_PARAM_DESC& desc = iterFind->second;
+
+			if (desc.type != type || desc.rendererSemantic != rendererSemantic)
+				BS_EXCEPT(InvalidParametersException, "Shader parameter with the name \"" + name + "\" already exists with different properties.");
+
+			Vector<String>& gpuVariableNames = desc.gpuVariableNames;
+			bool found = false;
+			for (UINT32 i = 0; i < (UINT32)gpuVariableNames.size(); i++)
+			{
+				if (gpuVariableNames[i] == gpuVariableName)
+				{
+					found = true;
+					break;
+				}
+			}
+
+			if (!found)
+				gpuVariableNames.push_back(gpuVariableName);
+		}
 
-		mObjectParams[name] = desc;
 		mDataParams.erase(name);
 
 		markCoreDirty();

+ 4 - 8
BansheeEngine/Source/BsBuiltinResources.cpp

@@ -840,10 +840,8 @@ namespace BansheeEngine
 		mShaderSpriteText->addParameter("invViewportWidth", "invViewportWidth", GPDT_FLOAT1);
 		mShaderSpriteText->addParameter("invViewportHeight", "invViewportHeight", GPDT_FLOAT1);
 
-		if (mRenderSystemPlugin == RenderSystemPlugin::DX11) // TODO: Find a way to avoid this
-			mShaderSpriteText->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);
-		else
-			mShaderSpriteText->addParameter("mainTexSamp", "mainTexture", GPOT_SAMPLER2D);
+		mShaderSpriteText->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);
+		mShaderSpriteText->addParameter("mainTexSamp", "mainTexture", GPOT_SAMPLER2D);
 
 		mShaderSpriteText->addParameter("mainTexture", "mainTexture", GPOT_TEXTURE2D);
 		mShaderSpriteText->addParameter("tint", "tint", GPDT_FLOAT4);
@@ -882,10 +880,8 @@ namespace BansheeEngine
 		mShaderSpriteImage->addParameter("invViewportWidth", "invViewportWidth", GPDT_FLOAT1);
 		mShaderSpriteImage->addParameter("invViewportHeight", "invViewportHeight", GPDT_FLOAT1);
 
-		if (mRenderSystemPlugin == RenderSystemPlugin::DX11) // TODO: Find a way to avoid this
-			mShaderSpriteImage->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);
-		else
-			mShaderSpriteImage->addParameter("mainTexSamp", "mainTexture", GPOT_SAMPLER2D);
+		mShaderSpriteImage->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);
+		mShaderSpriteImage->addParameter("mainTexSamp", "mainTexture", GPOT_SAMPLER2D);
 
 		mShaderSpriteImage->addParameter("mainTexture", "mainTexture", GPOT_TEXTURE2D);
 		mShaderSpriteImage->addParameter("tint", "tint", GPDT_FLOAT4);

+ 0 - 2
SceneView.txt

@@ -6,9 +6,7 @@ Weekend:
  - Set up grid material and hook it up to renderer (+ actually instantiate it in EditorApplication)
  
  - Fix up shader so I can reference two different gpu vars with a single shader var (e.g. DX11 sampler variables will have different names than DX9 or GL sampler variables)
- - You can create a resource handle to invalid resource type. Add a security feature to prevent that, at least in debug mode?
  - When unloading unused resources I should do it recursively so it unloads any new ones that might have been released during the first unload
- - Ensure that resource handles only have a single mData (and fix Resources::unloadAllUnused)
 
  - Think about picking implementation and possibly Handles implementation