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