From a82389224f5dbca196b4e6ac0d44bd10a2e15742 Mon Sep 17 00:00:00 2001 From: Simon Gellis Date: Sun, 9 Feb 2025 10:56:33 -0500 Subject: [PATCH] Avoid unnecessary computation/cloning in renderer --- src/vram.rs | 30 +++++++++++++++++++++--------- src/window/vram/bgmap.rs | 10 +++++----- src/window/vram/chardata.rs | 10 +++++----- 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/vram.rs b/src/vram.rs index 2394617..04f6644 100644 --- a/src/vram.rs +++ b/src/vram.rs @@ -1,5 +1,5 @@ use std::{ - collections::{hash_map::Entry, HashMap}, + collections::{hash_map::Entry, HashMap, HashSet}, hash::Hash, sync::{Arc, Mutex}, }; @@ -11,12 +11,12 @@ use egui::{ }; use serde::{Deserialize, Serialize}; -pub trait VramResource: Sized + PartialEq + Eq + Hash { +pub trait VramResource: Sized + Clone + PartialEq + Eq + Hash { fn to_uri(&self) -> String; fn from_uri(uri: &str) -> Option; } -impl Deserialize<'a> + PartialEq + Eq + Hash> VramResource for T { +impl Deserialize<'a> + Clone + PartialEq + Eq + Hash> VramResource for T { fn to_uri(&self) -> String { format!("vram://{}", serde_json::to_string(self).unwrap()) } @@ -28,7 +28,7 @@ impl Deserialize<'a> + PartialEq + Eq + Hash> VramResourc } pub enum VramImage { - Unchanged(Arc), + Unchanged(Option>), Changed(ColorImage), } @@ -40,11 +40,12 @@ impl VramImage { pub fn write(&mut self, coords: (usize, usize), shade: u8) { match self { Self::Unchanged(image) => { - let value = image[coords]; - if value.r() == shade { + if image.as_ref().is_none_or(|i| i[coords].r() == shade) { + return; + } + let Some(mut new_image) = image.take().map(Arc::unwrap_or_clone) else { return; }; - let mut new_image = ColorImage::clone(image); new_image[coords] = Color32::from_gray(shade); *self = Self::Changed(new_image); } @@ -59,7 +60,7 @@ impl VramImage { Self::Unchanged(_) => None, Self::Changed(image) => { let arced = Arc::new(std::mem::take(image)); - *self = Self::Unchanged(arced.clone()); + *self = Self::Unchanged(Some(arced.clone())); Some(arced) } } @@ -81,6 +82,7 @@ pub struct VramTextureLoader { id: String, loader: Mutex, cache: Mutex>, + seen: Mutex>, } impl VramTextureLoader { @@ -89,8 +91,16 @@ impl VramTextureLoader { id: loader.id().to_string(), loader: Mutex::new(loader), cache: Mutex::new(HashMap::new()), + seen: Mutex::new(HashSet::new()), } } + + pub fn begin_pass(&self) { + let mut cache = self.cache.lock().unwrap(); + let mut seen = self.seen.lock().unwrap(); + cache.retain(|res, _| seen.contains(res)); + seen.clear(); + } } impl TextureLoader for VramTextureLoader { @@ -113,8 +123,10 @@ impl TextureLoader for VramTextureLoader { "Only TextureOptions::NEAREST are supported".into(), )); } - let loader = self.loader.lock().unwrap(); let mut cache = self.cache.lock().unwrap(); + let mut seen = self.seen.lock().unwrap(); + seen.insert(resource.clone()); + let loader = self.loader.lock().unwrap(); let resources = cache.iter_mut().map(|(k, v)| (k, &mut v.1)); loader.update(resources); for (handle, image) in cache.values_mut() { diff --git a/src/window/vram/bgmap.rs b/src/window/vram/bgmap.rs index 32ed66f..6129530 100644 --- a/src/window/vram/bgmap.rs +++ b/src/window/vram/bgmap.rs @@ -18,7 +18,7 @@ use super::utils::{parse_palette, CharacterGrid, GENERIC_PALETTE}; pub struct BgMapWindow { sim_id: SimId, - loader: Option, + loader: Arc>, bgmaps: MemoryView, cell_index: usize, cell_index_str: String, @@ -31,7 +31,7 @@ impl BgMapWindow { pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self { Self { sim_id, - loader: Some(BgMapLoader::new(sim_id, memory)), + loader: Arc::new(VramTextureLoader::new(BgMapLoader::new(sim_id, memory))), bgmaps: memory.view(sim_id, 0x00020000, 0x1d800), cell_index: 0, cell_index_str: "0".into(), @@ -188,11 +188,11 @@ impl AppWindow for BgMapWindow { } fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) { - let loader = self.loader.take().unwrap(); - ctx.add_texture_loader(Arc::new(VramTextureLoader::new(loader))); + ctx.add_texture_loader(self.loader.clone()); } fn show(&mut self, ctx: &Context) { + self.loader.begin_pass(); CentralPanel::default().show(ctx, |ui| { ui.horizontal_top(|ui| { StripBuilder::new(ui) @@ -219,7 +219,7 @@ fn parse_cell(cell: u16) -> (usize, bool, bool, usize) { (char_index, vflip, hflip, palette_index) } -#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] enum BgMapResource { BgMap { index: usize, generic_palette: bool }, Cell { index: usize, generic_palette: bool }, diff --git a/src/window/vram/chardata.rs b/src/window/vram/chardata.rs index 504a6eb..28c90eb 100644 --- a/src/window/vram/chardata.rs +++ b/src/window/vram/chardata.rs @@ -77,7 +77,7 @@ impl Display for VramPalette { pub struct CharacterDataWindow { sim_id: SimId, - loader: Option, + loader: Arc>, brightness: MemoryView, palettes: MemoryView, palette: VramPalette, @@ -91,7 +91,7 @@ impl CharacterDataWindow { pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self { Self { sim_id, - loader: Some(CharDataLoader::new(sim_id, memory)), + loader: Arc::new(VramTextureLoader::new(CharDataLoader::new(sim_id, memory))), brightness: memory.view(sim_id, 0x0005f824, 8), palettes: memory.view(sim_id, 0x0005f860, 16), palette: VramPalette::Generic, @@ -250,11 +250,11 @@ impl AppWindow for CharacterDataWindow { } fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) { - let loader = self.loader.take().unwrap(); - ctx.add_texture_loader(Arc::new(VramTextureLoader::new(loader))); + ctx.add_texture_loader(self.loader.clone()); } fn show(&mut self, ctx: &Context) { + self.loader.begin_pass(); CentralPanel::default().show(ctx, |ui| { ui.horizontal_top(|ui| { StripBuilder::new(ui) @@ -273,7 +273,7 @@ impl AppWindow for CharacterDataWindow { } } -#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)] +#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)] enum CharDataResource { Character { palette: VramPalette, index: usize }, CharacterData { palette: VramPalette },