public ConstantSetup(SourceShader source, string techniqueName, Platform platform)
		{
			this.source = source;
			this.techniqueName = techniqueName;

			this.attributeNames = new List<string>();
			this.attributeFields = new List<CodeFieldReferenceExpression>();
			this.attributeArrayFields = new List<CodeFieldReferenceExpression>();
			this.attributeAssignment = new Dictionary<Type, List<CodeStatement>>();
			this.semanticMapping = new List<SemanticMapping>();
			this.globals = new List<GlobalAttribute>();

			this.asm = source.GetAsmTechnique(techniqueName, platform);

			ComputeAllValidSemantics();
		}
Beispiel #2
0
        private void ExtractAsmTechniques()
        {
            if (!mixedMode)
            {
                //both platforms compile their own effects

                //pull the actual asm data out..
                this.asmTechniques.AddRange(AsmTechnique.ExtractTechniques(this, Platform.Windows));
                this.xboxAsmTechniques.AddRange(AsmTechnique.ExtractTechniques(this, Platform.Xbox));
            }
            else
            {
                //one set of techniques for both windows and xbox

                //pull the actual asm data out..
                this.asmTechniques.AddRange(AsmTechnique.ExtractTechniques(this, Platform.Both));
            }
        }
		public Preshaders(SourceShader source, string techniqueName, Platform platform)
		{
			technique = source.GetAsmTechnique(techniqueName, platform);

			if (technique.PixelPreShader != null)
			{
				pixelPreShaderStatements = new CodeStatementCollection();
				pixelPreShader = new PreshaderSrc(technique.PixelPreShader, pixelPreShaderStatements);

				technique.PixelShader.RegisterSet.SetMinFloatRegisterCount(pixelPreShader.MaxConstantRegisterAccess);
				technique.PixelShader.RegisterSet.SetMinBooleanRegisterCount(pixelPreShader.MaxBooleanConstantRegisterWrite);
			}

			if (technique.VertexPreShader != null)
			{
				vertexPreShaderStatements = new CodeStatementCollection();
				vertexPreShader = new PreshaderSrc(technique.VertexPreShader, vertexPreShaderStatements);

				technique.VertexShader.RegisterSet.SetMinFloatRegisterCount(vertexPreShader.MaxConstantRegisterAccess);
				technique.VertexShader.RegisterSet.SetMinBooleanRegisterCount(vertexPreShader.MaxBooleanConstantRegisterWrite);
			}
		}
Beispiel #4
0
        //this is a bit of a hack.
        //it relies on the fact that the DirectX shader compiler
        //marks up the disasembled shader with comments detailing the shader inputs.
        public static AsmTechnique[] ExtractTechniques(SourceShader shader, Platform platform)
        {
            //decompile the shader
            DecompiledEffect fx = new DecompiledEffect(shader, platform);

            //break it up into techniques
            Tokenizer assemblyTokens = new Tokenizer(fx.DecompiledAsm, false, true, true);

            List <AsmTechnique> techniqes = new List <AsmTechnique>();

            while (assemblyTokens.NextToken())
            {
                if (assemblyTokens.Token.Equals("technique", StringComparison.InvariantCultureIgnoreCase))
                {
                    //should be format:
                    //technique NAME
                    //{
                    //}

                    assemblyTokens.NextToken();
                    string name = assemblyTokens.Token;

                    assemblyTokens.NextToken();

                    //may be a line break
                    if (assemblyTokens.Token.Trim().Length == 0)
                    {
                        assemblyTokens.NextToken();
                    }

                    //should be a {
                    if (assemblyTokens.Token != "{")
                    {
                        throw new CompileException("Unexpected token in assembly technique declaration, expected '{': " + assemblyTokens.Token);
                    }

                    // read the entire technique {} block
                    if (!assemblyTokens.ReadBlock())
                    {
                        throw new CompileException("Unexpected end of string in assembly technique pass declaration");
                    }

                    AsmTechnique asm = new AsmTechnique(name, assemblyTokens.Token, fx.GetTechniqueDefaultValues(name));

                    if (!shader.SkipConstantValidation)
                    {
                        //do some extra validation to make sure pixel inputs match vertex outputs
                        asm.ValidatePixleShaderInput(shader, platform);
                    }

                    techniqes.Add(asm);
                }
            }

            for (int i = 0; i < techniqes.Count; i++)
            {
                techniqes[i].MergeSemantics(fx.EffectRegisters);
            }

            return(techniqes.ToArray());
        }
		private static string BuildMapping(AsmTechnique asmTechnique, string extension, RegisterSet set)
		{
			StringBuilder sb = new StringBuilder();

			for (int i = 0; i < set.RegisterCount; i++)
			{
				Register reg = set.GetRegister(i);
				string type = reg.Type;

				string source = "_" + extension + "_";

				switch (reg.Category)
				{
					case RegisterCategory.Boolean:
						source += "b";
						break;
					case RegisterCategory.Float4:
						source += "c";
						switch (reg.Rank)
						{
							case RegisterRank.FloatNx2:
							case RegisterRank.IntNx2:
								type = "float4x2";
								break;
							case RegisterRank.FloatNx3:
							case RegisterRank.IntNx3:
								type = "float4x3";
								break;
							case RegisterRank.FloatNx4:
							case RegisterRank.IntNx4:
								type = "float4x4";
								break;
						}
						break;
					default:
						continue;
				}


				sb.Append("#define ");
				sb.Append(TranslateRegisterName(reg.Name, extension));
				string index = "";
				if (reg.ArraySize > 0)
				{
					index = "(__INDEX__)";
					sb.Append(index);
				}

				sb.Append(" (");

				MapToValue(sb, reg, reg.Index, source, index);

				sb.AppendLine(")");
			}

			return sb.ToString();
		}
		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 string GetMatrixRankExpansion(string registerName, AsmTechnique asmTechnique, out string matrixType)
		{
			//the matrix being computed is not a 4x4, but internally it must be treated as such,
			//so work out the extension required to fill it out to a full 4x4
			Register reg;
			asmTechnique.CommonRegisters.TryGetRegister(registerName, out reg);
			switch (reg.Rank)
			{
				default:
					matrixType = "float4x4";
					return "";
				case RegisterRank.FloatNx3:
					matrixType = "float4x3";
					return ",float4(0,0,0,1)";
				case RegisterRank.FloatNx2:
					matrixType = "float4x2";
					return ",float4(0,0,0,0),float4(0,0,0,1)";
				case RegisterRank.FloatNx1:
					matrixType = "float4x1";
					return ",float4(0,0,0,0),float4(0,0,0,0),float4(0,0,0,1)";
			}
		}
		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);

		}
		public static byte[] Generate(AsmTechnique technique, Platform platform)
		{
			string techniqueCode;
		
			AsmToHlslConverter vsConvert = new AsmToHlslConverter(technique.VertexShader, "vs", platform, technique.VertexShader.RegisterSet.FloatRegisterCount, technique.VertexShader.RegisterSet.BooleanRegisterCount);
			AsmToHlslConverter psConvert = new AsmToHlslConverter(technique.PixelShader, "ps", platform, technique.PixelShader.RegisterSet.FloatRegisterCount, technique.PixelShader.RegisterSet.BooleanRegisterCount);

			if (platform == Platform.Windows)
			{
				StringBuilder constantSetup = new StringBuilder();
			//	technique.ConstructTechniqueConstants(constantSetup, false);

				string vsAsm = technique.VertexShader.ToString();
				vsAsm = vsAsm.Replace(Environment.NewLine, Environment.NewLine + "\t\t\t\t");

				string psAsm = technique.PixelShader.ToString();
				psAsm = psAsm.Replace(Environment.NewLine, Environment.NewLine + "\t\t\t\t");

				techniqueCode = string.Format(
@"
uniform float4 _vs_c[11] : register(vs, c0);
{4}
technique Shader
{0}
	pass
	{0}
		VertexShader = 
			asm 
			{0}
				{2}
			{1};
		PixelShader  = 
			asm 
			{0}
				{3}
			{1};
	{1}
{1}",
				"{", "}", vsAsm, psAsm, constantSetup);

			}
			else
			{
				string vsSource = vsConvert.GetSource();
				string psSource = psConvert.GetSource();

				//setup the technique.
				techniqueCode = string.Format(
	@"
{2}

{3}

technique Shader
{0}
	pass
	{0}
		VertexShader = compile {4} vsMain();
		PixelShader  = compile {5} psMain();
	{1}
{1}",
				"{", "}", vsSource, psSource, vsConvert.GetProfile().ToString().ToLower(), psConvert.GetProfile().ToString().ToLower());

			}
			
			TargetPlatform target = TargetPlatform.Unknown;
			switch (platform)
			{
				case Platform.Both:
					throw new ArgumentException();
				case Platform.Windows:
					target = TargetPlatform.Windows;
					break;
				case Platform.Xbox:
					target = TargetPlatform.Xbox360;
					break;
			}

			CompiledEffect effectSource = Effect.CompileEffectFromSource(techniqueCode, null, null, CompilerOptions.None, target);

			if (effectSource.Success == false)
				Common.ThrowError(effectSource.ErrorsAndWarnings, techniqueCode);

			byte[] code = effectSource.GetEffectCode();

			Effect effect = new Effect(Graphics.GraphicsDevice, code, CompilerOptions.None, new EffectPool());

			Vector4[] valuesV = new Vector4[11];
			for (int i = 0; i < valuesV.Length; i++)
			{
				valuesV[i] = new Vector4(i,0,0,0);
			}
			//Vector4[] valuesP = new Vector4[24];
			//for (int i = 0; i < valuesP.Length; i++)
			//{
			//    valuesP[i] = new Vector4(0, i, 0, 0);
			//}
			effect.Parameters[0].SetValue(valuesV);
			Vector4[] test = effect.Parameters[0].GetValueVector4Array(11);
			//effect.Parameters[1].SetValue(valuesP);
			//effect.Parameters[2].SetValue(new bool[] { false, false });

			GraphicsDevice gd = Graphics.GraphicsDevice;

			effect.CurrentTechnique = effect.Techniques[0];
			effect.Begin();
			effect.Techniques[0].Passes[0].Begin();


			Vector4[] outputV = gd.GetVertexShaderVector4ArrayConstant(0, 255);
			Vector4[] outputP = gd.GetPixelShaderVector4ArrayConstant(0, 24);
			//bool[] outputPB = gd.GetPixelShaderBooleanConstant(0, 2);

			effect.Techniques[0].Passes[0].End();
			effect.End();

			string asm = effect.Disassemble(false);

			return code;
        }
		//this is a bit of a hack.
		//it relies on the fact that the DirectX shader compiler
		//marks up the disasembled shader with comments detailing the shader inputs.
		public static AsmTechnique[] ExtractTechniques(SourceShader shader, Platform platform, out DecompiledEffect fx, string generatedPrefix)
		{
			//decompile the shader
			fx = new DecompiledEffect(shader, platform);

			//break it up into techniques
			Tokenizer assemblyTokens = new Tokenizer(fx.DecompiledAsm, false, true, true);

			List<AsmTechnique> techniqes = new List<AsmTechnique>();

			while (assemblyTokens.NextToken())
			{
				if (assemblyTokens.Token.Equals("technique", StringComparison.InvariantCultureIgnoreCase))
				{
					//should be format:
					//technique NAME
					//{
					//}

					assemblyTokens.NextToken();
					string name = assemblyTokens.Token;

					if (generatedPrefix != null)
					{
						//only include generated techniques
						if (name.EndsWith(generatedPrefix))
							name = name.Substring(0, name.Length - generatedPrefix.Length);
						else
							continue;
					}

					assemblyTokens.NextToken();

					//may be a line break
					if (assemblyTokens.Token.Trim().Length == 0)
						assemblyTokens.NextToken();

					//should be a {
					if (assemblyTokens.Token != "{")
						throw new CompileException("Unexpected token in assembly technique declaration, expected '{': " + assemblyTokens.Token);

					// read the entire technique {} block
					if (!assemblyTokens.ReadBlock())
						throw new CompileException("Unexpected end of string in assembly technique pass declaration");

					AsmTechnique asm = new AsmTechnique(name, assemblyTokens.Token, fx.GetTechniqueDefaultValues(name));

					if (!shader.SkipConstantValidation)
					{
						//do some extra validation to make sure pixel inputs match vertex outputs
						asm.ValidatePixleShaderInput(shader, platform);
					}

					techniqes.Add(asm);
				}
			}

			for (int i = 0; i < techniqes.Count; i++)
			{
				techniqes[i].MergeSemantics(fx.EffectRegisters);
			}

			return techniqes.ToArray();
		}