void PrepareParallelTasks() { //create a collection of task that will run in parallel on several threads. //the number of threads and tasks to perform are not dependent. _multiParallelTasks = new MultiThreadedParallelTaskCollection(NUM_OF_SVELTO_THREADS, true); //in this case though we just want to perform a task for each thread //ParticlesCPUKernel is a task (IEnumerator) that executes the //algebra operation on the particles. Each task perform the operation //on particlesPerThread particles #if BENCHMARK pc = new ParticleCounter(particlesPerThread - 16); #else _pc = new ParticleCounter(0); #endif #if OLD_STYLE //calculate the number of particles per thread uint particlesPerThread = _particleCount / NUM_OF_SVELTO_THREADS; for (int i = 0; i < NUM_OF_SVELTO_THREADS; i++) { _multiParallelTasks.Add(new ParticlesCPUKernel((int)(particlesPerThread * i), (int)particlesPerThread, this, _pc)); } #else var particlesCpuKernel = new ParticlesCPUKernel(this); _multiParallelTasks.Add(ref particlesCpuKernel, (int)_particleCount); #endif }
IEnumerator MainThreadOperations(ParticleCounter particleCounter) { var bounds = new Bounds(_BoundCenter, _BoundSize); var syncRunner = new SyncRunner(); //these will help with synchronization between threads WaitForSignalEnumerator _waitForSignal = new WaitForSignalEnumerator(() => _breakIt); WaitForSignalEnumerator _otherwaitForSignal = new WaitForSignalEnumerator(); //Start the operations on other threads OperationsRunningOnOtherThreads(_waitForSignal, _otherwaitForSignal) .ThreadSafeRunOnSchedule(StandardSchedulers.multiThreadScheduler); //start the mainloop while (true) { _time = Time.time / 10; //wait until the other thread tell us that the data is ready to be used. //Note that I am stalling the main thread here! This is entirely up to you //if you don't want to stall it, as you can see with the other use cases _otherwaitForSignal.RunOnSchedule(syncRunner); #if BENCHMARK if (PerformanceCheker.PerformanceProfiler.showingFPSValue > 30.0f) { if (particleCounter.particlesLimit >= 16) { particleCounter.particlesLimit -= 16; } PerformanceCheker.PerformanceProfiler.particlesCount = particleCounter.particlesTransformed; } particleCounter.particlesTransformed = 0; #endif _particleDataBuffer.SetData(_gpuparticleDataArr); //render the particles. I use DrawMeshInstancedIndirect but //there aren't any compute shaders running. This is so cool! Graphics.DrawMeshInstancedIndirect(_pointMesh, 0, _material, bounds, _GPUInstancingArgsBuffer); //tell to the other thread that now it can perform the operations //for the next frame. _waitForSignal.Signal(); //continue the cycle on the next frame yield return(null); } }
void FixedUpdate() { emitCount += emitRate * Time.deltaTime; if (_reset) { ResetBuffer(); return; } SetEmitInfoBuffer(); DispatchEmitCount(); if (emitCount > 0) { DispatchEmitParticle(); } DispatchUpdateParticle(); Swap <ComputeBuffer>(ref alivelistCB, ref alivelistSecCB); // Swap alive list DispatchDrawArg(); if (_debug) { ParticleCounter[] particleC = new ParticleCounter[] { new ParticleCounter() }; uint[] arg = new uint[5] { 0, 0, 0, 0, 0 }; uint[] indirectB = new uint[3]; uint[] alivelist = new uint[maxParticle]; uint[] alivelistSec = new uint[maxParticle]; alivelistCB.GetData(alivelist); alivelistSecCB.GetData(alivelistSec); int aliveC = GetBufferCount(alivelistCB); int aliveSecC = GetBufferCount(alivelistSecCB); int deadlistC = GetBufferCount(deadlistCB); instancingArgCB.GetData(arg); particleCounterCB.GetData(particleC); updateIndirectCB.GetData(indirectB); emitParticleInfoCB.GetData(emitInfoParam); int z = 0; } prevPosition = transform.position; emitCount -= (uint)emitCount; }