Bug 1602458 - Avoid reallocating the tile compare cache each rame. r=gw
authorNicolas Silva <nsilva@mozilla.com>
Thu, 12 Dec 2019 09:10:11 +0000
changeset 506637 116c84612571ece9fe439cb89292120f5c05f1af
parent 506636 afdbc174451905720fd9d9be93e402fc4793aba3
child 506638 59cfb8104165cd5d25ab10abe0b634995b6a9552
push id36910
push usercsabou@mozilla.com
push dateThu, 12 Dec 2019 21:50:40 +0000
treeherdermozilla-central@0f6958f49842 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgw
bugs1602458
milestone73.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 1602458 - Avoid reallocating the tile compare cache each rame. r=gw Differential Revision: https://phabricator.services.mozilla.com/D56408
gfx/wr/webrender/src/picture.rs
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -362,16 +362,19 @@ struct TilePostUpdateContext<'a> {
 
 // Mutable state passed to picture cache tiles during post_update
 struct TilePostUpdateState<'a> {
     /// Allow access to the texture cache for requesting tiles
     resource_cache: &'a mut ResourceCache,
 
     /// Current configuration and setup for compositing all the picture cache tiles in renderer.
     composite_state: &'a mut CompositeState,
+
+    /// A cache of comparison results to avoid re-computation during invalidation.
+    compare_cache: &'a mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
 }
 
 /// Information about the dependencies of a single primitive instance.
 struct PrimitiveDependencyInfo {
     /// If true, we should clip the prim rect to the tile boundaries.
     clip_by_tile: bool,
 
     /// Unique content identifier of the primitive.
@@ -636,59 +639,56 @@ impl Tile {
         self.current_descriptor.print(pt);
         pt.end_level();
     }
 
     /// Check if the content of the previous and current tile descriptors match
     fn update_dirty_rects(
         &mut self,
         ctx: &TilePostUpdateContext,
-        state: &TilePostUpdateState,
-        compare_cache: &mut FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
+        state: &mut TilePostUpdateState,
         invalidation_reason: &mut Option<InvalidationReason>,
     ) -> PictureRect {
         let mut prim_comparer = PrimitiveComparer::new(
             &self.prev_descriptor,
             &self.current_descriptor,
             state.resource_cache,
             ctx.spatial_nodes,
             ctx.opacity_bindings,
         );
 
         let mut dirty_rect = PictureRect::zero();
-
         self.root.update_dirty_rects(
             &self.prev_descriptor.prims,
             &self.current_descriptor.prims,
             &mut prim_comparer,
             &mut dirty_rect,
-            compare_cache,
+            state.compare_cache,
             invalidation_reason,
         );
 
         dirty_rect
     }
 
     /// Invalidate a tile based on change in content. This
     /// must be called even if the tile is not currently
     /// visible on screen. We might be able to improve this
     /// later by changing how ComparableVec is used.
     fn update_content_validity(
         &mut self,
         ctx: &TilePostUpdateContext,
-        state: &TilePostUpdateState,
+        state: &mut TilePostUpdateState,
     ) {
         // Check if the contents of the primitives, clips, and
         // other dependencies are the same.
-        let mut compare_cache = FastHashMap::default();
+        state.compare_cache.clear();
         let mut invalidation_reason = None;
         let dirty_rect = self.update_dirty_rects(
             ctx,
             state,
-            &mut compare_cache,
             &mut invalidation_reason,
         );
         if !dirty_rect.is_empty() {
             self.invalidate(
                 Some(dirty_rect),
                 invalidation_reason.expect("bug: no invalidation_reason"),
             );
         }
@@ -1494,16 +1494,19 @@ pub struct TileCacheInstance {
     root_transform: TransformKey,
     /// The number of frames until this cache next evaluates what tile size to use.
     /// If a picture rect size is regularly changing just around a size threshold,
     /// we don't want to constantly invalidate and reallocate different tile size
     /// configuration each frame.
     frames_until_size_eval: usize,
     /// The current fractional offset of the cached picture
     fract_offset: PictureVector2D,
+    /// keep around the hash map used as compare_cache to avoid reallocating it each
+    /// frame.
+    compare_cache: FastHashMap<PrimitiveComparisonKey, PrimitiveCompareResult>,
 }
 
 impl TileCacheInstance {
     pub fn new(
         slice: usize,
         spatial_node_index: SpatialNodeIndex,
         background_color: Option<ColorF>,
         shared_clips: Vec<ClipDataHandle>,
@@ -1540,16 +1543,17 @@ impl TileCacheInstance {
             backdrop: BackdropInfo::empty(),
             subpixel_mode: SubpixelMode::Allow,
             root_transform: TransformKey::Local,
             shared_clips,
             shared_clip_chain,
             current_tile_size: DeviceIntSize::zero(),
             frames_until_size_eval: 0,
             fract_offset: PictureVector2D::zero(),
+            compare_cache: FastHashMap::default(),
         }
     }
 
     /// Returns true if this tile cache is considered opaque.
     pub fn is_opaque(&self) -> bool {
         // If known opaque due to background clear color and being the first slice.
         // The background_color will only be Some(..) if this is the first slice.
         match self.background_color {
@@ -2282,24 +2286,22 @@ impl TileCacheInstance {
             spatial_nodes: &self.spatial_nodes,
             opacity_bindings: &self.opacity_bindings,
             current_tile_size: self.current_tile_size,
         };
 
         let mut state = TilePostUpdateState {
             resource_cache: frame_state.resource_cache,
             composite_state: frame_state.composite_state,
+            compare_cache: &mut self.compare_cache,
         };
 
         // Step through each tile and invalidate if the dependencies have changed.
         for (key, tile) in self.tiles.iter_mut() {
-            if tile.post_update(
-                &ctx,
-                &mut state,
-            ) {
+            if tile.post_update(&ctx, &mut state) {
                 self.tiles_to_draw.push(*key);
             }
         }
 
         // When under test, record a copy of the dirty region to support
         // invalidation testing in wrench.
         if frame_context.config.testing {
             frame_state.scratch.recorded_dirty_regions.push(self.dirty_region.record());