summaryrefslogtreecommitdiffstats
path: root/cc/layers/picture_layer_impl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'cc/layers/picture_layer_impl.cc')
-rw-r--r--cc/layers/picture_layer_impl.cc92
1 files changed, 80 insertions, 12 deletions
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index a8fecb9..e0e9340 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -488,7 +488,7 @@ const Region* PictureLayerImpl::GetInvalidation() {
}
const PictureLayerTiling* PictureLayerImpl::GetTwinTiling(
- const PictureLayerTiling* tiling) {
+ const PictureLayerTiling* tiling) const {
if (!twin_layer_)
return NULL;
@@ -659,6 +659,10 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
DCHECK(ideal_contents_scale_);
DCHECK_GT(tilings_->num_tilings(), 0u);
+ // The goal of this function is to find the minimum set of tiles that need to
+ // be ready to draw in order to activate without flashing content from a
+ // higher res on the active tree to a lower res on the pending tree.
+
gfx::Rect rect(visible_content_rect());
float min_acceptable_scale =
@@ -675,17 +679,21 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
}
}
- // Mark tiles for activation in two passes. Ready to draw tiles in acceptable
- // but non-ideal tilings are marked as required for activation, but any
- // non-ready tiles are not marked as required. From there, any missing holes
- // will need to be filled in from the high res tiling.
-
PictureLayerTiling* high_res = NULL;
+ PictureLayerTiling* low_res = NULL;
+
+ // First pass: ready to draw tiles in acceptable but non-ideal tilings are
+ // marked as required for activation so that their textures are not thrown
+ // away; any non-ready tiles are not marked as required.
Region missing_region = rect;
for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
PictureLayerTiling* tiling = tilings_->tiling_at(i);
DCHECK(tiling->has_ever_been_updated());
+ if (tiling->resolution() == LOW_RESOLUTION) {
+ DCHECK(!low_res) << "There can only be one low res tiling";
+ low_res = tiling;
+ }
if (tiling->contents_scale() < min_acceptable_scale)
continue;
if (tiling->resolution() == HIGH_RESOLUTION) {
@@ -711,21 +719,69 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
iter->MarkRequiredForActivation();
}
}
-
DCHECK(high_res) << "There must be one high res tiling";
- for (PictureLayerTiling::CoverageIterator iter(high_res,
- contents_scale_x(),
+
+ // If these pointers are null (because no twin, no matching tiling, or the
+ // simpification just below), then high res tiles will be required to fill any
+ // holes left by the first pass above. If the pointers are valid, then this
+ // layer is allowed to skip any tiles that are not ready on its twin.
+ const PictureLayerTiling* twin_high_res = NULL;
+ const PictureLayerTiling* twin_low_res = NULL;
+
+ // As a simplification, only allow activating to skip twin tiles that the
+ // active layer is also missing when both this layer and its twin have 2
+ // tilings (high and low). This avoids having to iterate/track coverage of
+ // non-ideal tilings during the last draw call on the active layer.
+ if (high_res && low_res && tilings_->num_tilings() == 2 &&
+ twin_layer_ && twin_layer_->tilings_->num_tilings() == 2) {
+ twin_low_res = GetTwinTiling(low_res);
+ if (twin_low_res)
+ twin_high_res = GetTwinTiling(high_res);
+ }
+ // If this layer and its twin have different transforms, then don't compare
+ // them and only allow activating to high res tiles, since tiles on each layer
+ // will be in different places on screen.
+ if (!twin_high_res || !twin_low_res ||
+ draw_properties().screen_space_transform !=
+ twin_layer_->draw_properties().screen_space_transform) {
+ twin_high_res = NULL;
+ twin_low_res = NULL;
+ }
+
+ // As a second pass, mark as required any visible high res tiles not filled in
+ // by acceptable non-ideal tiles from the first pass.
+ if (MarkVisibleTilesAsRequired(
+ high_res, twin_high_res, contents_scale_x(), rect, missing_region)) {
+ // As an optional third pass, if a high res tile was skipped because its
+ // twin was also missing, then fall back to mark low res tiles as required
+ // in case the active twin is substituting those for missing high res
+ // content.
+ MarkVisibleTilesAsRequired(
+ low_res, twin_low_res, contents_scale_x(), rect, missing_region);
+ }
+}
+
+bool PictureLayerImpl::MarkVisibleTilesAsRequired(
+ PictureLayerTiling* tiling,
+ const PictureLayerTiling* optional_twin_tiling,
+ float contents_scale,
+ gfx::Rect rect,
+ const Region& missing_region) const {
+ bool twin_had_missing_tile = false;
+ for (PictureLayerTiling::CoverageIterator iter(tiling,
+ contents_scale,
rect);
iter;
++iter) {
+ Tile* tile = *iter;
// A null tile (i.e. missing recording) can just be skipped.
- if (!*iter)
+ if (!tile)
continue;
// This iteration is over the visible content rect which is potentially
// less conservative than projecting the viewport into the layer.
// Ignore tiles that are know to be outside the viewport.
- if (iter->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
+ if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
continue;
// If the missing region doesn't cover it, this tile is fully
@@ -733,8 +789,20 @@ void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
if (!missing_region.Intersects(iter.geometry_rect()))
continue;
- iter->MarkRequiredForActivation();
+ // If the twin tile doesn't exist (i.e. missing recording or so far away
+ // that it is outside the visible tile rect) or this tile is shared between
+ // with the twin, then this tile isn't required to prevent flashing.
+ if (optional_twin_tiling) {
+ Tile* twin_tile = optional_twin_tiling->TileAt(iter.i(), iter.j());
+ if (!twin_tile || twin_tile == tile) {
+ twin_had_missing_tile = true;
+ continue;
+ }
+ }
+
+ tile->MarkRequiredForActivation();
}
+ return twin_had_missing_tile;
}
void PictureLayerImpl::DoPostCommitInitialization() {