OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "cc/resources/raster_tile_priority_queue_all.h" | |
6 | |
7 #include "cc/resources/tiling_set_raster_queue_all.h" | |
8 | |
9 namespace cc { | |
10 | |
11 namespace { | |
12 | |
13 class RasterOrderComparator { | |
14 public: | |
15 explicit RasterOrderComparator(TreePriority tree_priority) | |
16 : tree_priority_(tree_priority) {} | |
17 | |
18 bool operator()( | |
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(); | |
26 | |
27 WhichTree a_tree = a->NextTileIteratorTree(tree_priority_); | |
28 const TilingSetRasterQueueAll* a_queue = | |
29 a_tree == ACTIVE_TREE ? a->active_queue() : a->pending_queue(); | |
30 | |
31 WhichTree b_tree = b->NextTileIteratorTree(tree_priority_); | |
32 const TilingSetRasterQueueAll* b_queue = | |
33 b_tree == ACTIVE_TREE ? b->active_queue() : b->pending_queue(); | |
34 | |
35 const Tile* a_tile = a_queue->Top(); | |
36 const Tile* b_tile = b_queue->Top(); | |
37 | |
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; | |
43 | |
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; | |
56 | |
57 // In case neither one is pending now, fall through. | |
58 } | |
59 | |
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) | |
68 return true; | |
69 | |
70 if (b_priority.resolution == NON_IDEAL_RESOLUTION) | |
71 return false; | |
72 | |
73 if (prioritize_low_res) | |
74 return b_priority.resolution == LOW_RESOLUTION; | |
75 return b_priority.resolution == HIGH_RESOLUTION; | |
76 } | |
77 | |
78 return b_priority.IsHigherPriorityThan(a_priority); | |
79 } | |
80 | |
81 private: | |
82 TreePriority tree_priority_; | |
83 }; | |
84 | |
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(); | |
94 | |
95 const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); | |
96 const TilePriority& pending_priority = | |
97 pending_tile->priority(PENDING_TREE); | |
98 | |
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) { | |
104 return PENDING_TREE; | |
105 } | |
106 return ACTIVE_TREE; | |
107 } | |
108 case NEW_CONTENT_TAKES_PRIORITY: | |
109 return PENDING_TREE; | |
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(); | |
114 | |
115 const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); | |
116 const TilePriority& pending_priority = | |
117 pending_tile->priority(PENDING_TREE); | |
118 | |
119 if (active_priority.IsHigherPriorityThan(pending_priority)) | |
120 return ACTIVE_TREE; | |
121 return PENDING_TREE; | |
122 } | |
123 default: | |
124 NOTREACHED(); | |
125 return ACTIVE_TREE; | |
126 } | |
127 } | |
128 | |
129 scoped_ptr<TilingSetRasterQueueAll> CreateTilingSetRasterQueue( | |
130 PictureLayerImpl* layer, | |
131 TreePriority tree_priority) { | |
132 if (!layer) | |
133 return nullptr; | |
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)); | |
138 } | |
139 | |
140 } // namespace | |
141 | |
142 RasterTilePriorityQueueAll::RasterTilePriorityQueueAll() { | |
143 } | |
144 | |
145 RasterTilePriorityQueueAll::~RasterTilePriorityQueueAll() { | |
146 } | |
147 | |
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_))); | |
157 } | |
158 paired_queues_.make_heap(RasterOrderComparator(tree_priority_)); | |
159 } | |
160 | |
161 bool RasterTilePriorityQueueAll::IsEmpty() const { | |
162 return paired_queues_.empty() || paired_queues_.front()->IsEmpty(); | |
163 } | |
164 | |
165 Tile* RasterTilePriorityQueueAll::Top() { | |
166 DCHECK(!IsEmpty()); | |
167 return paired_queues_.front()->Top(tree_priority_); | |
168 } | |
169 | |
170 void RasterTilePriorityQueueAll::Pop() { | |
171 DCHECK(!IsEmpty()); | |
172 | |
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_)); | |
177 } | |
178 | |
179 RasterTilePriorityQueueAll::PairedTilingSetQueue::PairedTilingSetQueue() { | |
180 } | |
181 | |
182 RasterTilePriorityQueueAll::PairedTilingSetQueue::PairedTilingSetQueue( | |
183 const PictureLayerImpl::Pair& layer_pair, | |
184 TreePriority tree_priority) | |
185 : active_queue_( | |
186 CreateTilingSetRasterQueue(layer_pair.active, tree_priority)), | |
187 pending_queue_( | |
188 CreateTilingSetRasterQueue(layer_pair.pending, tree_priority)), | |
189 has_both_layers_(layer_pair.active && layer_pair.pending) { | |
190 SkipTilesReturnedByTwin(tree_priority); | |
191 | |
192 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
193 "PairedTilingSetQueue::PairedTilingSetQueue", | |
194 TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); | |
195 } | |
196 | |
197 RasterTilePriorityQueueAll::PairedTilingSetQueue::~PairedTilingSetQueue() { | |
198 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
199 "PairedTilingSetQueue::~PairedTilingSetQueue", | |
200 TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); | |
201 } | |
202 | |
203 bool RasterTilePriorityQueueAll::PairedTilingSetQueue::IsEmpty() const { | |
204 return (!active_queue_ || active_queue_->IsEmpty()) && | |
205 (!pending_queue_ || pending_queue_->IsEmpty()); | |
206 } | |
207 | |
208 Tile* RasterTilePriorityQueueAll::PairedTilingSetQueue::Top( | |
209 TreePriority tree_priority) { | |
210 DCHECK(!IsEmpty()); | |
211 | |
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()); | |
219 return tile; | |
220 } | |
221 | |
222 void RasterTilePriorityQueueAll::PairedTilingSetQueue::Pop( | |
223 TreePriority tree_priority) { | |
224 DCHECK(!IsEmpty()); | |
225 | |
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); | |
231 next_queue->Pop(); | |
232 | |
233 SkipTilesReturnedByTwin(tree_priority); | |
234 | |
235 // If no empty, use Top to do DCHECK the next iterator. | |
236 DCHECK(IsEmpty() || Top(tree_priority)); | |
237 } | |
238 | |
239 void RasterTilePriorityQueueAll::PairedTilingSetQueue::SkipTilesReturnedByTwin( | |
240 TreePriority tree_priority) { | |
241 if (!has_both_layers_) | |
242 return; | |
243 | |
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). | |
246 while (!IsEmpty()) { | |
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()); | |
251 | |
252 // Accept all non-shared tiles. | |
253 const Tile* tile = next_queue->Top(); | |
254 if (!tile->is_shared()) | |
255 break; | |
256 | |
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)) | |
261 break; | |
262 | |
263 next_queue->Pop(); | |
264 } | |
265 } | |
266 | |
267 WhichTree | |
268 RasterTilePriorityQueueAll::PairedTilingSetQueue::NextTileIteratorTree( | |
269 TreePriority tree_priority) const { | |
270 DCHECK(!IsEmpty()); | |
271 | |
272 // If we only have one queue with tiles, return it. | |
273 if (!active_queue_ || active_queue_->IsEmpty()) | |
274 return PENDING_TREE; | |
275 if (!pending_queue_ || pending_queue_->IsEmpty()) | |
276 return ACTIVE_TREE; | |
277 | |
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); | |
281 } | |
282 | |
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(); | |
287 | |
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; | |
296 } | |
297 | |
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(); | |
303 | |
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; | |
312 } | |
313 | |
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(); | |
319 return state; | |
320 } | |
321 | |
322 } // namespace cc | |
OLD | NEW |