// Get the operands for the runtime evaluation
        public Operands GetOperands(VFXExpressionGraph graph)
        {
            var addOperands = additionnalOperands;

            if (parents.Length + addOperands.Length > 4)
            {
                throw new Exception("Too much parameter for expression : " + this);
            }

            var data = new Operands(-1);

            if (graph != null)
            {
                for (int i = 0; i < parents.Length; ++i)
                {
                    data[i] = graph.GetFlattenedIndex(parents[i]);
                }
            }

            for (int i = 0; i < addOperands.Length; ++i)
            {
                data[Operands.OperandCount - addOperands.Length + i] = addOperands[i];
            }

            return(data);
        }
        private static void CollectExposedDesc(List <VFXMapping> outExposedParameters, string name, VFXSlot slot, VFXExpressionGraph graph)
        {
            var expression = slot.valueType != VFXValueType.None ? slot.GetInExpression() : null;

            if (expression != null)
            {
                var exprIndex = graph.GetFlattenedIndex(expression);
                if (exprIndex == -1)
                {
                    throw new InvalidOperationException("Unable to retrieve value from exposed for " + name);
                }

                outExposedParameters.Add(new VFXMapping()
                {
                    name  = name,
                    index = exprIndex
                });
            }
            else
            {
                foreach (var child in slot.children)
                {
                    CollectExposedDesc(outExposedParameters, name + "_" + child.name, child, graph);
                }
            }
        }
        private static void FillSpawner(Dictionary <VFXContext, SpawnInfo> outContextSpawnToSpawnInfo, List <VFXCPUBufferDesc> outCpuBufferDescs, List <VFXEditorSystemDesc> outSystemDescs, IEnumerable <VFXContext> contexts, VFXExpressionGraph graph, List <VFXLayoutElementDesc> globalEventAttributeDescs, Dictionary <VFXContext, VFXContextCompiledData> contextToCompiledData)
        {
            var spawners = CollectSpawnersHierarchy(contexts);

            foreach (var it in spawners.Select((spawner, index) => new { spawner, index }))
            {
                outContextSpawnToSpawnInfo.Add(it.spawner, new SpawnInfo()
                {
                    bufferIndex = outCpuBufferDescs.Count, systemIndex = it.index
                });
                outCpuBufferDescs.Add(new VFXCPUBufferDesc()
                {
                    capacity    = 1u,
                    stride      = globalEventAttributeDescs.First().offset.structure,
                    layout      = globalEventAttributeDescs.ToArray(),
                    initialData = ComputeArrayOfStructureInitialData(globalEventAttributeDescs)
                });
            }
            foreach (var spawnContext in spawners)
            {
                var buffers = new List <VFXMapping>();
                buffers.Add(new VFXMapping()
                {
                    index = outContextSpawnToSpawnInfo[spawnContext].bufferIndex,
                    name  = "spawner_output"
                });

                for (int indexSlot = 0; indexSlot < 2; ++indexSlot)
                {
                    foreach (var input in spawnContext.inputFlowSlot[indexSlot].link)
                    {
                        var inputContext = input.context as VFXContext;
                        if (outContextSpawnToSpawnInfo.ContainsKey(inputContext))
                        {
                            buffers.Add(new VFXMapping()
                            {
                                index = outContextSpawnToSpawnInfo[inputContext].bufferIndex,
                                name  = "spawner_input_" + (indexSlot == 0 ? "OnPlay" : "OnStop")
                            });
                        }
                    }
                }

                var contextData = contextToCompiledData[spawnContext];
                outSystemDescs.Add(new VFXEditorSystemDesc()
                {
                    buffers  = buffers.ToArray(),
                    capacity = 0u,
                    flags    = VFXSystemFlag.SystemDefault,
                    layer    = uint.MaxValue,
                    tasks    = spawnContext.activeChildrenWithImplicit.Select((b, index) =>
                    {
                        var spawnerBlock = b as VFXAbstractSpawner;
                        if (spawnerBlock == null)
                        {
                            throw new InvalidCastException("Unexpected block type in spawnerContext");
                        }
                        if (spawnerBlock.spawnerType == VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior == null)
                        {
                            throw new InvalidOperationException("VFXAbstractSpawner excepts a custom behavior for custom callback type");
                        }
                        if (spawnerBlock.spawnerType != VFXTaskType.CustomCallbackSpawner && spawnerBlock.customBehavior != null)
                        {
                            throw new InvalidOperationException("VFXAbstractSpawner only expects a custom behavior for custom callback type");
                        }

                        var cpuExpression = contextData.cpuMapper.CollectExpression(index, false).Select(o =>
                        {
                            return(new VFXMapping
                            {
                                index = graph.GetFlattenedIndex(o.exp),
                                name = o.name
                            });
                        }).ToArray();

                        Object processor = null;
                        if (spawnerBlock.customBehavior != null)
                        {
                            var assets = AssetDatabase.FindAssets("t:TextAsset " + spawnerBlock.customBehavior.Name);
                            if (assets.Length != 1)
                            {
                                // AssetDatabase.FindAssets will not search in package by default. Search in our package explicitely
                                assets = AssetDatabase.FindAssets("t:TextAsset " + spawnerBlock.customBehavior.Name, new string[] { VisualEffectGraphPackageInfo.assetPackagePath });
                                if (assets.Length != 1)
                                {
                                    throw new InvalidOperationException("Unable to find the definition .cs file for " + spawnerBlock.customBehavior + " Make sure that the class name and file name match");
                                }
                            }

                            var assetPath = AssetDatabase.GUIDToAssetPath(assets[0]);
                            processor     = AssetDatabase.LoadAssetAtPath <TextAsset>(assetPath);
                        }

                        return(new VFXEditorTaskDesc
                        {
                            type = spawnerBlock.spawnerType,
                            buffers = new VFXMapping[0],
                            values = cpuExpression.ToArray(),
                            parameters = contextData.parameters,
                            externalProcessor = processor
                        });
                    }).ToArray()
                });
            }
        }
Beispiel #4
0
        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)
        {
            var context     = m_Owners[0];
            var contextData = contextToCompiledData[context];

            var mappings = new List <VFXMapping>();

            foreach (var uniform in contextData.uniformMapper.uniforms.Concat(contextData.uniformMapper.textures))
            {
                int exprIndex = expressionGraph.GetFlattenedIndex(uniform);
                foreach (var name in contextData.uniformMapper.GetNames(uniform))
                {
                    mappings.Add(new VFXMapping(name, exprIndex));
                }
            }

            var paramList = new List <VFXMapping>(contextData.parameters);

            // TODO Remove once material are serialized
            {
                var mat         = GetOrCreateMaterial();
                var keywordsStr = new StringBuilder();

                foreach (var k in mat.shaderKeywords)
                {
                    keywordsStr.Append(k);
                    keywordsStr.Append(' ');
                }

                const int kKeywordID = 0x5a93713b;
                paramList.Add(new VFXMapping(keywordsStr.ToString(), kKeywordID));

                // Add material properties mappings
                for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); ++i)
                {
                    if (ShaderUtil.IsShaderPropertyHidden(shader, i))
                    {
                        var name    = ShaderUtil.GetPropertyName(shader, i);
                        var propExp = contextData.cpuMapper.FromNameAndId(name, -1);
                        if (propExp != null)
                        {
                            int propIndex = expressionGraph.GetFlattenedIndex(propExp);
                            if (propIndex != -1)
                            {
                                paramList.Add(new VFXMapping(name, propIndex));
                            }
                        }
                    }
                }
            }

            var task = new VFXEditorTaskDesc()
            {
                externalProcessor = shader,
                values            = mappings.ToArray(),
                parameters        = paramList.ToArray(),
                type = (UnityEngine.VFX.VFXTaskType)VFXTaskType.Output
            };

            mappings.Clear();
            var mapper = contextData.cpuMapper;

            // TODO Factorize that
            var meshExp      = mapper.FromNameAndId("mesh", -1);
            var transformExp = mapper.FromNameAndId("transform", -1);
            var subMaskExp   = mapper.FromNameAndId("subMeshMask", -1);

            int meshIndex = meshExp != null?expressionGraph.GetFlattenedIndex(meshExp) : -1;

            int transformIndex = transformExp != null?expressionGraph.GetFlattenedIndex(transformExp) : -1;

            int subMaskIndex = subMaskExp != null?expressionGraph.GetFlattenedIndex(subMaskExp) : -1;

            if (meshIndex != -1)
            {
                mappings.Add(new VFXMapping("mesh", meshIndex));
            }
            if (transformIndex != -1)
            {
                mappings.Add(new VFXMapping("transform", transformIndex));
            }
            if (subMaskIndex != -1)
            {
                mappings.Add(new VFXMapping("subMeshMask", subMaskIndex));
            }

            outSystemDescs.Add(new VFXEditorSystemDesc()
            {
                tasks = new VFXEditorTaskDesc[1] {
                    task
                },
                values = mappings.ToArray(),
                type   = VFXSystemType.Mesh,
                layer  = uint.MaxValue,
            });
        }
        public override void FillDescs(
            List <VFXGPUBufferDesc> outBufferDescs,
            List <VFXTemporaryGPUBufferDesc> outTemporaryBufferDescs,
            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)
        {
            var context     = m_Owners[0];
            var contextData = contextToCompiledData[context];

            var mappings = new List <VFXMapping>();

            foreach (var uniform in contextData.uniformMapper.uniforms.Concat(contextData.uniformMapper.textures))
            {
                int exprIndex = expressionGraph.GetFlattenedIndex(uniform);
                foreach (var name in contextData.uniformMapper.GetNames(uniform))
                {
                    mappings.Add(new VFXMapping(name, exprIndex));
                }
            }

            var task = new VFXEditorTaskDesc()
            {
                externalProcessor = shader,
                values            = mappings.ToArray(),
                parameters        = contextData.parameters,
                type = (UnityEngine.VFX.VFXTaskType)VFXTaskType.Output
            };

            mappings.Clear();
            var mapper = contextData.cpuMapper;

            // TODO Factorize that
            var meshExp      = mapper.FromNameAndId("mesh", -1);
            var transformExp = mapper.FromNameAndId("transform", -1);
            var subMaskExp   = mapper.FromNameAndId("subMeshMask", -1);

            int meshIndex = meshExp != null?expressionGraph.GetFlattenedIndex(meshExp) : -1;

            int transformIndex = transformExp != null?expressionGraph.GetFlattenedIndex(transformExp) : -1;

            int subMaskIndex = subMaskExp != null?expressionGraph.GetFlattenedIndex(subMaskExp) : -1;

            if (meshIndex != -1)
            {
                mappings.Add(new VFXMapping("mesh", meshIndex));
            }
            if (transformIndex != -1)
            {
                mappings.Add(new VFXMapping("transform", transformIndex));
            }
            if (subMaskIndex != -1)
            {
                mappings.Add(new VFXMapping("subMeshMask", subMaskIndex));
            }

            outSystemDescs.Add(new VFXEditorSystemDesc()
            {
                tasks = new VFXEditorTaskDesc[1] {
                    task
                },
                values = mappings.ToArray(),
                type   = VFXSystemType.Mesh,
                layer  = uint.MaxValue,
            });
        }
Beispiel #6
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
            });
        }
Beispiel #8
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
            });
        }