diff options
Diffstat (limited to 'wgpu/src/image/raster.rs')
-rw-r--r-- | wgpu/src/image/raster.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs new file mode 100644 index 00000000..4f69df8c --- /dev/null +++ b/wgpu/src/image/raster.rs @@ -0,0 +1,134 @@ +use crate::image::atlas::{self, Atlas}; +use iced_native::image; +use std::collections::{HashMap, HashSet}; + +#[derive(Debug)] +pub enum Memory { + Host(::image::ImageBuffer<::image::Bgra<u8>, Vec<u8>>), + Device(atlas::Entry), + NotFound, + Invalid, +} + +impl Memory { + pub fn dimensions(&self) -> (u32, u32) { + match self { + Memory::Host(image) => image.dimensions(), + Memory::Device(entry) => entry.size(), + Memory::NotFound => (1, 1), + Memory::Invalid => (1, 1), + } + } +} + +#[derive(Debug)] +pub struct Cache { + map: HashMap<u64, Memory>, + hits: HashSet<u64>, +} + +impl Cache { + pub fn new() -> Self { + Self { + map: HashMap::new(), + hits: HashSet::new(), + } + } + + pub fn load(&mut self, handle: &image::Handle) -> &mut Memory { + if self.contains(handle) { + return self.get(handle).unwrap(); + } + + let memory = match handle.data() { + image::Data::Path(path) => { + if let Ok(image) = ::image::open(path) { + Memory::Host(image.to_bgra()) + } else { + Memory::NotFound + } + } + image::Data::Bytes(bytes) => { + if let Ok(image) = ::image::load_from_memory(&bytes) { + Memory::Host(image.to_bgra()) + } else { + Memory::Invalid + } + } + image::Data::Pixels { + width, + height, + pixels, + } => { + if let Some(image) = ::image::ImageBuffer::from_vec( + *width, + *height, + pixels.to_vec(), + ) { + Memory::Host(image) + } else { + Memory::Invalid + } + } + }; + + self.insert(handle, memory); + self.get(handle).unwrap() + } + + pub fn upload( + &mut self, + handle: &image::Handle, + device: &wgpu::Device, + encoder: &mut wgpu::CommandEncoder, + atlas: &mut Atlas, + ) -> Option<&atlas::Entry> { + let memory = self.load(handle); + + if let Memory::Host(image) = memory { + let (width, height) = image.dimensions(); + + let entry = atlas.upload(width, height, &image, device, encoder)?; + + *memory = Memory::Device(entry); + } + + if let Memory::Device(allocation) = memory { + Some(allocation) + } else { + None + } + } + + pub fn trim(&mut self, atlas: &mut Atlas) { + let hits = &self.hits; + + self.map.retain(|k, memory| { + let retain = hits.contains(k); + + if !retain { + if let Memory::Device(entry) = memory { + atlas.remove(entry); + } + } + + retain + }); + + self.hits.clear(); + } + + fn get(&mut self, handle: &image::Handle) -> Option<&mut Memory> { + let _ = self.hits.insert(handle.id()); + + self.map.get_mut(&handle.id()) + } + + fn insert(&mut self, handle: &image::Handle, memory: Memory) { + let _ = self.map.insert(handle.id(), memory); + } + + fn contains(&self, handle: &image::Handle) -> bool { + self.map.contains_key(&handle.id()) + } +} |