What Are Precision Qualifiers in GLSL ES?
In OpenGL ES Shading Language (GLSL ES), precision qualifiers such as
lowp, mediump, and highp
determine the numerical precision, bit depth, and dynamic range used to
calculate and store floating-point and integer data on the GPU. These
qualifiers allow developers to strike an optimal balance between visual
fidelity, memory bandwidth, battery efficiency, and hardware
performance, which is especially critical on mobile GPUs and embedded
hardware architectures.
Why Precision Qualifiers Exist
Desktop GPUs typically execute all floating-point shader calculations at standard 32-bit single precision (FP32) or even 64-bit double precision (FP64), often ignoring precision qualifiers entirely. Mobile GPUs, however, are severely constrained by thermal limits, power consumption, and memory bus bandwidth.
To mitigate these constraints, mobile hardware includes dedicated Arithmetic Logic Units (ALUs) and registers capable of operating natively at reduced precision, such as 16-bit half precision (FP16) or 8-bit/10-bit integer formats. GLSL ES precision qualifiers act as explicit hints to the shader compiler, specifying the minimum accuracy required for a given variable.
The Three Precision Levels
GLSL ES defines three standard precision qualifiers:
highp(High Precision): Intended for calculations that require full precision and large dynamic range. Floating-point values provide at least IEEE 754 24-bit representation (equivalent to FP32 in practice on most hardware), with a minimum range of \(2^{-62}\) to \(2^{62}\).mediump(Medium Precision): Intended for general computations where minor rounding errors are imperceptible. Floating-point values use a minimum of 16-bit precision (FP16), covering a range of \(-2^{14}\) to \(2^{14}\) (around \(-16,384\) to \(+16,384\)) with 10 bits of fractional precision.lowp(Low Precision): Intended for simple calculations with bounded ranges. Floating-point values require a minimum range of \(-2.0\) to \(+2.0\) with an 8-bit fixed-point resolution (\(1/256\)).
Recommended Use Cases
Choosing the proper qualifier depends on the mathematical sensitivity and numerical range of the data being processed:
- Positions and World Coordinates
(
highp): Vertex positions, transformation matrices, depth buffer values, and world-space lighting computations require high precision to prevent severe visual artifacts, vertex jittering, and Z-fighting. - Texture Coordinates and Normals
(
mediump): Normal vectors, normalized lighting vectors, and UV coordinates within standard \([0.0, 1.0]\) ranges are well-suited for medium precision, providing clean rendering without FP32 overhead. - Colors and Blend Factors (
lowp): Standard RGBA colors, opacity factors, and surface tint values bounded between \(0.0\) and \(1.0\) do not require fractional accuracy beyond 8 bits per channel.
Setting Default Precision
Typing precision qualifiers on every variable declaration can clutter shader code. GLSL ES supports setting default precision values for entire types at the top of a shader module:
// Sets default precision for all float variables in this shader
precision mediump float;
precision highp int;
// Override the default for specific critical variables
attribute highp vec4 a_Position;
varying lowp vec4 v_Color;In the vertex shader, GLSL ES defaults float and
int to highp. In the fragment shader, however,
there is no mandatory default float precision in GLSL ES 1.0/WebGL 1.0.
Failing to define a default float precision in the fragment shader will
result in a compilation error on compliant implementations.