Name

    ARB_arrays_of_arrays

Name Strings

    GL_ARB_arrays_of_arrays

Contact

    John Kessenich (cepheus 'at' frii.com)

Contributors

    XXX

Notice

    Copyright (c) 2012-2013 The Khronos Group Inc. Copyright terms at
        http://www.khronos.org/registry/speccopyright.html

Specification Update Policy

    Khronos-approved extension specifications are updated in response to
    issues and bugs prioritized by the Khronos OpenGL Working Group. For
    extensions which have been promoted to a core Specification, fixes will
    first appear in the latest version of that core Specification, and will
    eventually be backported to the extension document. This policy is
    described in more detail at
        https://www.khronos.org/registry/OpenGL/docs/update_policy.php

Status

    Complete.
    Approved by the ARB on 2012/06/12.

Version

    Last Modified Date: 2012/07/01
    Revision: 7

Number

    ARB Extension #120

Dependencies

    GLSL 1.2 is required.

    OpenGL ?? (Core Profile) specification is required.  (See issues.)

Overview

    Multi-dimensional arrays are a frequently requested feature.  This extension
    removes the restriciton that arrays cannot be formed into arrays, allowing
    arrays of arrays to be declared.  Technically, removing this restriction is 
    all that is necessary to enable this feature, but it is worthwhile showing
    what the result of doing that looks like.

    The following will be true of arrays of arrays

    - They will first class objects.  (They know their size, can be passed by 
      copy-in semantics to functions, etc.)

    - They will only be one-dimensional arrays of other first class objects.
      (arrays are already first class objects).

    - The syntax

        vec4 a[3][2];

      Declares a one-dimensional array of size 3 of one-dimensional arrays of 
      size 2 of vec4s.  Also, these syntaxes do the same thing:

        vec4[2] a[3];
        vec4[3][2] a;

      or, looking at more dimensions, these are all the same

        int a[1][2][3][4][5][6];

        int[1][2][3][4][5][6] a;

        int[4][5][6] a[1][2][3];

      note this latter is equivalent to C, in meaning the same thing, if done as

        typedef int int456[4][5][6];

        int456 a[1][2][3];

      that is, this GLSL proposal matches C behavior in this way.  The type needed for
      both constructors and nameless parameters is:

         int[1][2][3][4][5][6]

    - This type could be declared as a formal parameter in a function prototype as

        void foo(vec4[3][2]);

    - Accessing is done as

        a[x][y]  // x selects which array of size 2 is desired
                 // y selects which vec4 is desired

        a[x]     // this results in a one-dimensional array, with all rights and
                 // priviledges implied

    - The .length() operator works as normal:

        a.length()     // this is 3
        a[x].length()  // this is 2

    - The constructor for the above is

        vec4[3][2](vec4[2](vec4(0.0), vec4(1.0)),   
                   vec4[2](vec4(0.0), vec4(1.0)),   
                   vec4[2](vec4(0.0), vec4(1.0)))

    - Initializers for the above are

        vec4 a[3][2] = vec4[3][2](vec4[2](vec4(0.0), vec4(1.0)),   
                                  vec4[2](vec4(0.0), vec4(1.0)),   
                                  vec4[2](vec4(0.0), vec4(1.0)));

        // or

        vec4 a[3][2] = {vec4[2](vec4(0.0), vec4(1.0)),   
                        vec4[2](vec4(0.0), vec4(1.0)),   
                        vec4[2](vec4(0.0), vec4(1.0))) };

        // or 

        vec4 a[3][2] = {{ vec4(0.0), vec4(1.0) },   
                        { vec4(0.0), vec4(1.0) },   
                        { vec4(0.0), vec4(1.0) }  };  // requires matching nesting of 
                                                      // {} with object's hierarchy


    Note that all the above is naturally already specified in the core 
    specification.


New Procedures and Functions


New Tokens


Additions to Chapter 2 of the OpenGL 4.2 (Core Profile) Specification
(OpenGL Operation)


Additions to Chapter 3 of the OpenGL 4.2 (Core Profile) Specification
(Rasterization)

    None.

Additions to Chapter 4 of the OpenGL 4.2 (Core Profile) Specification
(Per-Fragment Operations and the Framebuffer)

    None.

Additions to Chapter 5 of the OpenGL 4.2 (Core Profile) Specification
(Special Functions)


Additions to Chapter 6 of the OpenGL 4.2 (Core Profile) Specification
(State and State Requests)

    None.

Additions to Chapter 4 of the OpenGL Shading Language Specification, Version
4.20 (Variables and Types)

    Section 4.1.9 Arrays

    Rewrite the sentences "Only one-dimensional arrays may be declared. All 
    basic types and structures can be formed into arrays." as 

    "Arrays only have a single dimension (a single number within "[ ]", 
     however, arrays of arrays can be declared.  All types (basic types, 
     structures, arrays) can be formed into an array."

    "When in transparent memory (like in a uniform block), the layout is that 
     the 'inner' (right-most in declaration) dimensions iterate faster than the 
     out dimensions.  That is, for the above, the order in memory would be:

         low address...a[0][0] a[0][1] a[1][0] a[1][1] a[2][0] a[2][1]...high address"

    Expand the examples in this section by incorporating the declaration and
    use content from the overview section above.

    Add

        vec4 a[3][2];
        a.length()     // this is 3
        a[x].length()  // this is 2

    When the *length* method will return a compile-time constant, the expression 
    in brackets (x above) will be evaluated and subject to the rules required
    for array indexes, but the array will not be deferenced.  Thus, behavior
    is well defined even if the run-time value of the expression is out of bounds.

    Remove the illegal examples of arrays of arrays.

    Add the following:

    "For unsized arrays, only the outermost dimension can be lacking a
    size. A type that includes an unknown array size cannot be formed into
    an array until it gets an explicit size."

    Section 4.1.11 Initializers

    Expand the examples in this section by incorporating the initializer
    content from the overview section above.

    Section 4.3.4 Input Variables

    For this paragraph, keep this introductory text the same

    "Some inputs and outputs are arrayed, meaning that for an interface between 
    two shader stages either the input or output declaration requires an extra 
    level of array indexing for the declarations to match.  

    but rewrite the remainder

    "For example, with 
    the interface between a vertex shader and a geometry shader, vertex shader 
    output variables and geometry shader input variables of the same name must 
    match in type and qualification, except that the vertex shader name cannot 
    be declared as an array while the geometry shader name must be declared 
    as an array, to allow for vertex indexing.  
    It is a link error if a 
    non-arrayed input is not declared with the same type, qualification, and 
    array dimensionality as the matching output.  It is an error if an arrayed 
    input is not declared as an array of the same type and qualification as the 
    corresponding (non-array) output. Symmetrically, it is an error if an 
    arrayed output is not  declared as an array of the same type and 
    qualification as the corresponding (non-array) input."

    instead as 

    "For example, with 
    the interface between a vertex shader and a geometry shader, vertex shader 
    output variables and geometry shader input variables of the same name must 
    match in type and storage qualification, except that the geometry shader will have 
    one more array dimension than the vertex shader, to allow for vertex 
    indexing.
    If such an arrayed interface variable is not declared with the necessary 
    additional input or output array dimension, a link-time error will result."

    "For non-arrayed interfaces (meaning array dimensionally stays the same between 
    stages), it is a link-time error if the input variable is not declared with the 
    same type, including array dimensionality, as the matching output variable."

    Remove the following paragraph

    "If the output corresponding to an arrayed input is itself an array, it 
    must appear in an output block (see interface blocks below) in the 
    outputting shader and in an input block in the inputting shader with a block
    instance name declared as an array.  This is required because two-dimensional 
    arrays are not supported."

    Section 4.3.6 Output Variables

    Remove the following paragraph

    "As described under the section 4.3.4 'Input Variables' above, if a 
    per-vertex output of the tessellation control shader is itself an array 
    with multiple values per vertex, it must appear in an output block (see 
    interface blocks below) in the tessellation control shader with a block 
    instance name declared as an array."

Additions to Chapter 5 of the OpenGL Shading Language Specification, Version
4.20 (Built-in Variables)

    Section 5.4 Array Constructors

    Expand the constructor examples with the constructor examples from the
    overview section of this specification.

    Section 5.7 Structure and Array Operations

    Expand the examples with the .length() and [] examples from the overview
    section of this specification.

Changes to the grammar

    There are 7 pairs of rules that allowed either an empty array 
    declaration or one with a size.  For example:

        init_declarator_list:
                init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET 
                init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET 

    plus 1 rule for parameter array declarations:
        
        parameter_declarator:
                type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET 

    These 15 total (2*7 + 1) declaration rules are all replaced with 8 uses 
    of a new rule array_specifier:

        array_specifier:
                LEFT_BRACKET RIGHT_BRACKET
                LEFT_BRACKET constant_expression RIGHT_BRACKET
                array_specifier LEFT_BRACKET RIGHT_BRACKET
                array_specifier LEFT_BRACKET constant_expression RIGHT_BRACKET

    For example, the pair given in the example above becomes:

        init_declarator_list:
                init_declarator_list COMMA IDENTIFIER array_specifier

    The LEFT_BRACKET now appears in exactly 5 rules now; the 1 for postfix 
    expressions (remains unchanged) and the 4 for array_specifier.

New State

    None.

New Implementation Dependent State

    None.

Issues


1.  Do we want to support the following form as well?

        vec4[3][2] a;

    Probably, to match the constructor and formal parameter declaration.  These
    require that 

        vec4[3][2]   // a valid type

    is a type in its own right, and the general syntax to declare something is 

        <type> <name>

    GLSL already has required the following since 1.2:

        vec4[3] a;

    RESOLUTION: Yes, allow this syntax.
    
2.  What does the enumeration API look like?  Don't want to enumerate down to 
    10,000 little individual elements, want something more hierarchical instead.

    This will significantly effect this extension if this extension turns into
    defining a new discovery API.

    Nested issue: What about optimizers eliminating holes in a data structure?

    RESOLUTION: Belongs in another extension.

3.  How are large buffer/memory arrays declared?  E.g.,

        buffer vec4 a[][2];

    RESOLUTION: Belongs in another extension.  Probably will be

        buffer BufferBlock {
            vec4 a[][2];
        };

4.  Can large memory arrays be passed by reference to a function?  Want to pick 
    up pointer-like feature without full introduction of pointers.

    RESOLUTION: Belongs in another extension.

5.  How does this extension interact with ??, which is adding the large 
    memory/buffer style arrays.

    RESOLUTION: Belongs in another extension.

6.  Can vertex inputs be arrays of arrays?

    RESOLUTION: Yes.  

7.  Can fragment outputs be arrays of arrays?

    RESOLUTION: Yes.

8.  Can vertex outputs be arrays of arrays?  Note that some stage inputs can 
    now be arrays of arrays, due to adding a new array level to a previous
    stage's output type.

    RESOLUTION: Yes.

9.  Can uniforms be arrays of arrays?

    RESOLUTION: Yes.

10.  Can interface blocks (e.g. uniform blocks) be arrays of arrays?

    RESOLUTION: Yes.

11.  Can subroutine variables be arrays of arrays?

    Recommended: Yes.

    RESOLUTION:

12.  Do we want to eliminate the syntax?

    vec4[2] a[3];  // same as vec4 a[3][2];

    It might seem the 3 and 2 should be reversed.  However, thinking through how 
    precedence, the grammar, etc. all work, this is actually very well defined 
    and correct and consistent with C/C++.

    RESOLUTION: Yes, allow these syntaxes.

Revision History

    Rev.    Date      Author    Changes
    ----  --------    --------  -----------------------------------------
     7    1-Jul-2012  JohnK     Added grammar changes.
     6   10-May-2012  JohnK     Editorial fixes before merging into core spec.
     5   16-Mar-2012  JohnK     Update with resolutions from language meeting
                                (Generally, allow arrays of arrays for most I/O, 
                                 and allow the syntaxes that naturally fall out.)
     4   24-Feb-2012  JohnK     Minor clarifications within issues.
     3    3-Feb-2012  JohnK     Fix reversed 2/3, add new example, resolve issues 2-5
     2    1-Feb-2012  JohnK     Flesh out with specification language
     1    1-Feb-2012  JohnK     Initial revision
