public static SourceShader Create(string shaderSource, string filename) { SourceShader ss = null; string dir = Directory.GetCurrentDirectory(); try { Directory.SetCurrentDirectory(new FileInfo(filename).Directory.FullName); ss = new SourceShader(shaderSource, filename, null); ss.ExtractAsmTechniques(null); if (!ss.manualExtensions) { try { int line; shaderSource = ShaderExtensionGenerator.GenerateShaderCode(ss, "", ss.mixedMode, out line); ss = new SourceShader(shaderSource, filename, null); ss.generatedLineStart = line; ss.ExtractAsmTechniques(null); } catch (Exception ex) { ShaderExtensionGenerator.ThrowGeneratorError(ex.ToString(), filename); } } } finally { Directory.SetCurrentDirectory(dir); } return ss; }
public SourceDom(SourceShader shader, string baseNamespace, CodeDomProvider provider) { this.codeProvider = provider; this.directives = new CompileDirectives(provider); this.source = shader; this.baseNamespace = baseNamespace; string namespaceName = baseNamespace; if (!shader.UseParentNamespace) namespaceName += "." + Common.ToUpper(Path.GetFileNameWithoutExtension(source.FileName)); this.outputNamespace = namespaceName; HlslTechnique[] techniques = shader.GetAllTechniques(); if (shader.DefinePlatform) { //create a copy for each platform //xbox first this.rootPcNamespace = new CodeNamespace(namespaceName); this.rootXboxNamespace = new CodeNamespace(namespaceName); for (int i = 0; i < techniques.Length; i++) { //build the PC shaders if ((techniques[i].Platform & Platform.Windows) == Platform.Windows) { ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Windows, directives); this.rootPcNamespace.Types.Add(dom.CodeTypeDeclaration); } } for (int i = 0; i < techniques.Length; i++) { //build the xbox shaders if ((techniques[i].Platform & Platform.Xbox) == Platform.Xbox) { ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Xbox, directives); this.rootXboxNamespace.Types.Add(dom.CodeTypeDeclaration); } } } else { this.rootNamespace = new CodeNamespace(namespaceName); for (int i = 0; i < techniques.Length; i++) { //build the combined pc / xbox shaders if ((techniques[i].Platform & Platform.Both) == Platform.Both) { ShaderDom dom = new ShaderDom(source, techniques[i].Name, Platform.Both, directives); this.rootNamespace.Types.Add(dom.CodeTypeDeclaration); } } } }
public static string GenerateShaderCode(SourceShader shader, string techniquePostfix, bool mixedModeOutput, out int startLine) { string noTechniques = TechniqueRemover.Process(shader); startLine = 1; for (int i = 0; i < noTechniques.Length; i++) { if (noTechniques[i] == '\n') startLine++; } if (shader.GenerateInternalClass || shader.UseParentNamespace || shader.DefinePlatform || shader.ExposeRegisters) { //recreate the extensions flag, if needed StringBuilder newExtensons = new StringBuilder("//CompilerOptions = "); if (shader.GenerateInternalClass) newExtensons.Append("internalclass, "); if (shader.UseParentNamespace) newExtensons.Append("parentnamespace, "); if (shader.DefinePlatform) newExtensons.Append("defineplatform, "); if (shader.ExposeRegisters) newExtensons.Append("exposeregisters"); newExtensons.AppendLine(); if (noTechniques.Length > 1 && noTechniques.Substring(0, 2) == Environment.NewLine) noTechniques = noTechniques.Substring(2); newExtensons.Append(noTechniques); noTechniques = newExtensons.ToString(); } if (!mixedModeOutput) { //separate platforms string xbox = new ShaderExtensionGenerator(shader, Platform.Xbox, techniquePostfix).result; string pc = new ShaderExtensionGenerator(shader, Platform.Windows, techniquePostfix).result; return string.Format(@"{0} #ifdef XBOX360 {1} #else {2} #endif", noTechniques, xbox, pc); } else { string both = new ShaderExtensionGenerator(shader, Platform.Both, techniquePostfix).result; return string.Format(@"{0} {1}",noTechniques, both); } }
private void ExtractIncludeSource(ref bool useVfetch) { if (filename != null) { //parse the hs, look for #include's in the root level only foreach (HlslStructure hs in this.hlslShader.Children) { if (hs.Elements.Length > 4) { if (hs.Elements[0] == "#" && hs.Elements[1] == "include") { bool global = hs.Elements[2] == "<"; StringBuilder file = new StringBuilder(); for (int i = 3; i < hs.Elements.Length - 1; i++) { if ((global && hs.Elements[i] == ">") || (!global && hs.Elements[i] == "\"")) { break; } file.Append(hs.Elements[i]); } string includeName = file.ToString(); if (includeName == VFetchIncludeHandler.IncludeSymbol) { //vfetch requires shaders are built separately useVfetch = true; } else { //find the file string path = VFetchIncludeHandler.ResolveIncludePath(file.ToString(), this.filename); if (File.Exists(path)) { //load the file and parse it as well SourceShader include = new SourceShader(File.ReadAllText(path), path, false); includedSource.Add(include); } } } } } } }
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 VFetchXboxMethodExtractor(SourceShader shader, HlslTechnique technique) { this.source = shader; HlslMethod method = shader.GetMethod(technique.VertexShaderMethodName, Platform.Xbox); if (method != null && method.UsesVFetch) { vsCode = ProcessMethod(method, technique.VertexShaderArgs, ShaderProfile.VS_3_0); } method = shader.GetMethod(technique.PixelShaderVersion, Platform.Xbox); //pixel shader using vfetch?! if (method != null && method.UsesVFetch) { psCode = ProcessMethod(method, technique.PixelShaderArgs, ShaderProfile.PS_3_0); } }
private void ValidatePixleShaderInput(SourceShader source, Platform platform) { if (psListing != null && vsListing != null) { for (int i = 0; i < psListing.InputCount; i++) { if (!vsListing.ContainsOutput(psListing.GetInput(i))) { throw new CompileException(string.Format( "Pixel Shader '{0}' for Technique '{1}' tries to access input '{2} {3}', which is not output by Vertex Shader '{4}'{5}(Use the CompilerOption 'SkipConstantValidation' to disable this check)", source.GetTechnique(name, platform).PixelShaderMethodName, name, psListing.GetInput(i).Usage, psListing.GetInput(i).Index, source.GetTechnique(name, platform).VertexShaderMethodName, Environment.NewLine)); } } } }
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; } }
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 void ExtractIncludeSource() { if (filename != null) { //parse the hs, look for #include's in the root level only foreach (HlslStructure hs in this.hlslShader.Children) { if (hs.Elements.Length > 4) { if (hs.Elements[0] == "#" && hs.Elements[1] == "include") { bool global = hs.Elements[2] == "<"; StringBuilder file = new StringBuilder(); for (int i = 3; i < hs.Elements.Length-1; i++) { if ((global && hs.Elements[i] == ">") || (!global && hs.Elements[i] == "\"")) break; file.Append(hs.Elements[i]); } string includeName = file.ToString(); //find the file string path = Path.IsPathRooted(file.ToString()) ? file.ToString() : Path.Combine(Path.GetDirectoryName(filename), file.ToString()); if (File.Exists(path)) { //load the file and parse it as well SourceShader include = new SourceShader(File.ReadAllText(path), path, null); includedSource.Add(include); } } } } } }
//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(); }
private void ExtractEffectDefaults(Effect effect, List<Register> textures, SourceShader source, Platform platform) { //nasty-ness ensues! GraphicsDevice device = Graphics.GraphicsDevice; int maxVsConst = 256; int maxPsConst = 32; int maxPsTextures = 16; int maxVsTextures = 4; bool[] shaderBooleanConstants = new bool[16]; List<Texture> allTextures = new List<Texture>(); foreach (EffectTechnique technique in effect.Techniques) { //Thanks to Darren Grant (again :) //annotate a Technique with 'BaseTypes' and the generates class will inherit from those types string[] baseTypes = new string[0]; foreach (EffectAnnotation annotation in technique.Annotations) { if (annotation.Name.Equals("BaseTypes", StringComparison.InvariantCulture) || annotation.Name.Equals("BaseType", StringComparison.InvariantCulture)) { baseTypes = annotation.GetValueString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < baseTypes.Length; i++) baseTypes[i] = baseTypes[i].Trim(); } } float[] psConstants = new float[maxPsConst * 4]; // pixel float[] vsConstants = new float[maxVsConst * 4]; // not-pixel TextureSamplerState[] psSamplers = new TextureSamplerState[maxPsTextures]; TextureSamplerState[] vsSamplers = new TextureSamplerState[maxVsTextures]; int[] psTexturesIndex = new int[maxPsTextures]; int[] vsTexturesIndex = new int[maxVsTextures]; int[] psBooleanConstants = new int[16]; int[] vsBooleanConstants = new int[16]; allTextures.Clear(); Dictionary<string, Vector4[]> techniqueSingleValues = new Dictionary<string, Vector4[]>(); //get the device object devicePtr = device.GetType().GetField("pComPtr", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(device); var deviceInterop = new Xen.Graphics.ShaderSystem.Native.DeviceInterop((System.Reflection.Pointer)devicePtr); try { //I'm sure XNA won't mind... deviceInterop.ZeroShaderConstants(); for (int i = 0; i < maxPsTextures; i++) { deviceInterop.SetTextureFilters(i, false); ResetSampler(device, i, true); } for (int i = 0; i < maxVsTextures; i++) { deviceInterop.SetTextureFilters(i, true); ResetSampler(device, i, false); } //assign the technique textures foreach (Register texReg in textures) { Type type = Common.GetTextureType(texReg.Type); Texture tex = Graphics.BeginGetTempTexture(type); effect.Parameters[texReg.Name].SetValue(tex); allTextures.Add(tex); } //bind the effect technique effect.CurrentTechnique = technique; if (technique.Passes.Count > 0) { EffectPass pass = technique.Passes[0]; pass.Apply(); } foreach (var param in effect.Parameters) { try { if (param.ParameterType == EffectParameterType.Single || param.ParameterType == EffectParameterType.Int32) { Vector4[] values = param.GetValueVector4Array(param.RowCount); techniqueSingleValues.Add(param.Name, values); } } catch { } } //all done. Now read back what has changed. :D deviceInterop.GetShaderConstantsPS(psConstants); deviceInterop.GetShaderConstantsVS(vsConstants); //psConstants = device.GetPixelShaderVector4ArrayConstant(0, maxPsConst); //vsConstants = device.GetVertexShaderVector4ArrayConstant(0, maxVsConst); for (int i = 0; i < maxPsTextures; i++) psSamplers[i] = GetState(device, deviceInterop, i, true, allTextures, out psTexturesIndex[i]); for (int i = 0; i < maxVsTextures; i++) vsSamplers[i] = GetState(device, deviceInterop, i, false, allTextures, out vsTexturesIndex[i]); for (int i = 0; i < allTextures.Count; i++) Graphics.EndGetTempTexture(allTextures[i]); allTextures.Clear(); deviceInterop.GetShaderConstantsPS(psBooleanConstants); deviceInterop.GetShaderConstantsVS(vsBooleanConstants); //vsBooleanConstants = device.GetVertexShaderBooleanConstant(0, 16); //psBooleanConstants = device.GetPixelShaderBooleanConstant(0, 16); } catch { //something went wrong... Eg, binding a SM 3.0 shader on SM 2.0 hardware device throw new CompileException("An unexpected error occured while compiling shader: The DirectX device may not be XNA 'HiDef' capable"); } TechniqueExtraData defaults = new TechniqueExtraData(); defaults.PixelSamplerStates = psSamplers; defaults.PixelShaderConstants = Convert(psConstants); defaults.VertexSamplerStates = vsSamplers; defaults.VertexShaderConstants = Convert(vsConstants); defaults.PixelSamplerTextureIndex = psTexturesIndex; defaults.VertexSamplerTextureIndex = vsTexturesIndex; defaults.TechniqueTextures = textures.ToArray(); defaults.ClassBaseTypes = baseTypes; defaults.PixelShaderBooleanConstants = Convert(psBooleanConstants); defaults.VertexShaderBooleanConstants = Convert(vsBooleanConstants); defaults.DefaultSingleValues = techniqueSingleValues; if (this.techniqueDefaults.ContainsKey(technique.Name) == false) this.techniqueDefaults.Add(technique.Name, defaults); } }
public DecompiledEffect(SourceShader source, Platform platform) { CompilerMacro[] macros = null; if (platform == Platform.Xbox) { macros = XboxCompileMacros; } CompilerIncludeHandler include = null; TargetPlatform target = TargetPlatform.Windows; this.techniqueDefaults = new Dictionary <string, TechniqueExtraData>(); if (platform != Platform.Both) { include = new VFetchIncludeHandler(source.FileName, true); //ALWAYS target the PC for the vfetch macro } else { include = new VFetchIncludeHandler(source.FileName); //Acts as a generic handler } CompiledEffect compiledEffect = Effect.CompileEffectFromSource(source.ShaderSource, macros, include, source.CompilerOptions, target); if (!compiledEffect.Success) { Common.ThrowError(compiledEffect.ErrorsAndWarnings, source.ShaderSource); } //now pull the good stuff out. using (EffectPool pool = new EffectPool()) using (Effect effect = new Effect(Graphics.GraphicsDevice, compiledEffect.GetEffectCode(), CompilerOptions.None, pool)) { Register[] registers = new Register[effect.Parameters.Count]; List <Register> textures = new List <Register>(); for (int i = 0; i < registers.Length; i++) { if (effect.Parameters[i].ParameterType == EffectParameterType.Single || effect.Parameters[i].ParameterType == EffectParameterType.Int32 || effect.Parameters[i].ParameterType == EffectParameterType.Bool) { registers[i].Name = effect.Parameters[i].Name; registers[i].Semantic = effect.Parameters[i].Semantic; } 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; } registers[i].Name = effect.Parameters[i].Name; registers[i].Semantic = effect.Parameters[i].Semantic; registers[i].Type = type.ToString(); textures.Add(registers[i]); } } this.effectRegisters = new RegisterSet(registers); this.decompiledAsm = Effect.Disassemble(effect, false); ExtractEffectDefaults(effect, textures, source, platform); } }
private void ExtractEffectDefaults(Effect effect, List <Register> textures, SourceShader source, Platform platform) { //nasty-ness ensues! GraphicsDevice device = Graphics.GraphicsDevice; int maxVsConst = device.GraphicsDeviceCapabilities.MaxVertexShaderConstants; int maxPsConst = 32; int maxPsTextures = 16; int maxVsTextures = 4; bool setPsBooleanConstants = device.GraphicsDeviceCapabilities.PixelShaderVersion.Major == 3; bool[] shaderBooleanConstants = new bool[16]; List <Texture> allTextures = new List <Texture>(); foreach (EffectTechnique technique in effect.Techniques) { //Thanks to Darren Grant (again :) //annotate a Technique with 'BaseTypes' and the generates class will inherit from those types string[] baseTypes = new string[0]; foreach (EffectAnnotation annotation in technique.Annotations) { if (annotation.Name.Equals("BaseTypes", StringComparison.InvariantCulture) || annotation.Name.Equals("BaseType", StringComparison.InvariantCulture)) { baseTypes = annotation.GetValueString().Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < baseTypes.Length; i++) { baseTypes[i] = baseTypes[i].Trim(); } } } Vector4[] psConstants = new Vector4[maxPsConst]; // pixel Vector4[] vsConstants = new Vector4[maxVsConst]; // not-pixel TextureSamplerState[] psSamplers = new TextureSamplerState[maxPsTextures]; TextureSamplerState[] vsSamplers = new TextureSamplerState[maxVsTextures]; int[] psTexturesIndex = new int[maxPsTextures]; int[] vsTexturesIndex = new int[maxVsTextures]; bool[] psBooleanConstants = new bool[16]; bool[] vsBooleanConstants = new bool[16]; allTextures.Clear(); Dictionary <string, Vector4[]> techniqueSingleValues = new Dictionary <string, Vector4[]>(); try { device.SetPixelShaderConstant(0, psConstants); device.SetVertexShaderConstant(0, vsConstants); device.SetVertexShaderConstant(0, shaderBooleanConstants); if (setPsBooleanConstants) { device.SetPixelShaderConstant(0, shaderBooleanConstants); } for (int i = 0; i < maxPsTextures; i++) { ResetSampler(device, i, true); } for (int i = 0; i < maxVsTextures; i++) { ResetSampler(device, i, false); } //assign the technique textures foreach (Register texReg in textures) { Type type = Common.GetTextureType(texReg.Type); Texture tex = Graphics.BeginGetTempTexture(type); effect.Parameters[texReg.Name].SetValue(tex); allTextures.Add(tex); } //bind the effect technique effect.CurrentTechnique = technique; effect.Begin(); if (technique.Passes.Count > 0) { EffectPass pass = technique.Passes[0]; pass.Begin(); pass.End(); } effect.End(); foreach (var param in effect.Parameters) { try { if (param.ParameterType == EffectParameterType.Single || param.ParameterType == EffectParameterType.Int32) { Vector4[] values = param.GetValueVector4Array(param.RowCount); techniqueSingleValues.Add(param.Name, values); } } catch { } } //all done. Now read back what has changed. :D psConstants = device.GetPixelShaderVector4ArrayConstant(0, maxPsConst); vsConstants = device.GetVertexShaderVector4ArrayConstant(0, maxVsConst); for (int i = 0; i < maxPsTextures; i++) { psSamplers[i] = GetState(device, i, true, allTextures, out psTexturesIndex[i]); } for (int i = 0; i < maxVsTextures; i++) { vsSamplers[i] = GetState(device, i, false, allTextures, out vsTexturesIndex[i]); } for (int i = 0; i < allTextures.Count; i++) { Graphics.EndGetTempTexture(allTextures[i]); } allTextures.Clear(); vsBooleanConstants = device.GetVertexShaderBooleanConstant(0, 16); psBooleanConstants = device.GetPixelShaderBooleanConstant(0, 16); } catch { //something went wrong... Eg, binding a SM 3.0 shader on SM 2.0 hardware device //Need to be running the Reference device throw new CompileException("Unable to compile shader: The DirectX Reference Device may be missing (Is the DirectX SDK Installed?)"); } TechniqueExtraData defaults = new TechniqueExtraData(); defaults.PixelSamplerStates = psSamplers; defaults.PixelShaderConstants = psConstants; defaults.VertexSamplerStates = vsSamplers; defaults.VertexShaderConstants = vsConstants; defaults.PixelSamplerTextureIndex = psTexturesIndex; defaults.VertexSamplerTextureIndex = vsTexturesIndex; defaults.TechniqueTextures = textures.ToArray(); defaults.ClassBaseTypes = baseTypes; defaults.PixelShaderBooleanConstants = psBooleanConstants; defaults.VertexShaderBooleanConstants = vsBooleanConstants; defaults.DefaultSingleValues = techniqueSingleValues; if (this.techniqueDefaults.ContainsKey(technique.Name) == false) { this.techniqueDefaults.Add(technique.Name, defaults); } } }
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 TechniqueRemover(SourceShader shader) { techniques = new HashSet<HlslStructure>(); foreach (var tech in shader.GetAllTechniques()) techniques.Add(tech.HlslShader); result = new StringBuilder(); shader.HlslShader.ToString(result, 0, this, null, false, true); }
private static string[] SanitizeConversionErrorMessage(string errors, string source, string original, SourceShader shader) { CompileException compileException = null; try { List<string> errorList = new List<string>(); string[] lines = errors.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); StringBuilder output = new StringBuilder(errors.Length); string[] sourceLines = source.Split('\n'); string[] originalLines = original.Split('\n'); foreach (string line in lines) { if (line.Length > 1 && line[0] == '(') { //write the previous error out, if it exists if (output.Length > 0) { errorList.Add(output.ToString()); output.Length = 0; } //ok, this might be a line error. string number = ""; string lineNumberStr = null; for (int i = 1; i < line.Length - 1; i++) { if (line[i] == ')') { if (line[i + 1] != ':') number = "";// invalid break; } if (char.IsNumber(line[i])) number += line[i]; else { if (line[i] == ',') { lineNumberStr = number; number = ""; } else { number = ""; // invalid break; } } } if (lineNumberStr == null) { lineNumberStr = number; number = "0"; } int lineNumber; if (lineNumberStr.Length > 0 && int.TryParse(lineNumberStr, out lineNumber) && lineNumber > 0 && lineNumber <= sourceLines.Length) { //find an error line reindex, int remapLine = -1; int reps = 4; //look back at most 4 lines while (lineNumber-- > 0 && remapLine == -1 && reps-- > 0) { string errorLine = sourceLines[lineNumber]; //find any '/*NUMBER*/' blocks, which remap to source line for (int i = 0; i < errorLine.Length - 1; i++) { if (errorLine[i] == '/' && errorLine[i + 1] == '*') { //this could be it. string remapLineStr = ""; for (int n = i + 2; n < errorLine.Length - 2; n++) { if (char.IsNumber(errorLine[n])) remapLineStr += errorLine[n]; else { if (!(errorLine[n] == '*' && errorLine[n + 1] == '/')) remapLineStr = ""; //invalid break; } } int lineIdx; if (remapLineStr.Length > 0 && int.TryParse(remapLineStr, out lineIdx)) remapLine = lineIdx; } if (remapLine != -1) break; } } //write the new line index at the start of the line output.Append(string.Format("({0},", remapLine + 1)); } else output.Append("(0,"); output.AppendLine(line.Substring(number.Length + 3)); } else output.Append(line); } //write the previous error out, if it exists if (output.Length > 0) errorList.Add(output.ToString()); return errorList.ToArray(); } catch (CompileException ex) { compileException = ex; } catch { return null; } if (compileException != null) throw compileException; return null; }
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 BuildTechniqueMethod(SourceShader shader, ShaderExtension extension) { methodExtractionExtension = extension; foreach (var method in methodList) { if (methodBuilt.ContainsKey(method.Name) == false) methodBuilt.Add(method.Name, false); } foreach (var tech in shader.GetAllTechniques()) { BuildMethod(tech.VertexShaderMethodName, extension); } methodBuilt.Clear(); UnwindBackup(shader.HlslShader); }
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 TokenRename(SourceShader shader, Platform platform, string extension) { this.shader = shader; this.platform = platform; this.extension = extension; }
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; }
public ShaderDom(SourceShader source, string techniqueName, Platform platform, CompileDirectives directives) { this.domList = new List<DomBase>(); this.domList.Add(this); //add custom dom's this.domList.Add(new ShaderBytes(source, techniqueName, platform)); //needs to be passed to the registers as an interface provider ConstantSetup constantes = new ConstantSetup(source, techniqueName, platform); this.domList.Add(new ShaderRegisters(source, techniqueName, platform, constantes)); this.domList.Add(constantes); this.domList.Add(new ShaderTextures(source, techniqueName, platform)); foreach (DomBase dom in domList) dom.Setup(this); this.techniqueName = techniqueName; this.source = source; this.platform = platform; classDom = new CodeTypeDeclaration(techniqueName); classDom.IsClass = true; classDom.Attributes = MemberAttributes.Final | MemberAttributes.Public; classDom.TypeAttributes = TypeAttributes.Sealed | TypeAttributes.Public | TypeAttributes.Class; //provide a useful comment to the class GenerateClassComment(); if (source.GenerateInternalClass) { classDom.Attributes = MemberAttributes.Final | MemberAttributes.Assembly; classDom.TypeAttributes = TypeAttributes.NestedAssembly | TypeAttributes.Class | TypeAttributes.Sealed; } classDom.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.Diagnostics.DebuggerStepThroughAttribute)))); classDom.CustomAttributes.Add(new CodeAttributeDeclaration(new CodeTypeReference(typeof(System.CodeDom.Compiler.GeneratedCodeAttribute)),new CodeAttributeArgument(new CodePrimitiveExpression(GetType().Assembly.ManifestModule.Name)),new CodeAttributeArgument(new CodePrimitiveExpression(GetType().Assembly.ManifestModule.ModuleVersionId.ToString())))); classDom.BaseTypes.Add(new CodeTypeReference(typeof(BaseShader))); //add custom base types to the shader //these are defined in TechniqueExtraData AsmTechnique asmTechnique = this.source.GetAsmTechnique(this.techniqueName, this.platform); if (asmTechnique.TechniqueExtraData != null && asmTechnique.TechniqueExtraData.ClassBaseTypes != null) { foreach (string baseTypeName in asmTechnique.TechniqueExtraData.ClassBaseTypes) classDom.BaseTypes.Add(new CodeTypeReference(baseTypeName)); } this.directives = directives; SetupMembers(techniqueName); foreach (DomBase dom in domList) dom.SetupMembers(this); CreateConstructor(); CreateStaticGraphicsInitMethod(); CreateBindMethod(); CreateWarmShaderMethod(); CreateChangedMethod(); CreateVertexInputMethods(); CodeTypeMemberCollection pcMembers = new CodeTypeMemberCollection(); CodeTypeMemberCollection xboxMembers = new CodeTypeMemberCollection(); foreach (DomBase dom in this.domList) { dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); classDom.Members.Add(s); }, Platform.Both); if (!source.DefinePlatform) // no need for specialization when the platform is constant { dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); pcMembers.Add(s); }, Platform.Windows); dom.AddMembers(this, delegate(CodeTypeMember s, string c) { Comment(s, c); xboxMembers.Add(s); }, Platform.Xbox); } } foreach (DomBase dom in this.domList) { dom.AddReadonlyMembers(this, delegate(CodeTypeMember s, string c) { CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet(); Comment(readonlySnip ?? s, c); if (readonlySnip != null) classDom.Members.Add(readonlySnip); classDom.Members.Add(s); }, Platform.Both); if (!source.DefinePlatform) { dom.AddReadonlyMembers(this, delegate(CodeTypeMember s, string c) { CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet(); Comment(readonlySnip ?? s, c); if (readonlySnip != null) pcMembers.Add(readonlySnip); pcMembers.Add(s); }, Platform.Windows); dom.AddReadonlyMembers(this, delegate(CodeTypeMember s, string c) { CodeTypeMember readonlySnip = directives.CreateReadOnlySnippet(); Comment(readonlySnip ?? s, c); if (readonlySnip != null) xboxMembers.Add(readonlySnip); xboxMembers.Add(s); }, Platform.Xbox); } } if (pcMembers.Count > 0 || xboxMembers.Count > 0) { //add #if / else blocks classDom.Members.Add(directives.IfXboxStatement); foreach (CodeTypeMember type in xboxMembers) classDom.Members.Add(type); classDom.Members.Add(directives.ElseStatement); foreach (CodeTypeMember type in pcMembers) classDom.Members.Add(type); classDom.Members.Add(directives.EndifStatement); } //finally, create the attribute setters CreateSetAttributeMethod(typeof(float), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector2), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector3), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector4), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Matrix), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(bool), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(float[]), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector2[]), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector3[]), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Vector4[]), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Matrix[]), "SetAttributeImpl", "attribute"); CreateSetAttributeMethod(typeof(Xen.Graphics.TextureSamplerState), "SetSamplerStateImpl", "sampler"); CreateSetAttributeMethod(typeof(Texture), "SetTextureImpl", "texture"); CreateSetAttributeMethod(typeof(Texture2D), "SetTextureImpl", "texture"); CreateSetAttributeMethod(typeof(Texture3D), "SetTextureImpl", "texture"); CreateSetAttributeMethod(typeof(TextureCube), "SetTextureImpl", "texture"); }
public static string Process(SourceShader shader) { return new TechniqueRemover(shader).result.ToString(); }
//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()); }
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; } } }