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
3.1 Compile-Link Model
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]:
- Scalar types:
bool,int(32-bit signed),uint(32-bit unsigned),float(32-bit IEEE 754),double(64-bit, GLSL 4.00+). - Vector types:
vecN(float, N=2,3,4),ivecN(int),uvecN(uint),bvecN(bool),dvecN(double, 4.00+). Component swizzling allows reordering or selecting components:v.xyz,v.bgr,v.wwwwproduce derived vectors without temporaries. - Matrix types:
matNxM(float, column-major),dmatNxM(double, 4.00+). Aliasesmat2,mat3,mat4meanmat2x2,mat3x3,mat4x4. - Sampler types:
sampler2D,sampler3D,samplerCube,sampler2DArray,samplerCubeShadow, etc. — opaque handles bound to texture units. Used only asuniformvariables; cannot be assigned or indexed dynamically in GLSL 1.x (dynamic indexing added in later versions via extensions). - Image types:
image2D,imageBuffer, etc. — similar to samplers but support load/store semantics viaimageLoad/imageStore; introduced in GLSL 4.20. - Aggregate types: arrays (fixed-size or run-time-sized in SSBOs), structs, interface blocks.
3.4 Qualifiers
GLSL uses qualifiers to annotate variables with their origin, destination, and memory layout:
in: value sourced from the previous pipeline stage (or vertex attribute for vertex shaders). Read-only within the stage.out: value passed to the next pipeline stage (or written to the framebuffer for fragment shaders). Write-only (or read-after-write within the same stage since GLSL 4.00).uniform: a value set by the application viaglUniform*calls; constant for the duration of a draw call; shared across all invocations of a given stage. Applies to simple types and to Uniform Buffer Object (UBO) interface blocks.buffer: declares a Shader Storage Buffer Object (SSBO) block; readable and writable from the shader; supports run-time-sized arrays; access is coherent across invocations with explicit memory barriers.shared: compute-shader-only; declares a variable in work-group shared memory, visible to all invocations within the same work group.layout(...): a meta-qualifier specifying binding points (binding = N), input/output locations (location = N), memory layout (std140,std430,packed), or tessellation parameters (vertices,equal_spacing,ccw).
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:
- GLSL (for OpenGL targets that do not accept SPIR-V natively)
- HLSL (High-Level Shading Language, for Direct3D backends)
- MSL (Metal Shading Language, for Apple platform backends)
- ESSL (for OpenGL ES targets)
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:
- Compile-time: driver info logs retrieved via
glGetShaderInfoLogandglGetProgramInfoLogprovide line-numbered error messages. glslang’s standalone binary can validate and produce info logs offline, before reaching a driver. - Runtime inspection: RenderDoc captures draw calls and surfaces the GLSL (or SPIR-V, decompiled back to GLSL) source bound at each draw, with per-invocation shader debugging on supported backends.
- Static analysis: tools such as glslang’s
--ast-dumpflag and SPIRV-Tools’spirv-valvalidate SPIR-V modules for conformance, enabling CI-time shader validation independent of any GPU driver.
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
- [standard] https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.60.pdf — GLSL 4.60 language specification (authoritative)
- [standard] https://www.khronos.org/opengl/wiki/Core_Language_(GLSL) — GLSL core language wiki reference
- [standard] https://www.khronos.org/opengl/wiki/Shader — Shader stages, inputs, outputs
- [standard] https://www.khronos.org/opengl/wiki/History_of_OpenGL — OpenGL/GLSL version timeline
- [standard] https://registry.khronos.org/OpenGL/ — OpenGL + GLSL specification index and extension registry
- [standard] https://registry.khronos.org/OpenGL/specs/es/3.2/GLSL_ES_Specification_3.20.pdf — GLSL ES 3.20 specification
- [standard] https://registry.khronos.org/OpenGL/specs/es/3.2/es_spec_3.2.pdf — OpenGL ES 3.2 specification
- [standard] https://registry.khronos.org/SPIR-V/ — SPIR-V specification
- [standard] https://github.com/KhronosGroup/glslang — glslang reference GLSL-to-SPIR-V compiler
- [standard] https://github.com/KhronosGroup/SPIRV-Cross — SPIR-V to GLSL/HLSL/MSL translator
- [standard] https://github.com/KhronosGroup — Khronos open-source repositories
- [encyclopedia] https://en.wikipedia.org/wiki/OpenGL_Shading_Language — GLSL article (version parallel to GL, stages)
- [encyclopedia] https://en.wikipedia.org/wiki/SPIR-V — SPIR-V article
- [encyclopedia] https://en.wikipedia.org/wiki/Khronos_Group — Khronos Group governance context