1// Copyright (c) 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 "base/containers/hash_tables.h"
6#include "base/logging.h"
7#include "base/time/time.h"
8#include "skia/ext/benchmarking_canvas.h"
9#include "third_party/skia/include/core/SkBitmapDevice.h"
10#include "third_party/skia/include/utils/SkProxyCanvas.h"
11
12namespace skia {
13
14class AutoStamper {
15public:
16  AutoStamper(TimingCanvas* timing_canvas);
17  ~AutoStamper();
18
19private:
20  TimingCanvas* timing_canvas_;
21  base::TimeTicks start_ticks_;
22};
23
24class TimingCanvas : public SkProxyCanvas {
25public:
26  TimingCanvas(int width, int height, const BenchmarkingCanvas* track_canvas)
27      : tracking_canvas_(track_canvas) {
28    skia::RefPtr<SkBaseDevice> device = skia::AdoptRef(
29        SkNEW_ARGS(SkBitmapDevice, (SkBitmap::kARGB_8888_Config, width, height)));
30    canvas_ = skia::AdoptRef(SkNEW_ARGS(SkCanvas, (device.get())));
31
32    setProxy(canvas_.get());
33  }
34
35  virtual ~TimingCanvas() {
36  }
37
38  double GetTime(size_t index) {
39    TimingsMap::const_iterator timing_info = timings_map_.find(index);
40    return timing_info != timings_map_.end()
41        ? timing_info->second.InMillisecondsF()
42        : 0.0;
43  }
44
45  // SkCanvas overrides.
46  virtual int save(SaveFlags flags = kMatrixClip_SaveFlag) OVERRIDE {
47    AutoStamper stamper(this);
48    return SkProxyCanvas::save(flags);
49  }
50
51  virtual int saveLayer(const SkRect* bounds, const SkPaint* paint,
52                        SaveFlags flags = kARGB_ClipLayer_SaveFlag) OVERRIDE {
53    AutoStamper stamper(this);
54    return SkProxyCanvas::saveLayer(bounds, paint, flags);
55  }
56
57  virtual void restore() OVERRIDE {
58    AutoStamper stamper(this);
59    SkProxyCanvas::restore();
60  }
61
62  virtual bool clipRect(const SkRect& rect, SkRegion::Op op,
63                        bool doAa) OVERRIDE {
64    AutoStamper stamper(this);
65    return SkProxyCanvas::clipRect(rect, op, doAa);
66  }
67
68  virtual bool clipRRect(const SkRRect& rrect, SkRegion::Op op,
69                         bool doAa) OVERRIDE {
70    AutoStamper stamper(this);
71    return SkProxyCanvas::clipRRect(rrect, op, doAa);
72  }
73
74  virtual bool clipPath(const SkPath& path, SkRegion::Op op,
75                        bool doAa) OVERRIDE {
76    AutoStamper stamper(this);
77    return SkProxyCanvas::clipPath(path, op, doAa);
78  }
79
80  virtual bool clipRegion(const SkRegion& region,
81                          SkRegion::Op op = SkRegion::kIntersect_Op) OVERRIDE {
82    AutoStamper stamper(this);
83    return SkProxyCanvas::clipRegion(region, op);
84  }
85
86  virtual void drawPaint(const SkPaint& paint) OVERRIDE {
87    AutoStamper stamper(this);
88    SkProxyCanvas::drawPaint(paint);
89  }
90
91  virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
92                          const SkPaint& paint) OVERRIDE {
93    AutoStamper stamper(this);
94    SkProxyCanvas::drawPoints(mode, count, pts, paint);
95  }
96
97  virtual void drawOval(const SkRect& rect, const SkPaint& paint) OVERRIDE {
98    AutoStamper stamper(this);
99    SkProxyCanvas::drawOval(rect, paint);
100  }
101
102  virtual void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE {
103    AutoStamper stamper(this);
104    SkProxyCanvas::drawRect(rect, paint);
105  }
106
107  virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint) OVERRIDE {
108    AutoStamper stamper(this);
109    SkProxyCanvas::drawRRect(rrect, paint);
110  }
111
112  virtual void drawPath(const SkPath& path, const SkPaint& paint) OVERRIDE {
113    AutoStamper stamper(this);
114    SkProxyCanvas::drawPath(path, paint);
115  }
116
117  virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
118                          const SkPaint* paint = NULL) OVERRIDE {
119    AutoStamper stamper(this);
120    SkProxyCanvas::drawBitmap(bitmap, left, top, paint);
121  }
122
123  virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
124                                    const SkRect& dst,
125                                    const SkPaint* paint,
126                                    DrawBitmapRectFlags flags) OVERRIDE {
127    AutoStamper stamper(this);
128    SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
129  }
130
131  virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
132                                const SkPaint* paint = NULL) OVERRIDE {
133    AutoStamper stamper(this);
134    SkProxyCanvas::drawBitmapMatrix(bitmap, m, paint);
135  }
136
137  virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
138                          const SkPaint* paint = NULL) OVERRIDE {
139    AutoStamper stamper(this);
140    SkProxyCanvas::drawSprite(bitmap, left, top, paint);
141  }
142
143  virtual void drawText(const void* text, size_t byteLength, SkScalar x,
144                        SkScalar y, const SkPaint& paint) OVERRIDE {
145    AutoStamper stamper(this);
146    SkProxyCanvas::drawText(text, byteLength, x, y, paint);
147  }
148
149  virtual void drawPosText(const void* text, size_t byteLength,
150                           const SkPoint pos[],
151                           const SkPaint& paint) OVERRIDE {
152    AutoStamper stamper(this);
153    SkProxyCanvas::drawPosText(text, byteLength, pos, paint);
154  }
155
156  virtual void drawPosTextH(const void* text, size_t byteLength,
157                            const SkScalar xpos[], SkScalar constY,
158                            const SkPaint& paint) OVERRIDE {
159    AutoStamper stamper(this);
160    SkProxyCanvas::drawPosTextH(text, byteLength, xpos, constY, paint);
161  }
162
163  virtual void drawTextOnPath(const void* text, size_t byteLength,
164                              const SkPath& path, const SkMatrix* matrix,
165                              const SkPaint& paint) OVERRIDE {
166    AutoStamper stamper(this);
167    SkProxyCanvas::drawTextOnPath(text, byteLength, path, matrix, paint);
168  }
169
170  virtual void drawPicture(SkPicture& picture) OVERRIDE {
171    AutoStamper stamper(this);
172    SkProxyCanvas::drawPicture(picture);
173  }
174
175  virtual void drawVertices(VertexMode vmode, int vertexCount,
176                            const SkPoint vertices[], const SkPoint texs[],
177                            const SkColor colors[], SkXfermode* xmode,
178                            const uint16_t indices[], int indexCount,
179                            const SkPaint& paint) OVERRIDE {
180    AutoStamper stamper(this);
181    SkProxyCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors,
182                                xmode, indices, indexCount, paint);
183  }
184
185  virtual void drawData(const void* data, size_t length) OVERRIDE {
186    AutoStamper stamper(this);
187    SkProxyCanvas::drawData(data, length);
188  }
189
190private:
191  typedef base::hash_map<size_t, base::TimeDelta> TimingsMap;
192  TimingsMap timings_map_;
193
194  skia::RefPtr<SkCanvas> canvas_;
195
196  friend class AutoStamper;
197  const BenchmarkingCanvas* tracking_canvas_;
198};
199
200AutoStamper::AutoStamper(TimingCanvas *timing_canvas)
201    : timing_canvas_(timing_canvas) {
202  start_ticks_ = base::TimeTicks::HighResNow();
203}
204
205AutoStamper::~AutoStamper() {
206  base::TimeDelta delta = base::TimeTicks::HighResNow() - start_ticks_;
207  int command_index = timing_canvas_->tracking_canvas_->CommandCount() - 1;
208  DCHECK_GE(command_index, 0);
209  timing_canvas_->timings_map_[command_index] = delta;
210}
211
212BenchmarkingCanvas::BenchmarkingCanvas(int width, int height)
213    : SkNWayCanvas(width, height) {
214  debug_canvas_ = skia::AdoptRef(SkNEW_ARGS(SkDebugCanvas, (width, height)));
215  timing_canvas_ = skia::AdoptRef(SkNEW_ARGS(TimingCanvas, (width, height, this)));
216
217  addCanvas(debug_canvas_.get());
218  addCanvas(timing_canvas_.get());
219}
220
221BenchmarkingCanvas::~BenchmarkingCanvas() {
222  removeAll();
223}
224
225size_t BenchmarkingCanvas::CommandCount() const {
226  return debug_canvas_->getSize();
227}
228
229SkDrawCommand* BenchmarkingCanvas::GetCommand(size_t index) {
230  DCHECK_LT(index, static_cast<size_t>(debug_canvas_->getSize()));
231  return debug_canvas_->getDrawCommandAt(index);
232}
233
234double BenchmarkingCanvas::GetTime(size_t index) {
235  DCHECK_LT(index,  static_cast<size_t>(debug_canvas_->getSize()));
236  return timing_canvas_->GetTime(index);
237}
238
239} // namespace skia
240