Bug 1517723 - Update webrender to commit a40a5ffd1649d6bf6f55b76c7d633e4d157d4478 (WR PR #3467). r=kats
authorWR Updater Bot <graphics-team@mozilla.staktrace.com>
Fri, 04 Jan 2019 13:26:28 +0000
changeset 509646 1b01f47f32c02a3335ee107c53ebf85306026875
parent 509645 2b6f049b5daf133771afb38efe807a7fd73a4f19
child 509647 1f465582eb8c486fc9b2ba3cc140eafa9df9d1f9
push id10547
push userffxbld-merge
push dateMon, 21 Jan 2019 13:03:58 +0000
treeherdermozilla-beta@24ec1916bffe [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskats
bugs1517723
milestone66.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 1517723 - Update webrender to commit a40a5ffd1649d6bf6f55b76c7d633e4d157d4478 (WR PR #3467). r=kats https://github.com/servo/webrender/pull/3467 Differential Revision: https://phabricator.services.mozilla.com/D15722
gfx/webrender_bindings/revision.txt
gfx/wr/webrender/src/picture.rs
--- a/gfx/webrender_bindings/revision.txt
+++ b/gfx/webrender_bindings/revision.txt
@@ -1,1 +1,1 @@
-8a7212b628ae39e7251201b0a9761c74bab42c5d
+a40a5ffd1649d6bf6f55b76c7d633e4d157d4478
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -108,16 +108,19 @@ struct TileId(usize);
 #[derive(Debug)]
 pub struct Tile {
     /// The current world rect of thie tile.
     world_rect: WorldRect,
     /// The current local rect of this tile.
     pub local_rect: LayoutRect,
     /// The valid rect within this tile.
     valid_rect: WorldRect,
+    /// The currently visible rect within this tile, updated per frame.
+    /// If None, this tile is not currently visible.
+    visible_rect: Option<WorldRect>,
     /// Uniquely describes the content of this tile, in a way that can be
     /// (reasonably) efficiently hashed and compared.
     descriptor: TileDescriptor,
     /// Handle to the cached texture for this tile.
     pub handle: TextureCacheHandle,
     /// If true, this tile is marked valid, and the existing texture
     /// cache handle can be used. Tiles are invalidated during the
     /// build_dirty_regions method.
@@ -131,16 +134,17 @@ impl Tile {
     /// Construct a new, invalid tile.
     fn new(
         id: TileId,
     ) -> Self {
         Tile {
             local_rect: LayoutRect::zero(),
             world_rect: WorldRect::zero(),
             valid_rect: WorldRect::zero(),
+            visible_rect: None,
             handle: TextureCacheHandle::invalid(),
             descriptor: TileDescriptor::new(),
             is_valid: false,
             id,
         }
     }
 
     /// Clear the dependencies for a tile.
@@ -486,16 +490,27 @@ impl TileCache {
         // given the world reference point constraint.
         let device_ref_point = world_ref_point * frame_context.device_pixel_scale;
         let device_world_rect = frame_context.screen_world_rect * frame_context.device_pixel_scale;
         let pic_device_rect = pic_world_rect * frame_context.device_pixel_scale;
         let needed_device_rect = pic_device_rect
             .intersection(&device_world_rect)
             .expect("todo: handle clipped device rect");
 
+        // Expand the needed device rect vertically by a small number of tiles. This
+        // ensures that as tiles are scrolled in/out of view, they are retained for
+        // a while before being discarded.
+        // TODO(gw): On some pages it might be worth also inflating horizontally.
+        //           (is this locale specific?). It might be possible to make a good
+        //           guess based on the size of the picture rect for the tile cache.
+        let needed_device_rect = needed_device_rect.inflate(
+            0.0,
+            3.0 * TILE_SIZE_HEIGHT as f32,
+        );
+
         let p0 = needed_device_rect.origin;
         let p1 = needed_device_rect.bottom_right();
 
         let p0 = DevicePoint::new(
             device_ref_point.x + ((p0.x - device_ref_point.x) / TILE_SIZE_WIDTH as f32).floor() * TILE_SIZE_WIDTH as f32,
             device_ref_point.y + ((p0.y - device_ref_point.y) / TILE_SIZE_HEIGHT as f32).floor() * TILE_SIZE_HEIGHT as f32,
         );
 
@@ -549,16 +564,18 @@ impl TileCache {
                     ),
                     self.world_tile_size,
                 );
 
                 tile.local_rect = world_mapper
                     .unmap(&tile.world_rect)
                     .expect("bug: can't unmap world rect");
 
+                tile.visible_rect = tile.world_rect.intersection(&frame_context.screen_world_rect);
+
                 self.tiles.push(tile);
             }
         }
 
         if !old_tiles.is_empty() {
             // TODO(gw): Should we explicitly drop the tile texture cache handles here?
         }
 
@@ -605,17 +622,16 @@ impl TileCache {
         prim_list: &PrimitiveList,
         clip_scroll_tree: &ClipScrollTree,
         resources: &FrameResources,
         clip_chain_nodes: &[ClipChainNode],
         pictures: &[PicturePrimitive],
         resource_cache: &ResourceCache,
         opacity_binding_store: &OpacityBindingStorage,
         image_instances: &ImageInstanceStorage,
-        screen_world_rect: &WorldRect,
     ) {
         if !self.needs_update {
             return;
         }
 
         // We need to ensure that if a primitive belongs to a cluster that has
         // been marked invisible, we exclude it here. Otherwise, we may end up
         // with a primitive that is outside the bounding rect of the calculated
@@ -761,20 +777,23 @@ impl TileCache {
                     // so we need to treat them as normal style clips with vertices.
                     if clip_spatial_node.coordinate_system_id == CoordinateSystemId(0) {
                         let local_rect = LayoutRect::new(
                             clip_chain_node.local_pos,
                             size,
                         );
 
                         if let Some(clip_world_rect) = self.map_local_to_world.map(&local_rect) {
-                            world_clip_rect = match world_clip_rect.intersection(&clip_world_rect) {
-                                Some(rect) => rect,
-                                None => return,
-                            };
+                            // Even if this ends up getting clipped out by the current clip
+                            // stack, we want to ensure the primitive gets added to the tiles
+                            // below, to ensure invalidation isn't tripped up by the wrong
+                            // number of primitives that affect this tile.
+                            world_clip_rect = world_clip_rect
+                                .intersection(&clip_world_rect)
+                                .unwrap_or(WorldRect::zero());
                         }
 
                         false
                     } else {
                         true
                     }
                 }
                 ClipItem::Rectangle(_, ClipMode::ClipOut) |
@@ -814,24 +833,41 @@ impl TileCache {
                 // area, just ignore those.
                 if x < 0 || x >= self.tile_count.width || y < 0 || y >= self.tile_count.height {
                     continue;
                 }
 
                 let index = (y * self.tile_count.width + x) as usize;
                 let tile = &mut self.tiles[index];
 
+                // TODO(gw): For now, we need to always build the dependencies each
+                //           frame, so can't early exit here. In future, we should
+                //           support retaining the tile descriptor from when the
+                //           tile goes off-screen, which will mean we can then
+                //           compare against that next time it becomes visible.
+                let visible_rect = match tile.visible_rect {
+                    Some(visible_rect) => visible_rect,
+                    None => WorldRect::zero(),
+                };
+
                 // Work out the needed rect for the primitive on this tile.
                 // TODO(gw): We should be able to remove this for any tile that is not
                 //           a partially clipped tile, which would be a significant
                 //           optimization for the common case (non-clipped tiles).
-                let needed_rect = match world_clip_rect.intersection(&tile.world_rect).and_then(|r| r.intersection(screen_world_rect)) {
-                    Some(rect) => rect.translate(&-tile.world_rect.origin.to_vector()),
-                    None => continue,
-                };
+
+                // Get the required tile-local rect that this primitive occupies.
+                // Ensure that even if it's currently clipped out of this tile,
+                // we still insert a rect of zero size, so that the tile descriptor's
+                // needed rects array matches.
+                let needed_rect = world_clip_rect
+                    .intersection(&visible_rect)
+                    .map(|rect| {
+                        rect.translate(&-tile.world_rect.origin.to_vector())
+                    })
+                    .unwrap_or(WorldRect::zero());
 
                 tile.descriptor.needed_rects.push(needed_rect);
 
                 // Mark if the tile is cacheable at all.
                 tile.is_valid &= is_cacheable;
 
                 // Include any image keys this tile depends on.
                 tile.descriptor.image_keys.extend_from_slice(&image_keys);
@@ -925,20 +961,17 @@ impl TileCache {
                 // assuming that it's either visible or we want to retain it for
                 // a while in case it gets scrolled back onto screen soon.
                 // TODO(gw): Consider switching to manual eviction policy?
                 resource_cache.texture_cache.request(&tile.handle, gpu_cache);
             } else {
                 tile.is_valid = false;
             }
 
-            let visible_rect = match tile
-                .world_rect
-                .intersection(&frame_context.screen_world_rect)
-            {
+            let visible_rect = match tile.visible_rect {
                 Some(rect) => rect,
                 None => continue,
             };
 
             // Check the content of the tile is the same
             tile.is_valid &= tile.descriptor.is_valid();
 
             // Decide how to handle this tile when drawing this frame.
@@ -2005,17 +2038,16 @@ impl PicturePrimitive {
                 &self.prim_list,
                 &frame_context.clip_scroll_tree,
                 resources,
                 &clip_store.clip_chain_nodes,
                 pictures,
                 resource_cache,
                 opacity_binding_store,
                 image_instances,
-                &frame_context.screen_world_rect,
             );
         }
     }
 
     /// Called after updating child pictures during the initial
     /// picture traversal.
     pub fn post_update(
         &mut self,