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
42    bool isVisual() override { return true; }
43
44protected:
45    virtual void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) {
46        c->drawRect(r, p);
47    }
48
49    const char* onGetName() override { return computeName("rects"); }
50
51    void onDelayedSetup() override {
52        SkRandom rand;
53        const SkScalar offset = SK_Scalar1/3;
54        for (int i = 0; i < N; i++) {
55            int x = rand.nextU() % W;
56            int y = rand.nextU() % H;
57            int w = rand.nextU() % W;
58            int h = rand.nextU() % H;
59            w >>= fShift;
60            h >>= fShift;
61            x -= w/2;
62            y -= h/2;
63            fRects[i].set(SkIntToScalar(x), SkIntToScalar(y),
64                          SkIntToScalar(x+w), SkIntToScalar(y+h));
65            fRects[i].offset(offset, offset);
66            fColors[i] = rand.nextU() | 0xFF808080;
67        }
68    }
69
70    void onDraw(int loops, SkCanvas* canvas) override {
71        SkPaint paint;
72        if (fStroke > 0) {
73            paint.setStyle(SkPaint::kStroke_Style);
74            paint.setStrokeWidth(SkIntToScalar(fStroke));
75        }
76        for (int i = 0; i < loops; i++) {
77            paint.setColor(fColors[i % N]);
78            this->setupPaint(&paint);
79            this->drawThisRect(canvas, fRects[i % N], paint);
80        }
81    }
82private:
83    typedef Benchmark INHERITED;
84};
85
86class SrcModeRectBench : public RectBench {
87public:
88    SrcModeRectBench() : INHERITED(1, 0) {
89        fMode = SkXfermode::Create(SkXfermode::kSrc_Mode);
90    }
91
92    virtual ~SrcModeRectBench() {
93        SkSafeUnref(fMode);
94    }
95
96protected:
97    void setupPaint(SkPaint* paint) override {
98        this->INHERITED::setupPaint(paint);
99        // srcmode is most interesting when we're not opaque
100        paint->setAlpha(0x80);
101        paint->setXfermode(fMode);
102    }
103
104    const char* onGetName() override {
105        fName.set(this->INHERITED::onGetName());
106        fName.prepend("srcmode_");
107        return fName.c_str();
108    }
109
110private:
111    SkString fName;
112    SkXfermode* fMode;
113
114    typedef RectBench INHERITED;
115};
116
117class TransparentRectBench : public RectBench {
118public:
119    TransparentRectBench() : INHERITED(1, 0) {}
120
121protected:
122    void setupPaint(SkPaint* paint) override {
123        this->INHERITED::setupPaint(paint);
124        // draw non opaque rect
125        paint->setAlpha(0x80);
126    }
127
128    const char* onGetName() override {
129        fName.set(this->INHERITED::onGetName());
130        fName.prepend("transparent_");
131        return fName.c_str();
132    }
133
134private:
135    SkString fName;
136
137    typedef RectBench INHERITED;
138};
139
140
141class OvalBench : public RectBench {
142public:
143    OvalBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
144protected:
145    void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override {
146        c->drawOval(r, p);
147    }
148    const char* onGetName() override { return computeName("ovals"); }
149};
150
151class RRectBench : public RectBench {
152public:
153    RRectBench(int shift, int stroke = 0) : RectBench(shift, stroke) {}
154protected:
155    void drawThisRect(SkCanvas* c, const SkRect& r, const SkPaint& p) override {
156        c->drawRoundRect(r, r.width() / 4, r.height() / 4, p);
157    }
158    const char* onGetName() override { return computeName("rrects"); }
159};
160
161class PointsBench : public RectBench {
162public:
163    SkCanvas::PointMode fMode;
164    const char* fName;
165
166    PointsBench(SkCanvas::PointMode mode, const char* name)
167        : RectBench(2)
168        , fMode(mode) {
169        fName = name;
170    }
171
172protected:
173    void onDraw(int loops, SkCanvas* canvas) override {
174        SkScalar gSizes[] = {
175            SkIntToScalar(7), 0
176        };
177        size_t sizes = SK_ARRAY_COUNT(gSizes);
178
179        if (FLAGS_strokeWidth >= 0) {
180            gSizes[0] = (SkScalar)FLAGS_strokeWidth;
181            sizes = 1;
182        }
183
184        SkPaint paint;
185        paint.setStrokeCap(SkPaint::kRound_Cap);
186
187        for (int loop = 0; loop < loops; loop++) {
188            for (size_t i = 0; i < sizes; i++) {
189                paint.setStrokeWidth(gSizes[i]);
190                this->setupPaint(&paint);
191                canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint);
192                paint.setColor(fColors[i % N]);
193            }
194        }
195    }
196    const char* onGetName() override { return fName; }
197};
198
199/*******************************************************************************
200 * to bench BlitMask [Opaque, Black, color, shader]
201 *******************************************************************************/
202
203class BlitMaskBench : public RectBench {
204public:
205    enum kMaskType {
206        kMaskOpaque = 0,
207        kMaskBlack,
208        kMaskColor,
209        KMaskShader
210    };
211    SkCanvas::PointMode fMode;
212    const char* fName;
213
214    BlitMaskBench(SkCanvas::PointMode mode,
215                  BlitMaskBench::kMaskType type, const char* name) :
216        RectBench(2), fMode(mode), _type(type) {
217        fName = name;
218    }
219
220protected:
221    void onDraw(int loops, SkCanvas* canvas) override {
222        SkScalar gSizes[] = {
223            SkIntToScalar(13), SkIntToScalar(24)
224        };
225        size_t sizes = SK_ARRAY_COUNT(gSizes);
226
227        if (FLAGS_strokeWidth >= 0) {
228            gSizes[0] = (SkScalar)FLAGS_strokeWidth;
229            sizes = 1;
230        }
231        SkRandom rand;
232        SkColor color = 0xFF000000;
233        U8CPU alpha = 0xFF;
234        SkPaint paint;
235        paint.setStrokeCap(SkPaint::kRound_Cap);
236        if (_type == KMaskShader) {
237            SkBitmap srcBM;
238            srcBM.allocN32Pixels(10, 1);
239            srcBM.eraseColor(0xFF00FF00);
240
241            SkShader* s;
242            s  = SkShader::CreateBitmapShader(srcBM, SkShader::kClamp_TileMode,
243                                              SkShader::kClamp_TileMode);
244            paint.setShader(s)->unref();
245        }
246        for (int loop = 0; loop < loops; loop++) {
247            for (size_t i = 0; i < sizes; i++) {
248                switch (_type) {
249                    case kMaskOpaque:
250                        color = fColors[i];
251                        alpha = 0xFF;
252                        break;
253                    case kMaskBlack:
254                        alpha = 0xFF;
255                        color = 0xFF000000;
256                        break;
257                    case kMaskColor:
258                        color = fColors[i];
259                        alpha = rand.nextU() & 255;
260                        break;
261                    case KMaskShader:
262                        break;
263                }
264                paint.setStrokeWidth(gSizes[i]);
265                this->setupPaint(&paint);
266                paint.setColor(color);
267                paint.setAlpha(alpha);
268                canvas->drawPoints(fMode, N * 2, SkTCast<SkPoint*>(fRects), paint);
269           }
270        }
271    }
272    const char* onGetName() override { return fName; }
273private:
274    typedef RectBench INHERITED;
275    kMaskType _type;
276};
277
278DEF_BENCH(return new RectBench(1);)
279DEF_BENCH(return new RectBench(1, 4);)
280DEF_BENCH(return new RectBench(3);)
281DEF_BENCH(return new RectBench(3, 4);)
282DEF_BENCH(return new OvalBench(1);)
283DEF_BENCH(return new OvalBench(3);)
284DEF_BENCH(return new OvalBench(1, 4);)
285DEF_BENCH(return new OvalBench(3, 4);)
286DEF_BENCH(return new RRectBench(1);)
287DEF_BENCH(return new RRectBench(1, 4);)
288DEF_BENCH(return new RRectBench(3);)
289DEF_BENCH(return new RRectBench(3, 4);)
290DEF_BENCH(return new PointsBench(SkCanvas::kPoints_PointMode, "points");)
291DEF_BENCH(return new PointsBench(SkCanvas::kLines_PointMode, "lines");)
292DEF_BENCH(return new PointsBench(SkCanvas::kPolygon_PointMode, "polygon");)
293
294DEF_BENCH(return new SrcModeRectBench();)
295
296DEF_BENCH(return new TransparentRectBench();)
297
298/* init the blitmask bench
299 */
300DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
301                                   BlitMaskBench::kMaskOpaque,
302                                   "maskopaque");)
303DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
304                                   BlitMaskBench::kMaskBlack,
305                                   "maskblack");)
306DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
307                                   BlitMaskBench::kMaskColor,
308                                   "maskcolor");)
309DEF_BENCH(return new BlitMaskBench(SkCanvas::kPoints_PointMode,
310                                   BlitMaskBench::KMaskShader,
311                                   "maskshader");)
312