Index: cc/resources/picture_layer_tiling.cc |
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc |
index e9e3b86180a0dba8a297dc77235f6f84224fe191..964c9b16b1b9a8cd86a91f3bfa4a0cee621308ae 100644 |
--- a/cc/resources/picture_layer_tiling.cc |
+++ b/cc/resources/picture_layer_tiling.cc |
@@ -56,6 +56,40 @@ class TileEvictionOrder { |
} // namespace |
+const int |
+ PictureLayerTiling::TileInvalidationState::kFrequentInvalidationThreshold = |
+ 2; |
+ |
+PictureLayerTiling::TileInvalidationState::TileInvalidationState() |
+ : frame_count_(0) { |
+} |
+ |
+void PictureLayerTiling::TileInvalidationState::Invalidate( |
+ base::TimeTicks current_frame_time) { |
+ if (current_frame_time == last_frame_time_) |
+ return; |
+ |
+ // Check the time intervals between consecutive invalidations: |
+ // - If the intervals are shorter than kIntervalMin for a number of |
+ // consecutive invalidations, it's a "frequently invalidated" tile. |
+ // - If the interval between two invalidations is longer than kIntervalMax, |
+ // it's not a "frequently invalidated" tile anymore. |
+ base::TimeDelta time_since = current_frame_time - last_frame_time_; |
+ const base::TimeDelta kIntervalMin = base::TimeDelta::FromMilliseconds(700); |
+ const base::TimeDelta kIntervalMax = base::TimeDelta::FromMilliseconds(2000); |
+ const base::TimeDelta interval = |
+ FrequentlyInvalidated() ? kIntervalMax : kIntervalMin; |
+ frame_count_ = |
+ time_since < interval |
+ ? std::min(frame_count_ + 1, kFrequentInvalidationThreshold) |
+ : 0; |
+ last_frame_time_ = current_frame_time; |
+} |
+ |
+bool PictureLayerTiling::TileInvalidationState::FrequentlyInvalidated() const { |
+ return frame_count_ >= kFrequentInvalidationThreshold; |
+} |
+ |
scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( |
float contents_scale, |
const gfx::Size& layer_bounds, |
@@ -138,8 +172,15 @@ Tile* PictureLayerTiling::CreateTile(int i, |
} |
} |
+ int flags = 0; |
+ auto found = tile_invalidation_states_.find(key); |
+ if (found != tile_invalidation_states_.end()) { |
+ if (found->second.FrequentlyInvalidated()) |
+ flags |= Tile::FREQUENTLY_INVALIDATED; |
+ } |
+ |
// Create a new tile because our twin didn't have a valid one. |
- scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect); |
+ scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect, flags); |
if (tile.get()) { |
DCHECK(!tile->is_shared()); |
tile->set_tiling_index(i, j); |
@@ -170,7 +211,8 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() { |
void PictureLayerTiling::UpdateTilesToCurrentRasterSource( |
RasterSource* raster_source, |
const Region& layer_invalidation, |
- const gfx::Size& new_layer_bounds) { |
+ const gfx::Size& new_layer_bounds, |
+ base::TimeTicks frame_time) { |
DCHECK(!new_layer_bounds.IsEmpty()); |
gfx::Size content_bounds = |
@@ -218,11 +260,11 @@ void PictureLayerTiling::UpdateTilesToCurrentRasterSource( |
// Drop tiles outside the new layer bounds if the layer shrank. |
for (int i = after_right + 1; i <= before_right; ++i) { |
for (int j = before_top; j <= before_bottom; ++j) |
- RemoveTileAt(i, j, recycled_twin); |
+ RemoveTileAt(i, j, recycled_twin, true); |
} |
for (int i = before_left; i <= after_right; ++i) { |
for (int j = after_bottom + 1; j <= before_bottom; ++j) |
- RemoveTileAt(i, j, recycled_twin); |
+ RemoveTileAt(i, j, recycled_twin, true); |
} |
// If the layer grew, the live_tiles_rect_ is not changed, but a new row |
@@ -247,7 +289,7 @@ void PictureLayerTiling::UpdateTilesToCurrentRasterSource( |
// as valid keys to the TileMap, so just drop all tiles. |
Reset(); |
} else { |
- Invalidate(layer_invalidation); |
+ Invalidate(layer_invalidation, frame_time); |
} |
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) |
@@ -257,16 +299,19 @@ void PictureLayerTiling::UpdateTilesToCurrentRasterSource( |
void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) { |
bool recreate_invalidated_tiles = false; |
- DoInvalidate(layer_region, recreate_invalidated_tiles); |
+ DoInvalidate(layer_region, recreate_invalidated_tiles, base::TimeTicks()); |
} |
-void PictureLayerTiling::Invalidate(const Region& layer_region) { |
+void PictureLayerTiling::Invalidate(const Region& layer_region, |
+ base::TimeTicks frame_time) { |
bool recreate_invalidated_tiles = true; |
- DoInvalidate(layer_region, recreate_invalidated_tiles); |
+ DoInvalidate(layer_region, recreate_invalidated_tiles, frame_time); |
} |
void PictureLayerTiling::DoInvalidate(const Region& layer_region, |
- bool recreate_invalidated_tiles) { |
+ bool recreate_invalidated_tiles, |
+ base::TimeTicks frame_time) { |
+ bool update_invalidation_states = frame_time != base::TimeTicks(); |
std::vector<TileMapKey> new_tile_keys; |
gfx::Rect expanded_live_tiles_rect = |
tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_); |
@@ -291,11 +336,14 @@ void PictureLayerTiling::DoInvalidate(const Region& layer_region, |
&tiling_data_, content_rect, include_borders); |
iter; |
++iter) { |
+ if (update_invalidation_states) |
+ tile_invalidation_states_[iter.index()].Invalidate(frame_time); |
+ |
// There is no recycled twin since this is run on the pending tiling. |
PictureLayerTiling* recycled_twin = NULL; |
DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this)); |
DCHECK_EQ(PENDING_TREE, client_->GetTree()); |
- if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin)) |
+ if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin, false)) |
new_tile_keys.push_back(iter.index()); |
} |
} |
@@ -462,16 +510,24 @@ gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const { |
bool PictureLayerTiling::RemoveTileAt(int i, |
int j, |
- PictureLayerTiling* recycled_twin) { |
+ PictureLayerTiling* recycled_twin, |
+ bool remove_invalidation_state) { |
TileMap::iterator found = tiles_.find(TileMapKey(i, j)); |
if (found == tiles_.end()) |
return false; |
found->second->set_shared(false); |
tiles_.erase(found); |
eviction_tiles_cache_valid_ = false; |
+ |
+ if (remove_invalidation_state) { |
+ auto found = tile_invalidation_states_.find(TileMapKey(i, j)); |
+ if (found != tile_invalidation_states_.end()) |
+ tile_invalidation_states_.erase(found); |
+ } |
+ |
if (recycled_twin) { |
// Recycled twin does not also have a recycled twin, so pass NULL. |
- recycled_twin->RemoveTileAt(i, j, NULL); |
+ recycled_twin->RemoveTileAt(i, j, NULL, remove_invalidation_state); |
} |
return true; |
} |
@@ -481,10 +537,13 @@ void PictureLayerTiling::Reset() { |
PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this); |
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
it->second->set_shared(false); |
- if (recycled_twin) |
- recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL); |
+ if (recycled_twin) { |
+ recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL, |
+ true); |
+ } |
} |
tiles_.clear(); |
+ tile_invalidation_states_.clear(); |
eviction_tiles_cache_valid_ = false; |
} |
@@ -628,7 +687,7 @@ void PictureLayerTiling::SetLiveTilesRect( |
new_live_tiles_rect); |
iter; |
++iter) { |
- RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin); |
+ RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin, true); |
} |
const PictureLayerTiling* twin_tiling = |