GLSL f16mat4 Matrix Multiplication Restrictions

Using explicit half-precision floating-point matrices like f16mat4 in GLSL offers substantial memory bandwidth and throughput improvements on supported hardware, but it introduces strict mathematical, architectural, and language-level limitations. This article outlines the operational restrictions imposed on f16mat4 matrix multiplication, focusing on explicit type safety rules, dynamic range boundaries, intermediate accumulation semantics, and driver-level requirements.

Extension and Target Requirements

To use f16mat4, the shader must explicitly enable the float16 arithmetic extension:

#extension GL_EXT_shader_explicit_arithmetic_types_float16 : require

Compilation requires targeting an environment that supports explicit 16-bit floating-point capabilities, such as SPIR-V 1.0+ with the Float16 capability enabled, alongside underlying GPU architecture support for native 16-bit operations. If the hardware lacks native FP16 execution units, the driver may emulate the operation using standard 32-bit floats, nullifying potential performance gains.

Strict Type Matching and Disallowed Conversions

Explicit precision extensions in GLSL enforce strict type matching. Matrix multiplication involving f16mat4 is subject to the following rules:

  • No Implicit Promotion: Multiplication between an f16mat4 and a standard 32-bit mat4, vec4, or scalar float is strictly invalid. Mixed-precision matrix multiplication causes a compile-time error.
  • Explicit Casting Required: Any interaction between standard types and explicit half-precision types requires explicit constructor casting (e.g., converting a vec4 to f16vec4 before multiplying by an f16mat4).
  • Operand Shape Compatibility: Standard linear algebra sizing rules apply strictly. You may multiply an f16mat4 by another f16mat4, an f16mat4 by an f16vec4 (column vector transformation), or an f16vec4 by an f16mat4 (row vector transformation).

Dynamic Range and Overflow Constraints

Half-precision floats follow the IEEE 754 binary16 format, which severely restricts the valid numerical range compared to single-precision:

  • Range Limits: The maximum representable finite value is \(65504\), and the minimum positive normalized value is approximately \(6.10 \times 10^{-5}\).
  • Premature Overflow: A \(4 \times 4\) matrix multiplication computes each entry as the dot product of four products: \(\sum_{i=0}^{3} A_{ik} B_{kj}\). If intermediate products exceed \(65504\), the value immediately overflows to infinity (\(\text{Inf}\)). This can occur even if the inputs appear moderate (for example, multiplying coordinates larger than \(\sim 128\) by a scale factor larger than \(\sim 512\)).
  • Rapid Precision Loss: With only 10 bits of mantissa (yielding roughly 3.3 decimal digits of precision), repeated matrix transforms (such as hierarchical model transforms) compound rounding errors significantly faster than 32-bit operations.

Intermediate Accumulation Semantics

Under GL_EXT_shader_explicit_arithmetic_types_float16, the specification does not mandate intermediate 32-bit accumulation for dot products and matrix operations. Unless an implementation specifically optimizes or targets a fused multiply-add path with extended precision, both the intermediate multiplications and additions occur in native 16-bit precision. Consequently, precision is truncated at each addition step within the 4-component dot product, increasing truncation bias.

Subnormal Flushing (FTZ)

Many GPU architectures operate on 16-bit floating-point values using Flush-to-Zero (FTZ) mode by default to maximize throughput:

  • Numbers smaller than the minimum normalized value (\(2^{-14} \approx 6.10 \times 10^{-5}\)) are automatically flushed to zero.
  • Denormalized inputs to an f16mat4 multiplication are often treated as zero before computation begins.
  • Fine-scale translation or minute rotation increments in a matrix will collapse to zero, leading to visible stuttering or geometric cracking if f16mat4 is used directly for world-space vertex positioning.

Memory Layout and Alignment Rules

When loading or storing f16mat4 matrices via Uniform Buffer Objects (UBO) or Shader Storage Buffer Objects (SSBO):

  • Under std140, packing rules generally pad matrix columns up to standard base alignment boundaries, often requiring vector-equivalent padding.
  • Under std430 (or scalar layout via extensions), an f16mat4 is composed of four consecutive f16vec4 columns, with each column aligned to 8 bytes (since each float16_t is 2 bytes). Misaligned source memory will cause undefined behavior or invalid reads prior to the multiplication step.