public PreshaderSrc(AsmListing listing, CodeStatementCollection statementCollection) { statements = new List<CodeStatement>(); object[] paramsArray = new object[1]; StringBuilder sb = new StringBuilder(); foreach (AsmCommand cmd in listing.Commands) { MethodInfo method; if (!methodList.TryGetValue(cmd.Target, out method)) { if (cmd.Target == "preshader") continue; throw new CompileException(string.Format("Error decoding PreShader: Unexpected command '{0}'", cmd.Target)); } string[] args = new string[cmd.OpCount]; for (int i = 0; i < cmd.OpCount; i++) { cmd.GetOp(i).ToString(sb); args[i] = sb.ToString(); sb.Length = 0; } paramsArray[0] = args; method.Invoke(this, paramsArray); } statementCollection.AddRange(this.statements.ToArray()); }
public PreshaderSrc(AsmListing listing, CodeStatementCollection statementCollection) { statements = new List <CodeStatement>(); object[] paramsArray = new object[1]; StringBuilder sb = new StringBuilder(); foreach (AsmCommand cmd in listing.Commands) { MethodInfo method; if (!methodList.TryGetValue(cmd.Target, out method)) { if (cmd.Target == "preshader") { continue; } throw new CompileException(string.Format("Error decoding PreShader: Unexpected command '{0}'", cmd.Target)); } string[] args = new string[cmd.OpCount]; for (int i = 0; i < cmd.OpCount; i++) { cmd.GetOp(i).ToString(sb); args[i] = sb.ToString(); sb.Length = 0; } paramsArray[0] = args; method.Invoke(this, paramsArray); } statementCollection.AddRange(this.statements.ToArray()); }
public AsmToHlslAsmConverter(AsmListing asmSource, Microsoft.Xna.Framework.TargetPlatform platform, int shaderMaxConstants, int shaderMaxBooleanConstants, bool throwOnError) { this.platform = platform; maxConstant = -1; if (shaderMaxConstants != 0) maxConstant = shaderMaxConstants; maxBoolean = -1; if (shaderMaxBooleanConstants != 0) maxBoolean = shaderMaxBooleanConstants; maxRegister = -1; this.samplers = new List<InputOutput>(); this.inputs = new List<InputOutput>(); this.outputs = new List<InputOutput>(); this.assignedConstants = new Dictionary<int, bool>(); this.localConstants = new Dictionary<int, string>(); this.localBooleanConstants = new Dictionary<int, string>(); this.localIntegerConstants = new Dictionary<int, string>(); for (int i = 0; i < 256; i++) assignedConstants.Add(i, false); this.source = new StringBuilder(); this.listing = asmSource; if (listing.GetCommandCount() > 0) { //attempt to decode the shader if (DetectProfile()) { List<Command> commands = new List<Command>(); for (int i = 1; i < listing.GetCommandCount(); i++) { //extract the commands Command cmd = new Command(listing.GetCommand(i)); if (cmd.name != null) commands.Add(cmd); } List<Command> allCommands = new List<Command>(); List<Command> newCommands = new List<Command>(); foreach (Command command in commands) { newCommands.Clear(); GenerateCode(command, newCommands); allCommands.AddRange(newCommands); } commands = allCommands; bool isAsm = false; foreach (Command cmd in commands) { if (cmd.isAsm != isAsm) { if (isAsm) { this.source.Append("};"); this.source.AppendLine(); } else { this.source.Append("asm{"); this.source.AppendLine(); } isAsm = cmd.isAsm; } this.source.Append(cmd.name); for (int i = 0; i < cmd.args.Length; i++) { this.source.Append(' '); if (i != 0) this.source.Append(','); for (int a = 0; a < cmd.args[i].Length; a++) this.source.Append(cmd.args[i][a]); } this.source.AppendLine(); } if (isAsm) this.source.Append("};"); } } BuildMethod(); CompiledShader shader = ShaderCompiler.CompileFromSource( this.source.ToString(), null, null, CompilerOptions.AvoidFlowControl, "Main", profile, platform); if (throwOnError && !shader.Success) Common.ThrowError("An error occured running the Xbox shader HLSL/ASM preprocessor", shader.ErrorsAndWarnings, asmSource.ToString()); if (!shader.Success) { //tried the best.. if it failed, ohh well, go back to AssembleFromSource //probably used complex flow control? string rawAsm = asmSource.ToString(); shader = ShaderCompiler.AssembleFromSource(rawAsm, null, null, CompilerOptions.None, platform); if (!shader.Success) Common.ThrowError(shader.ErrorsAndWarnings, rawAsm); } output = shader.GetShaderCode(); }
private bool ExtractAssignmentForExtenionBlock(CodeStatement assign, IShaderDom shader, AsmListing asmListing) { //special case, blending or instancing assignments need to go in an if block. if (asmListing == asm.BlendingShader) { blendExtensionAssignments.Add(assign); return true; } if (asmListing == asm.InstancingShader) { instancingExtensionAssignments.Add(assign); return true; } return false; }
private void CreateVertexInputMethods() { AsmListing asmVS = this.source.GetAsmTechnique(this.techniqueName, this.platform).VertexShader; //create the GetVertexInputCount() and GetVertexInput() methods CodeMemberMethod count = new CodeMemberMethod(); count.Name = "GetVertexInputCount"; count.Attributes = MemberAttributes.Family | MemberAttributes.Override; count.ReturnType = new CodeTypeReference(typeof(int)); Comment(count, "Returns the number of vertex inputs used by this shader"); count.Statements.Add(new CodeMethodReturnStatement(new CodePrimitiveExpression(asmVS.InputCount))); classDom.Members.Add(count); //inputs are stored in a static array //create it... int[] arrayValues = new int[asmVS.InputCount * 2]; for (int i = 0; i < asmVS.InputCount; i++) { arrayValues[i] = (int)asmVS.GetInput(i).Usage; arrayValues[i + asmVS.InputCount] = (int)asmVS.GetInput(i).Index; } this.vsInputField = new CodeMemberField(typeof(int[]), "vin"); this.vsInputField.Attributes = MemberAttributes.Private | MemberAttributes.Static | MemberAttributes.Final; this.vsInputField.InitExpression = ShaderBytes.ToArray(arrayValues, this.directives); CodeFieldReferenceExpression vsInputRef = new CodeFieldReferenceExpression(ShaderClassEx, vsInputField.Name); //protected internal abstract void GetVertexInput(int index, out VertexElementUsage elementUsage, out int elementIndex); CodeMemberMethod getInput = new CodeMemberMethod(); getInput.Name = "GetVertexInput"; getInput.Attributes = MemberAttributes.Family | MemberAttributes.Override; CodeParameterDeclarationExpression indexParam = new CodeParameterDeclarationExpression(typeof(int), "i"); getInput.Parameters.Add(indexParam); CodeParameterDeclarationExpression param = new CodeParameterDeclarationExpression(typeof(VertexElementUsage), "usage"); param.Direction = FieldDirection.Out; getInput.Parameters.Add(param); param = new CodeParameterDeclarationExpression(typeof(int), "index"); param.Direction = FieldDirection.Out; getInput.Parameters.Add(param); CodeArgumentReferenceExpression indexRef = new CodeArgumentReferenceExpression(indexParam.Name); //the element index is stored at 'i + asmVS.InputCount' CodeExpression indexArray = new CodeArrayIndexerExpression(vsInputRef, new CodeBinaryOperatorExpression(indexRef, CodeBinaryOperatorType.Add, new CodePrimitiveExpression(asmVS.InputCount))); //and the usage must be cast CodeExpression usageCast = new CodeCastExpression(typeof(VertexElementUsage), new CodeArrayIndexerExpression(vsInputRef, indexRef)); getInput.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("usage"), usageCast)); getInput.Statements.Add(new CodeAssignStatement(new CodeArgumentReferenceExpression("index"), indexArray)); Comment(getInput, "Returns a vertex input used by this shader"); classDom.Members.Add(getInput); }
private void ProcessShader(string asm, out AsmListing shader, out string comment) { //format: //either, /* * //header * preshader * //header * shader * //comment */ //or /* * //header * shader * //comment */ string[] asmLinesSource = asm.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); //ignore first and last line (the { and }) string[] asmLines = new string[Math.Max(0,asmLinesSource.Length - 2)]; for (int i = 1; i < asmLinesSource.Length-1; i++) asmLines[i - 1] = asmLinesSource[i].Trim(); comment = ""; if (asmLines.Length > 0) { comment = asmLines[asmLines.Length - 1]; if (comment.StartsWith("// ")) comment = comment.Substring(3); } bool[] isComment = new bool[asmLines.Length]; for (int i = 0; i < asmLines.Length - 1; i++) isComment[i] = asmLines[i].StartsWith("//"); //top header int headerLength = 0; int start = 0; for (int i = 1; i < asmLines.Length; i++) { if (!isComment[i] && asmLines[i].Length != 0) break; headerLength = i+1; start = i+1; } int firstBlockLength = 0; int firstBlockStart = start; for (int i = start; i < asmLines.Length; i++) { firstBlockLength = i - headerLength + 1; start = i+1; if (isComment[i]) break; } int secondHeaderLength = 0; int secondHeaderStart = start; for (int i = start; i < asmLines.Length; i++) { if (!isComment[i] && asmLines[i].Length != 0) break; secondHeaderLength = i - firstBlockLength + 1; start = i+1; } int secondBlockLength = 0; int secondBlockStart = start; for (int i = start; i < asmLines.Length; i++) { secondBlockLength = i - secondHeaderLength + 1; start = i+1; if (isComment[i]) break; } if (secondHeaderLength > 0 && secondBlockLength > 0) { //preshader is used // preshader = new AsmListing(CombineLines(asmLines, firstBlockStart, firstBlockLength), new RegisterSet(CombineLines(asmLines, 1, headerLength))); // shader = new AsmListing(CombineLines(asmLines, secondBlockStart, secondBlockLength), new RegisterSet(CombineLines(asmLines, secondHeaderStart, secondHeaderLength))); throw new CompileException("Compile Error: Unexpected preshader encountered! Turn back to save yourself!"); } else { //no preshader shader = new AsmListing(CombineLines(asmLines, firstBlockStart, firstBlockLength), new RegisterSet(CombineLines(asmLines, 1, headerLength))); } }
private void SetupCommonRegisters() { Dictionary<string, Register> common = new Dictionary<string, Register>(); AsmListing[] listings = new AsmListing[] { vsListing, psListing, vsBlendOverride, vsInstancingOverride }; foreach (AsmListing listing in listings) { if (listing == null) continue; for (int i = 0; i < listing.RegisterSet.RegisterCount; i++) { Register reg = listing.RegisterSet.GetRegister(i); if (!common.ContainsKey(reg.Name)) common.Add(reg.Name, reg); } } Register[] registers = new Register[common.Count]; int count = 0; foreach (Register reg in common.Values) { registers[count++] = reg; } this.registers = new RegisterSet(registers); }
private AsmTechnique(string name, string source, TechniqueExtraData defaultValues) { Tokenizer tokenizer = new Tokenizer(source, false, true, true); this.name = name; this.defaultValues = defaultValues; //parse the asm, and extract the first pass. string pass = null; string firstPassName = null; string blendPass = null, instancingPass = null; while (tokenizer.NextToken()) { if (tokenizer.Token.Equals("pass", StringComparison.InvariantCultureIgnoreCase)) { //may have a name next... tokenizer.NextToken(); string token = tokenizer.Token; string passName = null; if (token != "{") { //the name is specified passName = tokenizer.Token; tokenizer.NextToken(); token = tokenizer.Token; } //may be a new line while (token.Trim().Length == 0) { tokenizer.NextToken(); token = tokenizer.Token; } if (token != "{") throw new CompileException("Unexpected token in assembly technique pass declaration, expected '{': " + token); if (!tokenizer.ReadBlock()) throw new CompileException("Unexpected end of string in assembly technique pass declaration"); bool isAnimated, isInstancing; ExtractPassType(passName, out isAnimated, out isInstancing); string help = @" For example: technique TechniqueName { //default pass: pass { VertexShader = compile vs_2_0 BaseVS(); PixelShader = compile ps_2_0 BasePS(); } pass Animated { VertexShader = compile vs_2_0 AnimatedVS(); } pass Instancing { VertexShader = compile vs_2_0 InstancingVS(); } } Note, the instancing or animation passes may only replace the vertex shader"; if (pass != null) { if (blendPass == null && isAnimated) { blendPass = tokenizer.Token; } else if (instancingPass == null && isInstancing) { instancingPass = tokenizer.Token; } else throw new CompileException(@"A shader technique may only define a single Pass, or define a dedicated Animation and/or Instancing pass:"******"A shader technique must define a default pass before defining an instancing or animation pass:"******"Technique '" + name + "' does not define a pass"); ProcessPass(pass); this.vsBlendOverride = ProcessSupplimentaryPass(blendPass); this.vsInstancingOverride = ProcessSupplimentaryPass(instancingPass); SetupCommonRegisters(); if (this.vsBlendOverride != null) this.vsBlendOverride.RegisterSet.CompactDuplicateRegisters(this.vsListing.RegisterSet, "Animated", this.name); if (this.vsInstancingOverride != null) this.vsInstancingOverride.RegisterSet.CompactDuplicateRegisters(this.vsListing.RegisterSet, "Instancing", this.name); }