diff options
| author | 2019-12-15 06:19:07 +0100 | |
|---|---|---|
| committer | 2019-12-15 06:19:07 +0100 | |
| commit | 09707f29fcf7fbd71570a43db214921043427c3f (patch) | |
| tree | b3e045a64e81f58910c976b0478e6f7f91780ad0 /wgpu/src/image/raster.rs | |
| parent | 27717bc70c3947f553a8b75da9789fe967994a31 (diff) | |
| download | iced-09707f29fcf7fbd71570a43db214921043427c3f.tar.gz iced-09707f29fcf7fbd71570a43db214921043427c3f.tar.bz2 iced-09707f29fcf7fbd71570a43db214921043427c3f.zip | |
Rerasterize SVGs when resized and refactor a bit
Diffstat (limited to 'wgpu/src/image/raster.rs')
| -rw-r--r-- | wgpu/src/image/raster.rs | 176 | 
1 files changed, 176 insertions, 0 deletions
| diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs new file mode 100644 index 00000000..fa107879 --- /dev/null +++ b/wgpu/src/image/raster.rs @@ -0,0 +1,176 @@ +use iced_native::image; +use std::{ +    collections::{HashMap, HashSet}, +    rc::Rc, +}; + +#[derive(Debug)] +pub enum Memory { +    Host(::image::ImageBuffer<::image::Bgra<u8>, Vec<u8>>), +    Device { +        bind_group: Rc<wgpu::BindGroup>, +        width: u32, +        height: u32, +    }, +    NotFound, +    Invalid, +} + +impl Memory { +    pub fn dimensions(&self) -> (u32, u32) { +        match self { +            Memory::Host(image) => image.dimensions(), +            Memory::Device { width, height, .. } => (*width, *height), +            Memory::NotFound => (1, 1), +            Memory::Invalid => (1, 1), +        } +    } + +    pub fn upload( +        &mut self, +        device: &wgpu::Device, +        encoder: &mut wgpu::CommandEncoder, +        texture_layout: &wgpu::BindGroupLayout, +    ) -> Option<Rc<wgpu::BindGroup>> { +        match self { +            Memory::Host(image) => { +                let (width, height) = image.dimensions(); + +                let extent = wgpu::Extent3d { +                    width, +                    height, +                    depth: 1, +                }; + +                let texture = device.create_texture(&wgpu::TextureDescriptor { +                    size: extent, +                    array_layer_count: 1, +                    mip_level_count: 1, +                    sample_count: 1, +                    dimension: wgpu::TextureDimension::D2, +                    format: wgpu::TextureFormat::Bgra8UnormSrgb, +                    usage: wgpu::TextureUsage::COPY_DST +                        | wgpu::TextureUsage::SAMPLED, +                }); + +                let temp_buf = { +                    let flat_samples = image.as_flat_samples(); +                    let slice = flat_samples.as_slice(); + +                    device +                        .create_buffer_mapped( +                            slice.len(), +                            wgpu::BufferUsage::COPY_SRC, +                        ) +                        .fill_from_slice(slice) +                }; + +                encoder.copy_buffer_to_texture( +                    wgpu::BufferCopyView { +                        buffer: &temp_buf, +                        offset: 0, +                        row_pitch: 4 * width as u32, +                        image_height: height as u32, +                    }, +                    wgpu::TextureCopyView { +                        texture: &texture, +                        array_layer: 0, +                        mip_level: 0, +                        origin: wgpu::Origin3d { +                            x: 0.0, +                            y: 0.0, +                            z: 0.0, +                        }, +                    }, +                    extent, +                ); + +                let bind_group = +                    device.create_bind_group(&wgpu::BindGroupDescriptor { +                        layout: texture_layout, +                        bindings: &[wgpu::Binding { +                            binding: 0, +                            resource: wgpu::BindingResource::TextureView( +                                &texture.create_default_view(), +                            ), +                        }], +                    }); + +                let bind_group = Rc::new(bind_group); + +                *self = Memory::Device { +                    bind_group: bind_group.clone(), +                    width, +                    height, +                }; + +                Some(bind_group) +            } +            Memory::Device { bind_group, .. } => Some(bind_group.clone()), +            Memory::NotFound => None, +            Memory::Invalid => None, +        } +    } +} + +#[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 +                } +            } +        }; + +        self.insert(handle, memory); +        self.get(handle).unwrap() +    } + +    pub fn trim(&mut self) { +        let hits = &self.hits; + +        self.map.retain(|k, _| hits.contains(k)); +        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()) +    } +} | 
