Skip to content

Commit

Permalink
Store textures in a Weak
Browse files Browse the repository at this point in the history
When a texture is no longer referenced anymore, it'll be deallocated. We still get the optimization of not needing to load the same texture multiple times, however when loading a texture that's not used anywhere else it'll immediately be deallocated. This is useful for graphic pickers, which shouldn't keep textures loaded
  • Loading branch information
melody-rs committed Jul 2, 2024
1 parent 576e7a5 commit eebe29e
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 17 deletions.
72 changes: 60 additions & 12 deletions crates/graphics/src/loaders/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,39 @@
//
// You should have received a copy of the GNU General Public License
// along with Luminol. If not, see <http://www.gnu.org/licenses/>.
use crate::{Atlas, GraphicsState};
use crate::{primitives::tiles::AUTOTILE_AMOUNT, Atlas, GraphicsState, Texture};
use std::sync::{Arc, Weak};

#[derive(Default)]
pub struct Loader {
atlases: dashmap::DashMap<usize, Atlas>,
atlases: dashmap::DashMap<usize, WeakAtlas>,
}

struct WeakAtlas {
atlas_texture: Weak<Texture>,
autotile_width: u32,
tileset_height: u32,
autotile_frames: [u32; AUTOTILE_AMOUNT as usize],
}

impl WeakAtlas {
fn upgrade(&self) -> Option<Atlas> {
self.atlas_texture.upgrade().map(|atlas_texture| Atlas {
atlas_texture,
autotile_width: self.autotile_width,
tileset_height: self.tileset_height,
autotile_frames: self.autotile_frames,
})
}

fn from_atlas(atlas: &Atlas) -> Self {
WeakAtlas {
atlas_texture: Arc::downgrade(&atlas.atlas_texture),
autotile_width: atlas.autotile_width,
tileset_height: atlas.tileset_height,
autotile_frames: atlas.autotile_frames,
}
}
}

impl Loader {
Expand All @@ -28,11 +56,17 @@ impl Loader {
filesystem: &impl luminol_filesystem::FileSystem,
tileset: &luminol_data::rpg::Tileset,
) -> color_eyre::Result<Atlas> {
Ok(self
.atlases
.entry(tileset.id)
.or_insert_with(|| Atlas::new(graphics_state, filesystem, tileset))
.clone())
self.atlases
.get(&tileset.id)
.as_deref()
.and_then(WeakAtlas::upgrade)
.map(Ok)
.unwrap_or_else(|| {
let atlas = Atlas::new(graphics_state, filesystem, tileset);
let weak_atlas = WeakAtlas::from_atlas(&atlas);
self.atlases.insert(tileset.id, weak_atlas);
Ok(atlas)
})
}

pub fn reload_atlas(
Expand All @@ -41,11 +75,25 @@ impl Loader {
filesystem: &impl luminol_filesystem::FileSystem,
tileset: &luminol_data::rpg::Tileset,
) -> color_eyre::Result<Atlas> {
Ok(self
.atlases
.entry(tileset.id)
.insert(Atlas::new(graphics_state, filesystem, tileset))
.clone())
let atlas = Atlas::new(graphics_state, filesystem, tileset);
let weak_atlas = WeakAtlas::from_atlas(&atlas);
self.atlases.insert(tileset.id, weak_atlas);
Ok(atlas)
}

pub fn get_atlas(&self, id: usize) -> Option<Atlas> {
self.atlases
.get(&id)
.as_deref()
.and_then(WeakAtlas::upgrade)
}

pub fn get_expect(&self, id: usize) -> Atlas {
self.atlases
.get(&id)
.as_deref()
.and_then(WeakAtlas::upgrade)
.expect("Atlas not loaded!")
}

pub fn clear(&self) {
Expand Down
13 changes: 8 additions & 5 deletions crates/graphics/src/loaders/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@

use dashmap::DashMap;

use std::sync::Arc;
use std::sync::{Arc, Weak};

use wgpu::util::DeviceExt;

pub struct Loader {
loaded_textures: DashMap<camino::Utf8PathBuf, Arc<Texture>>,
loaded_textures: DashMap<camino::Utf8PathBuf, Weak<Texture>>,

placeholder_texture: Arc<Texture>,
blank_autotile_texture: Arc<Texture>,
Expand Down Expand Up @@ -231,18 +231,21 @@ impl Loader {

let texture =
register_native_texture(self.render_state.clone(), texture, Some(path.as_str()));
self.loaded_textures.insert(path, texture.clone());
self.loaded_textures.insert(path, Arc::downgrade(&texture));
texture
}

pub fn get(&self, path: impl AsRef<camino::Utf8Path>) -> Option<Arc<Texture>> {
self.loaded_textures.get(path.as_ref()).as_deref().cloned()
self.loaded_textures
.get(path.as_ref())
.as_deref()
.and_then(Weak::upgrade)
}

pub fn remove(&self, path: impl AsRef<camino::Utf8Path>) -> Option<Arc<Texture>> {
self.loaded_textures
.remove(path.as_ref())
.map(|(_, value)| value)
.and_then(|(_, value)| value.upgrade())
}

pub fn clear(&self) {
Expand Down

0 comments on commit eebe29e

Please sign in to comment.