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