diff options
| author | 2020-01-13 15:33:12 +0100 | |
|---|---|---|
| committer | 2020-02-25 13:26:50 +0100 | |
| commit | 2f77a6bf5ac1b657c1f54ea0b589b1e115b95e6b (patch) | |
| tree | 36ac71c22c829ce18c7197870943c9b9b8842d67 /wgpu/src/image | |
| parent | 8562a4c986ff48d478be794c8c4268047a9a57d7 (diff) | |
| download | iced-2f77a6bf5ac1b657c1f54ea0b589b1e115b95e6b.tar.gz iced-2f77a6bf5ac1b657c1f54ea0b589b1e115b95e6b.tar.bz2 iced-2f77a6bf5ac1b657c1f54ea0b589b1e115b95e6b.zip  | |
Use array of atlases instead of one growing indefinitely.
Diffstat (limited to 'wgpu/src/image')
| -rw-r--r-- | wgpu/src/image/raster.rs | 129 | ||||
| -rw-r--r-- | wgpu/src/image/vector.rs | 149 | 
2 files changed, 51 insertions, 227 deletions
diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index 33750cac..32afb749 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -1,17 +1,19 @@ +use crate::image::AtlasArray;  use iced_native::image;  use std::{      collections::{HashMap, HashSet},  }; -use guillotiere::{Allocation, AtlasAllocator, Size}; +use guillotiere::{Allocation, Size};  use debug_stub_derive::*;  #[derive(DebugStub)]  pub enum Memory {      Host(::image::ImageBuffer<::image::Bgra<u8>, Vec<u8>>), -    Device( +    Device { +        layer: u32,          #[debug_stub="ReplacementValue"] -        Allocation -    ), +        allocation: Allocation, +    },      NotFound,      Invalid,  } @@ -20,7 +22,7 @@ impl Memory {      pub fn dimensions(&self) -> (u32, u32) {          match self {              Memory::Host(image) => image.dimensions(), -            Memory::Device(allocation) => { +            Memory::Device { allocation, .. } => {                  let size = &allocation.rectangle.size();                  (size.width as u32, size.height as u32)              }, @@ -75,8 +77,7 @@ impl Cache {          handle: &image::Handle,          device: &wgpu::Device,          encoder: &mut wgpu::CommandEncoder, -        allocator: &mut AtlasAllocator, -        atlas: &mut wgpu::Texture, +        atlas_array: &mut AtlasArray,      ) -> &Memory {          let _ = self.load(handle); @@ -86,119 +87,29 @@ impl Cache {              let (width, height) = image.dimensions();              let size = Size::new(width as i32, height as i32); -            let old_atlas_size = allocator.size(); -            let allocation; +            let (layer, allocation) = atlas_array.allocate(size).unwrap_or_else(|| { +                atlas_array.grow(1, device, encoder); +                atlas_array.allocate(size).unwrap() +            }); -            loop { -                if let Some(a) = allocator.allocate(size) { -                    allocation = a; -                    break; -                } - -                allocator.grow(allocator.size() * 2); -            } +            let flat_samples = image.as_flat_samples(); +            let slice = flat_samples.as_slice(); -            let new_atlas_size = allocator.size(); - -            if new_atlas_size != old_atlas_size { -                let new_atlas = device.create_texture(&wgpu::TextureDescriptor { -                    size: wgpu::Extent3d { -                        width: new_atlas_size.width as u32, -                        height: new_atlas_size.height as u32, -                        depth: 1, -                    }, -                    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::COPY_SRC -                        | wgpu::TextureUsage::SAMPLED, -                }); - -                encoder.copy_texture_to_texture( -                    wgpu::TextureCopyView { -                        texture: atlas, -                        array_layer: 0, -                        mip_level: 0, -                        origin: wgpu::Origin3d { -                            x: 0.0, -                            y: 0.0, -                            z: 0.0, -                        }, -                    }, -                    wgpu::TextureCopyView { -                        texture: &new_atlas, -                        array_layer: 0, -                        mip_level: 0, -                        origin: wgpu::Origin3d { -                            x: 0.0, -                            y: 0.0, -                            z: 0.0, -                        }, -                    }, -                    wgpu::Extent3d { -                        width: old_atlas_size.width as u32, -                        height: old_atlas_size.height as u32, -                        depth: 1, -                    } -                ); - -                *atlas = new_atlas; -            } +            atlas_array.upload(slice, layer, &allocation, device, encoder); -            let extent = wgpu::Extent3d { -                width, -                height, -                depth: 1, -            }; - -            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, -                    image_height: height, -                }, -                wgpu::TextureCopyView { -                    texture: atlas, -                    array_layer: 0, -                    mip_level: 0, -                    origin: wgpu::Origin3d { -                        x: allocation.rectangle.min.x as f32, -                        y: allocation.rectangle.min.y as f32, -                        z: 0.0, -                    }, -                }, -                extent, -            ); - -            *memory = Memory::Device(allocation); +            *memory = Memory::Device { layer, allocation };          }          memory      } -    pub fn trim(&mut self, allocator: &mut AtlasAllocator) { +    pub fn trim(&mut self, atlas_array: &mut AtlasArray) {          let hits = &self.hits; -        for (id, mem) in &mut self.map { -            if let Memory::Device(allocation) = mem { +        for (id, mem) in &self.map { +            if let Memory::Device { layer, allocation } = mem {                  if !hits.contains(&id) { -                    allocator.deallocate(allocation.id); +                    atlas_array.deallocate(*layer, allocation);                  }              }          } diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 2afe7d92..2972bc4a 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -1,8 +1,9 @@ +use crate::image::AtlasArray;  use iced_native::svg;  use std::{      collections::{HashMap, HashSet},  }; -use guillotiere::{Allocation, AtlasAllocator, Size}; +use guillotiere::{Allocation, Size};  use debug_stub_derive::*;  #[derive(DebugStub)] @@ -31,7 +32,7 @@ impl Svg {  pub struct Cache {      svgs: HashMap<u64, Svg>,      #[debug_stub="ReplacementValue"] -    rasterized: HashMap<(u64, u32, u32), Allocation>, +    rasterized: HashMap<(u64, u32, u32), (u32, Allocation)>,      svg_hits: HashSet<u64>,      rasterized_hits: HashSet<(u64, u32, u32)>,  } @@ -69,9 +70,8 @@ impl Cache {          scale: f32,          device: &wgpu::Device,          encoder: &mut wgpu::CommandEncoder, -        allocator: &mut AtlasAllocator, -        atlas: &mut wgpu::Texture, -    ) -> Option<&Allocation> { +        atlas_array: &mut AtlasArray, +    ) -> Option<&(u32, Allocation)> {          let id = handle.id();          let (width, height) = ( @@ -99,127 +99,40 @@ impl Cache {                  }                  let size = Size::new(width as i32, height as i32); -                let old_atlas_size = allocator.size(); -                let allocation; -                loop { -                    if let Some(a) = allocator.allocate(size) { -                        allocation = a; -                        break; -                    } - -                    allocator.grow(allocator.size() * 2); -                } - -                let new_atlas_size = allocator.size(); - -                if new_atlas_size != old_atlas_size { -                    let new_atlas = device.create_texture(&wgpu::TextureDescriptor { -                        size: wgpu::Extent3d { -                            width: new_atlas_size.width as u32, -                            height: new_atlas_size.height as u32, -                            depth: 1, -                        }, -                        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::COPY_SRC -                            | wgpu::TextureUsage::SAMPLED, -                    }); - -                    encoder.copy_texture_to_texture( -                        wgpu::TextureCopyView { -                            texture: atlas, -                            array_layer: 0, -                            mip_level: 0, -                            origin: wgpu::Origin3d { -                                x: 0.0, -                                y: 0.0, -                                z: 0.0, -                            }, -                        }, -                        wgpu::TextureCopyView { -                            texture: &new_atlas, -                            array_layer: 0, -                            mip_level: 0, -                            origin: wgpu::Origin3d { -                                x: 0.0, -                                y: 0.0, -                                z: 0.0, -                            }, -                        }, -                        wgpu::Extent3d { -                            width: old_atlas_size.width as u32, -                            height: old_atlas_size.height as u32, -                            depth: 1, -                        } -                    ); - -                    *atlas = new_atlas; -                } +                let (layer, allocation) = atlas_array.allocate(size).unwrap_or_else(|| { +                    atlas_array.grow(1, device, encoder); +                    atlas_array.allocate(size).unwrap() +                });                  // TODO: Optimize!                  // We currently rerasterize the SVG when its size changes. This is slow                  // as heck. A GPU rasterizer like `pathfinder` may perform better.                  // It would be cool to be able to smooth resize the `svg` example. -                let temp_buf = { -                    let screen_size = -                        resvg::ScreenSize::new(width, height).unwrap(); - -                    let mut canvas = resvg::raqote::DrawTarget::new( -                        width as i32, -                        height as i32, -                    ); - -                    resvg::backend_raqote::render_to_canvas( -                        tree, -                        &resvg::Options::default(), -                        screen_size, -                        &mut canvas, -                    ); - -                    let slice = canvas.get_data(); - -                    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: atlas, -                        array_layer: 0, -                        mip_level: 0, -                        origin: wgpu::Origin3d { -                            x: allocation.rectangle.min.x as f32, -                            y: allocation.rectangle.min.y as f32, -                            z: 0.0, -                        }, -                    }, -                    wgpu::Extent3d { -                        width, -                        height, -                        depth: 1, -                    }, +                let screen_size = +                    resvg::ScreenSize::new(width, height).unwrap(); + +                let mut canvas = resvg::raqote::DrawTarget::new( +                    width as i32, +                    height as i32,                  ); +                resvg::backend_raqote::render_to_canvas( +                    tree, +                    &resvg::Options::default(), +                    screen_size, +                    &mut canvas, +                ); + +                let slice = canvas.get_data(); + +                atlas_array.upload(slice, layer, &allocation, device, encoder); +                  let _ = self.svg_hits.insert(id);                  let _ = self.rasterized_hits.insert((id, width, height));                  let _ = self                      .rasterized -                    .insert((id, width, height), allocation); +                    .insert((id, width, height), (layer, allocation));                  self.rasterized.get(&(id, width, height))              } @@ -227,13 +140,13 @@ impl Cache {          }      } -    pub fn trim(&mut self, allocator: &mut AtlasAllocator) { +    pub fn trim(&mut self, atlas_array: &mut AtlasArray) {          let svg_hits = &self.svg_hits;          let rasterized_hits = &self.rasterized_hits; -        for (k, alloc) in &mut self.rasterized { -            if !rasterized_hits.contains(&k) { -                allocator.deallocate(alloc.id); +        for (k, (layer, allocation)) in &self.rasterized { +            if !rasterized_hits.contains(k) { +                atlas_array.deallocate(*layer, allocation);              }          }  | 
