IF statement causes FPS drop!

I’ve got a strange issue here. I’m using a custom map format, in which I may have one or more textures per face.
I’m willing to have my shader render the right textures according to the ones associated to the current face, i.e. one face has texture + lightmap, one other face has texture + texture + lightmap… Here’s what I do:

In my OpengGL C++ code:

// send used layers to shader
GLfloat lay[] =
	(GLfloat)((dmf.materialList[polyPtr->materialIndex].layers[0].type != DMF_LAYER_TYPE_UNUSED
		&& dmf.materialList[polyPtr->materialIndex].numLayers > 0)?1.0f:0.0f),
	(GLfloat)((dmf.materialList[polyPtr->materialIndex].layers[1].type != DMF_LAYER_TYPE_UNUSED
		&& dmf.materialList[polyPtr->materialIndex].numLayers > 1)?1.0f:0.0f),
	(GLfloat)((dmf.materialList[polyPtr->materialIndex].layers[2].type != DMF_LAYER_TYPE_UNUSED
		&& dmf.materialList[polyPtr->materialIndex].numLayers > 2)?1.0f:0.0f),
	(GLfloat)((dmf.materialList[polyPtr->materialIndex].layers[3].type != DMF_LAYER_TYPE_UNUSED
		&& dmf.materialList[polyPtr->materialIndex].numLayers > 3)?1.0f:0.0f),

my_sampler_uniform_location = graphics->GetVariable("layers");
glUniform4fvARB(my_sampler_uniform_location, 1, lay);

in my GLSL fragment shader code:

varying vec4 lightDir;
varying vec3 normal;

uniform sampler2D tex0, tex1, tex2, lightmap;
uniform vec4 layers;

void main()
	vec3 n,l,halfV;
	vec4 texel, texlight;
	float NdotL,NdotHV;
	float att;
	float spotEffect;
	float denominator;
	// retrieve material parameters ***************************************************************
	vec4 color = gl_FrontLightModelProduct.sceneColor;
	vec4 ambient = gl_FrontLightProduct[0].ambient;
	vec4 diffuse = gl_FrontLightProduct[0].diffuse;
	vec4 specular = gl_FrontLightProduct[0].specular;

	// compute light ******************************************************************************
	n = normalize(normal);
	l = normalize(lightDir.xyz);
	denominator = lightDir.w;

	NdotL = max(dot(n,l),0.0);

	if (NdotL > 0.0)
		spotEffect = dot(normalize(gl_LightSource[0].spotDirection.xyz), normalize(-l));
		if (spotEffect > gl_LightSource[0].spotCosCutoff)
			spotEffect = pow(spotEffect, gl_LightSource[0].spotExponent);
			att = spotEffect * denominator;
			color += att * (diffuse * NdotL + ambient);
			halfV = normalize(gl_LightSource[0].halfVector.xyz);
			NdotHV = max(dot(n,halfV),0.0);
			color += att * specular * pow(NdotHV, gl_FrontMaterial.shininess);
		color = vec4(-max(NdotL, -1.0), 0.0, 0.0, 1.0);

	// apply texture ******************************************************************************
	if(layers[0] == 1.0)
		texel = texture2D(tex0,gl_TexCoord[0].st);
		color *= texel;

	if(layers[1] == 1.0)
		texel = texture2D(tex1,gl_TexCoord[1].st);
		color *= texel;
	if(layers[2] == 1.0)
		texel = texture2D(tex2,gl_TexCoord[2].st);
		color *= texel;

	if(layers[3] == 1.0)
		texlight = texture2D(lightmap,gl_TexCoord[3].st);
		color *= texlight;
	// set fragment color *************************************************************************
	gl_FragColor = color;

I don’t post the VS as it’s quite straightforward, I just set the gl_TexCoord[].

This code gives me horrendous FPS. When I disable all texture units but the first (I just keep the tex0 and comment out the other cases), it’s the same. BUT when I comment the IF statement (if(layers[0] == 1.0)) to force the application of the first texture inconditionally, I get the good framerate I used to have. As the if statement is always assumed to be true (I always have at least one texture applied), I don’t understand why it causes such a drop. The layers variable is a uniform all the same, it shouldn’t change per fragment, but per primitive. :confused:

Anybody has a clue? Or maybe my means of selecting the textures in my shader are bad? What will I have to do when I’ll add the lighting (I may have up to 7 lights in my scene, in addition to the one you can see in my FS), as not all the light may be enabled at the same time. I can’t render them by IF statements as I have a SM2.0 hardware. I hope I don’t have to write a shader for each case, i.e. 7 shaders for 7 lights…

Thanks for your attention :slight_smile:

Originally posted by hardtop:

I hope I don’t have to write a shader for each case, i.e. 7 shaders for 7 lights…

Driver is not required to optimize the if operations out and it is likely that it will never do it for ordinary float vectors because they may contain arbitrary values and it would be time consuming, hard an inpractical to do analysis of your shader to find the special cases and keeping track of them.
Try to use the bvec4 uniform type instead of vec4.

If that does not work you can always use one shader source to generate several shaders you will select from during the runtime by using compile time constants prepended to the shader source during compilation (e.g. const bvec4 layers = bvec4( true, false, false, false ) ) instead of using the uniforms.

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.