Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement/use atomic counter in Metal fragment shader?

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!

like image 940
bsabiston Avatar asked Nov 10 '17 00:11

bsabiston


1 Answers

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.

like image 111
Ken Thomases Avatar answered Oct 03 '22 03:10

Ken Thomases