Short Question: How can i integrate a buffer variable in a compute shader over each pixel i.e. how can i ensure memory coherence in such a case?
Long Question: I've written a deferred renderer with hdr and i want to implement automatic exposure. For that purpose i orignally used mipmapping, but that is not very performant and i want to improve my knowledge about compute shaders. So i tried to write a compute shader that approximates the average luminance of a image (approximation in the sense that i don't process every pixel but e.g. only 64 x 36 samples).
That would require me to accumulate the luminance of each pixel i.e. of each shader invocation. So i created a buffer which holds my luminance value:
volatile layout(std430, binding = 0) buffer averageBlock{
float luminance;
} average;
BUT: there are no atomic operations for floats so i changed it to
uint luminance[10];
Were each entry holds a part of the luminance (i.e. the first pixel writes to entry 0, the second to 1, ... the tenth to 0, ...) to increase the value range. I then mapped the float values to ints (multiplied them with 280, since that uses the available memory range nearly completly in the edge case were everything as a luminance of 1).
I then accumulated the values with:
uint discl = uint(lum * 280.0);
int slot = int(mod(gl_GlobalInvocationID.x, 10));
memoryBarrierBuffer();
atomicAdd(average.luminance[slot], discl);
memoryBarrierBuffer();
barrier();
But it seems that this also leads to visibility problems, since when i set lum
to a certain value, only a random proportion of that value is present after barrier()
(maybe because between those memoryBarrier calls the atomic adds don't see the changed values of the other ones).
So how do i do this correctly? Thanks for your help!