GLSL instruction or operation limitation?

I write both vertex and fragment shader with GLSL , for trying to blend 4 or more textures in one pass which means sampling different textures and summation those texel values with some sort of weighting .

When I use 3 textures , the result is fine . When I use 4 , the program using is fail . At started I think it might be memory , I decrease the variable number i using at shader , still failed . When I comment the calculation of weighting , 4 texture is OK .

So , I wonder that is there instruction limitation or some other limitation in GLSL , or how small it is ( because I didn’t write too large my codes ) ?

My graphic card is GeForce 7600GS , OpenGL2.0 , NVidia driver updated and NVidia OpenGL SDK 10 is installed .

My code is following :

vertex shader :


varying vec3 L0 ;// 4 light position for weighting
varying vec3 L1 ;
varying vec3 L2 ;
varying vec3 L3 ;
varying vec3 N ;// normal

void main(void)
{
	vec3 P = vec3( gl_ModelViewMatrix * gl_Vertex) ;
	L0 = normalize( gl_LightSource[ 0 ].position - P ) ;
	L1 = normalize( gl_LightSource[ 1 ].position - P ) ;
	L2 = normalize( gl_LightSource[ 2 ].position - P ) ;
	L3 = normalize( gl_LightSource[ 3 ].position - P ) ;	
	N = normalize( gl_NormalMatrix * gl_Normal);
	
        // texture matrix for projective texture
	gl_TexCoord[ 0 ] = gl_TextureMatrix[ 0 ] * gl_Vertex ;
	gl_TexCoord[ 1 ] = gl_TextureMatrix[ 1 ] * gl_Vertex ;
	gl_TexCoord[ 2 ] = gl_TextureMatrix[ 2 ] * gl_Vertex ;
	gl_TexCoord[ 3 ] = gl_TextureMatrix[ 3 ] * gl_Vertex ;	
	
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex ;
}

fragment shader :


varying vec3 L0 ;
varying vec3 L1 ;
varying vec3 L2 ;
varying vec3 L3 ;
varying vec3 N ;
uniform sampler2D Texture0 ;// 4 texture binded with GL_TEXTURE0~4
uniform sampler2D Texture1 ;
uniform sampler2D Texture2 ;
uniform sampler2D Texture3 ;

void main (void)
{
	vec4 texColor = texture2DProj( Texture0 , gl_TexCoord[ 0 ] ) * max( dot( N , L0 ), 0.0 ) ;
	texColor += texture2DProj( Texture1 , gl_TexCoord[ 1 ] ) * max( dot( N , L1 ), 0.0 ) ;
	texColor += texture2DProj( Texture3 , gl_TexCoord[ 2 ] ) * max( dot( N , L2 ), 0.0 ) ;

	texColor += texture2DProj( Texture3 , gl_TexCoord[ 3 ] ) * max( dot( N , L3 ), 0.0 ) ;// If i comment this line , the program works .

	gl_FragColor = min( texColor , 1.0 )  ;	// prevent overflow
}

thanks in advance.

You are using too many varyings. I think the Geforce 7 has a limit of 8 vec4’s. (you are attempting to use 9)

You are running into number of varyings. The driver seems to be unable to pack the vectors effectively into all available float interpolators and runs out of them even if they should fit (the specification talks about individual floats not vec4 interpolators which they really are in the hw). You can work around that by using vec4 varyings and explicitly packing the vectors into them. Something like


varying vec4 packed_data_0 ;
varying vec4 packed_data_1 ;
varying vec4 packed_data_2 ;

#define L0 ( packed_data_0.xyz )
#define L1 ( packed_data_1.xyz )
#define L2 ( packed_data_2.xyz )
#define N vec3( packed_data_0.w, packed_data_1.w, packed_data_2.w )

thanks for replying in the first .

I want to make it more clearly .

  1. The number of “GL_MAX_VARYING_FLOATS” of mine program is 32 , and is that the same as the limit of you said “8 vec4’s” ? Or which function I should use to get the correct info ?

  2. to Komat , you mean that the packing of vector seems ineffectively , therefore , if I use vec3 , it will cost one float useless , aren’t you ?

  3. to sqrt , you mean i use 9 varyings . Do you mind count it for me ? 'Cause I only see L0 L1 L2 L3 N .( Assumimg vec3 occupy vec4 storage ) . If the limit of “8 vec4s” is varying + uniform , is that one uniform will occupy one vec4 storage , how cound i pack “sampler2D” together ? Or the local variable like “vec3 P” and “vec4 texColor” should be included counted ?

btw , i found another thread of likely issue , but still coufused :
http://forums.nvidia.com/index.php?act=ST&f=71&t=57743
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=233383#Post233383

The GLSL counts varying limits in individual floats (those 32) so the user does not need to care how they are implemented in hw or packed. At least that is how it should work in theory. Older extensions counted them as number of vec4 elements corresponding to real state of the hw when those extensions were created (I think that it is still the same even with latest hw).

  1. to Komat , you mean that the packing of vector seems ineffectively , therefore , if I use vec3 , it will cost one float useless , aren’t you ?

With driver fully compliant with the GLSL specification it should cost only 3 floats. In your case the driver wasted the fourth float from real hw interpolator.

  1. to sqrt , you mean i use 9 varyings . Do you mind count it for me ? 'Cause I only see L0 L1 L2 L3 N .( Assumimg vec3 occupy vec4 storage ) .

Each gl_TexCoord[ x ] will count as vec4 varying. Theoretically the driver might be smart and ignore components of it which are not used however that is unlikely and not guaranteed.

to Komat , if i need to use 8 multitexture coordinate in fragment shader from gl_TexCoord[ 0 ] to gl_TexCoord[ 7 ] , that will fully use all varying storage , and result in no other varying of my own can be used .

Am I right ?

What is the suggection will you give in this situation ?

Yes.

What is the suggection will you give in this situation ?

If you are utilizing less than four components from the gl_TexCoord (e.g. the texture2DProj ignores the .z component if it is used with vec4 coordinates), you can manually pack something else into the unused component. If you pack everything manually into the vec4 for the shader you posted, you will fit into the limit and yet have additional 4 floats available.

If limited range and precision is sufficient, you can also use the gl_Color and gl_SecondaryColor builtin varyings since they do not count against that that limit on GeForce 7 class hw.

If you need to use more than 32 full precision floats then you are out of luck and you will need to find more clever way of passing them to the shader. For example in your case the Lx varyings are calculated as ( gl_LightSource[ x ] - P ). You can send the P to the fragment shader using one varying and calculate the subtraction for all lights in the fragment shader (it can access the gl_LightSource[ x ] uniforms too). Similiary with the projected coordinates.

hi , Komat ,

thank you for replay deeply .

I rewrite my shader as your suggection ,

  1. I move mostly calculation from vertex shader to fragment shader . ( originally I thought that “Calculate them in VS and let hardware interpolate for me” will be better . )

  2. Try using minimal varying variable as 1.) said , especially re-use one vec4 as texture coordinate instead of gl_TexCoord[]

I will keep on testing more texture units on my project .

Vertex Shader :


varying vec3 N ;
varying vec4 Vertex ;

void main(void)
{
	Vertex = gl_Vertex ;	
	N = normalize( gl_NormalMatrix * gl_Normal) ;
	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex ;
}


Fragment Shader :


varying vec3 N ;
varying vec4 Vertex ;
uniform sampler2D Texture0 ;
uniform sampler2D Texture1 ;
uniform sampler2D Texture2 ;
uniform sampler2D Texture3 ;

void main (void)
{
	vec3 P = vec3( gl_ModelViewMatrix * Vertex ) ;
	vec3 LDir ;
	float Weight ;	
	vec4 TexCoord ;
	vec4 texColor ;
	
	LDir = normalize( gl_LightSource[ 0 ].position - P ) ;
	Weight = max( dot( N , LDir ) , 0.0 ) ;	
	TexCoord = gl_TextureMatrix[ 0 ] * Vertex ;
	texColor = texture2DProj( Texture0 , TexCoord ) * Weight ;
	
	LDir = normalize( gl_LightSource[ 1 ].position - P ) ;
	Weight = max( dot( N , LDir ) , 0.0 ) ;
	TexCoord = gl_TextureMatrix[ 1 ] * Vertex ;
	texColor += texture2DProj( Texture1 , TexCoord ) * Weight ;

	LDir = normalize( gl_LightSource[ 2 ].position - P ) ;
	Weight = max( dot( N , LDir ) , 0.0 ) ;	
	TexCoord = gl_TextureMatrix[ 2 ] * Vertex ;
	texColor += texture2DProj( Texture2 , TexCoord ) * Weight ;	
	
	LDir = normalize( gl_LightSource[ 3 ].position - P ) ;
	Weight = max( dot( N , LDir ) , 0.0 ) ;
	TexCoord = gl_TextureMatrix[ 3 ] * Vertex ;
	texColor += texture2DProj( Texture3 , TexCoord ) * Weight ;	
	
	gl_FragColor = texColor ;	
}

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