From ba79eeaad7ab2c27984114252eead54d76700beb Mon Sep 17 00:00:00 2001 From: Benjamin Saunders Date: Fri, 25 Oct 2019 19:26:19 -0700 Subject: [PATCH] Helper macro for including precompiled SPIR-V Should help suppress the temptation to court UB via naive include_bytes. Implementation placed in the root because macros are always imported via the root and it'd be weird for the returned type to not be beside it. --- ash/src/lib.rs | 27 +++++++++++++++++++++++++++ ash/src/util.rs | 4 ++++ examples/src/bin/triangle.rs | 16 +++++----------- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/ash/src/lib.rs b/ash/src/lib.rs index 832cc96f0..d68e532a0 100644 --- a/ash/src/lib.rs +++ b/ash/src/lib.rs @@ -52,9 +52,36 @@ impl<'r, T> RawPtr for Option<&'r T> { } } +/// Include correctly aligned and typed precompiled SPIR-V +/// +/// Does not account for endianness mismatches between the SPIR-V file and the target. See +/// `util::read_spv` for a more general solution. +#[macro_export] +macro_rules! include_spv { + ($path:expr) => { + &$crate::util::Align4(*include_bytes!($path)) as &$crate::Spirv + }; +} + +/// Type returned by `include_spv`, convertible to `&[u32]` +/// +/// The definition of this type is unstable. +pub type Spirv = util::Align4<[u8]>; + +impl std::ops::Deref for Spirv { + type Target = [u32]; + fn deref(&self) -> &[u32] { + #[allow(clippy::cast_ptr_alignment)] + unsafe { + std::slice::from_raw_parts(self.0.as_ptr() as *const u32, self.0.len() / 4) + } + } +} + #[cfg(test)] mod tests { use super::vk; + #[test] fn test_ptr_chains() { let mut variable_pointers = vk::PhysicalDeviceVariablePointerFeatures::builder(); diff --git a/ash/src/util.rs b/ash/src/util.rs index 48591d85c..e8ab9273a 100644 --- a/ash/src/util.rs +++ b/ash/src/util.rs @@ -136,3 +136,7 @@ pub fn read_spv(x: &mut R) -> io::Result> { } Ok(result) } + +#[repr(align(4))] +#[doc(hidden)] +pub struct Align4(pub T); diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 86ca5ed6b..5ec0c9a53 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -1,9 +1,8 @@ use ash::util::*; -use ash::vk; +use ash::{include_spv, vk, Spirv}; use examples::*; use std::default::Default; use std::ffi::CString; -use std::io::Cursor; use std::mem; use std::mem::align_of; @@ -198,17 +197,12 @@ fn main() { base.device .bind_buffer_memory(vertex_input_buffer, vertex_input_buffer_memory, 0) .unwrap(); - let mut vertex_spv_file = - Cursor::new(&include_bytes!("../../shader/triangle/vert.spv")[..]); - let mut frag_spv_file = Cursor::new(&include_bytes!("../../shader/triangle/frag.spv")[..]); - let vertex_code = - read_spv(&mut vertex_spv_file).expect("Failed to read vertex shader spv file"); - let vertex_shader_info = vk::ShaderModuleCreateInfo::builder().code(&vertex_code); + const VERTEX_CODE: &Spirv = include_spv!("../../shader/triangle/vert.spv"); + let vertex_shader_info = vk::ShaderModuleCreateInfo::builder().code(VERTEX_CODE); - let frag_code = - read_spv(&mut frag_spv_file).expect("Failed to read fragment shader spv file"); - let frag_shader_info = vk::ShaderModuleCreateInfo::builder().code(&frag_code); + const FRAG_CODE: &Spirv = include_spv!("../../shader/triangle/frag.spv"); + let frag_shader_info = vk::ShaderModuleCreateInfo::builder().code(FRAG_CODE); let vertex_shader_module = base .device