Name ARB_shading_language_420pack Name Strings GL_ARB_shading_language_420pack Contact John Kessenich (cepheus 'at' frii.com) Contributors Pat Brown, NVIDIA Jeff Bolz, NVIDIA Pierre Boudier, AMD Piers Daniell, NVIDIA Patrick Doane, Blizzard John Kessenich Daniel Koch, Transgaming Bill Licea-Kane, AMD Barthold Lichtenbelt, NVIDIA Ian Romanick, Intel Bruce Merry, ARM Graham Sellers, AMD Robert Simpson, Qualcomm Notice Copyright (c) 2011-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 25-Jul-2011. Approved by the Khronos Promoters on 2011/07/29. Version Last Modified Date: 11-Sep-2014 Revision: 4 Number ARB Extension #108 Dependencies GLSL 1.3 is required for all features. GLSL 1.4 is required declaring a binding for a uniform block, as uniform blocks were not present until version 1.4. This extension interacts with the ARB_shader_image_load_store extension, for assigning locations to image variables. References to *patch* are not valid unless tessellation stages are present and enabled. While this document is self-contained, clarifying context for how to add the following changes can be seen by looking at version 4.20 of the GLSL specification. Overview This is a language feature only extension formed from changes made to version 4.20 of GLSL. It includes: * Add line-continuation using '\', as in C++. * Change from ASCII to UTF-8 for the language character set and also allow any characters inside comments. * Allow implicit conversions of return values to the declared type of the function. * The *const* keyword can be used to declare variables within a function body with initializer expressions that are not constant expressions. * Qualifiers on variable declarations no longer have to follow a strict order. The layout qualifier can be used multiple times, and multiple parameter qualifiers can be used. However, this is not as straightforward as saying declarations have arbitrary lists of initializers. Typically, one qualifier from each class of qualifiers is allowed, so care is now taken to classify them and say so. Then, of these, order restrictions are removed. * Add layout qualifier identifier "binding" to bind the location of a uniform block. This requires version 1.4 of GLSL. If this extension is used with an earlier version than 1.4, this feature is not present. * Add layout qualifier identifier "binding" to bind units to sampler and image variable declarations. * Add C-style curly brace initializer lists syntax for initializers. Full initialization of aggregates is required when these are used. * Allow ".length()" to be applied to vectors and matrices, returning the number of components or columns. * Allow swizzle operations on scalars. * Built-in constants for gl_MinProgramTexelOffset and gl_MaxProgramTexelOffset. IP Status No known IP claims. Additions to Chapter 3 of the OpenGL Shading Language Change the opening of 3.1 Character Set to "The source character set used for the OpenGL shading languages, outside of comments, is a subset of UTF-8. It includes the following characters: "The backslash ( \ ) as the line-continuation character when used as the last character of a line, just before a new line." and after the list, referring to all the characters: "An error will be given if any other character is used outside a comment. "There are no trigraphs. There are no escape sequences or other uses of the backslash beyond use as the line-continuation character." At the end of section 3.2, add "Line numbers are one more than the number of new lines that have been processed, including counting the new lines that will be removed by the line-continuation character ( \ ). "Lines separated by the line-continuation character preceding a new line are concatenated together before either comment processing or preprocessing. No white space is substituted for the line-continuation character. That is, a single token could be formed by the concatenation by taking the characters at the end of one line concatenating them with the characters at the beginning of the next line." float f\ oo; // forms a single line equivalent to "float foo;" // (assuming '\' is the last character before the new line and "oo" are // the first two characters of the next line) Add to the preprocessor: "Preprocessing takes places after new lines have been removed by the line-continuation character." "Including the following line in a shader will enable module import and related extended language features described in this extension: #extension GL_ARB_shading_language_420pack : where is as specified in section 3.3 for the #extension directive." A new preprocessor macro is added to the OpenGL Shading Language: #define GL_ARB_shading_language_420pack 1 Add to the section on comments "Inside comments, any byte values may be used, except a byte whose value is 0. No errors will be given for the content of comments and no validation on the content of comments need be done. "Removal of new lines by the line-continuation character ( \ ) logically occurs before comments are processed. That is, a single-line comment ending in the line-continuation character ( \ ) includes the next line in the comment." // a single-line comment containing the next line \ a = b; // this is still in the first comment Additions to Chapter 4 of the OpenGL Shading Language Add to the syntax description of integer literals: "When tokenizing, the maximal token matching the above will be recognized before a new token is started." Add to the syntax description of floating-point literals: "When tokenizing, the maximal token matching the above will be recognized before a new token is started." Add to the description of .length(): "This returns a type int." Add a new section for initializers "Initializers "At declaration, an initial value for an aggregate variable may be provided, specified as an equals (=) followed by an initializer. The initializer is either an assignment-expression or a list of initializers enclosed in curly braces. The grammar for the initializer is: initializer : assignment-expression { initializer-list } { initializer-list , } initializer-list : initializer initializer-list , initializer "The assignment-expression is a normal expression except that a comma ( , ) outside parentheses is interpreted as the end of the initializer, not as the sequence operator. As explained in more detail below, this allows creation of nested initializers: The aggregate and its initializer must exactly match in terms of nesting, number of components/elements/members present at each level, and types of components/elements/members. "An assignment-expression in an initializer must be either the same type as the object it initializes or be a type that can be converted to the object's type according to section 4.1.10 "Implicit Conversions". Since these include constructors, an aggregate can be initialized by either a constructor or an initializer list; an element in an initializer list can be a constructor. "If an initializer is a list of initializers enclosed in curly braces, the variable being declared must be a vector, a matrix, an array, or a structure. int i = { 1 }; // illegal, i is not an aggregate "A list of initializers enclosed in a matching set of curly braces is applied to one aggregate. This may be the variable being declared or an aggregate contained in the variable being declared. Individual initializers from the initializer list are applied to the elements/members of the aggregate, in order. "If the aggregate has a vector type, initializers from the list are applied to the components of the vector, in order, starting with component 0. The number of initializers must match the number of components. "If the aggregate has a matrix type, initializers from the list must be vector initializers and are applied to the columns of the matrix, in order, starting with column 0. The number of initializers must match the number of columns. "If the aggregate has a structure type, initializers from the list are applied to the members of the structure, in the order declared in the structure, starting with the first member. The number of initializers must match the number of members. "Applying these rules, the following matrix declarations are equivalent: mat2x2 a = mat2( vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) ); mat2x2 b = { vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) }; mat2x2 c = { { 1.0, 0.0 }, { 0.0, 1.0 } }; "All of the following declarations are illegal. float a[2] = { 3.4, 4.2, 5.0 }; // illegal vec2 b = { 1.0, 2.0, 3.0 }; // illegal mat3x3 c = { vec3(0.0), vec3(1.0), vec3(2.0), vec3(3.0) }; // illegal mat2x2 d = { 1.0, 0.0, 0.0, 1.0 }; // illegal, can't flatten nesting struct { float a; int b; } e = { 1.2, 2, 3 }; // illegal "In all cases, the innermost initializer (i.e., not a list of initializers enclosed in curly braces) applied to an object must have the same type as the object being initialized or be a type that can be converted to the object's type according to section 4.1.10 "Implicit Conversions". In the latter case, an implicit conversion will be done on the initializer before the assignment is done. All of the following declarations are illegal. int a = true; // illegal vec4 b[2] = { vec4(0.0), 1.0 }; // illegal mat4x2 c = { vec3(0.0), vec3(1.0) }; // illegal struct S1 { vec4 a; vec4 b; }; struct { float s; float t; } d[] = { S1(vec4(0.0), vec4(1.1)) }; // illegal "If an initializer (of either form) is provided for an unsized array, the size of the array is determined by the number of top-level (non-nested) initializers within the initializer. All of the following declarations create arrays explicitly sized with five elements: float a[] = float[](3.4, 4.2, 5.0, 5.2, 1.1); float b[] = { 3.4, 4.2, 5.0, 5.2, 1.1 }; float c[] = a; // c is explicitly size 5 float d[5] = b; // means the same thing "It is an error to have too few or too many initializers in an initializer list for the aggregate being initialized. That is, all elements of an array, all members of a structure, all columns of a matrix, and all components of a vector must have exactly one initializer expression present, with no unconsumed initializers. Change the definition of the storage qualifier *const* in the table: const | a variable whose value cannot be changed Change the definition of storage qualifiers to only include the following rows const in out attribute uniform varying (Removing "centroid in", "sample in", "centroid out", "sample out", "centroid varying", "patch in", and "patch out".) and with this introduction: "Variable declarations may have at most one storage qualifier specified in front of the type." and make a new class "Auxiliary Storage Qualifier" to contain Auxiliary Storage | Meaning Qualifier | ----------------- ------- centroid | centroid-based interpolation sample | per-sample interpolation patch | per-tessellation-patch attributes add that "Some input and output qualified variables can be qualified with at most one additional auxiliary storage qualifier. "Not all combinations of qualification are allowed. Which variable types can have which qualifiers are specifically defined in upcoming sections." Removing "These interpolation qualifiers may only precede the qualifiers in, centroid in, sample in, out, centroid out, or sample out in a declaration." Change the last paragraph in this section to say "Initializers in global declarations may only be used in declarations of global variables with no storage qualifier, with a *const* qualifier or with a uniform qualifier...." Change the Constant Qualifier section to instead say "Named compile-time constants or read-only variables can be declared using the const qualifier. The const qualifier can be used with any of the non-void transparent basic data types, as well as with structures and arrays of these. It is an error to write to a const variable outside of its declaration, so they must be initialized when declared. For example, const vec3 zAxis = vec3 (0.0, 0.0, 1.0); const float ceiling = a + b; // a and b not necessarily constants "Structure members may not be qualified with *const*. Structure variables can be declared as *const*, and initialized with a structure constructor or initializer. "Initializers for *const* declarations at global scope must be constant expressions..." In the Constant Expressions section, change the *const* bullet to say * a variable declared with the const qualifier and an initializer, where the initializer is a constant expression and add the bullet * valid use of the length() method on a sized object, whether or not the object itself is constant Add to "Inputs" section "It is an error to use any auxiliary or interpolation qualifiers on a vertex shader input." "Applying the *patch* qualifier to inputs can only be done in tessellation evaluation shaders." "The auxiliary storage qualifiers *centroid* and *sample* can also be applied, as well as the interpolation qualifiers *flat*, *noperspective*, and *smooth*." Change all occurances of "patch in qualifier" to "patch qualifier" or "patch in qualifiers". Similarly for any occurances of "patch out", "centroid in", "sample in", "centroid out", and "sample out", through-out the specification. Also change "Fragment shader inputs get per-fragment values, typically interpolated from a previous stage's outputs. They are declared in fragment shaders with the in storage qualifier, the centroid in storage qualifier, ..." to "Fragment shader inputs get per-fragment values, typically interpolated from a previous stage's outputs. They are declared in fragment shaders with the in storage qualifier. The auxiliary storage qualifiers centroid and sample can also be applied, as well as the interpolation qualifiers flat, noperspective, and smooth..." Change "They are declared in fragment shaders with the in storage qualifier, the centroid in storage qualifier, or the deprecated varying and centroid varying storage qualifiers." to "They are declared in fragment shaders with the in storage qualifier or the deprecated varying storage qualifier." Add to the "Outputs" section "A variable also cannot be declared with both the *in* and the *out* qualifiers." Change "Vertex, tessellation evaluation, and geometry output variables output per-vertex data and are declared using the out, centroid out, or sample out storage qualifiers" to "Vertex, tessellation evaluation, and geometry output variables output per-vertex data and are declared using the out storage qualifier" Change "It is an error to use patch out in a vertex, tessellation evaluation, or geometry shader." to "Applying *patch* to an output can only be done in a tessellation control shader." Change "Per vertex output variables are arrayed (see arrayed under 4.3.4 Inputs) and declared using out or centroid out storage qualifiers." to "Per-vertex output variables are arrayed and declared using the *out* qualifier without the *patch* qualifier. Per-patch output variables are declared using the *patch* and *out* storage qualifiers." Add "It is an error to use auxiliary storage qualifiers or interpolation qualifiers on an output in a fragment shader." Modify Interface Blocks with new relaxed qualifier rules: "If optional qualifiers are used, they can include interpolation qualifiers, auxiliary storage qualifiers, and storage qualifiers..." Add to Layout Qualifiers: "More than one layout qualifier may appear in a single declaration. If the same layout-qualifier-name occurs in multiple layout qualifiers for the same declaration, the last one overrides the former ones." Add to Uniform Block Layout Qualifiers, if the base language version is 1.4 or above: layout-qualifier-id binding = integer-constant "The binding identifier specifies the uniform buffer binding point corresponding to the uniform block, which will be used to obtain the values of the member variables of the block. It is an error to specify the binding identifier for the global scope or for block member declarations. Any uniform block declared without a binding identifier is initially assigned to block binding point zero. After a program is linked, the binding points used for uniform blocks declared with or without a binding identifier can be updated by the OpenGL API. "If the binding identifier is used with a uniform block instanced as an array then the first element of the array takes the specified block binding and each subsequent element takes the next consecutive uniform block binding point. "If the binding point for any uniform block instance is less than zero, or greater than or equal to the implementation-dependent maximum number of uniform buffer bindings, a compilation error will occur. When the binding identifier is used with a uniform block instanced as an array of size N, all elements of the array from binding through binding + N - 1 must be within this range." Add for sampler and image layout qualifiers: Note: The "image" variable aspect of this interacts with ARB_shader_image_load_store and only applies if the extension ARB_shader_image_load_store is enabled. "Uniform layout qualifiers can be used to bind opaque uniform variables to specific buffers or units. Texture image units can be bound to samplers and image units can be bound to images. layout-qualifier-id binding = integer-constant "The identifier binding specifies which unit will be bound. Any uniform sampler or image variable declared without a binding qualifier is initially bound to unit zero. After a program is linked, the unit referenced by a sampler or image uniform variable declared with or without a binding identifier can be updated by the OpenGL API. "If the binding identifier is used with an array, the first element of the array takes the specified unit and each subsequent element takes the next consecutive unit. If the binding is less than zero, or greater than or equal to the implementation-dependent maximum supported number of units, a compilation error will occur. When the binding identifier is used with an array of size N, all elements of the array from binding through binding + N - 1 must be within this range." Change the "Interpolation" section to be the "Interplotation Qualifiers" section and change the first paragraph to now be the following. "Inputs and outputs that could be interpolated can be further qualified by at most one of the following interpolation qualifiers: Qualifier Meaning --------- ------- smooth perspective correct interpolation flat no interpolation noperspective linear interpolation "The presence of and type of interpolation is controlled by the above interpolation qualifiers as well as the auxiliary storage qualifiers *centroid* and *sample*. The auxiliary storage qualifier *patch* is not used for interpolation; it is an error to use interpolation qualifiers with *patch*. Add the following parameter qualifier Qualifier Meaning --------- ------- const for function parameters that cannot be written to and note that precision qualifiers are also allowed on parameters. Delete the following sentence in the "Invariant Qualifier" section: "The invariant qualifier must appear before any interpolation qualifiers or storage qualifiers when combined with a declaration." Replace the "Order of Qualification" section with the following 4.11 "Order and Repetition of Qualification" "When multiple qualifiers are present in a variable or parameter declaration, they may appear in any order, but they must all appear before the type. The layout qualifier is the only qualifier that can appear more than once. Further, a declaration can have at most one storage qualifier, at most one auxiliary storage qualifier, and at most one interpolation qualifier. If inout is used, neither in nor out may be used. Multiple memory qualifiers can be used. Any violation of these rules will cause a compile-time error." Additions to Chapter 5 of the OpenGL Shading Language Change the section title "Vector Components" to be "Vector and Scalar Components and Length". In that section do the following. Change first sentence to "The names of the components of a vector or scalar are denoted by a single letter." Add the following last sentence to its paragraph: "The component names x, r, and s are, for example, synonyms for the same (first) component in a vector. They are also the names of the only component in a scalar." Add to the example float height; height.x // is legal height.y // is illegal and to the third example float f = 1.2; vec4 dup = f.xxxx; // dup = (1.2, 1.2, 1.2, 1.2) "This notation is more concise than the constructor syntax. To form an r-value, it can be applied to any expression that results in a vector or scalar r-value. Any resulting vector of any operation must be a valid vector in the language; hence the following is illegal:" vec4 f; vec4 g = pos.xyzwxy.xyzw; // illegal; pos.xyzwxy is non-existent "vec6" Add to the end of this section: "The *length* method may be applied to vectors (but not scalars). The result is the number of components in the vector. For example, vec3 v; const int L = v.length(); "sets the constant L to 3. The type returned by .length() on a vector is *int*." Add to the Matrix Components section: "The length method may be applied to matrices. The result is the number of columns of the matrix. For example, mat3x4 v; const int L = v.length(); "sets the constant L to 3. The type returned by .length() on a matrix is *int*." Additions to Chapter 6 of the OpenGL Shading Language Add to the "Function Definitions" section the following functionality regarding function return values: "If the type of returnValue does not match returnType, there must be an implicit conversion in section 4.1.10 "Implicit Conversions" that converts the type of returnValue to returnType, or a compile error will result." and the clarifations: "A void function can only use return without a return argument, even if the return argument has void type. Return statements only accept values: void func1() { } void func2() { return func1(); } // illegal return statement "Only a precision qualifier is allowed on the return type of a function. Formal parameters can have parameter, precision, and memory qualifiers, but no other qualifiers." Under the section "Function Calling Conventions" change to the *inout* bullet: * "The keyword *inout* is used as a qualifier to denote the parameter is to be both copied in and copied out. It means the same thing as specifying both in and out." and the following grammar changes: Delete the const-qualifier parts of the existing grammar and instead use parameter-qualifiers : empty list of parameter-qualifier parameter-qualifier : empty const in out inout memory qualifier precision qualifier Additions to Chapter 7 of the OpenGL Shading Language Add to the built-in constants const int gl_MinProgramTexelOffset = -7; const int gl_MaxProgramTexelOffset = 8; Additions to Chapter 9 of the OpenGL Shading Language TBD. Conformance Tests Verify that the following two vectors are identical: vec4 a = vec4(1.0); vec4 b = (1.0).xxxx; Verify that the following generates a compilation error: vec2 a = 1.xx; Verify that the following two vectors are identical: vec2 a = (1).xx; vec2 b = vec2(1.0); Verify that the following two arrays are identical: vec4 a[] = vec4 [] (vec4(1.2), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(2.4), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(3.6)); vec4 b[] = { vec4(1.2), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(2.4), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(3.6) }; Verify that the following two arrays are identical: vec4 a[12] = vec4 [] (vec4(1.2), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(2.4), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0)); vec4 b[12] = { vec4(1.2), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(0.0), vec4(2.4) }; Verify that the following three matrices are identical: mat2x2 a = mat2( vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) ); mat2x2 b = { vec2( 1.0, 0.0 ), vec2( 0.0, 1.0 ) }; mat2x2 c = { { 1.0, 0.0 }, { 0.0, 1.0 } }; Verify that the following generates a compliation error: float a[2] = { 1.0, 2.0, 3.0 }; Verify that the following generates a compliation error: mat2x2 d = { 1.0, 0.0, 0.0, 1.0 }; Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (vec2(0).length() == 2) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with vec2(0).length() replaced by ivec2(0).length(). Repeat the above test with vec2(0).length() replaced by uvec2(0).length(). Repeat the above test with vec2(0).length() replaced by bvec2(0).length(). Repeat the above test with vec2(0).length() replaced by dvec2(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (vec3(0).length() == 3) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with vec3(0).length() replaced by ivec3(0).length(). Repeat the above test with vec3(0).length() replaced by uvec3(0).length(). Repeat the above test with vec3(0).length() replaced by bvec3(0).length(). Repeat the above test with vec3(0).length() replaced by dvec3(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (vec4(0).length() == 4) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with vec4(0).length() replaced by ivec4(0).length(). Repeat the above test with vec4(0).length() replaced by uvec4(0).length(). Repeat the above test with vec4(0).length() replaced by bvec4(0).length(). Repeat the above test with vec4(0).length() replaced by dvec4(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat2(0).length() == 2) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat2(0).length() replaced by mat2x2(0).length(). Repeat the above test with mat2(0).length() replaced by dmat2x2(0).length(). Repeat the above test with mat2(0).length() replaced by mat2x3(0).length(). Repeat the above test with mat2(0).length() replaced by dmat2x3(0).length(). Repeat the above test with mat2(0).length() replaced by mat2x4(0).length(). Repeat the above test with mat2(0).length() replaced by dmat2x4(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat3(0).length() == 3) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat3(0).length() replaced by mat3x2(0).length(). Repeat the above test with mat3(0).length() replaced by dmat3x2(0).length(). Repeat the above test with mat3(0).length() replaced by mat3x3(0).length(). Repeat the above test with mat3(0).length() replaced by dmat3x3(0).length(). Repeat the above test with mat3(0).length() replaced by mat3x4(0).length(). Repeat the above test with mat3(0).length() replaced by dmat3x4(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat4(0).length() == 4) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat4(0).length() replaced by mat4x2(0).length(). Repeat the above test with mat4(0).length() replaced by dmat4x2(0).length(). Repeat the above test with mat4(0).length() replaced by mat4x3(0).length(). Repeat the above test with mat4(0).length() replaced by dmat4x3(0).length(). Repeat the above test with mat4(0).length() replaced by mat4x4(0).length(). Repeat the above test with mat4(0).length() replaced by dmat4x4(0).length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat2(0)[0].length() == 2) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat2(0)[0].length() replaced by mat2x2(0)[0].length(). Repeat the above test with mat2(0)[0].length() replaced by dmat2x2(0)[0].length(). Repeat the above test with mat2(0)[0].length() replaced by mat3x2(0)[0].length(). Repeat the above test with mat2(0)[0].length() replaced by dmat3x2(0)[0].length(). Repeat the above test with mat2(0)[0].length() replaced by mat4x2(0)[0].length(). Repeat the above test with mat2(0)[0].length() replaced by dmat4x2(0)[0].length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat3(0)[0].length() == 3) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat3(0)[0].length() replaced by mat2x3(0)[0].length(). Repeat the above test with mat3(0)[0].length() replaced by dmat2x3(0)[0].length(). Repeat the above test with mat3(0)[0].length() replaced by mat3x3(0)[0].length(). Repeat the above test with mat3(0)[0].length() replaced by dmat3x3(0)[0].length(). Repeat the above test with mat3(0)[0].length() replaced by mat4x3(0)[0].length(). Repeat the above test with mat3(0)[0].length() replaced by dmat4x3(0)[0].length(). Verify that the output of the following fragment shader is (0, 1, 0, 1): #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { color = (mat4(0)[0].length() == 4) ? vec4(0, 1, 0, 1) : vec4(1, 0, 0, 1); } Repeat the above test with mat4(0)[0].length() replaced by mat2x4(0)[0].length(). Repeat the above test with mat4(0)[0].length() replaced by dmat2x4(0)[0].length(). Repeat the above test with mat4(0)[0].length() replaced by mat3x4(0)[0].length(). Repeat the above test with mat4(0)[0].length() replaced by dmat3x4(0)[0].length(). Repeat the above test with mat4(0)[0].length() replaced by mat4x4(0)[0].length(). Repeat the above test with mat4(0)[0].length() replaced by dmat4x4(0)[0].length(). Verify that the following shader generates a compilation error: #version 410 #extension GL_ARB_shading_language_420pack: require out vec4 color; void main() { float v; int l = v.length(); color = vec4(1, 0, 0, 1); } Repeat the above test with "float v" replaced by "int v". Repeat the above test with "float v" replaced by "uint v". Repeat the above test with "float v" replaced by "bool v". Repeat the above test with "float v" replaced by "double v". Verify that the following shader compiles without error: #version 410 #extension GL_ARB_shading_language_420pack: require void main() { float b[vec2(0).length()]; } Repeat the above test with vec2(0).length() replaced by ivec2(0).length(). Repeat the above test with vec2(0).length() replaced by uvec2(0).length(). Repeat the above test with vec2(0).length() replaced by bvec2(0).length(). Repeat the above test with vec2(0).length() replaced by dvec2(0).length(). Repeat the above test with vec2(0).length() replaced by ivec3(0).length(). Repeat the above test with vec2(0).length() replaced by uvec3(0).length(). Repeat the above test with vec2(0).length() replaced by bvec3(0).length(). Repeat the above test with vec2(0).length() replaced by dvec3(0).length(). Repeat the above test with vec2(0).length() replaced by ivec4(0).length(). Repeat the above test with vec2(0).length() replaced by uvec4(0).length(). Repeat the above test with vec2(0).length() replaced by bvec4(0).length(). Repeat the above test with vec2(0).length() replaced by dvec4(0).length(). Repeat the above test with vec2(0).length() replaced by mat2(0).length(). Repeat the above test with vec2(0).length() replaced by mat2x2(0).length(). Repeat the above test with vec2(0).length() replaced by mat2x3(0).length(). Repeat the above test with vec2(0).length() replaced by mat2x4(0).length(). Repeat the above test with vec2(0).length() replaced by mat3(0).length(). Repeat the above test with vec2(0).length() replaced by mat3x2(0).length(). Repeat the above test with vec2(0).length() replaced by mat3x3(0).length(). Repeat the above test with vec2(0).length() replaced by mat3x4(0).length(). Repeat the above test with vec2(0).length() replaced by mat4(0).length(). Repeat the above test with vec2(0).length() replaced by mat4x2(0).length(). Repeat the above test with vec2(0).length() replaced by mat4x3(0).length(). Repeat the above test with vec2(0).length() replaced by mat4x4(0).length(). Repeat the above test with vec2(0).length() replaced by dmat2(0).length(). Repeat the above test with vec2(0).length() replaced by dmat2x2(0).length(). Repeat the above test with vec2(0).length() replaced by dmat2x3(0).length(). Repeat the above test with vec2(0).length() replaced by dmat2x4(0).length(). Repeat the above test with vec2(0).length() replaced by dmat3(0).length(). Repeat the above test with vec2(0).length() replaced by dmat3x2(0).length(). Repeat the above test with vec2(0).length() replaced by dmat3x3(0).length(). Repeat the above test with vec2(0).length() replaced by dmat3x4(0).length(). Repeat the above test with vec2(0).length() replaced by dmat4(0).length(). Repeat the above test with vec2(0).length() replaced by dmat4x2(0).length(). Repeat the above test with vec2(0).length() replaced by dmat4x3(0).length(). Repeat the above test with vec2(0).length() replaced by dmat4x4(0).length(). More TBD. Issues 1) How is the ambiguity of swizzling an integer literal resolved? RESOLVED: Greedy lexing. The sequence "5.x" will be interpreted as the floating-point literal 5.0 followed by the identifier "x". 2) Should the array subscript operator be applicable to scalars as it is to vectors? RESOLVED: NO. In conduction with the rest of the features of this extension, this would allow writing generic code such as: #define SUM_COMPONENTS(value, result) \ do { for (int i = 0; i < (value).length(); i++) result += (value)[i]; } while (0) However, using macros in this fashion is a poor approximation of generic functions. Until a better mechanism is added to GLSL, there is little utility in array accesses to scalars or single component vectors. 3) Should vectors and matrices also be able to use initializer lists? RESOLVED: YES. Many places in the language treat vectors as 2, 3, or 4 element arrays of a scalar type. Matrices are often treated as arrays of vector types. Continuing that treatment here is logical. 4) What happens when an explicitly sized array is initialized with too few elements? Is it allowed? RESOLVED: DISALLOWED. In C/C++ this is allowed. The uninitialized elements are implicitly initialized to the appropriate reprensentation of zero. However, the belief is that this enables a variety of programming errors that are difficult to debug on a GPU. 5) Can scalars be initialized using an initializer list? RESOLVED: NO. In C/C++ this is allowed. The ISO C99 specification specifically say, "The initializer for a scalar shall be a single expression, optionally enclosed in braces." However, this may pose problems if / when a vec1 type is added. 6) Are initializer lists for vectors flexible in the same way that vector constructors are? Specifically, is the initialzier list for 'c', below, legal? vec2 a = vec2(2, 3); vec4 b = vec4(1, a, 4); // b = { 1, 2, 3, 4 } vec4 c = { 1, a, 4 }; // Legal? RESOLVED: NO. In C++ there is a distinction between a constructor and an initializer list. If you had vec2 and vec4 classes in C++, a constructor 'vec4(float, vec2, float)' might exist, but the initializer list for 'c' would not be legal. 7) Does adding *const* for read-only variables effect array sizing? RESOLVED. No. Array sizing changes are not part of this proposal. Array sizing rules stay the same, where sizes must be compile-time constants, whether or not the keyword 'const' was involved, just like it always has been. The following was and still is disallowed: "void foo(const s) { int a[s]; }", as will be "void foo() { const s = exp; int a[s]; }". 8) Should we allow non-compile-time constant initializers for const at global scope as well? RESOLVED. No. Would make linking more difficult. 9) Do we want to add the new C++ constexpr for declaring constant functions? RESOLVED. No, not yet, could be a potential performance benefit in the future, but treat as a separate extension. Note that most built-in functions are already understood to be "constexpr". This has been submitted into bugzilla. 10) What combinations of interpolation qualifiers are allowed? Before, you could take one of smooth, flat, and noperspective and combine that with one of centroid, sample, or patch. What do combinations do we actually want? Do we want multiple intances of a single qualifier allowed? (E.g. two layout qualifiers, or "in out"?) RESOLVED. Allow multiple "layout". Not anything else. 11) Should we allow multiple block declarations to use the same binding point? For example: layout(binding = 3) uniform Block1 { ... }; layout(binding = 3) uniform Block2 { ... }; RESOLVED: There is no reason to disallow this usage; in particular, existing UBO shaders effectively declare all blocks with "layout(block = 0)". 12) Should the qualifier be called "location", "block" or "binding"? RESOLVED: The qualifier is called "binding" because it makes it more clear what parameter of UniformBlockBinding that this qualifier affects. "block" could be confused with either the or and "location" might be confused with the current uses of the qualifier "location" for attribute locations or it could be confused with uses of "location" for uniform variable location, which blocks don't have. 13) Should sampler initialization use a layout(binding) qualifier instead of specifying a uniform initializer? RESOLVED: Revision #4 of the sampler initialization spec uses a layout(binding) qualifier for sampler uniforms. This is more forward looking and makes the spec more consistent with ARB_uniform_block_binding_initialization and ARB_shader_atomic_counters. Revision History Revision 4, 11-Sep-2014 (pbrown) - Fix minor typo. Revision 3, 13-May-2014 (John Kessenich) - Resolve bug 10593. Revision 2, 25-Jul-2011 (John Kessenich) - Mark as complete and approved. - Tidy up some formating and non-raw-text quote marks. - Pull in the initializers for images, to completely subsume GL_ARB_uniform_sampler_initialization. - Point out image and patch dependencies. Revision 1, 5-Jul-2011 (John Kessenich) - Initial version. Formed by combing the content of the 4.20 draft specification and the content of draft extensions: * ARB_shading_language_vec1 * ARB_shading_language_relaxed_qualifiers * ARB_shading_language_length * ARB_shading_language_initializer_list * GL_ARB_uniform_block_binding_initialization * GL_ARB_uniform_sampler_initialization (just sampler binding) Issues were carried across and renumbered. Conformance tests were carried over.