OpenGL ES 3.1: atomicCompSwap

Target: OpenGL ES 3.1

I am trying to atomically swap memory inside a SSBO. Here’s how I do it:

Fragment Shader:

layout (std430,binding=1) buffer linkedlist 
  {                                         
  uint u_Records[];                
  };

(...)

uint prev = ...
uint index = ...
uint ptr = ...
uint curr = ...
coherent uint mem = u_Records + prev;
uint res = atomicCompSwap( mem, curr, ptr );

The above gives me compilation errors:

I/Adreno: ERROR: 0:82: '+' :  wrong operand types  no operation '+' exists that takes a left-hand operand of type 'unknown qualifier array of uint' and a right operand of type 'uint' (or there is no acceptable conversion)
          ERROR: 0:82: '=' :  cannot convert from 'unknown qualifier array of uint' to 'uint'
          ERROR: 0:83: 'atomicCompSwap' :  atomic memory function argument is not shared/SSBO variable

The ‘0:82’ ERROR is the ‘mem = u_Records + prev’ line. As you can see I am trying to obtain a ‘pointer’ into inside of a SSBO and compiler does not like it.

I kind of know what the compiler is complaining about, but I am not sure how to correct this. On full-blown OpenGL desktop NVidia there are pointers (NV_shader_buffer_load extension) and we could write

coherent uint32_t *mem = u_Records + prev;
uint32_t res   = atomicCompSwap( mem , cur, ptr );

(that’s actually where I took the above from) but on generic OpenGL ES ?

I believe you want:


uint res = atomicCompSwap(u_Records[prev], curr, ptr);

Yes, it does compile now - thanks!

I still haven’t verified that it works (unrelated problems). To be honest I still do not quite understand. I thought that atomicCompSwap’s first parameter was supposed to be a POINTER to a shared memory, and ‘u_Records[prev]’ is the VALUE stored at the prev’th index?

GLSL 310 ES spec:

uint atomicCompSwap (coherent inout uint mem, uint compare, uint data)
Compares the value of compare and the contents of mem. If the values are equal, the new value is given by data; otherwise, it is taken from the original contents of mem.

Standard GLSL (desktop or ES) doesn’t have pointers. Atomic functions typically have an [var]inout[/var] parameter which is required to satisfy specific storage constraints: be a [var]buffer[/var] or [var]shared[/var] variable, including an element of an array or vector.

Well, I know that GLSL doesn’t have pointers, but I still don’t understand.

When you’re calling 'atomicCompSwap(u_Records[N], a,b) then aren’t you passing the VALUE of whatever is stored inside the memory location ‘u_Records[N]’ ? If so, than how does atomicCompSwap know which MEMORY to compare?

To a C programmer this simply looks bizarre…

[QUOTE=Utumno;1291086]Well, I know that GLSL doesn’t have pointers, but I still don’t understand.

When you’re calling 'atomicCompSwap(u_Records[N], a,b) then aren’t you passing the VALUE of whatever is stored inside the memory location ‘u_Records[N]’ ? If so, than how does atomicCompSwap know which MEMORY to compare?
[/QUOTE]
The first parameter to atomicCompSwap() has the [var]inout[/var] qualifier, meaning that its value may be read and a new value may be stored in it. It’s equivalent to a parameter of reference type in C++, “ref” parameter in C# or “var” parameter in Pascal.

Parameters with [var]out[/var] or [var]inout[/var] qualifiers can only be what would be called “lvalues” in C, i.e. they must identify a storage location; they can’t be arbitrary expressions.

C doesn’t have references because … well, you can always use a pointer instead.

‘inout’ is passing by reference - that was the missing bit of information to Yours Truly (a C&R type), thanks a lot GClements!
I also now verified that it not only compiles but actually works :slight_smile: