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 20namespace cc { 21 22namespace { 23 24const int kDefaultRasterizeRepeatCount = 100; 25 26class 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 PicturePileImpl* picture_pile = picture_pile_->GetCloneForDrawingOnThread( 42 RasterWorkerPool::GetPictureCloneIndexForCurrentThread()); 43 44 // Parameters for LapTimer. 45 const int kTimeLimitMillis = 1; 46 const int kWarmupRuns = 0; 47 const int kTimeCheckInterval = 1; 48 49 for (size_t i = 0; i < repeat_count_; ++i) { 50 // Run for a minimum amount of time to avoid problems with timer 51 // quantization when the layer is very small. 52 LapTimer timer(kWarmupRuns, 53 base::TimeDelta::FromMilliseconds(kTimeLimitMillis), 54 kTimeCheckInterval); 55 do { 56 SkBitmap bitmap; 57 bitmap.allocPixels(SkImageInfo::MakeN32Premul(content_rect_.width(), 58 content_rect_.height())); 59 SkCanvas canvas(bitmap); 60 PicturePileImpl::Analysis analysis; 61 62 picture_pile->AnalyzeInRect( 63 content_rect_, contents_scale_, &analysis, NULL); 64 picture_pile->RasterToBitmap( 65 &canvas, content_rect_, contents_scale_, NULL); 66 67 is_solid_color_ = analysis.is_solid_color; 68 69 timer.NextLap(); 70 } while (!timer.HasTimeLimitExpired()); 71 base::TimeDelta duration = 72 base::TimeDelta::FromMillisecondsD(timer.MsPerLap()); 73 if (duration < best_time_) 74 best_time_ = duration; 75 76 } 77 } 78 79 bool IsSolidColor() const { return is_solid_color_; } 80 base::TimeDelta GetBestTime() const { return best_time_; } 81 82 private: 83 virtual ~BenchmarkRasterTask() {} 84 85 PicturePileImpl* picture_pile_; 86 gfx::Rect content_rect_; 87 float contents_scale_; 88 size_t repeat_count_; 89 bool is_solid_color_; 90 base::TimeDelta best_time_; 91}; 92 93} // namespace 94 95RasterizeAndRecordBenchmarkImpl::RasterizeAndRecordBenchmarkImpl( 96 scoped_refptr<base::MessageLoopProxy> origin_loop, 97 base::Value* value, 98 const MicroBenchmarkImpl::DoneCallback& callback) 99 : MicroBenchmarkImpl(callback, origin_loop), 100 rasterize_repeat_count_(kDefaultRasterizeRepeatCount) { 101 base::DictionaryValue* settings = NULL; 102 value->GetAsDictionary(&settings); 103 if (!settings) 104 return; 105 106 if (settings->HasKey("rasterize_repeat_count")) 107 settings->GetInteger("rasterize_repeat_count", &rasterize_repeat_count_); 108} 109 110RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {} 111 112void RasterizeAndRecordBenchmarkImpl::DidCompleteCommit( 113 LayerTreeHostImpl* host) { 114 LayerTreeHostCommon::CallFunctionForSubtree( 115 host->RootLayer(), 116 base::Bind(&RasterizeAndRecordBenchmarkImpl::Run, 117 base::Unretained(this))); 118 119 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); 120 result->SetDouble("rasterize_time_ms", 121 rasterize_results_.total_best_time.InMillisecondsF()); 122 result->SetInteger("pixels_rasterized", rasterize_results_.pixels_rasterized); 123 result->SetInteger("pixels_rasterized_with_non_solid_color", 124 rasterize_results_.pixels_rasterized_with_non_solid_color); 125 result->SetInteger("pixels_rasterized_as_opaque", 126 rasterize_results_.pixels_rasterized_as_opaque); 127 result->SetInteger("total_layers", rasterize_results_.total_layers); 128 result->SetInteger("total_picture_layers", 129 rasterize_results_.total_picture_layers); 130 result->SetInteger("total_picture_layers_with_no_content", 131 rasterize_results_.total_picture_layers_with_no_content); 132 result->SetInteger("total_picture_layers_off_screen", 133 rasterize_results_.total_picture_layers_off_screen); 134 135 NotifyDone(result.PassAs<base::Value>()); 136} 137 138void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) { 139 rasterize_results_.total_layers++; 140 layer->RunMicroBenchmark(this); 141} 142 143void RasterizeAndRecordBenchmarkImpl::RunOnLayer(PictureLayerImpl* layer) { 144 rasterize_results_.total_picture_layers++; 145 if (!layer->DrawsContent()) { 146 rasterize_results_.total_picture_layers_with_no_content++; 147 return; 148 } 149 if (layer->visible_content_rect().IsEmpty()) { 150 rasterize_results_.total_picture_layers_off_screen++; 151 return; 152 } 153 154 TaskGraphRunner* task_graph_runner = RasterWorkerPool::GetTaskGraphRunner(); 155 DCHECK(task_graph_runner); 156 157 if (!task_namespace_.IsValid()) 158 task_namespace_ = task_graph_runner->GetNamespaceToken(); 159 160 PictureLayerTilingSet tiling_set(layer, layer->content_bounds()); 161 162 PictureLayerTiling* tiling = tiling_set.AddTiling(layer->contents_scale_x()); 163 tiling->CreateAllTilesForTesting(); 164 for (PictureLayerTiling::CoverageIterator it( 165 tiling, layer->contents_scale_x(), layer->visible_content_rect()); 166 it; 167 ++it) { 168 DCHECK(*it); 169 170 PicturePileImpl* picture_pile = (*it)->picture_pile(); 171 gfx::Rect content_rect = (*it)->content_rect(); 172 float contents_scale = (*it)->contents_scale(); 173 174 scoped_refptr<BenchmarkRasterTask> benchmark_raster_task( 175 new BenchmarkRasterTask(picture_pile, 176 content_rect, 177 contents_scale, 178 rasterize_repeat_count_)); 179 180 TaskGraph graph; 181 182 graph.nodes.push_back( 183 TaskGraph::Node(benchmark_raster_task, 184 RasterWorkerPool::kBenchmarkRasterTaskPriority, 185 0u)); 186 187 task_graph_runner->ScheduleTasks(task_namespace_, &graph); 188 task_graph_runner->WaitForTasksToFinishRunning(task_namespace_); 189 190 Task::Vector completed_tasks; 191 task_graph_runner->CollectCompletedTasks(task_namespace_, &completed_tasks); 192 DCHECK_EQ(1u, completed_tasks.size()); 193 DCHECK_EQ(completed_tasks[0], benchmark_raster_task); 194 195 int tile_size = content_rect.width() * content_rect.height(); 196 base::TimeDelta min_time = benchmark_raster_task->GetBestTime(); 197 bool is_solid_color = benchmark_raster_task->IsSolidColor(); 198 199 if (layer->contents_opaque()) 200 rasterize_results_.pixels_rasterized_as_opaque += tile_size; 201 202 if (!is_solid_color) { 203 rasterize_results_.pixels_rasterized_with_non_solid_color += tile_size; 204 } 205 206 rasterize_results_.pixels_rasterized += tile_size; 207 rasterize_results_.total_best_time += min_time; 208 } 209} 210 211RasterizeAndRecordBenchmarkImpl::RasterizeResults::RasterizeResults() 212 : pixels_rasterized(0), 213 pixels_rasterized_with_non_solid_color(0), 214 pixels_rasterized_as_opaque(0), 215 total_layers(0), 216 total_picture_layers(0), 217 total_picture_layers_with_no_content(0), 218 total_picture_layers_off_screen(0) {} 219 220RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {} 221 222} // namespace cc 223