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