private static string GetTechniqueInvoke(TokenRename rename, StringBuilder sb, HlslMethod method, IEnumerator<string> argsEnum) { string methodCall = rename.TranslateMethodName(method.Name); StringBuilder call = new StringBuilder(); call.Append(methodCall); call.Append("("); while (argsEnum.MoveNext()) { call.Append(argsEnum.Current); } call.Append(")"); return call.ToString(); }
private static void ExtractMethodBody(TokenRename rename, StringBuilder sb, HlslMethod method, string prefix) { method.HlslShader.ToString(sb, 0, rename, prefix, true, false); }
private static void ExtractMethodBodies(StringBuilder sb, TokenRename rename) { StringBuilder methodBody = new StringBuilder(); for (int i = 0; i < rename.methodList.Count; i++) { ExtractMethodBody(rename, methodBody, rename.methodList[i], null); sb.Insert(0, methodBody); methodBody.Length = 0; } }
private static void MapRegistersToRenamer(TokenRename rename, RegisterSet set, string extension) { foreach (Register reg in set) { if (reg.Category == RegisterCategory.Sampler) rename.samplerRemapping.Add(reg.Name, string.Format("_" + extension + "_s{0}", reg.Index)); else { if (reg.ArraySize > 0) rename.arrayRemapping.Add(reg.Name, TranslateRegisterName(reg.Name, extension)); else rename.registerRemapping.Add(reg.Name, TranslateRegisterName(reg.Name, extension)); } } }
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; }