diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..9123716 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "minimal-viable-game-engine" +version = "0.1.0" +authors = ["mitchellhansen "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +wgpu = "0.6.0" +arrayvec = "0.5" +futures = "0.3" +parking_lot = "0.11" +raw-window-handle = "0.3" +smallvec = "1" +tracing = { version = "0.1", default-features = false, features = ["std"] } +typed-arena = "2.0.1" +serde = { version = "1", features = ["derive"], optional = true } +gfx-backend-vulkan = { version = "0.6", features = ["x11"] } +cgmath = "0.17" +log = "0.4" +png = "0.16" +winit = { version = "0.22.1", features = ["web-sys"] } +rand = { version = "0.7.2", features = ["wasm-bindgen"] } +bytemuck = "1" +noise = "0.6" +ddsfile = "0.4" +wgpu-subscriber = "0.1.0" + + + + + diff --git a/readme.md b/readme.md deleted file mode 100644 index c63f0c4..0000000 --- a/readme.md +++ /dev/null @@ -1,3 +0,0 @@ -# Can I create the 4-5 interconnected components for a minimal viable game engine? - -probably not diff --git a/resources/bake.frag b/resources/bake.frag new file mode 100644 index 0000000..f0bcb49 --- /dev/null +++ b/resources/bake.frag @@ -0,0 +1,4 @@ +#version 450 + +void main() { +} diff --git a/resources/bake.frag.spv b/resources/bake.frag.spv new file mode 100644 index 0000000..dbd2938 Binary files /dev/null and b/resources/bake.frag.spv differ diff --git a/shadow/bake.vert b/resources/bake.vert similarity index 100% rename from shadow/bake.vert rename to resources/bake.vert diff --git a/shadow/bake.vert.spv b/resources/bake.vert.spv similarity index 100% rename from shadow/bake.vert.spv rename to resources/bake.vert.spv diff --git a/shadow/forward.frag b/resources/forward.frag similarity index 100% rename from shadow/forward.frag rename to resources/forward.frag diff --git a/shadow/forward.frag.spv b/resources/forward.frag.spv similarity index 100% rename from shadow/forward.frag.spv rename to resources/forward.frag.spv diff --git a/shadow/forward.vert b/resources/forward.vert similarity index 100% rename from shadow/forward.vert rename to resources/forward.vert diff --git a/shadow/forward.vert.spv b/resources/forward.vert.spv similarity index 100% rename from shadow/forward.vert.spv rename to resources/forward.vert.spv diff --git a/shadow/README.md b/shadow/README.md deleted file mode 100644 index 62bc83e..0000000 --- a/shadow/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# shadow - -This animated example demonstrates shadow mapping. - -## To Run - -``` -cargo run --example shadow -``` - -## Screenshots - -![Shadow mapping](./screenshot.png) diff --git a/shadow/screenshot.png b/shadow/screenshot.png deleted file mode 100644 index ae07823..0000000 Binary files a/shadow/screenshot.png and /dev/null differ diff --git a/src/framework.rs b/src/framework.rs new file mode 100644 index 0000000..2914e98 --- /dev/null +++ b/src/framework.rs @@ -0,0 +1,312 @@ +use futures::task::LocalSpawn; +#[cfg(not(target_arch = "wasm32"))] +use std::time::{Duration, Instant}; +use winit::{ + event::{self, WindowEvent}, + event_loop::{ControlFlow, EventLoop}, +}; +use wgpu_subscriber; + +#[cfg_attr(rustfmt, rustfmt_skip)] +#[allow(unused)] +pub const OPENGL_TO_WGPU_MATRIX: cgmath::Matrix4 = cgmath::Matrix4::new( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.5, 0.0, + 0.0, 0.0, 0.5, 1.0, +); + +#[allow(dead_code)] +pub fn cast_slice(data: &[T]) -> &[u8] { + use std::{mem::size_of, slice::from_raw_parts}; + + unsafe { from_raw_parts(data.as_ptr() as *const u8, data.len() * size_of::()) } +} + +#[allow(dead_code)] +pub enum ShaderStage { + Vertex, + Fragment, + Compute, +} + +pub trait Example: 'static + Sized { + fn optional_features() -> wgpu::Features { + wgpu::Features::empty() + } + fn required_features() -> wgpu::Features { + wgpu::Features::empty() + } + fn required_limits() -> wgpu::Limits { + wgpu::Limits::default() + } + fn init( + sc_desc: &wgpu::SwapChainDescriptor, + device: &wgpu::Device, + queue: &wgpu::Queue, + ) -> Self; + fn resize( + &mut self, + sc_desc: &wgpu::SwapChainDescriptor, + device: &wgpu::Device, + queue: &wgpu::Queue, + ); + fn update(&mut self, event: WindowEvent); + fn render( + &mut self, + frame: &wgpu::SwapChainTexture, + device: &wgpu::Device, + queue: &wgpu::Queue, + spawner: &impl LocalSpawn, + ); +} + +struct Setup { + window: winit::window::Window, + event_loop: EventLoop<()>, + instance: wgpu::Instance, + size: winit::dpi::PhysicalSize, + surface: wgpu::Surface, + adapter: wgpu::Adapter, + device: wgpu::Device, + queue: wgpu::Queue, +} + +async fn setup(title: &str) -> Setup { + #[cfg(not(target_arch = "wasm32"))] + { + let chrome_tracing_dir = std::env::var("WGPU_CHROME_TRACE"); + wgpu_subscriber::initialize_default_subscriber( + chrome_tracing_dir.as_ref().map(std::path::Path::new).ok(), + ); + }; + + #[cfg(target_arch = "wasm32")] + console_log::init().expect("could not initialize logger"); + + let event_loop = EventLoop::new(); + let mut builder = winit::window::WindowBuilder::new(); + builder = builder.with_title(title); + #[cfg(windows_OFF)] // TODO + { + use winit::platform::windows::WindowBuilderExtWindows; + builder = builder.with_no_redirection_bitmap(true); + } + let window = builder.build(&event_loop).unwrap(); + + log::info!("Initializing the surface..."); + + let instance = wgpu::Instance::new(wgpu::BackendBit::PRIMARY); + let (size, surface) = unsafe { + let size = window.inner_size(); + let surface = instance.create_surface(&window); + (size, surface) + }; + + let adapter = instance + .request_adapter(&wgpu::RequestAdapterOptions { + power_preference: wgpu::PowerPreference::HighPerformance, + compatible_surface: Some(&surface), + }) + .await + .unwrap(); + + let optional_features = E::optional_features(); + let required_features = E::required_features(); + let adapter_features = adapter.features(); + assert!( + adapter_features.contains(required_features), + "Adapter does not support required features for this example: {:?}", + required_features - adapter_features + ); + + let needed_limits = E::required_limits(); + + let trace_dir = std::env::var("WGPU_TRACE"); + let (device, queue) = adapter + .request_device( + &wgpu::DeviceDescriptor { + features: (optional_features & adapter_features) | required_features, + limits: needed_limits, + shader_validation: true, + }, + trace_dir.ok().as_ref().map(std::path::Path::new), + ) + .await + .unwrap(); + + Setup { + window, + event_loop, + instance, + size, + surface, + adapter, + device, + queue, + } +} + +fn start( + Setup { + window, + event_loop, + instance, + size, + surface, + adapter, + device, + queue, + }: Setup, +) { + #[cfg(not(target_arch = "wasm32"))] + let (mut pool, spawner) = { + let local_pool = futures::executor::LocalPool::new(); + let spawner = local_pool.spawner(); + (local_pool, spawner) + }; + + #[cfg(target_arch = "wasm32")] + let spawner = { + use futures::{future::LocalFutureObj, task::SpawnError}; + use winit::platform::web::WindowExtWebSys; + + struct WebSpawner {} + impl LocalSpawn for WebSpawner { + fn spawn_local_obj( + &self, + future: LocalFutureObj<'static, ()>, + ) -> Result<(), SpawnError> { + Ok(wasm_bindgen_futures::spawn_local(future)) + } + } + + std::panic::set_hook(Box::new(console_error_panic_hook::hook)); + + // On wasm, append the canvas to the document body + web_sys::window() + .and_then(|win| win.document()) + .and_then(|doc| doc.body()) + .and_then(|body| { + body.append_child(&web_sys::Element::from(window.canvas())) + .ok() + }) + .expect("couldn't append canvas to document body"); + + WebSpawner {} + }; + + let mut sc_desc = wgpu::SwapChainDescriptor { + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, + // TODO: Allow srgb unconditionally + format: if cfg!(target_arch = "wasm32") { + wgpu::TextureFormat::Bgra8Unorm + } else { + wgpu::TextureFormat::Bgra8UnormSrgb + }, + width: size.width, + height: size.height, + present_mode: wgpu::PresentMode::Mailbox, + }; + let mut swap_chain = device.create_swap_chain(&surface, &sc_desc); + + log::info!("Initializing the example..."); + let mut example = E::init(&sc_desc, &device, &queue); + + #[cfg(not(target_arch = "wasm32"))] + let mut last_update_inst = Instant::now(); + + log::info!("Entering render loop..."); + event_loop.run(move |event, _, control_flow| { + let _ = (&instance, &adapter); // force ownership by the closure + *control_flow = if cfg!(feature = "metal-auto-capture") { + ControlFlow::Exit + } else { + #[cfg(not(target_arch = "wasm32"))] + { + ControlFlow::WaitUntil(Instant::now() + Duration::from_millis(10)) + } + #[cfg(target_arch = "wasm32")] + { + ControlFlow::Poll + } + }; + match event { + event::Event::MainEventsCleared => { + #[cfg(not(target_arch = "wasm32"))] + { + if last_update_inst.elapsed() > Duration::from_millis(20) { + window.request_redraw(); + last_update_inst = Instant::now(); + } + + pool.run_until_stalled(); + } + + #[cfg(target_arch = "wasm32")] + window.request_redraw(); + } + event::Event::WindowEvent { + event: WindowEvent::Resized(size), + .. + } => { + log::info!("Resizing to {:?}", size); + sc_desc.width = size.width; + sc_desc.height = size.height; + example.resize(&sc_desc, &device, &queue); + swap_chain = device.create_swap_chain(&surface, &sc_desc); + } + event::Event::WindowEvent { event, .. } => match event { + WindowEvent::KeyboardInput { + input: + event::KeyboardInput { + virtual_keycode: Some(event::VirtualKeyCode::Escape), + state: event::ElementState::Pressed, + .. + }, + .. + } + | WindowEvent::CloseRequested => { + *control_flow = ControlFlow::Exit; + } + _ => { + example.update(event); + } + }, + event::Event::RedrawRequested(_) => { + let frame = match swap_chain.get_current_frame() { + Ok(frame) => frame, + Err(_) => { + swap_chain = device.create_swap_chain(&surface, &sc_desc); + swap_chain + .get_current_frame() + .expect("Failed to acquire next swap chain texture!") + } + }; + + example.render(&frame.output, &device, &queue, &spawner); + } + _ => {} + } + }); +} + +#[cfg(not(target_arch = "wasm32"))] +pub fn run(title: &str) { + let setup = futures::executor::block_on(setup::(title)); + start::(setup); +} + +#[cfg(target_arch = "wasm32")] +pub fn run(title: &str) { + let title = title.to_owned(); + wasm_bindgen_futures::spawn_local(async move { + let setup = setup::(&title).await; + start::(setup); + }); +} + +// This allows treating the framework as a standalone example, +// thus avoiding listing the example names in `Cargo.toml`. +#[allow(dead_code)] +fn main() {} diff --git a/shadow/main.rs b/src/main.rs similarity index 87% rename from shadow/main.rs rename to src/main.rs index 8c28624..c74da62 100644 --- a/shadow/main.rs +++ b/src/main.rs @@ -1,18 +1,26 @@ use std::{iter, mem, num::NonZeroU32, ops::Range, rc::Rc}; -#[path = "../framework.rs"] +extern crate winit; + +#[path = "framework.rs"] mod framework; + + use bytemuck::{Pod, Zeroable}; use wgpu::util::DeviceExt; #[repr(C)] -#[derive(Clone, Copy, Pod, Zeroable)] +#[derive(Clone, Copy)] + struct Vertex { _pos: [i8; 4], _normal: [i8; 4], } +unsafe impl Pod for Vertex {} +unsafe impl Zeroable for Vertex {} + fn vertex(pos: [i8; 3], nor: [i8; 3]) -> Vertex { Vertex { _pos: [pos[0], pos[1], pos[2], 1], @@ -85,9 +93,9 @@ struct Entity { color: wgpu::Color, vertex_buf: Rc, index_buf: Rc, - index_format: wgpu::IndexFormat, index_count: usize, - uniform_offset: wgpu::DynamicOffset, + bind_group: wgpu::BindGroup, + uniform_buf: wgpu::Buffer, } struct Light { @@ -99,13 +107,16 @@ struct Light { } #[repr(C)] -#[derive(Clone, Copy, Pod, Zeroable)] +#[derive(Clone, Copy)] struct LightRaw { proj: [[f32; 4]; 4], pos: [f32; 4], color: [f32; 4], } +unsafe impl Pod for LightRaw {} +unsafe impl Zeroable for LightRaw {} + impl Light { fn to_raw(&self) -> LightRaw { use cgmath::{Deg, EuclideanSpace, Matrix4, PerspectiveFov, Point3, Vector3}; @@ -134,19 +145,25 @@ impl Light { } #[repr(C)] -#[derive(Clone, Copy, Pod, Zeroable)] +#[derive(Clone, Copy)] struct ForwardUniforms { proj: [[f32; 4]; 4], num_lights: [u32; 4], } +unsafe impl Pod for ForwardUniforms {} +unsafe impl Zeroable for ForwardUniforms {} + #[repr(C)] -#[derive(Clone, Copy, Pod, Zeroable)] +#[derive(Clone, Copy)] struct EntityUniforms { model: [[f32; 4]; 4], color: [f32; 4], } +unsafe impl Pod for EntityUniforms {} +unsafe impl Zeroable for EntityUniforms {} + #[repr(C)] struct ShadowUniforms { proj: [[f32; 4]; 4], @@ -165,9 +182,7 @@ struct Example { shadow_pass: Pass, forward_pass: Pass, forward_depth: wgpu::TextureView, - entity_bind_group: wgpu::BindGroup, light_uniform_buf: wgpu::Buffer, - entity_uniform_buf: wgpu::Buffer, } impl Example { @@ -234,6 +249,53 @@ impl framework::Example for Example { usage: wgpu::BufferUsage::INDEX, }); + let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; + let plane_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: entity_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); + + let local_bind_group_layout = + device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { + entries: &[wgpu::BindGroupLayoutEntry { + binding: 0, + visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, + min_binding_size: wgpu::BufferSize::new( + mem::size_of::() as _ + ), + }, + count: None, + }], + label: None, + }); + + let mut entities = vec![{ + use cgmath::SquareMatrix; + + let bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &local_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer(plane_uniform_buf.slice(..)), + }], + label: None, + }); + Entity { + mx_world: cgmath::Matrix4::identity(), + rotation_speed: 0.0, + color: wgpu::Color::WHITE, + vertex_buf: Rc::new(plane_vertex_buf), + index_buf: Rc::new(plane_index_buf), + index_count: plane_index_data.len(), + bind_group, + uniform_buf: plane_uniform_buf, + } + }]; + struct CubeDesc { offset: cgmath::Vector3, angle: f32, @@ -267,34 +329,7 @@ impl framework::Example for Example { }, ]; - let entity_uniform_size = mem::size_of::() as wgpu::BufferAddress; - let num_entities = 1 + cube_descs.len() as wgpu::BufferAddress; - assert!(entity_uniform_size <= wgpu::BIND_BUFFER_ALIGNMENT); - //Note: dynamic offsets also have to be aligned to `BIND_BUFFER_ALIGNMENT`. - let entity_uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { - label: None, - size: num_entities * wgpu::BIND_BUFFER_ALIGNMENT, - usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, - mapped_at_creation: false, - }); - - let index_format = wgpu::IndexFormat::Uint16; - - let mut entities = vec![{ - use cgmath::SquareMatrix; - Entity { - mx_world: cgmath::Matrix4::identity(), - rotation_speed: 0.0, - color: wgpu::Color::WHITE, - vertex_buf: Rc::new(plane_vertex_buf), - index_buf: Rc::new(plane_index_buf), - index_format, - index_count: plane_index_data.len(), - uniform_offset: 0, - } - }]; - - for (i, cube) in cube_descs.iter().enumerate() { + for cube in &cube_descs { use cgmath::{Decomposed, Deg, InnerSpace, Quaternion, Rotation3}; let transform = Decomposed { @@ -302,45 +337,31 @@ impl framework::Example for Example { rot: Quaternion::from_axis_angle(cube.offset.normalize(), Deg(cube.angle)), scale: cube.scale, }; + let uniform_buf = device.create_buffer(&wgpu::BufferDescriptor { + label: None, + size: entity_uniform_size, + usage: wgpu::BufferUsage::UNIFORM | wgpu::BufferUsage::COPY_DST, + mapped_at_creation: false, + }); entities.push(Entity { mx_world: cgmath::Matrix4::from(transform), rotation_speed: cube.rotation, color: wgpu::Color::GREEN, vertex_buf: Rc::clone(&cube_vertex_buf), index_buf: Rc::clone(&cube_index_buf), - index_format, index_count: cube_index_data.len(), - uniform_offset: ((i + 1) * wgpu::BIND_BUFFER_ALIGNMENT as usize) as _, + bind_group: device.create_bind_group(&wgpu::BindGroupDescriptor { + layout: &local_bind_group_layout, + entries: &[wgpu::BindGroupEntry { + binding: 0, + resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), + }], + label: None, + }), + uniform_buf, }); } - let local_bind_group_layout = - device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor { - entries: &[wgpu::BindGroupLayoutEntry { - binding: 0, - visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: true, - min_binding_size: wgpu::BufferSize::new(entity_uniform_size), - }, - count: None, - }], - label: None, - }); - let entity_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor { - layout: &local_bind_group_layout, - entries: &[wgpu::BindGroupEntry { - binding: 0, - resource: wgpu::BindingResource::Buffer { - buffer: &entity_uniform_buf, - offset: 0, - size: wgpu::BufferSize::new(entity_uniform_size), - }, - }], - label: None, - }); - // Create other resources let shadow_sampler = device.create_sampler(&wgpu::SamplerDescriptor { label: Some("shadow"), @@ -360,7 +381,7 @@ impl framework::Example for Example { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::SHADOW_FORMAT, - usage: wgpu::TextureUsage::RENDER_ATTACHMENT | wgpu::TextureUsage::SAMPLED, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT | wgpu::TextureUsage::SAMPLED, label: None, }); let shadow_view = shadow_texture.create_view(&wgpu::TextureViewDescriptor::default()); @@ -432,9 +453,8 @@ impl framework::Example for Example { entries: &[wgpu::BindGroupLayoutEntry { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, min_binding_size: wgpu::BufferSize::new(uniform_size), }, count: None, @@ -458,13 +478,14 @@ impl framework::Example for Example { layout: &bind_group_layout, entries: &[wgpu::BindGroupEntry { binding: 0, - resource: uniform_buf.as_entire_binding(), + resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }], label: None, }); // Create the render pipeline - let vs_module = device.create_shader_module(&wgpu::include_spirv!("bake.vert.spv")); + let vs_module = device.create_shader_module(wgpu::include_spirv!("../resources/bake.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("../resources/bake.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("shadow"), @@ -473,11 +494,13 @@ impl framework::Example for Example { module: &vs_module, entry_point: "main", }, - fragment_stage: None, + fragment_stage: Some(wgpu::ProgrammableStageDescriptor { + module: &fs_module, + entry_point: "main", + }), rasterization_state: Some(wgpu::RasterizationStateDescriptor { front_face: wgpu::FrontFace::Ccw, cull_mode: wgpu::CullMode::Back, - polygon_mode: wgpu::PolygonMode::Fill, depth_bias: 2, // corresponds to bilinear filtering depth_bias_slope_scale: 2.0, depth_bias_clamp: 0.0, @@ -492,7 +515,7 @@ impl framework::Example for Example { stencil: wgpu::StencilStateDescriptor::default(), }), vertex_state: wgpu::VertexStateDescriptor { - index_format: Some(index_format), + index_format: wgpu::IndexFormat::Uint16, vertex_buffers: &[vb_desc.clone()], }, sample_count: 1, @@ -515,9 +538,8 @@ impl framework::Example for Example { wgpu::BindGroupLayoutEntry { binding: 0, // global visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, min_binding_size: wgpu::BufferSize::new(mem::size_of::< ForwardUniforms, >( @@ -529,9 +551,8 @@ impl framework::Example for Example { wgpu::BindGroupLayoutEntry { binding: 1, // lights visibility: wgpu::ShaderStage::VERTEX | wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Buffer { - ty: wgpu::BufferBindingType::Uniform, - has_dynamic_offset: false, + ty: wgpu::BindingType::UniformBuffer { + dynamic: false, min_binding_size: wgpu::BufferSize::new(light_uniform_size), }, count: None, @@ -539,20 +560,17 @@ impl framework::Example for Example { wgpu::BindGroupLayoutEntry { binding: 2, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Texture { + ty: wgpu::BindingType::SampledTexture { multisampled: false, - sample_type: wgpu::TextureSampleType::Depth, - view_dimension: wgpu::TextureViewDimension::D2Array, + component_type: wgpu::TextureComponentType::Float, + dimension: wgpu::TextureViewDimension::D2Array, }, count: None, }, wgpu::BindGroupLayoutEntry { binding: 3, visibility: wgpu::ShaderStage::FRAGMENT, - ty: wgpu::BindingType::Sampler { - comparison: true, - filtering: false, - }, + ty: wgpu::BindingType::Sampler { comparison: true }, count: None, }, ], @@ -581,11 +599,11 @@ impl framework::Example for Example { entries: &[ wgpu::BindGroupEntry { binding: 0, - resource: uniform_buf.as_entire_binding(), + resource: wgpu::BindingResource::Buffer(uniform_buf.slice(..)), }, wgpu::BindGroupEntry { binding: 1, - resource: light_uniform_buf.as_entire_binding(), + resource: wgpu::BindingResource::Buffer(light_uniform_buf.slice(..)), }, wgpu::BindGroupEntry { binding: 2, @@ -600,8 +618,8 @@ impl framework::Example for Example { }); // Create the render pipeline - 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 vs_module = device.create_shader_module(wgpu::include_spirv!("../resources/forward.vert.spv")); + let fs_module = device.create_shader_module(wgpu::include_spirv!("../resources/forward.frag.spv")); let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor { label: Some("main"), @@ -628,7 +646,7 @@ impl framework::Example for Example { stencil: wgpu::StencilStateDescriptor::default(), }), vertex_state: wgpu::VertexStateDescriptor { - index_format: Some(index_format), + index_format: wgpu::IndexFormat::Uint16, vertex_buffers: &[vb_desc], }, sample_count: 1, @@ -653,7 +671,7 @@ impl framework::Example for Example { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsage::RENDER_ATTACHMENT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, label: None, }); @@ -665,8 +683,6 @@ impl framework::Example for Example { forward_pass, forward_depth: depth_texture.create_view(&wgpu::TextureViewDescriptor::default()), light_uniform_buf, - entity_uniform_buf, - entity_bind_group, } } @@ -699,7 +715,7 @@ impl framework::Example for Example { sample_count: 1, dimension: wgpu::TextureDimension::D2, format: Self::DEPTH_FORMAT, - usage: wgpu::TextureUsage::RENDER_ATTACHMENT, + usage: wgpu::TextureUsage::OUTPUT_ATTACHMENT, label: None, }); self.forward_depth = depth_texture.create_view(&wgpu::TextureViewDescriptor::default()); @@ -727,11 +743,7 @@ impl framework::Example for Example { entity.color.a as f32, ], }; - queue.write_buffer( - &self.entity_uniform_buf, - entity.uniform_offset as wgpu::BufferAddress, - bytemuck::bytes_of(&data), - ); + queue.write_buffer(&entity.uniform_buf, 0, bytemuck::bytes_of(&data)); } if self.lights_are_dirty { @@ -768,7 +780,6 @@ impl framework::Example for Example { encoder.insert_debug_marker("render entities"); { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, color_attachments: &[], depth_stencil_attachment: Some( wgpu::RenderPassDepthStencilAttachmentDescriptor { @@ -785,8 +796,8 @@ impl framework::Example for Example { pass.set_bind_group(0, &self.shadow_pass.bind_group, &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); - pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); + pass.set_bind_group(1, &entity.bind_group, &[]); + pass.set_index_buffer(entity.index_buf.slice(..)); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); } @@ -800,7 +811,6 @@ impl framework::Example for Example { encoder.push_debug_group("forward rendering pass"); { let mut pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { - label: None, color_attachments: &[wgpu::RenderPassColorAttachmentDescriptor { attachment: &frame.view, resolve_target: None, @@ -827,8 +837,8 @@ impl framework::Example for Example { pass.set_bind_group(0, &self.forward_pass.bind_group, &[]); for entity in &self.entities { - pass.set_bind_group(1, &self.entity_bind_group, &[entity.uniform_offset]); - pass.set_index_buffer(entity.index_buf.slice(..), entity.index_format); + pass.set_bind_group(1, &entity.bind_group, &[]); + pass.set_index_buffer(entity.index_buf.slice(..)); pass.set_vertex_buffer(0, entity.vertex_buf.slice(..)); pass.draw_indexed(0..entity.index_count as u32, 0, 0..1); }