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/debug/overdraw_metrics.h"
     14 #include "cc/layers/layer_impl.h"
     15 #include "cc/layers/tiled_layer_impl.h"
     16 #include "cc/resources/layer_updater.h"
     17 #include "cc/resources/prioritized_resource.h"
     18 #include "cc/resources/priority_calculator.h"
     19 #include "cc/trees/layer_tree_host.h"
     20 #include "third_party/khronos/GLES2/gl2.h"
     21 #include "ui/gfx/rect_conversions.h"
     22 
     23 namespace cc {
     24 
     25 // Maximum predictive expansion of the visible area.
     26 static const int kMaxPredictiveTilesCount = 2;
     27 
     28 // Number of rows/columns of tiles to pre-paint.
     29 // We should increase these further as all textures are
     30 // prioritized and we insure performance doesn't suffer.
     31 static const int kPrepaintRows = 4;
     32 static const int kPrepaintColumns = 2;
     33 
     34 class UpdatableTile : public LayerTilingData::Tile {
     35  public:
     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_(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 
     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::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 
    161 void TiledLayer::SetTileSize(gfx::Size size) { tiler_->SetTileSize(size); }
    162 
    163 void TiledLayer::SetBorderTexelOption(
    164     LayerTilingData::BorderTexelOption border_texel_option) {
    165   tiler_->SetBorderTexelOption(border_texel_option);
    166 }
    167 
    168 bool TiledLayer::DrawsContent() const {
    169   if (!ContentsScalingLayer::DrawsContent())
    170     return false;
    171 
    172   bool has_more_than_one_tile =
    173       tiler_->num_tiles_x() > 1 || tiler_->num_tiles_y() > 1;
    174   if (tiling_option_ == NEVER_TILE && has_more_than_one_tile)
    175     return false;
    176 
    177   return true;
    178 }
    179 
    180 void TiledLayer::ReduceMemoryUsage() {
    181   if (Updater())
    182     Updater()->ReduceMemoryUsage();
    183 }
    184 
    185 void TiledLayer::SetIsMask(bool is_mask) {
    186   set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
    187 }
    188 
    189 void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
    190   ContentsScalingLayer::PushPropertiesTo(layer);
    191 
    192   TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
    193 
    194   tiled_layer->set_skips_draw(skips_draw_);
    195   tiled_layer->SetTilingData(*tiler_);
    196   std::vector<UpdatableTile*> invalid_tiles;
    197 
    198   for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
    199        iter != tiler_->tiles().end();
    200        ++iter) {
    201     int i = iter->first.first;
    202     int j = iter->first.second;
    203     UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
    204     // TODO(enne): This should not ever be null.
    205     if (!tile)
    206       continue;
    207 
    208     if (!tile->managed_resource()->have_backing_texture()) {
    209       // Evicted tiles get deleted from both layers
    210       invalid_tiles.push_back(tile);
    211       continue;
    212     }
    213 
    214     if (!tile->valid_for_frame) {
    215       // Invalidated tiles are set so they can get different debug colors.
    216       tiled_layer->PushInvalidTile(i, j);
    217       continue;
    218     }
    219 
    220     tiled_layer->PushTileProperties(
    221         i,
    222         j,
    223         tile->managed_resource()->resource_id(),
    224         tile->opaque_rect(),
    225         tile->managed_resource()->contents_swizzled());
    226   }
    227   for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
    228        iter != invalid_tiles.end();
    229        ++iter)
    230     tiler_->TakeTile((*iter)->i(), (*iter)->j());
    231 
    232   // TiledLayer must push properties every frame, since viewport state and
    233   // occlusion from anywhere in the tree can change what the layer decides to
    234   // push to the impl tree.
    235   needs_push_properties_ = true;
    236 }
    237 
    238 bool TiledLayer::BlocksPendingCommit() const { return true; }
    239 
    240 PrioritizedResourceManager* TiledLayer::ResourceManager() const {
    241   if (!layer_tree_host())
    242     return NULL;
    243   return layer_tree_host()->contents_texture_manager();
    244 }
    245 
    246 const 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 
    254 void 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 
    271 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
    272   return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
    273 }
    274 
    275 UpdatableTile* 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 
    294 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
    295   InvalidateContentRect(LayerRectToContentRect(dirty_rect));
    296   ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
    297 }
    298 
    299 void 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.
    319 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
    320   return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
    321          tile->managed_resource()->have_backing_texture();
    322 }
    323 
    324 bool 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 
    354 void TiledLayer::MarkOcclusionsAndRequestTextures(
    355     int left,
    356     int top,
    357     int right,
    358     int bottom,
    359     const OcclusionTracker* occlusion) {
    360   // There is some difficult dependancies between occlusions, recording
    361   // occlusion metrics and requesting memory so those are encapsulated in this
    362   // function: - We only want to call RequestLate on unoccluded textures (to
    363   // preserve memory for other layers when near OOM).  - We only want to record
    364   // occlusion metrics if all memory requests succeed.
    365 
    366   int occluded_tile_count = 0;
    367   bool succeeded = true;
    368   for (int j = top; j <= bottom; ++j) {
    369     for (int i = left; i <= right; ++i) {
    370       UpdatableTile* tile = TileAt(i, j);
    371       DCHECK(tile);  // Did SetTexturePriorities get skipped?
    372       // TODO(enne): This should not ever be null.
    373       if (!tile)
    374         continue;
    375       // Did ResetUpdateState get skipped? Are we doing more than one occlusion
    376       // pass?
    377       DCHECK(!tile->occluded);
    378       gfx::Rect visible_tile_rect = gfx::IntersectRects(
    379           tiler_->tile_bounds(i, j), visible_content_rect());
    380       if (occlusion && occlusion->Occluded(render_target(),
    381                                            visible_tile_rect,
    382                                            draw_transform(),
    383                                            draw_transform_is_animating(),
    384                                            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 
    401 bool 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 
    430 gfx::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 
    470 void 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.
    577 bool 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 
    590 namespace {
    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.
    594 void 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 
    615 void 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 
    660 Region 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 
    668 void 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 
    684 namespace {
    685 gfx::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 
    694 void 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 
    730 bool 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 
    854 bool 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 
    887 gfx::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