Enable Enhanced Bookmark on Android Tablet
[chromium-blink-merge.git] / cc / resources / picture_layer_tiling_set.cc
bloba3348bc72d350f608c21555cef7a60ed9da5c727
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.
5 #include "cc/resources/picture_layer_tiling_set.h"
7 #include <limits>
8 #include <set>
9 #include <vector>
11 namespace cc {
13 namespace {
15 class LargestToSmallestScaleFunctor {
16 public:
17 bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) {
18 return left->contents_scale() > right->contents_scale();
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;
28 } // namespace
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));
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) {
53 PictureLayerTilingSet::~PictureLayerTilingSet() {
56 void PictureLayerTilingSet::UpdateTilingsToCurrentRasterSource(
57 RasterSource* raster_source,
58 const PictureLayerTilingSet* twin_set,
59 const gfx::Size& layer_bounds,
60 const Region& layer_invalidation,
61 float minimum_contents_scale) {
62 RemoveTilingsBelowScale(minimum_contents_scale);
64 // Copy over tilings that are shared with the |twin_set| tiling set (if it
65 // exists).
66 if (twin_set) {
67 for (PictureLayerTiling* twin_tiling : twin_set->tilings_) {
68 float contents_scale = twin_tiling->contents_scale();
69 DCHECK_GE(contents_scale, minimum_contents_scale);
71 PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale);
72 if (!this_tiling) {
73 scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
74 contents_scale, layer_bounds, client_, max_tiles_for_interest_area_,
75 skewport_target_time_in_seconds_,
76 skewport_extrapolation_limit_in_content_pixels_);
77 tilings_.push_back(new_tiling.Pass());
78 this_tiling = tilings_.back();
80 this_tiling->CloneTilesAndPropertiesFrom(*twin_tiling);
84 // For unshared tilings, invalidate tiles and update them to the new raster
85 // source.
86 for (PictureLayerTiling* tiling : tilings_) {
87 if (twin_set && twin_set->FindTilingWithScale(tiling->contents_scale()))
88 continue;
90 tiling->Resize(layer_bounds);
91 tiling->Invalidate(layer_invalidation);
92 tiling->SetRasterSource(raster_source);
93 // This is needed for cases where the live tiles rect didn't change but
94 // recordings exist in the raster source that did not exist on the last
95 // raster source.
96 tiling->CreateMissingTilesInLiveTilesRect();
98 // If |twin_set| is present, use the resolutions from there. Otherwise leave
99 // all resolutions as they are.
100 if (twin_set)
101 tiling->set_resolution(NON_IDEAL_RESOLUTION);
104 tilings_.sort(LargestToSmallestScaleFunctor());
106 #if DCHECK_IS_ON
107 for (PictureLayerTiling* tiling : tilings_) {
108 DCHECK(tiling->tile_size() ==
109 client_->CalculateTileSize(tiling->tiling_size()))
110 << "tile_size: " << tiling->tile_size().ToString()
111 << " tiling_size: " << tiling->tiling_size().ToString()
112 << " CalculateTileSize: "
113 << client_->CalculateTileSize(tiling->tiling_size()).ToString();
116 if (!tilings_.empty()) {
117 size_t num_high_res = std::count_if(tilings_.begin(), tilings_.end(),
118 [](PictureLayerTiling* tiling) {
119 return tiling->resolution() == HIGH_RESOLUTION;
121 DCHECK_EQ(1u, num_high_res);
123 #endif
126 void PictureLayerTilingSet::CleanUpTilings(
127 float min_acceptable_high_res_scale,
128 float max_acceptable_high_res_scale,
129 const std::vector<PictureLayerTiling*>& needed_tilings,
130 bool should_have_low_res,
131 PictureLayerTilingSet* twin_set,
132 PictureLayerTilingSet* recycled_twin_set) {
133 float twin_low_res_scale = 0.f;
134 if (twin_set) {
135 PictureLayerTiling* tiling =
136 twin_set->FindTilingWithResolution(LOW_RESOLUTION);
137 if (tiling)
138 twin_low_res_scale = tiling->contents_scale();
141 std::vector<PictureLayerTiling*> to_remove;
142 for (auto* tiling : tilings_) {
143 // Keep all tilings within the min/max scales.
144 if (tiling->contents_scale() >= min_acceptable_high_res_scale &&
145 tiling->contents_scale() <= max_acceptable_high_res_scale) {
146 continue;
149 // Keep low resolution tilings, if the tiling set should have them.
150 if (should_have_low_res &&
151 (tiling->resolution() == LOW_RESOLUTION ||
152 tiling->contents_scale() == twin_low_res_scale)) {
153 continue;
156 // Don't remove tilings that are required.
157 if (std::find(needed_tilings.begin(), needed_tilings.end(), tiling) !=
158 needed_tilings.end()) {
159 continue;
162 to_remove.push_back(tiling);
165 for (auto* tiling : to_remove) {
166 PictureLayerTiling* recycled_twin_tiling =
167 recycled_twin_set
168 ? recycled_twin_set->FindTilingWithScale(tiling->contents_scale())
169 : nullptr;
170 // Remove the tiling from the recycle tree. Note that we ignore resolution,
171 // since we don't need to maintain high/low res on the recycle set.
172 if (recycled_twin_tiling)
173 recycled_twin_set->Remove(recycled_twin_tiling);
175 DCHECK_NE(HIGH_RESOLUTION, tiling->resolution());
176 Remove(tiling);
180 void PictureLayerTilingSet::RemoveNonIdealTilings() {
181 auto to_remove = tilings_.remove_if([](PictureLayerTiling* t) {
182 return t->resolution() == NON_IDEAL_RESOLUTION;
184 tilings_.erase(to_remove, tilings_.end());
187 void PictureLayerTilingSet::MarkAllTilingsNonIdeal() {
188 for (auto* tiling : tilings_)
189 tiling->set_resolution(NON_IDEAL_RESOLUTION);
192 bool PictureLayerTilingSet::SyncTilingsForTesting(
193 const PictureLayerTilingSet& other,
194 const gfx::Size& new_layer_bounds,
195 const Region& layer_invalidation,
196 float minimum_contents_scale,
197 RasterSource* raster_source) {
198 if (new_layer_bounds.IsEmpty()) {
199 RemoveAllTilings();
200 return false;
203 tilings_.reserve(other.tilings_.size());
205 // Remove any tilings that aren't in |other| or don't meet the minimum.
206 for (size_t i = 0; i < tilings_.size(); ++i) {
207 float scale = tilings_[i]->contents_scale();
208 if (scale >= minimum_contents_scale && !!other.FindTilingWithScale(scale))
209 continue;
210 // Swap with the last element and remove it.
211 tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
212 tilings_.pop_back();
213 --i;
216 bool have_high_res_tiling = false;
218 // Add any missing tilings from |other| that meet the minimum.
219 for (size_t i = 0; i < other.tilings_.size(); ++i) {
220 float contents_scale = other.tilings_[i]->contents_scale();
221 if (contents_scale < minimum_contents_scale)
222 continue;
223 if (PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale)) {
224 this_tiling->set_resolution(other.tilings_[i]->resolution());
226 this_tiling->Resize(new_layer_bounds);
227 this_tiling->Invalidate(layer_invalidation);
228 this_tiling->SetRasterSource(raster_source);
229 this_tiling->CreateMissingTilesInLiveTilesRect();
230 if (this_tiling->resolution() == HIGH_RESOLUTION)
231 have_high_res_tiling = true;
233 DCHECK(this_tiling->tile_size() ==
234 client_->CalculateTileSize(this_tiling->tiling_size()))
235 << "tile_size: " << this_tiling->tile_size().ToString()
236 << " tiling_size: " << this_tiling->tiling_size().ToString()
237 << " CalculateTileSize: "
238 << client_->CalculateTileSize(this_tiling->tiling_size()).ToString();
239 continue;
241 scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
242 contents_scale, new_layer_bounds, client_, max_tiles_for_interest_area_,
243 skewport_target_time_in_seconds_,
244 skewport_extrapolation_limit_in_content_pixels_);
245 new_tiling->set_resolution(other.tilings_[i]->resolution());
246 if (new_tiling->resolution() == HIGH_RESOLUTION)
247 have_high_res_tiling = true;
248 tilings_.push_back(new_tiling.Pass());
250 tilings_.sort(LargestToSmallestScaleFunctor());
252 return have_high_res_tiling;
255 PictureLayerTiling* PictureLayerTilingSet::AddTiling(
256 float contents_scale,
257 const gfx::Size& layer_bounds) {
258 for (size_t i = 0; i < tilings_.size(); ++i)
259 DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
261 tilings_.push_back(PictureLayerTiling::Create(
262 contents_scale, layer_bounds, client_, max_tiles_for_interest_area_,
263 skewport_target_time_in_seconds_,
264 skewport_extrapolation_limit_in_content_pixels_));
265 PictureLayerTiling* appended = tilings_.back();
267 tilings_.sort(LargestToSmallestScaleFunctor());
268 return appended;
271 int PictureLayerTilingSet::NumHighResTilings() const {
272 int num_high_res = 0;
273 for (size_t i = 0; i < tilings_.size(); ++i) {
274 if (tilings_[i]->resolution() == HIGH_RESOLUTION)
275 num_high_res++;
277 return num_high_res;
280 PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScale(
281 float scale) const {
282 for (size_t i = 0; i < tilings_.size(); ++i) {
283 if (tilings_[i]->contents_scale() == scale)
284 return tilings_[i];
286 return NULL;
289 PictureLayerTiling* PictureLayerTilingSet::FindTilingWithResolution(
290 TileResolution resolution) const {
291 auto iter = std::find_if(tilings_.begin(), tilings_.end(),
292 [resolution](const PictureLayerTiling* tiling) {
293 return tiling->resolution() == resolution;
295 if (iter == tilings_.end())
296 return NULL;
297 return *iter;
300 void PictureLayerTilingSet::RemoveTilingsBelowScale(float minimum_scale) {
301 auto to_remove =
302 tilings_.remove_if([minimum_scale](PictureLayerTiling* tiling) {
303 return tiling->contents_scale() < minimum_scale;
305 tilings_.erase(to_remove, tilings_.end());
308 void PictureLayerTilingSet::RemoveAllTilings() {
309 tilings_.clear();
312 void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
313 ScopedPtrVector<PictureLayerTiling>::iterator iter =
314 std::find(tilings_.begin(), tilings_.end(), tiling);
315 if (iter == tilings_.end())
316 return;
317 tilings_.erase(iter);
320 void PictureLayerTilingSet::RemoveAllTiles() {
321 for (size_t i = 0; i < tilings_.size(); ++i)
322 tilings_[i]->Reset();
325 float PictureLayerTilingSet::GetSnappedContentsScale(
326 float start_scale,
327 float snap_to_existing_tiling_ratio) const {
328 // If a tiling exists within the max snapping ratio, snap to its scale.
329 float snapped_contents_scale = start_scale;
330 float snapped_ratio = snap_to_existing_tiling_ratio;
331 for (const auto* tiling : tilings_) {
332 float tiling_contents_scale = tiling->contents_scale();
333 float ratio = LargerRatio(tiling_contents_scale, start_scale);
334 if (ratio < snapped_ratio) {
335 snapped_contents_scale = tiling_contents_scale;
336 snapped_ratio = ratio;
339 return snapped_contents_scale;
342 float PictureLayerTilingSet::GetMaximumContentsScale() const {
343 if (tilings_.empty())
344 return 0.f;
345 // The first tiling has the largest contents scale.
346 return tilings_[0]->contents_scale();
349 bool PictureLayerTilingSet::UpdateTilePriorities(
350 const gfx::Rect& required_rect_in_layer_space,
351 float ideal_contents_scale,
352 double current_frame_time_in_seconds,
353 const Occlusion& occlusion_in_layer_space,
354 bool can_require_tiles_for_activation) {
355 bool tiling_needs_update = false;
356 // TODO(vmpstr): Check if we have to early out here, or if we can just do it
357 // as part of computing tile priority rects for tilings.
358 for (auto* tiling : tilings_) {
359 if (tiling->NeedsUpdateForFrameAtTimeAndViewport(
360 current_frame_time_in_seconds, required_rect_in_layer_space)) {
361 tiling_needs_update = true;
362 break;
365 if (!tiling_needs_update)
366 return false;
368 for (auto* tiling : tilings_) {
369 tiling->set_can_require_tiles_for_activation(
370 can_require_tiles_for_activation);
371 tiling->ComputeTilePriorityRects(
372 required_rect_in_layer_space, ideal_contents_scale,
373 current_frame_time_in_seconds, occlusion_in_layer_space);
375 return true;
378 void PictureLayerTilingSet::GetAllTilesForTracing(
379 std::set<const Tile*>* tiles) const {
380 for (auto* tiling : tilings_)
381 tiling->GetAllTilesForTracing(tiles);
384 PictureLayerTilingSet::CoverageIterator::CoverageIterator(
385 const PictureLayerTilingSet* set,
386 float contents_scale,
387 const gfx::Rect& content_rect,
388 float ideal_contents_scale)
389 : set_(set),
390 contents_scale_(contents_scale),
391 ideal_contents_scale_(ideal_contents_scale),
392 current_tiling_(-1) {
393 missing_region_.Union(content_rect);
395 for (ideal_tiling_ = 0;
396 static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
397 ++ideal_tiling_) {
398 PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
399 if (tiling->contents_scale() < ideal_contents_scale_) {
400 if (ideal_tiling_ > 0)
401 ideal_tiling_--;
402 break;
406 DCHECK_LE(set_->tilings_.size(),
407 static_cast<size_t>(std::numeric_limits<int>::max()));
409 int num_tilings = set_->tilings_.size();
410 if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
411 ideal_tiling_--;
413 ++(*this);
416 PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
419 gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
420 if (!tiling_iter_) {
421 if (!region_iter_.has_rect())
422 return gfx::Rect();
423 return region_iter_.rect();
425 return tiling_iter_.geometry_rect();
428 gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
429 if (!tiling_iter_)
430 return gfx::RectF();
431 return tiling_iter_.texture_rect();
434 gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
435 if (!tiling_iter_)
436 return gfx::Size();
437 return tiling_iter_.texture_size();
440 Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
441 if (!tiling_iter_)
442 return NULL;
443 return *tiling_iter_;
446 Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
447 if (!tiling_iter_)
448 return NULL;
449 return *tiling_iter_;
452 TileResolution PictureLayerTilingSet::CoverageIterator::resolution() const {
453 const PictureLayerTiling* tiling = CurrentTiling();
454 DCHECK(tiling);
455 return tiling->resolution();
458 PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling()
459 const {
460 if (current_tiling_ < 0)
461 return NULL;
462 if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
463 return NULL;
464 return set_->tilings_[current_tiling_];
467 int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
468 // Order returned by this method is:
469 // 1. Ideal tiling index
470 // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
471 // 3. Tiling index > Ideal in increasing order (lower res than ideal)
472 // 4. Tiling index > tilings.size() (invalid index)
473 if (current_tiling_ < 0)
474 return ideal_tiling_;
475 else if (current_tiling_ > ideal_tiling_)
476 return current_tiling_ + 1;
477 else if (current_tiling_)
478 return current_tiling_ - 1;
479 else
480 return ideal_tiling_ + 1;
483 PictureLayerTilingSet::CoverageIterator&
484 PictureLayerTilingSet::CoverageIterator::operator++() {
485 bool first_time = current_tiling_ < 0;
487 if (!*this && !first_time)
488 return *this;
490 if (tiling_iter_)
491 ++tiling_iter_;
493 // Loop until we find a valid place to stop.
494 while (true) {
495 while (tiling_iter_ &&
496 (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) {
497 missing_region_.Union(tiling_iter_.geometry_rect());
498 ++tiling_iter_;
500 if (tiling_iter_)
501 return *this;
503 // If the set of current rects for this tiling is done, go to the next
504 // tiling and set up to iterate through all of the remaining holes.
505 // This will also happen the first time through the loop.
506 if (!region_iter_.has_rect()) {
507 current_tiling_ = NextTiling();
508 current_region_.Swap(&missing_region_);
509 missing_region_.Clear();
510 region_iter_ = Region::Iterator(current_region_);
512 // All done and all filled.
513 if (!region_iter_.has_rect()) {
514 current_tiling_ = set_->tilings_.size();
515 return *this;
518 // No more valid tiles, return this checkerboard rect.
519 if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
520 return *this;
523 // Pop a rect off. If there are no more tilings, then these will be
524 // treated as geometry with null tiles that the caller can checkerboard.
525 gfx::Rect last_rect = region_iter_.rect();
526 region_iter_.next();
528 // Done, found next checkerboard rect to return.
529 if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
530 return *this;
532 // Construct a new iterator for the next tiling, but we need to loop
533 // again until we get to a valid one.
534 tiling_iter_ = PictureLayerTiling::CoverageIterator(
535 set_->tilings_[current_tiling_],
536 contents_scale_,
537 last_rect);
540 return *this;
543 PictureLayerTilingSet::CoverageIterator::operator bool() const {
544 return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
545 region_iter_.has_rect();
548 void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const {
549 for (size_t i = 0; i < tilings_.size(); ++i) {
550 state->BeginDictionary();
551 tilings_[i]->AsValueInto(state);
552 state->EndDictionary();
556 size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
557 size_t amount = 0;
558 for (size_t i = 0; i < tilings_.size(); ++i)
559 amount += tilings_[i]->GPUMemoryUsageInBytes();
560 return amount;
563 PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
564 TilingRangeType type) const {
565 // Doesn't seem to be the case right now but if it ever becomes a performance
566 // problem to compute these ranges each time this function is called, we can
567 // compute them only when the tiling set has changed instead.
568 TilingRange high_res_range(0, 0);
569 TilingRange low_res_range(tilings_.size(), tilings_.size());
570 for (size_t i = 0; i < tilings_.size(); ++i) {
571 const PictureLayerTiling* tiling = tilings_[i];
572 if (tiling->resolution() == HIGH_RESOLUTION)
573 high_res_range = TilingRange(i, i + 1);
574 if (tiling->resolution() == LOW_RESOLUTION)
575 low_res_range = TilingRange(i, i + 1);
578 TilingRange range(0, 0);
579 switch (type) {
580 case HIGHER_THAN_HIGH_RES:
581 range = TilingRange(0, high_res_range.start);
582 break;
583 case HIGH_RES:
584 range = high_res_range;
585 break;
586 case BETWEEN_HIGH_AND_LOW_RES:
587 // TODO(vmpstr): This code assumes that high res tiling will come before
588 // low res tiling, however there are cases where this assumption is
589 // violated. As a result, it's better to be safe in these situations,
590 // since otherwise we can end up accessing a tiling that doesn't exist.
591 // See crbug.com/429397 for high res tiling appearing after low res
592 // tiling discussion/fixes.
593 if (high_res_range.start <= low_res_range.start)
594 range = TilingRange(high_res_range.end, low_res_range.start);
595 else
596 range = TilingRange(low_res_range.end, high_res_range.start);
597 break;
598 case LOW_RES:
599 range = low_res_range;
600 break;
601 case LOWER_THAN_LOW_RES:
602 range = TilingRange(low_res_range.end, tilings_.size());
603 break;
606 DCHECK_LE(range.start, range.end);
607 return range;
610 } // namespace cc