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