Skip to main content

spirv_std/
float.rs

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