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
#[cfg(target_arch = "spirv")]
use core::arch::asm;
use core::marker::PhantomData;
/// 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.
/// Hence, this type represents something very similar to a slice, but with no way of knowing its
/// length.
#[spirv(runtime_array)]
pub struct RuntimeArray<T> {
// spooky! this field does not exist, so if it's referenced in rust code, things will explode
_do_not_touch: 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 {
asm! {
"%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result",
arr = in(reg) self,
index = in(reg) index,
options(noreturn),
}
}
/// 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 {
asm! {
"%result = OpAccessChain _ {arr} {index}",
"OpReturnValue %result",
arr = in(reg) self,
index = in(reg) index,
options(noreturn),
}
}
}