1 // Copyright 2015 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/raster_tile_priority_queue_all.h"
7 #include "cc/resources/tiling_set_raster_queue_all.h"
13 class RasterOrderComparator
{
15 explicit RasterOrderComparator(TreePriority tree_priority
)
16 : tree_priority_(tree_priority
) {}
19 const RasterTilePriorityQueueAll::PairedTilingSetQueue
* a
,
20 const RasterTilePriorityQueueAll::PairedTilingSetQueue
* b
) const {
21 // Note that in this function, we have to return true if and only if
22 // a is strictly lower priority than b. Note that for the sake of
23 // completeness, empty queue is considered to have lowest priority.
24 if (a
->IsEmpty() || b
->IsEmpty())
25 return b
->IsEmpty() < a
->IsEmpty();
27 WhichTree a_tree
= a
->NextTileIteratorTree(tree_priority_
);
28 const TilingSetRasterQueueAll
* a_queue
=
29 a_tree
== ACTIVE_TREE
? a
->active_queue() : a
->pending_queue();
31 WhichTree b_tree
= b
->NextTileIteratorTree(tree_priority_
);
32 const TilingSetRasterQueueAll
* b_queue
=
33 b_tree
== ACTIVE_TREE
? b
->active_queue() : b
->pending_queue();
35 const Tile
* a_tile
= a_queue
->Top();
36 const Tile
* b_tile
= b_queue
->Top();
38 const TilePriority
& a_priority
=
39 a_tile
->priority_for_tree_priority(tree_priority_
);
40 const TilePriority
& b_priority
=
41 b_tile
->priority_for_tree_priority(tree_priority_
);
42 bool prioritize_low_res
= tree_priority_
== SMOOTHNESS_TAKES_PRIORITY
;
44 // In smoothness mode, we should return pending NOW tiles before active
45 // EVENTUALLY tiles. So if both priorities here are eventually, we need to
46 // check the pending priority.
47 if (prioritize_low_res
&&
48 a_priority
.priority_bin
== TilePriority::EVENTUALLY
&&
49 b_priority
.priority_bin
== TilePriority::EVENTUALLY
) {
50 bool a_is_pending_now
=
51 a_tile
->priority(PENDING_TREE
).priority_bin
== TilePriority::NOW
;
52 bool b_is_pending_now
=
53 b_tile
->priority(PENDING_TREE
).priority_bin
== TilePriority::NOW
;
54 if (a_is_pending_now
|| b_is_pending_now
)
55 return a_is_pending_now
< b_is_pending_now
;
57 // In case neither one is pending now, fall through.
60 // If the bin is the same but the resolution is not, then the order will be
61 // determined by whether we prioritize low res or not.
62 // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile
63 // class but instead produced by the iterators.
64 if (b_priority
.priority_bin
== a_priority
.priority_bin
&&
65 b_priority
.resolution
!= a_priority
.resolution
) {
66 // Non ideal resolution should be sorted lower than other resolutions.
67 if (a_priority
.resolution
== NON_IDEAL_RESOLUTION
)
70 if (b_priority
.resolution
== NON_IDEAL_RESOLUTION
)
73 if (prioritize_low_res
)
74 return b_priority
.resolution
== LOW_RESOLUTION
;
75 return b_priority
.resolution
== HIGH_RESOLUTION
;
78 return b_priority
.IsHigherPriorityThan(a_priority
);
82 TreePriority tree_priority_
;
85 WhichTree
HigherPriorityTree(TreePriority tree_priority
,
86 const TilingSetRasterQueueAll
* active_queue
,
87 const TilingSetRasterQueueAll
* pending_queue
,
88 const Tile
* shared_tile
) {
89 switch (tree_priority
) {
90 case SMOOTHNESS_TAKES_PRIORITY
: {
91 const Tile
* active_tile
= shared_tile
? shared_tile
: active_queue
->Top();
92 const Tile
* pending_tile
=
93 shared_tile
? shared_tile
: pending_queue
->Top();
95 const TilePriority
& active_priority
= active_tile
->priority(ACTIVE_TREE
);
96 const TilePriority
& pending_priority
=
97 pending_tile
->priority(PENDING_TREE
);
99 // If we're down to eventually bin tiles on the active tree, process the
100 // pending tree to allow tiles required for activation to be initialized
101 // when memory policy only allows prepaint.
102 if (active_priority
.priority_bin
== TilePriority::EVENTUALLY
&&
103 pending_priority
.priority_bin
== TilePriority::NOW
) {
108 case NEW_CONTENT_TAKES_PRIORITY
:
110 case SAME_PRIORITY_FOR_BOTH_TREES
: {
111 const Tile
* active_tile
= shared_tile
? shared_tile
: active_queue
->Top();
112 const Tile
* pending_tile
=
113 shared_tile
? shared_tile
: pending_queue
->Top();
115 const TilePriority
& active_priority
= active_tile
->priority(ACTIVE_TREE
);
116 const TilePriority
& pending_priority
=
117 pending_tile
->priority(PENDING_TREE
);
119 if (active_priority
.IsHigherPriorityThan(pending_priority
))
129 scoped_ptr
<TilingSetRasterQueueAll
> CreateTilingSetRasterQueue(
130 PictureLayerImpl
* layer
,
131 TreePriority tree_priority
) {
134 PictureLayerTilingSet
* tiling_set
= layer
->picture_layer_tiling_set();
135 bool prioritize_low_res
= tree_priority
== SMOOTHNESS_TAKES_PRIORITY
;
136 return make_scoped_ptr(
137 new TilingSetRasterQueueAll(tiling_set
, prioritize_low_res
));
142 RasterTilePriorityQueueAll::RasterTilePriorityQueueAll() {
145 RasterTilePriorityQueueAll::~RasterTilePriorityQueueAll() {
148 void RasterTilePriorityQueueAll::Build(
149 const std::vector
<PictureLayerImpl::Pair
>& paired_layers
,
150 TreePriority tree_priority
) {
151 tree_priority_
= tree_priority
;
152 for (std::vector
<PictureLayerImpl::Pair
>::const_iterator it
=
153 paired_layers
.begin();
154 it
!= paired_layers
.end(); ++it
) {
155 paired_queues_
.push_back(
156 make_scoped_ptr(new PairedTilingSetQueue(*it
, tree_priority_
)));
158 paired_queues_
.make_heap(RasterOrderComparator(tree_priority_
));
161 bool RasterTilePriorityQueueAll::IsEmpty() const {
162 return paired_queues_
.empty() || paired_queues_
.front()->IsEmpty();
165 Tile
* RasterTilePriorityQueueAll::Top() {
167 return paired_queues_
.front()->Top(tree_priority_
);
170 void RasterTilePriorityQueueAll::Pop() {
173 paired_queues_
.pop_heap(RasterOrderComparator(tree_priority_
));
174 PairedTilingSetQueue
* paired_queue
= paired_queues_
.back();
175 paired_queue
->Pop(tree_priority_
);
176 paired_queues_
.push_heap(RasterOrderComparator(tree_priority_
));
179 RasterTilePriorityQueueAll::PairedTilingSetQueue::PairedTilingSetQueue() {
182 RasterTilePriorityQueueAll::PairedTilingSetQueue::PairedTilingSetQueue(
183 const PictureLayerImpl::Pair
& layer_pair
,
184 TreePriority tree_priority
)
186 CreateTilingSetRasterQueue(layer_pair
.active
, tree_priority
)),
188 CreateTilingSetRasterQueue(layer_pair
.pending
, tree_priority
)),
189 has_both_layers_(layer_pair
.active
&& layer_pair
.pending
) {
190 SkipTilesReturnedByTwin(tree_priority
);
192 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
193 "PairedTilingSetQueue::PairedTilingSetQueue",
194 TRACE_EVENT_SCOPE_THREAD
, "state", StateAsValue());
197 RasterTilePriorityQueueAll::PairedTilingSetQueue::~PairedTilingSetQueue() {
198 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
199 "PairedTilingSetQueue::~PairedTilingSetQueue",
200 TRACE_EVENT_SCOPE_THREAD
, "state", StateAsValue());
203 bool RasterTilePriorityQueueAll::PairedTilingSetQueue::IsEmpty() const {
204 return (!active_queue_
|| active_queue_
->IsEmpty()) &&
205 (!pending_queue_
|| pending_queue_
->IsEmpty());
208 Tile
* RasterTilePriorityQueueAll::PairedTilingSetQueue::Top(
209 TreePriority tree_priority
) {
212 WhichTree next_tree
= NextTileIteratorTree(tree_priority
);
213 TilingSetRasterQueueAll
* next_queue
=
214 next_tree
== ACTIVE_TREE
? active_queue_
.get() : pending_queue_
.get();
215 DCHECK(next_queue
&& !next_queue
->IsEmpty());
216 Tile
* tile
= next_queue
->Top();
217 DCHECK(returned_tiles_for_debug_
.find(tile
) ==
218 returned_tiles_for_debug_
.end());
222 void RasterTilePriorityQueueAll::PairedTilingSetQueue::Pop(
223 TreePriority tree_priority
) {
226 WhichTree next_tree
= NextTileIteratorTree(tree_priority
);
227 TilingSetRasterQueueAll
* next_queue
=
228 next_tree
== ACTIVE_TREE
? active_queue_
.get() : pending_queue_
.get();
229 DCHECK(next_queue
&& !next_queue
->IsEmpty());
230 DCHECK(returned_tiles_for_debug_
.insert(next_queue
->Top()).second
);
233 SkipTilesReturnedByTwin(tree_priority
);
235 // If no empty, use Top to do DCHECK the next iterator.
236 DCHECK(IsEmpty() || Top(tree_priority
));
239 void RasterTilePriorityQueueAll::PairedTilingSetQueue::SkipTilesReturnedByTwin(
240 TreePriority tree_priority
) {
241 if (!has_both_layers_
)
244 // We have both layers (active and pending) thus we can encounter shared
245 // tiles twice (from the active iterator and from the pending iterator).
247 WhichTree next_tree
= NextTileIteratorTree(tree_priority
);
248 TilingSetRasterQueueAll
* next_queue
=
249 next_tree
== ACTIVE_TREE
? active_queue_
.get() : pending_queue_
.get();
250 DCHECK(next_queue
&& !next_queue
->IsEmpty());
252 // Accept all non-shared tiles.
253 const Tile
* tile
= next_queue
->Top();
254 if (!tile
->is_shared())
257 // Accept a shared tile if the next tree is the higher priority one
258 // corresponding the iterator (active or pending) which usually (but due
259 // to spiral iterators not always) returns the shared tile first.
260 if (next_tree
== HigherPriorityTree(tree_priority
, nullptr, nullptr, tile
))
268 RasterTilePriorityQueueAll::PairedTilingSetQueue::NextTileIteratorTree(
269 TreePriority tree_priority
) const {
272 // If we only have one queue with tiles, return it.
273 if (!active_queue_
|| active_queue_
->IsEmpty())
275 if (!pending_queue_
|| pending_queue_
->IsEmpty())
278 // Now both iterators have tiles, so we have to decide based on tree priority.
279 return HigherPriorityTree(tree_priority
, active_queue_
.get(),
280 pending_queue_
.get(), nullptr);
283 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
284 RasterTilePriorityQueueAll::PairedTilingSetQueue::StateAsValue() const {
285 scoped_refptr
<base::trace_event::TracedValue
> state
=
286 new base::trace_event::TracedValue();
288 bool active_queue_has_tile
= active_queue_
&& !active_queue_
->IsEmpty();
289 TilePriority::PriorityBin active_priority_bin
= TilePriority::EVENTUALLY
;
290 TilePriority::PriorityBin pending_priority_bin
= TilePriority::EVENTUALLY
;
291 if (active_queue_has_tile
) {
292 active_priority_bin
=
293 active_queue_
->Top()->priority(ACTIVE_TREE
).priority_bin
;
294 pending_priority_bin
=
295 active_queue_
->Top()->priority(PENDING_TREE
).priority_bin
;
298 state
->BeginDictionary("active_queue");
299 state
->SetBoolean("has_tile", active_queue_has_tile
);
300 state
->SetInteger("active_priority_bin", active_priority_bin
);
301 state
->SetInteger("pending_priority_bin", pending_priority_bin
);
302 state
->EndDictionary();
304 bool pending_queue_has_tile
= pending_queue_
&& !pending_queue_
->IsEmpty();
305 active_priority_bin
= TilePriority::EVENTUALLY
;
306 pending_priority_bin
= TilePriority::EVENTUALLY
;
307 if (pending_queue_has_tile
) {
308 active_priority_bin
=
309 pending_queue_
->Top()->priority(ACTIVE_TREE
).priority_bin
;
310 pending_priority_bin
=
311 pending_queue_
->Top()->priority(PENDING_TREE
).priority_bin
;
314 state
->BeginDictionary("pending_queue");
315 state
->SetBoolean("has_tile", active_queue_has_tile
);
316 state
->SetInteger("active_priority_bin", active_priority_bin
);
317 state
->SetInteger("pending_priority_bin", pending_priority_bin
);
318 state
->EndDictionary();