diff options
author | 2024-04-30 07:57:54 +0200 | |
---|---|---|
committer | 2024-04-30 07:57:54 +0200 | |
commit | b5b78d505e22cafccb4ecbf57dc61f536ca558ca (patch) | |
tree | 2563da1f3038607a329088ac3f7e460ca3d772fd /wgpu | |
parent | 24501fd73b5ae884367a2d112ff44625058b876b (diff) | |
download | iced-b5b78d505e22cafccb4ecbf57dc61f536ca558ca.tar.gz iced-b5b78d505e22cafccb4ecbf57dc61f536ca558ca.tar.bz2 iced-b5b78d505e22cafccb4ecbf57dc61f536ca558ca.zip |
Introduce `canvas::Cache` grouping
Caches with the same `Group` will share their text
atlas!
Diffstat (limited to 'wgpu')
-rw-r--r-- | wgpu/src/geometry.rs | 13 | ||||
-rw-r--r-- | wgpu/src/text.rs | 74 |
2 files changed, 65 insertions, 22 deletions
diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs index 60967082..f6213e1d 100644 --- a/wgpu/src/geometry.rs +++ b/wgpu/src/geometry.rs @@ -3,6 +3,7 @@ use crate::core::text::LineHeight; use crate::core::{ Pixels, Point, Radians, Rectangle, Size, Transformation, Vector, }; +use crate::graphics::cache::{self, Cached}; use crate::graphics::color; use crate::graphics::geometry::fill::{self, Fill}; use crate::graphics::geometry::{ @@ -10,7 +11,7 @@ use crate::graphics::geometry::{ }; use crate::graphics::gradient::{self, Gradient}; use crate::graphics::mesh::{self, Mesh}; -use crate::graphics::{self, Cached, Text}; +use crate::graphics::{self, Text}; use crate::text; use crate::triangle; @@ -38,7 +39,11 @@ impl Cached for Geometry { Geometry::Cached(cache.clone()) } - fn cache(self, previous: Option<Self::Cache>) -> Self::Cache { + fn cache( + self, + group: cache::Group, + previous: Option<Self::Cache>, + ) -> Self::Cache { match self { Self::Live { meshes, text } => { if let Some(mut previous) = previous { @@ -51,14 +56,14 @@ impl Cached for Geometry { if let Some(cache) = &mut previous.text { cache.update(text); } else { - previous.text = text::Cache::new(text); + previous.text = text::Cache::new(group, text); } previous } else { Cache { meshes: triangle::Cache::new(meshes), - text: text::Cache::new(text), + text: text::Cache::new(group, text), } } } diff --git a/wgpu/src/text.rs b/wgpu/src/text.rs index 38712660..5806863c 100644 --- a/wgpu/src/text.rs +++ b/wgpu/src/text.rs @@ -1,7 +1,8 @@ use crate::core::alignment; use crate::core::{Rectangle, Size, Transformation}; +use crate::graphics::cache; use crate::graphics::color; -use crate::graphics::text::cache::{self, Cache as BufferCache}; +use crate::graphics::text::cache::{self as text_cache, Cache as BufferCache}; use crate::graphics::text::{font_system, to_color, Editor, Paragraph}; use rustc_hash::FxHashMap; @@ -35,6 +36,7 @@ pub enum Item { #[derive(Debug, Clone)] pub struct Cache { id: Id, + group: cache::Group, text: Rc<[Text]>, version: usize, } @@ -43,7 +45,7 @@ pub struct Cache { pub struct Id(u64); impl Cache { - pub fn new(text: Vec<Text>) -> Option<Self> { + pub fn new(group: cache::Group, text: Vec<Text>) -> Option<Self> { static NEXT_ID: AtomicU64 = AtomicU64::new(0); if text.is_empty() { @@ -52,6 +54,7 @@ impl Cache { Some(Self { id: Id(NEXT_ID.fetch_add(1, atomic::Ordering::Relaxed)), + group, text: Rc::from(text), version: 0, }) @@ -65,29 +68,39 @@ impl Cache { struct Upload { renderer: glyphon::TextRenderer, - atlas: glyphon::TextAtlas, buffer_cache: BufferCache, transformation: Transformation, version: usize, text: rc::Weak<[Text]>, + _atlas: rc::Weak<()>, } #[derive(Default)] pub struct Storage { + groups: FxHashMap<cache::Group, Group>, uploads: FxHashMap<Id, Upload>, } +struct Group { + atlas: glyphon::TextAtlas, + previous_uploads: usize, + handle: Rc<()>, +} + impl Storage { pub fn new() -> Self { Self::default() } - fn get(&self, cache: &Cache) -> Option<&Upload> { + fn get(&self, cache: &Cache) -> Option<(&glyphon::TextAtlas, &Upload)> { if cache.text.is_empty() { return None; } - self.uploads.get(&cache.id) + self.groups + .get(&cache.group) + .map(|group| &group.atlas) + .zip(self.uploads.get(&cache.id)) } fn prepare( @@ -101,6 +114,20 @@ impl Storage { bounds: Rectangle, target_size: Size<u32>, ) { + let group_count = self.groups.len(); + + let group = self.groups.entry(cache.group).or_insert_with(|| { + log::info!("New text atlas created (total: {})", group_count + 1); + + Group { + atlas: glyphon::TextAtlas::with_color_mode( + device, queue, format, COLOR_MODE, + ), + previous_uploads: 0, + handle: Rc::new(()), + } + }); + match self.uploads.entry(cache.id) { hash_map::Entry::Occupied(entry) => { let upload = entry.into_mut(); @@ -114,7 +141,7 @@ impl Storage { queue, encoder, &mut upload.renderer, - &mut upload.atlas, + &mut group.atlas, &mut upload.buffer_cache, &cache.text, bounds, @@ -127,16 +154,11 @@ impl Storage { upload.transformation = new_transformation; upload.buffer_cache.trim(); - upload.atlas.trim(); } } hash_map::Entry::Vacant(entry) => { - let mut atlas = glyphon::TextAtlas::with_color_mode( - device, queue, format, COLOR_MODE, - ); - let mut renderer = glyphon::TextRenderer::new( - &mut atlas, + &mut group.atlas, device, wgpu::MultisampleState::default(), None, @@ -149,7 +171,7 @@ impl Storage { queue, encoder, &mut renderer, - &mut atlas, + &mut group.atlas, &mut buffer_cache, &cache.text, bounds, @@ -159,11 +181,11 @@ impl Storage { let _ = entry.insert(Upload { renderer, - atlas, buffer_cache, transformation: new_transformation, version: 0, text: Rc::downgrade(&cache.text), + _atlas: Rc::downgrade(&group.handle), }); log::info!( @@ -178,6 +200,22 @@ impl Storage { pub fn trim(&mut self) { self.uploads .retain(|_id, upload| upload.text.strong_count() > 0); + + self.groups.retain(|_id, group| { + let uploads_alive = Rc::weak_count(&group.handle); + + if uploads_alive == 0 { + return false; + } + + if uploads_alive < group.previous_uploads { + group.atlas.trim(); + } + + group.previous_uploads = uploads_alive; + + true + }); } } @@ -306,10 +344,10 @@ impl Pipeline { layer_count += 1; } Item::Cached { cache, .. } => { - if let Some(upload) = storage.get(cache) { + if let Some((atlas, upload)) = storage.get(cache) { upload .renderer - .render(&upload.atlas, render_pass) + .render(atlas, render_pass) .expect("Render cached text"); } } @@ -345,7 +383,7 @@ fn prepare( enum Allocation { Paragraph(Paragraph), Editor(Editor), - Cache(cache::KeyHash), + Cache(text_cache::KeyHash), Raw(Arc<glyphon::Buffer>), } @@ -369,7 +407,7 @@ fn prepare( } => { let (key, _) = buffer_cache.allocate( font_system, - cache::Key { + text_cache::Key { content, size: f32::from(*size), line_height: f32::from(*line_height), |