Bug 1521329 - Fix adding extremely large primitives to picture caching tile dependencies. r=jrmuizel
authorGlenn Watson <github@intuitionlibrary.com>
Sun, 20 Jan 2019 01:30:21 +0000
changeset 454633 47e442ac35b3
parent 454632 0a4598992141
child 454634 6aa3c460ff66
push id76435
push usergwatson@mozilla.com
push dateSun, 20 Jan 2019 01:55:02 +0000
treeherderautoland@47e442ac35b3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjrmuizel
bugs1521329
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 1521329 - Fix adding extremely large primitives to picture caching tile dependencies. r=jrmuizel Differential Revision: https://phabricator.services.mozilla.com/D17072
gfx/wr/webrender/src/picture.rs
--- a/gfx/wr/webrender/src/picture.rs
+++ b/gfx/wr/webrender/src/picture.rs
@@ -116,16 +116,20 @@ const MAX_SURFACE_SIZE: f32 = 4096.0;
 /// The maximum number of primitives to look for in a display
 /// list, trying to find unique primitives.
 const MAX_PRIMS_TO_SEARCH: usize = 128;
 
 /// Used to get unique tile IDs, even when the tile cache is
 /// destroyed between display lists / scenes.
 static NEXT_TILE_ID: AtomicUsize = ATOMIC_USIZE_INIT;
 
+fn clamp(value: i32, low: i32, high: i32) -> i32 {
+    value.max(low).min(high)
+}
+
 /// Information about the state of an opacity binding.
 #[derive(Debug)]
 pub struct OpacityBindingInfo {
     /// The current value retrieved from dynamic scene properties.
     value: f32,
     /// True if it was changed (or is new) since the last frame build.
     changed: bool,
 }
@@ -693,26 +697,32 @@ impl TileCache {
     fn get_tile_coords_for_rect(
         &self,
         rect: &WorldRect,
     ) -> (TileOffset, TileOffset) {
         // Translate the rectangle into the virtual tile space
         let origin = rect.origin - self.world_origin;
 
         // Get the tile coordinates in the picture space.
-        let p0 = TileOffset::new(
+        let mut p0 = TileOffset::new(
             (origin.x / self.world_tile_size.width).floor() as i32,
             (origin.y / self.world_tile_size.height).floor() as i32,
         );
 
-        let p1 = TileOffset::new(
+        let mut p1 = TileOffset::new(
             ((origin.x + rect.size.width) / self.world_tile_size.width).ceil() as i32,
             ((origin.y + rect.size.height) / self.world_tile_size.height).ceil() as i32,
         );
 
+        // Clamp the tile coordinates here to avoid looping over irrelevant tiles later on.
+        p0.x = clamp(p0.x, 0, self.tile_count.width);
+        p0.y = clamp(p0.y, 0, self.tile_count.height);
+        p1.x = clamp(p1.x, 0, self.tile_count.width);
+        p1.y = clamp(p1.y, 0, self.tile_count.height);
+
         (p0, p1)
     }
 
     /// Update transforms, opacity bindings and tile rects.
     pub fn pre_update(
         &mut self,
         pic_rect: LayoutRect,
         frame_context: &FrameVisibilityContext,
@@ -1228,22 +1238,16 @@ impl TileCache {
             .map_local_to_world
             .map(&culling_rect)
             .expect("bug: unable to map local clip rect");
 
         // Normalize the tile coordinates before adding to tile dependencies.
         // For each affected tile, mark any of the primitive dependencies.
         for y in p0.y .. p1.y {
             for x in p0.x .. p1.x {
-                // If the primitive exists on tiles outside the selected tile cache
-                // 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];
 
                 // Store the local clip rect by calculating what portion
                 // of the tile it covers.
                 let world_culling_rect = world_culling_rect
                     .intersection(&tile.world_rect)
                     .map(|rect| {