Refactor mesh commands (again)
This commit is contained in:
parent
2d6f408230
commit
3ca8e2f4c6
132
src/commands.rs
132
src/commands.rs
|
@ -1,5 +1,6 @@
|
|||
use super::{MeshHandle, MeshPool, TextureHandle, TexturePool};
|
||||
use super::{MeshHandle, TextureHandle};
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub struct MeshInstance {
|
||||
|
@ -8,20 +9,86 @@ pub struct MeshInstance {
|
|||
pub transform: glam::Mat4,
|
||||
}
|
||||
|
||||
pub struct MeshCommands {
|
||||
transforms: Vec<[f32; 16]>,
|
||||
draws: Vec<(usize, usize, std::ops::Range<u32>)>,
|
||||
#[derive(Clone)]
|
||||
struct DrawState {
|
||||
group_id: usize,
|
||||
texture_id: usize,
|
||||
sub_id: usize,
|
||||
instance_range: Range<u32>,
|
||||
}
|
||||
|
||||
impl MeshCommands {
|
||||
pub enum Command {
|
||||
BindMeshGroup {
|
||||
group_id: usize,
|
||||
},
|
||||
BindTexture {
|
||||
texture_id: usize,
|
||||
},
|
||||
Draw {
|
||||
sub_id: usize,
|
||||
instance_range: Range<u32>,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct CommandIterator<'a> {
|
||||
command_set: &'a CommandSet,
|
||||
command_idx: usize, // TODO use iterator instead lol
|
||||
last_group_id: usize,
|
||||
last_texture_id: usize,
|
||||
}
|
||||
|
||||
impl<'a> CommandIterator<'a> {
|
||||
pub fn new(command_set: &'a CommandSet) -> Self {
|
||||
Self {
|
||||
command_set,
|
||||
command_idx: 0,
|
||||
last_group_id: usize::MAX,
|
||||
last_texture_id: usize::MAX,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for CommandIterator<'a> {
|
||||
type Item = Command;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let DrawState {
|
||||
group_id,
|
||||
sub_id,
|
||||
texture_id,
|
||||
instance_range,
|
||||
} = self.command_set.draws.get(self.command_idx)?.clone();
|
||||
|
||||
if group_id != self.last_group_id {
|
||||
self.last_group_id = group_id;
|
||||
Some(Command::BindMeshGroup { group_id })
|
||||
} else if texture_id != self.last_texture_id {
|
||||
self.last_texture_id = texture_id;
|
||||
Some(Command::BindTexture { texture_id })
|
||||
} else {
|
||||
self.command_idx += 1;
|
||||
Some(Command::Draw {
|
||||
sub_id,
|
||||
instance_range,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CommandSet {
|
||||
transforms: Vec<[f32; 16]>,
|
||||
draws: Vec<DrawState>,
|
||||
}
|
||||
|
||||
impl CommandSet {
|
||||
pub fn build(instances: &Vec<MeshInstance>) -> Self {
|
||||
let mut sorted_meshes = HashMap::<(usize, usize), Vec<MeshInstance>>::new();
|
||||
for instance in instances.iter() {
|
||||
let group_id = instance.mesh.group_id;
|
||||
let texture_id = instance.albedo.id;
|
||||
let key = (group_id, texture_id);
|
||||
if let Some(by_group) = sorted_meshes.get_mut(&key) {
|
||||
by_group.push(*instance);
|
||||
if let Some(by_state) = sorted_meshes.get_mut(&key) {
|
||||
by_state.push(*instance);
|
||||
} else {
|
||||
sorted_meshes.insert(key, vec![*instance]);
|
||||
}
|
||||
|
@ -30,14 +97,30 @@ impl MeshCommands {
|
|||
let mut transforms = Vec::new();
|
||||
let mut draws = Vec::new();
|
||||
|
||||
// this code assumes MeshHandle only uses group_id (which it does for now)
|
||||
// TODO bucket by sub_id too before MeshHandle supports it
|
||||
for ((group_id, texture_id), meshes) in sorted_meshes.iter() {
|
||||
let start_idx = transforms.len() as u32;
|
||||
let as_arrays = meshes.iter().map(|i| i.transform.to_cols_array());
|
||||
transforms.extend(as_arrays);
|
||||
let end_idx = transforms.len() as u32;
|
||||
draws.push((*group_id, *texture_id, start_idx..end_idx));
|
||||
for ((group_id, texture_id), mut meshes) in sorted_meshes.drain() {
|
||||
let mut sorted_subs = HashMap::<usize, Vec<MeshInstance>>::new();
|
||||
for mesh in meshes.drain(..) {
|
||||
let sub_id = mesh.mesh.sub_id;
|
||||
if let Some(by_sub) = sorted_subs.get_mut(&sub_id) {
|
||||
by_sub.push(mesh);
|
||||
} else {
|
||||
sorted_subs.insert(sub_id, vec![mesh]);
|
||||
}
|
||||
}
|
||||
|
||||
for (sub_id, meshes) in sorted_subs.drain() {
|
||||
let start_idx = transforms.len() as u32;
|
||||
let as_arrays = meshes.iter().map(|i| i.transform.to_cols_array());
|
||||
transforms.extend(as_arrays);
|
||||
let end_idx = transforms.len() as u32;
|
||||
let instance_range = start_idx..end_idx;
|
||||
draws.push(DrawState {
|
||||
group_id,
|
||||
texture_id,
|
||||
sub_id,
|
||||
instance_range,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Self { transforms, draws }
|
||||
|
@ -47,22 +130,7 @@ impl MeshCommands {
|
|||
bytemuck::cast_slice(&self.transforms)
|
||||
}
|
||||
|
||||
pub fn dispatch<'a>(
|
||||
&self,
|
||||
rp: &mut wgpu::RenderPass<'a>,
|
||||
mesh_pool: &'a MeshPool,
|
||||
texture_pool: &'a TexturePool,
|
||||
) {
|
||||
// TODO one group per mesh, still...
|
||||
// TODO this could be implemented without accessing private members
|
||||
for (group_id, texture_id, meshes_range) in self.draws.iter() {
|
||||
let group = mesh_pool.groups.get(*group_id).unwrap();
|
||||
let texture = texture_pool.textures.get(*texture_id).unwrap();
|
||||
rp.set_vertex_buffer(0, group.vertices.slice(..));
|
||||
rp.set_index_buffer(group.indices.slice(..), wgpu::IndexFormat::Uint32);
|
||||
rp.set_bind_group(2, &texture.bind_group, &[]);
|
||||
let indices = 0..(group.index_capacity as u32);
|
||||
rp.draw_indexed(indices, 0, meshes_range.to_owned());
|
||||
}
|
||||
pub fn iter(&self) -> CommandIterator {
|
||||
CommandIterator::new(self)
|
||||
}
|
||||
}
|
||||
|
|
27
src/main.rs
27
src/main.rs
|
@ -262,7 +262,7 @@ impl Renderer {
|
|||
bytemuck::cast_slice(&[self.camera_uniform]),
|
||||
);
|
||||
|
||||
let mesh_commands = commands::MeshCommands::build(meshes);
|
||||
let mesh_commands = CommandSet::build(meshes);
|
||||
|
||||
// TODO persistent staging buffer (write_buffer creates a new one per call)
|
||||
self.queue
|
||||
|
@ -307,7 +307,30 @@ impl Renderer {
|
|||
rp.set_pipeline(&self.render_pipeline);
|
||||
rp.set_bind_group(0, &self.camera_bind_group, &[]);
|
||||
rp.set_bind_group(1, &self.meshes_bind_group, &[]);
|
||||
mesh_commands.dispatch(&mut rp, &self.mesh_pool, &self.texture_pool);
|
||||
|
||||
let mut group: Option<&MeshGroup> = None;
|
||||
for cmd in mesh_commands.iter() {
|
||||
match cmd {
|
||||
Command::BindMeshGroup { group_id } => {
|
||||
group = self.mesh_pool.groups.get(group_id);
|
||||
let group = group.unwrap();
|
||||
rp.set_vertex_buffer(0, group.vertices.slice(..));
|
||||
rp.set_index_buffer(group.indices.slice(..), wgpu::IndexFormat::Uint32);
|
||||
}
|
||||
Command::BindTexture { texture_id } => {
|
||||
let texture = self.texture_pool.textures.get(texture_id).unwrap();
|
||||
rp.set_bind_group(2, &texture.bind_group, &[]);
|
||||
}
|
||||
Command::Draw {
|
||||
sub_id: _,
|
||||
instance_range,
|
||||
} => {
|
||||
// TODO use sub_id in mesh draw
|
||||
let indices = 0..(group.unwrap().index_capacity as u32);
|
||||
rp.draw_indexed(indices, 0, instance_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.queue.submit(std::iter::once(encoder.finish()));
|
||||
|
|
Loading…
Reference in New Issue