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