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 "SkBitmap.h"
10#include "SkCanvas.h"
11#include "SkColorPriv.h"
12#include "SkPaint.h"
13#include "SkRandom.h"
14#include "SkShader.h"
15#include "SkString.h"
16#include "SkTArray.h"
17
18enum Flags {
19    kStroke_Flag = 1 << 0,
20    kBig_Flag    = 1 << 1
21};
22
23#define FLAGS00  Flags(0)
24#define FLAGS01  Flags(kStroke_Flag)
25#define FLAGS10  Flags(kBig_Flag)
26#define FLAGS11  Flags(kStroke_Flag | kBig_Flag)
27
28class PathBench : public Benchmark {
29    SkPaint     fPaint;
30    SkString    fName;
31    Flags       fFlags;
32public:
33    PathBench(Flags flags) : fFlags(flags) {
34        fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
35                        SkPaint::kFill_Style);
36        fPaint.setStrokeWidth(SkIntToScalar(5));
37        fPaint.setStrokeJoin(SkPaint::kBevel_Join);
38    }
39
40    virtual void appendName(SkString*) = 0;
41    virtual void makePath(SkPath*) = 0;
42    virtual int complexity() { return 0; }
43
44protected:
45    virtual const char* onGetName() SK_OVERRIDE {
46        fName.printf("path_%s_%s_",
47                     fFlags & kStroke_Flag ? "stroke" : "fill",
48                     fFlags & kBig_Flag ? "big" : "small");
49        this->appendName(&fName);
50        return fName.c_str();
51    }
52
53    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
54        SkPaint paint(fPaint);
55        this->setupPaint(&paint);
56
57        SkPath path;
58        this->makePath(&path);
59        if (fFlags & kBig_Flag) {
60            SkMatrix m;
61            m.setScale(SkIntToScalar(10), SkIntToScalar(10));
62            path.transform(m);
63        }
64
65        int count = loops;
66        if (fFlags & kBig_Flag) {
67            count >>= 2;
68        }
69        count >>= (3 * complexity());
70
71        for (int i = 0; i < count; i++) {
72            canvas->drawPath(path, paint);
73        }
74    }
75
76private:
77    typedef Benchmark INHERITED;
78};
79
80class TrianglePathBench : public PathBench {
81public:
82    TrianglePathBench(Flags flags) : INHERITED(flags) {}
83
84    virtual void appendName(SkString* name) SK_OVERRIDE {
85        name->append("triangle");
86    }
87    virtual void makePath(SkPath* path) SK_OVERRIDE {
88        static const int gCoord[] = {
89            10, 10, 15, 5, 20, 20
90        };
91        path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
92        path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
93        path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
94        path->close();
95    }
96private:
97    typedef PathBench INHERITED;
98};
99
100class RectPathBench : public PathBench {
101public:
102    RectPathBench(Flags flags) : INHERITED(flags) {}
103
104    virtual void appendName(SkString* name) SK_OVERRIDE {
105        name->append("rect");
106    }
107    virtual void makePath(SkPath* path) SK_OVERRIDE {
108        SkRect r = { 10, 10, 20, 20 };
109        path->addRect(r);
110    }
111private:
112    typedef PathBench INHERITED;
113};
114
115class OvalPathBench : public PathBench {
116public:
117    OvalPathBench(Flags flags) : INHERITED(flags) {}
118
119    virtual void appendName(SkString* name) SK_OVERRIDE {
120        name->append("oval");
121    }
122    virtual void makePath(SkPath* path) SK_OVERRIDE {
123        SkRect r = { 10, 10, 23, 20 };
124        path->addOval(r);
125    }
126private:
127    typedef PathBench INHERITED;
128};
129
130class CirclePathBench: public PathBench {
131public:
132    CirclePathBench(Flags flags) : INHERITED(flags) {}
133
134    virtual void appendName(SkString* name) SK_OVERRIDE {
135        name->append("circle");
136    }
137    virtual void makePath(SkPath* path) SK_OVERRIDE {
138        path->addCircle(SkIntToScalar(20), SkIntToScalar(20),
139                        SkIntToScalar(10));
140    }
141private:
142    typedef PathBench INHERITED;
143};
144
145class SawToothPathBench : public PathBench {
146public:
147    SawToothPathBench(Flags flags) : INHERITED(flags) {}
148
149    virtual void appendName(SkString* name) SK_OVERRIDE {
150        name->append("sawtooth");
151    }
152    virtual void makePath(SkPath* path) {
153        SkScalar x = SkIntToScalar(20);
154        SkScalar y = SkIntToScalar(20);
155        const SkScalar x0 = x;
156        const SkScalar dx = SK_Scalar1 * 5;
157        const SkScalar dy = SK_Scalar1 * 10;
158
159        path->moveTo(x, y);
160        for (int i = 0; i < 32; i++) {
161            x += dx;
162            path->lineTo(x, y - dy);
163            x += dx;
164            path->lineTo(x, y + dy);
165        }
166        path->lineTo(x, y + 2 * dy);
167        path->lineTo(x0, y + 2 * dy);
168        path->close();
169    }
170    virtual int complexity() SK_OVERRIDE { return 1; }
171private:
172    typedef PathBench INHERITED;
173};
174
175class LongCurvedPathBench : public PathBench {
176public:
177    LongCurvedPathBench(Flags flags) : INHERITED(flags) {}
178
179    virtual void appendName(SkString* name) SK_OVERRIDE {
180        name->append("long_curved");
181    }
182    virtual void makePath(SkPath* path) SK_OVERRIDE {
183        SkRandom rand (12);
184        int i;
185        for (i = 0; i < 100; i++) {
186            path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
187                         SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)),
188                         SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
189                         SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)));
190        }
191        path->close();
192    }
193    virtual int complexity() SK_OVERRIDE { return 2; }
194private:
195    typedef PathBench INHERITED;
196};
197
198class LongLinePathBench : public PathBench {
199public:
200    LongLinePathBench(Flags flags) : INHERITED(flags) {}
201
202    virtual void appendName(SkString* name) SK_OVERRIDE {
203        name->append("long_line");
204    }
205    virtual void makePath(SkPath* path) SK_OVERRIDE {
206        SkRandom rand;
207        path->moveTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
208        for (size_t i = 1; i < 100; i++) {
209            path->lineTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
210        }
211    }
212    virtual int complexity() SK_OVERRIDE { return 2; }
213private:
214    typedef PathBench INHERITED;
215};
216
217class RandomPathBench : public Benchmark {
218public:
219    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
220        return backend == kNonRendering_Backend;
221    }
222
223protected:
224    void createData(int minVerbs,
225                    int maxVerbs,
226                    bool allowMoves = true,
227                    SkRect* bounds = NULL) {
228        SkRect tempBounds;
229        if (NULL == bounds) {
230            tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
231            bounds = &tempBounds;
232        }
233        fVerbCnts.reset(kNumVerbCnts);
234        for (int i = 0; i < kNumVerbCnts; ++i) {
235            fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
236        }
237        fVerbs.reset(kNumVerbs);
238        for (int i = 0; i < kNumVerbs; ++i) {
239            do {
240                fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb));
241            } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]);
242        }
243        fPoints.reset(kNumPoints);
244        for (int i = 0; i < kNumPoints; ++i) {
245            fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
246                           fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
247        }
248        this->restartMakingPaths();
249    }
250
251    void restartMakingPaths() {
252        fCurrPath = 0;
253        fCurrVerb = 0;
254        fCurrPoint = 0;
255    }
256
257    void makePath(SkPath* path) {
258        int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)];
259        for (int v = 0; v < vCount; ++v) {
260            int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)];
261            switch (verb) {
262                case SkPath::kMove_Verb:
263                    path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
264                    break;
265                case SkPath::kLine_Verb:
266                    path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
267                    break;
268                case SkPath::kQuad_Verb:
269                    path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
270                                 fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
271                    fCurrPoint += 2;
272                    break;
273                case SkPath::kConic_Verb:
274                    path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
275                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
276                                  SK_ScalarHalf);
277                    fCurrPoint += 2;
278                    break;
279                case SkPath::kCubic_Verb:
280                    path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
281                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
282                                  fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]);
283                    fCurrPoint += 3;
284                    break;
285                case SkPath::kClose_Verb:
286                    path->close();
287                    break;
288                default:
289                    SkDEBUGFAIL("Unexpected path verb");
290                    break;
291            }
292        }
293    }
294
295    void finishedMakingPaths() {
296        fVerbCnts.reset(0);
297        fVerbs.reset(0);
298        fPoints.reset(0);
299    }
300
301private:
302    enum {
303        // these should all be pow 2
304        kNumVerbCnts = 1 << 5,
305        kNumVerbs    = 1 << 5,
306        kNumPoints   = 1 << 5,
307    };
308    SkAutoTArray<int>           fVerbCnts;
309    SkAutoTArray<SkPath::Verb>  fVerbs;
310    SkAutoTArray<SkPoint>       fPoints;
311    int                         fCurrPath;
312    int                         fCurrVerb;
313    int                         fCurrPoint;
314    SkRandom                    fRandom;
315    typedef Benchmark INHERITED;
316};
317
318class PathCreateBench : public RandomPathBench {
319public:
320    PathCreateBench()  {
321    }
322
323protected:
324    virtual const char* onGetName() SK_OVERRIDE {
325        return "path_create";
326    }
327
328    virtual void onPreDraw() SK_OVERRIDE {
329        this->createData(10, 100);
330    }
331
332    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
333        for (int i = 0; i < loops; ++i) {
334            if (i % 1000 == 0) {
335                fPath.reset();  // PathRef memory can grow without bound otherwise.
336            }
337            this->makePath(&fPath);
338        }
339        this->restartMakingPaths();
340    }
341
342private:
343    SkPath fPath;
344
345    typedef RandomPathBench INHERITED;
346};
347
348class PathCopyBench : public RandomPathBench {
349public:
350    PathCopyBench()  {
351    }
352
353protected:
354    virtual const char* onGetName() SK_OVERRIDE {
355        return "path_copy";
356    }
357    virtual void onPreDraw() SK_OVERRIDE {
358        this->createData(10, 100);
359        fPaths.reset(kPathCnt);
360        fCopies.reset(kPathCnt);
361        for (int i = 0; i < kPathCnt; ++i) {
362            this->makePath(&fPaths[i]);
363        }
364        this->finishedMakingPaths();
365    }
366    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
367        for (int i = 0; i < loops; ++i) {
368            int idx = i & (kPathCnt - 1);
369            fCopies[idx] = fPaths[idx];
370        }
371    }
372
373private:
374    enum {
375        // must be a pow 2
376        kPathCnt = 1 << 5,
377    };
378    SkAutoTArray<SkPath> fPaths;
379    SkAutoTArray<SkPath> fCopies;
380
381    typedef RandomPathBench INHERITED;
382};
383
384class PathTransformBench : public RandomPathBench {
385public:
386    PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
387
388protected:
389    virtual const char* onGetName() SK_OVERRIDE {
390        return fInPlace ? "path_transform_in_place" : "path_transform_copy";
391    }
392
393    virtual void onPreDraw() SK_OVERRIDE {
394        fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1);
395        this->createData(10, 100);
396        fPaths.reset(kPathCnt);
397        for (int i = 0; i < kPathCnt; ++i) {
398            this->makePath(&fPaths[i]);
399        }
400        this->finishedMakingPaths();
401        if (!fInPlace) {
402            fTransformed.reset(kPathCnt);
403        }
404    }
405
406    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
407        if (fInPlace) {
408            for (int i = 0; i < loops; ++i) {
409                fPaths[i & (kPathCnt - 1)].transform(fMatrix);
410            }
411        } else {
412            for (int i = 0; i < loops; ++i) {
413                int idx = i & (kPathCnt - 1);
414                fPaths[idx].transform(fMatrix, &fTransformed[idx]);
415            }
416        }
417    }
418
419private:
420    enum {
421        // must be a pow 2
422        kPathCnt = 1 << 5,
423    };
424    SkAutoTArray<SkPath> fPaths;
425    SkAutoTArray<SkPath> fTransformed;
426
427    SkMatrix fMatrix;
428    bool fInPlace;
429    typedef RandomPathBench INHERITED;
430};
431
432class PathEqualityBench : public RandomPathBench {
433public:
434    PathEqualityBench() { }
435
436protected:
437    virtual const char* onGetName() SK_OVERRIDE {
438        return "path_equality_50%";
439    }
440
441    virtual void onPreDraw() SK_OVERRIDE {
442        fParity = 0;
443        this->createData(10, 100);
444        fPaths.reset(kPathCnt);
445        fCopies.reset(kPathCnt);
446        for (int i = 0; i < kPathCnt; ++i) {
447            this->makePath(&fPaths[i]);
448            fCopies[i] = fPaths[i];
449        }
450        this->finishedMakingPaths();
451    }
452
453    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
454        for (int i = 0; i < loops; ++i) {
455            int idx = i & (kPathCnt - 1);
456            fParity ^= (fPaths[idx] == fCopies[idx & ~0x1]);
457        }
458    }
459
460private:
461    bool fParity; // attempt to keep compiler from optimizing out the ==
462    enum {
463        // must be a pow 2
464        kPathCnt = 1 << 5,
465    };
466    SkAutoTArray<SkPath> fPaths;
467    SkAutoTArray<SkPath> fCopies;
468    typedef RandomPathBench INHERITED;
469};
470
471class SkBench_AddPathTest : public RandomPathBench {
472public:
473    enum AddType {
474        kAdd_AddType,
475        kAddTrans_AddType,
476        kAddMatrix_AddType,
477        kReverseAdd_AddType,
478        kReversePathTo_AddType,
479    };
480
481    SkBench_AddPathTest(AddType type) : fType(type) {
482        fMatrix.setRotate(60 * SK_Scalar1);
483    }
484
485protected:
486    virtual const char* onGetName() SK_OVERRIDE {
487        switch (fType) {
488            case kAdd_AddType:
489                return "path_add_path";
490            case kAddTrans_AddType:
491                return "path_add_path_trans";
492            case kAddMatrix_AddType:
493                return "path_add_path_matrix";
494            case kReverseAdd_AddType:
495                return "path_reverse_add_path";
496            case kReversePathTo_AddType:
497                return "path_reverse_path_to";
498            default:
499                SkDEBUGFAIL("Bad add type");
500                return "";
501        }
502    }
503
504    virtual void onPreDraw() SK_OVERRIDE {
505        // reversePathTo assumes a single contour path.
506        bool allowMoves = kReversePathTo_AddType != fType;
507        this->createData(10, 100, allowMoves);
508        fPaths0.reset(kPathCnt);
509        fPaths1.reset(kPathCnt);
510        for (int i = 0; i < kPathCnt; ++i) {
511            this->makePath(&fPaths0[i]);
512            this->makePath(&fPaths1[i]);
513        }
514        this->finishedMakingPaths();
515    }
516
517    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
518        switch (fType) {
519            case kAdd_AddType:
520                for (int i = 0; i < loops; ++i) {
521                    int idx = i & (kPathCnt - 1);
522                    SkPath result = fPaths0[idx];
523                    result.addPath(fPaths1[idx]);
524                }
525                break;
526            case kAddTrans_AddType:
527                for (int i = 0; i < loops; ++i) {
528                    int idx = i & (kPathCnt - 1);
529                    SkPath result = fPaths0[idx];
530                    result.addPath(fPaths1[idx], 2 * SK_Scalar1, 5 * SK_Scalar1);
531                }
532                break;
533            case kAddMatrix_AddType:
534                for (int i = 0; i < loops; ++i) {
535                    int idx = i & (kPathCnt - 1);
536                    SkPath result = fPaths0[idx];
537                    result.addPath(fPaths1[idx], fMatrix);
538                }
539                break;
540            case kReverseAdd_AddType:
541                for (int i = 0; i < loops; ++i) {
542                    int idx = i & (kPathCnt - 1);
543                    SkPath result = fPaths0[idx];
544                    result.reverseAddPath(fPaths1[idx]);
545                }
546                break;
547            case kReversePathTo_AddType:
548                for (int i = 0; i < loops; ++i) {
549                    int idx = i & (kPathCnt - 1);
550                    SkPath result = fPaths0[idx];
551                    result.reversePathTo(fPaths1[idx]);
552                }
553                break;
554        }
555    }
556
557private:
558    AddType fType; // or reverseAddPath
559    enum {
560        // must be a pow 2
561        kPathCnt = 1 << 5,
562    };
563    SkAutoTArray<SkPath> fPaths0;
564    SkAutoTArray<SkPath> fPaths1;
565    SkMatrix         fMatrix;
566    typedef RandomPathBench INHERITED;
567};
568
569
570class CirclesBench : public Benchmark {
571protected:
572    SkString            fName;
573    Flags               fFlags;
574
575public:
576    CirclesBench(Flags flags) : fFlags(flags) {
577        fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
578    }
579
580protected:
581    virtual const char* onGetName() SK_OVERRIDE {
582        return fName.c_str();
583    }
584
585    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
586        SkPaint paint;
587
588        paint.setColor(SK_ColorBLACK);
589        paint.setAntiAlias(true);
590        if (fFlags & kStroke_Flag) {
591            paint.setStyle(SkPaint::kStroke_Style);
592        }
593
594        SkRandom rand;
595
596        SkRect r;
597
598        for (int i = 0; i < loops; ++i) {
599            SkScalar radius = rand.nextUScalar1() * 3;
600            r.fLeft = rand.nextUScalar1() * 300;
601            r.fTop =  rand.nextUScalar1() * 300;
602            r.fRight =  r.fLeft + 2 * radius;
603            r.fBottom = r.fTop + 2 * radius;
604
605            if (fFlags & kStroke_Flag) {
606                paint.setStrokeWidth(rand.nextUScalar1() * 5.0f);
607            }
608
609            SkPath temp;
610
611            // mimic how Chrome does circles
612            temp.arcTo(r, 0, 0, false);
613            temp.addOval(r, SkPath::kCCW_Direction);
614            temp.arcTo(r, 360, 0, true);
615            temp.close();
616
617            canvas->drawPath(temp, paint);
618        }
619    }
620
621private:
622    typedef Benchmark INHERITED;
623};
624
625
626// Chrome creates its own round rects with each corner possibly being different.
627// In its "zero radius" incarnation it creates degenerate round rects.
628// Note: PathTest::test_arb_round_rect_is_convex and
629// test_arb_zero_rad_round_rect_is_rect perform almost exactly
630// the same test (but with no drawing)
631class ArbRoundRectBench : public Benchmark {
632protected:
633    SkString            fName;
634
635public:
636    ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
637        if (zeroRad) {
638            fName.printf("zeroradroundrect");
639        } else {
640            fName.printf("arbroundrect");
641        }
642    }
643
644protected:
645    virtual const char* onGetName() SK_OVERRIDE {
646        return fName.c_str();
647    }
648
649    static void add_corner_arc(SkPath* path, const SkRect& rect,
650                               SkScalar xIn, SkScalar yIn,
651                               int startAngle)
652    {
653
654        SkScalar rx = SkMinScalar(rect.width(), xIn);
655        SkScalar ry = SkMinScalar(rect.height(), yIn);
656
657        SkRect arcRect;
658        arcRect.set(-rx, -ry, rx, ry);
659        switch (startAngle) {
660        case 0:
661            arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
662            break;
663        case 90:
664            arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
665            break;
666        case 180:
667            arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
668            break;
669        case 270:
670            arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
671            break;
672        default:
673            break;
674        }
675
676        path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
677    }
678
679    static void make_arb_round_rect(SkPath* path, const SkRect& r,
680                                    SkScalar xCorner, SkScalar yCorner) {
681        // we are lazy here and use the same x & y for each corner
682        add_corner_arc(path, r, xCorner, yCorner, 270);
683        add_corner_arc(path, r, xCorner, yCorner, 0);
684        add_corner_arc(path, r, xCorner, yCorner, 90);
685        add_corner_arc(path, r, xCorner, yCorner, 180);
686        path->close();
687
688        SkASSERT(path->isConvex());
689    }
690
691    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
692        SkRandom rand;
693        SkRect r;
694
695        for (int i = 0; i < loops; ++i) {
696            SkPaint paint;
697            paint.setColor(0xff000000 | rand.nextU());
698            paint.setAntiAlias(true);
699
700            SkScalar size = rand.nextUScalar1() * 30;
701            if (size < SK_Scalar1) {
702                continue;
703            }
704            r.fLeft = rand.nextUScalar1() * 300;
705            r.fTop =  rand.nextUScalar1() * 300;
706            r.fRight =  r.fLeft + 2 * size;
707            r.fBottom = r.fTop + 2 * size;
708
709            SkPath temp;
710
711            if (fZeroRad) {
712                make_arb_round_rect(&temp, r, 0, 0);
713
714                SkASSERT(temp.isRect(NULL));
715            } else {
716                make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
717            }
718
719            canvas->drawPath(temp, paint);
720        }
721    }
722
723private:
724    bool fZeroRad;      // should 0 radius rounds rects be tested?
725
726    typedef Benchmark INHERITED;
727};
728
729class ConservativelyContainsBench : public Benchmark {
730public:
731    enum Type {
732        kRect_Type,
733        kRoundRect_Type,
734        kOval_Type,
735    };
736
737    ConservativelyContainsBench(Type type)  {
738        fParity = false;
739        fName = "conservatively_contains_";
740        switch (type) {
741            case kRect_Type:
742                fName.append("rect");
743                fPath.addRect(kBaseRect);
744                break;
745            case kRoundRect_Type:
746                fName.append("round_rect");
747                fPath.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1]);
748                break;
749            case kOval_Type:
750                fName.append("oval");
751                fPath.addOval(kBaseRect);
752                break;
753        }
754    }
755
756    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
757        return backend == kNonRendering_Backend;
758    }
759
760private:
761    virtual const char* onGetName() SK_OVERRIDE {
762        return fName.c_str();
763    }
764
765    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
766        for (int i = 0; i < loops; ++i) {
767            const SkRect& rect = fQueryRects[i % kQueryRectCnt];
768            fParity = fParity != fPath.conservativelyContainsRect(rect);
769        }
770    }
771
772    virtual void onPreDraw() SK_OVERRIDE {
773        fQueryRects.setCount(kQueryRectCnt);
774
775        SkRandom rand;
776        for (int i = 0; i < kQueryRectCnt; ++i) {
777            SkSize size;
778            SkPoint xy;
779            size.fWidth = rand.nextRangeScalar(kQueryMin.fWidth,  kQueryMax.fWidth);
780            size.fHeight = rand.nextRangeScalar(kQueryMin.fHeight, kQueryMax.fHeight);
781            xy.fX = rand.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth);
782            xy.fY = rand.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight);
783
784            fQueryRects[i] = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
785        }
786    }
787
788    enum {
789        kQueryRectCnt = 400,
790    };
791    static const SkRect kBounds;   // bounds for all random query rects
792    static const SkSize kQueryMin; // minimum query rect size, should be <= kQueryMax
793    static const SkSize kQueryMax; // max query rect size, should < kBounds
794    static const SkRect kBaseRect; // rect that is used to construct the path
795    static const SkScalar kRRRadii[2]; // x and y radii for round rect
796
797    SkString            fName;
798    SkPath              fPath;
799    bool                fParity;
800    SkTDArray<SkRect>   fQueryRects;
801
802    typedef Benchmark INHERITED;
803};
804
805///////////////////////////////////////////////////////////////////////////////
806
807#include "SkGeometry.h"
808
809class ConicBench_Chop5 : public Benchmark {
810    SkConic fRQ;
811public:
812    ConicBench_Chop5()  {
813        fRQ.fPts[0].set(0, 0);
814        fRQ.fPts[1].set(100, 0);
815        fRQ.fPts[2].set(100, 100);
816        fRQ.fW = SkScalarCos(SK_ScalarPI/4);
817    }
818
819private:
820    virtual const char* onGetName() SK_OVERRIDE {
821        return "ratquad-chop-0.5";
822    }
823
824    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
825        SkConic dst[2];
826        for (int i = 0; i < loops; ++i) {
827            fRQ.chopAt(0.5f, dst);
828        }
829    }
830
831    typedef Benchmark INHERITED;
832};
833
834class ConicBench_ChopHalf : public Benchmark {
835    SkConic fRQ;
836public:
837    ConicBench_ChopHalf()  {
838        fRQ.fPts[0].set(0, 0);
839        fRQ.fPts[1].set(100, 0);
840        fRQ.fPts[2].set(100, 100);
841        fRQ.fW = SkScalarCos(SK_ScalarPI/4);
842    }
843
844private:
845    virtual const char* onGetName() SK_OVERRIDE {
846        return "ratquad-chop-half";
847    }
848
849    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
850        SkConic dst[2];
851        for (int i = 0; i < loops; ++i) {
852            fRQ.chop(dst);
853        }
854    }
855
856    typedef Benchmark INHERITED;
857};
858
859///////////////////////////////////////////////////////////////////////////////
860
861static void rand_conic(SkConic* conic, SkRandom& rand) {
862    for (int i = 0; i < 3; ++i) {
863        conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
864    }
865    if (rand.nextUScalar1() > 0.5f) {
866        conic->fW = rand.nextUScalar1();
867    } else {
868        conic->fW = 1 + rand.nextUScalar1() * 4;
869    }
870}
871
872class ConicBench : public Benchmark {
873public:
874    ConicBench()  {
875        SkRandom rand;
876        for (int i = 0; i < CONICS; ++i) {
877            rand_conic(&fConics[i], rand);
878        }
879    }
880
881    virtual bool isSuitableFor(Backend backend) SK_OVERRIDE {
882        return backend == kNonRendering_Backend;
883    }
884
885protected:
886    enum {
887        CONICS = 100
888    };
889    SkConic fConics[CONICS];
890
891private:
892    typedef Benchmark INHERITED;
893};
894
895class ConicBench_ComputeError : public ConicBench {
896public:
897    ConicBench_ComputeError()  {}
898
899protected:
900    virtual const char* onGetName() SK_OVERRIDE {
901        return "conic-compute-error";
902    }
903
904    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
905        SkVector err;
906        for (int i = 0; i < loops; ++i) {
907            for (int j = 0; j < CONICS; ++j) {
908                fConics[j].computeAsQuadError(&err);
909            }
910        }
911    }
912
913private:
914    typedef ConicBench INHERITED;
915};
916
917class ConicBench_asQuadTol : public ConicBench {
918public:
919    ConicBench_asQuadTol()  {}
920
921protected:
922    virtual const char* onGetName() SK_OVERRIDE {
923        return "conic-asQuadTol";
924    }
925
926    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
927        for (int i = 0; i < loops; ++i) {
928            for (int j = 0; j < CONICS; ++j) {
929                fConics[j].asQuadTol(SK_ScalarHalf);
930            }
931        }
932    }
933
934private:
935    typedef ConicBench INHERITED;
936};
937
938class ConicBench_quadPow2 : public ConicBench {
939public:
940    ConicBench_quadPow2()  {}
941
942protected:
943    virtual const char* onGetName() SK_OVERRIDE {
944        return "conic-quadPow2";
945    }
946
947    virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE {
948        for (int i = 0; i < loops; ++i) {
949            for (int j = 0; j < CONICS; ++j) {
950                fConics[j].computeQuadPOW2(SK_ScalarHalf);
951            }
952        }
953    }
954
955private:
956    typedef ConicBench INHERITED;
957};
958
959///////////////////////////////////////////////////////////////////////////////
960
961const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
962const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1));
963const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40));
964const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
965const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
966
967DEF_BENCH( return new TrianglePathBench(FLAGS00); )
968DEF_BENCH( return new TrianglePathBench(FLAGS01); )
969DEF_BENCH( return new TrianglePathBench(FLAGS10); )
970DEF_BENCH( return new TrianglePathBench(FLAGS11); )
971
972DEF_BENCH( return new RectPathBench(FLAGS00); )
973DEF_BENCH( return new RectPathBench(FLAGS01); )
974DEF_BENCH( return new RectPathBench(FLAGS10); )
975DEF_BENCH( return new RectPathBench(FLAGS11); )
976
977DEF_BENCH( return new OvalPathBench(FLAGS00); )
978DEF_BENCH( return new OvalPathBench(FLAGS01); )
979DEF_BENCH( return new OvalPathBench(FLAGS10); )
980DEF_BENCH( return new OvalPathBench(FLAGS11); )
981
982DEF_BENCH( return new CirclePathBench(FLAGS00); )
983DEF_BENCH( return new CirclePathBench(FLAGS01); )
984DEF_BENCH( return new CirclePathBench(FLAGS10); )
985DEF_BENCH( return new CirclePathBench(FLAGS11); )
986
987DEF_BENCH( return new SawToothPathBench(FLAGS00); )
988DEF_BENCH( return new SawToothPathBench(FLAGS01); )
989
990DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
991DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
992DEF_BENCH( return new LongLinePathBench(FLAGS00); )
993DEF_BENCH( return new LongLinePathBench(FLAGS01); )
994
995DEF_BENCH( return new PathCreateBench(); )
996DEF_BENCH( return new PathCopyBench(); )
997DEF_BENCH( return new PathTransformBench(true); )
998DEF_BENCH( return new PathTransformBench(false); )
999DEF_BENCH( return new PathEqualityBench(); )
1000
1001DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
1002DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
1003DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
1004DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
1005DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
1006
1007DEF_BENCH( return new CirclesBench(FLAGS00); )
1008DEF_BENCH( return new CirclesBench(FLAGS01); )
1009DEF_BENCH( return new ArbRoundRectBench(false); )
1010DEF_BENCH( return new ArbRoundRectBench(true); )
1011DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
1012DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
1013DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
1014
1015// These seem to be optimized away, which is troublesome for timing.
1016/*
1017DEF_BENCH( return new ConicBench_Chop5() )
1018DEF_BENCH( return new ConicBench_ChopHalf() )
1019DEF_BENCH( return new ConicBench_ComputeError() )
1020DEF_BENCH( return new ConicBench_asQuadTol() )
1021DEF_BENCH( return new ConicBench_quadPow2() )
1022*/
1023