Apenas o SpinLock GLSL funciona principalmente

Eu implementei um algoritmo de peeling de profundidade usando um spinlock GLSL (inspirado emisto). Na visualização a seguir, observe como o algoritmo de peeling de profundidade funciona de maneira geral (primeira camada superior esquerda, segunda camada superior direita, terceira camada inferior esquerda, quarta camada inferior direita). As quatro camadas de profundidade são armazenadas em uma única textura RGBA.

Infelizmente, o spinlock às vezes não consegue evitar erros - você pode ver pequenas manchas brancas, particularmente na quarta camada. Há também um na asa da espaçonave na segunda camada. Essas manchas variam em cada quadro.

No meu GLSL spinlock, quando um fragmento deve ser desenhado, o programa de fragmento lê e grava um valor de bloqueio em uma textura de bloqueio separada atomicamente, esperando até que um 0 apareça, indicando que o bloqueio está aberto.Na práticaDescobri que o programa deve ser paralelo, porque se dois threads estiverem no mesmo pixel, o warp não pode continuar (um deve esperar, enquanto o outro continua, e todos os threads em um warp de thread de GPU devem ser executados simultaneamente).

Meu programa de fragmentos se parece com isso (comentários e espaçamento adicionados):

#version 420 core

//locking texture
layout(r32ui) coherent uniform uimage2D img2D_0;
//data texture, also render target
layout(RGBA32F) coherent uniform image2D img2D_1;

//Inserts "new_data" into "data", a sorted list
vec4 insert(vec4 data, float new_data) {
    if      (new_data<data.x) return vec4(      new_data,data.xyz);
    else if (new_data<data.y) return vec4(data.x,new_data,data.yz);
    else if (new_data<data.z) return vec4(data.xy,new_data,data.z);
    else if (new_data<data.w) return vec4(data.xyz,new_data      );
    else                      return data;
}

void main() {
    ivec2 coord = ivec2(gl_FragCoord.xy);

    //The idea here is to keep looping over a pixel until a value is written.
    //By looping over the entire logic, threads in the same warp aren't stalled
    //by other waiting threads.  The first imageAtomicExchange call sets the
    //locking value to 1.  If the locking value was already 1, then someone
    //else has the lock, and can_write is false.   If the locking value was 0,
    //then the lock is free, and can_write is true.  The depth is then read,
    //the new value inserted, but only written if can_write is true (the
    //locking texture was free).  The second imageAtomicExchange call resets
    //the lock back to 0.

    bool have_written = false;
    while (!have_written) {
        bool can_write = (imageAtomicExchange(img2D_0,coord,1u) != 1u);

        memoryBarrier();

        vec4 depths = imageLoad(img2D_1,coord);
        depths = insert(depths,gl_FragCoord.z);

        if (can_write) {
            imageStore(img2D_1,coord,depths);
            have_written = true;
        }

        memoryBarrier();

        imageAtomicExchange(img2D_0,coord,0);

        memoryBarrier();
    }
    discard; //Already wrote to render target with imageStore
}

Minha pergunta é por que esse comportamento pontual ocorre? Eu quero que o spinlock funcione 100% do tempo! Poderia relacionar-se com o meu posicionamento de memoryBarrier ()?

questionAnswers(2)

yourAnswerToTheQuestion