Use an actual render queue instead of a HashMap

This commit is contained in:
SeanOMik 2023-05-18 23:44:07 -04:00
parent 645dd93f21
commit b957414143
Signed by: SeanOMik
GPG Key ID: 568F326C7EB33ACB
4 changed files with 49 additions and 44 deletions

View File

@ -10,6 +10,7 @@ mkShell rec {
trunk trunk
valgrind valgrind
heaptrack heaptrack
mold
]; ];
buildInputs = [ buildInputs = [
udev alsa-lib vulkan-loader udev alsa-lib vulkan-loader

View File

@ -16,6 +16,12 @@ impl Default for Transform {
} }
} }
impl Into<glam::Mat4> for Transform {
fn into(self) -> glam::Mat4 {
self.matrix
}
}
#[allow(dead_code)] #[allow(dead_code)]
impl Transform { impl Transform {
pub fn new() -> Self { 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 /// Create Transform from scale, rotation (in degrees), and translation
pub fn from_scale_rotation_deg_translation(scale: Vec3, mut rotation: Vec3, translation: Vec3) -> Self { pub fn from_scale_rotation_deg_translation(scale: Vec3, mut rotation: Vec3, translation: Vec3) -> Self {
rotation.x = angle::degrees_to_radians(rotation.x); rotation.x = angle::degrees_to_radians(rotation.x);
@ -147,8 +157,6 @@ impl Transform {
rot rot
} }
pub fn scale(&mut self, scale: Vec3) -> &mut Self { pub fn scale(&mut self, scale: Vec3) -> &mut Self {
let scale = Mat4::from_scale(scale); let scale = Mat4::from_scale(scale);
self.matrix *= scale; self.matrix *= scale;

View File

@ -9,12 +9,12 @@ pub struct RenderJob {
material: Material, material: Material,
entity: Entity, entity: Entity,
pub transform: Option<Transform>, transform: Transform,
pub last_transform: Option<Transform>, // TODO: render interpolation last_transform: Option<Transform>, // TODO: render interpolation
} }
impl RenderJob { impl RenderJob {
pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Option<Transform>, last_transform: Option<Transform>) -> Self { pub fn new(mesh: Mesh, material: Material, entity: Entity, transform: Transform, last_transform: Option<Transform>) -> Self {
Self { Self {
mesh, mesh,
material, material,
@ -35,4 +35,20 @@ impl RenderJob {
pub fn entity(&self)-> Entity { pub fn entity(&self)-> 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);
}
} }

View File

@ -1,5 +1,5 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::collections::{HashMap, VecDeque};
use std::sync::Arc; use std::sync::Arc;
use std::borrow::Cow; use std::borrow::Cow;
@ -54,7 +54,7 @@ pub struct BasicRenderer {
pub clear_color: wgpu::Color, pub clear_color: wgpu::Color,
pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>, pub render_pipelines: HashMap<u32, Arc<FullRenderPipeline>>,
pub render_jobs: HashMap<u32, Vec<RenderJob>>, pub render_jobs: VecDeque<RenderJob>,
buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components buffer_storage: HashMap<Entity, RenderBufferStorage>, // TODO: clean up left over buffers from deleted entities/components
@ -248,7 +248,7 @@ impl BasicRenderer {
a: 1.0, a: 1.0,
}, },
render_pipelines: pipelines, render_pipelines: pipelines,
render_jobs: HashMap::new(), render_jobs: VecDeque::new(),
buffer_storage: HashMap::new(), buffer_storage: HashMap::new(),
transform_buffer, transform_buffer,
@ -348,22 +348,10 @@ impl BasicRenderer {
#[async_trait] #[async_trait]
impl Renderer for BasicRenderer { impl Renderer for BasicRenderer {
async fn prepare(&mut self, main_world: &mut World) { async fn prepare(&mut self, main_world: &mut World) {
for (entity, (model, transform)) in main_world.query::<(&MeshComponent, Option<&TransformComponent>)>().iter() { for (entity, (model, transform)) in main_world.query::<(&MeshComponent, &TransformComponent)>().iter() {
let transform = match transform { // Create the render job and push it to the queue
Some(transform) => { let job = RenderJob::new(model.mesh.clone(), model.material.clone(), entity, transform.transform, None);
Some(transform.transform) self.render_jobs.push_back(job);
},
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]);
}
if self.buffer_storage.get(&entity).is_none() { if self.buffer_storage.get(&entity).is_none() {
let buffers = self.create_model_buffers(model); let buffers = self.create_model_buffers(model);
@ -384,8 +372,6 @@ impl Renderer for BasicRenderer {
} }
async fn render(&mut self) -> Result<(), wgpu::SurfaceError> { async fn render(&mut self) -> Result<(), wgpu::SurfaceError> {
let jobs = &self.render_jobs;
let output = self.surface.get_current_texture()?; let output = self.surface.get_current_texture()?;
let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default()); let view = output.texture.create_view(&wgpu::TextureViewDescriptor::default());
@ -393,8 +379,9 @@ impl Renderer for BasicRenderer {
label: Some("Basic Renderer's Encoder") label: Some("Basic Renderer's Encoder")
}); });
// Loop through all the render pipelines and draw the buffers. // Create a new variable scope for the render pass
for (shader_id, pipeline) in self.render_pipelines.iter() { {
// There's only one render pass currently
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"), label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment { color_attachments: &[Some(wgpu::RenderPassColorAttachment {
@ -408,11 +395,11 @@ impl Renderer for BasicRenderer {
depth_stencil_attachment: None, 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 mesh = job.mesh();
let buffers = self.buffer_storage.get(&job.entity()).unwrap(); let buffers = self.buffer_storage.get(&job.entity()).unwrap();
@ -420,13 +407,9 @@ impl Renderer for BasicRenderer {
render_pass.set_bind_group(0, &tex, &[]); render_pass.set_bind_group(0, &tex, &[]);
} }
// If the job has a transform, set the uniform to it // Update transform buffer, and bind to the bind group
if let Some(transform) = job.transform { self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[job.transform().get_matrix()]));
//self.queue.write_buffer(&self.transform_buffer, 0, bytemuck::cast_slice(&[transform])); render_pass.set_bind_group(1, &self.transform_bind_group, &[]);
render_pass.set_bind_group(1, &self.transform_bind_group, &[]);
} else {
debug!("//TODO: clear transform uniform if the RenderJob doesn't have a transform.");
}
// There will always be a camera (hopefully) // There will always be a camera (hopefully)
render_pass.set_bind_group(2, &self.camera_bind_group, &[]); 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.set_vertex_buffer(buffers.buffer_vertex.slot(), buffers.buffer_vertex.buffer().slice(..));
render_pass.draw(0..mesh.vertices.len() as u32, 0..1); 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())); self.queue.submit(std::iter::once(encoder.finish()));
output.present(); output.present();
// TODO: Use an actual queue instead of a hashmap
self.render_jobs = HashMap::new();
Ok(()) Ok(())
} }