diff options
author | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-22 18:53:18 +0000 |
---|---|---|
committer | enne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-04-22 18:53:18 +0000 |
commit | b7d57217eda14c6415522b74bf9c6b6089fb3b61 (patch) | |
tree | f94c17347e0415b43e013f4da72a069f5a0894e9 | |
parent | 66b31f81a284cf3f2936585d43e8d3bcb9ac6119 (diff) | |
download | chromium_src-b7d57217eda14c6415522b74bf9c6b6089fb3b61.zip chromium_src-b7d57217eda14c6415522b74bf9c6b6089fb3b61.tar.gz chromium_src-b7d57217eda14c6415522b74bf9c6b6089fb3b61.tar.bz2 |
cc: Fix missing compositor invalidations during resize
In practice, cc is responsible for implicit invalidations on layers,
such as the original layer being entirely invalid or new areas being
exposed during resize.
In this case, these invalidations were being clipped to the live tiles
rect, which itself is clipped to the bounds of the tiling. Therefore,
when the bounds of a layer grew, the new invalidation intersected with
the old bounds was empty.
The intersection of invalidations with the live tiles rect is an
optimization, to prevent needless work trying to look up invalidations
on parts of the layer that don't matter.
To fix the bug, rather than intersecting with the live tiles rect,
expand the live tiles rect to tile boundaries. This lets implicit
invalidation due to resize within a tile not skip rerasterizing
that tile.
BUG=357120
Review URL: https://codereview.chromium.org/240593004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@265313 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/base/tiling_data.cc | 17 | ||||
-rw-r--r-- | cc/base/tiling_data.h | 2 | ||||
-rw-r--r-- | cc/base/tiling_data_unittest.cc | 71 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling.cc | 6 | ||||
-rw-r--r-- | cc/resources/picture_layer_tiling_unittest.cc | 17 |
5 files changed, 112 insertions, 1 deletions
diff --git a/cc/base/tiling_data.cc b/cc/base/tiling_data.cc index af581ff..a52c940 100644 --- a/cc/base/tiling_data.cc +++ b/cc/base/tiling_data.cc @@ -138,6 +138,23 @@ int TilingData::LastBorderTileYIndexFromSrcCoord(int src_position) const { return std::min(std::max(y, 0), num_tiles_y_ - 1); } +gfx::Rect TilingData::ExpandRectToTileBoundsWithBorders( + const gfx::Rect rect) const { + if (!rect.Intersects(tiling_rect_) || has_empty_bounds()) + return gfx::Rect(); + int index_x = FirstBorderTileXIndexFromSrcCoord(rect.x()); + int index_y = FirstBorderTileYIndexFromSrcCoord(rect.y()); + int index_right = LastBorderTileXIndexFromSrcCoord(rect.right()); + int index_bottom = LastBorderTileYIndexFromSrcCoord(rect.bottom()); + + gfx::Rect rect_top_left(TileBoundsWithBorder(index_x, index_y)); + gfx::Rect rect_bottom_right(TileBoundsWithBorder(index_right, index_bottom)); + + gfx::Rect expanded(rect_top_left); + expanded.Union(rect_bottom_right); + return expanded; +} + gfx::Rect TilingData::TileBounds(int i, int j) const { AssertTile(i, j); int max_texture_size_x = max_texture_size_.width() - 2 * border_texels_; diff --git a/cc/base/tiling_data.h b/cc/base/tiling_data.h index 27ec034..3059c21 100644 --- a/cc/base/tiling_data.h +++ b/cc/base/tiling_data.h @@ -52,6 +52,8 @@ class CC_EXPORT TilingData { int LastBorderTileXIndexFromSrcCoord(int src_position) const; int LastBorderTileYIndexFromSrcCoord(int src_position) const; + gfx::Rect ExpandRectToTileBoundsWithBorders(const gfx::Rect rect) const; + gfx::Rect TileBounds(int i, int j) const; gfx::Rect TileBoundsWithBorder(int i, int j) const; int TilePositionX(int x_index) const; diff --git a/cc/base/tiling_data_unittest.cc b/cc/base/tiling_data_unittest.cc index 1563b02..fd0809d 100644 --- a/cc/base/tiling_data_unittest.cc +++ b/cc/base/tiling_data_unittest.cc @@ -2133,6 +2133,77 @@ TEST_P(TilingDataTest, SetMaxTextureSizeBorders) { EXPECT_EQ(10, data.num_tiles_y()); } +TEST_P(TilingDataTest, ExpandRectToTileBoundsWithBordersEmpty) { + gfx::Point origin = GetParam(); + TilingData empty_total_size( + gfx::Size(0, 0), gfx::Rect(origin, gfx::Size(8, 8)), true); + EXPECT_RECT_EQ( + gfx::Rect(), + empty_total_size.ExpandRectToTileBoundsWithBorders(gfx::Rect())); + EXPECT_RECT_EQ(gfx::Rect(), + empty_total_size.ExpandRectToTileBoundsWithBorders( + gfx::Rect(100, 100, 100, 100))); + EXPECT_RECT_EQ(gfx::Rect(), + empty_total_size.ExpandRectToTileBoundsWithBorders( + gfx::Rect(0, 0, 100, 100))); + + TilingData empty_max_texture_size( + gfx::Size(8, 8), gfx::Rect(origin, gfx::Size(0, 0)), true); + EXPECT_RECT_EQ( + gfx::Rect(), + empty_max_texture_size.ExpandRectToTileBoundsWithBorders(gfx::Rect())); + EXPECT_RECT_EQ(gfx::Rect(), + empty_max_texture_size.ExpandRectToTileBoundsWithBorders( + gfx::Rect(100, 100, 100, 100))); + EXPECT_RECT_EQ(gfx::Rect(), + empty_max_texture_size.ExpandRectToTileBoundsWithBorders( + gfx::Rect(0, 0, 100, 100))); +} + +TEST_P(TilingDataTest, ExpandRectToTileBoundsWithBorders) { + gfx::Point origin = GetParam(); + TilingData data(gfx::Size(4, 4), gfx::Rect(origin, gfx::Size(16, 32)), true); + + // Small rect at origin rounds up to tile 0, 0. + gfx::Rect at_origin_src(origin, gfx::Size(1, 1)); + gfx::Rect at_origin_result(data.TileBoundsWithBorder(0, 0)); + EXPECT_NE(at_origin_src, at_origin_result); + EXPECT_RECT_EQ(at_origin_result, + data.ExpandRectToTileBoundsWithBorders(at_origin_src)); + + // Arbitrary internal rect. + gfx::Rect rect_src(origin.x() + 6, origin.y() + 6, 1, 3); + // Tile 2, 2 => gfx::Rect(4, 4, 4, 4) + // Tile 3, 4 => gfx::Rect(6, 8, 4, 4) + gfx::Rect rect_result(gfx::UnionRects(data.TileBoundsWithBorder(2, 2), + data.TileBoundsWithBorder(3, 4))); + EXPECT_NE(rect_src, rect_result); + EXPECT_RECT_EQ(rect_result, data.ExpandRectToTileBoundsWithBorders(rect_src)); + + // On tile bounds rounds up to next tile (since border overlaps). + gfx::Rect border_rect_src( + gfx::UnionRects(data.TileBounds(1, 2), data.TileBounds(3, 4))); + gfx::Rect border_rect_result(gfx::UnionRects( + data.TileBoundsWithBorder(0, 1), data.TileBoundsWithBorder(4, 5))); + EXPECT_RECT_EQ(border_rect_result, + data.ExpandRectToTileBoundsWithBorders(border_rect_src)); + + // Equal to tiling rect. + EXPECT_RECT_EQ(data.tiling_rect(), + data.ExpandRectToTileBoundsWithBorders(data.tiling_rect())); + + // Containing, but larger than tiling rect. + EXPECT_RECT_EQ(data.tiling_rect(), + data.ExpandRectToTileBoundsWithBorders( + gfx::Rect(origin, gfx::Size(100, 100)))); + + // Non-intersecting with tiling rect. + gfx::Rect non_intersect(origin.x() + 200, origin.y() + 200, 100, 100); + EXPECT_FALSE(non_intersect.Intersects(data.tiling_rect())); + EXPECT_RECT_EQ(gfx::Rect(), + data.ExpandRectToTileBoundsWithBorders(non_intersect)); +} + TEST_P(TilingDataTest, Assignment) { gfx::Point origin = GetParam(); diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc index d2a732d..a3664e7 100644 --- a/cc/resources/picture_layer_tiling.cc +++ b/cc/resources/picture_layer_tiling.cc @@ -189,11 +189,15 @@ void PictureLayerTiling::Invalidate(const Region& layer_region) { void PictureLayerTiling::DoInvalidate(const Region& layer_region, bool recreate_tiles) { std::vector<TileMapKey> new_tile_keys; + gfx::Rect expanded_live_tiles_rect( + tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_)); for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) { gfx::Rect layer_rect = iter.rect(); gfx::Rect content_rect = gfx::ScaleToEnclosingRect(layer_rect, contents_scale_); - content_rect.Intersect(live_tiles_rect_); + // Avoid needless work by not bothering to invalidate where there aren't + // tiles. + content_rect.Intersect(expanded_live_tiles_rect); if (content_rect.IsEmpty()) continue; bool include_borders = true; diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc index 976ed6b..e1eddd7 100644 --- a/cc/resources/picture_layer_tiling_unittest.cc +++ b/cc/resources/picture_layer_tiling_unittest.cc @@ -173,6 +173,23 @@ class PictureLayerTilingIteratorTest : public testing::Test { DISALLOW_COPY_AND_ASSIGN(PictureLayerTilingIteratorTest); }; +TEST_F(PictureLayerTilingIteratorTest, ResizeDeletesTiles) { + // Verifies that a resize deletes tiles that used to be on the edge. + gfx::Size tile_size(100, 100); + gfx::Size original_layer_size(10, 10); + Initialize(tile_size, 1.f, original_layer_size); + SetLiveRectAndVerifyTiles(gfx::Rect(original_layer_size)); + + // Tiling only has one tile, since its total size is less than one. + EXPECT_TRUE(tiling_->TileAt(0, 0)); + + // Stop creating tiles so that any invalidations are left as holes. + client_.set_allow_create_tile(false); + + tiling_->SetLayerBounds(gfx::Size(200, 200)); + EXPECT_FALSE(tiling_->TileAt(0, 0)); +} + TEST_F(PictureLayerTilingIteratorTest, LiveTilesExactlyCoverLiveTileRect) { Initialize(gfx::Size(100, 100), 1, gfx::Size(1099, 801)); SetLiveRectAndVerifyTiles(gfx::Rect(100, 100)); |