| 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 |