M2 — GLSL

The OpenGL Shading Language — Stages, Type System, Toolchain
Module 2 · Tibsfox Research · April 20, 2026

M2 — GLSL: The OpenGL Shading Language — Stages, Type System, and Toolchain

Section 1 — Origin

The OpenGL Shading Language (GLSL, also referred to historically as GLslang) was designed to give developers direct, high-level control over the programmable stages of the graphics pipeline. GLSL is a component of the OpenGL Application Programming Interface (API): each major GLSL version ships with a specific OpenGL host version (for example, GLSL 4.60 ships with OpenGL 4.6; see the version table in §2). Before GLSL, Graphics Processing Unit (GPU) programmability was expressed through architecture-specific assembly languages: the ARB vertex program (ARB_vertex_program) and ARB fragment program (ARB_fragment_program) extensions introduced in OpenGL 1.4 (2002) provided per-vertex and per-fragment programmability using a register-based instruction set derived from hardware micro-architecture. These assembly extensions required developers to reason in terms of hardware registers and instruction counts, severely limiting portability and maintainability.

GLSL was introduced by the OpenGL ARB (Architecture Review Board) as the ARB_vertex_shader and ARB_fragment_shader extensions alongside OpenGL 1.4, and was formally promoted into the OpenGL 2.0 core in 2004 [Khronos OGL Wiki — Core Language (GLSL) — khronos.org/opengl/wiki/Core_Language_(GLSL)]. The language adopted a C-like syntax — deliberately familiar to system programmers — while stripping constructs that are undefined or hazardous on parallel GPU hardware: no pointers, no dynamic memory allocation, no recursion (detected and rejected at compile time), and no file I/O. In return, GLSL added first-class vector and matrix types, swizzling, and a rich library of GPU-specific built-in functions. According to the Wikipedia “OpenGL Shading Language” article, GLSL’s core introduction in OpenGL 2.0 was the first major revision to the API since the original 1.0 release in 1992 [Wikipedia — OpenGL Shading Language].

Governance follows the same path as OpenGL itself: the ARB drafted GLSL — which is why GLSL shipped under the ARB before Khronos took over — the Khronos Group took over stewardship in September 2006 (the ARB-to-Khronos 2006 handoff documented in M1 §1), and the GLSL specification is maintained as part of the OpenGL Working Group within Khronos. The authoritative specification document is hosted at the Khronos registry as “OpenGL Shading Language, Version 4.60.8” [GLSL 4.60 spec — registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf].


Section 2 — Versions

GLSL Desktop Version History

GLSL versions track the OpenGL version that first exposed them, but the numbering was misaligned until OpenGL 3.3 / GLSL 3.30. Starting with OpenGL 3.3 (2010), Khronos deliberately realigned the GLSL version number to match the OpenGL version: GL 3.3 uses GLSL 3.30, GL 4.0 uses GLSL 4.00, GL 4.1 uses GLSL 4.10, and so on through 4.60 [Khronos OGL Wiki — History of OpenGL]. This realignment was an explicit governance decision to reduce developer confusion; before it, GLSL 1.50 paired with OpenGL 3.2 while GLSL 3.30 paired with OpenGL 3.3, creating an apparent numbering jump.

GLSL Version GL Host Year Key Additions
1.10 OpenGL 2.0 2004 Original core GLSL; vertex shader + fragment shader; attribute, varying, uniform qualifiers
1.20 OpenGL 2.1 2006 mat2x3, mat3x4 non-square matrices; transpose(), outerProduct(); invariance qualifiers
1.30 OpenGL 3.0 2008 in / out replace attribute / varying; integer types; bitwise operators; texture functions revised
1.40 OpenGL 3.1 2009 Uniform blocks (layout(std140)); textureFetch; dynamic indexing of samplers
1.50 OpenGL 3.2 2009 Geometry shader stage; interface blocks; gl_PerVertex block; layout specifiers on I/O
3.30 OpenGL 3.3 2010 Version realigned with GL; layout(location = N) on vertex inputs; uint bitfield functions
4.00 OpenGL 4.0 2010 Tessellation control + evaluation shader stages; double / dvec / dmat types; 64-bit uniforms
4.10 OpenGL 4.1 2010 Viewport-index in geometry shader; gl_DepthRangeParameters
4.20 OpenGL 4.2 2011 Atomic counters; image types (image2D, imageBuffer); layout(binding = N) on uniforms
4.30 OpenGL 4.3 2012 Compute shader stage; Shader Storage Buffer Objects (SSBOs); layout(local_size_x/y/z); explicit array stride
4.40 OpenGL 4.4 2013 layout(std430) on uniform blocks; multi-bind layout qualifiers
4.50 OpenGL 4.5 2014 Derivative control (GL_ARB_derivative_control); conservative depth output
4.60 OpenGL 4.6 2017 SPIR-V consumption; subgroup operations; GL_KHR_vulkan_glsl extensions documented

[GLSL 4.60 spec — registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf], [Khronos OGL Wiki — History of OpenGL]

GLSL ES (Embedded Systems Shading Language) Sub-table

GLSL ES (also called ESSL — Embedded Systems Shading Language) is the variant of GLSL used by OpenGL ES and WebGL. While closely related to desktop GLSL, GLSL ES has a distinct specification with tighter precision requirements, mandatory precision qualifiers in earlier versions, and a smaller built-in function set [GLSL ES 3.20 spec — registry.khronos.org/OpenGL/specs/es/3.2/GLSL_ES_Specification_3.20.pdf].

GLSL ES Version ES/WebGL Host Year Notes
1.00 OpenGL ES 2.0 / WebGL 1.0 2007 Mandatory precision qualifier; highp/mediump/lowp; attribute/varying keywords
3.00 OpenGL ES 3.0 / WebGL 2.0 2012 in/out replace attribute/varying; uniform blocks; instanced arrays; texelFetch
3.10 OpenGL ES 3.1 2014 Compute shaders; image load/store; SSBOs; atomic ops
3.20 OpenGL ES 3.2 2015 Geometry and tessellation shaders; spec updated 2023

[Khronos OpenGL ES 3.2 specification — registry.khronos.org/OpenGL/specs/es/3.2/es_spec_3.2.pdf], [GLSL ES 3.20 spec — registry.khronos.org/OpenGL/specs/es/3.2/GLSL_ES_Specification_3.20.pdf]


Section 3 — Features

GLSL follows a compile-link workflow analogous to compiled C code [Khronos OGL Wiki — Shader — khronos.org/opengl/wiki/Shader]. Each shader source string is submitted to the driver as a shader object via glShaderSource and compiled with glCompileShader. The driver runs a front-end compilation pass that produces driver-internal intermediate code; compilation errors are retrieved as a human-readable info log via glGetShaderInfoLog. One or more compiled shader objects are then attached to a program object via glAttachShader and linked with glLinkProgram. The linker validates interface matching between stages (output variables of the vertex shader must match input variables of the fragment shader by name and type in GLSL 1.30 and earlier, or by explicit location in 3.30+), resolves uniform locations, and produces the final binary that the GPU executes. The linked program is installed for subsequent draw calls with glUseProgram.

This compile-link model has important practical implications: driver compilation occurs at runtime the first time a program is linked, introducing a latency spike during gameplay or application startup. OpenGL 4.1 introduced program binary caching (GL_ARB_get_program_binary) to amortize this cost across sessions. OpenGL 4.6 added SPIR-V ingestion as an alternative front-end that bypasses the driver’s GLSL front-end entirely, loading pre-compiled binary modules instead.

3.2 The Six Programmable Shader Stages

GLSL targets six distinct programmable stages of the OpenGL rendering pipeline. Each stage is compiled into its own shader object and operates on a different unit of the pipeline [Khronos OGL Wiki — Shader — khronos.org/opengl/wiki/Shader], [Khronos OGL Wiki — Core Language (GLSL)]:

1. Vertex Shader (introduced GL 2.0 / GLSL 1.10) - Role: transforms per-vertex data from application-supplied buffer objects into clip-space coordinates. - Inputs: vertex attributes declared with the in qualifier, accessed by location index; built-in input gl_VertexID, gl_InstanceID. - Outputs: values passed to the next stage via out variables; the built-in output gl_Position (vec4, clip-space position) is mandatory. - A vertex shader is required for every OpenGL program object.

2. Tessellation Control Shader (introduced GL 4.0 / GLSL 4.00) - Role: runs once per output control point of a tessellation patch; sets the tessellation levels that determine how finely the subsequent tessellation evaluation stage subdivides the patch. - Inputs: all vertex shader outputs for the patch, indexed by gl_InvocationID; gl_in[] array. - Outputs: per-control-point data in gl_out[]; the mandatory built-in outputs gl_TessLevelOuter[4] and gl_TessLevelInner[2]. - Optional; must be paired with a tessellation evaluation shader.

3. Tessellation Evaluation Shader (introduced GL 4.0 / GLSL 4.00) - Role: runs once per tessellated vertex generated by the fixed-function tessellator; computes the final position of each new vertex by interpolating across the patch. - Inputs: control-point outputs from the tessellation control shader; gl_TessCoord (the barycentric or UV coordinate of the tessellated vertex within the patch). - Outputs: same interface as vertex shader outputs — gl_Position and user-defined out variables. - Can be used without a tessellation control shader (tessellation levels then come from default values or glPatchParameterfv).

4. Geometry Shader (introduced GL 3.2 / GLSL 1.50) - Role: receives complete assembled primitives (triangles, lines, or points) after vertex / tessellation processing and may emit zero or more output primitives, potentially of a different type. - Inputs: gl_in[] array of per-vertex data for the input primitive; gl_PrimitiveIDIn. - Outputs: emitted via EmitVertex() and EndPrimitive() calls; output primitive type declared via layout(triangles) in; layout(triangle_strip, max_vertices = N) out;. - Useful for layered rendering, cube-map face selection, and particle systems, though geometry shaders carry significant performance overhead on some GPU architectures.

5. Fragment Shader (introduced GL 2.0 / GLSL 1.10) - Role: runs once per fragment generated by rasterization; computes per-fragment color and depth values that are written to the framebuffer after per-sample operations. - Inputs: interpolated outputs from the previous stage (vertex or geometry); built-ins gl_FragCoord, gl_FrontFacing, gl_PointCoord. - Outputs: one or more out vec4 color outputs mapped to draw-buffer attachment points via layout(location = N); optional write to gl_FragDepth. - The fragment shader is required in standard rendering programs; it may be omitted only for depth-only passes (shadow maps, pre-z passes) where the driver performs implicit depth writes.

6. Compute Shader (introduced GL 4.3 / GLSL 4.30) - Role: executes arbitrary, data-parallel computation entirely outside the fixed rendering pipeline; used for particle simulation, physics, image post-processing, and other General-Purpose GPU (GPGPU) workloads within the OpenGL context. - Inputs: no vertex or primitive inputs; operates on SSBOs, image units, and atomic counters. Launched via glDispatchCompute(num_groups_x, num_groups_y, num_groups_z). - Outputs: writes to SSBOs or image objects; results are memory-fence-synchronized with subsequent draw or compute dispatches. - Work-group dimensions are declared in the compute shader itself: layout(local_size_x = 32, local_size_y = 32, local_size_z = 1) in;.

3.3 Type System

GLSL’s type system is statically typed and closed — all types are known at compile time, and implicit conversions are limited [GLSL 4.60 spec — registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf]:

3.4 Qualifiers

GLSL uses qualifiers to annotate variables with their origin, destination, and memory layout:

3.5 The #version Directive and Profile Selection

Every GLSL shader should begin with a #version directive that declares the language version and, for versions 1.50 and later, the profile [Khronos OGL Wiki — Core Language (GLSL)]. The syntax is:

#version 460 core
#version 460 compatibility
#version 320 es

If no #version directive is present, the driver treats the shader as GLSL 1.10, which pre-dates in/out qualifiers, integer types, and most modern features — effectively guaranteeing misbehavior on any modern program. The #version must be the very first token in the source string (preceding even blank lines in strict implementations).

For GLSL ES shaders, the version token is 100 (GLSL ES 1.00), 300 es, 310 es, or 320 es. The es profile suffix is mandatory for GLSL ES 3.00 and later.

3.6 Interface Blocks and Uniform Buffers

Interface blocks group related variables into named structures that can be matched across stages or backed by a GPU buffer [GLSL 4.60 spec — registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf]. Uniform Buffer Objects (UBOs) declared with layout(std140, binding = 0) uniform MatrixBlock { mat4 model; mat4 view; mat4 projection; }; allow the same buffer to be shared across multiple program objects without re-uploading per-program. The std140 layout rule specifies deterministic member offsets, making the buffer layout predictable without driver-specific queries. The std430 layout, available for SSBOs since GLSL 4.30, uses tighter packing for arrays of scalars and small vectors.


Section 4 — Ecosystem

4.1 glslang and the GLSL-to-SPIR-V Toolchain

The primary standalone GLSL compiler and GLSL-to-SPIR-V (Standard Portable Intermediate Representation — Version 5) translator is glslang (also invoked as glslangValidator), the Khronos reference implementation [GitHub — KhronosGroup/glslang — github.com/KhronosGroup/glslang]. glslang accepts GLSL source for any stage and target API (OpenGL 4.x or Vulkan) and emits SPIR-V binary modules. In Vulkan workflows, GLSL shaders are not submitted to the driver as source text; they are precompiled to SPIR-V offline using glslang, then loaded by vkCreateShaderModule. In OpenGL 4.6 workflows, the same SPIR-V binary can be loaded via glShaderBinary with the GL_SHADER_BINARY_FORMAT_SPIR_V token. The downstream consumer of this pipeline — the Vulkan driver’s SPIR-V ingestion path — is covered in detail in M4 §3.8 (“SPIR-V Shader Ingestion”); M4 also enumerates the broader SPIR-V toolchain (DXC for HLSL input, SPIRV-Cross for cross-language output).

glslangValidator is available as a standalone binary (distributed as part of the LunarG Vulkan SDK and the Khronos glslang GitHub release) and as a C++ library for embedding in build pipelines and game engine toolchains. Google’s shaderc library wraps glslang with an improved C API and is the GLSL front-end used by Chromium’s Skia graphics library.

4.2 SPIR-V and Cross-Compilation

SPIR-V is the binary intermediate language that connects GLSL (and other shading languages) to Vulkan, OpenCL, and hardware drivers [SPIR-V spec — registry.khronos.org/SPIR-V/]. Once a GLSL shader is compiled to SPIR-V, it can be translated back to other target languages using SPIRV-Cross [GitHub — KhronosGroup/SPIRV-Cross]. SPIRV-Cross supports:

This SPIR-V + SPIRV-Cross pipeline is the foundation of cross-platform graphics engine shader systems: authors write GLSL once, compile to SPIR-V, and redistribute SPIR-V to SPIRV-Cross for platform-native shader generation.

4.3 GLSL in the Vulkan Workflow

Vulkan does not include a GLSL compiler in the driver. Shaders must be provided as SPIR-V binary. However, Khronos defines the GL_KHR_vulkan_glsl GLSL extension that specifies how GLSL maps to Vulkan’s descriptor-set / binding model (replacing OpenGL’s glUniform* and glBindTexture calls with explicit layout(set = N, binding = M) annotations) [GLSL 4.60 spec — registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf]. Google also defines GL_GOOGLE_include_directive and GL_GOOGLE_cpp_style_line_directive extensions to enable #include and enhanced line-directive support in GLSL-for-Vulkan source files — features absent from core GLSL [GitHub — KhronosGroup/glslang].

4.4 GLSL and WebGL

WebGL 1.0 uses GLSL ES 1.00 as its shading language; WebGL 2.0 uses GLSL ES 3.00. Browser implementations do not feed GLSL ES source directly to GPU drivers; instead, the browser’s WebGL implementation (typically ANGLE — Almost Native Graphics Layer Engine) transpiles GLSL ES to HLSL (on Windows/Direct3D), MSL (on macOS/Metal), or GLSL desktop (on Linux with native OpenGL drivers). This transpilation step enforces security constraints (bounds checking, precision guarantees) that would otherwise require driver-level enforcement on heterogeneous consumer hardware.

4.5 Governance and Specification Maintenance

GLSL specifications are maintained within the Khronos OpenGL Working Group and hosted on the Khronos registry [OpenGL Registry — registry.khronos.org/OpenGL/]. The GLSL 4.60 specification, version 8, is the current authoritative desktop GLSL document. GLSL ES 3.20, updated August 14, 2023, is the current authoritative ESSL document. Specification errata and clarifications are tracked via GitHub issues in the KhronosGroup/GLSL repository. The GLSL ES specification is published as a joint product of the OpenGL ES and WebGL working groups, reflecting the requirement that GLSL ES remain consistent across both embedded and browser contexts.

4.6 Debug and Tooling Surface for GLSL

Shader debugging and inspection tools operate at several levels:

See M5 Pipeline & Patterns for the full pipeline diagram (including where each GLSL stage sits in the OpenGL / Vulkan rendering pipeline) and for the cross-API terminology map that unifies GLSL stage names with their Vulkan / SPIR-V execution-model equivalents.


Section 5 — Sources

↑ Top · GFX Home · CSP Pathway 6