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