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"
15 class LargestToSmallestScaleFunctor
{
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
;
31 scoped_ptr
<PictureLayerTilingSet
> PictureLayerTilingSet::Create(
32 PictureLayerTilingClient
* client
) {
33 return make_scoped_ptr(new PictureLayerTilingSet(client
));
36 PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient
* client
)
40 PictureLayerTilingSet::~PictureLayerTilingSet() {
43 void PictureLayerTilingSet::SetClient(PictureLayerTilingClient
* client
) {
45 for (size_t i
= 0; i
< tilings_
.size(); ++i
)
46 tilings_
[i
]->SetClient(client_
);
49 void PictureLayerTilingSet::RemoveTilesInRegion(const Region
& region
) {
50 for (size_t i
= 0; i
< tilings_
.size(); ++i
)
51 tilings_
[i
]->RemoveTilesInRegion(region
);
54 void PictureLayerTilingSet::CleanUpTilings(
55 float min_acceptable_high_res_scale
,
56 float max_acceptable_high_res_scale
,
57 const std::vector
<PictureLayerTiling
*>& needed_tilings
,
58 bool should_have_low_res
,
59 PictureLayerTilingSet
* twin_set
,
60 PictureLayerTilingSet
* recycled_twin_set
) {
61 float twin_low_res_scale
= 0.f
;
63 PictureLayerTiling
* tiling
=
64 twin_set
->FindTilingWithResolution(LOW_RESOLUTION
);
66 twin_low_res_scale
= tiling
->contents_scale();
69 std::vector
<PictureLayerTiling
*> to_remove
;
70 for (auto* tiling
: tilings_
) {
71 // Keep all tilings within the min/max scales.
72 if (tiling
->contents_scale() >= min_acceptable_high_res_scale
&&
73 tiling
->contents_scale() <= max_acceptable_high_res_scale
) {
77 // Keep low resolution tilings, if the tiling set should have them.
78 if (should_have_low_res
&&
79 (tiling
->resolution() == LOW_RESOLUTION
||
80 tiling
->contents_scale() == twin_low_res_scale
)) {
84 // Don't remove tilings that are required.
85 if (std::find(needed_tilings
.begin(), needed_tilings
.end(), tiling
) !=
86 needed_tilings
.end()) {
90 to_remove
.push_back(tiling
);
93 for (auto* tiling
: to_remove
) {
94 PictureLayerTiling
* twin_tiling
=
95 twin_set
? twin_set
->FindTilingWithScale(tiling
->contents_scale())
97 // Only remove tilings from the twin layer if they have
98 // NON_IDEAL_RESOLUTION.
99 if (twin_tiling
&& twin_tiling
->resolution() == NON_IDEAL_RESOLUTION
)
100 twin_set
->Remove(twin_tiling
);
102 PictureLayerTiling
* recycled_twin_tiling
=
104 ? recycled_twin_set
->FindTilingWithScale(tiling
->contents_scale())
106 // Remove the tiling from the recycle tree. Note that we ignore resolution,
107 // since we don't need to maintain high/low res on the recycle set.
108 if (recycled_twin_tiling
)
109 recycled_twin_set
->Remove(recycled_twin_tiling
);
111 DCHECK_NE(HIGH_RESOLUTION
, tiling
->resolution());
116 void PictureLayerTilingSet::MarkAllTilingsNonIdeal() {
117 for (auto* tiling
: tilings_
)
118 tiling
->set_resolution(NON_IDEAL_RESOLUTION
);
121 bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet
& other
,
122 const gfx::Size
& new_layer_bounds
,
123 const Region
& layer_invalidation
,
124 float minimum_contents_scale
,
125 RasterSource
* raster_source
) {
126 if (new_layer_bounds
.IsEmpty()) {
131 tilings_
.reserve(other
.tilings_
.size());
133 // Remove any tilings that aren't in |other| or don't meet the minimum.
134 for (size_t i
= 0; i
< tilings_
.size(); ++i
) {
135 float scale
= tilings_
[i
]->contents_scale();
136 if (scale
>= minimum_contents_scale
&& !!other
.FindTilingWithScale(scale
))
138 // Swap with the last element and remove it.
139 tilings_
.swap(tilings_
.begin() + i
, tilings_
.end() - 1);
144 bool have_high_res_tiling
= false;
146 // Add any missing tilings from |other| that meet the minimum.
147 for (size_t i
= 0; i
< other
.tilings_
.size(); ++i
) {
148 float contents_scale
= other
.tilings_
[i
]->contents_scale();
149 if (contents_scale
< minimum_contents_scale
)
151 if (PictureLayerTiling
* this_tiling
= FindTilingWithScale(contents_scale
)) {
152 this_tiling
->set_resolution(other
.tilings_
[i
]->resolution());
154 this_tiling
->UpdateTilesToCurrentRasterSource(
155 raster_source
, layer_invalidation
, new_layer_bounds
);
156 this_tiling
->CreateMissingTilesInLiveTilesRect();
157 if (this_tiling
->resolution() == HIGH_RESOLUTION
)
158 have_high_res_tiling
= true;
160 DCHECK(this_tiling
->tile_size() ==
161 client_
->CalculateTileSize(this_tiling
->tiling_size()))
162 << "tile_size: " << this_tiling
->tile_size().ToString()
163 << " tiling_size: " << this_tiling
->tiling_size().ToString()
164 << " CalculateTileSize: "
165 << client_
->CalculateTileSize(this_tiling
->tiling_size()).ToString();
168 scoped_ptr
<PictureLayerTiling
> new_tiling
= PictureLayerTiling::Create(
172 new_tiling
->set_resolution(other
.tilings_
[i
]->resolution());
173 if (new_tiling
->resolution() == HIGH_RESOLUTION
)
174 have_high_res_tiling
= true;
175 tilings_
.push_back(new_tiling
.Pass());
177 tilings_
.sort(LargestToSmallestScaleFunctor());
179 return have_high_res_tiling
;
182 PictureLayerTiling
* PictureLayerTilingSet::AddTiling(
183 float contents_scale
,
184 const gfx::Size
& layer_bounds
) {
185 for (size_t i
= 0; i
< tilings_
.size(); ++i
)
186 DCHECK_NE(tilings_
[i
]->contents_scale(), contents_scale
);
189 PictureLayerTiling::Create(contents_scale
, layer_bounds
, client_
));
190 PictureLayerTiling
* appended
= tilings_
.back();
192 tilings_
.sort(LargestToSmallestScaleFunctor());
196 int PictureLayerTilingSet::NumHighResTilings() const {
197 int num_high_res
= 0;
198 for (size_t i
= 0; i
< tilings_
.size(); ++i
) {
199 if (tilings_
[i
]->resolution() == HIGH_RESOLUTION
)
205 PictureLayerTiling
* PictureLayerTilingSet::FindTilingWithScale(
207 for (size_t i
= 0; i
< tilings_
.size(); ++i
) {
208 if (tilings_
[i
]->contents_scale() == scale
)
214 PictureLayerTiling
* PictureLayerTilingSet::FindTilingWithResolution(
215 TileResolution resolution
) const {
216 auto iter
= std::find_if(tilings_
.begin(), tilings_
.end(),
217 [resolution
](const PictureLayerTiling
* tiling
) {
218 return tiling
->resolution() == resolution
;
220 if (iter
== tilings_
.end())
225 void PictureLayerTilingSet::RemoveAllTilings() {
229 void PictureLayerTilingSet::Remove(PictureLayerTiling
* tiling
) {
230 ScopedPtrVector
<PictureLayerTiling
>::iterator iter
=
231 std::find(tilings_
.begin(), tilings_
.end(), tiling
);
232 if (iter
== tilings_
.end())
234 tilings_
.erase(iter
);
237 void PictureLayerTilingSet::RemoveAllTiles() {
238 for (size_t i
= 0; i
< tilings_
.size(); ++i
)
239 tilings_
[i
]->Reset();
242 float PictureLayerTilingSet::GetSnappedContentsScale(
244 float snap_to_existing_tiling_ratio
) const {
245 // If a tiling exists within the max snapping ratio, snap to its scale.
246 float snapped_contents_scale
= start_scale
;
247 float snapped_ratio
= snap_to_existing_tiling_ratio
;
248 for (const auto* tiling
: tilings_
) {
249 float tiling_contents_scale
= tiling
->contents_scale();
250 float ratio
= LargerRatio(tiling_contents_scale
, start_scale
);
251 if (ratio
< snapped_ratio
) {
252 snapped_contents_scale
= tiling_contents_scale
;
253 snapped_ratio
= ratio
;
256 return snapped_contents_scale
;
259 float PictureLayerTilingSet::GetMaximumContentsScale() const {
260 if (tilings_
.empty())
262 // The first tiling has the largest contents scale.
263 return tilings_
[0]->contents_scale();
266 bool PictureLayerTilingSet::UpdateTilePriorities(
267 const gfx::Rect
& required_rect_in_layer_space
,
268 float ideal_contents_scale
,
269 double current_frame_time_in_seconds
,
270 const Occlusion
& occlusion_in_layer_space
,
271 bool can_require_tiles_for_activation
) {
272 bool tiling_needs_update
= false;
273 // TODO(vmpstr): Check if we have to early out here, or if we can just do it
274 // as part of computing tile priority rects for tilings.
275 for (auto* tiling
: tilings_
) {
276 if (tiling
->NeedsUpdateForFrameAtTimeAndViewport(
277 current_frame_time_in_seconds
, required_rect_in_layer_space
)) {
278 tiling_needs_update
= true;
282 if (!tiling_needs_update
)
285 for (auto* tiling
: tilings_
) {
286 tiling
->set_can_require_tiles_for_activation(
287 can_require_tiles_for_activation
);
288 tiling
->ComputeTilePriorityRects(
289 required_rect_in_layer_space
, ideal_contents_scale
,
290 current_frame_time_in_seconds
, occlusion_in_layer_space
);
295 void PictureLayerTilingSet::GetAllTilesForTracing(
296 std::set
<const Tile
*>* tiles
) const {
297 for (auto* tiling
: tilings_
)
298 tiling
->GetAllTilesForTracing(tiles
);
301 PictureLayerTilingSet::CoverageIterator::CoverageIterator(
302 const PictureLayerTilingSet
* set
,
303 float contents_scale
,
304 const gfx::Rect
& content_rect
,
305 float ideal_contents_scale
)
307 contents_scale_(contents_scale
),
308 ideal_contents_scale_(ideal_contents_scale
),
309 current_tiling_(-1) {
310 missing_region_
.Union(content_rect
);
312 for (ideal_tiling_
= 0;
313 static_cast<size_t>(ideal_tiling_
) < set_
->tilings_
.size();
315 PictureLayerTiling
* tiling
= set_
->tilings_
[ideal_tiling_
];
316 if (tiling
->contents_scale() < ideal_contents_scale_
) {
317 if (ideal_tiling_
> 0)
323 DCHECK_LE(set_
->tilings_
.size(),
324 static_cast<size_t>(std::numeric_limits
<int>::max()));
326 int num_tilings
= set_
->tilings_
.size();
327 if (ideal_tiling_
== num_tilings
&& ideal_tiling_
> 0)
333 PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
336 gfx::Rect
PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
338 if (!region_iter_
.has_rect())
340 return region_iter_
.rect();
342 return tiling_iter_
.geometry_rect();
345 gfx::RectF
PictureLayerTilingSet::CoverageIterator::texture_rect() const {
348 return tiling_iter_
.texture_rect();
351 gfx::Size
PictureLayerTilingSet::CoverageIterator::texture_size() const {
354 return tiling_iter_
.texture_size();
357 Tile
* PictureLayerTilingSet::CoverageIterator::operator->() const {
360 return *tiling_iter_
;
363 Tile
* PictureLayerTilingSet::CoverageIterator::operator*() const {
366 return *tiling_iter_
;
369 TileResolution
PictureLayerTilingSet::CoverageIterator::resolution() const {
370 const PictureLayerTiling
* tiling
= CurrentTiling();
372 return tiling
->resolution();
375 PictureLayerTiling
* PictureLayerTilingSet::CoverageIterator::CurrentTiling()
377 if (current_tiling_
< 0)
379 if (static_cast<size_t>(current_tiling_
) >= set_
->tilings_
.size())
381 return set_
->tilings_
[current_tiling_
];
384 int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
385 // Order returned by this method is:
386 // 1. Ideal tiling index
387 // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
388 // 3. Tiling index > Ideal in increasing order (lower res than ideal)
389 // 4. Tiling index > tilings.size() (invalid index)
390 if (current_tiling_
< 0)
391 return ideal_tiling_
;
392 else if (current_tiling_
> ideal_tiling_
)
393 return current_tiling_
+ 1;
394 else if (current_tiling_
)
395 return current_tiling_
- 1;
397 return ideal_tiling_
+ 1;
400 PictureLayerTilingSet::CoverageIterator
&
401 PictureLayerTilingSet::CoverageIterator::operator++() {
402 bool first_time
= current_tiling_
< 0;
404 if (!*this && !first_time
)
410 // Loop until we find a valid place to stop.
412 while (tiling_iter_
&&
413 (!*tiling_iter_
|| !tiling_iter_
->IsReadyToDraw())) {
414 missing_region_
.Union(tiling_iter_
.geometry_rect());
420 // If the set of current rects for this tiling is done, go to the next
421 // tiling and set up to iterate through all of the remaining holes.
422 // This will also happen the first time through the loop.
423 if (!region_iter_
.has_rect()) {
424 current_tiling_
= NextTiling();
425 current_region_
.Swap(&missing_region_
);
426 missing_region_
.Clear();
427 region_iter_
= Region::Iterator(current_region_
);
429 // All done and all filled.
430 if (!region_iter_
.has_rect()) {
431 current_tiling_
= set_
->tilings_
.size();
435 // No more valid tiles, return this checkerboard rect.
436 if (current_tiling_
>= static_cast<int>(set_
->tilings_
.size()))
440 // Pop a rect off. If there are no more tilings, then these will be
441 // treated as geometry with null tiles that the caller can checkerboard.
442 gfx::Rect last_rect
= region_iter_
.rect();
445 // Done, found next checkerboard rect to return.
446 if (current_tiling_
>= static_cast<int>(set_
->tilings_
.size()))
449 // Construct a new iterator for the next tiling, but we need to loop
450 // again until we get to a valid one.
451 tiling_iter_
= PictureLayerTiling::CoverageIterator(
452 set_
->tilings_
[current_tiling_
],
460 PictureLayerTilingSet::CoverageIterator::operator bool() const {
461 return current_tiling_
< static_cast<int>(set_
->tilings_
.size()) ||
462 region_iter_
.has_rect();
465 void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue
* state
) const {
466 for (size_t i
= 0; i
< tilings_
.size(); ++i
) {
467 state
->BeginDictionary();
468 tilings_
[i
]->AsValueInto(state
);
469 state
->EndDictionary();
473 size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
475 for (size_t i
= 0; i
< tilings_
.size(); ++i
)
476 amount
+= tilings_
[i
]->GPUMemoryUsageInBytes();
480 PictureLayerTilingSet::TilingRange
PictureLayerTilingSet::GetTilingRange(
481 TilingRangeType type
) const {
482 // Doesn't seem to be the case right now but if it ever becomes a performance
483 // problem to compute these ranges each time this function is called, we can
484 // compute them only when the tiling set has changed instead.
485 TilingRange
high_res_range(0, 0);
486 TilingRange
low_res_range(tilings_
.size(), tilings_
.size());
487 for (size_t i
= 0; i
< tilings_
.size(); ++i
) {
488 const PictureLayerTiling
* tiling
= tilings_
[i
];
489 if (tiling
->resolution() == HIGH_RESOLUTION
)
490 high_res_range
= TilingRange(i
, i
+ 1);
491 if (tiling
->resolution() == LOW_RESOLUTION
)
492 low_res_range
= TilingRange(i
, i
+ 1);
495 TilingRange
range(0, 0);
497 case HIGHER_THAN_HIGH_RES
:
498 range
= TilingRange(0, high_res_range
.start
);
501 range
= high_res_range
;
503 case BETWEEN_HIGH_AND_LOW_RES
:
504 // TODO(vmpstr): This code assumes that high res tiling will come before
505 // low res tiling, however there are cases where this assumption is
506 // violated. As a result, it's better to be safe in these situations,
507 // since otherwise we can end up accessing a tiling that doesn't exist.
508 // See crbug.com/429397 for high res tiling appearing after low res
509 // tiling discussion/fixes.
510 if (high_res_range
.start
<= low_res_range
.start
)
511 range
= TilingRange(high_res_range
.end
, low_res_range
.start
);
513 range
= TilingRange(low_res_range
.end
, high_res_range
.start
);
516 range
= low_res_range
;
518 case LOWER_THAN_LOW_RES
:
519 range
= TilingRange(low_res_range
.end
, tilings_
.size());
523 DCHECK_LE(range
.start
, range
.end
);