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