1 // Copyright 2013 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/debug/rasterize_and_record_benchmark_impl.h" 6 7 #include <algorithm> 8 #include <limits> 9 10 #include "base/basictypes.h" 11 #include "base/values.h" 12 #include "cc/debug/lap_timer.h" 13 #include "cc/layers/layer_impl.h" 14 #include "cc/layers/picture_layer_impl.h" 15 #include "cc/resources/raster_worker_pool.h" 16 #include "cc/trees/layer_tree_host_common.h" 17 #include "cc/trees/layer_tree_host_impl.h" 18 #include "ui/gfx/rect.h" 19 20 namespace cc { 21 22 namespace { 23 24 const int kDefaultRasterizeRepeatCount = 100; 25 26 class BenchmarkRasterTask : public Task { 27 public: 28 BenchmarkRasterTask(PicturePileImpl* picture_pile, 29 const gfx::Rect& content_rect, 30 float contents_scale, 31 size_t repeat_count) 32 : picture_pile_(picture_pile), 33 content_rect_(content_rect), 34 contents_scale_(contents_scale), 35 repeat_count_(repeat_count), 36 is_solid_color_(false), 37 best_time_(base::TimeDelta::Max()) {} 38 39 // Overridden from Task: 40 virtual void RunOnWorkerThread() OVERRIDE { 41 // Parameters for LapTimer. 42 const int kTimeLimitMillis = 1; 43 const int kWarmupRuns = 0; 44 const int kTimeCheckInterval = 1; 45 46 for (size_t i = 0; i < repeat_count_; ++i) { 47 // Run for a minimum amount of time to avoid problems with timer 48 // quantization when the layer is very small. 49 LapTimer timer(kWarmupRuns, 50 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), 51 kTimeCheckInterval); 52 do { 53 SkBitmap bitmap; 54 bitmap.allocPixels(SkImageInfo::MakeN32Premul(content_rect_.width(), 55 content_rect_.height())); 56 SkCanvas canvas(bitmap); 57 PicturePileImpl::Analysis analysis; 58 59 picture_pile_->AnalyzeInRect( 60 content_rect_, contents_scale_, &analysis, NULL); 61 picture_pile_->RasterToBitmap( 62 &canvas, content_rect_, contents_scale_, NULL); 63 64 is_solid_color_ = analysis.is_solid_color; 65 66 timer.NextLap(); 67 } while (!timer.HasTimeLimitExpired()); 68 base::TimeDelta duration = 69 base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); 70 if (duration < best_time_) 71 best_time_ = duration; 72 } 73 } 74 75 bool IsSolidColor() const { return is_solid_color_; } 76 base::TimeDelta GetBestTime() const { return best_time_; } 77 78 private: 79 virtual ~BenchmarkRasterTask() {} 80 81 PicturePileImpl* picture_pile_; 82 gfx::Rect content_rect_; 83 float contents_scale_; 84 size_t repeat_count_; 85 bool is_solid_color_; 86 base::TimeDelta best_time_; 87 }; 88 89 class FixedInvalidationPictureLayerTilingClient 90 : public PictureLayerTilingClient { 91 public: 92 FixedInvalidationPictureLayerTilingClient( 93 PictureLayerTilingClient* base_client, 94 const Region invalidation) 95 : base_client_(base_client), invalidation_(invalidation) {} 96 97 virtual scoped_refptr<Tile> CreateTile( 98 PictureLayerTiling* tiling, 99 const gfx::Rect& content_rect) OVERRIDE { 100 return base_client_->CreateTile(tiling, content_rect); 101 } 102 103 virtual PicturePileImpl* GetPile() OVERRIDE { 104 return base_client_->GetPile(); 105 } 106 107 virtual gfx::Size CalculateTileSize( 108 const gfx::Size& content_bounds) const OVERRIDE { 109 return base_client_->CalculateTileSize(content_bounds); 110 } 111 112 // This is the only function that returns something different from the base 113 // client. 114 virtual const Region* GetInvalidation() OVERRIDE { return &invalidation_; } 115 116 virtual const PictureLayerTiling* GetTwinTiling( 117 const PictureLayerTiling* tiling) const OVERRIDE { 118 return base_client_->GetTwinTiling(tiling); 119 } 120 121 virtual PictureLayerTiling* GetRecycledTwinTiling( 122 const PictureLayerTiling* tiling) OVERRIDE { 123 return base_client_->GetRecycledTwinTiling(tiling); 124 } 125 126 virtual size_t GetMaxTilesForInterestArea() const OVERRIDE { 127 return base_client_->GetMaxTilesForInterestArea(); 128 } 129 130 virtual float GetSkewportTargetTimeInSeconds() const OVERRIDE { 131 return base_client_->GetSkewportTargetTimeInSeconds(); 132 } 133 134 virtual int GetSkewportExtrapolationLimitInContentPixels() const OVERRIDE { 135 return base_client_->GetSkewportExtrapolationLimitInContentPixels(); 136 } 137 138 virtual WhichTree GetTree() const OVERRIDE { return base_client_->GetTree(); } 139 140 private: 141 PictureLayerTilingClient* base_client_; 142 Region invalidation_; 143 }; 144 145 } // namespace 146 147 RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl( 148 scoped_refptr<base::MessageLoopProxy> origin_loop, 149 base::Value* value, 150 const MicroBenchmarkImpl::DoneCallback& callback) 151 : MicroBenchmarkImpl(callback, origin_loop), 152 rasterize_repeat_count_(kDefaultRasterizeRepeatCount) { 153 base::DictionaryValue* settings = NULL; 154 value->GetAsDictionary(&settings); 155 if (!settings) 156 return; 157 158 if (settings->HasKey("rasterize_repeat_count")) 159 settings->GetInteger("rasterize_repeat_count", &rasterize_repeat_count_); 160 } 161 162 RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {} 163 164 void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit( 165 LayerTreeHostImpl* host) { 166 LayerTreeHostCommon::CallFunctionForSubtree( 167 host->RootLayer(), 168 base::Bind(&RasterizeAndRecordBenchmarkImpl::Run, 169 base::Unretained(this))); 170 171 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 172 result->SetDouble("rasterize_time_ms", 173 rasterize_results_.total_best_time.InMillisecondsF()); 174 result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized); 175 result->SetInteger("pixels_rasterized_with_non_solid_color", 176 rasterize_results_.pixels_rasterized_with_non_solid_color); 177 result->SetInteger("pixels_rasterized_as_opaque", 178 rasterize_results_.pixels_rasterized_as_opaque); 179 result->SetInteger("total_layers", rasterize_results_.total_layers); 180 result->SetInteger("total_picture_layers", 181 rasterize_results_.total_picture_layers); 182 result->SetInteger("total_picture_layers_with_no_content", 183 rasterize_results_.total_picture_layers_with_no_content); 184 result->SetInteger("total_picture_layers_off_screen", 185 rasterize_results_.total_picture_layers_off_screen); 186 187 NotifyDone(result.PassAs<base::Value>()); 188 } 189 190 void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) { 191 rasterize_results_.total_layers++; 192 layer->RunMicroBenchmark(this); 193 } 194 195 void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { 196 rasterize_results_.total_picture_layers++; 197 if (!layer->DrawsContent()) { 198 rasterize_results_.total_picture_layers_with_no_content++; 199 return; 200 } 201 if (layer->visible_content_rect().IsEmpty()) { 202 rasterize_results_.total_picture_layers_off_screen++; 203 return; 204 } 205 206 TaskGraphRunner* task_graph_runner = RasterWorkerPool::GetTaskGraphRunner(); 207 DCHECK(task_graph_runner); 208 209 if (!task_namespace_.IsValid()) 210 task_namespace_ = task_graph_runner->GetNamespaceToken(); 211 212 FixedInvalidationPictureLayerTilingClient client( 213 layer, gfx::Rect(layer->content_bounds())); 214 PictureLayerTilingSet tiling_set(&client, layer->content_bounds()); 215 216 PictureLayerTiling* tiling = tiling_set.AddTiling(layer->contents_scale_x()); 217 tiling->CreateAllTilesForTesting(); 218 for (PictureLayerTiling::CoverageIterator it( 219 tiling, layer->contents_scale_x(), layer->visible_content_rect()); 220 it; 221 ++it) { 222 DCHECK(*it); 223 224 PicturePileImpl* picture_pile = (*it)->picture_pile(); 225 gfx::Rect content_rect = (*it)->content_rect(); 226 float contents_scale = (*it)->contents_scale(); 227 228 scoped_refptr<BenchmarkRasterTask> benchmark_raster_task( 229 new BenchmarkRasterTask(picture_pile, 230 content_rect, 231 contents_scale, 232 rasterize_repeat_count_)); 233 234 TaskGraph graph; 235 236 graph.nodes.push_back( 237 TaskGraph::Node(benchmark_raster_task.get(), 238 RasterWorkerPool::kBenchmarkRasterTaskPriority, 239 0u)); 240 241 task_graph_runner->ScheduleTasks(task_namespace_, &graph); 242 task_graph_runner->WaitForTasksToFinishRunning(task_namespace_); 243 244 Task::Vector completed_tasks; 245 task_graph_runner->CollectCompletedTasks(task_namespace_, &completed_tasks); 246 DCHECK_EQ(1u, completed_tasks.size()); 247 DCHECK_EQ(completed_tasks[0], benchmark_raster_task); 248 249 int tile_size = content_rect.width() * content_rect.height(); 250 base::TimeDelta min_time = benchmark_raster_task->GetBestTime(); 251 bool is_solid_color = benchmark_raster_task->IsSolidColor(); 252 253 if (layer->contents_opaque()) 254 rasterize_results_.pixels_rasterized_as_opaque += tile_size; 255 256 if (!is_solid_color) { 257 rasterize_results_.pixels_rasterized_with_non_solid_color += tile_size; 258 } 259 260 rasterize_results_.pixels_rasterized += tile_size; 261 rasterize_results_.total_best_time += min_time; 262 } 263 } 264 265 RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults() 266 : pixels_rasterized(0), 267 pixels_rasterized_with_non_solid_color(0), 268 pixels_rasterized_as_opaque(0), 269 total_layers(0), 270 total_picture_layers(0), 271 total_picture_layers_with_no_content(0), 272 total_picture_layers_off_screen(0) {} 273 274 RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {} 275 276 } // namespace cc 277