Home | History | Annotate | Download | only in bench
      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 
     18 enum 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 
     28 class PathBench : public Benchmark {
     29     SkPaint     fPaint;
     30     SkString    fName;
     31     Flags       fFlags;
     32 public:
     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 
     44 protected:
     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 
     75 private:
     76     typedef Benchmark INHERITED;
     77 };
     78 
     79 class TrianglePathBench : public PathBench {
     80 public:
     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     }
     95 private:
     96     typedef PathBench INHERITED;
     97 };
     98 
     99 class RectPathBench : public PathBench {
    100 public:
    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     }
    110 private:
    111     typedef PathBench INHERITED;
    112 };
    113 
    114 class OvalPathBench : public PathBench {
    115 public:
    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     }
    125 private:
    126     typedef PathBench INHERITED;
    127 };
    128 
    129 class CirclePathBench: public PathBench {
    130 public:
    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     }
    140 private:
    141     typedef PathBench INHERITED;
    142 };
    143 
    144 class SawToothPathBench : public PathBench {
    145 public:
    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; }
    170 private:
    171     typedef PathBench INHERITED;
    172 };
    173 
    174 class LongCurvedPathBench : public PathBench {
    175 public:
    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; }
    193 private:
    194     typedef PathBench INHERITED;
    195 };
    196 
    197 class LongLinePathBench : public PathBench {
    198 public:
    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; }
    212 private:
    213     typedef PathBench INHERITED;
    214 };
    215 
    216 class RandomPathBench : public Benchmark {
    217 public:
    218     bool isSuitableFor(Backend backend) override {
    219         return backend == kNonRendering_Backend;
    220     }
    221 
    222 protected:
    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 
    300 private:
    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 
    317 class PathCreateBench : public RandomPathBench {
    318 public:
    319     PathCreateBench()  {
    320     }
    321 
    322 protected:
    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 
    341 private:
    342     SkPath fPath;
    343 
    344     typedef RandomPathBench INHERITED;
    345 };
    346 
    347 class PathCopyBench : public RandomPathBench {
    348 public:
    349     PathCopyBench()  {
    350     }
    351 
    352 protected:
    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 
    372 private:
    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 
    383 class PathTransformBench : public RandomPathBench {
    384 public:
    385     PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
    386 
    387 protected:
    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 
    418 private:
    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 
    431 class PathEqualityBench : public RandomPathBench {
    432 public:
    433     PathEqualityBench() { }
    434 
    435 protected:
    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 
    459 private:
    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 
    470 class SkBench_AddPathTest : public RandomPathBench {
    471 public:
    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 
    484 protected:
    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 
    556 private:
    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 
    569 class CirclesBench : public Benchmark {
    570 protected:
    571     SkString            fName;
    572     Flags               fFlags;
    573 
    574 public:
    575     CirclesBench(Flags flags) : fFlags(flags) {
    576         fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
    577     }
    578 
    579 protected:
    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 
    620 private:
    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)
    630 class ArbRoundRectBench : public Benchmark {
    631 protected:
    632     SkString            fName;
    633 
    634 public:
    635     ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
    636         if (zeroRad) {
    637             fName.printf("zeroradroundrect");
    638         } else {
    639             fName.printf("arbroundrect");
    640         }
    641     }
    642 
    643 protected:
    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 
    722 private:
    723     bool fZeroRad;      // should 0 radius rounds rects be tested?
    724 
    725     typedef Benchmark INHERITED;
    726 };
    727 
    728 class ConservativelyContainsBench : public Benchmark {
    729 public:
    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 
    759 private:
    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 
    808 class ConicBench_Chop : public Benchmark {
    809 protected:
    810     SkConic fRQ, fDst[2];
    811     SkString fName;
    812 public:
    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 
    824 private:
    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 };
    835 DEF_BENCH( return new ConicBench_Chop; )
    836 
    837 class ConicBench_EvalPos : public ConicBench_Chop {
    838     const bool fUseV2;
    839 public:
    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 };
    859 DEF_BENCH( return new ConicBench_EvalPos(false); )
    860 DEF_BENCH( return new ConicBench_EvalPos(true); )
    861 
    862 class ConicBench_EvalTan : public ConicBench_Chop {
    863     const bool fUseV2;
    864 public:
    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 };
    884 DEF_BENCH( return new ConicBench_EvalTan(false); )
    885 DEF_BENCH( return new ConicBench_EvalTan(true); )
    886 
    887 ///////////////////////////////////////////////////////////////////////////////
    888 
    889 static 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 
    900 class ConicBench : public Benchmark {
    901 public:
    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 
    913 protected:
    914     enum {
    915         CONICS = 100
    916     };
    917     SkConic fConics[CONICS];
    918 
    919 private:
    920     typedef Benchmark INHERITED;
    921 };
    922 
    923 class ConicBench_ComputeError : public ConicBench {
    924 public:
    925     ConicBench_ComputeError()  {}
    926 
    927 protected:
    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 
    941 private:
    942     typedef ConicBench INHERITED;
    943 };
    944 
    945 class ConicBench_asQuadTol : public ConicBench {
    946 public:
    947     ConicBench_asQuadTol()  {}
    948 
    949 protected:
    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 
    962 private:
    963     typedef ConicBench INHERITED;
    964 };
    965 
    966 class ConicBench_quadPow2 : public ConicBench {
    967 public:
    968     ConicBench_quadPow2()  {}
    969 
    970 protected:
    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 
    983 private:
    984     typedef ConicBench INHERITED;
    985 };
    986 
    987 ///////////////////////////////////////////////////////////////////////////////
    988 
    989 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
    990 const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1));
    991 const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40));
    992 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
    993 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
    994 
    995 DEF_BENCH( return new TrianglePathBench(FLAGS00); )
    996 DEF_BENCH( return new TrianglePathBench(FLAGS01); )
    997 DEF_BENCH( return new TrianglePathBench(FLAGS10); )
    998 DEF_BENCH( return new TrianglePathBench(FLAGS11); )
    999 
   1000 DEF_BENCH( return new RectPathBench(FLAGS00); )
   1001 DEF_BENCH( return new RectPathBench(FLAGS01); )
   1002 DEF_BENCH( return new RectPathBench(FLAGS10); )
   1003 DEF_BENCH( return new RectPathBench(FLAGS11); )
   1004 
   1005 DEF_BENCH( return new OvalPathBench(FLAGS00); )
   1006 DEF_BENCH( return new OvalPathBench(FLAGS01); )
   1007 DEF_BENCH( return new OvalPathBench(FLAGS10); )
   1008 DEF_BENCH( return new OvalPathBench(FLAGS11); )
   1009 
   1010 DEF_BENCH( return new CirclePathBench(FLAGS00); )
   1011 DEF_BENCH( return new CirclePathBench(FLAGS01); )
   1012 DEF_BENCH( return new CirclePathBench(FLAGS10); )
   1013 DEF_BENCH( return new CirclePathBench(FLAGS11); )
   1014 
   1015 DEF_BENCH( return new SawToothPathBench(FLAGS00); )
   1016 DEF_BENCH( return new SawToothPathBench(FLAGS01); )
   1017 
   1018 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
   1019 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
   1020 DEF_BENCH( return new LongLinePathBench(FLAGS00); )
   1021 DEF_BENCH( return new LongLinePathBench(FLAGS01); )
   1022 
   1023 DEF_BENCH( return new PathCreateBench(); )
   1024 DEF_BENCH( return new PathCopyBench(); )
   1025 DEF_BENCH( return new PathTransformBench(true); )
   1026 DEF_BENCH( return new PathTransformBench(false); )
   1027 DEF_BENCH( return new PathEqualityBench(); )
   1028 
   1029 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
   1030 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
   1031 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
   1032 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
   1033 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
   1034 
   1035 DEF_BENCH( return new CirclesBench(FLAGS00); )
   1036 DEF_BENCH( return new CirclesBench(FLAGS01); )
   1037 DEF_BENCH( return new ArbRoundRectBench(false); )
   1038 DEF_BENCH( return new ArbRoundRectBench(true); )
   1039 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
   1040 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
   1041 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
   1042 
   1043 
   1044 // These seem to be optimized away, which is troublesome for timing.
   1045 /*
   1046 DEF_BENCH( return new ConicBench_Chop5() )
   1047 DEF_BENCH( return new ConicBench_ComputeError() )
   1048 DEF_BENCH( return new ConicBench_asQuadTol() )
   1049 DEF_BENCH( return new ConicBench_quadPow2() )
   1050 */
   1051