6

I want to implement an A-Buffer algorithm for order-independent-transparency in my Metal application. The description of the technique mentions using an atomic counter. I've never used one of these or even heard of them. I just read about atomic variables in the Metal Shading Language Specification, but I can't figure out how to actually implement or use one.

Does anyone have experience with these in Metal? Can you point me to an example of how to set up and use a simple integer counter? Basically each render pass I need to be able to increment an integer from within the fragment shader, starting from zero. This is used to index into the A-Buffer.

Thanks!

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
bsabiston
  • 721
  • 6
  • 22

1 Answers1

12

Well, your question is lacking sufficient detail to provide much more than a general overview. You might consider adding an incomplete shader function, with pseudo-code where you're not sure how to implement something.

Anyway, an atomic counter is a variable of type atomic_uint (or atomic_int if you need sign). To be useful, the variable needs to be shared across a particular address space. Your example sounds like it needs device address space. So, you would want a device variable backed by a buffer. You would declare it as:

fragment FragmentOut my_fragment_func(device atomic_uint &counter [[buffer(0)]], ...)
{
    ...
}

You could also use a struct type for the parameter and have a field of the struct be your atomic_uint variable.

To atomically increment the atomic variable by 1 and obtain the prior value, you could do this:

    uint value = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);

The initial value of the atomic variable is taken from the contents of the buffer at a point before the draw or dispatch command is executed. It's not documented as such in the spec, but the size and bit-interpretation of an atomic type seems to match the corresponding non-atomic type. That is, you would write a uint (a.k.a. unsigned int or uint32_t) to the buffer to initialize an atomic_uint.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Thanks, that's a great explanation! A general overview is exactly what I needed. Sorry I didn't provide more detail -- I have not begun to write the shader yet, I'm just learning whether I understand enough to proceed with it. – bsabiston Nov 10 '17 at 16:08
  • 5
    I am REALLY interested in metal compute kernels/shaders but I do not know any source / book / site that explains optimisations / features like the one mentioned above. I have written lots of shaders but I have no idea what imageblocks are and generally lots of the features in Metal. E.g. how the hell can I implement a custom MPSGaussianBlur with random kernel size per pixel that is close to Apple's implementation in performance? I know it will be two pass X, Y but this is the first step. I feel there is a ton of potential in these GPUs and we only scratch the surface of it. – Summon Sep 05 '19 at 12:51