summaryrefslogtreecommitdiffstats
path: root/wgpu/src/image/raster.rs
diff options
context:
space:
mode:
Diffstat (limited to 'wgpu/src/image/raster.rs')
-rw-r--r--wgpu/src/image/raster.rs134
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())
+ }
+}