Jump to content
  • Advertisement
Sign in to follow this  
ileonte

GLSL: overcoming uniform space limitations (and more)

This topic is 2891 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've written a vertex shader to do skeletal animation on a Milkshape model. The shader includes the following declaration (amongst others):
uniform mat4 aniKeyframes[128];
On all of my test machines (which all have nVIDIA cards) this worked just fine. Then I tested my code on a friends computer with a fairly recent ATI card (a 5770 Radeon to be exact). To my great surprise nothing seemed to work: the model I was drawing would simply not show up. After some investigation I found out that glUniformLocation() was returning -1 for some of my uniforms like the projection matrix and the model matrix. After some more testing I determined that I can get everything to work by lowering the size of the aniKeyframes array shown above (turns out on that particular vertex+card+driver combination the maximum size for the array was 58 - setting it to 59 or higher would cause glUniformLocation() to start returning -1 again for what seem to be random uniforms in the vertex shader). The question is how to go about detecting such limits (testing shows that nVIDIA drivers simply refuse to link the shader if it uses more uniforms than the hardware can accommodate while ATI drivers simply fail silently at runtime) and what can be done once the limit is detected. There are certain tricks I could use on the C++ side to avoid sending all of the data at once but I would rather not complicate what is already a pretty obfuscated maze of matrix/quaternion math.

Unrelated (but not quite) to the above: is there any way to read data from a buffer from within a shader ? It would be great to be able to place all those matrices in a GL_DYNAMIC_DRAW buffer instead of a uniform and be able to access them from the shader (I don't think having them as vertex attributes is a good idea as I'd just be copying redundant data all over the place since there is a one-to-many relationship between the keyframe matrices and the vertices in the model).

PS: just for reference, this is the complete shader code
#version 330 core

struct EglobalLight {
vec3 direction;
vec4 ambient;
vec4 specular;
vec4 diffuse;
};

uniform mat3 matWorld3;
uniform mat4 matModel;
uniform mat3 matNormalMatrix;
uniform mat4 matProjection;
uniform EglobalLight globalIllum;
uniform mat4 aniKeyframes[128];
uniform int aniEnabled;
uniform vec3 camPosition;
uniform mat4 matWorld;

in vec2 attrTC;
in vec3 attrPosition;
in vec3 attrNormal;
in int attrBoneId;

out vec2 fragTexCoords;
out vec3 fragNormal;
out vec3 halfVector;
out vec3 lightDir;

void main( void )
{
vec4 pos;
if ( aniEnabled != 0 ) {
if ( attrBoneId >= 0 ) {
pos = matWorld * matModel * aniKeyframes[attrBoneId] * vec4( attrPosition, 1.0 );
} else {
pos = matWorld * matModel * vec4( attrPosition, 1.0 );
}
} else {
pos = matWorld * matModel * vec4( attrPosition, 1.0 );
}
fragTexCoords = attrTC;
fragNormal = normalize( matNormalMatrix * attrNormal );
lightDir = normalize( matWorld3 * -globalIllum.direction );
halfVector = normalize( normalize( matWorld3 * camPosition ) + lightDir );
gl_Position = matProjection * pos;
}

Share this post


Link to post
Share on other sites
Advertisement
You can query the number of available uniform registers: clicky

One tips: use quaternion (vec4) and position(vec3) for animation instead of mat4, this will half the number of needed uniforms.

Share this post


Link to post
Share on other sites

You can query the number of available uniform registers: clicky

One tips: use quaternion (vec4) and position(vec3) for animation instead of mat4, this will half the number of needed uniforms.



Thanks for the link.

[font="sans-serif"]Implementation note: OpenGL implementations are allowed to reject shaders for implementation-dependent reasons. So you can have fewer active uniform components by your reckoning and still fail to link due to uniform limits. This is usually on hardware that is inately vector hardware. Pre GeForce 8xxx hardware, and all ATi hardware does this. In this case, you should assume that each separate uniform takes up 4 components, much like it would in D3D. That means a "uniform float" is 4 components, a mat2x4 is 16 components (each row is 4 components), but a mat4x2 is 8 components.[/font]
[font="sans-serif"]ATI/AMD note: The ATI max component values are wrong. They are the actual number of components divided by 4.[/font][/quote]

Gotta love ATI :) On topic though: my question was more along the lines of 'once you detect this limit (assuming you can detect it correctly on all hardware) what steps (if any) can be taken to ensure that a shader runs (short of having hardware-specific shader code to load based on the available video card) ?'. This is also linked to my second question: is there any way to alleviate uniform buffer 'stress' by passing larger chunks of data in buffers (those created via glGenBuffers()) instead of uniforms ?

Share this post


Link to post
Share on other sites
Wih Opengl 3 there are Texture Buffers(also available threw an extension inb opengl2).

With this extension you can bind a Buffer Object as a 1D Texture.

And when you do this you can just access it in your vertex/fragment shader with a simple texture lookup.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!