Reputation: 11732
Quote from here:
When this function returns, the results of any memory stores performed using coherent variables performed prior to the call will be visible to any future coherent memory access to the same addresses from other shader invocations.
Ok, say I want to do this in a frag shader:
void main() {
ivec2 fc = ivec2(gl_FragCoord.xy);
vec4 f = imageLoad(image, fc);
f *= 2;
imageStore(image, fc, f);
}
I believe this doesn't require a memoryBarrier() between the imageLoad and the imageStore. And the following does:
out vec4 OUT;
void main() {
ivec2 fc = ivec2(gl_FragCoord.xy);
imageStore(image, fc, vec4(5));
vec4 f = imageLoad(image, fc);
OUT = f * 2;
}
Do I understand GLSL's memoryBarrier correctly?
Upvotes: 0
Views: 2304
Reputation: 474336
The scenarios you've posted here are reliant on unstated and unknown information, things you probably assume about the nature of your rendering process, which you didn't state on the assumption that they don't matter. Even though they very much do, as we will see here.
So, let's start there. If we assume that you are issuing rendering calls such that no two fragments will ever have the same gl_FragCoord
values (and thus, no two shader invocations will ever attempt to write to the same location), then both cases are well-defined and do not need memory barriers. Yes, really; from the GLSL specification:
Within a single shader invocation, the visibility and order of writes made by that invocation are well-defined.
See, the in-shader memoryBarrier
functions and coherent
qualifiers are about reading values written by separate shader invocations. Reading a value that your invocation wrote is not a problem. So you don't even need coherent
here, in either case.
Hence the need for the initial assumption. Because, if that assumption goes away, if there is ever any overlap between fragments, such that two invocations will attempt to write to the same location, both cases are undefined. And memoryBarrier
will not change that. Why?
Because two invocations from the same stage have no ordering between them. GLSL makes no guarantees about when any two invocations in the same stage execute. They might execute at the same time, or a fragment from a later primitive might execute before one from an earlier one despite them being out of order, or anything of the kind.
memoryBarrier
and similar functions only matter for cases where shader invocations have some kind of order dependency between them. This could be compute or tessellation control shaders issuing a barrier
call, or it could be a vertex shader who wrote data that a fragment shader for the primitive associated with that vertex reads, or other cases where there is a clear ordering between the invocations.
Two fragment shader executions in the same rendering command (or different rendering commands for that mater) have no ordering between them. So barriers aren't going to help.
You don't want multiple fragment shader invocations trying to write to the same memory. Not unless they're in different rendering commands with a proper glMemoryBarrier
call between them.
Upvotes: 3