diff --git a/src/mesh.rs b/src/mesh.rs index ff76bfd..2fea9d1 100644 --- a/src/mesh.rs +++ b/src/mesh.rs @@ -3,7 +3,7 @@ use slab::Slab; use smallvec::SmallVec; use std::any::TypeId; use std::collections::HashMap; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; /// An error that can be returned when allocating a mesh. #[derive(Debug)] @@ -39,6 +39,7 @@ pub struct AttrInfo { } /// The data single mesh attribute. +#[derive(Clone)] pub struct AttrBuffer { pub id: AttrId, pub count: usize, @@ -67,8 +68,8 @@ pub trait Attribute: Sized { /// A store of [AttrIds][AttrId]. pub struct AttrStore { - attributes: Slab, - types: HashMap, + attributes: RwLock>, + types: RwLock>, } impl AttrStore { @@ -80,8 +81,8 @@ impl AttrStore { } /// Dynamically creates a new [AttrId]. - pub fn add(&mut self, info: AttrInfo) -> AttrId { - let index = self.attributes.insert(info); + pub fn add(&self, info: AttrInfo) -> AttrId { + let index = self.attributes.write().unwrap().insert(info); AttrId(index) } @@ -89,10 +90,12 @@ impl AttrStore { /// /// Creates a new [AttrId] for unrecognized types, otherwise reuses an /// existing [AttrId]. - pub fn get_type(&mut self) -> AttrId { + pub fn get_type(&self) -> AttrId { let type_id = TypeId::of::(); - if let Some(id) = self.types.get(&type_id) { - *id + let existing_id = self.types.read().unwrap().get(&type_id).map(|v| *v); + + if let Some(id) = existing_id { + id } else { let layout = T::get_layout(); let usages = T::get_usages(); @@ -103,14 +106,14 @@ impl AttrStore { default_pool_size, }; let id = self.add(info); - self.types.insert(type_id, id); + self.types.write().unwrap().insert(type_id, id); id } } /// Gets the [AttrInfo] for an [AttrId]. - pub fn get_info(&self, id: &AttrId) -> Option<&AttrInfo> { - self.attributes.get(id.0) + pub fn get_info(&self, id: &AttrId) -> Option { + self.attributes.read().unwrap().get(id.0).map(|v| v.clone()) } } @@ -322,6 +325,7 @@ impl AttrPool { pub const MAX_MESH_INLINE_ATTRIBUTES: usize = 16; /// A mesh and all of its attributes. +#[derive(Clone, Default)] pub struct MeshBuffer { pub attributes: SmallVec<[AttrBuffer; MAX_MESH_INLINE_ATTRIBUTES]>, } @@ -344,15 +348,15 @@ pub type MeshLayoutDesc = smallmap::Set; pub struct MeshLayoutId(usize); /// Mappings of the attributes in a [MeshLayout] to specific pools. -pub type MeshLayoutBindings<'a> = smallmap::Map; +pub type MeshLayoutBindings = 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 struct MeshLayoutInstances { + pub bindings: MeshLayoutBindings, pub instances: Vec<(T, MeshAllocOffsets)>, } @@ -361,9 +365,9 @@ pub struct MeshPool { device: Arc, staging: StagingPool, attr_store: Arc, - allocs: Slab, - mesh_layouts: Slab, - pools: HashMap>, + allocs: RwLock>, + mesh_layouts: RwLock>, + pools: RwLock>>, } impl MeshPool { @@ -381,13 +385,13 @@ impl MeshPool { /// 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); + pub fn add_layout(&self, layout: MeshLayoutDesc) -> Result { + let idx = self.mesh_layouts.write().unwrap().insert(layout); Ok(MeshLayoutId(idx)) } /// Loads a [MeshBuffer]. - pub fn load(&mut self, buf: MeshBuffer) -> Result { + pub fn load(&self, buf: MeshBuffer) -> Result { let mut attrs = HashMap::new(); for attr in buf.attributes.into_iter() { @@ -400,7 +404,9 @@ impl MeshPool { let mut attr_allocs = SmallVec::new(); let mut copies = Vec::new(); for (id, buf) in attrs.drain() { - let pools = match self.pools.get_mut(&id) { + let mut pools_write = self.pools.write().unwrap(); + + let pools = match pools_write.get_mut(&id) { Some(pools) => pools, None => { let info = match self.attr_store.get_info(&id) { @@ -408,9 +414,9 @@ impl MeshPool { None => return Err(PoolError::AttrUnregistered), }; - let pool = AttrPool::new(&self.device, id, 0, *info); - self.pools.insert(id, vec![pool]); - self.pools.get_mut(&id).unwrap() + let pool = AttrPool::new(&self.device, id, 0, info); + pools_write.insert(id, vec![pool]); + pools_write.get_mut(&id).unwrap() } }; @@ -438,14 +444,16 @@ impl MeshPool { let alloc = MeshAlloc { attributes: attr_allocs, }; - let key = self.allocs.insert(alloc); + let key = self.allocs.write().unwrap().insert(alloc); let handle = MeshHandle(key); Ok(handle) } - pub fn flush(&mut self, commands: &mut wgpu::CommandEncoder) { + pub fn flush(&self, commands: &mut wgpu::CommandEncoder) { + let pools_read = self.pools.read().unwrap(); + let get_dst = |target: &AttrAllocKey| { - self.pools + pools_read .get(&target.attr) .unwrap() .get(target.pool) @@ -472,16 +480,20 @@ impl MeshPool { { let layout = self .mesh_layouts + .read() + .unwrap() .get(layout.0) - .ok_or(PoolError::LayoutUnregistered)?; + .ok_or(PoolError::LayoutUnregistered)? + .clone(); let layout_attrs: Vec = layout.iter().map(|(id, _)| *id).collect(); let mut layouts = Vec::>::new(); + let allocs_read = self.allocs.read().unwrap(); 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)?; + let alloc = allocs_read.get(handle.0).ok_or(PoolError::InvalidIndex)?; attr_allocs.clear(); for layout_attr in layout_attrs.iter() { @@ -502,15 +514,15 @@ impl MeshPool { let mut layout_bindings = MeshLayoutBindings::default(); let mut alloc_offsets = MeshAllocOffsets::default(); for alloc in attr_allocs.iter() { - let pools = self - .pools + let pools_read = self.pools.read().unwrap(); + let pools = pools_read .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); + layout_bindings.insert(alloc.attr, alloc.pool); alloc_offsets.push((alloc.attr, alloc_offset)); }