[NaCl SDK]: use standard __BEGIN_DECLS macros in sys/select.h
[chromium-blink-merge.git] / cc / resources / picture_layer_tiling.cc
blob8cb342488e8cc6505f97764a7c7d9eff10be92ae
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.h"
7 #include <algorithm>
8 #include <cmath>
9 #include <limits>
10 #include <set>
12 #include "base/debug/trace_event.h"
13 #include "base/debug/trace_event_argument.h"
14 #include "base/logging.h"
15 #include "cc/base/math_util.h"
16 #include "cc/resources/tile.h"
17 #include "cc/resources/tile_priority.h"
18 #include "cc/trees/occlusion_tracker.h"
19 #include "ui/gfx/point_conversions.h"
20 #include "ui/gfx/rect_conversions.h"
21 #include "ui/gfx/safe_integer_conversions.h"
22 #include "ui/gfx/size_conversions.h"
24 namespace cc {
25 namespace {
27 const float kSoonBorderDistanceInScreenPixels = 312.f;
29 class TileEvictionOrder {
30 public:
31 explicit TileEvictionOrder(TreePriority tree_priority)
32 : tree_priority_(tree_priority) {}
33 ~TileEvictionOrder() {}
35 bool operator()(const Tile* a, const Tile* b) {
36 const TilePriority& a_priority =
37 a->priority_for_tree_priority(tree_priority_);
38 const TilePriority& b_priority =
39 b->priority_for_tree_priority(tree_priority_);
41 DCHECK(a_priority.priority_bin == b_priority.priority_bin);
42 DCHECK(a->required_for_activation() == b->required_for_activation());
44 // Or if a is occluded and b is unoccluded.
45 bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_);
46 bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_);
47 if (a_is_occluded != b_is_occluded)
48 return a_is_occluded;
50 // Or if a is farther away from visible.
51 return a_priority.distance_to_visible > b_priority.distance_to_visible;
54 private:
55 TreePriority tree_priority_;
58 void ReleaseTile(Tile* tile, WhichTree tree) {
59 // Reset priority as tile is ref-counted and might still be used
60 // even though we no longer hold a reference to it here anymore.
61 tile->SetPriority(tree, TilePriority());
62 tile->set_shared(false);
65 } // namespace
67 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
68 float contents_scale,
69 const gfx::Size& layer_bounds,
70 PictureLayerTilingClient* client) {
71 return make_scoped_ptr(new PictureLayerTiling(contents_scale,
72 layer_bounds,
73 client));
76 PictureLayerTiling::PictureLayerTiling(float contents_scale,
77 const gfx::Size& layer_bounds,
78 PictureLayerTilingClient* client)
79 : contents_scale_(contents_scale),
80 layer_bounds_(layer_bounds),
81 resolution_(NON_IDEAL_RESOLUTION),
82 client_(client),
83 tiling_data_(gfx::Size(), gfx::Size(), true),
84 last_impl_frame_time_in_seconds_(0.0),
85 has_visible_rect_tiles_(false),
86 has_skewport_rect_tiles_(false),
87 has_soon_border_rect_tiles_(false),
88 has_eventually_rect_tiles_(false),
89 eviction_tiles_cache_valid_(false),
90 eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
91 gfx::Size content_bounds =
92 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
93 gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
94 if (tile_size.IsEmpty()) {
95 layer_bounds_ = gfx::Size();
96 content_bounds = gfx::Size();
99 DCHECK(!gfx::ToFlooredSize(
100 gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
101 "Tiling created with scale too small as contents become empty." <<
102 " Layer bounds: " << layer_bounds.ToString() <<
103 " Contents scale: " << contents_scale;
105 tiling_data_.SetTilingSize(content_bounds);
106 tiling_data_.SetMaxTextureSize(tile_size);
109 PictureLayerTiling::~PictureLayerTiling() {
110 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
111 ReleaseTile(it->second.get(), client_->GetTree());
114 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
115 client_ = client;
118 Tile* PictureLayerTiling::CreateTile(int i,
119 int j,
120 const PictureLayerTiling* twin_tiling) {
121 TileMapKey key(i, j);
122 DCHECK(tiles_.find(key) == tiles_.end());
124 gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
125 gfx::Rect tile_rect = paint_rect;
126 tile_rect.set_size(tiling_data_.max_texture_size());
128 // Check our twin for a valid tile.
129 if (twin_tiling &&
130 tiling_data_.max_texture_size() ==
131 twin_tiling->tiling_data_.max_texture_size()) {
132 if (Tile* candidate_tile = twin_tiling->TileAt(i, j)) {
133 gfx::Rect rect =
134 gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
135 if (!client_->GetInvalidation()->Intersects(rect)) {
136 DCHECK(!candidate_tile->is_shared());
137 candidate_tile->set_shared(true);
138 tiles_[key] = candidate_tile;
139 return candidate_tile;
144 // Create a new tile because our twin didn't have a valid one.
145 scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
146 if (tile.get()) {
147 DCHECK(!tile->is_shared());
148 tiles_[key] = tile;
150 return tile.get();
153 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
154 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
155 bool include_borders = false;
156 for (TilingData::Iterator iter(
157 &tiling_data_, live_tiles_rect_, include_borders);
158 iter;
159 ++iter) {
160 TileMapKey key = iter.index();
161 TileMap::iterator find = tiles_.find(key);
162 if (find != tiles_.end())
163 continue;
164 CreateTile(key.first, key.second, twin_tiling);
167 VerifyLiveTilesRect();
170 void PictureLayerTiling::UpdateTilesToCurrentPile(
171 const Region& layer_invalidation,
172 const gfx::Size& new_layer_bounds) {
173 DCHECK(!new_layer_bounds.IsEmpty());
175 gfx::Size tile_size = tiling_data_.max_texture_size();
177 if (new_layer_bounds != layer_bounds_) {
178 gfx::Size content_bounds =
179 gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
181 tile_size = client_->CalculateTileSize(content_bounds);
182 if (tile_size.IsEmpty()) {
183 layer_bounds_ = gfx::Size();
184 content_bounds = gfx::Size();
185 } else {
186 layer_bounds_ = new_layer_bounds;
189 // The SetLiveTilesRect() method would drop tiles outside the new bounds,
190 // but may do so incorrectly if resizing the tiling causes the number of
191 // tiles in the tiling_data_ to change.
192 gfx::Rect content_rect(content_bounds);
193 int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
194 int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
195 int before_right =
196 tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
197 int before_bottom =
198 tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
200 // The live_tiles_rect_ is clamped to stay within the tiling size as we
201 // change it.
202 live_tiles_rect_.Intersect(content_rect);
203 tiling_data_.SetTilingSize(content_bounds);
205 int after_right = -1;
206 int after_bottom = -1;
207 if (!live_tiles_rect_.IsEmpty()) {
208 after_right =
209 tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
210 after_bottom =
211 tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
214 // There is no recycled twin since this is run on the pending tiling.
215 PictureLayerTiling* recycled_twin = NULL;
216 DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
217 DCHECK_EQ(PENDING_TREE, client_->GetTree());
219 // Drop tiles outside the new layer bounds if the layer shrank.
220 for (int i = after_right + 1; i <= before_right; ++i) {
221 for (int j = before_top; j <= before_bottom; ++j)
222 RemoveTileAt(i, j, recycled_twin);
224 for (int i = before_left; i <= after_right; ++i) {
225 for (int j = after_bottom + 1; j <= before_bottom; ++j)
226 RemoveTileAt(i, j, recycled_twin);
229 // If the layer grew, the live_tiles_rect_ is not changed, but a new row
230 // and/or column of tiles may now exist inside the same live_tiles_rect_.
231 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
232 if (after_right > before_right) {
233 DCHECK_EQ(after_right, before_right + 1);
234 for (int j = before_top; j <= after_bottom; ++j)
235 CreateTile(after_right, j, twin_tiling);
237 if (after_bottom > before_bottom) {
238 DCHECK_EQ(after_bottom, before_bottom + 1);
239 for (int i = before_left; i <= before_right; ++i)
240 CreateTile(i, after_bottom, twin_tiling);
244 if (tile_size != tiling_data_.max_texture_size()) {
245 tiling_data_.SetMaxTextureSize(tile_size);
246 // When the tile size changes, the TilingData positions no longer work
247 // as valid keys to the TileMap, so just drop all tiles.
248 Reset();
249 } else {
250 Invalidate(layer_invalidation);
253 PicturePileImpl* pile = client_->GetPile();
254 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
255 it->second->set_picture_pile(pile);
256 VerifyLiveTilesRect();
259 void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
260 bool recreate_invalidated_tiles = false;
261 DoInvalidate(layer_region, recreate_invalidated_tiles);
264 void PictureLayerTiling::Invalidate(const Region& layer_region) {
265 bool recreate_invalidated_tiles = true;
266 DoInvalidate(layer_region, recreate_invalidated_tiles);
269 void PictureLayerTiling::DoInvalidate(const Region& layer_region,
270 bool recreate_invalidated_tiles) {
271 std::vector<TileMapKey> new_tile_keys;
272 gfx::Rect expanded_live_tiles_rect =
273 tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
274 for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
275 gfx::Rect layer_rect = iter.rect();
276 gfx::Rect content_rect =
277 gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
278 // Consider tiles inside the live tiles rect even if only their border
279 // pixels intersect the invalidation. But don't consider tiles outside
280 // the live tiles rect with the same conditions, as they won't exist.
281 int border_pixels = tiling_data_.border_texels();
282 content_rect.Inset(-border_pixels, -border_pixels);
283 // Avoid needless work by not bothering to invalidate where there aren't
284 // tiles.
285 content_rect.Intersect(expanded_live_tiles_rect);
286 if (content_rect.IsEmpty())
287 continue;
288 // Since the content_rect includes border pixels already, don't include
289 // borders when iterating to avoid double counting them.
290 bool include_borders = false;
291 for (TilingData::Iterator iter(
292 &tiling_data_, content_rect, include_borders);
293 iter;
294 ++iter) {
295 // There is no recycled twin since this is run on the pending tiling.
296 PictureLayerTiling* recycled_twin = NULL;
297 DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
298 DCHECK_EQ(PENDING_TREE, client_->GetTree());
299 if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin))
300 new_tile_keys.push_back(iter.index());
304 if (recreate_invalidated_tiles && !new_tile_keys.empty()) {
305 for (size_t i = 0; i < new_tile_keys.size(); ++i) {
306 // Don't try to share a tile with the twin layer, it's been invalidated so
307 // we have to make our own tile here.
308 const PictureLayerTiling* twin_tiling = NULL;
309 CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
314 PictureLayerTiling::CoverageIterator::CoverageIterator()
315 : tiling_(NULL),
316 current_tile_(NULL),
317 tile_i_(0),
318 tile_j_(0),
319 left_(0),
320 top_(0),
321 right_(-1),
322 bottom_(-1) {
325 PictureLayerTiling::CoverageIterator::CoverageIterator(
326 const PictureLayerTiling* tiling,
327 float dest_scale,
328 const gfx::Rect& dest_rect)
329 : tiling_(tiling),
330 dest_rect_(dest_rect),
331 dest_to_content_scale_(0),
332 current_tile_(NULL),
333 tile_i_(0),
334 tile_j_(0),
335 left_(0),
336 top_(0),
337 right_(-1),
338 bottom_(-1) {
339 DCHECK(tiling_);
340 if (dest_rect_.IsEmpty())
341 return;
343 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
345 gfx::Rect content_rect =
346 gfx::ScaleToEnclosingRect(dest_rect_,
347 dest_to_content_scale_,
348 dest_to_content_scale_);
349 // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
350 // check for non-intersection first.
351 content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
352 if (content_rect.IsEmpty())
353 return;
355 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x());
356 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y());
357 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(
358 content_rect.right() - 1);
359 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(
360 content_rect.bottom() - 1);
362 tile_i_ = left_ - 1;
363 tile_j_ = top_;
364 ++(*this);
367 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
370 PictureLayerTiling::CoverageIterator&
371 PictureLayerTiling::CoverageIterator::operator++() {
372 if (tile_j_ > bottom_)
373 return *this;
375 bool first_time = tile_i_ < left_;
376 bool new_row = false;
377 tile_i_++;
378 if (tile_i_ > right_) {
379 tile_i_ = left_;
380 tile_j_++;
381 new_row = true;
382 if (tile_j_ > bottom_) {
383 current_tile_ = NULL;
384 return *this;
388 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
390 // Calculate the current geometry rect. Due to floating point rounding
391 // and ToEnclosingRect, tiles might overlap in destination space on the
392 // edges.
393 gfx::Rect last_geometry_rect = current_geometry_rect_;
395 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_);
397 current_geometry_rect_ =
398 gfx::ScaleToEnclosingRect(content_rect,
399 1 / dest_to_content_scale_,
400 1 / dest_to_content_scale_);
402 current_geometry_rect_.Intersect(dest_rect_);
404 if (first_time)
405 return *this;
407 // Iteration happens left->right, top->bottom. Running off the bottom-right
408 // edge is handled by the intersection above with dest_rect_. Here we make
409 // sure that the new current geometry rect doesn't overlap with the last.
410 int min_left;
411 int min_top;
412 if (new_row) {
413 min_left = dest_rect_.x();
414 min_top = last_geometry_rect.bottom();
415 } else {
416 min_left = last_geometry_rect.right();
417 min_top = last_geometry_rect.y();
420 int inset_left = std::max(0, min_left - current_geometry_rect_.x());
421 int inset_top = std::max(0, min_top - current_geometry_rect_.y());
422 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
424 if (!new_row) {
425 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
426 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
427 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
430 return *this;
433 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
434 return current_geometry_rect_;
437 gfx::Rect
438 PictureLayerTiling::CoverageIterator::full_tile_geometry_rect() const {
439 gfx::Rect rect = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_);
440 rect.set_size(tiling_->tiling_data_.max_texture_size());
441 return rect;
444 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
445 gfx::PointF tex_origin =
446 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin();
448 // Convert from dest space => content space => texture space.
449 gfx::RectF texture_rect(current_geometry_rect_);
450 texture_rect.Scale(dest_to_content_scale_,
451 dest_to_content_scale_);
452 texture_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
453 if (texture_rect.IsEmpty())
454 return texture_rect;
455 texture_rect.Offset(-tex_origin.OffsetFromOrigin());
457 return texture_rect;
460 gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const {
461 return tiling_->tiling_data_.max_texture_size();
464 bool PictureLayerTiling::RemoveTileAt(int i,
465 int j,
466 PictureLayerTiling* recycled_twin) {
467 TileMap::iterator found = tiles_.find(TileMapKey(i, j));
468 if (found == tiles_.end())
469 return false;
470 ReleaseTile(found->second.get(), client_->GetTree());
471 tiles_.erase(found);
472 if (recycled_twin) {
473 // Recycled twin does not also have a recycled twin, so pass NULL.
474 recycled_twin->RemoveTileAt(i, j, NULL);
476 return true;
479 void PictureLayerTiling::Reset() {
480 live_tiles_rect_ = gfx::Rect();
481 PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
482 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
483 ReleaseTile(it->second.get(), client_->GetTree());
484 if (recycled_twin)
485 recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL);
487 tiles_.clear();
490 gfx::Rect PictureLayerTiling::ComputeSkewport(
491 double current_frame_time_in_seconds,
492 const gfx::Rect& visible_rect_in_content_space) const {
493 gfx::Rect skewport = visible_rect_in_content_space;
494 if (last_impl_frame_time_in_seconds_ == 0.0)
495 return skewport;
497 double time_delta =
498 current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
499 if (time_delta == 0.0)
500 return skewport;
502 float skewport_target_time_in_seconds =
503 client_->GetSkewportTargetTimeInSeconds();
504 double extrapolation_multiplier =
505 skewport_target_time_in_seconds / time_delta;
507 int old_x = last_visible_rect_in_content_space_.x();
508 int old_y = last_visible_rect_in_content_space_.y();
509 int old_right = last_visible_rect_in_content_space_.right();
510 int old_bottom = last_visible_rect_in_content_space_.bottom();
512 int new_x = visible_rect_in_content_space.x();
513 int new_y = visible_rect_in_content_space.y();
514 int new_right = visible_rect_in_content_space.right();
515 int new_bottom = visible_rect_in_content_space.bottom();
517 int skewport_limit = client_->GetSkewportExtrapolationLimitInContentPixels();
519 // Compute the maximum skewport based on |skewport_limit|.
520 gfx::Rect max_skewport = skewport;
521 max_skewport.Inset(
522 -skewport_limit, -skewport_limit, -skewport_limit, -skewport_limit);
524 // Inset the skewport by the needed adjustment.
525 skewport.Inset(extrapolation_multiplier * (new_x - old_x),
526 extrapolation_multiplier * (new_y - old_y),
527 extrapolation_multiplier * (old_right - new_right),
528 extrapolation_multiplier * (old_bottom - new_bottom));
530 // Clip the skewport to |max_skewport|.
531 skewport.Intersect(max_skewport);
533 // Finally, ensure that visible rect is contained in the skewport.
534 skewport.Union(visible_rect_in_content_space);
535 return skewport;
538 void PictureLayerTiling::UpdateTilePriorities(
539 WhichTree tree,
540 const gfx::Rect& visible_layer_rect,
541 float ideal_contents_scale,
542 double current_frame_time_in_seconds,
543 const OcclusionTracker<LayerImpl>* occlusion_tracker,
544 const LayerImpl* render_target,
545 const gfx::Transform& draw_transform) {
546 if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) {
547 // This should never be zero for the purposes of has_ever_been_updated().
548 DCHECK_NE(current_frame_time_in_seconds, 0.0);
549 return;
552 gfx::Rect visible_rect_in_content_space =
553 gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
555 if (tiling_size().IsEmpty()) {
556 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
557 last_visible_rect_in_content_space_ = visible_rect_in_content_space;
558 return;
561 size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea();
563 gfx::Size tile_size = tiling_data_.max_texture_size();
564 int64 eventually_rect_area =
565 max_tiles_for_interest_area * tile_size.width() * tile_size.height();
567 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds,
568 visible_rect_in_content_space);
569 DCHECK(skewport.Contains(visible_rect_in_content_space));
571 gfx::Rect eventually_rect =
572 ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
573 eventually_rect_area,
574 gfx::Rect(tiling_size()),
575 &expansion_cache_);
577 DCHECK(eventually_rect.IsEmpty() ||
578 gfx::Rect(tiling_size()).Contains(eventually_rect))
579 << "tiling_size: " << tiling_size().ToString()
580 << " eventually_rect: " << eventually_rect.ToString();
582 SetLiveTilesRect(eventually_rect);
584 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
585 last_visible_rect_in_content_space_ = visible_rect_in_content_space;
587 eviction_tiles_cache_valid_ = false;
589 TilePriority now_priority(resolution_, TilePriority::NOW, 0);
590 float content_to_screen_scale = ideal_contents_scale / contents_scale_;
592 // Assign now priority to all visible tiles.
593 bool include_borders = false;
594 has_visible_rect_tiles_ = false;
595 for (TilingData::Iterator iter(
596 &tiling_data_, visible_rect_in_content_space, include_borders);
597 iter;
598 ++iter) {
599 TileMap::iterator find = tiles_.find(iter.index());
600 if (find == tiles_.end())
601 continue;
602 has_visible_rect_tiles_ = true;
603 Tile* tile = find->second.get();
605 tile->SetPriority(tree, now_priority);
607 // Set whether tile is occluded or not.
608 bool is_occluded = false;
609 if (occlusion_tracker) {
610 gfx::Rect tile_query_rect = ScaleToEnclosingRect(
611 IntersectRects(tile->content_rect(), visible_rect_in_content_space),
612 1.0f / contents_scale_);
613 // TODO(vmpstr): Remove render_target and draw_transform from the
614 // parameters so they can be hidden from the tiling.
615 is_occluded = occlusion_tracker->Occluded(
616 render_target, tile_query_rect, draw_transform);
618 tile->set_is_occluded(tree, is_occluded);
621 // Assign soon priority to skewport tiles.
622 has_skewport_rect_tiles_ = false;
623 for (TilingData::DifferenceIterator iter(
624 &tiling_data_, skewport, visible_rect_in_content_space);
625 iter;
626 ++iter) {
627 TileMap::iterator find = tiles_.find(iter.index());
628 if (find == tiles_.end())
629 continue;
630 has_skewport_rect_tiles_ = true;
631 Tile* tile = find->second.get();
633 gfx::Rect tile_bounds =
634 tiling_data_.TileBounds(iter.index_x(), iter.index_y());
636 float distance_to_visible =
637 visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
638 content_to_screen_scale;
640 TilePriority priority(resolution_, TilePriority::SOON, distance_to_visible);
641 tile->SetPriority(tree, priority);
644 // Assign eventually priority to interest rect tiles.
645 has_eventually_rect_tiles_ = false;
646 for (TilingData::DifferenceIterator iter(
647 &tiling_data_, eventually_rect, skewport);
648 iter;
649 ++iter) {
650 TileMap::iterator find = tiles_.find(iter.index());
651 if (find == tiles_.end())
652 continue;
653 has_eventually_rect_tiles_ = true;
654 Tile* tile = find->second.get();
656 gfx::Rect tile_bounds =
657 tiling_data_.TileBounds(iter.index_x(), iter.index_y());
659 float distance_to_visible =
660 visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
661 content_to_screen_scale;
662 TilePriority priority(
663 resolution_, TilePriority::EVENTUALLY, distance_to_visible);
664 tile->SetPriority(tree, priority);
667 // Upgrade the priority on border tiles to be SOON.
668 gfx::Rect soon_border_rect = visible_rect_in_content_space;
669 float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
670 soon_border_rect.Inset(-border, -border, -border, -border);
671 has_soon_border_rect_tiles_ = false;
672 for (TilingData::DifferenceIterator iter(
673 &tiling_data_, soon_border_rect, skewport);
674 iter;
675 ++iter) {
676 TileMap::iterator find = tiles_.find(iter.index());
677 if (find == tiles_.end())
678 continue;
679 has_soon_border_rect_tiles_ = true;
680 Tile* tile = find->second.get();
682 TilePriority priority(resolution_,
683 TilePriority::SOON,
684 tile->priority(tree).distance_to_visible);
685 tile->SetPriority(tree, priority);
688 // Update iteration rects.
689 current_visible_rect_ = visible_rect_in_content_space;
690 current_skewport_rect_ = skewport;
691 current_soon_border_rect_ = soon_border_rect;
692 current_eventually_rect_ = eventually_rect;
695 void PictureLayerTiling::SetLiveTilesRect(
696 const gfx::Rect& new_live_tiles_rect) {
697 DCHECK(new_live_tiles_rect.IsEmpty() ||
698 gfx::Rect(tiling_size()).Contains(new_live_tiles_rect))
699 << "tiling_size: " << tiling_size().ToString()
700 << " new_live_tiles_rect: " << new_live_tiles_rect.ToString();
701 if (live_tiles_rect_ == new_live_tiles_rect)
702 return;
704 // Iterate to delete all tiles outside of our new live_tiles rect.
705 PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
706 for (TilingData::DifferenceIterator iter(&tiling_data_,
707 live_tiles_rect_,
708 new_live_tiles_rect);
709 iter;
710 ++iter) {
711 RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin);
714 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
716 // Iterate to allocate new tiles for all regions with newly exposed area.
717 for (TilingData::DifferenceIterator iter(&tiling_data_,
718 new_live_tiles_rect,
719 live_tiles_rect_);
720 iter;
721 ++iter) {
722 TileMapKey key(iter.index());
723 CreateTile(key.first, key.second, twin_tiling);
726 live_tiles_rect_ = new_live_tiles_rect;
727 VerifyLiveTilesRect();
730 void PictureLayerTiling::VerifyLiveTilesRect() {
731 #if DCHECK_IS_ON
732 for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
733 if (!it->second.get())
734 continue;
735 DCHECK(it->first.first < tiling_data_.num_tiles_x())
736 << this << " " << it->first.first << "," << it->first.second
737 << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
738 << live_tiles_rect_.ToString();
739 DCHECK(it->first.second < tiling_data_.num_tiles_y())
740 << this << " " << it->first.first << "," << it->first.second
741 << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
742 << live_tiles_rect_.ToString();
743 DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
744 .Intersects(live_tiles_rect_))
745 << this << " " << it->first.first << "," << it->first.second
746 << " tile bounds "
747 << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
748 << " live_tiles_rect " << live_tiles_rect_.ToString();
750 #endif
753 void PictureLayerTiling::DidBecomeRecycled() {
754 // DidBecomeActive below will set the active priority for tiles that are
755 // still in the tree. Calling this first on an active tiling that is becoming
756 // recycled takes care of tiles that are no longer in the active tree (eg.
757 // due to a pending invalidation).
758 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
759 it->second->SetPriority(ACTIVE_TREE, TilePriority());
763 void PictureLayerTiling::DidBecomeActive() {
764 PicturePileImpl* active_pile = client_->GetPile();
765 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
766 it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE));
767 it->second->SetPriority(PENDING_TREE, TilePriority());
769 // Tile holds a ref onto a picture pile. If the tile never gets invalidated
770 // and recreated, then that picture pile ref could exist indefinitely. To
771 // prevent this, ask the client to update the pile to its own ref. This
772 // will cause PicturePileImpls to get deleted once the corresponding
773 // PictureLayerImpl and any in flight raster jobs go out of scope.
774 it->second->set_picture_pile(active_pile);
778 void PictureLayerTiling::GetAllTilesForTracing(
779 std::set<const Tile*>* tiles) const {
780 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
781 tiles->insert(it->second.get());
784 void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const {
785 state->SetInteger("num_tiles", tiles_.size());
786 state->SetDouble("content_scale", contents_scale_);
787 state->BeginDictionary("tiling_size");
788 MathUtil::AddToTracedValue(tiling_size(), state);
789 state->EndDictionary();
792 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
793 size_t amount = 0;
794 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
795 const Tile* tile = it->second.get();
796 amount += tile->GPUMemoryUsageInBytes();
798 return amount;
801 PictureLayerTiling::RectExpansionCache::RectExpansionCache()
802 : previous_target(0) {
805 namespace {
807 // This struct represents an event at which the expending rect intersects
808 // one of its boundaries. 4 intersection events will occur during expansion.
809 struct EdgeEvent {
810 enum { BOTTOM, TOP, LEFT, RIGHT } edge;
811 int* num_edges;
812 int distance;
815 // Compute the delta to expand from edges to cover target_area.
816 int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
817 int width, int height,
818 int64 target_area) {
819 // Compute coefficients for the quadratic equation:
820 // a*x^2 + b*x + c = 0
821 int a = num_y_edges * num_x_edges;
822 int b = num_y_edges * width + num_x_edges * height;
823 int64 c = static_cast<int64>(width) * height - target_area;
825 // Compute the delta for our edges using the quadratic equation.
826 return a == 0 ? -c / b :
827 (-b + static_cast<int>(
828 std::sqrt(static_cast<int64>(b) * b - 4.0 * a * c))) / (2 * a);
831 } // namespace
833 gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
834 const gfx::Rect& starting_rect,
835 int64 target_area,
836 const gfx::Rect& bounding_rect,
837 RectExpansionCache* cache) {
838 if (starting_rect.IsEmpty())
839 return starting_rect;
841 if (cache &&
842 cache->previous_start == starting_rect &&
843 cache->previous_bounds == bounding_rect &&
844 cache->previous_target == target_area)
845 return cache->previous_result;
847 if (cache) {
848 cache->previous_start = starting_rect;
849 cache->previous_bounds = bounding_rect;
850 cache->previous_target = target_area;
853 DCHECK(!bounding_rect.IsEmpty());
854 DCHECK_GT(target_area, 0);
856 // Expand the starting rect to cover target_area, if it is smaller than it.
857 int delta = ComputeExpansionDelta(
858 2, 2, starting_rect.width(), starting_rect.height(), target_area);
859 gfx::Rect expanded_starting_rect = starting_rect;
860 if (delta > 0)
861 expanded_starting_rect.Inset(-delta, -delta);
863 gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect);
864 if (rect.IsEmpty()) {
865 // The starting_rect and bounding_rect are far away.
866 if (cache)
867 cache->previous_result = rect;
868 return rect;
870 if (delta >= 0 && rect == expanded_starting_rect) {
871 // The starting rect already covers the entire bounding_rect and isn't too
872 // large for the target_area.
873 if (cache)
874 cache->previous_result = rect;
875 return rect;
878 // Continue to expand/shrink rect to let it cover target_area.
880 // These values will be updated by the loop and uses as the output.
881 int origin_x = rect.x();
882 int origin_y = rect.y();
883 int width = rect.width();
884 int height = rect.height();
886 // In the beginning we will consider 2 edges in each dimension.
887 int num_y_edges = 2;
888 int num_x_edges = 2;
890 // Create an event list.
891 EdgeEvent events[] = {
892 { EdgeEvent::BOTTOM, &num_y_edges, rect.y() - bounding_rect.y() },
893 { EdgeEvent::TOP, &num_y_edges, bounding_rect.bottom() - rect.bottom() },
894 { EdgeEvent::LEFT, &num_x_edges, rect.x() - bounding_rect.x() },
895 { EdgeEvent::RIGHT, &num_x_edges, bounding_rect.right() - rect.right() }
898 // Sort the events by distance (closest first).
899 if (events[0].distance > events[1].distance) std::swap(events[0], events[1]);
900 if (events[2].distance > events[3].distance) std::swap(events[2], events[3]);
901 if (events[0].distance > events[2].distance) std::swap(events[0], events[2]);
902 if (events[1].distance > events[3].distance) std::swap(events[1], events[3]);
903 if (events[1].distance > events[2].distance) std::swap(events[1], events[2]);
905 for (int event_index = 0; event_index < 4; event_index++) {
906 const EdgeEvent& event = events[event_index];
908 int delta = ComputeExpansionDelta(
909 num_x_edges, num_y_edges, width, height, target_area);
911 // Clamp delta to our event distance.
912 if (delta > event.distance)
913 delta = event.distance;
915 // Adjust the edge count for this kind of edge.
916 --*event.num_edges;
918 // Apply the delta to the edges and edge events.
919 for (int i = event_index; i < 4; i++) {
920 switch (events[i].edge) {
921 case EdgeEvent::BOTTOM:
922 origin_y -= delta;
923 height += delta;
924 break;
925 case EdgeEvent::TOP:
926 height += delta;
927 break;
928 case EdgeEvent::LEFT:
929 origin_x -= delta;
930 width += delta;
931 break;
932 case EdgeEvent::RIGHT:
933 width += delta;
934 break;
936 events[i].distance -= delta;
939 // If our delta is less then our event distance, we're done.
940 if (delta < event.distance)
941 break;
944 gfx::Rect result(origin_x, origin_y, width, height);
945 if (cache)
946 cache->previous_result = result;
947 return result;
950 void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
951 TreePriority tree_priority) {
952 if (eviction_tiles_cache_valid_ &&
953 eviction_cache_tree_priority_ == tree_priority)
954 return;
956 eviction_tiles_now_.clear();
957 eviction_tiles_now_and_required_for_activation_.clear();
958 eviction_tiles_soon_.clear();
959 eviction_tiles_soon_and_required_for_activation_.clear();
960 eviction_tiles_eventually_.clear();
961 eviction_tiles_eventually_and_required_for_activation_.clear();
963 for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
964 // TODO(vmpstr): This should update the priority if UpdateTilePriorities
965 // changes not to do this.
966 Tile* tile = it->second.get();
967 const TilePriority& priority =
968 tile->priority_for_tree_priority(tree_priority);
969 switch (priority.priority_bin) {
970 case TilePriority::EVENTUALLY:
971 if (tile->required_for_activation())
972 eviction_tiles_eventually_and_required_for_activation_.push_back(
973 tile);
974 else
975 eviction_tiles_eventually_.push_back(tile);
976 break;
977 case TilePriority::SOON:
978 if (tile->required_for_activation())
979 eviction_tiles_soon_and_required_for_activation_.push_back(tile);
980 else
981 eviction_tiles_soon_.push_back(tile);
982 break;
983 case TilePriority::NOW:
984 if (tile->required_for_activation())
985 eviction_tiles_now_and_required_for_activation_.push_back(tile);
986 else
987 eviction_tiles_now_.push_back(tile);
988 break;
992 // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that
993 // can be updated for each of the queues.
994 TileEvictionOrder sort_order(tree_priority);
995 std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order);
996 std::sort(eviction_tiles_now_and_required_for_activation_.begin(),
997 eviction_tiles_now_and_required_for_activation_.end(),
998 sort_order);
999 std::sort(
1000 eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order);
1001 std::sort(eviction_tiles_soon_and_required_for_activation_.begin(),
1002 eviction_tiles_soon_and_required_for_activation_.end(),
1003 sort_order);
1004 std::sort(eviction_tiles_eventually_.begin(),
1005 eviction_tiles_eventually_.end(),
1006 sort_order);
1007 std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(),
1008 eviction_tiles_eventually_and_required_for_activation_.end(),
1009 sort_order);
1011 eviction_tiles_cache_valid_ = true;
1012 eviction_cache_tree_priority_ = tree_priority;
1015 const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles(
1016 TreePriority tree_priority,
1017 EvictionCategory category) {
1018 UpdateEvictionCacheIfNeeded(tree_priority);
1019 switch (category) {
1020 case EVENTUALLY:
1021 return &eviction_tiles_eventually_;
1022 case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
1023 return &eviction_tiles_eventually_and_required_for_activation_;
1024 case SOON:
1025 return &eviction_tiles_soon_;
1026 case SOON_AND_REQUIRED_FOR_ACTIVATION:
1027 return &eviction_tiles_soon_and_required_for_activation_;
1028 case NOW:
1029 return &eviction_tiles_now_;
1030 case NOW_AND_REQUIRED_FOR_ACTIVATION:
1031 return &eviction_tiles_now_and_required_for_activation_;
1033 NOTREACHED();
1034 return &eviction_tiles_eventually_;
1037 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
1038 : tiling_(NULL), current_tile_(NULL) {}
1040 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
1041 PictureLayerTiling* tiling,
1042 WhichTree tree)
1043 : tiling_(tiling), phase_(VISIBLE_RECT), tree_(tree), current_tile_(NULL) {
1044 if (!tiling_->has_visible_rect_tiles_) {
1045 AdvancePhase();
1046 return;
1049 visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_,
1050 tiling_->current_visible_rect_,
1051 false /* include_borders */);
1052 if (!visible_iterator_) {
1053 AdvancePhase();
1054 return;
1057 current_tile_ =
1058 tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
1059 if (!current_tile_ || !TileNeedsRaster(current_tile_))
1060 ++(*this);
1063 PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
1065 void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
1066 DCHECK_LT(phase_, EVENTUALLY_RECT);
1068 do {
1069 phase_ = static_cast<Phase>(phase_ + 1);
1070 switch (phase_) {
1071 case VISIBLE_RECT:
1072 NOTREACHED();
1073 return;
1074 case SKEWPORT_RECT:
1075 if (!tiling_->has_skewport_rect_tiles_)
1076 continue;
1078 spiral_iterator_ = TilingData::SpiralDifferenceIterator(
1079 &tiling_->tiling_data_,
1080 tiling_->current_skewport_rect_,
1081 tiling_->current_visible_rect_,
1082 tiling_->current_visible_rect_);
1083 break;
1084 case SOON_BORDER_RECT:
1085 if (!tiling_->has_soon_border_rect_tiles_)
1086 continue;
1088 spiral_iterator_ = TilingData::SpiralDifferenceIterator(
1089 &tiling_->tiling_data_,
1090 tiling_->current_soon_border_rect_,
1091 tiling_->current_skewport_rect_,
1092 tiling_->current_visible_rect_);
1093 break;
1094 case EVENTUALLY_RECT:
1095 if (!tiling_->has_eventually_rect_tiles_) {
1096 current_tile_ = NULL;
1097 return;
1100 spiral_iterator_ = TilingData::SpiralDifferenceIterator(
1101 &tiling_->tiling_data_,
1102 tiling_->current_eventually_rect_,
1103 tiling_->current_skewport_rect_,
1104 tiling_->current_soon_border_rect_);
1105 break;
1108 while (spiral_iterator_) {
1109 current_tile_ = tiling_->TileAt(spiral_iterator_.index_x(),
1110 spiral_iterator_.index_y());
1111 if (current_tile_ && TileNeedsRaster(current_tile_))
1112 break;
1113 ++spiral_iterator_;
1116 if (!spiral_iterator_ && phase_ == EVENTUALLY_RECT) {
1117 current_tile_ = NULL;
1118 break;
1120 } while (!spiral_iterator_);
1123 PictureLayerTiling::TilingRasterTileIterator&
1124 PictureLayerTiling::TilingRasterTileIterator::
1125 operator++() {
1126 current_tile_ = NULL;
1127 while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
1128 std::pair<int, int> next_index;
1129 switch (phase_) {
1130 case VISIBLE_RECT:
1131 ++visible_iterator_;
1132 if (!visible_iterator_) {
1133 AdvancePhase();
1134 return *this;
1136 next_index = visible_iterator_.index();
1137 break;
1138 case SKEWPORT_RECT:
1139 case SOON_BORDER_RECT:
1140 ++spiral_iterator_;
1141 if (!spiral_iterator_) {
1142 AdvancePhase();
1143 return *this;
1145 next_index = spiral_iterator_.index();
1146 break;
1147 case EVENTUALLY_RECT:
1148 ++spiral_iterator_;
1149 if (!spiral_iterator_) {
1150 current_tile_ = NULL;
1151 return *this;
1153 next_index = spiral_iterator_.index();
1154 break;
1156 current_tile_ = tiling_->TileAt(next_index.first, next_index.second);
1158 return *this;
1161 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
1162 : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
1165 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
1166 PictureLayerTiling* tiling,
1167 TreePriority tree_priority,
1168 EvictionCategory category)
1169 : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
1170 // Note: initializing to "0 - 1" works as overflow is well defined for
1171 // unsigned integers.
1172 current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
1173 DCHECK(eviction_tiles_);
1174 ++(*this);
1177 PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
1180 PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
1181 return eviction_tiles_ &&
1182 current_eviction_tiles_index_ != eviction_tiles_->size();
1185 Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
1186 DCHECK(*this);
1187 return (*eviction_tiles_)[current_eviction_tiles_index_];
1190 const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
1191 DCHECK(*this);
1192 return (*eviction_tiles_)[current_eviction_tiles_index_];
1195 PictureLayerTiling::TilingEvictionTileIterator&
1196 PictureLayerTiling::TilingEvictionTileIterator::
1197 operator++() {
1198 DCHECK(*this);
1199 do {
1200 ++current_eviction_tiles_index_;
1201 } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
1202 !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
1204 return *this;
1207 } // namespace cc