OLD | NEW |
| (Empty) |
1 // Copyright 2012 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/picture_layer_tiling_set.h" | |
6 | |
7 #include <limits> | |
8 #include <set> | |
9 #include <vector> | |
10 | |
11 namespace cc { | |
12 | |
13 namespace { | |
14 | |
15 class LargestToSmallestScaleFunctor { | |
16 public: | |
17 bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) { | |
18 return left->contents_scale() > right->contents_scale(); | |
19 } | |
20 }; | |
21 | |
22 inline float LargerRatio(float float1, float float2) { | |
23 DCHECK_GT(float1, 0.f); | |
24 DCHECK_GT(float2, 0.f); | |
25 return float1 > float2 ? float1 / float2 : float2 / float1; | |
26 } | |
27 | |
28 } // namespace | |
29 | |
30 // static | |
31 scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create( | |
32 PictureLayerTilingClient* client, | |
33 size_t max_tiles_for_interest_area, | |
34 float skewport_target_time_in_seconds, | |
35 int skewport_extrapolation_limit_in_content_pixels) { | |
36 return make_scoped_ptr(new PictureLayerTilingSet( | |
37 client, max_tiles_for_interest_area, skewport_target_time_in_seconds, | |
38 skewport_extrapolation_limit_in_content_pixels)); | |
39 } | |
40 | |
41 PictureLayerTilingSet::PictureLayerTilingSet( | |
42 PictureLayerTilingClient* client, | |
43 size_t max_tiles_for_interest_area, | |
44 float skewport_target_time_in_seconds, | |
45 int skewport_extrapolation_limit_in_content_pixels) | |
46 : max_tiles_for_interest_area_(max_tiles_for_interest_area), | |
47 skewport_target_time_in_seconds_(skewport_target_time_in_seconds), | |
48 skewport_extrapolation_limit_in_content_pixels_( | |
49 skewport_extrapolation_limit_in_content_pixels), | |
50 client_(client) { | |
51 } | |
52 | |
53 PictureLayerTilingSet::~PictureLayerTilingSet() { | |
54 } | |
55 | |
56 void PictureLayerTilingSet::CopyTilingsFromPendingTwin( | |
57 const PictureLayerTilingSet* pending_twin_set, | |
58 const scoped_refptr<RasterSource>& raster_source) { | |
59 if (pending_twin_set->tilings_.empty()) { | |
60 // If the twin (pending) tiling set is empty, it was not updated for the | |
61 // current frame. So we drop tilings from our set as well, instead of | |
62 // leaving behind unshared tilings that are all non-ideal. | |
63 RemoveAllTilings(); | |
64 } | |
65 | |
66 for (PictureLayerTiling* pending_twin_tiling : pending_twin_set->tilings_) { | |
67 float contents_scale = pending_twin_tiling->contents_scale(); | |
68 PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale); | |
69 if (!this_tiling) { | |
70 scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( | |
71 contents_scale, raster_source, client_, max_tiles_for_interest_area_, | |
72 skewport_target_time_in_seconds_, | |
73 skewport_extrapolation_limit_in_content_pixels_); | |
74 tilings_.push_back(new_tiling.Pass()); | |
75 this_tiling = tilings_.back(); | |
76 } | |
77 this_tiling->CloneTilesAndPropertiesFrom(*pending_twin_tiling); | |
78 } | |
79 } | |
80 | |
81 void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSource( | |
82 scoped_refptr<RasterSource> raster_source, | |
83 const PictureLayerTilingSet* pending_twin_set, | |
84 const Region& layer_invalidation, | |
85 float minimum_contents_scale, | |
86 float maximum_contents_scale) { | |
87 RemoveTilingsBelowScale(minimum_contents_scale); | |
88 RemoveTilingsAboveScale(maximum_contents_scale); | |
89 | |
90 // Copy over tilings that are shared with the |pending_twin_set| tiling set | |
91 // (if it exists). | |
92 if (pending_twin_set) | |
93 CopyTilingsFromPendingTwin(pending_twin_set, raster_source); | |
94 | |
95 // If the tiling is not shared (FindTilingWithScale returns nullptr) or if | |
96 // |this| is the sync set (pending_twin_set is nullptr), then invalidate | |
97 // tiles and update them to the new raster source. | |
98 for (PictureLayerTiling* tiling : tilings_) { | |
99 if (pending_twin_set && | |
100 pending_twin_set->FindTilingWithScale(tiling->contents_scale())) { | |
101 continue; | |
102 } | |
103 | |
104 tiling->SetRasterSourceAndResize(raster_source); | |
105 tiling->Invalidate(layer_invalidation); | |
106 tiling->SetRasterSourceOnTiles(); | |
107 // This is needed for cases where the live tiles rect didn't change but | |
108 // recordings exist in the raster source that did not exist on the last | |
109 // raster source. | |
110 tiling->CreateMissingTilesInLiveTilesRect(); | |
111 | |
112 // If |pending_twin_set| is present, then |this| is active and |tiling| is | |
113 // not in the pending set, which means it is now NON_IDEAL_RESOLUTION. | |
114 if (pending_twin_set) | |
115 tiling->set_resolution(NON_IDEAL_RESOLUTION); | |
116 } | |
117 | |
118 tilings_.sort(LargestToSmallestScaleFunctor()); | |
119 | |
120 #if DCHECK_IS_ON() | |
121 for (PictureLayerTiling* tiling : tilings_) { | |
122 DCHECK(tiling->tile_size() == | |
123 client_->CalculateTileSize(tiling->tiling_size())) | |
124 << "tile_size: " << tiling->tile_size().ToString() | |
125 << " tiling_size: " << tiling->tiling_size().ToString() | |
126 << " CalculateTileSize: " | |
127 << client_->CalculateTileSize(tiling->tiling_size()).ToString(); | |
128 } | |
129 | |
130 if (!tilings_.empty()) { | |
131 DCHECK_LE(NumHighResTilings(), 1); | |
132 // When commiting from the main thread the high res tiling may get dropped, | |
133 // but when cloning to the active tree, there should always be one. | |
134 if (pending_twin_set) { | |
135 DCHECK_EQ(1, NumHighResTilings()) | |
136 << " num tilings on active: " << tilings_.size() | |
137 << " num tilings on pending: " << pending_twin_set->tilings_.size() | |
138 << " num high res on pending: " | |
139 << pending_twin_set->NumHighResTilings() | |
140 << " are on active tree: " << (client_->GetTree() == ACTIVE_TREE); | |
141 } | |
142 } | |
143 #endif | |
144 } | |
145 | |
146 void PictureLayerTilingSet::CleanUpTilings( | |
147 float min_acceptable_high_res_scale, | |
148 float max_acceptable_high_res_scale, | |
149 const std::vector<PictureLayerTiling*>& needed_tilings, | |
150 bool should_have_low_res, | |
151 PictureLayerTilingSet* twin_set, | |
152 PictureLayerTilingSet* recycled_twin_set) { | |
153 float twin_low_res_scale = 0.f; | |
154 if (twin_set) { | |
155 PictureLayerTiling* tiling = | |
156 twin_set->FindTilingWithResolution(LOW_RESOLUTION); | |
157 if (tiling) | |
158 twin_low_res_scale = tiling->contents_scale(); | |
159 } | |
160 | |
161 std::vector<PictureLayerTiling*> to_remove; | |
162 for (auto* tiling : tilings_) { | |
163 // Keep all tilings within the min/max scales. | |
164 if (tiling->contents_scale() >= min_acceptable_high_res_scale && | |
165 tiling->contents_scale() <= max_acceptable_high_res_scale) { | |
166 continue; | |
167 } | |
168 | |
169 // Keep low resolution tilings, if the tiling set should have them. | |
170 if (should_have_low_res && | |
171 (tiling->resolution() == LOW_RESOLUTION || | |
172 tiling->contents_scale() == twin_low_res_scale)) { | |
173 continue; | |
174 } | |
175 | |
176 // Don't remove tilings that are required. | |
177 if (std::find(needed_tilings.begin(), needed_tilings.end(), tiling) != | |
178 needed_tilings.end()) { | |
179 continue; | |
180 } | |
181 | |
182 to_remove.push_back(tiling); | |
183 } | |
184 | |
185 for (auto* tiling : to_remove) { | |
186 PictureLayerTiling* recycled_twin_tiling = | |
187 recycled_twin_set | |
188 ? recycled_twin_set->FindTilingWithScale(tiling->contents_scale()) | |
189 : nullptr; | |
190 // Remove the tiling from the recycle tree. Note that we ignore resolution, | |
191 // since we don't need to maintain high/low res on the recycle set. | |
192 if (recycled_twin_tiling) | |
193 recycled_twin_set->Remove(recycled_twin_tiling); | |
194 | |
195 DCHECK_NE(HIGH_RESOLUTION, tiling->resolution()); | |
196 Remove(tiling); | |
197 } | |
198 } | |
199 | |
200 void PictureLayerTilingSet::RemoveNonIdealTilings() { | |
201 auto to_remove = tilings_.remove_if([](PictureLayerTiling* t) { | |
202 return t->resolution() == NON_IDEAL_RESOLUTION; | |
203 }); | |
204 tilings_.erase(to_remove, tilings_.end()); | |
205 } | |
206 | |
207 void PictureLayerTilingSet::MarkAllTilingsNonIdeal() { | |
208 for (auto* tiling : tilings_) | |
209 tiling->set_resolution(NON_IDEAL_RESOLUTION); | |
210 } | |
211 | |
212 PictureLayerTiling* PictureLayerTilingSet::AddTiling( | |
213 float contents_scale, | |
214 scoped_refptr<RasterSource> raster_source) { | |
215 for (size_t i = 0; i < tilings_.size(); ++i) { | |
216 DCHECK_NE(tilings_[i]->contents_scale(), contents_scale); | |
217 DCHECK_EQ(tilings_[i]->raster_source(), raster_source.get()); | |
218 } | |
219 | |
220 tilings_.push_back(PictureLayerTiling::Create( | |
221 contents_scale, raster_source, client_, max_tiles_for_interest_area_, | |
222 skewport_target_time_in_seconds_, | |
223 skewport_extrapolation_limit_in_content_pixels_)); | |
224 PictureLayerTiling* appended = tilings_.back(); | |
225 | |
226 tilings_.sort(LargestToSmallestScaleFunctor()); | |
227 return appended; | |
228 } | |
229 | |
230 int PictureLayerTilingSet::NumHighResTilings() const { | |
231 return std::count_if(tilings_.begin(), tilings_.end(), | |
232 [](PictureLayerTiling* tiling) { | |
233 return tiling->resolution() == HIGH_RESOLUTION; | |
234 }); | |
235 } | |
236 | |
237 PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScale( | |
238 float scale) const { | |
239 for (size_t i = 0; i < tilings_.size(); ++i) { | |
240 if (tilings_[i]->contents_scale() == scale) | |
241 return tilings_[i]; | |
242 } | |
243 return NULL; | |
244 } | |
245 | |
246 PictureLayerTiling* PictureLayerTilingSet::FindTilingWithResolution( | |
247 TileResolution resolution) const { | |
248 auto iter = std::find_if(tilings_.begin(), tilings_.end(), | |
249 [resolution](const PictureLayerTiling* tiling) { | |
250 return tiling->resolution() == resolution; | |
251 }); | |
252 if (iter == tilings_.end()) | |
253 return NULL; | |
254 return *iter; | |
255 } | |
256 | |
257 void PictureLayerTilingSet::RemoveTilingsBelowScale(float minimum_scale) { | |
258 auto to_remove = | |
259 tilings_.remove_if([minimum_scale](PictureLayerTiling* tiling) { | |
260 return tiling->contents_scale() < minimum_scale; | |
261 }); | |
262 tilings_.erase(to_remove, tilings_.end()); | |
263 } | |
264 | |
265 void PictureLayerTilingSet::RemoveTilingsAboveScale(float maximum_scale) { | |
266 auto to_remove = | |
267 tilings_.remove_if([maximum_scale](PictureLayerTiling* tiling) { | |
268 return tiling->contents_scale() > maximum_scale; | |
269 }); | |
270 tilings_.erase(to_remove, tilings_.end()); | |
271 } | |
272 | |
273 void PictureLayerTilingSet::RemoveAllTilings() { | |
274 tilings_.clear(); | |
275 } | |
276 | |
277 void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) { | |
278 ScopedPtrVector<PictureLayerTiling>::iterator iter = | |
279 std::find(tilings_.begin(), tilings_.end(), tiling); | |
280 if (iter == tilings_.end()) | |
281 return; | |
282 tilings_.erase(iter); | |
283 } | |
284 | |
285 void PictureLayerTilingSet::RemoveAllTiles() { | |
286 for (size_t i = 0; i < tilings_.size(); ++i) | |
287 tilings_[i]->Reset(); | |
288 } | |
289 | |
290 float PictureLayerTilingSet::GetSnappedContentsScale( | |
291 float start_scale, | |
292 float snap_to_existing_tiling_ratio) const { | |
293 // If a tiling exists within the max snapping ratio, snap to its scale. | |
294 float snapped_contents_scale = start_scale; | |
295 float snapped_ratio = snap_to_existing_tiling_ratio; | |
296 for (const auto* tiling : tilings_) { | |
297 float tiling_contents_scale = tiling->contents_scale(); | |
298 float ratio = LargerRatio(tiling_contents_scale, start_scale); | |
299 if (ratio < snapped_ratio) { | |
300 snapped_contents_scale = tiling_contents_scale; | |
301 snapped_ratio = ratio; | |
302 } | |
303 } | |
304 return snapped_contents_scale; | |
305 } | |
306 | |
307 float PictureLayerTilingSet::GetMaximumContentsScale() const { | |
308 if (tilings_.empty()) | |
309 return 0.f; | |
310 // The first tiling has the largest contents scale. | |
311 return tilings_[0]->contents_scale(); | |
312 } | |
313 | |
314 bool PictureLayerTilingSet::UpdateTilePriorities( | |
315 const gfx::Rect& required_rect_in_layer_space, | |
316 float ideal_contents_scale, | |
317 double current_frame_time_in_seconds, | |
318 const Occlusion& occlusion_in_layer_space, | |
319 bool can_require_tiles_for_activation) { | |
320 bool updated = false; | |
321 for (auto* tiling : tilings_) { | |
322 tiling->set_can_require_tiles_for_activation( | |
323 can_require_tiles_for_activation); | |
324 updated |= tiling->ComputeTilePriorityRects( | |
325 required_rect_in_layer_space, ideal_contents_scale, | |
326 current_frame_time_in_seconds, occlusion_in_layer_space); | |
327 } | |
328 return updated; | |
329 } | |
330 | |
331 void PictureLayerTilingSet::GetAllTilesAndPrioritiesForTracing( | |
332 std::map<const Tile*, TilePriority>* tile_map) const { | |
333 for (auto* tiling : tilings_) | |
334 tiling->GetAllTilesAndPrioritiesForTracing(tile_map); | |
335 } | |
336 | |
337 PictureLayerTilingSet::CoverageIterator::CoverageIterator( | |
338 const PictureLayerTilingSet* set, | |
339 float contents_scale, | |
340 const gfx::Rect& content_rect, | |
341 float ideal_contents_scale) | |
342 : set_(set), | |
343 contents_scale_(contents_scale), | |
344 ideal_contents_scale_(ideal_contents_scale), | |
345 current_tiling_(-1) { | |
346 missing_region_.Union(content_rect); | |
347 | |
348 for (ideal_tiling_ = 0; | |
349 static_cast<size_t>(ideal_tiling_) < set_->tilings_.size(); | |
350 ++ideal_tiling_) { | |
351 PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_]; | |
352 if (tiling->contents_scale() < ideal_contents_scale_) { | |
353 if (ideal_tiling_ > 0) | |
354 ideal_tiling_--; | |
355 break; | |
356 } | |
357 } | |
358 | |
359 DCHECK_LE(set_->tilings_.size(), | |
360 static_cast<size_t>(std::numeric_limits<int>::max())); | |
361 | |
362 int num_tilings = set_->tilings_.size(); | |
363 if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0) | |
364 ideal_tiling_--; | |
365 | |
366 ++(*this); | |
367 } | |
368 | |
369 PictureLayerTilingSet::CoverageIterator::~CoverageIterator() { | |
370 } | |
371 | |
372 gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const { | |
373 if (!tiling_iter_) { | |
374 if (!region_iter_.has_rect()) | |
375 return gfx::Rect(); | |
376 return region_iter_.rect(); | |
377 } | |
378 return tiling_iter_.geometry_rect(); | |
379 } | |
380 | |
381 gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const { | |
382 if (!tiling_iter_) | |
383 return gfx::RectF(); | |
384 return tiling_iter_.texture_rect(); | |
385 } | |
386 | |
387 Tile* PictureLayerTilingSet::CoverageIterator::operator->() const { | |
388 if (!tiling_iter_) | |
389 return NULL; | |
390 return *tiling_iter_; | |
391 } | |
392 | |
393 Tile* PictureLayerTilingSet::CoverageIterator::operator*() const { | |
394 if (!tiling_iter_) | |
395 return NULL; | |
396 return *tiling_iter_; | |
397 } | |
398 | |
399 TileResolution PictureLayerTilingSet::CoverageIterator::resolution() const { | |
400 const PictureLayerTiling* tiling = CurrentTiling(); | |
401 DCHECK(tiling); | |
402 return tiling->resolution(); | |
403 } | |
404 | |
405 PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() | |
406 const { | |
407 if (current_tiling_ < 0) | |
408 return NULL; | |
409 if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size()) | |
410 return NULL; | |
411 return set_->tilings_[current_tiling_]; | |
412 } | |
413 | |
414 int PictureLayerTilingSet::CoverageIterator::NextTiling() const { | |
415 // Order returned by this method is: | |
416 // 1. Ideal tiling index | |
417 // 2. Tiling index < Ideal in decreasing order (higher res than ideal) | |
418 // 3. Tiling index > Ideal in increasing order (lower res than ideal) | |
419 // 4. Tiling index > tilings.size() (invalid index) | |
420 if (current_tiling_ < 0) | |
421 return ideal_tiling_; | |
422 else if (current_tiling_ > ideal_tiling_) | |
423 return current_tiling_ + 1; | |
424 else if (current_tiling_) | |
425 return current_tiling_ - 1; | |
426 else | |
427 return ideal_tiling_ + 1; | |
428 } | |
429 | |
430 PictureLayerTilingSet::CoverageIterator& | |
431 PictureLayerTilingSet::CoverageIterator::operator++() { | |
432 bool first_time = current_tiling_ < 0; | |
433 | |
434 if (!*this && !first_time) | |
435 return *this; | |
436 | |
437 if (tiling_iter_) | |
438 ++tiling_iter_; | |
439 | |
440 // Loop until we find a valid place to stop. | |
441 while (true) { | |
442 while (tiling_iter_ && | |
443 (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) { | |
444 missing_region_.Union(tiling_iter_.geometry_rect()); | |
445 ++tiling_iter_; | |
446 } | |
447 if (tiling_iter_) | |
448 return *this; | |
449 | |
450 // If the set of current rects for this tiling is done, go to the next | |
451 // tiling and set up to iterate through all of the remaining holes. | |
452 // This will also happen the first time through the loop. | |
453 if (!region_iter_.has_rect()) { | |
454 current_tiling_ = NextTiling(); | |
455 current_region_.Swap(&missing_region_); | |
456 missing_region_.Clear(); | |
457 region_iter_ = Region::Iterator(current_region_); | |
458 | |
459 // All done and all filled. | |
460 if (!region_iter_.has_rect()) { | |
461 current_tiling_ = set_->tilings_.size(); | |
462 return *this; | |
463 } | |
464 | |
465 // No more valid tiles, return this checkerboard rect. | |
466 if (current_tiling_ >= static_cast<int>(set_->tilings_.size())) | |
467 return *this; | |
468 } | |
469 | |
470 // Pop a rect off. If there are no more tilings, then these will be | |
471 // treated as geometry with null tiles that the caller can checkerboard. | |
472 gfx::Rect last_rect = region_iter_.rect(); | |
473 region_iter_.next(); | |
474 | |
475 // Done, found next checkerboard rect to return. | |
476 if (current_tiling_ >= static_cast<int>(set_->tilings_.size())) | |
477 return *this; | |
478 | |
479 // Construct a new iterator for the next tiling, but we need to loop | |
480 // again until we get to a valid one. | |
481 tiling_iter_ = PictureLayerTiling::CoverageIterator( | |
482 set_->tilings_[current_tiling_], | |
483 contents_scale_, | |
484 last_rect); | |
485 } | |
486 | |
487 return *this; | |
488 } | |
489 | |
490 PictureLayerTilingSet::CoverageIterator::operator bool() const { | |
491 return current_tiling_ < static_cast<int>(set_->tilings_.size()) || | |
492 region_iter_.has_rect(); | |
493 } | |
494 | |
495 void PictureLayerTilingSet::AsValueInto( | |
496 base::trace_event::TracedValue* state) const { | |
497 for (size_t i = 0; i < tilings_.size(); ++i) { | |
498 state->BeginDictionary(); | |
499 tilings_[i]->AsValueInto(state); | |
500 state->EndDictionary(); | |
501 } | |
502 } | |
503 | |
504 size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const { | |
505 size_t amount = 0; | |
506 for (size_t i = 0; i < tilings_.size(); ++i) | |
507 amount += tilings_[i]->GPUMemoryUsageInBytes(); | |
508 return amount; | |
509 } | |
510 | |
511 PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange( | |
512 TilingRangeType type) const { | |
513 // Doesn't seem to be the case right now but if it ever becomes a performance | |
514 // problem to compute these ranges each time this function is called, we can | |
515 // compute them only when the tiling set has changed instead. | |
516 TilingRange high_res_range(0, 0); | |
517 TilingRange low_res_range(tilings_.size(), tilings_.size()); | |
518 for (size_t i = 0; i < tilings_.size(); ++i) { | |
519 const PictureLayerTiling* tiling = tilings_[i]; | |
520 if (tiling->resolution() == HIGH_RESOLUTION) | |
521 high_res_range = TilingRange(i, i + 1); | |
522 if (tiling->resolution() == LOW_RESOLUTION) | |
523 low_res_range = TilingRange(i, i + 1); | |
524 } | |
525 | |
526 TilingRange range(0, 0); | |
527 switch (type) { | |
528 case HIGHER_THAN_HIGH_RES: | |
529 range = TilingRange(0, high_res_range.start); | |
530 break; | |
531 case HIGH_RES: | |
532 range = high_res_range; | |
533 break; | |
534 case BETWEEN_HIGH_AND_LOW_RES: | |
535 // TODO(vmpstr): This code assumes that high res tiling will come before | |
536 // low res tiling, however there are cases where this assumption is | |
537 // violated. As a result, it's better to be safe in these situations, | |
538 // since otherwise we can end up accessing a tiling that doesn't exist. | |
539 // See crbug.com/429397 for high res tiling appearing after low res | |
540 // tiling discussion/fixes. | |
541 if (high_res_range.start <= low_res_range.start) | |
542 range = TilingRange(high_res_range.end, low_res_range.start); | |
543 else | |
544 range = TilingRange(low_res_range.end, high_res_range.start); | |
545 break; | |
546 case LOW_RES: | |
547 range = low_res_range; | |
548 break; | |
549 case LOWER_THAN_LOW_RES: | |
550 range = TilingRange(low_res_range.end, tilings_.size()); | |
551 break; | |
552 } | |
553 | |
554 DCHECK_LE(range.start, range.end); | |
555 return range; | |
556 } | |
557 | |
558 } // namespace cc | |
OLD | NEW |