MeshPool thread safety
This commit is contained in:
parent
8ef1d47947
commit
ba12827dd6
76
src/mesh.rs
76
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<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));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue