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:
Create(scoped_ptr<LayerUpdater::Resource> updater_resource)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
updater_resource()41 LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
managed_resource()42 PrioritizedResource* managed_resource() {
43 return updater_resource_->texture();
44 }
45
is_dirty() const46 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.
ResetUpdateState()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.
MarkForUpdate()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:
UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)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
TiledLayer()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
~TiledLayer()97 TiledLayer::~TiledLayer() {}
98
CreateLayerImpl(LayerTreeImpl * tree_impl)99 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
100 return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
101 }
102
UpdateTileSizeAndTilingOption()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
UpdateBounds()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
SetTileSize(const gfx::Size & size)160 void TiledLayer::SetTileSize(const gfx::Size& size) {
161 tiler_->SetTileSize(size);
162 }
163
SetBorderTexelOption(LayerTilingData::BorderTexelOption border_texel_option)164 void TiledLayer::SetBorderTexelOption(
165 LayerTilingData::BorderTexelOption border_texel_option) {
166 tiler_->SetBorderTexelOption(border_texel_option);
167 }
168
DrawsContent() const169 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
ReduceMemoryUsage()181 void TiledLayer::ReduceMemoryUsage() {
182 if (Updater())
183 Updater()->ReduceMemoryUsage();
184 }
185
SetIsMask(bool is_mask)186 void TiledLayer::SetIsMask(bool is_mask) {
187 set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
188 }
189
PushPropertiesTo(LayerImpl * layer)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
ResourceManager()239 PrioritizedResourceManager* TiledLayer::ResourceManager() {
240 if (!layer_tree_host())
241 return NULL;
242 return layer_tree_host()->contents_texture_manager();
243 }
244
ResourceAtForTesting(int i,int j) const245 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
SetLayerTreeHost(LayerTreeHost * host)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
TileAt(int i,int j) const270 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
271 return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
272 }
273
CreateTile(int i,int j)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
SetNeedsDisplayRect(const gfx::RectF & dirty_rect)293 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
294 InvalidateContentRect(LayerRectToContentRect(dirty_rect));
295 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
296 }
297
InvalidateContentRect(const gfx::Rect & content_rect)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.
TileOnlyNeedsPartialUpdate(UpdatableTile * tile)318 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
319 return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
320 tile->managed_resource()->have_backing_texture();
321 }
322
UpdateTiles(int left,int top,int right,int bottom,ResourceUpdateQueue * queue,const OcclusionTracker<Layer> * occlusion,bool * updated)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
MarkOcclusionsAndRequestTextures(int left,int top,int right,int bottom,const OcclusionTracker<Layer> * occlusion)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
HaveTexturesForTiles(int left,int top,int right,int bottom,bool ignore_occlusions)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
MarkTilesForUpdate(gfx::Rect * update_rect,gfx::Rect * paint_rect,int left,int top,int right,int bottom,bool ignore_occlusions)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
UpdateTileTextures(const gfx::Rect & update_rect,const gfx::Rect & paint_rect,int left,int top,int right,int bottom,ResourceUpdateQueue * queue,const OcclusionTracker<Layer> * occlusion)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.
IsSmallAnimatedLayer() const561 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.
SetPriorityForTexture(const gfx::Rect & visible_rect,const gfx::Rect & tile_rect,bool draws_to_root,bool is_small_animated_layer,PrioritizedResource * texture)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
SetTexturePriorities(const PriorityCalculator & priority_calc)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
VisibleContentOpaqueRegion() const644 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
ResetUpdateState()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 {
ExpandRectByDelta(const gfx::Rect & rect,const gfx::Vector2d & delta)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
UpdateScrollPrediction()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
Update(ResourceUpdateQueue * queue,const OcclusionTracker<Layer> * occlusion)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
OnOutputSurfaceCreated()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
NeedsIdlePaint()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
IdlePaintRect()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