Skip to content

Commit 74bfb0c

Browse files
committed
Implemented automatic deallocation of texture space for dropped allocations
1 parent b0722d3 commit 74bfb0c

3 files changed

Lines changed: 88 additions & 85 deletions

File tree

wgpu/src/image.rs

Lines changed: 86 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,7 @@ use crate::image::raster::Memory;
99
use crate::Transformation;
1010
use iced_native::{image, svg, Rectangle};
1111

12-
use std::mem;
13-
14-
#[cfg(any(feature = "image", feature = "svg"))]
15-
use std::cell::RefCell;
12+
use std::{cell::RefCell, mem, rc::Rc};
1613

1714
use guillotiere::{Allocation, AtlasAllocator, Size};
1815

@@ -377,10 +374,10 @@ impl Pipeline {
377374

378375
pub fn trim_cache(&mut self) {
379376
#[cfg(feature = "image")]
380-
self.raster_cache.borrow_mut().trim(&mut self.texture_array);
377+
self.raster_cache.borrow_mut().trim();
381378

382379
#[cfg(feature = "svg")]
383-
self.vector_cache.borrow_mut().trim(&mut self.texture_array);
380+
self.vector_cache.borrow_mut().trim();
384381
}
385382
}
386383

@@ -423,14 +420,14 @@ fn add_instance(
423420
let y = (allocation.position().1 as f32 + 0.5) / (ATLAS_SIZE as f32);
424421
let w = (allocation.size().0 as f32 - 0.5) / (ATLAS_SIZE as f32);
425422
let h = (allocation.size().1 as f32 - 0.5) / (ATLAS_SIZE as f32);
426-
let layer = allocation.layer() as f32;
423+
let layer_index = allocation.layer_index() as f32;
427424

428425
let instance = Instance {
429426
_position: position,
430427
_scale: scale,
431428
_position_in_atlas: [x, y],
432429
_scale_in_atlas: [w, h],
433-
_layer: layer,
430+
_layer: layer_index,
434431
};
435432

436433
instances.push(instance);
@@ -478,11 +475,13 @@ impl ImageAllocation {
478475

479476
pub enum ArrayAllocation {
480477
AtlasAllocation {
481-
layer: usize,
478+
layer_index: usize,
479+
layer: Rc<RefCell<TextureLayer>>,
482480
allocation: Allocation,
483481
},
484482
WholeLayer {
485-
layer: usize,
483+
layer_index: usize,
484+
layer: Rc<RefCell<TextureLayer>>,
486485
}
487486
}
488487

@@ -507,22 +506,45 @@ impl ArrayAllocation {
507506
}
508507
}
509508

510-
pub fn layer(&self) -> usize {
509+
pub fn layer_index(&self) -> usize {
511510
match self {
512-
ArrayAllocation::AtlasAllocation { layer, .. } => *layer,
513-
ArrayAllocation::WholeLayer { layer } => *layer,
511+
ArrayAllocation::AtlasAllocation { layer_index, .. } => *layer_index,
512+
ArrayAllocation::WholeLayer { layer_index, .. } => *layer_index,
514513
}
515514
}
516515
}
517516

518517
impl std::fmt::Debug for ArrayAllocation {
519518
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
520519
match self {
521-
ArrayAllocation::AtlasAllocation { layer, .. } => {
522-
write!(f, "ArrayAllocation::AtlasAllocation {{ layer: {} }}", layer)
520+
ArrayAllocation::AtlasAllocation { layer_index, .. } => {
521+
write!(f, "ArrayAllocation::AtlasAllocation {{ layer_index: {:} }}", layer_index)
523522
},
524-
ArrayAllocation::WholeLayer { layer } => {
525-
write!(f, "ArrayAllocation::WholeLayer {{ layer: {} }}", layer)
523+
ArrayAllocation::WholeLayer { layer_index, .. } => {
524+
write!(f, "ArrayAllocation::WholeLayer {{ layer_index: {} }}", layer_index)
525+
}
526+
}
527+
}
528+
}
529+
530+
impl Drop for ArrayAllocation {
531+
fn drop(&mut self) {
532+
match self {
533+
ArrayAllocation::WholeLayer { layer, .. } => {
534+
let _ = layer.replace(TextureLayer::Whole);
535+
}
536+
ArrayAllocation::AtlasAllocation { allocation, layer, .. } => {
537+
let mut layer = layer.borrow_mut();
538+
if let Some(allocator) = layer.allocator_mut() {
539+
allocator.deallocate(allocation.id);
540+
541+
let mut empty_allocator = true;
542+
allocator.for_each_allocated_rectangle(|_, _| empty_allocator = false);
543+
544+
if empty_allocator {
545+
*layer = TextureLayer::Empty;
546+
}
547+
}
526548
}
527549
}
528550
}
@@ -534,6 +556,23 @@ pub enum TextureLayer {
534556
Empty,
535557
}
536558

559+
impl TextureLayer {
560+
pub fn is_empty(&self) -> bool {
561+
if let TextureLayer::Empty = self {
562+
true
563+
} else {
564+
false
565+
}
566+
}
567+
568+
pub fn allocator_mut(&mut self) -> Option<&mut AtlasAllocator> {
569+
match self {
570+
TextureLayer::Atlas(allocator) => Some(allocator),
571+
_ => None
572+
}
573+
}
574+
}
575+
537576
impl std::fmt::Debug for TextureLayer {
538577
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
539578
match self {
@@ -544,11 +583,17 @@ impl std::fmt::Debug for TextureLayer {
544583
}
545584
}
546585

586+
impl From<AtlasAllocator> for TextureLayer {
587+
fn from(allocator: AtlasAllocator) -> Self {
588+
TextureLayer::Atlas(allocator)
589+
}
590+
}
591+
547592
#[derive(Debug)]
548593
pub struct TextureArray {
549594
texture: wgpu::Texture,
550595
texture_array_size: u32,
551-
layers: Vec<TextureLayer>,
596+
layers: Vec<Rc<RefCell<TextureLayer>>>,
552597
}
553598

554599
impl TextureArray {
@@ -576,26 +621,27 @@ impl TextureArray {
576621
TextureArray {
577622
texture,
578623
texture_array_size: 1,
579-
layers: vec!(TextureLayer::Empty),
624+
layers: vec!(Rc::new(RefCell::new(TextureLayer::Empty))),
580625
}
581626
}
582627

583628
fn allocate(&mut self, size: Size) -> Option<ImageAllocation> {
584629
// Allocate one layer if allocation fits perfectly
585630
if size.width == ATLAS_SIZE as i32 && size.height == ATLAS_SIZE as i32 {
586631
for (i, layer) in self.layers.iter_mut().enumerate() {
587-
if let TextureLayer::Empty = layer
632+
if layer.borrow().is_empty()
588633
{
589-
*layer = TextureLayer::Whole;
634+
let _ = layer.replace(TextureLayer::Whole);
590635
return Some(ImageAllocation::SingleAllocation(
591-
ArrayAllocation::WholeLayer { layer: i }
636+
ArrayAllocation::WholeLayer { layer: layer.clone(), layer_index: i }
592637
));
593638
}
594639
}
595640

596-
self.layers.push(TextureLayer::Whole);
641+
let layer = Rc::new(RefCell::new(TextureLayer::Whole));
642+
self.layers.push(layer.clone());
597643
return Some(ImageAllocation::SingleAllocation(
598-
ArrayAllocation::WholeLayer { layer: self.layers.len() - 1 }
644+
ArrayAllocation::WholeLayer { layer, layer_index: self.layers.len() - 1 }
599645
));
600646
}
601647

@@ -632,9 +678,13 @@ impl TextureArray {
632678

633679
// Try allocating on an existing layer
634680
for (i, layer) in self.layers.iter_mut().enumerate() {
635-
if let TextureLayer::Atlas(allocator) = layer {
681+
if let Some(allocator) = layer.borrow_mut().allocator_mut() {
636682
if let Some(allocation) = allocator.allocate(size.clone()) {
637-
let array_allocation = ArrayAllocation::AtlasAllocation { layer: i, allocation };
683+
let array_allocation = ArrayAllocation::AtlasAllocation {
684+
layer: layer.clone(),
685+
layer_index: i,
686+
allocation
687+
};
638688
return Some(ImageAllocation::SingleAllocation(array_allocation));
639689
}
640690
}
@@ -643,11 +693,13 @@ impl TextureArray {
643693
// Create new layer with atlas allocator
644694
let mut allocator = AtlasAllocator::new(Size::new(ATLAS_SIZE as i32, ATLAS_SIZE as i32));
645695
if let Some(allocation) = allocator.allocate(size) {
646-
self.layers.push(TextureLayer::Atlas(allocator));
696+
let layer = Rc::new(RefCell::new(allocator.into()));
697+
self.layers.push(layer.clone());
647698

648699
return Some(ImageAllocation::SingleAllocation(
649700
ArrayAllocation::AtlasAllocation {
650-
layer: self.layers.len() - 1,
701+
layer,
702+
layer_index: self.layers.len() - 1,
651703
allocation,
652704
}
653705
));
@@ -657,41 +709,6 @@ impl TextureArray {
657709
None
658710
}
659711

660-
fn deallocate(&mut self, allocation: &ImageAllocation) {
661-
match allocation {
662-
ImageAllocation::SingleAllocation(allocation) => {
663-
self.deallocate_single_allocation(allocation);
664-
}
665-
ImageAllocation::MultipleAllocations { mappings, .. } => {
666-
for mapping in mappings {
667-
self.deallocate_single_allocation(&mapping.allocation);
668-
}
669-
}
670-
}
671-
}
672-
673-
fn deallocate_single_allocation(&mut self, allocation: &ArrayAllocation) {
674-
if let Some(layer) = self.layers.get_mut(allocation.layer()) {
675-
match allocation {
676-
ArrayAllocation::WholeLayer { .. } => {
677-
*layer = TextureLayer::Empty;
678-
}
679-
ArrayAllocation::AtlasAllocation { allocation, .. } => {
680-
if let TextureLayer::Atlas(allocator) = layer {
681-
allocator.deallocate(allocation.id);
682-
683-
let mut empty_allocator = true;
684-
allocator.for_each_allocated_rectangle(|_, _| empty_allocator = false);
685-
686-
if empty_allocator {
687-
*layer = TextureLayer::Empty;
688-
}
689-
}
690-
}
691-
}
692-
}
693-
}
694-
695712
fn upload<C, I>(
696713
&mut self,
697714
image: &I,
@@ -715,7 +732,7 @@ impl TextureArray {
715732
)
716733
.fill_from_slice(data);
717734

718-
if allocation.layer() >= self.texture_array_size as usize {
735+
if allocation.layer_index() >= self.texture_array_size as usize {
719736
self.grow(1, device, encoder);
720737
}
721738

@@ -731,7 +748,7 @@ impl TextureArray {
731748

732749
let highest_layer = mappings
733750
.iter()
734-
.map(|m| m.allocation.layer() as u32)
751+
.map(|m| m.allocation.layer_index() as u32)
735752
.max()
736753
.unwrap_or(0);
737754

@@ -783,7 +800,7 @@ impl TextureArray {
783800
allocation: &ArrayAllocation,
784801
encoder: &mut wgpu::CommandEncoder,
785802
) {
786-
let array_layer = allocation.layer() as u32;
803+
let array_layer = allocation.layer_index() as u32;
787804

788805
let (width, height) = allocation.size();
789806

@@ -844,12 +861,12 @@ impl TextureArray {
844861
| wgpu::TextureUsage::SAMPLED,
845862
});
846863

847-
for (i, layer) in self.layers.iter().enumerate() {
864+
for (i, layer) in self.layers.iter_mut().enumerate() {
848865
if i >= old_texture_array_size as usize {
849866
break;
850867
}
851868

852-
if let TextureLayer::Empty = layer {
869+
if layer.borrow().is_empty() {
853870
continue;
854871
}
855872

@@ -952,7 +969,7 @@ const QUAD_VERTS: [Vertex; 4] = [
952969
},
953970
];
954971

955-
const ATLAS_SIZE: u32 = 256;
972+
const ATLAS_SIZE: u32 = 4096;
956973

957974
#[repr(C)]
958975
#[derive(Debug, Clone, Copy)]

wgpu/src/image/raster.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,17 +91,9 @@ impl Cache {
9191
memory
9292
}
9393

94-
pub fn trim(&mut self, texture_array: &mut TextureArray) {
94+
pub fn trim(&mut self) {
9595
let hits = &self.hits;
9696

97-
for (id, mem) in &self.map {
98-
if let Memory::Device(allocation) = mem {
99-
if !hits.contains(&id) {
100-
texture_array.deallocate(allocation);
101-
}
102-
}
103-
}
104-
10597
self.map.retain(|k, _| hits.contains(k));
10698
self.hits.clear();
10799
}

wgpu/src/image/vector.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,16 +130,10 @@ impl Cache {
130130
}
131131
}
132132

133-
pub fn trim(&mut self, texture_array: &mut TextureArray) {
133+
pub fn trim(&mut self) {
134134
let svg_hits = &self.svg_hits;
135135
let rasterized_hits = &self.rasterized_hits;
136136

137-
for (k, allocation) in &self.rasterized {
138-
if !rasterized_hits.contains(k) {
139-
texture_array.deallocate(allocation);
140-
}
141-
}
142-
143137
self.svgs.retain(|k, _| svg_hits.contains(k));
144138
self.rasterized.retain(|k, _| rasterized_hits.contains(k));
145139
self.svg_hits.clear();

0 commit comments

Comments
 (0)