Hi, I am implementing Per Pixel Linked Lists in OpenGL 4.3 using 2 SSBOs:
// -------------- PPLL Structures --------------- //
//
struct PixelPointers //
{ //
uint root_ptr; //
uint closest_ptr; //
}; //
layout( std430, binding=4 ) buffer PixelMap //
{ //
PixelPointers pixel[]; //
}; //
//
struct Fragment //
{ //
vec3 pos; //
float depth; //
vec3 normal; //
uint mat_id; //
}; //
struct FragNode //
{ //
uint next_ptr; //
Fragment frag; //
}; //
layout( binding=6 ) uniform atomic_uint counter; //
layout( std430, binding=5 ) buffer PPLL //
{ //
FragNode frags[]; //
}; //
//
// ---------------------------------------------- //
Notice how I am storing the root of each linked-list of fragments per pixel (root_ptr
). However, I am also storing the index of the fragment nearest to the viewpoint (closest_ptr
). This is how I store it:
// ---------------------- depth check -------------------------- //
//
uint closest = pixel[pixelIndex].closest_ptr; //
if(closest == 0 || gl_FragCoord.z < frags[closest-1].frag.depth) //
atomicExchange(pixel[pixelIndex].closest_ptr,index+1); //
//
// ------------------------------------------------------------- //
As you can see, I do my own depth check. I first get the index of the closest fragment (zero means there’s no linked-list) and then use the index to access the fragment node and compare its depth to the current fragment’s depth. Then I atomically replace the pointer if I found a new nearest fragment. However, I get some visual glitches that suggest there’s more than 1 kernel looking at the same pixel. It suggests that there’s two fragments from the same pixel being processed simultaneously and both test as nearest and override the pixel’s pointer(index) to the nearest fragment. The result is that sometimes a fragment from behind is painted instead of the nearest fragment. Let me clarify with an example:
There’s two possible fragments to be written onto a pixel, A is near, B is far. The pixel’s closest_ptr
starts as ZERO. Let’s imagine both fragments start being processed at the same time. They both look at closest_ptr
and see a ZERO so they both are going to atomically replace it with their index (a pointer to them), but A does it first and B does it afterwards. The closest_ptr
will actually be pointing to B which is incorrect!
How would I make this “thread safe”?