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