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            "%float = OpTypeFloat 32",
53            "%vec2 = OpTypeVector %float 2",
54            // 62 = UnpackHalf2x16
55            "%result = OpExtInst %vec2 %glsl 62 {int}",
56            "OpStore {result} %result",
57            int = in(reg) int,
58            result = in(reg) &mut result,
59        );
60    }
61    result
62}
63
64/// Converts an f32 (float) into an f16 (half). The result is a u32, not a u16, due to GPU support
65/// for u16 not being universal - the upper 16 bits will always be zero.
66#[spirv_std_macros::gpu_only]
67pub fn f32_to_f16(float: f32) -> u32 {
68    vec2_to_f16x2(glam::Vec2::new(float, 0.))
69}
70
71/// Converts an f16 (half) into an f32 (float). The parameter is a u32, due to GPU support for u16
72/// not being universal - the upper 16 bits are ignored.
73#[spirv_std_macros::gpu_only]
74pub fn f16_to_f32(packed: u32) -> f32 {
75    f16x2_to_vec2::<glam::Vec2>(packed).x
76}
77
78/// Packs a vec4 into 4 8-bit signed integers. See
79/// [PackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
80/// semantics.
81#[spirv_std_macros::gpu_only]
82pub fn vec4_to_u8x4_snorm(vec: impl Vector<f32, 4>) -> u32 {
83    let result;
84    unsafe {
85        asm!(
86            "%glsl = OpExtInstImport \"GLSL.std.450\"",
87            "%uint = OpTypeInt 32 0",
88            "%vec = OpLoad _ {vec}",
89            // 54 = PackSnorm4x8
90            "{result} = OpExtInst %uint %glsl 54 %vec",
91            vec = in(reg) &vec,
92            result = out(reg) result,
93        );
94    }
95    result
96}
97
98/// Packs a vec4 into 4 8-bit unsigned integers. See
99/// [PackUnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
100/// semantics.
101#[spirv_std_macros::gpu_only]
102pub fn vec4_to_u8x4_unorm(vec: impl Vector<f32, 4>) -> u32 {
103    let result;
104    unsafe {
105        asm!(
106            "%glsl = OpExtInstImport \"GLSL.std.450\"",
107            "%uint = OpTypeInt 32 0",
108            "%vec = OpLoad _ {vec}",
109            // 55 = PackUnorm4x8
110            "{result} = OpExtInst %uint %glsl 55 %vec",
111            vec = in(reg) &vec,
112            result = out(reg) result,
113        );
114    }
115    result
116}
117
118/// Packs a vec2 into 2 16-bit signed integers. See
119/// [PackSnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
120/// semantics.
121#[spirv_std_macros::gpu_only]
122pub fn vec2_to_u16x2_snorm(vec: impl Vector<f32, 2>) -> u32 {
123    let result;
124    unsafe {
125        asm!(
126            "%glsl = OpExtInstImport \"GLSL.std.450\"",
127            "%uint = OpTypeInt 32 0",
128            "%vec = OpLoad _ {vec}",
129            // 56 = PackSnorm2x16
130            "{result} = OpExtInst %uint %glsl 56 %vec",
131            vec = in(reg) &vec,
132            result = out(reg) result,
133        );
134    }
135    result
136}
137
138/// Packs a vec2 into 2 16-bit unsigned integers. See
139/// [PackUnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
140/// semantics.
141#[spirv_std_macros::gpu_only]
142pub fn vec2_to_u16x2_unorm(vec: impl Vector<f32, 2>) -> u32 {
143    let result;
144    unsafe {
145        asm!(
146            "%glsl = OpExtInstImport \"GLSL.std.450\"",
147            "%uint = OpTypeInt 32 0",
148            "%vec = OpLoad _ {vec}",
149            // 57 = PackUnorm2x16
150            "{result} = OpExtInst %uint %glsl 57 %vec",
151            vec = in(reg) &vec,
152            result = out(reg) result,
153        );
154    }
155    result
156}
157
158/// Unpacks 4 8-bit signed integers into a vec4. See
159/// [UnpackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
160/// semantics.
161#[spirv_std_macros::gpu_only]
162pub fn u8x4_to_vec4_snorm<V: Vector<f32, 4>>(int: u32) -> V {
163    let mut result = Default::default();
164    unsafe {
165        asm!(
166            "%glsl = OpExtInstImport \"GLSL.std.450\"",
167            "%float = OpTypeFloat 32",
168            "%vec4 = OpTypeVector %float 4",
169            // 63 = UnpackSnorm4x8
170            "%result = OpExtInst %vec4 %glsl 63 {int}",
171            "OpStore {result} %result",
172            int = in(reg) int,
173            result = in(reg) &mut result,
174        );
175    }
176    result
177}
178
179/// Unpacks 4 8-bit unsigned integers into a vec4. See
180/// [UnpackSnorm4x8](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for exact
181/// semantics.
182#[spirv_std_macros::gpu_only]
183pub fn u8x4_to_vec4_unorm<V: Vector<f32, 4>>(int: u32) -> V {
184    let mut result = Default::default();
185    unsafe {
186        asm!(
187            "%glsl = OpExtInstImport \"GLSL.std.450\"",
188            "%float = OpTypeFloat 32",
189            "%vec4 = OpTypeVector %float 4",
190            // 64 = UnpackUnorm4x8
191            "%result = OpExtInst %vec4 %glsl 64 {int}",
192            "OpStore {result} %result",
193            int = in(reg) int,
194            result = in(reg) &mut result,
195        );
196    }
197    result
198}
199
200/// Unpacks 2 16-bit signed integers into a vec2. See
201/// [UnpackSnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for
202/// exact semantics.
203#[spirv_std_macros::gpu_only]
204pub fn u16x2_to_vec2_snorm<V: Vector<f32, 2>>(int: u32) -> V {
205    let mut result = Default::default();
206    unsafe {
207        asm!(
208            "%glsl = OpExtInstImport \"GLSL.std.450\"",
209            "%float = OpTypeFloat 32",
210            "%vec2 = OpTypeVector %float 2",
211            // 60 = UnpackSnorm2x16
212            "%result = OpExtInst %vec2 %glsl 60 {int}",
213            "OpStore {result} %result",
214            int = in(reg) int,
215            result = in(reg) &mut result,
216        );
217    }
218    result
219}
220
221/// Unpacks 2 16-bit unsigned integers into a vec2. See
222/// [UnpackUnorm2x16](https://www.khronos.org/registry/SPIR-V/specs/1.0/GLSL.std.450.html) for
223/// exact semantics.
224#[spirv_std_macros::gpu_only]
225pub fn u16x2_to_vec2_unorm<V: Vector<f32, 2>>(int: u32) -> V {
226    let mut result = Default::default();
227    unsafe {
228        asm!(
229            "%glsl = OpExtInstImport \"GLSL.std.450\"",
230            "%float = OpTypeFloat 32",
231            "%vec2 = OpTypeVector %float 2",
232            // 61 = UnpackUnorm2x16
233            "%result = OpExtInst %vec2 %glsl 61 {int}",
234            "OpStore {result} %result",
235            int = in(reg) int,
236            result = in(reg) &mut result,
237        );
238    }
239    result
240}