Dlaczego bariera synchronizuje pamięć współdzieloną, gdy nie działa memoryBarrier?
Poniższe shader obliczeniowy GLSL po prostu kopiujeinImage
dooutImage
. Pochodzi z bardziej złożonego przebiegu przetwarzania końcowego.
W pierwszych kilku liniachmain()
, pojedynczy wątek ładuje 64 piksele danych do wspólnej tablicy. Następnie po synchronizacji każdy z 64 wątków zapisuje jeden piksel na obrazie wyjściowym.
W zależności od sposobu synchronizacji otrzymuję różne wyniki. Pierwotnie myślałemmemoryBarrierShared()
byłoby poprawne połączenie, ale daje następujący wynik:
który jest taki sam, jak brak synchronizacji lub użyciamemoryBarrier()
zamiast.
Jeśli używambarrier()
, Otrzymuję następujący (pożądany) wynik:
Pasek ma szerokość 32 pikseli, a jeśli zmienię rozmiar grupy roboczej na mniejszą lub równą 32, otrzymam poprawne wyniki.
Co tu się dzieje? Czy nie rozumiem celumemoryBarrierShared()
? Dlaczego powinieneśbarrier()
praca?
#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]);
}