From fdeda0d0ed5441da289f1827cb54d656b3224e05 Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Fri, 20 Nov 2020 17:41:29 +0100 Subject: [PATCH] Add some basic image loading caching for images loaded from the file system Place them in a HashMap that's indexed by the path. This needs further tuning, for example to also be applied to embedded images, and the cache shouldn't hold a strong reference. But it makes the berlin page playable. --- sixtyfps_runtime/rendering_backends/gl/lib.rs | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/sixtyfps_runtime/rendering_backends/gl/lib.rs b/sixtyfps_runtime/rendering_backends/gl/lib.rs index 1cf72c988..cfa59cd37 100644 --- a/sixtyfps_runtime/rendering_backends/gl/lib.rs +++ b/sixtyfps_runtime/rendering_backends/gl/lib.rs @@ -24,7 +24,7 @@ use sixtyfps_corelib::{ SharedArray, }; use smallvec::{smallvec, SmallVec}; -use std::cell::RefCell; +use std::{cell::RefCell, collections::HashMap}; extern crate alloc; use alloc::rc::Rc; @@ -76,7 +76,7 @@ enum GLRenderingPrimitive { Texture { vertices: GLArrayBuffer, texture_vertices: GLArrayBuffer, - texture: texture::AtlasAllocation, + texture: Rc, }, #[cfg(target_arch = "wasm32")] DynamicPrimitive { @@ -102,6 +102,8 @@ struct NormalRectangle { indices: GLIndexBuffer, } +type TextureCacheKey = String; + pub struct GLRenderer { context: Rc, path_shader: PathShader, @@ -119,6 +121,7 @@ pub struct GLRenderer { #[cfg(not(target_arch = "wasm32"))] windowed_context: Option>, normal_rectangle: Option, + texture_cache: Rc>>>, } pub struct GLRenderingPrimitivesBuilder { @@ -136,6 +139,8 @@ pub struct GLRenderingPrimitivesBuilder { Rc>, #[cfg(not(target_arch = "wasm32"))] windowed_context: glutin::WindowedContext, + + texture_cache: Rc>>>, } pub struct GLFrame { @@ -272,6 +277,7 @@ impl GLRenderer { #[cfg(not(target_arch = "wasm32"))] windowed_context: Some(unsafe { windowed_context.make_not_current().unwrap() }), normal_rectangle: None, + texture_cache: Default::default(), } } } @@ -322,6 +328,8 @@ impl GraphicsBackend for GLRenderer { event_loop_proxy: self.event_loop_proxy.clone(), #[cfg(not(target_arch = "wasm32"))] windowed_context: current_windowed_context, + + texture_cache: self.texture_cache.clone(), } } @@ -420,17 +428,15 @@ impl RenderingPrimitivesBuilder for GLRenderingPrimitivesBuilder { let mut image_path = std::env::current_exe().unwrap(); image_path.pop(); // pop of executable name image_path.push(&*path.clone()); - let image = image::open(image_path.as_path()).unwrap().into_rgba(); - let image = image::ImageBuffer::, &[u8]>::from_raw( - image.width(), - image.height(), - &image, - ) - .unwrap(); - smallvec![GLRenderingPrimitivesBuilder::create_image( + + let atlas_allocation = self + .cached_texture(image_path.to_string_lossy().to_string(), || { + image::open(image_path.as_path()).unwrap().into_rgba() + }); + + smallvec![GLRenderingPrimitivesBuilder::create_texture( &self.context, - &mut *self.texture_atlas.borrow_mut(), - image, + atlas_allocation, source_clip_rect )] } @@ -634,16 +640,29 @@ impl GLRenderingPrimitivesBuilder { image: impl texture::UploadableAtlasImage, source_rect: &IntRect, ) -> GLRenderingPrimitive { - let rect = - Rect::new(Point::new(0.0, 0.0), Size::new(image.width() as f32, image.height() as f32)); + let atlas_allocation = atlas.allocate_image_in_atlas(&context, image); + + Self::create_texture(context, Rc::new(atlas_allocation), source_rect) + } + + fn create_texture( + context: &Rc, + atlas_allocation: Rc, + source_rect: &IntRect, + ) -> GLRenderingPrimitive { + let rect = Rect::new( + Point::new(0.0, 0.0), + Size::new( + atlas_allocation.texture_coordinates.width() as f32, + atlas_allocation.texture_coordinates.height() as f32, + ), + ); let vertex1 = Vertex { _pos: [rect.min_x(), rect.min_y()] }; let vertex2 = Vertex { _pos: [rect.max_x(), rect.min_y()] }; let vertex3 = Vertex { _pos: [rect.max_x(), rect.max_y()] }; let vertex4 = Vertex { _pos: [rect.min_x(), rect.max_y()] }; - let atlas_allocation = atlas.allocate_image_in_atlas(&context, image); - let vertices = GLArrayBuffer::new( &context, &vec![vertex1, vertex2, vertex3, vertex1, vertex3, vertex4], @@ -656,6 +675,24 @@ impl GLRenderingPrimitivesBuilder { GLRenderingPrimitive::Texture { vertices, texture_vertices, texture: atlas_allocation } } + fn cached_texture( + &self, + key: TextureCacheKey, + create_fn: impl Fn() -> Img, + ) -> Rc { + self.texture_cache + .borrow_mut() + .entry(key) + .or_insert_with(|| { + Rc::new( + self.texture_atlas + .borrow_mut() + .allocate_image_in_atlas(&self.context, create_fn()), + ) + }) + .clone() + } + #[cfg(not(target_arch = "wasm32"))] fn create_glyph_runs( &mut self,