Bug 1624565 - Eagerly deallocate empty texture arrays in the texture cache. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Tue, 24 Mar 2020 22:53:21 +0000
changeset 520302 cb7a03e737951349193fb99410bb907991f7bc35
parent 520301 d9b2acdce930ee1279fd8e51a4b8f85c5350435d
child 520303 61582f6d817a401e12c32340873d3d781e6cfaf2
push id37246
push useropoprus@mozilla.com
push dateWed, 25 Mar 2020 03:40:33 +0000
treeherdermozilla-central@14b59d4adc95 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1624565
milestone76.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1624565 - Eagerly deallocate empty texture arrays in the texture cache. r=gw We already have a cooldown from texture cache items being deallocated a certain amount of time and frames after their last use so we can deallocate texture arrays as soon as they are completely empty. We do this at the end of the frame to avoid deallocating and reallocating within the frame. It's better to reclaim texture memory this way than run into maybe_reclaim_shared_memory which will throw away everything and cause new allocations on the next frame. Differential Revision: https://phabricator.services.mozilla.com/D68050
gfx/wr/webrender/src/texture_cache.rs
--- a/gfx/wr/webrender/src/texture_cache.rs
+++ b/gfx/wr/webrender/src/texture_cache.rs
@@ -952,16 +952,21 @@ impl TextureCache {
         // 512 pixels. Cached render tasks also frequently get standalone entries,
         // but those use the Eviction::Eager policy (for now). So the tradeoff there
         // is largely around reducing texture upload jank while keeping memory usage
         // at an acceptable level.
         let threshold = self.default_eviction();
         self.expire_old_entries(EntryKind::Standalone, threshold);
         self.expire_old_entries(EntryKind::Picture, threshold);
 
+        self.shared_textures.array_alpha8_linear.release_empty_textures(&mut self.pending_updates);
+        self.shared_textures.array_alpha16_linear.release_empty_textures(&mut self.pending_updates);
+        self.shared_textures.array_color8_linear.release_empty_textures(&mut self.pending_updates);
+        self.shared_textures.array_color8_nearest.release_empty_textures(&mut self.pending_updates);
+
         self.shared_textures.array_alpha8_linear
             .update_profile(&mut texture_cache_profile.pages_alpha8_linear);
         self.shared_textures.array_alpha16_linear
             .update_profile(&mut texture_cache_profile.pages_alpha16_linear);
         self.shared_textures.array_color8_linear
             .update_profile(&mut texture_cache_profile.pages_color8_linear);
         self.shared_textures.array_color8_nearest
             .update_profile(&mut texture_cache_profile.pages_color8_nearest);
@@ -1726,16 +1731,20 @@ impl TextureArrayUnit {
     }
 
     /// Returns true if we can allocate the given entry.
     fn can_alloc(&self, slab_size: SlabSize) -> bool {
         self.empty_regions != 0 || self.regions.iter().any(|region| {
             region.slab_size == slab_size && !region.free_slots.is_empty()
         })
     }
+
+    fn is_empty(&self) -> bool {
+        self.empty_regions == self.regions.len()
+    }
 }
 
 /// A texture array contains a number of textures, each with a number of
 /// layers, where each layer contains a region that can act as a slab allocator.
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 struct TextureArray {
     filter: TextureFilter,
@@ -1773,16 +1782,28 @@ impl TextureArray {
     }
 
     fn clear(&mut self, updates: &mut TextureUpdateList) {
         for unit in self.units.drain() {
             updates.push_free(unit.texture_id);
         }
     }
 
+    fn release_empty_textures(&mut self, updates: &mut TextureUpdateList) {
+        self.units.retain(|unit| {
+            if unit.is_empty() {
+                updates.push_free(unit.texture_id);
+
+                false
+            } else {
+                true
+            }
+        });
+    }
+
     fn update_profile(&self, counter: &mut ResourceProfileCounter) {
         let num_regions: usize = self.units.iter().map(|u| u.regions.len()).sum();
         counter.set(num_regions, self.size_in_bytes());
     }
 
     /// Allocate space in this texture array.
     fn alloc(
         &mut self,