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 23namespace cc { 24 25// Maximum predictive expansion of the visible area. 26static 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. 31static const int kPrepaintRows = 4; 32static const int kPrepaintColumns = 2; 33 34class 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 87TiledLayer::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 97TiledLayer::~TiledLayer() {} 98 99scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) { 100 return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>(); 101} 102 103void 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 144void 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 160void TiledLayer::SetTileSize(const gfx::Size& size) { 161 tiler_->SetTileSize(size); 162} 163 164void TiledLayer::SetBorderTexelOption( 165 LayerTilingData::BorderTexelOption border_texel_option) { 166 tiler_->SetBorderTexelOption(border_texel_option); 167} 168 169bool 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 181void TiledLayer::ReduceMemoryUsage() { 182 if (Updater()) 183 Updater()->ReduceMemoryUsage(); 184} 185 186void TiledLayer::SetIsMask(bool is_mask) { 187 set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE); 188} 189 190void 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 239PrioritizedResourceManager* TiledLayer::ResourceManager() { 240 if (!layer_tree_host()) 241 return NULL; 242 return layer_tree_host()->contents_texture_manager(); 243} 244 245const 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 253void 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 270UpdatableTile* TiledLayer::TileAt(int i, int j) const { 271 return static_cast<UpdatableTile*>(tiler_->TileAt(i, j)); 272} 273 274UpdatableTile* 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 293void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) { 294 InvalidateContentRect(LayerRectToContentRect(dirty_rect)); 295 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect); 296} 297 298void 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. 318bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) { 319 return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) && 320 tile->managed_resource()->have_backing_texture(); 321} 322 323bool 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 352void 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 384bool 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 413void 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 457void 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. 561bool 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 574namespace { 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. 578void 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 599void 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 644Region 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 652void 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 668namespace { 669gfx::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 678void 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 714bool 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 842void 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 855bool 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 888gfx::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