summaryrefslogtreecommitdiffstats
path: root/third_party/rust/ash/src/util.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/ash/src/util.rs')
-rw-r--r--third_party/rust/ash/src/util.rs139
1 files changed, 139 insertions, 0 deletions
diff --git a/third_party/rust/ash/src/util.rs b/third_party/rust/ash/src/util.rs
new file mode 100644
index 0000000000..119fab9c65
--- /dev/null
+++ b/third_party/rust/ash/src/util.rs
@@ -0,0 +1,139 @@
+use crate::vk;
+use std::iter::Iterator;
+use std::marker::PhantomData;
+use std::mem::size_of;
+use std::os::raw::c_void;
+use std::{io, slice};
+
+/// [`Align`] handles dynamic alignment. The is useful for dynamic uniform buffers where
+/// the alignment might be different. For example a 4x4 f32 matrix has a size of 64 bytes
+/// but the min alignment for a dynamic uniform buffer might be 256 bytes. A slice of `&[Mat4x4<f32>]`
+/// has a memory layout of `[[64 bytes], [64 bytes], [64 bytes]]`, but it might need to have a memory
+/// layout of `[[256 bytes], [256 bytes], [256 bytes]]`.
+/// [`Align::copy_from_slice`] will copy a slice of `&[T]` directly into the host memory without
+/// an additional allocation and with the correct alignment.
+#[derive(Debug, Clone)]
+pub struct Align<T> {
+ ptr: *mut c_void,
+ elem_size: vk::DeviceSize,
+ size: vk::DeviceSize,
+ _m: PhantomData<T>,
+}
+
+#[derive(Debug)]
+pub struct AlignIter<'a, T: 'a> {
+ align: &'a mut Align<T>,
+ current: vk::DeviceSize,
+}
+
+impl<T: Copy> Align<T> {
+ pub fn copy_from_slice(&mut self, slice: &[T]) {
+ use std::slice::from_raw_parts_mut;
+ if self.elem_size == size_of::<T>() as u64 {
+ unsafe {
+ let mapped_slice = from_raw_parts_mut(self.ptr.cast(), slice.len());
+ mapped_slice.copy_from_slice(slice);
+ }
+ } else {
+ for (i, val) in self.iter_mut().enumerate().take(slice.len()) {
+ *val = slice[i];
+ }
+ }
+ }
+}
+
+fn calc_padding(adr: vk::DeviceSize, align: vk::DeviceSize) -> vk::DeviceSize {
+ (align - adr % align) % align
+}
+
+impl<T> Align<T> {
+ pub unsafe fn new(ptr: *mut c_void, alignment: vk::DeviceSize, size: vk::DeviceSize) -> Self {
+ let padding = calc_padding(size_of::<T>() as vk::DeviceSize, alignment);
+ let elem_size = size_of::<T>() as vk::DeviceSize + padding;
+ assert!(calc_padding(size, alignment) == 0, "size must be aligned");
+ Self {
+ ptr,
+ elem_size,
+ size,
+ _m: PhantomData,
+ }
+ }
+
+ pub fn iter_mut(&mut self) -> AlignIter<T> {
+ AlignIter {
+ current: 0,
+ align: self,
+ }
+ }
+}
+
+impl<'a, T: Copy + 'a> Iterator for AlignIter<'a, T> {
+ type Item = &'a mut T;
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.current == self.align.size {
+ return None;
+ }
+ unsafe {
+ // Need to cast to *mut u8 because () has size 0
+ let ptr = (self.align.ptr.cast::<u8>())
+ .offset(self.current as isize)
+ .cast();
+ self.current += self.align.elem_size;
+ Some(&mut *ptr)
+ }
+ }
+}
+
+/// Decode SPIR-V from bytes.
+///
+/// This function handles SPIR-V of arbitrary endianness gracefully, and returns correctly aligned
+/// storage.
+///
+/// # Examples
+/// ```no_run
+/// // Decode SPIR-V from a file
+/// let mut file = std::fs::File::open("/path/to/shader.spv").unwrap();
+/// let words = ash::util::read_spv(&mut file).unwrap();
+/// ```
+/// ```
+/// // Decode SPIR-V from memory
+/// const SPIRV: &[u8] = &[
+/// // ...
+/// # 0x03, 0x02, 0x23, 0x07,
+/// ];
+/// let words = ash::util::read_spv(&mut std::io::Cursor::new(&SPIRV[..])).unwrap();
+/// ```
+pub fn read_spv<R: io::Read + io::Seek>(x: &mut R) -> io::Result<Vec<u32>> {
+ let size = x.seek(io::SeekFrom::End(0))?;
+ if size % 4 != 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "input length not divisible by 4",
+ ));
+ }
+ if size > usize::max_value() as u64 {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "input too long"));
+ }
+ let words = (size / 4) as usize;
+ // https://github.com/MaikKlein/ash/issues/354:
+ // Zero-initialize the result to prevent read_exact from possibly
+ // reading uninitialized memory.
+ let mut result = vec![0u32; words];
+ x.seek(io::SeekFrom::Start(0))?;
+ x.read_exact(unsafe {
+ slice::from_raw_parts_mut(result.as_mut_ptr().cast::<u8>(), words * 4)
+ })?;
+ const MAGIC_NUMBER: u32 = 0x0723_0203;
+ if !result.is_empty() && result[0] == MAGIC_NUMBER.swap_bytes() {
+ for word in &mut result {
+ *word = word.swap_bytes();
+ }
+ }
+ if result.is_empty() || result[0] != MAGIC_NUMBER {
+ return Err(io::Error::new(
+ io::ErrorKind::InvalidData,
+ "input missing SPIR-V magic number",
+ ));
+ }
+ Ok(result)
+}