From 0d9f4232a554be17ecf8b253ab2eb4fb8b2c71ba Mon Sep 17 00:00:00 2001 From: Kevin Reid Date: Mon, 12 Sep 2022 21:53:40 -0700 Subject: [PATCH] mesh: Add `BlockMeshCache` (unused). See for context. The cache is not yet used but I believe having this small amount of dead code will be better overall for development than having yet another unmerged branch. (Unless the cache never happens or looks totally different than this, of course.) --- all-is-cubes-mesh/src/cache.rs | 78 ++++++++++++++++++++++++++++++++++ all-is-cubes-mesh/src/lib.rs | 1 + 2 files changed, 79 insertions(+) create mode 100644 all-is-cubes-mesh/src/cache.rs 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::*;