1
2/*
3 * Copyright 2011 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8#include "Benchmark.h"
9#include "SkCanvas.h"
10#include "SkCommandLineFlags.h"
11#include "SkPaint.h"
12#include "SkRandom.h"
13#include "SkShader.h"
14#include "SkString.h"
15
16DEFINE_double(strokeWidth, -1.0, "If set, use this stroke width in RectBench.");
17
18class RectBench : public Benchmark {
19public:
20    int fShift, fStroke;
21    enum {
22        W = 640,
23        H = 480,
24        N = 300,
25    };
26    SkRect  fRects[N];
27    SkColor fColors[N];
28
29    RectBench(int shift, int stroke = 0)
30        : fShift(shift)
31        , fStroke(stroke) {}
32
33    SkString fName;
34    const char* computeName(const char root[]) {
35        fName.printf("%s_%d", root, fShift);
36        if (fStroke > 0) {
37            fName.appendf("_stroke_%d", fStroke);
38        }
39        return fName.c_str();
40    }
41
42protected:
43    virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
44        c->drawRect(r, p);
45    }
46
47    virtual const char* onGetName() { return computeName("rects"); }
48
49    virtual void onPreDraw() {
50        SkRandom rand;
51        const SkScalar offset = SK_Scalar1/3;
52        for (int i = 0; i < N; i++) {
53            int x = rand.nextU() % W;
54            int y = rand.nextU() % H;
55            int w = rand.nextU() % W;
56            int h = rand.nextU() % H;
57            w >>= fShift;
58            h >>= fShift;
59            x -= w/2;
60            y -= h/2;
61            fRects[i].set(SkIntToScalar(x), SkIntToScalar(y),
62                          SkIntToScalar(x+w), SkIntToScalar(y+h));
63            fRects[i].offset(offset, offset);
64            fColors[i] = rand.nextU() | 0xFF808080;
65        }
66    }
67
68    virtual void onDraw(const int loops, SkCanvas* canvas) {
69        SkPaint paint;
70        if (fStroke > 0) {
71            paint.setStyle(SkPaint::kStroke_Style);
72            paint.setStrokeWidth(SkIntToScalar(fStroke));
73        }
74        for (int i = 0; i < loops; i++) {
75            paint.setColor(fColors[i % N]);
76            this->setupPaint(&paint);
77            this->drawThisRect(canvas, fRects[i % N], paint);
78        }
79    }
80private:
81    typedef Benchmark INHERITED;
82};
83
84class SrcModeRectBench : public RectBench {
85public:
86    SrcModeRectBench() : INHERITED(1, 0) {
87        fMode = SkXfermode::Create(SkXfermode::kSrc_Mode);
88    }
89
90    virtual ~SrcModeRectBench() {
91        SkSafeUnref(fMode);
92    }
93
94protected:
95    virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
96        this->INHERITED::setupPaint(paint);
97        // srcmode is most interesting when we're not opaque
98        paint->setAlpha(0x80);
99        paint->setXfermode(fMode);
100    }
101
102    virtual const char* onGetName() SK_OVERRIDE {
103        fName.set(this->INHERITED::onGetName());
104        fName.prepend("srcmode_");
105        return fName.c_str();
106    }
107
108private:
109    SkString fName;
110    SkXfermode* fMode;
111
112    typedef RectBench INHERITED;
113};
114
115class OvalBench : public RectBench {
116public:
117    OvalBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
118protected:
119    virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
120        c->drawOval(r, p);
121    }
122    virtual const char* onGetName() { return computeName("ovals"); }
123};
124
125class RRectBench : public RectBench {
126public:
127    RRectBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
128protected:
129    virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
130        c->drawRoundRect(r, r.width() / 4, r.height() / 4, p);
131    }
132    virtual const char* onGetName() { return computeName("rrects"); }
133};
134
135class PointsBench : public RectBench {
136public:
137    SkCanvas::PointMode fMode;
138    const char* fName;
139
140    PointsBench(SkCanvas::PointMode mode, const char* name)
141        : RectBench(2)
142        , fMode(mode) {
143        fName = name;
144    }
145
146protected:
147    virtual void onDraw(const int loops, SkCanvas* canvas) {
148        SkScalar gSizes[] = {
149            SkIntToScalar(7), 0
150        };
151        size_t sizes = SK_ARRAY_COUNT(gSizes);
152
153        if (FLAGS_strokeWidth >= 0) {
154            gSizes[0] = (SkScalar)FLAGS_strokeWidth;
155            sizes = 1;
156        }
157
158        SkPaint paint;
159        paint.setStrokeCap(SkPaint::kRound_Cap);
160
161        for (int loop = 0; loop < loops; loop++) {
162            for (size_t i = 0; i < sizes; i++) {
163                paint.setStrokeWidth(gSizes[i]);
164                this->setupPaint(&paint);
165                canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint);
166                paint.setColor(fColors[i % N]);
167            }
168        }
169    }
170    virtual const char* onGetName() { return fName; }
171};
172
173class AARectBench : public Benchmark {
174public:
175    enum {
176        W = 640,
177        H = 480,
178    };
179
180    AARectBench(bool rotate) : fRotate(rotate) {}
181
182protected:
183
184    virtual const char* onGetName() {
185        if (fRotate) {
186            return "aarects_rotated";
187        }
188        return "aarects";
189    }
190
191    virtual void onDraw(const int loops, SkCanvas* canvas) {
192        static const SkScalar kHalfRectSize = 0.75f;
193
194        SkPaint paint;
195        this->setupPaint(&paint);
196        paint.setAntiAlias(true);
197        paint.setColor(SK_ColorBLACK);
198        SkRect r = { -kHalfRectSize, -kHalfRectSize, kHalfRectSize, kHalfRectSize };
199        int rot = 0;
200
201        for (int i = 0; i < loops; i++) {
202            // Draw small aa rects in a grid across the screen
203            for (SkScalar y = kHalfRectSize+SK_Scalar1; y < H; y += 2*kHalfRectSize+2) {
204                for (SkScalar x = kHalfRectSize+SK_Scalar1; x < W; x += 2*kHalfRectSize+2) {
205                    canvas->save();
206                    canvas->translate(x, y);
207
208                    if (fRotate) {
209                        SkMatrix rotate;
210                        rotate.setRotate(SkIntToScalar(rot));
211                        canvas->concat(rotate);
212                        rot += 10;
213                    }
214
215                    canvas->drawRect(r, paint);
216                    canvas->restore();
217                }
218            }
219        }
220
221    }
222private:
223    bool fRotate;
224    typedef Benchmark INHERITED;
225};
226
227/*******************************************************************************
228 * to bench BlitMask [Opaque, Black, color, shader]
229 *******************************************************************************/
230
231class BlitMaskBench : public RectBench {
232public:
233    enum kMaskType {
234        kMaskOpaque = 0,
235        kMaskBlack,
236        kMaskColor,
237        KMaskShader
238    };
239    SkCanvas::PointMode fMode;
240    const char* fName;
241
242    BlitMaskBench(SkCanvas::PointMode mode,
243                  BlitMaskBench::kMaskType type, const char* name) :
244        RectBench(2), fMode(mode), _type(type) {
245        fName = name;
246    }
247
248protected:
249    virtual void onDraw(const int loops, SkCanvas* canvas) {
250        SkScalar gSizes[] = {
251            SkIntToScalar(13), SkIntToScalar(24)
252        };
253        size_t sizes = SK_ARRAY_COUNT(gSizes);
254
255        if (FLAGS_strokeWidth >= 0) {
256            gSizes[0] = (SkScalar)FLAGS_strokeWidth;
257            sizes = 1;
258        }
259        SkRandom rand;
260        SkColor color = 0xFF000000;
261        U8CPU alpha = 0xFF;
262        SkPaint paint;
263        paint.setStrokeCap(SkPaint::kRound_Cap);
264        if (_type == KMaskShader) {
265            SkBitmap srcBM;
266            srcBM.allocN32Pixels(10, 1);
267            srcBM.eraseColor(0xFF00FF00);
268
269            SkShader* s;
270            s  = SkShader::CreateBitmapShader(srcBM, SkShader::kClamp_TileMode,
271                                              SkShader::kClamp_TileMode);
272            paint.setShader(s)->unref();
273        }
274        for (int loop = 0; loop < loops; loop++) {
275            for (size_t i = 0; i < sizes; i++) {
276                switch (_type) {
277                    case kMaskOpaque:
278                        color = fColors[i];
279                        alpha = 0xFF;
280                        break;
281                    case kMaskBlack:
282                        alpha = 0xFF;
283                        color = 0xFF000000;
284                        break;
285                    case kMaskColor:
286                        color = fColors[i];
287                        alpha = rand.nextU() & 255;
288                        break;
289                    case KMaskShader:
290                        break;
291                }
292                paint.setStrokeWidth(gSizes[i]);
293                this->setupPaint(&paint);
294                paint.setColor(color);
295                paint.setAlpha(alpha);
296                canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint);
297           }
298        }
299    }
300    virtual const char* onGetName() { return fName; }
301private:
302    typedef RectBench INHERITED;
303    kMaskType _type;
304};
305
306
307DEF_BENCH( return SkNEW_ARGS(RectBench, (1)); )
308DEF_BENCH( return SkNEW_ARGS(RectBench, (1, 4)); )
309DEF_BENCH( return SkNEW_ARGS(RectBench, (3)); )
310DEF_BENCH( return SkNEW_ARGS(RectBench, (3, 4)); )
311DEF_BENCH( return SkNEW_ARGS(OvalBench, (1)); )
312DEF_BENCH( return SkNEW_ARGS(OvalBench, (3)); )
313DEF_BENCH( return SkNEW_ARGS(OvalBench, (1, 4)); )
314DEF_BENCH( return SkNEW_ARGS(OvalBench, (3, 4)); )
315DEF_BENCH( return SkNEW_ARGS(RRectBench, (1)); )
316DEF_BENCH( return SkNEW_ARGS(RRectBench, (1, 4)); )
317DEF_BENCH( return SkNEW_ARGS(RRectBench, (3)); )
318DEF_BENCH( return SkNEW_ARGS(RRectBench, (3, 4)); )
319DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kPoints_PointMode, "points")); )
320DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kLines_PointMode, "lines")); )
321DEF_BENCH( return SkNEW_ARGS(PointsBench, (SkCanvas::kPolygon_PointMode, "polygon")); )
322
323DEF_BENCH( return SkNEW_ARGS(SrcModeRectBench, ()); )
324
325DEF_BENCH( return SkNEW_ARGS(AARectBench, (false)); )
326DEF_BENCH( return SkNEW_ARGS(AARectBench, (true)); )
327
328/* init the blitmask bench
329 */
330DEF_BENCH( return SkNEW_ARGS(BlitMaskBench,
331                      (SkCanvas::kPoints_PointMode,
332                      BlitMaskBench::kMaskOpaque, "maskopaque")
333                      ); )
334DEF_BENCH( return SkNEW_ARGS(BlitMaskBench,
335                      (SkCanvas::kPoints_PointMode,
336                      BlitMaskBench::kMaskBlack, "maskblack")
337                      ); )
338DEF_BENCH( return SkNEW_ARGS(BlitMaskBench,
339                      (SkCanvas::kPoints_PointMode,
340                      BlitMaskBench::kMaskColor, "maskcolor")
341                      ); )
342DEF_BENCH( return SkNEW_ARGS(BlitMaskBench,
343                     (SkCanvas::kPoints_PointMode,
344                     BlitMaskBench::KMaskShader, "maskshader")
345                     ); )
346