summaryrefslogtreecommitdiff
path: root/src/renderer.rs
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2022-09-20 19:08:34 -0400
committerMicha White <botahamec@outlook.com>2022-09-20 19:08:34 -0400
commit7f364d2642784fcffea730b1f168270ce907a27c (patch)
tree1234403f7872fa67162eb87b9f3b648e9ccb6de3 /src/renderer.rs
parent1b65982f87856af2b14ac2eefe666316b2d05c82 (diff)
Optimized the instance buffer
Diffstat (limited to 'src/renderer.rs')
-rw-r--r--src/renderer.rs80
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();
- }
_ => {}
})
}