Bug 1624565 - Avoid clearing the texture cache as often. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Tue, 24 Mar 2020 22:52:57 +0000
changeset 520303 61582f6d817a401e12c32340873d3d781e6cfaf2
parent 520302 cb7a03e737951349193fb99410bb907991f7bc35
child 520304 167562affb96a1777609f6c6bb6f0a1dab520309
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 - Avoid clearing the texture cache as often. r=gw The current heuristic in TextureCache::maybe_reclaim_shared_memory pretty much clears the cache every 5 seconds. Clearing the cache is prtty drastic though, because it causes us to re-upload data and reallocate several textures on the next frame. We really only want to do it when the savings are big, which happens less often now that texture array layer count is capped at 16 and that textures are released as soon as they are empty. This makes us clear the cache less often by augmenting the threshold to 16 megabytes and only considering texture regions that would not be reallocated right away (since we grow some texture arrays more than one region at a time). Differential Revision: https://phabricator.services.mozilla.com/D68051
gfx/wr/webrender/src/texture_cache.rs
--- a/gfx/wr/webrender/src/texture_cache.rs
+++ b/gfx/wr/webrender/src/texture_cache.rs
@@ -36,17 +36,17 @@ const PICTURE_TEXTURE_ADD_SLICES: usize 
 const PICTURE_TILE_FORMAT: ImageFormat = ImageFormat::RGBA8;
 
 /// The number of pixels in a region. Derived from the above.
 const TEXTURE_REGION_PIXELS: usize =
     (TEXTURE_REGION_DIMENSIONS as usize) * (TEXTURE_REGION_DIMENSIONS as usize);
 
 // The minimum number of bytes that we must be able to reclaim in order
 // to justify clearing the entire shared cache in order to shrink it.
-const RECLAIM_THRESHOLD_BYTES: usize = 5 * 1024 * 1024;
+const RECLAIM_THRESHOLD_BYTES: usize = 16 * 512 * 512 * 4;
 
 /// Items in the texture cache can either be standalone textures,
 /// or a sub-rect inside the shared cache.
 #[derive(Debug)]
 #[cfg_attr(feature = "capture", derive(Serialize))]
 #[cfg_attr(feature = "replay", derive(Deserialize))]
 enum EntryDetails {
     Standalone,
@@ -310,21 +310,21 @@ impl SharedTextures {
     fn size_in_bytes(&self) -> usize {
         self.array_alpha8_linear.size_in_bytes() +
         self.array_alpha16_linear.size_in_bytes() +
         self.array_color8_linear.size_in_bytes() +
         self.array_color8_nearest.size_in_bytes()
     }
 
     /// Returns the cumulative number of GPU bytes consumed by empty regions.
-    fn empty_region_bytes(&self) -> usize {
-        self.array_alpha8_linear.empty_region_bytes() +
-        self.array_alpha16_linear.empty_region_bytes() +
-        self.array_color8_linear.empty_region_bytes() +
-        self.array_color8_nearest.empty_region_bytes()
+    fn reclaimable_region_bytes(&self) -> usize {
+        self.array_alpha8_linear.reclaimable_region_bytes() +
+        self.array_alpha16_linear.reclaimable_region_bytes() +
+        self.array_color8_linear.reclaimable_region_bytes() +
+        self.array_color8_nearest.reclaimable_region_bytes()
     }
 
     /// Clears each texture in the set, with the given set of pending updates.
     fn clear(&mut self, updates: &mut TextureUpdateList) {
         self.array_alpha8_linear.clear(updates);
         self.array_alpha16_linear.clear(updates);
         self.array_color8_linear.clear(updates);
         self.array_color8_nearest.clear(updates);
@@ -899,24 +899,25 @@ impl TextureCache {
         // We could do this more intelligently with a resize+blit, but that would
         // add complexity for a rare case.
         //
         // This function must be called before the first begin_frame() for a group
         // of documents, otherwise documents could end up ignoring the
         // self.require_frame_build flag which is set if we end up calling
         // clear_shared.
         debug_assert!(!self.now.is_valid());
-        if self.shared_textures.empty_region_bytes() >= RECLAIM_THRESHOLD_BYTES {
+        if self.shared_textures.reclaimable_region_bytes() >= RECLAIM_THRESHOLD_BYTES {
             self.reached_reclaim_threshold.get_or_insert(time);
         } else {
             self.reached_reclaim_threshold = None;
         }
         if let Some(t) = self.reached_reclaim_threshold {
             let dur = time.duration_since(t).unwrap_or_default();
             if dur >= Duration::from_secs(5) {
+                println!("#n !! reclaim shared memory");
                 self.clear_shared();
                 self.reached_reclaim_threshold = None;
             }
         }
     }
 
     /// Called at the beginning of each frame to periodically GC by expiring
     /// old shared entries. If necessary, the shared memory opened up as a
@@ -930,16 +931,17 @@ impl TextureCache {
         // we recover unused memory in bounded time, rather than having it
         // depend on allocation patterns of subsequent content.
         let time_since_last_gc = self.now.time()
             .duration_since(self.doc_data.last_shared_cache_expiration.time())
             .unwrap_or_default();
         let do_periodic_gc = time_since_last_gc >= Duration::from_secs(5) &&
             self.shared_textures.size_in_bytes() >= RECLAIM_THRESHOLD_BYTES * 2;
         if do_periodic_gc {
+            println!("#n ######## periodic GC");
             let threshold = EvictionThresholdBuilder::new(self.now)
                 .max_frames(1)
                 .max_time_s(10)
                 .build();
             self.maybe_expire_old_shared_entries(threshold);
         }
     }
 
@@ -1770,17 +1772,17 @@ impl TextureArray {
     /// Returns the number of GPU bytes consumed by this texture array.
     fn size_in_bytes(&self) -> usize {
         let bpp = self.formats.internal.bytes_per_pixel() as usize;
         let num_regions: usize = self.units.iter().map(|u| u.regions.len()).sum();
         num_regions * TEXTURE_REGION_PIXELS * bpp
     }
 
     /// Returns the number of GPU bytes consumed by empty regions.
-    fn empty_region_bytes(&self) -> usize {
+    fn reclaimable_region_bytes(&self) -> usize {
         let bpp = self.formats.internal.bytes_per_pixel() as usize;
         let empty_regions: usize = self.units.iter().map(|u| u.empty_regions).sum();
         empty_regions * TEXTURE_REGION_PIXELS * bpp
     }
 
     fn clear(&mut self, updates: &mut TextureUpdateList) {
         for unit in self.units.drain() {
             updates.push_free(unit.texture_id);