diff options
| -rw-r--r-- | wgpu/src/image.rs | 8 | ||||
| -rw-r--r-- | wgpu/src/image/raster.rs | 15 | ||||
| -rw-r--r-- | wgpu/src/image/vector.rs | 12 | ||||
| -rw-r--r-- | wgpu/src/texture/atlas.rs | 38 | ||||
| -rw-r--r-- | wgpu/src/texture/atlas/allocator.rs | 57 | 
5 files changed, 84 insertions, 46 deletions
diff --git a/wgpu/src/image.rs b/wgpu/src/image.rs index 1ffa50d2..7155b540 100644 --- a/wgpu/src/image.rs +++ b/wgpu/src/image.rs @@ -415,10 +415,10 @@ impl Pipeline {      pub fn trim_cache(&mut self) {          #[cfg(feature = "image")] -        self.raster_cache.borrow_mut().trim(); +        self.raster_cache.borrow_mut().trim(&mut self.texture_atlas);          #[cfg(feature = "svg")] -        self.vector_cache.borrow_mut().trim(); +        self.vector_cache.borrow_mut().trim(&mut self.texture_atlas);      }  } @@ -531,8 +531,8 @@ fn add_instance(              (y as f32 + 0.5) / atlas::SIZE as f32,          ],          _size_in_atlas: [ -            (width as f32 - 0.5) / atlas::SIZE as f32, -            (height as f32 - 0.5) / atlas::SIZE as f32, +            (width as f32 - 1.0) / atlas::SIZE as f32, +            (height as f32 - 1.0) / atlas::SIZE as f32,          ],          _layer: layer as u32,      }; diff --git a/wgpu/src/image/raster.rs b/wgpu/src/image/raster.rs index b19da582..cae8e065 100644 --- a/wgpu/src/image/raster.rs +++ b/wgpu/src/image/raster.rs @@ -95,10 +95,21 @@ impl Cache {          }      } -    pub fn trim(&mut self) { +    pub fn trim(&mut self, atlas: &mut Atlas) {          let hits = &self.hits; -        self.map.retain(|k, _| hits.contains(k)); +        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();      } diff --git a/wgpu/src/image/vector.rs b/wgpu/src/image/vector.rs index 0dabc9ca..e7eb4906 100644 --- a/wgpu/src/image/vector.rs +++ b/wgpu/src/image/vector.rs @@ -130,12 +130,20 @@ impl Cache {          }      } -    pub fn trim(&mut self) { +    pub fn trim(&mut self, atlas: &mut Atlas) {          let svg_hits = &self.svg_hits;          let rasterized_hits = &self.rasterized_hits;          self.svgs.retain(|k, _| svg_hits.contains(k)); -        self.rasterized.retain(|k, _| rasterized_hits.contains(k)); +        self.rasterized.retain(|k, entry| { +            let retain = rasterized_hits.contains(k); + +            if !retain { +                atlas.remove(entry); +            } + +            retain +        });          self.svg_hits.clear();          self.rasterized_hits.clear();      } diff --git a/wgpu/src/texture/atlas.rs b/wgpu/src/texture/atlas.rs index 3d4e81c1..a76c035b 100644 --- a/wgpu/src/texture/atlas.rs +++ b/wgpu/src/texture/atlas.rs @@ -112,11 +112,47 @@ impl Atlas {              }          } -        log::info!("Current atlas: {:?}", &self); +        log::info!("Current atlas: {:?}", self);          Some(entry)      } +    pub fn remove(&mut self, entry: &Entry) { +        log::info!("Removing atlas entry: {:?}", entry); + +        match entry { +            Entry::Contiguous(allocation) => { +                self.deallocate(allocation); +            } +            Entry::Fragmented { fragments, .. } => { +                for fragment in fragments { +                    self.deallocate(&fragment.allocation); +                } +            } +        } +    } + +    fn deallocate(&mut self, allocation: &Allocation) { +        log::info!("Deallocating atlas: {:?}", allocation); + +        match allocation { +            Allocation::Full { layer } => { +                self.layers[*layer] = Layer::Empty; +            } +            Allocation::Partial { layer, region } => { +                let layer = &mut self.layers[*layer]; + +                if let Layer::Busy(allocator) = layer { +                    allocator.deallocate(region); + +                    if allocator.is_empty() { +                        *layer = Layer::Empty; +                    } +                } +            } +        } +    } +      fn allocate(&mut self, width: u32, height: u32) -> Option<Entry> {          // Allocate one layer if texture fits perfectly          if width == SIZE && height == SIZE { diff --git a/wgpu/src/texture/atlas/allocator.rs b/wgpu/src/texture/atlas/allocator.rs index ad111212..7a4ff5b1 100644 --- a/wgpu/src/texture/atlas/allocator.rs +++ b/wgpu/src/texture/atlas/allocator.rs @@ -2,70 +2,54 @@ use guillotiere::{AtlasAllocator, Size};  pub struct Allocator {      raw: AtlasAllocator, -    size: u32, +    allocations: usize,  }  impl Allocator { -    const PADDING: u32 = 1; -      pub fn new(size: u32) -> Allocator {          let raw = AtlasAllocator::new(Size::new(size as i32, size as i32)); -        Allocator { raw, size } +        Allocator { +            raw, +            allocations: 0, +        }      }      pub fn allocate(&mut self, width: u32, height: u32) -> Option<Region> { -        let padding = ( -            if width + Self::PADDING * 2 < self.size { -                Self::PADDING -            } else { -                0 -            }, -            if height + Self::PADDING * 2 < self.size { -                Self::PADDING -            } else { -                0 -            }, -        ); - -        let allocation = self.raw.allocate(Size::new( -            (width + padding.0 * 2) as i32, -            (height + padding.1 * 2) as i32, -        ))?; - -        Some(Region { -            allocation, -            padding, -        }) +        let allocation = +            self.raw.allocate(Size::new(width as i32, height as i32))?; + +        self.allocations += 1; + +        Some(Region { allocation })      } -    pub fn deallocate(&mut self, region: Region) { +    pub fn deallocate(&mut self, region: &Region) {          self.raw.deallocate(region.allocation.id); + +        self.allocations = self.allocations.saturating_sub(1); +    } + +    pub fn is_empty(&self) -> bool { +        self.allocations == 0      }  }  pub struct Region {      allocation: guillotiere::Allocation, -    padding: (u32, u32),  }  impl Region {      pub fn position(&self) -> (u32, u32) {          let rectangle = &self.allocation.rectangle; -        ( -            rectangle.min.x as u32 + self.padding.0, -            rectangle.min.y as u32 + self.padding.1, -        ) +        (rectangle.min.x as u32, rectangle.min.y as u32)      }      pub fn size(&self) -> (u32, u32) {          let size = self.allocation.rectangle.size(); -        ( -            size.width as u32 - self.padding.0 * 2, -            size.height as u32 - self.padding.1 * 2, -        ) +        (size.width as u32, size.height as u32)      }  } @@ -80,7 +64,6 @@ impl std::fmt::Debug for Region {          f.debug_struct("Region")              .field("id", &self.allocation.id)              .field("rectangle", &self.allocation.rectangle) -            .field("padding", &self.padding)              .finish()      }  }  | 
