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