diff options
Diffstat (limited to 'cc/layers/picture_layer_impl.cc')
-rw-r--r-- | cc/layers/picture_layer_impl.cc | 92 |
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() { |