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