OpenGL Shading Language (GLSL) Specification

repository·main·Indexed 19 days ago

https://github.com/khronosgroup/glsl

Documentation and specifications for the OpenGL Shading Language (GLSL) and OpenGL ES Shading Language (ESSL). Includes details on language versions, preprocessor directives, compilation phases, and extension specifications. Provides instructions for building the specification into HTML5 and PDF formats using the Khronos-provided Docker image and AsciiDoc.

Tokens
46.7K
Snippets
119
Records
187
Agent score
65%

What's inside GLSL

  1. Overview of the GLSL Repository

    main

    This repository contains the source for the GLSL (OpenGL Shading Language) Specification and various GLSL extensions. It primarily focuses on extensions related to Vulkan, specifically those that are not part of the standard Khronos registries for OpenGL or OpenGL ES.

    Key features include:

    • New shading language extension proposals and discussions.
    • Issue tracking for unreleased extensions.

    Note on Source of Truth: While a Khronos internal GitLab mirror exists, the public GitHub repository is considered the true source for extensions once they have moved to GitHub.

  2. GLSL Specification Navigation Structure

    main

    The GLSL specification documentation is organized into several top-level chapters. The navigation follows the order of the core specification. Note that certain chapters, such as interfacematching.adoc and iocounting.adoc, are conditionally included only when the ESSL (EGL SL) attribute is defined during the Antora build process.

    * xref:chapters/preamble.adoc[]
    * xref:chapters/introduction.adoc[]
    * xref:chapters/overview.adoc[]
    * xref:chapters/basics.adoc[]
    * xref:chapters/variables.adoc[]
    * xref:chapters/operators.adoc[]
    * xref:chapters/statements.adoc[]
    * xref:chapters/builtins.adoc[]
    * xref:chapters/builtinfunctions.adoc[]
    ifdef::ESSL[]
    * xref:chapters/interfacematching.adoc[]
    endif::ESSL[]
    * xref:chapters/grammar.adoc[]
    ifdef::ESSL[]
    * xref:chapters/iocounting.adoc[]
    endif::ESSL[]
    * xref:chapters/acknowledgements.adoc[]
    * xref:chapters/references.adoc[]
    * xref:chapters/spirvmappings.adoc[]
  3. Understand the licensing for the GLSL project

    main

    The KhronosGroup/GLSL repository uses multiple licenses depending on the type of file. When using or redistributing files from this repository, ensure you identify the correct license for the specific file type:

    • Apache License 2.0 (Apache-2.0): Applied to most files and scripts in the repository.
    • Creative Commons Attribution 4.0 International (CC-BY-4.0): Applied to specification source documents.
    • MIT License (MIT): Applied to files that have been copied from other MIT-licensed projects.
  4. Targeting Vulkan via SPIR-V generation

    main

    When using GLSL to generate SPIR-V for consumption by the Vulkan API, this is referred to as targeting Vulkan.

    SPIR-V generation is not triggered by a #extension, #version, or a specific profile. Instead, it is determined by the offline toolchain used (e.g., a compiler like glslang).

    When using such tools, you must direct the compiler regarding which SPIR-V Capabilities are legal at run-time. The compiler can also be informed of implementation-dependent limits to report errors when they are exceeded in the source code.

  5. Input/Output Matching in Linked Programs

    main

    When linking shaders (e.g., vertex and fragment shaders) into a program object, variables passed between stages via in and out qualifiers must match by name and type.

    Key Rules:

    • Type Matching: The type of declared vertex outputs and fragment inputs with the same name must match, or the link command will fail.
    • Static Use: Only fragment inputs that are actually read (statically used) in the fragment shader must be declared as outputs in the vertex shader. Declaring extra outputs in the vertex shader is allowed.
    • Precision: The precision of a vertex output does not need to match the precision of the corresponding fragment input. The interpolation precision is determined by the minimum of the two.
    • Transform Feedback: Outputs exported to a transform feedback buffer use the vertex shader output precision but are converted to highp before being written.

    Mismatched Variable Behavior:

    Generating Shader (output)Consuming Shader (input)Result
    No DeclarationNo DeclarationAllowed
    No DeclarationDeclared but no Static UseAllowed
    No DeclarationDeclared and Static Useerror
    Declares; no static UseNo DeclarationAllowed
    Declares; no static UseDeclared but no Static UseAllowed
    Declares; no static UseDeclared and Static UseAllowed (values undefined)
    Declares and static UseNo DeclarationAllowed
    Declares and static UseDeclared but no Static UseAllowed
    Declares and static UseDeclared and Static UseAllowed (values potentially undefined)
  6. Use Uniform Variables with the 'uniform' qualifier

    main

    The uniform qualifier declares global variables that remain constant across an entire primitive.

    Usage Rules:

    • Read-only: All uniform variables are read-only.
    • Initialization: In GLSL, they can be initialized with a value (used at link time). In ESSL, they are initialized to 0 at link time (except for variables within a uniform block).
    • Vulkan Note: When targeting Vulkan, you must declare uniform variables within a block.
    • Namespace: Uniforms share a single global name space when linked. Types, precisions, and location specifiers for variables with the same name must match across all linked shaders.
    • Locations: Uniform locations are logical values and do not overlap. For example, layout(location = 2) uniform mat4 x; and layout(location = 3) uniform mat4 y; are distinct.
    uniform vec4 lightPosition;
    uniform vec3 color = vec3(0.7, 0.7, 0.2); // value assigned at link time
    
    // Using locations
    layout(location = 2) uniform mat4 x;
    layout(location = 3) uniform mat4 y;
  7. Use iteration statements: for, while, and do-while

    main

    GLSL supports three types of loops:

    • for loop: for (init-expression; condition-expression; loop-expression) sub-statement
      • Variables declared in init-expression or condition-expression are only in scope until the end of the loop body.
    • while loop: while (condition-expression) sub-statement
      • Variables declared in condition-expression are only in scope until the end of the loop body.
    • do-while loop: do { statement } while (condition-expression)
      • The condition-expression cannot declare a variable.

    Note: Non-terminating loops are allowed, but their consequences are platform-dependent.

    for (int i = 0; i < 10; i++) {
        // loop body
    }
    
    while (condition) {
        // loop body
    }
    
    do {
        // loop body
    } while (condition);
  8. Understand GLSL Type Specifiers and Qualifiers

    main

    A type_specifier is composed of a type_specifier_nonarray and an optional array_specifier.

    Types are modified by type_qualifiers, which can include:

    • Storage Qualifiers: const, in, out, inout, centroid, patch, sample, uniform, buffer, shared, coherent, volatile, restrict, readonly, writeonly.
    • Layout Qualifiers: layout(...) used to specify resource bindings.
    • Precision Qualifiers: highp, mediump, lowp.
    • Interpolation Qualifiers: smooth, flat, noperspective (GLSL only).
    • Other Qualifiers: invariant, precise.
  9. Understand non-uniform control flow in GLSL

    main

    Non-uniform control flow occurs when different shader invocations follow different execution paths. This can lead to performance issues or undefined behavior in certain hardware contexts. Common causes include:

    • Loops: When some invocations execute specific iterations that others do not.
    • Conditional Statements: Using break, continue, or return inside loops or branches where the condition evaluates differently across fragments.
    • Fragment Discards: Using discard when the condition is true for some fragments but not others.

    Note that constant expressions are considered trivially dynamically uniform, meaning loop counters based on constant expressions are generally safe from non-uniformity issues.

  10. Access Vector and Matrix components

    main

    Components can be accessed via dot notation (swizzling) or array subscripting.

    Swizzling (Dot Notation)

    Vectors support component selection using names from these sets:

    • Spatial: x, y, z, w
    • Color: r, g, b, a
    • Texture: s, t, p, q

    Components are synonyms (e.g., x, r, and s all refer to the first component). You can select multiple components in any order to create a new vector (swizzling).

    Rules:

    • You cannot select more than 4 components.
    • You cannot use duplicate components when assigning to an l-value (e.g., pos.xx = ... is illegal).
    • Swizzling can be used on both r-values (to read) and l-values (to write).

    Array Subscripting

    Vectors support numeric indexing (e.g., pos[2] is equivalent to pos.z).

    • Indexing starts at 0.
    • For non-constant indices, behavior is undefined if the index is out of bounds.

    Matrix Access

    Matrices are treated as arrays of column vectors.

    • m[1] selects the second column (a vector).
    • m[0][0] selects the element at column 0, row 0.

    Length Method

    • vector.length() returns the number of components in the vector (as an int).
    • matrix.length() returns the number of columns in the matrix (as an int).
    vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
    vec4 swiz = pos.wzyx;   // (4.0, 3.0, 2.0, 1.0)
    vec4 dup = pos.xxyy;    // (1.0, 1.0, 2.0, 2.0)
    
    pos.xw = vec2(5.0, 6.0); // writes to components
    
    mat4 m;
    m[1] = vec4(2.0);      // sets second column to 2.0
    m[0][0] = 1.0;         // sets upper left element
  11. How GLSL versioning and #version declarations work

    main

    The GLSL language version is specified using the #version directive. The version number provided in this directive determines the language rules applied to the shader.

    If a smaller version number is declared, the compiler will use the rules of that previous version (subject to API context support).

    For GLSL, the directive follows the pattern #version {version}. (e.g., #version 450.). For ESSL, it follows #version {version} es (e.g., #version 320 es).

    #version 450