From b957414143a9f3f70833150401a269a980b38d21 Mon Sep 17 00:00:00 2001 From: SeanOMik Date: Thu, 18 May 2023 23:44:07 -0400 Subject: [PATCH] Use an actual render queue instead of a HashMap --- shell.nix | 1 + src/math/transform.rs | 12 +++++++-- src/render/render_job.rs | 22 ++++++++++++--- src/render/renderer.rs | 58 +++++++++++++--------------------------- 4 files changed, 49 insertions(+), 44 deletions(-) diff --git a/shell.nix b/shell.nix index 0044c65..8008d63 100755 --- a/shell.nix +++ b/shell.nix @@ -10,6 +10,7 @@ mkShell rec { trunk valgrind heaptrack + mold ]; buildInputs = [ udev alsa-lib vulkan-loader diff --git a/src/math/transform.rs b/src/math/transform.rs index 27e052c..eaef717 100755 --- a/src/math/transform.rs +++ b/src/math/transform.rs @@ -16,6 +16,12 @@ impl Default for Transform { } } +impl Into for Transform { + fn into(self) -> glam::Mat4 { + self.matrix + } +} + #[allow(dead_code)] impl Transform { pub fn new() -> Self { @@ -28,6 +34,10 @@ impl Transform { } } + pub fn get_matrix(&self) -> glam::Mat4 { + self.matrix + } + /// Create Transform from scale, rotation (in degrees), and translation pub fn from_scale_rotation_deg_translation(scale: Vec3, mut rotation: Vec3, translation: Vec3) -> Self { rotation.x = angle::degrees_to_radians(rotation.x); @@ -147,8 +157,6 @@ impl Transform { rot } - - pub fn scale(&mut self, scale: Vec3) -> &mut Self { let scale = Mat4::from_scale(scale); self.matrix *= scale; diff --git a/src/render/render_job.rs b/src/render/render_job.rs index 6b30e70..4411e6c 100755 --- a/src/render/render_job.rs +++ b/src/render/render_job.rs @@ -9,12 +9,12 @@ pub struct RenderJob { material: Material, entity: Entity, - pub transform: Option, - pub last_transform: Option, // TODO: render interpolation + transform: Transform, + last_transform: Option, // TODO: render interpolation } impl RenderJob { - pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Option, last_transform: Option) -> Self { + pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Transform, last_transform: Option) -> Self { Self { mesh, material, @@ -35,4 +35,20 @@ impl RenderJob { pub fn entity(&self)-> Entity { self.entity } + + pub fn transform(&self)-> &Transform { + &self.transform + } + + pub fn set_transform(&mut self, transform: Transform){ + self.transform = transform; + } + + pub fn last_transform(&self)-> Option<&Transform> { + self.last_transform.as_ref() + } + + pub fn set_last_transform(&mut self, last_transform: Transform){ + self.last_transform = Some(last_transform); + } } \ No newline at end of file diff --git a/src/render/renderer.rs b/src/render/renderer.rs index 12d690f..965da22 100755 --- a/src/render/renderer.rs +++ b/src/render/renderer.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashMap; +use std::collections::{HashMap, VecDeque}; use std::sync::Arc; use std::borrow::Cow; @@ -54,7 +54,7 @@ pub struct BasicRenderer { pub clear_color: wgpu::Color, pub render_pipelines: HashMap>, - pub render_jobs: HashMap>, + pub render_jobs: VecDeque, buffer_storage: HashMap, // TODO: clean up left over buffers from deleted entities/components @@ -248,7 +248,7 @@ impl BasicRenderer { a: 1.0, }, render_pipelines: pipelines, - render_jobs: HashMap::new(), + render_jobs: VecDeque::new(), buffer_storage: HashMap::new(), transform_buffer, @@ -348,22 +348,10 @@ impl BasicRenderer { #[async_trait] impl Renderer for BasicRenderer { async fn prepare(&mut self, main_world: &mut World) { - for (entity, (model, transform)) in main_world.query::<(&MeshComponent, Option<&TransformComponent>)>().iter() { - let transform = match transform { - Some(transform) => { - Some(transform.transform) - }, - None => None, - }; - - let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform, None); - - // Insert the new job into the queue - if let Some(shader_jobs) = self.render_jobs.get_mut(&model.material.shader_id) { - shader_jobs.push(job); - } else { - self.render_jobs.insert(model.material.shader_id, vec![job]); - } + for (entity, (model, transform)) in main_world.query::<(&MeshComponent, &TransformComponent)>().iter() { + // Create the render job and push it to the queue + let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None); + self.render_jobs.push_back(job); if self.buffer_storage.get(&entity).is_none() { let buffers = self.create_model_buffers(model); @@ -384,8 +372,6 @@ impl Renderer for BasicRenderer { } async fn render(&mut self) -> Result<(), wgpu::SurfaceError> { - let jobs = &self.render_jobs; - let output = self.surface.get_current_texture()?; let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); @@ -393,8 +379,9 @@ impl Renderer for BasicRenderer { label: Some("Basic Renderer's Encoder") }); - // Loop through all the render pipelines and draw the buffers. - for (shader_id, pipeline) in self.render_pipelines.iter() { + // Create a new variable scope for the render pass + { + // There's only one render pass currently let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { label: Some("Render Pass"), color_attachments: &[Some(wgpu::RenderPassColorAttachment { @@ -408,11 +395,11 @@ impl Renderer for BasicRenderer { depth_stencil_attachment: None, }); - render_pass.set_pipeline(pipeline.get_wgpu_pipeline()); + // Pop off jobs from the queue as they're being processed + while let Some(job) = self.render_jobs.pop_front() { + if let Some(pipeline) = self.render_pipelines.get(&job.material().shader_id) { + render_pass.set_pipeline(pipeline.get_wgpu_pipeline()); - let pipeline_jobs = jobs.get(shader_id); - if let Some(jobs) = pipeline_jobs { - for job in jobs.iter() { let mesh = job.mesh(); let buffers = self.buffer_storage.get(&job.entity()).unwrap(); @@ -420,13 +407,9 @@ impl Renderer for BasicRenderer { render_pass.set_bind_group(0, &tex, &[]); } - // If the job has a transform, set the uniform to it - if let Some(transform) = job.transform { - //self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[transform])); - render_pass.set_bind_group(1, &self.transform_bind_group, &[]); - } else { - debug!("//TODO: clear transform uniform if the RenderJob doesn't have a transform."); - } + // Update transform buffer, and bind to the bind group + self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[job.transform().get_matrix()])); + render_pass.set_bind_group(1, &self.transform_bind_group, &[]); // There will always be a camera (hopefully) render_pass.set_bind_group(2, &self.camera_bind_group, &[]); @@ -441,18 +424,15 @@ impl Renderer for BasicRenderer { render_pass.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..)); render_pass.draw(0..mesh.vertices.len() as u32, 0..1); } + } else { + warn!("Failure to find RenderPipeline with shader id of '{}'!", job.material().shader_id); } - - //pipeline.render(&jobs, &mut render_pass, 0..VERTICES.len() as u32, 0..1); } } self.queue.submit(std::iter::once(encoder.finish())); output.present(); - // TODO: Use an actual queue instead of a hashmap - self.render_jobs = HashMap::new(); - Ok(()) }