diff --git a/wgpu/Cargo.toml b/wgpu/Cargo.toml index e59b7eab62..4d8d0a16d3 100644 --- a/wgpu/Cargo.toml +++ b/wgpu/Cargo.toml @@ -28,14 +28,14 @@ vulkan = ["wgc/gfx-backend-vulkan"] package = "wgpu-core" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "fc2dd481b2713cd0eda6ffa540faeaf7418fd051" +rev = "6bca38feed155aa80776ae5e7dfa4769c655b638" features = ["raw-window-handle"] [dependencies.wgt] package = "wgpu-types" version = "0.5" git = "https://github.com/gfx-rs/wgpu" -rev = "fc2dd481b2713cd0eda6ffa540faeaf7418fd051" +rev = "6bca38feed155aa80776ae5e7dfa4769c655b638" [dependencies] arrayvec = "0.5" diff --git a/wgpu/examples/boids/main.rs b/wgpu/examples/boids/main.rs index c70b7f3c93..460ac5215a 100644 --- a/wgpu/examples/boids/main.rs +++ b/wgpu/examples/boids/main.rs @@ -6,8 +6,6 @@ extern crate rand; #[path = "../framework.rs"] mod framework; -use wgpu::vertex_attr_array; - // number of boid particles to simulate const NUM_PARTICLES: u32 = 1500; @@ -36,17 +34,9 @@ impl framework::Example for Example { ) -> (Self, Option) { // load (and compile) shaders and create shader modules - let boids = include_bytes!("boids.comp.spv"); - let boids_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&boids[..])).unwrap()); - - let vs = include_bytes!("shader.vert.spv"); - let vs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap()); - - let fs = include_bytes!("shader.frag.spv"); - let fs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap()); + let boids_module = device.create_shader_module(wgpu::include_spirv!("boids.comp.spv")); + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv")); // buffer for simulation parameters uniform @@ -148,12 +138,12 @@ impl framework::Example for Example { wgpu::VertexBufferDescriptor { stride: 4 * 4, step_mode: wgpu::InputStepMode::Instance, - attributes: &vertex_attr_array![0 => Float2, 1 => Float2], + attributes: &wgpu::vertex_attr_array![0 => Float2, 1 => Float2], }, wgpu::VertexBufferDescriptor { stride: 2 * 4, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![2 => Float2], + attributes: &wgpu::vertex_attr_array![2 => Float2], }, ], }, diff --git a/wgpu/examples/cube/main.rs b/wgpu/examples/cube/main.rs index 5488c5eb26..cb02ecbf75 100644 --- a/wgpu/examples/cube/main.rs +++ b/wgpu/examples/cube/main.rs @@ -234,12 +234,8 @@ impl framework::Example for Example { }); // Create the render pipeline - let vs_bytes = include_bytes!("shader.vert.spv"); - let fs_bytes = include_bytes!("shader.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, diff --git a/wgpu/examples/hello-compute/main.rs b/wgpu/examples/hello-compute/main.rs index e6ab9c7f64..abe3b22c50 100644 --- a/wgpu/examples/hello-compute/main.rs +++ b/wgpu/examples/hello-compute/main.rs @@ -47,9 +47,7 @@ async fn execute_gpu(numbers: Vec) -> Vec { .await .unwrap(); - let cs = include_bytes!("shader.comp.spv"); - let cs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&cs[..])).unwrap()); + let cs_module = device.create_shader_module(wgpu::include_spirv!("shader.comp.spv")); let staging_buffer = device.create_buffer(&wgpu::BufferDescriptor { label: None, diff --git a/wgpu/examples/hello-triangle/main.rs b/wgpu/examples/hello-triangle/main.rs index 58cd9d563f..ec5d8fdc44 100644 --- a/wgpu/examples/hello-triangle/main.rs +++ b/wgpu/examples/hello-triangle/main.rs @@ -32,13 +32,8 @@ async fn run(event_loop: EventLoop<()>, window: Window, swapchain_format: wgpu:: .await .unwrap(); - let vs = include_bytes!("shader.vert.spv"); - let vs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs[..])).unwrap()); - - let fs = include_bytes!("shader.frag.spv"); - let fs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv")); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[], diff --git a/wgpu/examples/mipmap/main.rs b/wgpu/examples/mipmap/main.rs index 59479bcb26..e57af3c387 100644 --- a/wgpu/examples/mipmap/main.rs +++ b/wgpu/examples/mipmap/main.rs @@ -3,8 +3,6 @@ mod framework; use bytemuck::{Pod, Zeroable}; -use wgpu::vertex_attr_array; - const TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba8UnormSrgb; #[repr(C)] @@ -105,12 +103,8 @@ impl Example { bind_group_layouts: &[&bind_group_layout], }); - let vs_bytes = include_bytes!("blit.vert.spv"); - let fs_bytes = include_bytes!("blit.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("blit.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("blit.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, @@ -337,12 +331,8 @@ impl framework::Example for Example { }); // Create the render pipeline - let vs_bytes = include_bytes!("draw.vert.spv"); - let fs_bytes = include_bytes!("draw.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("draw.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("draw.frag.spv")); let draw_pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, @@ -374,7 +364,7 @@ impl framework::Example for Example { vertex_buffers: &[wgpu::VertexBufferDescriptor { stride: vertex_size as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![0 => Float4], + attributes: &wgpu::vertex_attr_array![0 => Float4], }], }, sample_count: 1, diff --git a/wgpu/examples/msaa-line/main.rs b/wgpu/examples/msaa-line/main.rs index 48c9c585a1..19d9c57d78 100644 --- a/wgpu/examples/msaa-line/main.rs +++ b/wgpu/examples/msaa-line/main.rs @@ -14,8 +14,6 @@ use std::iter; use bytemuck::{Pod, Zeroable}; -use wgpu::vertex_attr_array; - #[repr(C)] #[derive(Clone, Copy)] struct Vertex { @@ -81,7 +79,7 @@ impl Example { vertex_buffers: &[wgpu::VertexBufferDescriptor { stride: std::mem::size_of::() as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![0 => Float2, 1 => Float4], + attributes: &wgpu::vertex_attr_array![0 => Float2, 1 => Float4], }], }, sample_count, @@ -138,12 +136,8 @@ impl framework::Example for Example { log::info!("Press left/right arrow keys to change sample_count."); let sample_count = 4; - let vs_bytes = include_bytes!("shader.vert.spv"); - let fs_bytes = include_bytes!("shader.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv")); let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor { bind_group_layouts: &[], diff --git a/wgpu/examples/shadow/main.rs b/wgpu/examples/shadow/main.rs index d9d0e76c8e..8526a00655 100644 --- a/wgpu/examples/shadow/main.rs +++ b/wgpu/examples/shadow/main.rs @@ -5,8 +5,6 @@ mod framework; use bytemuck::{Pod, Zeroable}; -use wgpu::vertex_attr_array; - #[repr(C)] #[derive(Clone, Copy)] @@ -426,7 +424,7 @@ impl framework::Example for Example { let vb_desc = wgpu::VertexBufferDescriptor { stride: vertex_size as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![0 => Char4, 1 => Char4], + attributes: &wgpu::vertex_attr_array![0 => Char4, 1 => Char4], }; let shadow_pass = { @@ -466,14 +464,8 @@ impl framework::Example for Example { }); // Create the render pipeline - let vs_bytes = include_bytes!("bake.vert.spv"); - let fs_bytes = include_bytes!("bake.frag.spv"); - let vs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap(), - ); - let fs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap(), - ); + let vs_module = device.create_shader_module(wgpu::include_spirv!("bake.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("bake.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, @@ -602,14 +594,8 @@ impl framework::Example for Example { }); // Create the render pipeline - let vs_bytes = include_bytes!("forward.vert.spv"); - let fs_bytes = include_bytes!("forward.frag.spv"); - let vs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap(), - ); - let fs_module = device.create_shader_module( - &wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap(), - ); + let vs_module = device.create_shader_module(wgpu::include_spirv!("forward.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("forward.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { layout: &pipeline_layout, diff --git a/wgpu/examples/skybox/main.rs b/wgpu/examples/skybox/main.rs index 6cc6bb23f6..8b275c3513 100644 --- a/wgpu/examples/skybox/main.rs +++ b/wgpu/examples/skybox/main.rs @@ -69,12 +69,8 @@ impl framework::Example for Skybox { }); // Create the render pipeline - let vs_bytes = include_bytes!("shader.vert.spv"); - let fs_bytes = include_bytes!("shader.frag.spv"); - let vs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&vs_bytes[..])).unwrap()); - let fs_module = device - .create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(&fs_bytes[..])).unwrap()); + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("shader.frag.spv")); let aspect = sc_desc.width as f32 / sc_desc.height as f32; let uniforms = Self::generate_uniforms(aspect); diff --git a/wgpu/examples/texture-arrays/main.rs b/wgpu/examples/texture-arrays/main.rs index e731eaaa88..0a45ee3875 100644 --- a/wgpu/examples/texture-arrays/main.rs +++ b/wgpu/examples/texture-arrays/main.rs @@ -97,29 +97,26 @@ impl framework::Example for Example { queue: &wgpu::Queue, ) -> (Self, Option) { let mut uniform_workaround = false; - let vs_bytes: &[u8] = include_bytes!("shader.vert.spv"); - let fs_bytes: &[u8] = match device.capabilities() { + let vs_module = device.create_shader_module(wgpu::include_spirv!("shader.vert.spv")); + let fs_bytes: Vec = match device.capabilities() { c if c.contains(wgpu::Capabilities::UNSIZED_BINDING_ARRAY) => { - include_bytes!("unsized-non-uniform.frag.spv") + include_bytes!("unsized-non-uniform.frag.spv").to_vec() } c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_NON_UNIFORM_INDEXING) => { - include_bytes!("non-uniform.frag.spv") + include_bytes!("non-uniform.frag.spv").to_vec() } c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_ARRAY_DYNAMIC_INDEXING) => { uniform_workaround = true; - include_bytes!("uniform.frag.spv") + include_bytes!("uniform.frag.spv").to_vec() } c if c.contains(wgpu::Capabilities::SAMPLED_TEXTURE_BINDING_ARRAY) => { - include_bytes!("constant.frag.spv") + include_bytes!("constant.frag.spv").to_vec() } _ => { panic!("Graphics adapter does not support any of the capabilities needed for this example"); } }; - let vs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(vs_bytes)).unwrap()); - let fs_module = - device.create_shader_module(&wgpu::read_spirv(std::io::Cursor::new(fs_bytes)).unwrap()); + let fs_module = device.create_shader_module(wgpu::util::make_spirv(&fs_bytes)); let vertex_size = std::mem::size_of::(); let vertex_data = create_vertices(); diff --git a/wgpu/examples/water/main.rs b/wgpu/examples/water/main.rs index 0bc7e0507e..a692ab220d 100644 --- a/wgpu/examples/water/main.rs +++ b/wgpu/examples/water/main.rs @@ -4,8 +4,7 @@ mod framework; mod point_gen; use cgmath::Point3; -use std::{io, mem}; -use wgpu::vertex_attr_array; +use std::mem; /// /// Radius of the terrain. @@ -477,23 +476,15 @@ impl framework::Example for Example { label: Some("Terrain Flipped Bind Group"), }); - // Read shaders from file. - let water_vs_bytes = include_bytes!("water_shader.vert.spv"); - let water_fs_bytes = include_bytes!("water_shader.frag.spv"); // Upload/compile them to GPU code. - let water_vs_module = device - .create_shader_module(&wgpu::read_spirv(io::Cursor::new(&water_vs_bytes[..])).unwrap()); - let water_fs_module = device - .create_shader_module(&wgpu::read_spirv(io::Cursor::new(&water_fs_bytes[..])).unwrap()); - - let terrain_vs_bytes = include_bytes!("terrain_shader.vert.spv"); - let terrain_fs_bytes = include_bytes!("terrain_shader.frag.spv"); - let terrain_vs_module = device.create_shader_module( - &wgpu::read_spirv(io::Cursor::new(&terrain_vs_bytes[..])).unwrap(), - ); - let terrain_fs_module = device.create_shader_module( - &wgpu::read_spirv(io::Cursor::new(&terrain_fs_bytes[..])).unwrap(), - ); + let water_vs_module = + device.create_shader_module(wgpu::include_spirv!("water_shader.vert.spv")); + let water_fs_module = + device.create_shader_module(wgpu::include_spirv!("water_shader.frag.spv")); + let terrain_vs_module = + device.create_shader_module(wgpu::include_spirv!("terrain_shader.vert.spv")); + let terrain_fs_module = + device.create_shader_module(wgpu::include_spirv!("terrain_shader.frag.spv")); // Create the render pipelines. These describe how the data will flow through the GPU, and what // constraints and modifiers it will have. @@ -566,7 +557,7 @@ impl framework::Example for Example { vertex_buffers: &[wgpu::VertexBufferDescriptor { stride: water_vertex_size as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![0 => Short2, 1 => Char4], + attributes: &wgpu::vertex_attr_array![0 => Short2, 1 => Char4], }], }, sample_count: 1, @@ -613,7 +604,7 @@ impl framework::Example for Example { vertex_buffers: &[wgpu::VertexBufferDescriptor { stride: terrain_vertex_size as wgpu::BufferAddress, step_mode: wgpu::InputStepMode::Vertex, - attributes: &vertex_attr_array![0 => Float3, 1 => Float3, 2 => Uchar4Norm], + attributes: &wgpu::vertex_attr_array![0 => Float3, 1 => Float3, 2 => Uchar4Norm], }], }, sample_count: 1, diff --git a/wgpu/src/backend/direct.rs b/wgpu/src/backend/direct.rs index 57ab832e6f..2683a8f8c8 100644 --- a/wgpu/src/backend/direct.rs +++ b/wgpu/src/backend/direct.rs @@ -2,7 +2,8 @@ use crate::{ backend::native_gpu_future, BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BufferDescriptor, Capabilities, CommandEncoderDescriptor, ComputePipelineDescriptor, Extensions, Limits, MapMode, PipelineLayoutDescriptor, RenderPipelineDescriptor, - SamplerDescriptor, SwapChainStatus, TextureDescriptor, TextureViewDescriptor, + SamplerDescriptor, ShaderModuleSource, SwapChainStatus, TextureDescriptor, + TextureViewDescriptor, }; use arrayvec::ArrayVec; @@ -402,15 +403,13 @@ impl crate::Context for Context { fn device_create_shader_module( &self, device: &Self::DeviceId, - spv: &[u32], + source: ShaderModuleSource, ) -> Self::ShaderModuleId { - let desc = wgc::pipeline::ShaderModuleDescriptor { - code: wgc::U32Array { - bytes: spv.as_ptr(), - length: spv.len(), - }, + let desc = match source { + ShaderModuleSource::SpirV(spv) => wgc::pipeline::ShaderModuleSource::SpirV(spv), + ShaderModuleSource::Wgsl(code) => wgc::pipeline::ShaderModuleSource::Wgsl(code), }; - gfx_select!(*device => self.device_create_shader_module(*device, &desc, PhantomData)) + gfx_select!(*device => self.device_create_shader_module(*device, desc, PhantomData)) } fn device_create_bind_group_layout( diff --git a/wgpu/src/backend/web.rs b/wgpu/src/backend/web.rs index e2744d3fa5..b8164cdb7f 100644 --- a/wgpu/src/backend/web.rs +++ b/wgpu/src/backend/web.rs @@ -1,8 +1,8 @@ use crate::{ BindGroupDescriptor, BindGroupLayoutDescriptor, BindingResource, BindingType, BufferDescriptor, CommandEncoderDescriptor, ComputePipelineDescriptor, PipelineLayoutDescriptor, - ProgrammableStageDescriptor, RenderPipelineDescriptor, SamplerDescriptor, SwapChainStatus, - TextureDescriptor, TextureViewDescriptor, TextureViewDimension, + ProgrammableStageDescriptor, RenderPipelineDescriptor, SamplerDescriptor, ShaderModuleSource, + SwapChainStatus, TextureDescriptor, TextureViewDescriptor, TextureViewDimension, }; use futures::FutureExt; @@ -773,9 +773,16 @@ impl crate::Context for Context { fn device_create_shader_module( &self, device: &Self::DeviceId, - spv: &[u32], + source: ShaderModuleSource, ) -> Self::ShaderModuleId { - let desc = web_sys::GpuShaderModuleDescriptor::new(&js_sys::Uint32Array::from(spv)); + let desc = match source { + ShaderModuleSource::SpirV(spv) => { + web_sys::GpuShaderModuleDescriptor::new(&js_sys::Uint32Array::from(spv)) + } + ShaderModuleSource::Wgsl(code) => { + panic!("WGSL is not yet supported by the Web backend") + } + }; // TODO: label Sendable(device.0.create_shader_module(&desc)) } diff --git a/wgpu/src/lib.rs b/wgpu/src/lib.rs index 977f25755d..848dbd16d8 100644 --- a/wgpu/src/lib.rs +++ b/wgpu/src/lib.rs @@ -1,7 +1,7 @@ //! A cross-platform graphics and compute library based on WebGPU. mod backend; -mod util; +pub mod util; #[macro_use] mod macros; @@ -33,7 +33,6 @@ pub use wgt::{ }; use backend::Context as C; -pub use util::read_spirv; trait ComputePassInner { fn set_pipeline(&mut self, pipeline: &Ctx::ComputePipelineId); @@ -162,7 +161,7 @@ trait Context: Sized { fn device_create_shader_module( &self, device: &Self::DeviceId, - spv: &[u32], + source: ShaderModuleSource, ) -> Self::ShaderModuleId; fn device_create_bind_group_layout( &self, @@ -571,6 +570,20 @@ impl Drop for ShaderModule { } } +/// Source of a shader module. +pub enum ShaderModuleSource<'a> { + /// SPIR-V module represented as a slice of words. + /// wgpu-rs will try to reflect it and use for validation, but the + /// original data is passed to gfx-rs and spirv_cross for translation. + SpirV(&'a [u32]), + /// WGSL module as a string slice. + /// wgpu-rs will parse it and use for validation. It will attempt + /// to build a SPIR-V module internally and panic otherwise. + /// + /// Note: WGSL is not yet supported on the Web. + Wgsl(&'a str), +} + /// An opaque handle to a pipeline layout. /// /// A `PipelineLayout` object describes the available binding groups of a pipeline. @@ -1046,11 +1059,11 @@ impl Device { Context::device_capabilities(&*self.context, &self.id) } - /// Creates a shader module from SPIR-V source code. - pub fn create_shader_module(&self, spv: &[u32]) -> ShaderModule { + /// Creates a shader module from either SPIR-V or WGSL source code. + pub fn create_shader_module(&self, source: ShaderModuleSource) -> ShaderModule { ShaderModule { context: Arc::clone(&self.context), - id: Context::device_create_shader_module(&*self.context, &self.id, spv), + id: Context::device_create_shader_module(&*self.context, &self.id, source), } } diff --git a/wgpu/src/macros.rs b/wgpu/src/macros.rs index f2b1376658..278500aa8e 100644 --- a/wgpu/src/macros.rs +++ b/wgpu/src/macros.rs @@ -135,3 +135,13 @@ fn test_vertex_attr_array() { assert_eq!(attrs[1].offset, std::mem::size_of::<(f32, f32)>() as u64); assert_eq!(attrs[1].shader_location, 3); } + +/// Macro to load a SPIR-V module statically. +/// +/// It ensure the word alignment as well as the magic number. +#[macro_export] +macro_rules! include_spirv { + ($path:literal) => { + $crate::util::make_spirv(&$crate::util::WordAligned(*include_bytes!($path)).0) + }; +} diff --git a/wgpu/src/util/mod.rs b/wgpu/src/util/mod.rs index 6ab30d0319..64348fdb91 100644 --- a/wgpu/src/util/mod.rs +++ b/wgpu/src/util/mod.rs @@ -1,41 +1,18 @@ -use std::{io, slice}; +#[repr(align(4))] +pub struct WordAligned(pub Bytes); -// TODO: This is copy/pasted from gfx-hal, so we need to find a new place to put -// this function -pub fn read_spirv(mut x: R) -> io::Result> { - 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::::with_capacity(words); - x.seek(io::SeekFrom::Start(0))?; - unsafe { - // Writing all bytes through a pointer with less strict alignment when our type has no - // invalid bitpatterns is safe. - x.read_exact(slice::from_raw_parts_mut( - result.as_mut_ptr() as *mut u8, - words * 4, - ))?; - result.set_len(words); - } +/// Treat the given by slice as a SPIR-V module. +/// The pointer has to be aligned to 32-bit boundary and be a valid SPIR-V binary. +pub fn make_spirv<'a>(data: &'a [u8]) -> super::ShaderModuleSource<'a> { 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) + + let (pre, words, post) = unsafe { data.align_to::() }; + assert_eq!(pre, &[], "data offset is not aligned to words!"); + assert_eq!(post, &[], "data size is not aligned to words!"); + assert_eq!( + words[0], MAGIC_NUMBER, + "wrong magic word {:x}. Make sure you are using a binary SPIRV file.", + words[0] + ); + super::ShaderModuleSource::SpirV(words) }