diff options
Diffstat (limited to 'src/renderer.rs')
| -rw-r--r-- | src/renderer.rs | 80 |
1 files changed, 54 insertions, 26 deletions
diff --git a/src/renderer.rs b/src/renderer.rs index a15015b..a86b05b 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,4 +1,4 @@ -use std::{convert::TryInto, num::NonZeroU32}; +use std::{convert::TryInto, mem::size_of, num::NonZeroU32}; use crate::{instance::InstanceId, vertex::SQUARE, Instance, RenderWindowConfig, Vertex}; use pollster::FutureExt; @@ -45,6 +45,8 @@ pub struct Renderer { render_pipeline: wgpu::RenderPipeline, square_vertex_buffer: wgpu::Buffer, square_vertices: u32, + instance_buffer: wgpu::Buffer, + instance_buffer_size: usize, instances: Vec<Instance>, window: Window, } @@ -114,6 +116,21 @@ impl Renderer { }) } + fn new_instance_buffer( + device: &wgpu::Device, + instances: &Vec<Instance>, + ) -> (wgpu::Buffer, usize) { + let instance_buffer_size = instances.capacity(); + let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Sprite Instance Buffer"), + size: (instance_buffer_size * size_of::<Instance>()) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }); + + (instance_buffer, instance_buffer_size) + } + /// Initializes the renderer /// /// # Errors @@ -180,7 +197,10 @@ impl Renderer { usage: wgpu::BufferUsages::VERTEX, }); + // create the instance buffer let instances = Vec::with_capacity(config.instance_capacity); + let (instance_buffer, instance_buffer_size) = + Self::new_instance_buffer(&device, &instances); Ok(Self { surface, @@ -191,6 +211,8 @@ impl Renderer { render_pipeline, square_vertex_buffer, square_vertices, + instance_buffer, + instance_buffer_size, instances, window, }) @@ -231,6 +253,23 @@ impl Renderer { self.window.set_title(title); } + fn expand_instance_buffer(&mut self) { + (self.instance_buffer, self.instance_buffer_size) = + Self::new_instance_buffer(&self.device, &self.instances); + } + + fn fill_instance_buffer(&mut self) { + if self.instances.len() > self.instance_buffer_size { + self.expand_instance_buffer(); + } + + self.queue.write_buffer( + &self.instance_buffer, + 0 as wgpu::BufferAddress, + bytemuck::cast_slice(&self.instances), + ); + } + /// Add an instance to the renderer, and returns an `InstanceId` to the /// instance. This id becomes invalid if the instances are cleared. pub fn push_instance(&mut self, instance: Instance) -> InstanceId { @@ -270,18 +309,12 @@ impl Renderer { label: Some("Render Encoder"), }); + self.fill_instance_buffer(); 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 { @@ -299,7 +332,7 @@ impl Renderer { render_pass.set_pipeline(&self.render_pipeline); render_pass.set_vertex_buffer(0, self.square_vertex_buffer.slice(..)); - render_pass.set_vertex_buffer(1, instance_buffer.slice(..)); + render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); render_pass.draw(0..self.square_vertices, 0..num_instances); } // the encoder can't finish building the command buffer until the @@ -325,26 +358,21 @@ impl Renderer { } } } - Event::RedrawRequested(window_id) => { - if window_id == self.window.id() { - match self.render() { - Ok(_) => {} - // reconfigure the surface if it's been lost - Err(wgpu::SurfaceError::Lost) => { - self.reconfigure(); - } - // if we ran out of memory, then we'll die - Err(wgpu::SurfaceError::OutOfMemory) => { - *control_flow = ControlFlow::ExitWithCode(1); - } - // otherwise, we'll just log the error - Err(e) => log::error!("{}", e), + Event::MainEventsCleared => { + match self.render() { + Ok(_) => {} + // reconfigure the surface if it's been lost + Err(wgpu::SurfaceError::Lost) => { + self.reconfigure(); + } + // if we ran out of memory, then we'll die + Err(wgpu::SurfaceError::OutOfMemory) => { + *control_flow = ControlFlow::ExitWithCode(1); } + // otherwise, we'll just log the error + Err(e) => log::error!("{}", e), } } - Event::MainEventsCleared => { - self.window.request_redraw(); - } _ => {} }) } |
