atomicCompSwap

Hi there,

These days I played with OpenGL Compute Shaders and atomic operations. Unfortunately, the GLSL compiler keeps complaining about my use of the function atomicCompSwap.
It claims “0(63) : error C1115: unable to find compatible overloaded function “atomicCompSwap(uint, uint, uint)””.

bool getMutex(inout uint mutex) {
	if (atomicCompSwap(mutex, uint(0), threadId) == threadId) {
		return true;
	} else {
		return false;
	}
}

According to the specs, the argument list is perfectly valid. I also tried the signed version with the same results. May this be a driver bug?

My system specs are:
Windows 7 64bit
Geforce GT 555M
Driver version: 310.90

atomicCompSwap can only be used with uint variables declared as either shared or buffer. An inout function parameter is neither of those things; it’s merely a function parameter.

You must call it directly with a shared or buffer variable. Or an array entry indexed from one of those. You can’t pass one through an intermediate function like that.

[QUOTE=Alfonse Reinheart;1247129]atomicCompSwap can only be used with uint variables declared as either shared or buffer. An inout function parameter is neither of those things; it’s merely a function parameter.

You must call it directly with a shared or buffer variable. Or an array entry indexed from one of those. You can’t pass one through an intermediate function like that.[/QUOTE]

Ahhh thanks for the clarification!
You were right, of course. Now I am using a macro instead of a function and everything works as expected. Tank you!

Hm I thought I did understand how atomicCompSwap works, but I was wrong.

There are two points that I dont’ get:

  1. The documentation says that the return value of atomicCompSwap is the new value if the comparison yields true and the old value if it yields false. But it seems that the return value is always the old value and the comparison just triggers if the memory is changed or not.

  2. Why do I need a barrier() call after an atomicCompSwap in order to see the new values in the same thread?

The following code snipped demonstrates what I mean:

void main() {	
	subDivisionQueueCounter = 17;

	// Write to debug output
	Debug.Data[0] = subDivisionQueueCounter;	
	
	uint newVal = subDivisionQueueCounter + 2;		
	uint veryNewVal = atomicCompSwap(subDivisionQueueCounter, 17, newVal);
	//barrier();       // Weird I need to uncomment this!
	
	// Write to debug output	
	Debug.Data[1] = subDivisionQueueCounter;
}

In this example Debug is just a ShaderStorageBuffer that I use to get debug information out of a shader invocation and subDivisionQueueCounter is a shared uint variable. I start exactly one thread, i.e. the workgroup size is (1,1,1) and I start the kernel with glDispatchCompute(1, 1, 1) so there should be no concurrency issues.

If I comment the call to barrier(), the contents of the debug buffer are [17, 17] while they are [17, 19] if I uncomment it. In my mind, it should always be [17, 19] regardless of barrier.

The documentation says that the return value of atomicCompSwap is the new value if the comparison yields true and the old value if it yields false.

No. The atomic memory functions always return the old value. The idea being that if you need the old value, you just got it. And if you need the new value, you can compute it.

If you do an atomicCompSwap, you have to do the conditional logic with the old value and your test value to see if it was swapped or not. Most of the time, you don’t have to care.

Why do I need a barrier() call after an atomicCompSwap in order to see the new values in the same thread?

I don’t claim to have a full and complete understanding of how the memory model works in the case of shared variables, but my reading of the spec suggests that visibility issues regarding them are about other threads. So this sounds like a driver bug.

That being said, since every local invocation is writing to the same shared variable (regardless of the fact that there’s only one invocation), you’re probably confusing the compiler.

Thanks again for the quick reply! This forum is really helpful :slight_smile:

It sounds logical for the atomic functions to always return the old value, I agree on that. Probably the following quote is just a typo or some other sort of mistake: “If the content of mem is equal to compare, then the content of data is written into mem and is returned from the function” (http://www.opengl.org/sdk/docs/manglsl/).

As stated on the page you linked to, “If you find any inaccuracies or typos in the reference pages, don’t hesitate to inform us via the feedback form or using the Khronos Bugzilla (you must first create a Bugzilla account, however).” So you should do that. The OpenGL specification clearly states it correctly, as does the Wiki page.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.