1 use crate::vk;
2 use std::iter::Iterator;
3 use std::marker::PhantomData;
4 use std::mem::size_of;
5 use std::os::raw::c_void;
6 use std::{io, slice};
7 
8 /// [`Align`] handles dynamic alignment. The is useful for dynamic uniform buffers where
9 /// the alignment might be different. For example a 4x4 f32 matrix has a size of 64 bytes
10 /// but the min alignment for a dynamic uniform buffer might be 256 bytes. A slice of `&[Mat4x4<f32>]`
11 /// has a memory layout of `[[64 bytes], [64 bytes], [64 bytes]]`, but it might need to have a memory
12 /// layout of `[[256 bytes], [256 bytes], [256 bytes]]`.
13 /// [`Align::copy_from_slice`] will copy a slice of `&[T]` directly into the host memory without
14 /// an additional allocation and with the correct alignment.
15 #[derive(Debug, Clone)]
16 pub struct Align<T> {
17     ptr: *mut c_void,
18     elem_size: vk::DeviceSize,
19     size: vk::DeviceSize,
20     _m: PhantomData<T>,
21 }
22 
23 #[derive(Debug)]
24 pub struct AlignIter<'a, T: 'a> {
25     align: &'a mut Align<T>,
26     current: vk::DeviceSize,
27 }
28 
29 impl<T: Copy> Align<T> {
copy_from_slice(&mut self, slice: &[T])30     pub fn copy_from_slice(&mut self, slice: &[T]) {
31         use std::slice::from_raw_parts_mut;
32         if self.elem_size == size_of::<T>() as u64 {
33             unsafe {
34                 let mapped_slice = from_raw_parts_mut(self.ptr.cast(), slice.len());
35                 mapped_slice.copy_from_slice(slice);
36             }
37         } else {
38             for (i, val) in self.iter_mut().enumerate().take(slice.len()) {
39                 *val = slice[i];
40             }
41         }
42     }
43 }
44 
calc_padding(adr: vk::DeviceSize, align: vk::DeviceSize) -> vk::DeviceSize45 fn calc_padding(adr: vk::DeviceSize, align: vk::DeviceSize) -> vk::DeviceSize {
46     (align - adr % align) % align
47 }
48 
49 impl<T> Align<T> {
new(ptr: *mut c_void, alignment: vk::DeviceSize, size: vk::DeviceSize) -> Self50     pub unsafe fn new(ptr: *mut c_void, alignment: vk::DeviceSize, size: vk::DeviceSize) -> Self {
51         let padding = calc_padding(size_of::<T>() as vk::DeviceSize, alignment);
52         let elem_size = size_of::<T>() as vk::DeviceSize + padding;
53         assert!(calc_padding(size, alignment) == 0, "size must be aligned");
54         Self {
55             ptr,
56             elem_size,
57             size,
58             _m: PhantomData,
59         }
60     }
61 
iter_mut(&mut self) -> AlignIter<T>62     pub fn iter_mut(&mut self) -> AlignIter<T> {
63         AlignIter {
64             current: 0,
65             align: self,
66         }
67     }
68 }
69 
70 impl<'a, T: Copy + 'a> Iterator for AlignIter<'a, T> {
71     type Item = &'a mut T;
next(&mut self) -> Option<Self::Item>72     fn next(&mut self) -> Option<Self::Item> {
73         if self.current == self.align.size {
74             return None;
75         }
76         unsafe {
77             // Need to cast to *mut u8 because () has size 0
78             let ptr = (self.align.ptr.cast::<u8>())
79                 .offset(self.current as isize)
80                 .cast();
81             self.current += self.align.elem_size;
82             Some(&mut *ptr)
83         }
84     }
85 }
86 
87 /// Decode SPIR-V from bytes.
88 ///
89 /// This function handles SPIR-V of arbitrary endianness gracefully, and returns correctly aligned
90 /// storage.
91 ///
92 /// # Examples
93 /// ```no_run
94 /// // Decode SPIR-V from a file
95 /// let mut file = std::fs::File::open("/path/to/shader.spv").unwrap();
96 /// let words = ash::util::read_spv(&mut file).unwrap();
97 /// ```
98 /// ```
99 /// // Decode SPIR-V from memory
100 /// const SPIRV: &[u8] = &[
101 ///     // ...
102 /// #   0x03, 0x02, 0x23, 0x07,
103 /// ];
104 /// let words = ash::util::read_spv(&mut std::io::Cursor::new(&SPIRV[..])).unwrap();
105 /// ```
read_spv<R: io::Read + io::Seek>(x: &mut R) -> io::Result<Vec<u32>>106 pub fn read_spv<R: io::Read + io::Seek>(x: &mut R) -> io::Result<Vec<u32>> {
107     // TODO use stream_len() once it is stabilized and remove the subsequent rewind() call
108     let size = x.seek(io::SeekFrom::End(0))?;
109     x.rewind()?;
110     if size % 4 != 0 {
111         return Err(io::Error::new(
112             io::ErrorKind::InvalidData,
113             "input length not divisible by 4",
114         ));
115     }
116     if size > usize::max_value() as u64 {
117         return Err(io::Error::new(io::ErrorKind::InvalidData, "input too long"));
118     }
119     let words = (size / 4) as usize;
120     // https://github.com/MaikKlein/ash/issues/354:
121     // Zero-initialize the result to prevent read_exact from possibly
122     // reading uninitialized memory.
123     let mut result = vec![0u32; words];
124     x.read_exact(unsafe {
125         slice::from_raw_parts_mut(result.as_mut_ptr().cast::<u8>(), words * 4)
126     })?;
127     const MAGIC_NUMBER: u32 = 0x0723_0203;
128     if !result.is_empty() && result[0] == MAGIC_NUMBER.swap_bytes() {
129         for word in &mut result {
130             *word = word.swap_bytes();
131         }
132     }
133     if result.is_empty() || result[0] != MAGIC_NUMBER {
134         return Err(io::Error::new(
135             io::ErrorKind::InvalidData,
136             "input missing SPIR-V magic number",
137         ));
138     }
139     Ok(result)
140 }
141