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