Browse Source

Added D3D9 emulated param blocks

Marko Pintera 11 years ago
parent
commit
9e2e375839

+ 2 - 1
BansheeCore/Include/BsCorePrerequisites.h

@@ -295,7 +295,8 @@ namespace BansheeEngine
 		TID_MeshBase = 1065,
 		TID_MeshBase = 1065,
 		TID_GameObjectHandleBase = 1066,
 		TID_GameObjectHandleBase = 1066,
 		TID_ResourceManifest = 1067,
 		TID_ResourceManifest = 1067,
-		TID_ResourceManifestEntry = 1068
+		TID_ResourceManifestEntry = 1068,
+		TID_EmulatedParamBlock = 1069
 	};
 	};
 }
 }
 
 

+ 2 - 0
BansheeD3D9RenderSystem/BansheeD3D9RenderSystem.vcxproj

@@ -237,6 +237,7 @@
     <ClInclude Include="Include\BsD3D9DeviceManager.h" />
     <ClInclude Include="Include\BsD3D9DeviceManager.h" />
     <ClInclude Include="Include\BsD3D9Driver.h" />
     <ClInclude Include="Include\BsD3D9Driver.h" />
     <ClInclude Include="Include\BsD3D9DriverList.h" />
     <ClInclude Include="Include\BsD3D9DriverList.h" />
+    <ClInclude Include="Include\BsD3D9EmulatedParamBlocks.h" />
     <ClInclude Include="Include\BsD3D9EventQuery.h" />
     <ClInclude Include="Include\BsD3D9EventQuery.h" />
     <ClInclude Include="Include\BsD3D9GpuBuffer.h" />
     <ClInclude Include="Include\BsD3D9GpuBuffer.h" />
     <ClInclude Include="Include\BsD3D9GpuProgram.h" />
     <ClInclude Include="Include\BsD3D9GpuProgram.h" />
@@ -271,6 +272,7 @@
     <ClCompile Include="Source\BsD3D9DeviceManager.cpp" />
     <ClCompile Include="Source\BsD3D9DeviceManager.cpp" />
     <ClCompile Include="Source\BsD3D9Driver.cpp" />
     <ClCompile Include="Source\BsD3D9Driver.cpp" />
     <ClCompile Include="Source\BsD3D9DriverList.cpp" />
     <ClCompile Include="Source\BsD3D9DriverList.cpp" />
+    <ClCompile Include="Source\BsD3D9EmulatedParamBlocks.cpp" />
     <ClCompile Include="Source\BsD3D9EventQuery.cpp" />
     <ClCompile Include="Source\BsD3D9EventQuery.cpp" />
     <ClCompile Include="Source\BsD3D9GpuBuffer.cpp" />
     <ClCompile Include="Source\BsD3D9GpuBuffer.cpp" />
     <ClCompile Include="Source\BsD3D9GpuProgram.cpp" />
     <ClCompile Include="Source\BsD3D9GpuProgram.cpp" />

+ 6 - 0
BansheeD3D9RenderSystem/BansheeD3D9RenderSystem.vcxproj.filters

@@ -111,6 +111,9 @@
     <ClInclude Include="Include\BsD3D9GpuProgramRTTI.h">
     <ClInclude Include="Include\BsD3D9GpuProgramRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\BsD3D9EmulatedParamBlocks.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsD3D9VideoModeInfo.cpp">
     <ClCompile Include="Source\BsD3D9VideoModeInfo.cpp">
@@ -200,5 +203,8 @@
     <ClCompile Include="Source\BsD3D9Device.cpp">
     <ClCompile Include="Source\BsD3D9Device.cpp">
       <Filter>Source Files</Filter>
       <Filter>Source Files</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\BsD3D9EmulatedParamBlocks.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 35 - 0
BansheeD3D9RenderSystem/Include/BsD3D9EmulatedParamBlocks.h

@@ -0,0 +1,35 @@
+#pragma once
+
+#include "BsD3D9Prerequisites.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Represents a parameter block that can be used with GPU programs
+	 *			that do not support them natively. Each block is defined with a unique
+	 *			name (user defined) and a set of parameter names belonging to that block
+	 *			(names must reference actual GPU variables).
+	 */
+	struct D3D9EmulatedParamBlock
+	{
+		String blockName;
+		Vector<String> paramNames;
+	};
+
+	/**
+	 * @brief	Parses GPU program source and retrieves 
+	 *			parameter blocks from it.
+	 */
+	class D3D9EmulatedParamBlockParser
+	{
+	public:
+		/**
+		 * Parses GPU program source and retrieves parameter blocks from it. Returns
+		 * source without parameter block code.
+		 *
+		 * Parameter blocks can be anywhere in the source file and they must follow this exact structure:
+		 *  BS_PARAM_BLOCK blockName { param1, param2, etc }
+		 */
+		static String parse(const String& gpuProgSource, Vector<D3D9EmulatedParamBlock>& paramBlocks);
+	};
+}

+ 2 - 0
BansheeD3D9RenderSystem/Include/BsD3D9GpuProgram.h

@@ -3,6 +3,7 @@
 #include "BsD3D9Prerequisites.h"
 #include "BsD3D9Prerequisites.h"
 #include "BsGpuProgram.h"
 #include "BsGpuProgram.h"
 #include "BsD3D9Resource.h"
 #include "BsD3D9Resource.h"
+#include "BsD3D9EmulatedParamBlocks.h"
 
 
 namespace BansheeEngine 
 namespace BansheeEngine 
 {
 {
@@ -70,6 +71,7 @@ namespace BansheeEngine
 	protected:    
 	protected:    
 		OptimizationLevel mOptimisationLevel;
 		OptimizationLevel mOptimisationLevel;
 		String mPreprocessorDefines;
 		String mPreprocessorDefines;
+		Vector<D3D9EmulatedParamBlock> mBlocks;
 		bool mColumnMajorMatrices;
 		bool mColumnMajorMatrices;
 		ID3DXBuffer* mMicrocode;
 		ID3DXBuffer* mMicrocode;
 
 

+ 67 - 24
BansheeD3D9RenderSystem/Include/BsD3D9HLSLParamParser.h

@@ -1,27 +1,54 @@
 #pragma once
 #pragma once
 
 
 #include "BsD3D9Prerequisites.h"
 #include "BsD3D9Prerequisites.h"
+#include "BsD3D9GpuProgram.h"
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
 	class D3D9HLSLParamParser
 	class D3D9HLSLParamParser
 	{
 	{
 	public:
 	public:
-		D3D9HLSLParamParser(LPD3DXCONSTANTTABLE constTable)
-			:mpConstTable(constTable)
+		D3D9HLSLParamParser(LPD3DXCONSTANTTABLE constTable, const Vector<D3D9EmulatedParamBlock>& blocks)
+			:mpConstTable(constTable), mBlocks(blocks)
 		{ }
 		{ }
 
 
 		GpuParamDesc buildParameterDescriptions();
 		GpuParamDesc buildParameterDescriptions();
 
 
 	private:
 	private:
-		void processParameter(GpuParamBlockDesc& blockDesc, D3DXHANDLE parent, String prefix, UINT32 index);
+		void processParameter(GpuParamBlockDesc& blockDesc, const String& paramName, D3DXHANDLE constant,
+			String prefix, UINT32 index);
 		void populateParamMemberDesc(GpuParamDataDesc& memberDesc, D3DXCONSTANT_DESC& d3dDesc);
 		void populateParamMemberDesc(GpuParamDataDesc& memberDesc, D3DXCONSTANT_DESC& d3dDesc);
 
 
+		String getParamName(D3DXHANDLE constant);
+
 	private:
 	private:
 		LPD3DXCONSTANTTABLE mpConstTable;
 		LPD3DXCONSTANTTABLE mpConstTable;
+		Vector<D3D9EmulatedParamBlock> mBlocks;
 		GpuParamDesc mParamDesc;
 		GpuParamDesc mParamDesc;
 	};
 	};
 
 
+	String D3D9HLSLParamParser::getParamName(D3DXHANDLE constant)
+	{
+		D3DXCONSTANT_DESC desc;
+		UINT32 numParams = 1;
+		HRESULT hr = mpConstTable->GetConstantDesc(constant, &desc, &numParams);
+		if (FAILED(hr))
+		{
+			BS_EXCEPT(InternalErrorException, "Cannot retrieve constant description from HLSL program.");
+		}
+
+		String paramName = desc.Name;
+		// trim the odd '$' which appears at the start of the names in HLSL
+		if (paramName.at(0) == '$')
+			paramName.erase(paramName.begin());
+
+		// Also trim the '[0]' suffix if it exists, we will add our own indexing later
+		if (StringUtil::endsWith(paramName, "[0]", false))
+			paramName.erase(paramName.size() - 3);
+
+		return paramName;
+	}
+
 	GpuParamDesc D3D9HLSLParamParser::buildParameterDescriptions()
 	GpuParamDesc D3D9HLSLParamParser::buildParameterDescriptions()
 	{
 	{
 		// Derive parameter names from const table
 		// Derive parameter names from const table
@@ -34,49 +61,62 @@ namespace BansheeEngine
 		if (FAILED(hr))
 		if (FAILED(hr))
 			BS_EXCEPT(InternalErrorException, "Cannot retrieve constant descriptions from HLSL program.");
 			BS_EXCEPT(InternalErrorException, "Cannot retrieve constant descriptions from HLSL program.");
 
 
-		// DX9 has no concept of parameter blocks so we just put all members in one global block
+		// DX9 has no concept of parameter blocks so we emulate them if needed
 		String name = "BS_INTERNAL_Globals";
 		String name = "BS_INTERNAL_Globals";
 		mParamDesc.paramBlocks.insert(std::make_pair(name, GpuParamBlockDesc()));
 		mParamDesc.paramBlocks.insert(std::make_pair(name, GpuParamBlockDesc()));
-		GpuParamBlockDesc& blockDesc = mParamDesc.paramBlocks[name];
-		blockDesc.name = name;
-		blockDesc.slot = 0;
-		blockDesc.blockSize = 0;
-		blockDesc.isShareable = false;
+		GpuParamBlockDesc& globalBlockDesc = mParamDesc.paramBlocks[name];
+		globalBlockDesc.name = name;
+		globalBlockDesc.slot = 0;
+		globalBlockDesc.blockSize = 0;
+		globalBlockDesc.isShareable = false;
+
+		UnorderedMap<String, String> nonGlobalBlocks;
+		UINT32 curSlot = 1;
+		for (auto& block : mBlocks)
+		{
+			mParamDesc.paramBlocks.insert(std::make_pair(block.blockName, GpuParamBlockDesc()));
+			GpuParamBlockDesc& blockDesc = mParamDesc.paramBlocks[block.blockName];
+			globalBlockDesc.name = block.blockName;
+			globalBlockDesc.slot = curSlot++;
+			globalBlockDesc.blockSize = 0;
+			globalBlockDesc.isShareable = true;
+
+			for (auto& fieldName : block.paramNames)
+			{
+				nonGlobalBlocks.insert(std::make_pair(fieldName, block.blockName));
+			}
+		}
 
 
 		// Iterate over the constants
 		// Iterate over the constants
 		for (UINT32 i = 0; i < desc.Constants; ++i)
 		for (UINT32 i = 0; i < desc.Constants; ++i)
 		{
 		{
+			D3DXHANDLE constantHandle = mpConstTable->GetConstant(NULL, i);
+			String paramName = getParamName(constantHandle);
+
 			// Recursively descend through the structure levels
 			// Recursively descend through the structure levels
-			processParameter(blockDesc, NULL, "", i);
+			auto findIter = nonGlobalBlocks.find(paramName);
+			if (findIter == nonGlobalBlocks.end())
+				processParameter(globalBlockDesc, paramName, constantHandle, "", i);
+			else
+				processParameter(mParamDesc.paramBlocks[findIter->second], paramName, constantHandle, "", i);
 		}
 		}
 
 
 		return mParamDesc;
 		return mParamDesc;
 	}
 	}
 
 
-	void D3D9HLSLParamParser::processParameter(GpuParamBlockDesc& blockDesc, D3DXHANDLE parent, String prefix, UINT32 index)
+	void D3D9HLSLParamParser::processParameter(GpuParamBlockDesc& blockDesc, const String& paramName, D3DXHANDLE constant, String prefix, UINT32 index)
 	{
 	{
-		D3DXHANDLE hConstant = mpConstTable->GetConstant(parent, index);
-
 		// Since D3D HLSL doesn't deal with naming of array and struct parameters
 		// Since D3D HLSL doesn't deal with naming of array and struct parameters
 		// automatically, we have to do it by hand
 		// automatically, we have to do it by hand
 
 
 		D3DXCONSTANT_DESC desc;
 		D3DXCONSTANT_DESC desc;
 		UINT32 numParams = 1;
 		UINT32 numParams = 1;
-		HRESULT hr = mpConstTable->GetConstantDesc(hConstant, &desc, &numParams);
+		HRESULT hr = mpConstTable->GetConstantDesc(constant, &desc, &numParams);
 		if (FAILED(hr))
 		if (FAILED(hr))
 		{
 		{
 			BS_EXCEPT(InternalErrorException, "Cannot retrieve constant description from HLSL program.");
 			BS_EXCEPT(InternalErrorException, "Cannot retrieve constant description from HLSL program.");
 		}
 		}
 
 
-		String paramName = desc.Name;
-		// trim the odd '$' which appears at the start of the names in HLSL
-		if (paramName.at(0) == '$')
-			paramName.erase(paramName.begin());
-
-		// Also trim the '[0]' suffix if it exists, we will add our own indexing later
-		if (StringUtil::endsWith(paramName, "[0]", false))
-			paramName.erase(paramName.size() - 3);
-
 		if (desc.Class == D3DXPC_STRUCT)
 		if (desc.Class == D3DXPC_STRUCT)
 		{
 		{
 			// work out a new prefix for nested members, if it's an array, we need an index
 			// work out a new prefix for nested members, if it's an array, we need an index
@@ -84,7 +124,10 @@ namespace BansheeEngine
 			// Cascade into struct
 			// Cascade into struct
 			for (UINT32 i = 0; i < desc.StructMembers; ++i)
 			for (UINT32 i = 0; i < desc.StructMembers; ++i)
 			{
 			{
-				processParameter(blockDesc, hConstant, prefix, i);
+				D3DXHANDLE childHandle = mpConstTable->GetConstant(constant, i);
+				String childParamName = getParamName(childHandle);
+
+				processParameter(blockDesc, childParamName, childHandle, prefix, i);
 			}
 			}
 		}
 		}
 		else
 		else

+ 44 - 0
BansheeD3D9RenderSystem/Source/BsD3D9EmulatedParamBlocks.cpp

@@ -0,0 +1,44 @@
+#include "BsD3D9EmulatedParamBlocks.h"
+#include <regex>
+
+namespace BansheeEngine
+{
+	String D3D9EmulatedParamBlockParser::parse(const String& gpuProgSource, Vector<D3D9EmulatedParamBlock>& paramBlocks)
+	{
+		static std::regex paramBlockRegex("BS_PARAM_BLOCK\\s*(.*})");
+		static std::regex blockNameRegex("([^\\s{]*)");
+		static std::regex paramNameRegex("(?:{ *([^\\, ]*))|(?:\\, *([^\\, }]*))");
+		static std::regex replaceRegex("BS_PARAM_BLOCK\\s*(.*}\\n?)");
+
+		std::sregex_iterator paramBlockIter(gpuProgSource.begin(), gpuProgSource.end(), paramBlockRegex);
+		std::sregex_iterator iterEnd;
+
+		while (paramBlockIter != iterEnd)
+		{
+			std::string stdString = paramBlockIter->str();
+			String paramBlockString = String(stdString.begin(), stdString.end());
+
+			paramBlocks.push_back(D3D9EmulatedParamBlock());
+			D3D9EmulatedParamBlock& block = paramBlocks.back();
+
+			std::smatch nameMatch;
+			if (std::regex_search(paramBlockString, nameMatch, blockNameRegex))
+			{
+				stdString = nameMatch.str();
+				block.blockName = String(stdString.begin(), stdString.end());
+			}
+
+			std::sregex_iterator paramNameIter(paramBlockString.begin(), paramBlockString.end(), paramNameRegex);
+			while (paramNameIter != iterEnd)
+			{
+				stdString = paramNameIter->str();
+				block.paramNames.push_back(String(stdString.begin(), stdString.end()));
+			}
+
+			paramBlockIter++;
+		}
+
+		// Return string without param block definitions
+		return std::regex_replace(gpuProgSource, replaceRegex, "");
+	}
+}

+ 3 - 1
BansheeD3D9RenderSystem/Source/BsD3D9GpuProgram.cpp

@@ -147,6 +147,8 @@ namespace BansheeEngine
 
 
 		String hlslProfile = D3D9RenderSystem::instance().getCapabilities()->gpuProgProfileToRSSpecificProfile(mProfile);
 		String hlslProfile = D3D9RenderSystem::instance().getCapabilities()->gpuProgProfileToRSSpecificProfile(mProfile);
 
 
+		mSource = D3D9EmulatedParamBlockParser::parse(mSource, mBlocks);
+
 		// Compile & assemble into microcode
 		// Compile & assemble into microcode
 		HRESULT hr = D3DXCompileShader(
 		HRESULT hr = D3DXCompileShader(
 			mSource.c_str(),
 			mSource.c_str(),
@@ -184,7 +186,7 @@ namespace BansheeEngine
 				createInternalResources(d3d9Device);
 				createInternalResources(d3d9Device);
 			}
 			}
 
 
-			D3D9HLSLParamParser paramParser(constTable);
+			D3D9HLSLParamParser paramParser(constTable, mBlocks);
 			mParametersDesc = paramParser.buildParameterDescriptions();
 			mParametersDesc = paramParser.buildParameterDescriptions();
 
 
 			mIsCompiled = true;
 			mIsCompiled = true;