From 07a26d86fe1738cf7e6056d6034cd03b3c5d02d6 Mon Sep 17 00:00:00 2001 From: mars Date: Mon, 18 Apr 2022 00:52:17 -0600 Subject: [PATCH] MeshLayouts and iter_meshes() --- Cargo.toml | 1 + src/mesh.rs | 127 ++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 114 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a1b4234..b4fc4c9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] rayon = "1" slab = "^0.4" +smallmap = { git = "https://github.com/marceline-cramer/smallmap" } smallvec = "^1.0" strum = { version = "0.24", features = ["derive"] } wgpu = "^0.12" diff --git a/src/mesh.rs b/src/mesh.rs index 3f6b415..925b90d 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -12,6 +12,7 @@ pub enum PoolError { InvalidIndex, AttrTaken, AttrUnregistered, + LayoutUnregistered, MismatchedId, MismatchedLayout, } @@ -144,6 +145,12 @@ pub struct AttrPool { free_space: Vec, } +impl PartialEq for AttrPool { + fn eq(&self, other: &Self) -> bool { + self.pool_id == other.pool_id && self.id == other.id + } +} + impl AttrPool { pub fn new(id: AttrId, pool_id: usize, info: AttrInfo) -> Self { let layout = info.layout; @@ -223,11 +230,7 @@ impl AttrPool { /// Allocates an array of attribute at a specific free space index. /// /// Returns the new [AttrAllocKey]. - fn alloc_at( - &mut self, - index: usize, - count: usize, - ) -> Result { + fn alloc_at(&mut self, index: usize, count: usize) -> Result { let free_space = match self.free_space.get_mut(index) { Some(index) => index, None => return Err(PoolError::InvalidIndex), @@ -281,6 +284,12 @@ impl AttrPool { Ok(()) } + + /// Gets the offset (in elements) of an allocation, passed by key. + pub fn get_offset(&self, key: usize) -> Result { + let alloc = self.allocs.get(key).ok_or(PoolError::InvalidIndex)?; + Ok(alloc.offset) + } } /// The number of attributes a mesh can have before they're moved to the heap. @@ -300,16 +309,25 @@ pub struct MeshAlloc { #[repr(transparent)] pub struct MeshHandle(usize); -impl HasMeshHandle for MeshHandle { - fn get_mesh_handle(&self) -> &Self { - self - } -} +/// A reusable set of [AttrIds][AttrId], for use with querying compatible meshes. +pub type MeshLayoutDesc = smallmap::Set; -/// A trait for structs containing [MeshHandles][MeshHandle] that are not -/// themselves handles. Used for iteration. -pub trait HasMeshHandle { - fn get_mesh_handle(&self) -> &MeshHandle; +/// The ID of a [MeshLayoutDesc] registered in a [MeshPool]. +#[repr(transparent)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct MeshLayoutId(usize); + +/// Mappings of the attributes in a [MeshLayout] to specific pools. +pub type MeshLayoutBindings<'a> = smallmap::Map; + +/// Mappings of the attributes in a [MeshAlloc] to specific pool offsets. +pub type MeshAllocOffsets = SmallVec<[(AttrId, usize); MAX_MESH_INLINE_ATTRIBUTES]>; + +/// A set of mesh instances fitting a common [MeshLayoutDesc]. +#[derive(Default)] +pub struct MeshLayoutInstances<'a, T> { + pub bindings: MeshLayoutBindings<'a>, + pub instances: Vec<(T, MeshAllocOffsets)>, } /// A mesh data pool. @@ -318,6 +336,7 @@ pub struct MeshPool { staging: StagingPool, attr_store: Arc, allocs: Slab, + mesh_layouts: Slab, pools: HashMap>, } @@ -327,11 +346,20 @@ impl MeshPool { device: device.clone(), staging: StagingPool::new(device, 1024 * 1024), attr_store, + mesh_layouts: Default::default(), allocs: Default::default(), pools: Default::default(), }) } + /// Registers a [MeshLayoutDesc] with this pool. + /// + /// TODO: keep track of mesh allocations that fit each layout + pub fn add_layout(&mut self, layout: MeshLayoutDesc) -> Result { + let idx = self.mesh_layouts.insert(layout); + Ok(MeshLayoutId(idx)) + } + /// Loads a [MeshBuffer]. pub fn load(&mut self, buf: MeshBuffer) -> Result { let mut attrs = HashMap::new(); @@ -388,4 +416,75 @@ impl MeshPool { let handle = MeshHandle(key); Ok(handle) } + + pub fn iter_meshes( + &self, + layout: MeshLayoutId, + meshes: I, + get_handle: F, + ) -> Result>, PoolError> + where + I: Iterator, + F: Fn(&T) -> &'static MeshHandle, + { + let layout = self + .mesh_layouts + .get(layout.0) + .ok_or(PoolError::LayoutUnregistered)?; + + let layout_attrs: Vec = layout.iter().map(|(id, _)| *id).collect(); + let mut layouts = Vec::>::new(); + + let mut attr_allocs: Vec = Vec::with_capacity(layout_attrs.len()); + for mesh in meshes { + let handle = get_handle(&mesh); + let alloc = self.allocs.get(handle.0).ok_or(PoolError::InvalidIndex)?; + + attr_allocs.clear(); + for layout_attr in layout_attrs.iter() { + match alloc + .attributes + .iter() + .find(|attr_alloc| attr_alloc.attr == *layout_attr) + { + Some(alloc) => attr_allocs.push(alloc.clone()), + None => break, + } + } + + if attr_allocs.len() != layout_attrs.len() { + continue; + } + + let mut layout_bindings = MeshLayoutBindings::default(); + let mut alloc_offsets = MeshAllocOffsets::default(); + for alloc in attr_allocs.iter() { + let pools = self + .pools + .get(&alloc.attr) + .ok_or(PoolError::AttrUnregistered)?; + + let pool = pools.get(alloc.pool).ok_or(PoolError::InvalidIndex)?; + let alloc_offset = pool.get_offset(alloc.alloc)?; + + layout_bindings.insert(alloc.attr, pool); + alloc_offsets.push((alloc.attr, alloc_offset)); + } + + let instance = (mesh, alloc_offsets); + + match layouts + .iter_mut() + .find(|layout| layout.bindings == layout_bindings) + { + Some(layout) => layout.instances.push(instance), + None => layouts.push(MeshLayoutInstances { + bindings: layout_bindings, + instances: vec![instance], + }), + } + } + + Ok(layouts) + } }