Arrays of size 1

So I’m trying to kludge around the glGetActiveUniform bug (previous post), and I find:

#version 120

int list3[3] = int[]( 1, 2, 3 );   // Valid
int list2[2] = int[]( 1, 2 );      // Valid
int list1[1] = int[]( 1 );         // Invalid!

What gives? I know you can’t have arrays of length 0 (annoying, but OK). But what’s wrong with arrays of length 1?

Could be a completely wrong answer, but an array of length one would implicitly mean it is able to be declared as something besides an array.

Perhaps #version 120 takes offense? :wink:

I’m sure you already knew this but I like to try to contribute!

Are you sure? There is language in the spec that says you can’t have arrays of size 0, but nothing I can find that says you can’t have arrays of size 1. Cannot even initialize an array of size 1 with a scalar initializer.

Perhaps #version 120 takes offense? :wink:

Not too likely, as that is the version that introduced array initializers IIRC.

I’m sure you already knew this but I like to try to contribute!

Thanks!

You can’t have length 1 for an array of structures either, so no help from that route:

#version 120

struct S 
{
  int mode;
  int val ;
};

S t[ 2 ] = S[]( S( 1, 2 ),
                S( 3, 4 ) );  // Valid
S t[ 1 ] = S[]( S( 1, 2 ) );  // Invalid!

This plus the glGetActiveUniform limitation on arrays makes it hard to write generic shader code…

Without knowing too much of the GLSL specs, I’m a newbie, logic leads me to believe that it would avoid initializing an array of say ‘int’ since an array of one element would mean you could specify ‘int’ and avoid the array entirely. With an array of size 0 it would have to have compilation errors because that would be elementless.

Perhaps this isn’t the case when the language was made, but after using GLSL and openGL for a few months now, the more strict the standards sometimes, apparently!, the better.

I, too, looked at the specs when seeing your post. I can’t find anything directly referencing array’s of 1 element. Peculiar? Conspiracy perhaps?

You could, yes, but then you’d need obtuse shader logic to handle this strange case.

For instance (to take the absolute simplest of examples), whereas you’d like to just write this:

for ( int i = 0; i < tex_unit.length(); i++ )
  color = texlookup( color, tex_unit[i] );

To kludge around the no-0-length-arrays thing, you need this:

#if NUM_TEX_UNITS > 0
for ( int i = 0; i < tex_unit.length(); i++ )
  color = texlookup( color, tex_unit[i] );
#endif

along with #if’ing out the definition of the tex_unit array and all code referencing it, only when the length is 0.

And to kludge around the no-1-length-array-initializers thing, you need this:

#if NUM_TEX_UNITS == 1
color = texlookup( color, tex_unit );
#elif NUM_TEX_UNITS > 1
for ( int i = 0; i < tex_unit.length(); i++ )
  color = texlookup( color, tex_unit[i] );
#endif

and #if’ing the definition of the tex_unit array and all referencing code so that it can be 1) not there, 2) a simple value or struct, or 3) an array of values or structs …all depending on the number of elements you want to put into the tex_unit array.

And I wouldn’t even be exploring all this if GLSL would just tell me correctly the maximum array element referenced in the linked shader program. Then I could declare the array with some max, and only populate those array elements that were “compiled in” to the program.

This makes it difficult to write maintainable ubershaders.

If no-one sees an error in my code, I’ll probably just have to ditch uniform arrays altogether and use preproccesor glue to populate arrays dynamically in the shader…

I see where your coming from. Makes sense that you’d have to start #if’ing to avoid that. I’m not sure how to do/maintain ubershaders but I’ll assume it only gets more complex.

I wonder why this occurs and isn’t referenced, as far as I can tell, in the Specs?

Driver bug. File a bug report on it.

Arg! Can’t do that when samplers are involved:

struct TextureUnit
{
  sampler2D         sampler;           // Texture sampler unit
  ...
};

Result: error C7554: OpenGL requires samplers to be explicitly declared as uniform

Ok fine:

struct TextureUnit
{
  uniform sampler2D sampler;           // Texture sampler unit
  ...
};

Result: error C7524: OpenGL requires uniform variables to be declared in global scope

So bottom line, there is no way to generically iterate across an array of textures in a shader without using uniform sampler arrays, and those don’t tell you “which” are actually referenced in the shader so you know which to bind in the application.

Seems the only kludge for this is to have the application “just know” what textures are going to be used by the shader for all permutations based its knowledge of how the shader works… Ugly.

Dont get too attached to /iterating/ sampler arrays either (from 130 spec with diff):


Changes from revision 10 of version 1.20 of the OpenGL Shading Language
...
The ability to index into an array of samplers with a variable index is removed.

Dont get too attached to /iterating/ sampler arrays either (from 130 spec with diff):


Changes from revision 10 of version 1.20 of the OpenGL Shading Language
...
The ability to index into an array of samplers with a variable index is removed.

[/QUOTE]

Yes, sampler2DArray are required for array of samplers.

Thanks. Question is: what does “variable” mean in this context? In my case we’re not talking about a variable index here (i.e. one computed dynamically in the shader from say tex lookups, which cannot be predetermined by the compiler), but rather one determined totally at compile time from the length of a constant array and replaced with constants though loop unrolling. For instance:


uniform sampler2D tex_unit[ 16 ];
...
for ( int i = 0; i < tex_unit.length(); i++ )
  color = texlookup( color, tex_unit[i] );

The compiler would (and does) unroll the loop internally and collapse out any empty iterations, leaving only constants indexing the tex_unit sampler array. So I believe this should be allowed despite the clause you mentioned.

Will do. Just wanted someone else to double-check me on that. Thanks.

Its pretty silly, but you can index into such arrays with integral constant expression only (literals and builtin operations on them)
It is silly as in the code you provided this forces you to manually unroll the loop.
(i also cant see a reason why would they explicitly forbid such usage)

Ok, thanks. Yeah, I’d actually just manually unrolled the loops this morning to avoid app-knowledge kludges of which samplers are actually used in the shader for different compile permutations.

Without a glGetActiveUniform or glGetUniformLocation that properly recognizes unused (inactive) samplers in sampler arrays, sampler arrays are pretty useless unless you’ll always have the same number of samplers.

For those that find this thread searching the archives, the above pretty well sums it up, but the latest GLSL Orange Book (3rd ed - GL 3.0-3.1), has this to say about arrays of samplers:

Whouuuuu! I didn’t know that array of sampler finally worked!
I remember Micheal Gold speech at Siggraph 2007 OpenGL BOF introducing sampler array saying that array of sampler doesn’t work … maybe this feature should be deprecated.

although with the restriction that the texture formats and texture sizes are constant across the sampler array.

That sounds suspiciously like the driver automatically creating an array texture.