GLSL dvec3 vs vec3 ALU Throughput Impact
Switching from single-precision vec3 to double-precision
dvec3 in desktop OpenGL Shading Language (GLSL) causes a
severe reduction in Arithmetic Logic Unit (ALU) throughput. Desktop GPUs
are fundamentally optimized for 32-bit floating-point math, meaning
double-precision operations execute on dedicated, highly restricted
hardware paths. This article explains how the FP64 execution bottleneck,
register pressure, and pipeline stalls combine to reduce compute
efficiency when using dvec3.
Hardware FP64-to-FP32 Execution Ratios
The primary factor limiting dvec3 throughput is the
physical ratio of 64-bit floating-point (FP64) cores to 32-bit
floating-point (FP32) cores on desktop GPUs. Consumer-grade
architectures heavily deprioritize FP64 hardware to maximize silicon
space for graphics and AI workloads:
- NVIDIA GeForce (Ampere, Ada Lovelace): Typically features an FP64-to-FP32 throughput ratio of 1:64.
- AMD Radeon (RDNA 2, RDNA 3): Typically features an FP64-to-FP32 throughput ratio of 1:16 or 1:32.
When processing a vec3, the GPU's primary vector or
scalar execution units handle three 32-bit operations at full clock
rate. When replacing it with a dvec3, the hardware must
dispatch three 64-bit operations to the scarce FP64 units. On an NVIDIA
GPU with a 1:64 ratio, the ALU throughput for these operations drops by
a factor of 64, turning lightweight vector math into a massive
computational bottleneck.
Register Allocation and Occupancy
Each component of a dvec3 requires 64 bits of storage,
requiring 192 bits (24 bytes) in total, compared to 96 bits (12 bytes)
for a vec3. In low-level GPU machine code, hardware
registers are almost universally organized into 32-bit slots.
Consequently, storing a single dvec3 requires six 32-bit
physical registers instead of three.
This increased register demand leads to two performance degradations:
- Reduced Warp/Wavefront Occupancy: GPUs rely on having a high number of active warps (NVIDIA) or wavefronts (AMD) scheduled on a Streaming Multiprocessor (SM) or Compute Unit (CU) to hide memory and arithmetic latencies. As per-thread register usage doubles, fewer threads can run concurrently.
- Register Spilling: If the shader is already
complex, the extra register load introduced by
dvec3variables increases the likelihood of spilling registers to local scratch memory (VRAM/L1 cache), drastically degrading throughput.
Instruction Latency and Pipeline Serialization
Double-precision ALUs often operate with longer instruction latencies than their single-precision counterparts. Because fewer FP64 execution units exist per hardware block, multiple threads in a warp cannot execute FP64 operations in parallel as easily as FP32 operations.
Instead, the hardware must serialize the execution across fewer execution units over multiple clock cycles. This leads to:
- Increased issue-to-read latency for dependent instructions.
- Stalled execution pipelines when alternating between single- and double-precision math, as execution units wait for instruction schedulers to clear the FP64 pipeline.
Vector Packing and Special Function Units
Desktop GPUs utilize scalar SIMT (Single Instruction, Multiple
Threads) architectures. A vec3 splits cleanly into three
independent scalar 32-bit instructions (e.g., ADD,
MUL, FMA). Similarly, a dvec3
splits into three 64-bit instructions.
However, transcendentals and special functions (such as
sin(), cos(), normalize(), or
inversesqrt()) do not have native 64-bit Special Function
Unit (SFU) hardware on desktop chips. While a
normalize(vec3) uses fast reciprocal square root hardware,
a normalize(dvec3) is expanded by the driver into a complex
multi-instruction software emulation sequence using basic FP64
arithmetic, resulting in an order-of-magnitude throughput penalty.
Alternatives for Performance-Critical Shaders
Unless native double precision is strictly required for numerical
stability (such as large-scale planetary coordinate systems),
dvec3 should be avoided in performance-critical desktop
GLSL code. Common alternatives include:
- Camera-Relative Rendering: Subtracting the camera
position on the CPU and passing relative offsets to the shader as
standard
vec3values to eliminate precision jitter without FP64 cost. - Emulated Double Precision (DSFUN32): Representing
64-bit values as pairs of two 32-bit floats (
float-floatarithmetic). While this takes roughly 10 to 20 FP32 operations per math function, it is frequently faster on consumer GPUs than native FP64 hardware executing at a 1:64 rate.