| OLD | NEW |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "cc/resources/picture_pile.h" | 5 #include "cc/resources/picture_pile.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <limits> | 8 #include <limits> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "cc/base/region.h" | 11 #include "cc/base/region.h" |
| 12 #include "cc/resources/picture_pile_impl.h" | 12 #include "cc/resources/picture_pile_impl.h" |
| 13 #include "cc/resources/raster_worker_pool.h" | 13 #include "cc/resources/raster_worker_pool.h" |
| 14 #include "skia/ext/analysis_canvas.h" | 14 #include "skia/ext/analysis_canvas.h" |
| 15 | 15 |
| 16 namespace { | 16 namespace { |
| 17 // Layout pixel buffer around the visible layer rect to record. Any base | 17 // Layout pixel buffer around the visible layer rect to record. Any base |
| 18 // picture that intersects the visible layer rect expanded by this distance | 18 // picture that intersects the visible layer rect expanded by this distance |
| 19 // will be recorded. | 19 // will be recorded. |
| 20 const int kPixelDistanceToRecord = 8000; | 20 const int kPixelDistanceToRecord = 8000; |
| 21 // We don't perform solid color analysis on images that have more than 10 skia | 21 // We don't perform solid color analysis on images that have more than 10 skia |
| 22 // operations. | 22 // operations. |
| 23 const int kOpCountThatIsOkToAnalyze = 10; | 23 const int kOpCountThatIsOkToAnalyze = 10; |
| 24 | 24 |
| 25 // Dimensions of the tiles in this picture pile as well as the dimensions of |
| 26 // the base picture in each tile. |
| 27 const int kBasePictureSize = 512; |
| 28 const int kTileGridBorderPixels = 1; |
| 29 #ifdef NDEBUG |
| 30 const bool kDefaultClearCanvasSetting = false; |
| 31 #else |
| 32 const bool kDefaultClearCanvasSetting = true; |
| 33 #endif |
| 34 |
| 35 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value |
| 36 // between 0 and 1 meaning invalidation frequency between 0% and 100% that |
| 37 // indicates when to stop invalidating offscreen regions. |
| 38 // kFrequentInvalidationDistanceThreshold defines what it means to be |
| 39 // "offscreen" in terms of distance to visible in css pixels. |
| 40 const float kInvalidationFrequencyThreshold = 0.75f; |
| 41 const int kFrequentInvalidationDistanceThreshold = 512; |
| 42 |
| 25 // TODO(humper): The density threshold here is somewhat arbitrary; need a | 43 // TODO(humper): The density threshold here is somewhat arbitrary; need a |
| 26 // way to set // this from the command line so we can write a benchmark | 44 // way to set // this from the command line so we can write a benchmark |
| 27 // script and find a sweet spot. | 45 // script and find a sweet spot. |
| 28 const float kDensityThreshold = 0.5f; | 46 const float kDensityThreshold = 0.5f; |
| 29 | 47 |
| 30 bool rect_sort_y(const gfx::Rect& r1, const gfx::Rect& r2) { | 48 bool rect_sort_y(const gfx::Rect& r1, const gfx::Rect& r2) { |
| 31 return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); | 49 return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); |
| 32 } | 50 } |
| 33 | 51 |
| 34 bool rect_sort_x(const gfx::Rect& r1, const gfx::Rect& r2) { | 52 bool rect_sort_x(const gfx::Rect& r1, const gfx::Rect& r2) { |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 | 160 |
| 143 *record_rects = vertical_clustering; | 161 *record_rects = vertical_clustering; |
| 144 return vertical_density; | 162 return vertical_density; |
| 145 } | 163 } |
| 146 | 164 |
| 147 } // namespace | 165 } // namespace |
| 148 | 166 |
| 149 namespace cc { | 167 namespace cc { |
| 150 | 168 |
| 151 PicturePile::PicturePile() | 169 PicturePile::PicturePile() |
| 152 : is_suitable_for_gpu_rasterization_(true), | 170 : min_contents_scale_(0), |
| 153 pixel_record_distance_(kPixelDistanceToRecord) { | 171 slow_down_raster_scale_factor_for_debug_(0), |
| 172 contents_opaque_(false), |
| 173 contents_fill_bounds_completely_(false), |
| 174 clear_canvas_with_debug_color_(kDefaultClearCanvasSetting), |
| 175 has_any_recordings_(false), |
| 176 is_mask_(false), |
| 177 is_solid_color_(false), |
| 178 solid_color_(SK_ColorTRANSPARENT), |
| 179 pixel_record_distance_(kPixelDistanceToRecord), |
| 180 is_suitable_for_gpu_rasterization_(true) { |
| 181 tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize)); |
| 182 tile_grid_info_.fTileInterval.setEmpty(); |
| 183 tile_grid_info_.fMargin.setEmpty(); |
| 184 tile_grid_info_.fOffset.setZero(); |
| 154 } | 185 } |
| 155 | 186 |
| 156 PicturePile::~PicturePile() { | 187 PicturePile::~PicturePile() { |
| 157 } | 188 } |
| 158 | 189 |
| 159 bool PicturePile::UpdateAndExpandInvalidation( | 190 bool PicturePile::UpdateAndExpandInvalidation( |
| 160 ContentLayerClient* painter, | 191 ContentLayerClient* painter, |
| 161 Region* invalidation, | 192 Region* invalidation, |
| 162 SkColor background_color, | 193 SkColor background_color, |
| 163 bool contents_opaque, | 194 bool contents_opaque, |
| 164 bool contents_fill_bounds_completely, | 195 bool contents_fill_bounds_completely, |
| 165 const gfx::Size& layer_size, | 196 const gfx::Size& layer_size, |
| 166 const gfx::Rect& visible_layer_rect, | 197 const gfx::Rect& visible_layer_rect, |
| 167 int frame_number, | 198 int frame_number, |
| 168 Picture::RecordingMode recording_mode) { | 199 Picture::RecordingMode recording_mode) { |
| 169 background_color_ = background_color; | 200 background_color_ = background_color; |
| 170 contents_opaque_ = contents_opaque; | 201 contents_opaque_ = contents_opaque; |
| 171 contents_fill_bounds_completely_ = contents_fill_bounds_completely; | 202 contents_fill_bounds_completely_ = contents_fill_bounds_completely; |
| 172 | 203 |
| 173 bool updated = false; | 204 bool updated = false; |
| 174 | 205 |
| 175 Region resize_invalidation; | 206 Region resize_invalidation; |
| 176 gfx::Size old_tiling_size = tiling_size(); | 207 gfx::Size old_tiling_size = GetSize(); |
| 177 if (old_tiling_size != layer_size) { | 208 if (old_tiling_size != layer_size) { |
| 178 tiling_.SetTilingSize(layer_size); | 209 tiling_.SetTilingSize(layer_size); |
| 179 updated = true; | 210 updated = true; |
| 180 } | 211 } |
| 181 | 212 |
| 182 gfx::Rect interest_rect = visible_layer_rect; | 213 gfx::Rect interest_rect = visible_layer_rect; |
| 183 interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); | 214 interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); |
| 184 recorded_viewport_ = interest_rect; | 215 recorded_viewport_ = interest_rect; |
| 185 recorded_viewport_.Intersect(gfx::Rect(tiling_size())); | 216 recorded_viewport_.Intersect(gfx::Rect(GetSize())); |
| 186 | 217 |
| 187 gfx::Rect interest_rect_over_tiles = | 218 gfx::Rect interest_rect_over_tiles = |
| 188 tiling_.ExpandRectToTileBounds(interest_rect); | 219 tiling_.ExpandRectToTileBounds(interest_rect); |
| 189 | 220 |
| 190 gfx::Size min_tiling_size( | 221 gfx::Size min_tiling_size( |
| 191 std::min(tiling_size().width(), old_tiling_size.width()), | 222 std::min(GetSize().width(), old_tiling_size.width()), |
| 192 std::min(tiling_size().height(), old_tiling_size.height())); | 223 std::min(GetSize().height(), old_tiling_size.height())); |
| 193 gfx::Size max_tiling_size( | 224 gfx::Size max_tiling_size( |
| 194 std::max(tiling_size().width(), old_tiling_size.width()), | 225 std::max(GetSize().width(), old_tiling_size.width()), |
| 195 std::max(tiling_size().height(), old_tiling_size.height())); | 226 std::max(GetSize().height(), old_tiling_size.height())); |
| 196 | 227 |
| 197 if (old_tiling_size != layer_size) { | 228 if (old_tiling_size != layer_size) { |
| 198 has_any_recordings_ = false; | 229 has_any_recordings_ = false; |
| 199 | 230 |
| 200 // Drop recordings that are outside the new or old layer bounds or that | 231 // Drop recordings that are outside the new or old layer bounds or that |
| 201 // changed size. Newly exposed areas are considered invalidated. | 232 // changed size. Newly exposed areas are considered invalidated. |
| 202 // Previously exposed areas that are now outside of bounds also need to | 233 // Previously exposed areas that are now outside of bounds also need to |
| 203 // be invalidated, as they may become part of raster when scale < 1. | 234 // be invalidated, as they may become part of raster when scale < 1. |
| 204 std::vector<PictureMapKey> to_erase; | 235 std::vector<PictureMapKey> to_erase; |
| 205 int min_toss_x = tiling_.num_tiles_x(); | 236 int min_toss_x = tiling_.num_tiles_x(); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 381 resize_invalidation.Union(right_rect); | 412 resize_invalidation.Union(right_rect); |
| 382 resize_invalidation.Union(top_rect); | 413 resize_invalidation.Union(top_rect); |
| 383 resize_invalidation.Union(bottom_rect); | 414 resize_invalidation.Union(bottom_rect); |
| 384 resize_invalidation.Union(exposed_rect); | 415 resize_invalidation.Union(exposed_rect); |
| 385 } | 416 } |
| 386 } | 417 } |
| 387 | 418 |
| 388 // Detect cases where the full pile is invalidated, in this situation we | 419 // Detect cases where the full pile is invalidated, in this situation we |
| 389 // can just drop/invalidate everything. | 420 // can just drop/invalidate everything. |
| 390 if (invalidation->Contains(gfx::Rect(old_tiling_size)) || | 421 if (invalidation->Contains(gfx::Rect(old_tiling_size)) || |
| 391 invalidation->Contains(gfx::Rect(tiling_size()))) { | 422 invalidation->Contains(gfx::Rect(GetSize()))) { |
| 392 for (auto& it : picture_map_) | 423 for (auto& it : picture_map_) |
| 393 updated = it.second.Invalidate(frame_number) || updated; | 424 updated = it.second.Invalidate(frame_number) || updated; |
| 394 } else { | 425 } else { |
| 395 // Expand invalidation that is on tiles that aren't in the interest rect and | 426 // Expand invalidation that is on tiles that aren't in the interest rect and |
| 396 // will not be re-recorded below. These tiles are no longer valid and should | 427 // will not be re-recorded below. These tiles are no longer valid and should |
| 397 // be considerered fully invalid, so we can know to not keep around raster | 428 // be considerered fully invalid, so we can know to not keep around raster |
| 398 // tiles that intersect with these recording tiles. | 429 // tiles that intersect with these recording tiles. |
| 399 Region invalidation_expanded_to_full_tiles; | 430 Region invalidation_expanded_to_full_tiles; |
| 400 | 431 |
| 401 for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) { | 432 for (Region::Iterator i(*invalidation); i.has_rect(); i.next()) { |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 532 DetermineIfSolidColor(); | 563 DetermineIfSolidColor(); |
| 533 DCHECK(found_tile_for_recorded_picture); | 564 DCHECK(found_tile_for_recorded_picture); |
| 534 } | 565 } |
| 535 | 566 |
| 536 has_any_recordings_ = true; | 567 has_any_recordings_ = true; |
| 537 DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); | 568 DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); |
| 538 return true; | 569 return true; |
| 539 } | 570 } |
| 540 | 571 |
| 541 gfx::Size PicturePile::GetSize() const { | 572 gfx::Size PicturePile::GetSize() const { |
| 542 return tiling_size(); | 573 return tiling_.tiling_size(); |
| 543 } | 574 } |
| 544 | 575 |
| 545 void PicturePile::SetEmptyBounds() { | 576 void PicturePile::SetEmptyBounds() { |
| 546 tiling_.SetTilingSize(gfx::Size()); | 577 tiling_.SetTilingSize(gfx::Size()); |
| 547 Clear(); | 578 Clear(); |
| 548 } | 579 } |
| 549 | 580 |
| 550 void PicturePile::SetMinContentsScale(float min_contents_scale) { | 581 void PicturePile::SetMinContentsScale(float min_contents_scale) { |
| 551 PicturePileBase::SetMinContentsScale(min_contents_scale); | 582 DCHECK(min_contents_scale); |
| 583 if (min_contents_scale_ == min_contents_scale) |
| 584 return; |
| 585 |
| 586 // Picture contents are played back scaled. When the final contents scale is |
| 587 // less than 1 (i.e. low res), then multiple recorded pixels will be used |
| 588 // to raster one final pixel. To avoid splitting a final pixel across |
| 589 // pictures (which would result in incorrect rasterization due to blending), a |
| 590 // buffer margin is added so that any picture can be snapped to integral |
| 591 // final pixels. |
| 592 // |
| 593 // For example, if a 1/4 contents scale is used, then that would be 3 buffer |
| 594 // pixels, since that's the minimum number of pixels to add so that resulting |
| 595 // content can be snapped to a four pixel aligned grid. |
| 596 int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1); |
| 597 buffer_pixels = std::max(0, buffer_pixels); |
| 598 SetBufferPixels(buffer_pixels); |
| 599 min_contents_scale_ = min_contents_scale; |
| 600 } |
| 601 |
| 602 // static |
| 603 void PicturePile::ComputeTileGridInfo(const gfx::Size& tile_grid_size, |
| 604 SkTileGridFactory::TileGridInfo* info) { |
| 605 DCHECK(info); |
| 606 info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels, |
| 607 tile_grid_size.height() - 2 * kTileGridBorderPixels); |
| 608 DCHECK_GT(info->fTileInterval.width(), 0); |
| 609 DCHECK_GT(info->fTileInterval.height(), 0); |
| 610 info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels); |
| 611 // Offset the tile grid coordinate space to take into account the fact |
| 612 // that the top-most and left-most tiles do not have top and left borders |
| 613 // respectively. |
| 614 info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels); |
| 552 } | 615 } |
| 553 | 616 |
| 554 void PicturePile::SetTileGridSize(const gfx::Size& tile_grid_size) { | 617 void PicturePile::SetTileGridSize(const gfx::Size& tile_grid_size) { |
| 555 PicturePileBase::SetTileGridSize(tile_grid_size); | 618 ComputeTileGridInfo(tile_grid_size, &tile_grid_info_); |
| 556 } | 619 } |
| 557 | 620 |
| 558 void PicturePile::SetSlowdownRasterScaleFactor(int factor) { | 621 void PicturePile::SetSlowdownRasterScaleFactor(int factor) { |
| 559 slow_down_raster_scale_factor_for_debug_ = factor; | 622 slow_down_raster_scale_factor_for_debug_ = factor; |
| 560 } | 623 } |
| 561 | 624 |
| 562 void PicturePile::SetShowDebugPictureBorders(bool show) { | |
| 563 show_debug_picture_borders_ = show; | |
| 564 } | |
| 565 | |
| 566 void PicturePile::SetIsMask(bool is_mask) { | 625 void PicturePile::SetIsMask(bool is_mask) { |
| 567 set_is_mask(is_mask); | 626 is_mask_ = is_mask; |
| 568 } | 627 } |
| 569 | 628 |
| 570 void PicturePile::SetUnsuitableForGpuRasterizationForTesting() { | 629 void PicturePile::SetUnsuitableForGpuRasterizationForTesting() { |
| 571 is_suitable_for_gpu_rasterization_ = false; | 630 is_suitable_for_gpu_rasterization_ = false; |
| 572 } | 631 } |
| 573 | 632 |
| 574 bool PicturePile::IsSuitableForGpuRasterization() const { | 633 bool PicturePile::IsSuitableForGpuRasterization() const { |
| 575 return is_suitable_for_gpu_rasterization_; | 634 return is_suitable_for_gpu_rasterization_; |
| 576 } | 635 } |
| 577 | 636 |
| 578 scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const { | 637 scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const { |
| 579 return PicturePileImpl::CreateFromOther(this); | 638 return scoped_refptr<RasterSource>( |
| 639 PicturePileImpl::CreateFromPicturePile(this)); |
| 580 } | 640 } |
| 581 | 641 |
| 582 SkTileGridFactory::TileGridInfo PicturePile::GetTileGridInfoForTesting() const { | 642 SkTileGridFactory::TileGridInfo PicturePile::GetTileGridInfoForTesting() const { |
| 583 return PicturePileBase::GetTileGridInfoForTesting(); | 643 return tile_grid_info_; |
| 584 } | 644 } |
| 585 | 645 |
| 586 bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const { | 646 bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const { |
| 587 bool include_borders = false; | 647 bool include_borders = false; |
| 588 for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); | 648 for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders); |
| 589 tile_iter; ++tile_iter) { | 649 tile_iter; ++tile_iter) { |
| 590 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); | 650 PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index()); |
| 591 if (map_iter == picture_map_.end()) | 651 if (map_iter == picture_map_.end()) |
| 592 return false; | 652 return false; |
| 593 if (!map_iter->second.GetPicture()) | 653 if (!map_iter->second.GetPicture()) |
| (...skipping 27 matching lines...) Expand all Loading... |
| 621 if (it->second.GetPicture() != picture) | 681 if (it->second.GetPicture() != picture) |
| 622 return; | 682 return; |
| 623 } | 683 } |
| 624 skia::AnalysisCanvas canvas(recorded_viewport_.width(), | 684 skia::AnalysisCanvas canvas(recorded_viewport_.width(), |
| 625 recorded_viewport_.height()); | 685 recorded_viewport_.height()); |
| 626 canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y()); | 686 canvas.translate(-recorded_viewport_.x(), -recorded_viewport_.y()); |
| 627 picture->Raster(&canvas, nullptr, Region(), 1.0f); | 687 picture->Raster(&canvas, nullptr, Region(), 1.0f); |
| 628 is_solid_color_ = canvas.GetColorIfSolid(&solid_color_); | 688 is_solid_color_ = canvas.GetColorIfSolid(&solid_color_); |
| 629 } | 689 } |
| 630 | 690 |
| 691 gfx::Rect PicturePile::PaddedRect(const PictureMapKey& key) const { |
| 692 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); |
| 693 return PadRect(tile); |
| 694 } |
| 695 |
| 696 gfx::Rect PicturePile::PadRect(const gfx::Rect& rect) const { |
| 697 gfx::Rect padded_rect = rect; |
| 698 padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(), |
| 699 -buffer_pixels()); |
| 700 return padded_rect; |
| 701 } |
| 702 |
| 703 void PicturePile::Clear() { |
| 704 picture_map_.clear(); |
| 705 recorded_viewport_ = gfx::Rect(); |
| 706 has_any_recordings_ = false; |
| 707 is_solid_color_ = false; |
| 708 } |
| 709 |
| 710 PicturePile::PictureInfo::PictureInfo() : last_frame_number_(0) { |
| 711 } |
| 712 |
| 713 PicturePile::PictureInfo::~PictureInfo() { |
| 714 } |
| 715 |
| 716 void PicturePile::PictureInfo::AdvanceInvalidationHistory(int frame_number) { |
| 717 DCHECK_GE(frame_number, last_frame_number_); |
| 718 if (frame_number == last_frame_number_) |
| 719 return; |
| 720 |
| 721 invalidation_history_ <<= (frame_number - last_frame_number_); |
| 722 last_frame_number_ = frame_number; |
| 723 } |
| 724 |
| 725 bool PicturePile::PictureInfo::Invalidate(int frame_number) { |
| 726 AdvanceInvalidationHistory(frame_number); |
| 727 invalidation_history_.set(0); |
| 728 |
| 729 bool did_invalidate = !!picture_.get(); |
| 730 picture_ = NULL; |
| 731 return did_invalidate; |
| 732 } |
| 733 |
| 734 bool PicturePile::PictureInfo::NeedsRecording(int frame_number, |
| 735 int distance_to_visible) { |
| 736 AdvanceInvalidationHistory(frame_number); |
| 737 |
| 738 // We only need recording if we don't have a picture. Furthermore, we only |
| 739 // need a recording if we're within frequent invalidation distance threshold |
| 740 // or the invalidation is not frequent enough (below invalidation frequency |
| 741 // threshold). |
| 742 return !picture_.get() && |
| 743 ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) || |
| 744 (GetInvalidationFrequency() < kInvalidationFrequencyThreshold)); |
| 745 } |
| 746 |
| 747 void PicturePile::SetBufferPixels(int new_buffer_pixels) { |
| 748 if (new_buffer_pixels == buffer_pixels()) |
| 749 return; |
| 750 |
| 751 Clear(); |
| 752 tiling_.SetBorderTexels(new_buffer_pixels); |
| 753 } |
| 754 |
| 755 void PicturePile::PictureInfo::SetPicture(scoped_refptr<Picture> picture) { |
| 756 picture_ = picture; |
| 757 } |
| 758 |
| 759 const Picture* PicturePile::PictureInfo::GetPicture() const { |
| 760 return picture_.get(); |
| 761 } |
| 762 |
| 763 float PicturePile::PictureInfo::GetInvalidationFrequency() const { |
| 764 return invalidation_history_.count() / |
| 765 static_cast<float>(INVALIDATION_FRAMES_TRACKED); |
| 766 } |
| 767 |
| 631 } // namespace cc | 768 } // namespace cc |
| OLD | NEW |