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 18enum 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 28class PathBench : public Benchmark { 29 SkPaint fPaint; 30 SkString fName; 31 Flags fFlags; 32public: 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 44protected: 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 75private: 76 typedef Benchmark INHERITED; 77}; 78 79class TrianglePathBench : public PathBench { 80public: 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 } 95private: 96 typedef PathBench INHERITED; 97}; 98 99class RectPathBench : public PathBench { 100public: 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 } 110private: 111 typedef PathBench INHERITED; 112}; 113 114class OvalPathBench : public PathBench { 115public: 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 } 125private: 126 typedef PathBench INHERITED; 127}; 128 129class CirclePathBench: public PathBench { 130public: 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 } 140private: 141 typedef PathBench INHERITED; 142}; 143 144class SawToothPathBench : public PathBench { 145public: 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; } 170private: 171 typedef PathBench INHERITED; 172}; 173 174class LongCurvedPathBench : public PathBench { 175public: 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; } 193private: 194 typedef PathBench INHERITED; 195}; 196 197class LongLinePathBench : public PathBench { 198public: 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; } 212private: 213 typedef PathBench INHERITED; 214}; 215 216class RandomPathBench : public Benchmark { 217public: 218 bool isSuitableFor(Backend backend) override { 219 return backend == kNonRendering_Backend; 220 } 221 222protected: 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 300private: 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 317class PathCreateBench : public RandomPathBench { 318public: 319 PathCreateBench() { 320 } 321 322protected: 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 341private: 342 SkPath fPath; 343 344 typedef RandomPathBench INHERITED; 345}; 346 347class PathCopyBench : public RandomPathBench { 348public: 349 PathCopyBench() { 350 } 351 352protected: 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 372private: 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 383class PathTransformBench : public RandomPathBench { 384public: 385 PathTransformBench(bool inPlace) : fInPlace(inPlace) {} 386 387protected: 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 418private: 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 431class PathEqualityBench : public RandomPathBench { 432public: 433 PathEqualityBench() { } 434 435protected: 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 459private: 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 470class SkBench_AddPathTest : public RandomPathBench { 471public: 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 484protected: 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 556private: 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 569class CirclesBench : public Benchmark { 570protected: 571 SkString fName; 572 Flags fFlags; 573 574public: 575 CirclesBench(Flags flags) : fFlags(flags) { 576 fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill"); 577 } 578 579protected: 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 620private: 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) 630class ArbRoundRectBench : public Benchmark { 631protected: 632 SkString fName; 633 634public: 635 ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) { 636 if (zeroRad) { 637 fName.printf("zeroradroundrect"); 638 } else { 639 fName.printf("arbroundrect"); 640 } 641 } 642 643protected: 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 722private: 723 bool fZeroRad; // should 0 radius rounds rects be tested? 724 725 typedef Benchmark INHERITED; 726}; 727 728class ConservativelyContainsBench : public Benchmark { 729public: 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 759private: 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 808class ConicBench_Chop : public Benchmark { 809protected: 810 SkConic fRQ, fDst[2]; 811 SkString fName; 812public: 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 824private: 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}; 835DEF_BENCH( return new ConicBench_Chop; ) 836 837class ConicBench_EvalPos : public ConicBench_Chop { 838 const bool fUseV2; 839public: 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}; 859DEF_BENCH( return new ConicBench_EvalPos(false); ) 860DEF_BENCH( return new ConicBench_EvalPos(true); ) 861 862class ConicBench_EvalTan : public ConicBench_Chop { 863 const bool fUseV2; 864public: 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}; 884DEF_BENCH( return new ConicBench_EvalTan(false); ) 885DEF_BENCH( return new ConicBench_EvalTan(true); ) 886 887/////////////////////////////////////////////////////////////////////////////// 888 889static 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 900class ConicBench : public Benchmark { 901public: 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 913protected: 914 enum { 915 CONICS = 100 916 }; 917 SkConic fConics[CONICS]; 918 919private: 920 typedef Benchmark INHERITED; 921}; 922 923class ConicBench_ComputeError : public ConicBench { 924public: 925 ConicBench_ComputeError() {} 926 927protected: 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 941private: 942 typedef ConicBench INHERITED; 943}; 944 945class ConicBench_asQuadTol : public ConicBench { 946public: 947 ConicBench_asQuadTol() {} 948 949protected: 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 962private: 963 typedef ConicBench INHERITED; 964}; 965 966class ConicBench_quadPow2 : public ConicBench { 967public: 968 ConicBench_quadPow2() {} 969 970protected: 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 983private: 984 typedef ConicBench INHERITED; 985}; 986 987/////////////////////////////////////////////////////////////////////////////// 988 989const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100)); 990const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1)); 991const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40)); 992const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50)); 993const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)}; 994 995DEF_BENCH( return new TrianglePathBench(FLAGS00); ) 996DEF_BENCH( return new TrianglePathBench(FLAGS01); ) 997DEF_BENCH( return new TrianglePathBench(FLAGS10); ) 998DEF_BENCH( return new TrianglePathBench(FLAGS11); ) 999 1000DEF_BENCH( return new RectPathBench(FLAGS00); ) 1001DEF_BENCH( return new RectPathBench(FLAGS01); ) 1002DEF_BENCH( return new RectPathBench(FLAGS10); ) 1003DEF_BENCH( return new RectPathBench(FLAGS11); ) 1004 1005DEF_BENCH( return new OvalPathBench(FLAGS00); ) 1006DEF_BENCH( return new OvalPathBench(FLAGS01); ) 1007DEF_BENCH( return new OvalPathBench(FLAGS10); ) 1008DEF_BENCH( return new OvalPathBench(FLAGS11); ) 1009 1010DEF_BENCH( return new CirclePathBench(FLAGS00); ) 1011DEF_BENCH( return new CirclePathBench(FLAGS01); ) 1012DEF_BENCH( return new CirclePathBench(FLAGS10); ) 1013DEF_BENCH( return new CirclePathBench(FLAGS11); ) 1014 1015DEF_BENCH( return new SawToothPathBench(FLAGS00); ) 1016DEF_BENCH( return new SawToothPathBench(FLAGS01); ) 1017 1018DEF_BENCH( return new LongCurvedPathBench(FLAGS00); ) 1019DEF_BENCH( return new LongCurvedPathBench(FLAGS01); ) 1020DEF_BENCH( return new LongLinePathBench(FLAGS00); ) 1021DEF_BENCH( return new LongLinePathBench(FLAGS01); ) 1022 1023DEF_BENCH( return new PathCreateBench(); ) 1024DEF_BENCH( return new PathCopyBench(); ) 1025DEF_BENCH( return new PathTransformBench(true); ) 1026DEF_BENCH( return new PathTransformBench(false); ) 1027DEF_BENCH( return new PathEqualityBench(); ) 1028 1029DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); ) 1030DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); ) 1031DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); ) 1032DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); ) 1033DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); ) 1034 1035DEF_BENCH( return new CirclesBench(FLAGS00); ) 1036DEF_BENCH( return new CirclesBench(FLAGS01); ) 1037DEF_BENCH( return new ArbRoundRectBench(false); ) 1038DEF_BENCH( return new ArbRoundRectBench(true); ) 1039DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); ) 1040DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); ) 1041DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); ) 1042 1043 1044// These seem to be optimized away, which is troublesome for timing. 1045/* 1046DEF_BENCH( return new ConicBench_Chop5() ) 1047DEF_BENCH( return new ConicBench_ComputeError() ) 1048DEF_BENCH( return new ConicBench_asQuadTol() ) 1049DEF_BENCH( return new ConicBench_quadPow2() ) 1050*/ 1051