16-Bit vs 32-Bit Float in Mobile GLSL ES
In mobile OpenGL ES Shading Language (GLSL ES), choosing between
16-bit half-precision (mediump) and 32-bit single-precision
(highp) floating-point arithmetic represents a fundamental
trade-off between performance, power efficiency, and numerical accuracy.
While 32-bit floats provide the dynamic range and precision required for
complex calculations like world-space positioning and depth mapping,
16-bit floats offer significant performance enhancements, reduced
register pressure, and lower power consumption on mobile GPUs. This
article breaks down the mathematical, hardware, and visual differences
between these two precision formats and outlines when to use each in
mobile graphics development.
Numerical Representation and Dynamic Range
The primary mathematical difference between 16-bit and 32-bit arithmetic lies in how bits are allocated for precision and scale according to floating-point standards (such as IEEE 754):
- 16-bit Float (
mediump): Composed of 1 sign bit, 5 exponent bits, and 10 mantissa (fraction) bits. This provides roughly 3 to 4 decimal digits of precision and a dynamic range of approximately \(\pm65,504\), with the smallest positive normalized value around \(6.10 \times 10^{-5}\). - 32-bit Float (
highp): Composed of 1 sign bit, 8 exponent bits, and 23 mantissa bits. This delivers approximately 7 decimal digits of precision and an expansive range of roughly \(\pm3.4 \times 10^{38}\).
In GLSL ES, the standard defines minimum required ranges for
qualifiers rather than absolute bit depths. However, virtually all
modern mobile architectures (such as ARM Mali, Qualcomm Adreno, and
Imagination PowerVR) implement mediump as native IEEE 754
16-bit floats and highp as IEEE 754 32-bit floats.
ALU Throughput and Performance
Mobile GPUs are thermally constrained and engineered to maximize throughput per watt. Most modern mobile architectures include dual-issue or dedicated 16-bit Arithmetic Logic Units (ALUs):
- Vector Packing and Vectorization: Many mobile GPUs
can execute two 16-bit operations in the time and space required for a
single 32-bit operation (often referred to as 2x FP16 throughput). Using
mediumpeffectively doubles the theoretical arithmetic capacity of the shader core. - Register Pressure and Occupancy: Registers on mobile GPUs are a finite, shared resource. Storing 16-bit values cuts register allocation per thread in half. Lower register usage allows the GPU driver to dispatch more concurrent execution threads (higher occupancy), which hides memory latency more effectively.
Memory Bandwidth and Cache Footprint
Graphics workloads on mobile devices are frequently bottlenecked by memory bandwidth rather than raw compute:
- Varyings and Interpolators: Passing data from the
vertex shader to the fragment shader via
mediumpvaryings reduces the data transfer footprint across the chip. - Texture Reads and Framebuffers: Arithmetic often matches storage formats. Sampling FP16 textures or rendering to FP16 render targets consumes half the memory bandwidth of FP32 equivalents, saving cache lines and keeping the GPU memory subsystem clear of stalls.
- Thermal Throttling: Reduced bandwidth and compute load directly translate to lower dynamic power consumption, preventing devices from overheating and throttling clock speeds during sustained gameplay.
Common Visual Artifacts of 16-Bit Float
Using 16-bit arithmetic inappropriately leads to recognizable visual degradation:
- Color Banding: A 10-bit mantissa lacks the granularity to represent subtle, smooth gradients, resulting in visible stepping in skies, vignettes, or softly lit surfaces.
- Underflow and Overflow: Lighting equations involving high specular exponents, physically based rendering (PBR) equations, or high dynamic range (HDR) values can quickly exceed \(65,504\), producing black patches (clipping/NaNs) or stark white blowing-out.
- Jitter and Vertex Snapping: Using
mediumpfor absolute world coordinates or projection matrices causes precision jitter, where geometry visibly shakes or tears as the camera moves, because coordinates far from the origin lack relative precision. - Texture Coordinate Distortion: Large, tiled
textures mapped with
mediumpcoordinates lose precision as UV coordinates grow, resulting in warped or blocky texel sampling.
Strategic Usage in Mobile Shaders
To balance fidelity and efficiency, shaders should isolate precision based on the task:
- Use
mediumpfor:- Colors, albedo, and ambient lighting values (normalized \(0.0\) to \(1.0\) ranges).
- Surface normals, tangents, and bitangents.
- Localized UV coordinates (clamped between \(0.0\) and \(1.0\)).
- Simple blend factors, opacity, and UI elements.
- Use
highpfor:- World-space, view-space, and clip-space vertex positions.
- Depth buffer operations, shadow map comparisons, and logarithmic depth.
- Analytical functions like
sin,cos,pow, andexpthat amplify precision errors. - Unwrapped or repetitive UV coordinates spanning large numerical ranges.