14

次の GLSL 計算シェーダーは、単純に にコピーinImageoutImageます。これは、より複雑な後処理パスから派生しています。

の最初の数行ではmain()、1 つのスレッドが 64 ピクセルのデータを共有配列にロードします。次に、同期後、64 個のスレッドのそれぞれが 1 つのピクセルを出力画像に書き込みます。

どのように同期するかによって、異なる結果が得られます。当初memoryBarrierShared()は正しい呼び出しだと思っていましたが、次の結果が生成されます。

非同期の結果

memoryBarrier()これは、同期を行わないか、代わりに使用するのと同じ結果です。

を使用するbarrier()と、次の (望ましい) 結果が得られます。

ここに画像の説明を入力

ストライピングの幅は 32 ピクセルです。ワークグループのサイズを 32 以下に変更すると、正しい結果が得られます。

何が起きてる?の目的を誤解していmemoryBarrierShared()ますか? なぜbarrier()機能する必要があるのですか?

#version 430

#define SIZE 64

layout (local_size_x = SIZE, local_size_y = 1, local_size_z = 1) in;

layout(rgba32f) uniform readonly  image2D inImage;
uniform writeonly image2D outImage;

shared vec4 shared_data[SIZE];

void main() {
    ivec2 base = ivec2(gl_WorkGroupID.xy * gl_WorkGroupSize.xy);
    ivec2 my_index = base + ivec2(gl_LocalInvocationID.x,0);

    if (gl_LocalInvocationID.x == 0) {
        for (int i = 0; i < SIZE; i++) {
            shared_data[i] = imageLoad(inImage, base + ivec2(i,0));
        }
    }

    // with no synchronization:   stripes
    // memoryBarrier();        // stripes
    // memoryBarrierShared();  // stripes
    // barrier();              // works

    imageStore(outImage, my_index, shared_data[gl_LocalInvocationID.x]);
}
4

1 に答える 1