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