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 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 Benchmark 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 Benchmark { 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 Benchmark 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 } 331 332 virtual void onDraw(const int loops, SkCanvas*) SK_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 342 private: 343 SkPath fPath; 344 345 typedef RandomPathBench INHERITED; 346 }; 347 348 class PathCopyBench : public RandomPathBench { 349 public: 350 PathCopyBench() { 351 } 352 353 protected: 354 virtual const char* onGetName() SK_OVERRIDE { 355 return "path_copy"; 356 } 357 virtual void onPreDraw() SK_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 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 367 for (int i = 0; i < loops; ++i) { 368 int idx = i & (kPathCnt - 1); 369 fCopies[idx] = fPaths[idx]; 370 } 371 } 372 373 private: 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 384 class PathTransformBench : public RandomPathBench { 385 public: 386 PathTransformBench(bool inPlace) : fInPlace(inPlace) {} 387 388 protected: 389 virtual const char* onGetName() SK_OVERRIDE { 390 return fInPlace ? "path_transform_in_place" : "path_transform_copy"; 391 } 392 393 virtual void onPreDraw() SK_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 virtual void onDraw(const int loops, SkCanvas*) SK_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 419 private: 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 432 class PathEqualityBench : public RandomPathBench { 433 public: 434 PathEqualityBench() { } 435 436 protected: 437 virtual const char* onGetName() SK_OVERRIDE { 438 return "path_equality_50%"; 439 } 440 441 virtual void onPreDraw() SK_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 virtual void onDraw(const int loops, SkCanvas*) SK_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 460 private: 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 471 class SkBench_AddPathTest : public RandomPathBench { 472 public: 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 485 protected: 486 virtual const char* onGetName() SK_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 virtual void onPreDraw() SK_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 virtual void onDraw(const int loops, SkCanvas*) SK_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 557 private: 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 570 class CirclesBench : public Benchmark { 571 protected: 572 SkString fName; 573 Flags fFlags; 574 575 public: 576 CirclesBench(Flags flags) : fFlags(flags) { 577 fName.printf("circles_%s", fFlags & kStroke_Flag ? "stroke" : "fill"); 578 } 579 580 protected: 581 virtual const char* onGetName() SK_OVERRIDE { 582 return fName.c_str(); 583 } 584 585 virtual void onDraw(const int loops, SkCanvas* canvas) SK_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 621 private: 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) 631 class ArbRoundRectBench : public Benchmark { 632 protected: 633 SkString fName; 634 635 public: 636 ArbRoundRectBench(bool zeroRad) : fZeroRad(zeroRad) { 637 if (zeroRad) { 638 fName.printf("zeroradroundrect"); 639 } else { 640 fName.printf("arbroundrect"); 641 } 642 } 643 644 protected: 645 virtual const char* onGetName() SK_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 virtual void onDraw(const int loops, SkCanvas* canvas) SK_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(NULL)); 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 723 private: 724 bool fZeroRad; // should 0 radius rounds rects be tested? 725 726 typedef Benchmark INHERITED; 727 }; 728 729 class ConservativelyContainsBench : public Benchmark { 730 public: 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 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { 757 return backend == kNonRendering_Backend; 758 } 759 760 private: 761 virtual const char* onGetName() SK_OVERRIDE { 762 return fName.c_str(); 763 } 764 765 virtual void onDraw(const int loops, SkCanvas*) SK_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 virtual void onPreDraw() SK_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 809 class ConicBench_Chop5 : public Benchmark { 810 SkConic fRQ; 811 public: 812 ConicBench_Chop5() { 813 fRQ.fPts[0].set(0, 0); 814 fRQ.fPts[1].set(100, 0); 815 fRQ.fPts[2].set(100, 100); 816 fRQ.fW = SkScalarCos(SK_ScalarPI/4); 817 } 818 819 private: 820 virtual const char* onGetName() SK_OVERRIDE { 821 return "ratquad-chop-0.5"; 822 } 823 824 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 825 SkConic dst[2]; 826 for (int i = 0; i < loops; ++i) { 827 fRQ.chopAt(0.5f, dst); 828 } 829 } 830 831 typedef Benchmark INHERITED; 832 }; 833 834 class ConicBench_ChopHalf : public Benchmark { 835 SkConic fRQ; 836 public: 837 ConicBench_ChopHalf() { 838 fRQ.fPts[0].set(0, 0); 839 fRQ.fPts[1].set(100, 0); 840 fRQ.fPts[2].set(100, 100); 841 fRQ.fW = SkScalarCos(SK_ScalarPI/4); 842 } 843 844 private: 845 virtual const char* onGetName() SK_OVERRIDE { 846 return "ratquad-chop-half"; 847 } 848 849 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 850 SkConic dst[2]; 851 for (int i = 0; i < loops; ++i) { 852 fRQ.chop(dst); 853 } 854 } 855 856 typedef Benchmark INHERITED; 857 }; 858 859 /////////////////////////////////////////////////////////////////////////////// 860 861 static void rand_conic(SkConic* conic, SkRandom& rand) { 862 for (int i = 0; i < 3; ++i) { 863 conic->fPts[i].set(rand.nextUScalar1() * 100, rand.nextUScalar1() * 100); 864 } 865 if (rand.nextUScalar1() > 0.5f) { 866 conic->fW = rand.nextUScalar1(); 867 } else { 868 conic->fW = 1 + rand.nextUScalar1() * 4; 869 } 870 } 871 872 class ConicBench : public Benchmark { 873 public: 874 ConicBench() { 875 SkRandom rand; 876 for (int i = 0; i < CONICS; ++i) { 877 rand_conic(&fConics[i], rand); 878 } 879 } 880 881 virtual bool isSuitableFor(Backend backend) SK_OVERRIDE { 882 return backend == kNonRendering_Backend; 883 } 884 885 protected: 886 enum { 887 CONICS = 100 888 }; 889 SkConic fConics[CONICS]; 890 891 private: 892 typedef Benchmark INHERITED; 893 }; 894 895 class ConicBench_ComputeError : public ConicBench { 896 public: 897 ConicBench_ComputeError() {} 898 899 protected: 900 virtual const char* onGetName() SK_OVERRIDE { 901 return "conic-compute-error"; 902 } 903 904 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 905 SkVector err; 906 for (int i = 0; i < loops; ++i) { 907 for (int j = 0; j < CONICS; ++j) { 908 fConics[j].computeAsQuadError(&err); 909 } 910 } 911 } 912 913 private: 914 typedef ConicBench INHERITED; 915 }; 916 917 class ConicBench_asQuadTol : public ConicBench { 918 public: 919 ConicBench_asQuadTol() {} 920 921 protected: 922 virtual const char* onGetName() SK_OVERRIDE { 923 return "conic-asQuadTol"; 924 } 925 926 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 927 for (int i = 0; i < loops; ++i) { 928 for (int j = 0; j < CONICS; ++j) { 929 fConics[j].asQuadTol(SK_ScalarHalf); 930 } 931 } 932 } 933 934 private: 935 typedef ConicBench INHERITED; 936 }; 937 938 class ConicBench_quadPow2 : public ConicBench { 939 public: 940 ConicBench_quadPow2() {} 941 942 protected: 943 virtual const char* onGetName() SK_OVERRIDE { 944 return "conic-quadPow2"; 945 } 946 947 virtual void onDraw(const int loops, SkCanvas*) SK_OVERRIDE { 948 for (int i = 0; i < loops; ++i) { 949 for (int j = 0; j < CONICS; ++j) { 950 fConics[j].computeQuadPOW2(SK_ScalarHalf); 951 } 952 } 953 } 954 955 private: 956 typedef ConicBench INHERITED; 957 }; 958 959 /////////////////////////////////////////////////////////////////////////////// 960 961 const SkRect ConservativelyContainsBench::kBounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(100)); 962 const SkSize ConservativelyContainsBench::kQueryMin = SkSize::Make(SkIntToScalar(1), SkIntToScalar(1)); 963 const SkSize ConservativelyContainsBench::kQueryMax = SkSize::Make(SkIntToScalar(40), SkIntToScalar(40)); 964 const SkRect ConservativelyContainsBench::kBaseRect = SkRect::MakeXYWH(SkIntToScalar(25), SkIntToScalar(25), SkIntToScalar(50), SkIntToScalar(50)); 965 const SkScalar ConservativelyContainsBench::kRRRadii[2] = {SkIntToScalar(5), SkIntToScalar(10)}; 966 967 DEF_BENCH( return new TrianglePathBench(FLAGS00); ) 968 DEF_BENCH( return new TrianglePathBench(FLAGS01); ) 969 DEF_BENCH( return new TrianglePathBench(FLAGS10); ) 970 DEF_BENCH( return new TrianglePathBench(FLAGS11); ) 971 972 DEF_BENCH( return new RectPathBench(FLAGS00); ) 973 DEF_BENCH( return new RectPathBench(FLAGS01); ) 974 DEF_BENCH( return new RectPathBench(FLAGS10); ) 975 DEF_BENCH( return new RectPathBench(FLAGS11); ) 976 977 DEF_BENCH( return new OvalPathBench(FLAGS00); ) 978 DEF_BENCH( return new OvalPathBench(FLAGS01); ) 979 DEF_BENCH( return new OvalPathBench(FLAGS10); ) 980 DEF_BENCH( return new OvalPathBench(FLAGS11); ) 981 982 DEF_BENCH( return new CirclePathBench(FLAGS00); ) 983 DEF_BENCH( return new CirclePathBench(FLAGS01); ) 984 DEF_BENCH( return new CirclePathBench(FLAGS10); ) 985 DEF_BENCH( return new CirclePathBench(FLAGS11); ) 986 987 DEF_BENCH( return new SawToothPathBench(FLAGS00); ) 988 DEF_BENCH( return new SawToothPathBench(FLAGS01); ) 989 990 DEF_BENCH( return new LongCurvedPathBench(FLAGS00); ) 991 DEF_BENCH( return new LongCurvedPathBench(FLAGS01); ) 992 DEF_BENCH( return new LongLinePathBench(FLAGS00); ) 993 DEF_BENCH( return new LongLinePathBench(FLAGS01); ) 994 995 DEF_BENCH( return new PathCreateBench(); ) 996 DEF_BENCH( return new PathCopyBench(); ) 997 DEF_BENCH( return new PathTransformBench(true); ) 998 DEF_BENCH( return new PathTransformBench(false); ) 999 DEF_BENCH( return new PathEqualityBench(); ) 1000 1001 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAdd_AddType); ) 1002 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddTrans_AddType); ) 1003 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kAddMatrix_AddType); ) 1004 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReverseAdd_AddType); ) 1005 DEF_BENCH( return new SkBench_AddPathTest(SkBench_AddPathTest::kReversePathTo_AddType); ) 1006 1007 DEF_BENCH( return new CirclesBench(FLAGS00); ) 1008 DEF_BENCH( return new CirclesBench(FLAGS01); ) 1009 DEF_BENCH( return new ArbRoundRectBench(false); ) 1010 DEF_BENCH( return new ArbRoundRectBench(true); ) 1011 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRect_Type); ) 1012 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kRoundRect_Type); ) 1013 DEF_BENCH( return new ConservativelyContainsBench(ConservativelyContainsBench::kOval_Type); ) 1014 1015 DEF_BENCH( return new ConicBench_Chop5() ) 1016 DEF_BENCH( return new ConicBench_ChopHalf() ) 1017 DEF_BENCH( return new ConicBench_ComputeError() ) 1018 DEF_BENCH( return new ConicBench_asQuadTol() ) 1019 DEF_BENCH( return new ConicBench_quadPow2() ) 1020