Is the use of barrier()
permitted following, but outside of, divergent flow control?
Within an OpenGL 4.00 compliant Compute Shader, I'm doing some work that involves a divergent (ie not dynamically uniform) branch statement. Later in the same shader, I need to synchronize execution of all the invocations within that work group for the purposes of memory access. This is also good for efficiency, as I'd like them all back in lock-step with each other. However, after consulting the khronos.org wiki and refpages, I'm not clear on whether what I want to do is valid as per the standard (regardless of whether it works in practice).
From this page, we see that:
Calls to barrier may not be placed within any control flow.
From this page, we see that:
barrier()
can be called from flow-control, but it can only be called from uniform flow control. All expressions that lead to the evaluation of abarrier()
must be dynamically uniform.
First, the apparent contradiction regarding flow control. I'm assuming that it is only divergent (within a work group) flow control that is disallowed?
Second, there seems to me to be some ambiguity here regarding calls to barrier()
that occur after divergent flow control. Importantly, note again the assertion that "All expressions that lead to the evaluation of a barrier() must be dynamically uniform." Does this mean leading up to, or ... ? Some examples to help illustrate my confusion.
void main() {
// ... do some work here ...
barrier(); // valid use case
// ... do some more work ...
}
void main() {
if (IS_BEST_WORK_GROUP) { // dynamically uniform within work group
// ... do some work here ...
barrier(); // valid use case
// ... do some more work ...
}
}
void main() {
if (IS_BEST_INVOCATION) { // divergent within work group
// ... do some work here ...
barrier(); // this is illegal
// ... do some more work ...
}
}
void main() {
if (IS_BEST_INVOCATION) { // divergent within work group
// ... do some work here ...
}
barrier(); // is this allowed?
// it occurs after, but outside of, a divergent branch statement
// ... do some more work ...
}
The only declarative source is the GLSL Specification.
Section 8.16 states:
For tessellation control shaders, the barrier() function may only be placed inside the function main() of the tessellation control shader and may not be called within any control flow. [...]
For compute shaders, the barrier() function may be placed within flow control, but that flow control must be uniform flow control.
Your Example 4 is perfectly fine since the call to barrier
is not in any control flow. It doesn't matter what you do before the barrier as long as you make sure that all shader invocations reach the same barrier.