#include <algorithm>
#include <cmath>
#include <limits>
+#include <set>
#include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
+#include "base/logging.h"
#include "cc/base/math_util.h"
#include "cc/resources/tile.h"
#include "cc/resources/tile_priority.h"
const TilePriority& b_priority =
b->priority_for_tree_priority(tree_priority_);
- if (a_priority.priority_bin == b_priority.priority_bin &&
- a->required_for_activation() != b->required_for_activation()) {
- return b->required_for_activation();
- }
- return b_priority.IsHigherPriorityThan(a_priority);
+ DCHECK(a_priority.priority_bin == b_priority.priority_bin);
+ DCHECK(a->required_for_activation() == b->required_for_activation());
+
+ // Or if a is occluded and b is unoccluded.
+ bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_);
+ bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_);
+ if (a_is_occluded != b_is_occluded)
+ return a_is_occluded;
+
+ // Or if a is farther away from visible.
+ return a_priority.distance_to_visible > b_priority.distance_to_visible;
}
private:
TreePriority tree_priority_;
};
+
+void ReleaseTile(Tile* tile, WhichTree tree) {
+ // Reset priority as tile is ref-counted and might still be used
+ // even though we no longer hold a reference to it here anymore.
+ tile->SetPriority(tree, TilePriority());
+ tile->set_shared(false);
+}
+
} // namespace
scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
layer_bounds_(layer_bounds),
resolution_(NON_IDEAL_RESOLUTION),
client_(client),
- tiling_data_(gfx::Size(), gfx::Rect(), true),
+ tiling_data_(gfx::Size(), gfx::Size(), true),
last_impl_frame_time_in_seconds_(0.0),
+ has_visible_rect_tiles_(false),
+ has_skewport_rect_tiles_(false),
+ has_soon_border_rect_tiles_(false),
+ has_eventually_rect_tiles_(false),
eviction_tiles_cache_valid_(false),
eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
gfx::Size content_bounds =
gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
+ if (tile_size.IsEmpty()) {
+ layer_bounds_ = gfx::Size();
+ content_bounds = gfx::Size();
+ }
DCHECK(!gfx::ToFlooredSize(
gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
" Layer bounds: " << layer_bounds.ToString() <<
" Contents scale: " << contents_scale;
- tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
+ tiling_data_.SetTilingSize(content_bounds);
tiling_data_.SetMaxTextureSize(tile_size);
}
PictureLayerTiling::~PictureLayerTiling() {
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+ ReleaseTile(it->second.get(), client_->GetTree());
}
void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
client_ = client;
}
-gfx::Rect PictureLayerTiling::TilingRect() const {
- return tiling_data_.tiling_rect();
-}
-
Tile* PictureLayerTiling::CreateTile(int i,
int j,
const PictureLayerTiling* twin_tiling) {
gfx::Rect rect =
gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
if (!client_->GetInvalidation()->Intersects(rect)) {
+ DCHECK(!candidate_tile->is_shared());
+ candidate_tile->set_shared(true);
tiles_[key] = candidate_tile;
return candidate_tile;
}
// Create a new tile because our twin didn't have a valid one.
scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
- if (tile.get())
+ if (tile.get()) {
+ DCHECK(!tile->is_shared());
tiles_[key] = tile;
+ }
return tile.get();
}
void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
- bool include_borders = true;
+ bool include_borders = false;
for (TilingData::Iterator iter(
&tiling_data_, live_tiles_rect_, include_borders);
iter;
continue;
CreateTile(key.first, key.second, twin_tiling);
}
+
+ VerifyLiveTilesRect();
}
-void PictureLayerTiling::SetLayerBounds(const gfx::Size& layer_bounds) {
- if (layer_bounds_ == layer_bounds)
- return;
+void PictureLayerTiling::UpdateTilesToCurrentPile(
+ const Region& layer_invalidation,
+ const gfx::Size& new_layer_bounds) {
+ DCHECK(!new_layer_bounds.IsEmpty());
- DCHECK(!layer_bounds.IsEmpty());
+ gfx::Size tile_size = tiling_data_.max_texture_size();
- gfx::Size old_layer_bounds = layer_bounds_;
- layer_bounds_ = layer_bounds;
- gfx::Size content_bounds =
- gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_));
+ if (new_layer_bounds != layer_bounds_) {
+ gfx::Size content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+
+ tile_size = client_->CalculateTileSize(content_bounds);
+ if (tile_size.IsEmpty()) {
+ layer_bounds_ = gfx::Size();
+ content_bounds = gfx::Size();
+ } else {
+ layer_bounds_ = new_layer_bounds;
+ }
+
+ // The SetLiveTilesRect() method would drop tiles outside the new bounds,
+ // but may do so incorrectly if resizing the tiling causes the number of
+ // tiles in the tiling_data_ to change.
+ gfx::Rect content_rect(content_bounds);
+ int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
+ int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
+ int before_right =
+ tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+ int before_bottom =
+ tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+
+ // The live_tiles_rect_ is clamped to stay within the tiling size as we
+ // change it.
+ live_tiles_rect_.Intersect(content_rect);
+ tiling_data_.SetTilingSize(content_bounds);
+
+ int after_right = -1;
+ int after_bottom = -1;
+ if (!live_tiles_rect_.IsEmpty()) {
+ after_right =
+ tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+ after_bottom =
+ tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+ }
+
+ // 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());
+
+ // 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);
+ }
+ for (int i = before_left; i <= after_right; ++i) {
+ for (int j = after_bottom + 1; j <= before_bottom; ++j)
+ RemoveTileAt(i, j, recycled_twin);
+ }
+
+ // If the layer grew, the live_tiles_rect_ is not changed, but a new row
+ // and/or column of tiles may now exist inside the same live_tiles_rect_.
+ const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
+ if (after_right > before_right) {
+ DCHECK_EQ(after_right, before_right + 1);
+ for (int j = before_top; j <= after_bottom; ++j)
+ CreateTile(after_right, j, twin_tiling);
+ }
+ if (after_bottom > before_bottom) {
+ DCHECK_EQ(after_bottom, before_bottom + 1);
+ for (int i = before_left; i <= before_right; ++i)
+ CreateTile(i, after_bottom, twin_tiling);
+ }
+ }
- gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
if (tile_size != tiling_data_.max_texture_size()) {
- tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
tiling_data_.SetMaxTextureSize(tile_size);
+ // When the tile size changes, the TilingData positions no longer work
+ // as valid keys to the TileMap, so just drop all tiles.
Reset();
- return;
+ } else {
+ Invalidate(layer_invalidation);
}
- // Any tiles outside our new bounds are invalid and should be dropped.
- gfx::Rect bounded_live_tiles_rect(live_tiles_rect_);
- bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds));
- SetLiveTilesRect(bounded_live_tiles_rect);
- tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
-
- // Create tiles for newly exposed areas.
- Region layer_region((gfx::Rect(layer_bounds_)));
- layer_region.Subtract(gfx::Rect(old_layer_bounds));
- Invalidate(layer_region);
+ PicturePileImpl* pile = client_->GetPile();
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+ it->second->set_picture_pile(pile);
+ VerifyLiveTilesRect();
}
void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
- DoInvalidate(layer_region, false /* recreate_tiles */);
+ bool recreate_invalidated_tiles = false;
+ DoInvalidate(layer_region, recreate_invalidated_tiles);
}
void PictureLayerTiling::Invalidate(const Region& layer_region) {
- DoInvalidate(layer_region, true /* recreate_tiles */);
+ bool recreate_invalidated_tiles = true;
+ DoInvalidate(layer_region, recreate_invalidated_tiles);
}
void PictureLayerTiling::DoInvalidate(const Region& layer_region,
- bool recreate_tiles) {
+ bool recreate_invalidated_tiles) {
std::vector<TileMapKey> new_tile_keys;
- gfx::Rect expanded_live_tiles_rect(
- tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_));
+ gfx::Rect expanded_live_tiles_rect =
+ tiling_data_.ExpandRectIgnoringBordersToTileBounds(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_);
+ // Consider tiles inside the live tiles rect even if only their border
+ // pixels intersect the invalidation. But don't consider tiles outside
+ // the live tiles rect with the same conditions, as they won't exist.
+ int border_pixels = tiling_data_.border_texels();
+ content_rect.Inset(-border_pixels, -border_pixels);
// 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;
+ // Since the content_rect includes border pixels already, don't include
+ // borders when iterating to avoid double counting them.
+ bool include_borders = false;
for (TilingData::Iterator iter(
&tiling_data_, content_rect, include_borders);
iter;
++iter) {
- TileMapKey key(iter.index());
- TileMap::iterator find = tiles_.find(key);
- if (find == tiles_.end())
- continue;
- tiles_.erase(find);
- if (recreate_tiles)
- new_tile_keys.push_back(key);
+ // 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))
+ new_tile_keys.push_back(iter.index());
}
}
- if (recreate_tiles) {
- const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
- for (size_t i = 0; i < new_tile_keys.size(); ++i)
+ if (recreate_invalidated_tiles && !new_tile_keys.empty()) {
+ for (size_t i = 0; i < new_tile_keys.size(); ++i) {
+ // Don't try to share a tile with the twin layer, it's been invalidated so
+ // we have to make our own tile here.
+ const PictureLayerTiling* twin_tiling = NULL;
CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
+ }
}
}
dest_to_content_scale_);
// IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
// check for non-intersection first.
- content_rect.Intersect(tiling_->TilingRect());
+ content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
if (content_rect.IsEmpty())
return;
gfx::RectF texture_rect(current_geometry_rect_);
texture_rect.Scale(dest_to_content_scale_,
dest_to_content_scale_);
- texture_rect.Intersect(tiling_->TilingRect());
+ texture_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
if (texture_rect.IsEmpty())
return texture_rect;
texture_rect.Offset(-tex_origin.OffsetFromOrigin());
return tiling_->tiling_data_.max_texture_size();
}
+bool PictureLayerTiling::RemoveTileAt(int i,
+ int j,
+ PictureLayerTiling* recycled_twin) {
+ TileMap::iterator found = tiles_.find(TileMapKey(i, j));
+ if (found == tiles_.end())
+ return false;
+ ReleaseTile(found->second.get(), client_->GetTree());
+ tiles_.erase(found);
+ if (recycled_twin) {
+ // Recycled twin does not also have a recycled twin, so pass NULL.
+ recycled_twin->RemoveTileAt(i, j, NULL);
+ }
+ return true;
+}
+
void PictureLayerTiling::Reset() {
live_tiles_rect_ = gfx::Rect();
+ PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+ ReleaseTile(it->second.get(), client_->GetTree());
+ if (recycled_twin)
+ recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL);
+ }
tiles_.clear();
}
void PictureLayerTiling::UpdateTilePriorities(
WhichTree tree,
- const gfx::Rect& visible_layer_rect,
- float layer_contents_scale,
- double current_frame_time_in_seconds) {
+ const gfx::Rect& viewport_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space) {
if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) {
// This should never be zero for the purposes of has_ever_been_updated().
DCHECK_NE(current_frame_time_in_seconds, 0.0);
}
gfx::Rect visible_rect_in_content_space =
- gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
+ gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
- if (TilingRect().IsEmpty()) {
+ if (tiling_size().IsEmpty()) {
last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
last_visible_rect_in_content_space_ = visible_rect_in_content_space;
return;
gfx::Rect eventually_rect =
ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
eventually_rect_area,
- TilingRect(),
+ gfx::Rect(tiling_size()),
&expansion_cache_);
- DCHECK(eventually_rect.IsEmpty() || TilingRect().Contains(eventually_rect));
+ DCHECK(eventually_rect.IsEmpty() ||
+ gfx::Rect(tiling_size()).Contains(eventually_rect))
+ << "tiling_size: " << tiling_size().ToString()
+ << " eventually_rect: " << eventually_rect.ToString();
SetLiveTilesRect(eventually_rect);
last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
last_visible_rect_in_content_space_ = visible_rect_in_content_space;
- current_visible_rect_in_content_space_ = visible_rect_in_content_space;
- current_skewport_ = skewport;
- current_eventually_rect_ = eventually_rect;
eviction_tiles_cache_valid_ = false;
TilePriority now_priority(resolution_, TilePriority::NOW, 0);
- float content_to_screen_scale =
- 1.0f / (contents_scale_ * layer_contents_scale);
+ float content_to_screen_scale = ideal_contents_scale / contents_scale_;
// Assign now priority to all visible tiles.
- bool include_borders = true;
+ bool include_borders = false;
+ has_visible_rect_tiles_ = false;
for (TilingData::Iterator iter(
&tiling_data_, visible_rect_in_content_space, include_borders);
iter;
TileMap::iterator find = tiles_.find(iter.index());
if (find == tiles_.end())
continue;
+ has_visible_rect_tiles_ = true;
Tile* tile = find->second.get();
tile->SetPriority(tree, now_priority);
+
+ // Set whether tile is occluded or not.
+ gfx::Rect tile_query_rect = ScaleToEnclosingRect(
+ IntersectRects(tile->content_rect(), visible_rect_in_content_space),
+ 1.0f / contents_scale_);
+ bool is_occluded = occlusion_in_layer_space.IsOccluded(tile_query_rect);
+ tile->set_is_occluded(tree, is_occluded);
}
// Assign soon priority to skewport tiles.
+ has_skewport_rect_tiles_ = false;
for (TilingData::DifferenceIterator iter(
&tiling_data_, skewport, visible_rect_in_content_space);
iter;
TileMap::iterator find = tiles_.find(iter.index());
if (find == tiles_.end())
continue;
+ has_skewport_rect_tiles_ = true;
Tile* tile = find->second.get();
gfx::Rect tile_bounds =
}
// Assign eventually priority to interest rect tiles.
+ has_eventually_rect_tiles_ = false;
for (TilingData::DifferenceIterator iter(
&tiling_data_, eventually_rect, skewport);
iter;
TileMap::iterator find = tiles_.find(iter.index());
if (find == tiles_.end())
continue;
+ has_eventually_rect_tiles_ = true;
Tile* tile = find->second.get();
gfx::Rect tile_bounds =
}
// Upgrade the priority on border tiles to be SOON.
- current_soon_border_rect_ = visible_rect_in_content_space;
+ gfx::Rect soon_border_rect = visible_rect_in_content_space;
float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
- current_soon_border_rect_.Inset(-border, -border, -border, -border);
+ soon_border_rect.Inset(-border, -border, -border, -border);
+ has_soon_border_rect_tiles_ = false;
for (TilingData::DifferenceIterator iter(
- &tiling_data_, current_soon_border_rect_, skewport);
+ &tiling_data_, soon_border_rect, skewport);
iter;
++iter) {
TileMap::iterator find = tiles_.find(iter.index());
if (find == tiles_.end())
continue;
+ has_soon_border_rect_tiles_ = true;
Tile* tile = find->second.get();
TilePriority priority(resolution_,
tile->priority(tree).distance_to_visible);
tile->SetPriority(tree, priority);
}
+
+ // Update iteration rects.
+ current_visible_rect_ = visible_rect_in_content_space;
+ current_skewport_rect_ = skewport;
+ current_soon_border_rect_ = soon_border_rect;
+ current_eventually_rect_ = eventually_rect;
}
void PictureLayerTiling::SetLiveTilesRect(
const gfx::Rect& new_live_tiles_rect) {
DCHECK(new_live_tiles_rect.IsEmpty() ||
- TilingRect().Contains(new_live_tiles_rect));
+ gfx::Rect(tiling_size()).Contains(new_live_tiles_rect))
+ << "tiling_size: " << tiling_size().ToString()
+ << " new_live_tiles_rect: " << new_live_tiles_rect.ToString();
if (live_tiles_rect_ == new_live_tiles_rect)
return;
// Iterate to delete all tiles outside of our new live_tiles rect.
+ PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
for (TilingData::DifferenceIterator iter(&tiling_data_,
live_tiles_rect_,
new_live_tiles_rect);
iter;
++iter) {
- TileMapKey key(iter.index());
- TileMap::iterator found = tiles_.find(key);
- // If the tile was outside of the recorded region, it won't exist even
- // though it was in the live rect.
- if (found != tiles_.end())
- tiles_.erase(found);
+ RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin);
}
const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
}
live_tiles_rect_ = new_live_tiles_rect;
+ VerifyLiveTilesRect();
+}
+
+void PictureLayerTiling::VerifyLiveTilesRect() {
+#if DCHECK_IS_ON
+ for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+ if (!it->second.get())
+ continue;
+ DCHECK(it->first.first < tiling_data_.num_tiles_x())
+ << this << " " << it->first.first << "," << it->first.second
+ << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
+ << live_tiles_rect_.ToString();
+ DCHECK(it->first.second < tiling_data_.num_tiles_y())
+ << this << " " << it->first.first << "," << it->first.second
+ << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
+ << live_tiles_rect_.ToString();
+ DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
+ .Intersects(live_tiles_rect_))
+ << this << " " << it->first.first << "," << it->first.second
+ << " tile bounds "
+ << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
+ << " live_tiles_rect " << live_tiles_rect_.ToString();
+ }
+#endif
}
void PictureLayerTiling::DidBecomeRecycled() {
}
void PictureLayerTiling::DidBecomeActive() {
+ PicturePileImpl* active_pile = client_->GetPile();
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE));
it->second->SetPriority(PENDING_TREE, TilePriority());
// Tile holds a ref onto a picture pile. If the tile never gets invalidated
// and recreated, then that picture pile ref could exist indefinitely. To
// prevent this, ask the client to update the pile to its own ref. This
- // will cause PicturePileImpls and their clones to get deleted once the
- // corresponding PictureLayerImpl and any in flight raster jobs go out of
- // scope.
- client_->UpdatePile(it->second.get());
+ // will cause PicturePileImpls to get deleted once the corresponding
+ // PictureLayerImpl and any in flight raster jobs go out of scope.
+ it->second->set_picture_pile(active_pile);
}
}
-void PictureLayerTiling::UpdateTilesToCurrentPile() {
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
- client_->UpdatePile(it->second.get());
- }
+void PictureLayerTiling::GetAllTilesForTracing(
+ std::set<const Tile*>* tiles) const {
+ for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+ tiles->insert(it->second.get());
}
-scoped_ptr<base::Value> PictureLayerTiling::AsValue() const {
- scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
+void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const {
state->SetInteger("num_tiles", tiles_.size());
state->SetDouble("content_scale", contents_scale_);
- state->Set("tiling_rect", MathUtil::AsValue(TilingRect()).release());
- return state.PassAs<base::Value>();
+ state->BeginDictionary("tiling_size");
+ MathUtil::AddToTracedValue(tiling_size(), state);
+ state->EndDictionary();
}
size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
int64 c = static_cast<int64>(width) * height - target_area;
// Compute the delta for our edges using the quadratic equation.
- return a == 0 ? -c / b :
- (-b + static_cast<int>(
- std::sqrt(static_cast<int64>(b) * b - 4.0 * a * c))) / (2 * a);
+ int delta =
+ (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt(
+ static_cast<int64>(b) * b - 4.0 * a * c))) /
+ (2 * a);
+ return std::max(0, delta);
}
} // namespace
eviction_cache_tree_priority_ == tree_priority)
return;
- eviction_tiles_cache_.clear();
- eviction_tiles_cache_.reserve(tiles_.size());
+ eviction_tiles_now_.clear();
+ eviction_tiles_now_and_required_for_activation_.clear();
+ eviction_tiles_soon_.clear();
+ eviction_tiles_soon_and_required_for_activation_.clear();
+ eviction_tiles_eventually_.clear();
+ eviction_tiles_eventually_and_required_for_activation_.clear();
+
for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
// TODO(vmpstr): This should update the priority if UpdateTilePriorities
// changes not to do this.
- eviction_tiles_cache_.push_back(it->second);
+ Tile* tile = it->second.get();
+ const TilePriority& priority =
+ tile->priority_for_tree_priority(tree_priority);
+ switch (priority.priority_bin) {
+ case TilePriority::EVENTUALLY:
+ if (tile->required_for_activation())
+ eviction_tiles_eventually_and_required_for_activation_.push_back(
+ tile);
+ else
+ eviction_tiles_eventually_.push_back(tile);
+ break;
+ case TilePriority::SOON:
+ if (tile->required_for_activation())
+ eviction_tiles_soon_and_required_for_activation_.push_back(tile);
+ else
+ eviction_tiles_soon_.push_back(tile);
+ break;
+ case TilePriority::NOW:
+ if (tile->required_for_activation())
+ eviction_tiles_now_and_required_for_activation_.push_back(tile);
+ else
+ eviction_tiles_now_.push_back(tile);
+ break;
+ }
}
- std::sort(eviction_tiles_cache_.begin(),
- eviction_tiles_cache_.end(),
- TileEvictionOrder(tree_priority));
+ // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that
+ // can be updated for each of the queues.
+ TileEvictionOrder sort_order(tree_priority);
+ std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order);
+ std::sort(eviction_tiles_now_and_required_for_activation_.begin(),
+ eviction_tiles_now_and_required_for_activation_.end(),
+ sort_order);
+ std::sort(
+ eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order);
+ std::sort(eviction_tiles_soon_and_required_for_activation_.begin(),
+ eviction_tiles_soon_and_required_for_activation_.end(),
+ sort_order);
+ std::sort(eviction_tiles_eventually_.begin(),
+ eviction_tiles_eventually_.end(),
+ sort_order);
+ std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(),
+ eviction_tiles_eventually_and_required_for_activation_.end(),
+ sort_order);
+
eviction_tiles_cache_valid_ = true;
eviction_cache_tree_priority_ = tree_priority;
}
+const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles(
+ TreePriority tree_priority,
+ EvictionCategory category) {
+ UpdateEvictionCacheIfNeeded(tree_priority);
+ switch (category) {
+ case EVENTUALLY:
+ return &eviction_tiles_eventually_;
+ case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
+ return &eviction_tiles_eventually_and_required_for_activation_;
+ case SOON:
+ return &eviction_tiles_soon_;
+ case SOON_AND_REQUIRED_FOR_ACTIVATION:
+ return &eviction_tiles_soon_and_required_for_activation_;
+ case NOW:
+ return &eviction_tiles_now_;
+ case NOW_AND_REQUIRED_FOR_ACTIVATION:
+ return &eviction_tiles_now_and_required_for_activation_;
+ }
+ NOTREACHED();
+ return &eviction_tiles_eventually_;
+}
+
PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
: tiling_(NULL), current_tile_(NULL) {}
PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
PictureLayerTiling* tiling,
WhichTree tree)
- : tiling_(tiling),
- type_(TilePriority::NOW),
- visible_rect_in_content_space_(
- tiling_->current_visible_rect_in_content_space_),
- skewport_in_content_space_(tiling_->current_skewport_),
- eventually_rect_in_content_space_(tiling_->current_eventually_rect_),
- soon_border_rect_in_content_space_(tiling_->current_soon_border_rect_),
- tree_(tree),
- current_tile_(NULL),
- visible_iterator_(&tiling->tiling_data_,
- visible_rect_in_content_space_,
- true /* include_borders */),
- spiral_iterator_(&tiling->tiling_data_,
- skewport_in_content_space_,
- visible_rect_in_content_space_,
- visible_rect_in_content_space_),
- skewport_processed_(false) {
+ : tiling_(tiling), phase_(VISIBLE_RECT), tree_(tree), current_tile_(NULL) {
+ if (!tiling_->has_visible_rect_tiles_) {
+ AdvancePhase();
+ return;
+ }
+
+ visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_,
+ tiling_->current_visible_rect_,
+ false /* include_borders */);
if (!visible_iterator_) {
AdvancePhase();
return;
PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
- DCHECK_LT(type_, TilePriority::EVENTUALLY);
+ DCHECK_LT(phase_, EVENTUALLY_RECT);
do {
- type_ = static_cast<TilePriority::PriorityBin>(type_ + 1);
- if (type_ == TilePriority::EVENTUALLY) {
- spiral_iterator_ = TilingData::SpiralDifferenceIterator(
- &tiling_->tiling_data_,
- eventually_rect_in_content_space_,
- skewport_in_content_space_,
- visible_rect_in_content_space_);
+ phase_ = static_cast<Phase>(phase_ + 1);
+ switch (phase_) {
+ case VISIBLE_RECT:
+ NOTREACHED();
+ return;
+ case SKEWPORT_RECT:
+ if (!tiling_->has_skewport_rect_tiles_)
+ continue;
+
+ spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+ &tiling_->tiling_data_,
+ tiling_->current_skewport_rect_,
+ tiling_->current_visible_rect_,
+ tiling_->current_visible_rect_);
+ break;
+ case SOON_BORDER_RECT:
+ if (!tiling_->has_soon_border_rect_tiles_)
+ continue;
+
+ spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+ &tiling_->tiling_data_,
+ tiling_->current_soon_border_rect_,
+ tiling_->current_skewport_rect_,
+ tiling_->current_visible_rect_);
+ break;
+ case EVENTUALLY_RECT:
+ if (!tiling_->has_eventually_rect_tiles_) {
+ current_tile_ = NULL;
+ return;
+ }
+
+ spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+ &tiling_->tiling_data_,
+ tiling_->current_eventually_rect_,
+ tiling_->current_skewport_rect_,
+ tiling_->current_soon_border_rect_);
+ break;
}
while (spiral_iterator_) {
++spiral_iterator_;
}
- if (!spiral_iterator_ && type_ == TilePriority::EVENTUALLY) {
+ if (!spiral_iterator_ && phase_ == EVENTUALLY_RECT) {
current_tile_ = NULL;
break;
}
current_tile_ = NULL;
while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
std::pair<int, int> next_index;
- switch (type_) {
- case TilePriority::NOW:
+ switch (phase_) {
+ case VISIBLE_RECT:
++visible_iterator_;
if (!visible_iterator_) {
AdvancePhase();
}
next_index = visible_iterator_.index();
break;
- case TilePriority::SOON:
+ case SKEWPORT_RECT:
+ case SOON_BORDER_RECT:
++spiral_iterator_;
if (!spiral_iterator_) {
- if (skewport_processed_) {
- AdvancePhase();
- return *this;
- }
- skewport_processed_ = true;
- spiral_iterator_ = TilingData::SpiralDifferenceIterator(
- &tiling_->tiling_data_,
- soon_border_rect_in_content_space_,
- skewport_in_content_space_,
- visible_rect_in_content_space_);
- if (!spiral_iterator_) {
- AdvancePhase();
- return *this;
- }
+ AdvancePhase();
+ return *this;
}
next_index = spiral_iterator_.index();
break;
- case TilePriority::EVENTUALLY:
+ case EVENTUALLY_RECT:
++spiral_iterator_;
if (!spiral_iterator_) {
current_tile_ = NULL;
}
PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
- : is_valid_(false), tiling_(NULL) {}
+ : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
+}
PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
PictureLayerTiling* tiling,
- TreePriority tree_priority)
- : is_valid_(false), tiling_(tiling), tree_priority_(tree_priority) {}
-
-PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {}
+ TreePriority tree_priority,
+ EvictionCategory category)
+ : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
+ // Note: initializing to "0 - 1" works as overflow is well defined for
+ // unsigned integers.
+ current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
+ DCHECK(eviction_tiles_);
+ ++(*this);
+}
-PictureLayerTiling::TilingEvictionTileIterator::operator bool() {
- if (!IsValid())
- Initialize();
+PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
+}
- return IsValid() && tile_iterator_ != tiling_->eviction_tiles_cache_.end();
+PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
+ return eviction_tiles_ &&
+ current_eviction_tiles_index_ != eviction_tiles_->size();
}
Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
- if (!IsValid())
- Initialize();
+ DCHECK(*this);
+ return (*eviction_tiles_)[current_eviction_tiles_index_];
+}
+const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
DCHECK(*this);
- return *tile_iterator_;
+ return (*eviction_tiles_)[current_eviction_tiles_index_];
}
PictureLayerTiling::TilingEvictionTileIterator&
operator++() {
DCHECK(*this);
do {
- ++tile_iterator_;
- } while (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
- (!(*tile_iterator_)->HasResources()));
+ ++current_eviction_tiles_index_;
+ } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
+ !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
return *this;
}
-void PictureLayerTiling::TilingEvictionTileIterator::Initialize() {
- if (!tiling_)
- return;
-
- tiling_->UpdateEvictionCacheIfNeeded(tree_priority_);
- tile_iterator_ = tiling_->eviction_tiles_cache_.begin();
- is_valid_ = true;
- if (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
- !(*tile_iterator_)->HasResources()) {
- ++(*this);
- }
-}
-
} // namespace cc