From 5795fa79438f16e415cfb20e9288c4a5eb1369fd Mon Sep 17 00:00:00 2001 From: Jay Oster Date: Sun, 27 Oct 2019 19:50:15 -0700 Subject: [PATCH] Add include_spv!() macro, donated by Ralith (#26) --- Cargo.lock | 1 - Cargo.toml | 1 - src/lib.rs | 7 ++++--- src/macros.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/renderers.rs | 22 +++------------------- 5 files changed, 49 insertions(+), 24 deletions(-) create mode 100644 src/macros.rs diff --git a/Cargo.lock b/Cargo.lock index 411d663..cb78aad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -702,7 +702,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "pixels" version = "0.0.1" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "pixels-mocks 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index b3b5fba..7974122 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ categories = ["graphics", "rendering"] license = "MIT" [dependencies] -byteorder = "1.3" wgpu = { git = "https://github.com/gfx-rs/wgpu-rs", rev = "012d08d64de924da93289c2b51fb06b22d7348cf" } [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 9ad5082..65738b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,14 +16,15 @@ use std::error::Error as StdError; use std::fmt; use std::rc::Rc; +pub use crate::macros::*; +pub use crate::render_pass::{BoxedRenderPass, Device, Queue, RenderPass}; +use crate::renderers::Renderer; pub use wgpu; use wgpu::{Extent3d, TextureView}; +mod macros; mod render_pass; -pub use render_pass::{BoxedRenderPass, Device, Queue, RenderPass}; - mod renderers; -use renderers::Renderer; type RenderPassFactory = Box BoxedRenderPass>; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..f91746a --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,42 @@ +//! Provides a macro and type for including SPIR-V shaders in const data. +//! +//! In an ideal world, a shader will be compiled at build-time directly into the executable. This +//! is opposed to the typical method of including a shader, which reads a GLSL source code file +//! from the file system at start, compiles it, and sends it to the GPU. That process adds a +//! non-trivial amount of time to startup, and additional error handling code at runtime. +//! +//! This macro moves all of that complexity to build-time. At least for the SPIR-V part of the +//! shader pipeline. (`gfx-hal` backends have their own SPIR-V-to-native compilers at runtime.) +//! +//! Cribbed with permission from Ralith +//! See: https://github.com/MaikKlein/ash/pull/245 + +/// Include correctly aligned and typed precompiled SPIR-V +/// +/// Does not account for endianness mismatches between the SPIR-V file and the target. See +/// [`wgpu::read_spirv`] for a more general solution. +#[macro_export] +macro_rules! include_spv { + ($path:expr) => { + &$crate::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 = 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) + } + } +} + +#[repr(align(4))] +#[doc(hidden)] +pub struct Align4(pub T); diff --git a/src/renderers.rs b/src/renderers.rs index dcd07d5..39ffd27 100644 --- a/src/renderers.rs +++ b/src/renderers.rs @@ -1,8 +1,8 @@ -use byteorder::{ByteOrder, LittleEndian}; use std::fmt; use std::rc::Rc; use wgpu::{self, Extent3d, TextureView}; +use crate::include_spv; use crate::render_pass::{BoxedRenderPass, Device, Queue, RenderPass}; /// Renderer implements [`RenderPass`]. @@ -24,24 +24,8 @@ impl Renderer { texture_view: &TextureView, texture_size: &Extent3d, ) -> BoxedRenderPass { - let vert_spv = include_bytes!("../shaders/vert.spv"); - let mut vert = Vec::new(); - vert.resize_with( - vert_spv.len() / std::mem::size_of::(), - Default::default, - ); - LittleEndian::read_u32_into(vert_spv, &mut vert); - - let frag_spv = include_bytes!("../shaders/frag.spv"); - let mut frag = Vec::new(); - frag.resize_with( - frag_spv.len() / std::mem::size_of::(), - Default::default, - ); - LittleEndian::read_u32_into(frag_spv, &mut frag); - - let vs_module = device.create_shader_module(&vert); - let fs_module = device.create_shader_module(&frag); + let vs_module = device.create_shader_module(include_spv!("../shaders/vert.spv")); + let fs_module = device.create_shader_module(include_spv!("../shaders/frag.spv")); // Create a texture sampler with nearest neighbor let sampler = device.create_sampler(&wgpu::SamplerDescriptor {