spirv_std/
float.rs

1//! Traits and helper functions related to floats.
2
3use crate::vector::Vector;
4#[cfg(target_arch = "spirv")]
5use core::arch::asm;
6
7/// Abstract trait representing a SPIR-V floating point type.
8///
9/// # Safety
10/// Implementing this trait on non-primitive-float types breaks assumptions of other unsafe code,
11/// and should not be done.
12pub unsafe trait Float: num_traits::Float + crate::scalar::Scalar + Default {
13    /// Width of the float, in bits.
14    const WIDTH: usize;
15}
16
17unsafe impl Float for f32 {
18    const WIDTH: usize = 32;
19}
20
21unsafe impl Float for f64 {
22    const WIDTH: usize = 64;
23}
24
25/// Converts two f32 values (floats) into two f16 values (halfs). The result is a u32, with the low
26/// 16 bits being the first f16, and the high 16 bits being the second f16.
27#[spirv_std_macros::gpu_only]
28pub fn vec2_to_f16x2(vec: impl Vector<f32, 2>) -> u32 {
29    let result;
30    unsafe {
31        asm!(
32            "%glsl = OpExtInstImport \"GLSL.std.450\"",
33            "%uint = OpTypeInt 32 0",
34            "%vec = OpLoad _ {vec}",
35            // 58 = PackHalf2x16
36            "{result} = OpExtInst %uint %glsl 58 %vec",
37            vec = in(reg) &vec,
38            result = out(reg) result,
39        );
40    }
41    result
42}
43
44/// Converts two f16 values (halfs) into two f32 values (floats). The parameter is a u32, with the
45/// low 16 bits being the first f16, and the high 16 bits being the second f16.
46#[spirv_std_macros::gpu_only]
47pub fn f16x2_to_vec2<V: Vector<f32, 2>>(int: u32) -> V {
48    let mut result = Default::default();
49    unsafe {
50        asm!(
51            "%glsl = OpExtInstImport \"GLSL.std.450\"",
52            // 62 = UnpackHalf2x16
53            "%result = OpExtInst typeof*{result} %glsl 62 {int}",
54            "OpStore {result} %result",
55            int = in(reg) int,
56            result = in(reg) &mut result,
57        );
58    }
59    result
60}
61
62/// Converts an f32 (float) into an f16 (half). The result is a u32, not a u16, due to GPU support
63/// for u16 not being universal - the upper 16 bits will always be zero.
64#[spirv_std_macros::gpu_only]
65pub fn f32_to_f16(float: f32) -> u32 {
66    vec2_to_f16x2(glam::Vec2::new(float, 0.))
67}
68
69/// Converts an f16 (half) into an f32 (float). The parameter is a u32, due to GPU support for u16
70/// not being universal - the upper 16 bits are ignored.
71#[spirv_std_macros::gpu_only]
72pub fn f16_to_f32(packed: u32) -> f32 {
73    f16x2_to_vec2::<glam::Vec2>(packed).x
74}
75
76/// Packs a vec4 into 4 8-bit signed integers. See
77/// [PackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
78/// semantics.
79#[spirv_std_macros::gpu_only]
80pub fn vec4_to_u8x4_snorm(vec: impl Vector<f32, 4>) -> u32 {
81    let result;
82    unsafe {
83        asm!(
84            "%glsl = OpExtInstImport \"GLSL.std.450\"",
85            "%uint = OpTypeInt 32 0",
86            "%vec = OpLoad _ {vec}",
87            // 54 = PackSnorm4x8
88            "{result} = OpExtInst %uint %glsl 54 %vec",
89            vec = in(reg) &vec,
90            result = out(reg) result,
91        );
92    }
93    result
94}
95
96/// Packs a vec4 into 4 8-bit unsigned integers. See
97/// [PackUnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
98/// semantics.
99#[spirv_std_macros::gpu_only]
100pub fn vec4_to_u8x4_unorm(vec: impl Vector<f32, 4>) -> u32 {
101    let result;
102    unsafe {
103        asm!(
104            "%glsl = OpExtInstImport \"GLSL.std.450\"",
105            "%uint = OpTypeInt 32 0",
106            "%vec = OpLoad _ {vec}",
107            // 55 = PackUnorm4x8
108            "{result} = OpExtInst %uint %glsl 55 %vec",
109            vec = in(reg) &vec,
110            result = out(reg) result,
111        );
112    }
113    result
114}
115
116/// Packs a vec2 into 2 16-bit signed integers. See
117/// [PackSnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
118/// semantics.
119#[spirv_std_macros::gpu_only]
120pub fn vec2_to_u16x2_snorm(vec: impl Vector<f32, 2>) -> u32 {
121    let result;
122    unsafe {
123        asm!(
124            "%glsl = OpExtInstImport \"GLSL.std.450\"",
125            "%uint = OpTypeInt 32 0",
126            "%vec = OpLoad _ {vec}",
127            // 56 = PackSnorm2x16
128            "{result} = OpExtInst %uint %glsl 56 %vec",
129            vec = in(reg) &vec,
130            result = out(reg) result,
131        );
132    }
133    result
134}
135
136/// Packs a vec2 into 2 16-bit unsigned integers. See
137/// [PackUnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
138/// semantics.
139#[spirv_std_macros::gpu_only]
140pub fn vec2_to_u16x2_unorm(vec: impl Vector<f32, 2>) -> u32 {
141    let result;
142    unsafe {
143        asm!(
144            "%glsl = OpExtInstImport \"GLSL.std.450\"",
145            "%uint = OpTypeInt 32 0",
146            "%vec = OpLoad _ {vec}",
147            // 57 = PackUnorm2x16
148            "{result} = OpExtInst %uint %glsl 57 %vec",
149            vec = in(reg) &vec,
150            result = out(reg) result,
151        );
152    }
153    result
154}
155
156/// Unpacks 4 8-bit signed integers into a vec4. See
157/// [UnpackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
158/// semantics.
159#[spirv_std_macros::gpu_only]
160pub fn u8x4_to_vec4_snorm<V: Vector<f32, 4>>(int: u32) -> V {
161    let mut result = Default::default();
162    unsafe {
163        asm!(
164            "%glsl = OpExtInstImport \"GLSL.std.450\"",
165            // 63 = UnpackSnorm4x8
166            "%result = OpExtInst typeof*{result} %glsl 63 {int}",
167            "OpStore {result} %result",
168            int = in(reg) int,
169            result = in(reg) &mut result,
170        );
171    }
172    result
173}
174
175/// Unpacks 4 8-bit unsigned integers into a vec4. See
176/// [UnpackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
177/// semantics.
178#[spirv_std_macros::gpu_only]
179pub fn u8x4_to_vec4_unorm<V: Vector<f32, 4>>(int: u32) -> V {
180    let mut result = Default::default();
181    unsafe {
182        asm!(
183            "%glsl = OpExtInstImport \"GLSL.std.450\"",
184            // 64 = UnpackUnorm4x8
185            "%result = OpExtInst typeof*{result} %glsl 64 {int}",
186            "OpStore {result} %result",
187            int = in(reg) int,
188            result = in(reg) &mut result,
189        );
190    }
191    result
192}
193
194/// Unpacks 2 16-bit signed integers into a vec2. See
195/// [UnpackSnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for
196/// exact semantics.
197#[spirv_std_macros::gpu_only]
198pub fn u16x2_to_vec2_snorm<V: Vector<f32, 2>>(int: u32) -> V {
199    let mut result = Default::default();
200    unsafe {
201        asm!(
202            "%glsl = OpExtInstImport \"GLSL.std.450\"",
203            // 60 = UnpackSnorm2x16
204            "%result = OpExtInst typeof*{result} %glsl 60 {int}",
205            "OpStore {result} %result",
206            int = in(reg) int,
207            result = in(reg) &mut result,
208        );
209    }
210    result
211}
212
213/// Unpacks 2 16-bit unsigned integers into a vec2. See
214/// [UnpackUnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for
215/// exact semantics.
216#[spirv_std_macros::gpu_only]
217pub fn u16x2_to_vec2_unorm<V: Vector<f32, 2>>(int: u32) -> V {
218    let mut result = Default::default();
219    unsafe {
220        asm!(
221            "%glsl = OpExtInstImport \"GLSL.std.450\"",
222            // 61 = UnpackUnorm2x16
223            "%result = OpExtInst typeof*{result} %glsl 61 {int}",
224            "OpStore {result} %result",
225            int = in(reg) int,
226            result = in(reg) &mut result,
227        );
228    }
229    result
230}