1ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// Copyright 2011 The Chromium Authors. All rights reserved.
2ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// Use of this source code is governed by a BSD-style license that can be
31b362b15af34006e6a11974088a46d42b903418eJohann// found in the LICENSE file.
41b362b15af34006e6a11974088a46d42b903418eJohann
51b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/layers/tiled_layer.h"
61b362b15af34006e6a11974088a46d42b903418eJohann
71b362b15af34006e6a11974088a46d42b903418eJohann#include <algorithm>
81b362b15af34006e6a11974088a46d42b903418eJohann#include <vector>
91b362b15af34006e6a11974088a46d42b903418eJohann
10ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "base/auto_reset.h"
11ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "base/basictypes.h"
12ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang#include "build/build_config.h"
131b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/base/simple_enclosed_region.h"
141b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/layers/layer_impl.h"
151b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/layers/tiled_layer_impl.h"
161b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/resources/layer_updater.h"
171b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/resources/prioritized_resource.h"
181b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/resources/priority_calculator.h"
191b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/trees/layer_tree_host.h"
201b362b15af34006e6a11974088a46d42b903418eJohann#include "cc/trees/occlusion_tracker.h"
211b362b15af34006e6a11974088a46d42b903418eJohann#include "third_party/khronos/GLES2/gl2.h"
221b362b15af34006e6a11974088a46d42b903418eJohann#include "ui/gfx/rect_conversions.h"
231b362b15af34006e6a11974088a46d42b903418eJohann
241b362b15af34006e6a11974088a46d42b903418eJohannnamespace cc {
25ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang
26ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang// Maximum predictive expansion of the visible area.
27ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuangstatic const int kMaxPredictiveTilesCount = 2;
281b362b15af34006e6a11974088a46d42b903418eJohann
291b362b15af34006e6a11974088a46d42b903418eJohann// Number of rows/columns of tiles to pre-paint.
301b362b15af34006e6a11974088a46d42b903418eJohann// We should increase these further as all textures are
311b362b15af34006e6a11974088a46d42b903418eJohann// prioritized and we insure performance doesn't suffer.
321b362b15af34006e6a11974088a46d42b903418eJohannstatic const int kPrepaintRows = 4;
331b362b15af34006e6a11974088a46d42b903418eJohannstatic const int kPrepaintColumns = 2;
341b362b15af34006e6a11974088a46d42b903418eJohann
351b362b15af34006e6a11974088a46d42b903418eJohannclass UpdatableTile : public LayerTilingData::Tile {
361b362b15af34006e6a11974088a46d42b903418eJohann public:
371b362b15af34006e6a11974088a46d42b903418eJohann  static scoped_ptr<UpdatableTile> Create(
381b362b15af34006e6a11974088a46d42b903418eJohann      scoped_ptr<LayerUpdater::Resource> updater_resource) {
391b362b15af34006e6a11974088a46d42b903418eJohann    return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
401b362b15af34006e6a11974088a46d42b903418eJohann  }
411b362b15af34006e6a11974088a46d42b903418eJohann
421b362b15af34006e6a11974088a46d42b903418eJohann  LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
431b362b15af34006e6a11974088a46d42b903418eJohann  PrioritizedResource* managed_resource() {
441b362b15af34006e6a11974088a46d42b903418eJohann    return updater_resource_->texture();
451b362b15af34006e6a11974088a46d42b903418eJohann  }
461b362b15af34006e6a11974088a46d42b903418eJohann
471b362b15af34006e6a11974088a46d42b903418eJohann  bool is_dirty() const { return !dirty_rect.IsEmpty(); }
481b362b15af34006e6a11974088a46d42b903418eJohann
491b362b15af34006e6a11974088a46d42b903418eJohann  // Reset update state for the current frame. This should occur before painting
501b362b15af34006e6a11974088a46d42b903418eJohann  // for all layers. Since painting one layer can invalidate another layer after
511b362b15af34006e6a11974088a46d42b903418eJohann  // it has already painted, mark all non-dirty tiles as valid before painting
521b362b15af34006e6a11974088a46d42b903418eJohann  // such that invalidations during painting won't prevent them from being
531b362b15af34006e6a11974088a46d42b903418eJohann  // pushed.
541b362b15af34006e6a11974088a46d42b903418eJohann  void ResetUpdateState() {
551b362b15af34006e6a11974088a46d42b903418eJohann    update_rect = gfx::Rect();
561b362b15af34006e6a11974088a46d42b903418eJohann    occluded = false;
571b362b15af34006e6a11974088a46d42b903418eJohann    partial_update = false;
581b362b15af34006e6a11974088a46d42b903418eJohann    valid_for_frame = !is_dirty();
591b362b15af34006e6a11974088a46d42b903418eJohann  }
601b362b15af34006e6a11974088a46d42b903418eJohann
611b362b15af34006e6a11974088a46d42b903418eJohann  // This promises to update the tile and therefore also guarantees the tile
621b362b15af34006e6a11974088a46d42b903418eJohann  // will be valid for this frame. dirty_rect is copied into update_rect so we
631b362b15af34006e6a11974088a46d42b903418eJohann  // can continue to track re-entrant invalidations that occur during painting.
641b362b15af34006e6a11974088a46d42b903418eJohann  void MarkForUpdate() {
651b362b15af34006e6a11974088a46d42b903418eJohann    valid_for_frame = true;
661b362b15af34006e6a11974088a46d42b903418eJohann    update_rect = dirty_rect;
671b362b15af34006e6a11974088a46d42b903418eJohann    dirty_rect = gfx::Rect();
681b362b15af34006e6a11974088a46d42b903418eJohann  }
691b362b15af34006e6a11974088a46d42b903418eJohann
701b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Rect dirty_rect;
711b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Rect update_rect;
721b362b15af34006e6a11974088a46d42b903418eJohann  bool partial_update;
731b362b15af34006e6a11974088a46d42b903418eJohann  bool valid_for_frame;
741b362b15af34006e6a11974088a46d42b903418eJohann  bool occluded;
751b362b15af34006e6a11974088a46d42b903418eJohann
761b362b15af34006e6a11974088a46d42b903418eJohann private:
771b362b15af34006e6a11974088a46d42b903418eJohann  explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
781b362b15af34006e6a11974088a46d42b903418eJohann      : partial_update(false),
791b362b15af34006e6a11974088a46d42b903418eJohann        valid_for_frame(false),
801b362b15af34006e6a11974088a46d42b903418eJohann        occluded(false),
811b362b15af34006e6a11974088a46d42b903418eJohann        updater_resource_(updater_resource.Pass()) {}
821b362b15af34006e6a11974088a46d42b903418eJohann
831b362b15af34006e6a11974088a46d42b903418eJohann  scoped_ptr<LayerUpdater::Resource> updater_resource_;
841b362b15af34006e6a11974088a46d42b903418eJohann
851b362b15af34006e6a11974088a46d42b903418eJohann  DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
861b362b15af34006e6a11974088a46d42b903418eJohann};
871b362b15af34006e6a11974088a46d42b903418eJohann
881b362b15af34006e6a11974088a46d42b903418eJohannTiledLayer::TiledLayer()
891b362b15af34006e6a11974088a46d42b903418eJohann    : ContentsScalingLayer(),
901b362b15af34006e6a11974088a46d42b903418eJohann      texture_format_(RGBA_8888),
91ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang      skips_draw_(false),
921b362b15af34006e6a11974088a46d42b903418eJohann      failed_update_(false),
931b362b15af34006e6a11974088a46d42b903418eJohann      tiling_option_(AUTO_TILE) {
941b362b15af34006e6a11974088a46d42b903418eJohann  tiler_ =
951b362b15af34006e6a11974088a46d42b903418eJohann      LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
961b362b15af34006e6a11974088a46d42b903418eJohann}
971b362b15af34006e6a11974088a46d42b903418eJohann
981b362b15af34006e6a11974088a46d42b903418eJohannTiledLayer::~TiledLayer() {}
991b362b15af34006e6a11974088a46d42b903418eJohann
1001b362b15af34006e6a11974088a46d42b903418eJohannscoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
1011b362b15af34006e6a11974088a46d42b903418eJohann  return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
1021b362b15af34006e6a11974088a46d42b903418eJohann}
1031b362b15af34006e6a11974088a46d42b903418eJohann
1041b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::UpdateTileSizeAndTilingOption() {
1051b362b15af34006e6a11974088a46d42b903418eJohann  DCHECK(layer_tree_host());
1061b362b15af34006e6a11974088a46d42b903418eJohann
1071b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size default_tile_size = layer_tree_host()->settings().default_tile_size;
1081b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size max_untiled_layer_size =
1091b362b15af34006e6a11974088a46d42b903418eJohann      layer_tree_host()->settings().max_untiled_layer_size;
1101b362b15af34006e6a11974088a46d42b903418eJohann  int layer_width = content_bounds().width();
1111b362b15af34006e6a11974088a46d42b903418eJohann  int layer_height = content_bounds().height();
1121b362b15af34006e6a11974088a46d42b903418eJohann
1131b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
1141b362b15af34006e6a11974088a46d42b903418eJohann                      std::min(default_tile_size.height(), layer_height));
1151b362b15af34006e6a11974088a46d42b903418eJohann
1161b362b15af34006e6a11974088a46d42b903418eJohann  // Tile if both dimensions large, or any one dimension large and the other
1171b362b15af34006e6a11974088a46d42b903418eJohann  // extends into a second tile but the total layer area isn't larger than that
1181b362b15af34006e6a11974088a46d42b903418eJohann  // of the largest possible untiled layer. This heuristic allows for long
1191b362b15af34006e6a11974088a46d42b903418eJohann  // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
1201b362b15af34006e6a11974088a46d42b903418eJohann  // texture space but still avoids creating very large tiles.
1211b362b15af34006e6a11974088a46d42b903418eJohann  bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
1221b362b15af34006e6a11974088a46d42b903418eJohann                             layer_height > max_untiled_layer_size.height();
1231b362b15af34006e6a11974088a46d42b903418eJohann  bool any_dimension_one_tile =
1241b362b15af34006e6a11974088a46d42b903418eJohann      (layer_width <= default_tile_size.width() ||
1251b362b15af34006e6a11974088a46d42b903418eJohann       layer_height <= default_tile_size.height()) &&
1261b362b15af34006e6a11974088a46d42b903418eJohann      (layer_width * layer_height) <= (max_untiled_layer_size.width() *
1271b362b15af34006e6a11974088a46d42b903418eJohann                                       max_untiled_layer_size.height());
1281b362b15af34006e6a11974088a46d42b903418eJohann  bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
1291b362b15af34006e6a11974088a46d42b903418eJohann
1301b362b15af34006e6a11974088a46d42b903418eJohann  bool is_tiled;
1311b362b15af34006e6a11974088a46d42b903418eJohann  if (tiling_option_ == ALWAYS_TILE)
1321b362b15af34006e6a11974088a46d42b903418eJohann    is_tiled = true;
1331b362b15af34006e6a11974088a46d42b903418eJohann  else if (tiling_option_ == NEVER_TILE)
1341b362b15af34006e6a11974088a46d42b903418eJohann    is_tiled = false;
1351b362b15af34006e6a11974088a46d42b903418eJohann  else
1361b362b15af34006e6a11974088a46d42b903418eJohann    is_tiled = auto_tiled;
1371b362b15af34006e6a11974088a46d42b903418eJohann
1381b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
1391b362b15af34006e6a11974088a46d42b903418eJohann  const int max_size =
1401b362b15af34006e6a11974088a46d42b903418eJohann      layer_tree_host()->GetRendererCapabilities().max_texture_size;
1411b362b15af34006e6a11974088a46d42b903418eJohann  requested_size.SetToMin(gfx::Size(max_size, max_size));
1421b362b15af34006e6a11974088a46d42b903418eJohann  SetTileSize(requested_size);
1431b362b15af34006e6a11974088a46d42b903418eJohann}
1441b362b15af34006e6a11974088a46d42b903418eJohann
1451b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::UpdateBounds() {
1461b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size old_tiling_size = tiler_->tiling_size();
1471b362b15af34006e6a11974088a46d42b903418eJohann  gfx::Size new_tiling_size = content_bounds();
1481b362b15af34006e6a11974088a46d42b903418eJohann  if (old_tiling_size == new_tiling_size)
1491b362b15af34006e6a11974088a46d42b903418eJohann    return;
1501b362b15af34006e6a11974088a46d42b903418eJohann  tiler_->SetTilingSize(new_tiling_size);
1511b362b15af34006e6a11974088a46d42b903418eJohann
1521b362b15af34006e6a11974088a46d42b903418eJohann  // Invalidate any areas that the new bounds exposes.
1531b362b15af34006e6a11974088a46d42b903418eJohann  Region new_region =
1541b362b15af34006e6a11974088a46d42b903418eJohann      SubtractRegions(gfx::Rect(new_tiling_size), gfx::Rect(old_tiling_size));
1551b362b15af34006e6a11974088a46d42b903418eJohann  for (Region::Iterator new_rects(new_region); new_rects.has_rect();
1561b362b15af34006e6a11974088a46d42b903418eJohann       new_rects.next())
1571b362b15af34006e6a11974088a46d42b903418eJohann    InvalidateContentRect(new_rects.rect());
1581b362b15af34006e6a11974088a46d42b903418eJohann  UpdateDrawsContent(HasDrawableContent());
1591b362b15af34006e6a11974088a46d42b903418eJohann}
1601b362b15af34006e6a11974088a46d42b903418eJohann
1611b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::SetTileSize(const gfx::Size& size) {
1621b362b15af34006e6a11974088a46d42b903418eJohann  tiler_->SetTileSize(size);
1631b362b15af34006e6a11974088a46d42b903418eJohann  UpdateDrawsContent(HasDrawableContent());
1641b362b15af34006e6a11974088a46d42b903418eJohann}
1651b362b15af34006e6a11974088a46d42b903418eJohann
1661b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::SetBorderTexelOption(
1671b362b15af34006e6a11974088a46d42b903418eJohann    LayerTilingData::BorderTexelOption border_texel_option) {
1681b362b15af34006e6a11974088a46d42b903418eJohann  tiler_->SetBorderTexelOption(border_texel_option);
1691b362b15af34006e6a11974088a46d42b903418eJohann  UpdateDrawsContent(HasDrawableContent());
1701b362b15af34006e6a11974088a46d42b903418eJohann}
1711b362b15af34006e6a11974088a46d42b903418eJohann
1721b362b15af34006e6a11974088a46d42b903418eJohannbool TiledLayer::HasDrawableContent() const {
1731b362b15af34006e6a11974088a46d42b903418eJohann  bool has_more_than_one_tile =
1741b362b15af34006e6a11974088a46d42b903418eJohann      (tiler_->num_tiles_x() > 1) || (tiler_->num_tiles_y() > 1);
1751b362b15af34006e6a11974088a46d42b903418eJohann
1761b362b15af34006e6a11974088a46d42b903418eJohann  return !(tiling_option_ == NEVER_TILE && has_more_than_one_tile) &&
1771b362b15af34006e6a11974088a46d42b903418eJohann         ContentsScalingLayer::HasDrawableContent();
1781b362b15af34006e6a11974088a46d42b903418eJohann}
1791b362b15af34006e6a11974088a46d42b903418eJohann
1801b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::ReduceMemoryUsage() {
1811b362b15af34006e6a11974088a46d42b903418eJohann  if (Updater())
1821b362b15af34006e6a11974088a46d42b903418eJohann    Updater()->ReduceMemoryUsage();
1831b362b15af34006e6a11974088a46d42b903418eJohann}
1841b362b15af34006e6a11974088a46d42b903418eJohann
1851b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::SetIsMask(bool is_mask) {
1861b362b15af34006e6a11974088a46d42b903418eJohann  set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
1871b362b15af34006e6a11974088a46d42b903418eJohann}
1881b362b15af34006e6a11974088a46d42b903418eJohann
1891b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::PushPropertiesTo(LayerImpl* layer) {
1901b362b15af34006e6a11974088a46d42b903418eJohann  ContentsScalingLayer::PushPropertiesTo(layer);
1911b362b15af34006e6a11974088a46d42b903418eJohann
1921b362b15af34006e6a11974088a46d42b903418eJohann  TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
1931b362b15af34006e6a11974088a46d42b903418eJohann
1941b362b15af34006e6a11974088a46d42b903418eJohann  tiled_layer->set_skips_draw(skips_draw_);
1951b362b15af34006e6a11974088a46d42b903418eJohann  tiled_layer->SetTilingData(*tiler_);
1961b362b15af34006e6a11974088a46d42b903418eJohann  std::vector<UpdatableTile*> invalid_tiles;
1971b362b15af34006e6a11974088a46d42b903418eJohann
1981b362b15af34006e6a11974088a46d42b903418eJohann  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
1991b362b15af34006e6a11974088a46d42b903418eJohann       iter != tiler_->tiles().end();
2001b362b15af34006e6a11974088a46d42b903418eJohann       ++iter) {
2011b362b15af34006e6a11974088a46d42b903418eJohann    int i = iter->first.first;
2021b362b15af34006e6a11974088a46d42b903418eJohann    int j = iter->first.second;
2031b362b15af34006e6a11974088a46d42b903418eJohann    UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
2041b362b15af34006e6a11974088a46d42b903418eJohann    // TODO(enne): This should not ever be null.
2051b362b15af34006e6a11974088a46d42b903418eJohann    if (!tile)
2061b362b15af34006e6a11974088a46d42b903418eJohann      continue;
2071b362b15af34006e6a11974088a46d42b903418eJohann
2081b362b15af34006e6a11974088a46d42b903418eJohann    if (!tile->managed_resource()->have_backing_texture()) {
2091b362b15af34006e6a11974088a46d42b903418eJohann      // Evicted tiles get deleted from both layers
2101b362b15af34006e6a11974088a46d42b903418eJohann      invalid_tiles.push_back(tile);
2111b362b15af34006e6a11974088a46d42b903418eJohann      continue;
2121b362b15af34006e6a11974088a46d42b903418eJohann    }
2131b362b15af34006e6a11974088a46d42b903418eJohann
2141b362b15af34006e6a11974088a46d42b903418eJohann    if (!tile->valid_for_frame) {
2151b362b15af34006e6a11974088a46d42b903418eJohann      // Invalidated tiles are set so they can get different debug colors.
2161b362b15af34006e6a11974088a46d42b903418eJohann      tiled_layer->PushInvalidTile(i, j);
217ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      continue;
218ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    }
219ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
220ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    tiled_layer->PushTileProperties(
221ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin        i,
222ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin        j,
223ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin        tile->managed_resource()->resource_id(),
224ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin        tile->managed_resource()->contents_swizzled());
225ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  }
226ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
227ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin       iter != invalid_tiles.end();
228ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin       ++iter)
229ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    tiler_->TakeTile((*iter)->i(), (*iter)->j());
230ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
231ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  // TiledLayer must push properties every frame, since viewport state and
232ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  // occlusion from anywhere in the tree can change what the layer decides to
233ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  // push to the impl tree.
234ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  needs_push_properties_ = true;
235ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
236ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
237ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter GultekinPrioritizedResourceManager* TiledLayer::ResourceManager() {
238ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  if (!layer_tree_host())
239ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    return NULL;
240ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  return layer_tree_host()->contents_texture_manager();
241ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
242ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
243ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekinconst PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
244ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin                                                            int j) const {
245ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  UpdatableTile* tile = TileAt(i, j);
246ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  if (!tile)
247ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    return NULL;
248ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  return tile->managed_resource();
249ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
250ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
251ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekinvoid TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
252ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  if (host && host != layer_tree_host()) {
253ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    for (LayerTilingData::TileMap::const_iterator
254ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin             iter = tiler_->tiles().begin();
255ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin         iter != tiler_->tiles().end();
256ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin         ++iter) {
257ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
258ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      // TODO(enne): This should not ever be null.
259ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      if (!tile)
260ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin        continue;
261ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      tile->managed_resource()->SetTextureManager(
262ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin          host->contents_texture_manager());
263ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin    }
264ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  }
265ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  ContentsScalingLayer::SetLayerTreeHost(host);
266ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
267ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
268ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter GultekinUpdatableTile* TiledLayer::TileAt(int i, int j) const {
269ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
270ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
271ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
272ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter GultekinUpdatableTile* TiledLayer::CreateTile(int i, int j) {
273ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  CreateUpdaterIfNeeded();
274ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
275ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  scoped_ptr<UpdatableTile> tile(
276ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin      UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
277ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  tile->managed_resource()->SetDimensions(tiler_->tile_size(), texture_format_);
278ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
279ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  UpdatableTile* added_tile = tile.get();
280ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
281ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
282ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  added_tile->dirty_rect = tiler_->TileRect(added_tile);
283ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
284ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  // Temporary diagnostic crash.
285ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  CHECK(added_tile);
286ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  CHECK(TileAt(i, j));
287ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
288ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin  return added_tile;
289ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin}
290ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekin
291ca15b5fc158a9df465aaf1acfe38d8cb5042c81bKunter Gultekinvoid TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
292ba164dffc5a6795bce97fae02b51ccf3330e15e4hkuang  InvalidateContentRect(LayerRectToContentRect(dirty_rect));
2931b362b15af34006e6a11974088a46d42b903418eJohann  ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
2941b362b15af34006e6a11974088a46d42b903418eJohann}
2951b362b15af34006e6a11974088a46d42b903418eJohann
2961b362b15af34006e6a11974088a46d42b903418eJohannvoid TiledLayer::InvalidateContentRect(const gfx::Rect& content_rect) {
2971b362b15af34006e6a11974088a46d42b903418eJohann  UpdateBounds();
2981b362b15af34006e6a11974088a46d42b903418eJohann  if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
2991b362b15af34006e6a11974088a46d42b903418eJohann    return;
3001b362b15af34006e6a11974088a46d42b903418eJohann
3011b362b15af34006e6a11974088a46d42b903418eJohann  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
302       iter != tiler_->tiles().end();
303       ++iter) {
304    UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
305    DCHECK(tile);
306    // TODO(enne): This should not ever be null.
307    if (!tile)
308      continue;
309    gfx::Rect bound = tiler_->TileRect(tile);
310    bound.Intersect(content_rect);
311    tile->dirty_rect.Union(bound);
312  }
313}
314
315// Returns true if tile is dirty and only part of it needs to be updated.
316bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
317  return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
318         tile->managed_resource()->have_backing_texture();
319}
320
321bool TiledLayer::UpdateTiles(int left,
322                             int top,
323                             int right,
324                             int bottom,
325                             ResourceUpdateQueue* queue,
326                             const OcclusionTracker<Layer>* occlusion,
327                             bool* updated) {
328  CreateUpdaterIfNeeded();
329
330  bool ignore_occlusions = !occlusion;
331  if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
332    failed_update_ = true;
333    return false;
334  }
335
336  gfx::Rect update_rect;
337  gfx::Rect paint_rect;
338  MarkTilesForUpdate(
339    &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions);
340
341  if (paint_rect.IsEmpty())
342    return true;
343
344  *updated = true;
345  UpdateTileTextures(
346      update_rect, paint_rect, left, top, right, bottom, queue, occlusion);
347  return true;
348}
349
350void TiledLayer::MarkOcclusionsAndRequestTextures(
351    int left,
352    int top,
353    int right,
354    int bottom,
355    const OcclusionTracker<Layer>* occlusion) {
356  int occluded_tile_count = 0;
357  bool succeeded = true;
358  for (int j = top; j <= bottom; ++j) {
359    for (int i = left; i <= right; ++i) {
360      UpdatableTile* tile = TileAt(i, j);
361      DCHECK(tile);  // Did SetTexturePriorities get skipped?
362      // TODO(enne): This should not ever be null.
363      if (!tile)
364        continue;
365      // Did ResetUpdateState get skipped? Are we doing more than one occlusion
366      // pass?
367      DCHECK(!tile->occluded);
368      gfx::Rect visible_tile_rect = gfx::IntersectRects(
369          tiler_->tile_bounds(i, j), visible_content_rect());
370      if (!draw_transform_is_animating() && occlusion &&
371          occlusion->GetCurrentOcclusionForLayer(draw_transform())
372              .IsOccluded(visible_tile_rect)) {
373        tile->occluded = true;
374        occluded_tile_count++;
375      } else {
376        succeeded &= tile->managed_resource()->RequestLate();
377      }
378    }
379  }
380}
381
382bool TiledLayer::HaveTexturesForTiles(int left,
383                                      int top,
384                                      int right,
385                                      int bottom,
386                                      bool ignore_occlusions) {
387  for (int j = top; j <= bottom; ++j) {
388    for (int i = left; i <= right; ++i) {
389      UpdatableTile* tile = TileAt(i, j);
390      DCHECK(tile);  // Did SetTexturePriorites get skipped?
391                     // TODO(enne): This should not ever be null.
392      if (!tile)
393        continue;
394
395      // Ensure the entire tile is dirty if we don't have the texture.
396      if (!tile->managed_resource()->have_backing_texture())
397        tile->dirty_rect = tiler_->TileRect(tile);
398
399      // If using occlusion and the visible region of the tile is occluded,
400      // don't reserve a texture or update the tile.
401      if (tile->occluded && !ignore_occlusions)
402        continue;
403
404      if (!tile->managed_resource()->can_acquire_backing_texture())
405        return false;
406    }
407  }
408  return true;
409}
410
411void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect,
412                                    gfx::Rect* paint_rect,
413                                    int left,
414                                    int top,
415                                    int right,
416                                    int bottom,
417                                    bool ignore_occlusions) {
418  for (int j = top; j <= bottom; ++j) {
419    for (int i = left; i <= right; ++i) {
420      UpdatableTile* tile = TileAt(i, j);
421      DCHECK(tile);  // Did SetTexturePriorites get skipped?
422                     // TODO(enne): This should not ever be null.
423      if (!tile)
424        continue;
425      if (tile->occluded && !ignore_occlusions)
426        continue;
427
428      // Prepare update rect from original dirty rects.
429      update_rect->Union(tile->dirty_rect);
430
431      // TODO(reveman): Decide if partial update should be allowed based on cost
432      // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
433      if (tile->is_dirty() &&
434          !layer_tree_host()->AlwaysUsePartialTextureUpdates()) {
435        // If we get a partial update, we use the same texture, otherwise return
436        // the current texture backing, so we don't update visible textures
437        // non-atomically.  If the current backing is in-use, it won't be
438        // deleted until after the commit as the texture manager will not allow
439        // deletion or recycling of in-use textures.
440        if (TileOnlyNeedsPartialUpdate(tile) &&
441            layer_tree_host()->RequestPartialTextureUpdate()) {
442          tile->partial_update = true;
443        } else {
444          tile->dirty_rect = tiler_->TileRect(tile);
445          tile->managed_resource()->ReturnBackingTexture();
446        }
447      }
448
449      paint_rect->Union(tile->dirty_rect);
450      tile->MarkForUpdate();
451    }
452  }
453}
454
455void TiledLayer::UpdateTileTextures(const gfx::Rect& update_rect,
456                                    const gfx::Rect& paint_rect,
457                                    int left,
458                                    int top,
459                                    int right,
460                                    int bottom,
461                                    ResourceUpdateQueue* queue,
462                                    const OcclusionTracker<Layer>* occlusion) {
463  // The update_rect should be in layer space. So we have to convert the
464  // paint_rect from content space to layer space.
465  float width_scale = 1 / draw_properties().contents_scale_x;
466  float height_scale = 1 / draw_properties().contents_scale_y;
467  update_rect_ = gfx::ScaleRect(update_rect, width_scale, height_scale);
468
469  // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
470  // side effect of disabling compositing, which causes our reference to the
471  // texture updater to be deleted.  However, we can't free the memory backing
472  // the SkCanvas until the paint finishes, so we grab a local reference here to
473  // hold the updater alive until the paint completes.
474  scoped_refptr<LayerUpdater> protector(Updater());
475  Updater()->PrepareToUpdate(content_bounds(),
476                             paint_rect,
477                             tiler_->tile_size(),
478                             1.f / width_scale,
479                             1.f / height_scale);
480
481  for (int j = top; j <= bottom; ++j) {
482    for (int i = left; i <= right; ++i) {
483      UpdatableTile* tile = TileAt(i, j);
484      DCHECK(tile);  // Did SetTexturePriorites get skipped?
485                     // TODO(enne): This should not ever be null.
486      if (!tile)
487        continue;
488
489      gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
490
491      // Use update_rect as the above loop copied the dirty rect for this frame
492      // to update_rect.
493      gfx::Rect dirty_rect = tile->update_rect;
494      if (dirty_rect.IsEmpty())
495        continue;
496
497      // source_rect starts as a full-sized tile with border texels included.
498      gfx::Rect source_rect = tiler_->TileRect(tile);
499      source_rect.Intersect(dirty_rect);
500      // Paint rect not guaranteed to line up on tile boundaries, so
501      // make sure that source_rect doesn't extend outside of it.
502      source_rect.Intersect(paint_rect);
503
504      tile->update_rect = source_rect;
505
506      if (source_rect.IsEmpty())
507        continue;
508
509      const gfx::Point anchor = tiler_->TileRect(tile).origin();
510
511      // Calculate tile-space rectangle to upload into.
512      gfx::Vector2d dest_offset = source_rect.origin() - anchor;
513      CHECK_GE(dest_offset.x(), 0);
514      CHECK_GE(dest_offset.y(), 0);
515
516      // Offset from paint rectangle to this tile's dirty rectangle.
517      gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
518      CHECK_GE(paint_offset.x(), 0);
519      CHECK_GE(paint_offset.y(), 0);
520      CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
521      CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
522
523      tile->updater_resource()->Update(
524          queue, source_rect, dest_offset, tile->partial_update);
525    }
526  }
527}
528
529// This picks a small animated layer to be anything less than one viewport. This
530// is specifically for page transitions which are viewport-sized layers. The
531// extra tile of padding is due to these layers being slightly larger than the
532// viewport in some cases.
533bool TiledLayer::IsSmallAnimatedLayer() const {
534  if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
535    return false;
536  gfx::Size viewport_size =
537      layer_tree_host() ? layer_tree_host()->device_viewport_size()
538                        : gfx::Size();
539  gfx::Rect content_rect(content_bounds());
540  return content_rect.width() <=
541         viewport_size.width() + tiler_->tile_size().width() &&
542         content_rect.height() <=
543         viewport_size.height() + tiler_->tile_size().height();
544}
545
546namespace {
547// TODO(epenner): Remove this and make this based on distance once distance can
548// be calculated for offscreen layers. For now, prioritize all small animated
549// layers after 512 pixels of pre-painting.
550void SetPriorityForTexture(const gfx::Rect& visible_rect,
551                           const gfx::Rect& tile_rect,
552                           bool draws_to_root,
553                           bool is_small_animated_layer,
554                           PrioritizedResource* texture) {
555  int priority = PriorityCalculator::LowestPriority();
556  if (!visible_rect.IsEmpty()) {
557    priority = PriorityCalculator::PriorityFromDistance(
558        visible_rect, tile_rect, draws_to_root);
559  }
560
561  if (is_small_animated_layer) {
562    priority = PriorityCalculator::max_priority(
563        priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
564  }
565
566  if (priority != PriorityCalculator::LowestPriority())
567    texture->set_request_priority(priority);
568}
569}  // namespace
570
571void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
572  UpdateBounds();
573  ResetUpdateState();
574  UpdateScrollPrediction();
575
576  if (tiler_->has_empty_bounds())
577    return;
578
579  bool draws_to_root = !render_target()->parent();
580  bool small_animated_layer = IsSmallAnimatedLayer();
581
582  // Minimally create the tiles in the desired pre-paint rect.
583  gfx::Rect create_tiles_rect = IdlePaintRect();
584  if (small_animated_layer)
585    create_tiles_rect = gfx::Rect(content_bounds());
586  if (!create_tiles_rect.IsEmpty()) {
587    int left, top, right, bottom;
588    tiler_->ContentRectToTileIndices(
589        create_tiles_rect, &left, &top, &right, &bottom);
590    for (int j = top; j <= bottom; ++j) {
591      for (int i = left; i <= right; ++i) {
592        if (!TileAt(i, j))
593          CreateTile(i, j);
594      }
595    }
596  }
597
598  // Now update priorities on all tiles we have in the layer, no matter where
599  // they are.
600  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
601       iter != tiler_->tiles().end();
602       ++iter) {
603    UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
604    // TODO(enne): This should not ever be null.
605    if (!tile)
606      continue;
607    gfx::Rect tile_rect = tiler_->TileRect(tile);
608    SetPriorityForTexture(predicted_visible_rect_,
609                          tile_rect,
610                          draws_to_root,
611                          small_animated_layer,
612                          tile->managed_resource());
613  }
614}
615
616SimpleEnclosedRegion TiledLayer::VisibleContentOpaqueRegion() const {
617  if (skips_draw_)
618    return SimpleEnclosedRegion();
619  return Layer::VisibleContentOpaqueRegion();
620}
621
622void TiledLayer::ResetUpdateState() {
623  skips_draw_ = false;
624  failed_update_ = false;
625
626  LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
627  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
628       iter != end;
629       ++iter) {
630    UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
631    // TODO(enne): This should not ever be null.
632    if (!tile)
633      continue;
634    tile->ResetUpdateState();
635  }
636}
637
638namespace {
639gfx::Rect ExpandRectByDelta(const gfx::Rect& rect, const gfx::Vector2d& delta) {
640  int width = rect.width() + std::abs(delta.x());
641  int height = rect.height() + std::abs(delta.y());
642  int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
643  int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
644  return gfx::Rect(x, y, width, height);
645}
646}
647
648void TiledLayer::UpdateScrollPrediction() {
649  // This scroll prediction is very primitive and should be replaced by a
650  // a recursive calculation on all layers which uses actual scroll/animation
651  // velocities. To insure this doesn't miss-predict, we only use it to predict
652  // the visible_rect if:
653  // - content_bounds() hasn't changed.
654  // - visible_rect.size() hasn't changed.
655  // These two conditions prevent rotations, scales, pinch-zooms etc. where
656  // the prediction would be incorrect.
657  gfx::Vector2d delta = visible_content_rect().CenterPoint() -
658                        previous_visible_rect_.CenterPoint();
659  predicted_scroll_ = -delta;
660  predicted_visible_rect_ = visible_content_rect();
661  if (previous_content_bounds_ == content_bounds() &&
662      previous_visible_rect_.size() == visible_content_rect().size()) {
663    // Only expand the visible rect in the major scroll direction, to prevent
664    // massive paints due to diagonal scrolls.
665    gfx::Vector2d major_scroll_delta =
666        (std::abs(delta.x()) > std::abs(delta.y())) ?
667        gfx::Vector2d(delta.x(), 0) :
668        gfx::Vector2d(0, delta.y());
669    predicted_visible_rect_ =
670        ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
671
672    // Bound the prediction to prevent unbounded paints, and clamp to content
673    // bounds.
674    gfx::Rect bound = visible_content_rect();
675    bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
676                -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
677    bound.Intersect(gfx::Rect(content_bounds()));
678    predicted_visible_rect_.Intersect(bound);
679  }
680  previous_content_bounds_ = content_bounds();
681  previous_visible_rect_ = visible_content_rect();
682}
683
684bool TiledLayer::Update(ResourceUpdateQueue* queue,
685                        const OcclusionTracker<Layer>* occlusion) {
686  DCHECK(!skips_draw_ && !failed_update_);  // Did ResetUpdateState get skipped?
687
688  // Tiled layer always causes commits to wait for activation, as it does
689  // not support pending trees.
690  SetNextCommitWaitsForActivation();
691
692  bool updated = false;
693
694  {
695    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
696                                                  true);
697
698    updated |= ContentsScalingLayer::Update(queue, occlusion);
699    UpdateBounds();
700  }
701
702  if (tiler_->has_empty_bounds() || !DrawsContent())
703    return false;
704
705  // Animation pre-paint. If the layer is small, try to paint it all
706  // immediately whether or not it is occluded, to avoid paint/upload
707  // hiccups while it is animating.
708  if (IsSmallAnimatedLayer()) {
709    int left, top, right, bottom;
710    tiler_->ContentRectToTileIndices(gfx::Rect(content_bounds()),
711                                     &left,
712                                     &top,
713                                     &right,
714                                     &bottom);
715    UpdateTiles(left, top, right, bottom, queue, NULL, &updated);
716    if (updated)
717      return updated;
718    // This was an attempt to paint the entire layer so if we fail it's okay,
719    // just fallback on painting visible etc. below.
720    failed_update_ = false;
721  }
722
723  if (predicted_visible_rect_.IsEmpty())
724    return updated;
725
726  // Visible painting. First occlude visible tiles and paint the non-occluded
727  // tiles.
728  int left, top, right, bottom;
729  tiler_->ContentRectToTileIndices(
730      predicted_visible_rect_, &left, &top, &right, &bottom);
731  MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
732  skips_draw_ = !UpdateTiles(
733      left, top, right, bottom, queue, occlusion, &updated);
734  if (skips_draw_)
735    tiler_->reset();
736  if (skips_draw_ || updated)
737    return true;
738
739  // If we have already painting everything visible. Do some pre-painting while
740  // idle.
741  gfx::Rect idle_paint_content_rect = IdlePaintRect();
742  if (idle_paint_content_rect.IsEmpty())
743    return updated;
744
745  // Prepaint anything that was occluded but inside the layer's visible region.
746  if (!UpdateTiles(left, top, right, bottom, queue, NULL, &updated) ||
747      updated)
748    return updated;
749
750  int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
751  tiler_->ContentRectToTileIndices(idle_paint_content_rect,
752                                   &prepaint_left,
753                                   &prepaint_top,
754                                   &prepaint_right,
755                                   &prepaint_bottom);
756
757  // Then expand outwards one row/column at a time until we find a dirty
758  // row/column to update. Increment along the major and minor scroll directions
759  // first.
760  gfx::Vector2d delta = -predicted_scroll_;
761  delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
762                        delta.y() == 0 ? 1 : delta.y());
763  gfx::Vector2d major_delta =
764      (std::abs(delta.x()) > std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
765                                        : gfx::Vector2d(0, delta.y());
766  gfx::Vector2d minor_delta =
767      (std::abs(delta.x()) <= std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
768                                         : gfx::Vector2d(0, delta.y());
769  gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
770                              -minor_delta };
771  for (int i = 0; i < 4; i++) {
772    if (deltas[i].y() > 0) {
773      while (bottom < prepaint_bottom) {
774        ++bottom;
775        if (!UpdateTiles(
776                left, bottom, right, bottom, queue, NULL, &updated) ||
777            updated)
778          return updated;
779      }
780    }
781    if (deltas[i].y() < 0) {
782      while (top > prepaint_top) {
783        --top;
784        if (!UpdateTiles(
785                left, top, right, top, queue, NULL, &updated) ||
786            updated)
787          return updated;
788      }
789    }
790    if (deltas[i].x() < 0) {
791      while (left > prepaint_left) {
792        --left;
793        if (!UpdateTiles(
794                left, top, left, bottom, queue, NULL, &updated) ||
795            updated)
796          return updated;
797      }
798    }
799    if (deltas[i].x() > 0) {
800      while (right < prepaint_right) {
801        ++right;
802        if (!UpdateTiles(
803                right, top, right, bottom, queue, NULL, &updated) ||
804            updated)
805          return updated;
806      }
807    }
808  }
809  return updated;
810}
811
812void TiledLayer::OnOutputSurfaceCreated() {
813  // Ensure that all textures are of the right format.
814  for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
815       iter != tiler_->tiles().end();
816       ++iter) {
817    UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
818    if (!tile)
819      continue;
820    PrioritizedResource* resource = tile->managed_resource();
821    resource->SetDimensions(resource->size(), texture_format_);
822  }
823}
824
825bool TiledLayer::NeedsIdlePaint() {
826  // Don't trigger more paints if we failed (as we'll just fail again).
827  if (failed_update_ || visible_content_rect().IsEmpty() ||
828      tiler_->has_empty_bounds() || !DrawsContent())
829    return false;
830
831  gfx::Rect idle_paint_content_rect = IdlePaintRect();
832  if (idle_paint_content_rect.IsEmpty())
833    return false;
834
835  int left, top, right, bottom;
836  tiler_->ContentRectToTileIndices(
837      idle_paint_content_rect, &left, &top, &right, &bottom);
838
839  for (int j = top; j <= bottom; ++j) {
840    for (int i = left; i <= right; ++i) {
841      UpdatableTile* tile = TileAt(i, j);
842      DCHECK(tile);  // Did SetTexturePriorities get skipped?
843      if (!tile)
844        continue;
845
846      bool updated = !tile->update_rect.IsEmpty();
847      bool can_acquire =
848          tile->managed_resource()->can_acquire_backing_texture();
849      bool dirty =
850          tile->is_dirty() || !tile->managed_resource()->have_backing_texture();
851      if (!updated && can_acquire && dirty)
852        return true;
853    }
854  }
855  return false;
856}
857
858gfx::Rect TiledLayer::IdlePaintRect() {
859  // Don't inflate an empty rect.
860  if (visible_content_rect().IsEmpty())
861    return gfx::Rect();
862
863  gfx::Rect prepaint_rect = visible_content_rect();
864  prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
865                      -tiler_->tile_size().height() * kPrepaintRows);
866  gfx::Rect content_rect(content_bounds());
867  prepaint_rect.Intersect(content_rect);
868
869  return prepaint_rect;
870}
871
872}  // namespace cc
873