xref: /aosp_15_r20/external/skia/bench/PathBench.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2011 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "bench/Benchmark.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColorPriv.h"
12 #include "include/core/SkPaint.h"
13 #include "include/core/SkPath.h"
14 #include "include/core/SkPathUtils.h"
15 #include "include/core/SkRRect.h"
16 #include "include/core/SkShader.h"
17 #include "include/core/SkString.h"
18 #include "include/private/base/SkTArray.h"
19 #include "include/private/base/SkTDArray.h"
20 #include "src/base/SkRandom.h"
21 
22 #include "src/core/SkDraw.h"
23 #include "src/core/SkMatrixPriv.h"
24 
25 using namespace skia_private;
26 
27 enum Flags {
28     kStroke_Flag = 1 << 0,
29     kBig_Flag    = 1 << 1
30 };
31 
32 #define FLAGS00  Flags(0)
33 #define FLAGS01  Flags(kStroke_Flag)
34 #define FLAGS10  Flags(kBig_Flag)
35 #define FLAGS11  Flags(kStroke_Flag | kBig_Flag)
36 
37 class PathBench : public Benchmark {
38     SkPaint     fPaint;
39     SkString    fName;
40     Flags       fFlags;
41 public:
PathBench(Flags flags)42     PathBench(Flags flags) : fFlags(flags) {
43         fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
44                         SkPaint::kFill_Style);
45         fPaint.setStrokeWidth(SkIntToScalar(5));
46         fPaint.setStrokeJoin(SkPaint::kBevel_Join);
47     }
48 
49     virtual void appendName(SkString*) = 0;
50     virtual void makePath(SkPath*) = 0;
complexity()51     virtual int complexity() { return 0; }
52 
53 protected:
onGetName()54     const char* onGetName() override {
55         fName.printf("path_%s_%s_",
56                      fFlags & kStroke_Flag ? "stroke" : "fill",
57                      fFlags & kBig_Flag ? "big" : "small");
58         this->appendName(&fName);
59         return fName.c_str();
60     }
61 
onDraw(int loops,SkCanvas * canvas)62     void onDraw(int loops, SkCanvas* canvas) override {
63         SkPaint paint(fPaint);
64         this->setupPaint(&paint);
65 
66         SkPath path;
67         this->makePath(&path);
68         if (fFlags & kBig_Flag) {
69             const SkMatrix m = SkMatrix::Scale(10, 10);
70             path.transform(m);
71         }
72 
73         for (int i = 0; i < loops; i++) {
74             canvas->drawPath(path, paint);
75         }
76     }
77 
78 private:
79     using INHERITED = Benchmark;
80 };
81 
82 class TrianglePathBench : public PathBench {
83 public:
TrianglePathBench(Flags flags)84     TrianglePathBench(Flags flags) : INHERITED(flags) {}
85 
appendName(SkString * name)86     void appendName(SkString* name) override {
87         name->append("triangle");
88     }
makePath(SkPath * path)89     void makePath(SkPath* path) override {
90         static const int gCoord[] = {
91             10, 10, 15, 5, 20, 20
92         };
93         path->moveTo(SkIntToScalar(gCoord[0]), SkIntToScalar(gCoord[1]));
94         path->lineTo(SkIntToScalar(gCoord[2]), SkIntToScalar(gCoord[3]));
95         path->lineTo(SkIntToScalar(gCoord[4]), SkIntToScalar(gCoord[5]));
96         path->close();
97     }
98 private:
99     using INHERITED = PathBench;
100 };
101 
102 class RectPathBench : public PathBench {
103 public:
RectPathBench(Flags flags)104     RectPathBench(Flags flags) : INHERITED(flags) {}
105 
appendName(SkString * name)106     void appendName(SkString* name) override {
107         name->append("rect");
108     }
makePath(SkPath * path)109     void makePath(SkPath* path) override {
110         SkRect r = { 10, 10, 20, 20 };
111         path->addRect(r);
112     }
113 private:
114     using INHERITED = PathBench;
115 };
116 
117 class RotatedRectBench : public PathBench {
118 public:
RotatedRectBench(Flags flags,bool aa,int degrees)119     RotatedRectBench(Flags flags, bool aa, int degrees) : INHERITED(flags) {
120         fAA = aa;
121         fDegrees = degrees;
122     }
123 
appendName(SkString * name)124     void appendName(SkString* name) override {
125         SkString suffix;
126         suffix.printf("rotated_rect_%s_%d", fAA ? "aa" : "noaa", fDegrees);
127         name->append(suffix);
128     }
129 
makePath(SkPath * path)130     void makePath(SkPath* path) override {
131         SkRect r = { 10, 10, 20, 20 };
132         path->addRect(r);
133         SkMatrix rotateMatrix;
134         rotateMatrix.setRotate((SkScalar)fDegrees);
135         path->transform(rotateMatrix);
136     }
137 
setupPaint(SkPaint * paint)138     void setupPaint(SkPaint* paint) override {
139         PathBench::setupPaint(paint);
140         paint->setAntiAlias(fAA);
141     }
142 private:
143     using INHERITED = PathBench;
144     int fDegrees;
145     bool fAA;
146 };
147 
148 class OvalPathBench : public PathBench {
149 public:
OvalPathBench(Flags flags)150     OvalPathBench(Flags flags) : INHERITED(flags) {}
151 
appendName(SkString * name)152     void appendName(SkString* name) override {
153         name->append("oval");
154     }
makePath(SkPath * path)155     void makePath(SkPath* path) override {
156         SkRect r = { 10, 10, 23, 20 };
157         path->addOval(r);
158     }
159 private:
160     using INHERITED = PathBench;
161 };
162 
163 class CirclePathBench: public PathBench {
164 public:
CirclePathBench(Flags flags)165     CirclePathBench(Flags flags) : INHERITED(flags) {}
166 
appendName(SkString * name)167     void appendName(SkString* name) override {
168         name->append("circle");
169     }
makePath(SkPath * path)170     void makePath(SkPath* path) override {
171         path->addCircle(SkIntToScalar(20), SkIntToScalar(20),
172                         SkIntToScalar(10));
173     }
174 private:
175     using INHERITED = PathBench;
176 };
177 
178 class NonAACirclePathBench: public CirclePathBench {
179 public:
NonAACirclePathBench(Flags flags)180     NonAACirclePathBench(Flags flags) : INHERITED(flags) {}
181 
appendName(SkString * name)182     void appendName(SkString* name) override {
183         name->append("nonaacircle");
184     }
185 
setupPaint(SkPaint * paint)186     void setupPaint(SkPaint* paint) override {
187         CirclePathBench::setupPaint(paint);
188         paint->setAntiAlias(false);
189     }
190 
191 private:
192     using INHERITED = CirclePathBench;
193 };
194 
195 // Test max speedup of Analytic AA for concave paths
196 class AAAConcavePathBench : public PathBench {
197 public:
AAAConcavePathBench(Flags flags)198     AAAConcavePathBench(Flags flags) : INHERITED(flags) {}
199 
appendName(SkString * name)200     void appendName(SkString* name) override {
201         name->append("concave_aaa");
202     }
203 
makePath(SkPath * path)204     void makePath(SkPath* path) override {
205         path->moveTo(10, 10);
206         path->lineTo(15, 10);
207         path->lineTo(15, 5);
208         path->lineTo(40, 40);
209         path->close();
210     }
211 
212 private:
213     using INHERITED = PathBench;
214 };
215 
216 // Test max speedup of Analytic AA for convex paths
217 class AAAConvexPathBench : public PathBench {
218 public:
AAAConvexPathBench(Flags flags)219     AAAConvexPathBench(Flags flags) : INHERITED(flags) {}
220 
appendName(SkString * name)221     void appendName(SkString* name) override {
222         name->append("convex_aaa");
223     }
224 
makePath(SkPath * path)225     void makePath(SkPath* path) override {
226         path->moveTo(10, 10);
227         path->lineTo(15, 10);
228         path->lineTo(40, 50);
229         path->close();
230     }
231 
232 private:
233     using INHERITED = PathBench;
234 };
235 
236 class SawToothPathBench : public PathBench {
237 public:
SawToothPathBench(Flags flags)238     SawToothPathBench(Flags flags) : INHERITED(flags) {}
239 
appendName(SkString * name)240     void appendName(SkString* name) override {
241         name->append("sawtooth");
242     }
makePath(SkPath * path)243     void makePath(SkPath* path) override {
244         SkScalar x = SkIntToScalar(20);
245         SkScalar y = SkIntToScalar(20);
246         const SkScalar x0 = x;
247         const SkScalar dx = SK_Scalar1 * 5;
248         const SkScalar dy = SK_Scalar1 * 10;
249 
250         path->moveTo(x, y);
251         for (int i = 0; i < 32; i++) {
252             x += dx;
253             path->lineTo(x, y - dy);
254             x += dx;
255             path->lineTo(x, y + dy);
256         }
257         path->lineTo(x, y + 2 * dy);
258         path->lineTo(x0, y + 2 * dy);
259         path->close();
260     }
complexity()261     int complexity() override { return 1; }
262 private:
263     using INHERITED = PathBench;
264 };
265 
266 class LongCurvedPathBench : public PathBench {
267 public:
LongCurvedPathBench(Flags flags)268     LongCurvedPathBench(Flags flags) : INHERITED(flags) {}
269 
appendName(SkString * name)270     void appendName(SkString* name) override {
271         name->append("long_curved");
272     }
makePath(SkPath * path)273     void makePath(SkPath* path) override {
274         SkRandom rand (12);
275         int i;
276         for (i = 0; i < 100; i++) {
277             path->quadTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480,
278                          rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
279         }
280         path->close();
281     }
complexity()282     int complexity() override { return 2; }
283 private:
284     using INHERITED = PathBench;
285 };
286 
287 class LongLinePathBench : public PathBench {
288 public:
LongLinePathBench(Flags flags)289     LongLinePathBench(Flags flags) : INHERITED(flags) {}
290 
appendName(SkString * name)291     void appendName(SkString* name) override {
292         name->append("long_line");
293     }
makePath(SkPath * path)294     void makePath(SkPath* path) override {
295         SkRandom rand;
296         path->moveTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
297         for (size_t i = 1; i < 100; i++) {
298             path->lineTo(rand.nextUScalar1() * 640, rand.nextUScalar1() * 480);
299         }
300     }
complexity()301     int complexity() override { return 2; }
302 private:
303     using INHERITED = PathBench;
304 };
305 
306 class RandomPathBench : public Benchmark {
307 public:
isSuitableFor(Backend backend)308     bool isSuitableFor(Backend backend) override {
309         return backend == Backend::kNonRendering;
310     }
311 
312 protected:
createData(int minVerbs,int maxVerbs,bool allowMoves=true,SkRect * bounds=nullptr)313     void createData(int minVerbs,
314                     int maxVerbs,
315                     bool allowMoves = true,
316                     SkRect* bounds = nullptr) {
317         SkRect tempBounds;
318         if (nullptr == bounds) {
319             tempBounds.setXYWH(0, 0, SK_Scalar1, SK_Scalar1);
320             bounds = &tempBounds;
321         }
322         fVerbCnts.reset(kNumVerbCnts);
323         for (int i = 0; i < kNumVerbCnts; ++i) {
324             fVerbCnts[i] = fRandom.nextRangeU(minVerbs, maxVerbs + 1);
325         }
326         fVerbs.reset(kNumVerbs);
327         for (int i = 0; i < kNumVerbs; ++i) {
328             do {
329                 fVerbs[i] = static_cast<SkPath::Verb>(fRandom.nextULessThan(SkPath::kDone_Verb));
330             } while (!allowMoves && SkPath::kMove_Verb == fVerbs[i]);
331         }
332         fPoints.reset(kNumPoints);
333         for (int i = 0; i < kNumPoints; ++i) {
334             fPoints[i].set(fRandom.nextRangeScalar(bounds->fLeft, bounds->fRight),
335                            fRandom.nextRangeScalar(bounds->fTop, bounds->fBottom));
336         }
337         this->restartMakingPaths();
338     }
339 
restartMakingPaths()340     void restartMakingPaths() {
341         fCurrPath = 0;
342         fCurrVerb = 0;
343         fCurrPoint = 0;
344     }
345 
makePath(SkPath * path)346     void makePath(SkPath* path) {
347         int vCount = fVerbCnts[(fCurrPath++) & (kNumVerbCnts - 1)];
348         for (int v = 0; v < vCount; ++v) {
349             int verb = fVerbs[(fCurrVerb++) & (kNumVerbs - 1)];
350             switch (verb) {
351                 case SkPath::kMove_Verb:
352                     path->moveTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
353                     break;
354                 case SkPath::kLine_Verb:
355                     path->lineTo(fPoints[(fCurrPoint++) & (kNumPoints - 1)]);
356                     break;
357                 case SkPath::kQuad_Verb:
358                     path->quadTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
359                                  fPoints[(fCurrPoint + 1) & (kNumPoints - 1)]);
360                     fCurrPoint += 2;
361                     break;
362                 case SkPath::kConic_Verb:
363                     path->conicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
364                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
365                                   SK_ScalarHalf);
366                     fCurrPoint += 2;
367                     break;
368                 case SkPath::kCubic_Verb:
369                     path->cubicTo(fPoints[(fCurrPoint + 0) & (kNumPoints - 1)],
370                                   fPoints[(fCurrPoint + 1) & (kNumPoints - 1)],
371                                   fPoints[(fCurrPoint + 2) & (kNumPoints - 1)]);
372                     fCurrPoint += 3;
373                     break;
374                 case SkPath::kClose_Verb:
375                     path->close();
376                     break;
377                 default:
378                     SkDEBUGFAIL("Unexpected path verb");
379                     break;
380             }
381         }
382     }
383 
finishedMakingPaths()384     void finishedMakingPaths() {
385         fVerbCnts.reset(0);
386         fVerbs.reset(0);
387         fPoints.reset(0);
388     }
389 
390 private:
391     enum {
392         // these should all be pow 2
393         kNumVerbCnts = 1 << 5,
394         kNumVerbs    = 1 << 5,
395         kNumPoints   = 1 << 5,
396     };
397     AutoTArray<int>           fVerbCnts;
398     AutoTArray<SkPath::Verb>  fVerbs;
399     AutoTArray<SkPoint>       fPoints;
400     int                         fCurrPath;
401     int                         fCurrVerb;
402     int                         fCurrPoint;
403     SkRandom                    fRandom;
404     using INHERITED = Benchmark;
405 };
406 
407 class PathCreateBench : public RandomPathBench {
408 public:
PathCreateBench()409     PathCreateBench()  {
410     }
411 
412 protected:
onGetName()413     const char* onGetName() override {
414         return "path_create";
415     }
416 
onDelayedSetup()417     void onDelayedSetup() override {
418         this->createData(10, 100);
419     }
420 
onDraw(int loops,SkCanvas *)421     void onDraw(int loops, SkCanvas*) override {
422         for (int i = 0; i < loops; ++i) {
423             if (i % 1000 == 0) {
424                 fPath.reset();  // PathRef memory can grow without bound otherwise.
425             }
426             this->makePath(&fPath);
427         }
428         this->restartMakingPaths();
429     }
430 
431 private:
432     SkPath fPath;
433 
434     using INHERITED = RandomPathBench;
435 };
436 
437 class PathCopyBench : public RandomPathBench {
438 public:
PathCopyBench()439     PathCopyBench()  {
440     }
441 
442 protected:
onGetName()443     const char* onGetName() override {
444         return "path_copy";
445     }
onDelayedSetup()446     void onDelayedSetup() override {
447         this->createData(10, 100);
448         fPaths.reset(kPathCnt);
449         fCopies.reset(kPathCnt);
450         for (int i = 0; i < kPathCnt; ++i) {
451             this->makePath(&fPaths[i]);
452         }
453         this->finishedMakingPaths();
454     }
onDraw(int loops,SkCanvas *)455     void onDraw(int loops, SkCanvas*) override {
456         for (int i = 0; i < loops; ++i) {
457             int idx = i & (kPathCnt - 1);
458             fCopies[idx] = fPaths[idx];
459         }
460     }
461 
462 private:
463     enum {
464         // must be a pow 2
465         kPathCnt = 1 << 5,
466     };
467     AutoTArray<SkPath> fPaths;
468     AutoTArray<SkPath> fCopies;
469 
470     using INHERITED = RandomPathBench;
471 };
472 
473 class PathTransformBench : public RandomPathBench {
474 public:
PathTransformBench(bool inPlace)475     PathTransformBench(bool inPlace) : fInPlace(inPlace) {}
476 
477 protected:
onGetName()478     const char* onGetName() override {
479         return fInPlace ? "path_transform_in_place" : "path_transform_copy";
480     }
481 
onDelayedSetup()482     void onDelayedSetup() override {
483         fMatrix.setScale(5 * SK_Scalar1, 6 * SK_Scalar1);
484         this->createData(10, 100);
485         fPaths.reset(kPathCnt);
486         for (int i = 0; i < kPathCnt; ++i) {
487             this->makePath(&fPaths[i]);
488         }
489         this->finishedMakingPaths();
490         if (!fInPlace) {
491             fTransformed.reset(kPathCnt);
492         }
493     }
494 
onDraw(int loops,SkCanvas *)495     void onDraw(int loops, SkCanvas*) override {
496         if (fInPlace) {
497             for (int i = 0; i < loops; ++i) {
498                 fPaths[i & (kPathCnt - 1)].transform(fMatrix);
499             }
500         } else {
501             for (int i = 0; i < loops; ++i) {
502                 int idx = i & (kPathCnt - 1);
503                 fPaths[idx].transform(fMatrix, &fTransformed[idx]);
504             }
505         }
506     }
507 
508 private:
509     enum {
510         // must be a pow 2
511         kPathCnt = 1 << 5,
512     };
513     AutoTArray<SkPath> fPaths;
514     AutoTArray<SkPath> fTransformed;
515 
516     SkMatrix fMatrix;
517     bool fInPlace;
518     using INHERITED = RandomPathBench;
519 };
520 
521 class PathEqualityBench : public RandomPathBench {
522 public:
PathEqualityBench()523     PathEqualityBench() { }
524 
525 protected:
onGetName()526     const char* onGetName() override {
527         return "path_equality_50%";
528     }
529 
onDelayedSetup()530     void onDelayedSetup() override {
531         fParity = 0;
532         this->createData(10, 100);
533         fPaths.reset(kPathCnt);
534         fCopies.reset(kPathCnt);
535         for (int i = 0; i < kPathCnt; ++i) {
536             this->makePath(&fPaths[i]);
537             fCopies[i] = fPaths[i];
538         }
539         this->finishedMakingPaths();
540     }
541 
onDraw(int loops,SkCanvas *)542     void onDraw(int loops, SkCanvas*) override {
543         for (int i = 0; i < loops; ++i) {
544             int idx = i & (kPathCnt - 1);
545             fParity ^= (fPaths[idx] == fCopies[idx & ~0x1]);
546         }
547     }
548 
549 private:
550     bool fParity; // attempt to keep compiler from optimizing out the ==
551     enum {
552         // must be a pow 2
553         kPathCnt = 1 << 5,
554     };
555     AutoTArray<SkPath> fPaths;
556     AutoTArray<SkPath> fCopies;
557     using INHERITED = RandomPathBench;
558 };
559 
560 class SkBench_AddPathTest : public RandomPathBench {
561 public:
562     enum AddType {
563         kAdd_AddType,
564         kAddTrans_AddType,
565         kAddMatrix_AddType,
566         kReverseAdd_AddType,
567         kReversePathTo_AddType,
568     };
569 
SkBench_AddPathTest(AddType type)570     SkBench_AddPathTest(AddType type) : fType(type) {
571         fMatrix.setRotate(60 * SK_Scalar1);
572     }
573 
574 protected:
onGetName()575     const char* onGetName() override {
576         switch (fType) {
577             case kAdd_AddType:
578                 return "path_add_path";
579             case kAddTrans_AddType:
580                 return "path_add_path_trans";
581             case kAddMatrix_AddType:
582                 return "path_add_path_matrix";
583             case kReverseAdd_AddType:
584                 return "path_reverse_add_path";
585             case kReversePathTo_AddType:
586                 return "path_reverse_path_to";
587             default:
588                 SkDEBUGFAIL("Bad add type");
589                 return "";
590         }
591     }
592 
onDelayedSetup()593     void onDelayedSetup() override {
594         // reversePathTo assumes a single contour path.
595         bool allowMoves = kReversePathTo_AddType != fType;
596         this->createData(10, 100, allowMoves);
597         fPaths0.reset(kPathCnt);
598         fPaths1.reset(kPathCnt);
599         for (int i = 0; i < kPathCnt; ++i) {
600             this->makePath(&fPaths0[i]);
601             this->makePath(&fPaths1[i]);
602         }
603         this->finishedMakingPaths();
604     }
605 
onDraw(int loops,SkCanvas *)606     void onDraw(int loops, SkCanvas*) override {
607         switch (fType) {
608             case kAdd_AddType:
609                 for (int i = 0; i < loops; ++i) {
610                     int idx = i & (kPathCnt - 1);
611                     SkPath result = fPaths0[idx];
612                     result.addPath(fPaths1[idx]);
613                 }
614                 break;
615             case kAddTrans_AddType:
616                 for (int i = 0; i < loops; ++i) {
617                     int idx = i & (kPathCnt - 1);
618                     SkPath result = fPaths0[idx];
619                     result.addPath(fPaths1[idx], 2 * SK_Scalar1, 5 * SK_Scalar1);
620                 }
621                 break;
622             case kAddMatrix_AddType:
623                 for (int i = 0; i < loops; ++i) {
624                     int idx = i & (kPathCnt - 1);
625                     SkPath result = fPaths0[idx];
626                     result.addPath(fPaths1[idx], fMatrix);
627                 }
628                 break;
629             case kReverseAdd_AddType:
630                 for (int i = 0; i < loops; ++i) {
631                     int idx = i & (kPathCnt - 1);
632                     SkPath result = fPaths0[idx];
633                     result.reverseAddPath(fPaths1[idx]);
634                 }
635                 break;
636             case kReversePathTo_AddType:
637                 for (int i = 0; i < loops; ++i) {
638                     int idx = i & (kPathCnt - 1);
639                     SkPath result = fPaths0[idx];
640                     result.reversePathTo(fPaths1[idx]);
641                 }
642                 break;
643         }
644     }
645 
646 private:
647     AddType fType; // or reverseAddPath
648     enum {
649         // must be a pow 2
650         kPathCnt = 1 << 5,
651     };
652     AutoTArray<SkPath> fPaths0;
653     AutoTArray<SkPath> fPaths1;
654     SkMatrix         fMatrix;
655     using INHERITED = RandomPathBench;
656 };
657 
658 
659 class CirclesBench : public Benchmark {
660 protected:
661     SkString            fName;
662     Flags               fFlags;
663 
664 public:
CirclesBench(Flags flags)665     CirclesBench(Flags flags) : fFlags(flags) {
666         fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill");
667     }
668 
669 protected:
onGetName()670     const char* onGetName() override {
671         return fName.c_str();
672     }
673 
onDraw(int loops,SkCanvas * canvas)674     void onDraw(int loops, SkCanvas* canvas) override {
675         SkPaint paint;
676 
677         paint.setColor(SK_ColorBLACK);
678         paint.setAntiAlias(true);
679         if (fFlags & kStroke_Flag) {
680             paint.setStyle(SkPaint::kStroke_Style);
681         }
682 
683         SkRandom rand;
684 
685         SkRect r;
686 
687         for (int i = 0; i < loops; ++i) {
688             SkScalar radius = rand.nextUScalar1() * 3;
689             r.fLeft = rand.nextUScalar1() * 300;
690             r.fTop =  rand.nextUScalar1() * 300;
691             r.fRight =  r.fLeft + 2 * radius;
692             r.fBottom = r.fTop + 2 * radius;
693 
694             if (fFlags & kStroke_Flag) {
695                 paint.setStrokeWidth(rand.nextUScalar1() * 5.0f);
696             }
697 
698             SkPath temp;
699 
700             // mimic how Chrome does circles
701             temp.arcTo(r, 0, 0, false);
702             temp.addOval(r, SkPathDirection::kCCW);
703             temp.arcTo(r, 360, 0, true);
704             temp.close();
705 
706             canvas->drawPath(temp, paint);
707         }
708     }
709 
710 private:
711     using INHERITED = Benchmark;
712 };
713 
714 
715 // Chrome creates its own round rects with each corner possibly being different.
716 // In its "zero radius" incarnation it creates degenerate round rects.
717 // Note: PathTest::test_arb_round_rect_is_convex and
718 // test_arb_zero_rad_round_rect_is_rect perform almost exactly
719 // the same test (but with no drawing)
720 class ArbRoundRectBench : public Benchmark {
721 protected:
722     SkString            fName;
723 
724 public:
ArbRoundRectBench(bool zeroRad)725     ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) {
726         if (zeroRad) {
727             fName.printf("zeroradroundrect");
728         } else {
729             fName.printf("arbroundrect");
730         }
731     }
732 
733 protected:
onGetName()734     const char* onGetName() override {
735         return fName.c_str();
736     }
737 
add_corner_arc(SkPath * path,const SkRect & rect,SkScalar xIn,SkScalar yIn,int startAngle)738     static void add_corner_arc(SkPath* path, const SkRect& rect,
739                                SkScalar xIn, SkScalar yIn,
740                                int startAngle)
741     {
742 
743         SkScalar rx = std::min(rect.width(), xIn);
744         SkScalar ry = std::min(rect.height(), yIn);
745 
746         SkRect arcRect;
747         arcRect.setLTRB(-rx, -ry, rx, ry);
748         switch (startAngle) {
749         case 0:
750             arcRect.offset(rect.fRight - arcRect.fRight, rect.fBottom - arcRect.fBottom);
751             break;
752         case 90:
753             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fBottom - arcRect.fBottom);
754             break;
755         case 180:
756             arcRect.offset(rect.fLeft - arcRect.fLeft, rect.fTop - arcRect.fTop);
757             break;
758         case 270:
759             arcRect.offset(rect.fRight - arcRect.fRight, rect.fTop - arcRect.fTop);
760             break;
761         default:
762             break;
763         }
764 
765         path->arcTo(arcRect, SkIntToScalar(startAngle), SkIntToScalar(90), false);
766     }
767 
make_arb_round_rect(SkPath * path,const SkRect & r,SkScalar xCorner,SkScalar yCorner)768     static void make_arb_round_rect(SkPath* path, const SkRect& r,
769                                     SkScalar xCorner, SkScalar yCorner) {
770         // we are lazy here and use the same x & y for each corner
771         add_corner_arc(path, r, xCorner, yCorner, 270);
772         add_corner_arc(path, r, xCorner, yCorner, 0);
773         add_corner_arc(path, r, xCorner, yCorner, 90);
774         add_corner_arc(path, r, xCorner, yCorner, 180);
775         path->close();
776 
777         SkASSERT(path->isConvex());
778     }
779 
onDraw(int loops,SkCanvas * canvas)780     void onDraw(int loops, SkCanvas* canvas) override {
781         SkRandom rand;
782         SkRect r;
783 
784         for (int i = 0; i < loops; ++i) {
785             SkPaint paint;
786             paint.setColor(0xff000000 | rand.nextU());
787             paint.setAntiAlias(true);
788 
789             SkScalar size = rand.nextUScalar1() * 30;
790             if (size < SK_Scalar1) {
791                 continue;
792             }
793             r.fLeft = rand.nextUScalar1() * 300;
794             r.fTop =  rand.nextUScalar1() * 300;
795             r.fRight =  r.fLeft + 2 * size;
796             r.fBottom = r.fTop + 2 * size;
797 
798             SkPath temp;
799 
800             if (fZeroRad) {
801                 make_arb_round_rect(&temp, r, 0, 0);
802 
803                 SkASSERT(temp.isRect(nullptr));
804             } else {
805                 make_arb_round_rect(&temp, r, r.width() / 10, r.height() / 15);
806             }
807 
808             canvas->drawPath(temp, paint);
809         }
810     }
811 
812 private:
813     bool fZeroRad;      // should 0 radius rounds rects be tested?
814 
815     using INHERITED = Benchmark;
816 };
817 
818 class ConservativelyContainsBench : public Benchmark {
819 public:
820     enum Type {
821         kRect_Type,
822         kRoundRect_Type,
823         kOval_Type,
824     };
825 
ConservativelyContainsBench(Type type)826     ConservativelyContainsBench(Type type)  {
827         fParity = false;
828         fName = "conservatively_contains_";
829         switch (type) {
830             case kRect_Type:
831                 fName.append("rect");
832                 fPath.addRect(kBaseRect);
833                 break;
834             case kRoundRect_Type:
835                 fName.append("round_rect");
836                 fPath.addRoundRect(kBaseRect, kRRRadii[0], kRRRadii[1]);
837                 break;
838             case kOval_Type:
839                 fName.append("oval");
840                 fPath.addOval(kBaseRect);
841                 break;
842         }
843     }
844 
isSuitableFor(Backend backend)845     bool isSuitableFor(Backend backend) override {
846         return backend == Backend::kNonRendering;
847     }
848 
849 private:
onGetName()850     const char* onGetName() override {
851         return fName.c_str();
852     }
853 
onDraw(int loops,SkCanvas *)854     void onDraw(int loops, SkCanvas*) override {
855         for (int i = 0; i < loops; ++i) {
856             const SkRect& rect = fQueryRects[i % kQueryRectCnt];
857             fParity = fParity != fPath.conservativelyContainsRect(rect);
858         }
859     }
860 
onDelayedSetup()861     void onDelayedSetup() override {
862         fQueryRects.resize(kQueryRectCnt);
863 
864         SkRandom rand;
865         for (int i = 0; i < kQueryRectCnt; ++i) {
866             SkSize size;
867             SkPoint xy;
868             size.fWidth = rand.nextRangeScalar(kQueryMin.fWidth,  kQueryMax.fWidth);
869             size.fHeight = rand.nextRangeScalar(kQueryMin.fHeight, kQueryMax.fHeight);
870             xy.fX = rand.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth);
871             xy.fY = rand.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight);
872 
873             fQueryRects[i] = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
874         }
875     }
876 
877     enum {
878         kQueryRectCnt = 400,
879     };
880     static const SkRect kBounds;   // bounds for all random query rects
881     static const SkSize kQueryMin; // minimum query rect size, should be <= kQueryMax
882     static const SkSize kQueryMax; // max query rect size, should < kBounds
883     static const SkRect kBaseRect; // rect that is used to construct the path
884     static const SkScalar kRRRadii[2]; // x and y radii for round rect
885 
886     SkString            fName;
887     SkPath              fPath;
888     bool                fParity;
889     SkTDArray<SkRect>   fQueryRects;
890 
891     using INHERITED = Benchmark;
892 };
893 
894 ///////////////////////////////////////////////////////////////////////////////
895 
896 #include "src/core/SkGeometry.h"
897 
898 class ConicBench_Chop : public Benchmark {
899 protected:
900     SkConic fRQ, fDst[2];
901     SkString fName;
902 public:
ConicBench_Chop()903     ConicBench_Chop() : fName("conic-chop") {
904         fRQ.fPts[0].set(0, 0);
905         fRQ.fPts[1].set(100, 0);
906         fRQ.fPts[2].set(100, 100);
907         fRQ.fW = SkScalarCos(SK_ScalarPI/4);
908     }
909 
isSuitableFor(Backend backend)910     bool isSuitableFor(Backend backend) override {
911         return backend == Backend::kNonRendering;
912     }
913 
914 private:
onGetName()915     const char* onGetName() override { return fName.c_str(); }
916 
onDraw(int loops,SkCanvas *)917     void onDraw(int loops, SkCanvas*) override {
918         for (int i = 0; i < loops; ++i) {
919             fRQ.chop(fDst);
920         }
921     }
922 
923     using INHERITED = Benchmark;
924 };
925 DEF_BENCH( return new ConicBench_Chop; )
926 
927 class ConicBench_EvalPos : public ConicBench_Chop {
928     const bool fUseV2;
929 public:
ConicBench_EvalPos(bool useV2)930     ConicBench_EvalPos(bool useV2) : fUseV2(useV2) {
931         fName.printf("conic-eval-pos%d", useV2);
932     }
onDraw(int loops,SkCanvas *)933     void onDraw(int loops, SkCanvas*) override {
934         if (fUseV2) {
935             for (int i = 0; i < loops; ++i) {
936                 for (int j = 0; j < 1000; ++j) {
937                     fDst[0].fPts[0] = fRQ.evalAt(0.4f);
938                 }
939             }
940         } else {
941             for (int i = 0; i < loops; ++i) {
942                 for (int j = 0; j < 1000; ++j) {
943                     fRQ.evalAt(0.4f, &fDst[0].fPts[0], nullptr);
944                 }
945             }
946         }
947     }
948 };
949 DEF_BENCH( return new ConicBench_EvalPos(false); )
950 DEF_BENCH( return new ConicBench_EvalPos(true); )
951 
952 class ConicBench_EvalTan : public ConicBench_Chop {
953     const bool fUseV2;
954 public:
ConicBench_EvalTan(bool useV2)955     ConicBench_EvalTan(bool useV2) : fUseV2(useV2) {
956         fName.printf("conic-eval-tan%d", useV2);
957     }
onDraw(int loops,SkCanvas *)958     void onDraw(int loops, SkCanvas*) override {
959         if (fUseV2) {
960             for (int i = 0; i < loops; ++i) {
961                 for (int j = 0; j < 1000; ++j) {
962                     fDst[0].fPts[0] = fRQ.evalTangentAt(0.4f);
963                 }
964             }
965         } else {
966             for (int i = 0; i < loops; ++i) {
967                 for (int j = 0; j < 1000; ++j) {
968                     fRQ.evalAt(0.4f, nullptr, &fDst[0].fPts[0]);
969                 }
970             }
971         }
972     }
973 };
974 DEF_BENCH( return new ConicBench_EvalTan(false); )
975 DEF_BENCH( return new ConicBench_EvalTan(true); )
976 
977 class ConicBench_TinyError : public Benchmark {
978 protected:
979     SkString fName;
980 
981 public:
ConicBench_TinyError()982     ConicBench_TinyError() : fName("conic-tinyerror") {}
983 
984 protected:
onGetName()985     const char* onGetName() override { return fName.c_str(); }
986 
onDraw(int loops,SkCanvas *)987     void onDraw(int loops, SkCanvas*) override {
988         SkPaint paint;
989         paint.setColor(SK_ColorBLACK);
990         paint.setAntiAlias(true);
991         paint.setStyle(SkPaint::kStroke_Style);
992         paint.setStrokeWidth(2);
993 
994         SkPath path;
995         path.moveTo(-100, 1);
996         path.cubicTo(-101, 1, -118, -47, -138, -44);
997 
998         // The large y scale factor produces a tiny error threshold.
999         const SkMatrix mtx = SkMatrix::MakeAll(3.07294035f, 0.833333373f, 361.111115f, 0.0f,
1000                                                6222222.5f, 28333.334f, 0.0f, 0.0f, 1.0f);
1001         for (int i = 0; i < loops; ++i) {
1002             SkPath dst;
1003             skpathutils::FillPathWithPaint(path, paint, &dst, nullptr,
1004                                            SkMatrixPriv::ComputeResScaleForStroking(mtx));
1005         }
1006     }
1007 
1008 private:
1009     using INHERITED = Benchmark;
1010 };
DEF_BENCH(return new ConicBench_TinyError;)1011 DEF_BENCH( return new ConicBench_TinyError; )
1012 
1013 ///////////////////////////////////////////////////////////////////////////////
1014 
1015 static void rand_conic(SkConic* conic, SkRandom& rand) {
1016     for (int i = 0; i < 3; ++i) {
1017         conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100);
1018     }
1019     if (rand.nextUScalar1() > 0.5f) {
1020         conic->fW = rand.nextUScalar1();
1021     } else {
1022         conic->fW = 1 + rand.nextUScalar1() * 4;
1023     }
1024 }
1025 
1026 class ConicBench : public Benchmark {
1027 public:
ConicBench()1028     ConicBench()  {
1029         SkRandom rand;
1030         for (int i = 0; i < CONICS; ++i) {
1031             rand_conic(&fConics[i], rand);
1032         }
1033     }
1034 
isSuitableFor(Backend backend)1035     bool isSuitableFor(Backend backend) override {
1036         return backend == Backend::kNonRendering;
1037     }
1038 
1039 protected:
1040     enum {
1041         CONICS = 100
1042     };
1043     SkConic fConics[CONICS];
1044 
1045 private:
1046     using INHERITED = Benchmark;
1047 };
1048 
1049 class ConicBench_ComputeError : public ConicBench {
1050 public:
ConicBench_ComputeError()1051     ConicBench_ComputeError()  {}
1052 
1053 protected:
onGetName()1054     const char* onGetName() override {
1055         return "conic-compute-error";
1056     }
1057 
onDraw(int loops,SkCanvas *)1058     void onDraw(int loops, SkCanvas*) override {
1059         SkVector err;
1060         for (int i = 0; i < loops; ++i) {
1061             for (int j = 0; j < CONICS; ++j) {
1062                 fConics[j].computeAsQuadError(&err);
1063             }
1064         }
1065     }
1066 
1067 private:
1068     using INHERITED = ConicBench;
1069 };
1070 
1071 class ConicBench_asQuadTol : public ConicBench {
1072 public:
ConicBench_asQuadTol()1073     ConicBench_asQuadTol()  {}
1074 
1075 protected:
onGetName()1076     const char* onGetName() override {
1077         return "conic-asQuadTol";
1078     }
1079 
onDraw(int loops,SkCanvas *)1080     void onDraw(int loops, SkCanvas*) override {
1081         for (int i = 0; i < loops; ++i) {
1082             for (int j = 0; j < CONICS; ++j) {
1083                 fConics[j].asQuadTol(SK_ScalarHalf);
1084             }
1085         }
1086     }
1087 
1088 private:
1089     using INHERITED = ConicBench;
1090 };
1091 
1092 class ConicBench_quadPow2 : public ConicBench {
1093 public:
ConicBench_quadPow2()1094     ConicBench_quadPow2()  {}
1095 
1096 protected:
onGetName()1097     const char* onGetName() override {
1098         return "conic-quadPow2";
1099     }
1100 
onDraw(int loops,SkCanvas *)1101     void onDraw(int loops, SkCanvas*) override {
1102         for (int i = 0; i < loops; ++i) {
1103             for (int j = 0; j < CONICS; ++j) {
1104                 fConics[j].computeQuadPOW2(SK_ScalarHalf);
1105             }
1106         }
1107     }
1108 
1109 private:
1110     using INHERITED = ConicBench;
1111 };
1112 
1113 ///////////////////////////////////////////////////////////////////////////////
1114 
1115 class TightBoundsBench : public Benchmark {
1116     SkPath      fPath;
1117     SkString    fName;
1118     SkRect      (*fProc)(const SkPath&);
1119 
1120 public:
TightBoundsBench(SkRect (* proc)(const SkPath &),const char suffix[])1121     TightBoundsBench(SkRect (*proc)(const SkPath&), const char suffix[]) : fProc(proc) {
1122         fName.printf("tight_bounds_%s", suffix);
1123 
1124         const int N = 100;
1125         SkRandom rand;
1126         for (int i = 0; i < N; ++i) {
1127             fPath.moveTo(rand.nextF()*100, rand.nextF()*100);
1128             fPath.lineTo(rand.nextF()*100, rand.nextF()*100);
1129             fPath.quadTo(rand.nextF()*100, rand.nextF()*100, rand.nextF()*100, rand.nextF()*100);
1130             fPath.conicTo(rand.nextF()*100, rand.nextF()*100, rand.nextF()*100, rand.nextF()*100,
1131                           rand.nextF()*10);
1132             fPath.cubicTo(rand.nextF()*100, rand.nextF()*100, rand.nextF()*100, rand.nextF()*100,
1133                           rand.nextF()*100, rand.nextF()*100);
1134         }
1135     }
1136 
1137 protected:
isSuitableFor(Backend backend)1138     bool isSuitableFor(Backend backend) override {
1139         return backend == Backend::kNonRendering;
1140     }
1141 
onGetName()1142     const char* onGetName() override { return fName.c_str(); }
1143 
onDraw(int loops,SkCanvas * canvas)1144     void onDraw(int loops, SkCanvas* canvas) override {
1145         for (int i = 0; i < loops*100; ++i) {
1146             fProc(fPath);
1147         }
1148     }
1149 
1150 private:
1151     using INHERITED = Benchmark;
1152 };
1153 
1154 
1155 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100));
1156 const SkSize ConservativelyContainsBench::kQueryMin = {SkIntToScalar(1), SkIntToScalar(1)};
1157 const SkSize ConservativelyContainsBench::kQueryMax = {SkIntToScalar(40), SkIntToScalar(40)};
1158 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50));
1159 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)};
1160 
1161 DEF_BENCH( return new TrianglePathBench(FLAGS00); )
1162 DEF_BENCH( return new TrianglePathBench(FLAGS01); )
1163 DEF_BENCH( return new TrianglePathBench(FLAGS10); )
1164 DEF_BENCH( return new TrianglePathBench(FLAGS11); )
1165 
1166 DEF_BENCH( return new RectPathBench(FLAGS00); )
1167 DEF_BENCH( return new RectPathBench(FLAGS01); )
1168 DEF_BENCH( return new RectPathBench(FLAGS10); )
1169 DEF_BENCH( return new RectPathBench(FLAGS11); )
1170 
1171 DEF_BENCH( return new RotatedRectBench(FLAGS00, false, 45));
1172 DEF_BENCH( return new RotatedRectBench(FLAGS10, false, 45));
1173 DEF_BENCH( return new RotatedRectBench(FLAGS00, true, 45));
1174 DEF_BENCH( return new RotatedRectBench(FLAGS10, true, 45));
1175 
1176 DEF_BENCH( return new OvalPathBench(FLAGS00); )
1177 DEF_BENCH( return new OvalPathBench(FLAGS01); )
1178 DEF_BENCH( return new OvalPathBench(FLAGS10); )
1179 DEF_BENCH( return new OvalPathBench(FLAGS11); )
1180 
1181 DEF_BENCH( return new CirclePathBench(FLAGS00); )
1182 DEF_BENCH( return new CirclePathBench(FLAGS01); )
1183 DEF_BENCH( return new CirclePathBench(FLAGS10); )
1184 DEF_BENCH( return new CirclePathBench(FLAGS11); )
1185 
1186 DEF_BENCH( return new NonAACirclePathBench(FLAGS00); )
1187 DEF_BENCH( return new NonAACirclePathBench(FLAGS10); )
1188 
1189 DEF_BENCH( return new AAAConcavePathBench(FLAGS00); )
1190 DEF_BENCH( return new AAAConcavePathBench(FLAGS10); )
1191 DEF_BENCH( return new AAAConvexPathBench(FLAGS00); )
1192 DEF_BENCH( return new AAAConvexPathBench(FLAGS10); )
1193 
1194 DEF_BENCH( return new SawToothPathBench(FLAGS00); )
1195 DEF_BENCH( return new SawToothPathBench(FLAGS01); )
1196 
1197 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); )
1198 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); )
1199 DEF_BENCH( return new LongLinePathBench(FLAGS00); )
1200 DEF_BENCH( return new LongLinePathBench(FLAGS01); )
1201 
1202 DEF_BENCH( return new PathCreateBench(); )
1203 DEF_BENCH( return new PathCopyBench(); )
1204 DEF_BENCH( return new PathTransformBench(true); )
1205 DEF_BENCH( return new PathTransformBench(false); )
1206 DEF_BENCH( return new PathEqualityBench(); )
1207 
1208 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); )
1209 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); )
1210 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); )
1211 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); )
1212 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); )
1213 
1214 DEF_BENCH( return new CirclesBench(FLAGS00); )
1215 DEF_BENCH( return new CirclesBench(FLAGS01); )
1216 DEF_BENCH( return new ArbRoundRectBench(false); )
1217 DEF_BENCH( return new ArbRoundRectBench(true); )
1218 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); )
1219 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); )
1220 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); )
1221 
1222 #include "include/pathops/SkPathOps.h"
1223 #include "src/core/SkPathPriv.h"
1224 
__anonb7dfbe8b0802(const SkPath& path)1225 DEF_BENCH( return new TightBoundsBench([](const SkPath& path){ return path.computeTightBounds();},
1226                                        "priv"); )
__anonb7dfbe8b0902(const SkPath& path) 1227 DEF_BENCH( return new TightBoundsBench([](const SkPath& path) {
1228         SkRect bounds; TightBounds(path, &bounds); return bounds;
1229     }, "pathops"); )
1230 
1231 // These seem to be optimized away, which is troublesome for timing.
1232 /*
1233 DEF_BENCH( return new ConicBench_Chop5() )
1234 DEF_BENCH( return new ConicBench_ComputeError() )
1235 DEF_BENCH( return new ConicBench_asQuadTol() )
1236 DEF_BENCH( return new ConicBench_quadPow2() )
1237 */
1238 
1239 class CommonConvexBench : public Benchmark {
1240 protected:
1241     SkString    fName;
1242     SkPath      fPath;
1243     const bool  fAA;
1244 
1245 public:
CommonConvexBench(int w,int h,bool forceConcave,bool aa)1246     CommonConvexBench(int w, int h, bool forceConcave, bool aa) : fAA(aa) {
1247         fName.printf("convex_path_%d_%d_%d_%d", w, h, forceConcave, aa);
1248 
1249         SkRect r = SkRect::MakeXYWH(10, 10, w*1.0f, h*1.0f);
1250         fPath.addRRect(SkRRect::MakeRectXY(r, w/8.0f, h/8.0f));
1251 
1252         if (forceConcave) {
1253             SkPathPriv::SetConvexity(fPath, SkPathConvexity::kConcave);
1254             SkASSERT(!fPath.isConvex());
1255         } else {
1256             SkASSERT(fPath.isConvex());
1257         }
1258     }
1259 
1260 protected:
onGetName()1261     const char* onGetName() override {
1262         return fName.c_str();
1263     }
1264 
onDraw(int loops,SkCanvas * canvas)1265     void onDraw(int loops, SkCanvas* canvas) override {
1266         SkPaint paint;
1267         paint.setAntiAlias(fAA);
1268 
1269         for (int i = 0; i < loops; ++i) {
1270             for (int inner = 0; inner < 100; ++inner) {
1271                 canvas->drawPath(fPath, paint);
1272             }
1273         }
1274     }
1275 
1276 private:
1277     using INHERITED = Benchmark;
1278 };
1279 
1280 DEF_BENCH( return new CommonConvexBench( 16, 16, false, false); )
1281 DEF_BENCH( return new CommonConvexBench( 16, 16, true,  false); )
1282 DEF_BENCH( return new CommonConvexBench( 16, 16, false, true); )
1283 DEF_BENCH( return new CommonConvexBench( 16, 16, true,  true); )
1284 
1285 DEF_BENCH( return new CommonConvexBench(200, 16, false, false); )
1286 DEF_BENCH( return new CommonConvexBench(200, 16, true,  false); )
1287 DEF_BENCH( return new CommonConvexBench(200, 16, false, true); )
1288 DEF_BENCH( return new CommonConvexBench(200, 16, true,  true); )
1289