GLSL indexing into uniform array with variable length

Jitu picture Jitu · Nov 8, 2013 · Viewed 17.5k times · Source

I am passing an uniform array to geometry shader and want to index into it using a variable. I can use variable length array & index with fixed number (numeric constant) OR I can define a fixed length array & index using varible. However I can't index into variable length array using a variable.

Below is pseudo code for geometry shader with cases that work & case that doesn't work

This works:

    uniform vec2 dimensions[2];
    // some code which computes index which is an int
    float dimX = dimensions[index].x;

This works:

    uniform vec2 dimensions[];
    // some code which computes index which is an int
    float dimX = dimensions[0].x;

This doesn't work:

    uniform vec2 dimensions[];
    // some code which computes index which is an int
    float dimX = dimensions[index].x; 

Is it possible to do something like this?

Answer

Andon M. Coleman picture Andon M. Coleman · Nov 8, 2013

Sadly, no this is not possible. You did not include the GLSL version you are targeting but did mention geometry shaders, so I have included the relevant part of the GLSL 1.5 spec. below:

GLSL Specification (Version 1.5) - 4.1.9 Arrays - pp. 25.

Variables of the same type can be aggregated into arrays by declaring a name followed by brackets ( [ ] ) enclosing an optional size. When an array size is specified in a declaration, it must be an integral constant expression (see Section 4.3.3 “Constant Expressions” ) greater than zero. If an array is indexed with an expression that is not an integral constant expression, or if an array is passed as an argument to a function, then its size must be declared before any such use.

While desktop GLSL is much more forgiving when it comes to indexing arrays with non-const expressions than GLSL ES, you still have to work within some limitations. The same way that texture lookups are often used to overcome non-const array indexing in OpenGL ES, you may be able to work around this by using a 1D texture lookup in your geometry shader. I have to wonder if you really need this functionality that badly though?

It is a good idea to define an upper limit to your uniform array anyway, because the GLSL spec. only requires an implementation provide 1024 uniform components (e.g. 1024 float, 256 vec4, 64 mat4 or some combination of each) in the geometry shader stage. If your array has a known maximum size at compile time you can avoid trouble later down the road associated with unknowingly exceeding this limitation.

UPDATE:

Since you mentioned GLSL 4.x, I would like to point out a newer feature in OpenGL known as Shader Storage Buffer Objects. Using SSBOs, it may be possible to use an array with dynamic length at run-time for your purposes. You can query the length of an SSBO using .length () in the shader, and handle range validation yourself. However, I think this is probably overkill but worth mentioning nevertheless.