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