170: SPIR-V reading helper r=MaikKlein a=Ralith

SPIR-V is defined in terms of 4-byte words and does not have a defined endianness, and compiler and target endianness may differ. Furthermore, Vulkan seems to require SPIR-V supplied to the implementation to be 4-byte-aligned. As a result, reading SPIR-V in a safe and portable fashion is error-prone.

So far we have largely shied away from including nontrivial helper code in ash, but arguably most portable code using ash will want this function. Do we want to break precedent? Or should we introduce a separate, optional, utility crate for code that doesn't directly wrap some part of Vulkan?

Co-authored-by: Benjamin Saunders <ben.e.saunders@gmail.com>
This commit is contained in:
bors[bot] 2018-12-09 08:19:02 +00:00
commit 43eabee68a
2 changed files with 57 additions and 0 deletions

View file

@ -1,6 +1,7 @@
#[macro_use]
extern crate lazy_static;
extern crate shared_library;
pub use device::Device;
pub use entry::{Entry, InstanceError, LoadingError};
pub use instance::Instance;

View file

@ -2,6 +2,7 @@ use std::iter::Iterator;
use std::marker::PhantomData;
use std::mem::size_of;
use std::os::raw::c_void;
use std::{io, slice};
use vk;
/// `Align` handles dynamic alignment. The is useful for dynamic uniform buffers where
@ -80,3 +81,58 @@ impl<'a, T: Copy + 'a> Iterator for AlignIter<'a, T> {
}
}
}
/// 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;
let mut result = Vec::<u32>::with_capacity(words);
x.seek(io::SeekFrom::Start(0))?;
unsafe {
x.read_exact(slice::from_raw_parts_mut(
result.as_mut_ptr() as *mut u8,
words * 4,
))?;
result.set_len(words);
}
const MAGIC_NUMBER: u32 = 0x07230203;
if result.len() > 0 && result[0] == MAGIC_NUMBER.swap_bytes() {
for word in &mut result {
*word = word.swap_bytes();
}
}
if result.len() == 0 || result[0] != MAGIC_NUMBER {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"input missing SPIR-V magic number",
));
}
Ok(result)
}