Refactor MeshCommands
This commit is contained in:
parent
55264bfceb
commit
0c75860efd
|
@ -0,0 +1,55 @@
|
|||
use super::{MeshInstance, MeshPool};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct MeshCommands {
|
||||
transforms: Vec<[f32; 16]>,
|
||||
transform_ranges: Vec<(usize, std::ops::Range<u32>)>,
|
||||
}
|
||||
|
||||
impl MeshCommands {
|
||||
pub fn build(instances: &Vec<MeshInstance>) -> Self {
|
||||
let mut sorted_meshes = HashMap::<usize, Vec<MeshInstance>>::new();
|
||||
for mesh in instances.iter() {
|
||||
let group_id = mesh.handle.group_id;
|
||||
if let Some(by_group) = sorted_meshes.get_mut(&group_id) {
|
||||
by_group.push(*mesh);
|
||||
} else {
|
||||
sorted_meshes.insert(group_id, vec![*mesh]);
|
||||
}
|
||||
}
|
||||
|
||||
let mut transforms = Vec::new();
|
||||
let mut transform_ranges = 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, 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;
|
||||
transform_ranges.push((*group_id, start_idx..end_idx));
|
||||
}
|
||||
|
||||
Self {
|
||||
transforms,
|
||||
transform_ranges,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_storage(&self) -> &[u8] {
|
||||
bytemuck::cast_slice(&self.transforms)
|
||||
}
|
||||
|
||||
pub fn dispatch<'a>(&self, rp: &mut wgpu::RenderPass<'a>, mesh_pool: &'a MeshPool) {
|
||||
// TODO one group per mesh, still...
|
||||
// TODO this could be implemented without accessing private members
|
||||
for (group_id, meshes_range) in self.transform_ranges.iter() {
|
||||
let group = mesh_pool.groups.get(*group_id).unwrap();
|
||||
rp.set_vertex_buffer(0, group.vertices.slice(..));
|
||||
rp.set_index_buffer(group.indices.slice(..), wgpu::IndexFormat::Uint32);
|
||||
let indices = 0..(group.index_capacity as u32);
|
||||
rp.draw_indexed(indices, 0, meshes_range.to_owned());
|
||||
}
|
||||
}
|
||||
}
|
73
src/main.rs
73
src/main.rs
|
@ -1,4 +1,3 @@
|
|||
use std::collections::HashMap;
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
use winit::{
|
||||
|
@ -8,6 +7,7 @@ use winit::{
|
|||
};
|
||||
|
||||
mod camera;
|
||||
mod commands;
|
||||
mod mesh;
|
||||
|
||||
use camera::*;
|
||||
|
@ -102,8 +102,7 @@ impl Renderer {
|
|||
let meshes_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("Meshes Buffer"),
|
||||
size: 65536, // TODO resizable meshes buffer/gpu vectors
|
||||
usage: wgpu::BufferUsages::STORAGE
|
||||
| wgpu::BufferUsages::COPY_DST,
|
||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
||||
|
@ -203,7 +202,7 @@ impl Renderer {
|
|||
pub fn render(
|
||||
&mut self,
|
||||
camera: &impl Camera,
|
||||
meshes: &MeshCommands,
|
||||
meshes: &Vec<MeshInstance>,
|
||||
) -> Result<(), wgpu::SurfaceError> {
|
||||
self.camera_uniform.update(camera);
|
||||
self.queue.write_buffer(
|
||||
|
@ -212,36 +211,11 @@ impl Renderer {
|
|||
bytemuck::cast_slice(&[self.camera_uniform]),
|
||||
);
|
||||
|
||||
let mut sorted_meshes = HashMap::<usize, Vec<MeshInstance>>::new();
|
||||
for mesh in meshes.iter() {
|
||||
let group_id = mesh.handle.group_id;
|
||||
if let Some(by_group) = sorted_meshes.get_mut(&group_id) {
|
||||
by_group.push(*mesh);
|
||||
} else {
|
||||
let new_list = vec![*mesh];
|
||||
sorted_meshes.insert(group_id, new_list);
|
||||
}
|
||||
}
|
||||
|
||||
let mut mesh_transforms = Vec::<[f32; 16]>::new();
|
||||
let mut transform_ranges = Vec::<(usize, std::ops::Range<u32>)>::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, instances) in sorted_meshes.iter() {
|
||||
let start_idx = mesh_transforms.len() as u32;
|
||||
let transforms = instances.iter().map(|i| i.transform.to_cols_array());
|
||||
mesh_transforms.extend(transforms);
|
||||
let end_idx = mesh_transforms.len() as u32;
|
||||
transform_ranges.push((*group_id, start_idx..end_idx));
|
||||
}
|
||||
let mesh_commands = commands::MeshCommands::build(meshes);
|
||||
|
||||
// TODO persistent staging buffer (write_buffer creates a new one per call)
|
||||
self.queue.write_buffer(
|
||||
&self.meshes_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&mesh_transforms),
|
||||
);
|
||||
self.queue
|
||||
.write_buffer(&self.meshes_buffer, 0, mesh_commands.get_storage());
|
||||
|
||||
let output = self.surface.get_current_texture()?;
|
||||
let view = output
|
||||
|
@ -254,7 +228,7 @@ impl Renderer {
|
|||
});
|
||||
|
||||
{
|
||||
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
let mut rp = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
||||
label: Some("Render Pass"),
|
||||
color_attachments: &[wgpu::RenderPassColorAttachment {
|
||||
view: &view,
|
||||
|
@ -272,19 +246,10 @@ impl Renderer {
|
|||
depth_stencil_attachment: None,
|
||||
});
|
||||
|
||||
render_pass.set_pipeline(&self.render_pipeline);
|
||||
render_pass.set_bind_group(0, &self.camera_bind_group, &[]);
|
||||
render_pass.set_bind_group(1, &self.meshes_bind_group, &[]);
|
||||
|
||||
// TODO one group per mesh, still...
|
||||
// TODO this could be implemented without accessing private members
|
||||
for (group_id, meshes_range) in transform_ranges.iter() {
|
||||
let group = self.mesh_pool.groups.get(*group_id).unwrap();
|
||||
render_pass.set_vertex_buffer(0, group.vertices.slice(..));
|
||||
render_pass.set_index_buffer(group.indices.slice(..), wgpu::IndexFormat::Uint32);
|
||||
let indices = 0..(group.index_capacity as u32);
|
||||
render_pass.draw_indexed(indices, 0, meshes_range.to_owned());
|
||||
}
|
||||
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.queue.submit(std::iter::once(encoder.finish()));
|
||||
|
@ -294,7 +259,7 @@ impl Renderer {
|
|||
}
|
||||
}
|
||||
|
||||
struct MeshGroup {
|
||||
pub struct MeshGroup {
|
||||
vertices: wgpu::Buffer,
|
||||
vertex_capacity: usize,
|
||||
indices: wgpu::Buffer,
|
||||
|
@ -302,7 +267,7 @@ struct MeshGroup {
|
|||
}
|
||||
|
||||
impl MeshGroup {
|
||||
pub fn new(device: &wgpu::Device, data: &MeshData) -> Self {
|
||||
fn new(device: &wgpu::Device, data: &MeshData) -> Self {
|
||||
let vertex_capacity = data.vertices.len();
|
||||
let vertices = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
|
||||
label: Some("Vertex Buffer"),
|
||||
|
@ -327,7 +292,7 @@ impl MeshGroup {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct MeshPool {
|
||||
pub struct MeshPool {
|
||||
groups: slab::Slab<MeshGroup>,
|
||||
}
|
||||
|
||||
|
@ -338,6 +303,10 @@ impl MeshPool {
|
|||
let sub_id = 0;
|
||||
MeshHandle { group_id, sub_id }
|
||||
}
|
||||
|
||||
pub fn get_group(&self, handle: &MeshHandle) -> Option<&MeshGroup> {
|
||||
self.groups.get(handle.group_id)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
@ -360,20 +329,18 @@ impl CameraUniform {
|
|||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Eq, Hash, PartialEq)]
|
||||
struct MeshHandle {
|
||||
pub struct MeshHandle {
|
||||
group_id: usize,
|
||||
// unused for now, since each group contains only one mesh
|
||||
sub_id: usize,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
struct MeshInstance {
|
||||
pub struct MeshInstance {
|
||||
pub handle: MeshHandle,
|
||||
pub transform: glam::Mat4,
|
||||
}
|
||||
|
||||
type MeshCommands = Vec<MeshInstance>;
|
||||
|
||||
fn load_model() -> MeshData {
|
||||
use tobj::*;
|
||||
|
||||
|
|
Loading…
Reference in New Issue