iced_wgpu/image/
raster.rs1use crate::core::Size;
2use crate::core::image;
3use crate::graphics;
4use crate::image::atlas::{self, Atlas};
5
6use rustc_hash::{FxHashMap, FxHashSet};
7use std::sync::{Arc, Weak};
8
9pub type Image = graphics::image::Buffer;
10
11#[derive(Debug)]
13pub enum Memory {
14 Host(Image),
16 Device {
18 entry: atlas::Entry,
19 bind_group: Option<Arc<wgpu::BindGroup>>,
20 allocation: Option<Weak<image::Memory>>,
21 },
22 Error(image::Error),
23}
24
25impl Memory {
26 pub fn load(handle: &image::Handle) -> Self {
27 match graphics::image::load(handle) {
28 Ok(image) => Self::Host(image),
29 Err(error) => Self::Error(error),
30 }
31 }
32
33 pub fn dimensions(&self) -> Size<u32> {
34 match self {
35 Memory::Host(image) => {
36 let (width, height) = image.dimensions();
37
38 Size::new(width, height)
39 }
40 Memory::Device { entry, .. } => entry.size(),
41 Memory::Error(_) => Size::new(1, 1),
42 }
43 }
44
45 pub fn host(&self) -> Option<Image> {
46 match self {
47 Memory::Host(image) => Some(image.clone()),
48 Memory::Device { .. } | Memory::Error(_) => None,
49 }
50 }
51}
52
53#[derive(Debug, Default)]
54pub struct Cache {
55 map: FxHashMap<image::Id, Memory>,
56 hits: FxHashSet<image::Id>,
57 should_trim: bool,
58}
59
60impl Cache {
61 pub fn get_mut(&mut self, handle: &image::Handle) -> Option<&mut Memory> {
62 let _ = self.hits.insert(handle.id());
63
64 self.map.get_mut(&handle.id())
65 }
66
67 pub fn insert(&mut self, handle: &image::Handle, memory: Memory) {
68 let _ = self.map.insert(handle.id(), memory);
69 let _ = self.hits.insert(handle.id());
70
71 self.should_trim = true;
72 }
73
74 pub fn contains(&self, handle: &image::Handle) -> bool {
75 self.map.contains_key(&handle.id())
76 }
77
78 pub fn trim(&mut self, atlas: &mut Atlas, on_drop: impl Fn(Arc<wgpu::BindGroup>)) {
79 if !self.should_trim {
81 return;
82 }
83
84 let hits = &self.hits;
85
86 self.map.retain(|id, memory| {
87 if let Memory::Device { allocation, .. } = memory
89 && allocation
90 .as_ref()
91 .is_some_and(|allocation| allocation.strong_count() > 0)
92 {
93 return true;
94 }
95
96 let retain = hits.contains(id);
97
98 if !retain {
99 log::debug!("Dropping image allocation: {id:?}");
100
101 if let Memory::Device {
102 entry, bind_group, ..
103 } = memory
104 {
105 if let Some(bind_group) = bind_group.take() {
106 on_drop(bind_group);
107 } else {
108 atlas.remove(entry);
109 }
110 }
111 }
112
113 retain
114 });
115
116 self.hits.clear();
117 self.should_trim = false;
118 }
119}