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(); }
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); } }
public ShaderRegisters(SourceShader source, string techniqueName, Platform platform, IExtensionStatementProvider extensionStatementProvider) { AsmTechnique technique = source.GetAsmTechnique(techniqueName, platform); this.extensionStatementProvider = extensionStatementProvider; vsReg = technique.VertexShader.RegisterSet; psReg = technique.PixelShader.RegisterSet; if (technique.InstancingShader != null) vsInstancingReg = technique.InstancingShader.RegisterSet; if (technique.BlendingShader != null) vsBlendingReg = technique.BlendingShader.RegisterSet; if (technique.TechniqueExtraData != null) { this.techniqueData = technique.TechniqueExtraData; psDefault = technique.TechniqueExtraData.PixelShaderConstants; vsDefault = technique.TechniqueExtraData.VertexShaderConstants; psBooleanDefault = technique.TechniqueExtraData.PixelShaderBooleanConstants; vsBooleanDefault = technique.TechniqueExtraData.VertexShaderBooleanConstants; } }
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 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); }
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 ShaderTextures(SourceShader source, string techniqueName, Platform platform) { this.psSamplers = new List<Register>(); this.vsSamplers = new List<Register>(); this.allSamplers = new Dictionary<string, SharedSampler>(); AsmTechnique technique = source.GetAsmTechnique(techniqueName, platform); TechniqueExtraData extras = technique.TechniqueExtraData; //pull out the textures that will be used textures = new TextureAssociation[extras.TechniqueTextures.Length]; for (int i = 0; i < extras.TechniqueTextures.Length; i++) textures[i] = new TextureAssociation(extras.TechniqueTextures[i]); //now do the samplers RegisterSet set = technique.PixelShader.RegisterSet; //pixel first foreach (Register reg in set) { if (reg.Category == RegisterCategory.Sampler) { psSamplers.Add(reg); int textureIndex = extras.PixelSamplerTextureIndex[reg.Index]; if (textureIndex == -1) ThrowSamplerNoTextureException(reg); textures[textureIndex].PsSamplers.Add(reg.Index); //add the sampler to 'allSamplers' SharedSampler ss = new SharedSampler(); ss.PsIndex = reg.Index; ss.SamplerDetails = reg; ss.Index = allSamplers.Count; ss.DefaultState = extras.PixelSamplerStates[reg.Index]; allSamplers.Add(reg.Name, ss); } } set = technique.VertexShader.RegisterSet; //now vertex foreach (Register reg in set) { if (reg.Category == RegisterCategory.Sampler) { vsSamplers.Add(reg); int textureIndex = extras.VertexSamplerTextureIndex[reg.Index]; if (textureIndex == -1) ThrowSamplerNoTextureException(reg); textures[textureIndex].VsSamplers.Add(reg.Index); //add the sampler to 'allSamplers' SharedSampler ss; if (!allSamplers.TryGetValue(reg.Name, out ss)) { ss = new SharedSampler(); ss.SamplerDetails = reg; ss.Index = allSamplers.Count; ss.DefaultState = extras.VertexSamplerStates[reg.Index]; allSamplers.Add(reg.Name, ss); } ss.VsIndex = reg.Index; } } }