I have an OpenGL based graphics engine coming along quite nicely, but I'm currently stumped on a problem that arose after adding a new vertex shader output array.

The vertex shader is outputing the usual things one would calculate per vertex to minimise fragment processing - eg fragment locations in tangent and light space etc which are done on a per light basis with currently an 8 light max per lighting zone. Structure as below.

#version 460
const int cMaxZoneLightCount = 8;

out vData
    vec3 vFragmentLocationWorld;  //  This vertice's location in world coords
    vec2 vTextureUV;
    vec4 vNormal;
    vec4 vFragmentLocationLightSpace[cMaxZoneLightCount];  // Light space location per light (up to 8)
    vec4 vFragmentLocationTextureSpace[cMaxZoneLightCount]; //  Transform for projective texture lights
    vec4 vViewLocationTangent;
    vec4 vFragmentLocationTangent;  //  Tangent space transforms for normal mapping
    vec4 vLightLocationTangent[cMaxZoneLightCount];  // Light locations in tangent space (up to 8)
    vec4 vLightMRPTangent[cMaxZoneLightCount];  //  MRP for tube lights in tangent space (up to 8)
    vec4 vTangent;
    vec4 vBitangent;  //  Pre computed vertex tangent/bitangent data.
}   vDataOut;

Everything was working fine until I added the vLightMRPTangent[cMaxZoneLightCount] array. Adding that brings the total number of vertex outputs to 153 and I receive error C5041 when the shader compiles - "cannot located suitable resources to bind variable... possibly large array".

This is strange though because an int mvoc = GL_MAX_VERTEX_OUTPUT_COMPONENTS returns 37,154.

Now, the interesting thing is - if I make vLightMRPTangent[2] instead of 8, this brings the number of vertex shader outputs down to 129 and it works. Similarly, a vLightMRPTangent[3] which would put it up to 133 output components generates a different but verbose and nasty link failure message.

So it's looking a lot like my still formidible GTX970 only wants to send 128 components down the pipeline!! (tell me that can't be right...)

I'm developing on Windows 10 with GLEW v2.1 and the November 2019 nVidia driver. I'm not using any other extensions/libraries, eg glm/glut (doing all my matrix work myself).

I can get around this by implementing subsequent features per pixel rather than per vertex, but that's a real pain because its going to result in sub-optimal efficiency which could become a big problem later.

Any ideas anyone?

Cheers, MWS


1 Answer 1


This is strange though because an int mvoc = GL_MAX_VERTEX_OUTPUT_COMPONENTS returns 37,154.

That's the value of the enumerator; it's a static, compile-time value. The actual runtime limit is queried from the implementation using that enumerator. Typically via glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &mvoc).

tell me that can't be right...

Why not? Sending 128 components per vertex is plenty.

You shouldn't be doing transformations into light-space in your VS; that should happen in your fragment shader. You should be sending the basic information to the FS needed for it to do its job: normals (and tangent/bitangent as needed), texture coordinates, etc.

If you find that your FS's performance is not what it needs to be, then the best thing you can do is reduce the number of FS executions. You can use a depth pre-pass to eliminate overdraw, so the only FS executions that happen are those which produces an actual visible element. Or you can go to full-on deferred rendering.

But this method of pre-computing large quantities of data per-vertex is not going to work. Interpolation of vertex data is not free, nor are the caches between the VS and the rasterizer.

  • $\begingroup$ Thanks Nicol, Before you answered I actually moved the lighting calculations over to the FS to see how they would perform... and gained a performance boost!! It's great to have your confirmation so I know this is the right track. 128 vertex components "ought to be enough for anybody". :) $\endgroup$
    – MarvinWS
    Commented Nov 25, 2019 at 21:51
  • $\begingroup$ actually, there is a common practice to convert lightdirection, cameraposition, and lightposition to tangent space in the vertex shader (search for learnopengl.com > normal mapping), and these to the fragment shader. This greatly reduces the fragment shader load. This also means that if you have a lightposition array, then you have to go through that and convert each position to tangentspace in the vertex shader. $\endgroup$
    – Avi
    Commented Sep 20, 2023 at 20:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.