Home | History | Annotate | Download | only in layers
      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 
     23 namespace cc {
     24 
     25 // Maximum predictive expansion of the visible area.
     26 static const int kMaxPredictiveTilesCount = 2;
     27 
     28 // Number of rows/columns of tiles to pre-paint.
     29 // We should increase these further as all textures are
     30 // prioritized and we insure performance doesn't suffer.
     31 static const int kPrepaintRows = 4;
     32 static const int kPrepaintColumns = 2;
     33 
     34 class UpdatableTile : public LayerTilingData::Tile {
     35  public:
     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 
     87 TiledLayer::TiledLayer()
     88     : ContentsScalingLayer(),
     89       texture_format_(RGBA_8888),
     90       skips_draw_(false),
     91       failed_update_(false),
     92       tiling_option_(AUTO_TILE) {
     93   tiler_ =
     94       LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
     95 }
     96 
     97 TiledLayer::~TiledLayer() {}
     98 
     99 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
    100   return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
    101 }
    102 
    103 void TiledLayer::UpdateTileSizeAndTilingOption() {
    104   DCHECK(layer_tree_host());
    105 
    106   gfx::Size default_tile_size = layer_tree_host()->settings().default_tile_size;
    107   gfx::Size max_untiled_layer_size =
    108       layer_tree_host()->settings().max_untiled_layer_size;
    109   int layer_width = content_bounds().width();
    110   int layer_height = content_bounds().height();
    111 
    112   gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
    113                       std::min(default_tile_size.height(), layer_height));
    114 
    115   // Tile if both dimensions large, or any one dimension large and the other
    116   // extends into a second tile but the total layer area isn't larger than that
    117   // of the largest possible untiled layer. This heuristic allows for long
    118   // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
    119   // texture space but still avoids creating very large tiles.
    120   bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
    121                              layer_height > max_untiled_layer_size.height();
    122   bool any_dimension_one_tile =
    123       (layer_width <= default_tile_size.width() ||
    124        layer_height <= default_tile_size.height()) &&
    125       (layer_width * layer_height) <= (max_untiled_layer_size.width() *
    126                                        max_untiled_layer_size.height());
    127   bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
    128 
    129   bool is_tiled;
    130   if (tiling_option_ == ALWAYS_TILE)
    131     is_tiled = true;
    132   else if (tiling_option_ == NEVER_TILE)
    133     is_tiled = false;
    134   else
    135     is_tiled = auto_tiled;
    136 
    137   gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
    138   const int max_size =
    139       layer_tree_host()->GetRendererCapabilities().max_texture_size;
    140   requested_size.SetToMin(gfx::Size(max_size, max_size));
    141   SetTileSize(requested_size);
    142 }
    143 
    144 void 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 
    160 void TiledLayer::SetTileSize(const gfx::Size& size) {
    161   tiler_->SetTileSize(size);
    162 }
    163 
    164 void TiledLayer::SetBorderTexelOption(
    165     LayerTilingData::BorderTexelOption border_texel_option) {
    166   tiler_->SetBorderTexelOption(border_texel_option);
    167 }
    168 
    169 bool 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 
    181 void TiledLayer::ReduceMemoryUsage() {
    182   if (Updater())
    183     Updater()->ReduceMemoryUsage();
    184 }
    185 
    186 void TiledLayer::SetIsMask(bool is_mask) {
    187   set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
    188 }
    189 
    190 void 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 
    239 PrioritizedResourceManager* TiledLayer::ResourceManager() {
    240   if (!layer_tree_host())
    241     return NULL;
    242   return layer_tree_host()->contents_texture_manager();
    243 }
    244 
    245 const 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 
    253 void 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 
    270 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
    271   return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
    272 }
    273 
    274 UpdatableTile* 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 
    293 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
    294   InvalidateContentRect(LayerRectToContentRect(dirty_rect));
    295   ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
    296 }
    297 
    298 void 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.
    318 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
    319   return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
    320          tile->managed_resource()->have_backing_texture();
    321 }
    322 
    323 bool 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 
    352 void 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 
    384 bool 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 
    413 void 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 
    457 void 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.
    561 bool 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 
    574 namespace {
    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.
    578 void 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 
    599 void 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 
    644 Region 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 
    652 void 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 
    668 namespace {
    669 gfx::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 
    678 void 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 
    714 bool 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 
    842 void 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 
    855 bool 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 
    888 gfx::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