GLSL SpinLock funktioniert meistens nur

Ich habe einen Tiefenschälalgorithmus mit einem GLSL - Spinlock implementiert (inspiriert vondiese). Beachten Sie in der folgenden Visualisierung, wie der Tiefenschälalgorithmus insgesamt korrekt funktioniert (erste Schicht oben links, zweite Schicht oben rechts, dritte Schicht unten links, vierte Schicht unten rechts). Die vier Tiefenebenen werden in einer einzigen RGBA-Textur gespeichert.

Leider kann der Spinlock manchmal Fehler nicht verhindern - Sie sehen kleine weiße Flecken, insbesondere in der vierten Schicht. Es gibt auch eine auf dem Flügel des Raumschiffs in der zweiten Schicht. Diese Flecken variieren in jedem Bild.

Wenn in meinem GLSL-Spinlock ein Fragment gezeichnet werden soll, liest und schreibt das Fragmentprogramm einen Sperrwert atomar in eine separate Sperrtextur und wartet, bis eine 0 angezeigt wird, was darauf hinweist, dass das Schloss geöffnet ist.In der Praxis, Ich fand, dass das Programm parallel sein muss, weil, wenn zwei Threads auf demselben Pixel sind, der Warp nicht fortgesetzt werden kann (einer muss warten, während der andere fortgesetzt wird, und alle Threads in einem GPU-Thread-Warp müssen gleichzeitig ausgeführt werden).

Mein Fragmentprogramm sieht folgendermaßen aus (Kommentare und Abstände hinzugefügt):

#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
}

Meine Frage ist, warum dieses gesprenkelte Verhalten auftritt? Ich möchte, dass der Spinlock 100% der Zeit funktioniert! Könnte es mit meiner Platzierung von memoryBarrier () zusammenhängen?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage