diff --git a/src/mesh/attr.rs b/src/mesh/attr.rs index 52d39be..f2b9b95 100644 --- a/src/mesh/attr.rs +++ b/src/mesh/attr.rs @@ -4,19 +4,92 @@ //! fit more data. use super::*; +use std::any::TypeId; +use std::collections::HashMap; /// An externally-defined identifier for a mesh attribute. #[repr(transparent)] #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct AttrId(pub usize); -/// A description of a mesh attribute. -#[derive(Clone, Debug, Hash, PartialEq, Eq)] +/// A description of a attribute's layout in memory. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct AttrLayout { /// The size (in bytes) of this attribute. pub size: usize, } +/// Information about an [Attribute] registered in [AttrStore]. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct AttrInfo { + pub layout: AttrLayout, + pub default_pool_size: usize, +} + +/// A compile-time attribute data type. +pub trait Attribute: Sized { + /// The memory layout of this data. + fn get_layout() -> AttrLayout { + AttrLayout { + size: std::mem::size_of::(), + } + } + + /// The default size for new pools of this attribute. + /// + /// Defaults to 1024 * 1024. (Around one million.) + fn get_default_pool_size() -> usize { + 1024 * 1024 + } +} + +/// A store of [AttrIds][AttrId]. +pub struct AttrStore { + attributes: Slab, + types: HashMap, +} + +impl AttrStore { + pub fn new() -> Self { + Self { + attributes: Default::default(), + types: Default::default(), + } + } + + /// Dynamically creates a new [AttrId]. + pub fn add(&mut self, info: AttrInfo) -> AttrId { + let index = self.attributes.insert(info); + AttrId(index) + } + + /// Gets the [AttrId] for a type implementing [Attribute]. + /// + /// Creates a new [AttrId] for unrecognized types, otherwise reuses an + /// existing [AttrId]. + pub fn get_type(&mut self) -> AttrId { + let type_id = TypeId::of::(); + if let Some(id) = self.types.get(&type_id) { + *id + } else { + let layout = T::get_layout(); + let default_pool_size = T::get_default_pool_size(); + let info = AttrInfo { + layout, + default_pool_size, + }; + let id = self.add(info); + self.types.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) + } +} + /// An attribute buffer that has been allocated in an [AttrPool]. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct AttrAlloc { @@ -41,12 +114,10 @@ pub struct AttrPool { } impl AttrPool { - pub fn new( - group: usize, - id: AttrId, - layout: AttrLayout, - size: usize, - ) -> Result { + pub fn new(group: usize, id: AttrId, info: AttrInfo) -> Result { + let layout = info.layout; + let size = info.default_pool_size; + Ok(Self { group, id, diff --git a/src/mesh/group.rs b/src/mesh/group.rs index 837258b..4cf01e5 100644 --- a/src/mesh/group.rs +++ b/src/mesh/group.rs @@ -1,6 +1,7 @@ //! Fixed-room pooling of mesh data. use super::*; +use std::sync::Arc; /// A mesh that has been allocated in a [MeshGroup]. pub struct MeshAlloc { @@ -10,49 +11,35 @@ pub struct MeshAlloc { /// A set of GPU-side vertex attribute pools and index pools. pub struct MeshGroup { id: usize, + attr_store: Arc, pools: HashMap, meshes: Slab, } impl MeshGroup { - pub fn new(id: usize) -> Self { + pub fn new(id: usize, attr_store: Arc) -> Self { Self { id, + attr_store, pools: Default::default(), meshes: Default::default(), } } - /// Registers an [AttrId], and creates the [AttrPool] for it. - /// - /// Fails if the [AttrId] has already been registered. - /// - /// `pool_size` defines the size of the new pool. Once an attribute pool - /// has been created, it cannot be resized, so if it runs out of room for - /// new attributes, a new [MeshGroup] must be created. - pub fn add_attribute( - &mut self, - id: AttrId, - layout: AttrLayout, - pool_size: usize, - ) -> Result<(), PoolError> { - if self.pools.contains_key(&id) { - return Err(PoolError::AttrTaken); - } - - let pool = AttrPool::new(self.id, id, layout, pool_size)?; - self.pools.insert(id, pool); - - Ok(()) - } - /// Checks to see if a mesh can be loaded within this group. pub fn can_load(&self, buf: &MeshBuffer) -> Result<(), PoolError> { for attr in buf.attributes.iter() { match self.pools.get(&attr.id) { - None => return Err(PoolError::AttrUnregistered), - Some(pool) => pool.can_load(attr)?, - }; + None => { + match self.attr_store.get_info(&attr.id) { + Some(_) => {} // new pools of valid attrs can be made + None => return Err(PoolError::AttrUnregistered), + }; + } + Some(pool) => { + pool.can_load(attr)?; + } + } } Ok(()) @@ -66,14 +53,24 @@ impl MeshGroup { let mut copies = Vec::new(); for attr in buf.attributes.iter() { - match self.pools.get_mut(&attr.id) { - None => unreachable!(), - Some(pool) => { - let (alloc, copy) = pool.load(attr)?; - allocs.push((alloc, attr.id)); - copies.push(copy); + let id = &attr.id; + let pool = match self.pools.get_mut(id) { + Some(pool) => pool, + None => { + let info = match self.attr_store.get_info(id) { + Some(info) => *info, + None => return Err(PoolError::AttrUnregistered), + }; + + let new_pool = AttrPool::new(self.id, *id, info)?; + self.pools.insert(*id, new_pool); + self.pools.get_mut(id).unwrap() } - } + }; + + let (alloc, copy) = pool.load(attr)?; + allocs.push((alloc, attr.id)); + copies.push(copy); } let mesh = MeshAlloc { attributes: allocs }; diff --git a/src/mesh/mod.rs b/src/mesh/mod.rs index b21a85f..a570fdd 100644 --- a/src/mesh/mod.rs +++ b/src/mesh/mod.rs @@ -45,6 +45,7 @@ //! TODO: make spillover buffers GPU-transferrable on iGPUs use slab::Slab; +use std::sync::Arc; use smallvec::SmallVec; use std::collections::HashMap; @@ -94,14 +95,16 @@ pub struct MeshHandle { /// The top-level mesh data pool. pub struct MeshPool { - pub staging: StagingPool, - pub groups: Vec, + staging: StagingPool, + attr_store: Arc, + groups: Vec, } impl MeshPool { - pub fn new() -> Self { + pub fn new(attr_store: Arc) -> Self { Self { staging: StagingPool::new(1_000_000), + attr_store, groups: Default::default(), } } @@ -119,7 +122,7 @@ impl MeshPool { } let group_index = self.groups.len(); - self.groups.push(MeshGroup::new(group_index)); + self.groups.push(MeshGroup::new(group_index, self.attr_store.clone())); let group = self.groups.get_mut(group_index).unwrap(); let (handle, copies) = group.load(buf)?;