How GLSL packDouble2x32 Combines Two 32-Bit uints

This article provides an overview of how the GLSL built-in function packDouble2x32 packs a two-component 32-bit unsigned integer vector into a single 64-bit double-precision floating-point number. It details the bit-level arrangement prescribed by the OpenGL Shading Language specification, the specific placement of the least and most significant bits, and how the underlying 64-bit sequence is reinterpreted according to the IEEE 754 standard without undergoing mathematical type conversion.

The packDouble2x32 function accepts a single parameter of type uvec2 (a vector of two 32-bit unsigned integers) and returns a single double. Its primary purpose is to reconstruct a 64-bit representation that may have been split across 32-bit registers or buffers, common in graphics pipelines where memory buses or certain stages are optimized around 32-bit words.

Under the GLSL specification, the packing operation treats the input vector's components as raw bitfields rather than performing an arithmetic conversion. The first component, v[0] (or v.x), provides the 32 least significant bits (bits 0 through 31) of the resulting 64-bit value. The second component, v[1] (or v.y), provides the 32 most significant bits (bits 32 through 63). Conceptually, this operation aligns with the bitwise expression (uint64(v[1]) << 32) | uint64(v[0]).

Once these two 32-bit patterns are concatenated into a contiguous 64-bit word, the GPU reinterprets the resulting bit sequence directly as an IEEE 754 double-precision floating-point value. In this format, bit 63 serves as the sign bit, bits 62 through 52 form the 11-bit biased exponent, and bits 51 through 0 represent the 52-bit fractional significand (mantissa). Because v.y supplies bits 32 to 63, it dictates the sign, exponent, and the upper 20 bits of the mantissa, while v.x supplies the remaining lower 32 bits of the mantissa.

Because packDouble2x32 is a bitwise reinterpretation (equivalent to a bit-cast), the values inside v.x and v.y do not represent the whole and fractional parts of a decimal number. If the combined 64-bit pattern matches special IEEE 754 encodings, the returned double will evaluate directly to those values, such as subnormal numbers, positive or negative infinity, or NaN (Not-a-Number). The inverse of this operation is handled by unpackDouble2x32, which extracts a double back into its constituent low and high 32-bit unsigned integers.