private static void SaveShaderFiles(VisualEffectResource resource, List <GeneratedCodeData> generatedCodeData, Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData)
        {
            Profiler.BeginSample("VFXEditor.SaveShaderFiles");
            try
            {
                VFXShaderSourceDesc[] descs = new VFXShaderSourceDesc[generatedCodeData.Count];

                for (int i = 0; i < generatedCodeData.Count; ++i)
                {
                    var generated = generatedCodeData[i];
                    var fileName  = string.Format("Temp_{1}_{0}_{2}_{3}.{1}", VFXCodeGeneratorHelper.GeneratePrefix((uint)i), generated.computeShader ? "compute" : "shader", generated.context.name.ToLower(), generated.compilMode);

                    descs[i].source  = generated.content.ToString();
                    descs[i].name    = fileName;
                    descs[i].compute = generated.computeShader;
                }

                resource.shaderSources = descs;

                for (int i = 0; i < generatedCodeData.Count; ++i)
                {
                    var generated   = generatedCodeData[i];
                    var contextData = contextToCompiledData[generated.context];
                    contextData.indexInShaderSource          = i;
                    contextToCompiledData[generated.context] = contextData;
                }
            }
            finally
            {
                Profiler.EndSample();
            }
        }
        static private VFXShaderWriter GenerateStoreAttribute(string matching, VFXContext context, uint linkedOutCount)
        {
            var r     = new VFXShaderWriter();
            var regex = new Regex(matching);

            var attributesFromContext = context.GetData().GetAttributes().Where(o => regex.IsMatch(o.attrib.name) &&
                                                                                context.GetData().IsAttributeStored(o.attrib) &&
                                                                                (context.contextType == VFXContextType.Init || context.GetData().IsCurrentAttributeWritten(o.attrib, context))).ToArray();

            foreach (var attribute in attributesFromContext.Select(o => o.attrib))
            {
                r.Write(context.GetData().GetStoreAttributeCode(attribute, new VFXAttributeExpression(attribute).GetCodeString(null)));
                r.WriteLine(';');
            }

            if (regex.IsMatch(VFXAttribute.EventCount.name))
            {
                for (uint i = 0; i < linkedOutCount; ++i)
                {
                    var prefix = VFXCodeGeneratorHelper.GeneratePrefix(i);
                    r.WriteLineFormat("for (uint i{0} = 0; i{0} < {1}_{0}; ++i{0}) {2}_{0}.Append(index);", prefix, VFXAttribute.EventCount.name, eventListOutName);
                }
            }
            return(r);
        }
        static private VFXShaderWriter GenerateLoadAttribute(string matching, VFXContext context)
        {
            var r = new VFXShaderWriter();

            var regex = new Regex(matching);
            var attributesFromContext = context.GetData().GetAttributes().Where(o => regex.IsMatch(o.attrib.name)).ToArray();
            var attributesSource      = attributesFromContext.Where(o => (o.mode & VFXAttributeMode.ReadSource) != 0).ToArray();
            var attributesCurrent     = attributesFromContext.Where(o => o.mode != VFXAttributeMode.ReadSource).Where(a => context.GetData().IsAttributeUsed(a.attrib, context) || (context.contextType == VFXContextType.kInit && context.GetData().IsAttributeStored(a.attrib))).ToArray();

            //< Current Attribute
            foreach (var attribute in attributesCurrent.Select(o => o.attrib))
            {
                var name = attribute.name;
                if (name != VFXAttribute.EventCount.name)
                {
                    if (context.contextType != VFXContextType.kInit && context.GetData().IsAttributeStored(attribute))
                    {
                        r.WriteVariable(attribute.type, name, context.GetData().GetLoadAttributeCode(attribute, VFXAttributeLocation.Current));
                    }
                    else
                    {
                        r.WriteVariable(attribute.type, name, attribute.value.GetCodeString(null));
                    }
                }
                else
                {
                    var linkedOutCount = context.allLinkedOutputSlot.Count();
                    for (uint i = 0; i < linkedOutCount; ++i)
                    {
                        r.WriteLineFormat("uint {0}_{1} = 0u;", name, VFXCodeGeneratorHelper.GeneratePrefix(i));
                    }
                    r.WriteVariable(attribute.type, name, attribute.value.GetCodeString(null));
                }
                r.WriteLine();
            }

            //< Source Attribute (default temporary behavior, source is always the initial current value except for init context)
            foreach (var attribute in attributesSource.Select(o => o.attrib))
            {
                var name = string.Format("{0}_source", attribute.name);
                if (context.contextType == VFXContextType.kInit)
                {
                    r.WriteVariable(attribute.type, name, context.GetData().GetLoadAttributeCode(attribute, VFXAttributeLocation.Source));
                }
                else
                {
                    if (attributesCurrent.Any(o => o.attrib.name == attribute.name))
                    {
                        var reference = new VFXAttributeExpression(new VFXAttribute(attribute.name, attribute.value), VFXAttributeLocation.Current);
                        r.WriteVariable(reference.valueType, name, reference.GetCodeString(null));
                    }
                    else
                    {
                        r.WriteVariable(attribute.type, name, attribute.value.GetCodeString(null));
                    }
                }
                r.WriteLine();
            }
            return(r);
        }
Exemple #4
0
        public void WriteVariable(VFXExpression exp, Dictionary <VFXExpression, string> variableNames)
        {
            if (!variableNames.ContainsKey(exp))
            {
                string entry;
                if (exp.Is(VFXExpression.Flags.Constant))
                {
                    entry = exp.GetCodeString(null); // Patch constant directly
                }
                else
                {
                    foreach (var parent in exp.parents)
                    {
                        WriteVariable(parent, variableNames);
                    }

                    // Generate a new variable name
                    entry = "tmp_" + VFXCodeGeneratorHelper.GeneratePrefix((uint)variableNames.Count());
                    string value = exp.GetCodeString(exp.parents.Select(p => variableNames[p]).ToArray());

                    WriteVariable(exp.valueType, entry, value);
                    WriteLine();
                }

                variableNames[exp] = entry;
            }
        }
Exemple #5
0
 public void WriteEventBuffers(string baseName, int count)
 {
     for (int i = 0; i < count; ++i)
     {
         var prefix = VFXCodeGeneratorHelper.GeneratePrefix((uint)i);
         WriteLineFormat("AppendStructuredBuffer<uint> {0}_{1};", baseName, prefix);
     }
 }
        private void CollectAndAddUniforms(VFXExpression exp, IEnumerable <string> names)
        {
            if (!exp.IsAny(VFXExpression.Flags.NotCompilableOnCPU))
            {
                string prefix;
                Dictionary <VFXExpression, List <string> > expressions;

                if (VFXExpression.IsUniform(exp.valueType))
                {
                    if (m_FilterOutConstants && exp.Is(VFXExpression.Flags.Constant)) // Filter out constant uniform that should be patched directly in shader
                    {
                        return;
                    }

                    prefix      = "uniform_";
                    expressions = m_UniformToName;
                }
                else if (VFXExpression.IsTexture(exp.valueType))
                {
                    prefix      = "texture_";
                    expressions = m_TextureToName;
                }
                else
                {
                    if (VFXExpression.IsTypeValidOnGPU(exp.valueType))
                    {
                        throw new InvalidOperationException(string.Format("Missing handling for type: {0}", exp.valueType));
                    }
                    return;
                }

                List <string> previousNames;
                expressions.TryGetValue(exp, out previousNames);

                if (previousNames == null)
                {
                    previousNames    = new List <string>();
                    expressions[exp] = previousNames;
                }

                if (names == null)
                {
                    previousNames.Add(prefix + VFXCodeGeneratorHelper.GeneratePrefix((uint)expressions.Count()));
                }
                else
                {
                    previousNames.AddRange(names);
                }
            }
            else
            {
                foreach (var parent in exp.parents)
                {
                    CollectAndAddUniforms(parent, null);
                }
            }
        }
        private static void BuildBlock(VFXContextCompiledData contextData, List <VFXSlot> linkedEventOut, VFXShaderWriter blockFunction, VFXShaderWriter blockCallFunction, HashSet <string> blockDeclared, Dictionary <VFXExpression, string> expressionToName, VFXBlock block, ref int 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.GetNameInCode(VFXAttributeLocation.Current)));
            }

            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} += {2};", VFXAttribute.EventCount.name, VFXCodeGeneratorHelper.GeneratePrefix((uint)eventIndex), VFXAttribute.EventCount.GetNameInCode(VFXAttributeLocation.Current));
                    }
                }
            }
            if (needScope)
            {
                blockCallFunction.ExitScope();
            }

            blockIndex++;
        }
Exemple #8
0
        public override void FillDescs(
            VFXCompileErrorReporter reporter,
            List <VFXGPUBufferDesc> outBufferDescs,
            List <VFXTemporaryGPUBufferDesc> outTemporaryBufferDescs,
            List <VFXEditorSystemDesc> outSystemDescs,
            VFXExpressionGraph expressionGraph,
            Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData,
            Dictionary <VFXContext, int> contextSpawnToBufferIndex,
            VFXDependentBuffersData dependentBuffers,
            Dictionary <VFXContext, List <VFXContextLink>[]> effectiveFlowInputLinks,
            VFXSystemNames systemNames = null)
        {
            bool hasKill = IsAttributeStored(VFXAttribute.Alive);

            var deadListBufferIndex = -1;
            var deadListCountIndex  = -1;

            var systemBufferMappings = new List <VFXMapping>();
            var systemValueMappings  = new List <VFXMapping>();

            var attributeBufferIndex = dependentBuffers.attributeBuffers[this];

            int attributeSourceBufferIndex = -1;
            int eventGPUFrom = -1;

            var stripDataIndex    = -1;
            var boundsBufferIndex = -1;

            if (m_DependenciesIn.Any())
            {
                if (m_DependenciesIn.Count != 1)
                {
                    throw new InvalidOperationException("Unexpected multiple input dependency for GPU event");
                }
                attributeSourceBufferIndex = dependentBuffers.attributeBuffers[m_DependenciesIn.FirstOrDefault()];
                eventGPUFrom = dependentBuffers.eventBuffers[this];
            }

            if (attributeBufferIndex != -1)
            {
                systemBufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
            }

            if (m_ownAttributeSourceBuffer)
            {
                if (attributeSourceBufferIndex != -1)
                {
                    throw new InvalidOperationException("Unexpected source while filling description of data particle");
                }

                attributeSourceBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(m_layoutAttributeSource.GetBufferDesc(staticSourceCount));
            }

            if (attributeSourceBufferIndex != -1)
            {
                systemBufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
            }

            var systemFlag = VFXSystemFlag.SystemDefault;

            if (eventGPUFrom != -1)
            {
                systemFlag |= VFXSystemFlag.SystemReceivedEventGPU;
                systemBufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
            }

            if (hasKill)
            {
                systemFlag |= VFXSystemFlag.SystemHasKill;

                deadListBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Counter, size = capacity, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadList", deadListBufferIndex));

                deadListCountIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Raw, size = 1, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
            }

            if (hasStrip)
            {
                systemFlag |= VFXSystemFlag.SystemHasStrips;

                systemValueMappings.Add(new VFXMapping("stripCount", (int)stripCapacity));
                systemValueMappings.Add(new VFXMapping("particlePerStripCount", (int)particlePerStripCount));

                stripDataIndex = dependentBuffers.stripBuffers[this];
                systemBufferMappings.Add(new VFXMapping("stripDataBuffer", stripDataIndex));
            }

            if (hasDynamicSourceCount)
            {
                systemFlag |= VFXSystemFlag.SystemHasDirectLink;
            }

            if (needsComputeBounds || boundsSettingMode == BoundsSettingMode.Automatic)
            {
                systemFlag |= VFXSystemFlag.SystemNeedsComputeBounds;

                boundsBufferIndex = dependentBuffers.boundsBuffers[this];
                systemBufferMappings.Add(new VFXMapping("boundsBuffer", boundsBufferIndex));
            }

            if (boundsSettingMode == BoundsSettingMode.Automatic)
            {
                systemFlag |= VFXSystemFlag.SystemAutomaticBounds;
            }

            if (space == VFXCoordinateSpace.World)
            {
                systemFlag |= VFXSystemFlag.SystemInWorldSpace;
            }

            var initContext = m_Contexts.FirstOrDefault(o => o.contextType == VFXContextType.Init);

            if (initContext != null)
            {
                systemBufferMappings.AddRange(effectiveFlowInputLinks[initContext].SelectMany(t => t.Select(u => u.context)).Where(o => o.contextType == VFXContextType.Spawner).Select(o => new VFXMapping("spawner_input", contextSpawnToBufferIndex[o])));
            }
            if (m_Contexts.Count() > 0 && m_Contexts.First().contextType == VFXContextType.Init) // TODO This test can be removed once we ensure priorly the system is valid
            {
                var mapper = contextToCompiledData[m_Contexts.First()].cpuMapper;

                var boundsCenterExp  = mapper.FromNameAndId("bounds_center", -1);
                var boundsSizeExp    = mapper.FromNameAndId("bounds_size", -1);
                var boundsPaddingExp = mapper.FromNameAndId("boundsPadding", -1);

                int boundsCenterIndex = boundsCenterExp != null?expressionGraph.GetFlattenedIndex(boundsCenterExp) : -1;

                int boundsSizeIndex = boundsSizeExp != null?expressionGraph.GetFlattenedIndex(boundsSizeExp) : -1;

                int boundsPaddingIndex = boundsPaddingExp != null?expressionGraph.GetFlattenedIndex(boundsPaddingExp) : -1;

                if (boundsCenterIndex != -1 && boundsSizeIndex != -1)
                {
                    systemValueMappings.Add(new VFXMapping("bounds_center", boundsCenterIndex));
                    systemValueMappings.Add(new VFXMapping("bounds_size", boundsSizeIndex));
                }
                if (boundsPaddingIndex != -1)
                {
                    systemValueMappings.Add(new VFXMapping("boundsPadding", boundsPaddingIndex));
                }
            }

            Dictionary <VFXContext, VFXOutputUpdate> indirectOutputToCuller = null;
            bool needsIndirectBuffer       = NeedsIndirectBuffer();
            int  globalIndirectBufferIndex = -1;
            bool needsGlobalIndirectBuffer = false;

            if (needsIndirectBuffer)
            {
                indirectOutputToCuller = new Dictionary <VFXContext, VFXOutputUpdate>();
                foreach (var cullCompute in m_Contexts.OfType <VFXOutputUpdate>())
                {
                    if (cullCompute.HasFeature(VFXOutputUpdate.Features.IndirectDraw))
                    {
                        indirectOutputToCuller.Add(cullCompute.output, cullCompute);
                    }
                }

                var allIndirectOutputs = owners.OfType <VFXAbstractParticleOutput>().Where(o => o.HasIndirectDraw());

                needsGlobalIndirectBuffer = NeedsGlobalIndirectBuffer();
                if (needsGlobalIndirectBuffer)
                {
                    globalIndirectBufferIndex = outBufferDescs.Count;
                    systemBufferMappings.Add(new VFXMapping("indirectBuffer0", outBufferDescs.Count));
                    outBufferDescs.Add(new VFXGPUBufferDesc()
                    {
                        type = ComputeBufferType.Counter, size = capacity, stride = 4
                    });
                }

                int currentIndirectBufferIndex = globalIndirectBufferIndex == -1 ? 0 : 1;
                foreach (var indirectOutput in allIndirectOutputs)
                {
                    if (indirectOutputToCuller.ContainsKey(indirectOutput))
                    {
                        VFXOutputUpdate culler      = indirectOutputToCuller[indirectOutput];
                        uint            bufferCount = culler.bufferCount;
                        culler.bufferIndex = outBufferDescs.Count;
                        bool perCamera    = culler.isPerCamera;
                        uint bufferStride = culler.HasFeature(VFXOutputUpdate.Features.Sort) ? 8u : 4u;
                        for (uint i = 0; i < bufferCount; ++i)
                        {
                            string bufferName = "indirectBuffer" + currentIndirectBufferIndex++;
                            if (perCamera)
                            {
                                bufferName += "PerCamera";
                            }
                            systemBufferMappings.Add(new VFXMapping(bufferName, outBufferDescs.Count));
                            outBufferDescs.Add(new VFXGPUBufferDesc()
                            {
                                type = ComputeBufferType.Counter, size = capacity, stride = bufferStride
                            });
                        }

                        if (culler.HasFeature(VFXOutputUpdate.Features.Sort))
                        {
                            culler.sortedBufferIndex = outBufferDescs.Count;
                            for (uint i = 0; i < bufferCount; ++i)
                            {
                                outBufferDescs.Add(new VFXGPUBufferDesc()
                                {
                                    type = ComputeBufferType.Default, size = capacity, stride = 4
                                });
                            }
                        }
                        else
                        {
                            culler.sortedBufferIndex = culler.bufferIndex;
                        }
                    }
                }
            }

            // sort buffers
            int  sortBufferAIndex = -1;
            int  sortBufferBIndex = -1;
            bool needsSort        = NeedsGlobalSort();

            if (needsSort)
            {
                sortBufferAIndex = outBufferDescs.Count;
                sortBufferBIndex = sortBufferAIndex + 1;

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferA", sortBufferAIndex));

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferB", sortBufferBIndex));
            }

            var elementToVFXBufferMotionVector = new Dictionary <VFXContext, int>();

            foreach (VFXOutputUpdate context in m_Contexts.OfType <VFXOutputUpdate>())
            {
                if (context.HasFeature(VFXOutputUpdate.Features.MotionVector))
                {
                    uint sizePerElement = 12U * 4U;
                    if (context.output.SupportsMotionVectorPerVertex(out uint vertsCount))
                    {
                        // 2 floats per vertex
                        sizePerElement = vertsCount * 2U * 4U;
                    }
                    // add previous frame index
                    sizePerElement += 4U;
                    int currentElementToVFXBufferMotionVector = outTemporaryBufferDescs.Count;
                    outTemporaryBufferDescs.Add(new VFXTemporaryGPUBufferDesc()
                    {
                        frameCount = 2u, desc = new VFXGPUBufferDesc {
                            type = ComputeBufferType.Raw, size = capacity * sizePerElement, stride = 4
                        }
                    });
                    elementToVFXBufferMotionVector.Add(context.output, currentElementToVFXBufferMotionVector);
                }
            }

            var taskDescs            = new List <VFXEditorTaskDesc>();
            var bufferMappings       = new List <VFXMapping>();
            var uniformMappings      = new List <VFXMapping>();
            var additionalParameters = new List <VFXMapping>();

            for (int i = 0; i < m_Contexts.Count; ++i)
            {
                var temporaryBufferMappings = new List <VFXMappingTemporary>();

                var context = m_Contexts[i];
                if (!contextToCompiledData.TryGetValue(context, out var contextData))
                {
                    throw new InvalidOperationException("Unexpected context which hasn't been compiled : " + context);
                }

                var taskDesc = new VFXEditorTaskDesc();
                taskDesc.type = (UnityEngine.VFX.VFXTaskType)context.taskType;

                bufferMappings.Clear();
                additionalParameters.Clear();

                if (context is VFXOutputUpdate)
                {
                    var update = (VFXOutputUpdate)context;
                    if (update.HasFeature(VFXOutputUpdate.Features.MotionVector))
                    {
                        var currentIndex = elementToVFXBufferMotionVector[update.output];
                        temporaryBufferMappings.Add(new VFXMappingTemporary()
                        {
                            pastFrameIndex = 0u, perCameraBuffer = true, mapping = new VFXMapping("elementToVFXBuffer", currentIndex)
                        });
                    }
                }
                else if (context.contextType == VFXContextType.Output && (context is IVFXSubRenderer) && (context as IVFXSubRenderer).hasMotionVector)
                {
                    var currentIndex = elementToVFXBufferMotionVector[context];
                    temporaryBufferMappings.Add(new VFXMappingTemporary()
                    {
                        pastFrameIndex = 1u, perCameraBuffer = true, mapping = new VFXMapping("elementToVFXBufferPrevious", currentIndex)
                    });
                }

                if (attributeBufferIndex != -1)
                {
                    bufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
                }

                if (eventGPUFrom != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
                }

                if (deadListBufferIndex != -1 && (context.taskType == VFXTaskType.Initialize || context.taskType == VFXTaskType.Update))
                {
                    bufferMappings.Add(new VFXMapping(context.contextType == VFXContextType.Update ? "deadListOut" : "deadListIn", deadListBufferIndex));
                }

                if (deadListCountIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (attributeSourceBufferIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
                }

                if (stripDataIndex != -1 && context.ownedType == VFXDataType.ParticleStrip)
                {
                    bufferMappings.Add(new VFXMapping("stripDataBuffer", stripDataIndex));
                }

                bool hasAttachedStrip = IsAttributeStored(VFXAttribute.StripAlive);
                if (hasAttachedStrip)
                {
                    var stripData = dependenciesOut.First(d => ((VFXDataParticle)d).hasStrip); // TODO Handle several strip attached
                    bufferMappings.Add(new VFXMapping("attachedStripDataBuffer", dependentBuffers.stripBuffers[stripData]));
                }

                if (needsIndirectBuffer)
                {
                    systemFlag |= VFXSystemFlag.SystemHasIndirectBuffer;

                    if (context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).HasIndirectDraw())
                    {
                        bool hasCuller = indirectOutputToCuller.ContainsKey(context);
                        additionalParameters.Add(new VFXMapping("indirectIndex", hasCuller ? indirectOutputToCuller[context].bufferIndex : globalIndirectBufferIndex));
                        bufferMappings.Add(new VFXMapping("indirectBuffer", hasCuller ? indirectOutputToCuller[context].sortedBufferIndex : globalIndirectBufferIndex));
                    }

                    if (context.contextType == VFXContextType.Update)
                    {
                        if (context.taskType == VFXTaskType.Update && needsGlobalIndirectBuffer)
                        {
                            bufferMappings.Add(new VFXMapping("indirectBuffer", globalIndirectBufferIndex));
                        }
                    }

                    if (context.contextType == VFXContextType.Filter)
                    {
                        if (context.taskType == VFXTaskType.CameraSort && needsGlobalIndirectBuffer)
                        {
                            bufferMappings.Add(new VFXMapping("inputBuffer", globalIndirectBufferIndex));
                        }
                        else if (context is VFXOutputUpdate)
                        {
                            var  outputUpdate = (VFXOutputUpdate)context;
                            int  startIndex   = outputUpdate.bufferIndex;
                            uint bufferCount  = outputUpdate.bufferCount;
                            for (int j = 0; j < bufferCount; ++j)
                            {
                                bufferMappings.Add(new VFXMapping("outputBuffer" + j, startIndex + j));
                            }
                        }
                    }
                }

                if (deadListBufferIndex != -1 && context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).NeedsDeadListCount())
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (context.taskType == VFXTaskType.CameraSort)
                {
                    bufferMappings.Add(new VFXMapping("outputBuffer", sortBufferAIndex));
                    if (deadListCountIndex != -1)
                    {
                        bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                    }
                }

                var gpuTarget = context.allLinkedOutputSlot.SelectMany(o => (o.owner as VFXContext).outputContexts)
                                .Where(c => c.CanBeCompiled())
                                .Select(o => dependentBuffers.eventBuffers[o.GetData()])
                                .ToArray();
                for (uint indexTarget = 0; indexTarget < (uint)gpuTarget.Length; ++indexTarget)
                {
                    var prefix = VFXCodeGeneratorHelper.GeneratePrefix(indexTarget);
                    bufferMappings.Add(new VFXMapping(string.Format("eventListOut_{0}", prefix), gpuTarget[indexTarget]));
                }

                uniformMappings.Clear();

                foreach (var uniform in contextData.uniformMapper.uniforms)
                {
                    uniformMappings.Add(new VFXMapping(contextData.uniformMapper.GetName(uniform), expressionGraph.GetFlattenedIndex(uniform)));
                }
                foreach (var buffer in contextData.uniformMapper.buffers)
                {
                    uniformMappings.Add(new VFXMapping(contextData.uniformMapper.GetName(buffer), expressionGraph.GetFlattenedIndex(buffer)));
                }
                foreach (var texture in contextData.uniformMapper.textures)
                {
                    // TODO At the moment issue all names sharing the same texture as different texture slots. This is not optimized as it required more texture binding than necessary
                    foreach (var name in contextData.uniformMapper.GetNames(texture))
                    {
                        uniformMappings.Add(new VFXMapping(name, expressionGraph.GetFlattenedIndex(texture)));
                    }
                }

                // Retrieve all cpu mappings at context level (-1)
                var cpuMappings = contextData.cpuMapper.CollectExpression(-1).Select(exp => new VFXMapping(exp.name, expressionGraph.GetFlattenedIndex(exp.exp))).ToArray();

                //Check potential issue with invalid operation on CPU
                foreach (var mapping in cpuMappings)
                {
                    if (mapping.index < 0)
                    {
                        reporter?.RegisterError(context.GetSlotByPath(true, mapping.name), "GPUNodeLinkedTOCPUSlot", VFXErrorType.Error, "Can not link a GPU operator to a system wide (CPU) input.");;
                        throw new InvalidOperationException("Unable to compute CPU expression for mapping : " + mapping.name);
                    }
                }

                taskDesc.buffers           = bufferMappings.ToArray();
                taskDesc.temporaryBuffers  = temporaryBufferMappings.ToArray();
                taskDesc.values            = uniformMappings.ToArray();
                taskDesc.parameters        = cpuMappings.Concat(contextData.parameters).Concat(additionalParameters).ToArray();
                taskDesc.shaderSourceIndex = contextToCompiledData[context].indexInShaderSource;
                taskDesc.model             = context;

                if (context is IVFXMultiMeshOutput) // If the context is a multi mesh output, split and patch task desc into several tasks
                {
                    var multiMeshOutput = (IVFXMultiMeshOutput)context;
                    for (int j = (int)multiMeshOutput.meshCount - 1; j >= 0; --j) // Back to front to be consistent with LOD and alpha
                    {
                        VFXEditorTaskDesc singleMeshTaskDesc = taskDesc;
                        singleMeshTaskDesc.parameters = VFXMultiMeshHelper.PatchCPUMapping(taskDesc.parameters, multiMeshOutput.meshCount, j).ToArray();
                        singleMeshTaskDesc.buffers    = VFXMultiMeshHelper.PatchBufferMapping(taskDesc.buffers, j).ToArray();
                        taskDescs.Add(singleMeshTaskDesc);
                    }
                }
                else
                {
                    taskDescs.Add(taskDesc);
                }

                // if task is a per camera update with sorting, add sort tasks
                if (context is VFXOutputUpdate)
                {
                    var update = (VFXOutputUpdate)context;

                    if (update.HasFeature(VFXOutputUpdate.Features.Sort))
                    {
                        for (int j = 0; j < update.bufferCount; ++j)
                        {
                            VFXEditorTaskDesc sortTaskDesc = new VFXEditorTaskDesc();
                            sortTaskDesc.type = UnityEngine.VFX.VFXTaskType.PerCameraSort;
                            sortTaskDesc.externalProcessor = null;
                            sortTaskDesc.model             = context;

                            sortTaskDesc.buffers    = new VFXMapping[3];
                            sortTaskDesc.buffers[0] = new VFXMapping("srcBuffer", update.bufferIndex + j);
                            if (capacity > 4096) // Add scratch buffer
                            {
                                sortTaskDesc.buffers[1] = new VFXMapping("scratchBuffer", outBufferDescs.Count);
                                outBufferDescs.Add(new VFXGPUBufferDesc()
                                {
                                    type = ComputeBufferType.Default, size = capacity, stride = 8
                                });
                            }
                            else
                            {
                                sortTaskDesc.buffers[1] = new VFXMapping("scratchBuffer", -1); // No scratchBuffer needed
                            }
                            sortTaskDesc.buffers[2] = new VFXMapping("dstBuffer", update.sortedBufferIndex + j);

                            sortTaskDesc.parameters    = new VFXMapping[1];
                            sortTaskDesc.parameters[0] = new VFXMapping("globalSort", 0);

                            taskDescs.Add(sortTaskDesc);
                        }
                    }
                }
            }

            string nativeName = string.Empty;

            if (systemNames != null)
            {
                nativeName = systemNames.GetUniqueSystemName(this);
            }
            else
            {
                throw new InvalidOperationException("system names manager cannot be null");
            }

            outSystemDescs.Add(new VFXEditorSystemDesc()
            {
                flags    = systemFlag,
                tasks    = taskDescs.ToArray(),
                capacity = capacity,
                name     = nativeName,
                buffers  = systemBufferMappings.ToArray(),
                values   = systemValueMappings.ToArray(),
                type     = VFXSystemType.Particle,
                layer    = m_Layer
            });
        }
        public override void FillDescs(
            List <VFXGPUBufferDesc> outBufferDescs,
            List <VFXTemporaryGPUBufferDesc> outTemporaryBufferDescs,
            List <VFXEditorSystemDesc> outSystemDescs,
            VFXExpressionGraph expressionGraph,
            Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData,
            Dictionary <VFXContext, int> contextSpawnToBufferIndex,
            VFXDependentBuffersData dependentBuffers,
            Dictionary <VFXContext, List <VFXContextLink>[]> effectiveFlowInputLinks,
            VFXSystemNames systemNames = null)
        {
            bool hasKill = IsAttributeStored(VFXAttribute.Alive);

            var deadListBufferIndex = -1;
            var deadListCountIndex  = -1;

            var systemBufferMappings = new List <VFXMapping>();
            var systemValueMappings  = new List <VFXMapping>();

            var attributeBufferIndex = dependentBuffers.attributeBuffers[this];

            int attributeSourceBufferIndex = -1;
            int eventGPUFrom = -1;

            var stripDataIndex = -1;

            if (m_DependenciesIn.Any())
            {
                if (m_DependenciesIn.Count != 1)
                {
                    throw new InvalidOperationException("Unexpected multiple input dependency for GPU event");
                }
                attributeSourceBufferIndex = dependentBuffers.attributeBuffers[m_DependenciesIn.FirstOrDefault()];
                eventGPUFrom = dependentBuffers.eventBuffers[this];
            }

            if (attributeBufferIndex != -1)
            {
                systemBufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
            }

            if (m_ownAttributeSourceBuffer && m_layoutAttributeSource.GetBufferSize(sourceCount) > 0u)
            {
                if (attributeSourceBufferIndex != -1)
                {
                    throw new InvalidOperationException("Unexpected source while filling description of data particle");
                }

                attributeSourceBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(m_layoutAttributeSource.GetBufferDesc(sourceCount));
            }

            if (attributeSourceBufferIndex != -1)
            {
                systemBufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
            }

            var systemFlag = VFXSystemFlag.SystemDefault;

            if (eventGPUFrom != -1)
            {
                systemFlag |= VFXSystemFlag.SystemReceivedEventGPU;
                systemBufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
            }

            if (hasKill)
            {
                systemFlag |= VFXSystemFlag.SystemHasKill;

                deadListBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Counter, size = capacity, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadList", deadListBufferIndex));

                deadListCountIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Raw, size = 1, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
            }

            if (hasStrip)
            {
                systemFlag |= VFXSystemFlag.SystemHasStrips;

                systemValueMappings.Add(new VFXMapping("stripCount", (int)stripCapacity));
                systemValueMappings.Add(new VFXMapping("particlePerStripCount", (int)particlePerStripCount));

                stripDataIndex = dependentBuffers.stripBuffers[this];
                systemBufferMappings.Add(new VFXMapping("stripDataBuffer", stripDataIndex));
            }

            var initContext = m_Contexts.FirstOrDefault(o => o.contextType == VFXContextType.Init);

            if (initContext != null)
            {
                systemBufferMappings.AddRange(effectiveFlowInputLinks[initContext].SelectMany(t => t.Select(u => u.context)).Where(o => o.contextType == VFXContextType.Spawner).Select(o => new VFXMapping("spawner_input", contextSpawnToBufferIndex[o])));
            }
            if (m_Contexts.Count() > 0 && m_Contexts.First().contextType == VFXContextType.Init) // TODO This test can be removed once we ensure priorly the system is valid
            {
                var mapper = contextToCompiledData[m_Contexts.First()].cpuMapper;

                var boundsCenterExp = mapper.FromNameAndId("bounds_center", -1);
                var boundsSizeExp   = mapper.FromNameAndId("bounds_size", -1);

                int boundsCenterIndex = boundsCenterExp != null?expressionGraph.GetFlattenedIndex(boundsCenterExp) : -1;

                int boundsSizeIndex = boundsSizeExp != null?expressionGraph.GetFlattenedIndex(boundsSizeExp) : -1;

                if (boundsCenterIndex != -1 && boundsSizeIndex != -1)
                {
                    systemValueMappings.Add(new VFXMapping("bounds_center", boundsCenterIndex));
                    systemValueMappings.Add(new VFXMapping("bounds_size", boundsSizeIndex));
                }
            }

            int  indirectBufferIndex = -1;
            bool needsIndirectBuffer = NeedsIndirectBuffer();

            if (needsIndirectBuffer)
            {
                systemFlag         |= VFXSystemFlag.SystemHasIndirectBuffer;
                indirectBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Counter, size = capacity, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("indirectBuffer", indirectBufferIndex));
            }

            // sort buffers
            int  sortBufferAIndex = -1;
            int  sortBufferBIndex = -1;
            bool needsSort        = NeedsSort();

            if (needsSort)
            {
                sortBufferAIndex = outBufferDescs.Count;
                sortBufferBIndex = sortBufferAIndex + 1;

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferA", sortBufferAIndex));

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferB", sortBufferBIndex));
            }

            var elementToVFXBufferMotionVector = new Dictionary <VFXContext, int>();

            foreach (VFXMotionVector motionVectorContext in m_Contexts.OfType <VFXMotionVector>())
            {
                int currentElementToVFXBufferMotionVector = outTemporaryBufferDescs.Count;
                outTemporaryBufferDescs.Add(new VFXTemporaryGPUBufferDesc()
                {
                    frameCount = 2u, desc = new VFXGPUBufferDesc {
                        type = ComputeBufferType.Raw, size = capacity * 64, stride = 4
                    }
                });
                elementToVFXBufferMotionVector.Add(motionVectorContext.encapsulatedOutput, currentElementToVFXBufferMotionVector);
            }

            var taskDescs       = new List <VFXEditorTaskDesc>();
            var bufferMappings  = new List <VFXMapping>();
            var uniformMappings = new List <VFXMapping>();

            for (int i = 0; i < m_Contexts.Count; ++i)
            {
                var temporaryBufferMappings = new List <VFXMappingTemporary>();

                var context     = m_Contexts[i];
                var contextData = contextToCompiledData[context];

                var taskDesc = new VFXEditorTaskDesc();
                taskDesc.type = (UnityEngine.VFX.VFXTaskType)context.taskType;

                bufferMappings.Clear();

                if (context is VFXMotionVector)
                {
                    var currentIndex = elementToVFXBufferMotionVector[(context as VFXMotionVector).encapsulatedOutput];
                    temporaryBufferMappings.Add(new VFXMappingTemporary()
                    {
                        pastFrameIndex = 0u, perCameraBuffer = true, mapping = new VFXMapping("elementToVFXBuffer", currentIndex)
                    });
                }
                else if (context.contextType == VFXContextType.Output && (context is IVFXSubRenderer) && (context as IVFXSubRenderer).hasMotionVector)
                {
                    var currentIndex = elementToVFXBufferMotionVector[context];
                    temporaryBufferMappings.Add(new VFXMappingTemporary()
                    {
                        pastFrameIndex = 1u, perCameraBuffer = true, mapping = new VFXMapping("elementToVFXBufferPrevious", currentIndex)
                    });
                }

                if (attributeBufferIndex != -1)
                {
                    bufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
                }

                if (eventGPUFrom != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
                }

                if (deadListBufferIndex != -1 && context.contextType != VFXContextType.Output && context.taskType != VFXTaskType.CameraSort)
                {
                    bufferMappings.Add(new VFXMapping(context.contextType == VFXContextType.Update ? "deadListOut" : "deadListIn", deadListBufferIndex));
                }

                if (deadListCountIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (attributeSourceBufferIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
                }

                if (stripDataIndex != -1 && context.ownedType == VFXDataType.ParticleStrip)
                {
                    bufferMappings.Add(new VFXMapping("stripDataBuffer", stripDataIndex));
                }

                bool hasAttachedStrip = IsAttributeStored(VFXAttribute.StripAlive);
                if (hasAttachedStrip)
                {
                    var stripData = dependenciesOut.First(d => ((VFXDataParticle)d).hasStrip); // TODO Handle several strip attached
                    bufferMappings.Add(new VFXMapping("attachedStripDataBuffer", dependentBuffers.stripBuffers[stripData]));
                }

                if (indirectBufferIndex != -1 &&
                    (context.contextType == VFXContextType.Update ||
                     (context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).HasIndirectDraw())))
                {
                    bufferMappings.Add(new VFXMapping(context.taskType == VFXTaskType.CameraSort ? "inputBuffer" : "indirectBuffer", indirectBufferIndex));
                }

                if (deadListBufferIndex != -1 && context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).NeedsDeadListCount())
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (context.taskType == VFXTaskType.CameraSort)
                {
                    bufferMappings.Add(new VFXMapping("outputBuffer", sortBufferAIndex));
                    if (deadListCountIndex != -1)
                    {
                        bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                    }
                }

                var gpuTarget = context.allLinkedOutputSlot.SelectMany(o => (o.owner as VFXContext).outputContexts)
                                .Where(c => c.CanBeCompiled())
                                .Select(o => dependentBuffers.eventBuffers[o.GetData()])
                                .ToArray();
                for (uint indexTarget = 0; indexTarget < (uint)gpuTarget.Length; ++indexTarget)
                {
                    var prefix = VFXCodeGeneratorHelper.GeneratePrefix(indexTarget);
                    bufferMappings.Add(new VFXMapping(string.Format("eventListOut_{0}", prefix), gpuTarget[indexTarget]));
                }

                uniformMappings.Clear();
                foreach (var uniform in contextData.uniformMapper.uniforms)
                {
                    uniformMappings.Add(new VFXMapping(contextData.uniformMapper.GetName(uniform), expressionGraph.GetFlattenedIndex(uniform)));
                }
                foreach (var texture in contextData.uniformMapper.textures)
                {
                    // TODO At the moment issue all names sharing the same texture as different texture slots. This is not optimized as it required more texture binding than necessary
                    foreach (var name in contextData.uniformMapper.GetNames(texture))
                    {
                        uniformMappings.Add(new VFXMapping(name, expressionGraph.GetFlattenedIndex(texture)));
                    }
                }

                // Retrieve all cpu mappings at context level (-1)
                var cpuMappings = contextData.cpuMapper.CollectExpression(-1).Select(exp => new VFXMapping(exp.name, expressionGraph.GetFlattenedIndex(exp.exp))).ToArray();

                //Check potential issue with invalid operation on CPU
                foreach (var mapping in cpuMappings)
                {
                    if (mapping.index < 0)
                    {
                        throw new InvalidOperationException("Unable to compute CPU expression for mapping : " + mapping.name);
                    }
                }

                taskDesc.buffers           = bufferMappings.ToArray();
                taskDesc.temporaryBuffers  = temporaryBufferMappings.ToArray();
                taskDesc.values            = uniformMappings.ToArray();
                taskDesc.parameters        = cpuMappings.Concat(contextData.parameters).ToArray();
                taskDesc.shaderSourceIndex = contextToCompiledData[context].indexInShaderSource;

                taskDescs.Add(taskDesc);
            }

            string nativeName = string.Empty;

            if (systemNames != null)
            {
                nativeName = systemNames.GetUniqueSystemName(this);
            }
            else
            {
                throw new InvalidOperationException("system names manager cannot be null");
            }

            outSystemDescs.Add(new VFXEditorSystemDesc()
            {
                flags    = systemFlag,
                tasks    = taskDescs.ToArray(),
                capacity = capacity,
                name     = nativeName,
                buffers  = systemBufferMappings.ToArray(),
                values   = systemValueMappings.ToArray(),
                type     = VFXSystemType.Particle,
                layer    = m_Layer
            });
        }
        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);
        }
 protected string GetDefaultName(int index)
 {
     return(VFXCodeGeneratorHelper.GeneratePrefix((uint)index));
 }
Exemple #12
0
        public override void FillDescs(
            List <VFXGPUBufferDesc> outBufferDescs,
            List <VFXEditorSystemDesc> outSystemDescs,
            VFXExpressionGraph expressionGraph,
            Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData,
            Dictionary <VFXContext, int> contextSpawnToBufferIndex,
            Dictionary <VFXData, int> attributeBuffer,
            Dictionary <VFXData, int> eventBuffer,
            Dictionary <VFXContext, List <VFXContextLink>[]> effectiveFlowInputLinks)
        {
            bool hasKill = IsAttributeStored(VFXAttribute.Alive);

            var deadListBufferIndex = -1;
            var deadListCountIndex  = -1;

            var systemBufferMappings = new List <VFXMapping>();
            var systemValueMappings  = new List <VFXMapping>();

            var attributeBufferIndex = attributeBuffer[this];

            int attributeSourceBufferIndex = -1;
            int eventGPUFrom = -1;

            if (m_DependenciesIn.Any())
            {
                if (m_DependenciesIn.Count != 1)
                {
                    throw new InvalidOperationException("Unexpected multiple input dependency for GPU event");
                }
                attributeSourceBufferIndex = attributeBuffer[m_DependenciesIn.FirstOrDefault()];
                eventGPUFrom = eventBuffer[this];
            }

            if (attributeBufferIndex != -1)
            {
                outBufferDescs.Add(m_layoutAttributeCurrent.GetBufferDesc(alignedCapacity));
                systemBufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
            }

            if (m_ownAttributeSourceBuffer && m_layoutAttributeSource.GetBufferSize(sourceCount) > 0u)
            {
                if (attributeSourceBufferIndex != -1)
                {
                    throw new InvalidOperationException("Unexpected source while filling description of data particle");
                }

                attributeSourceBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(m_layoutAttributeSource.GetBufferDesc(sourceCount));
            }

            if (attributeSourceBufferIndex != -1)
            {
                systemBufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
            }

            var systemFlag = VFXSystemFlag.SystemDefault;

            if (eventGPUFrom != -1)
            {
                systemFlag |= VFXSystemFlag.SystemReceivedEventGPU;
                systemBufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
            }

            if (hasKill)
            {
                systemFlag |= VFXSystemFlag.SystemHasKill;

                deadListBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Counter, size = capacity, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadList", deadListBufferIndex));

                deadListCountIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Raw, size = 1, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
            }

            var initContext = m_Contexts.FirstOrDefault(o => o.contextType == VFXContextType.Init);

            if (initContext != null)
            {
                systemBufferMappings.AddRange(effectiveFlowInputLinks[initContext].SelectMany(t => t.Select(u => u.context)).Where(o => o.contextType == VFXContextType.Spawner).Select(o => new VFXMapping("spawner_input", contextSpawnToBufferIndex[o])));
            }
            if (m_Contexts.Count() > 0 && m_Contexts.First().contextType == VFXContextType.Init) // TODO This test can be removed once we ensure priorly the system is valid
            {
                var mapper = contextToCompiledData[m_Contexts.First()].cpuMapper;

                var boundsCenterExp = mapper.FromNameAndId("bounds_center", -1);
                var boundsSizeExp   = mapper.FromNameAndId("bounds_size", -1);

                int boundsCenterIndex = boundsCenterExp != null?expressionGraph.GetFlattenedIndex(boundsCenterExp) : -1;

                int boundsSizeIndex = boundsSizeExp != null?expressionGraph.GetFlattenedIndex(boundsSizeExp) : -1;

                if (boundsCenterIndex != -1 && boundsSizeIndex != -1)
                {
                    systemValueMappings.Add(new VFXMapping("bounds_center", boundsCenterIndex));
                    systemValueMappings.Add(new VFXMapping("bounds_size", boundsSizeIndex));
                }
            }

            int  indirectBufferIndex = -1;
            bool needsIndirectBuffer = NeedsIndirectBuffer();

            if (needsIndirectBuffer)
            {
                systemFlag         |= VFXSystemFlag.SystemHasIndirectBuffer;
                indirectBufferIndex = outBufferDescs.Count;
                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Counter, size = capacity, stride = 4
                });
                systemBufferMappings.Add(new VFXMapping("indirectBuffer", indirectBufferIndex));
            }

            // sort buffers
            int  sortBufferAIndex = -1;
            int  sortBufferBIndex = -1;
            bool needsSort        = NeedsSort();

            if (needsSort)
            {
                sortBufferAIndex = outBufferDescs.Count;
                sortBufferBIndex = sortBufferAIndex + 1;

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferA", sortBufferAIndex));

                outBufferDescs.Add(new VFXGPUBufferDesc()
                {
                    type = ComputeBufferType.Default, size = capacity, stride = 8
                });
                systemBufferMappings.Add(new VFXMapping("sortBufferB", sortBufferBIndex));
            }


            var taskDescs       = new List <VFXEditorTaskDesc>();
            var bufferMappings  = new List <VFXMapping>();
            var uniformMappings = new List <VFXMapping>();

            for (int i = 0; i < m_Contexts.Count; ++i)
            {
                var context     = m_Contexts[i];
                var contextData = contextToCompiledData[context];

                var taskDesc = new VFXEditorTaskDesc();
                taskDesc.type = context.taskType;

                bufferMappings.Clear();

                if (attributeBufferIndex != -1)
                {
                    bufferMappings.Add(new VFXMapping("attributeBuffer", attributeBufferIndex));
                }

                if (eventGPUFrom != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("eventList", eventGPUFrom));
                }

                if (deadListBufferIndex != -1 && context.contextType != VFXContextType.Output && context.taskType != VFXTaskType.CameraSort)
                {
                    bufferMappings.Add(new VFXMapping(context.contextType == VFXContextType.Update ? "deadListOut" : "deadListIn", deadListBufferIndex));
                }

                if (deadListCountIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (attributeSourceBufferIndex != -1 && context.contextType == VFXContextType.Init)
                {
                    bufferMappings.Add(new VFXMapping("sourceAttributeBuffer", attributeSourceBufferIndex));
                }

                if (indirectBufferIndex != -1 &&
                    (context.contextType == VFXContextType.Update ||
                     (context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).HasIndirectDraw())))
                {
                    bufferMappings.Add(new VFXMapping(context.taskType == VFXTaskType.CameraSort ? "inputBuffer" : "indirectBuffer", indirectBufferIndex));
                }

                if (deadListBufferIndex != -1 && context.contextType == VFXContextType.Output && (context as VFXAbstractParticleOutput).NeedsDeadListCount())
                {
                    bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                }

                if (context.taskType == VFXTaskType.CameraSort)
                {
                    bufferMappings.Add(new VFXMapping("outputBuffer", sortBufferAIndex));
                    if (deadListCountIndex != -1)
                    {
                        bufferMappings.Add(new VFXMapping("deadListCount", deadListCountIndex));
                    }
                }

                var gpuTarget = context.allLinkedOutputSlot.SelectMany(o => (o.owner as VFXContext).outputContexts)
                                .Where(c => c.CanBeCompiled())
                                .Select(o => eventBuffer[o.GetData()])
                                .ToArray();
                for (uint indexTarget = 0; indexTarget < (uint)gpuTarget.Length; ++indexTarget)
                {
                    var prefix = VFXCodeGeneratorHelper.GeneratePrefix(indexTarget);
                    bufferMappings.Add(new VFXMapping(string.Format("eventListOut_{0}", prefix), gpuTarget[indexTarget]));
                }

                uniformMappings.Clear();
                foreach (var uniform in contextData.uniformMapper.uniforms.Concat(contextData.uniformMapper.textures))
                {
                    uniformMappings.Add(new VFXMapping(contextData.uniformMapper.GetName(uniform), expressionGraph.GetFlattenedIndex(uniform)));
                }

                // Retrieve all cpu mappings at context level (-1)
                var cpuMappings = contextData.cpuMapper.CollectExpression(-1).Select(exp => new VFXMapping(exp.name, expressionGraph.GetFlattenedIndex(exp.exp))).ToArray();

                //Check potential issue with invalid operation on CPU
                foreach (var mapping in cpuMappings)
                {
                    if (mapping.index < 0)
                    {
                        throw new InvalidOperationException("Unable to compute CPU expression for mapping : " + mapping.name);
                    }
                }

                taskDesc.buffers           = bufferMappings.ToArray();
                taskDesc.values            = uniformMappings.ToArray();
                taskDesc.parameters        = cpuMappings.Concat(contextData.parameters).ToArray();
                taskDesc.shaderSourceIndex = contextToCompiledData[context].indexInShaderSource;

                taskDescs.Add(taskDesc);
            }

            outSystemDescs.Add(new VFXEditorSystemDesc()
            {
                flags    = systemFlag,
                tasks    = taskDescs.ToArray(),
                capacity = capacity,
                buffers  = systemBufferMappings.ToArray(),
                values   = systemValueMappings.ToArray(),
                type     = VFXSystemType.Particle,
                layer    = m_Layer
            });
        }