GLSL ES 3.00 Features in WebGL 2.0 Explained
WebGL 2.0 brought modern GPU programming to the web primarily through its adoption of the OpenGL ES 3.0 API and its companion shading language, GLSL ES 3.00. Moving away from the legacy constraints of GLSL ES 1.00 used in WebGL 1.0, this upgrade introduced native integer support, enhanced data structures, structured memory blocks, and powerful new texture-sampling methods. This article breaks down the major shader features, syntax modernizations, and pipeline capabilities unlocked by this standard.
Updated Syntax and Variable Qualifiers
GLSL ES 3.00 shaders must begin with the #version 300 es
directive. The update replaced deprecated qualifiers to unify input and
output semantics:
inandoutQualifiers: Replaced the olderattributeandvaryingkeywords. Vertex shader inputs are marked within, vertex outputs/fragment inputs withoutandinrespectively, and fragment shader outputs without.- Explicit Attribute Locations: Developers can use
layout qualifiers such as
layout(location = 0) in vec3 aPosition;to bind attribute indices directly within shader code, reducing the need for CPU-side bindings.
Full Integer and Bitwise Support
GLSL ES 1.00 lacked robust integer handling, forcing developers to simulate bitwise operations and integer logic using floating-point math. GLSL ES 3.00 introduced:
- True Signed and Unsigned Integers: Native
intanduinttypes along with their corresponding vector formats (ivec,uvec). - Bitwise Operations: Standard bitwise operators
(
&,|,^,~,<<,>>) for efficient masking, bit-packing, hashing, and procedural generation directly on the GPU.
Uniform Buffer Objects (UBOs)
In WebGL 1.0, uniforms had to be updated independently per shader
program. GLSL ES 3.00 added uniform blocks, enabling the
use of Uniform Buffer Objects (UBOs):
- Data Sharing: Large sets of uniforms (such as camera matrices or lighting parameters) can be grouped into single buffers and shared across multiple shader programs without redundant re-binding.
- Faster CPU-to-GPU Transfers: Uniform data can be updated in contiguous memory blocks, reducing CPU overhead and draw call latency.
Multiple Render Targets (MRT)
GLSL ES 3.00 natively integrates Multiple Render Targets into the
core standard, removing the need for browser-dependent extensions.
Fragment shaders can output to multiple textures simultaneously by
defining multiple out variables tied to specific attachment
locations:
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outNormal;
layout(location = 2) out vec4 outDepth;This capability is foundational for modern rendering pipelines, particularly deferred shading and screen-space ambient occlusion (SSAO).
Advanced Texture Querying and Formats
The standard overhauled how shaders interact with textures, replacing
specific functions like texture2D and
textureCube with overloaded texture()
functions:
texelFetch(): Allows fetching raw texels directly by integer coordinates without filtering or normalized coordinates, behaving like a standard array lookup.textureSize(): Enables shaders to query the dimensions of a texture directly, eliminating the need to pass image dimensions as uniforms.- 3D and Array Textures: Introduced samplers such as
sampler3D,sampler2DArray, and comparison samplers for hardware-accelerated depth mapping (sampler2DShadow).
Expanded Matrix Operations and Standard Library
The standard expanded linear algebra functionality and flow control:
- Non-Square Matrices: Full support for
mat2x3,mat3x2,mat2x4,mat4x2,mat3x4, andmat4x3. - Built-in Matrix Functions: Native support for
transpose()andinverse(). - Flow Control: Support for
switchstatements, dynamic loop indexing, and extended built-in numerical functions, making complex shader logic simpler to write and maintain.