9

From the OpenGL ES spec section 2.10.4 (Shader Variables: Varying Variables):

The number of interpolators available for processing varying variables is given by the implementation-dependent constant MAX_VARYING_VECTORS.

This value represents the number of four-element floating-point vectors that can be interpolated; varying variables declared as matrices or arrays will consume multiple interpolators.

When a program is linked, any varying variable written by a vertex shader, or read by a fragment shader, will count against this limit.

A program whose shaders access more than MAX_VARYING_VECTORS worth of varying variables may fail to link

In Chrome on my machine, gl.getParameter(gl.MAX_VARYING_VECTORS) returns 15, which means I can use 15 vec4 varyings in a shader.

I've verified this with a few tests. 15 vec4 varyings work OK, but when attempting to use 16, the program fails to link and gl.getProgramInfoLog() returns "Varyings over maximum register limit".

But how many varyings of type vec3, vec2 or float can be used?

The OpenGL ES spec seems to hint at this, without being explicit:

any varying variable ... will count against this limit.

A program whose shaders access more than MAX_VARYING_VECTORS worth of varying variables may fail to link

I'm making two guesses:

  1. The maximum number of varying floats is given by:
    MAX_VARYING_VECTORS * 4
    (4 floats per vec4 vector)
  2. If (for example) MAX_VARYING_VECTORS is 8, then each of the following can safely be used without causing any linking errors:
    • 8 vec4 varyings
    • 10 vec3 varyings
    • 16 vec2 varyings
    • 32 float varyings
    • 3 vec4, 3 vec3, 3 vec2 and 5 float varyings
    • 1 vec4 varying array of length 8
    • 1 vec3 varying array of length 10
    • 1 vec2 varying array of length 16
    • 1 float varying array of length 32
    • Any other combination of vec4 / vec3 / vec2 / float variables or arrays, which uses a maximum of 32 floats

So with my MAX_VARYING_VECTORS value of 15, I guess I can use a maximum of 60 floats. My tests seem to confirm this. For example, 30 vec2 varyings work OK on my machine, but 31 causes a "Varyings over maximum register limit" linking error.

So my questions are:

  • Are my two guesses correct?
  • If MAX_VARYING_VECTORS is 8, then is it safe to use 16 vec2 varyings? Is this guaranteed to always work?
TachyonVortex
  • 8,242
  • 3
  • 48
  • 63

1 Answers1

10

From the WebGL spec

6.24 Packing Restrictions for Uniforms and Varyings

The OpenGL ES Shading Language, Version 1.00 [GLES20GLSL], Appendix A, Section 7 "Counting of Varyings and Uniforms" defines a conservative algorithm for computing the storage required for all of the uniform and varying variables in a shader. The GLSL ES specification requires that if the packing algorithm defined in Appendix A succeeds, then the shader must succeed compilation on the target platform. The WebGL API further requires that if the packing algorithm fails either for the uniform variables of a shader or for the varying variables of a program, compilation or linking must fail.

So yes, if you read the algorithm if MAX_VARYING_VECTORS is 8 you can use 16 vec2s. You can not however use 10 vec3s. You could only use 8 vec3s

There are also array restrictions. For example you couldn't have an array of floats larger than 8 nor an array of vec2 larger than 8 if MAX_VARYING_VECTORS is 8.

Community
  • 1
  • 1
gman
  • 100,619
  • 31
  • 269
  • 393
  • 1
    Many thanks. The description of the packing algorithm is very helpful, especially: *"The target architecture consists of a grid of registers, `MAX_VARYING_VECTORS` rows by 4 columns for varying variables. Each register can contain a `float` value. No splitting of variables is permitted. Vectors always occupy registers in a single row."* That explains why 10 `vec3`s are not allowed. *"Elements of an array must be in different rows."* So an array can't have more than `MAX_VARYING_VECTORS` elements. – TachyonVortex Oct 31 '14 at 21:24
  • 1
    This point seems important to be aware of too: *"If referenced in the fragment shader (after preprocessing), the built-in special variables (`gl_FragCoord`, `gl_FrontFacing` and `gl_PointCoord`) are included when calculating the storage requirements of varyings."* – TachyonVortex Oct 31 '14 at 21:25
  • @TachyonVortex I know this is a somewhat old post, but it seems like the array restrictions do not always apply. On Firefox on my Mac machine, `gl.getParameter(gl.MAX_VARYING_VECTORS)` returns 16, yet I am able to use a 32-element `vec2` array. However, on Chrome, my `MAX_VARYING_VECTORS` is 31, and the browser refuses to link the program, saying `Varyings over maximum register limit`. I need a varying `vec2` array of around 50 elements, and I'm wondering how I can achieve that. – Daniel W Mar 11 '15 at 18:11
  • This looks like a bug in firefox 36. [The conformance test](https://www.khronos.org/registry/webgl/sdk/tests/conformance/glsl/misc/shader-uniform-packing-restrictions.html?webglVersion=1) fails for me on my Mac. Checking [FirefoxNightly](http://nightly.mozilla.org/) (FF 39) it seems to be fixed. Maybe you should try it and see if your program starts having the same behavior as Chrome. As for needing 50 vec2s it sounds like you're S.O.L. If `MAX_VARYING_VECTORS` is 16 the most vec2s you could possibly have is 32. – gman Mar 11 '15 at 23:21
  • Oddly enough, my program still functions with 50 vec2s in both firefox and nightly. Hooray for me, but not so great in terms of conformance. – Daniel W Mar 13 '15 at 01:54
  • I know this is old but for people reading this thread, if you want a random access array of values in a shader you should probably be [using a texture](https://webglfundamentals.org/webgl/lessons/webgl-gpgpu.html), not a uniform array. – gman Jan 30 '21 at 01:30