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() } } |