diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/instance.rs | 91 | ||||
| -rw-r--r-- | src/lib.rs | 1 | ||||
| -rw-r--r-- | src/renderer.rs | 84 | ||||
| -rw-r--r-- | src/texture.rs | 10 |
4 files changed, 109 insertions, 77 deletions
diff --git a/src/instance.rs b/src/instance.rs index eded8cf..dc1ee40 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -3,7 +3,7 @@ use std::mem::size_of; use bytemuck::{Pod, Zeroable}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct InstanceId(pub(crate) usize); +pub struct InstanceId(usize); #[repr(C)] #[derive(Copy, Clone, Debug, PartialEq, Pod, Zeroable)] @@ -58,3 +58,92 @@ impl Instance { } } } + +pub struct InstanceBuffer { + instances: Vec<Instance>, + instance_buffer: wgpu::Buffer, + instance_buffer_size: usize, +} + +fn create_buffer(device: &wgpu::Device, instances: &Vec<Instance>) -> wgpu::Buffer { + device.create_buffer(&wgpu::BufferDescriptor { + label: Some("Sprite Instance Buffer"), + size: (instances.capacity() * size_of::<Instance>()) as wgpu::BufferAddress, + usage: wgpu::BufferUsages::VERTEX | wgpu::BufferUsages::COPY_DST, + mapped_at_creation: false, + }) +} + +impl InstanceBuffer { + pub(crate) fn new(device: &wgpu::Device, capacity: usize) -> Self { + let instances = Vec::with_capacity(capacity); + 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, + }); + + Self { + instances, + instance_buffer, + instance_buffer_size, + } + } + + pub fn len(&self) -> u32 { + self.instances + .len() + .try_into() + .expect("expected less than 3 billion instances") + } + + pub fn is_empty(&self) -> bool { + self.instances.is_empty() + } + + pub const fn buffer_size(&self) -> usize { + self.instance_buffer_size + } + + pub(crate) fn buffer_slice(&self) -> wgpu::BufferSlice { + self.instance_buffer.slice(..) + } + + pub fn push_instance(&mut self, instance: Instance) -> InstanceId { + let index = self.instances.len(); + self.instances.push(instance); + InstanceId(index) + } + + pub fn get_instance(&self, id: InstanceId) -> Option<&Instance> { + self.instances.get(id.0) + } + + pub fn get_instance_mut(&mut self, id: InstanceId) -> Option<&mut Instance> { + self.instances.get_mut(id.0) + } + + pub fn clear(&mut self) { + self.instances.clear(); + } + + fn expand_buffer(&mut self, device: &wgpu::Device) { + self.instance_buffer_size = self.instances.capacity(); + self.instance_buffer = create_buffer(device, &self.instances); + } + + #[profiling::function] + pub(crate) fn fill_buffer(&mut self, device: &wgpu::Device, queue: &wgpu::Queue) { + if self.instances.len() > self.instance_buffer_size { + self.expand_buffer(device); + } + + queue.write_buffer( + &self.instance_buffer, + 0 as wgpu::BufferAddress, + bytemuck::cast_slice(&self.instances), + ); + } +} @@ -15,6 +15,7 @@ mod vertex; pub(crate) use camera::Camera; pub use config::RenderWindowConfig; pub use instance::Instance; +pub(crate) use instance::InstanceBuffer; pub use renderer::Renderer; pub use texture::ImageFormat; pub(crate) use texture::WgpuTextures; diff --git a/src/renderer.rs b/src/renderer.rs index e48f3e4..20edf34 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -1,10 +1,9 @@ -use std::{convert::TryInto, mem::size_of, num::NonZeroU32}; +use std::{convert::TryInto, num::NonZeroU32}; use crate::{ - instance::InstanceId, texture::{TextureError, TextureId}, vertex::SQUARE, - Camera, ImageFormat, Instance, RenderWindowConfig, Vertex, WgpuTextures, + Camera, ImageFormat, Instance, InstanceBuffer, RenderWindowConfig, Vertex, WgpuTextures, }; use pollster::FutureExt; use thiserror::Error; @@ -52,9 +51,7 @@ 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>, + instances: InstanceBuffer, camera: Camera, textures: WgpuTextures, window: Window, @@ -121,21 +118,6 @@ 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 @@ -215,9 +197,7 @@ impl Renderer { }); // create the instance buffer - let instances = Vec::with_capacity(config.instance_capacity); - let (instance_buffer, instance_buffer_size) = - Self::new_instance_buffer(&device, &instances); + let instances = InstanceBuffer::new(&device, config.instance_capacity); // TODO make this configurable let (textures, texture_layout) = WgpuTextures::new( @@ -246,8 +226,6 @@ impl Renderer { render_pipeline, square_vertex_buffer, square_vertices, - instance_buffer, - instance_buffer_size, instances, camera, textures, @@ -291,27 +269,14 @@ impl Renderer { self.window.set_title(title); } - /// 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 { - let index = self.instances.len(); - self.instances.push(instance); - InstanceId(index) + /// The reference buffer + pub const fn instances(&self) -> &InstanceBuffer { + &self.instances } - /// Get an immutable reference to an instance - pub fn instance(&self, id: InstanceId) -> Option<&Instance> { - self.instances.get(id.0) - } - - /// Get a mutable reference to an instance - pub fn instance_mut(&mut self, id: InstanceId) -> Option<&mut Instance> { - self.instances.get_mut(id.0) - } - - /// Clears the list of instances, making all instance ID's invalid - pub fn clear_instances(&mut self) { - self.instances.clear(); + /// The reference buffer + pub fn instances_mut(&mut self) -> &mut InstanceBuffer { + &mut self.instances } /// Get the camera information @@ -358,24 +323,6 @@ impl Renderer { self.textures.clear_textures(); } - fn expand_instance_buffer(&mut self) { - (self.instance_buffer, self.instance_buffer_size) = - Self::new_instance_buffer(&self.device, &self.instances); - } - - #[profiling::function] - 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), - ); - } - /// Renders a new frame to the window /// /// # Errors @@ -399,13 +346,8 @@ 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 num_instances = self.instances.len(); + self.instances.fill_buffer(&self.device, &self.queue); self.camera.refresh(&self.queue); self.textures.fill_textures(&self.queue); @@ -428,7 +370,7 @@ impl Renderer { render_pass.set_bind_group(0, self.camera.bind_group(), &[]); render_pass.set_bind_group(1, self.textures.bind_group(), &[]); render_pass.set_vertex_buffer(0, self.square_vertex_buffer.slice(..)); - render_pass.set_vertex_buffer(1, self.instance_buffer.slice(..)); + render_pass.set_vertex_buffer(1, self.instances.buffer_slice()); render_pass.draw(0..self.square_vertices, 0..num_instances); } // the encoder can't finish building the command buffer until the diff --git a/src/texture.rs b/src/texture.rs index a3e2c10..e0ceb7d 100644 --- a/src/texture.rs +++ b/src/texture.rs @@ -64,14 +64,14 @@ impl From<ImageError> for TextureError { // TODO make this Debug // TODO make these resizable // TODO this could probably be moved into WgpuTextures -pub struct TextureAtlases<'a> { +pub struct TextureAtlas<'a> { packer: TexturePacker<'a, image::RgbaImage, TextureId>, image: RgbaImage, width: u32, height: u32, } -impl<'a> Default for TextureAtlases<'a> { +impl<'a> Default for TextureAtlas<'a> { fn default() -> Self { Self::new(1024, 1024) } @@ -86,7 +86,7 @@ macro_rules! texture_info { }; } -impl<'a> TextureAtlases<'a> { +impl<'a> TextureAtlas<'a> { /// Creates a new texture atlas, with the given size // TODO why is this u32? pub fn new(width: u32, height: u32) -> Self { @@ -166,7 +166,7 @@ impl<'a> TextureAtlases<'a> { } pub struct WgpuTextures { - atlases: TextureAtlases<'static>, + atlases: TextureAtlas<'static>, diffuse_texture: wgpu::Texture, diffuse_bind_group: wgpu::BindGroup, changed: bool, @@ -187,7 +187,7 @@ macro_rules! get_info { impl WgpuTextures { // TODO this is still too large pub fn new(device: &wgpu::Device, width: u32, height: u32) -> (Self, wgpu::BindGroupLayout) { - let atlases = TextureAtlases::new(width, height); + let atlases = TextureAtlas::new(width, height); let atlas_size = atlases.extent_3d(); let diffuse_texture = device.create_texture(&wgpu::TextureDescriptor { |
