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(); }
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); } }
//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(); }