1/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bench/Benchmark.h"
9#include "include/core/SkCanvas.h"
10#include "include/core/SkPaint.h"
11#include "include/core/SkPath.h"
12#include "include/core/SkShader.h"
13#include "include/core/SkString.h"
14#include "include/utils/SkRandom.h"
15
16enum Flags {
17    kBig_Flag = 1 << 0,
18    kAA_Flag = 1 << 1
19};
20
21#define FLAGS00 Flags(0)
22#define FLAGS01 Flags(kBig_Flag)
23#define FLAGS10 Flags(kAA_Flag)
24#define FLAGS11 Flags(kBig_Flag | kAA_Flag)
25
26static const int points[] = {
27    10, 10, 15, 5, 20, 20,
28    30, 5, 25, 20, 15, 12,
29    21, 21, 30, 30, 12, 4,
30    32, 28, 20, 18, 12, 10
31};
32
33static const int kMaxPathSize = 10;
34
35class HairlinePathBench : public Benchmark {
36public:
37    HairlinePathBench(Flags flags) : fFlags(flags) {
38        fPaint.setStyle(SkPaint::kStroke_Style);
39        fPaint.setStrokeWidth(SkIntToScalar(0));
40    }
41
42    virtual void appendName(SkString*) = 0;
43    virtual void makePath(SkPath*) = 0;
44
45protected:
46    const char* onGetName() override {
47        fName.printf("path_hairline_%s_%s_",
48                     fFlags & kBig_Flag ? "big" : "small",
49                     fFlags & kAA_Flag ? "AA" : "noAA");
50        this->appendName(&fName);
51        return fName.c_str();
52    }
53
54    void onDraw(int loops, SkCanvas* canvas) override {
55        SkPaint paint(fPaint);
56        this->setupPaint(&paint);
57
58        paint.setAntiAlias(fFlags & kAA_Flag ? true : false);
59
60        SkPath path;
61        this->makePath(&path);
62        if (fFlags & kBig_Flag) {
63            const SkMatrix m = SkMatrix::Scale(3, 3);
64            path.transform(m);
65        }
66
67        for (int i = 0; i < loops; i++) {
68            for (int j = 0; j < 100; ++j) {
69                canvas->drawPath(path, paint);
70            }
71        }
72    }
73
74private:
75    SkPaint     fPaint;
76    SkString    fName;
77    Flags       fFlags;
78    using INHERITED = Benchmark;
79};
80
81class LinePathBench : public HairlinePathBench {
82public:
83    LinePathBench(Flags flags) : INHERITED(flags) {}
84
85    void appendName(SkString* name) override {
86        name->append("line");
87    }
88    void makePath(SkPath* path) override {
89        SkRandom rand;
90        int size = SK_ARRAY_COUNT(points);
91        int hSize = size / 2;
92        for (int i = 0; i < kMaxPathSize; ++i) {
93            int xTrans = 10 + 40 * (i%(kMaxPathSize/2));
94            int yTrans = 0;
95            if (i > kMaxPathSize/2 - 1) {
96                yTrans = 40;
97            }
98            int base1 = 2 * rand.nextULessThan(hSize);
99            int base2 = 2 * rand.nextULessThan(hSize);
100            int base3 = 2 * rand.nextULessThan(hSize);
101            path->moveTo(SkIntToScalar(points[base1] + xTrans),
102                         SkIntToScalar(points[base1+1] + yTrans));
103            path->lineTo(SkIntToScalar(points[base2] + xTrans),
104                         SkIntToScalar(points[base2+1] + yTrans));
105            path->lineTo(SkIntToScalar(points[base3] + xTrans),
106                         SkIntToScalar(points[base3+1] + yTrans));
107        }
108    }
109private:
110    using INHERITED = HairlinePathBench;
111};
112
113class QuadPathBench : public HairlinePathBench {
114public:
115    QuadPathBench(Flags flags) : INHERITED(flags) {}
116
117    void appendName(SkString* name) override {
118        name->append("quad");
119    }
120    void makePath(SkPath* path) override {
121        SkRandom rand;
122        int size = SK_ARRAY_COUNT(points);
123        int hSize = size / 2;
124        for (int i = 0; i < kMaxPathSize; ++i) {
125            int xTrans = 10 + 40 * (i%(kMaxPathSize/2));
126            int yTrans = 0;
127            if (i > kMaxPathSize/2 - 1) {
128                yTrans = 40;
129            }
130            int base1 = 2 * rand.nextULessThan(hSize);
131            int base2 = 2 * rand.nextULessThan(hSize);
132            int base3 = 2 * rand.nextULessThan(hSize);
133            path->moveTo(SkIntToScalar(points[base1] + xTrans),
134                         SkIntToScalar(points[base1+1] + yTrans));
135            path->quadTo(SkIntToScalar(points[base2] + xTrans),
136                         SkIntToScalar(points[base2+1] + yTrans),
137                         SkIntToScalar(points[base3] + xTrans),
138                         SkIntToScalar(points[base3+1] + yTrans));
139        }
140    }
141private:
142    using INHERITED = HairlinePathBench;
143};
144
145class ConicPathBench : public HairlinePathBench {
146public:
147    ConicPathBench(Flags flags) : INHERITED(flags) {}
148
149    void appendName(SkString* name) override {
150        name->append("conic");
151    }
152    void makePath(SkPath* path) override {
153        SkRandom rand;
154        SkRandom randWeight;
155        int size = SK_ARRAY_COUNT(points);
156        int hSize = size / 2;
157        for (int i = 0; i < kMaxPathSize; ++i) {
158            int xTrans = 10 + 40 * (i%(kMaxPathSize/2));
159            int yTrans = 0;
160            if (i > kMaxPathSize/2 - 1) {
161                yTrans = 40;
162            }
163            int base1 = 2 * rand.nextULessThan(hSize);
164            int base2 = 2 * rand.nextULessThan(hSize);
165            int base3 = 2 * rand.nextULessThan(hSize);
166            float weight = randWeight.nextRangeF(0.0f, 2.0f);
167            path->moveTo(SkIntToScalar(points[base1] + xTrans),
168                         SkIntToScalar(points[base1+1] + yTrans));
169            path->conicTo(SkIntToScalar(points[base2] + xTrans),
170                          SkIntToScalar(points[base2+1] + yTrans),
171                         SkIntToScalar(points[base3] + xTrans),
172                         SkIntToScalar(points[base3+1] + yTrans),
173                         weight);
174        }
175    }
176
177private:
178    using INHERITED = HairlinePathBench;
179};
180
181class CubicPathBench : public HairlinePathBench {
182public:
183    CubicPathBench(Flags flags) : INHERITED(flags) {}
184
185    void appendName(SkString* name) override {
186        name->append("cubic");
187    }
188    void makePath(SkPath* path) override {
189        SkRandom rand;
190        int size = SK_ARRAY_COUNT(points);
191        int hSize = size / 2;
192        for (int i = 0; i < kMaxPathSize; ++i) {
193            int xTrans = 10 + 40 * (i%(kMaxPathSize/2));
194            int yTrans = 0;
195            if (i > kMaxPathSize/2 - 1) {
196                yTrans = 40;
197            }
198            int base1 = 2 * rand.nextULessThan(hSize);
199            int base2 = 2 * rand.nextULessThan(hSize);
200            int base3 = 2 * rand.nextULessThan(hSize);
201            int base4 = 2 * rand.nextULessThan(hSize);
202            path->moveTo(SkIntToScalar(points[base1] + xTrans),
203                         SkIntToScalar(points[base1+1] + yTrans));
204            path->cubicTo(SkIntToScalar(points[base2] + xTrans),
205                         SkIntToScalar(points[base2+1] + yTrans),
206                         SkIntToScalar(points[base3] + xTrans),
207                         SkIntToScalar(points[base3+1] + yTrans),
208                         SkIntToScalar(points[base4] + xTrans),
209                         SkIntToScalar(points[base4+1] + yTrans));
210        }
211    }
212private:
213    using INHERITED = HairlinePathBench;
214};
215
216// FLAG00 - no AA, small
217// FLAG01 - no AA, small
218// FLAG10 - AA, big
219// FLAG11 - AA, big
220
221DEF_BENCH( return new LinePathBench(FLAGS00); )
222DEF_BENCH( return new LinePathBench(FLAGS01); )
223DEF_BENCH( return new LinePathBench(FLAGS10); )
224DEF_BENCH( return new LinePathBench(FLAGS11); )
225
226DEF_BENCH( return new QuadPathBench(FLAGS00); )
227DEF_BENCH( return new QuadPathBench(FLAGS01); )
228DEF_BENCH( return new QuadPathBench(FLAGS10); )
229DEF_BENCH( return new QuadPathBench(FLAGS11); )
230
231// Don't have default path renderer for conics yet on GPU, so must use AA
232// DEF_BENCH( return new ConicPathBench(FLAGS00); )
233// DEF_BENCH( return new ConicPathBench(FLAGS01); )
234DEF_BENCH( return new ConicPathBench(FLAGS10); )
235DEF_BENCH( return new ConicPathBench(FLAGS11); )
236
237DEF_BENCH( return new CubicPathBench(FLAGS00); )
238DEF_BENCH( return new CubicPathBench(FLAGS01); )
239DEF_BENCH( return new CubicPathBench(FLAGS10); )
240DEF_BENCH( return new CubicPathBench(FLAGS11); )
241