/// <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;
        }
Example #6
0
        /// <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);
        }
Example #10
0
        /// <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());
        }
Example #11
0
        /// <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());
        }
Example #13
0
 public ModuleMixinInfo()
 {
     Log = new LoggerResult();
     Instanciated = true;
 }
Example #14
0
        /// <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?
                            }
                        }
                    }
                }
            }
        }
Example #15
0
        /// <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;
        }
Example #17
0
        /// <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();
 }
Example #21
0
 public ShaderBlockVisitor(ShaderKeyGeneratorBase parent, LoggerResult logging)
     : base(false, false)
 {
     this.parent = parent;
     this.logging = logging;
 }
 public ShaderNavigationResult()
 {
     Messages = new LoggerResult();
 }
Example #23
0
        /// <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);
                    }
                }
            }
        }
Example #24
0
        /// <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;
        }