Jump to content

  • Log In with Google      Sign In   
  • Create Account


The uniform qualifier and for loop


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
8 replies to this topic

#1 Michael Wojcik   Members   -  Reputation: 163

Like
0Likes
Like

Posted 24 November 2011 - 01:19 AM

Hello all.

I checked out the glsl specs and looked in google, but surprisingly, I can't seem to find the answer for this question. Here goes..

Can I have a uniform variable be used like this in my for loop's condition expression?

	for(int i = 0; i < u_texCount; i++)
	{
 		//.....
	}

where u_texCount is declared like so...

uniform int u_texCount;

I am currently doing this right now, but my shader freaks out. When I replace u_texCount with say, 2, it works.
Generalist Game Developer and Cofounder at Voidseer Realms

Sponsor:

#2 samoth   Crossbones+   -  Reputation: 4677

Like
0Likes
Like

Posted 24 November 2011 - 03:13 AM

Ugh... the answer would be "yes, and no, and yes, with caution". The GLSL specification does not say anything special about what you can put in a for loop (section 6.3), and it even explicitly allows loops that do not terminate (albeit with "implementation dependent" results).

In reality, there exists hardware that has no true dynamic control flow at all, hardware that has "some kind" of it, and hardware that has full dynamic control flow like a CPU would have.

When a shader is compiled, the compiler commits itself to the validity, much in the sense of a contract that says "I agree with this, it will work". That means it cannot decide that a shader is not valid at a later time, e.g. if you change a uniform (you could possibly change a loop counter from 5 to 5000000, which would be a desaster if the compiler must unroll that loop).

Therefore, in many cases, loop counters must be constant even if by the letter the spec does not require it, and it is generally a good idea to have them compile time constants (also because some, notably nVidia, implementations have been well-known in the past to recompile and relink shaders when some uniform is changed, sometimes only on "magic" values, and sometimes on who knows what).

#3 gdmarkou   Members   -  Reputation: 332

Like
0Likes
Like

Posted 24 November 2011 - 03:18 AM

The following code works just fine for me, even for a = 200000.
So, the next questions are:
a) What do you mean with "the shader freaks out" ? Doesn't compile? Incorrect result?
b) are you sure you are setting a value to u_texCount?
c) What's your hardware?

attribute vec3 in_pos;
attribute vec4 in_color;
varying vec4 v_color;

uniform int a;

uniform mat4 gc_mvp_matrix;

void main ()
{
	v_color = in_color;
	for (int x = 0; x < a; x++)
	{
		v_color.r += 0.01;
	}
	gl_Position = gc_mvp_matrix * vec4 (in_pos.x, in_pos.y, in_pos.z, 1.0);
}


#4 Michael Wojcik   Members   -  Reputation: 163

Like
0Likes
Like

Posted 24 November 2011 - 07:26 AM

Thanks for the replies.

What I mean by 'freak out' is that it compiles and links fine, but when my code is running and rendering the shader program, it draws sort of a lightshow instead of my texture. When I replace the uniform variable with a constant, I get my normal textures being rendered. So some things in GLSL from what samoth mentioned can be thought of as, it will compile for now, but it might not work. Good to know.
Yet it is interesting that gdmarkou code works. My video card is a NVIDIA GeForce GTX 260. I verified that the uniform is also being set.
I would prefer to make the iteration based on a uniform variable but I'll use constants if I must.
Generalist Game Developer and Cofounder at Voidseer Realms

#5 samoth   Crossbones+   -  Reputation: 4677

Like
0Likes
Like

Posted 24 November 2011 - 09:18 AM

So some things in GLSL from what samoth mentioned can be thought of as, it will compile for now, but it might not work. Good to know.


No, no! The opposite! The compiler either rejects your shader program with an error or it accepts it (compiles and links with no errors). If it accepts your shader, it is agreed that it must make sure it renders properly, independently of what you set as uniforms or what textures you bind. The implementation cannot just decide at will any time later that this promise won't be kept.

If your hardware cannot support something you ask from within your program (such as dynamic branching, some derivative or LOD functions, non-constant array indices, or whatever), then the compilation will fail. Though of course in principle, an implementation is allowed to silently fall back to software rendering too, but I don't think any kind-of-modern, halfway serious implementation ever does such a thing (Intel might, who knows?).

#6 Michael Wojcik   Members   -  Reputation: 163

Like
0Likes
Like

Posted 24 November 2011 - 02:14 PM

Okay, thanks for the clarification. Well, in my engine code side, I simply set the uniform to 1, for testing purposes. Still renders erroneously though. I suppose that might mean my hardware might not support it. I too saw that the specification made no specific rules about the concept.
Generalist Game Developer and Cofounder at Voidseer Realms

#7 Tasaq   Members   -  Reputation: 1211

Like
0Likes
Like

Posted 25 November 2011 - 08:53 AM

Okay, thanks for the clarification. Well, in my engine code side, I simply set the uniform to 1, for testing purposes. Still renders erroneously though. I suppose that might mean my hardware might not support it. I too saw that the specification made no specific rules about the concept.


I wanted to make a shader which will enable me to use a hell lot of lights, i passed the light number like you, so it should work. And also i passed the array of light postions (uniform vec4 lightpos[20]) to have up to 20 lights. everything was ok, then I wanted to make light a little bit more complex, adding some more arrays. I found out that there's a limit, which makes shader not compileable when it's exceded, duh:\
Anyway, when my light numbers was higher than size of array, my compiler also went nuts, what is logical because i exceded the array size. I think it is essential to tell us what you had in for loop, because it maybe that the counter isn't a problem at all :)

#8 Matias Goldberg   Crossbones+   -  Reputation: 3128

Like
0Likes
Like

Posted 25 November 2011 - 09:44 AM

Hi!

I just wanted to add that SM 3.0 capable video cards (I'm not sure about SM +4.0 running on OpenGL) such as GeForce 6 & 7 series have a couple limitations when doing for loops:

In theory, SM 3.0 adds dynamic branching and loops, therefore something like for( int i=0; i<100000; ++i ) should work. BUT, it's not that easy. For two reasons.


The first one, some stuff cannot be inside a branch. For example, something as simple as "constantExpression[i]" (constant register addressing/indexing) cannot be made inside a pixel shader while being in a dynamic branch; therefore the loop must be unrolled. This is true for DX9, not for DX10. OpenGL is a mistery to me.

My GeForce 8600 GTS has a MaxPixelShader30InstructionSlots of 4.096; which means that if the shader compiles into more than 4.096 instructions (a number very easy to achieve with an unrolled loop) it will fail. Of course, that's if I were using D3D9. I don't know what would happen in OpenGL (whether DX10 or DX9 specifications are used). Nonetheless, I'm 100% sure it will fail in a GeForce 6/7 because of hardware limitations. Note SM 3.0 has a minimum guaranteed of only 512 instruction slots (ATI Radeon X1000 series just have the minimum); while SM 4.0 has a minimum guaranteed of 65.535

Additionally, my GPU has a MaxPShaderInstructionsExecuted 65.535; which is a relatively high number and sane number and this counts instructions slots + for non-unrolled loops. Again, this is a limit for D3D9, but if you're using OGL, I don't know if works under DX9 or DX10 specs, or a mix of them. And again, a GF 6/7 will fail to execute more than 65.535 instructions in a non-unrolled loop because of HW limitations. Note in SM 4.0 there is virtually no limit of executed instructions in a for loop (unless unrolled, of course).


The second reason it may fail, Windows Vista (7 too?) has a very lame (OK; it's not that lame, it's really hard to solve the problem) way to tell if a GPU has stopped responding (due to HW failure or lock up, driver errors, etc) by just using a timeout and sending a heartbeat to the driver. If the GPU fails to answer the heartbeat in two seconds, the driver is ordered to shutdown the GPU and reset. This means very high values in your for loop will increase the likehood of getting a reset. This mechanism is explained here. Edit: Updated version here.



Cheers
Dark Sylinc

#9 Michael Wojcik   Members   -  Reputation: 163

Like
0Likes
Like

Posted 26 November 2011 - 09:58 PM

Thanks for the information. I'll post my fragment shader code since this is where I use the variable.

precision mediump float;
uniform vec3 u_colorMod;
uniform float u_opacity;
uniform sampler2D u_tex[2];
uniform int u_texCount;
uniform int u_blend[2];
varying vec2 v_texCoord0;
varying vec2 v_texCoord1;

//////////////////////////////////////////////////
// 					Functions   	//
//////////////////////////////////////////////////
vec4 performFragmentBlends(int blendIndex, vec4 srcFragment, vec4 destFragment)
{
	vec4 blendedColor = vec4(1.0,1.0,1.0,1.0);

	// The are blend constants that the void engine uses from a material script. 
	if(blendIndex == 0)
	{
		// BLEND_REPLACE
		blendedColor = srcFragment;
	}
	else if(blendIndex == 1)
	{
		// BLEND_SOURCEALPHA
		blendedColor = (srcFragment.a * srcFragment) + ((1.0 - srcFragment.a) * destFragment);
	}
	else if(blendIndex == 2)
	{
		// BLEND_MODULATE
		blendedColor = vec4(srcFragment.rgb * destFragment.rgb, 1.0);
	}
	else
	{
		// BLEND_ADD
		blendedColor = vec4(srcFragment.rgb + destFragment.rgb, 1.0);
	}
	
	return blendedColor;
}

//////////////////////////////////////////////////
//      	Fragment Shader	//               				
//////////////////////////////////////////////////   		
void main()
{
	vec4 finalColor = vec4(1.0, 1.0, 1.0, 1.0);
	vec4 texcolor[2];
	texcolor[0] = texture2D(u_tex[0], v_texCoord0);
	texcolor[1] = texture2D(u_tex[1], v_texCoord1);
	
	// Blend textures together based on blend index
	for(int i = 0; i < u_texCount; i++)
	{
		finalColor = performFragmentBlends(u_blend[i], texcolor[i], finalColor);
	}
	
	// Modulate the color
	finalColor.rgb *= u_colorMod.rgb;
	
	// Set the opacity alpha value
	finalColor.a *= u_opacity;
	
	gl_FragColor = finalColor;
}

As a reminder, on the for loop, if I replace u_texCount with 2, the shader draws correctly. When u_texCount is used and set to 2 in my engine code, the shader draws incorrectly (it looks like a lot of multicolor stars). I appreciate the help.
Generalist Game Developer and Cofounder at Voidseer Realms




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS