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"
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "build/build_config.h"
13 #include "cc/debug/overdraw_metrics.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 "third_party/khronos/GLES2/gl2.h"
21 #include "ui/gfx/rect_conversions.h"
25 // Maximum predictive expansion of the visible area.
26 static const int kMaxPredictiveTilesCount
= 2;
28 // Number of rows/columns of tiles to pre-paint.
29 // We should increase these further as all textures are
30 // prioritized and we insure performance doesn't suffer.
31 static const int kPrepaintRows
= 4;
32 static const int kPrepaintColumns
= 2;
34 class UpdatableTile
: public LayerTilingData::Tile
{
36 static scoped_ptr
<UpdatableTile
> Create(
37 scoped_ptr
<LayerUpdater::Resource
> updater_resource
) {
38 return make_scoped_ptr(new UpdatableTile(updater_resource
.Pass()));
41 LayerUpdater::Resource
* updater_resource() { return updater_resource_
.get(); }
42 PrioritizedResource
* managed_resource() {
43 return updater_resource_
->texture();
46 bool is_dirty() const { return !dirty_rect
.IsEmpty(); }
48 // Reset update state for the current frame. This should occur before painting
49 // for all layers. Since painting one layer can invalidate another layer after
50 // it has already painted, mark all non-dirty tiles as valid before painting
51 // such that invalidations during painting won't prevent them from being
53 void ResetUpdateState() {
54 update_rect
= gfx::Rect();
56 partial_update
= false;
57 valid_for_frame
= !is_dirty();
60 // This promises to update the tile and therefore also guarantees the tile
61 // will be valid for this frame. dirty_rect is copied into update_rect so we
62 // can continue to track re-entrant invalidations that occur during painting.
63 void MarkForUpdate() {
64 valid_for_frame
= true;
65 update_rect
= dirty_rect
;
66 dirty_rect
= gfx::Rect();
70 gfx::Rect update_rect
;
76 explicit UpdatableTile(scoped_ptr
<LayerUpdater::Resource
> updater_resource
)
77 : partial_update(false),
78 valid_for_frame(false),
80 updater_resource_(updater_resource
.Pass()) {}
82 scoped_ptr
<LayerUpdater::Resource
> updater_resource_
;
84 DISALLOW_COPY_AND_ASSIGN(UpdatableTile
);
87 TiledLayer::TiledLayer()
88 : ContentsScalingLayer(),
89 texture_format_(RGBA_8888
),
91 failed_update_(false),
92 tiling_option_(AUTO_TILE
) {
94 LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS
);
97 TiledLayer::~TiledLayer() {}
99 scoped_ptr
<LayerImpl
> TiledLayer::CreateLayerImpl(LayerTreeImpl
* tree_impl
) {
100 return TiledLayerImpl::Create(tree_impl
, id()).PassAs
<LayerImpl
>();
103 void TiledLayer::UpdateTileSizeAndTilingOption() {
104 DCHECK(layer_tree_host());
106 gfx::Size default_tile_size
= layer_tree_host()->settings().default_tile_size
;
107 gfx::Size max_untiled_layer_size
=
108 layer_tree_host()->settings().max_untiled_layer_size
;
109 int layer_width
= content_bounds().width();
110 int layer_height
= content_bounds().height();
112 gfx::Size
tile_size(std::min(default_tile_size
.width(), layer_width
),
113 std::min(default_tile_size
.height(), layer_height
));
115 // Tile if both dimensions large, or any one dimension large and the other
116 // extends into a second tile but the total layer area isn't larger than that
117 // of the largest possible untiled layer. This heuristic allows for long
118 // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
119 // texture space but still avoids creating very large tiles.
120 bool any_dimension_large
= layer_width
> max_untiled_layer_size
.width() ||
121 layer_height
> max_untiled_layer_size
.height();
122 bool any_dimension_one_tile
=
123 (layer_width
<= default_tile_size
.width() ||
124 layer_height
<= default_tile_size
.height()) &&
125 (layer_width
* layer_height
) <= (max_untiled_layer_size
.width() *
126 max_untiled_layer_size
.height());
127 bool auto_tiled
= any_dimension_large
&& !any_dimension_one_tile
;
130 if (tiling_option_
== ALWAYS_TILE
)
132 else if (tiling_option_
== NEVER_TILE
)
135 is_tiled
= auto_tiled
;
137 gfx::Size requested_size
= is_tiled
? tile_size
: content_bounds();
139 layer_tree_host()->GetRendererCapabilities().max_texture_size
;
140 requested_size
.SetToMin(gfx::Size(max_size
, max_size
));
141 SetTileSize(requested_size
);
144 void TiledLayer::UpdateBounds() {
145 gfx::Size old_bounds
= tiler_
->bounds();
146 gfx::Size new_bounds
= content_bounds();
147 if (old_bounds
== new_bounds
)
149 tiler_
->SetBounds(new_bounds
);
151 // Invalidate any areas that the new bounds exposes.
152 Region old_region
= gfx::Rect(old_bounds
);
153 Region new_region
= gfx::Rect(new_bounds
);
154 new_region
.Subtract(old_region
);
155 for (Region::Iterator
new_rects(new_region
);
156 new_rects
.has_rect();
158 InvalidateContentRect(new_rects
.rect());
161 void TiledLayer::SetTileSize(const gfx::Size
& size
) {
162 tiler_
->SetTileSize(size
);
165 void TiledLayer::SetBorderTexelOption(
166 LayerTilingData::BorderTexelOption border_texel_option
) {
167 tiler_
->SetBorderTexelOption(border_texel_option
);
170 bool TiledLayer::DrawsContent() const {
171 if (!ContentsScalingLayer::DrawsContent())
174 bool has_more_than_one_tile
=
175 tiler_
->num_tiles_x() > 1 || tiler_
->num_tiles_y() > 1;
176 if (tiling_option_
== NEVER_TILE
&& has_more_than_one_tile
)
182 void TiledLayer::ReduceMemoryUsage() {
184 Updater()->ReduceMemoryUsage();
187 void TiledLayer::SetIsMask(bool is_mask
) {
188 set_tiling_option(is_mask
? NEVER_TILE
: AUTO_TILE
);
191 void TiledLayer::PushPropertiesTo(LayerImpl
* layer
) {
192 ContentsScalingLayer::PushPropertiesTo(layer
);
194 TiledLayerImpl
* tiled_layer
= static_cast<TiledLayerImpl
*>(layer
);
196 tiled_layer
->set_skips_draw(skips_draw_
);
197 tiled_layer
->SetTilingData(*tiler_
);
198 std::vector
<UpdatableTile
*> invalid_tiles
;
200 for (LayerTilingData::TileMap::const_iterator iter
= tiler_
->tiles().begin();
201 iter
!= tiler_
->tiles().end();
203 int i
= iter
->first
.first
;
204 int j
= iter
->first
.second
;
205 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
206 // TODO(enne): This should not ever be null.
210 if (!tile
->managed_resource()->have_backing_texture()) {
211 // Evicted tiles get deleted from both layers
212 invalid_tiles
.push_back(tile
);
216 if (!tile
->valid_for_frame
) {
217 // Invalidated tiles are set so they can get different debug colors.
218 tiled_layer
->PushInvalidTile(i
, j
);
222 tiled_layer
->PushTileProperties(
225 tile
->managed_resource()->resource_id(),
227 tile
->managed_resource()->contents_swizzled());
229 for (std::vector
<UpdatableTile
*>::const_iterator iter
= invalid_tiles
.begin();
230 iter
!= invalid_tiles
.end();
232 tiler_
->TakeTile((*iter
)->i(), (*iter
)->j());
234 // TiledLayer must push properties every frame, since viewport state and
235 // occlusion from anywhere in the tree can change what the layer decides to
236 // push to the impl tree.
237 needs_push_properties_
= true;
240 PrioritizedResourceManager
* TiledLayer::ResourceManager() {
241 if (!layer_tree_host())
243 return layer_tree_host()->contents_texture_manager();
246 const PrioritizedResource
* TiledLayer::ResourceAtForTesting(int i
,
248 UpdatableTile
* tile
= TileAt(i
, j
);
251 return tile
->managed_resource();
254 void TiledLayer::SetLayerTreeHost(LayerTreeHost
* host
) {
255 if (host
&& host
!= layer_tree_host()) {
256 for (LayerTilingData::TileMap::const_iterator
257 iter
= tiler_
->tiles().begin();
258 iter
!= tiler_
->tiles().end();
260 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
261 // TODO(enne): This should not ever be null.
264 tile
->managed_resource()->SetTextureManager(
265 host
->contents_texture_manager());
268 ContentsScalingLayer::SetLayerTreeHost(host
);
271 UpdatableTile
* TiledLayer::TileAt(int i
, int j
) const {
272 return static_cast<UpdatableTile
*>(tiler_
->TileAt(i
, j
));
275 UpdatableTile
* TiledLayer::CreateTile(int i
, int j
) {
276 CreateUpdaterIfNeeded();
278 scoped_ptr
<UpdatableTile
> tile(
279 UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
280 tile
->managed_resource()->SetDimensions(tiler_
->tile_size(), texture_format_
);
282 UpdatableTile
* added_tile
= tile
.get();
283 tiler_
->AddTile(tile
.PassAs
<LayerTilingData::Tile
>(), i
, j
);
285 added_tile
->dirty_rect
= tiler_
->TileRect(added_tile
);
287 // Temporary diagnostic crash.
294 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF
& dirty_rect
) {
295 InvalidateContentRect(LayerRectToContentRect(dirty_rect
));
296 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect
);
299 void TiledLayer::InvalidateContentRect(const gfx::Rect
& content_rect
) {
301 if (tiler_
->is_empty() || content_rect
.IsEmpty() || skips_draw_
)
304 for (LayerTilingData::TileMap::const_iterator iter
= tiler_
->tiles().begin();
305 iter
!= tiler_
->tiles().end();
307 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
309 // TODO(enne): This should not ever be null.
312 gfx::Rect bound
= tiler_
->TileRect(tile
);
313 bound
.Intersect(content_rect
);
314 tile
->dirty_rect
.Union(bound
);
318 // Returns true if tile is dirty and only part of it needs to be updated.
319 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile
* tile
) {
320 return !tile
->dirty_rect
.Contains(tiler_
->TileRect(tile
)) &&
321 tile
->managed_resource()->have_backing_texture();
324 bool TiledLayer::UpdateTiles(int left
,
328 ResourceUpdateQueue
* queue
,
329 const OcclusionTracker
* occlusion
,
331 CreateUpdaterIfNeeded();
333 bool ignore_occlusions
= !occlusion
;
334 if (!HaveTexturesForTiles(left
, top
, right
, bottom
, ignore_occlusions
)) {
335 failed_update_
= true;
339 gfx::Rect update_rect
;
340 gfx::Rect paint_rect
;
342 &update_rect
, &paint_rect
, left
, top
, right
, bottom
, ignore_occlusions
);
345 occlusion
->overdraw_metrics()->DidPaint(paint_rect
);
347 if (paint_rect
.IsEmpty())
352 update_rect
, paint_rect
, left
, top
, right
, bottom
, queue
, occlusion
);
356 void TiledLayer::MarkOcclusionsAndRequestTextures(
361 const OcclusionTracker
* occlusion
) {
362 // There is some difficult dependancies between occlusions, recording
363 // occlusion metrics and requesting memory so those are encapsulated in this
364 // function: - We only want to call RequestLate on unoccluded textures (to
365 // preserve memory for other layers when near OOM). - We only want to record
366 // occlusion metrics if all memory requests succeed.
368 int occluded_tile_count
= 0;
369 bool succeeded
= true;
370 for (int j
= top
; j
<= bottom
; ++j
) {
371 for (int i
= left
; i
<= right
; ++i
) {
372 UpdatableTile
* tile
= TileAt(i
, j
);
373 DCHECK(tile
); // Did SetTexturePriorities get skipped?
374 // TODO(enne): This should not ever be null.
377 // Did ResetUpdateState get skipped? Are we doing more than one occlusion
379 DCHECK(!tile
->occluded
);
380 gfx::Rect visible_tile_rect
= gfx::IntersectRects(
381 tiler_
->tile_bounds(i
, j
), visible_content_rect());
382 if (occlusion
&& occlusion
->Occluded(render_target(),
385 draw_transform_is_animating())) {
386 tile
->occluded
= true;
387 occluded_tile_count
++;
389 succeeded
&= tile
->managed_resource()->RequestLate();
397 occlusion
->overdraw_metrics()->DidCullTilesForUpload(occluded_tile_count
);
400 bool TiledLayer::HaveTexturesForTiles(int left
,
404 bool ignore_occlusions
) {
405 for (int j
= top
; j
<= bottom
; ++j
) {
406 for (int i
= left
; i
<= right
; ++i
) {
407 UpdatableTile
* tile
= TileAt(i
, j
);
408 DCHECK(tile
); // Did SetTexturePriorites get skipped?
409 // TODO(enne): This should not ever be null.
413 // Ensure the entire tile is dirty if we don't have the texture.
414 if (!tile
->managed_resource()->have_backing_texture())
415 tile
->dirty_rect
= tiler_
->TileRect(tile
);
417 // If using occlusion and the visible region of the tile is occluded,
418 // don't reserve a texture or update the tile.
419 if (tile
->occluded
&& !ignore_occlusions
)
422 if (!tile
->managed_resource()->can_acquire_backing_texture())
429 void TiledLayer::MarkTilesForUpdate(gfx::Rect
* update_rect
,
430 gfx::Rect
* paint_rect
,
435 bool ignore_occlusions
) {
436 for (int j
= top
; j
<= bottom
; ++j
) {
437 for (int i
= left
; i
<= right
; ++i
) {
438 UpdatableTile
* tile
= TileAt(i
, j
);
439 DCHECK(tile
); // Did SetTexturePriorites get skipped?
440 // TODO(enne): This should not ever be null.
443 if (tile
->occluded
&& !ignore_occlusions
)
446 // Prepare update rect from original dirty rects.
447 update_rect
->Union(tile
->dirty_rect
);
449 // TODO(reveman): Decide if partial update should be allowed based on cost
450 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
451 if (tile
->is_dirty() &&
452 !layer_tree_host()->AlwaysUsePartialTextureUpdates()) {
453 // If we get a partial update, we use the same texture, otherwise return
454 // the current texture backing, so we don't update visible textures
455 // non-atomically. If the current backing is in-use, it won't be
456 // deleted until after the commit as the texture manager will not allow
457 // deletion or recycling of in-use textures.
458 if (TileOnlyNeedsPartialUpdate(tile
) &&
459 layer_tree_host()->RequestPartialTextureUpdate()) {
460 tile
->partial_update
= true;
462 tile
->dirty_rect
= tiler_
->TileRect(tile
);
463 tile
->managed_resource()->ReturnBackingTexture();
467 paint_rect
->Union(tile
->dirty_rect
);
468 tile
->MarkForUpdate();
473 void TiledLayer::UpdateTileTextures(const gfx::Rect
& update_rect
,
474 const gfx::Rect
& paint_rect
,
479 ResourceUpdateQueue
* queue
,
480 const OcclusionTracker
* occlusion
) {
481 // The update_rect should be in layer space. So we have to convert the
482 // paint_rect from content space to layer space.
484 paint_properties().bounds
.width() /
485 static_cast<float>(content_bounds().width());
487 paint_properties().bounds
.height() /
488 static_cast<float>(content_bounds().height());
489 update_rect_
= gfx::ScaleRect(update_rect
, width_scale
, height_scale
);
491 // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
492 // side effect of disabling compositing, which causes our reference to the
493 // texture updater to be deleted. However, we can't free the memory backing
494 // the SkCanvas until the paint finishes, so we grab a local reference here to
495 // hold the updater alive until the paint completes.
496 scoped_refptr
<LayerUpdater
> protector(Updater());
497 gfx::Rect painted_opaque_rect
;
498 Updater()->PrepareToUpdate(paint_rect
,
502 &painted_opaque_rect
);
504 for (int j
= top
; j
<= bottom
; ++j
) {
505 for (int i
= left
; i
<= right
; ++i
) {
506 UpdatableTile
* tile
= TileAt(i
, j
);
507 DCHECK(tile
); // Did SetTexturePriorites get skipped?
508 // TODO(enne): This should not ever be null.
512 gfx::Rect tile_rect
= tiler_
->tile_bounds(i
, j
);
514 // Use update_rect as the above loop copied the dirty rect for this frame
516 gfx::Rect dirty_rect
= tile
->update_rect
;
517 if (dirty_rect
.IsEmpty())
520 // Save what was painted opaque in the tile. Keep the old area if the
521 // paint didn't touch it, and didn't paint some other part of the tile
523 gfx::Rect tile_painted_rect
= gfx::IntersectRects(tile_rect
, paint_rect
);
524 gfx::Rect tile_painted_opaque_rect
=
525 gfx::IntersectRects(tile_rect
, painted_opaque_rect
);
526 if (!tile_painted_rect
.IsEmpty()) {
527 gfx::Rect paint_inside_tile_opaque_rect
=
528 gfx::IntersectRects(tile
->opaque_rect(), tile_painted_rect
);
529 bool paint_inside_tile_opaque_rect_is_non_opaque
=
530 !paint_inside_tile_opaque_rect
.IsEmpty() &&
531 !tile_painted_opaque_rect
.Contains(paint_inside_tile_opaque_rect
);
532 bool opaque_paint_not_inside_tile_opaque_rect
=
533 !tile_painted_opaque_rect
.IsEmpty() &&
534 !tile
->opaque_rect().Contains(tile_painted_opaque_rect
);
536 if (paint_inside_tile_opaque_rect_is_non_opaque
||
537 opaque_paint_not_inside_tile_opaque_rect
)
538 tile
->set_opaque_rect(tile_painted_opaque_rect
);
541 // source_rect starts as a full-sized tile with border texels included.
542 gfx::Rect source_rect
= tiler_
->TileRect(tile
);
543 source_rect
.Intersect(dirty_rect
);
544 // Paint rect not guaranteed to line up on tile boundaries, so
545 // make sure that source_rect doesn't extend outside of it.
546 source_rect
.Intersect(paint_rect
);
548 tile
->update_rect
= source_rect
;
550 if (source_rect
.IsEmpty())
553 const gfx::Point anchor
= tiler_
->TileRect(tile
).origin();
555 // Calculate tile-space rectangle to upload into.
556 gfx::Vector2d dest_offset
= source_rect
.origin() - anchor
;
557 CHECK_GE(dest_offset
.x(), 0);
558 CHECK_GE(dest_offset
.y(), 0);
560 // Offset from paint rectangle to this tile's dirty rectangle.
561 gfx::Vector2d paint_offset
= source_rect
.origin() - paint_rect
.origin();
562 CHECK_GE(paint_offset
.x(), 0);
563 CHECK_GE(paint_offset
.y(), 0);
564 CHECK_LE(paint_offset
.x() + source_rect
.width(), paint_rect
.width());
565 CHECK_LE(paint_offset
.y() + source_rect
.height(), paint_rect
.height());
567 tile
->updater_resource()->Update(
568 queue
, source_rect
, dest_offset
, tile
->partial_update
);
570 occlusion
->overdraw_metrics()->
571 DidUpload(gfx::Transform(), source_rect
, tile
->opaque_rect());
577 // This picks a small animated layer to be anything less than one viewport. This
578 // is specifically for page transitions which are viewport-sized layers. The
579 // extra tile of padding is due to these layers being slightly larger than the
580 // viewport in some cases.
581 bool TiledLayer::IsSmallAnimatedLayer() const {
582 if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
584 gfx::Size viewport_size
=
585 layer_tree_host() ? layer_tree_host()->device_viewport_size()
587 gfx::Rect
content_rect(content_bounds());
588 return content_rect
.width() <=
589 viewport_size
.width() + tiler_
->tile_size().width() &&
590 content_rect
.height() <=
591 viewport_size
.height() + tiler_
->tile_size().height();
595 // TODO(epenner): Remove this and make this based on distance once distance can
596 // be calculated for offscreen layers. For now, prioritize all small animated
597 // layers after 512 pixels of pre-painting.
598 void SetPriorityForTexture(const gfx::Rect
& visible_rect
,
599 const gfx::Rect
& tile_rect
,
601 bool is_small_animated_layer
,
602 PrioritizedResource
* texture
) {
603 int priority
= PriorityCalculator::LowestPriority();
604 if (!visible_rect
.IsEmpty()) {
605 priority
= PriorityCalculator::PriorityFromDistance(
606 visible_rect
, tile_rect
, draws_to_root
);
609 if (is_small_animated_layer
) {
610 priority
= PriorityCalculator::max_priority(
611 priority
, PriorityCalculator::SmallAnimatedLayerMinPriority());
614 if (priority
!= PriorityCalculator::LowestPriority())
615 texture
->set_request_priority(priority
);
619 void TiledLayer::SetTexturePriorities(const PriorityCalculator
& priority_calc
) {
622 UpdateScrollPrediction();
624 if (tiler_
->has_empty_bounds())
627 bool draws_to_root
= !render_target()->parent();
628 bool small_animated_layer
= IsSmallAnimatedLayer();
630 // Minimally create the tiles in the desired pre-paint rect.
631 gfx::Rect create_tiles_rect
= IdlePaintRect();
632 if (small_animated_layer
)
633 create_tiles_rect
= gfx::Rect(content_bounds());
634 if (!create_tiles_rect
.IsEmpty()) {
635 int left
, top
, right
, bottom
;
636 tiler_
->ContentRectToTileIndices(
637 create_tiles_rect
, &left
, &top
, &right
, &bottom
);
638 for (int j
= top
; j
<= bottom
; ++j
) {
639 for (int i
= left
; i
<= right
; ++i
) {
646 // Now update priorities on all tiles we have in the layer, no matter where
648 for (LayerTilingData::TileMap::const_iterator iter
= tiler_
->tiles().begin();
649 iter
!= tiler_
->tiles().end();
651 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
652 // TODO(enne): This should not ever be null.
655 gfx::Rect tile_rect
= tiler_
->TileRect(tile
);
656 SetPriorityForTexture(predicted_visible_rect_
,
659 small_animated_layer
,
660 tile
->managed_resource());
664 Region
TiledLayer::VisibleContentOpaqueRegion() const {
667 if (contents_opaque())
668 return visible_content_rect();
669 return tiler_
->OpaqueRegionInContentRect(visible_content_rect());
672 void TiledLayer::ResetUpdateState() {
674 failed_update_
= false;
676 LayerTilingData::TileMap::const_iterator end
= tiler_
->tiles().end();
677 for (LayerTilingData::TileMap::const_iterator iter
= tiler_
->tiles().begin();
680 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
681 // TODO(enne): This should not ever be null.
684 tile
->ResetUpdateState();
689 gfx::Rect
ExpandRectByDelta(const gfx::Rect
& rect
, const gfx::Vector2d
& delta
) {
690 int width
= rect
.width() + std::abs(delta
.x());
691 int height
= rect
.height() + std::abs(delta
.y());
692 int x
= rect
.x() + ((delta
.x() < 0) ? delta
.x() : 0);
693 int y
= rect
.y() + ((delta
.y() < 0) ? delta
.y() : 0);
694 return gfx::Rect(x
, y
, width
, height
);
698 void TiledLayer::UpdateScrollPrediction() {
699 // This scroll prediction is very primitive and should be replaced by a
700 // a recursive calculation on all layers which uses actual scroll/animation
701 // velocities. To insure this doesn't miss-predict, we only use it to predict
702 // the visible_rect if:
703 // - content_bounds() hasn't changed.
704 // - visible_rect.size() hasn't changed.
705 // These two conditions prevent rotations, scales, pinch-zooms etc. where
706 // the prediction would be incorrect.
707 gfx::Vector2d delta
= visible_content_rect().CenterPoint() -
708 previous_visible_rect_
.CenterPoint();
709 predicted_scroll_
= -delta
;
710 predicted_visible_rect_
= visible_content_rect();
711 if (previous_content_bounds_
== content_bounds() &&
712 previous_visible_rect_
.size() == visible_content_rect().size()) {
713 // Only expand the visible rect in the major scroll direction, to prevent
714 // massive paints due to diagonal scrolls.
715 gfx::Vector2d major_scroll_delta
=
716 (std::abs(delta
.x()) > std::abs(delta
.y())) ?
717 gfx::Vector2d(delta
.x(), 0) :
718 gfx::Vector2d(0, delta
.y());
719 predicted_visible_rect_
=
720 ExpandRectByDelta(visible_content_rect(), major_scroll_delta
);
722 // Bound the prediction to prevent unbounded paints, and clamp to content
724 gfx::Rect bound
= visible_content_rect();
725 bound
.Inset(-tiler_
->tile_size().width() * kMaxPredictiveTilesCount
,
726 -tiler_
->tile_size().height() * kMaxPredictiveTilesCount
);
727 bound
.Intersect(gfx::Rect(content_bounds()));
728 predicted_visible_rect_
.Intersect(bound
);
730 previous_content_bounds_
= content_bounds();
731 previous_visible_rect_
= visible_content_rect();
734 bool TiledLayer::Update(ResourceUpdateQueue
* queue
,
735 const OcclusionTracker
* occlusion
) {
736 DCHECK(!skips_draw_
&& !failed_update_
); // Did ResetUpdateState get skipped?
738 // Tiled layer always causes commits to wait for activation, as it does
739 // not support pending trees.
740 SetNextCommitWaitsForActivation();
742 bool updated
= false;
745 base::AutoReset
<bool> ignore_set_needs_commit(&ignore_set_needs_commit_
,
748 updated
|= ContentsScalingLayer::Update(queue
, occlusion
);
752 if (tiler_
->has_empty_bounds() || !DrawsContent())
755 // Animation pre-paint. If the layer is small, try to paint it all
756 // immediately whether or not it is occluded, to avoid paint/upload
757 // hiccups while it is animating.
758 if (IsSmallAnimatedLayer()) {
759 int left
, top
, right
, bottom
;
760 tiler_
->ContentRectToTileIndices(gfx::Rect(content_bounds()),
765 UpdateTiles(left
, top
, right
, bottom
, queue
, NULL
, &updated
);
768 // This was an attempt to paint the entire layer so if we fail it's okay,
769 // just fallback on painting visible etc. below.
770 failed_update_
= false;
773 if (predicted_visible_rect_
.IsEmpty())
776 // Visible painting. First occlude visible tiles and paint the non-occluded
778 int left
, top
, right
, bottom
;
779 tiler_
->ContentRectToTileIndices(
780 predicted_visible_rect_
, &left
, &top
, &right
, &bottom
);
781 MarkOcclusionsAndRequestTextures(left
, top
, right
, bottom
, occlusion
);
782 skips_draw_
= !UpdateTiles(
783 left
, top
, right
, bottom
, queue
, occlusion
, &updated
);
786 if (skips_draw_
|| updated
)
789 // If we have already painting everything visible. Do some pre-painting while
791 gfx::Rect idle_paint_content_rect
= IdlePaintRect();
792 if (idle_paint_content_rect
.IsEmpty())
795 // Prepaint anything that was occluded but inside the layer's visible region.
796 if (!UpdateTiles(left
, top
, right
, bottom
, queue
, NULL
, &updated
) ||
800 int prepaint_left
, prepaint_top
, prepaint_right
, prepaint_bottom
;
801 tiler_
->ContentRectToTileIndices(idle_paint_content_rect
,
807 // Then expand outwards one row/column at a time until we find a dirty
808 // row/column to update. Increment along the major and minor scroll directions
810 gfx::Vector2d delta
= -predicted_scroll_
;
811 delta
= gfx::Vector2d(delta
.x() == 0 ? 1 : delta
.x(),
812 delta
.y() == 0 ? 1 : delta
.y());
813 gfx::Vector2d major_delta
=
814 (std::abs(delta
.x()) > std::abs(delta
.y())) ? gfx::Vector2d(delta
.x(), 0)
815 : gfx::Vector2d(0, delta
.y());
816 gfx::Vector2d minor_delta
=
817 (std::abs(delta
.x()) <= std::abs(delta
.y())) ? gfx::Vector2d(delta
.x(), 0)
818 : gfx::Vector2d(0, delta
.y());
819 gfx::Vector2d deltas
[4] = { major_delta
, minor_delta
, -major_delta
,
821 for (int i
= 0; i
< 4; i
++) {
822 if (deltas
[i
].y() > 0) {
823 while (bottom
< prepaint_bottom
) {
826 left
, bottom
, right
, bottom
, queue
, NULL
, &updated
) ||
831 if (deltas
[i
].y() < 0) {
832 while (top
> prepaint_top
) {
835 left
, top
, right
, top
, queue
, NULL
, &updated
) ||
840 if (deltas
[i
].x() < 0) {
841 while (left
> prepaint_left
) {
844 left
, top
, left
, bottom
, queue
, NULL
, &updated
) ||
849 if (deltas
[i
].x() > 0) {
850 while (right
< prepaint_right
) {
853 right
, top
, right
, bottom
, queue
, NULL
, &updated
) ||
862 void TiledLayer::OnOutputSurfaceCreated() {
863 // Ensure that all textures are of the right format.
864 for (LayerTilingData::TileMap::const_iterator iter
= tiler_
->tiles().begin();
865 iter
!= tiler_
->tiles().end();
867 UpdatableTile
* tile
= static_cast<UpdatableTile
*>(iter
->second
);
870 PrioritizedResource
* resource
= tile
->managed_resource();
871 resource
->SetDimensions(resource
->size(), texture_format_
);
875 bool TiledLayer::NeedsIdlePaint() {
876 // Don't trigger more paints if we failed (as we'll just fail again).
877 if (failed_update_
|| visible_content_rect().IsEmpty() ||
878 tiler_
->has_empty_bounds() || !DrawsContent())
881 gfx::Rect idle_paint_content_rect
= IdlePaintRect();
882 if (idle_paint_content_rect
.IsEmpty())
885 int left
, top
, right
, bottom
;
886 tiler_
->ContentRectToTileIndices(
887 idle_paint_content_rect
, &left
, &top
, &right
, &bottom
);
889 for (int j
= top
; j
<= bottom
; ++j
) {
890 for (int i
= left
; i
<= right
; ++i
) {
891 UpdatableTile
* tile
= TileAt(i
, j
);
892 DCHECK(tile
); // Did SetTexturePriorities get skipped?
896 bool updated
= !tile
->update_rect
.IsEmpty();
898 tile
->managed_resource()->can_acquire_backing_texture();
900 tile
->is_dirty() || !tile
->managed_resource()->have_backing_texture();
901 if (!updated
&& can_acquire
&& dirty
)
908 gfx::Rect
TiledLayer::IdlePaintRect() {
909 // Don't inflate an empty rect.
910 if (visible_content_rect().IsEmpty())
913 gfx::Rect prepaint_rect
= visible_content_rect();
914 prepaint_rect
.Inset(-tiler_
->tile_size().width() * kPrepaintColumns
,
915 -tiler_
->tile_size().height() * kPrepaintRows
);
916 gfx::Rect
content_rect(content_bounds());
917 prepaint_rect
.Intersect(content_rect
);
919 return prepaint_rect
;