Don't invoke Render() upon receipt of pause complete signal.
[chromium-blink-merge.git] / cc / layers / tiled_layer.cc
blob2a327417c61c602c1a4d5792e6e59e198649b62e
1 // Copyright 2011 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/layers/tiled_layer.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "build/build_config.h"
13 #include "cc/base/simple_enclosed_region.h"
14 #include "cc/layers/layer_impl.h"
15 #include "cc/layers/tiled_layer_impl.h"
16 #include "cc/resources/layer_updater.h"
17 #include "cc/resources/prioritized_resource.h"
18 #include "cc/resources/priority_calculator.h"
19 #include "cc/trees/layer_tree_host.h"
20 #include "cc/trees/occlusion_tracker.h"
21 #include "third_party/khronos/GLES2/gl2.h"
22 #include "ui/gfx/geometry/rect_conversions.h"
24 namespace cc {
26 // Maximum predictive expansion of the visible area.
27 static const int kMaxPredictiveTilesCount = 2;
29 // Number of rows/columns of tiles to pre-paint.
30 // We should increase these further as all textures are
31 // prioritized and we insure performance doesn't suffer.
32 static const int kPrepaintRows = 4;
33 static const int kPrepaintColumns = 2;
35 class UpdatableTile : public LayerTilingData::Tile {
36 public:
37 static scoped_ptr<UpdatableTile> Create(
38 scoped_ptr<LayerUpdater::Resource> updater_resource) {
39 return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
42 LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
43 PrioritizedResource* managed_resource() {
44 return updater_resource_->texture();
47 bool is_dirty() const { return !dirty_rect.IsEmpty(); }
49 // Reset update state for the current frame. This should occur before painting
50 // for all layers. Since painting one layer can invalidate another layer after
51 // it has already painted, mark all non-dirty tiles as valid before painting
52 // such that invalidations during painting won't prevent them from being
53 // pushed.
54 void ResetUpdateState() {
55 update_rect = gfx::Rect();
56 occluded = false;
57 partial_update = false;
58 valid_for_frame = !is_dirty();
61 // This promises to update the tile and therefore also guarantees the tile
62 // will be valid for this frame. dirty_rect is copied into update_rect so we
63 // can continue to track re-entrant invalidations that occur during painting.
64 void MarkForUpdate() {
65 valid_for_frame = true;
66 update_rect = dirty_rect;
67 dirty_rect = gfx::Rect();
70 gfx::Rect dirty_rect;
71 gfx::Rect update_rect;
72 bool partial_update;
73 bool valid_for_frame;
74 bool occluded;
76 private:
77 explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
78 : partial_update(false),
79 valid_for_frame(false),
80 occluded(false),
81 updater_resource_(updater_resource.Pass()) {}
83 scoped_ptr<LayerUpdater::Resource> updater_resource_;
85 DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
88 TiledLayer::TiledLayer()
89 : ContentsScalingLayer(),
90 texture_format_(RGBA_8888),
91 skips_draw_(false),
92 failed_update_(false),
93 tiling_option_(AUTO_TILE) {
94 tiler_ =
95 LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
98 TiledLayer::~TiledLayer() {}
100 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
101 return TiledLayerImpl::Create(tree_impl, id());
104 void TiledLayer::UpdateTileSizeAndTilingOption() {
105 DCHECK(layer_tree_host());
107 gfx::Size default_tile_size = layer_tree_host()->settings().default_tile_size;
108 gfx::Size max_untiled_layer_size =
109 layer_tree_host()->settings().max_untiled_layer_size;
110 int layer_width = content_bounds().width();
111 int layer_height = content_bounds().height();
113 gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
114 std::min(default_tile_size.height(), layer_height));
116 // Tile if both dimensions large, or any one dimension large and the other
117 // extends into a second tile but the total layer area isn't larger than that
118 // of the largest possible untiled layer. This heuristic allows for long
119 // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
120 // texture space but still avoids creating very large tiles.
121 bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
122 layer_height > max_untiled_layer_size.height();
123 bool any_dimension_one_tile =
124 (layer_width <= default_tile_size.width() ||
125 layer_height <= default_tile_size.height()) &&
126 (layer_width * layer_height) <= (max_untiled_layer_size.width() *
127 max_untiled_layer_size.height());
128 bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
130 bool is_tiled;
131 if (tiling_option_ == ALWAYS_TILE)
132 is_tiled = true;
133 else if (tiling_option_ == NEVER_TILE)
134 is_tiled = false;
135 else
136 is_tiled = auto_tiled;
138 gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
139 const int max_size =
140 layer_tree_host()->GetRendererCapabilities().max_texture_size;
141 requested_size.SetToMin(gfx::Size(max_size, max_size));
142 SetTileSize(requested_size);
145 void TiledLayer::UpdateBounds() {
146 gfx::Size old_tiling_size = tiler_->tiling_size();
147 gfx::Size new_tiling_size = content_bounds();
148 if (old_tiling_size == new_tiling_size)
149 return;
150 tiler_->SetTilingSize(new_tiling_size);
152 // Invalidate any areas that the new bounds exposes.
153 Region new_region =
154 SubtractRegions(gfx::Rect(new_tiling_size), gfx::Rect(old_tiling_size));
155 for (Region::Iterator new_rects(new_region); new_rects.has_rect();
156 new_rects.next())
157 InvalidateContentRect(new_rects.rect());
158 UpdateDrawsContent(HasDrawableContent());
161 void TiledLayer::SetTileSize(const gfx::Size& size) {
162 tiler_->SetTileSize(size);
163 UpdateDrawsContent(HasDrawableContent());
166 void TiledLayer::SetBorderTexelOption(
167 LayerTilingData::BorderTexelOption border_texel_option) {
168 tiler_->SetBorderTexelOption(border_texel_option);
169 UpdateDrawsContent(HasDrawableContent());
172 bool TiledLayer::HasDrawableContent() const {
173 bool has_more_than_one_tile =
174 (tiler_->num_tiles_x() > 1) || (tiler_->num_tiles_y() > 1);
176 return !(tiling_option_ == NEVER_TILE && has_more_than_one_tile) &&
177 ContentsScalingLayer::HasDrawableContent();
180 void TiledLayer::ReduceMemoryUsage() {
181 if (Updater())
182 Updater()->ReduceMemoryUsage();
185 void TiledLayer::SetIsMask(bool is_mask) {
186 set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
189 void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
190 ContentsScalingLayer::PushPropertiesTo(layer);
192 TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
194 tiled_layer->set_skips_draw(skips_draw_);
195 tiled_layer->SetTilingData(*tiler_);
196 std::vector<UpdatableTile*> invalid_tiles;
198 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
199 iter != tiler_->tiles().end();
200 ++iter) {
201 int i = iter->first.first;
202 int j = iter->first.second;
203 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
204 // TODO(enne): This should not ever be null.
205 if (!tile)
206 continue;
208 if (!tile->managed_resource()->have_backing_texture()) {
209 // Evicted tiles get deleted from both layers
210 invalid_tiles.push_back(tile);
211 continue;
214 if (!tile->valid_for_frame) {
215 // Invalidated tiles are set so they can get different debug colors.
216 tiled_layer->PushInvalidTile(i, j);
217 continue;
220 tiled_layer->PushTileProperties(
223 tile->managed_resource()->resource_id(),
224 tile->managed_resource()->contents_swizzled());
226 for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
227 iter != invalid_tiles.end();
228 ++iter)
229 tiler_->TakeTile((*iter)->i(), (*iter)->j());
231 // TiledLayer must push properties every frame, since viewport state and
232 // occlusion from anywhere in the tree can change what the layer decides to
233 // push to the impl tree.
234 needs_push_properties_ = true;
237 PrioritizedResourceManager* TiledLayer::ResourceManager() {
238 if (!layer_tree_host())
239 return nullptr;
240 return layer_tree_host()->contents_texture_manager();
243 const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
244 int j) const {
245 UpdatableTile* tile = TileAt(i, j);
246 if (!tile)
247 return nullptr;
248 return tile->managed_resource();
251 void TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
252 if (host && host != layer_tree_host()) {
253 for (LayerTilingData::TileMap::const_iterator
254 iter = tiler_->tiles().begin();
255 iter != tiler_->tiles().end();
256 ++iter) {
257 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
258 // TODO(enne): This should not ever be null.
259 if (!tile)
260 continue;
261 tile->managed_resource()->SetTextureManager(
262 host->contents_texture_manager());
265 ContentsScalingLayer::SetLayerTreeHost(host);
268 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
269 return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
272 UpdatableTile* TiledLayer::CreateTile(int i, int j) {
273 CreateUpdaterIfNeeded();
275 scoped_ptr<UpdatableTile> tile(
276 UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
277 tile->managed_resource()->SetDimensions(tiler_->tile_size(), texture_format_);
279 UpdatableTile* added_tile = tile.get();
280 tiler_->AddTile(tile.Pass(), i, j);
282 added_tile->dirty_rect = tiler_->TileRect(added_tile);
284 // Temporary diagnostic crash.
285 CHECK(added_tile);
286 CHECK(TileAt(i, j));
288 return added_tile;
291 void TiledLayer::SetNeedsDisplayRect(const gfx::Rect& dirty_rect) {
292 InvalidateContentRect(LayerRectToContentRect(dirty_rect));
293 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
296 void TiledLayer::InvalidateContentRect(const gfx::Rect& content_rect) {
297 UpdateBounds();
298 if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
299 return;
301 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
302 iter != tiler_->tiles().end();
303 ++iter) {
304 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
305 DCHECK(tile);
306 // TODO(enne): This should not ever be null.
307 if (!tile)
308 continue;
309 gfx::Rect bound = tiler_->TileRect(tile);
310 bound.Intersect(content_rect);
311 tile->dirty_rect.Union(bound);
315 // Returns true if tile is dirty and only part of it needs to be updated.
316 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
317 return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
318 tile->managed_resource()->have_backing_texture();
321 bool TiledLayer::UpdateTiles(int left,
322 int top,
323 int right,
324 int bottom,
325 ResourceUpdateQueue* queue,
326 const OcclusionTracker<Layer>* occlusion,
327 bool* updated) {
328 CreateUpdaterIfNeeded();
330 bool ignore_occlusions = !occlusion;
331 if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
332 failed_update_ = true;
333 return false;
336 gfx::Rect update_rect;
337 gfx::Rect paint_rect;
338 MarkTilesForUpdate(
339 &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions);
341 if (paint_rect.IsEmpty())
342 return true;
344 *updated = true;
345 UpdateTileTextures(
346 update_rect, paint_rect, left, top, right, bottom, queue, occlusion);
347 return true;
350 void TiledLayer::MarkOcclusionsAndRequestTextures(
351 int left,
352 int top,
353 int right,
354 int bottom,
355 const OcclusionTracker<Layer>* occlusion) {
356 int occluded_tile_count = 0;
357 bool succeeded = true;
358 for (int j = top; j <= bottom; ++j) {
359 for (int i = left; i <= right; ++i) {
360 UpdatableTile* tile = TileAt(i, j);
361 DCHECK(tile); // Did SetTexturePriorities get skipped?
362 // TODO(enne): This should not ever be null.
363 if (!tile)
364 continue;
365 // Did ResetUpdateState get skipped? Are we doing more than one occlusion
366 // pass?
367 DCHECK(!tile->occluded);
368 gfx::Rect visible_tile_rect = gfx::IntersectRects(
369 tiler_->tile_bounds(i, j), visible_content_rect());
370 if (!draw_transform_is_animating() && occlusion &&
371 occlusion->GetCurrentOcclusionForLayer(draw_transform())
372 .IsOccluded(visible_tile_rect)) {
373 tile->occluded = true;
374 occluded_tile_count++;
375 } else {
376 succeeded &= tile->managed_resource()->RequestLate();
382 bool TiledLayer::HaveTexturesForTiles(int left,
383 int top,
384 int right,
385 int bottom,
386 bool ignore_occlusions) {
387 for (int j = top; j <= bottom; ++j) {
388 for (int i = left; i <= right; ++i) {
389 UpdatableTile* tile = TileAt(i, j);
390 DCHECK(tile); // Did SetTexturePriorites get skipped?
391 // TODO(enne): This should not ever be null.
392 if (!tile)
393 continue;
395 // Ensure the entire tile is dirty if we don't have the texture.
396 if (!tile->managed_resource()->have_backing_texture())
397 tile->dirty_rect = tiler_->TileRect(tile);
399 // If using occlusion and the visible region of the tile is occluded,
400 // don't reserve a texture or update the tile.
401 if (tile->occluded && !ignore_occlusions)
402 continue;
404 if (!tile->managed_resource()->can_acquire_backing_texture())
405 return false;
408 return true;
411 void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect,
412 gfx::Rect* paint_rect,
413 int left,
414 int top,
415 int right,
416 int bottom,
417 bool ignore_occlusions) {
418 for (int j = top; j <= bottom; ++j) {
419 for (int i = left; i <= right; ++i) {
420 UpdatableTile* tile = TileAt(i, j);
421 DCHECK(tile); // Did SetTexturePriorites get skipped?
422 // TODO(enne): This should not ever be null.
423 if (!tile)
424 continue;
425 if (tile->occluded && !ignore_occlusions)
426 continue;
428 // Prepare update rect from original dirty rects.
429 update_rect->Union(tile->dirty_rect);
431 // TODO(reveman): Decide if partial update should be allowed based on cost
432 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
433 if (tile->is_dirty() &&
434 !layer_tree_host()->AlwaysUsePartialTextureUpdates()) {
435 // If we get a partial update, we use the same texture, otherwise return
436 // the current texture backing, so we don't update visible textures
437 // non-atomically. If the current backing is in-use, it won't be
438 // deleted until after the commit as the texture manager will not allow
439 // deletion or recycling of in-use textures.
440 if (TileOnlyNeedsPartialUpdate(tile) &&
441 layer_tree_host()->RequestPartialTextureUpdate()) {
442 tile->partial_update = true;
443 } else {
444 tile->dirty_rect = tiler_->TileRect(tile);
445 tile->managed_resource()->ReturnBackingTexture();
449 paint_rect->Union(tile->dirty_rect);
450 tile->MarkForUpdate();
455 void TiledLayer::UpdateTileTextures(const gfx::Rect& update_rect,
456 const gfx::Rect& paint_rect,
457 int left,
458 int top,
459 int right,
460 int bottom,
461 ResourceUpdateQueue* queue,
462 const OcclusionTracker<Layer>* occlusion) {
463 // The update_rect should be in layer space. So we have to convert the
464 // paint_rect from content space to layer space.
465 float width_scale = 1 / draw_properties().contents_scale_x;
466 float height_scale = 1 / draw_properties().contents_scale_y;
467 update_rect_ =
468 gfx::ScaleToEnclosingRect(update_rect, width_scale, height_scale);
470 // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
471 // side effect of disabling compositing, which causes our reference to the
472 // texture updater to be deleted. However, we can't free the memory backing
473 // the SkCanvas until the paint finishes, so we grab a local reference here to
474 // hold the updater alive until the paint completes.
475 scoped_refptr<LayerUpdater> protector(Updater());
476 Updater()->PrepareToUpdate(content_bounds(),
477 paint_rect,
478 tiler_->tile_size(),
479 1.f / width_scale,
480 1.f / height_scale);
482 for (int j = top; j <= bottom; ++j) {
483 for (int i = left; i <= right; ++i) {
484 UpdatableTile* tile = TileAt(i, j);
485 DCHECK(tile); // Did SetTexturePriorites get skipped?
486 // TODO(enne): This should not ever be null.
487 if (!tile)
488 continue;
490 gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
492 // Use update_rect as the above loop copied the dirty rect for this frame
493 // to update_rect.
494 gfx::Rect dirty_rect = tile->update_rect;
495 if (dirty_rect.IsEmpty())
496 continue;
498 // source_rect starts as a full-sized tile with border texels included.
499 gfx::Rect source_rect = tiler_->TileRect(tile);
500 source_rect.Intersect(dirty_rect);
501 // Paint rect not guaranteed to line up on tile boundaries, so
502 // make sure that source_rect doesn't extend outside of it.
503 source_rect.Intersect(paint_rect);
505 tile->update_rect = source_rect;
507 if (source_rect.IsEmpty())
508 continue;
510 const gfx::Point anchor = tiler_->TileRect(tile).origin();
512 // Calculate tile-space rectangle to upload into.
513 gfx::Vector2d dest_offset = source_rect.origin() - anchor;
514 CHECK_GE(dest_offset.x(), 0);
515 CHECK_GE(dest_offset.y(), 0);
517 // Offset from paint rectangle to this tile's dirty rectangle.
518 gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
519 CHECK_GE(paint_offset.x(), 0);
520 CHECK_GE(paint_offset.y(), 0);
521 CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
522 CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
524 tile->updater_resource()->Update(
525 queue, source_rect, dest_offset, tile->partial_update);
530 // This picks a small animated layer to be anything less than one viewport. This
531 // is specifically for page transitions which are viewport-sized layers. The
532 // extra tile of padding is due to these layers being slightly larger than the
533 // viewport in some cases.
534 bool TiledLayer::IsSmallAnimatedLayer() const {
535 if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
536 return false;
537 gfx::Size viewport_size =
538 layer_tree_host() ? layer_tree_host()->device_viewport_size()
539 : gfx::Size();
540 gfx::Rect content_rect(content_bounds());
541 return content_rect.width() <=
542 viewport_size.width() + tiler_->tile_size().width() &&
543 content_rect.height() <=
544 viewport_size.height() + tiler_->tile_size().height();
547 namespace {
548 // TODO(epenner): Remove this and make this based on distance once distance can
549 // be calculated for offscreen layers. For now, prioritize all small animated
550 // layers after 512 pixels of pre-painting.
551 void SetPriorityForTexture(const gfx::Rect& visible_rect,
552 const gfx::Rect& tile_rect,
553 bool draws_to_root,
554 bool is_small_animated_layer,
555 PrioritizedResource* texture) {
556 int priority = PriorityCalculator::LowestPriority();
557 if (!visible_rect.IsEmpty()) {
558 priority = PriorityCalculator::PriorityFromDistance(
559 visible_rect, tile_rect, draws_to_root);
562 if (is_small_animated_layer) {
563 priority = PriorityCalculator::max_priority(
564 priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
567 if (priority != PriorityCalculator::LowestPriority())
568 texture->set_request_priority(priority);
570 } // namespace
572 void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
573 UpdateBounds();
574 ResetUpdateState();
575 UpdateScrollPrediction();
577 if (tiler_->has_empty_bounds())
578 return;
580 bool draws_to_root = !render_target()->parent();
581 bool small_animated_layer = IsSmallAnimatedLayer();
583 // Minimally create the tiles in the desired pre-paint rect.
584 gfx::Rect create_tiles_rect = IdlePaintRect();
585 if (small_animated_layer)
586 create_tiles_rect = gfx::Rect(content_bounds());
587 if (!create_tiles_rect.IsEmpty()) {
588 int left, top, right, bottom;
589 tiler_->ContentRectToTileIndices(
590 create_tiles_rect, &left, &top, &right, &bottom);
591 for (int j = top; j <= bottom; ++j) {
592 for (int i = left; i <= right; ++i) {
593 if (!TileAt(i, j))
594 CreateTile(i, j);
599 // Now update priorities on all tiles we have in the layer, no matter where
600 // they are.
601 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
602 iter != tiler_->tiles().end();
603 ++iter) {
604 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
605 // TODO(enne): This should not ever be null.
606 if (!tile)
607 continue;
608 gfx::Rect tile_rect = tiler_->TileRect(tile);
609 SetPriorityForTexture(predicted_visible_rect_,
610 tile_rect,
611 draws_to_root,
612 small_animated_layer,
613 tile->managed_resource());
617 SimpleEnclosedRegion TiledLayer::VisibleContentOpaqueRegion() const {
618 if (skips_draw_)
619 return SimpleEnclosedRegion();
620 return Layer::VisibleContentOpaqueRegion();
623 void TiledLayer::ResetUpdateState() {
624 skips_draw_ = false;
625 failed_update_ = false;
627 LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
628 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
629 iter != end;
630 ++iter) {
631 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
632 // TODO(enne): This should not ever be null.
633 if (!tile)
634 continue;
635 tile->ResetUpdateState();
639 namespace {
640 gfx::Rect ExpandRectByDelta(const gfx::Rect& rect, const gfx::Vector2d& delta) {
641 int width = rect.width() + std::abs(delta.x());
642 int height = rect.height() + std::abs(delta.y());
643 int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
644 int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
645 return gfx::Rect(x, y, width, height);
649 void TiledLayer::UpdateScrollPrediction() {
650 // This scroll prediction is very primitive and should be replaced by a
651 // a recursive calculation on all layers which uses actual scroll/animation
652 // velocities. To insure this doesn't miss-predict, we only use it to predict
653 // the visible_rect if:
654 // - content_bounds() hasn't changed.
655 // - visible_rect.size() hasn't changed.
656 // These two conditions prevent rotations, scales, pinch-zooms etc. where
657 // the prediction would be incorrect.
658 gfx::Vector2d delta = visible_content_rect().CenterPoint() -
659 previous_visible_rect_.CenterPoint();
660 predicted_scroll_ = -delta;
661 predicted_visible_rect_ = visible_content_rect();
662 if (previous_content_bounds_ == content_bounds() &&
663 previous_visible_rect_.size() == visible_content_rect().size()) {
664 // Only expand the visible rect in the major scroll direction, to prevent
665 // massive paints due to diagonal scrolls.
666 gfx::Vector2d major_scroll_delta =
667 (std::abs(delta.x()) > std::abs(delta.y())) ?
668 gfx::Vector2d(delta.x(), 0) :
669 gfx::Vector2d(0, delta.y());
670 predicted_visible_rect_ =
671 ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
673 // Bound the prediction to prevent unbounded paints, and clamp to content
674 // bounds.
675 gfx::Rect bound = visible_content_rect();
676 bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
677 -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
678 bound.Intersect(gfx::Rect(content_bounds()));
679 predicted_visible_rect_.Intersect(bound);
681 previous_content_bounds_ = content_bounds();
682 previous_visible_rect_ = visible_content_rect();
685 bool TiledLayer::Update(ResourceUpdateQueue* queue,
686 const OcclusionTracker<Layer>* occlusion) {
687 DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
689 // Tiled layer always causes commits to wait for activation, as it does
690 // not support pending trees.
691 SetNextCommitWaitsForActivation();
693 bool updated = false;
696 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
697 true);
699 updated |= ContentsScalingLayer::Update(queue, occlusion);
700 UpdateBounds();
703 if (tiler_->has_empty_bounds() || !DrawsContent())
704 return false;
706 // Animation pre-paint. If the layer is small, try to paint it all
707 // immediately whether or not it is occluded, to avoid paint/upload
708 // hiccups while it is animating.
709 if (IsSmallAnimatedLayer()) {
710 int left, top, right, bottom;
711 tiler_->ContentRectToTileIndices(gfx::Rect(content_bounds()),
712 &left,
713 &top,
714 &right,
715 &bottom);
716 UpdateTiles(left, top, right, bottom, queue, nullptr, &updated);
717 if (updated)
718 return updated;
719 // This was an attempt to paint the entire layer so if we fail it's okay,
720 // just fallback on painting visible etc. below.
721 failed_update_ = false;
724 if (predicted_visible_rect_.IsEmpty())
725 return updated;
727 // Visible painting. First occlude visible tiles and paint the non-occluded
728 // tiles.
729 int left, top, right, bottom;
730 tiler_->ContentRectToTileIndices(
731 predicted_visible_rect_, &left, &top, &right, &bottom);
732 MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
733 skips_draw_ = !UpdateTiles(
734 left, top, right, bottom, queue, occlusion, &updated);
735 if (skips_draw_)
736 tiler_->reset();
737 if (skips_draw_ || updated)
738 return true;
740 // If we have already painting everything visible. Do some pre-painting while
741 // idle.
742 gfx::Rect idle_paint_content_rect = IdlePaintRect();
743 if (idle_paint_content_rect.IsEmpty())
744 return updated;
746 // Prepaint anything that was occluded but inside the layer's visible region.
747 if (!UpdateTiles(left, top, right, bottom, queue, nullptr, &updated) ||
748 updated)
749 return updated;
751 int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
752 tiler_->ContentRectToTileIndices(idle_paint_content_rect,
753 &prepaint_left,
754 &prepaint_top,
755 &prepaint_right,
756 &prepaint_bottom);
758 // Then expand outwards one row/column at a time until we find a dirty
759 // row/column to update. Increment along the major and minor scroll directions
760 // first.
761 gfx::Vector2d delta = -predicted_scroll_;
762 delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
763 delta.y() == 0 ? 1 : delta.y());
764 gfx::Vector2d major_delta =
765 (std::abs(delta.x()) > std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
766 : gfx::Vector2d(0, delta.y());
767 gfx::Vector2d minor_delta =
768 (std::abs(delta.x()) <= std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
769 : gfx::Vector2d(0, delta.y());
770 gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
771 -minor_delta };
772 for (int i = 0; i < 4; i++) {
773 if (deltas[i].y() > 0) {
774 while (bottom < prepaint_bottom) {
775 ++bottom;
776 if (!UpdateTiles(
777 left, bottom, right, bottom, queue, nullptr, &updated) ||
778 updated)
779 return updated;
782 if (deltas[i].y() < 0) {
783 while (top > prepaint_top) {
784 --top;
785 if (!UpdateTiles(left, top, right, top, queue, nullptr, &updated) ||
786 updated)
787 return updated;
790 if (deltas[i].x() < 0) {
791 while (left > prepaint_left) {
792 --left;
793 if (!UpdateTiles(left, top, left, bottom, queue, nullptr, &updated) ||
794 updated)
795 return updated;
798 if (deltas[i].x() > 0) {
799 while (right < prepaint_right) {
800 ++right;
801 if (!UpdateTiles(right, top, right, bottom, queue, nullptr, &updated) ||
802 updated)
803 return updated;
807 return updated;
810 void TiledLayer::OnOutputSurfaceCreated() {
811 // Ensure that all textures are of the right format.
812 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
813 iter != tiler_->tiles().end();
814 ++iter) {
815 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
816 if (!tile)
817 continue;
818 PrioritizedResource* resource = tile->managed_resource();
819 resource->SetDimensions(resource->size(), texture_format_);
823 bool TiledLayer::NeedsIdlePaint() {
824 // Don't trigger more paints if we failed (as we'll just fail again).
825 if (failed_update_ || visible_content_rect().IsEmpty() ||
826 tiler_->has_empty_bounds() || !DrawsContent())
827 return false;
829 gfx::Rect idle_paint_content_rect = IdlePaintRect();
830 if (idle_paint_content_rect.IsEmpty())
831 return false;
833 int left, top, right, bottom;
834 tiler_->ContentRectToTileIndices(
835 idle_paint_content_rect, &left, &top, &right, &bottom);
837 for (int j = top; j <= bottom; ++j) {
838 for (int i = left; i <= right; ++i) {
839 UpdatableTile* tile = TileAt(i, j);
840 DCHECK(tile); // Did SetTexturePriorities get skipped?
841 if (!tile)
842 continue;
844 bool updated = !tile->update_rect.IsEmpty();
845 bool can_acquire =
846 tile->managed_resource()->can_acquire_backing_texture();
847 bool dirty =
848 tile->is_dirty() || !tile->managed_resource()->have_backing_texture();
849 if (!updated && can_acquire && dirty)
850 return true;
853 return false;
856 gfx::Rect TiledLayer::IdlePaintRect() {
857 // Don't inflate an empty rect.
858 if (visible_content_rect().IsEmpty())
859 return gfx::Rect();
861 gfx::Rect prepaint_rect = visible_content_rect();
862 prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
863 -tiler_->tile_size().height() * kPrepaintRows);
864 gfx::Rect content_rect(content_bounds());
865 prepaint_rect.Intersect(content_rect);
867 return prepaint_rect;
870 } // namespace cc