Why do I need memory barrier when doing atomic operations? I am reading the OpenGL SuperBible 7th edition which covers atomic operations on memory specifically within shader storage blocks.

It says (about atomic operations):


  If two invocations access the same memory locations... then they will be serialized and only one will get to go at one time.


Great. However, it then goes on to cover Synchronizing Access to Memory specifically and the use of glMemoryBarrier

As I understand it, you need to use glMemoryBarrier once you start writing to buffers from shaders.

However, the distinction is not made clear to me about why I need to use a barrier if the operations I am doing within my shader are atomic operations.

It's possible I am conflating atomic operations and general memory access, but, in the book the line is not clearly drawn.

When is it that a glMemoryBarrier is required? Is it everytime a shader writes to memory (whether the operations are atomic or not)?
glMemoryBarrier is for when you want to make writes from one rendering command visible to reads from a subsequent rendering command.

That is, you can do all the atomics you like during a rendering command. But without the barrier, there's no guarantee that any of those atomic actions will be visible to later commands. Yes, they will still be atomic, but this only ensures that they will each execute in some order and each operation will fully execute before the next. What they won't ensure is that operations which OpenGL defines has happening "later" will execute before earlier operations.

Sometimes, you actually don't care about the order of the operations; being atomic may be enough. And sometimes, you do care.

Consider the case of a "linked-list" style blending buffer. Each pixel in the image is an integer that represents one of the items in the list. Each FS invocation will use an atomic increment to get a unique identifier, then swap that identifier with the current value in the image. It writes its pixel data to the entry in an SSBO, along with the identifier it swapped out of the image.

When doing that atomic increment on the unique identifier, you don't care if FS invocations from two different rendering commands execute out of order. You simply need the operation to be atomic. Similarly, the swap doesn't have to be in order; it just needs to be atomic. As long as they all execute, and the atomic operations do their jobs, then they will be fine.

Now, when it comes time to do blending based on this data, that is when you need to be able to read all of the data that was previously written. And that rendering operation requires glMemoryBarrier.

Of course, you're not necessarily using atomic operations to read these values.