public VFetchXboxMethodExtractor(SourceShader shader, HlslTechnique technique)
		{
			this.source = shader;

			HlslMethod method = shader.GetMethod(technique.VertexShaderMethodName, Platform.Xbox);
			if (method != null && method.UsesVFetch)
			{
				vsCode = ProcessMethod(method, technique.VertexShaderArgs, ShaderProfile.VS_3_0);
			}

			method = shader.GetMethod(technique.PixelShaderVersion, Platform.Xbox); //pixel shader using vfetch?!
			if (method != null && method.UsesVFetch)
			{
				psCode = ProcessMethod(method, technique.PixelShaderArgs, ShaderProfile.PS_3_0);
			}
		}
Esempio n. 2
0
        public VFetchXboxMethodExtractor(SourceShader shader, HlslTechnique technique)
        {
            this.source = shader;

            HlslMethod method = shader.GetMethod(technique.VertexShaderMethodName, Platform.Xbox);

            if (method != null && method.UsesVFetch)
            {
                vsCode = ProcessMethod(method, technique.VertexShaderArgs, ShaderProfile.VS_3_0);
            }

            method = shader.GetMethod(technique.PixelShaderVersion, Platform.Xbox);             //pixel shader using vfetch?!
            if (method != null && method.UsesVFetch)
            {
                psCode = ProcessMethod(method, technique.PixelShaderArgs, ShaderProfile.PS_3_0);
            }
        }
		public static byte[] Generate(SourceShader source, HlslTechnique technique, Platform platform)
		{

		//	ShaderExtensionGenerator exGen = new ShaderExtensionGenerator(source, platform);

			TokenRename vsRename, psRename;
			TokenRename vsBlendRename, vsInstanceRename;

			vsRename = new TokenRename(source, platform, "VS");
			psRename = new TokenRename(source, platform, "PS");

			vsBlendRename = new TokenRename(source, platform, "VS_B");
			vsInstanceRename = new TokenRename(source, platform, "VS_I");

			HlslMethod methodVS = source.GetMethod(technique.VertexShaderMethodName, platform);
			HlslMethod methodPS = source.GetMethod(technique.PixelShaderMethodName, platform);
			
			HlslMethod methodBlending = source.GetMethod(technique.BlendingShaderMethodName, platform);
			HlslMethod methodInstancing = source.GetMethod(technique.InstancingShaderMethodName, platform);

			if (methodPS == null || methodVS == null)
				return null;

			string vsPrefix, psPrefix;

			AsmTechnique asmTechnique = source.GetAsmTechnique(technique.Name, platform);
			vsPrefix = BuildMapping(asmTechnique, "vs", asmTechnique.VertexShader.RegisterSet);
			psPrefix = BuildMapping(asmTechnique, "ps", asmTechnique.PixelShader.RegisterSet);

			string blendingPrefix = null, instancingPrefix = null;
			if (asmTechnique.BlendingShader != null)
				blendingPrefix = BuildMapping(asmTechnique, "vsb", asmTechnique.BlendingShader.RegisterSet);
			if (asmTechnique.InstancingShader != null)
				instancingPrefix = BuildMapping(asmTechnique, "vsi", asmTechnique.InstancingShader.RegisterSet);

			//build the method bodies for the technique

			//process through all the methods used.
			vsRename.methodList.Add(methodVS);
			psRename.methodList.Add(methodPS);

			if (methodBlending != null) vsBlendRename.methodList.Add(methodBlending);
			if (methodInstancing != null) vsInstanceRename.methodList.Add(methodInstancing);

			//setup remapping for registers used
			MapRegistersToRenamer(vsRename, asmTechnique.VertexShader.RegisterSet, "vs");
			MapRegistersToRenamer(psRename, asmTechnique.PixelShader.RegisterSet, "ps");

			if (asmTechnique.BlendingShader != null)
			{
				MapRegistersToRenamer(vsBlendRename, asmTechnique.VertexShader.RegisterSet, "vs");
				MapRegistersToRenamer(vsBlendRename, asmTechnique.BlendingShader.RegisterSet, "vsb");
			}
			if (asmTechnique.InstancingShader != null)
			{
				MapRegistersToRenamer(vsInstanceRename, asmTechnique.VertexShader.RegisterSet, "vs");
				MapRegistersToRenamer(vsInstanceRename, asmTechnique.InstancingShader.RegisterSet, "vsi");
			}

			//finally, parse all the registers used by the Effect. Dump them in as 'unused'
			RegisterSet decompiledEffectRegisters = source.GetDecompiledEffect(platform).EffectRegisters;

			string unusedSamplerName = "__unused_sampler";
			string unusedFloatName = "__unused_";
			string unusedMatrixName = "__unused4x4_";
			string unusedArrayName = "__unused_array";

			foreach (Register reg in decompiledEffectRegisters)
			{
				if (reg.Name == null || reg.Category == RegisterCategory.Texture)
					continue;
				if (reg.Category == RegisterCategory.Sampler)
				{
					vsRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					psRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					vsBlendRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
					vsInstanceRename.unusedRemapping.Add(reg.Name, unusedSamplerName);
				}
				else
				{
					vsRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					psRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					vsBlendRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
					vsInstanceRename.unusedRemapping.Add(reg.Name, reg.ArraySize > 0 ? unusedArrayName : (reg.Size > 1 ? unusedMatrixName : unusedFloatName));
				}
			}
			//will write booleans down if the values are used.
			vsRename.unusedAccessed = new Dictionary<string, bool>();
			psRename.unusedAccessed = vsRename.unusedAccessed;
			vsBlendRename.unusedAccessed = vsRename.unusedAccessed;
			vsInstanceRename.unusedAccessed = vsRename.unusedAccessed;


			//note, the method list will be added to as new methods are needed by the base method.
			StringBuilder sb = new StringBuilder();

			//extract PS methods
			ExtractMethodBodies(sb, psRename);

			//extract VS methods
			ExtractMethodBodies(sb, vsRename);

			ExtractMethodBodies(sb, vsBlendRename);
			ExtractMethodBodies(sb, vsInstanceRename);

			string techniqueVsName = GetTechniqueInvoke(vsRename, sb, methodVS, technique.VertexShaderArgs);
			string techniquePsName = GetTechniqueInvoke(psRename, sb, methodPS, technique.PixelShaderArgs);

			string techniqueBlendingName = null, techniqueInstancingName = null;

			if (asmTechnique.BlendingShader != null)
				techniqueBlendingName = GetTechniqueInvoke(vsBlendRename, sb, methodBlending, technique.BlendingShaderArgs);
			if (asmTechnique.InstancingShader != null)
				techniqueInstancingName = GetTechniqueInvoke(vsInstanceRename, sb, methodInstancing, technique.InstancingShaderArgs);

			StringBuilder constants = new StringBuilder();

			//work out if any unused values were touched...
			//if so, add them.
			bool addUnusedSampler = false;
			bool addUnusedFloat = false;

			foreach (KeyValuePair<string,bool> item in vsRename.unusedAccessed)
			{
				if (item.Value)
				{
					//something has been used unexpectadly.
					Register reg;
					if (decompiledEffectRegisters.TryGetRegister(item.Key,out reg))
					{
						if (reg.Category == RegisterCategory.Sampler)
							addUnusedSampler = true;
						else
							addUnusedFloat = true;
					}
				}
			}
			if (addUnusedSampler)
				constants.AppendLine("sampler " + unusedSamplerName + ";");
			if (addUnusedFloat)
			{
				constants.AppendLine("const static float4 " + unusedFloatName + " = 0;");
				constants.AppendLine("const static float4x4 " + unusedMatrixName + " = 0;");
				constants.AppendLine("#define " + unusedArrayName + "(__INDEX__) " + unusedFloatName);
			}


			//setup the VS/PS constants
			asmTechnique.ConstructTechniqueConstants(constants, true);

			constants.Append(vsPrefix);
			constants.Append(psPrefix);
			if (blendingPrefix != null) constants.Append(blendingPrefix);
			if (instancingPrefix != null) constants.Append(instancingPrefix);

			constants.AppendLine(ExtractFixedDeclarations(source.HlslShader));

			//finally, build the technique delcaration
			string techniqueStructure =
@"{2}
{3}
technique Shader
{0}
	pass
	{0}
		VertexShader = compile {4} {5};
		PixelShader  = compile {6} {7};
	{1}
{8}{9}{1}";

			string extensionPass =
@"	pass {2}
	{0}
		VertexShader = compile {3} {4};
		PixelShader  = compile {5} {6};
	{1}
";
			string blendExtension = "", instanceExtension = "";

			if (asmTechnique.BlendingShader != null)
			{
				blendExtension = string.Format(extensionPass, "{", "}", "Blending", technique.GetVertexShaderVersion(platform), techniqueBlendingName, technique.GetPixelShaderVersion(platform), techniquePsName);
			}
			if (asmTechnique.InstancingShader != null)
			{
				instanceExtension = string.Format(extensionPass, "{", "}", "Instancing", "vs_3_0", techniqueInstancingName, "ps_3_0", techniquePsName);
			}

			string techniqueSource = string.Format(techniqueStructure, "{", "}", constants, sb,
				technique.GetVertexShaderVersion(platform), techniqueVsName,
				technique.GetPixelShaderVersion(platform), techniquePsName,
				blendExtension,instanceExtension);

			var types = typeof(EffectCompiler).Assembly.GetType("Xen.Graphics.ShaderSystem.EffectCompiler");
			var method = types.GetMethod("CompileEffect");

			CompileEffect effect = Delegate.CreateDelegate(typeof(CompileEffect), types.GetMethod("CompileEffect")) as CompileEffect;

			string compileErrors;
			byte[] compiledEffect = EffectCompiler.CompileEffect(techniqueSource, source.FileName, platform == Platform.Xbox, out compileErrors);

			if (compileErrors != null)
			{
				string[] errors = SanitizeConversionErrorMessage(compileErrors, techniqueSource, source.ShaderSource, source);

				if (source.ManualExtensions == false)
				{
					string errorsLine = "";
					foreach (var error in errors)
						errorsLine += error + Environment.NewLine;

					//error occured in generated code!
					ShaderExtensionGenerator.ThrowGeneratorError(errorsLine.Trim(), source.FileName);
				}
				else
				{
					string header = "XenFX Platform Technique Extraction Failed:";

					if (errors == null)
						Common.ThrowError(header, compileErrors);
					else
						Common.ThrowError(header, errors);
				}
			}

			return compiledEffect;
		}
		private void ExtractMethods(string generatedPrefix)
		{
			string str = this.hlslShader.ToString();

			List<Platform> platformStack = new List<Platform>();

			//pull out methods and techniques, but only from the root level...
			foreach (HlslStructure hs in this.hlslShader.Children)
			{
				//could be an #if, #else, #etc
				if (hs.Children.Length == 0 &&
					hs.Elements.Length > 1 &&
					hs.Elements[0].Statement.Length == 1 &&
					hs.Elements[0].Statement[0] == '#')
				{
					//need to account for #if XBOX360 blocks
					switch (hs.Elements[1].Statement)
					{
						case "if":
						case "ifdef":
							if (hs.Elements.Length > 2)
							{
								if (hs.Elements[2] == "XBOX360" ||
									hs.Elements[2] == "XBOX")
									platformStack.Add(Platform.Xbox);
								else
								if (hs.Elements[2] == "!XBOX360" ||
									hs.Elements[2] == "!XBOX")
									platformStack.Add(Platform.Windows);
								else
									platformStack.Add(Platform.Both);
							}
							break;

						case "ifndef":
							if (hs.Elements.Length > 2)
							{
								if (hs.Elements[2] == "XBOX360" ||
									hs.Elements[2] == "XBOX")
									platformStack.Add(Platform.Windows);
								else
								if (hs.Elements[2] == "!XBOX360" ||
									hs.Elements[2] == "!XBOX")
									platformStack.Add(Platform.Xbox);
								else
									platformStack.Add(Platform.Both);
							}
							break;

						case "else":
							if (platformStack.Count > 0)
							{
								Platform peek = platformStack[platformStack.Count - 1];
								platformStack.RemoveAt(platformStack.Count - 1);

								if (peek == Platform.Xbox)
									platformStack.Add(Platform.Windows);
								if (peek == Platform.Windows)
									platformStack.Add(Platform.Xbox);
							}
							break;
						case "endif":
							if (platformStack.Count > 0)
								platformStack.RemoveAt(platformStack.Count - 1);
							break;
					}
				}


				if (hs.BraceEnclosedChildren) 
				{
					if (hs.Elements.Length > 0 && hs.Elements[0].Statement.Equals("technique", StringComparison.InvariantCultureIgnoreCase))
					{
						//figure out the platform, based on #if blocks stack.
						Platform platform = Platform.Both;
						for (int i = 0; i < platformStack.Count; i++)
							platform &= platformStack[i];

						var technique = new HlslTechnique(hs, platform, generatedPrefix);
						if (technique.IsGenerated || generatedPrefix == null)
							this.techniques.Add(technique);
					}

					//finding a method is a bit trickier

					if (hs.Elements.Length > 2)
					{
						//should have a (...) block in it to be a method...
						int openDepth = 0;
						for (int i = 2; i < hs.Elements.Length; i++)
						{
							if (hs.Elements[i] == "(")
								openDepth++;

							if (hs.Elements[i] == ")")
							{
								if (--openDepth == 0)
								{
									//figure out the platform, based on #if blocks stack.
									Platform platform = Platform.Both;
									for (int p = 0; p < platformStack.Count; p++)
										platform &= platformStack[p];

									//found the method.
									this.methods.Add(new HlslMethod(hs, platform));
									break;
								}
							}
						}
					}
				}
			}

			foreach (SourceShader child in this.includedSource)
				child.ExtractMethods(generatedPrefix);
		}
		private string ProcessTechniqueVS(SourceShader shader, HlslTechnique technique, AsmTechnique asmTechnique, ShaderExtension extension, Platform platform)
		{
			HlslMethod vs = shader.GetMethod(technique.VertexShaderMethodName, platform);
			HlslMethod ps = shader.GetMethod(technique.PixelShaderMethodName, platform);

			if (vs == null) throw new CompileException(string.Format("Unabled to find declaration for vertex shader method '{0}'", technique.VertexShaderMethodName));
			if (ps == null) throw new CompileException(string.Format("Unabled to find declaration for pixel shader method '{0}'", technique.PixelShaderMethodName));

			string nameAppend = "_" + Guid.NewGuid().ToString("N") + "_" + extension.ToString();
			string blendName = "__blend_weights__GEN";
			string indicesName = "__blend_indices__GEN";

			//generated merged matrices
			StringBuilder matrixGen = new StringBuilder();
			foreach (var remap in matrixRemap.Values)
			{
				if (remap.BaseName != null) // this will be null for the world matrix
				{
					//find the matching register in the technique
					string matrixType;
					string matrixExpansion = GetMatrixRankExpansion(remap.Name, asmTechnique, out matrixType);

					if (extension == ShaderExtension.Instancing)
						matrixGen.AppendFormat("\tfloat4x4 {0} = float4x4(({4})mul({1},{2}){3});", remap.RemapTo, worldMatrixName, remap.BaseName, matrixExpansion, matrixType);
					if (extension == ShaderExtension.Blending)
						matrixGen.AppendFormat("\tfloat4x4 {0} = float4x4(({4})mul({1},{2}){3});", remap.RemapTo, worldMatrixName, remap.Name, matrixExpansion, matrixType);
					matrixGen.AppendLine();
				}
			}


			//create the method signatures
			footer.AppendLine();
			bool multiArg = false;
			StringBuilder argList = new StringBuilder();
			int argIndex = -1;
			bool transposeWorldMatrix = false;

			foreach (var element in vs.HlslShader.Elements)
			{
				if (element.Statement == vs.Name)
				{
					footer.Append(vs.Name);
					footer.Append(nameAppend);
				}
				else
				{
					if (element.Statement == "(" || element.Statement == ",")
						argIndex = 0;
					else
					{
						argIndex++;
						if (element.Statement == "out" ||
							element.Statement == "in" ||
							element.Statement == "inout" ||
							element.Statement == "uniform" ||
							element.Statement == "const")
							argIndex--;
						if (argIndex != -1 && argIndex == 2)
						{
							if (argList.Length > 0)
								argList.Append(", ");
							argList.Append(element.Statement);
						}
					}

					if (element.Statement == ")")
					{
						argIndex = -1;

						if (methodNames.TryGetValue(vs.Name, out multiArg) && multiArg)
							footer.Append(", ");

						if (extension == ShaderExtension.Instancing)
						{
							footer.Append("float4x4 " + worldMatrixName + "_transpose : POSITION12");
							transposeWorldMatrix = true;
						}
						if (extension == ShaderExtension.Blending)
						{
							footer.AppendFormat("float4 {0} : BLENDWEIGHT, int4 {1} : BLENDINDICES", blendName, indicesName);
						}
					}

					footer.Append(element);
					footer.Append(' ');
				}
			}
			footer.AppendLine();
			footer.AppendLine("{");

			if (transposeWorldMatrix)
			{
				footer.AppendLine("\tfloat4x4 " + worldMatrixName + " = transpose(" + worldMatrixName + "_transpose);");
			}

			if (extension == ShaderExtension.Blending)
			{
				string calculation =
@"	float4x4 {3}
		= transpose(float4x4(
			{0}[{1}.x * 3 + 0] * {2}.x + {0}[{1}.y * 3 + 0] * {2}.y + {0}[{1}.z * 3 + 0] * {2}.z + {0}[{1}.w * 3 + 0] * {2}.w,
			{0}[{1}.x * 3 + 1] * {2}.x + {0}[{1}.y * 3 + 1] * {2}.y + {0}[{1}.z * 3 + 1] * {2}.z + {0}[{1}.w * 3 + 1] * {2}.w,
			{0}[{1}.x * 3 + 2] * {2}.x + {0}[{1}.y * 3 + 2] * {2}.y + {0}[{1}.z * 3 + 2] * {2}.z + {0}[{1}.w * 3 + 2] * {2}.w,
			float4(0,0,0,1)));";

				footer.AppendFormat(calculation, blendMatricesName, indicesName, blendName, worldMatrixName);
				footer.AppendLine();
			}
			
			footer.Append(matrixGen);
			
			footer.AppendFormat("\t{4}{0}({1}{2}{3});", ToInternalMethodName(vs.Name, extension), methodCallAppend, multiArg ? ", " : "", argList, vs.HasReturnValue ? "return " : "");

			footer.AppendLine();
			footer.AppendLine("}");

			return vs.Name + nameAppend;
		}
		private void GenerateTechnique(SourceShader shader, HlslTechnique technique, AsmTechnique asmTechnique, Platform platform)
		{
			string blendVS = ProcessTechniqueVS(shader, technique, asmTechnique, ShaderExtension.Blending, platform);
			string instVS = ProcessTechniqueVS(shader, technique, asmTechnique, ShaderExtension.Instancing, platform);
			
			footer.AppendLine();

			////append the new technique
			string techniqueName = technique.Name + techniquePostfix;
			string code = @"
technique {0} {11}
{9}
	pass
	{9}
		VertexShader = compile {1} {5}({6});
		PixelShader = compile {2} {3}({4});
	{10}
	pass Blending
	{9}
		VertexShader = compile {1} {7}({6});
	{10}
	pass Instancing
	{9}
		VertexShader = compile {1} {8}({6});
	{10}
{10}
";

			var annotation = new StringBuilder();

			var asm = shader.GetAsmTechnique(technique.Name, platform);

			if (asm != null && asm.TechniqueExtraData != null &&
				asm.TechniqueExtraData.ClassBaseTypes != null && asm.TechniqueExtraData.ClassBaseTypes.Length > 0)
			{
				annotation.Append("< string  BaseTypes = \"");

				bool first = true;
				foreach (var baseType in asm.TechniqueExtraData.ClassBaseTypes)
				{
					if (!first)
						annotation.Append(", ");
					first = false;
					annotation.Append(baseType);
				}

				annotation.Append("\"; >");
			}
			
			footer.AppendFormat(
				code,
				techniqueName,
				technique.GetVertexShaderVersion(platform),
				technique.GetPixelShaderVersion(platform),
				technique.PixelShaderMethodName,
				CombineArgs(technique.PixelShaderArgs),
				technique.VertexShaderMethodName,
				CombineArgs(technique.VertexShaderArgs),
				blendVS,
				instVS,
				"{","}",
				annotation);

		}