Skip to main content

khal_std/
float.rs

1//! Floating-point conversion utilities.
2
3use glamx::Vec2;
4
5/// Unpack a u32 containing two f16 values into a Vec2 of f32.
6///
7/// The low 16 bits are the first f16 value, high 16 bits are the second.
8///
9/// On SPIR-V: uses `spirv_std::float::f16x2_to_vec2`.
10/// On other targets: software conversion.
11#[inline(always)]
12pub fn unpack_half2x16(v: u32) -> Vec2 {
13    #[cfg(target_arch = "spirv")]
14    {
15        let v2 = spirv_std::float::f16x2_to_vec2(v);
16        Vec2::new(v2.x, v2.y)
17    }
18    #[cfg(not(target_arch = "spirv"))]
19    {
20        let lo = (v & 0xFFFF) as u16;
21        let hi = ((v >> 16) & 0xFFFF) as u16;
22        Vec2::new(f16_to_f32(lo), f16_to_f32(hi))
23    }
24}
25
26/// Convert an f16 (as u16 bits) to f32 in software.
27#[cfg(not(target_arch = "spirv"))]
28#[inline]
29fn f16_to_f32(bits: u16) -> f32 {
30    let sign = ((bits >> 15) as u32) << 31;
31    let exp = (bits >> 10) & 0x1F;
32    let mantissa = (bits & 0x3FF) as u32;
33
34    if exp == 0 {
35        if mantissa == 0 {
36            f32::from_bits(sign)
37        } else {
38            // Subnormal: normalize
39            let mut m = mantissa;
40            let mut e: i32 = -14 + 127;
41            while m & 0x400 == 0 {
42                m <<= 1;
43                e -= 1;
44            }
45            m &= 0x3FF;
46            f32::from_bits(sign | ((e as u32) << 23) | (m << 13))
47        }
48    } else if exp == 31 {
49        // Inf or NaN
50        f32::from_bits(sign | 0x7F800000 | (mantissa << 13))
51    } else {
52        // Normal: exp is 1..30, so exp + 112 is 113..142
53        let e = (exp as u32) + 112;
54        f32::from_bits(sign | (e << 23) | (mantissa << 13))
55    }
56}