static public StringBuilder Build(VFXContext context, VFXCompilationMode compilationMode, VFXContextCompiledData contextData, HashSet <string> dependencies)
        {
            var templatePath = string.Format("{0}.template", context.codeGeneratorTemplate);

            dependencies.Add(AssetDatabase.AssetPathToGUID(templatePath));
            return(Build(context, templatePath, compilationMode, contextData, dependencies));
        }
Beispiel #2
0
 public void SetCompilationMode(VFXCompilationMode mode)
 {
     if (m_CompilationMode != mode)
     {
         m_CompilationMode = mode;
         SetExpressionGraphDirty();
         RecompileIfNeeded(false, true);
     }
 }
Beispiel #3
0
 public void SetCompilationMode(VFXCompilationMode mode)
 {
     if (m_CompilationMode != mode)
     {
         m_CompilationMode = mode;
         SetExpressionGraphDirty();
         AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(this));
     }
 }
        public void Compile(VFXCompilationMode compilationMode)
        {
            // Prevent doing anything ( and especially showing progesses ) in an empty graph.
            if (m_Graph.children.Count() < 1)
            {
                // Cleaning
                if (m_Graph.visualEffectResource != null)
                {
                    m_Graph.visualEffectResource.ClearRuntimeData();
                }

                m_ExpressionGraph  = new VFXExpressionGraph();
                m_ExpressionValues = new VFXExpressionValueContainerDesc[] {};
                return;
            }

            Profiler.BeginSample("VFXEditor.CompileAsset");
            try
            {
                float  nbSteps          = 12.0f;
                string assetPath        = AssetDatabase.GetAssetPath(visualEffectResource);
                string progressBarTitle = "Compiling " + assetPath;

                EditorUtility.DisplayProgressBar(progressBarTitle, "Collecting dependencies", 0 / nbSteps);
                var models = new HashSet <ScriptableObject>();
                m_Graph.CollectDependencies(models);

                var contexts = models.OfType <VFXContext>().ToArray();

                foreach (var c in contexts) // Unflag all contexts
                {
                    c.MarkAsCompiled(false);
                }

                var compilableContexts = models.OfType <VFXContext>().Where(c => c.CanBeCompiled());
                var compilableData     = models.OfType <VFXData>().Where(d => d.CanBeCompiled());

                IEnumerable <VFXContext> implicitContexts = Enumerable.Empty <VFXContext>();
                foreach (var d in compilableData) // Flag compiled contexts
                {
                    implicitContexts = implicitContexts.Concat(d.InitImplicitContexts());
                }
                compilableContexts = compilableContexts.Concat(implicitContexts.ToArray());

                foreach (var c in compilableContexts) // Flag compiled contexts
                {
                    c.MarkAsCompiled(true);
                }

                EditorUtility.DisplayProgressBar(progressBarTitle, "Collecting attributes", 1 / nbSteps);
                foreach (var data in compilableData)
                {
                    data.CollectAttributes();
                }

                EditorUtility.DisplayProgressBar(progressBarTitle, "Computing layers", 2 / nbSteps);
                foreach (var data in compilableData)
                {
                    data.ComputeLayer();
                }

                EditorUtility.DisplayProgressBar(progressBarTitle, "Compiling expression Graph", 3 / nbSteps);
                m_ExpressionGraph = new VFXExpressionGraph();
                var exposedExpressionContext = ScriptableObject.CreateInstance <VFXImplicitContextOfExposedExpression>();
                exposedExpressionContext.FillExpression(m_Graph); //Force all exposed expression to be visible, only for registering in CompileExpressions

                var expressionContextOptions = compilationMode == VFXCompilationMode.Runtime ? VFXExpressionContextOption.ConstantFolding : VFXExpressionContextOption.Reduction;
                m_ExpressionGraph.CompileExpressions(compilableContexts.Concat(new VFXContext[] { exposedExpressionContext }), expressionContextOptions);

                EditorUtility.DisplayProgressBar(progressBarTitle, "Generating bytecode", 4 / nbSteps);
                var expressionDescs = new List <VFXExpressionDesc>();
                var valueDescs      = new List <VFXExpressionValueContainerDesc>();
                FillExpressionDescs(expressionDescs, valueDescs, m_ExpressionGraph);

                Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData = new Dictionary <VFXContext, VFXContextCompiledData>();
                foreach (var context in compilableContexts)
                {
                    contextToCompiledData.Add(context, new VFXContextCompiledData());
                }

                EditorUtility.DisplayProgressBar(progressBarTitle, "Generating mappings", 5 / nbSteps);
                foreach (var context in compilableContexts)
                {
                    var cpuMapper   = m_ExpressionGraph.BuildCPUMapper(context);
                    var contextData = contextToCompiledData[context];
                    contextData.cpuMapper          = cpuMapper;
                    contextData.parameters         = context.additionalMappings.ToArray();
                    contextToCompiledData[context] = contextData;
                }

                var exposedParameterDescs = new List <VFXMapping>();
                FillExposedDescs(exposedParameterDescs, m_ExpressionGraph, models.OfType <VFXParameter>());
                var globalEventAttributeDescs = new List <VFXLayoutElementDesc>()
                {
                    new VFXLayoutElementDesc()
                    {
                        name = "spawnCount", type = VFXValueType.Float
                    }
                };
                FillEventAttributeDescs(globalEventAttributeDescs, m_ExpressionGraph, compilableContexts);

                EditorUtility.DisplayProgressBar(progressBarTitle, "Generating Attribute layouts", 6 / nbSteps);
                foreach (var data in compilableData)
                {
                    data.GenerateAttributeLayout();
                }

                var generatedCodeData = new List <GeneratedCodeData>();

                EditorUtility.DisplayProgressBar(progressBarTitle, "Generating shaders", 7 / nbSteps);
                GenerateShaders(generatedCodeData, m_ExpressionGraph, compilableContexts, contextToCompiledData, compilationMode);

                EditorUtility.DisplayProgressBar(progressBarTitle, "Saving shaders", 8 / nbSteps);
                SaveShaderFiles(m_Graph.visualEffectResource, generatedCodeData, contextToCompiledData);

                var bufferDescs    = new List <VFXGPUBufferDesc>();
                var cpuBufferDescs = new List <VFXCPUBufferDesc>();
                var systemDescs    = new List <VFXEditorSystemDesc>();

                EditorUtility.DisplayProgressBar(progressBarTitle, "Generating systems", 9 / nbSteps);
                cpuBufferDescs.Add(new VFXCPUBufferDesc()
                {
                    capacity    = 1u,
                    layout      = globalEventAttributeDescs.ToArray(),
                    stride      = globalEventAttributeDescs.First().offset.structure,
                    initialData = ComputeArrayOfStructureInitialData(globalEventAttributeDescs)
                });
                var contextSpawnToSpawnInfo = new Dictionary <VFXContext, SpawnInfo>();
                FillSpawner(contextSpawnToSpawnInfo, cpuBufferDescs, systemDescs, compilableContexts, m_ExpressionGraph, globalEventAttributeDescs, contextToCompiledData);

                var eventDescs = new List <VFXEventDesc>();
                FillEvent(eventDescs, contextSpawnToSpawnInfo, compilableContexts);

                var attributeBufferDictionnary = new Dictionary <VFXData, int>();
                var eventGpuBufferDictionnary  = new Dictionary <VFXData, int>();
                FillDependentBuffer(compilableData, bufferDescs, attributeBufferDictionnary, eventGpuBufferDictionnary);

                var contextSpawnToBufferIndex = contextSpawnToSpawnInfo.Select(o => new { o.Key, o.Value.bufferIndex }).ToDictionary(o => o.Key, o => o.bufferIndex);
                foreach (var data in compilableData)
                {
                    data.FillDescs(bufferDescs,
                                   systemDescs,
                                   m_ExpressionGraph,
                                   contextToCompiledData,
                                   contextSpawnToBufferIndex,
                                   attributeBufferDictionnary,
                                   eventGpuBufferDictionnary);
                }

                // Update renderer settings
                VFXRendererSettings rendererSettings = GetRendererSettings(m_Graph.visualEffectResource.rendererSettings, compilableContexts.OfType <IVFXSubRenderer>());
                m_Graph.visualEffectResource.rendererSettings = rendererSettings;

                EditorUtility.DisplayProgressBar(progressBarTitle, "Setting up systems", 10 / nbSteps);
                var expressionSheet = new VFXExpressionSheet();
                expressionSheet.expressions = expressionDescs.ToArray();
                expressionSheet.values      = valueDescs.OrderBy(o => o.expressionIndex).ToArray();
                expressionSheet.exposed     = exposedParameterDescs.OrderBy(o => o.name).ToArray();

                m_Graph.visualEffectResource.SetRuntimeData(expressionSheet, systemDescs.ToArray(), eventDescs.ToArray(), bufferDescs.ToArray(), cpuBufferDescs.ToArray());
                m_ExpressionValues = expressionSheet.values;

                EditorUtility.DisplayProgressBar(progressBarTitle, "Importing VFX", 11 / nbSteps);
                Profiler.BeginSample("VFXEditor.CompileAsset:ImportAsset");
                AssetDatabase.ImportAsset(assetPath, ImportAssetOptions.ForceUpdate); //This should compile the shaders on the C++ size
                Profiler.EndSample();
            }
            catch (Exception e)
            {
                Debug.LogError(string.Format("Exception while compiling expression graph: {0}: {1}", e, e.StackTrace));

                // Cleaning
                if (m_Graph.visualEffectResource != null)
                {
                    m_Graph.visualEffectResource.ClearRuntimeData();
                }

                m_ExpressionGraph  = new VFXExpressionGraph();
                m_ExpressionValues = new VFXExpressionValueContainerDesc[] {};
            }
            finally
            {
                Profiler.EndSample();
                EditorUtility.ClearProgressBar();
            }
        }
        private static void GenerateShaders(List <GeneratedCodeData> outGeneratedCodeData, VFXExpressionGraph graph, IEnumerable <VFXContext> contexts, Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData, VFXCompilationMode compilationMode)
        {
            Profiler.BeginSample("VFXEditor.GenerateShaders");
            try
            {
                foreach (var context in contexts)
                {
                    var gpuMapper     = graph.BuildGPUMapper(context);
                    var uniformMapper = new VFXUniformMapper(gpuMapper, context.doesGenerateShader);

                    // Add gpu and uniform mapper
                    var contextData = contextToCompiledData[context];
                    contextData.gpuMapper          = gpuMapper;
                    contextData.uniformMapper      = uniformMapper;
                    contextToCompiledData[context] = contextData;

                    if (context.doesGenerateShader)
                    {
                        var generatedContent = VFXCodeGenerator.Build(context, compilationMode, contextData);

                        outGeneratedCodeData.Add(new GeneratedCodeData()
                        {
                            context       = context,
                            computeShader = context.codeGeneratorCompute,
                            compilMode    = compilationMode,
                            content       = generatedContent
                        });
                    }
                }
            }
            finally
            {
                Profiler.EndSample();
            }
        }
        static private StringBuilder Build(VFXContext context, string templatePath, VFXCompilationMode compilationMode, VFXContextCompiledData contextData, HashSet <string> dependencies)
        {
            if (!context.SetupCompilation())
            {
                return(null);
            }
            var stringBuilder = GetFlattenedTemplateContent(templatePath, new List <string>(), context.additionalDefines, dependencies);

            var allCurrentAttributes = context.GetData().GetAttributes().Where(a =>
                                                                               (context.GetData().IsCurrentAttributeUsed(a.attrib, context)) ||
                                                                               (context.contextType == VFXContextType.Init && context.GetData().IsAttributeStored(a.attrib))); // In init, needs to declare all stored attributes for intialization

            var allSourceAttributes = context.GetData().GetAttributes().Where(a => (context.GetData().IsSourceAttributeUsed(a.attrib, context)));

            var globalDeclaration = new VFXShaderWriter();

            globalDeclaration.WriteCBuffer(contextData.uniformMapper, "parameters");
            globalDeclaration.WriteLine();
            globalDeclaration.WriteAttributeStruct(allCurrentAttributes.Select(a => a.attrib), "Attributes");
            globalDeclaration.WriteLine();
            globalDeclaration.WriteAttributeStruct(allSourceAttributes.Select(a => a.attrib), "SourceAttributes");
            globalDeclaration.WriteLine();
            globalDeclaration.WriteTexture(contextData.uniformMapper);

            var linkedEventOut = context.allLinkedOutputSlot.Where(s => ((VFXModel)s.owner).GetFirstOfType <VFXContext>().CanBeCompiled()).ToList();

            globalDeclaration.WriteEventBuffer(eventListOutName, linkedEventOut.Count);

            //< Block processor
            var blockFunction     = new VFXShaderWriter();
            var blockCallFunction = new VFXShaderWriter();
            var blockDeclared     = new HashSet <string>();
            var expressionToName  = context.GetData().GetAttributes().ToDictionary(o => new VFXAttributeExpression(o.attrib) as VFXExpression, o => (new VFXAttributeExpression(o.attrib)).GetCodeString(null));

            expressionToName = expressionToName.Union(contextData.uniformMapper.expressionToCode).ToDictionary(s => s.Key, s => s.Value);

            int cpt = 0;

            foreach (var current in context.activeFlattenedChildrenWithImplicit)
            {
                BuildBlock(contextData, linkedEventOut, blockFunction, blockCallFunction, blockDeclared, expressionToName, current, ref cpt);
            }

            //< Final composition
            var    renderTemplatePipePath = VFXLibrary.currentSRPBinder.templatePath;
            var    renderRuntimePipePath  = VFXLibrary.currentSRPBinder.runtimePath;
            string renderPipeCommon       = context.doesIncludeCommonCompute ? "Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.hlsl" : VFXLibrary.currentSRPBinder.runtimePath + "/VFXCommon.hlsl";
            string renderPipePasses       = null;

            if (!context.codeGeneratorCompute && !string.IsNullOrEmpty(renderTemplatePipePath))
            {
                renderPipePasses = renderTemplatePipePath + "/VFXPasses.template";
            }

            var globalIncludeContent = new VFXShaderWriter();

            globalIncludeContent.WriteLine("#define NB_THREADS_PER_GROUP 64");
            globalIncludeContent.WriteLine("#define HAS_ATTRIBUTES 1");
            globalIncludeContent.WriteLine("#define VFX_PASSDEPTH_ACTUAL (0)");
            globalIncludeContent.WriteLine("#define VFX_PASSDEPTH_MOTION_VECTOR (1)");
            globalIncludeContent.WriteLine("#define VFX_PASSDEPTH_SELECTION (2)");
            globalIncludeContent.WriteLine("#define VFX_PASSDEPTH_SHADOW (3)");

            foreach (var attribute in allCurrentAttributes)
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(CultureInfo.InvariantCulture), "CURRENT");
            }
            foreach (var attribute in allSourceAttributes)
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(CultureInfo.InvariantCulture), "SOURCE");
            }

            foreach (var additionnalHeader in context.additionalDataHeaders)
            {
                globalIncludeContent.WriteLine(additionnalHeader);
            }

            foreach (var additionnalDefine in context.additionalDefines)
            {
                globalIncludeContent.WriteLineFormat("#define {0} 1", additionnalDefine);
            }

            if (renderPipePasses != null)
            {
                globalIncludeContent.Write(GetFlattenedTemplateContent(renderPipePasses, new List <string>(), context.additionalDefines, dependencies));
            }

            if (context.GetData() is ISpaceable)
            {
                var spaceable = context.GetData() as ISpaceable;
                globalIncludeContent.WriteLineFormat("#define {0} 1", spaceable.space == VFXCoordinateSpace.World ? "VFX_WORLD_SPACE" : "VFX_LOCAL_SPACE");
            }
            globalIncludeContent.WriteLineFormat("#include \"{0}/VFXDefines.hlsl\"", renderRuntimePipePath);

            var perPassIncludeContent = new VFXShaderWriter();

            perPassIncludeContent.WriteLine("#include \"" + renderPipeCommon + "\"");
            perPassIncludeContent.WriteLine("#include \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.hlsl\"");

            // Per-block includes
            var includes = Enumerable.Empty <string>();

            foreach (var block in context.activeFlattenedChildrenWithImplicit)
            {
                includes = includes.Concat(block.includes);
            }
            var uniqueIncludes = new HashSet <string>(includes);

            foreach (var includePath in uniqueIncludes)
            {
                perPassIncludeContent.WriteLine(string.Format("#include \"{0}\"", includePath));
            }


            ReplaceMultiline(stringBuilder, "${VFXGlobalInclude}", globalIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGlobalDeclaration}", globalDeclaration.builder);
            ReplaceMultiline(stringBuilder, "${VFXPerPassInclude}", perPassIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGeneratedBlockFunction}", blockFunction.builder);
            ReplaceMultiline(stringBuilder, "${VFXProcessBlocks}", blockCallFunction.builder);

            var mainParameters = contextData.gpuMapper.CollectExpression(-1).ToArray();

            foreach (var match in GetUniqueMatches("\\${VFXLoadParameter:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadParameters = GenerateLoadParameter(pattern, mainParameters, expressionToName);
                ReplaceMultiline(stringBuilder, str, loadParameters.builder);
            }
            var additionalInterpolantsGeneration  = new VFXShaderWriter();
            var additionalInterpolantsDeclaration = new VFXShaderWriter();
            var additionalInterpolantsPreparation = new VFXShaderWriter();


            int normSemantic = 0;

            foreach (string fragmentParameter in context.fragmentParameters)
            {
                var filteredNamedExpression = mainParameters.FirstOrDefault(o => fragmentParameter == o.name &&
                                                                            !(expressionToName.ContainsKey(o.exp) && expressionToName[o.exp] == o.name)); // if parameter already in the global scope, there's nothing to do

                if (filteredNamedExpression.exp != null)
                {
                    additionalInterpolantsDeclaration.WriteDeclaration(filteredNamedExpression.exp.valueType, filteredNamedExpression.name, $"NORMAL{normSemantic++}");
                    additionalInterpolantsGeneration.WriteVariable(filteredNamedExpression.exp.valueType, filteredNamedExpression.name + "__", "0");
                    var expressionToNameLocal = new Dictionary <VFXExpression, string>(expressionToName);
                    additionalInterpolantsGeneration.EnterScope();
                    {
                        if (!expressionToNameLocal.ContainsKey(filteredNamedExpression.exp))
                        {
                            additionalInterpolantsGeneration.WriteVariable(filteredNamedExpression.exp, expressionToNameLocal);
                            additionalInterpolantsGeneration.WriteLine();
                        }
                        additionalInterpolantsGeneration.WriteAssignement(filteredNamedExpression.exp.valueType, filteredNamedExpression.name + "__", expressionToNameLocal[filteredNamedExpression.exp]);
                        additionalInterpolantsGeneration.WriteLine();
                    }
                    additionalInterpolantsGeneration.ExitScope();
                    additionalInterpolantsGeneration.WriteAssignement(filteredNamedExpression.exp.valueType, "o." + filteredNamedExpression.name, filteredNamedExpression.name + "__");
                    additionalInterpolantsPreparation.WriteVariable(filteredNamedExpression.exp.valueType, filteredNamedExpression.name, "i." + filteredNamedExpression.name);
                }
            }
            ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsGeneration}", additionalInterpolantsGeneration.builder);
            ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsDeclaration}", additionalInterpolantsDeclaration.builder);
            ReplaceMultiline(stringBuilder, "${VFXAdditionalInterpolantsPreparation}", additionalInterpolantsPreparation.builder);

            //< Compute sourceIndex
            if (stringBuilder.ToString().Contains("${VFXComputeSourceIndex}"))
            {
                var r = GenerateComputeSourceIndex(context);
                ReplaceMultiline(stringBuilder, "${VFXComputeSourceIndex}", r.builder);
            }

            //< Load Attribute
            if (stringBuilder.ToString().Contains("${VFXLoadAttributes}"))
            {
                var loadAttributes = GenerateLoadAttribute(".*", context);
                ReplaceMultiline(stringBuilder, "${VFXLoadAttributes}", loadAttributes.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXLoadAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadAttributes = GenerateLoadAttribute(pattern, context);
                ReplaceMultiline(stringBuilder, str, loadAttributes.builder);
            }

            //< Store Attribute
            if (stringBuilder.ToString().Contains("${VFXStoreAttributes}"))
            {
                var storeAttribute = GenerateStoreAttribute(".*", context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, "${VFXStoreAttributes}", storeAttribute.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXStoreAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str             = match.Groups[0].Value;
                var pattern         = match.Groups[1].Value;
                var storeAttributes = GenerateStoreAttribute(pattern, context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, str, storeAttributes.builder);
            }

            foreach (var addionalReplacement in context.additionalReplacements)
            {
                ReplaceMultiline(stringBuilder, addionalReplacement.Key, addionalReplacement.Value.builder);
            }

            // Replace defines
            SubstituteMacros(stringBuilder);

            if (VFXViewPreference.advancedLogs)
            {
                Debug.LogFormat("GENERATED_OUTPUT_FILE_FOR : {0}\n{1}", context.ToString(), stringBuilder.ToString());
            }

            context.EndCompilation();
            return(stringBuilder);
        }
        static public StringBuilder Build(VFXContext context, VFXCompilationMode compilationMode, VFXContextCompiledData contextData)
        {
            var templatePath = string.Format("{0}.template", context.codeGeneratorTemplate);

            return(Build(context, templatePath, compilationMode, contextData));
        }
        static private StringBuilder Build(VFXContext context, string templatePath, VFXCompilationMode compilationMode, VFXContextCompiledData contextData)
        {
            var dependencies = new HashSet <ScriptableObject>();

            context.CollectDependencies(dependencies);

            var stringBuilder = GetFlattenedTemplateContent(templatePath, new List <string>(), context.additionalDefines);

            var globalDeclaration = new VFXShaderWriter();

            globalDeclaration.WriteCBuffer(contextData.uniformMapper, "parameters");
            globalDeclaration.WriteTexture(contextData.uniformMapper);

            var linkedEventOut = context.allLinkedOutputSlot.Where(s => ((VFXModel)s.owner).GetFirstOfType <VFXContext>().CanBeCompiled()).ToList();

            globalDeclaration.WriteEventBuffer(eventListOutName, linkedEventOut.Count);

            //< Block processor
            var blockFunction     = new VFXShaderWriter();
            var blockCallFunction = new VFXShaderWriter();
            var blockDeclared     = new HashSet <string>();
            var expressionToName  = context.GetData().GetAttributes().ToDictionary(o => new VFXAttributeExpression(o.attrib) as VFXExpression, o => (new VFXAttributeExpression(o.attrib)).GetCodeString(null));

            expressionToName = expressionToName.Union(contextData.uniformMapper.expressionToCode).ToDictionary(s => s.Key, s => s.Value);

            foreach (var current in context.activeChildrenWithImplicit.Select((v, i) => new { block = v, blockIndex = i }))
            {
                var block      = current.block;
                var blockIndex = current.blockIndex;

                var parameters = block.mergedAttributes.Select(o =>
                {
                    return(new VFXShaderWriter.FunctionParameter
                    {
                        name = o.attrib.name,
                        expression = new VFXAttributeExpression(o.attrib) as VFXExpression,
                        mode = o.mode
                    });
                }).ToList();

                foreach (var parameter in block.parameters)
                {
                    var expReduced = contextData.gpuMapper.FromNameAndId(parameter.name, blockIndex);
                    if (VFXExpression.IsTypeValidOnGPU(expReduced.valueType))
                    {
                        parameters.Add(new VFXShaderWriter.FunctionParameter
                        {
                            name       = parameter.name,
                            expression = expReduced,
                            mode       = VFXAttributeMode.None
                        });
                    }
                }

                string methodName, commentMethod;
                GetFunctionName(block, out methodName, out commentMethod);
                if (!blockDeclared.Contains(methodName))
                {
                    blockDeclared.Add(methodName);
                    blockFunction.WriteBlockFunction(contextData.gpuMapper,
                                                     methodName,
                                                     block.source,
                                                     parameters,
                                                     commentMethod);
                }

                //< Parameters (computed and/or extracted from uniform)
                var  expressionToNameLocal = expressionToName;
                bool needScope             = parameters.Any(o => !expressionToNameLocal.ContainsKey(o.expression));
                if (needScope)
                {
                    expressionToNameLocal = new Dictionary <VFXExpression, string>(expressionToNameLocal);
                    blockCallFunction.EnterScope();
                    foreach (var exp in parameters.Select(o => o.expression))
                    {
                        if (expressionToNameLocal.ContainsKey(exp))
                        {
                            continue;
                        }
                        blockCallFunction.WriteVariable(exp, expressionToNameLocal);
                    }
                }

                var indexEventCount = parameters.FindIndex(o => o.name == VFXAttribute.EventCount.name);
                if (indexEventCount != -1)
                {
                    if ((parameters[indexEventCount].mode & VFXAttributeMode.Read) != 0)
                    {
                        throw new InvalidOperationException(string.Format("{0} isn't expected as read (special case)", VFXAttribute.EventCount.name));
                    }
                    blockCallFunction.WriteLine(string.Format("{0} = 0u;", VFXAttribute.EventCount.name));
                }

                blockCallFunction.WriteCallFunction(methodName,
                                                    parameters,
                                                    contextData.gpuMapper,
                                                    expressionToNameLocal);

                if (indexEventCount != -1)
                {
                    foreach (var outputSlot in block.outputSlots.SelectMany(o => o.LinkedSlots))
                    {
                        var eventIndex = linkedEventOut.IndexOf(outputSlot);
                        if (eventIndex != -1)
                        {
                            blockCallFunction.WriteLineFormat("{0}_{1} += {0};", VFXAttribute.EventCount.name, VFXCodeGeneratorHelper.GeneratePrefix((uint)eventIndex));
                        }
                    }
                }
                if (needScope)
                {
                    blockCallFunction.ExitScope();
                }
            }

            //< Final composition
            var    renderPipePath   = UnityEngine.Experimental.VFX.VFXManager.renderPipeSettingsPath;
            string renderPipeCommon = "Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.cginc";
            string renderPipePasses = null;

            if (!context.codeGeneratorCompute && !string.IsNullOrEmpty(renderPipePath))
            {
                renderPipeCommon = renderPipePath + "/VFXCommon.cginc";
                renderPipePasses = renderPipePath + "/VFXPasses.template";
            }

            var globalIncludeContent = new VFXShaderWriter();

            globalIncludeContent.WriteLine("#define NB_THREADS_PER_GROUP 64");
            foreach (var attribute in context.GetData().GetAttributes().Where(a => (context.contextType == VFXContextType.kInit && context.GetData().IsAttributeStored(a.attrib)) || (context.GetData().IsAttributeUsed(a.attrib, context))))
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(), "CURRENT");
            }
            foreach (var attribute in context.GetData().GetAttributes().Where(a => context.GetData().IsSourceAttributeUsed(a.attrib, context)))
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(), "SOURCE");
            }

            foreach (var additionnalDefine in context.additionalDefines)
            {
                globalIncludeContent.WriteLineFormat("#define {0} 1", additionnalDefine);
            }

            if (renderPipePasses != null)
            {
                globalIncludeContent.Write(GetFlattenedTemplateContent(renderPipePasses, new List <string>(), context.additionalDefines));
            }

            if (context.GetData() is ISpaceable)
            {
                var spaceable = context.GetData() as ISpaceable;
                globalIncludeContent.WriteLineFormat("#define {0} 1", spaceable.space == VFXCoordinateSpace.World ? "VFX_WORLD_SPACE" : "VFX_LOCAL_SPACE");
            }
            globalIncludeContent.WriteLineFormat("#include \"{0}/VFXDefines.hlsl\"", renderPipePath);

            var perPassIncludeContent = new VFXShaderWriter();

            perPassIncludeContent.WriteLine("#include \"" + renderPipeCommon + "\"");
            perPassIncludeContent.WriteLine("#include \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.cginc\"");

            // Per-block includes
            var includes = Enumerable.Empty <string>();

            foreach (var block in context.activeChildrenWithImplicit)
            {
                includes = includes.Concat(block.includes);
            }
            var uniqueIncludes = new HashSet <string>(includes);

            foreach (var includePath in uniqueIncludes)
            {
                perPassIncludeContent.WriteLine(string.Format("#include \"{0}\"", includePath));
            }

            ReplaceMultiline(stringBuilder, "${VFXGlobalInclude}", globalIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGlobalDeclaration}", globalDeclaration.builder);
            ReplaceMultiline(stringBuilder, "${VFXPerPassInclude}", perPassIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGeneratedBlockFunction}", blockFunction.builder);
            ReplaceMultiline(stringBuilder, "${VFXProcessBlocks}", blockCallFunction.builder);

            var mainParameters = contextData.gpuMapper.CollectExpression(-1).ToArray();

            foreach (var match in GetUniqueMatches("\\${VFXLoadParameter:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadParameters = GenerateLoadParameter(pattern, mainParameters, expressionToName);
                ReplaceMultiline(stringBuilder, str, loadParameters.builder);
            }

            //< Compute sourceIndex
            if (stringBuilder.ToString().Contains("${VFXComputeSourceIndex}"))
            {
                var r = GenerateComputeSourceIndex(context);
                ReplaceMultiline(stringBuilder, "${VFXComputeSourceIndex}", r.builder);
            }

            //< Load Attribute
            if (stringBuilder.ToString().Contains("${VFXLoadAttributes}"))
            {
                var loadAttributes = GenerateLoadAttribute(".*", context);
                ReplaceMultiline(stringBuilder, "${VFXLoadAttributes}", loadAttributes.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXLoadAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadAttributes = GenerateLoadAttribute(pattern, context);
                ReplaceMultiline(stringBuilder, str, loadAttributes.builder);
            }

            //< Store Attribute
            if (stringBuilder.ToString().Contains("${VFXStoreAttributes}"))
            {
                var storeAttribute = GenerateStoreAttribute(".*", context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, "${VFXStoreAttributes}", storeAttribute.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXStoreAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str             = match.Groups[0].Value;
                var pattern         = match.Groups[1].Value;
                var storeAttributes = GenerateStoreAttribute(pattern, context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, str, storeAttributes.builder);
            }

            foreach (var addionalReplacement in context.additionalReplacements)
            {
                ReplaceMultiline(stringBuilder, addionalReplacement.Key, addionalReplacement.Value.builder);
            }

            // Replace defines
            SubstituteMacros(stringBuilder);

            if (VFXViewPreference.advancedLogs)
            {
                Debug.LogFormat("GENERATED_OUTPUT_FILE_FOR : {0}\n{1}", context.ToString(), stringBuilder.ToString());
            }

            return(stringBuilder);
        }
Beispiel #9
0
        static private StringBuilder Build(VFXContext context, string templatePath, VFXCompilationMode compilationMode, VFXContextCompiledData contextData)
        {
            var stringBuilder = GetFlattenedTemplateContent(templatePath, new List <string>(), context.additionalDefines);

            var globalDeclaration = new VFXShaderWriter();

            globalDeclaration.WriteCBuffer(contextData.uniformMapper, "parameters");
            globalDeclaration.WriteTexture(contextData.uniformMapper);

            var linkedEventOut = context.allLinkedOutputSlot.Where(s => ((VFXModel)s.owner).GetFirstOfType <VFXContext>().CanBeCompiled()).ToList();

            globalDeclaration.WriteEventBuffer(eventListOutName, linkedEventOut.Count);

            //< Block processor
            var blockFunction     = new VFXShaderWriter();
            var blockCallFunction = new VFXShaderWriter();
            var blockDeclared     = new HashSet <string>();
            var expressionToName  = context.GetData().GetAttributes().ToDictionary(o => new VFXAttributeExpression(o.attrib) as VFXExpression, o => (new VFXAttributeExpression(o.attrib)).GetCodeString(null));

            expressionToName = expressionToName.Union(contextData.uniformMapper.expressionToCode).ToDictionary(s => s.Key, s => s.Value);

            int cpt = 0;

            foreach (var current in context.activeFlattenedChildrenWithImplicit)
            {
                BuildBlock(contextData, linkedEventOut, blockFunction, blockCallFunction, blockDeclared, expressionToName, current, ref cpt);
            }

            //< Final composition
            var    renderPipePath   = UnityEngine.Experimental.VFX.VFXManager.renderPipeSettingsPath;
            string renderPipeCommon = "Packages/com.unity.visualeffectgraph/Shaders/Common/VFXCommonCompute.cginc";
            string renderPipePasses = null;

            if (!context.codeGeneratorCompute && !string.IsNullOrEmpty(renderPipePath))
            {
                renderPipeCommon = renderPipePath + "/VFXCommon.cginc";
                renderPipePasses = renderPipePath + "/VFXPasses.template";
            }

            var globalIncludeContent = new VFXShaderWriter();

            globalIncludeContent.WriteLine("#define NB_THREADS_PER_GROUP 64");
            foreach (var attribute in context.GetData().GetAttributes().Where(a => (context.contextType == VFXContextType.Init && context.GetData().IsAttributeStored(a.attrib)) || (context.GetData().IsAttributeUsed(a.attrib, context))))
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(), "CURRENT");
            }
            foreach (var attribute in context.GetData().GetAttributes().Where(a => context.GetData().IsSourceAttributeUsed(a.attrib, context)))
            {
                globalIncludeContent.WriteLineFormat("#define VFX_USE_{0}_{1} 1", attribute.attrib.name.ToUpper(), "SOURCE");
            }

            foreach (var additionnalDefine in context.additionalDefines)
            {
                globalIncludeContent.WriteLineFormat("#define {0} 1", additionnalDefine);
            }

            if (renderPipePasses != null)
            {
                globalIncludeContent.Write(GetFlattenedTemplateContent(renderPipePasses, new List <string>(), context.additionalDefines));
            }

            if (context.GetData() is ISpaceable)
            {
                var spaceable = context.GetData() as ISpaceable;
                globalIncludeContent.WriteLineFormat("#define {0} 1", spaceable.space == VFXCoordinateSpace.World ? "VFX_WORLD_SPACE" : "VFX_LOCAL_SPACE");
            }
            globalIncludeContent.WriteLineFormat("#include \"{0}/VFXDefines.hlsl\"", renderPipePath);

            var perPassIncludeContent = new VFXShaderWriter();

            perPassIncludeContent.WriteLine("#include \"" + renderPipeCommon + "\"");
            perPassIncludeContent.WriteLine("#include \"Packages/com.unity.visualeffectgraph/Shaders/VFXCommon.cginc\"");

            // Per-block includes
            var includes = Enumerable.Empty <string>();

            foreach (var block in context.activeFlattenedChildrenWithImplicit)
            {
                includes = includes.Concat(block.includes);
            }
            var uniqueIncludes = new HashSet <string>(includes);

            foreach (var includePath in uniqueIncludes)
            {
                perPassIncludeContent.WriteLine(string.Format("#include \"{0}\"", includePath));
            }

            ReplaceMultiline(stringBuilder, "${VFXGlobalInclude}", globalIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGlobalDeclaration}", globalDeclaration.builder);
            ReplaceMultiline(stringBuilder, "${VFXPerPassInclude}", perPassIncludeContent.builder);
            ReplaceMultiline(stringBuilder, "${VFXGeneratedBlockFunction}", blockFunction.builder);
            ReplaceMultiline(stringBuilder, "${VFXProcessBlocks}", blockCallFunction.builder);

            var mainParameters = contextData.gpuMapper.CollectExpression(-1).ToArray();

            foreach (var match in GetUniqueMatches("\\${VFXLoadParameter:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadParameters = GenerateLoadParameter(pattern, mainParameters, expressionToName);
                ReplaceMultiline(stringBuilder, str, loadParameters.builder);
            }

            //< Compute sourceIndex
            if (stringBuilder.ToString().Contains("${VFXComputeSourceIndex}"))
            {
                var r = GenerateComputeSourceIndex(context);
                ReplaceMultiline(stringBuilder, "${VFXComputeSourceIndex}", r.builder);
            }

            //< Load Attribute
            if (stringBuilder.ToString().Contains("${VFXLoadAttributes}"))
            {
                var loadAttributes = GenerateLoadAttribute(".*", context);
                ReplaceMultiline(stringBuilder, "${VFXLoadAttributes}", loadAttributes.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXLoadAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str            = match.Groups[0].Value;
                var pattern        = match.Groups[1].Value;
                var loadAttributes = GenerateLoadAttribute(pattern, context);
                ReplaceMultiline(stringBuilder, str, loadAttributes.builder);
            }

            //< Store Attribute
            if (stringBuilder.ToString().Contains("${VFXStoreAttributes}"))
            {
                var storeAttribute = GenerateStoreAttribute(".*", context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, "${VFXStoreAttributes}", storeAttribute.builder);
            }

            foreach (var match in GetUniqueMatches("\\${VFXStoreAttributes:{(.*?)}}", stringBuilder.ToString()))
            {
                var str             = match.Groups[0].Value;
                var pattern         = match.Groups[1].Value;
                var storeAttributes = GenerateStoreAttribute(pattern, context, (uint)linkedEventOut.Count);
                ReplaceMultiline(stringBuilder, str, storeAttributes.builder);
            }

            foreach (var addionalReplacement in context.additionalReplacements)
            {
                ReplaceMultiline(stringBuilder, addionalReplacement.Key, addionalReplacement.Value.builder);
            }

            // Replace defines
            SubstituteMacros(stringBuilder);

            if (VFXViewPreference.advancedLogs)
            {
                Debug.LogFormat("GENERATED_OUTPUT_FILE_FOR : {0}\n{1}", context.ToString(), stringBuilder.ToString());
            }

            return(stringBuilder);
        }