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/debug/rendering_stats_instrumentation.h" | 12 #include "cc/debug/rendering_stats_instrumentation.h" |
13 #include "cc/resources/picture_pile_impl.h" | 13 #include "cc/resources/picture_pile_impl.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 // Layout pixel buffer around the visible layer rect to record. Any base | 16 // Layout pixel buffer around the visible layer rect to record. Any base |
17 // picture that intersects the visible layer rect expanded by this distance | 17 // picture that intersects the visible layer rect expanded by this distance |
18 // will be recorded. | 18 // will be recorded. |
19 const int kPixelDistanceToRecord = 8000; | 19 const int kPixelDistanceToRecord = 8000; |
| 20 |
| 21 // TODO(humper): The density threshold here is somewhat arbitrary; need a |
| 22 // way to set // this from the command line so we can write a benchmark |
| 23 // script and find a sweet spot. |
| 24 const float kDensityThreshold = 0.5f; |
| 25 |
| 26 bool rect_sort_y(const gfx::Rect &r1, const gfx::Rect &r2) { |
| 27 return r1.y() < r2.y() || (r1.y() == r2.y() && r1.x() < r2.x()); |
| 28 } |
| 29 |
| 30 bool rect_sort_x(const gfx::Rect &r1, const gfx::Rect &r2) { |
| 31 return r1.x() < r2.x() || (r1.x() == r2.x() && r1.y() < r2.y()); |
| 32 } |
| 33 |
| 34 float do_clustering(const std::vector<gfx::Rect>& tiles, |
| 35 std::vector<gfx::Rect>* clustered_rects) { |
| 36 // These variables track the record area and invalid area |
| 37 // for the entire clustering |
| 38 int total_record_area = 0; |
| 39 int total_invalid_area = 0; |
| 40 |
| 41 // These variables track the record area and invalid area |
| 42 // for the current cluster being constructed. |
| 43 gfx::Rect cur_record_rect; |
| 44 int cluster_record_area = 0, cluster_invalid_area = 0; |
| 45 |
| 46 for (std::vector<gfx::Rect>::const_iterator it = tiles.begin(); |
| 47 it != tiles.end(); |
| 48 it++) { |
| 49 gfx::Rect invalid_tile = *it; |
| 50 |
| 51 // For each tile, we consider adding the invalid tile to the |
| 52 // current record rectangle. Only add it if the amount of empty |
| 53 // space created is below a density threshold. |
| 54 int tile_area = invalid_tile.width() * invalid_tile.height(); |
| 55 |
| 56 gfx::Rect proposed_union = cur_record_rect; |
| 57 proposed_union.Union(invalid_tile); |
| 58 int proposed_area = proposed_union.width() * proposed_union.height(); |
| 59 float proposed_density = |
| 60 static_cast<float>(cluster_invalid_area + tile_area) / |
| 61 static_cast<float>(proposed_area); |
| 62 |
| 63 if (proposed_density >= kDensityThreshold) { |
| 64 // It's okay to add this invalid tile to the |
| 65 // current recording rectangle. |
| 66 cur_record_rect = proposed_union; |
| 67 cluster_record_area = proposed_area; |
| 68 cluster_invalid_area += tile_area; |
| 69 total_invalid_area += tile_area; |
| 70 } else { |
| 71 // Adding this invalid tile to the current recording rectangle |
| 72 // would exceed our badness threshold, so put the current rectangle |
| 73 // in the list of recording rects, and start a new one. |
| 74 clustered_rects->push_back(cur_record_rect); |
| 75 total_record_area += cluster_record_area; |
| 76 cur_record_rect = invalid_tile; |
| 77 cluster_invalid_area = tile_area; |
| 78 cluster_record_area = tile_area; |
| 79 } |
| 80 } |
| 81 |
| 82 DCHECK(!cur_record_rect.IsEmpty()); |
| 83 clustered_rects->push_back(cur_record_rect); |
| 84 total_record_area += cluster_record_area;; |
| 85 |
| 86 DCHECK_NE(total_record_area, 0); |
| 87 |
| 88 return static_cast<float>(total_invalid_area) / |
| 89 static_cast<float>(total_record_area); |
| 90 } |
| 91 |
| 92 float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, |
| 93 std::vector<gfx::Rect>* record_rects) { |
| 94 TRACE_EVENT1("cc", "ClusterTiles", |
| 95 "count", |
| 96 invalid_tiles.size()); |
| 97 |
| 98 if (invalid_tiles.size() <= 1) { |
| 99 // Quickly handle the special case for common |
| 100 // single-invalidation update, and also the less common |
| 101 // case of no tiles passed in. |
| 102 *record_rects = invalid_tiles; |
| 103 return 1; |
| 104 } |
| 105 |
| 106 // Sort the invalid tiles by y coordinate. |
| 107 std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; |
| 108 std::sort(invalid_tiles_vertical.begin(), |
| 109 invalid_tiles_vertical.end(), |
| 110 rect_sort_y); |
| 111 |
| 112 float vertical_density; |
| 113 std::vector<gfx::Rect> vertical_clustering; |
| 114 vertical_density = do_clustering(invalid_tiles_vertical, |
| 115 &vertical_clustering); |
| 116 |
| 117 // Now try again with a horizontal sort, see which one is best |
| 118 // TODO(humper): Heuristics for skipping this step? |
| 119 std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; |
| 120 std::sort(invalid_tiles_vertical.begin(), |
| 121 invalid_tiles_vertical.end(), |
| 122 rect_sort_x); |
| 123 |
| 124 float horizontal_density; |
| 125 std::vector<gfx::Rect> horizontal_clustering; |
| 126 horizontal_density = do_clustering(invalid_tiles_vertical, |
| 127 &horizontal_clustering); |
| 128 |
| 129 if (vertical_density < horizontal_density) { |
| 130 *record_rects = horizontal_clustering; |
| 131 return horizontal_density; |
| 132 } |
| 133 |
| 134 *record_rects = vertical_clustering; |
| 135 return vertical_density; |
| 136 } |
| 137 |
20 } // namespace | 138 } // namespace |
21 | 139 |
22 namespace cc { | 140 namespace cc { |
23 | 141 |
24 PicturePile::PicturePile() { | 142 PicturePile::PicturePile() { |
25 } | 143 } |
26 | 144 |
27 PicturePile::~PicturePile() { | 145 PicturePile::~PicturePile() { |
28 } | 146 } |
29 | 147 |
(...skipping 24 matching lines...) Expand all Loading... |
54 const PictureMapKey& key = iter.index(); | 172 const PictureMapKey& key = iter.index(); |
55 | 173 |
56 PictureMap::iterator picture_it = picture_map_.find(key); | 174 PictureMap::iterator picture_it = picture_map_.find(key); |
57 if (picture_it == picture_map_.end()) | 175 if (picture_it == picture_map_.end()) |
58 continue; | 176 continue; |
59 | 177 |
60 invalidated = picture_it->second.Invalidate() || invalidated; | 178 invalidated = picture_it->second.Invalidate() || invalidated; |
61 } | 179 } |
62 } | 180 } |
63 | 181 |
64 gfx::Rect record_rect; | 182 // Make a list of all invalid tiles; we will attempt to |
| 183 // cluster these into multiple invalidation regions. |
| 184 std::vector<gfx::Rect> invalid_tiles; |
| 185 |
65 for (TilingData::Iterator it(&tiling_, interest_rect); | 186 for (TilingData::Iterator it(&tiling_, interest_rect); |
66 it; ++it) { | 187 it; ++it) { |
67 const PictureMapKey& key = it.index(); | 188 const PictureMapKey& key = it.index(); |
68 const PictureInfo& info = picture_map_[key]; | 189 const PictureInfo& info = picture_map_[key]; |
69 if (!info.picture.get()) { | 190 if (!info.picture.get()) { |
70 gfx::Rect tile = PaddedRect(key); | 191 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); |
71 record_rect.Union(tile); | 192 invalid_tiles.push_back(tile); |
72 } | 193 } |
73 } | 194 } |
74 | 195 |
75 if (record_rect.IsEmpty()) { | 196 std::vector<gfx::Rect> record_rects; |
| 197 ClusterTiles(invalid_tiles, &record_rects); |
| 198 |
| 199 if (record_rects.empty()) { |
76 if (invalidated) | 200 if (invalidated) |
77 UpdateRecordedRegion(); | 201 UpdateRecordedRegion(); |
78 return invalidated; | 202 return invalidated; |
79 } | 203 } |
80 | 204 |
81 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | 205 for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); |
82 scoped_refptr<Picture> picture = Picture::Create(record_rect); | 206 it != record_rects.end(); |
| 207 it++) { |
| 208 gfx::Rect record_rect = *it; |
| 209 record_rect = PadRect(record_rect); |
83 | 210 |
84 { | 211 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
85 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( | 212 scoped_refptr<Picture> picture = Picture::Create(record_rect); |
86 std::numeric_limits<int64>::max()); | 213 |
87 for (int i = 0; i < repeat_count; i++) { | 214 { |
88 base::TimeTicks start_time = stats_instrumentation->StartRecording(); | 215 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( |
89 picture->Record(painter, tile_grid_info_); | 216 std::numeric_limits<int64>::max()); |
90 base::TimeDelta duration = | 217 for (int i = 0; i < repeat_count; i++) { |
91 stats_instrumentation->EndRecording(start_time); | 218 base::TimeTicks start_time = stats_instrumentation->StartRecording(); |
92 best_duration = std::min(duration, best_duration); | 219 picture->Record(painter, tile_grid_info_); |
| 220 base::TimeDelta duration = |
| 221 stats_instrumentation->EndRecording(start_time); |
| 222 best_duration = std::min(duration, best_duration); |
| 223 } |
| 224 int recorded_pixel_count = |
| 225 picture->LayerRect().width() * picture->LayerRect().height(); |
| 226 stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); |
| 227 if (num_raster_threads_ > 1) |
| 228 picture->GatherPixelRefs(tile_grid_info_); |
| 229 picture->CloneForDrawing(num_raster_threads_); |
93 } | 230 } |
94 int recorded_pixel_count = | |
95 picture->LayerRect().width() * picture->LayerRect().height(); | |
96 stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); | |
97 if (num_raster_threads_ > 1) | |
98 picture->GatherPixelRefs(tile_grid_info_); | |
99 picture->CloneForDrawing(num_raster_threads_); | |
100 } | |
101 | 231 |
102 for (TilingData::Iterator it(&tiling_, record_rect); | 232 for (TilingData::Iterator it(&tiling_, record_rect); |
103 it; ++it) { | 233 it; ++it) { |
104 const PictureMapKey& key = it.index(); | 234 const PictureMapKey& key = it.index(); |
105 gfx::Rect tile = PaddedRect(key); | 235 gfx::Rect tile = PaddedRect(key); |
106 if (record_rect.Contains(tile)) { | 236 if (record_rect.Contains(tile)) { |
107 PictureInfo& info = picture_map_[key]; | 237 PictureInfo& info = picture_map_[key]; |
108 info.picture = picture; | 238 info.picture = picture; |
| 239 } |
109 } | 240 } |
110 } | 241 } |
111 | 242 |
112 UpdateRecordedRegion(); | 243 UpdateRecordedRegion(); |
113 return true; | 244 return true; |
114 } | 245 } |
115 | 246 |
116 } // namespace cc | 247 } // namespace cc |
OLD | NEW |