1 // 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.
5 #include "cc/resources/eviction_tile_priority_queue.h"
11 class EvictionOrderComparator
{
13 explicit EvictionOrderComparator(TreePriority tree_priority
)
14 : tree_priority_(tree_priority
) {}
17 const EvictionTilePriorityQueue::PairedTilingSetQueue
* a
,
18 const EvictionTilePriorityQueue::PairedTilingSetQueue
* b
) const {
19 // Note that in this function, we have to return true if and only if
20 // b is strictly lower priority than a. Note that for the sake of
21 // completeness, empty queue is considered to have lowest priority.
22 if (a
->IsEmpty() || b
->IsEmpty())
23 return b
->IsEmpty() < a
->IsEmpty();
25 WhichTree a_tree
= a
->NextTileIteratorTree();
26 const TilingSetEvictionQueue
* a_queue
=
27 a_tree
== ACTIVE_TREE
? a
->active_queue
.get() : a
->pending_queue
.get();
29 WhichTree b_tree
= b
->NextTileIteratorTree();
30 const TilingSetEvictionQueue
* b_queue
=
31 b_tree
== ACTIVE_TREE
? b
->active_queue
.get() : b
->pending_queue
.get();
33 const Tile
* a_tile
= a_queue
->Top();
34 const Tile
* b_tile
= b_queue
->Top();
36 const TilePriority
& a_priority
= a_tile
->combined_priority();
37 const TilePriority
& b_priority
= b_tile
->combined_priority();
38 bool prioritize_low_res
= tree_priority_
== SMOOTHNESS_TAKES_PRIORITY
;
40 // If the priority bin differs, b is lower priority if it has the higher
42 if (a_priority
.priority_bin
!= b_priority
.priority_bin
)
43 return b_priority
.priority_bin
> a_priority
.priority_bin
;
45 // Otherwise if the resolution differs, then the order will be determined by
46 // whether we prioritize low res or not.
47 // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
48 // class but instead produced by the iterators.
49 if (b_priority
.resolution
!= a_priority
.resolution
) {
50 // Non ideal resolution should be sorted higher than other resolutions.
51 if (a_priority
.resolution
== NON_IDEAL_RESOLUTION
)
54 if (b_priority
.resolution
== NON_IDEAL_RESOLUTION
)
57 if (prioritize_low_res
)
58 return a_priority
.resolution
== LOW_RESOLUTION
;
59 return a_priority
.resolution
== HIGH_RESOLUTION
;
62 // Otherwise if the occlusion differs, b is lower priority if it is
64 bool a_is_occluded
= a_tile
->is_occluded_combined();
65 bool b_is_occluded
= b_tile
->is_occluded_combined();
66 if (a_is_occluded
!= b_is_occluded
)
69 // b is lower priorty if it is farther from visible.
70 return b_priority
.distance_to_visible
> a_priority
.distance_to_visible
;
74 TreePriority tree_priority_
;
79 EvictionTilePriorityQueue::EvictionTilePriorityQueue() {
82 EvictionTilePriorityQueue::~EvictionTilePriorityQueue() {
85 void EvictionTilePriorityQueue::Build(
86 const std::vector
<PictureLayerImpl::Pair
>& paired_layers
,
87 TreePriority tree_priority
) {
88 tree_priority_
= tree_priority
;
90 for (std::vector
<PictureLayerImpl::Pair
>::const_iterator it
=
91 paired_layers
.begin();
92 it
!= paired_layers
.end(); ++it
) {
93 paired_queues_
.push_back(make_scoped_ptr(new PairedTilingSetQueue(*it
)));
96 paired_queues_
.make_heap(EvictionOrderComparator(tree_priority_
));
99 bool EvictionTilePriorityQueue::IsEmpty() const {
100 return paired_queues_
.empty() || paired_queues_
.front()->IsEmpty();
103 Tile
* EvictionTilePriorityQueue::Top() {
105 return paired_queues_
.front()->Top();
108 void EvictionTilePriorityQueue::Pop() {
111 paired_queues_
.pop_heap(EvictionOrderComparator(tree_priority_
));
112 PairedTilingSetQueue
* paired_queue
= paired_queues_
.back();
114 paired_queues_
.push_heap(EvictionOrderComparator(tree_priority_
));
117 EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() {
120 EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue(
121 const PictureLayerImpl::Pair
& layer_pair
) {
122 bool skip_shared_out_of_order_tiles
= layer_pair
.active
&& layer_pair
.pending
;
123 if (layer_pair
.active
) {
124 active_queue
= make_scoped_ptr(new TilingSetEvictionQueue(
125 layer_pair
.active
->picture_layer_tiling_set(),
126 skip_shared_out_of_order_tiles
));
128 if (layer_pair
.pending
) {
129 pending_queue
= make_scoped_ptr(new TilingSetEvictionQueue(
130 layer_pair
.pending
->picture_layer_tiling_set(),
131 skip_shared_out_of_order_tiles
));
135 EvictionTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() {
138 bool EvictionTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const {
139 return (!active_queue
|| active_queue
->IsEmpty()) &&
140 (!pending_queue
|| pending_queue
->IsEmpty());
143 Tile
* EvictionTilePriorityQueue::PairedTilingSetQueue::Top() {
146 WhichTree next_tree
= NextTileIteratorTree();
147 TilingSetEvictionQueue
* next_queue
=
148 next_tree
== ACTIVE_TREE
? active_queue
.get() : pending_queue
.get();
149 DCHECK(next_queue
&& !next_queue
->IsEmpty());
151 Tile
* tile
= next_queue
->Top();
152 DCHECK(returned_tiles_for_debug
.find(tile
) == returned_tiles_for_debug
.end());
156 void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop() {
159 WhichTree next_tree
= NextTileIteratorTree();
160 TilingSetEvictionQueue
* next_queue
=
161 next_tree
== ACTIVE_TREE
? active_queue
.get() : pending_queue
.get();
162 DCHECK(next_queue
&& !next_queue
->IsEmpty());
163 DCHECK(returned_tiles_for_debug
.insert(next_queue
->Top()).second
);
166 // If not empty, use Top to DCHECK the next iterator.
167 DCHECK_IMPLIES(!IsEmpty(), Top());
171 EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree() const {
174 // If we only have one iterator with tiles, return it.
175 if (!active_queue
|| active_queue
->IsEmpty())
177 if (!pending_queue
|| pending_queue
->IsEmpty())
180 const Tile
* active_tile
= active_queue
->Top();
181 const Tile
* pending_tile
= pending_queue
->Top();
183 // If tiles are the same, it doesn't matter which tree we return.
184 if (active_tile
== pending_tile
)
187 const TilePriority
& active_priority
= active_tile
->combined_priority();
188 const TilePriority
& pending_priority
= pending_tile
->combined_priority();
190 // If the bins are the same and activation differs, then return the tree of
191 // the tile not required for activation.
192 if (active_priority
.priority_bin
== pending_priority
.priority_bin
&&
193 active_tile
->required_for_activation() !=
194 pending_tile
->required_for_activation()) {
195 return active_tile
->required_for_activation() ? PENDING_TREE
: ACTIVE_TREE
;
198 // Return tile with a lower priority.
199 if (pending_priority
.IsHigherPriorityThan(active_priority
))