Can I perform atomic operations on a function parameter?


Hi, I would like to pass a struct contained in a shader storage buffer to a function and perform some atomic additions on a uint member of the struct. However the shader won’t compile because:

A shader will fail to compile if the value passed to the mem argument of an atomic memory function does not correspond to a buffer or shared variable

I was wondering if there’s some variable qualifier to enforce a function parameter to be backed by a buffer. As far as I know in, out, inout and const in are the only available parameter qualifiers, but maybe I’m missing something here.


Actually, thinking about how GLSL functions copy arguments in and out, I’m guessing it’s not possible, is it?


What GL driver (vendor/version) are you using?

I’m curious which one isn’t just inlining the function and automatically realizing what inputs back the function arguments?

Also, could you post a short shader that illustrates the problem? I (and maybe others too) would be interested in compiling it on a few drivers to see what behavior I get here.


No, it isn’t. If the struct member is in an array, you could pass an array index. But that’s about it.

I don’t see how that matters. Atomic functions cannot be called on things that aren’t buffer variables (or shared variables). As such, this:

void func(inout SomeStruct val)
  atomicAdd(val.x, 5);

Is explicitly not allowed by the rules of GLSL, even if you call it by passing in a SomeStruct member of a buffer variable. Inlining cannot change those rules.

server glx vendor string: NVIDIA Corporation
server glx version string: 1.4

The (compute) shader is as simple as:

#version 450 core

struct Data
	uint numGeneratedVertices;

	// ... other stuff

layout(std430) buffer DataBuffer
	Data data;

void generateGeometry(/* inout? */ Data data, ivec3 index)
	// Bunch of stuff

	uint numVertices = atomicAdd(data.numGeneratedVertices, 3);

layout(local_size_x = 36, local_size_y = 1, local_size_z = 36) in;
void main()
	// ...
	generateGeometry(data, ivec3(gl_GlobalInvocationID));

I guessed so.