次の GLSL 計算シェーダーは、単純に にコピーinImage
しoutImage
ます。これは、より複雑な後処理パスから派生しています。
の最初の数行では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]);
}