2

シングルパス深度ピーリングを実装できるように、GLSL スピンロックを実装しようとしています。ロックテクスチャの使用例が少なく困っています。ここでは、自分が何をしているのかよくわからないことを認めなければならないので、安全のために、おそらく必要以上にコンテキストを説明しています。

私は事実上何もしないはずのフラグメントプログラムを書きました:

#version 420 core

//The lock texture holds either 0 or 1.
//0 means that the texture is available.
//1 means that the texture is locked.  
layout(r32ui) coherent uniform uimage2D img2D_0; //locking texture

layout(RGBA32F) coherent uniform image2D img2D_1; //data texture (currently unused)

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

    //The loop's exchange function swaps out the old value with 1.

    //If the locking texture was 0, 0 will be returned, terminating the loop;
    //the locking texture will now contain 1, indicating that the locking
    //texture is now locked.

    //Conversely, if the locking texture contains 1, then the exchange function
    //will write a 1 (so the texture is still locked), and return 1, indicating
    //that the texture is locked and unavailable.
    while (imageAtomicExchange(img2D_0,coord,1u)==1u);

    //The locking texture is locked.  More code would go here

    //This unlocks the texture.
    imageAtomicExchange(img2D_0,coord,0);
}

ロック テクスチャは次のように作成されます。

//data is an array initialized to all 0.
glTexImage2D(GL_TEXTURE_2D,0,GL_R32UI,size_x,size_y,0,GL_RED_INTEGER,GL_UNSIGNED_INT,data);

アルゴリズムを実行するには、カラー RGBA F32 レンダー アタッチメントを使用して FBO を取得し、有効にします。上記のシェーダーをバインドし、次のコードを使用して、ロック テクスチャを img2D_0 に渡し、カラー アタッチメントを img2D_1 に渡します。

glBindImageTextureEXT(
    /* 0, 1, respectively */,
    texture_id, 0,GL_FALSE,0, GL_READ_WRITE,
    /* GL_R32UI, GL_RGBA32F, respectively */
);

次に、オブジェクトは VBO でレンダリングされ、いくつかの 2 次パスでデータの内容が表示されます。

問題は、指定されたフラグメント プログラムがビデオ ドライバをクラッシュさせることです (終了しないため)。私の質問はなぜですか?テクスチャは 0 に初期化されており、交換関数のロジックは有効であると確信しています。私のセットアップと方法論は基本的に正しいですか?

4

1 に答える 1

3

1 つの問題は、同じワープ内の 2 つのスレッドが同じロック位置にヒットした場合、一方のスレッドがロックを取得し、もう一方のスレッドがループするため、そのワープがデッドロックし、ワープがループしているスレッドを実行し続けることです。ロックが進行するのを防ぎます。

編集

改訂されたペーストビンに基づいて、次のようなものをお勧めします。

bool done = false;
while (!done) {
    if ((done = (imageAtomicExchange(img2D_0,coord,1u)==0))) {
        // guarded operations
                 :
        imageStore(img2D_0, coord, 0);
    }
}

これにより、ロックされた変更がすでに完了しているスレッドが除外されるため、ワープ ループのデッドロックが回避されます。1 つのスレッドだけがそのロックを取得できる場合、そのスレッドは進行します。

于 2012-08-04T19:16:06.080 に答える