public TextureAssociation(Register reg) { this.Texture = reg; this.PsSamplers = new List<int>(); this.VsSamplers = new List<int>(); }
public bool TryGetRegister(string name, out Register register) { register = new Register(); for (int i = 0; i < registers.Length; i++) { if (registers[i].Name == name) { register = registers[i]; return true; } } return false; }
public RegisterSet(string header) { //extract the registers used... /* * Example header: * // // Generated by Microsoft (R) D3DX9 Shader Compiler 9.15.779.0000 // // Parameters: // // float2 shadowCameraNearFar; // // // Registers: // // Name Reg Size // ------------------- ----- ---- // shadowCameraNearFar c0 1 // * */ Dictionary<string, Register> registers = new Dictionary<string, Register>(); Tokenizer tokenizer = new Tokenizer(header, false, true, true); string[] lines = header.Split('\n'); int state = 0; while (tokenizer.NextToken()) { switch (tokenizer.Token) { case ":": break; case "Parameters": state = 1; break; case "//": //determine if the line has content... if (lines[tokenizer.Line].Trim().Length > 2) { if (state == 1) { //try and extract something // float2 shadowCameraNearFar; tokenizer.NextToken(); string type = tokenizer.Token; tokenizer.NextToken(); if (type == "Registers") { state = 2; //done, go to registers break; } if (type == "struct") { string structContents = ""; string structName = ""; try { while (tokenizer.Token != "{") tokenizer.NextToken(); tokenizer.ReadBlock(); structContents = tokenizer.Token; tokenizer.NextToken(); structName = tokenizer.Token; } catch { } finally { throw new CompileException(string.Format("Shader compiler cannot map the custom constant structure '{0} {1}' into a compatible XNA data structure", structName, structContents.Replace(Environment.NewLine, "").Replace("//",""))); } } string name = tokenizer.Token; //possible array, or ; tokenizer.NextToken(); string token = tokenizer.Token; int array = -1; if (token == "[") { tokenizer.NextToken(); array = int.Parse(tokenizer.Token); tokenizer.NextToken(); //eat the ] tokenizer.NextToken(); } //should be a ; if (tokenizer.Token != ";") throw new CompileException("Expected ';' in shader header"); Register reg = new Register(); reg.ArraySize = array; reg.Name = name; reg.Type = type; registers.Add(name, reg); } if (state == 2 || state == 3 || state == 4) { // Name Reg Size // ------------------- ----- ---- // shadowCameraNearFar c0 1 string name, register, size; tokenizer.NextToken(); name = tokenizer.Token; tokenizer.NextToken(); register = tokenizer.Token; tokenizer.NextToken(); size = tokenizer.Token; bool skip = false; if (name == "Name" && register == "Reg" && size == "Size") skip = true; if (name.Replace("-","").Length == 0 && register.Replace("-","").Length == 0 && size.Replace("-","").Length == 0) skip = true; if (!skip) { Register reg; if (registers.TryGetValue(name, out reg)) { reg.Size = int.Parse(size); switch (register[0]) { case 'c': reg.Category = RegisterCategory.Float4; break; case 'i': reg.Category = RegisterCategory.Integer4; break; case 'b': reg.Category = RegisterCategory.Boolean; break; case 't': reg.Category = RegisterCategory.Texture; break; case 's': reg.Category = RegisterCategory.Sampler; break; case 'r': reg.Category = RegisterCategory.Temp; break; default: throw new CompileException(string.Format("Unexpected constant type '{0}'", register[0])); } reg.Index = int.Parse(register.Substring(1)); reg.Rank = ExtractRank(reg.Type, reg.Category, reg.ArraySize, reg.Size); registers[name] = reg; } } } } break; } } List<Register> registerList = new List<Register>(); foreach (Register register in registers.Values) registerList.Add(register); this.registers = registerList.ToArray(); }
public RegisterSet(Register[] set) { this.registers = set; }
private static void MapToValue(StringBuilder sb, Register reg, int index, string source, string arrayOffset) { if (reg.Category == RegisterCategory.Boolean) reg.Rank = RegisterRank.Bool; switch (reg.Rank) { case RegisterRank.Unknown: throw new ArgumentException("Unknown Register Type"); case RegisterRank.Bool: case RegisterRank.FloatNx1: case RegisterRank.IntNx1: { sb.Append(source); sb.Append('['); sb.Append(arrayOffset); sb.Append("+"); sb.Append(index++); sb.Append(']'); switch (reg.Type) { case "float": case "bool": case "int": sb.Append(".x"); break; case "int2": case "float2": sb.Append(".xy"); break; case "int3": case "float3": sb.Append(".xyz"); break; } } break; default: { sb.Append("transpose("); int count = 0; switch (reg.Rank) { case RegisterRank.FloatNx2: case RegisterRank.IntNx2: sb.Append("float2x4("); count = 2; break; case RegisterRank.FloatNx3: case RegisterRank.IntNx3: sb.Append("float3x4("); count = 3; break; case RegisterRank.FloatNx4: case RegisterRank.IntNx4: sb.Append("float4x4("); count = 4; break; default: return; //shouldn't be possible. } for (int i = 0; i < count; i++) { if (i != 0) sb.Append(','); sb.Append(source); sb.Append('['); if (arrayOffset.Length > 0) { sb.Append("((int)("); sb.Append(arrayOffset); sb.Append("))*"); sb.Append(count); } sb.Append("+"); sb.Append(index++); sb.Append(']'); } sb.Append("))"); } break; } }
private bool ExtractRegType(string name, out Register reg, out Type dataType, out bool hasSetMethod, out int stride) { dataType = null; hasSetMethod = true; stride = 1; reg = new Register(); if (!this.asm.CommonRegisters.TryGetRegister(name, out reg)) return false; if (reg.Category == RegisterCategory.Boolean) { dataType = typeof(bool); hasSetMethod = false; return true; } if (reg.Category != RegisterCategory.Float4) return false; switch (reg.Type) { case "float": case "float1"://? case "int": // integers or bools may be processed as floats by the FX compiler case "int1": case "bool": dataType = typeof(float); hasSetMethod = false; break; case "float2": case "int2": dataType = typeof(Vector2); break; case "float3": case "int3": dataType = typeof(Vector3); break; case "float4": case "int4": dataType = typeof(Vector4); break; default: if (reg.Rank >= RegisterRank.IntNx1) return false; dataType = typeof(Matrix); stride = (int)reg.Rank; break; } return true; }
private bool ExtractRegType(string name, out Register reg, out Type dataType) { bool hasSetMethod; int stride; return ExtractRegType(name, out reg, out dataType, out hasSetMethod, out stride); }
//pull a semantic bound register private void ExtractSemantic(IShaderDom shader, Register reg) { string semantic = reg.Semantic; Type dataType = null; switch (reg.Rank) { case RegisterRank.FloatNx1: { switch (reg.Type) { case "float": case "float1"://? dataType = typeof(Single); break; case "float2": dataType = typeof(Vector2); break; case "float3": dataType = typeof(Vector3); break; case "float4": dataType = typeof(Vector4); break; } } break; case RegisterRank.FloatNx2: case RegisterRank.FloatNx3: case RegisterRank.FloatNx4: dataType = typeof(Matrix); break; case RegisterRank.IntNx1: case RegisterRank.IntNx2: case RegisterRank.IntNx3: case RegisterRank.IntNx4: { //ints are almost always mapped to floats for semantic bound types (EG vertex count) //since the register category has been validated to Float4, this is the case here switch (reg.Type) { case "int": case "int1"://? dataType = typeof(Single); break; case "int2": dataType = typeof(Vector2); break; case "int3": dataType = typeof(Vector3); break; case "int4": dataType = typeof(Vector4); break; } } break; case RegisterRank.Bool: dataType = typeof(Single); break; } if (reg.Category == RegisterCategory.Boolean) dataType = typeof(bool); if (semantic.Length == 6 && semantic.Equals("global", StringComparison.InvariantCultureIgnoreCase)) { //special case global value. if (dataType == null) throw new CompileException(string.Format("Error parsing semantic for '{0}'. Global values of type '{1}' are not supported.",reg.Name, reg.Type)); GlobalAttribute global = new GlobalAttribute(); global.Register = reg; global.Type = dataType; global.GlobalIdRef = new CodeFieldReferenceExpression(shader.ShaderClassEx, string.Format("gid{0}", globals.Count)); List<CodeFieldReferenceExpression> globalRefs = new List<CodeFieldReferenceExpression>(); List<CodeFieldReferenceExpression> arrayRefs = new List<CodeFieldReferenceExpression>(); foreach (KeyValuePair<AsmListing, CodeExpression> listing in listingRegisters) { Register sreg; RegisterSet registers = listing.Key.RegisterSet; CodeExpression registersRef = listing.Value; if (registers.TryGetRegister(reg.Name, out sreg)) { if (sreg.Category != RegisterCategory.Boolean) { string refId = string.Format("gc{0}", globalRefCount); globalRefs.Add(new CodeFieldReferenceExpression(shader.Instance, refId)); globalRefCount++; } } } global.ChangeRefs = globalRefs.ToArray(); globals.Add(global); return; } //special case bool isBlendMatrices = semantic.Equals("BLENDMATRICES", StringComparison.InvariantCultureIgnoreCase); if (reg.ArraySize != -1 && !isBlendMatrices) { //INVALID. EXTERMINATE. throw new CompileException(string.Format("Shader attribute '{0}' is defined as an array and has a semantic '{1}'. Semantics other than 'BLENDMATRICES' and 'GLOBAL' are invalid for Array types.", reg.Name, reg.Semantic)); } bool isTranspose = semantic.Length > 9 && semantic.EndsWith("transpose", StringComparison.InvariantCultureIgnoreCase); if (isTranspose) semantic = semantic.Substring(0, semantic.Length - 9); SemanticType? dataSemanticType = null; foreach (SemanticType semanticType in semanticTypes) { if (semanticType.Type == dataType && semanticType.Mapping.Equals(semantic, StringComparison.InvariantCultureIgnoreCase)) { dataSemanticType = semanticType; break; } } if (dataSemanticType == null) { //INVALID. EXTERMINATE. throw new CompileException(string.Format("Shader attribute '{0}' has unrecognised semantic '{1}'.", reg.Name, reg.Semantic)); } //create the mapping... SemanticMapping mapping = new SemanticMapping(); mapping.Register = reg; mapping.Type = dataSemanticType.Value; //figure out how often this semantic is used.. List<CodeFieldReferenceExpression> changeRefs = new List<CodeFieldReferenceExpression>(); foreach (KeyValuePair<AsmListing, CodeExpression> listing in listingRegisters) { Register sreg; RegisterSet registers = listing.Key.RegisterSet; CodeExpression registersRef = listing.Value; if (registers.TryGetRegister(reg.Name, out sreg)) { string changeId = string.Format("sc{0}", semanticMappingRefCount++); changeRefs.Add(new CodeFieldReferenceExpression(shader.Instance, changeId)); } } mapping.ChangeRefs = changeRefs.ToArray(); this.semanticMapping.Add(mapping); }
private void AssignRegister(Type dataType, Register targetRegister, Register sourceRegister, CodeExpression codeExpression, CodeExpression valueRef, CodeStatementCollection statements, ref bool tempValuesCreated) { int arrayLength = Math.Max(1, targetRegister.ArraySize); bool isArray = targetRegister.ArraySize > 0; CodeExpression temp = null, loopIndex = null; if (isArray) { if (!tempValuesCreated) { statements.Add(new CodeVariableDeclarationStatement(dataType, "val")); statements.Add(new CodeVariableDeclarationStatement(typeof(int), "i")); //copies of readindex/writeindex statements.Add(new CodeVariableDeclarationStatement(typeof(uint), "ri")); statements.Add(new CodeVariableDeclarationStatement(typeof(uint), "wi")); tempValuesCreated = true; } loopIndex = new CodeVariableReferenceExpression("i"); temp = new CodeVariableReferenceExpression("val"); statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("ri"), new CodeArgumentReferenceExpression("readIndex"))); statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("wi"), new CodeArgumentReferenceExpression("writeIndex"))); } else loopIndex = new CodePrimitiveExpression(0); bool isMatrix = dataType == typeof(Matrix); bool isFloat = targetRegister.Rank >= RegisterRank.FloatNx1 && targetRegister.Rank <= RegisterRank.FloatNx4; int count = 1; switch (targetRegister.Rank) { case RegisterRank.FloatNx2: case RegisterRank.IntNx2: count = 2; break; case RegisterRank.FloatNx3: case RegisterRank.IntNx3: count = 3; break; case RegisterRank.FloatNx4: case RegisterRank.IntNx4: count = 4; break; } CodeExpression countRef = new CodeArgumentReferenceExpression("count"); CodeExpression readIndexRef = new CodeArgumentReferenceExpression("ri"); CodeExpression writeIndexRef = new CodeArgumentReferenceExpression("wi"); CodeExpression valueLength = new CodePropertyReferenceExpression(valueRef, "Length"); //check the incomming array if (isArray) { arrayLength = targetRegister.Size / count; //validate the input is not null CodeConditionStatement check = new CodeConditionStatement( new CodeBinaryOperatorExpression(valueRef, CodeBinaryOperatorType.IdentityEquality, new CodePrimitiveExpression(null)), new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentNullException),new CodePrimitiveExpression("value")))); statements.Add(check); //validate the array args are good. /* if (readIndex + count > value.Length || writeIndex + count > 10) throw new System.ArgumentException("Input array is either null or too short"); */ CodeExpression readCompare = new CodeBinaryOperatorExpression( new CodeBinaryOperatorExpression(readIndexRef, CodeBinaryOperatorType.Add, countRef), CodeBinaryOperatorType.GreaterThan, valueLength); CodeExpression writeCompare = new CodeBinaryOperatorExpression( new CodeBinaryOperatorExpression(writeIndexRef, CodeBinaryOperatorType.Add, countRef), CodeBinaryOperatorType.GreaterThan, new CodePrimitiveExpression(sourceRegister.ArraySize)); check = new CodeConditionStatement( new CodeBinaryOperatorExpression(readCompare, CodeBinaryOperatorType.BooleanOr, writeCompare), new CodeThrowExceptionStatement(new CodeObjectCreateExpression(typeof(ArgumentException), new CodePrimitiveExpression("Invalid range")))); statements.Add(check); } List<CodeStatement> innerStatements = new List<CodeStatement>(); //genrate the code to set the registers { CodeExpression valueTarget = valueRef; if (targetRegister.ArraySize > 0) { innerStatements.Add(new CodeAssignStatement(temp, new CodeArrayIndexerExpression(valueRef, readIndexRef))); valueTarget = temp; } for (int i = 0; i < count; i++) { //register index to write: CodeExpression arrayIndex = new CodePrimitiveExpression(i + targetRegister.Index); //loop is a bit more complex: loopIndex * count + i + reg.Index if (isArray) arrayIndex = new CodeBinaryOperatorExpression( new CodeBinaryOperatorExpression(writeIndexRef, CodeBinaryOperatorType.Multiply, new CodePrimitiveExpression(count)), CodeBinaryOperatorType.Add, arrayIndex); CodeExpression assignTarget = new CodeArrayIndexerExpression(codeExpression, arrayIndex); //float3x2 is rank 2, so 2 vectors are written. //each vector is 3 elements, so work out how many to write in XYZW per vector: //default the elements to zero. CodeExpression x = new CodePrimitiveExpression(0.0f), y = x, z = x, w = x; //get the first number of the '3x2' part of the type, eg from float3x2 int number = 1; //find the first number in the type name, if there is one. foreach (char c in targetRegister.Type) { if (char.IsNumber(c)) { number = int.Parse(c.ToString()); break; } } //simple assignment: if (number == 4 && count == 1) // float4 or int4 { //directly assign the value innerStatements.Add(new CodeAssignStatement(assignTarget, valueTarget)); continue; } //set the x,y,z,w coords if (number >= 4) w = new CodeFieldReferenceExpression(valueTarget, isMatrix ? "M4" + (i+1) : "W"); if (number >= 3) z = new CodeFieldReferenceExpression(valueTarget, isMatrix ? "M3" + (i+1) : "Z"); if (number >= 2) y = new CodeFieldReferenceExpression(valueTarget, isMatrix ? "M2" + (i+1) : "Y"); if (!isMatrix && number == 1) x = valueTarget; // float doesn't have a member else x = new CodeFieldReferenceExpression(valueTarget, isMatrix ? "M1" + (i+1) : "X"); //and assign.. innerStatements.Add(new CodeAssignStatement(assignTarget, new CodeObjectCreateExpression(typeof(Vector4), x,y,z,w))); } } if (isArray) { //generate the assignment loop // for (int i = 0; i < count; i++) // { // ... // readIndex++, writeIndex++ // } //add readIndex & writeIndex increment innerStatements.Add(new CodeAssignStatement(readIndexRef, new CodeBinaryOperatorExpression(readIndexRef, CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)))); innerStatements.Add(new CodeAssignStatement(writeIndexRef, new CodeBinaryOperatorExpression(writeIndexRef, CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1)))); CodeIterationStatement loop = new CodeIterationStatement( new CodeAssignStatement(loopIndex,new CodePrimitiveExpression(0)), new CodeBinaryOperatorExpression( new CodeBinaryOperatorExpression(loopIndex, CodeBinaryOperatorType.LessThan, countRef), CodeBinaryOperatorType.BooleanAnd, new CodeBinaryOperatorExpression(writeIndexRef, CodeBinaryOperatorType.LessThan, new CodePrimitiveExpression(arrayLength))), new CodeAssignStatement(loopIndex,new CodeBinaryOperatorExpression(loopIndex, CodeBinaryOperatorType.Add, new CodePrimitiveExpression(1))), innerStatements.ToArray()); statements.Add(loop); } else statements.AddRange(innerStatements.ToArray()); }
private ShaderExtensionGenerator(SourceShader shader, Platform platform, string techniquePostfix) { this.techniquePostfix = techniquePostfix; //this method temporary modifies the HlslStructure stored in the source shader, so take a backup first. structureBackup = new Dictionary<HlslStructure, HlslStructure.ShaderStatement[]>(); BackupStructure(shader.HlslShader); RegisterSet registers = shader.GetDecompiledEffect(platform).EffectRegisters; List<string> addRegisters = new List<string>(); methodList = shader.GetAllMethods(platform, true).ToArray(); foreach (var method in methodList) { if (methodNames.ContainsKey(method.Name)) continue; bool open = false; bool args = false; //work out if this method takes args foreach (var element in method.HlslShader.Elements) { if (open) { if (element == ")") open = false; else args = true; } if (element == "(") open = true; } methodNames.Add(method.Name,args); } //collect up the declared world matrices foreach (var reg in registers) { if (reg.Semantic != null && reg.Semantic.StartsWith("WORLD", StringComparison.InvariantCultureIgnoreCase)) { string replaceWith = reg.Semantic.Substring(5); //see if the replacement exists. if (replaceWith.Length > 0) { bool createReg = true; foreach (var r2 in registers) { if (r2.Semantic != null && r2.Semantic.Equals(replaceWith, StringComparison.InvariantCultureIgnoreCase)) { createReg = false; matrixRemap.Add(reg.Name, new MatrixMapping() { Name = reg.Name, RemapTo = r2.Name + worldMatrixName, BaseName = r2.Name}); } } if (createReg) { addRegisters.Add(replaceWith); matrixRemap.Add(reg.Name, new MatrixMapping() { Name = reg.Name, RemapTo = ToInternalMatrixName(reg.Name), BaseName = ToInternalMatrixName(replaceWith) }); } } else worldMatrix = reg; } } header.AppendLine(); header.AppendFormat("float4 {0}[216] : BLENDMATRICES; ", blendMatricesName); header.AppendLine(); //add the new registers foreach (var reg in addRegisters) { header.AppendFormat("float4x4 {0} : {1}; ", ToInternalMatrixName(reg), reg); header.AppendLine(); } methodSignatureAppend = ""; methodCallAppend = ""; foreach (var remap in matrixRemap.Values) { methodSignatureAppend += string.Format("float4x4 {0}, ", remap.RemapTo); methodCallAppend += string.Format("{0}, ", remap.RemapTo); } methodSignatureAppend += "float4x4 " + worldMatrixName; methodCallAppend += worldMatrixName; if (worldMatrix.Name != null) { matrixRemap.Add(worldMatrix.Name, new MatrixMapping() { Name = worldMatrix.Name, RemapTo = worldMatrixName }); } BuildTechniqueMethod(shader, ShaderExtension.Blending); BuildTechniqueMethod(shader, ShaderExtension.Instancing); foreach (var tech in shader.GetAllTechniques()) { if (tech.Platform == platform || tech.Platform == Platform.Both) { AsmTechnique asmTechnique = shader.GetAsmTechnique(tech.Name, platform); rootVsMethodName = tech.VertexShaderMethodName; GenerateTechnique(shader, tech, asmTechnique, platform); } } header.Append(builtShader); header.Append(footer); result = header.ToString(); }
public DecompiledEffect(SourceShader source, Platform platform) { this.techniqueDefaults = new Dictionary<string, TechniqueExtraData>(); var handler = new EffectHandler(); handler.source = source.ShaderSource; handler.filename = source.FileName; handler.buildForXbox = platform == Platform.Xbox; //create the native DX decompiler wrapper var decompiler = new Native.ShaderDecompiler(ASCIIEncoding.ASCII.GetBytes(source.ShaderSource), source.FileName, platform == Platform.Xbox, handler); Effect effect = handler.Effect; if (decompiler.Errors != null && decompiler.GetShaderCode() == null) Common.ThrowError(decompiler.Errors); //now pull the good stuff out. List<Register> registers = new List<Register>(); List<Register> textures = new List<Register>(); for (int i = 0; i < effect.Parameters.Count; i++) { Register register = new Register(); if (effect.Parameters[i].ParameterType == EffectParameterType.Single || effect.Parameters[i].ParameterType == EffectParameterType.Int32 || effect.Parameters[i].ParameterType == EffectParameterType.Bool) { register.Name = effect.Parameters[i].Name; register.Semantic = effect.Parameters[i].Semantic; register.ArraySize = effect.Parameters[i].Elements.Count; register.Size = effect.Parameters[i].RowCount * Math.Max(1, register.ArraySize); registers.Add(register); } if (effect.Parameters[i].ParameterType >= EffectParameterType.Texture && effect.Parameters[i].ParameterType <= EffectParameterType.TextureCube) { EffectParameterType type = effect.Parameters[i].ParameterType; if (type == EffectParameterType.Texture1D) type = EffectParameterType.Texture2D; register.Name = effect.Parameters[i].Name; register.Semantic = effect.Parameters[i].Semantic; register.Type = type.ToString(); textures.Add(register); register.Category = RegisterCategory.Texture; registers.Add(register); } } //iterate the samplers (XNA 4 removed the ability to query samplers!) var samplers = decompiler.GetSamplers(); for (int i = 0; i < samplers.Length; i++) { var sampler = new Register(); sampler.Name = samplers[i].Name; sampler.Semantic = samplers[i].Semantic; sampler.Type = samplers[i].Type; sampler.Category = RegisterCategory.Sampler; registers.Add(sampler); } //null any empty semantics for (int i = 0; i < registers.Count; i++) { Register reg = registers[i]; if (reg.Semantic != null && reg.Semantic.Length == 0) reg.Semantic = null; registers[i] = reg; } this.effectRegisters = new RegisterSet(registers.ToArray()); this.decompiledAsm = decompiler.DisassembledCode; ExtractEffectDefaults(effect, textures, source, platform); effect.Dispose(); effect = null; }
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); }
public RegisterSet(string header) { //extract the registers used... /* * Example header: * * // * // Generated by Microsoft (R) D3DX9 Shader Compiler 9.15.779.0000 * // * // Parameters: * // * // float2 shadowCameraNearFar; * // * // * // Registers: * // * // Name Reg Size * // ------------------- ----- ---- * // shadowCameraNearFar c0 1 * // * */ Dictionary <string, Register> registers = new Dictionary <string, Register>(); Tokenizer tokenizer = new Tokenizer(header, false, true, true); string[] lines = header.Split('\n'); int state = 0; while (tokenizer.NextToken()) { switch (tokenizer.Token) { case ":": break; case "Parameters": state = 1; break; case "//": //determine if the line has content... if (lines[tokenizer.Line].Trim().Length > 2) { if (state == 1) { //try and extract something // float2 shadowCameraNearFar; tokenizer.NextToken(); string type = tokenizer.Token; tokenizer.NextToken(); if (type == "Registers") { state = 2; //done, go to registers break; } if (type == "struct") { string structContents = ""; string structName = ""; try { while (tokenizer.Token != "{") { tokenizer.NextToken(); } tokenizer.ReadBlock(); structContents = tokenizer.Token; tokenizer.NextToken(); structName = tokenizer.Token; } catch { } finally { throw new CompileException(string.Format("Shader compiler cannot map the custom constant structure '{0} {1}' into a compatible XNA data structure", structName, structContents.Replace(Environment.NewLine, "").Replace("//", ""))); } } string name = tokenizer.Token; //possible array, or ; tokenizer.NextToken(); string token = tokenizer.Token; int array = -1; if (token == "[") { tokenizer.NextToken(); array = int.Parse(tokenizer.Token); tokenizer.NextToken(); //eat the ] tokenizer.NextToken(); } //should be a ; if (tokenizer.Token != ";") { throw new CompileException("Expected ';' in shader header"); } Register reg = new Register(); reg.ArraySize = array; reg.Name = name; reg.Type = type; registers.Add(name, reg); } if (state == 2 || state == 3 || state == 4) { // Name Reg Size // ------------------- ----- ---- // shadowCameraNearFar c0 1 string name, register, size; tokenizer.NextToken(); name = tokenizer.Token; tokenizer.NextToken(); register = tokenizer.Token; tokenizer.NextToken(); size = tokenizer.Token; bool skip = false; if (name == "Name" && register == "Reg" && size == "Size") { skip = true; } if (name.Replace("-", "").Length == 0 && register.Replace("-", "").Length == 0 && size.Replace("-", "").Length == 0) { skip = true; } if (!skip) { Register reg; if (registers.TryGetValue(name, out reg)) { reg.Size = int.Parse(size); switch (register[0]) { case 'c': reg.Category = RegisterCategory.Float4; break; case 'i': reg.Category = RegisterCategory.Integer4; break; case 'b': reg.Category = RegisterCategory.Boolean; break; case 't': reg.Category = RegisterCategory.Texture; break; case 's': reg.Category = RegisterCategory.Sampler; break; case 'r': reg.Category = RegisterCategory.Temp; break; default: throw new CompileException(string.Format("Unexpected constant type '{0}'", register[0])); } reg.Index = int.Parse(register.Substring(1)); reg.Rank = ExtractRank(reg.Type, reg.Category, reg.ArraySize, reg.Size); registers[name] = reg; } } } } break; } } List <Register> registerList = new List <Register>(); foreach (Register register in registers.Values) { registerList.Add(register); } this.registers = registerList.ToArray(); }
private static void ThrowSamplerNoTextureException(Register reg) { throw new CompileException(string.Format("Texture Sampler '{0} {1}' is not bound to a named Texture{2}The sampler must define a default sampler state, in the example format:{2}{2}texture{3} {1}Texture;{2}{0} {1} = sampler_state{2}{4}{2}\tTexture = ({1}Texture);{2}{5}; ", reg.Type, reg.Name, Environment.NewLine, reg.Type.Length >= 7 ? reg.Type.Substring(7) : "", "{", "}")); }