Atomic Counters in OpenFrameworks

Since OpenGL 4.2, atomic counters have been a core feature. They help solve a variety of problems, like counting the number of red pixels in a fragment shader or acting as a form of shared memory that can be altered by shaders.

The use case I’m interested in is to create a particle system using compute shaders. This means that I need to keep track of the number of particles that are alive or dead at any given time. To do that in the GPU, I can use atomic counters.

Looking online, there were only a handful of tutorials that taught how to use atomic counters in OpenFrameworks like this one. But it required the use of the verbose OpenGL api. This writer even says that OpenFrameworks doesn’t have an API for it. But as I found out, there is! This article is just a short and sweet walk through on how to set that up.

An image of a slime mold simulation titled Rainbow Tendrils
slime mold simulation done in compute shader (instagram: @_samuelcho_ )

Setting up the buffers

vector<GLuint> counter;
counter.resize(1);

The reason we’re using a vector is because OpenFrameworks’ ofBufferObject class allows us to allocate a buffer with the data itself. So let’s create an ofBufferObject and allocate it. After allocating it, we bind it, telling OpenGL that it is an atomic counter buffer at the binding point 0.

ofBufferObject counterBuffer;
counterBuffer.allocate(counter, GL_DYNAMIC_DRAW);
counterBuffer.bindBase(GL_ATOMIC_COUNTER_BUFFER, 0);

Setting up the shader

ofShader compute;
compute.setupShaderFromFile(GL_COMPUTE_SHADER, "shader.comp");
compute.linkProgram();

For this article, I’m making a fake particle system with 69 particles.

compute.begin();
compute.dispatchCompute(69,1,1);
compute.end();

Writing the shader

After doing this, we increment the counter. We can only use special functions for the atomic counter. A full list is found here.

layout(binding = 0) uniform atomic_uint counter;
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
void main(){
atomicCounterIncrement(counter);
}

This is our fake particle.

Reading the data from ofBufferObject

There are many ways of reading data from an ofBufferObject, but the easiest way I’ve found is this:

GLuint result[1];
glGetNamedBufferSubData(counterBuffer.getId(), 0, sizeof(GLuint), result);

The method glGetNamedBufferSubData loads the data from the GPU into RAM. Since we only have a buffer with a single unsigned integer (4 bytes), this shouldn’t affect our performance. But if you’re reading a lot of data, this can bottleneck your application!

Anyways, the method gives you a pointer to the data. I’ve found that initializing the output data as an array instead of pointer works best. After calling the method, we can read the data with a simple cout << result[0] << endl;. The output should be 69.

Summary

New Music Performer && Composer && Creative Coder || https://samuelcho.de

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store