blob: 8c5ff52f127099626c584429508b404d4ffce5e1 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/resources/tiling_set_eviction_queue.h"
namespace cc {
TilingSetEvictionQueue::TilingSetEvictionQueue()
: tiling_set_(nullptr),
tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
current_category_(PictureLayerTiling::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) {
}
TilingSetEvictionQueue::TilingSetEvictionQueue(
PictureLayerTilingSet* tiling_set,
TreePriority tree_priority)
: tiling_set_(tiling_set),
tree_priority_(tree_priority),
current_category_(PictureLayerTiling::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_);
// Early out if the layer has no tilings.
if (!tiling_set_->num_tilings())
return;
current_tiling_index_ = CurrentTilingRange().start - 1u;
AdvanceToNextValidTiling();
}
TilingSetEvictionQueue::~TilingSetEvictionQueue() {
}
bool TilingSetEvictionQueue::IsEmpty() const {
return !current_eviction_tile_;
}
void TilingSetEvictionQueue::Pop() {
DCHECK(!IsEmpty());
if (!AdvanceToNextEvictionTile())
AdvanceToNextValidTiling();
}
Tile* TilingSetEvictionQueue::Top() {
DCHECK(!IsEmpty());
return current_eviction_tile_;
}
const Tile* TilingSetEvictionQueue::Top() const {
DCHECK(!IsEmpty());
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);
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 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()) {
current_eviction_tile_ = tile;
return true;
}
}
current_eviction_tile_ = nullptr;
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.
DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
switch (current_tiling_range_type_) {
case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
return true;
case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
current_tiling_range_type_ =
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
return true;
case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
return true;
case PictureLayerTilingSet::LOW_RES:
current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
return true;
case PictureLayerTilingSet::HIGH_RES:
if (!AdvanceToNextCategory())
return false;
current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
return true;
}
NOTREACHED();
return false;
}
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 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.
DCHECK(!current_eviction_tile_);
DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
for (;;) {
++current_tiling_index_;
while (current_tiling_index_ == CurrentTilingRange().end) {
if (!AdvanceToNextTilingRangeType())
return false;
current_tiling_index_ = CurrentTilingRange().start;
}
PictureLayerTiling* tiling = tiling_set_->tiling_at(CurrentTilingIndex());
eviction_tiles_ =
tiling->GetEvictionTiles(tree_priority_, current_category_);
next_eviction_tile_index_ = 0u;
if (AdvanceToNextEvictionTile())
return true;
}
}
PictureLayerTilingSet::TilingRange
TilingSetEvictionQueue::CurrentTilingRange() const {
return tiling_set_->GetTilingRange(current_tiling_range_type_);
}
size_t TilingSetEvictionQueue::CurrentTilingIndex() const {
DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
switch (current_tiling_range_type_) {
case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
case PictureLayerTilingSet::LOW_RES:
case PictureLayerTilingSet::HIGH_RES:
return current_tiling_index_;
// Tilings in the following ranges are accessed in reverse order.
case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
size_t current_tiling_range_offset =
current_tiling_index_ - tiling_range.start;
return tiling_range.end - 1 - current_tiling_range_offset;
}
}
NOTREACHED();
return 0;
}
}