1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #include "BenchTimer.h" 9 #include "CopyTilesRenderer.h" 10 #include "PictureBenchmark.h" 11 #include "SkBenchLogger.h" 12 #include "SkCanvas.h" 13 #include "SkGraphics.h" 14 #include "SkImageDecoder.h" 15 #include "SkMath.h" 16 #include "SkOSFile.h" 17 #include "SkPicture.h" 18 #include "SkStream.h" 19 #include "SkTArray.h" 20 #include "picture_utils.h" 21 22 const int DEFAULT_REPEATS = 1; 23 24 static char const * const gFilterTypes[] = { 25 "paint", 26 "point", 27 "line", 28 "bitmap", 29 "rect", 30 "oval", 31 "path", 32 "text", 33 "all", 34 }; 35 36 static const size_t kFilterTypesCount = sizeof(gFilterTypes) / sizeof(gFilterTypes[0]); 37 38 static char const * const gFilterFlags[] = { 39 "antiAlias", 40 "filterBitmap", 41 "dither", 42 "underlineText", 43 "strikeThruText", 44 "fakeBoldText", 45 "linearText", 46 "subpixelText", 47 "devKernText", 48 "LCDRenderText", 49 "embeddedBitmapText", 50 "autoHinting", 51 "verticalText", 52 "genA8FromLCD", 53 "blur", 54 "hinting", 55 "slightHinting", 56 "AAClip", 57 }; 58 59 static const size_t kFilterFlagsCount = sizeof(gFilterFlags) / sizeof(gFilterFlags[0]); 60 61 static SkString filtersName(sk_tools::PictureRenderer::DrawFilterFlags* drawFilters) { 62 int all = drawFilters[0]; 63 size_t tIndex; 64 for (tIndex = 1; tIndex < SkDrawFilter::kTypeCount; ++tIndex) { 65 all &= drawFilters[tIndex]; 66 } 67 SkString result; 68 for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) { 69 SkString types; 70 if (all & (1 << fIndex)) { 71 types = gFilterTypes[SkDrawFilter::kTypeCount]; 72 } else { 73 for (tIndex = 0; tIndex < SkDrawFilter::kTypeCount; ++tIndex) { 74 if (drawFilters[tIndex] & (1 << fIndex)) { 75 types += gFilterTypes[tIndex]; 76 } 77 } 78 } 79 if (!types.size()) { 80 continue; 81 } 82 result += "_"; 83 result += types; 84 result += "."; 85 result += gFilterFlags[fIndex]; 86 } 87 return result; 88 } 89 90 static SkString filterTypesUsage() { 91 SkString result; 92 for (size_t index = 0; index < kFilterTypesCount; ++index) { 93 result += gFilterTypes[index]; 94 if (index < kFilterTypesCount - 1) { 95 result += " | "; 96 } 97 } 98 return result; 99 } 100 101 static SkString filterFlagsUsage() { 102 SkString result; 103 size_t len = 0; 104 for (size_t index = 0; index < kFilterFlagsCount; ++index) { 105 result += gFilterFlags[index]; 106 if (result.size() - len >= 72) { 107 result += "\n "; 108 len = result.size(); 109 } 110 if (index < kFilterFlagsCount - 1) { 111 result += " | "; 112 } 113 } 114 return result; 115 } 116 117 static void usage(const char* argv0) { 118 SkDebugf("SkPicture benchmarking tool\n"); 119 SkDebugf("\n" 120 "Usage: \n" 121 " %s <inputDir>...\n" 122 " [--logFile filename][--timers [wcgWC]*][--logPerIter 1|0][--min]\n" 123 " [--repeat][--timeIndividualTiles] \n" 124 " [--mode pow2tile minWidth height | record | simple\n" 125 " | tile width height | playbackCreation]\n" 126 " [--pipe]\n" 127 " [--bbh bbhType]\n" 128 " [--multi numThreads]\n" 129 " [--viewport width height][--scale sf]\n" 130 " [--device bitmap" 131 #if SK_SUPPORT_GPU 132 " | gpu" 133 #endif 134 "]\n" 135 " [--filter [%s]:\n [%s]]\n" 136 , argv0, filterTypesUsage().c_str(), filterFlagsUsage().c_str()); 137 SkDebugf("\n"); 138 SkDebugf( 139 " inputDir: A list of directories and files to use as input. Files are\n" 140 " expected to have the .skp extension.\n\n" 141 " --logFile filename : destination for writing log output, in addition to stdout.\n"); 142 SkDebugf(" --logPerIter 1|0 : " 143 "Log each repeat timer instead of mean, default is disabled.\n"); 144 SkDebugf(" --min : Print the minimum times (instead of average).\n"); 145 SkDebugf(" --timers [wcgWC]* : " 146 "Display wall, cpu, gpu, truncated wall or truncated cpu time for each picture.\n"); 147 SkDebugf(" --timeIndividualTiles : Report times for drawing individual tiles, rather than\n" 148 " times for drawing the whole page.\n" 149 " Requires --mode tile\n"); 150 SkDebugf( 151 " --mode pow2tile minWidth height | copyTile width height | record | simple\n" 152 " | tile width height | playbackCreation:\n" 153 " Run in the corresponding mode.\n" 154 " Default is simple.\n"); 155 SkDebugf( 156 " pow2tile minWidth height, Creates tiles with widths\n" 157 " that are all a power of two\n" 158 " such that they minimize the\n" 159 " amount of wasted tile space.\n" 160 " minWidth is the minimum width\n" 161 " of these tiles and must be a\n" 162 " power of two. Simple\n" 163 " rendering using these tiles\n" 164 " is benchmarked.\n"); 165 SkDebugf( 166 " record, Benchmark picture to picture recording.\n"); 167 SkDebugf( 168 " simple, Benchmark a simple rendering.\n"); 169 SkDebugf( 170 " tile width height, Benchmark simple rendering using\n" 171 " tiles with the given dimensions.\n" 172 " copyTile width height, Draw the picture, then copy it into tiles.\n" 173 " Does not support percentages.\n" 174 " If the picture is large enough, breaks it into\n" 175 " larger tiles (and draws the picture once per\n" 176 " larger tile) to avoid creating a large canvas.\n" 177 " Add --tiles x y to specify the number of tiles\n" 178 " per larger tile in the x and y direction.\n" 179 ); 180 SkDebugf( 181 " playbackCreation, Benchmark creation of the SkPicturePlayback.\n"); 182 SkDebugf("\n"); 183 SkDebugf( 184 " --multi numThreads : Set the number of threads for multi threaded drawing. Must be greater\n" 185 " than 1. Only works with tiled rendering.\n" 186 " --viewport width height : Set the viewport.\n" 187 " --scale sf : Scale drawing by sf.\n" 188 " --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n"); 189 SkDebugf( 190 " --bbh bbhType [width height]: Set the bounding box hierarchy type to\n" 191 " be used. Accepted values are: none, rtree, grid. Default\n" 192 " value is none. Not compatible with --pipe. With value\n" 193 " 'grid', width and height must be specified. 'grid' can\n" 194 " only be used with modes tile, record, and\n" 195 " playbackCreation."); 196 SkDebugf( 197 " --device bitmap" 198 #if SK_SUPPORT_GPU 199 " | gpu" 200 #endif 201 ": Use the corresponding device. Default is bitmap.\n"); 202 SkDebugf( 203 " bitmap, Render to a bitmap.\n"); 204 #if SK_SUPPORT_GPU 205 SkDebugf( 206 " gpu, Render to the GPU.\n"); 207 #endif 208 SkDebugf("\n"); 209 SkDebugf( 210 " --repeat: " 211 "Set the number of times to repeat each test." 212 " Default is %i.\n", DEFAULT_REPEATS); 213 SkDebugf( 214 " --filter type:flag : Enable canvas filtering to disable a paint flag,\n" 215 " use no blur or low quality blur, or use no hinting or\n" 216 " slight hinting. For all flags except AAClip, specify the\n" 217 " type of primitive to effect, or choose all. for AAClip\n" 218 " alone, the filter affects all clips independent of type.\n"); 219 } 220 221 SkBenchLogger gLogger; 222 223 static bool run_single_benchmark(const SkString& inputPath, 224 sk_tools::PictureBenchmark& benchmark) { 225 SkFILEStream inputStream; 226 227 inputStream.setPath(inputPath.c_str()); 228 if (!inputStream.isValid()) { 229 SkString err; 230 err.printf("Could not open file %s\n", inputPath.c_str()); 231 gLogger.logError(err); 232 return false; 233 } 234 235 bool success = false; 236 SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream); 237 if (!success) { 238 SkString err; 239 err.printf("Could not read an SkPicture from %s\n", inputPath.c_str()); 240 gLogger.logError(err); 241 return false; 242 } 243 244 SkString filename; 245 sk_tools::get_basename(&filename, inputPath); 246 247 SkString result; 248 result.printf("running bench [%i %i] %s ", picture.width(), 249 picture.height(), filename.c_str()); 250 gLogger.logProgress(result); 251 252 benchmark.run(&picture); 253 return true; 254 } 255 256 #define PRINT_USAGE_AND_EXIT \ 257 do { \ 258 usage(argv0); \ 259 exit(-1); \ 260 } while (0) 261 262 static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs, 263 sk_tools::PictureBenchmark* benchmark) { 264 const char* argv0 = argv[0]; 265 char* const* stop = argv + argc; 266 267 int repeats = DEFAULT_REPEATS; 268 sk_tools::PictureRenderer::SkDeviceTypes deviceType = 269 sk_tools::PictureRenderer::kBitmap_DeviceType; 270 271 SkAutoTUnref<sk_tools::PictureRenderer> renderer(NULL); 272 273 // Create a string to show our current settings. 274 // TODO: Make it prettier. Currently it just repeats the command line. 275 SkString commandLine("bench_pictures:"); 276 for (int i = 1; i < argc; i++) { 277 commandLine.appendf(" %s", *(argv+i)); 278 } 279 commandLine.append("\n"); 280 281 bool usePipe = false; 282 int numThreads = 1; 283 bool useTiles = false; 284 const char* widthString = NULL; 285 const char* heightString = NULL; 286 int gridWidth = 0; 287 int gridHeight = 0; 288 bool isPowerOf2Mode = false; 289 bool isCopyMode = false; 290 const char* xTilesString = NULL; 291 const char* yTilesString = NULL; 292 const char* mode = NULL; 293 bool gridSupported = false; 294 sk_tools::PictureRenderer::BBoxHierarchyType bbhType = 295 sk_tools::PictureRenderer::kNone_BBoxHierarchyType; 296 sk_tools::PictureRenderer::DrawFilterFlags drawFilters[SkDrawFilter::kTypeCount]; 297 sk_bzero(drawFilters, sizeof(drawFilters)); 298 SkISize viewport; 299 viewport.setEmpty(); 300 SkScalar scaleFactor = SK_Scalar1; 301 for (++argv; argv < stop; ++argv) { 302 if (0 == strcmp(*argv, "--repeat")) { 303 ++argv; 304 if (argv < stop) { 305 repeats = atoi(*argv); 306 if (repeats < 1) { 307 gLogger.logError("--repeat must be given a value > 0\n"); 308 PRINT_USAGE_AND_EXIT; 309 } 310 } else { 311 gLogger.logError("Missing arg for --repeat\n"); 312 PRINT_USAGE_AND_EXIT; 313 } 314 } else if (0 == strcmp(*argv, "--pipe")) { 315 usePipe = true; 316 } else if (0 == strcmp(*argv, "--logFile")) { 317 argv++; 318 if (argv < stop) { 319 if (!gLogger.SetLogFile(*argv)) { 320 SkString str; 321 str.printf("Could not open %s for writing.", *argv); 322 gLogger.logError(str); 323 usage(argv0); 324 // TODO(borenet): We're disabling this for now, due to 325 // write-protected Android devices. The very short-term 326 // solution is to ignore the fact that we have no log file. 327 //exit(-1); 328 } 329 } else { 330 gLogger.logError("Missing arg for --logFile\n"); 331 PRINT_USAGE_AND_EXIT; 332 } 333 } else if (0 == strcmp(*argv, "--multi")) { 334 ++argv; 335 if (argv >= stop) { 336 gLogger.logError("Missing arg for --multi\n"); 337 PRINT_USAGE_AND_EXIT; 338 } 339 numThreads = atoi(*argv); 340 if (numThreads < 2) { 341 gLogger.logError("Number of threads must be at least 2.\n"); 342 PRINT_USAGE_AND_EXIT; 343 } 344 } else if (0 == strcmp(*argv, "--bbh")) { 345 ++argv; 346 if (argv >= stop) { 347 gLogger.logError("Missing value for --bbh\n"); 348 PRINT_USAGE_AND_EXIT; 349 } 350 if (0 == strcmp(*argv, "none")) { 351 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType; 352 } else if (0 == strcmp(*argv, "rtree")) { 353 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType; 354 } else if (0 == strcmp(*argv, "grid")) { 355 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType; 356 ++argv; 357 if (argv >= stop) { 358 gLogger.logError("Missing width for --bbh grid\n"); 359 PRINT_USAGE_AND_EXIT; 360 } 361 gridWidth = atoi(*argv); 362 ++argv; 363 if (argv >= stop) { 364 gLogger.logError("Missing height for --bbh grid\n"); 365 PRINT_USAGE_AND_EXIT; 366 } 367 gridHeight = atoi(*argv); 368 } else { 369 SkString err; 370 err.printf("%s is not a valid value for --bbhType\n", *argv); 371 gLogger.logError(err); 372 PRINT_USAGE_AND_EXIT; 373 } 374 375 } else if (0 == strcmp(*argv, "--mode")) { 376 if (renderer.get() != NULL) { 377 SkDebugf("Cannot combine modes.\n"); 378 PRINT_USAGE_AND_EXIT; 379 } 380 381 ++argv; 382 if (argv >= stop) { 383 gLogger.logError("Missing mode for --mode\n"); 384 PRINT_USAGE_AND_EXIT; 385 } 386 387 if (0 == strcmp(*argv, "record")) { 388 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer)); 389 gridSupported = true; 390 } else if (0 == strcmp(*argv, "clone")) { 391 renderer.reset(sk_tools::CreatePictureCloneRenderer()); 392 } else if (0 == strcmp(*argv, "simple")) { 393 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer)); 394 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile")) 395 || 0 == strcmp(*argv, "copyTile")) { 396 useTiles = true; 397 mode = *argv; 398 399 if (0 == strcmp(*argv, "pow2tile")) { 400 isPowerOf2Mode = true; 401 } else if (0 == strcmp(*argv, "copyTile")) { 402 isCopyMode = true; 403 } else { 404 gridSupported = true; 405 } 406 407 ++argv; 408 if (argv >= stop) { 409 SkString err; 410 err.printf("Missing width for --mode %s\n", mode); 411 gLogger.logError(err); 412 PRINT_USAGE_AND_EXIT; 413 } 414 415 widthString = *argv; 416 ++argv; 417 if (argv >= stop) { 418 SkString err; 419 err.appendf("Missing height for --mode %s\n", mode); 420 gLogger.logError(err); 421 PRINT_USAGE_AND_EXIT; 422 } 423 heightString = *argv; 424 } else if (0 == strcmp(*argv, "playbackCreation")) { 425 renderer.reset(SkNEW(sk_tools::PlaybackCreationRenderer)); 426 gridSupported = true; 427 } else if (0 == strcmp(*argv, "gatherPixelRefs")) { 428 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer()); 429 } else { 430 SkString err; 431 err.printf("%s is not a valid mode for --mode\n", *argv); 432 gLogger.logError(err); 433 PRINT_USAGE_AND_EXIT; 434 } 435 } else if (0 == strcmp(*argv, "--viewport")) { 436 ++argv; 437 if (argv >= stop) { 438 gLogger.logError("Missing width for --viewport\n"); 439 PRINT_USAGE_AND_EXIT; 440 } 441 viewport.fWidth = atoi(*argv); 442 ++argv; 443 if (argv >= stop) { 444 gLogger.logError("Missing height for --viewport\n"); 445 PRINT_USAGE_AND_EXIT; 446 } 447 viewport.fHeight = atoi(*argv); 448 } else if (0 == strcmp(*argv, "--scale")) { 449 ++argv; 450 if (argv >= stop) { 451 gLogger.logError("Missing scaleFactor for --scale\n"); 452 PRINT_USAGE_AND_EXIT; 453 } 454 scaleFactor = SkDoubleToScalar(atof(*argv)); 455 } else if (0 == strcmp(*argv, "--tiles")) { 456 ++argv; 457 if (argv >= stop) { 458 gLogger.logError("Missing x for --tiles\n"); 459 PRINT_USAGE_AND_EXIT; 460 } 461 xTilesString = *argv; 462 ++argv; 463 if (argv >= stop) { 464 gLogger.logError("Missing y for --tiles\n"); 465 PRINT_USAGE_AND_EXIT; 466 } 467 yTilesString = *argv; 468 } else if (0 == strcmp(*argv, "--device")) { 469 ++argv; 470 if (argv >= stop) { 471 gLogger.logError("Missing mode for --device\n"); 472 PRINT_USAGE_AND_EXIT; 473 } 474 475 if (0 == strcmp(*argv, "bitmap")) { 476 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType; 477 } 478 #if SK_SUPPORT_GPU 479 else if (0 == strcmp(*argv, "gpu")) { 480 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType; 481 } 482 #endif 483 else { 484 SkString err; 485 err.printf("%s is not a valid mode for --device\n", *argv); 486 gLogger.logError(err); 487 PRINT_USAGE_AND_EXIT; 488 } 489 } else if (0 == strcmp(*argv, "--timers")) { 490 ++argv; 491 if (argv < stop) { 492 bool timerWall = false; 493 bool truncatedTimerWall = false; 494 bool timerCpu = false; 495 bool truncatedTimerCpu = false; 496 bool timerGpu = false; 497 for (char* t = *argv; *t; ++t) { 498 switch (*t) { 499 case 'w': 500 timerWall = true; 501 break; 502 case 'c': 503 timerCpu = true; 504 break; 505 case 'W': 506 truncatedTimerWall = true; 507 break; 508 case 'C': 509 truncatedTimerCpu = true; 510 break; 511 case 'g': 512 timerGpu = true; 513 break; 514 default: { 515 break; 516 } 517 } 518 } 519 benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu, 520 truncatedTimerCpu, timerGpu); 521 } else { 522 gLogger.logError("Missing arg for --timers\n"); 523 PRINT_USAGE_AND_EXIT; 524 } 525 } else if (0 == strcmp(*argv, "--timeIndividualTiles")) { 526 benchmark->setTimeIndividualTiles(true); 527 } else if (0 == strcmp(*argv, "--min")) { 528 benchmark->setPrintMin(true); 529 } else if (0 == strcmp(*argv, "--logPerIter")) { 530 ++argv; 531 if (argv < stop) { 532 bool log = atoi(*argv) != 0; 533 benchmark->setLogPerIter(log); 534 } else { 535 gLogger.logError("Missing arg for --logPerIter\n"); 536 PRINT_USAGE_AND_EXIT; 537 } 538 } else if (0 == strcmp(*argv, "--filter")) { 539 ++argv; 540 if (argv < stop) { 541 const char* colon = strchr(*argv, ':'); 542 if (colon) { 543 int type = -1; 544 size_t typeLen = colon - *argv; 545 for (size_t tIndex = 0; tIndex < kFilterTypesCount; ++tIndex) { 546 if (typeLen == strlen(gFilterTypes[tIndex]) 547 && !strncmp(*argv, gFilterTypes[tIndex], typeLen)) { 548 type = tIndex; 549 break; 550 } 551 } 552 if (type < 0) { 553 SkString err; 554 err.printf("Unknown type for --filter %s\n", *argv); 555 gLogger.logError(err); 556 PRINT_USAGE_AND_EXIT; 557 } 558 int flag = -1; 559 size_t flagLen = strlen(*argv) - typeLen - 1; 560 for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) { 561 if (flagLen == strlen(gFilterFlags[fIndex]) 562 && !strncmp(colon + 1, gFilterFlags[fIndex], flagLen)) { 563 flag = 1 << fIndex; 564 break; 565 } 566 } 567 if (flag < 0) { 568 SkString err; 569 err.printf("Unknown flag for --filter %s\n", *argv); 570 gLogger.logError(err); 571 PRINT_USAGE_AND_EXIT; 572 } 573 for (int index = 0; index < SkDrawFilter::kTypeCount; ++index) { 574 if (type != SkDrawFilter::kTypeCount && index != type) { 575 continue; 576 } 577 drawFilters[index] = (sk_tools::PictureRenderer::DrawFilterFlags) 578 (drawFilters[index] | flag); 579 } 580 } else { 581 SkString err; 582 err.printf("Unknown arg for --filter %s : missing colon\n", *argv); 583 gLogger.logError(err); 584 PRINT_USAGE_AND_EXIT; 585 } 586 } else { 587 gLogger.logError("Missing arg for --filter\n"); 588 PRINT_USAGE_AND_EXIT; 589 } 590 } else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) { 591 PRINT_USAGE_AND_EXIT; 592 } else { 593 inputs->push_back(SkString(*argv)); 594 } 595 } 596 597 if (numThreads > 1 && !useTiles) { 598 gLogger.logError("Multithreaded drawing requires tiled rendering.\n"); 599 PRINT_USAGE_AND_EXIT; 600 } 601 602 if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) { 603 gLogger.logError("--pipe and --bbh cannot be used together\n"); 604 PRINT_USAGE_AND_EXIT; 605 } 606 607 if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType && 608 !gridSupported) { 609 gLogger.logError("'--bbh grid' is not compatible with specified --mode.\n"); 610 PRINT_USAGE_AND_EXIT; 611 } 612 613 if (useTiles) { 614 SkASSERT(NULL == renderer); 615 sk_tools::TiledPictureRenderer* tiledRenderer; 616 if (isCopyMode) { 617 int x, y; 618 if (xTilesString != NULL) { 619 SkASSERT(yTilesString != NULL); 620 x = atoi(xTilesString); 621 y = atoi(yTilesString); 622 if (x <= 0 || y <= 0) { 623 gLogger.logError("--tiles must be given values > 0\n"); 624 PRINT_USAGE_AND_EXIT; 625 } 626 } else { 627 x = y = 4; 628 } 629 tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y)); 630 if (benchmark->timeIndividualTiles()) { 631 gLogger.logError("timeIndividualTiles is not compatible with copyTile\n"); 632 PRINT_USAGE_AND_EXIT; 633 } 634 } else if (numThreads > 1) { 635 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads)); 636 } else { 637 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer); 638 } 639 if (isPowerOf2Mode) { 640 int minWidth = atoi(widthString); 641 if (!SkIsPow2(minWidth) || minWidth < 0) { 642 tiledRenderer->unref(); 643 SkString err; 644 err.printf("-mode %s must be given a width" 645 " value that is a power of two\n", mode); 646 gLogger.logError(err); 647 PRINT_USAGE_AND_EXIT; 648 } 649 tiledRenderer->setTileMinPowerOf2Width(minWidth); 650 } else if (sk_tools::is_percentage(widthString)) { 651 if (isCopyMode) { 652 tiledRenderer->unref(); 653 SkString err; 654 err.printf("--mode %s does not support percentages.\n", mode); 655 gLogger.logError(err.c_str()); 656 PRINT_USAGE_AND_EXIT; 657 } 658 tiledRenderer->setTileWidthPercentage(atof(widthString)); 659 if (!(tiledRenderer->getTileWidthPercentage() > 0)) { 660 tiledRenderer->unref(); 661 SkString err; 662 err.appendf("--mode %s must be given a width percentage > 0\n", mode); 663 gLogger.logError(err); 664 PRINT_USAGE_AND_EXIT; 665 } 666 } else { 667 tiledRenderer->setTileWidth(atoi(widthString)); 668 if (!(tiledRenderer->getTileWidth() > 0)) { 669 tiledRenderer->unref(); 670 SkString err; 671 err.appendf("--mode %s must be given a width > 0\n", mode); 672 gLogger.logError(err); 673 PRINT_USAGE_AND_EXIT; 674 } 675 } 676 677 if (sk_tools::is_percentage(heightString)) { 678 if (isCopyMode) { 679 tiledRenderer->unref(); 680 SkString err; 681 err.printf("--mode %s does not support percentages.\n", mode); 682 gLogger.logError(err.c_str()); 683 PRINT_USAGE_AND_EXIT; 684 } 685 tiledRenderer->setTileHeightPercentage(atof(heightString)); 686 if (!(tiledRenderer->getTileHeightPercentage() > 0)) { 687 tiledRenderer->unref(); 688 SkString err; 689 err.appendf("--mode %s must be given a height percentage > 0\n", mode); 690 gLogger.logError(err); 691 PRINT_USAGE_AND_EXIT; 692 } 693 } else { 694 tiledRenderer->setTileHeight(atoi(heightString)); 695 if (!(tiledRenderer->getTileHeight() > 0)) { 696 tiledRenderer->unref(); 697 SkString err; 698 err.appendf("--mode %s must be given a height > 0\n", mode); 699 gLogger.logError(err); 700 PRINT_USAGE_AND_EXIT; 701 } 702 } 703 if (numThreads > 1) { 704 #if SK_SUPPORT_GPU 705 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) { 706 tiledRenderer->unref(); 707 gLogger.logError("GPU not compatible with multithreaded tiling.\n"); 708 PRINT_USAGE_AND_EXIT; 709 } 710 #endif 711 } 712 renderer.reset(tiledRenderer); 713 if (usePipe) { 714 gLogger.logError("Pipe rendering is currently not compatible with tiling.\n" 715 "Turning off pipe.\n"); 716 } 717 } else { 718 if (benchmark->timeIndividualTiles()) { 719 gLogger.logError("timeIndividualTiles requires tiled rendering.\n"); 720 PRINT_USAGE_AND_EXIT; 721 } 722 if (usePipe) { 723 if (renderer.get() != NULL) { 724 gLogger.logError("Pipe is incompatible with other modes.\n"); 725 PRINT_USAGE_AND_EXIT; 726 } 727 renderer.reset(SkNEW(sk_tools::PipePictureRenderer)); 728 } 729 } 730 if (inputs->count() < 1) { 731 PRINT_USAGE_AND_EXIT; 732 } 733 734 if (NULL == renderer) { 735 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer)); 736 } 737 738 renderer->setBBoxHierarchyType(bbhType); 739 renderer->setDrawFilters(drawFilters, filtersName(drawFilters)); 740 renderer->setGridSize(gridWidth, gridHeight); 741 renderer->setViewport(viewport); 742 renderer->setScaleFactor(scaleFactor); 743 benchmark->setRenderer(renderer); 744 benchmark->setRepeats(repeats); 745 benchmark->setDeviceType(deviceType); 746 benchmark->setLogger(&gLogger); 747 // Report current settings: 748 gLogger.logProgress(commandLine); 749 } 750 751 static int process_input(const SkString& input, 752 sk_tools::PictureBenchmark& benchmark) { 753 SkOSFile::Iter iter(input.c_str(), "skp"); 754 SkString inputFilename; 755 int failures = 0; 756 if (iter.next(&inputFilename)) { 757 do { 758 SkString inputPath; 759 sk_tools::make_filepath(&inputPath, input, inputFilename); 760 if (!run_single_benchmark(inputPath, benchmark)) { 761 ++failures; 762 } 763 } while(iter.next(&inputFilename)); 764 } else if (SkStrEndsWith(input.c_str(), ".skp")) { 765 if (!run_single_benchmark(input, benchmark)) { 766 ++failures; 767 } 768 } else { 769 SkString warning; 770 warning.printf("Warning: skipping %s\n", input.c_str()); 771 gLogger.logError(warning); 772 } 773 return failures; 774 } 775 776 int tool_main(int argc, char** argv); 777 int tool_main(int argc, char** argv) { 778 #if SK_ENABLE_INST_COUNT 779 gPrintInstCount = true; 780 #endif 781 SkAutoGraphics ag; 782 783 SkTArray<SkString> inputs; 784 sk_tools::PictureBenchmark benchmark; 785 786 parse_commandline(argc, argv, &inputs, &benchmark); 787 788 int failures = 0; 789 for (int i = 0; i < inputs.count(); ++i) { 790 failures += process_input(inputs[i], benchmark); 791 } 792 793 if (failures != 0) { 794 SkString err; 795 err.printf("Failed to run %i benchmarks.\n", failures); 796 gLogger.logError(err); 797 return 1; 798 } 799 return 0; 800 } 801 802 #if !defined SK_BUILD_FOR_IOS 803 int main(int argc, char * const argv[]) { 804 return tool_main(argc, (char**) argv); 805 } 806 #endif 807