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