From 83295e01008bdf25e03f6b5aa18b93b735a5e326 Mon Sep 17 00:00:00 2001 From: Micha White Date: Sun, 18 Sep 2022 16:45:05 -0400 Subject: instancing --- src/instance.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 ++ src/renderer.rs | 24 +++++++++++++++++++++--- src/vertex.rs | 5 ++++- 4 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/instance.rs (limited to 'src') diff --git a/src/instance.rs b/src/instance.rs new file mode 100644 index 0000000..6de0133 --- /dev/null +++ b/src/instance.rs @@ -0,0 +1,46 @@ +use std::mem::size_of; + +use bytemuck::{Pod, Zeroable}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] +pub struct Instance { + /// Position on the screen + pub position: [f32; 2], + /// Relative size + pub size: [f32; 2], + /// Rotation, in radians + pub rotation: f32, + /// z-index + pub z_index: i32, +} + +impl Default for Instance { + fn default() -> Self { + Self { + position: [0.0; 2], + size: [1.0; 2], + rotation: 0.0, + z_index: 0, + } + } +} + +impl Instance { + // whenever this is updated, please also update `sprite.wgsl` + const ATTRIBUTES: [wgpu::VertexAttribute; 4] = + wgpu::vertex_attr_array![1 => Float32x2, 2 => Float32x2, 3 => Float32, 4 => Sint32]; + + pub(crate) fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { + // make sure these two don't conflict + debug_assert_eq!( + Self::ATTRIBUTES[0].shader_location as usize, + crate::Vertex::ATTRIBUTES.len() + ); + wgpu::VertexBufferLayout { + array_stride: size_of::() as wgpu::BufferAddress, + step_mode: wgpu::VertexStepMode::Instance, + attributes: &Self::ATTRIBUTES, + } + } +} diff --git a/src/lib.rs b/src/lib.rs index fbc517b..15f64b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,11 @@ #![allow(clippy::module_name_repetitions)] pub mod config; +mod instance; pub mod renderer; mod vertex; pub use config::RenderWindowConfig; +pub(crate) use instance::Instance; pub use renderer::Renderer; pub(crate) use vertex::Vertex; diff --git a/src/renderer.rs b/src/renderer.rs index dc8ecb2..75e6d1e 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,6 +1,6 @@ use std::convert::TryInto; -use crate::{vertex::SQUARE, RenderWindowConfig, Vertex}; +use crate::{vertex::SQUARE, Instance, RenderWindowConfig, Vertex}; use pollster::FutureExt; use thiserror::Error; use wgpu::{include_wgsl, util::DeviceExt}; @@ -44,6 +44,7 @@ pub struct Renderer { render_pipeline: wgpu::RenderPipeline, square_vertex_buffer: wgpu::Buffer, square_vertices: u32, + instances: Vec, window: Window, } @@ -128,7 +129,7 @@ impl Renderer { vertex: wgpu::VertexState { module: &shader, entry_point: "vs_main", - buffers: &[Vertex::desc()], + buffers: &[Vertex::desc(), Instance::desc()], }, // information about the fragment shader fragment: Some(wgpu::FragmentState { @@ -171,6 +172,8 @@ impl Renderer { usage: wgpu::BufferUsages::VERTEX, }); + let instances = Vec::new(); + Ok(Self { surface, device, @@ -179,6 +182,7 @@ impl Renderer { render_pipeline, square_vertex_buffer, square_vertices, + instances, window, }) } @@ -216,6 +220,19 @@ impl Renderer { label: Some("Render Encoder"), }); + let num_instances = self + .instances + .len() + .try_into() + .expect("expected less than 3 billion instances"); + let instance_buffer = self + .device + .create_buffer_init(&wgpu::util::BufferInitDescriptor { + label: Some("Sprite Instance Buffer"), + contents: bytemuck::cast_slice(&self.instances), + usage: wgpu::BufferUsages::VERTEX, + }); + { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), @@ -232,7 +249,8 @@ impl Renderer { render_pass.set_pipeline(&self.render_pipeline); render_pass.set_vertex_buffer(0, self.square_vertex_buffer.slice(..)); - render_pass.draw(0..self.square_vertices, 0..1); + render_pass.set_vertex_buffer(1, instance_buffer.slice(..)); + render_pass.draw(0..self.square_vertices, 0..num_instances); } // the encoder can't finish building the command buffer until the // render pass is dropped diff --git a/src/vertex.rs b/src/vertex.rs index 7735801..6514fd3 100644 --- a/src/vertex.rs +++ b/src/vertex.rs @@ -2,6 +2,7 @@ use std::mem::size_of; use bytemuck::{Pod, Zeroable}; +/// The vertices needed to form a square pub const SQUARE: [Vertex; 4] = [ Vertex::new(-0.5, -0.5), Vertex::new(0.5, -0.5), @@ -22,7 +23,9 @@ impl Vertex { } impl Vertex { - const ATTRIBUTES: [wgpu::VertexAttribute; 1] = wgpu::vertex_attr_array![0 => Float32x2]; + // whenever this is updated, please also update `sprite.wgsl` + pub(crate) const ATTRIBUTES: [wgpu::VertexAttribute; 1] = + wgpu::vertex_attr_array![0 => Float32x2]; pub(crate) const fn desc<'a>() -> wgpu::VertexBufferLayout<'a> { wgpu::VertexBufferLayout { -- cgit v1.2.3