4
\$\begingroup\$

I've implemented a simple particle system where each particle has a position, velocity, age and lifespan stored in different SSBOs.

Most of the data including all the position, velocity and age is updated through a compute shader. And emiting new particles is handled by CPU since it's a serial process. But in order to track whether each particle is alive or dead, I have to read all the lifespan data back to CPU from the SSBO (using glGetBufferSubData()), which do stalls the GPU I'm afraid.

So I was wondering is there any way to prevent reading the data back from GPU. I found a demo particle system made by AMD using directX, which uses a dead list and an alive list in the compute shader. But I have no idea how to achieve this with GLSL. Any ideas?

Demo code:

...

// The dead list, so any particles that are retired this frame can be added to this list
AppendStructuredBuffer<uint>            g_DeadListToAddTo       : register( u2 );

// The alive list which gets built using this shader
RWStructuredBuffer<float2>              g_IndexBuffer           : register( u3 );

...

// Dead particles are added to the dead list for recycling
if ( pb.m_Age <= 0.0f || killParticle )
{
    pb.m_Age = -1;
    g_DeadListToAddTo.Append( id.x );
}

...
\$\endgroup\$
  • \$\begingroup\$ I haven't used compute's yet, but this seems like a CPU-side issue where you need to remove elements from a list that's being iterated. In those cases, you add the "dead" objects into another list and then iterate the "recycling" list, afterwards. Is it possible to use a second computer shader to "iterate" the "dead list", if any, reinitialize the particles on the GPU, and feed them back in, as usual, next frame? Kind of a GPU ping-pong... \$\endgroup\$ – Jon Apr 11 '15 at 16:04
  • \$\begingroup\$ Second compute would output all "alive" particles, then append any revived particles. \$\endgroup\$ – Jon Apr 11 '15 at 16:07
  • \$\begingroup\$ @Jon So is there any dynamic data structure in glsl that is similiar to the "AppendStructuredBuffer" or "RWStructuredBuffer" in DirectX? \$\endgroup\$ – Oscar Apr 12 '15 at 2:59
  • \$\begingroup\$ I'm one of those DirectX people, sorry... I managed to find this but it makes very little sense to me. They are using the geometry shader to emit/kill and don't mention compute shaders at all. \$\endgroup\$ – Jon Apr 12 '15 at 3:56
  • \$\begingroup\$ The various "XXTransformFeedback" methods appear to have everything to do with routing outputs to inputs. However, if the geometry shader fails to output "dead" particles in the first place, the compute shader would only receive live particles and have nothing to do but chug velocities. \$\endgroup\$ – Jon Apr 12 '15 at 4:04
2
\$\begingroup\$

If the only way your particles die is through age, then there's no need to read the data back from the OpenGL buffers at all. Keep a CPU side buffer that tracks the current age for each particle (or equivalently, remembers the time at which they will die), then your CPU can scan through that list quickly every frame to find particles which need to be re-born. Then you can update just their portion of the GPU buffer.

I would also look into glMapBuffer() (glMapBufferOES() on OpenGL ES 2.0) for updating the GPU buffer, as I've found they have better performance (not stalling the GPU).

Alternatively you might consider checking for particle death within the shader itself. Depending on the complexity of your particle spawn process this may not be practical but if you're just emitting particles from a point source, for example, you could pass this position in as a shader parameter and then your shader could detect old particles and restart them at the emitter position.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.