Unbound sampler declaration andd GLSL shader code

Hi,

I have the following code:

uniform int isBound;
uniform usampler2D myImage;

if (isBound == 1)
    do something with myImage, calls texelFetch;
else
    do something without using myImage;

Is this allowed to leave sampler uniforms effectively not bound to anything, at certain times?
Sorry if this question seems obvious but I have a bug whereby a single texelFetch, not executed in my code (because isBound is 0), causes my shader to freeze. Although never executed, commenting out the texelFetch call indeed removes the issue. I suspect either a GLSL compiler issue as my shader code is very complex (> 2000 lines), or a driver issue. Even more likely, a problem with my code :wink:

Cheers,
Fred

The cause is that under certain conditions, all branches of a conditional statement are evaluated, no matter what. In any case, don’t program stuff that may lead to undefined behavior.

My isBound uniform value is 0 in all situations (it’s pretty much a constant), and the problem remains. That’s what I don’t understand, as I know the GPU just cannot execute the code I don’t want it to execute.

In GLSL 4.x, expressions which only involve constants and uniform variables are “dynamically uniform”. Using a dynamically-uniform expression as the condition in an “if” statement should ensure that the other branch is never executed. Earlier versions don’t require this; so both branches can be executed (unless the condition only involves constants). If you need to rely upon the 4.x behaviour, use “#version 400” or above.

The GLSL version I’m using is #version 420 compatibility
This problem really is driving nuts.
The offending code is in a fragment shader. If I do:

if (gl_FragCoord.x > 10000)
texelFetch();
else
do something else;

the problem occurs. Although there is absolutely no chance texelFetch() gets executed - if I comment it out, the problem goes away. I can’t find out why there is a problem all of a sudden when I add a texelFetch call …that is never executed!

My bad. Wasn’t thinking. In the above case, I guess there’s just no way control flow could take another path.

EDIT:

I’d say that this is actually non-uniform control flow - unless the implementation can cleverly deduce that gl_FragCoord.x can never be greater than 10000. Does the problem persist if you use a constant expression?


if (false)
  texelFetch();
else
  do something else;

with if (false), the problem disappears, but I suspect it’s because the GLSL compiler discards the compilation of the whole (false) condition block. (GLSL compilers are pretty good at this).

With if (isBound) the problem remains.

isBound is a vec3 in my code, eg.

uniform vec3 isBound;

I use isBound.r which is 0.0 in all cases. At runtime, I do if (isBound.r == 1.0), which is never true.

GClements, is what you said valid for vec3 as well? Just a thought.

I found with the AMD drivers, if I left a samplerBuffer unbound it would crash even if I didn’t sample from it. I ended up generating 3 dummy TBOs (float, int, uint) and binding those to the samplerBuffers were “not active”. Perhaps you could do something similar with a dummy unsigned 2D texture.

I’m using an nvidia GTS 450 card (drivers 311.06) but I suspect it could be the kind of problem you mention.

It’s tricky in my code to have a buffer bound at all times as the isBound==true fragment execution is acting as an add-on. The original drawing code in the fragment shader doesn’t want to bother with the image2D, as it is not affected by it.

The type doesn’t matter.

Because GLSL assumes (and GPUs implement) a SIMD architecture, a conditional is typically executed by executing both branches but ignoring state changes in whichever branch wasn’t selected by the condition. But if a non-selected branch results in an error, it can still effect the overall execution of the shader.

Ok on that part. int or vec3, who cares, they’re both uniform values. Fine.

GPUs do not have a branch prediction unit, do they? Therefore they don’t speculatively execute the code of the wrong branch.
Even if my condition is “if (gl_FragCoord.x > 10000)” which is not a dynamic-uniform (as you said), I don’t see any reason why the GPU would choose to evaluate the wrong block of code. On a CPU it’s because of the branch prediction unit (or maybe because of out-of-order execution), but on a GPU, I don’t get it.

I can’t find anywhere on the web a paragraph that says that shader samplers MUST be bound.

EDIT: I only found your post here: Check for invalid Sampler - OpenGL - Khronos Forums

I have been using dynamic subroutines to choose whether to load the fragment colour from different sources including a uniform, texture, multiple textures etc. If I am, for example, loading from a uniform, I do not bind a texture and I have had no problems with either the AMD nor nVidia drivers. One of my subroutines even has if tests inside it where some paths will load a texture and other won’t.

You are right, shader subroutines are a more appropriate way of instructing the driver which block of code is or is not used at runtime, and therefore the driver might not complain about unbound samplers if it knows the block of code does not access the (unbound) samplers.
Still, I would appreciate if the GL spec specified that unbound samplers are indeed valid or not, and under which conditions/circumstances.

Are you absolutely sure that the sampler wasn’t active? Otherwise I would suggest that this is a driver bug because active samplers should be properly detected at link time.

fred_em: is there any chance you can factor your shader into two separate shaders? don’t underestimate the fact that you do additional function calls with subroutines.

thorka is right to suggest separate subroutines where practical. My benchmarking (while not as scientific as I might like) showed dynamic subroutines do not come for free. I only use them in shaders that have a lot of branching options that the user can change at their whim and so in the program logic it is easier to dynamically create the shader.

Separate shaders. :wink:

sorry:mad:

It was the same situation as fred_em originally posted - a texelFetch() in a conditional clause that was never taken due to a uniform-valued condition (if(uniform_val == 0) texelFetch()). The sampleBuffer without a corresponding TBO bound crashed, likely due to predicated execution of the fetch/assignment. I was suggesting that leaving a unbound texture unit for an active sampler is not terribly safe.

I was suggesting that leaving a unbound texture unit for an active sampler is not terribly safe

Although quite easily deducible that this is undefined behavior, the GL/GLSL specs actually don’t seem to state as much and certainly don’t warn of potential program termination. The question is, is this worth being mentioned in the spec?