OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/resources/raster_tile_priority_queue.h" | 5 #include "cc/resources/raster_tile_priority_queue.h" |
6 | 6 |
7 #include "cc/resources/tiling_set_raster_queue_all.h" | 7 #include "cc/resources/raster_tile_priority_queue_all.h" |
8 #include "cc/resources/tiling_set_raster_queue_required.h" | 8 #include "cc/resources/raster_tile_priority_queue_required.h" |
9 | 9 |
10 namespace cc { | 10 namespace cc { |
11 | 11 |
12 namespace { | 12 // static |
13 | 13 scoped_ptr<RasterTilePriorityQueue> RasterTilePriorityQueue::Create( |
14 class RasterOrderComparator { | |
15 public: | |
16 explicit RasterOrderComparator(TreePriority tree_priority) | |
17 : tree_priority_(tree_priority) {} | |
18 | |
19 bool operator()( | |
20 const RasterTilePriorityQueue::PairedTilingSetQueue* a, | |
21 const RasterTilePriorityQueue::PairedTilingSetQueue* b) const { | |
22 // Note that in this function, we have to return true if and only if | |
23 // a is strictly lower priority than b. Note that for the sake of | |
24 // completeness, empty queue is considered to have lowest priority. | |
25 if (a->IsEmpty() || b->IsEmpty()) | |
26 return b->IsEmpty() < a->IsEmpty(); | |
27 | |
28 WhichTree a_tree = a->NextTileIteratorTree(tree_priority_); | |
29 const TilingSetRasterQueue* a_queue = | |
30 a_tree == ACTIVE_TREE ? a->active_queue() : a->pending_queue(); | |
31 | |
32 WhichTree b_tree = b->NextTileIteratorTree(tree_priority_); | |
33 const TilingSetRasterQueue* b_queue = | |
34 b_tree == ACTIVE_TREE ? b->active_queue() : b->pending_queue(); | |
35 | |
36 const Tile* a_tile = a_queue->Top(); | |
37 const Tile* b_tile = b_queue->Top(); | |
38 | |
39 const TilePriority& a_priority = | |
40 a_tile->priority_for_tree_priority(tree_priority_); | |
41 const TilePriority& b_priority = | |
42 b_tile->priority_for_tree_priority(tree_priority_); | |
43 bool prioritize_low_res = tree_priority_ == SMOOTHNESS_TAKES_PRIORITY; | |
44 | |
45 // In smoothness mode, we should return pending NOW tiles before active | |
46 // EVENTUALLY tiles. So if both priorities here are eventually, we need to | |
47 // check the pending priority. | |
48 if (prioritize_low_res && | |
49 a_priority.priority_bin == TilePriority::EVENTUALLY && | |
50 b_priority.priority_bin == TilePriority::EVENTUALLY) { | |
51 bool a_is_pending_now = | |
52 a_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW; | |
53 bool b_is_pending_now = | |
54 b_tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW; | |
55 if (a_is_pending_now || b_is_pending_now) | |
56 return a_is_pending_now < b_is_pending_now; | |
57 | |
58 // In case neither one is pending now, fall through. | |
59 } | |
60 | |
61 // If the bin is the same but the resolution is not, then the order will be | |
62 // determined by whether we prioritize low res or not. | |
63 // TODO(vmpstr): Remove this when TilePriority is no longer a member of Tile | |
64 // class but instead produced by the iterators. | |
65 if (b_priority.priority_bin == a_priority.priority_bin && | |
66 b_priority.resolution != a_priority.resolution) { | |
67 // Non ideal resolution should be sorted lower than other resolutions. | |
68 if (a_priority.resolution == NON_IDEAL_RESOLUTION) | |
69 return true; | |
70 | |
71 if (b_priority.resolution == NON_IDEAL_RESOLUTION) | |
72 return false; | |
73 | |
74 if (prioritize_low_res) | |
75 return b_priority.resolution == LOW_RESOLUTION; | |
76 return b_priority.resolution == HIGH_RESOLUTION; | |
77 } | |
78 | |
79 return b_priority.IsHigherPriorityThan(a_priority); | |
80 } | |
81 | |
82 private: | |
83 TreePriority tree_priority_; | |
84 }; | |
85 | |
86 WhichTree HigherPriorityTree(TreePriority tree_priority, | |
87 const TilingSetRasterQueue* active_queue, | |
88 const TilingSetRasterQueue* pending_queue, | |
89 const Tile* shared_tile) { | |
90 switch (tree_priority) { | |
91 case SMOOTHNESS_TAKES_PRIORITY: { | |
92 const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top(); | |
93 const Tile* pending_tile = | |
94 shared_tile ? shared_tile : pending_queue->Top(); | |
95 | |
96 const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); | |
97 const TilePriority& pending_priority = | |
98 pending_tile->priority(PENDING_TREE); | |
99 | |
100 // If we're down to eventually bin tiles on the active tree, process the | |
101 // pending tree to allow tiles required for activation to be initialized | |
102 // when memory policy only allows prepaint. | |
103 if (active_priority.priority_bin == TilePriority::EVENTUALLY && | |
104 pending_priority.priority_bin == TilePriority::NOW) { | |
105 return PENDING_TREE; | |
106 } | |
107 return ACTIVE_TREE; | |
108 } | |
109 case NEW_CONTENT_TAKES_PRIORITY: | |
110 return PENDING_TREE; | |
111 case SAME_PRIORITY_FOR_BOTH_TREES: { | |
112 const Tile* active_tile = shared_tile ? shared_tile : active_queue->Top(); | |
113 const Tile* pending_tile = | |
114 shared_tile ? shared_tile : pending_queue->Top(); | |
115 | |
116 const TilePriority& active_priority = active_tile->priority(ACTIVE_TREE); | |
117 const TilePriority& pending_priority = | |
118 pending_tile->priority(PENDING_TREE); | |
119 | |
120 if (active_priority.IsHigherPriorityThan(pending_priority)) | |
121 return ACTIVE_TREE; | |
122 return PENDING_TREE; | |
123 } | |
124 default: | |
125 NOTREACHED(); | |
126 return ACTIVE_TREE; | |
127 } | |
128 } | |
129 | |
130 scoped_ptr<TilingSetRasterQueue> CreateTilingSetRasterQueue( | |
131 PictureLayerImpl* layer, | |
132 TreePriority tree_priority, | |
133 RasterTilePriorityQueue::Type type) { | |
134 if (!layer) | |
135 return nullptr; | |
136 PictureLayerTilingSet* tiling_set = layer->picture_layer_tiling_set(); | |
137 if (type == RasterTilePriorityQueue::Type::ALL) { | |
138 bool prioritize_low_res = tree_priority == SMOOTHNESS_TAKES_PRIORITY; | |
139 return make_scoped_ptr( | |
140 new TilingSetRasterQueueAll(tiling_set, prioritize_low_res)); | |
141 } | |
142 return make_scoped_ptr(new TilingSetRasterQueueRequired(tiling_set, type)); | |
143 } | |
144 | |
145 } // namespace | |
146 | |
147 RasterTilePriorityQueue::RasterTilePriorityQueue() { | |
148 } | |
149 | |
150 RasterTilePriorityQueue::~RasterTilePriorityQueue() { | |
151 } | |
152 | |
153 void RasterTilePriorityQueue::Build( | |
154 const std::vector<PictureLayerImpl::Pair>& paired_layers, | 14 const std::vector<PictureLayerImpl::Pair>& paired_layers, |
155 TreePriority tree_priority, | 15 TreePriority tree_priority, |
156 Type type) { | 16 Type type) { |
157 tree_priority_ = tree_priority; | 17 switch (type) { |
158 for (std::vector<PictureLayerImpl::Pair>::const_iterator it = | 18 case Type::ALL: { |
159 paired_layers.begin(); | 19 scoped_ptr<RasterTilePriorityQueueAll> queue( |
160 it != paired_layers.end(); | 20 new RasterTilePriorityQueueAll); |
161 ++it) { | 21 queue->Build(paired_layers, tree_priority); |
162 paired_queues_.push_back( | 22 return queue.Pass(); |
163 make_scoped_ptr(new PairedTilingSetQueue(*it, tree_priority_, type))); | 23 } |
| 24 case Type::REQUIRED_FOR_ACTIVATION: |
| 25 case Type::REQUIRED_FOR_DRAW: { |
| 26 scoped_ptr<RasterTilePriorityQueueRequired> queue( |
| 27 new RasterTilePriorityQueueRequired); |
| 28 queue->Build(paired_layers, type); |
| 29 return queue.Pass(); |
| 30 } |
164 } | 31 } |
165 paired_queues_.make_heap(RasterOrderComparator(tree_priority_)); | 32 NOTREACHED(); |
166 } | 33 return nullptr; |
167 | |
168 void RasterTilePriorityQueue::Reset() { | |
169 paired_queues_.clear(); | |
170 } | |
171 | |
172 bool RasterTilePriorityQueue::IsEmpty() const { | |
173 return paired_queues_.empty() || paired_queues_.front()->IsEmpty(); | |
174 } | |
175 | |
176 Tile* RasterTilePriorityQueue::Top() { | |
177 DCHECK(!IsEmpty()); | |
178 return paired_queues_.front()->Top(tree_priority_); | |
179 } | |
180 | |
181 void RasterTilePriorityQueue::Pop() { | |
182 DCHECK(!IsEmpty()); | |
183 | |
184 paired_queues_.pop_heap(RasterOrderComparator(tree_priority_)); | |
185 PairedTilingSetQueue* paired_queue = paired_queues_.back(); | |
186 paired_queue->Pop(tree_priority_); | |
187 paired_queues_.push_heap(RasterOrderComparator(tree_priority_)); | |
188 } | |
189 | |
190 RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue() { | |
191 } | |
192 | |
193 RasterTilePriorityQueue::PairedTilingSetQueue::PairedTilingSetQueue( | |
194 const PictureLayerImpl::Pair& layer_pair, | |
195 TreePriority tree_priority, | |
196 Type type) | |
197 : has_both_layers_(false) { | |
198 switch (type) { | |
199 case RasterTilePriorityQueue::Type::ALL: | |
200 has_both_layers_ = layer_pair.active && layer_pair.pending; | |
201 active_queue_ = | |
202 CreateTilingSetRasterQueue(layer_pair.active, tree_priority, type); | |
203 pending_queue_ = | |
204 CreateTilingSetRasterQueue(layer_pair.pending, tree_priority, type); | |
205 break; | |
206 case RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION: | |
207 pending_queue_ = | |
208 CreateTilingSetRasterQueue(layer_pair.pending, tree_priority, type); | |
209 break; | |
210 case RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW: | |
211 active_queue_ = | |
212 CreateTilingSetRasterQueue(layer_pair.active, tree_priority, type); | |
213 break; | |
214 } | |
215 DCHECK_IMPLIES(has_both_layers_, active_queue_ && pending_queue_); | |
216 | |
217 SkipTilesReturnedByTwin(tree_priority); | |
218 | |
219 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
220 "PairedTilingSetQueue::PairedTilingSetQueue", | |
221 TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); | |
222 } | |
223 | |
224 RasterTilePriorityQueue::PairedTilingSetQueue::~PairedTilingSetQueue() { | |
225 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), | |
226 "PairedTilingSetQueue::~PairedTilingSetQueue", | |
227 TRACE_EVENT_SCOPE_THREAD, "state", StateAsValue()); | |
228 } | |
229 | |
230 bool RasterTilePriorityQueue::PairedTilingSetQueue::IsEmpty() const { | |
231 return (!active_queue_ || active_queue_->IsEmpty()) && | |
232 (!pending_queue_ || pending_queue_->IsEmpty()); | |
233 } | |
234 | |
235 Tile* RasterTilePriorityQueue::PairedTilingSetQueue::Top( | |
236 TreePriority tree_priority) { | |
237 DCHECK(!IsEmpty()); | |
238 | |
239 WhichTree next_tree = NextTileIteratorTree(tree_priority); | |
240 TilingSetRasterQueue* next_queue = | |
241 next_tree == ACTIVE_TREE ? active_queue_.get() : pending_queue_.get(); | |
242 DCHECK(next_queue && !next_queue->IsEmpty()); | |
243 Tile* tile = next_queue->Top(); | |
244 DCHECK(returned_tiles_for_debug_.find(tile) == | |
245 returned_tiles_for_debug_.end()); | |
246 return tile; | |
247 } | |
248 | |
249 void RasterTilePriorityQueue::PairedTilingSetQueue::Pop( | |
250 TreePriority tree_priority) { | |
251 DCHECK(!IsEmpty()); | |
252 | |
253 WhichTree next_tree = NextTileIteratorTree(tree_priority); | |
254 TilingSetRasterQueue* next_queue = | |
255 next_tree == ACTIVE_TREE ? active_queue_.get() : pending_queue_.get(); | |
256 DCHECK(next_queue && !next_queue->IsEmpty()); | |
257 DCHECK(returned_tiles_for_debug_.insert(next_queue->Top()).second); | |
258 next_queue->Pop(); | |
259 | |
260 SkipTilesReturnedByTwin(tree_priority); | |
261 | |
262 // If no empty, use Top to do DCHECK the next iterator. | |
263 DCHECK(IsEmpty() || Top(tree_priority)); | |
264 } | |
265 | |
266 void RasterTilePriorityQueue::PairedTilingSetQueue::SkipTilesReturnedByTwin( | |
267 TreePriority tree_priority) { | |
268 if (!has_both_layers_) | |
269 return; | |
270 | |
271 // We have both layers (active and pending) thus we can encounter shared | |
272 // tiles twice (from the active iterator and from the pending iterator). | |
273 while (!IsEmpty()) { | |
274 WhichTree next_tree = NextTileIteratorTree(tree_priority); | |
275 TilingSetRasterQueue* next_queue = | |
276 next_tree == ACTIVE_TREE ? active_queue_.get() : pending_queue_.get(); | |
277 DCHECK(next_queue && !next_queue->IsEmpty()); | |
278 | |
279 // Accept all non-shared tiles. | |
280 const Tile* tile = next_queue->Top(); | |
281 if (!tile->is_shared()) | |
282 break; | |
283 | |
284 // Accept a shared tile if the next tree is the higher priority one | |
285 // corresponding the iterator (active or pending) which usually (but due | |
286 // to spiral iterators not always) returns the shared tile first. | |
287 if (next_tree == HigherPriorityTree(tree_priority, nullptr, nullptr, tile)) | |
288 break; | |
289 | |
290 next_queue->Pop(); | |
291 } | |
292 } | |
293 | |
294 WhichTree RasterTilePriorityQueue::PairedTilingSetQueue::NextTileIteratorTree( | |
295 TreePriority tree_priority) const { | |
296 DCHECK(!IsEmpty()); | |
297 | |
298 // If we only have one queue with tiles, return it. | |
299 if (!active_queue_ || active_queue_->IsEmpty()) | |
300 return PENDING_TREE; | |
301 if (!pending_queue_ || pending_queue_->IsEmpty()) | |
302 return ACTIVE_TREE; | |
303 | |
304 // Now both iterators have tiles, so we have to decide based on tree priority. | |
305 return HigherPriorityTree(tree_priority, active_queue_.get(), | |
306 pending_queue_.get(), nullptr); | |
307 } | |
308 | |
309 scoped_refptr<base::debug::ConvertableToTraceFormat> | |
310 RasterTilePriorityQueue::PairedTilingSetQueue::StateAsValue() const { | |
311 scoped_refptr<base::debug::TracedValue> state = | |
312 new base::debug::TracedValue(); | |
313 | |
314 bool active_queue_has_tile = active_queue_ && !active_queue_->IsEmpty(); | |
315 TilePriority::PriorityBin active_priority_bin = TilePriority::EVENTUALLY; | |
316 TilePriority::PriorityBin pending_priority_bin = TilePriority::EVENTUALLY; | |
317 if (active_queue_has_tile) { | |
318 active_priority_bin = | |
319 active_queue_->Top()->priority(ACTIVE_TREE).priority_bin; | |
320 pending_priority_bin = | |
321 active_queue_->Top()->priority(PENDING_TREE).priority_bin; | |
322 } | |
323 | |
324 state->BeginDictionary("active_queue"); | |
325 state->SetBoolean("has_tile", active_queue_has_tile); | |
326 state->SetInteger("active_priority_bin", active_priority_bin); | |
327 state->SetInteger("pending_priority_bin", pending_priority_bin); | |
328 state->EndDictionary(); | |
329 | |
330 bool pending_queue_has_tile = pending_queue_ && !pending_queue_->IsEmpty(); | |
331 active_priority_bin = TilePriority::EVENTUALLY; | |
332 pending_priority_bin = TilePriority::EVENTUALLY; | |
333 if (pending_queue_has_tile) { | |
334 active_priority_bin = | |
335 pending_queue_->Top()->priority(ACTIVE_TREE).priority_bin; | |
336 pending_priority_bin = | |
337 pending_queue_->Top()->priority(PENDING_TREE).priority_bin; | |
338 } | |
339 | |
340 state->BeginDictionary("pending_queue"); | |
341 state->SetBoolean("has_tile", active_queue_has_tile); | |
342 state->SetInteger("active_priority_bin", active_priority_bin); | |
343 state->SetInteger("pending_priority_bin", pending_priority_bin); | |
344 state->EndDictionary(); | |
345 return state; | |
346 } | 34 } |
347 | 35 |
348 } // namespace cc | 36 } // namespace cc |
OLD | NEW |