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