Home > Enterprise >  Strange GLSL if condition behavior
Strange GLSL if condition behavior

Time:12-16

I am having a strange issue with a GLSL fragment shader on an 2020 Intel MacBook Pro with Intel Iris Plus graphics and MacOS Ventura 13. It seems that when I use an if block and don't have an else block, then the if block always executes.

I have stripped out everything else from the shader to validate it isn't something that is NaN/INFINITY, divide by zero, or something similar. I've also seen some people mention to not use == with float and even with only > or < it is still occurring. With everything stripped out the below code is what I am running:

#version 400
layout(location = 0)out vec4 gc_color;
void main(){
    float stackptr = -1.0;
    if(stackptr > 0.0) {
        gc_color = vec4(1.0, 1.0, 0.0, 0.0);
    } // this always runs the if block
}

When I run this, the output is always yellow no matter what I update stackptr to. The condition seems to always evaluate to true. But also when I update it with an else block like below it seems to work correctly.

if(stackptr > 0.0) {
    gc_color = vec4(1.0, 1.0, 0.0, 0.0);
} else {
    gc_color = vec4(1.0, 0.0, 1.0, 0.0);
} // this runs correctly

This will change the color based on what the value of stackptr is as you would expect.

I have also tried replacing "stackptr" in the condition with the value (-1.0) and that works as expected. So it seems like an issue with the variable being evaluated.

Has anyone seen this behavior before? Is it possibly a driver issue? I'll try it with an Nvidia GPU soon on Windows to check.

There is a similar issue here but no one has given an answer.

CodePudding user response:

You observe undefined behaviour here. In your first shader you don't assign gc_color if condition is false, you can see everything. Let's consider how it can be processed by shader's compiler and GPU.

  1. Shader's compiler eliminates condition, since stackptr is a constant (and it can be deduced in some cases). Result would be arbitrary, gc_color is never set.
  2. Dynamic branching. Yellow color is assigned when condition is true, otherwise it's undefined (any color). Dynamic branching implies branch prediction and drop part of command's pipeline in case of miss. It can be less efficient than static branching for simple conditions.
  3. Static branching. We calculate both branches (true and false) and choose one of them when condition is resolved. There are some preconditions for it (e.g. there should not be side-effects in branches), but your shader looks eligible for it. Some implementations execute true branch unconditionally. When condition is known and result is true, we can do a jump to a command after false block. If result is false, we allow to execute commands in false branch that rewrite what was set in true branch. In you case there is no false branch, so nothing is rewritten and you see yellow came from true branch.
  • Related