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(tree_priority_
);
26 const TilingSetEvictionQueue
* a_queue
=
27 a_tree
== ACTIVE_TREE
? a
->active_queue
.get() : a
->pending_queue
.get();
29 WhichTree b_tree
= b
->NextTileIteratorTree(tree_priority_
);
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
=
37 a_tile
->priority_for_tree_priority(tree_priority_
);
38 const TilePriority
& b_priority
=
39 b_tile
->priority_for_tree_priority(tree_priority_
);
40 bool prioritize_low_res
= tree_priority_
== SMOOTHNESS_TAKES_PRIORITY
;
42 // If the priority bin differs, b is lower priority if it has the higher
44 if (a_priority
.priority_bin
!= b_priority
.priority_bin
)
45 return b_priority
.priority_bin
> a_priority
.priority_bin
;
47 // Otherwise if the resolution differs, then the order will be determined by
48 // whether we prioritize low res or not.
49 // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
50 // class but instead produced by the iterators.
51 if (b_priority
.resolution
!= a_priority
.resolution
) {
52 // Non ideal resolution should be sorted higher than other resolutions.
53 if (a_priority
.resolution
== NON_IDEAL_RESOLUTION
)
56 if (b_priority
.resolution
== NON_IDEAL_RESOLUTION
)
59 if (prioritize_low_res
)
60 return a_priority
.resolution
== LOW_RESOLUTION
;
61 return a_priority
.resolution
== HIGH_RESOLUTION
;
64 // Otherwise if the occlusion differs, b is lower priority if it is
66 bool a_is_occluded
= a_tile
->is_occluded_for_tree_priority(tree_priority_
);
67 bool b_is_occluded
= b_tile
->is_occluded_for_tree_priority(tree_priority_
);
68 if (a_is_occluded
!= b_is_occluded
)
71 // b is lower priorty if it is farther from visible.
72 return b_priority
.distance_to_visible
> a_priority
.distance_to_visible
;
76 TreePriority tree_priority_
;
81 EvictionTilePriorityQueue::EvictionTilePriorityQueue() {
84 EvictionTilePriorityQueue::~EvictionTilePriorityQueue() {
87 void EvictionTilePriorityQueue::Build(
88 const std::vector
<PictureLayerImpl::Pair
>& paired_layers
,
89 TreePriority tree_priority
) {
90 tree_priority_
= tree_priority
;
92 for (std::vector
<PictureLayerImpl::Pair
>::const_iterator it
=
93 paired_layers
.begin();
94 it
!= paired_layers
.end();
96 paired_queues_
.push_back(
97 make_scoped_ptr(new PairedTilingSetQueue(*it
, tree_priority_
)));
100 paired_queues_
.make_heap(EvictionOrderComparator(tree_priority_
));
103 bool EvictionTilePriorityQueue::IsEmpty() const {
104 return paired_queues_
.empty() || paired_queues_
.front()->IsEmpty();
107 Tile
* EvictionTilePriorityQueue::Top() {
109 return paired_queues_
.front()->Top(tree_priority_
);
112 void EvictionTilePriorityQueue::Pop() {
115 paired_queues_
.pop_heap(EvictionOrderComparator(tree_priority_
));
116 PairedTilingSetQueue
* paired_queue
= paired_queues_
.back();
117 paired_queue
->Pop(tree_priority_
);
118 paired_queues_
.push_heap(EvictionOrderComparator(tree_priority_
));
121 EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() {
124 EvictionTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue(
125 const PictureLayerImpl::Pair
& layer_pair
,
126 TreePriority tree_priority
) {
127 bool skip_shared_out_of_order_tiles
= layer_pair
.active
&& layer_pair
.pending
;
128 if (layer_pair
.active
) {
129 active_queue
= make_scoped_ptr(new TilingSetEvictionQueue(
130 layer_pair
.active
->picture_layer_tiling_set(), tree_priority
,
131 skip_shared_out_of_order_tiles
));
133 if (layer_pair
.pending
) {
134 pending_queue
= make_scoped_ptr(new TilingSetEvictionQueue(
135 layer_pair
.pending
->picture_layer_tiling_set(), tree_priority
,
136 skip_shared_out_of_order_tiles
));
140 EvictionTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() {
143 bool EvictionTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const {
144 return (!active_queue
|| active_queue
->IsEmpty()) &&
145 (!pending_queue
|| pending_queue
->IsEmpty());
148 Tile
* EvictionTilePriorityQueue::PairedTilingSetQueue::Top(
149 TreePriority tree_priority
) {
152 WhichTree next_tree
= NextTileIteratorTree(tree_priority
);
153 TilingSetEvictionQueue
* next_queue
=
154 next_tree
== ACTIVE_TREE
? active_queue
.get() : pending_queue
.get();
155 DCHECK(next_queue
&& !next_queue
->IsEmpty());
157 Tile
* tile
= next_queue
->Top();
158 DCHECK(returned_tiles_for_debug
.find(tile
) == returned_tiles_for_debug
.end());
162 void EvictionTilePriorityQueue::PairedTilingSetQueue::Pop(
163 TreePriority tree_priority
) {
166 WhichTree next_tree
= NextTileIteratorTree(tree_priority
);
167 TilingSetEvictionQueue
* next_queue
=
168 next_tree
== ACTIVE_TREE
? active_queue
.get() : pending_queue
.get();
169 DCHECK(next_queue
&& !next_queue
->IsEmpty());
170 DCHECK(returned_tiles_for_debug
.insert(next_queue
->Top()).second
);
173 // If not empty, use Top to DCHECK the next iterator.
174 DCHECK_IMPLIES(!IsEmpty(), Top(tree_priority
));
178 EvictionTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree(
179 TreePriority tree_priority
) const {
182 // If we only have one iterator with tiles, return it.
183 if (!active_queue
|| active_queue
->IsEmpty())
185 if (!pending_queue
|| pending_queue
->IsEmpty())
188 const Tile
* active_tile
= active_queue
->Top();
189 const Tile
* pending_tile
= pending_queue
->Top();
191 // If tiles are the same, it doesn't matter which tree we return.
192 if (active_tile
== pending_tile
)
195 const TilePriority
& active_priority
=
196 active_tile
->priority_for_tree_priority(tree_priority
);
197 const TilePriority
& pending_priority
=
198 pending_tile
->priority_for_tree_priority(tree_priority
);
200 // If the bins are the same and activation differs, then return the tree of
201 // the tile not required for activation.
202 if (active_priority
.priority_bin
== pending_priority
.priority_bin
&&
203 active_tile
->required_for_activation() !=
204 pending_tile
->required_for_activation()) {
205 return active_tile
->required_for_activation() ? PENDING_TREE
: ACTIVE_TREE
;
208 // Return tile with a lower priority.
209 if (pending_priority
.IsHigherPriorityThan(active_priority
))