Пример #1
0
        /// <summary>
        /// Mixes shader parts to produces a single HLSL file shader.
        /// </summary>
        /// <param name="shaderMixinSource">The shader source.</param>
        /// <param name="macros">The shader perprocessor macros.</param>
        /// <param name="modifiedShaders">The list of modified shaders.</param>
        /// <returns>The combined shader in AST form.</returns>
        public ShaderMixinParsingResult Parse(ShaderMixinSource shaderMixinSource, Paradox.Shaders.ShaderMacro[] macros = null)
        {
            // Creates a parsing result
            HashSet <ModuleMixinInfo> mixinsToAnalyze;
            ShaderMixinParsingResult  parsingResult;
            var context = ParseAndAnalyze(shaderMixinSource, macros, out parsingResult, out mixinsToAnalyze);

            // Return directly if there was any errors
            if (parsingResult.HasErrors)
            {
                return(parsingResult);
            }

            // Update the clone context in case new instances of classes are created
            lock (hlslCloneContext)
            {
                HlslSemanticAnalysis.UpdateCloneContext(hlslCloneContext);
            }

            // only clone once the stage classes
            var mixCloneContext = new CloneContext(hlslCloneContext);

            foreach (var mixinInfo in mixinsToAnalyze)
            {
                foreach (var mixin in mixinInfo.Mixin.MinimalContext.Where(x => x.StageOnlyClass))
                {
                    mixin.DeepClone(mixCloneContext);
                }
            }

            // ----------------------------------------------------------
            // Perform Shader Mixer
            // ----------------------------------------------------------
            var externDict      = new CompositionDictionary();
            var finalModuleList = BuildCompositionsDictionary(shaderMixinSource, externDict, context, mixCloneContext, parsingResult);

            //PerformanceLogger.Stop(PerformanceStage.DeepClone);

            if (parsingResult.HasErrors)
            {
                return(parsingResult);
            }

            // look for stage compositions and add the links between variables and compositions when necessary
            var extraExternDict = new Dictionary <Variable, List <ModuleMixin> >();

            foreach (var item in externDict)
            {
                if (item.Key.Qualifiers.Contains(ParadoxStorageQualifier.Stage))
                {
                    FullLinkStageCompositions(item.Key, item.Value, externDict, extraExternDict, parsingResult);
                }
            }
            foreach (var item in extraExternDict)
            {
                externDict.Add(item.Key, item.Value);
            }

            var mixinDictionary = BuildMixinDictionary(finalModuleList);

            if (finalModuleList != null)
            {
                var finalModule = finalModuleList[0];
                //PerformanceLogger.Start(PerformanceStage.Mix);
                var mixer = new ParadoxShaderMixer(finalModule, parsingResult, mixinDictionary, externDict, new CloneContext(mixCloneContext));
                mixer.Mix();
                //PerformanceLogger.Stop(PerformanceStage.Mix);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                {
                    return(parsingResult);
                }

                var finalShader = mixer.GetMixedShader();

                // Simplifies the shader by removing dead code
                var simplifier = new ExpressionSimplifierVisitor();
                simplifier.Run(finalShader);

                parsingResult.Reflection = new EffectReflection();
                var pdxShaderLinker = new ShaderLinker(parsingResult);
                pdxShaderLinker.Run(finalShader);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                {
                    return(parsingResult);
                }

                // Find all entry points
                // TODO: make this configurable by CompileParameters
                foreach (var stage in new[] { ShaderStage.Compute, ShaderStage.Vertex, ShaderStage.Hull, ShaderStage.Domain, ShaderStage.Geometry, ShaderStage.Pixel })
                {
                    var entryPoint = finalShader.Declarations.OfType <MethodDefinition>().FirstOrDefault(f => f.Attributes.OfType <AttributeDeclaration>().Any(a => a.Name == "EntryPoint" && (string)a.Parameters[0].Value == stage.ToString()));

                    if (entryPoint == null)
                    {
                        continue;
                    }

                    parsingResult.EntryPoints[stage] = entryPoint.Name.Text;

                    // When this is a compute shader, there is no need to scan other stages
                    if (stage == ShaderStage.Compute)
                    {
                        break;
                    }
                }

                var typeCleaner = new ParadoxShaderCleaner();
                typeCleaner.Run(finalShader);

                //PerformanceLogger.Stop(PerformanceStage.Global);

                //PerformanceLogger.PrintLastResult();
                //SemanticPerformance.PrintResult();
                //MixPerformance.PrintResult();
                //GenerateShaderPerformance.PrintResult();
                //StreamCreatorPerformance.PrintResult();
                //ShaderLoader.PrintTime();

                //PerformanceLogger.WriteOut(52);

                parsingResult.Shader = finalShader;
            }

            return(parsingResult);
        }
Пример #2
0
        /// <summary>
        /// Mixes shader parts to produces a single HLSL file shader.
        /// </summary>
        /// <param name="shaderMixinSource">The shader source.</param>
        /// <param name="macros">The shader perprocessor macros.</param>
        /// <param name="modifiedShaders">The list of modified shaders.</param>
        /// <returns>The combined shader in AST form.</returns>
        public ShaderMixinParsingResult Parse(ShaderMixinSource shaderMixinSource, Paradox.Shaders.ShaderMacro[] macros = null)
        {
            // Creates a parsing result
            HashSet<ModuleMixinInfo> mixinsToAnalyze;
            ShaderMixinParsingResult parsingResult;
            var context = ParseAndAnalyze(shaderMixinSource, macros, out parsingResult, out mixinsToAnalyze);

            // Return directly if there was any errors
            if (parsingResult.HasErrors)
                return parsingResult;

            // Update the clone context in case new instances of classes are created
            lock (hlslCloneContext)
            {
                HlslSemanticAnalysis.UpdateCloneContext(hlslCloneContext);
            }

            // only clone once the stage classes
            var mixCloneContext = new CloneContext(hlslCloneContext);
            foreach (var mixinInfo in mixinsToAnalyze)
            {
                foreach (var mixin in mixinInfo.Mixin.MinimalContext.Where(x => x.StageOnlyClass))
                {
                    mixin.DeepClone(mixCloneContext);
                }
            }

            // ----------------------------------------------------------
            // Perform Shader Mixer
            // ----------------------------------------------------------
            var externDict = new CompositionDictionary();
            var finalModuleList = BuildCompositionsDictionary(shaderMixinSource, externDict, context, mixCloneContext, parsingResult);
            //PerformanceLogger.Stop(PerformanceStage.DeepClone);

            if (parsingResult.HasErrors)
                return parsingResult;

            // look for stage compositions and add the links between variables and compositions when necessary
            var extraExternDict = new Dictionary<Variable, List<ModuleMixin>>();
            foreach (var item in externDict)
            {
                if (item.Key.Qualifiers.Contains(ParadoxStorageQualifier.Stage))
                    FullLinkStageCompositions(item.Key, item.Value, externDict, extraExternDict, parsingResult);
            }
            foreach (var item in extraExternDict)
                externDict.Add(item.Key, item.Value);

            var mixinDictionary = BuildMixinDictionary(finalModuleList);

            if (finalModuleList != null)
            {
                var finalModule = finalModuleList[0];
                //PerformanceLogger.Start(PerformanceStage.Mix);
                var mixer = new ParadoxShaderMixer(finalModule, parsingResult, mixinDictionary, externDict, new CloneContext(mixCloneContext));
                mixer.Mix();
                //PerformanceLogger.Stop(PerformanceStage.Mix);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                    return parsingResult;

                var finalShader = mixer.GetMixedShader();

                // Simplifies the shader by removing dead code
                var simplifier = new ExpressionSimplifierVisitor();
                simplifier.Run(finalShader);

                parsingResult.Reflection = new EffectReflection();
                var pdxShaderLinker = new ShaderLinker(parsingResult);
                pdxShaderLinker.Run(finalShader);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                    return parsingResult;

                // Find all entry points
                // TODO: make this configurable by CompileParameters
                foreach (var stage in new[] {ShaderStage.Compute, ShaderStage.Vertex, ShaderStage.Hull, ShaderStage.Domain, ShaderStage.Geometry, ShaderStage.Pixel})
                {
                    var entryPoint = finalShader.Declarations.OfType<MethodDefinition>().FirstOrDefault(f => f.Attributes.OfType<AttributeDeclaration>().Any(a => a.Name == "EntryPoint" && (string)a.Parameters[0].Value == stage.ToString()));

                    if (entryPoint == null)
                    {
                        continue;
                    }

                    parsingResult.EntryPoints[stage] = entryPoint.Name.Text;
                    
                    // When this is a compute shader, there is no need to scan other stages
                    if (stage == ShaderStage.Compute)
                        break;
                }

                var typeCleaner = new ParadoxShaderCleaner();
                typeCleaner.Run(finalShader);

                //PerformanceLogger.Stop(PerformanceStage.Global);

                //PerformanceLogger.PrintLastResult();
                //SemanticPerformance.PrintResult();
                //MixPerformance.PrintResult();
                //GenerateShaderPerformance.PrintResult();
                //StreamCreatorPerformance.PrintResult();
                //ShaderLoader.PrintTime();

                //PerformanceLogger.WriteOut(52);

                parsingResult.Shader = finalShader;
            }

            return parsingResult;
        }
Пример #3
0
        /// <summary>
        /// Mixes shader parts to produces a single HLSL file shader.
        /// </summary>
        /// <param name="shaderMixinSource">The shader source.</param>
        /// <param name="macros">The shader perprocessor macros.</param>
        /// <param name="modifiedShaders">The list of modified shaders.</param>
        /// <returns>The combined shader in AST form.</returns>
        public ShaderMixinParsingResult Parse(ShaderMixinSource shaderMixinSource, Paradox.Shaders.ShaderMacro[] macros = null, HashSet <string> modifiedShaders = null)
        {
            //SemanticPerformance.Reset();
            //PerformanceLogger.Reset();
            //MixPerformance.Reset();
            //GenerateShaderPerformance.Reset();
            //StreamCreatorPerformance.Reset();

            // updates the list of modified shaders.
            shaderLibrary.ModifiedShaders = modifiedShaders;

            // Creates a parsing result
            var parsingResult = new ShaderMixinParsingResult();

            SiliconStudio.Shaders.Parser.ShaderMacro[] macrosParser;
            if (macros == null)
            {
                macrosParser = new SiliconStudio.Shaders.Parser.ShaderMacro[0];
            }
            else
            {
                macrosParser = new SiliconStudio.Shaders.Parser.ShaderMacro[macros.Length];
                for (var i = 0; i < macros.Length; ++i)
                {
                    macrosParser[i] = new SiliconStudio.Shaders.Parser.ShaderMacro(macros[i].Name, macros[i].Definition);
                }
            }
            //PerformanceLogger.Start(PerformanceStage.Global);

            // ----------------------------------------------------------
            // Load all shaders
            // ----------------------------------------------------------
            HashSet <ModuleMixinInfo> mixinsToAnalyze;

            lock (shaderLibrary)
            {
                //PerformanceLogger.Start(PerformanceStage.Loading);
                mixinsToAnalyze = shaderLibrary.LoadShaderSource(shaderMixinSource, macrosParser);
                //PerformanceLogger.Stop(PerformanceStage.Loading);
            }

            // Extract all ModuleMixinInfo and check for any errors
            var allMixinInfos = new HashSet <ModuleMixinInfo>();

            foreach (var moduleMixinInfo in mixinsToAnalyze)
            {
                allMixinInfos.UnionWith(moduleMixinInfo.MinimalContext);
            }
            foreach (var moduleMixinInfo in allMixinInfos)
            {
                moduleMixinInfo.Log.CopyTo(parsingResult);

                var ast = moduleMixinInfo.MixinAst;
                var shaderClassSource = moduleMixinInfo.ShaderSource as ShaderClassSource;
                if (ast != null && shaderClassSource != null)
                {
                    var sourcePath = SourceManager.FindFilePath(shaderClassSource.ClassName);
                    if (sourcePath == null)
                    {
                        throw new InvalidOperationException(string.Format("Can't find source path for class {0}", shaderClassSource.ClassName));
                    }
                    parsingResult.HashSources[sourcePath] = ast.SourceHash;
                }
            }

            // Return directly if there was any errors
            if (parsingResult.HasErrors)
            {
                return(parsingResult);
            }

            // ----------------------------------------------------------
            // Perform Type Analysis
            // ----------------------------------------------------------
            //PerformanceLogger.Start(PerformanceStage.TypeAnalysis);
            var context = GetCompilationContext(mixinsToAnalyze, parsingResult);

            //PerformanceLogger.Stop(PerformanceStage.TypeAnalysis);

            // Return directly if there was any errors
            if (parsingResult.HasErrors)
            {
                return(parsingResult);
            }

            lock (SemanticAnalyzerLock)
            {
                //PerformanceLogger.Start(PerformanceStage.SemanticAnalysis);
                //SemanticPerformance.Start(SemanticStage.Global);
                foreach (var mixin in mixinsToAnalyze)
                {
                    context.Analyze(mixin);
                }
                //SemanticPerformance.Pause(SemanticStage.Global);
                //PerformanceLogger.Stop(PerformanceStage.SemanticAnalysis);
            }

            // Return directly if there was any errors
            if (parsingResult.HasErrors)
            {
                return(parsingResult);
            }

            // Update the clone context in case new instances of classes are created
            lock (hlslCloneContext)
            {
                HlslSemanticAnalysis.UpdateCloneContext(hlslCloneContext);
            }

            // only clone once the stage classes
            var mixCloneContext = new CloneContext(hlslCloneContext);

            foreach (var mixinInfo in mixinsToAnalyze)
            {
                foreach (var mixin in mixinInfo.Mixin.MinimalContext.Where(x => x.StageOnlyClass))
                {
                    mixin.DeepClone(mixCloneContext);
                }
            }

            // ----------------------------------------------------------
            // Perform Shader Mixer
            // ----------------------------------------------------------
            var externDict      = new Dictionary <Variable, List <ModuleMixin> >();
            var finalModuleList = BuildCompositionsDictionary(shaderMixinSource, externDict, context, mixCloneContext);
            //PerformanceLogger.Stop(PerformanceStage.DeepClone);
            var mixinDictionary = BuildMixinDictionary(finalModuleList);

            if (finalModuleList != null)
            {
                var finalModule = finalModuleList[0];
                //PerformanceLogger.Start(PerformanceStage.Mix);
                var mixer = new ParadoxShaderMixer(finalModule, parsingResult, mixinDictionary, externDict, new CloneContext(mixCloneContext));
                mixer.Mix();
                //PerformanceLogger.Stop(PerformanceStage.Mix);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                {
                    return(parsingResult);
                }

                var finalShader = mixer.GetMixedShader();

                parsingResult.Reflection = new EffectReflection();
                var pdxShaderLinker = new ShaderLinker(parsingResult);
                pdxShaderLinker.Run(finalShader);

                // Return directly if there was any errors
                if (parsingResult.HasErrors)
                {
                    return(parsingResult);
                }

                // Find all entry points
                // TODO: make this configurable by CompileParameters
                foreach (var stage in new[] { ShaderStage.Compute, ShaderStage.Vertex, ShaderStage.Hull, ShaderStage.Domain, ShaderStage.Geometry, ShaderStage.Pixel })
                {
                    var entryPoint = finalShader.Declarations.OfType <MethodDefinition>().FirstOrDefault(f => f.Attributes.OfType <AttributeDeclaration>().Any(a => a.Name == "EntryPoint" && (string)a.Parameters[0].Value == stage.ToString()));

                    if (entryPoint == null)
                    {
                        continue;
                    }

                    parsingResult.EntryPoints[stage] = entryPoint.Name.Text;

                    // When this is a compute shader, there is no need to scan other stages
                    if (stage == ShaderStage.Compute)
                    {
                        break;
                    }
                }

                var typeCleaner = new ParadoxShaderCleaner();
                typeCleaner.Run(finalShader);

                //PerformanceLogger.Stop(PerformanceStage.Global);

                //PerformanceLogger.PrintLastResult();
                //SemanticPerformance.PrintResult();
                //MixPerformance.PrintResult();
                //GenerateShaderPerformance.PrintResult();
                //StreamCreatorPerformance.PrintResult();
                //ShaderLoader.PrintTime();

                //PerformanceLogger.WriteOut(52);

                parsingResult.Shader = finalShader;
            }

            return(parsingResult);
        }