blob: 1f0e2134a5576f14ad5c5a3e18d46fe5d9d537af [file] [log] [blame]
James Robinson6a64b812014-12-03 13:38:42 -08001// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Etienne Membrivesb1556b32014-12-16 13:56:09 +01005#include <utility>
6
James Robinson6a64b812014-12-03 13:38:42 -08007#include "cc/resources/tiling_set_eviction_queue.h"
8
9namespace cc {
10
James Robinson6a64b812014-12-03 13:38:42 -080011TilingSetEvictionQueue::TilingSetEvictionQueue(
12 PictureLayerTilingSet* tiling_set,
Etienne Membrivesb1556b32014-12-16 13:56:09 +010013 TreePriority tree_priority,
14 bool skip_shared_out_of_order_tiles)
James Robinson6a64b812014-12-03 13:38:42 -080015 : tiling_set_(tiling_set),
Etienne Membrivesb1556b32014-12-16 13:56:09 +010016 tree_(tiling_set->client()->GetTree()),
James Robinson6a64b812014-12-03 13:38:42 -080017 tree_priority_(tree_priority),
Etienne Membrivesb1556b32014-12-16 13:56:09 +010018 skip_all_shared_tiles_(
19 skip_shared_out_of_order_tiles &&
20 tree_priority == (tree_ == ACTIVE_TREE ? NEW_CONTENT_TAKES_PRIORITY
21 : SMOOTHNESS_TAKES_PRIORITY)),
22 skip_shared_out_of_order_tiles_(skip_shared_out_of_order_tiles),
23 processing_soon_border_rect_(false),
24 processing_tiling_with_required_for_activation_tiles_(false),
25 tiling_index_with_required_for_activation_tiles_(0u),
26 current_priority_bin_(TilePriority::EVENTUALLY),
James Robinson6a64b812014-12-03 13:38:42 -080027 current_tiling_index_(0u),
28 current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
Etienne Membrivesb1556b32014-12-16 13:56:09 +010029 current_eviction_tile_(nullptr) {
James Robinson6a64b812014-12-03 13:38:42 -080030 // Early out if the layer has no tilings.
31 if (!tiling_set_->num_tilings())
32 return;
33
Etienne Membrivesb1556b32014-12-16 13:56:09 +010034 tiling_index_with_required_for_activation_tiles_ =
35 TilingIndexWithRequiredForActivationTiles();
36
James Robinson6a64b812014-12-03 13:38:42 -080037 current_tiling_index_ = CurrentTilingRange().start - 1u;
38 AdvanceToNextValidTiling();
39}
40
41TilingSetEvictionQueue::~TilingSetEvictionQueue() {
42}
43
44bool TilingSetEvictionQueue::IsEmpty() const {
45 return !current_eviction_tile_;
46}
47
48void TilingSetEvictionQueue::Pop() {
49 DCHECK(!IsEmpty());
50
51 if (!AdvanceToNextEvictionTile())
52 AdvanceToNextValidTiling();
53}
54
55Tile* TilingSetEvictionQueue::Top() {
56 DCHECK(!IsEmpty());
57 return current_eviction_tile_;
58}
59
60const Tile* TilingSetEvictionQueue::Top() const {
61 DCHECK(!IsEmpty());
62 return current_eviction_tile_;
63}
64
James Robinson6a64b812014-12-03 13:38:42 -080065bool TilingSetEvictionQueue::AdvanceToNextEvictionTile() {
Etienne Membrivesb1556b32014-12-16 13:56:09 +010066 // Advance to the next eviction tile within the current priority bin and
67 // tiling. This is done while advancing to a new tiling and while popping
68 // the current tile.
James Robinson6a64b812014-12-03 13:38:42 -080069
Etienne Membrivesb1556b32014-12-16 13:56:09 +010070 bool required_for_activation =
71 processing_tiling_with_required_for_activation_tiles_;
72
73 for (;;) {
74 while (spiral_iterator_) {
75 std::pair<int, int> next_index = spiral_iterator_.index();
76 Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
77 ++spiral_iterator_;
Benjamin Lerman04616822014-12-22 13:08:16 +010078 if (!tile || !tile->HasResource())
Etienne Membrivesb1556b32014-12-16 13:56:09 +010079 continue;
80 if (skip_all_shared_tiles_ && tile->is_shared())
81 continue;
82 current_tiling_->UpdateTileAndTwinPriority(tile);
83 if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
84 continue;
85 if (tile->required_for_activation() != required_for_activation)
86 continue;
James Robinson6a64b812014-12-03 13:38:42 -080087 current_eviction_tile_ = tile;
88 return true;
89 }
Etienne Membrivesb1556b32014-12-16 13:56:09 +010090 if (processing_soon_border_rect_) {
91 // Advance from soon border rect to skewport rect.
92 processing_soon_border_rect_ = false;
93 if (current_tiling_->has_skewport_rect_tiles_) {
94 spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
95 &current_tiling_->tiling_data_,
96 current_tiling_->current_skewport_rect_,
97 current_tiling_->current_visible_rect_,
98 current_tiling_->current_visible_rect_);
99 continue;
100 }
101 }
102 break;
103 }
104
105 TilePriority::PriorityBin max_tile_priority_bin =
106 current_tiling_->client_->GetMaxTilePriorityBin();
107 while (visible_iterator_) {
108 std::pair<int, int> next_index = visible_iterator_.index();
109 Tile* tile = current_tiling_->TileAt(next_index.first, next_index.second);
110 ++visible_iterator_;
Benjamin Lerman04616822014-12-22 13:08:16 +0100111 if (!tile || !tile->HasResource())
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100112 continue;
113 if (skip_all_shared_tiles_ && tile->is_shared())
114 continue;
115 // If the max tile priority is not NOW, updated priorities for tiles
116 // returned by the visible iterator will not have NOW (but EVENTUALLY)
117 // priority bin and cannot therefore be required for activation tiles nor
118 // occluded NOW tiles in the current tiling.
119 if (max_tile_priority_bin <= TilePriority::NOW) {
120 // If the current tiling is a pending tree tiling, required for
121 // activation tiles can be detected without updating tile priorities.
122 if (tree_ == PENDING_TREE &&
123 current_tiling_->IsTileRequiredForActivationIfVisible(tile) !=
124 required_for_activation) {
125 continue;
126 }
127 // Unoccluded NOW tiles should be evicted (and thus returned) only after
128 // all occluded NOW tiles.
129 if (!current_tiling_->IsTileOccluded(tile)) {
130 unoccluded_now_tiles_.push_back(tile);
131 continue;
132 }
133 }
134 current_tiling_->UpdateTileAndTwinPriority(tile);
135 if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
136 continue;
137 if (tile->required_for_activation() != required_for_activation)
138 continue;
139 current_eviction_tile_ = tile;
140 return true;
141 }
142
143 while (!unoccluded_now_tiles_.empty()) {
144 // All (unoccluded) NOW tiles have the same priority bin (NOW) and the same
145 // distance to visible (0.0), so it does not matter that tiles are popped
146 // in reversed (FILO) order.
147 Tile* tile = unoccluded_now_tiles_.back();
148 unoccluded_now_tiles_.pop_back();
149 DCHECK(tile);
Benjamin Lerman04616822014-12-22 13:08:16 +0100150 if (!tile->HasResource())
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100151 continue;
152 current_tiling_->UpdateTileAndTwinPriority(tile);
153 if (skip_shared_out_of_order_tiles_ && IsSharedOutOfOrderTile(tile))
154 continue;
155 if (tile->required_for_activation() != required_for_activation)
156 continue;
157 current_eviction_tile_ = tile;
158 return true;
James Robinson6a64b812014-12-03 13:38:42 -0800159 }
160
161 current_eviction_tile_ = nullptr;
162 return false;
163}
164
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100165bool TilingSetEvictionQueue::AdvanceToNextPriorityBin() {
166 // Advance to the next priority bin. This is done only after all tiling range
167 // types (including the required for activation tiling) within the previous
168 // priority bin have been gone through.
169 DCHECK_EQ(current_tiling_range_type_, PictureLayerTilingSet::HIGH_RES);
170
171 switch (current_priority_bin_) {
172 case TilePriority::EVENTUALLY:
173 current_priority_bin_ = TilePriority::SOON;
174 return true;
175 case TilePriority::SOON:
176 current_priority_bin_ = TilePriority::NOW;
177 return true;
178 case TilePriority::NOW:
179 return false;
180 }
181 NOTREACHED();
182 return false;
183}
184
James Robinson6a64b812014-12-03 13:38:42 -0800185bool TilingSetEvictionQueue::AdvanceToNextTilingRangeType() {
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100186 // Advance to the next tiling range type within the current priority bin, to
187 // the required for activation tiling range type within the current priority
188 // bin or to the first tiling range type within the next priority bin. This
189 // is done only after all tilings within the previous tiling range type have
190 // been gone through.
James Robinson6a64b812014-12-03 13:38:42 -0800191 DCHECK_EQ(current_tiling_index_, CurrentTilingRange().end);
192
193 switch (current_tiling_range_type_) {
194 case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
195 current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
196 return true;
197 case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
198 current_tiling_range_type_ =
199 PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
200 return true;
201 case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
202 current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
203 return true;
204 case PictureLayerTilingSet::LOW_RES:
205 current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
206 return true;
207 case PictureLayerTilingSet::HIGH_RES:
Etienne Membrives175837a2014-12-19 15:45:38 +0100208 // Process required for activation tiles (unless that has already been
209 // done for the current priority bin) if there is a tiling with required
210 // for activation tiles and that tiling may have required for activation
211 // tiles having the current priority bin (in the pending tree only NOW
212 // tiles may be required for activation).
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100213 if (!processing_tiling_with_required_for_activation_tiles_ &&
214 tiling_index_with_required_for_activation_tiles_ <
Etienne Membrives175837a2014-12-19 15:45:38 +0100215 tiling_set_->num_tilings() &&
216 (current_priority_bin_ == TilePriority::NOW ||
217 tree_ == ACTIVE_TREE)) {
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100218 processing_tiling_with_required_for_activation_tiles_ = true;
219 return true;
220 }
221 processing_tiling_with_required_for_activation_tiles_ = false;
222
223 if (!AdvanceToNextPriorityBin())
James Robinson6a64b812014-12-03 13:38:42 -0800224 return false;
225
226 current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
227 return true;
228 }
229 NOTREACHED();
230 return false;
231}
232
233bool TilingSetEvictionQueue::AdvanceToNextValidTiling() {
234 // Advance to the next tiling within current tiling range type or to
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100235 // the first tiling within the next tiling range type or priority bin until
James Robinson6a64b812014-12-03 13:38:42 -0800236 // the next eviction tile is found. This is done only after all eviction
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100237 // tiles within the previous tiling within the current priority bin and
238 // tiling range type have been gone through.
James Robinson6a64b812014-12-03 13:38:42 -0800239 DCHECK(!current_eviction_tile_);
240 DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
241
242 for (;;) {
243 ++current_tiling_index_;
244 while (current_tiling_index_ == CurrentTilingRange().end) {
245 if (!AdvanceToNextTilingRangeType())
246 return false;
247 current_tiling_index_ = CurrentTilingRange().start;
248 }
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100249 current_tiling_ = tiling_set_->tiling_at(CurrentTilingIndex());
James Robinson6a64b812014-12-03 13:38:42 -0800250
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100251 switch (current_priority_bin_) {
252 case TilePriority::EVENTUALLY:
253 if (current_tiling_->has_eventually_rect_tiles_) {
254 spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
255 &current_tiling_->tiling_data_,
256 current_tiling_->current_eventually_rect_,
257 current_tiling_->current_skewport_rect_,
258 current_tiling_->current_soon_border_rect_);
259 if (AdvanceToNextEvictionTile())
260 return true;
261 }
262 break;
263 case TilePriority::SOON:
264 if (current_tiling_->has_skewport_rect_tiles_ ||
265 current_tiling_->has_soon_border_rect_tiles_) {
266 processing_soon_border_rect_ = true;
267 if (current_tiling_->has_soon_border_rect_tiles_)
268 spiral_iterator_ = TilingData::ReverseSpiralDifferenceIterator(
269 &current_tiling_->tiling_data_,
270 current_tiling_->current_soon_border_rect_,
271 current_tiling_->current_skewport_rect_,
272 current_tiling_->current_visible_rect_);
273 if (AdvanceToNextEvictionTile())
274 return true;
275 }
276 break;
277 case TilePriority::NOW:
278 if (current_tiling_->has_visible_rect_tiles_) {
279 visible_iterator_ =
280 TilingData::Iterator(&current_tiling_->tiling_data_,
281 current_tiling_->current_visible_rect_,
282 false /* include_borders */);
283 if (AdvanceToNextEvictionTile())
284 return true;
285 }
286 break;
287 }
James Robinson6a64b812014-12-03 13:38:42 -0800288 }
289}
290
291PictureLayerTilingSet::TilingRange
292TilingSetEvictionQueue::CurrentTilingRange() const {
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100293 if (processing_tiling_with_required_for_activation_tiles_)
294 return PictureLayerTilingSet::TilingRange(
295 tiling_index_with_required_for_activation_tiles_,
296 tiling_index_with_required_for_activation_tiles_ + 1);
James Robinson6a64b812014-12-03 13:38:42 -0800297 return tiling_set_->GetTilingRange(current_tiling_range_type_);
298}
299
300size_t TilingSetEvictionQueue::CurrentTilingIndex() const {
301 DCHECK_NE(current_tiling_index_, CurrentTilingRange().end);
302 switch (current_tiling_range_type_) {
303 case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
304 case PictureLayerTilingSet::LOW_RES:
305 case PictureLayerTilingSet::HIGH_RES:
306 return current_tiling_index_;
307 // Tilings in the following ranges are accessed in reverse order.
308 case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
309 case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
310 PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
311 size_t current_tiling_range_offset =
312 current_tiling_index_ - tiling_range.start;
313 return tiling_range.end - 1 - current_tiling_range_offset;
314 }
315 }
316 NOTREACHED();
317 return 0;
318}
319
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100320bool TilingSetEvictionQueue::IsSharedOutOfOrderTile(const Tile* tile) const {
321 if (!tile->is_shared())
322 return false;
323
324 switch (tree_priority_) {
325 case SMOOTHNESS_TAKES_PRIORITY:
326 DCHECK_EQ(ACTIVE_TREE, tree_);
327 return false;
328 case NEW_CONTENT_TAKES_PRIORITY:
329 DCHECK_EQ(PENDING_TREE, tree_);
330 return false;
331 case SAME_PRIORITY_FOR_BOTH_TREES:
332 break;
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100333 }
334
335 // The priority for tile priority of a shared tile will be a combined
336 // priority thus return shared tiles from a higher priority tree as
337 // it is out of order for a lower priority tree.
338 WhichTree twin_tree = tree_ == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
339 const TilePriority& priority = tile->priority(tree_);
340 const TilePriority& twin_priority = tile->priority(twin_tree);
341 if (priority.priority_bin != twin_priority.priority_bin)
342 return priority.priority_bin > twin_priority.priority_bin;
343 const bool occluded = tile->is_occluded(tree_);
344 const bool twin_occluded = tile->is_occluded(twin_tree);
345 if (occluded != twin_occluded)
346 return occluded;
347 if (priority.distance_to_visible != twin_priority.distance_to_visible)
348 return priority.distance_to_visible > twin_priority.distance_to_visible;
349
350 // If priorities are the same, it does not matter which tree returns
351 // the tile. Let's pick the pending tree.
352 return tree_ != PENDING_TREE;
James Robinson6a64b812014-12-03 13:38:42 -0800353}
Etienne Membrivesb1556b32014-12-16 13:56:09 +0100354
355size_t TilingSetEvictionQueue::TilingIndexWithRequiredForActivationTiles()
356 const {
357 // Returns the tiling index of the tiling with requuired for activation tiles.
358 // If no such tiling exists, returns the past-the-last index (num_tilings).
359 size_t num_tilings = tiling_set_->num_tilings();
360
361 if (tree_ == PENDING_TREE) {
362 // For the pending tree, the tiling with required for activation tiles is
363 // the high res one.
364 PictureLayerTilingSet::TilingRange high_res_tiling_range =
365 tiling_set_->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
366 if (high_res_tiling_range.start != high_res_tiling_range.end)
367 return high_res_tiling_range.start;
368 } else {
369 DCHECK_EQ(ACTIVE_TREE, tree_);
370 // Only pending tree tiles can be required for activation. They can appear
371 // also in the active tree only if they are shared. If we skip all shared
372 // tiles, there is no need to find them as they will not be returned.
373 if (skip_all_shared_tiles_)
374 return num_tilings;
375
376 // For the active tree, the tiling with required for activation tiles is
377 // the one whose twin tiling is the high res pending tiling.
378 for (size_t i = 0; i < num_tilings; ++i) {
379 const PictureLayerTiling* tiling = tiling_set_->tiling_at(i);
380 const PictureLayerTiling* pending_tiling =
381 tiling_set_->client()->GetPendingOrActiveTwinTiling(tiling);
382 if (pending_tiling && pending_tiling->resolution() == HIGH_RESOLUTION)
383 return i;
384 }
385 }
386
387 return num_tilings;
388}
389
390} // namespace cc