/// <summary> /// Constructor /// </summary> /// <param name="moduleMixin">the final shader information</param> /// <param name="log">The log.</param> /// <param name="context">all the mixins in the context</param> /// <param name="compositionsPerVariable">The compositions per variable.</param> /// <param name="cloneContext">The clone context.</param> /// <exception cref="System.ArgumentNullException"> /// moduleMixin /// or /// log /// or /// context /// </exception> public XenkoShaderMixer(ModuleMixin moduleMixin, LoggerResult log, Dictionary<string, ModuleMixin> context, CompositionDictionary compositionsPerVariable, CloneContext cloneContext = null) { if (moduleMixin == null) throw new ArgumentNullException("moduleMixin"); if (log == null) throw new ArgumentNullException("log"); if (context == null) throw new ArgumentNullException("context"); this.log = log; mixContext = context; mainModuleMixin = moduleMixin; defaultCloneContext = cloneContext; if (compositionsPerVariable != null) CompositionsPerVariable = compositionsPerVariable; else CompositionsPerVariable = new CompositionDictionary(); var mixinsToAnalyze = new Stack<ModuleMixin>(CompositionsPerVariable.Values.SelectMany(x => x)); mixinsToAnalyze.Push(mainModuleMixin); while (mixinsToAnalyze.Count > 0) AddDefaultCompositions(mixinsToAnalyze); }
private ParadoxStreamCreator(ShaderClassType shaderClassType, ModuleMixin mixin, List<ModuleMixin> mixins, LoggerResult errorLog) { shader = shaderClassType; mainModuleMixin = mixin; mixinInheritance = mixins; errorWarningLog = errorLog ?? new LoggerResult(); }
/// <summary> /// Replace the method occurence with its last definition /// </summary> /// <param name="methodDeclaration">the overriding method</param> /// <param name="errorLogger"></param> public void ReplaceVirtualMethod(MethodDeclaration methodDeclaration, LoggerResult errorLogger) { var baseDeclarationMixin = (string)methodDeclaration.GetTag(XenkoTags.BaseDeclarationMixin); foreach (var dict in VirtualTableGroup.Select(x => x.Value)) { for (int i = 0; i < dict.Length; ++i) { var method = dict[i]; var originalDecl = (string)method.GetTag(XenkoTags.BaseDeclarationMixin); // TODO: take typedefs into account... if (originalDecl == baseDeclarationMixin && method.IsSameSignature(methodDeclaration)) { if (method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !methodDeclaration.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { errorLogger.Warning(XenkoMessageCode.WarningMissingStageKeyword, methodDeclaration.Span, methodDeclaration, (methodDeclaration.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName); methodDeclaration.Qualifiers |= XenkoStorageQualifier.Stage; } else if (!method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && methodDeclaration.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { errorLogger.Error(XenkoMessageCode.ErrorExtraStageKeyword, methodDeclaration.Span, methodDeclaration, method, (methodDeclaration.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName); methodDeclaration.Qualifiers.Values.Remove(XenkoStorageQualifier.Stage); } dict[i] = methodDeclaration; } } } }
/// <summary> /// Adds the virtual table of the mixin /// </summary> /// <param name="shaderVirtualTable"></param> /// <param name="className"></param> /// <param name="errorLogger"></param> public void AddVirtualTable(ShaderVirtualTable shaderVirtualTable, string className, LoggerResult errorLogger) { var newVT = shaderVirtualTable.VirtualTableGroup[className].ToArray(); VirtualTableGroup.Add(className, newVT); foreach (var methodDecl in newVT) ReplaceVirtualMethod(methodDecl, errorLogger); }
public ShaderDependencyVisitor(LoggerResult log, ShaderSourceManager sourceManager) : base(false, true) { if (log == null) throw new ArgumentNullException("log"); if (sourceManager == null) throw new ArgumentNullException("sourceManager"); this.log = log; this.sourceManager = sourceManager; }
/// <summary> /// Copies all messages to another instance. /// </summary> /// <param name="results">The results.</param> public void CopyTo(LoggerResult results) { foreach (var reportMessage in this.Messages) { results.Messages.Add(reportMessage); } if (HasErrors) results.HasErrors = true; }
private XenkoClassInstantiator(ShaderClassType classType, Dictionary<string, Expression> expressions, Dictionary<string, Identifier> identifiers, bool autoGenericInstances, LoggerResult log) : base(false, false) { shaderClassType = classType; expressionGenerics = expressions; identifiersGenerics = identifiers; this.autoGenericInstances = autoGenericInstances; logger = log; variableGenerics = shaderClassType.ShaderGenerics.ToDictionary(x => x.Name.Text, x => x); }
/// <summary> /// Initializes a new instance of the <see cref="ShaderMixinCodeGen" /> class. /// </summary> /// <param name="shader">The shader.</param> /// <param name="logging">The logging.</param> /// <exception cref="System.ArgumentNullException">shader or logging</exception> /// <exception cref="System.InvalidOperationException">Cannot process shaders having already parsing errors</exception> public ShaderMixinCodeGen(Shader shader, LoggerResult logging) { if (shader == null) throw new ArgumentNullException("shader"); if (logging == null) throw new ArgumentNullException("logging"); this.shader = shader; this.logging = logging; EnablePreprocessorLine = false; }
/// <summary> /// Adds the methods defined in the final mixin /// </summary> /// <param name="methodDeclarations">a list of MethodDeclaration</param> /// <param name="className">the name of the class</param> /// <param name="errorLogger">the logger for errors and warnings</param> public void AddFinalDeclarations(List<MethodDeclaration> methodDeclarations, string className, LoggerResult errorLogger) { var finalDict = new MethodDeclaration[methodDeclarations.Count]; foreach (var methodDecl in methodDeclarations) { var vtableReference = (VTableReference)methodDecl.GetTag(XenkoTags.VirtualTableReference); finalDict[vtableReference.Slot] = methodDecl; // TODO: override/abstract behavior //if (methodDecl.Qualifiers.Contains(XenkoStorageQualifier.Override)) LookForBaseDeclarationMixin(methodDecl, errorLogger); } VirtualTableGroup.Add(className, finalDict); }
/// <summary> /// Generates the csharp code from a xkfx file. /// </summary> /// <param name="xkfxShaderCode">The PDXFX shader code.</param> /// <param name="filePath">The file path.</param> /// <returns>System.String.</returns> /// <exception cref="System.InvalidOperationException"></exception> public static string GenerateCsharp(string xkfxShaderCode, string filePath) { // Compile var shader = XenkoShaderParser.PreProcessAndParse(xkfxShaderCode, filePath); // Try to generate a mixin code. var loggerResult = new LoggerResult(); var shaderKeyGenerator = new ShaderMixinCodeGen(shader, loggerResult); if (shaderKeyGenerator.Run()) { return shaderKeyGenerator.Text; } throw new InvalidOperationException(loggerResult.ToString()); }
/// <summary> /// Merge with a local virtual table = need to check override keywords /// </summary> /// <param name="virtualTable">the virtual table to add</param> /// <param name="mixinName">the name of the mixin</param> /// <param name="log">the error logger</param> public void MergeWithLocalVirtualTable(MixinVirtualTable virtualTable, string mixinName, LoggerResult log) { foreach (var method in virtualTable.Methods) { var methodDecl = Methods.LastOrDefault(x => x.Method.IsSameSignature(method.Method)); if (methodDecl != null) { var isBaseMethod = method.Shader.BaseClasses.Any(x => x.Name.Text == methodDecl.Shader.Name.Text); if (isBaseMethod) { if (methodDecl.Method is MethodDefinition) { if (!method.Method.Qualifiers.Contains(ParadoxStorageQualifier.Override)) { log.Error(ParadoxMessageCode.ErrorMissingOverride, method.Method.Span, method.Method, mixinName); continue; } } else if (method.Method.Qualifiers.Contains(ParadoxStorageQualifier.Override)) { log.Error(ParadoxMessageCode.ErrorOverrideDeclaration, method.Method.Span, method.Method, mixinName); continue; } } Methods.Remove(methodDecl); } else { if (method.Method.Qualifiers.Contains(ParadoxStorageQualifier.Override)) { log.Error(ParadoxMessageCode.ErrorNoMethodToOverride, method.Method.Span, method.Method, mixinName); continue; } } Methods.Add(method); // TODO: handle declarations vs definitions } Variables.UnionWith(virtualTable.Variables.Where(x => !Variables.Contains(x))); StructureTypes.AddRange(virtualTable.StructureTypes.Where(x => !StructureTypes.Contains(x))); Typedefs.AddRange(virtualTable.Typedefs.Where(x => !Typedefs.Contains(x))); }
/// <summary> /// Generates the csharp code from a xkfx file. /// </summary> /// <param name="xkfxShaderCode">The PDXFX shader code.</param> /// <param name="filePath">The file path.</param> /// <returns>System.String.</returns> /// <exception cref="System.InvalidOperationException"></exception> public static string GenerateCsharp(string xkfxShaderCode, string filePath) { // In .xkfx, shader has been renamed to effect, in order to avoid ambiguities with HLSL and .xksl var macros = new [] { new SiliconStudio.Shaders.Parser.ShaderMacro("shader", "effect") }; // Compile var shader = XenkoShaderParser.PreProcessAndParse(xkfxShaderCode, filePath, macros); // Try to generate a mixin code. var loggerResult = new LoggerResult(); var shaderKeyGenerator = new ShaderMixinCodeGen(shader, loggerResult); if (shaderKeyGenerator.Run()) { return shaderKeyGenerator.Text; } throw new InvalidOperationException(loggerResult.ToString()); }
public ModuleMixinInfo() { Log = new LoggerResult(); Instanciated = true; }
/// <summary> /// Link all the stage compositions in case it is referenced at several places. /// </summary> /// <param name="variable">The variable of the composition.</param> /// <param name="composition">The composition.</param> /// <param name="dictionary">The already registered compositions.</param> /// <param name="extraDictionary">The new compositions.</param> /// <param name="log">The logger.</param> private static void FullLinkStageCompositions(Variable variable, List<ModuleMixin> composition, CompositionDictionary dictionary, Dictionary<Variable, List<ModuleMixin>> extraDictionary, LoggerResult log) { var mixin = variable.GetTag(ParadoxTags.ShaderScope) as ModuleMixin; if (mixin != null) { var className = mixin.MixinName; foreach (var item in dictionary) { if (item.Key == variable) continue; foreach (var module in item.Value) { if (module.MixinName == className || module.InheritanceList.Any(x => x.MixinName == className)) { // add reference var foundVars = module.FindAllVariablesByName(variable.Name).Where(value => value.Variable.Qualifiers.Contains(ParadoxStorageQualifier.Compose)).ToList();; if (foundVars.Count > 1) { log.Error(ParadoxMessageCode.ErrorAmbiguousComposition, new SourceSpan(), variable.Name); } else if (foundVars.Count > 0) { // if there is already a filled composition, it means that the ShaderMixinSource filled the composition information at two different places // TODO: verify that var foundVar = foundVars[0].Variable; List<ModuleMixin> previousList; if (dictionary.TryGetValue(foundVar, out previousList)) { previousList.AddRange(composition); } else extraDictionary.Add(foundVars[0].Variable, composition); } else { // No matching variable was found // TODO: log a message? } } } } } }
/// <summary> /// Get a compilation context based on the macros /// </summary> /// <param name="mixinToAnalyze">List of mixin to analyze</param> /// <param name="log">The log.</param> /// <returns>the correct compilation context</returns> private ShaderCompilationContext GetCompilationContext(IEnumerable<ModuleMixinInfo> mixinToAnalyze, LoggerResult log) { var mixinInfos = new HashSet<ModuleMixinInfo>(); foreach (var mixin in mixinToAnalyze) mixinInfos.UnionWith(mixin.MinimalContext); var context = new ShaderCompilationContext(log); context.Preprocess(mixinInfos); return context; }
/// <summary> /// Default constructor for cloning /// </summary> public ShaderCompilationContext(LoggerResult log) { if (log == null) throw new ArgumentNullException("log"); ErrorWarningLog = log; }
/// <summary> /// create the context for each composition by cloning their dependencies /// </summary> /// <param name="shaderSource">the entry ShaderSource (root)</param> /// <param name="dictionary">the ouputed compositions</param> /// <param name="compilationContext">the compilation context</param> /// <param name="cloneContext">The clone context.</param> /// <returns>a list of all the needed mixins</returns> private static List<ModuleMixin> BuildCompositionsDictionary(ShaderSource shaderSource, CompositionDictionary dictionary, ShaderCompilationContext compilationContext, CloneContext cloneContext, LoggerResult log) { if (shaderSource is ShaderMixinSource) { var shaderMixinSource = shaderSource as ShaderMixinSource; var finalModule = compilationContext.GetModuleMixinFromShaderSource(shaderSource); //PerformanceLogger.Start(PerformanceStage.DeepClone); finalModule = finalModule.DeepClone(new CloneContext(cloneContext)); //PerformanceLogger.Pause(PerformanceStage.DeepClone); foreach (var composition in shaderMixinSource.Compositions) { //look for the key var foundVars = finalModule.FindAllVariablesByName(composition.Key).Where(value => value.Variable.Qualifiers.Contains(ParadoxStorageQualifier.Compose)).ToList(); if (foundVars.Count > 1) { log.Error(ParadoxMessageCode.ErrorAmbiguousComposition, new SourceSpan(), composition.Key); } else if (foundVars.Count > 0) { Variable foundVar = foundVars[0].Variable; var moduleMixins = BuildCompositionsDictionary(composition.Value, dictionary, compilationContext, cloneContext, log); if (moduleMixins == null) return null; dictionary.Add(foundVar, moduleMixins); } else { // No matching variable was found // TODO: log a message? } } return new List<ModuleMixin> { finalModule }; } if (shaderSource is ShaderClassSource) { var finalModule = compilationContext.GetModuleMixinFromShaderSource(shaderSource); //PerformanceLogger.Start(PerformanceStage.DeepClone); finalModule = finalModule.DeepClone(new CloneContext(cloneContext)); //PerformanceLogger.Pause(PerformanceStage.DeepClone); return new List<ModuleMixin> { finalModule }; } if (shaderSource is ShaderArraySource) { var shaderArraySource = shaderSource as ShaderArraySource; var compositionArray = new List<ModuleMixin>(); foreach (var shader in shaderArraySource.Values) { var mixin = BuildCompositionsDictionary(shader, dictionary, compilationContext, cloneContext, log); if (mixin == null) return null; compositionArray.AddRange(mixin); } return compositionArray; } return null; }
public XenkoStreamAnalyzer(LoggerResult errorLog) : base(false, true) { errorWarningLog = errorLog ?? new LoggerResult(); }
public static void Run(ShaderClassType shaderClassType, ModuleMixin mixin, List<ModuleMixin> mixins, LoggerResult errorLog) { var streamCreator = new ParadoxStreamCreator(shaderClassType, mixin, mixins, errorLog); streamCreator.Run(); }
public static void Instantiate(ShaderClassType classType, Dictionary<string, Expression> expressions, Dictionary<string, Identifier> identifiers, bool autoGenericInstances, LoggerResult log) { var instantiator = new XenkoClassInstantiator(classType, expressions, identifiers, autoGenericInstances, log); instantiator.Run(); }
public ShaderBlockVisitor(ShaderKeyGeneratorBase parent, LoggerResult logging) : base(false, false) { this.parent = parent; this.logging = logging; }
public ShaderNavigationResult() { Messages = new LoggerResult(); }
/// <summary> /// Find the base definition of the method and override its occurence /// </summary> /// <param name="methodDeclaration"></param> /// <param name="errorLogger"></param> private void LookForBaseDeclarationMixin(MethodDeclaration methodDeclaration, LoggerResult errorLogger) { foreach (var dict in VirtualTableGroup.Select(x => x.Value)) { for (int i = 0; i < dict.Length; ++i) { var method = dict[i]; var baseDeclarationMixin = (string)method.GetTag(XenkoTags.BaseDeclarationMixin); // TODO: take typedefs into account... if (method.IsSameSignature(methodDeclaration)) { var sourceShader = ((ModuleMixin)methodDeclaration.GetTag(XenkoTags.ShaderScope)).MixinName; // test override if (methodDeclaration is MethodDefinition && method is MethodDefinition && !methodDeclaration.Qualifiers.Contains(XenkoStorageQualifier.Override)) errorLogger.Error(XenkoMessageCode.ErrorMissingOverride, method.Span, methodDeclaration, sourceShader); if (!(methodDeclaration is MethodDefinition)) errorLogger.Error(XenkoMessageCode.ErrorOverrindingDeclaration, method.Span, methodDeclaration, sourceShader); if (method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && !methodDeclaration.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { errorLogger.Warning(XenkoMessageCode.WarningMissingStageKeyword, methodDeclaration.Span, methodDeclaration, (methodDeclaration.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName); methodDeclaration.Qualifiers |= XenkoStorageQualifier.Stage; } else if (!method.Qualifiers.Contains(XenkoStorageQualifier.Stage) && methodDeclaration.Qualifiers.Contains(XenkoStorageQualifier.Stage)) { errorLogger.Error(XenkoMessageCode.ErrorExtraStageKeyword, methodDeclaration.Span, methodDeclaration, method, (methodDeclaration.GetTag(XenkoTags.ShaderScope) as ModuleMixin).MixinName); methodDeclaration.Qualifiers.Values.Remove(XenkoStorageQualifier.Stage); } dict[i] = methodDeclaration; methodDeclaration.SetTag(XenkoTags.BaseDeclarationMixin, baseDeclarationMixin); } } } }
/// <summary> /// Check the name conflict between the two virtual tables /// </summary> public bool CheckNameConflict(MixinVirtualTable virtualTable, LoggerResult log) { var conflict = false; foreach (var variable in virtualTable.Variables.Where(variable => Variables.Any(x => x.Variable.Name.Text == variable.Variable.Name.Text))) { log.Error(ParadoxMessageCode.ErrorVariableNameConflict, variable.Variable.Span, variable.Variable, ""); conflict = true; } return conflict; }