| Index: cc/resources/tiling_set_eviction_queue.cc
 | 
| diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
 | 
| index 8c5ff52f127099626c584429508b404d4ffce5e1..18f659ed53719e85778ff251d620949d8dcdc07c 100644
 | 
| --- a/cc/resources/tiling_set_eviction_queue.cc
 | 
| +++ b/cc/resources/tiling_set_eviction_queue.cc
 | 
| @@ -2,38 +2,53 @@
 | 
|  // Use of this source code is governed by a BSD-style license that can be
 | 
|  // found in the LICENSE file.
 | 
|  
 | 
| +#include <utility>
 | 
| +
 | 
|  #include "cc/resources/tiling_set_eviction_queue.h"
 | 
|  
 | 
|  namespace cc {
 | 
|  
 | 
|  TilingSetEvictionQueue::TilingSetEvictionQueue()
 | 
|      : tiling_set_(nullptr),
 | 
| +      tree_(ACTIVE_TREE),
 | 
|        tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
 | 
| -      current_category_(PictureLayerTiling::EVENTUALLY),
 | 
| +      skip_all_shared_tiles_(false),
 | 
| +      skip_shared_out_of_order_tiles_(false),
 | 
| +      processing_soon_border_rect_(false),
 | 
| +      processing_tiling_with_required_for_activation_tiles_(false),
 | 
| +      tiling_index_with_required_for_activation_tiles_(0u),
 | 
| +      current_priority_bin_(TilePriority::EVENTUALLY),
 | 
|        current_tiling_index_(0u),
 | 
|        current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
 | 
| -      current_eviction_tile_(nullptr),
 | 
| -      eviction_tiles_(nullptr),
 | 
| -      next_eviction_tile_index_(0u) {
 | 
| +      current_eviction_tile_(nullptr) {
 | 
|  }
 | 
|  
 | 
|  TilingSetEvictionQueue::TilingSetEvictionQueue(
 | 
|      PictureLayerTilingSet* tiling_set,
 | 
| -    TreePriority tree_priority)
 | 
| +    TreePriority tree_priority,
 | 
| +    bool skip_shared_out_of_order_tiles)
 | 
|      : tiling_set_(tiling_set),
 | 
| +      tree_(tiling_set->client()->GetTree()),
 | 
|        tree_priority_(tree_priority),
 | 
| -      current_category_(PictureLayerTiling::EVENTUALLY),
 | 
| +      skip_all_shared_tiles_(
 | 
| +          skip_shared_out_of_order_tiles &&
 | 
| +          tree_priority == (tree_ == ACTIVE_TREE ? NEW_CONTENT_TAKES_PRIORITY
 | 
| +                                                 : SMOOTHNESS_TAKES_PRIORITY)),
 | 
| +      skip_shared_out_of_order_tiles_(skip_shared_out_of_order_tiles),
 | 
| +      processing_soon_border_rect_(false),
 | 
| +      processing_tiling_with_required_for_activation_tiles_(false),
 | 
| +      tiling_index_with_required_for_activation_tiles_(0u),
 | 
| +      current_priority_bin_(TilePriority::EVENTUALLY),
 | 
|        current_tiling_index_(0u),
 | 
|        current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
 | 
| -      current_eviction_tile_(nullptr),
 | 
| -      eviction_tiles_(nullptr),
 | 
| -      next_eviction_tile_index_(0u) {
 | 
| -  DCHECK(tiling_set_);
 | 
| -
 | 
| +      current_eviction_tile_(nullptr) {
 | 
|    // Early out if the layer has no tilings.
 | 
|    if (!tiling_set_->num_tilings())
 | 
|      return;
 | 
|  
 | 
| +  tiling_index_with_required_for_activation_tiles_ =
 | 
| +      TilingIndexWithRequiredForActivationTiles();
 | 
| +
 | 
|    current_tiling_index_ = CurrentTilingRange().start - 1u;
 | 
|    AdvanceToNextValidTiling();
 | 
|  }
 | 
| @@ -62,60 +77,132 @@ const Tile* TilingSetEvictionQueue::Top() const {
 | 
|    return current_eviction_tile_;
 | 
|  }
 | 
|  
 | 
| -bool TilingSetEvictionQueue::AdvanceToNextCategory() {
 | 
| -  // Advance to the next category. This is done only after all tiling range
 | 
| -  // types within the previous category have been gone through.
 | 
| -  DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
 | 
| +bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
 | 
| +  // Advance to the next eviction tile within the current priority bin and
 | 
| +  // tiling. This is done while advancing to a new tiling and while popping
 | 
| +  // the current tile.
 | 
|  
 | 
| -  switch (current_category_) {
 | 
| -    case PictureLayerTiling::EVENTUALLY:
 | 
| -      current_category_ =
 | 
| -          PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
 | 
| -      return true;
 | 
| -    case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
 | 
| -      current_category_ = PictureLayerTiling::SOON;
 | 
| -      return true;
 | 
| -    case PictureLayerTiling::SOON:
 | 
| -      current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
 | 
| -      return true;
 | 
| -    case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
 | 
| -      current_category_ = PictureLayerTiling::NOW;
 | 
| -      return true;
 | 
| -    case PictureLayerTiling::NOW:
 | 
| -      current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
 | 
| -      return true;
 | 
| -    case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
 | 
| -      return false;
 | 
| -  }
 | 
| -  NOTREACHED();
 | 
| -  return false;
 | 
| -}
 | 
| +  bool required_for_activation =
 | 
| +      processing_tiling_with_required_for_activation_tiles_;
 | 
|  
 | 
| -bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
 | 
| -  // Advance to the next eviction tile within the current category and tiling.
 | 
| -  // This is done while advancing to a new tiling (in which case the next
 | 
| -  // eviction tile index is 0) and while popping the current tile (in which
 | 
| -  // case the next eviction tile index is greater than 0).
 | 
| -  DCHECK_EQ(next_eviction_tile_index_ > 0, current_eviction_tile_ != nullptr);
 | 
| -
 | 
| -  while (next_eviction_tile_index_ < eviction_tiles_->size()) {
 | 
| -    Tile* tile = (*eviction_tiles_)[next_eviction_tile_index_];
 | 
| -    ++next_eviction_tile_index_;
 | 
| -    if (tile->HasResources()) {
 | 
| +  for (;;) {
 | 
| +    while (spiral_iterator_) {
 | 
| +      std::pair<int, int> next_index = spiral_iterator_.index();
 | 
| +      Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
 | 
| +      ++spiral_iterator_;
 | 
| +      if (!tile || !tile->HasResources())
 | 
| +        continue;
 | 
| +      if (skip_all_shared_tiles_ && tile->is_shared())
 | 
| +        continue;
 | 
| +      current_tiling_->UpdateTileAndTwinPriority(tile);
 | 
| +      if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
 | 
| +        continue;
 | 
| +      if (tile->required_for_activation() != required_for_activation)
 | 
| +        continue;
 | 
|        current_eviction_tile_ = tile;
 | 
|        return true;
 | 
|      }
 | 
| +    if (processing_soon_border_rect_) {
 | 
| +      // Advance from soon border rect to skewport rect.
 | 
| +      processing_soon_border_rect_ = false;
 | 
| +      if (current_tiling_->has_skewport_rect_tiles_) {
 | 
| +        spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
 | 
| +            ¤t_tiling_->tiling_data_,
 | 
| +            current_tiling_->current_skewport_rect_,
 | 
| +            current_tiling_->current_visible_rect_,
 | 
| +            current_tiling_->current_visible_rect_);
 | 
| +        continue;
 | 
| +      }
 | 
| +    }
 | 
| +    break;
 | 
| +  }
 | 
| +
 | 
| +  TilePriority::PriorityBin max_tile_priority_bin =
 | 
| +      current_tiling_->client_->GetMaxTilePriorityBin();
 | 
| +  while (visible_iterator_) {
 | 
| +    std::pair<int, int> next_index = visible_iterator_.index();
 | 
| +    Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
 | 
| +    ++visible_iterator_;
 | 
| +    if (!tile || !tile->HasResources())
 | 
| +      continue;
 | 
| +    if (skip_all_shared_tiles_ && tile->is_shared())
 | 
| +      continue;
 | 
| +    // If the max tile priority is not NOW, updated priorities for tiles
 | 
| +    // returned by the visible iterator will not have NOW (but EVENTUALLY)
 | 
| +    // priority bin and cannot therefore be required for activation tiles nor
 | 
| +    // occluded NOW tiles in the current tiling.
 | 
| +    if (max_tile_priority_bin <= TilePriority::NOW) {
 | 
| +      // If the current tiling is a pending tree tiling, required for
 | 
| +      // activation tiles can be detected without updating tile priorities.
 | 
| +      if (tree_ == PENDING_TREE &&
 | 
| +          current_tiling_->IsTileRequiredForActivationIfVisible(tile) !=
 | 
| +              required_for_activation) {
 | 
| +        continue;
 | 
| +      }
 | 
| +      // Unoccluded NOW tiles should be evicted (and thus returned) only after
 | 
| +      // all occluded NOW tiles.
 | 
| +      if (!current_tiling_->IsTileOccluded(tile)) {
 | 
| +        unoccluded_now_tiles_.push_back(tile);
 | 
| +        continue;
 | 
| +      }
 | 
| +    }
 | 
| +    current_tiling_->UpdateTileAndTwinPriority(tile);
 | 
| +    if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
 | 
| +      continue;
 | 
| +    if (tile->required_for_activation() != required_for_activation)
 | 
| +      continue;
 | 
| +    current_eviction_tile_ = tile;
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  while (!unoccluded_now_tiles_.empty()) {
 | 
| +    // All (unoccluded) NOW tiles have the same priority bin (NOW) and the same
 | 
| +    // distance to visible (0.0), so it does not matter that tiles are popped
 | 
| +    // in reversed (FILO) order.
 | 
| +    Tile* tile = unoccluded_now_tiles_.back();
 | 
| +    unoccluded_now_tiles_.pop_back();
 | 
| +    DCHECK(tile);
 | 
| +    if (!tile->HasResources())
 | 
| +      continue;
 | 
| +    current_tiling_->UpdateTileAndTwinPriority(tile);
 | 
| +    if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
 | 
| +      continue;
 | 
| +    if (tile->required_for_activation() != required_for_activation)
 | 
| +      continue;
 | 
| +    current_eviction_tile_ = tile;
 | 
| +    return true;
 | 
|    }
 | 
|  
 | 
|    current_eviction_tile_ = nullptr;
 | 
|    return false;
 | 
|  }
 | 
|  
 | 
| +bool TilingSetEvictionQueue::AdvanceToNextPriorityBin() {
 | 
| +  // Advance to the next priority bin. This is done only after all tiling range
 | 
| +  // types (including the required for activation tiling) within the previous
 | 
| +  // priority bin have been gone through.
 | 
| +  DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
 | 
| +
 | 
| +  switch (current_priority_bin_) {
 | 
| +    case TilePriority::EVENTUALLY:
 | 
| +      current_priority_bin_ = TilePriority::SOON;
 | 
| +      return true;
 | 
| +    case TilePriority::SOON:
 | 
| +      current_priority_bin_ = TilePriority::NOW;
 | 
| +      return true;
 | 
| +    case TilePriority::NOW:
 | 
| +      return false;
 | 
| +  }
 | 
| +  NOTREACHED();
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
|  bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
 | 
| -  // Advance to the next tiling range type within the current category or to
 | 
| -  // the first tiling range type within the next category. This is done only
 | 
| -  // after all tilings within the previous tiling range type have been gone
 | 
| -  // through.
 | 
| +  // Advance to the next tiling range type within the current priority bin, to
 | 
| +  // the required for activation tiling range type within the current priority
 | 
| +  // bin or to the first tiling range type within the next priority bin. This
 | 
| +  // is done only after all tilings within the previous tiling range type have
 | 
| +  // been gone through.
 | 
|    DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
 | 
|  
 | 
|    switch (current_tiling_range_type_) {
 | 
| @@ -133,7 +220,15 @@ bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
 | 
|        current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
 | 
|        return true;
 | 
|      case PictureLayerTilingSet::HIGH_RES:
 | 
| -      if (!AdvanceToNextCategory())
 | 
| +      if (!processing_tiling_with_required_for_activation_tiles_ &&
 | 
| +          tiling_index_with_required_for_activation_tiles_ <
 | 
| +              tiling_set_->num_tilings()) {
 | 
| +        processing_tiling_with_required_for_activation_tiles_ = true;
 | 
| +        return true;
 | 
| +      }
 | 
| +      processing_tiling_with_required_for_activation_tiles_ = false;
 | 
| +
 | 
| +      if (!AdvanceToNextPriorityBin())
 | 
|          return false;
 | 
|  
 | 
|        current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
 | 
| @@ -145,10 +240,10 @@ bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
 | 
|  
 | 
|  bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
 | 
|    // Advance to the next tiling within current tiling range type or to
 | 
| -  // the first tiling within the next tiling range type or category until
 | 
| +  // the first tiling within the next tiling range type or priority bin until
 | 
|    // the next eviction tile is found. This is done only after all eviction
 | 
| -  // tiles within the previous tiling within the current category and tiling
 | 
| -  // range type have been gone through.
 | 
| +  // tiles within the previous tiling within the current priority bin and
 | 
| +  // tiling range type have been gone through.
 | 
|    DCHECK(!current_eviction_tile_);
 | 
|    DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
 | 
|  
 | 
| @@ -159,18 +254,54 @@ bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
 | 
|          return false;
 | 
|        current_tiling_index_ = CurrentTilingRange().start;
 | 
|      }
 | 
| +    current_tiling_ = tiling_set_->tiling_at(CurrentTilingIndex());
 | 
|  
 | 
| -    PictureLayerTiling* tiling = tiling_set_->tiling_at(CurrentTilingIndex());
 | 
| -    eviction_tiles_ =
 | 
| -        tiling->GetEvictionTiles(tree_priority_, current_category_);
 | 
| -    next_eviction_tile_index_ = 0u;
 | 
| -    if (AdvanceToNextEvictionTile())
 | 
| -      return true;
 | 
| +    switch (current_priority_bin_) {
 | 
| +      case TilePriority::EVENTUALLY:
 | 
| +        if (current_tiling_->has_eventually_rect_tiles_) {
 | 
| +          spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
 | 
| +              ¤t_tiling_->tiling_data_,
 | 
| +              current_tiling_->current_eventually_rect_,
 | 
| +              current_tiling_->current_skewport_rect_,
 | 
| +              current_tiling_->current_soon_border_rect_);
 | 
| +          if (AdvanceToNextEvictionTile())
 | 
| +            return true;
 | 
| +        }
 | 
| +        break;
 | 
| +      case TilePriority::SOON:
 | 
| +        if (current_tiling_->has_skewport_rect_tiles_ ||
 | 
| +            current_tiling_->has_soon_border_rect_tiles_) {
 | 
| +          processing_soon_border_rect_ = true;
 | 
| +          if (current_tiling_->has_soon_border_rect_tiles_)
 | 
| +            spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
 | 
| +                ¤t_tiling_->tiling_data_,
 | 
| +                current_tiling_->current_soon_border_rect_,
 | 
| +                current_tiling_->current_skewport_rect_,
 | 
| +                current_tiling_->current_visible_rect_);
 | 
| +          if (AdvanceToNextEvictionTile())
 | 
| +            return true;
 | 
| +        }
 | 
| +        break;
 | 
| +      case TilePriority::NOW:
 | 
| +        if (current_tiling_->has_visible_rect_tiles_) {
 | 
| +          visible_iterator_ =
 | 
| +              TilingData::Iterator(¤t_tiling_->tiling_data_,
 | 
| +                                   current_tiling_->current_visible_rect_,
 | 
| +                                   false /* include_borders */);
 | 
| +          if (AdvanceToNextEvictionTile())
 | 
| +            return true;
 | 
| +        }
 | 
| +        break;
 | 
| +    }
 | 
|    }
 | 
|  }
 | 
|  
 | 
|  PictureLayerTilingSet::TilingRange
 | 
|  TilingSetEvictionQueue::CurrentTilingRange() const {
 | 
| +  if (processing_tiling_with_required_for_activation_tiles_)
 | 
| +    return PictureLayerTilingSet::TilingRange(
 | 
| +        tiling_index_with_required_for_activation_tiles_,
 | 
| +        tiling_index_with_required_for_activation_tiles_ + 1);
 | 
|    return tiling_set_->GetTilingRange(current_tiling_range_type_);
 | 
|  }
 | 
|  
 | 
| @@ -194,4 +325,77 @@ size_t TilingSetEvictionQueue::CurrentTilingIndex() const {
 | 
|    return 0;
 | 
|  }
 | 
|  
 | 
| +bool TilingSetEvictionQueue::IsSharedOutOfOrderTile(const Tile* tile) const {
 | 
| +  if (!tile->is_shared())
 | 
| +    return false;
 | 
| +
 | 
| +  switch (tree_priority_) {
 | 
| +    case SMOOTHNESS_TAKES_PRIORITY:
 | 
| +      DCHECK_EQ(ACTIVE_TREE, tree_);
 | 
| +      return false;
 | 
| +    case NEW_CONTENT_TAKES_PRIORITY:
 | 
| +      DCHECK_EQ(PENDING_TREE, tree_);
 | 
| +      return false;
 | 
| +    case SAME_PRIORITY_FOR_BOTH_TREES:
 | 
| +      break;
 | 
| +    case NUM_TREE_PRIORITIES:
 | 
| +      NOTREACHED();
 | 
| +      break;
 | 
| +  }
 | 
| +
 | 
| +  // The priority for tile priority of a shared tile will be a combined
 | 
| +  // priority thus return shared tiles from a higher priority tree as
 | 
| +  // it is out of order for a lower priority tree.
 | 
| +  WhichTree twin_tree = tree_ == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
 | 
| +  const TilePriority& priority = tile->priority(tree_);
 | 
| +  const TilePriority& twin_priority = tile->priority(twin_tree);
 | 
| +  if (priority.priority_bin != twin_priority.priority_bin)
 | 
| +    return priority.priority_bin > twin_priority.priority_bin;
 | 
| +  const bool occluded = tile->is_occluded(tree_);
 | 
| +  const bool twin_occluded = tile->is_occluded(twin_tree);
 | 
| +  if (occluded != twin_occluded)
 | 
| +    return occluded;
 | 
| +  if (priority.distance_to_visible != twin_priority.distance_to_visible)
 | 
| +    return priority.distance_to_visible > twin_priority.distance_to_visible;
 | 
| +
 | 
| +  // If priorities are the same, it does not matter which tree returns
 | 
| +  // the tile. Let's pick the pending tree.
 | 
| +  return tree_ != PENDING_TREE;
 | 
| +}
 | 
| +
 | 
| +size_t TilingSetEvictionQueue::TilingIndexWithRequiredForActivationTiles()
 | 
| +    const {
 | 
| +  // Returns the tiling index of the tiling with requuired for activation tiles.
 | 
| +  // If no such tiling exists, returns the past-the-last index (num_tilings).
 | 
| +  size_t num_tilings = tiling_set_->num_tilings();
 | 
| +
 | 
| +  if (tree_ == PENDING_TREE) {
 | 
| +    // For the pending tree, the tiling with required for activation tiles is
 | 
| +    // the high res one.
 | 
| +    PictureLayerTilingSet::TilingRange high_res_tiling_range =
 | 
| +        tiling_set_->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
 | 
| +    if (high_res_tiling_range.start != high_res_tiling_range.end)
 | 
| +      return high_res_tiling_range.start;
 | 
| +  } else {
 | 
| +    DCHECK_EQ(ACTIVE_TREE, tree_);
 | 
| +    // Only pending tree tiles can be required for activation. They can appear
 | 
| +    // also in the active tree only if they are shared. If we skip all shared
 | 
| +    // tiles, there is no need to find them as they will not be returned.
 | 
| +    if (skip_all_shared_tiles_)
 | 
| +      return num_tilings;
 | 
| +
 | 
| +    // For the active tree, the tiling with required for activation tiles is
 | 
| +    // the one whose twin tiling is the high res pending tiling.
 | 
| +    for (size_t i = 0; i < num_tilings; ++i) {
 | 
| +      const PictureLayerTiling* tiling = tiling_set_->tiling_at(i);
 | 
| +      const PictureLayerTiling* pending_tiling =
 | 
| +          tiling_set_->client()->GetPendingOrActiveTwinTiling(tiling);
 | 
| +      if (pending_tiling && pending_tiling->resolution() == HIGH_RESOLUTION)
 | 
| +        return i;
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  return num_tilings;
 | 
|  }
 | 
| +
 | 
| +}  // namespace cc
 | 
| 
 |