benchmain.cpp revision ed5eb4ef2aa1d6c705bc3ed466f9caba2a230a2b
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 9 10#include "BenchTimer.h" 11 12#if SK_SUPPORT_GPU 13#include "GrContext.h" 14#include "GrContextFactory.h" 15#include "gl/GrGLDefines.h" 16#include "GrRenderTarget.h" 17#include "SkGpuDevice.h" 18#else 19class GrContext; 20#endif // SK_SUPPORT_GPU 21 22#include "SkBenchLogger.h" 23#include "SkBenchmark.h" 24#include "SkCanvas.h" 25#include "SkDeferredCanvas.h" 26#include "SkDevice.h" 27#include "SkColorPriv.h" 28#include "SkGraphics.h" 29#include "SkImageEncoder.h" 30#include "SkNWayCanvas.h" 31#include "SkPicture.h" 32#include "SkString.h" 33#include "SkTArray.h" 34#include "TimerData.h" 35 36enum benchModes { 37 kNormal_benchModes, 38 kDeferred_benchModes, 39 kDeferredSilent_benchModes, 40 kRecord_benchModes, 41 kPictureRecord_benchModes 42}; 43 44/////////////////////////////////////////////////////////////////////////////// 45 46static void erase(SkBitmap& bm) { 47 if (bm.config() == SkBitmap::kA8_Config) { 48 bm.eraseColor(SK_ColorTRANSPARENT); 49 } else { 50 bm.eraseColor(SK_ColorWHITE); 51 } 52} 53 54#if 0 55static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { 56 if (bm1.width() != bm2.width() || 57 bm1.height() != bm2.height() || 58 bm1.config() != bm2.config()) { 59 return false; 60 } 61 62 size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); 63 for (int y = 0; y < bm1.height(); y++) { 64 if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { 65 return false; 66 } 67 } 68 return true; 69} 70#endif 71 72class Iter { 73public: 74 Iter(void* param) { 75 fBench = BenchRegistry::Head(); 76 fParam = param; 77 } 78 79 SkBenchmark* next() { 80 if (fBench) { 81 BenchRegistry::Factory f = fBench->factory(); 82 fBench = fBench->next(); 83 return f(fParam); 84 } 85 return NULL; 86 } 87 88private: 89 const BenchRegistry* fBench; 90 void* fParam; 91}; 92 93class AutoPrePostDraw { 94public: 95 AutoPrePostDraw(SkBenchmark* bench) : fBench(bench) { 96 fBench->preDraw(); 97 } 98 ~AutoPrePostDraw() { 99 fBench->postDraw(); 100 } 101private: 102 SkBenchmark* fBench; 103}; 104 105static void make_filename(const char name[], SkString* path) { 106 path->set(name); 107 for (int i = 0; name[i]; i++) { 108 switch (name[i]) { 109 case '/': 110 case '\\': 111 case ' ': 112 case ':': 113 path->writable_str()[i] = '-'; 114 break; 115 default: 116 break; 117 } 118 } 119} 120 121static void saveFile(const char name[], const char config[], const char dir[], 122 const SkBitmap& bm) { 123 SkBitmap copy; 124 if (!bm.copyTo(©, SkBitmap::kARGB_8888_Config)) { 125 return; 126 } 127 128 if (bm.config() == SkBitmap::kA8_Config) { 129 // turn alpha into gray-scale 130 size_t size = copy.getSize() >> 2; 131 SkPMColor* p = copy.getAddr32(0, 0); 132 for (size_t i = 0; i < size; i++) { 133 int c = (*p >> SK_A32_SHIFT) & 0xFF; 134 c = 255 - c; 135 c |= (c << 24) | (c << 16) | (c << 8); 136 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); 137 } 138 } 139 140 SkString str; 141 make_filename(name, &str); 142 str.appendf("_%s.png", config); 143 str.prepend(dir); 144 ::remove(str.c_str()); 145 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, 146 100); 147} 148 149static void performClip(SkCanvas* canvas, int w, int h) { 150 SkRect r; 151 152 r.set(SkIntToScalar(10), SkIntToScalar(10), 153 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); 154 canvas->clipRect(r, SkRegion::kIntersect_Op); 155 156 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), 157 SkIntToScalar(w-10), SkIntToScalar(h-10)); 158 canvas->clipRect(r, SkRegion::kXOR_Op); 159} 160 161static void performRotate(SkCanvas* canvas, int w, int h) { 162 const SkScalar x = SkIntToScalar(w) / 2; 163 const SkScalar y = SkIntToScalar(h) / 2; 164 165 canvas->translate(x, y); 166 canvas->rotate(SkIntToScalar(35)); 167 canvas->translate(-x, -y); 168} 169 170static void performScale(SkCanvas* canvas, int w, int h) { 171 const SkScalar x = SkIntToScalar(w) / 2; 172 const SkScalar y = SkIntToScalar(h) / 2; 173 174 canvas->translate(x, y); 175 // just enough so we can't take the sprite case 176 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); 177 canvas->translate(-x, -y); 178} 179 180static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { 181 if (argv < stop) { 182 *var = atoi(*argv) != 0; 183 return true; 184 } 185 return false; 186} 187 188enum Backend { 189 kNonRendering_Backend, 190 kRaster_Backend, 191 kGPU_Backend, 192 kPDF_Backend, 193}; 194 195static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size, 196 Backend backend, int sampleCount, GrContext* context) { 197 SkDevice* device = NULL; 198 SkBitmap bitmap; 199 bitmap.setConfig(config, size.fX, size.fY); 200 201 switch (backend) { 202 case kRaster_Backend: 203 bitmap.allocPixels(); 204 erase(bitmap); 205 device = SkNEW_ARGS(SkDevice, (bitmap)); 206 break; 207#if SK_SUPPORT_GPU 208 case kGPU_Backend: { 209 GrTextureDesc desc; 210 desc.fConfig = kSkia8888_GrPixelConfig; 211 desc.fFlags = kRenderTarget_GrTextureFlagBit; 212 desc.fWidth = size.fX; 213 desc.fHeight = size.fY; 214 desc.fSampleCnt = sampleCount; 215 SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0)); 216 if (!texture) { 217 return NULL; 218 } 219 device = SkNEW_ARGS(SkGpuDevice, (context, texture.get())); 220 break; 221 } 222#endif 223 case kPDF_Backend: 224 default: 225 SkASSERT(!"unsupported"); 226 } 227 return device; 228} 229 230#if SK_SUPPORT_GPU 231GrContextFactory gContextFactory; 232typedef GrContextFactory::GLContextType GLContextType; 233static const GLContextType kDontCareGLCtxType = GrContextFactory::kNative_GLContextType; 234#else 235typedef int GLContextType; 236static const GLContextType kDontCareGLCtxType = 0; 237#endif 238 239static const struct { 240 SkBitmap::Config fConfig; 241 const char* fName; 242 int fSampleCnt; 243 Backend fBackend; 244 GLContextType fContextType; 245 bool fRunByDefault; 246} gConfigs[] = { 247 { SkBitmap::kNo_Config, "NONRENDERING", 0, kNonRendering_Backend, kDontCareGLCtxType, true }, 248 { SkBitmap::kARGB_8888_Config, "8888", 0, kRaster_Backend, kDontCareGLCtxType, true }, 249 { SkBitmap::kRGB_565_Config, "565", 0, kRaster_Backend, kDontCareGLCtxType, true }, 250#if SK_SUPPORT_GPU 251 { SkBitmap::kARGB_8888_Config, "GPU", 0, kGPU_Backend, GrContextFactory::kNative_GLContextType, true }, 252 { SkBitmap::kARGB_8888_Config, "MSAA4", 4, kGPU_Backend, GrContextFactory::kNative_GLContextType, false }, 253 { SkBitmap::kARGB_8888_Config, "MSAA16", 16, kGPU_Backend, GrContextFactory::kNative_GLContextType, false }, 254#if SK_ANGLE 255 { SkBitmap::kARGB_8888_Config, "ANGLE", 0, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, true }, 256#endif // SK_ANGLE 257#ifdef SK_DEBUG 258 { SkBitmap::kARGB_8888_Config, "Debug", 0, kGPU_Backend, GrContextFactory::kDebug_GLContextType, GR_DEBUG }, 259#endif // SK_DEBUG 260 { SkBitmap::kARGB_8888_Config, "NULLGPU", 0, kGPU_Backend, GrContextFactory::kNull_GLContextType, true }, 261#endif // SK_SUPPORT_GPU 262}; 263 264static int findConfig(const char config[]) { 265 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { 266 if (!strcmp(config, gConfigs[i].fName)) { 267 return i; 268 } 269 } 270 return -1; 271} 272 273static bool skip_name(const SkTDArray<const char*> array, const char name[]) { 274 // FIXME: this duplicates the logic in skia_test.cpp, gmmain.cpp -- consolidate 275 int count = array.count(); 276 size_t testLen = strlen(name); 277 bool anyExclude = count == 0; 278 for (int i = 0; i < array.count(); ++i) { 279 const char* matchName = array[i]; 280 size_t matchLen = strlen(matchName); 281 bool matchExclude, matchStart, matchEnd; 282 if ((matchExclude = matchName[0] == '~')) { 283 anyExclude = true; 284 matchName++; 285 matchLen--; 286 } 287 if ((matchStart = matchName[0] == '^')) { 288 matchName++; 289 matchLen--; 290 } 291 if ((matchEnd = matchName[matchLen - 1] == '$')) { 292 matchLen--; 293 } 294 if (matchStart ? (!matchEnd || matchLen == testLen) 295 && strncmp(name, matchName, matchLen) == 0 296 : matchEnd ? matchLen <= testLen 297 && strncmp(name + testLen - matchLen, matchName, matchLen) == 0 298 : strstr(name, matchName) != 0) { 299 return matchExclude; 300 } 301 } 302 return !anyExclude; 303} 304 305static void help() { 306 SkString configsStr; 307 static const size_t kConfigCount = SK_ARRAY_COUNT(gConfigs); 308 for (size_t i = 0; i < kConfigCount; ++i) { 309 configsStr.appendf("%s%s", gConfigs[i].fName, ((i == kConfigCount - 1) ? "" : "|")); 310 } 311 312 SkDebugf("Usage: bench [-o outDir] [--repeat nr] [--logPerIter] " 313 "[--timers [wcgWC]*] [--rotate]\n" 314 " [--scale] [--clip] [--min] [--forceAA 1|0] [--forceFilter 1|0]\n" 315 " [--forceDither 1|0] [--forceBlend 1|0]" 316#if SK_SUPPORT_GPU 317 " [--gpuCacheSize <bytes> <count>]" 318#endif 319 "\n" 320 " [--strokeWidth width] [--match name]\n" 321 " [--mode normal|deferred|deferredSilent|record|picturerecord]\n" 322 " [--config "); 323 SkDebugf("%s]\n", configsStr.c_str()); 324 SkDebugf(" [-Dfoo bar] [--logFile filename] [-h|--help]"); 325 SkDebugf("\n\n"); 326 SkDebugf(" -o outDir : Image of each bench will be put in outDir.\n"); 327 SkDebugf(" --repeat nr : Each bench repeats for nr times.\n"); 328 SkDebugf(" --logPerIter : " 329 "Log each repeat timer instead of mean, default is disabled.\n"); 330 SkDebugf(" --timers [wcgWC]* : " 331 "Display wall, cpu, gpu, truncated wall or truncated cpu time for each bench.\n"); 332 SkDebugf(" --rotate : Rotate before each bench runs.\n"); 333 SkDebugf(" --scale : Scale before each bench runs.\n"); 334 SkDebugf(" --clip : Clip before each bench runs.\n"); 335 SkDebugf(" --min : Print the minimum times (instead of average).\n"); 336 SkDebugf(" --forceAA 1|0 : " 337 "Enable/disable anti-aliased, default is enabled.\n"); 338 SkDebugf(" --forceFilter 1|0 : " 339 "Enable/disable bitmap filtering, default is disabled.\n"); 340 SkDebugf(" --forceDither 1|0 : " 341 "Enable/disable dithering, default is disabled.\n"); 342 SkDebugf(" --forceBlend 1|0 : " 343 "Enable/disable dithering, default is disabled.\n"); 344#if SK_SUPPORT_GPU 345 SkDebugf(" --gpuCacheSize <bytes> <count>: " 346 "limits gpu cache to bytes size or object count.\n"); 347 SkDebugf(" -1 for either value means use the default. 0 for either disables the cache.\n"); 348#endif 349 SkDebugf(" --strokeWidth width : The width for path stroke.\n"); 350 SkDebugf(" --match [~][^]substring[$] [...] of test name to run.\n" 351 " Multiple matches may be separated by spaces.\n" 352 " ~ causes a matching test to always be skipped\n" 353 " ^ requires the start of the test to match\n" 354 " $ requires the end of the test to match\n" 355 " ^ and $ requires an exact match\n" 356 " If a test does not match any list entry,\n" 357 " it is skipped unless some list entry starts with ~\n"); 358 SkDebugf(" --mode normal|deferred|deferredSilent|record|picturerecord :\n" 359 " Run in the corresponding mode\n" 360 " normal, Use a normal canvas to draw to;\n" 361 " deferred, Use a deferrred canvas when drawing;\n" 362 " deferredSilent, deferred with silent playback;\n" 363 " record, Benchmark the time to record to an SkPicture;\n" 364 " picturerecord, Benchmark the time to do record from a \n" 365 " SkPicture to a SkPicture.\n"); 366 SkDebugf(" --logFile filename : destination for writing log output, in addition to stdout.\n"); 367 SkDebugf(" --config %s:\n", configsStr.c_str()); 368 SkDebugf(" Run bench in corresponding config mode.\n"); 369 SkDebugf(" -Dfoo bar : Add extra definition to bench.\n"); 370 SkDebugf(" -h|--help : Show this help message.\n"); 371} 372 373int tool_main(int argc, char** argv); 374int tool_main(int argc, char** argv) { 375#if SK_ENABLE_INST_COUNT 376 gPrintInstCount = true; 377#endif 378 SkAutoGraphics ag; 379 380 SkTDict<const char*> defineDict(1024); 381 int repeatDraw = 1; 382 bool logPerIter = false; 383 int forceAlpha = 0xFF; 384 bool forceAA = true; 385 bool forceFilter = false; 386 SkTriState::State forceDither = SkTriState::kDefault; 387 bool timerWall = false; 388 bool truncatedTimerWall = false; 389 bool timerCpu = true; 390 bool truncatedTimerCpu = false; 391 bool timerGpu = true; 392 bool doScale = false; 393 bool doRotate = false; 394 bool doClip = false; 395 bool printMin = false; 396 bool hasStrokeWidth = false; 397 398#if SK_SUPPORT_GPU 399 struct { 400 int fBytes; 401 int fCount; 402 } gpuCacheSize = { -1, -1 }; // -1s mean use the default 403#endif 404 405 float strokeWidth; 406 SkTDArray<const char*> fMatches; 407 benchModes benchMode = kNormal_benchModes; 408 SkString perIterTimeformat("%.2f"); 409 SkString normalTimeFormat("%6.2f"); 410 411 SkString outDir; 412 SkBitmap::Config outConfig = SkBitmap::kNo_Config; 413 const char* configName = ""; 414 Backend backend = kRaster_Backend; // for warning 415 int sampleCount = 0; 416 SkTDArray<int> configs; 417 bool userConfig = false; 418 419 SkBenchLogger logger; 420 421 char* const* stop = argv + argc; 422 for (++argv; argv < stop; ++argv) { 423 if (strcmp(*argv, "-o") == 0) { 424 argv++; 425 if (argv < stop && **argv) { 426 outDir.set(*argv); 427 if (outDir.c_str()[outDir.size() - 1] != '/') { 428 outDir.append("/"); 429 } 430 } 431 } else if (strcmp(*argv, "--repeat") == 0) { 432 argv++; 433 if (argv < stop) { 434 repeatDraw = atoi(*argv); 435 if (repeatDraw < 1) { 436 repeatDraw = 1; 437 } 438 } else { 439 logger.logError("missing arg for --repeat\n"); 440 help(); 441 return -1; 442 } 443 } else if (strcmp(*argv, "--logPerIter") == 0) { 444 logPerIter = true; 445 } else if (strcmp(*argv, "--timers") == 0) { 446 argv++; 447 if (argv < stop) { 448 timerWall = false; 449 truncatedTimerWall = false; 450 timerCpu = false; 451 truncatedTimerCpu = false; 452 timerGpu = false; 453 for (char* t = *argv; *t; ++t) { 454 switch (*t) { 455 case 'w': timerWall = true; break; 456 case 'c': timerCpu = true; break; 457 case 'W': truncatedTimerWall = true; break; 458 case 'C': truncatedTimerCpu = true; break; 459 case 'g': timerGpu = true; break; 460 } 461 } 462 } else { 463 logger.logError("missing arg for --timers\n"); 464 help(); 465 return -1; 466 } 467 } else if (!strcmp(*argv, "--rotate")) { 468 doRotate = true; 469 } else if (!strcmp(*argv, "--scale")) { 470 doScale = true; 471 } else if (!strcmp(*argv, "--clip")) { 472 doClip = true; 473 } else if (!strcmp(*argv, "--min")) { 474 printMin = true; 475 } else if (strcmp(*argv, "--forceAA") == 0) { 476 if (!parse_bool_arg(++argv, stop, &forceAA)) { 477 logger.logError("missing arg for --forceAA\n"); 478 help(); 479 return -1; 480 } 481 } else if (strcmp(*argv, "--forceFilter") == 0) { 482 if (!parse_bool_arg(++argv, stop, &forceFilter)) { 483 logger.logError("missing arg for --forceFilter\n"); 484 help(); 485 return -1; 486 } 487 } else if (strcmp(*argv, "--forceDither") == 0) { 488 bool tmp; 489 if (!parse_bool_arg(++argv, stop, &tmp)) { 490 logger.logError("missing arg for --forceDither\n"); 491 help(); 492 return -1; 493 } 494 forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse; 495 } else if (strcmp(*argv, "--forceBlend") == 0) { 496 bool wantAlpha = false; 497 if (!parse_bool_arg(++argv, stop, &wantAlpha)) { 498 logger.logError("missing arg for --forceBlend\n"); 499 help(); 500 return -1; 501 } 502 forceAlpha = wantAlpha ? 0x80 : 0xFF; 503#if SK_SUPPORT_GPU 504 } else if (strcmp(*argv, "--gpuCacheSize") == 0) { 505 if (stop - argv > 2) { 506 gpuCacheSize.fBytes = atoi(*++argv); 507 gpuCacheSize.fCount = atoi(*++argv); 508 } else { 509 SkDebugf("missing arg for --gpuCacheSize\n"); 510 help(); 511 return -1; 512 } 513#endif 514 } else if (strcmp(*argv, "--mode") == 0) { 515 argv++; 516 if (argv < stop) { 517 if (strcmp(*argv, "normal") == 0) { 518 benchMode = kNormal_benchModes; 519 } else if (strcmp(*argv, "deferred") == 0) { 520 benchMode = kDeferred_benchModes; 521 } else if (strcmp(*argv, "deferredSilent") == 0) { 522 benchMode = kDeferredSilent_benchModes; 523 } else if (strcmp(*argv, "record") == 0) { 524 benchMode = kRecord_benchModes; 525 } else if (strcmp(*argv, "picturerecord") == 0) { 526 benchMode = kPictureRecord_benchModes; 527 } else { 528 logger.logError("bad arg for --mode\n"); 529 help(); 530 return -1; 531 } 532 } else { 533 logger.logError("missing arg for --mode\n"); 534 help(); 535 return -1; 536 } 537 } else if (strcmp(*argv, "--strokeWidth") == 0) { 538 argv++; 539 if (argv < stop) { 540 const char *strokeWidthStr = *argv; 541 if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { 542 logger.logError("bad arg for --strokeWidth\n"); 543 help(); 544 return -1; 545 } 546 hasStrokeWidth = true; 547 } else { 548 logger.logError("missing arg for --strokeWidth\n"); 549 help(); 550 return -1; 551 } 552 } else if (strcmp(*argv, "--match") == 0) { 553 argv++; 554 while (argv < stop && (*argv)[0] != '-') { 555 *fMatches.append() = *argv++; 556 } 557 argv--; 558 if (!fMatches.count()) { 559 logger.logError("missing arg for --match\n"); 560 help(); 561 return -1; 562 } 563 } else if (strcmp(*argv, "--config") == 0) { 564 argv++; 565 if (argv < stop) { 566 int index = findConfig(*argv); 567 if (index >= 0) { 568 *configs.append() = index; 569 userConfig = true; 570 } else { 571 SkString str; 572 str.printf("unrecognized config %s\n", *argv); 573 logger.logError(str); 574 help(); 575 return -1; 576 } 577 } else { 578 logger.logError("missing arg for --config\n"); 579 help(); 580 return -1; 581 } 582 } else if (strcmp(*argv, "--logFile") == 0) { 583 argv++; 584 if (argv < stop) { 585 if (!logger.SetLogFile(*argv)) { 586 SkString str; 587 str.printf("Could not open %s for writing.", *argv); 588 logger.logError(str); 589 return -1; 590 } 591 } else { 592 logger.logError("missing arg for --logFile\n"); 593 help(); 594 return -1; 595 } 596 } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) { 597 argv++; 598 if (argv < stop) { 599 defineDict.set(argv[-1] + 2, *argv); 600 } else { 601 logger.logError("incomplete '-Dfoo bar' definition\n"); 602 help(); 603 return -1; 604 } 605 } else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) { 606 help(); 607 return 0; 608 } else { 609 SkString str; 610 str.printf("unrecognized arg %s\n", *argv); 611 logger.logError(str); 612 help(); 613 return -1; 614 } 615 } 616 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes) 617 && !outDir.isEmpty()) { 618 logger.logError("'--mode record' and '--mode picturerecord' are not" 619 " compatible with -o.\n"); 620 return -1; 621 } 622 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)) { 623 perIterTimeformat.set("%.4f"); 624 normalTimeFormat.set("%6.4f"); 625 } 626 if (!userConfig) { 627 // if no config is specified by user, add the default configs 628 for (unsigned int i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { 629 if (gConfigs[i].fRunByDefault) { 630 *configs.append() = i; 631 } 632 } 633 } 634 if (kNormal_benchModes != benchMode) { 635 // Non-rendering configs only run in normal mode 636 for (int i = 0; i < configs.count(); ++i) { 637 int configIdx = configs[i]; 638 if (kNonRendering_Backend == gConfigs[configIdx].fBackend) { 639 configs.remove(i, 1); 640 --i; 641 } 642 } 643 } 644 645#if SK_SUPPORT_GPU 646 for (int i = 0; i < configs.count(); ++i) { 647 int configIdx = configs[i]; 648 649 if (kGPU_Backend == gConfigs[configIdx].fBackend && gConfigs[configIdx].fSampleCnt > 0) { 650 GrContext* context = gContextFactory.get(gConfigs[configIdx].fContextType); 651 if (NULL == context) { 652 SkString error; 653 error.printf("Error creating GrContext for config %s. Config will be skipped.\n", 654 gConfigs[configIdx].fName); 655 logger.logError(error.c_str()); 656 configs.remove(i); 657 --i; 658 continue; 659 } 660 if (gConfigs[configIdx].fSampleCnt > context->getMaxSampleCount()){ 661 SkString error; 662 error.printf("Sample count (%d) for config %s is unsupported. " 663 "Config will be skipped.\n", 664 gConfigs[configIdx].fSampleCnt, gConfigs[configIdx].fName); 665 logger.logError(error.c_str()); 666 configs.remove(i); 667 --i; 668 continue; 669 } 670 } 671 } 672#endif 673 674 // report our current settings 675 { 676 SkString str; 677 const char* deferredMode = benchMode == kDeferred_benchModes ? "yes" : 678 (benchMode == kDeferredSilent_benchModes ? "silent" : "no"); 679 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d " 680 "deferred=%s logperiter=%d", 681 forceAlpha, forceAA, forceFilter, deferredMode, 682 logPerIter); 683 str.appendf(" rotate=%d scale=%d clip=%d min=%d", 684 doRotate, doScale, doClip, printMin); 685 str.appendf(" record=%d picturerecord=%d", 686 benchMode == kRecord_benchModes, 687 benchMode == kPictureRecord_benchModes); 688 const char * ditherName; 689 switch (forceDither) { 690 case SkTriState::kDefault: ditherName = "default"; break; 691 case SkTriState::kTrue: ditherName = "true"; break; 692 case SkTriState::kFalse: ditherName = "false"; break; 693 default: ditherName = "<invalid>"; break; 694 } 695 str.appendf(" dither=%s", ditherName); 696 697 if (hasStrokeWidth) { 698 str.appendf(" strokeWidth=%f", strokeWidth); 699 } else { 700 str.append(" strokeWidth=none"); 701 } 702 703#if defined(SK_SCALAR_IS_FLOAT) 704 str.append(" scalar=float"); 705#elif defined(SK_SCALAR_IS_FIXED) 706 str.append(" scalar=fixed"); 707#endif 708 709#if defined(SK_BUILD_FOR_WIN32) 710 str.append(" system=WIN32"); 711#elif defined(SK_BUILD_FOR_MAC) 712 str.append(" system=MAC"); 713#elif defined(SK_BUILD_FOR_ANDROID) 714 str.append(" system=ANDROID"); 715#elif defined(SK_BUILD_FOR_UNIX) 716 str.append(" system=UNIX"); 717#else 718 str.append(" system=other"); 719#endif 720 721#if defined(SK_DEBUG) 722 str.append(" DEBUG"); 723#endif 724 str.append("\n"); 725 logger.logProgress(str); 726 } 727 728 SkTArray<BenchTimer*> timers(SK_ARRAY_COUNT(gConfigs)); 729 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { 730#if SK_SUPPORT_GPU 731 SkGLContextHelper* glCtx = NULL; 732 if (kGPU_Backend == gConfigs[i].fBackend) { 733 GrContext* context = gContextFactory.get(gConfigs[i].fContextType); 734 if (NULL != context) { 735 // Set the user specified cache limits if non-default. 736 size_t bytes; 737 int count; 738 context->getTextureCacheLimits(&count, &bytes); 739 if (-1 != gpuCacheSize.fBytes) { 740 bytes = static_cast<size_t>(gpuCacheSize.fBytes); 741 } 742 if (-1 != gpuCacheSize.fCount) { 743 count = gpuCacheSize.fCount; 744 } 745 context->setTextureCacheLimits(count, bytes); 746 } 747 glCtx = gContextFactory.getGLContext(gConfigs[i].fContextType); 748 } 749 timers.push_back(SkNEW_ARGS(BenchTimer, (glCtx))); 750#else 751 timers.push_back(SkNEW(BenchTimer)); 752#endif 753 } 754 755 Iter iter(&defineDict); 756 SkBenchmark* bench; 757 while ((bench = iter.next()) != NULL) { 758 SkAutoTUnref<SkBenchmark> benchUnref(bench); 759 760 SkIPoint dim = bench->getSize(); 761 if (dim.fX <= 0 || dim.fY <= 0) { 762 continue; 763 } 764 765 bench->setForceAlpha(forceAlpha); 766 bench->setForceAA(forceAA); 767 bench->setForceFilter(forceFilter); 768 bench->setDither(forceDither); 769 if (hasStrokeWidth) { 770 bench->setStrokeWidth(strokeWidth); 771 } 772 773 // only run benchmarks if their name contains matchStr 774 if (skip_name(fMatches, bench->getName())) { 775 continue; 776 } 777 778 bool loggedBenchStart = false; 779 780 AutoPrePostDraw appd(bench); 781 782 for (int x = 0; x < configs.count(); ++x) { 783 int configIndex = configs[x]; 784 785 bool setupFailed = false; 786 787 if (kNonRendering_Backend == gConfigs[configIndex].fBackend) { 788 if (bench->isRendering()) { 789 continue; 790 } 791 } else { 792 if (!bench->isRendering()) { 793 continue; 794 } 795 } 796 797 outConfig = gConfigs[configIndex].fConfig; 798 configName = gConfigs[configIndex].fName; 799 backend = gConfigs[configIndex].fBackend; 800 sampleCount = gConfigs[configIndex].fSampleCnt; 801 GrContext* context = NULL; 802 BenchTimer* timer = timers[configIndex]; 803 804#if SK_SUPPORT_GPU 805 SkGLContextHelper* glContext = NULL; 806 if (kGPU_Backend == backend) { 807 context = gContextFactory.get(gConfigs[configIndex].fContextType); 808 if (NULL == context) { 809 continue; 810 } 811 glContext = gContextFactory.getGLContext(gConfigs[configIndex].fContextType); 812 } 813#endif 814 SkDevice* device = NULL; 815 SkCanvas* canvas = NULL; 816 SkPicture pictureRecordFrom; 817 SkPicture pictureRecordTo; 818 819 if (kNonRendering_Backend != backend) { 820 device = make_device(outConfig, dim, backend, sampleCount, context); 821 if (NULL == device) { 822 SkString error; 823 error.printf("Device creation failure for config %s. Will skip.\n", configName); 824 logger.logError(error.c_str()); 825 setupFailed = true; 826 } else { 827 switch(benchMode) { 828 case kDeferredSilent_benchModes: 829 case kDeferred_benchModes: 830 canvas = 831#if SK_DEFERRED_CANVAS_USES_FACTORIES 832 SkDeferredCanvas::Create(device); 833#else 834 SkNEW_ARGS(SkDeferredCanvas, (device)); 835#endif 836 break; 837 case kRecord_benchModes: 838 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, 839 SkPicture::kUsePathBoundsForClip_RecordingFlag); 840 canvas->ref(); 841 break; 842 case kPictureRecord_benchModes: { 843 // This sets up picture-to-picture recording. 844 // The C++ drawing calls for the benchmark are recorded into 845 // pictureRecordFrom. As the benchmark, we will time how 846 // long it takes to playback pictureRecordFrom into 847 // pictureRecordTo. 848 SkCanvas* tempCanvas = pictureRecordFrom.beginRecording(dim.fX, dim.fY, 849 SkPicture::kUsePathBoundsForClip_RecordingFlag); 850 bench->draw(tempCanvas); 851 pictureRecordFrom.endRecording(); 852 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, 853 SkPicture::kUsePathBoundsForClip_RecordingFlag); 854 canvas->ref(); 855 break; 856 } 857 case kNormal_benchModes: 858 canvas = new SkCanvas(device); 859 break; 860 default: 861 SkASSERT(0); 862 } 863 device->unref(); 864 canvas->clear(SK_ColorWHITE); 865 } 866 } 867 SkAutoUnref canvasUnref(canvas); 868 if (!setupFailed) { 869 if (NULL != canvas) { 870 if (doClip) { 871 performClip(canvas, dim.fX, dim.fY); 872 } 873 if (doScale) { 874 performScale(canvas, dim.fX, dim.fY); 875 } 876 if (doRotate) { 877 performRotate(canvas, dim.fX, dim.fY); 878 } 879 } 880 881 if (!loggedBenchStart) { 882 loggedBenchStart = true; 883 SkString str; 884 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, bench->getName()); 885 logger.logProgress(str); 886 } 887 888 // warm up caches if needed 889 if (repeatDraw > 1 && NULL != canvas) { 890#if SK_SUPPORT_GPU 891 // purge the GPU resources to reduce variance 892 if (NULL != context) { 893 context->freeGpuResources(); 894 } 895#endif 896 SkAutoCanvasRestore acr(canvas, true); 897 if (benchMode == kPictureRecord_benchModes) { 898 pictureRecordFrom.draw(canvas); 899 } else { 900 bench->draw(canvas); 901 } 902 903 if (kDeferredSilent_benchModes == benchMode) { 904 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); 905 } else { 906 canvas->flush(); 907 } 908#if SK_SUPPORT_GPU 909 if (NULL != context) { 910 context->flush(); 911 SK_GL(*glContext, Finish()); 912 } 913#endif 914 } 915 916 // record timer values for each repeat, and their sum 917 TimerData timerData(perIterTimeformat, normalTimeFormat); 918 for (int i = 0; i < repeatDraw; i++) { 919 if ((benchMode == kRecord_benchModes || benchMode == kPictureRecord_benchModes)) { 920 // This will clear the recorded commands so that they do not 921 // accumulate. 922 canvas = pictureRecordTo.beginRecording(dim.fX, dim.fY, 923 SkPicture::kUsePathBoundsForClip_RecordingFlag); 924 } 925 926 timer->start(bench->getDurationScale()); 927 if (NULL != canvas) { 928 canvas->save(); 929 } 930 if (benchMode == kPictureRecord_benchModes) { 931 pictureRecordFrom.draw(canvas); 932 } else { 933 bench->draw(canvas); 934 } 935 936 if (kDeferredSilent_benchModes == benchMode) { 937 static_cast<SkDeferredCanvas*>(canvas)->silentFlush(); 938 } else if (NULL != canvas) { 939 canvas->flush(); 940 } 941 942 if (NULL != canvas) { 943 canvas->restore(); 944 } 945 946 // stop the truncated timer after the last canvas call but 947 // don't wait for all the GL calls to complete 948 timer->truncatedEnd(); 949#if SK_SUPPORT_GPU 950 if (NULL != glContext) { 951 context->flush(); 952 SK_GL(*glContext, Finish()); 953 } 954#endif 955 // stop the inclusive and gpu timers once all the GL calls 956 // have completed 957 timer->end(); 958 959 timerData.appendTimes(timer, repeatDraw - 1 == i); 960 961 } 962 if (repeatDraw > 1) { 963 SkString result = timerData.getResult( 964 logPerIter, printMin, repeatDraw, configName, 965 timerWall, truncatedTimerWall, timerCpu, 966 truncatedTimerCpu, 967 timerGpu && NULL != context); 968 logger.logProgress(result); 969 } 970 if (outDir.size() > 0 && kNonRendering_Backend != backend) { 971 saveFile(bench->getName(), configName, outDir.c_str(), 972 device->accessBitmap(false)); 973 } 974 } 975 } 976 if (loggedBenchStart) { 977 logger.logProgress(SkString("\n")); 978 } 979 } 980#if SK_SUPPORT_GPU 981#if GR_CACHE_STATS 982 for (int i = 0; i <= GrContextFactory::kLastGLContextType; ++i) { 983 GrContextFactory::GLContextType ctxType = (GrContextFactory::GLContextType)i; 984 GrContext* context = gContextFactory.get(ctxType); 985 if (NULL != context) { 986 SkDebugf("Cache Stats for %s context:\n", GrContextFactory::GLContextTypeName(ctxType)); 987 context->printCacheStats(); 988 SkDebugf("\n"); 989 } 990 } 991#endif 992 // Destroy the GrContext before the inst tracking printing at main() exit occurs. 993 gContextFactory.destroyContexts(); 994#endif 995 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); ++i) { 996 SkDELETE(timers[i]); 997 } 998 999 return 0; 1000} 1001 1002#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 1003int main(int argc, char * const argv[]) { 1004 return tool_main(argc, (char**) argv); 1005} 1006#endif 1007