forked from Rust-GPU/rust-gpu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruntime_array.rs
65 lines (62 loc) · 2.86 KB
/
runtime_array.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#[cfg(target_arch = "spirv")]
use core::arch::asm;
use core::marker::PhantomData;
/// SPIR-V "runtime array", similar to `[T]`, but with no way of knowing its length.
///
/// Dynamically-sized arrays in Rust carry around their length as the second half of a tuple.
/// Unfortunately, sometimes SPIR-V provides an unsized array with no way of obtaining its length.
#[spirv(runtime_array)]
// HACK(eddyb) avoids "transparent newtype of `_anti_zst_padding`" misinterpretation.
#[repr(C)]
// HACK(eddyb) false positive due to `rustc` not understanding e.g. entry-points.
#[allow(dead_code)]
pub struct RuntimeArray<T> {
// HACK(eddyb) avoids the layout becoming ZST (and being elided in one way
// or another, before `#[spirv(runtime_array)]` can special-case it).
_anti_zst_padding: core::mem::MaybeUninit<u32>,
_phantom: PhantomData<T>,
}
// It would be nice to use the Index/IndexMut traits here, but because we do not have the length of
// the array, it's impossible to make them be safe operations (indexing out of bounds), and
// Index/IndexMut are marked as safe functions.
impl<T> RuntimeArray<T> {
/// Index the array. Unfortunately, because the length of the runtime array cannot be known,
/// this function will happily index outside of the bounds of the array, and so is unsafe.
///
/// # Safety
/// Bounds checking is not performed, and indexing outside the bounds of the array can happen,
/// and lead to UB.
#[spirv_std_macros::gpu_only]
pub unsafe fn index(&self, index: usize) -> &T {
// FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! {
"%result = OpAccessChain _ {arr} {index}",
"OpStore {result_slot} %result",
arr = in(reg) self,
index = in(reg) index,
result_slot = in(reg) result_slot.as_mut_ptr(),
}
result_slot.assume_init()
}
/// Index the array, returning a mutable reference to an element. Unfortunately, because the
/// length of the runtime array cannot be known, this function will happily index outside of
/// the bounds of the array, and so is unsafe.
///
/// # Safety
/// Bounds checking is not performed, and indexing outside the bounds of the array can happen,
/// and lead to UB.
#[spirv_std_macros::gpu_only]
pub unsafe fn index_mut(&mut self, index: usize) -> &mut T {
// FIXME(eddyb) `let mut result = T::default()` uses (for `asm!`), with this.
let mut result_slot = core::mem::MaybeUninit::uninit();
asm! {
"%result = OpAccessChain _ {arr} {index}",
"OpStore {result_slot} %result",
arr = in(reg) self,
index = in(reg) index,
result_slot = in(reg) result_slot.as_mut_ptr(),
}
result_slot.assume_init()
}
}