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