OpenGL Compute Shader and conditional statements

Started by Kai, November 08, 2014, 21:55:38

Previous topic - Next topic

Kai

Hi there,

for three days straight I have been wondering about why some small piece of GLSL Compute Shader code was not working correctly. I also reimplemented it in C and ran it on the CPU and everything worked fine. Now, with shaders there can be hundreds of issues like memory layout in some accessed global buffer, memory synchronization issues, etc... etc..., but that all was not the case. :-)

I just want to share with you what was the issue for me and whether anyone of you stumbled on the same issues.
Btw. I used a Nvidia Quado K2000M and the Nvidia driver 340.84 for that, if that might be a driver issue.

The shader uses a Shader Storage Buffer Object (SSBO) from which it reads a binary tree, described via a struct "node":

struct node {
  int left;
  int right;
}

buffer Tree {
  node nodes[];
}


The critical part of the shader, which gave me headaches for days, contains a while loop like such:

node n = ...;
while (conditionDependingOn(n)) {
  if (predicate(n.left)) {
    n = nodes[n.left];
  } else if (predicate(n.right)) {
    n = nodes[n.right];
  } else {
    break;
  }
}


This code accesses the binary tree structure, where in each node the "left" and "right" fields contain the index within the SSBO of that respective child. It evaluates some predicate function which (apart from other things) depend on 'n'. Depending on the result, 'n' is reassigned either its left or its right child with an indexed access in the SSBO.

That code would not work, whatever I tried. It compiled fine without errors or warnings, but it behaved as if the first branch of the conditional was executed regardless of whether its predicate was true or not. Now, I rewrote it to do the following:

node n = ...;
while (conditionDependingOn(n)) {
  int childIndex;
  if (predicate(n.left)) {
    childIndex = n.left;
  } else if (predicate(n.right)) {
    childIndex = n.right;
  } else {
    break;
  }
  n = nodes[childIndex];
}


The difference here is that 'n' is not reassigned in the conditional, but instead the index 'childIndex' is stored with which the node is then retrieved outside of the conditional.

And THAT CODE WORKED... I have never seen such a strange behaviour!
Have you? ;-)

It seems that the shader invocation evaluates both branches (not only the predicate but also the body!) of the conditional.