Avoid unnecessary computation/cloning in renderer
This commit is contained in:
		
							parent
							
								
									600148c781
								
							
						
					
					
						commit
						a82389224f
					
				
							
								
								
									
										30
									
								
								src/vram.rs
								
								
								
								
							
							
						
						
									
										30
									
								
								src/vram.rs
								
								
								
								
							| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    collections::{hash_map::Entry, HashMap},
 | 
					    collections::{hash_map::Entry, HashMap, HashSet},
 | 
				
			||||||
    hash::Hash,
 | 
					    hash::Hash,
 | 
				
			||||||
    sync::{Arc, Mutex},
 | 
					    sync::{Arc, Mutex},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -11,12 +11,12 @@ use egui::{
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use serde::{Deserialize, Serialize};
 | 
					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 to_uri(&self) -> String;
 | 
				
			||||||
    fn from_uri(uri: &str) -> Option<Self>;
 | 
					    fn from_uri(uri: &str) -> Option<Self>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Serialize + for<'a> Deserialize<'a> + PartialEq + Eq + Hash> VramResource for T {
 | 
					impl<T: Serialize + for<'a> Deserialize<'a> + Clone + PartialEq + Eq + Hash> VramResource for T {
 | 
				
			||||||
    fn to_uri(&self) -> String {
 | 
					    fn to_uri(&self) -> String {
 | 
				
			||||||
        format!("vram://{}", serde_json::to_string(self).unwrap())
 | 
					        format!("vram://{}", serde_json::to_string(self).unwrap())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -28,7 +28,7 @@ impl<T: Serialize + for<'a> Deserialize<'a> + PartialEq + Eq + Hash> VramResourc
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub enum VramImage {
 | 
					pub enum VramImage {
 | 
				
			||||||
    Unchanged(Arc<ColorImage>),
 | 
					    Unchanged(Option<Arc<ColorImage>>),
 | 
				
			||||||
    Changed(ColorImage),
 | 
					    Changed(ColorImage),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,11 +40,12 @@ impl VramImage {
 | 
				
			||||||
    pub fn write(&mut self, coords: (usize, usize), shade: u8) {
 | 
					    pub fn write(&mut self, coords: (usize, usize), shade: u8) {
 | 
				
			||||||
        match self {
 | 
					        match self {
 | 
				
			||||||
            Self::Unchanged(image) => {
 | 
					            Self::Unchanged(image) => {
 | 
				
			||||||
                let value = image[coords];
 | 
					                if image.as_ref().is_none_or(|i| i[coords].r() == shade) {
 | 
				
			||||||
                if value.r() == shade {
 | 
					                    return;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                let Some(mut new_image) = image.take().map(Arc::unwrap_or_clone) else {
 | 
				
			||||||
                    return;
 | 
					                    return;
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                let mut new_image = ColorImage::clone(image);
 | 
					 | 
				
			||||||
                new_image[coords] = Color32::from_gray(shade);
 | 
					                new_image[coords] = Color32::from_gray(shade);
 | 
				
			||||||
                *self = Self::Changed(new_image);
 | 
					                *self = Self::Changed(new_image);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -59,7 +60,7 @@ impl VramImage {
 | 
				
			||||||
            Self::Unchanged(_) => None,
 | 
					            Self::Unchanged(_) => None,
 | 
				
			||||||
            Self::Changed(image) => {
 | 
					            Self::Changed(image) => {
 | 
				
			||||||
                let arced = Arc::new(std::mem::take(image));
 | 
					                let arced = Arc::new(std::mem::take(image));
 | 
				
			||||||
                *self = Self::Unchanged(arced.clone());
 | 
					                *self = Self::Unchanged(Some(arced.clone()));
 | 
				
			||||||
                Some(arced)
 | 
					                Some(arced)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -81,6 +82,7 @@ pub struct VramTextureLoader<T: VramImageLoader> {
 | 
				
			||||||
    id: String,
 | 
					    id: String,
 | 
				
			||||||
    loader: Mutex<T>,
 | 
					    loader: Mutex<T>,
 | 
				
			||||||
    cache: Mutex<HashMap<T::Resource, (TextureHandle, VramImage)>>,
 | 
					    cache: Mutex<HashMap<T::Resource, (TextureHandle, VramImage)>>,
 | 
				
			||||||
 | 
					    seen: Mutex<HashSet<T::Resource>>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: VramImageLoader> VramTextureLoader<T> {
 | 
					impl<T: VramImageLoader> VramTextureLoader<T> {
 | 
				
			||||||
| 
						 | 
					@ -89,8 +91,16 @@ impl<T: VramImageLoader> VramTextureLoader<T> {
 | 
				
			||||||
            id: loader.id().to_string(),
 | 
					            id: loader.id().to_string(),
 | 
				
			||||||
            loader: Mutex::new(loader),
 | 
					            loader: Mutex::new(loader),
 | 
				
			||||||
            cache: Mutex::new(HashMap::new()),
 | 
					            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<T: VramImageLoader> TextureLoader for VramTextureLoader<T> {
 | 
					impl<T: VramImageLoader> TextureLoader for VramTextureLoader<T> {
 | 
				
			||||||
| 
						 | 
					@ -113,8 +123,10 @@ impl<T: VramImageLoader> TextureLoader for VramTextureLoader<T> {
 | 
				
			||||||
                "Only TextureOptions::NEAREST are supported".into(),
 | 
					                "Only TextureOptions::NEAREST are supported".into(),
 | 
				
			||||||
            ));
 | 
					            ));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        let loader = self.loader.lock().unwrap();
 | 
					 | 
				
			||||||
        let mut cache = self.cache.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));
 | 
					        let resources = cache.iter_mut().map(|(k, v)| (k, &mut v.1));
 | 
				
			||||||
        loader.update(resources);
 | 
					        loader.update(resources);
 | 
				
			||||||
        for (handle, image) in cache.values_mut() {
 | 
					        for (handle, image) in cache.values_mut() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,7 +18,7 @@ use super::utils::{parse_palette, CharacterGrid, GENERIC_PALETTE};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct BgMapWindow {
 | 
					pub struct BgMapWindow {
 | 
				
			||||||
    sim_id: SimId,
 | 
					    sim_id: SimId,
 | 
				
			||||||
    loader: Option<BgMapLoader>,
 | 
					    loader: Arc<VramTextureLoader<BgMapLoader>>,
 | 
				
			||||||
    bgmaps: MemoryView,
 | 
					    bgmaps: MemoryView,
 | 
				
			||||||
    cell_index: usize,
 | 
					    cell_index: usize,
 | 
				
			||||||
    cell_index_str: String,
 | 
					    cell_index_str: String,
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,7 @@ impl BgMapWindow {
 | 
				
			||||||
    pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self {
 | 
					    pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            sim_id,
 | 
					            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),
 | 
					            bgmaps: memory.view(sim_id, 0x00020000, 0x1d800),
 | 
				
			||||||
            cell_index: 0,
 | 
					            cell_index: 0,
 | 
				
			||||||
            cell_index_str: "0".into(),
 | 
					            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) {
 | 
					    fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) {
 | 
				
			||||||
        let loader = self.loader.take().unwrap();
 | 
					        ctx.add_texture_loader(self.loader.clone());
 | 
				
			||||||
        ctx.add_texture_loader(Arc::new(VramTextureLoader::new(loader)));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show(&mut self, ctx: &Context) {
 | 
					    fn show(&mut self, ctx: &Context) {
 | 
				
			||||||
 | 
					        self.loader.begin_pass();
 | 
				
			||||||
        CentralPanel::default().show(ctx, |ui| {
 | 
					        CentralPanel::default().show(ctx, |ui| {
 | 
				
			||||||
            ui.horizontal_top(|ui| {
 | 
					            ui.horizontal_top(|ui| {
 | 
				
			||||||
                StripBuilder::new(ui)
 | 
					                StripBuilder::new(ui)
 | 
				
			||||||
| 
						 | 
					@ -219,7 +219,7 @@ fn parse_cell(cell: u16) -> (usize, bool, bool, usize) {
 | 
				
			||||||
    (char_index, vflip, hflip, palette_index)
 | 
					    (char_index, vflip, hflip, palette_index)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Hash)]
 | 
					#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
enum BgMapResource {
 | 
					enum BgMapResource {
 | 
				
			||||||
    BgMap { index: usize, generic_palette: bool },
 | 
					    BgMap { index: usize, generic_palette: bool },
 | 
				
			||||||
    Cell { index: usize, generic_palette: bool },
 | 
					    Cell { index: usize, generic_palette: bool },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,7 @@ impl Display for VramPalette {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub struct CharacterDataWindow {
 | 
					pub struct CharacterDataWindow {
 | 
				
			||||||
    sim_id: SimId,
 | 
					    sim_id: SimId,
 | 
				
			||||||
    loader: Option<CharDataLoader>,
 | 
					    loader: Arc<VramTextureLoader<CharDataLoader>>,
 | 
				
			||||||
    brightness: MemoryView,
 | 
					    brightness: MemoryView,
 | 
				
			||||||
    palettes: MemoryView,
 | 
					    palettes: MemoryView,
 | 
				
			||||||
    palette: VramPalette,
 | 
					    palette: VramPalette,
 | 
				
			||||||
| 
						 | 
					@ -91,7 +91,7 @@ impl CharacterDataWindow {
 | 
				
			||||||
    pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self {
 | 
					    pub fn new(sim_id: SimId, memory: &mut MemoryMonitor) -> Self {
 | 
				
			||||||
        Self {
 | 
					        Self {
 | 
				
			||||||
            sim_id,
 | 
					            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),
 | 
					            brightness: memory.view(sim_id, 0x0005f824, 8),
 | 
				
			||||||
            palettes: memory.view(sim_id, 0x0005f860, 16),
 | 
					            palettes: memory.view(sim_id, 0x0005f860, 16),
 | 
				
			||||||
            palette: VramPalette::Generic,
 | 
					            palette: VramPalette::Generic,
 | 
				
			||||||
| 
						 | 
					@ -250,11 +250,11 @@ impl AppWindow for CharacterDataWindow {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) {
 | 
					    fn on_init(&mut self, ctx: &Context, _render_state: &egui_wgpu::RenderState) {
 | 
				
			||||||
        let loader = self.loader.take().unwrap();
 | 
					        ctx.add_texture_loader(self.loader.clone());
 | 
				
			||||||
        ctx.add_texture_loader(Arc::new(VramTextureLoader::new(loader)));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn show(&mut self, ctx: &Context) {
 | 
					    fn show(&mut self, ctx: &Context) {
 | 
				
			||||||
 | 
					        self.loader.begin_pass();
 | 
				
			||||||
        CentralPanel::default().show(ctx, |ui| {
 | 
					        CentralPanel::default().show(ctx, |ui| {
 | 
				
			||||||
            ui.horizontal_top(|ui| {
 | 
					            ui.horizontal_top(|ui| {
 | 
				
			||||||
                StripBuilder::new(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 {
 | 
					enum CharDataResource {
 | 
				
			||||||
    Character { palette: VramPalette, index: usize },
 | 
					    Character { palette: VramPalette, index: usize },
 | 
				
			||||||
    CharacterData { palette: VramPalette },
 | 
					    CharacterData { palette: VramPalette },
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue