Chromium Code Reviews| 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 kDensityTreshold = 0.5f; | |
|
enne (OOO)
2013/11/21 21:55:42
Typo
| |
| 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 TRACE_EVENT0("cc.debug", "do_clustering"); | |
|
enne (OOO)
2013/11/21 21:55:42
No need for two traces. You already have one in C
| |
| 37 | |
| 38 // These variables track the record area and invalid area | |
| 39 // for the entire clustering | |
| 40 int total_record_area = 0; | |
| 41 int total_invalid_area = 0; | |
| 42 | |
| 43 // These variables track the record area and invalid area | |
| 44 // for the current cluster being constructed. | |
| 45 gfx::Rect cur_record_rect; | |
| 46 int total_area = 0, invalid_area = 0; | |
|
enne (OOO)
2013/11/21 21:55:42
total_area vs. total_record_area are a little hard
| |
| 47 | |
| 48 for (std::vector<gfx::Rect>::const_iterator it = tiles.begin(); | |
| 49 it != tiles.end(); | |
| 50 it++) { | |
| 51 gfx::Rect invalid_tile = *it; | |
| 52 | |
| 53 // For each tile, we consider adding the invalid tile to the | |
| 54 // current record rectangle. Only add it if the amount of empty | |
| 55 // space created is below a density threshold. | |
| 56 int tile_area = invalid_tile.width() * invalid_tile.height(); | |
| 57 | |
| 58 gfx::Rect proposed_union = cur_record_rect; | |
| 59 proposed_union.Union(invalid_tile); | |
| 60 int proposed_area = proposed_union.width() * proposed_union.height(); | |
| 61 float proposed_density = | |
| 62 static_cast<float>(invalid_area + tile_area) / | |
| 63 static_cast<float>(proposed_area); | |
| 64 | |
| 65 if (proposed_density >= kDensityTreshold) { | |
| 66 // It's okay to add this invalid tile to the | |
| 67 // current recording rectangle. | |
| 68 cur_record_rect = proposed_union; | |
| 69 total_area = proposed_area; | |
| 70 invalid_area += tile_area; | |
| 71 total_invalid_area += tile_area; | |
| 72 } else { | |
| 73 // Adding this invalid tile to the current recording rectangle | |
| 74 // would exceed our badness threshold, so put the current rectangle | |
| 75 // in the list of recording rects, and start a new one. | |
| 76 clustered_rects->push_back(cur_record_rect); | |
| 77 total_record_area += total_area; | |
| 78 cur_record_rect = invalid_tile; | |
| 79 invalid_area = tile_area; | |
| 80 total_area = tile_area; | |
| 81 } | |
| 82 } | |
| 83 | |
| 84 if (!cur_record_rect.IsEmpty()) { | |
|
vmpstr
2013/11/21 20:57:36
Can this condition ever be false?
| |
| 85 clustered_rects->push_back(cur_record_rect); | |
| 86 total_record_area += total_area; | |
| 87 } | |
| 88 | |
| 89 if (total_record_area == 0) { | |
| 90 return 1; | |
|
enne (OOO)
2013/11/21 21:55:42
1 => 1.f
| |
| 91 } else { | |
|
vmpstr
2013/11/21 20:57:36
nit: no need for else
if (...)
return 1;
return
enne (OOO)
2013/11/21 21:55:42
It doesn't look like it can. Maybe that can just
| |
| 92 return static_cast<float>(total_invalid_area) / | |
| 93 static_cast<float>(total_record_area); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 float ClusterTiles(const std::vector<gfx::Rect>& invalid_tiles, | |
| 98 std::vector<gfx::Rect>* record_rects) { | |
| 99 TRACE_EVENT1("cc.debug", "ClusterTiles", | |
|
enne (OOO)
2013/11/21 21:55:42
cc.debug => cc, I think. cc.debug is usually more
| |
| 100 "number of tiles", | |
|
enne (OOO)
2013/11/21 21:55:42
Also, I don't think any trace events use spaces in
| |
| 101 invalid_tiles.size()); | |
| 102 | |
| 103 if (invalid_tiles.size() <= 1) { | |
| 104 // Quickly handle the special case for common | |
| 105 // single-invalidation update, and also the less common | |
| 106 // case of no tiles passed in. | |
| 107 *record_rects = invalid_tiles; | |
| 108 return 1; | |
| 109 } | |
| 110 | |
| 111 // Sort the invalid tiles by y coordinate. | |
| 112 std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; | |
| 113 std::sort(invalid_tiles_vertical.begin(), | |
| 114 invalid_tiles_vertical.end(), | |
| 115 rect_sort_y); | |
| 116 | |
| 117 float vertical_density; | |
| 118 std::vector<gfx::Rect> vertical_clustering; | |
| 119 vertical_density = do_clustering(invalid_tiles_vertical, | |
| 120 &vertical_clustering); | |
| 121 | |
| 122 // Now try again with a horizontal sort, see which one is best | |
| 123 // TODO(humper): Heuristics for skipping this step? | |
| 124 std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; | |
| 125 std::sort(invalid_tiles_vertical.begin(), | |
| 126 invalid_tiles_vertical.end(), | |
| 127 rect_sort_x); | |
| 128 | |
| 129 float horizontal_density; | |
| 130 std::vector<gfx::Rect> horizontal_clustering; | |
| 131 horizontal_density = do_clustering(invalid_tiles_vertical, | |
| 132 &horizontal_clustering); | |
| 133 | |
| 134 if (vertical_density < horizontal_density) { | |
| 135 *record_rects = horizontal_clustering; | |
| 136 return horizontal_density; | |
| 137 } else { | |
|
vmpstr
2013/11/21 20:57:36
Also technically no need for the else, but it kind
enne (OOO)
2013/11/21 21:55:42
It's against the Chromium style guide. "Don't use
| |
| 138 *record_rects = vertical_clustering; | |
| 139 return vertical_density; | |
| 140 } | |
| 141 } | |
| 142 | |
| 20 } // namespace | 143 } // namespace |
| 21 | 144 |
| 22 namespace cc { | 145 namespace cc { |
| 23 | 146 |
| 24 PicturePile::PicturePile() { | 147 PicturePile::PicturePile() { |
| 25 } | 148 } |
| 26 | 149 |
| 27 PicturePile::~PicturePile() { | 150 PicturePile::~PicturePile() { |
| 28 } | 151 } |
| 29 | 152 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 54 const PictureMapKey& key = iter.index(); | 177 const PictureMapKey& key = iter.index(); |
| 55 | 178 |
| 56 PictureMap::iterator picture_it = picture_map_.find(key); | 179 PictureMap::iterator picture_it = picture_map_.find(key); |
| 57 if (picture_it == picture_map_.end()) | 180 if (picture_it == picture_map_.end()) |
| 58 continue; | 181 continue; |
| 59 | 182 |
| 60 invalidated = picture_it->second.Invalidate() || invalidated; | 183 invalidated = picture_it->second.Invalidate() || invalidated; |
| 61 } | 184 } |
| 62 } | 185 } |
| 63 | 186 |
| 64 gfx::Rect record_rect; | 187 // Make a list of all invalid tiles; we will attempt to |
| 188 // cluster these into multiple invalidation regions. | |
| 189 std::vector<gfx::Rect> invalid_tiles; | |
| 190 | |
| 65 for (TilingData::Iterator it(&tiling_, interest_rect); | 191 for (TilingData::Iterator it(&tiling_, interest_rect); |
| 66 it; ++it) { | 192 it; ++it) { |
| 67 const PictureMapKey& key = it.index(); | 193 const PictureMapKey& key = it.index(); |
| 68 const PictureInfo& info = picture_map_[key]; | 194 const PictureInfo& info = picture_map_[key]; |
| 69 if (!info.picture.get()) { | 195 if (!info.picture.get()) { |
| 70 gfx::Rect tile = PaddedRect(key); | 196 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); |
| 71 record_rect.Union(tile); | 197 invalid_tiles.push_back(tile); |
| 72 } | 198 } |
| 73 } | 199 } |
| 74 | 200 |
| 75 if (record_rect.IsEmpty()) { | 201 std::vector<gfx::Rect> record_rects; |
| 202 ClusterTiles(invalid_tiles, &record_rects); | |
| 203 | |
| 204 if (record_rects.empty()) { | |
| 76 if (invalidated) | 205 if (invalidated) |
| 77 UpdateRecordedRegion(); | 206 UpdateRecordedRegion(); |
| 78 return invalidated; | 207 return invalidated; |
| 79 } | 208 } |
| 80 | 209 |
| 81 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | 210 for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); |
| 82 scoped_refptr<Picture> picture = Picture::Create(record_rect); | 211 it != record_rects.end(); |
| 212 it++) { | |
| 213 gfx::Rect record_rect = *it; | |
| 214 record_rect.Inset(-buffer_pixels(), -buffer_pixels(), | |
|
enne (OOO)
2013/11/21 21:55:42
Can you add a PaddedRect(gfx::Rect) function, call
| |
| 215 -buffer_pixels(), -buffer_pixels()); | |
| 83 | 216 |
| 84 { | 217 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
| 85 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( | 218 scoped_refptr<Picture> picture = Picture::Create(record_rect); |
| 86 std::numeric_limits<int64>::max()); | 219 |
| 87 for (int i = 0; i < repeat_count; i++) { | 220 { |
| 88 base::TimeTicks start_time = stats_instrumentation->StartRecording(); | 221 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( |
| 89 picture->Record(painter, tile_grid_info_); | 222 std::numeric_limits<int64>::max()); |
| 90 base::TimeDelta duration = | 223 for (int i = 0; i < repeat_count; i++) { |
| 91 stats_instrumentation->EndRecording(start_time); | 224 base::TimeTicks start_time = stats_instrumentation->StartRecording(); |
| 92 best_duration = std::min(duration, best_duration); | 225 picture->Record(painter, tile_grid_info_); |
| 226 base::TimeDelta duration = | |
| 227 stats_instrumentation->EndRecording(start_time); | |
| 228 best_duration = std::min(duration, best_duration); | |
| 229 } | |
| 230 int recorded_pixel_count = | |
| 231 picture->LayerRect().width() * picture->LayerRect().height(); | |
| 232 stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); | |
| 233 if (num_raster_threads_ > 1) | |
| 234 picture->GatherPixelRefs(tile_grid_info_); | |
| 235 picture->CloneForDrawing(num_raster_threads_); | |
| 93 } | 236 } |
| 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 | 237 |
| 102 for (TilingData::Iterator it(&tiling_, record_rect); | 238 for (TilingData::Iterator it(&tiling_, record_rect); |
| 103 it; ++it) { | 239 it; ++it) { |
| 104 const PictureMapKey& key = it.index(); | 240 const PictureMapKey& key = it.index(); |
| 105 gfx::Rect tile = PaddedRect(key); | 241 gfx::Rect tile = PaddedRect(key); |
| 106 if (record_rect.Contains(tile)) { | 242 if (record_rect.Contains(tile)) { |
| 107 PictureInfo& info = picture_map_[key]; | 243 PictureInfo& info = picture_map_[key]; |
| 108 info.picture = picture; | 244 info.picture = picture; |
| 245 } | |
| 109 } | 246 } |
| 110 } | 247 } |
| 111 | 248 |
| 112 UpdateRecordedRegion(); | 249 UpdateRecordedRegion(); |
| 113 return true; | 250 return true; |
| 114 } | 251 } |
| 115 | 252 |
| 116 } // namespace cc | 253 } // namespace cc |
| OLD | NEW |