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/utils/SkProxyCanvas.h"
10
11namespace skia {
12
13class AutoStamper {
14public:
15  AutoStamper(TimingCanvas* timing_canvas);
16  ~AutoStamper();
17
18private:
19  TimingCanvas* timing_canvas_;
20  base::TimeTicks start_ticks_;
21};
22
23class TimingCanvas : public SkProxyCanvas {
24public:
25  TimingCanvas(int width, int height, const BenchmarkingCanvas* track_canvas)
26      : tracking_canvas_(track_canvas) {
27    canvas_ = skia::AdoptRef(SkCanvas::NewRasterN32(width, height));
28
29    setProxy(canvas_.get());
30  }
31
32  virtual ~TimingCanvas() {
33  }
34
35  double GetTime(size_t index) {
36    TimingsMap::const_iterator timing_info = timings_map_.find(index);
37    return timing_info != timings_map_.end()
38        ? timing_info->second.InMillisecondsF()
39        : 0.0;
40  }
41
42  // SkCanvas overrides.
43  virtual void willSave() OVERRIDE {
44    AutoStamper stamper(this);
45    SkProxyCanvas::willSave();
46  }
47
48  virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds,
49                                          const SkPaint* paint,
50                                          SaveFlags flags) OVERRIDE {
51    AutoStamper stamper(this);
52    return SkProxyCanvas::willSaveLayer(bounds, paint, flags);
53  }
54
55  virtual void willRestore() OVERRIDE {
56    AutoStamper stamper(this);
57    SkProxyCanvas::willRestore();
58  }
59
60  virtual void drawPaint(const SkPaint& paint) OVERRIDE {
61    AutoStamper stamper(this);
62    SkProxyCanvas::drawPaint(paint);
63  }
64
65  virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
66                          const SkPaint& paint) OVERRIDE {
67    AutoStamper stamper(this);
68    SkProxyCanvas::drawPoints(mode, count, pts, paint);
69  }
70
71  virtual void drawOval(const SkRect& rect, const SkPaint& paint) OVERRIDE {
72    AutoStamper stamper(this);
73    SkProxyCanvas::drawOval(rect, paint);
74  }
75
76  virtual void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE {
77    AutoStamper stamper(this);
78    SkProxyCanvas::drawRect(rect, paint);
79  }
80
81  virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint) OVERRIDE {
82    AutoStamper stamper(this);
83    SkProxyCanvas::drawRRect(rrect, paint);
84  }
85
86  virtual void drawPath(const SkPath& path, const SkPaint& paint) OVERRIDE {
87    AutoStamper stamper(this);
88    SkProxyCanvas::drawPath(path, paint);
89  }
90
91  virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
92                          const SkPaint* paint = NULL) OVERRIDE {
93    AutoStamper stamper(this);
94    SkProxyCanvas::drawBitmap(bitmap, left, top, paint);
95  }
96
97  virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
98                                    const SkRect& dst,
99                                    const SkPaint* paint,
100                                    DrawBitmapRectFlags flags) OVERRIDE {
101    AutoStamper stamper(this);
102    SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
103  }
104
105  virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
106                                const SkPaint* paint = NULL) OVERRIDE {
107    AutoStamper stamper(this);
108    SkProxyCanvas::drawBitmapMatrix(bitmap, m, paint);
109  }
110
111  virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
112                          const SkPaint* paint = NULL) OVERRIDE {
113    AutoStamper stamper(this);
114    SkProxyCanvas::drawSprite(bitmap, left, top, paint);
115  }
116
117  virtual void drawVertices(VertexMode vmode, int vertexCount,
118                            const SkPoint vertices[], const SkPoint texs[],
119                            const SkColor colors[], SkXfermode* xmode,
120                            const uint16_t indices[], int indexCount,
121                            const SkPaint& paint) OVERRIDE {
122    AutoStamper stamper(this);
123    SkProxyCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors,
124                                xmode, indices, indexCount, paint);
125  }
126
127  virtual void drawData(const void* data, size_t length) OVERRIDE {
128    AutoStamper stamper(this);
129    SkProxyCanvas::drawData(data, length);
130  }
131
132protected:
133  virtual void onDrawText(const void* text, size_t byteLength, SkScalar x,
134                          SkScalar y, const SkPaint& paint) OVERRIDE {
135    AutoStamper stamper(this);
136    SkProxyCanvas::onDrawText(text, byteLength, x, y, paint);
137  }
138
139  virtual void onDrawPosText(const void* text, size_t byteLength,
140                             const SkPoint pos[],
141                             const SkPaint& paint) OVERRIDE {
142    AutoStamper stamper(this);
143    SkProxyCanvas::onDrawPosText(text, byteLength, pos, paint);
144  }
145
146  virtual void onDrawPosTextH(const void* text, size_t byteLength,
147                              const SkScalar xpos[], SkScalar constY,
148                              const SkPaint& paint) OVERRIDE {
149    AutoStamper stamper(this);
150    SkProxyCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint);
151  }
152
153  virtual void onDrawTextOnPath(const void* text, size_t byteLength,
154                                const SkPath& path, const SkMatrix* matrix,
155                                const SkPaint& paint) OVERRIDE {
156    AutoStamper stamper(this);
157    SkProxyCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
158  }
159
160  virtual void onClipRect(const SkRect& rect, SkRegion::Op op,
161                          ClipEdgeStyle edge_style) OVERRIDE {
162    AutoStamper stamper(this);
163    SkProxyCanvas::onClipRect(rect, op, edge_style);
164  }
165
166  virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op,
167                          ClipEdgeStyle edge_style) OVERRIDE {
168    AutoStamper stamper(this);
169    SkProxyCanvas::onClipRRect(rrect, op, edge_style);
170  }
171
172  virtual void onClipPath(const SkPath& path, SkRegion::Op op,
173                          ClipEdgeStyle edge_style) OVERRIDE {
174    AutoStamper stamper(this);
175    SkProxyCanvas::onClipPath(path, op, edge_style);
176  }
177
178  virtual void onClipRegion(const SkRegion& region,
179                            SkRegion::Op op) OVERRIDE {
180    AutoStamper stamper(this);
181    SkProxyCanvas::onClipRegion(region, op);
182  }
183
184  virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
185                             const SkPaint* paint) OVERRIDE {
186    AutoStamper stamper(this);
187    SkProxyCanvas::onDrawPicture(picture, matrix, paint);
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