summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMicha White <botahamec@outlook.com>2022-10-12 12:06:37 -0400
committerMicha White <botahamec@outlook.com>2022-10-12 12:06:37 -0400
commit3c1822640f09d23c55a5e9a8fe4d131eb539d2f4 (patch)
treed2180000735118faeceb5148c3c5552381e6d0fc /src
parent3352e94bade525c9922b448208b1e6c44fc3340d (diff)
Move out instance logic
Diffstat (limited to 'src')
-rw-r--r--src/instance.rs91
-rw-r--r--src/lib.rs1
-rw-r--r--src/renderer.rs84
-rw-r--r--src/texture.rs10
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),
+ );
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 2fdc59a..311f060 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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 {