• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "cc/layers/tiled_layer.h"
6 
7 #include <algorithm>
8 #include <vector>
9 
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"
22 
23 namespace cc {
24 
25 // Maximum predictive expansion of the visible area.
26 static const int kMaxPredictiveTilesCount = 2;
27 
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;
33 
34 class UpdatableTile : public LayerTilingData::Tile {
35  public:
Create(scoped_ptr<LayerUpdater::Resource> updater_resource)36   static scoped_ptr<UpdatableTile> Create(
37       scoped_ptr<LayerUpdater::Resource> updater_resource) {
38     return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
39   }
40 
updater_resource()41   LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
managed_resource()42   PrioritizedResource* managed_resource() {
43     return updater_resource_->texture();
44   }
45 
is_dirty() const46   bool is_dirty() const { return !dirty_rect.IsEmpty(); }
47 
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
52   // pushed.
ResetUpdateState()53   void ResetUpdateState() {
54     update_rect = gfx::Rect();
55     occluded = false;
56     partial_update = false;
57     valid_for_frame = !is_dirty();
58   }
59 
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.
MarkForUpdate()63   void MarkForUpdate() {
64     valid_for_frame = true;
65     update_rect = dirty_rect;
66     dirty_rect = gfx::Rect();
67   }
68 
69   gfx::Rect dirty_rect;
70   gfx::Rect update_rect;
71   bool partial_update;
72   bool valid_for_frame;
73   bool occluded;
74 
75  private:
UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)76   explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
77       : partial_update(false),
78         valid_for_frame(false),
79         occluded(false),
80         updater_resource_(updater_resource.Pass()) {}
81 
82   scoped_ptr<LayerUpdater::Resource> updater_resource_;
83 
84   DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
85 };
86 
TiledLayer()87 TiledLayer::TiledLayer()
88     : ContentsScalingLayer(),
89       texture_format_(RGBA_8888),
90       skips_draw_(false),
91       failed_update_(false),
92       tiling_option_(AUTO_TILE) {
93   tiler_ =
94       LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
95 }
96 
~TiledLayer()97 TiledLayer::~TiledLayer() {}
98 
CreateLayerImpl(LayerTreeImpl * tree_impl)99 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
100   return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
101 }
102 
UpdateTileSizeAndTilingOption()103 void TiledLayer::UpdateTileSizeAndTilingOption() {
104   DCHECK(layer_tree_host());
105 
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();
111 
112   gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
113                       std::min(default_tile_size.height(), layer_height));
114 
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;
128 
129   bool is_tiled;
130   if (tiling_option_ == ALWAYS_TILE)
131     is_tiled = true;
132   else if (tiling_option_ == NEVER_TILE)
133     is_tiled = false;
134   else
135     is_tiled = auto_tiled;
136 
137   gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
138   const int max_size =
139       layer_tree_host()->GetRendererCapabilities().max_texture_size;
140   requested_size.SetToMin(gfx::Size(max_size, max_size));
141   SetTileSize(requested_size);
142 }
143 
UpdateBounds()144 void TiledLayer::UpdateBounds() {
145   gfx::Size old_bounds = tiler_->bounds();
146   gfx::Size new_bounds = content_bounds();
147   if (old_bounds == new_bounds)
148     return;
149   tiler_->SetBounds(new_bounds);
150 
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();
157        new_rects.next())
158     InvalidateContentRect(new_rects.rect());
159 }
160 
SetTileSize(gfx::Size size)161 void TiledLayer::SetTileSize(gfx::Size size) { tiler_->SetTileSize(size); }
162 
SetBorderTexelOption(LayerTilingData::BorderTexelOption border_texel_option)163 void TiledLayer::SetBorderTexelOption(
164     LayerTilingData::BorderTexelOption border_texel_option) {
165   tiler_->SetBorderTexelOption(border_texel_option);
166 }
167 
DrawsContent() const168 bool TiledLayer::DrawsContent() const {
169   if (!ContentsScalingLayer::DrawsContent())
170     return false;
171 
172   bool has_more_than_one_tile =
173       tiler_->num_tiles_x() > 1 || tiler_->num_tiles_y() > 1;
174   if (tiling_option_ == NEVER_TILE && has_more_than_one_tile)
175     return false;
176 
177   return true;
178 }
179 
ReduceMemoryUsage()180 void TiledLayer::ReduceMemoryUsage() {
181   if (Updater())
182     Updater()->ReduceMemoryUsage();
183 }
184 
SetIsMask(bool is_mask)185 void TiledLayer::SetIsMask(bool is_mask) {
186   set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
187 }
188 
PushPropertiesTo(LayerImpl * layer)189 void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
190   ContentsScalingLayer::PushPropertiesTo(layer);
191 
192   TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
193 
194   tiled_layer->set_skips_draw(skips_draw_);
195   tiled_layer->SetTilingData(*tiler_);
196   std::vector<UpdatableTile*> invalid_tiles;
197 
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;
207 
208     if (!tile->managed_resource()->have_backing_texture()) {
209       // Evicted tiles get deleted from both layers
210       invalid_tiles.push_back(tile);
211       continue;
212     }
213 
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;
218     }
219 
220     tiled_layer->PushTileProperties(
221         i,
222         j,
223         tile->managed_resource()->resource_id(),
224         tile->opaque_rect(),
225         tile->managed_resource()->contents_swizzled());
226   }
227   for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
228        iter != invalid_tiles.end();
229        ++iter)
230     tiler_->TakeTile((*iter)->i(), (*iter)->j());
231 
232   // TiledLayer must push properties every frame, since viewport state and
233   // occlusion from anywhere in the tree can change what the layer decides to
234   // push to the impl tree.
235   needs_push_properties_ = true;
236 }
237 
ResourceManager()238 PrioritizedResourceManager* TiledLayer::ResourceManager() {
239   if (!layer_tree_host())
240     return NULL;
241   return layer_tree_host()->contents_texture_manager();
242 }
243 
ResourceAtForTesting(int i,int j) const244 const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
245                                                             int j) const {
246   UpdatableTile* tile = TileAt(i, j);
247   if (!tile)
248     return NULL;
249   return tile->managed_resource();
250 }
251 
SetLayerTreeHost(LayerTreeHost * host)252 void TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
253   if (host && host != layer_tree_host()) {
254     for (LayerTilingData::TileMap::const_iterator
255              iter = tiler_->tiles().begin();
256          iter != tiler_->tiles().end();
257          ++iter) {
258       UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
259       // TODO(enne): This should not ever be null.
260       if (!tile)
261         continue;
262       tile->managed_resource()->SetTextureManager(
263           host->contents_texture_manager());
264     }
265   }
266   ContentsScalingLayer::SetLayerTreeHost(host);
267 }
268 
TileAt(int i,int j) const269 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
270   return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
271 }
272 
CreateTile(int i,int j)273 UpdatableTile* TiledLayer::CreateTile(int i, int j) {
274   CreateUpdaterIfNeeded();
275 
276   scoped_ptr<UpdatableTile> tile(
277       UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
278   tile->managed_resource()->SetDimensions(tiler_->tile_size(), texture_format_);
279 
280   UpdatableTile* added_tile = tile.get();
281   tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
282 
283   added_tile->dirty_rect = tiler_->TileRect(added_tile);
284 
285   // Temporary diagnostic crash.
286   CHECK(added_tile);
287   CHECK(TileAt(i, j));
288 
289   return added_tile;
290 }
291 
SetNeedsDisplayRect(const gfx::RectF & dirty_rect)292 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
293   InvalidateContentRect(LayerRectToContentRect(dirty_rect));
294   ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
295 }
296 
InvalidateContentRect(gfx::Rect content_rect)297 void TiledLayer::InvalidateContentRect(gfx::Rect content_rect) {
298   UpdateBounds();
299   if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
300     return;
301 
302   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
303        iter != tiler_->tiles().end();
304        ++iter) {
305     UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
306     DCHECK(tile);
307     // TODO(enne): This should not ever be null.
308     if (!tile)
309       continue;
310     gfx::Rect bound = tiler_->TileRect(tile);
311     bound.Intersect(content_rect);
312     tile->dirty_rect.Union(bound);
313   }
314 }
315 
316 // Returns true if tile is dirty and only part of it needs to be updated.
TileOnlyNeedsPartialUpdate(UpdatableTile * tile)317 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
318   return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
319          tile->managed_resource()->have_backing_texture();
320 }
321 
UpdateTiles(int left,int top,int right,int bottom,ResourceUpdateQueue * queue,const OcclusionTracker * occlusion,bool * updated)322 bool TiledLayer::UpdateTiles(int left,
323                              int top,
324                              int right,
325                              int bottom,
326                              ResourceUpdateQueue* queue,
327                              const OcclusionTracker* occlusion,
328                              bool* updated) {
329   CreateUpdaterIfNeeded();
330 
331   bool ignore_occlusions = !occlusion;
332   if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
333     failed_update_ = true;
334     return false;
335   }
336 
337   gfx::Rect update_rect;
338   gfx::Rect paint_rect;
339   MarkTilesForUpdate(
340     &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions);
341 
342   if (occlusion)
343     occlusion->overdraw_metrics()->DidPaint(paint_rect);
344 
345   if (paint_rect.IsEmpty())
346     return true;
347 
348   *updated = true;
349   UpdateTileTextures(
350       update_rect, paint_rect, left, top, right, bottom, queue, occlusion);
351   return true;
352 }
353 
MarkOcclusionsAndRequestTextures(int left,int top,int right,int bottom,const OcclusionTracker * occlusion)354 void TiledLayer::MarkOcclusionsAndRequestTextures(
355     int left,
356     int top,
357     int right,
358     int bottom,
359     const OcclusionTracker* occlusion) {
360   // There is some difficult dependancies between occlusions, recording
361   // occlusion metrics and requesting memory so those are encapsulated in this
362   // function: - We only want to call RequestLate on unoccluded textures (to
363   // preserve memory for other layers when near OOM).  - We only want to record
364   // occlusion metrics if all memory requests succeed.
365 
366   int occluded_tile_count = 0;
367   bool succeeded = true;
368   for (int j = top; j <= bottom; ++j) {
369     for (int i = left; i <= right; ++i) {
370       UpdatableTile* tile = TileAt(i, j);
371       DCHECK(tile);  // Did SetTexturePriorities get skipped?
372       // TODO(enne): This should not ever be null.
373       if (!tile)
374         continue;
375       // Did ResetUpdateState get skipped? Are we doing more than one occlusion
376       // pass?
377       DCHECK(!tile->occluded);
378       gfx::Rect visible_tile_rect = gfx::IntersectRects(
379           tiler_->tile_bounds(i, j), visible_content_rect());
380       if (occlusion && occlusion->Occluded(render_target(),
381                                            visible_tile_rect,
382                                            draw_transform(),
383                                            draw_transform_is_animating())) {
384         tile->occluded = true;
385         occluded_tile_count++;
386       } else {
387         succeeded &= tile->managed_resource()->RequestLate();
388       }
389     }
390   }
391 
392   if (!succeeded)
393     return;
394   if (occlusion)
395     occlusion->overdraw_metrics()->DidCullTilesForUpload(occluded_tile_count);
396 }
397 
HaveTexturesForTiles(int left,int top,int right,int bottom,bool ignore_occlusions)398 bool TiledLayer::HaveTexturesForTiles(int left,
399                                       int top,
400                                       int right,
401                                       int bottom,
402                                       bool ignore_occlusions) {
403   for (int j = top; j <= bottom; ++j) {
404     for (int i = left; i <= right; ++i) {
405       UpdatableTile* tile = TileAt(i, j);
406       DCHECK(tile);  // Did SetTexturePriorites get skipped?
407                      // TODO(enne): This should not ever be null.
408       if (!tile)
409         continue;
410 
411       // Ensure the entire tile is dirty if we don't have the texture.
412       if (!tile->managed_resource()->have_backing_texture())
413         tile->dirty_rect = tiler_->TileRect(tile);
414 
415       // If using occlusion and the visible region of the tile is occluded,
416       // don't reserve a texture or update the tile.
417       if (tile->occluded && !ignore_occlusions)
418         continue;
419 
420       if (!tile->managed_resource()->can_acquire_backing_texture())
421         return false;
422     }
423   }
424   return true;
425 }
426 
MarkTilesForUpdate(gfx::Rect * update_rect,gfx::Rect * paint_rect,int left,int top,int right,int bottom,bool ignore_occlusions)427 void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect,
428                                     gfx::Rect* paint_rect,
429                                     int left,
430                                     int top,
431                                     int right,
432                                     int bottom,
433                                     bool ignore_occlusions) {
434   for (int j = top; j <= bottom; ++j) {
435     for (int i = left; i <= right; ++i) {
436       UpdatableTile* tile = TileAt(i, j);
437       DCHECK(tile);  // Did SetTexturePriorites get skipped?
438                      // TODO(enne): This should not ever be null.
439       if (!tile)
440         continue;
441       if (tile->occluded && !ignore_occlusions)
442         continue;
443 
444       // Prepare update rect from original dirty rects.
445       update_rect->Union(tile->dirty_rect);
446 
447       // TODO(reveman): Decide if partial update should be allowed based on cost
448       // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
449       if (tile->is_dirty() &&
450           !layer_tree_host()->AlwaysUsePartialTextureUpdates()) {
451         // If we get a partial update, we use the same texture, otherwise return
452         // the current texture backing, so we don't update visible textures
453         // non-atomically.  If the current backing is in-use, it won't be
454         // deleted until after the commit as the texture manager will not allow
455         // deletion or recycling of in-use textures.
456         if (TileOnlyNeedsPartialUpdate(tile) &&
457             layer_tree_host()->RequestPartialTextureUpdate()) {
458           tile->partial_update = true;
459         } else {
460           tile->dirty_rect = tiler_->TileRect(tile);
461           tile->managed_resource()->ReturnBackingTexture();
462         }
463       }
464 
465       paint_rect->Union(tile->dirty_rect);
466       tile->MarkForUpdate();
467     }
468   }
469 }
470 
UpdateTileTextures(gfx::Rect update_rect,gfx::Rect paint_rect,int left,int top,int right,int bottom,ResourceUpdateQueue * queue,const OcclusionTracker * occlusion)471 void TiledLayer::UpdateTileTextures(gfx::Rect update_rect,
472                                     gfx::Rect paint_rect,
473                                     int left,
474                                     int top,
475                                     int right,
476                                     int bottom,
477                                     ResourceUpdateQueue* queue,
478                                     const OcclusionTracker* occlusion) {
479   // The update_rect should be in layer space. So we have to convert the
480   // paint_rect from content space to layer space.
481   float width_scale =
482       paint_properties().bounds.width() /
483       static_cast<float>(content_bounds().width());
484   float height_scale =
485       paint_properties().bounds.height() /
486       static_cast<float>(content_bounds().height());
487   update_rect_ = gfx::ScaleRect(update_rect, width_scale, height_scale);
488 
489   // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
490   // side effect of disabling compositing, which causes our reference to the
491   // texture updater to be deleted.  However, we can't free the memory backing
492   // the SkCanvas until the paint finishes, so we grab a local reference here to
493   // hold the updater alive until the paint completes.
494   scoped_refptr<LayerUpdater> protector(Updater());
495   gfx::Rect painted_opaque_rect;
496   Updater()->PrepareToUpdate(paint_rect,
497                              tiler_->tile_size(),
498                              1.f / width_scale,
499                              1.f / height_scale,
500                              &painted_opaque_rect);
501 
502   for (int j = top; j <= bottom; ++j) {
503     for (int i = left; i <= right; ++i) {
504       UpdatableTile* tile = TileAt(i, j);
505       DCHECK(tile);  // Did SetTexturePriorites get skipped?
506                      // TODO(enne): This should not ever be null.
507       if (!tile)
508         continue;
509 
510       gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
511 
512       // Use update_rect as the above loop copied the dirty rect for this frame
513       // to update_rect.
514       gfx::Rect dirty_rect = tile->update_rect;
515       if (dirty_rect.IsEmpty())
516         continue;
517 
518       // Save what was painted opaque in the tile. Keep the old area if the
519       // paint didn't touch it, and didn't paint some other part of the tile
520       // opaque.
521       gfx::Rect tile_painted_rect = gfx::IntersectRects(tile_rect, paint_rect);
522       gfx::Rect tile_painted_opaque_rect =
523           gfx::IntersectRects(tile_rect, painted_opaque_rect);
524       if (!tile_painted_rect.IsEmpty()) {
525         gfx::Rect paint_inside_tile_opaque_rect =
526             gfx::IntersectRects(tile->opaque_rect(), tile_painted_rect);
527         bool paint_inside_tile_opaque_rect_is_non_opaque =
528             !paint_inside_tile_opaque_rect.IsEmpty() &&
529             !tile_painted_opaque_rect.Contains(paint_inside_tile_opaque_rect);
530         bool opaque_paint_not_inside_tile_opaque_rect =
531             !tile_painted_opaque_rect.IsEmpty() &&
532             !tile->opaque_rect().Contains(tile_painted_opaque_rect);
533 
534         if (paint_inside_tile_opaque_rect_is_non_opaque ||
535             opaque_paint_not_inside_tile_opaque_rect)
536           tile->set_opaque_rect(tile_painted_opaque_rect);
537       }
538 
539       // source_rect starts as a full-sized tile with border texels included.
540       gfx::Rect source_rect = tiler_->TileRect(tile);
541       source_rect.Intersect(dirty_rect);
542       // Paint rect not guaranteed to line up on tile boundaries, so
543       // make sure that source_rect doesn't extend outside of it.
544       source_rect.Intersect(paint_rect);
545 
546       tile->update_rect = source_rect;
547 
548       if (source_rect.IsEmpty())
549         continue;
550 
551       const gfx::Point anchor = tiler_->TileRect(tile).origin();
552 
553       // Calculate tile-space rectangle to upload into.
554       gfx::Vector2d dest_offset = source_rect.origin() - anchor;
555       CHECK_GE(dest_offset.x(), 0);
556       CHECK_GE(dest_offset.y(), 0);
557 
558       // Offset from paint rectangle to this tile's dirty rectangle.
559       gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
560       CHECK_GE(paint_offset.x(), 0);
561       CHECK_GE(paint_offset.y(), 0);
562       CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
563       CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
564 
565       tile->updater_resource()->Update(
566           queue, source_rect, dest_offset, tile->partial_update);
567       if (occlusion) {
568         occlusion->overdraw_metrics()->
569             DidUpload(gfx::Transform(), source_rect, tile->opaque_rect());
570       }
571     }
572   }
573 }
574 
575 // This picks a small animated layer to be anything less than one viewport. This
576 // is specifically for page transitions which are viewport-sized layers. The
577 // extra tile of padding is due to these layers being slightly larger than the
578 // viewport in some cases.
IsSmallAnimatedLayer() const579 bool TiledLayer::IsSmallAnimatedLayer() const {
580   if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
581     return false;
582   gfx::Size viewport_size =
583       layer_tree_host() ? layer_tree_host()->device_viewport_size()
584                         : gfx::Size();
585   gfx::Rect content_rect(content_bounds());
586   return content_rect.width() <=
587          viewport_size.width() + tiler_->tile_size().width() &&
588          content_rect.height() <=
589          viewport_size.height() + tiler_->tile_size().height();
590 }
591 
592 namespace {
593 // TODO(epenner): Remove this and make this based on distance once distance can
594 // be calculated for offscreen layers. For now, prioritize all small animated
595 // layers after 512 pixels of pre-painting.
SetPriorityForTexture(gfx::Rect visible_rect,gfx::Rect tile_rect,bool draws_to_root,bool is_small_animated_layer,PrioritizedResource * texture)596 void SetPriorityForTexture(gfx::Rect visible_rect,
597                            gfx::Rect tile_rect,
598                            bool draws_to_root,
599                            bool is_small_animated_layer,
600                            PrioritizedResource* texture) {
601   int priority = PriorityCalculator::LowestPriority();
602   if (!visible_rect.IsEmpty()) {
603     priority = PriorityCalculator::PriorityFromDistance(
604         visible_rect, tile_rect, draws_to_root);
605   }
606 
607   if (is_small_animated_layer) {
608     priority = PriorityCalculator::max_priority(
609         priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
610   }
611 
612   if (priority != PriorityCalculator::LowestPriority())
613     texture->set_request_priority(priority);
614 }
615 }  // namespace
616 
SetTexturePriorities(const PriorityCalculator & priority_calc)617 void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
618   UpdateBounds();
619   ResetUpdateState();
620   UpdateScrollPrediction();
621 
622   if (tiler_->has_empty_bounds())
623     return;
624 
625   bool draws_to_root = !render_target()->parent();
626   bool small_animated_layer = IsSmallAnimatedLayer();
627 
628   // Minimally create the tiles in the desired pre-paint rect.
629   gfx::Rect create_tiles_rect = IdlePaintRect();
630   if (small_animated_layer)
631     create_tiles_rect = gfx::Rect(content_bounds());
632   if (!create_tiles_rect.IsEmpty()) {
633     int left, top, right, bottom;
634     tiler_->ContentRectToTileIndices(
635         create_tiles_rect, &left, &top, &right, &bottom);
636     for (int j = top; j <= bottom; ++j) {
637       for (int i = left; i <= right; ++i) {
638         if (!TileAt(i, j))
639           CreateTile(i, j);
640       }
641     }
642   }
643 
644   // Now update priorities on all tiles we have in the layer, no matter where
645   // they are.
646   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
647        iter != tiler_->tiles().end();
648        ++iter) {
649     UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
650     // TODO(enne): This should not ever be null.
651     if (!tile)
652       continue;
653     gfx::Rect tile_rect = tiler_->TileRect(tile);
654     SetPriorityForTexture(predicted_visible_rect_,
655                           tile_rect,
656                           draws_to_root,
657                           small_animated_layer,
658                           tile->managed_resource());
659   }
660 }
661 
VisibleContentOpaqueRegion() const662 Region TiledLayer::VisibleContentOpaqueRegion() const {
663   if (skips_draw_)
664     return Region();
665   if (contents_opaque())
666     return visible_content_rect();
667   return tiler_->OpaqueRegionInContentRect(visible_content_rect());
668 }
669 
ResetUpdateState()670 void TiledLayer::ResetUpdateState() {
671   skips_draw_ = false;
672   failed_update_ = false;
673 
674   LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
675   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
676        iter != end;
677        ++iter) {
678     UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
679     // TODO(enne): This should not ever be null.
680     if (!tile)
681       continue;
682     tile->ResetUpdateState();
683   }
684 }
685 
686 namespace {
ExpandRectByDelta(gfx::Rect rect,gfx::Vector2d delta)687 gfx::Rect ExpandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) {
688   int width = rect.width() + std::abs(delta.x());
689   int height = rect.height() + std::abs(delta.y());
690   int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
691   int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
692   return gfx::Rect(x, y, width, height);
693 }
694 }
695 
UpdateScrollPrediction()696 void TiledLayer::UpdateScrollPrediction() {
697   // This scroll prediction is very primitive and should be replaced by a
698   // a recursive calculation on all layers which uses actual scroll/animation
699   // velocities. To insure this doesn't miss-predict, we only use it to predict
700   // the visible_rect if:
701   // - content_bounds() hasn't changed.
702   // - visible_rect.size() hasn't changed.
703   // These two conditions prevent rotations, scales, pinch-zooms etc. where
704   // the prediction would be incorrect.
705   gfx::Vector2d delta = visible_content_rect().CenterPoint() -
706                         previous_visible_rect_.CenterPoint();
707   predicted_scroll_ = -delta;
708   predicted_visible_rect_ = visible_content_rect();
709   if (previous_content_bounds_ == content_bounds() &&
710       previous_visible_rect_.size() == visible_content_rect().size()) {
711     // Only expand the visible rect in the major scroll direction, to prevent
712     // massive paints due to diagonal scrolls.
713     gfx::Vector2d major_scroll_delta =
714         (std::abs(delta.x()) > std::abs(delta.y())) ?
715         gfx::Vector2d(delta.x(), 0) :
716         gfx::Vector2d(0, delta.y());
717     predicted_visible_rect_ =
718         ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
719 
720     // Bound the prediction to prevent unbounded paints, and clamp to content
721     // bounds.
722     gfx::Rect bound = visible_content_rect();
723     bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
724                 -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
725     bound.Intersect(gfx::Rect(content_bounds()));
726     predicted_visible_rect_.Intersect(bound);
727   }
728   previous_content_bounds_ = content_bounds();
729   previous_visible_rect_ = visible_content_rect();
730 }
731 
Update(ResourceUpdateQueue * queue,const OcclusionTracker * occlusion)732 bool TiledLayer::Update(ResourceUpdateQueue* queue,
733                         const OcclusionTracker* occlusion) {
734   DCHECK(!skips_draw_ && !failed_update_);  // Did ResetUpdateState get skipped?
735 
736   // Tiled layer always causes commits to wait for activation, as it does
737   // not support pending trees.
738   SetNextCommitWaitsForActivation();
739 
740   bool updated = false;
741 
742   {
743     base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
744                                                   true);
745 
746     updated |= ContentsScalingLayer::Update(queue, occlusion);
747     UpdateBounds();
748   }
749 
750   if (tiler_->has_empty_bounds() || !DrawsContent())
751     return false;
752 
753   // Animation pre-paint. If the layer is small, try to paint it all
754   // immediately whether or not it is occluded, to avoid paint/upload
755   // hiccups while it is animating.
756   if (IsSmallAnimatedLayer()) {
757     int left, top, right, bottom;
758     tiler_->ContentRectToTileIndices(gfx::Rect(content_bounds()),
759                                      &left,
760                                      &top,
761                                      &right,
762                                      &bottom);
763     UpdateTiles(left, top, right, bottom, queue, NULL, &updated);
764     if (updated)
765       return updated;
766     // This was an attempt to paint the entire layer so if we fail it's okay,
767     // just fallback on painting visible etc. below.
768     failed_update_ = false;
769   }
770 
771   if (predicted_visible_rect_.IsEmpty())
772     return updated;
773 
774   // Visible painting. First occlude visible tiles and paint the non-occluded
775   // tiles.
776   int left, top, right, bottom;
777   tiler_->ContentRectToTileIndices(
778       predicted_visible_rect_, &left, &top, &right, &bottom);
779   MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
780   skips_draw_ = !UpdateTiles(
781       left, top, right, bottom, queue, occlusion, &updated);
782   if (skips_draw_)
783     tiler_->reset();
784   if (skips_draw_ || updated)
785     return true;
786 
787   // If we have already painting everything visible. Do some pre-painting while
788   // idle.
789   gfx::Rect idle_paint_content_rect = IdlePaintRect();
790   if (idle_paint_content_rect.IsEmpty())
791     return updated;
792 
793   // Prepaint anything that was occluded but inside the layer's visible region.
794   if (!UpdateTiles(left, top, right, bottom, queue, NULL, &updated) ||
795       updated)
796     return updated;
797 
798   int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
799   tiler_->ContentRectToTileIndices(idle_paint_content_rect,
800                                    &prepaint_left,
801                                    &prepaint_top,
802                                    &prepaint_right,
803                                    &prepaint_bottom);
804 
805   // Then expand outwards one row/column at a time until we find a dirty
806   // row/column to update. Increment along the major and minor scroll directions
807   // first.
808   gfx::Vector2d delta = -predicted_scroll_;
809   delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
810                         delta.y() == 0 ? 1 : delta.y());
811   gfx::Vector2d major_delta =
812       (std::abs(delta.x()) > std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
813                                         : gfx::Vector2d(0, delta.y());
814   gfx::Vector2d minor_delta =
815       (std::abs(delta.x()) <= std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
816                                          : gfx::Vector2d(0, delta.y());
817   gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
818                               -minor_delta };
819   for (int i = 0; i < 4; i++) {
820     if (deltas[i].y() > 0) {
821       while (bottom < prepaint_bottom) {
822         ++bottom;
823         if (!UpdateTiles(
824                 left, bottom, right, bottom, queue, NULL, &updated) ||
825             updated)
826           return updated;
827       }
828     }
829     if (deltas[i].y() < 0) {
830       while (top > prepaint_top) {
831         --top;
832         if (!UpdateTiles(
833                 left, top, right, top, queue, NULL, &updated) ||
834             updated)
835           return updated;
836       }
837     }
838     if (deltas[i].x() < 0) {
839       while (left > prepaint_left) {
840         --left;
841         if (!UpdateTiles(
842                 left, top, left, bottom, queue, NULL, &updated) ||
843             updated)
844           return updated;
845       }
846     }
847     if (deltas[i].x() > 0) {
848       while (right < prepaint_right) {
849         ++right;
850         if (!UpdateTiles(
851                 right, top, right, bottom, queue, NULL, &updated) ||
852             updated)
853           return updated;
854       }
855     }
856   }
857   return updated;
858 }
859 
OnOutputSurfaceCreated()860 void TiledLayer::OnOutputSurfaceCreated() {
861   // Ensure that all textures are of the right format.
862   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
863        iter != tiler_->tiles().end();
864        ++iter) {
865     UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
866     if (!tile)
867       continue;
868     PrioritizedResource* resource = tile->managed_resource();
869     resource->SetDimensions(resource->size(), texture_format_);
870   }
871 }
872 
NeedsIdlePaint()873 bool TiledLayer::NeedsIdlePaint() {
874   // Don't trigger more paints if we failed (as we'll just fail again).
875   if (failed_update_ || visible_content_rect().IsEmpty() ||
876       tiler_->has_empty_bounds() || !DrawsContent())
877     return false;
878 
879   gfx::Rect idle_paint_content_rect = IdlePaintRect();
880   if (idle_paint_content_rect.IsEmpty())
881     return false;
882 
883   int left, top, right, bottom;
884   tiler_->ContentRectToTileIndices(
885       idle_paint_content_rect, &left, &top, &right, &bottom);
886 
887   for (int j = top; j <= bottom; ++j) {
888     for (int i = left; i <= right; ++i) {
889       UpdatableTile* tile = TileAt(i, j);
890       DCHECK(tile);  // Did SetTexturePriorities get skipped?
891       if (!tile)
892         continue;
893 
894       bool updated = !tile->update_rect.IsEmpty();
895       bool can_acquire =
896           tile->managed_resource()->can_acquire_backing_texture();
897       bool dirty =
898           tile->is_dirty() || !tile->managed_resource()->have_backing_texture();
899       if (!updated && can_acquire && dirty)
900         return true;
901     }
902   }
903   return false;
904 }
905 
IdlePaintRect()906 gfx::Rect TiledLayer::IdlePaintRect() {
907   // Don't inflate an empty rect.
908   if (visible_content_rect().IsEmpty())
909     return gfx::Rect();
910 
911   gfx::Rect prepaint_rect = visible_content_rect();
912   prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
913                       -tiler_->tile_size().height() * kPrepaintRows);
914   gfx::Rect content_rect(content_bounds());
915   prepaint_rect.Intersect(content_rect);
916 
917   return prepaint_rect;
918 }
919 
920 }  // namespace cc
921