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
valgrind
heaptrack
mold
];
buildInputs = [
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)]
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;

View File

@ -9,12 +9,12 @@ pub struct RenderJob {
material: Material,
entity: Entity,
pub transform: Option<Transform>,
pub last_transform: Option<Transform>, // TODO: render interpolation
transform: Transform,
last_transform: Option<Transform>, // TODO: render interpolation
}
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 {
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);
}
}

View File

@ -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<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
@ -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(())
}