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 |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 DCHECK(!cur_record_rect.IsEmpty()); | 99 DCHECK(!cur_record_rect.IsEmpty()); |
100 clustered_rects->push_back(cur_record_rect); | 100 clustered_rects->push_back(cur_record_rect); |
101 total_record_area += cluster_record_area;; | 101 total_record_area += cluster_record_area;; |
102 | 102 |
103 DCHECK_NE(total_record_area, 0); | 103 DCHECK_NE(total_record_area, 0); |
104 | 104 |
105 return static_cast<float>(total_invalid_area) / | 105 return static_cast<float>(total_invalid_area) / |
106 static_cast<float>(total_record_area); | 106 static_cast<float>(total_record_area); |
107 } | 107 } |
108 | 108 |
109 float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, | 109 void ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, |
110 std::vector<gfx::Rect>* record_rects) { | 110 std::vector<gfx::Rect>* record_rects) { |
111 TRACE_EVENT1("cc", "ClusterTiles", | 111 TRACE_EVENT1("cc", "ClusterTiles", |
112 "count", | 112 "count", |
113 invalid_tiles.size()); | 113 invalid_tiles.size()); |
114 | |
115 if (invalid_tiles.size() <= 1) { | 114 if (invalid_tiles.size() <= 1) { |
116 // Quickly handle the special case for common | 115 // Quickly handle the special case for common |
117 // single-invalidation update, and also the less common | 116 // single-invalidation update, and also the less common |
118 // case of no tiles passed in. | 117 // case of no tiles passed in. |
119 *record_rects = invalid_tiles; | 118 *record_rects = invalid_tiles; |
120 return 1; | 119 return; |
121 } | 120 } |
122 | 121 |
123 // Sort the invalid tiles by y coordinate. | 122 // Sort the invalid tiles by y coordinate. |
124 std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; | 123 std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; |
125 std::sort(invalid_tiles_vertical.begin(), | 124 std::sort(invalid_tiles_vertical.begin(), |
126 invalid_tiles_vertical.end(), | 125 invalid_tiles_vertical.end(), |
127 rect_sort_y); | 126 rect_sort_y); |
128 | 127 |
129 float vertical_density; | |
130 std::vector<gfx::Rect> vertical_clustering; | 128 std::vector<gfx::Rect> vertical_clustering; |
131 vertical_density = PerformClustering(invalid_tiles_vertical, | 129 float vertical_density = |
132 &vertical_clustering); | 130 PerformClustering(invalid_tiles_vertical, &vertical_clustering); |
133 | 131 |
134 // If vertical density is optimal, then we can return early. | 132 // If vertical density is optimal, then we can return early. |
135 if (vertical_density == 1.f) { | 133 if (vertical_density == 1.f) { |
136 *record_rects = vertical_clustering; | 134 *record_rects = vertical_clustering; |
137 return vertical_density; | 135 return; |
138 } | 136 } |
139 | 137 |
140 // Now try again with a horizontal sort, see which one is best | 138 // Now try again with a horizontal sort, see which one is best |
141 std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; | 139 std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; |
142 std::sort(invalid_tiles_horizontal.begin(), | 140 std::sort(invalid_tiles_horizontal.begin(), |
143 invalid_tiles_horizontal.end(), | 141 invalid_tiles_horizontal.end(), |
144 rect_sort_x); | 142 rect_sort_x); |
145 | 143 |
146 float horizontal_density; | |
147 std::vector<gfx::Rect> horizontal_clustering; | 144 std::vector<gfx::Rect> horizontal_clustering; |
148 horizontal_density = PerformClustering(invalid_tiles_horizontal, | 145 float horizontal_density = |
149 &horizontal_clustering); | 146 PerformClustering(invalid_tiles_horizontal, &horizontal_clustering); |
150 | 147 |
151 if (vertical_density < horizontal_density) { | 148 if (vertical_density < horizontal_density) { |
152 *record_rects = horizontal_clustering; | 149 *record_rects = horizontal_clustering; |
153 return horizontal_density; | 150 return; |
154 } | 151 } |
155 | 152 |
156 *record_rects = vertical_clustering; | 153 *record_rects = vertical_clustering; |
157 return vertical_density; | |
158 } | 154 } |
159 | 155 |
160 } // namespace | 156 } // namespace |
161 | 157 |
162 namespace cc { | 158 namespace cc { |
163 | 159 |
164 PicturePile::PicturePile() | 160 PicturePile::PicturePile() |
165 : min_contents_scale_(0), | 161 : min_contents_scale_(0), |
166 slow_down_raster_scale_factor_for_debug_(0), | 162 slow_down_raster_scale_factor_for_debug_(0), |
167 can_use_lcd_text_(true), | 163 can_use_lcd_text_(true), |
(...skipping 15 matching lines...) Expand all Loading... |
183 ContentLayerClient* painter, | 179 ContentLayerClient* painter, |
184 Region* invalidation, | 180 Region* invalidation, |
185 bool can_use_lcd_text, | 181 bool can_use_lcd_text, |
186 const gfx::Size& layer_size, | 182 const gfx::Size& layer_size, |
187 const gfx::Rect& visible_layer_rect, | 183 const gfx::Rect& visible_layer_rect, |
188 int frame_number, | 184 int frame_number, |
189 Picture::RecordingMode recording_mode) { | 185 Picture::RecordingMode recording_mode) { |
190 bool can_use_lcd_text_changed = can_use_lcd_text_ != can_use_lcd_text; | 186 bool can_use_lcd_text_changed = can_use_lcd_text_ != can_use_lcd_text; |
191 can_use_lcd_text_ = can_use_lcd_text; | 187 can_use_lcd_text_ = can_use_lcd_text; |
192 | 188 |
| 189 gfx::Rect interest_rect = visible_layer_rect; |
| 190 interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); |
| 191 recorded_viewport_ = interest_rect; |
| 192 recorded_viewport_.Intersect(gfx::Rect(layer_size)); |
| 193 |
| 194 bool updated = |
| 195 ApplyInvalidationAndResize(interest_rect, invalidation, layer_size, |
| 196 frame_number, can_use_lcd_text_changed); |
| 197 std::vector<gfx::Rect> invalid_tiles; |
| 198 GetInvalidTileRects(interest_rect, invalidation, visible_layer_rect, |
| 199 frame_number, &invalid_tiles); |
| 200 std::vector<gfx::Rect> record_rects; |
| 201 ClusterTiles(invalid_tiles, &record_rects); |
| 202 |
| 203 if (record_rects.empty()) |
| 204 return updated; |
| 205 |
| 206 CreatePictures(painter, recording_mode, record_rects); |
| 207 |
| 208 DetermineIfSolidColor(); |
| 209 |
| 210 has_any_recordings_ = true; |
| 211 DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); |
| 212 return true; |
| 213 } |
| 214 |
| 215 bool PicturePile::ApplyInvalidationAndResize(const gfx::Rect& interest_rect, |
| 216 Region* invalidation, |
| 217 const gfx::Size& layer_size, |
| 218 int frame_number, |
| 219 bool can_use_lcd_text_changed) { |
193 bool updated = false; | 220 bool updated = false; |
194 | 221 |
195 Region synthetic_invalidation; | 222 Region synthetic_invalidation; |
196 gfx::Size old_tiling_size = GetSize(); | 223 gfx::Size old_tiling_size = GetSize(); |
197 if (old_tiling_size != layer_size) { | 224 if (old_tiling_size != layer_size) { |
198 tiling_.SetTilingSize(layer_size); | 225 tiling_.SetTilingSize(layer_size); |
199 updated = true; | 226 updated = true; |
200 } | 227 } |
201 if (can_use_lcd_text_changed) { | 228 if (can_use_lcd_text_changed) { |
202 // When LCD text is enabled/disabled, we must drop any raster tiles for | 229 // When LCD text is enabled/disabled, we must drop any raster tiles for |
203 // the pile, so they can be recreated in a manner consistent with the new | 230 // the pile, so they can be recreated in a manner consistent with the new |
204 // setting. We do this with |synthetic_invalidation| since we don't need to | 231 // setting. We do this with |synthetic_invalidation| since we don't need to |
205 // do a new recording, just invalidate rastered content. | 232 // do a new recording, just invalidate rastered content. |
206 synthetic_invalidation.Union(gfx::Rect(GetSize())); | 233 synthetic_invalidation.Union(gfx::Rect(GetSize())); |
207 updated = true; | 234 updated = true; |
208 } | 235 } |
209 | 236 |
210 gfx::Rect interest_rect = visible_layer_rect; | |
211 interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_); | |
212 recorded_viewport_ = interest_rect; | |
213 recorded_viewport_.Intersect(gfx::Rect(GetSize())); | |
214 | |
215 gfx::Rect interest_rect_over_tiles = | 237 gfx::Rect interest_rect_over_tiles = |
216 tiling_.ExpandRectToTileBounds(interest_rect); | 238 tiling_.ExpandRectToTileBounds(interest_rect); |
217 | 239 |
218 gfx::Size min_tiling_size( | 240 if (old_tiling_size != layer_size) { |
219 std::min(GetSize().width(), old_tiling_size.width()), | 241 gfx::Size min_tiling_size( |
220 std::min(GetSize().height(), old_tiling_size.height())); | 242 std::min(GetSize().width(), old_tiling_size.width()), |
221 gfx::Size max_tiling_size( | 243 std::min(GetSize().height(), old_tiling_size.height())); |
222 std::max(GetSize().width(), old_tiling_size.width()), | 244 gfx::Size max_tiling_size( |
223 std::max(GetSize().height(), old_tiling_size.height())); | 245 std::max(GetSize().width(), old_tiling_size.width()), |
| 246 std::max(GetSize().height(), old_tiling_size.height())); |
224 | 247 |
225 if (old_tiling_size != layer_size) { | |
226 has_any_recordings_ = false; | 248 has_any_recordings_ = false; |
227 | 249 |
228 // Drop recordings that are outside the new or old layer bounds or that | 250 // Drop recordings that are outside the new or old layer bounds or that |
229 // changed size. Newly exposed areas are considered invalidated. | 251 // changed size. Newly exposed areas are considered invalidated. |
230 // Previously exposed areas that are now outside of bounds also need to | 252 // Previously exposed areas that are now outside of bounds also need to |
231 // be invalidated, as they may become part of raster when scale < 1. | 253 // be invalidated, as they may become part of raster when scale < 1. |
232 std::vector<PictureMapKey> to_erase; | 254 std::vector<PictureMapKey> to_erase; |
233 int min_toss_x = tiling_.num_tiles_x(); | 255 int min_toss_x = tiling_.num_tiles_x(); |
234 if (max_tiling_size.width() > min_tiling_size.width()) { | 256 if (max_tiling_size.width() > min_tiling_size.width()) { |
235 min_toss_x = | 257 min_toss_x = |
236 tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width()); | 258 tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width()); |
237 } | 259 } |
238 int min_toss_y = tiling_.num_tiles_y(); | 260 int min_toss_y = tiling_.num_tiles_y(); |
239 if (max_tiling_size.height() > min_tiling_size.height()) { | 261 if (max_tiling_size.height() > min_tiling_size.height()) { |
240 min_toss_y = | 262 min_toss_y = |
241 tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); | 263 tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height()); |
242 } | 264 } |
243 for (PictureMap::const_iterator it = picture_map_.begin(); | 265 for (const auto& key_picture_pair : picture_map_) { |
244 it != picture_map_.end(); | 266 const PictureMapKey& key = key_picture_pair.first; |
245 ++it) { | |
246 const PictureMapKey& key = it->first; | |
247 if (key.first < min_toss_x && key.second < min_toss_y) { | 267 if (key.first < min_toss_x && key.second < min_toss_y) { |
248 has_any_recordings_ |= !!it->second.GetPicture(); | 268 has_any_recordings_ |= !!key_picture_pair.second.GetPicture(); |
249 continue; | 269 continue; |
250 } | 270 } |
251 to_erase.push_back(key); | 271 to_erase.push_back(key); |
252 } | 272 } |
253 | 273 |
254 for (size_t i = 0; i < to_erase.size(); ++i) | 274 for (size_t i = 0; i < to_erase.size(); ++i) |
255 picture_map_.erase(to_erase[i]); | 275 picture_map_.erase(to_erase[i]); |
256 | 276 |
257 // If a recording is dropped and not re-recorded below, invalidate that | 277 // If a recording is dropped and not re-recorded below, invalidate that |
258 // full recording to cause any raster tiles that would use it to be | 278 // full recording to cause any raster tiles that would use it to be |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 DCHECK_IMPLIES(!tiling_.TileBounds(key.first, key.second) | 485 DCHECK_IMPLIES(!tiling_.TileBounds(key.first, key.second) |
466 .Intersects(interest_rect_over_tiles), | 486 .Intersects(interest_rect_over_tiles), |
467 invalidation_expanded_to_full_tiles.Contains( | 487 invalidation_expanded_to_full_tiles.Contains( |
468 tiling_.TileBounds(key.first, key.second))); | 488 tiling_.TileBounds(key.first, key.second))); |
469 } | 489 } |
470 } | 490 } |
471 invalidation->Union(invalidation_expanded_to_full_tiles); | 491 invalidation->Union(invalidation_expanded_to_full_tiles); |
472 } | 492 } |
473 | 493 |
474 invalidation->Union(synthetic_invalidation); | 494 invalidation->Union(synthetic_invalidation); |
| 495 return updated; |
| 496 } |
475 | 497 |
| 498 void PicturePile::GetInvalidTileRects(const gfx::Rect& interest_rect, |
| 499 Region* invalidation, |
| 500 const gfx::Rect& visible_layer_rect, |
| 501 int frame_number, |
| 502 std::vector<gfx::Rect>* invalid_tiles) { |
476 // Make a list of all invalid tiles; we will attempt to | 503 // Make a list of all invalid tiles; we will attempt to |
477 // cluster these into multiple invalidation regions. | 504 // cluster these into multiple invalidation regions. |
478 std::vector<gfx::Rect> invalid_tiles; | |
479 bool include_borders = true; | 505 bool include_borders = true; |
480 for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it; | 506 for (TilingData::Iterator it(&tiling_, interest_rect, include_borders); it; |
481 ++it) { | 507 ++it) { |
482 const PictureMapKey& key = it.index(); | 508 const PictureMapKey& key = it.index(); |
483 PictureInfo& info = picture_map_[key]; | 509 PictureInfo& info = picture_map_[key]; |
484 | 510 |
485 gfx::Rect rect = PaddedRect(key); | 511 gfx::Rect rect = PaddedRect(key); |
486 int distance_to_visible = | 512 int distance_to_visible = |
487 rect.ManhattanInternalDistance(visible_layer_rect); | 513 rect.ManhattanInternalDistance(visible_layer_rect); |
488 | 514 |
489 if (info.NeedsRecording(frame_number, distance_to_visible)) { | 515 if (info.NeedsRecording(frame_number, distance_to_visible)) { |
490 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); | 516 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); |
491 invalid_tiles.push_back(tile); | 517 invalid_tiles->push_back(tile); |
492 } else if (!info.GetPicture()) { | 518 } else if (!info.GetPicture()) { |
493 if (recorded_viewport_.Intersects(rect)) { | 519 if (recorded_viewport_.Intersects(rect)) { |
494 // Recorded viewport is just an optimization for a fully recorded | 520 // Recorded viewport is just an optimization for a fully recorded |
495 // interest rect. In this case, a tile in that rect has declined | 521 // interest rect. In this case, a tile in that rect has declined |
496 // to be recorded (probably due to frequent invalidations). | 522 // to be recorded (probably due to frequent invalidations). |
497 // TODO(enne): Shrink the recorded_viewport_ rather than clearing. | 523 // TODO(enne): Shrink the recorded_viewport_ rather than clearing. |
498 recorded_viewport_ = gfx::Rect(); | 524 recorded_viewport_ = gfx::Rect(); |
499 } | 525 } |
500 | 526 |
501 // If a tile in the interest rect is not recorded, the entire tile needs | 527 // If a tile in the interest rect is not recorded, the entire tile needs |
502 // to be considered invalid, so that we know not to keep around raster | 528 // to be considered invalid, so that we know not to keep around raster |
503 // tiles that intersect this recording tile. | 529 // tiles that intersect this recording tile. |
504 invalidation->Union(tiling_.TileBounds(it.index_x(), it.index_y())); | 530 invalidation->Union(tiling_.TileBounds(it.index_x(), it.index_y())); |
505 } | 531 } |
506 } | 532 } |
| 533 } |
507 | 534 |
508 std::vector<gfx::Rect> record_rects; | 535 void PicturePile::CreatePictures(ContentLayerClient* painter, |
509 ClusterTiles(invalid_tiles, &record_rects); | 536 Picture::RecordingMode recording_mode, |
510 | 537 const std::vector<gfx::Rect>& record_rects) { |
511 if (record_rects.empty()) | 538 for (const auto& record_rect : record_rects) { |
512 return updated; | 539 gfx::Rect padded_record_rect = PadRect(record_rect); |
513 | |
514 for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); | |
515 it != record_rects.end(); | |
516 it++) { | |
517 gfx::Rect record_rect = *it; | |
518 record_rect = PadRect(record_rect); | |
519 | 540 |
520 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | 541 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
521 scoped_refptr<Picture> picture; | 542 scoped_refptr<Picture> picture; |
522 | 543 |
523 // Note: Currently, gathering of pixel refs when using a single | 544 // Note: Currently, gathering of pixel refs when using a single |
524 // raster thread doesn't provide any benefit. This might change | 545 // raster thread doesn't provide any benefit. This might change |
525 // in the future but we avoid it for now to reduce the cost of | 546 // in the future but we avoid it for now to reduce the cost of |
526 // Picture::Create. | 547 // Picture::Create. |
527 bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1; | 548 bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1; |
528 | 549 |
529 { | 550 for (int i = 0; i < repeat_count; i++) { |
530 for (int i = 0; i < repeat_count; i++) { | 551 picture = Picture::Create(padded_record_rect, painter, tile_grid_info_, |
531 picture = Picture::Create(record_rect, | 552 gather_pixel_refs, recording_mode); |
532 painter, | 553 // Note the '&&' with previous is-suitable state. |
533 tile_grid_info_, | 554 // This means that once a picture-pile becomes unsuitable for gpu |
534 gather_pixel_refs, | 555 // rasterization due to some content, it will continue to be unsuitable |
535 recording_mode); | 556 // even if that content is replaced by gpu-friendly content. |
536 // Note the '&&' with previous is-suitable state. | 557 // This is an optimization to avoid iterating though all pictures in |
537 // This means that once a picture-pile becomes unsuitable for gpu | 558 // the pile after each invalidation. |
538 // rasterization due to some content, it will continue to be unsuitable | 559 is_suitable_for_gpu_rasterization_ &= |
539 // even if that content is replaced by gpu-friendly content. | 560 picture->IsSuitableForGpuRasterization(); |
540 // This is an optimization to avoid iterating though all pictures in | |
541 // the pile after each invalidation. | |
542 is_suitable_for_gpu_rasterization_ &= | |
543 picture->IsSuitableForGpuRasterization(); | |
544 } | |
545 } | 561 } |
546 | 562 |
547 bool found_tile_for_recorded_picture = false; | 563 bool found_tile_for_recorded_picture = false; |
548 | 564 |
549 bool include_borders = true; | 565 bool include_borders = true; |
550 for (TilingData::Iterator it(&tiling_, record_rect, include_borders); it; | 566 for (TilingData::Iterator it(&tiling_, padded_record_rect, include_borders); |
551 ++it) { | 567 it; ++it) { |
552 const PictureMapKey& key = it.index(); | 568 const PictureMapKey& key = it.index(); |
553 gfx::Rect tile = PaddedRect(key); | 569 gfx::Rect tile = PaddedRect(key); |
554 if (record_rect.Contains(tile)) { | 570 if (padded_record_rect.Contains(tile)) { |
555 PictureInfo& info = picture_map_[key]; | 571 PictureInfo& info = picture_map_[key]; |
556 info.SetPicture(picture); | 572 info.SetPicture(picture); |
557 found_tile_for_recorded_picture = true; | 573 found_tile_for_recorded_picture = true; |
558 } | 574 } |
559 } | 575 } |
560 DetermineIfSolidColor(); | |
561 DCHECK(found_tile_for_recorded_picture); | 576 DCHECK(found_tile_for_recorded_picture); |
562 } | 577 } |
563 | |
564 has_any_recordings_ = true; | |
565 DCHECK(CanRasterSlowTileCheck(recorded_viewport_)); | |
566 return true; | |
567 } | 578 } |
568 | 579 |
569 scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const { | 580 scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const { |
570 return scoped_refptr<RasterSource>( | 581 return scoped_refptr<RasterSource>( |
571 PicturePileImpl::CreateFromPicturePile(this)); | 582 PicturePileImpl::CreateFromPicturePile(this)); |
572 } | 583 } |
573 | 584 |
574 gfx::Size PicturePile::GetSize() const { | 585 gfx::Size PicturePile::GetSize() const { |
575 return tiling_.tiling_size(); | 586 return tiling_.tiling_size(); |
576 } | 587 } |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
752 const Picture* PicturePile::PictureInfo::GetPicture() const { | 763 const Picture* PicturePile::PictureInfo::GetPicture() const { |
753 return picture_.get(); | 764 return picture_.get(); |
754 } | 765 } |
755 | 766 |
756 float PicturePile::PictureInfo::GetInvalidationFrequency() const { | 767 float PicturePile::PictureInfo::GetInvalidationFrequency() const { |
757 return invalidation_history_.count() / | 768 return invalidation_history_.count() / |
758 static_cast<float>(INVALIDATION_FRAMES_TRACKED); | 769 static_cast<float>(INVALIDATION_FRAMES_TRACKED); |
759 } | 770 } |
760 | 771 |
761 } // namespace cc | 772 } // namespace cc |
OLD | NEW |