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