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