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