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    // 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
89class 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
147RasterizeAndRecordBenchmarkImpl::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
162RasterizeAndRecordBenchmarkImpl::~RasterizeAndRecordBenchmarkImpl() {}
163
164void 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
190void RasterizeAndRecordBenchmarkImpl::Run(LayerImpl* layer) {
191  rasterize_results_.total_layers++;
192  layer->RunMicroBenchmark(this);
193}
194
195void 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
265RasterizeAndRecordBenchmarkImpl::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
274RasterizeAndRecordBenchmarkImpl::RasterizeResults::~RasterizeResults() {}
275
276}  // namespace cc
277