Example #1
0
 public bool HasIndirectDraw()
 {
     return((indirectDraw || HasSorting() || VFXOutputUpdate.HasFeature(outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)) && !HasStrips(true));
 }
Example #2
0
 public bool NeedsGlobalSort()
 {
     return(owners.OfType <VFXAbstractParticleOutput>().Any(o => o.HasSorting() && !VFXOutputUpdate.HasFeature(o.outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)));
 }
Example #3
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;

            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));
                }
            }

            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];
                var contextData = contextToCompiledData[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;

                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.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
            });
        }
Example #4
0
 public bool NeedsGlobalIndirectBuffer()
 {
     return(compilableOwners.OfType <VFXAbstractParticleOutput>().Any(o => o.HasIndirectDraw() && !VFXOutputUpdate.HasFeature(o.outputUpdateFeatures, VFXOutputUpdate.Features.IndirectDraw)));
 }