iced_wgpu/image/
raster.rs

1use crate::core::Size;
2use crate::core::image;
3use crate::graphics;
4use crate::graphics::image::image_rs;
5use crate::image::atlas::{self, Atlas};
6
7use rustc_hash::{FxHashMap, FxHashSet};
8
9/// Entry in cache corresponding to an image handle
10#[derive(Debug)]
11pub enum Memory {
12    /// Image data on host
13    Host(image_rs::ImageBuffer<image_rs::Rgba<u8>, image::Bytes>),
14    /// Storage entry
15    Device(atlas::Entry),
16    /// Image not found
17    NotFound,
18    /// Invalid image data
19    Invalid,
20}
21
22impl Memory {
23    /// Width and height of image
24    pub fn dimensions(&self) -> Size<u32> {
25        match self {
26            Memory::Host(image) => {
27                let (width, height) = image.dimensions();
28
29                Size::new(width, height)
30            }
31            Memory::Device(entry) => entry.size(),
32            Memory::NotFound => Size::new(1, 1),
33            Memory::Invalid => Size::new(1, 1),
34        }
35    }
36}
37
38/// Caches image raster data
39#[derive(Debug, Default)]
40pub struct Cache {
41    map: FxHashMap<image::Id, Memory>,
42    hits: FxHashSet<image::Id>,
43    should_trim: bool,
44}
45
46impl Cache {
47    /// Load image
48    pub fn load(&mut self, handle: &image::Handle) -> &mut Memory {
49        if self.contains(handle) {
50            return self.get(handle).unwrap();
51        }
52
53        let memory = match graphics::image::load(handle) {
54            Ok(image) => Memory::Host(image),
55            Err(image_rs::error::ImageError::IoError(_)) => Memory::NotFound,
56            Err(_) => Memory::Invalid,
57        };
58
59        self.should_trim = true;
60
61        self.insert(handle, memory);
62        self.get(handle).unwrap()
63    }
64
65    /// Load image and upload raster data
66    pub fn upload(
67        &mut self,
68        device: &wgpu::Device,
69        encoder: &mut wgpu::CommandEncoder,
70        handle: &image::Handle,
71        atlas: &mut Atlas,
72    ) -> Option<&atlas::Entry> {
73        let memory = self.load(handle);
74
75        if let Memory::Host(image) = memory {
76            let (width, height) = image.dimensions();
77
78            let entry = atlas.upload(device, encoder, width, height, image)?;
79
80            *memory = Memory::Device(entry);
81        }
82
83        if let Memory::Device(allocation) = memory {
84            Some(allocation)
85        } else {
86            None
87        }
88    }
89
90    /// Trim cache misses from cache
91    pub fn trim(&mut self, atlas: &mut Atlas) {
92        // Only trim if new entries have landed in the `Cache`
93        if !self.should_trim {
94            return;
95        }
96
97        let hits = &self.hits;
98
99        self.map.retain(|k, memory| {
100            let retain = hits.contains(k);
101
102            if !retain {
103                if let Memory::Device(entry) = memory {
104                    atlas.remove(entry);
105                }
106            }
107
108            retain
109        });
110
111        self.hits.clear();
112        self.should_trim = false;
113    }
114
115    fn get(&mut self, handle: &image::Handle) -> Option<&mut Memory> {
116        let _ = self.hits.insert(handle.id());
117
118        self.map.get_mut(&handle.id())
119    }
120
121    fn insert(&mut self, handle: &image::Handle, memory: Memory) {
122        let _ = self.map.insert(handle.id(), memory);
123    }
124
125    fn contains(&self, handle: &image::Handle) -> bool {
126        self.map.contains_key(&handle.id())
127    }
128}