1#[cfg(target_arch = "spirv")]
7use crate::integer::Integer;
8use crate::{
9 integer::{SignedInteger, UnsignedInteger},
10 scalar::Scalar,
11 vector::Vector,
12};
13#[cfg(target_arch = "spirv")]
14use core::arch::asm;
15
16mod atomics;
17mod barrier;
18mod demote_to_helper_invocation_ext;
19mod derivative;
20mod mesh_shading;
21mod primitive;
22mod ray_tracing;
23mod subgroup;
24
25pub use atomics::*;
26pub use barrier::*;
27pub use demote_to_helper_invocation_ext::*;
28pub use derivative::*;
29pub use mesh_shading::*;
30pub use primitive::*;
31pub use ray_tracing::*;
32pub use subgroup::*;
33
34#[spirv_std_macros::gpu_only]
37#[doc(alias = "OpAny")]
38#[inline]
39pub fn any<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
40 let mut result = false;
41
42 unsafe {
43 asm! {
44 "%bool = OpTypeBool",
45 "%vector = OpLoad _ {vector}",
46 "%result = OpAny %bool %vector",
47 "OpStore {result} %result",
48 vector = in(reg) &vector,
49 result = in(reg) &mut result
50 }
51 }
52
53 result
54}
55
56#[spirv_std_macros::gpu_only]
59#[doc(alias = "OpAll")]
60#[inline]
61pub fn all<V: Vector<bool, N>, const N: usize>(vector: V) -> bool {
62 let mut result = false;
63
64 unsafe {
65 asm! {
66 "%bool = OpTypeBool",
67 "%vector = OpLoad _ {vector}",
68 "%result = OpAll %bool %vector",
69 "OpStore {result} %result",
70 vector = in(reg) &vector,
71 result = in(reg) &mut result
72 }
73 }
74
75 result
76}
77
78#[spirv_std_macros::gpu_only]
84#[doc(alias = "OpVectorExtractDynamic")]
85#[inline]
86pub unsafe fn vector_extract_dynamic<T: Scalar, const N: usize>(
87 vector: impl Vector<T, N>,
88 index: usize,
89) -> T {
90 unsafe {
91 let mut result = T::default();
92
93 asm! {
94 "%vector = OpLoad _ {vector}",
95 "%element = OpVectorExtractDynamic _ %vector {index}",
96 "OpStore {element} %element",
97 vector = in(reg) &vector,
98 index = in(reg) index,
99 element = in(reg) &mut result
100 }
101
102 result
103 }
104}
105
106#[spirv_std_macros::gpu_only]
113#[doc(alias = "OpVectorInsertDynamic")]
114#[inline]
115pub unsafe fn vector_insert_dynamic<T: Scalar, V: Vector<T, N>, const N: usize>(
116 vector: V,
117 index: usize,
118 element: T,
119) -> V {
120 unsafe {
121 let mut result = V::default();
122
123 asm! {
124 "%vector = OpLoad _ {vector}",
125 "%element = OpLoad _ {element}",
126 "%new_vector = OpVectorInsertDynamic _ %vector %element {index}",
127 "OpStore {result} %new_vector",
128 vector = in(reg) &vector,
129 index = in(reg) index,
130 element = in(reg) &element,
131 result = in(reg) &mut result,
132 }
133
134 result
135 }
136}
137
138#[spirv_std_macros::gpu_only]
144#[doc(alias = "OpKill", alias = "discard")]
145#[allow(clippy::empty_loop)]
146pub fn kill() -> ! {
147 unsafe { asm!("OpKill", options(noreturn)) }
148}
149
150#[spirv_std_macros::gpu_only]
155#[doc(alias = "OpReadClockKHR")]
156pub unsafe fn read_clock_khr<const SCOPE: u32>() -> u64 {
157 unsafe {
158 let mut result: u64;
159
160 asm! {
161 "%uint = OpTypeInt 32 0",
162 "%scope = OpConstant %uint {scope}",
163 "{result} = OpReadClockKHR typeof*{result} %scope",
164 result = out(reg) result,
165 scope = const SCOPE,
166 };
167
168 result
169 }
170}
171
172#[spirv_std_macros::gpu_only]
177#[doc(alias = "OpReadClockKHR")]
178pub unsafe fn read_clock_uvec2_khr<V: Vector<u32, 2>, const SCOPE: u32>() -> V {
179 unsafe {
180 let mut result = V::default();
181
182 asm! {
183 "%uint = OpTypeInt 32 0",
184 "%scope = OpConstant %uint {scope}",
185 "%result = OpReadClockKHR typeof*{result} %scope",
186 "OpStore {result} %result",
187 result = in(reg) &mut result,
188 scope = const SCOPE,
189 };
190
191 result
192 }
193}
194
195#[cfg(target_arch = "spirv")]
196unsafe fn call_glsl_op_with_ints<T: Integer, const OP: u32>(a: T, b: T) -> T {
197 unsafe {
198 let mut result = T::default();
199 asm!(
200 "%glsl = OpExtInstImport \"GLSL.std.450\"",
201 "%a = OpLoad _ {a}",
202 "%b = OpLoad _ {b}",
203 "%result = OpExtInst typeof*{result} %glsl {op} %a %b",
204 "OpStore {result} %result",
205 a = in(reg) &a,
206 b = in(reg) &b,
207 result = in(reg) &mut result,
208 op = const OP
209 );
210 result
211 }
212}
213
214#[spirv_std_macros::gpu_only]
216pub fn unsigned_min<T: UnsignedInteger>(a: T, b: T) -> T {
217 unsafe { call_glsl_op_with_ints::<_, 38>(a, b) }
218}
219
220#[spirv_std_macros::gpu_only]
222pub fn unsigned_max<T: UnsignedInteger>(a: T, b: T) -> T {
223 unsafe { call_glsl_op_with_ints::<_, 41>(a, b) }
224}
225
226#[spirv_std_macros::gpu_only]
228pub fn signed_min<T: SignedInteger>(a: T, b: T) -> T {
229 unsafe { call_glsl_op_with_ints::<_, 39>(a, b) }
230}
231
232#[spirv_std_macros::gpu_only]
234pub fn signed_max<T: SignedInteger>(a: T, b: T) -> T {
235 unsafe { call_glsl_op_with_ints::<_, 42>(a, b) }
236}
237
238pub trait IndexUnchecked<T> {
243 unsafe fn index_unchecked(&self, index: usize) -> &T;
248 unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T;
253}
254
255impl<T> IndexUnchecked<T> for [T] {
256 #[cfg(target_arch = "spirv")]
257 unsafe fn index_unchecked(&self, index: usize) -> &T {
258 unsafe {
259 let mut result_slot = core::mem::MaybeUninit::uninit();
261 asm! {
262 "%slice_ptr = OpLoad _ {slice_ptr_ptr}",
263 "%data_ptr = OpCompositeExtract _ %slice_ptr 0",
264 "%result = OpAccessChain _ %data_ptr {index}",
265 "OpStore {result_slot} %result",
266 slice_ptr_ptr = in(reg) &self,
267 index = in(reg) index,
268 result_slot = in(reg) result_slot.as_mut_ptr(),
269 }
270 result_slot.assume_init()
271 }
272 }
273
274 #[cfg(not(target_arch = "spirv"))]
275 unsafe fn index_unchecked(&self, index: usize) -> &T {
276 unsafe { self.get_unchecked(index) }
277 }
278
279 #[cfg(target_arch = "spirv")]
280 unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
281 unsafe {
282 let mut result_slot = core::mem::MaybeUninit::uninit();
284 asm! {
285 "%slice_ptr = OpLoad _ {slice_ptr_ptr}",
286 "%data_ptr = OpCompositeExtract _ %slice_ptr 0",
287 "%result = OpAccessChain _ %data_ptr {index}",
288 "OpStore {result_slot} %result",
289 slice_ptr_ptr = in(reg) &self,
290 index = in(reg) index,
291 result_slot = in(reg) result_slot.as_mut_ptr(),
292 }
293 result_slot.assume_init()
294 }
295 }
296
297 #[cfg(not(target_arch = "spirv"))]
298 unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
299 unsafe { self.get_unchecked_mut(index) }
300 }
301}
302
303impl<T, const N: usize> IndexUnchecked<T> for [T; N] {
304 #[cfg(target_arch = "spirv")]
305 unsafe fn index_unchecked(&self, index: usize) -> &T {
306 unsafe {
307 let mut result_slot = core::mem::MaybeUninit::uninit();
309 asm! {
310 "%result = OpAccessChain _ {array_ptr} {index}",
311 "OpStore {result_slot} %result",
312 array_ptr = in(reg) self,
313 index = in(reg) index,
314 result_slot = in(reg) result_slot.as_mut_ptr(),
315 }
316 result_slot.assume_init()
317 }
318 }
319
320 #[cfg(not(target_arch = "spirv"))]
321 unsafe fn index_unchecked(&self, index: usize) -> &T {
322 unsafe { self.get_unchecked(index) }
323 }
324
325 #[cfg(target_arch = "spirv")]
326 unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
327 unsafe {
328 let mut result_slot = core::mem::MaybeUninit::uninit();
330 asm! {
331 "%result = OpAccessChain _ {array_ptr} {index}",
332 "OpStore {result_slot} %result",
333 array_ptr = in(reg) self,
334 index = in(reg) index,
335 result_slot = in(reg) result_slot.as_mut_ptr(),
336 }
337 result_slot.assume_init()
338 }
339 }
340
341 #[cfg(not(target_arch = "spirv"))]
342 unsafe fn index_unchecked_mut(&mut self, index: usize) -> &mut T {
343 unsafe { self.get_unchecked_mut(index) }
344 }
345}