MeshPool thread safety

This commit is contained in:
mars 2022-04-18 20:10:59 -06:00
parent 8ef1d47947
commit ba12827dd6
1 changed files with 44 additions and 32 deletions

View File

@ -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<AttrInfo>,
types: HashMap<TypeId, AttrId>,
attributes: RwLock<Slab<AttrInfo>>,
types: RwLock<HashMap<TypeId, AttrId>>,
}
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<T: 'static + Attribute>(&mut self) -> AttrId {
pub fn get_type<T: 'static + Attribute>(&self) -> AttrId {
let type_id = TypeId::of::<T>();
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<AttrInfo> {
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<AttrId>;
pub struct MeshLayoutId(usize);
/// Mappings of the attributes in a [MeshLayout] to specific pools.
pub type MeshLayoutBindings<'a> = smallmap::Map<AttrId, &'a AttrPool>;
pub type MeshLayoutBindings = smallmap::Map<AttrId, usize>;
/// 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<T> {
pub bindings: MeshLayoutBindings,
pub instances: Vec<(T, MeshAllocOffsets)>,
}
@ -361,9 +365,9 @@ pub struct MeshPool {
device: Arc<wgpu::Device>,
staging: StagingPool<AttrAllocKey>,
attr_store: Arc<AttrStore>,
allocs: Slab<MeshAlloc>,
mesh_layouts: Slab<MeshLayoutDesc>,
pools: HashMap<AttrId, Vec<AttrPool>>,
allocs: RwLock<Slab<MeshAlloc>>,
mesh_layouts: RwLock<Slab<MeshLayoutDesc>>,
pools: RwLock<HashMap<AttrId, Vec<AttrPool>>>,
}
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<MeshLayoutId, PoolError> {
let idx = self.mesh_layouts.insert(layout);
pub fn add_layout(&self, layout: MeshLayoutDesc) -> Result<MeshLayoutId, PoolError> {
let idx = self.mesh_layouts.write().unwrap().insert(layout);
Ok(MeshLayoutId(idx))
}
/// Loads a [MeshBuffer].
pub fn load(&mut self, buf: MeshBuffer) -> Result<MeshHandle, PoolError> {
pub fn load(&self, buf: MeshBuffer) -> Result<MeshHandle, PoolError> {
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<AttrId> = layout.iter().map(|(id, _)| *id).collect();
let mut layouts = Vec::<MeshLayoutInstances<T>>::new();
let allocs_read = self.allocs.read().unwrap();
let mut attr_allocs: Vec<AttrAllocKey> = 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));
}