Too Many If Statements in Fragment Code?

I’m writing fragment shaders using the high level language and seem to have reached a point where my shader stops working and returns empty pixels.

Normally when the shader is broken due to a compilation error I get all white output and errors in the info log. However, in this case the info log is empty and the render just returns nothing (0,0,0,0).

My shader has a series of if-else statements which in turn each call a function for returning a float value. Each part of the code works fine, but it seems that I have reached a limit for the number of if statements allowed. If I remove the last if, the shader works fine. If I put one more if in then it all breaks again.

Maybe it is not the number of if statments, but some other problem. It does not seem to be a syntactical error, because otherwise I would expect to get a compilation error in the info log.

I’m attaching my entire shader code in the hopes that someone can figure out what may be happening. For me, the shader works fine if I remove the last if statement if(which == kColorChannel_YuvV)

				const int kColorChannel_RGB		= 1;
				const int kColorChannel_Null1		= 2;
				const int kColorChannel_Red		= 3;
				const int kColorChannel_Green		= 4;
				const int kColorChannel_Blue		= 5;
				const int kColorChannel_Alpha		= 6;
				const int kColorChannel_Luminance	= 7;
				const int kColorChannel_Average	= 8;
				const int kColorChannel_Lightness	= 9;
				const int kColorChannel_Hue		= 10;
				const int kColorChannel_Saturation	= 11;
				const int kColorChannel_Cyan		= 12;
				const int kColorChannel_Magenta	= 13;
				const int kColorChannel_Yellow		= 14;
				const int kColorChannel_Black		= 15;
				const int kColorChannel_LabL		= 16;
				const int kColorChannel_LabA		= 17;
				const int kColorChannel_LabB		= 18;
				const int kColorChannel_YuvU		= 19;
				const int kColorChannel_YuvV		= 20;
				float Alpha(in vec4 color) {
					return color.a;
				}
				float Red(in vec4 color) {
					return color.r;
				}
				float Green(in vec4 color) {
					return color.g;
				}
				float Blue(in vec4 color) {
					return color.b;
				}
				const float LumaR = 0.3058824;
				const float LumaG = 0.5921569;
				const float LumaB = 0.1019608;
				float Luminance(in vec4 color) {
					return (color.r * LumaR) + (color.g * LumaG) + (color.b * LumaB);
				}
				float Lightness(in vec4 color) {
					return (min(min(color.r, color.g),color.b) + max(max(color.r,color.g),color.b))/2.0;
				}
				float Average(in vec4 color) {
					return (color.r + color.g + color.b) / 3.0;
				}
				float Hue(in vec4 color) {
					return 0.75;
				}
				float Saturation(in vec4 color) {
					return 0.75;
				}
				float Cyan(in vec4 color) {
					return (1.0 - color.r);
				}
				float Magenta(in vec4 color) {
					return (1.0 - color.g);
				}
				float Yellow(in vec4 color) {
					return (1.0 - color.b);
				}
				float Black(in vec4 color) {
					return (1.0 - max(max(color.r,color.g),color.b));
				}
				float LabL(in vec4 color) {
					return 0.75;
				}
				float LabA(in vec4 color) {
					return 0.75;
				}
				float LabB(in vec4 color) {
					return 0.75;
				}
				float YuvU(in vec4 color) {
					return 0.75;
				}
				float YuvV(in vec4 color) {
					return 0.75;
				}
				float Channel(in vec4 color, in int which, in bool premult, in bool invert) {
					float value = 0.5;
					if(which == kColorChannel_RGB) {
						value = Average(color);
					} else
					if(which == kColorChannel_Red) {
						value = Red(color);
					} else
					if(which == kColorChannel_Green) {
						value = Green(color);
					} else
					if(which == kColorChannel_Blue) {
						value = Blue(color);
					} else
					if(which == kColorChannel_Alpha) {
						value = Alpha(color);
					} else
					if(which == kColorChannel_Lightness) {
						value = Lightness(color);
					} else
					if(which == kColorChannel_Average) {
						value = Average(color);
					} else
					if(which == kColorChannel_Luminance) {
						value = Luminance(color);
					} else
					if(which == kColorChannel_Hue) {
						value = Hue(color);
					} else
					if(which == kColorChannel_Saturation) {
						value = Saturation(color);
					} else
					if(which == kColorChannel_Cyan) {
						value = Cyan(color);
					} else
					if(which == kColorChannel_Magenta) {
						value = Magenta(color);
					} else
					if(which == kColorChannel_Yellow) {
						value = Yellow(color);
					} else
					if(which == kColorChannel_Black) {
						value = Black(color);
					} else
					if(which == kColorChannel_LabL) {
						value = LabL(color);
					} else
					if(which == kColorChannel_LabA) {
						value = LabA(color);
					} else
					if(which == kColorChannel_LabB) {
						value = LabB(color);
					} else
					if(which == kColorChannel_YuvU) {
						value = YuvU(color);
					} else
					if(which == kColorChannel_YuvV) {
						value = YuvV(color);
					}
					return value;
				}
				uniform int mode;
				uniform sampler2DRect inLayer;
				void main(void) {
					vec4 inp = texture2DRect(inLayer, gl_TexCoord[0].st);
					float channelVal = Channel(inp, mode, false, false);
					gl_FragColor = vec4(channelVal, channelVal, channelVal, 1.0);
				}

Perhaps I’m missing some other concept to writing fragment shaders? Is there a limitation to the length of shader code? Should I be breaking it up into smaller chunks for the compiler? My code will get much larger than this. Thanks for any help.

Walker

Can you give details on hardware/driver version you are working on ?

Unless you are using pixel shader 3.0 then all of those contitional statements will be executed, that may hit the instruction limit on your card.

Whatever the case, you should break the shader up into multiple shaders, one for each mode.

It is crazy to switch on a uniform per pixel, when the value will not change over the surface.

I assume this is a screen filter, which at say 800x600 would involve doing the if-else test 480,000 times in the shader, when it could be done just the once if you put it in your code.

This will definitely need to work with a bunch of different cards. So it looks as though I need to rethink the problem. How do people normally organize a huge list of algorithms that need to be accessed in different combinations? I could dynamically build a shader string based on the needs of the situation. But is there a better way?

Thanks for the help.

The quickest way would be to simply create a shader for each process, pushing your if-else loop off the GPU.

Obviously this can get pretty ugly as you could end up with a whole bunch of tiny shader files everywhere.

To help manage this, you could write a pre-processor for your shader files that creates a shader for every possible conditional outcome.

Thanks for the suggestion. For now I am just building the shader dynamically like a script. So my render code will make all the high-level decisions and custom build a shader from modular parts. This I am hoping will keep the shader code to a minimum size with each render invocation without limiting the possibilities. For complex shaders I may need to run it in passes on intermediate image buffers.

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