Internal Error (IOAF code 1) from using atomic_exchange_explicit

Hello,


I'm trying to implement an A-buffer algorithm in Metal, and I am getting this error when trying to use atomic_exchange_explicit() in a fragment shader:

"Execution of the command buffer was aborted due to an error during execution. Internal Error (IOAF code 1)"

I'm trying to exchange values in a screen-size buffer of uint32's. declared as device atomic_uint. I've been able to use atomic_fetch_add_explicit on a single uint counter, but it is giving me this error when trying to operate on the larger buffer. Any idea why that would happen? Here's the shader code:


fragment void stroke_abuffer_fragment(VertexIn interpolated [[stage_in]],
                                      const device uint&  color [[ buffer(0) ]],
                                      constant Uniforms&  uniforms    [[ buffer(1) ]],
                                      device FragLink*  LinkBuffer [[ buffer(3) ]],
                                      device atomic_uint &counter[[buffer(2)]],
                                      device atomic_uint *StartBuffer[[buffer(4)]]
                                      ) {
   
    uint pos = int(interpolated.position.x)+int(interpolated.position.y)*uniforms.displaySize[0];
   
    uint value = atomic_fetch_add_explicit(&counter, 1, memory_order_relaxed);
    value += 1;
   
    FragLink F;
    F.color = color;
    F.depth = interpolated.position.z;
    F.next = atomic_exchange_explicit(&StartBuffer[pos], value, memory_order_relaxed);
   
    LinkBuffer[value] = F;
}


Thanks

Bob



Accepted Reply

Okay, I finally got this sorted out after several hours of utter incomprehension. It was several problems actually. The most frustrating was that after I bound my large buffer, I was unknowingly binding another buffer to the same index in a diffent part of the program. So Dan you were right, it was overwriting the buffer bounds because it was bound to the wrong buffer.


Then I ran into some issues because I was using 'UInt' in some places where I should have been using 'UInt32' - I didn't realize that 'UInt' is 8 bytes!


Anyway, it's working now, I can't believe it!

Replies

An error like the one you've encounterd could be due to accessing memory outside the bounds of the buffer. StartBuffer would need to be pretty large for the algorithm you're trying to implement. Can you confirm that the size of the buffer passed into StartBuffer is large enough?

I believe it is large enough, yes -- I was wondering if it is okay to have an atomic buffer that large?

Could it have anything to do with the age of the hardware? My iMac is the first of the new 'thin' design, ie from late 2012.


There's a whole thread of my attempt to get this algorithm working here: https://stackoverflow.com/questions/47242066/metal-fragment-shader-a-buffer-produces-shimmering-glitch


Thanks

Bob

Do I have StartBuffer defined properly to be able to modify it? I am doing some testing -- changed that buffer size to just 64 UInts and am writing numbers into it. But when I read it back after waiting for the command buffer to complete, the values are not modified -- they are the same value that I use to initialize the buffer.


In the shader I am just writing to it like this. I'm just modding my normal position down to between 0-64 and writing that value to the buffer.


uint pos = int(interpolated.position.x)+int(interpolated.position.y)*width ;
atomic_store_explicit(&StartBuffer[pos%64], pos, memory_order_relaxed);


This is how I'm reading the data back after the render pass.

data = NSData(bytesNoCopy: offscreenStartBuffer!.contents(),
                                  length: offscreenBufferSize, freeWhenDone: false)
var tempArray = Array<UInt32>(repeating: 0, count:offscreenBufferSize/MemoryLayout<UInt32>.stride)
data.getBytes(&tempArray, length:offscreenBufferSize)


But the data is unchanged from value I write to it at the start of the render pass. Why would it not change the values in the buffer? The buffer storage mode is Shared.


I also tried 'atomic_fetch_add_explicit' instead of the 'atomic_store_explicit', since the former is working for my counter variable. The fact that it doesn't change my StartBuffer makes me wonder if there's something wrong with the way I have the buffer declared, or if it's even allowed to have a pointer to an array of atomic_uints in a shader.


Thanks

Bob

Okay, I finally got this sorted out after several hours of utter incomprehension. It was several problems actually. The most frustrating was that after I bound my large buffer, I was unknowingly binding another buffer to the same index in a diffent part of the program. So Dan you were right, it was overwriting the buffer bounds because it was bound to the wrong buffer.


Then I ran into some issues because I was using 'UInt' in some places where I should have been using 'UInt32' - I didn't realize that 'UInt' is 8 bytes!


Anyway, it's working now, I can't believe it!

Avoiding index collisions and misbound objects is why it's good practice to use an enum value in a header shared between your shader and app code rather than a literal for your buffer, texture, and sampler indices. Most of the samples and the Xcode Metal Game template does this.


It may make your code more verbose, but it also makes it more meaningful and easier to debug.