diff --git a/all-is-cubes-mesh/src/cache.rs b/all-is-cubes-mesh/src/cache.rs new file mode 100644 index 000000000..2715eb8c1 --- /dev/null +++ b/all-is-cubes-mesh/src/cache.rs @@ -0,0 +1,78 @@ +//! Caching of [`BlockMesh`]es. +//! +//! TODO: This cache is not yet used, but I expect to integrate it with `ChunkedSpaceMesh` +//! eventually, replacing part or all of the `MeshJobQueue`. +//! See for project details. +#![allow(dead_code)] + +use core::ops::Deref; +use std::collections::HashMap; +use std::sync::{Arc, Mutex, OnceLock}; + +use all_is_cubes::block::{EvKey, EvaluatedBlock}; + +use crate::{BlockMesh, MeshOptions, MeshTypes}; + +/// A cache with [`EvaluatedBlock`] keys and [`BlockMesh`] values. +/// +/// Purposes it serves: +/// * Avoiding recomputing block meshes even if the specific blocks +/// disappear and reappear from the visible content. +/// * Sharing mesh calculations between renderers of different [`Space`]s. +/// * TODO: Managing asynchronous block mesh computation. +/// +/// TODO: There is not yet a cache size/removal policy. +#[derive(Clone, Debug)] +pub(crate) struct BlockMeshCache { + storage: Arc>>, + options: MeshOptions, + texture_allocator: M::Alloc, +} + +#[derive(Debug)] +struct Storage { + blocks: HashMap>>>, +} + +impl BlockMeshCache { + pub fn new(options: MeshOptions, texture_allocator: M::Alloc) -> Self { + Self { + storage: Arc::new(Mutex::new(Storage { + blocks: HashMap::new(), + })), + options, + texture_allocator, + } + } + + /// Get a reference to a cached block mesh, or compute it if it is not present. + /// + /// If requests for the same mesh are made simultaneously from different threads, + /// then the mesh will be computed for only one of them and the others will wait. + /// Reentrantly accessing the cache (e.g. in a texture allocator implementation) + /// will fail in an unspecified fashion (deadlock, panic, etc.). + pub fn get_or_compute(&self, block: &EvaluatedBlock) -> impl Deref> { + let key = EvKey::new(block); + let cell: Arc>> = self + .storage + .lock() + .unwrap() + .blocks + .entry(key) + .or_default() + .clone(); + + cell.get_or_init(|| BlockMesh::new(block, &self.texture_allocator, &self.options)); + + Ptr(cell) + } +} + +struct Ptr(Arc>>); +impl Deref for Ptr { + type Target = BlockMesh; + + fn deref(&self) -> &Self::Target { + self.0.get().unwrap() + } +} diff --git a/all-is-cubes-mesh/src/lib.rs b/all-is-cubes-mesh/src/lib.rs index e5a653252..ecd8b6fdb 100644 --- a/all-is-cubes-mesh/src/lib.rs +++ b/all-is-cubes-mesh/src/lib.rs @@ -48,6 +48,7 @@ mod block_vertex; pub use block_vertex::*; mod block_mesh; pub use block_mesh::*; +mod cache; pub mod dynamic; mod index_vec; pub use index_vec::*;