Problem with if conditions

Hi,

I recently stumbled upon a problem with if conditions in a GLSL fragment shader.

The simplest shader to reproduce is as follows:

uniform int dummy; // always set to 1 in the client application

void main()
{
	vec4 colors[1];
	colors[0] = vec4(0.0, 1.0, 0.0, 1.0);

	int planeIndex = 0;

	if(dummy > 0)
		planeIndex = 0;	

	gl_FragColor =  colors[planeIndex];
}

When I run this shader on a GeForce Go 7400 (OpenGL 2.1, GLSL 1.2, Shader Model 3) it crashes (the shader, not the card). When it’s run on Shader Model 4 hardware, everything is fine. Testing on SM 3 machines besides the mentioned one is not possible due to a lack of the appropriate hardware.
After some investigation it seems as if the use of planeIndex after the if statement is the important point.

In case you dare to run an unknown application, I have uploaded a little test tool that uses this shader. http://rapidshare.com/files/266569351/shadertest.7z
(blue is intial color, green after clicking means shader was successful, red means the shader failed to run)

Is this problem in any way known behavior or likely to be a platform/hardware error on my side?

Any help appreciated.

Thanks in advance,
Shunter

Maybe the problem is not the “if”, but the dynamic indexing in “colors[planeIndex]”.

Try something like:
gl_FragColor = (dummy > 0) ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);

Edit: If you need dynamic indexing, you can store your data in textures and use dynamic texture coordinates.

on GF6200 drv 185.85 it shows red
on 8800GT drv 185.85 is shows green
on 8800GT drv 190.56 is shows green

(driver bug?)

Well, it seems as if the problem is some weird scope behavior. When I touch planeIndex in an if statement and try to access it afterwards, the shader fails. So the ternary operator should work flawlessly.

Thanks for your testing information. So up to now, all Shader Model 3 cards are red, all SM4 cards are green.

Thanks to an older catalyst driver on a Radeon I might have found the source of the problem. Instead of just crashing, the card gave me an error.
“Not supported temporary array indirect index”
It seems as if GLSL 1.2 does not allow indirect array indexing. On newer nVidia cards this problem is circumvented completely but on older cards (like my 7400 GO) it seems that using a non const int as an index basically works because the compiler can optimize the array access when the variable isn’t dynamically changed. But the if clause in the shader example is not resolvable during compile time, so there is now way for older cards to convert the indirect access into a direct one.

“But the if clause in the shader example is not resolvable during compile time, so there is now way for older cards to convert the indirect access into a direct one.”

#ifdef that block of code and supply the define via pre-source string. if GLSL <= 1.20 than alter the behavior.

“But the if clause in the shader example is not resolvable during compile time, so there is now way for older cards to convert the indirect access into a direct one.”

Also, IIRC “step( condition ) *” can be useful for masking if conditions from the compiler.

I’ve also come across this problem on a NV 8600M on
a Macbook Pro. I wasn’t able to indirectly index a
texture matrix in my vertex shader. E.g.,

#version 120

uniform int unit;

void main()
{
// this fails: cannot use ‘unit’ as index
gl_TexCoord[0] = gl_TextureMatrix[unit] * gl_Vertex;

//...

}

Does anyone know of a way to get around this?

.rex

  1. A brute-force way:

if(unit == 0):
 mx = gl_TextureMatrix[0];
else if(unit==1):
 mx = gl_TextureMatrix[1];
else mx = gl_TextureMatrix[2];

  1. Form a vec4 as an array of floats, which have only 1 in the index ‘unit’ and 0 in other values. Than mix all gl_TextureMatrix’es using this coefficients… This vector can be constructed in the following way:

vec4 a = (0.0,1.0,2.0,3.0), b = vec4(0.01), c = vec4(unit)
vec4 kf = step(a-b, c) * step(c, a+b);

then:


mat4 mx = gl_TM[0]*kf.x + gl_TM[1]*kf.y + gl_TM[2]*kf.z + gl_TM[3]*kf.w;
gl_TexCoord[0] = mx * gl_Vertex;