4 ms·
The classic explanation is "divergence", and it goes something like this: On GPUs, branching is tricky because the same code is evaluating many pixels at the sa
by Jasper_ 7y ago
The classic explanation is "divergence", and it goes something like this: On GPUs, branching is tricky because the same code is evaluating many pixels at the same time. If half of those pixels go one way, and half of those pixels go another way, the GPU has to run both pieces of code, with half the results "masked out" [1]. This is why branchless code tends to be more idiomatic in shading languages.
You might ask how max() and min() are implemented with a branchless model. Sometimes the GPU has a native instruction for it, and a "sufficiently stupid compiler" might not be able to recognize the branch and turn it into the corresponding max/min.
The modern reality is that most all GPUs all have conditional move instructions which allow them to do some amount of branchless conditional across vector lanes like "x >= 1.0 ? x : 0.0;" without incurring the penalty of true flow control.
However, some are still uncomfortable with trusting the compiler to recognize and support this, especially on mobile chipsets with poor quality compilers. Others still just prefer the coding style of the idiomatic branchless expressions, since it's what they're used to.
[1] Footnote: On super old GPUs, like those in the Direct3D 8 era, flow control was emulated completely through branchless systems. The native machine ISA was something like a series r=lerp(A,B,C)+D instructions, and flow control amounted to clever abuse of this paradigm -- lerping to 0.0 or 1.0 can get you a form of conditional move.