Decompose 64-Bit Integer into Two 32-Bit in GLSL
In modern OpenGL Shading Language (GLSL), processing 64-bit unsigned
integers (uint64_t) often requires decomposing them into
pairs of standard 32-bit unsigned integers (uint) for
storage in standard vector types (uvec2), inter-stage
communication, or compatibility with hardware lacking native 64-bit
interpolation. This article explains how to manually extract the high
and low 32-bit components from a 64-bit integer using bitwise
operations.
Prerequisites
To use 64-bit integer types in GLSL, you must enable the
GL_ARB_gpu_shader_int64 extension or use a core GLSL
version that natively supports 64-bit integers (version 4.5+ with the
appropriate feature set). Add the following directive to the top of your
shader:
#version 450 core
#extension GL_ARB_gpu_shader_int64 : enableThe Manual Decomposition Method
A 64-bit unsigned integer consists of 64 contiguous bits, where bits 0–31 represent the lower 32 bits and bits 32–63 represent the higher 32 bits. You can extract these segments manually using a bitwise shift and masking.
uvec2 decomposeUint64(uint64_t value) {
// Extract the lower 32 bits by masking or direct casting
uint low = uint(value & 0xFFFFFFFFul);
// Extract the upper 32 bits by shifting right by 32 bits
uint high = uint(value >> 32ul);
return uvec2(low, high);
}Step-by-Step Breakdown
Extracting the Low 32 Bits:
Applying the bitwise AND operation (&) with the 64-bit literal0xFFFFFFFFulisolates the first 32 bits of the integer while zeroing out bits 32 through 63. Converting the result to a standarduinttruncates the 64-bit container down to a 32-bit representation. In GLSL,uint(value)also implicitly discards the upper 32 bits, makinguint low = uint(value);a valid shorthand.Extracting the High 32 Bits:
The right-shift operator (>> 32ul) moves bits 32–63 into the positions of bits 0–31. The vacated upper bits are filled with zeros because the operation is performed on an unsigned type. Casting the shifted result touintdrops any unused remaining bits, yielding the upper 32-bit integer.Packaging the Result:
The resulting components are commonly stored in auvec2, where the.xcomponent holds the lower 32 bits and the.ycomponent holds the upper 32 bits (little-endian order convention).
Built-in Alternative
While the manual bit-shifting approach works across any custom bit
manipulation pipeline, the GL_ARB_gpu_shader_int64
extension also exposes the built-in function
unpackUint2x32(uint64_t value). This intrinsic achieves the
same result directly in hardware, returning a uvec2 where
.x contains the lower 32 bits and .y contains
the upper 32 bits. Manual decomposition is typically preferred when
implementing custom packing layouts or targeting intermediate
compilation targets.