1 /* 2 * Copyright 2011 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 /* 9 * Code for the "gm" (Golden Master) rendering comparison tool. 10 * 11 * If you make changes to this, re-run the self-tests at gm/tests/run.sh 12 * to make sure they still pass... you may need to change the expected 13 * results of the self-test. 14 */ 15 16 #include "gm.h" 17 #include "gm_error.h" 18 #include "gm_expectations.h" 19 #include "system_preferences.h" 20 #include "CrashHandler.h" 21 #include "ProcStats.h" 22 #include "Resources.h" 23 #include "SamplePipeControllers.h" 24 #include "SkBitmap.h" 25 #include "SkColorPriv.h" 26 #include "SkCommandLineFlags.h" 27 #include "SkData.h" 28 #include "SkDeferredCanvas.h" 29 #include "SkDevice.h" 30 #include "SkDocument.h" 31 #include "SkDrawFilter.h" 32 #include "SkForceLinking.h" 33 #include "SkGPipe.h" 34 #include "SkGraphics.h" 35 #include "SkImageDecoder.h" 36 #include "SkImageEncoder.h" 37 #include "SkJSONCPP.h" 38 #include "SkOSFile.h" 39 #include "SkPDFRasterizer.h" 40 #include "SkPicture.h" 41 #include "SkPictureRecorder.h" 42 #include "SkRefCnt.h" 43 #include "SkScalar.h" 44 #include "SkStream.h" 45 #include "SkString.h" 46 #include "SkSurface.h" 47 #include "SkTArray.h" 48 #include "SkTDict.h" 49 50 #ifdef SK_DEBUG 51 static const bool kDebugOnly = true; 52 #define GR_DUMP_FONT_CACHE 0 53 #else 54 static const bool kDebugOnly = false; 55 #endif 56 57 __SK_FORCE_IMAGE_DECODER_LINKING; 58 59 #if SK_SUPPORT_GPU 60 #include "GrContextFactory.h" 61 #include "SkGpuDevice.h" 62 typedef GrContextFactory::GLContextType GLContextType; 63 #define DEFAULT_CACHE_VALUE -1 64 static int gGpuCacheSizeBytes; 65 static int gGpuCacheSizeCount; 66 #else 67 class GrContextFactory; 68 class GrContext; 69 class GrSurface; 70 typedef int GLContextType; 71 typedef int GrGLStandard; 72 #endif 73 74 #define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message") 75 76 DECLARE_bool(useDocumentInsteadOfDevice); 77 78 #ifdef SK_SUPPORT_PDF 79 #include "SkPDFDevice.h" 80 #include "SkPDFDocument.h" 81 #endif 82 83 // Until we resolve http://code.google.com/p/skia/issues/detail?id=455 , 84 // stop writing out XPS-format image baselines in gm. 85 #undef SK_SUPPORT_XPS 86 #ifdef SK_SUPPORT_XPS 87 #include "SkXPSDevice.h" 88 #endif 89 90 #ifdef SK_BUILD_FOR_MAC 91 #include "SkCGUtils.h" 92 #endif 93 94 using namespace skiagm; 95 96 class Iter { 97 public: 98 Iter() { 99 this->reset(); 100 } 101 102 void reset() { 103 fReg = GMRegistry::Head(); 104 } 105 106 GM* next() { 107 if (fReg) { 108 GMRegistry::Factory fact = fReg->factory(); 109 fReg = fReg->next(); 110 return fact(0); 111 } 112 return NULL; 113 } 114 115 static int Count() { 116 const GMRegistry* reg = GMRegistry::Head(); 117 int count = 0; 118 while (reg) { 119 count += 1; 120 reg = reg->next(); 121 } 122 return count; 123 } 124 125 private: 126 const GMRegistry* fReg; 127 }; 128 129 // TODO(epoger): Right now, various places in this code assume that all the 130 // image files read/written by GM use this file extension. 131 // Search for references to this constant to find these assumptions. 132 const static char kPNG_FileExtension[] = "png"; 133 134 enum Backend { 135 kRaster_Backend, 136 kGPU_Backend, 137 kPDF_Backend, 138 kXPS_Backend, 139 }; 140 141 enum BbhType { 142 kNone_BbhType, 143 kRTree_BbhType, 144 kTileGrid_BbhType, 145 }; 146 147 enum ConfigFlags { 148 kNone_ConfigFlag = 0x0, 149 /* Write GM images if a write path is provided. */ 150 kWrite_ConfigFlag = 0x1, 151 /* Read reference GM images if a read path is provided. */ 152 kRead_ConfigFlag = 0x2, 153 kRW_ConfigFlag = (kWrite_ConfigFlag | kRead_ConfigFlag), 154 }; 155 156 struct ConfigData { 157 SkColorType fColorType; 158 Backend fBackend; 159 GLContextType fGLContextType; // GPU backend only 160 int fSampleCnt; // GPU backend only 161 ConfigFlags fFlags; 162 const char* fName; 163 bool fRunByDefault; 164 }; 165 166 struct PDFRasterizerData { 167 bool (*fRasterizerFunction)(SkStream*, SkBitmap*); 168 const char* fName; 169 bool fRunByDefault; 170 }; 171 172 class BWTextDrawFilter : public SkDrawFilter { 173 public: 174 virtual bool filter(SkPaint*, Type) SK_OVERRIDE; 175 }; 176 bool BWTextDrawFilter::filter(SkPaint* p, Type t) { 177 if (kText_Type == t) { 178 p->setAntiAlias(false); 179 } 180 return true; 181 } 182 183 struct PipeFlagComboData { 184 const char* name; 185 uint32_t flags; 186 }; 187 188 static PipeFlagComboData gPipeWritingFlagCombos[] = { 189 { "", 0 }, 190 { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, 191 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag 192 | SkGPipeWriter::kSharedAddressSpace_Flag } 193 }; 194 195 static SkData* encode_to_dct_data(size_t* pixelRefOffset, const SkBitmap& bitmap); 196 DECLARE_int32(pdfRasterDpi); 197 198 const static ErrorCombination kDefaultIgnorableErrorTypes = ErrorCombination() 199 .plus(kMissingExpectations_ErrorType) 200 .plus(kIntentionallySkipped_ErrorType); 201 202 class GMMain { 203 public: 204 GMMain() : fUseFileHierarchy(false), fWriteChecksumBasedFilenames(false), 205 fIgnorableErrorTypes(kDefaultIgnorableErrorTypes), 206 fMismatchPath(NULL), fMissingExpectationsPath(NULL), fTestsRun(0), 207 fRenderModesEncountered(1) {} 208 209 /** 210 * Assemble shortNamePlusConfig from (surprise!) shortName and configName. 211 * 212 * The method for doing so depends on whether we are using hierarchical naming. 213 * For example, shortName "selftest1" and configName "8888" could be assembled into 214 * either "selftest1_8888" or "8888/selftest1". 215 */ 216 SkString make_shortname_plus_config(const char *shortName, const char *configName) { 217 SkString name; 218 if (0 == strlen(configName)) { 219 name.append(shortName); 220 } else if (fUseFileHierarchy) { 221 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName); 222 } else { 223 name.appendf("%s_%s", shortName, configName); 224 } 225 return name; 226 } 227 228 /** 229 * Assemble filename, suitable for writing out the results of a particular test. 230 */ 231 SkString make_filename(const char *path, 232 const char *shortName, 233 const char *configName, 234 const char *renderModeDescriptor, 235 const char *suffix) { 236 SkString filename = make_shortname_plus_config(shortName, configName); 237 filename.append(renderModeDescriptor); 238 filename.appendUnichar('.'); 239 filename.append(suffix); 240 return SkOSPath::Join(path, filename.c_str()); 241 } 242 243 /** 244 * Assemble filename suitable for writing out an SkBitmap. 245 */ 246 SkString make_bitmap_filename(const char *path, 247 const char *shortName, 248 const char *configName, 249 const char *renderModeDescriptor, 250 const GmResultDigest &bitmapDigest) { 251 if (fWriteChecksumBasedFilenames) { 252 SkString filename; 253 filename.append(bitmapDigest.getHashType()); 254 filename.appendUnichar('_'); 255 filename.append(shortName); 256 filename.appendUnichar('_'); 257 filename.append(bitmapDigest.getDigestValue()); 258 filename.appendUnichar('.'); 259 filename.append(kPNG_FileExtension); 260 return SkOSPath::Join(path, filename.c_str()); 261 } else { 262 return make_filename(path, shortName, configName, renderModeDescriptor, 263 kPNG_FileExtension); 264 } 265 } 266 267 /* since PNG insists on unpremultiplying our alpha, we take no 268 precision chances and force all pixels to be 100% opaque, 269 otherwise on compare we may not get a perfect match. 270 */ 271 static void force_all_opaque(const SkBitmap& bitmap) { 272 SkColorType colorType = bitmap.colorType(); 273 switch (colorType) { 274 case kN32_SkColorType: 275 force_all_opaque_8888(bitmap); 276 break; 277 case kRGB_565_SkColorType: 278 // nothing to do here; 565 bitmaps are inherently opaque 279 break; 280 default: 281 SkDebugf("unsupported bitmap colorType %d\n", colorType); 282 DEBUGFAIL_SEE_STDERR; 283 } 284 } 285 286 static void force_all_opaque_8888(const SkBitmap& bitmap) { 287 SkAutoLockPixels lock(bitmap); 288 for (int y = 0; y < bitmap.height(); y++) { 289 for (int x = 0; x < bitmap.width(); x++) { 290 *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); 291 } 292 } 293 } 294 295 static ErrorCombination write_bitmap(const SkString& path, const SkBitmap& bitmap) { 296 // TODO(epoger): Now that we have removed force_all_opaque() 297 // from this method, we should be able to get rid of the 298 // transformation to 8888 format also. 299 SkBitmap copy; 300 bitmap.copyTo(©, kN32_SkColorType); 301 if (!SkImageEncoder::EncodeFile(path.c_str(), copy, 302 SkImageEncoder::kPNG_Type, 303 100)) { 304 SkDebugf("FAILED to write bitmap: %s\n", path.c_str()); 305 return ErrorCombination(kWritingReferenceImage_ErrorType); 306 } 307 return kEmpty_ErrorCombination; 308 } 309 310 /** 311 * Add all render modes encountered thus far to the "modes" array. 312 */ 313 void GetRenderModesEncountered(SkTArray<SkString> &modes) { 314 SkTDict<int>::Iter iter(this->fRenderModesEncountered); 315 const char* mode; 316 while ((mode = iter.next(NULL)) != NULL) { 317 SkString modeAsString = SkString(mode); 318 // TODO(epoger): It seems a bit silly that all of these modes were 319 // recorded with a leading "-" which we have to remove here 320 // (except for mode "", which means plain old original mode). 321 // But that's how renderModeDescriptor has been passed into 322 // compare_test_results_to_reference_bitmap() historically, 323 // and changing that now may affect other parts of our code. 324 if (modeAsString.startsWith("-")) { 325 modeAsString.remove(0, 1); 326 } 327 modes.push_back(modeAsString); 328 } 329 } 330 331 /** 332 * Returns true if failures on this test should be ignored. 333 */ 334 bool ShouldIgnoreTest(const char *name) const { 335 for (int i = 0; i < fIgnorableTestNames.count(); i++) { 336 if (fIgnorableTestNames[i].equals(name)) { 337 return true; 338 } 339 } 340 return false; 341 } 342 343 /** 344 * Calls RecordTestResults to record that we skipped a test. 345 * 346 * Depending on the backend, this may mean that we skipped a single rendermode, or all 347 * rendermodes; see http://skbug.com/1994 and https://codereview.chromium.org/129203002/ 348 */ 349 void RecordSkippedTest(const SkString& shortNamePlusConfig, 350 const char renderModeDescriptor [], Backend backend) { 351 if (kRaster_Backend == backend) { 352 // Skipping a test on kRaster_Backend means that we will skip ALL renderModes 353 // (as opposed to other backends, on which we only run the default renderMode). 354 // 355 // We cannot call RecordTestResults yet, because we won't know the full set of 356 // renderModes until we have run all tests. 357 fTestsSkippedOnAllRenderModes.push_back(shortNamePlusConfig); 358 } else { 359 this->RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 360 renderModeDescriptor); 361 } 362 } 363 364 /** 365 * Records the results of this test in fTestsRun and fFailedTests. 366 * 367 * We even record successes, and errors that we regard as 368 * "ignorable"; we can filter them out later. 369 */ 370 void RecordTestResults(const ErrorCombination& errorCombination, 371 const SkString& shortNamePlusConfig, 372 const char renderModeDescriptor []) { 373 // Things to do regardless of errorCombination. 374 fTestsRun++; 375 int renderModeCount = 0; 376 this->fRenderModesEncountered.find(renderModeDescriptor, &renderModeCount); 377 renderModeCount++; 378 this->fRenderModesEncountered.set(renderModeDescriptor, renderModeCount); 379 380 if (errorCombination.isEmpty()) { 381 return; 382 } 383 384 // Things to do only if there is some error condition. 385 SkString fullName = shortNamePlusConfig; 386 fullName.append(renderModeDescriptor); 387 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { 388 ErrorType type = static_cast<ErrorType>(typeInt); 389 if (errorCombination.includes(type)) { 390 fFailedTests[type].push_back(fullName); 391 } 392 } 393 } 394 395 /** 396 * Return the number of significant (non-ignorable) errors we have 397 * encountered so far. 398 */ 399 int NumSignificantErrors() { 400 int significantErrors = 0; 401 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { 402 ErrorType type = static_cast<ErrorType>(typeInt); 403 if (!fIgnorableErrorTypes.includes(type)) { 404 significantErrors += fFailedTests[type].count(); 405 } 406 } 407 return significantErrors; 408 } 409 410 /** 411 * Display the summary of results with this ErrorType. 412 * 413 * @param type which ErrorType 414 * @param verbose whether to be all verbose about it 415 */ 416 void DisplayResultTypeSummary(ErrorType type, bool verbose) { 417 bool isIgnorableType = fIgnorableErrorTypes.includes(type); 418 419 SkString line; 420 if (isIgnorableType) { 421 line.append("[ ] "); 422 } else { 423 line.append("[*] "); 424 } 425 426 SkTArray<SkString> *failedTestsOfThisType = &fFailedTests[type]; 427 int count = failedTestsOfThisType->count(); 428 line.appendf("%d %s", count, getErrorTypeName(type)); 429 if (!isIgnorableType || verbose) { 430 line.append(":"); 431 for (int i = 0; i < count; ++i) { 432 line.append(" "); 433 line.append((*failedTestsOfThisType)[i]); 434 } 435 } 436 SkDebugf("%s\n", line.c_str()); 437 } 438 439 /** 440 * List contents of fFailedTests to stdout. 441 * 442 * @param verbose whether to be all verbose about it 443 */ 444 void ListErrors(bool verbose) { 445 // First, print a single summary line. 446 SkString summary; 447 summary.appendf("Ran %d tests:", fTestsRun); 448 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { 449 ErrorType type = static_cast<ErrorType>(typeInt); 450 summary.appendf(" %s=%d", getErrorTypeName(type), fFailedTests[type].count()); 451 } 452 SkDebugf("%s\n", summary.c_str()); 453 454 // Now, for each failure type, list the tests that failed that way. 455 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { 456 this->DisplayResultTypeSummary(static_cast<ErrorType>(typeInt), verbose); 457 } 458 SkDebugf("(results marked with [*] will cause nonzero return value)\n"); 459 } 460 461 static ErrorCombination write_document(const SkString& path, SkStreamAsset* asset) { 462 SkFILEWStream stream(path.c_str()); 463 if (!stream.writeStream(asset, asset->getLength())) { 464 SkDebugf("FAILED to write document: %s\n", path.c_str()); 465 return ErrorCombination(kWritingReferenceImage_ErrorType); 466 } 467 return kEmpty_ErrorCombination; 468 } 469 470 /** 471 * Prepare an SkBitmap to render a GM into. 472 * 473 * After you've rendered the GM into the SkBitmap, you must call 474 * complete_bitmap()! 475 * 476 * @todo thudson 22 April 2011 - could refactor this to take in 477 * a factory to generate the context, always call readPixels() 478 * (logically a noop for rasters, if wasted time), and thus collapse the 479 * GPU special case and also let this be used for SkPicture testing. 480 */ 481 static void setup_bitmap(const ConfigData& gRec, SkISize& size, 482 SkBitmap* bitmap) { 483 bitmap->allocPixels(SkImageInfo::Make(size.width(), size.height(), 484 gRec.fColorType, kPremul_SkAlphaType)); 485 bitmap->eraseColor(SK_ColorTRANSPARENT); 486 } 487 488 /** 489 * Any finalization steps we need to perform on the SkBitmap after 490 * we have rendered the GM into it. 491 * 492 * It's too bad that we are throwing away alpha channel data 493 * we could otherwise be examining, but this had always been happening 494 * before... it was buried within the compare() method at 495 * https://code.google.com/p/skia/source/browse/trunk/gm/gmmain.cpp?r=7289#305 . 496 * 497 * Apparently we need this, at least for bitmaps that are either: 498 * (a) destined to be written out as PNG files, or 499 * (b) compared against bitmaps read in from PNG files 500 * for the reasons described just above the force_all_opaque() method. 501 * 502 * Neglecting to do this led to the difficult-to-diagnose 503 * http://code.google.com/p/skia/issues/detail?id=1079 ('gm generating 504 * spurious pixel_error messages as of r7258') 505 * 506 * TODO(epoger): Come up with a better solution that allows us to 507 * compare full pixel data, including alpha channel, while still being 508 * robust in the face of transformations to/from PNG files. 509 * Options include: 510 * 511 * 1. Continue to call force_all_opaque(), but ONLY for bitmaps that 512 * will be written to, or compared against, PNG files. 513 * PRO: Preserve/compare alpha channel info for the non-PNG cases 514 * (comparing different renderModes in-memory) 515 * CON: The bitmaps (and hash digests) for these non-PNG cases would be 516 * different than those for the PNG-compared cases, and in the 517 * case of a failed renderMode comparison, how would we write the 518 * image to disk for examination? 519 * 520 * 2. Always compute image hash digests from PNG format (either 521 * directly from the the bytes of a PNG file, or capturing the 522 * bytes we would have written to disk if we were writing the 523 * bitmap out as a PNG). 524 * PRO: I think this would allow us to never force opaque, and to 525 * the extent that alpha channel data can be preserved in a PNG 526 * file, we could observe it. 527 * CON: If we read a bitmap from disk, we need to take its hash digest 528 * from the source PNG (we can't compute it from the bitmap we 529 * read out of the PNG, because we will have already premultiplied 530 * the alpha). 531 * CON: Seems wasteful to convert a bitmap to PNG format just to take 532 * its hash digest. (Although we're wasting lots of effort already 533 * calling force_all_opaque().) 534 * 535 * 3. Make the alpha premultiply/unpremultiply routines 100% consistent, 536 * so we can transform images back and forth without fear of off-by-one 537 * errors. 538 * CON: Math is hard. 539 * 540 * 4. Perform a "close enough" comparison of bitmaps (+/- 1 bit in each 541 * channel), rather than demanding absolute equality. 542 * CON: Can't do this with hash digests. 543 */ 544 static void complete_bitmap(SkBitmap* bitmap) { 545 force_all_opaque(*bitmap); 546 } 547 548 static void installFilter(SkCanvas* canvas); 549 550 static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF, bool isDeferred) { 551 SkAutoCanvasRestore acr(canvas, true); 552 553 if (!isPDF) { 554 canvas->concat(gm->getInitialTransform()); 555 } 556 installFilter(canvas); 557 gm->setCanvasIsDeferred(isDeferred); 558 gm->draw(canvas); 559 canvas->setDrawFilter(NULL); 560 } 561 562 static ErrorCombination generate_image(GM* gm, const ConfigData& gRec, 563 GrSurface* gpuTarget, 564 SkBitmap* bitmap, 565 bool deferred) { 566 SkISize size (gm->getISize()); 567 setup_bitmap(gRec, size, bitmap); 568 const SkImageInfo info = bitmap->info(); 569 570 SkAutoTUnref<SkSurface> surface; 571 SkAutoTUnref<SkCanvas> canvas; 572 573 if (gRec.fBackend == kRaster_Backend) { 574 surface.reset(SkSurface::NewRasterDirect(info, 575 bitmap->getPixels(), 576 bitmap->rowBytes())); 577 if (deferred) { 578 canvas.reset(SkDeferredCanvas::Create(surface)); 579 } else { 580 canvas.reset(SkRef(surface->getCanvas())); 581 } 582 invokeGM(gm, canvas, false, deferred); 583 canvas->flush(); 584 } 585 #if SK_SUPPORT_GPU 586 else { // GPU 587 surface.reset(SkSurface::NewRenderTargetDirect(gpuTarget->asRenderTarget())); 588 if (deferred) { 589 canvas.reset(SkDeferredCanvas::Create(surface)); 590 } else { 591 canvas.reset(SkRef(surface->getCanvas())); 592 } 593 invokeGM(gm, canvas, false, deferred); 594 // the device is as large as the current rendertarget, so 595 // we explicitly only readback the amount we expect (in 596 // size) overwrite our previous allocation 597 bitmap->setInfo(SkImageInfo::MakeN32Premul(size.fWidth, size.fHeight)); 598 canvas->readPixels(bitmap, 0, 0); 599 } 600 #endif 601 complete_bitmap(bitmap); 602 return kEmpty_ErrorCombination; 603 } 604 605 static void generate_image_from_picture(GM* gm, const ConfigData& gRec, 606 SkPicture* pict, SkBitmap* bitmap, 607 SkScalar scale = SK_Scalar1, 608 bool tile = false) { 609 SkISize size = gm->getISize(); 610 setup_bitmap(gRec, size, bitmap); 611 612 if (tile) { 613 // Generate the result image by rendering to tiles and accumulating 614 // the results in 'bitmap' 615 616 // This 16x16 tiling matches the settings applied to 'pict' in 617 // 'generate_new_picture' 618 SkISize tileSize = SkISize::Make(16, 16); 619 620 SkBitmap tileBM; 621 setup_bitmap(gRec, tileSize, &tileBM); 622 SkCanvas tileCanvas(tileBM); 623 installFilter(&tileCanvas); 624 625 SkCanvas bmpCanvas(*bitmap); 626 SkPaint bmpPaint; 627 bmpPaint.setXfermodeMode(SkXfermode::kSrc_Mode); 628 629 for (int yTile = 0; yTile < (size.height()+15)/16; ++yTile) { 630 for (int xTile = 0; xTile < (size.width()+15)/16; ++xTile) { 631 int saveCount = tileCanvas.save(); 632 SkMatrix mat(tileCanvas.getTotalMatrix()); 633 mat.postTranslate(SkIntToScalar(-xTile*tileSize.width()), 634 SkIntToScalar(-yTile*tileSize.height())); 635 tileCanvas.setMatrix(mat); 636 pict->playback(&tileCanvas); 637 tileCanvas.flush(); 638 tileCanvas.restoreToCount(saveCount); 639 bmpCanvas.drawBitmap(tileBM, 640 SkIntToScalar(xTile * tileSize.width()), 641 SkIntToScalar(yTile * tileSize.height()), 642 &bmpPaint); 643 } 644 } 645 } else { 646 SkCanvas canvas(*bitmap); 647 installFilter(&canvas); 648 canvas.scale(scale, scale); 649 canvas.drawPicture(pict); 650 complete_bitmap(bitmap); 651 } 652 } 653 654 static bool generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { 655 #ifdef SK_SUPPORT_PDF 656 SkMatrix initialTransform = gm->getInitialTransform(); 657 if (FLAGS_useDocumentInsteadOfDevice) { 658 SkISize pageISize = gm->getISize(); 659 SkAutoTUnref<SkDocument> pdfDoc( 660 SkDocument::CreatePDF(&pdf, NULL, 661 encode_to_dct_data, 662 SkIntToScalar(FLAGS_pdfRasterDpi))); 663 664 if (!pdfDoc.get()) { 665 return false; 666 } 667 668 SkCanvas* canvas = NULL; 669 canvas = pdfDoc->beginPage(SkIntToScalar(pageISize.width()), 670 SkIntToScalar(pageISize.height())); 671 canvas->concat(initialTransform); 672 673 invokeGM(gm, canvas, true, false); 674 675 return pdfDoc->close(); 676 } else { 677 SkISize pageSize = gm->getISize(); 678 SkPDFDevice* dev = NULL; 679 if (initialTransform.isIdentity()) { 680 dev = new SkPDFDevice(pageSize, pageSize, initialTransform); 681 } else { 682 SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()), 683 SkIntToScalar(pageSize.height())); 684 initialTransform.mapRect(&content); 685 content.intersect(0, 0, SkIntToScalar(pageSize.width()), 686 SkIntToScalar(pageSize.height())); 687 SkISize contentSize = 688 SkISize::Make(SkScalarRoundToInt(content.width()), 689 SkScalarRoundToInt(content.height())); 690 dev = new SkPDFDevice(pageSize, contentSize, initialTransform); 691 } 692 dev->setDCTEncoder(encode_to_dct_data); 693 dev->setRasterDpi(SkIntToScalar(FLAGS_pdfRasterDpi)); 694 SkAutoUnref aur(dev); 695 SkCanvas c(dev); 696 invokeGM(gm, &c, true, false); 697 SkPDFDocument doc; 698 doc.appendPage(dev); 699 doc.emitPDF(&pdf); 700 } 701 #endif // SK_SUPPORT_PDF 702 return true; // Do not report failure if pdf is not supported. 703 } 704 705 static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) { 706 #ifdef SK_SUPPORT_XPS 707 SkISize size = gm->getISize(); 708 709 SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()), 710 SkIntToScalar(size.height())); 711 static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254); 712 static const SkScalar upm = 72 * inchesPerMeter; 713 SkVector unitsPerMeter = SkPoint::Make(upm, upm); 714 static const SkScalar ppm = 200 * inchesPerMeter; 715 SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm); 716 717 SkXPSDevice* dev = new SkXPSDevice(); 718 SkAutoUnref aur(dev); 719 720 SkCanvas c(dev); 721 dev->beginPortfolio(&xps); 722 dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize); 723 invokeGM(gm, &c, false, false); 724 dev->endSheet(); 725 dev->endPortfolio(); 726 727 #endif 728 } 729 730 /** 731 * Log more detail about the mistmatch between expectedBitmap and 732 * actualBitmap. 733 */ 734 void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& actualBitmap, 735 const char *testName) { 736 const int expectedWidth = expectedBitmap.width(); 737 const int expectedHeight = expectedBitmap.height(); 738 const int width = actualBitmap.width(); 739 const int height = actualBitmap.height(); 740 if ((expectedWidth != width) || (expectedHeight != height)) { 741 SkDebugf("---- %s: dimension mismatch -- expected [%d %d], actual [%d %d]\n", 742 testName, expectedWidth, expectedHeight, width, height); 743 return; 744 } 745 746 if ((kN32_SkColorType != expectedBitmap.colorType()) || 747 (kN32_SkColorType != actualBitmap.colorType())) { 748 SkDebugf("---- %s: not computing max per-channel pixel mismatch because non-8888\n", 749 testName); 750 return; 751 } 752 753 SkAutoLockPixels alp0(expectedBitmap); 754 SkAutoLockPixels alp1(actualBitmap); 755 int errR = 0; 756 int errG = 0; 757 int errB = 0; 758 int errA = 0; 759 int differingPixels = 0; 760 761 for (int y = 0; y < height; ++y) { 762 const SkPMColor* expectedPixelPtr = expectedBitmap.getAddr32(0, y); 763 const SkPMColor* actualPixelPtr = actualBitmap.getAddr32(0, y); 764 for (int x = 0; x < width; ++x) { 765 SkPMColor expectedPixel = *expectedPixelPtr++; 766 SkPMColor actualPixel = *actualPixelPtr++; 767 if (expectedPixel != actualPixel) { 768 differingPixels++; 769 errR = SkMax32(errR, SkAbs32((int)SkGetPackedR32(expectedPixel) - 770 (int)SkGetPackedR32(actualPixel))); 771 errG = SkMax32(errG, SkAbs32((int)SkGetPackedG32(expectedPixel) - 772 (int)SkGetPackedG32(actualPixel))); 773 errB = SkMax32(errB, SkAbs32((int)SkGetPackedB32(expectedPixel) - 774 (int)SkGetPackedB32(actualPixel))); 775 errA = SkMax32(errA, SkAbs32((int)SkGetPackedA32(expectedPixel) - 776 (int)SkGetPackedA32(actualPixel))); 777 } 778 } 779 } 780 SkDebugf("---- %s: %d (of %d) differing pixels, " 781 "max per-channel mismatch R=%d G=%d B=%d A=%d\n", 782 testName, differingPixels, width*height, errR, errG, errB, errA); 783 } 784 785 /** 786 * Compares actual hash digest to expectations, returning the set of errors 787 * (if any) that we saw along the way. 788 * 789 * If fMismatchPath has been set, and there are pixel diffs, then the 790 * actual bitmap will be written out to a file within fMismatchPath. 791 * And similarly for fMissingExpectationsPath... 792 * 793 * @param expectations what expectations to compare actualBitmap against 794 * @param actualBitmapAndDigest the SkBitmap we actually generated, and its GmResultDigest 795 * @param shortName name of test, e.g. "selftest1" 796 * @param configName name of config, e.g. "8888" 797 * @param renderModeDescriptor e.g., "-rtree", "-deferred" 798 * @param addToJsonSummary whether to add these results (both actual and 799 * expected) to the JSON summary. Regardless of this setting, if 800 * we find an image mismatch in this test, we will write these 801 * results to the JSON summary. (This is so that we will always 802 * report errors across rendering modes, such as pipe vs tiled. 803 * See https://codereview.chromium.org/13650002/ ) 804 */ 805 ErrorCombination compare_to_expectations(Expectations expectations, 806 const BitmapAndDigest& actualBitmapAndDigest, 807 const char *shortName, const char *configName, 808 const char *renderModeDescriptor, 809 bool addToJsonSummary) { 810 ErrorCombination errors; 811 SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName); 812 SkString completeNameString(shortNamePlusConfig); 813 completeNameString.append(renderModeDescriptor); 814 completeNameString.append("."); 815 completeNameString.append(kPNG_FileExtension); 816 const char* completeName = completeNameString.c_str(); 817 818 if (expectations.empty()) { 819 errors.add(kMissingExpectations_ErrorType); 820 821 // Write out the "actuals" for any tests without expectations, if we have 822 // been directed to do so. 823 if (fMissingExpectationsPath) { 824 SkString path = make_bitmap_filename(fMissingExpectationsPath, shortName, 825 configName, renderModeDescriptor, 826 actualBitmapAndDigest.fDigest); 827 write_bitmap(path, actualBitmapAndDigest.fBitmap); 828 } 829 830 } else if (!expectations.match(actualBitmapAndDigest.fDigest)) { 831 addToJsonSummary = true; 832 // The error mode we record depends on whether this was running 833 // in a non-standard renderMode. 834 if ('\0' == *renderModeDescriptor) { 835 errors.add(kExpectationsMismatch_ErrorType); 836 } else { 837 errors.add(kRenderModeMismatch_ErrorType); 838 } 839 840 // Write out the "actuals" for any mismatches, if we have 841 // been directed to do so. 842 if (fMismatchPath) { 843 SkString path = make_bitmap_filename(fMismatchPath, shortName, configName, 844 renderModeDescriptor, 845 actualBitmapAndDigest.fDigest); 846 write_bitmap(path, actualBitmapAndDigest.fBitmap); 847 } 848 849 // If we have access to a single expected bitmap, log more 850 // detail about the mismatch. 851 const SkBitmap *expectedBitmapPtr = expectations.asBitmap(); 852 if (expectedBitmapPtr) { 853 report_bitmap_diffs(*expectedBitmapPtr, actualBitmapAndDigest.fBitmap, 854 completeName); 855 } 856 } 857 858 if (addToJsonSummary) { 859 add_actual_results_to_json_summary(completeName, actualBitmapAndDigest.fDigest, errors, 860 expectations.ignoreFailure()); 861 add_expected_results_to_json_summary(completeName, expectations); 862 } 863 864 return errors; 865 } 866 867 /** 868 * Add this result to the appropriate JSON collection of actual results (but just ONE), 869 * depending on errors encountered. 870 */ 871 void add_actual_results_to_json_summary(const char testName[], 872 const GmResultDigest &actualResultDigest, 873 ErrorCombination errors, 874 bool ignoreFailure) { 875 Json::Value jsonActualResults = actualResultDigest.asJsonTypeValuePair(); 876 Json::Value *resultCollection = NULL; 877 878 if (errors.isEmpty()) { 879 resultCollection = &this->fJsonActualResults_Succeeded; 880 } else if (errors.includes(kRenderModeMismatch_ErrorType)) { 881 resultCollection = &this->fJsonActualResults_Failed; 882 } else if (errors.includes(kExpectationsMismatch_ErrorType)) { 883 if (ignoreFailure) { 884 resultCollection = &this->fJsonActualResults_FailureIgnored; 885 } else { 886 resultCollection = &this->fJsonActualResults_Failed; 887 } 888 } else if (errors.includes(kMissingExpectations_ErrorType)) { 889 // TODO: What about the case where there IS an expected 890 // image hash digest, but that gm test doesn't actually 891 // run? For now, those cases will always be ignored, 892 // because gm only looks at expectations that correspond 893 // to gm tests that were actually run. 894 // 895 // Once we have the ability to express expectations as a 896 // JSON file, we should fix this (and add a test case for 897 // which an expectation is given but the test is never 898 // run). 899 resultCollection = &this->fJsonActualResults_NoComparison; 900 } 901 902 // If none of the above cases match, we don't add it to ANY tally of actual results. 903 if (resultCollection) { 904 (*resultCollection)[testName] = jsonActualResults; 905 } 906 } 907 908 /** 909 * Add this test to the JSON collection of expected results. 910 */ 911 void add_expected_results_to_json_summary(const char testName[], 912 Expectations expectations) { 913 this->fJsonExpectedResults[testName] = expectations.asJsonValue(); 914 } 915 916 /** 917 * Compare actualBitmap to expectations stored in this->fExpectationsSource. 918 * 919 * @param gm which test generated the actualBitmap 920 * @param gRec 921 * @param configName The config name to look for in the expectation file. 922 * @param actualBitmapAndDigest ptr to bitmap generated by this run, or NULL 923 * if we don't have a usable bitmap representation 924 */ 925 ErrorCombination compare_test_results_to_stored_expectations( 926 GM* gm, const ConfigData& gRec, const char* configName, 927 const BitmapAndDigest* actualBitmapAndDigest) { 928 ErrorCombination errors; 929 930 if (NULL == actualBitmapAndDigest) { 931 // Note that we intentionally skipped validating the results for 932 // this test, because we don't know how to generate an SkBitmap 933 // version of the output. 934 errors.add(ErrorCombination(kIntentionallySkipped_ErrorType)); 935 } else if (!(gRec.fFlags & kWrite_ConfigFlag)) { 936 // We don't record the results for this test or compare them 937 // against any expectations, because the output image isn't 938 // meaningful. 939 // See https://code.google.com/p/skia/issues/detail?id=1410 ('some 940 // GM result images not available for download from Google Storage') 941 errors.add(ErrorCombination(kIntentionallySkipped_ErrorType)); 942 } else { 943 ExpectationsSource *expectationsSource = this->fExpectationsSource.get(); 944 SkString nameWithExtension = make_shortname_plus_config(gm->getName(), configName); 945 nameWithExtension.append("."); 946 nameWithExtension.append(kPNG_FileExtension); 947 948 if (expectationsSource && (gRec.fFlags & kRead_ConfigFlag)) { 949 /* 950 * Get the expected results for this test, as one or more allowed 951 * hash digests. The current implementation of expectationsSource 952 * get this by computing the hash digest of a single PNG file on disk. 953 * 954 * TODO(epoger): This relies on the fact that 955 * force_all_opaque() was called on the bitmap before it 956 * was written to disk as a PNG in the first place. If 957 * not, the hash digest returned here may not match the 958 * hash digest of actualBitmap, which *has* been run through 959 * force_all_opaque(). 960 * See comments above complete_bitmap() for more detail. 961 */ 962 Expectations expectations = expectationsSource->get(nameWithExtension.c_str()); 963 if (this->ShouldIgnoreTest(gm->getName())) { 964 expectations.setIgnoreFailure(true); 965 } 966 errors.add(compare_to_expectations(expectations, *actualBitmapAndDigest, 967 gm->getName(), configName, "", true)); 968 } else { 969 // If we are running without expectations, we still want to 970 // record the actual results. 971 add_actual_results_to_json_summary(nameWithExtension.c_str(), 972 actualBitmapAndDigest->fDigest, 973 ErrorCombination(kMissingExpectations_ErrorType), 974 false); 975 errors.add(ErrorCombination(kMissingExpectations_ErrorType)); 976 } 977 } 978 return errors; 979 } 980 981 /** 982 * Compare actualBitmap to referenceBitmap. 983 * 984 * @param shortName test name, e.g. "selftest1" 985 * @param configName configuration name, e.g. "8888" 986 * @param renderModeDescriptor 987 * @param actualBitmap actual bitmap generated by this run 988 * @param referenceBitmap bitmap we expected to be generated 989 */ 990 ErrorCombination compare_test_results_to_reference_bitmap( 991 const char *shortName, const char *configName, const char *renderModeDescriptor, 992 SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) { 993 994 SkASSERT(referenceBitmap); 995 Expectations expectations(*referenceBitmap); 996 BitmapAndDigest actualBitmapAndDigest(actualBitmap); 997 998 // TODO: Eliminate RecordTestResults from here. 999 // Results recording code for the test_drawing path has been refactored so that 1000 // RecordTestResults is only called once, at the topmost level. However, the 1001 // other paths have not yet been refactored, and RecordTestResults has been added 1002 // here to maintain proper behavior for calls not coming from the test_drawing path. 1003 ErrorCombination errors; 1004 errors.add(compare_to_expectations(expectations, actualBitmapAndDigest, shortName, 1005 configName, renderModeDescriptor, false)); 1006 SkString shortNamePlusConfig = make_shortname_plus_config(shortName, configName); 1007 RecordTestResults(errors, shortNamePlusConfig, renderModeDescriptor); 1008 1009 return errors; 1010 } 1011 1012 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t recordFlags, 1013 SkScalar scale = SK_Scalar1) { 1014 SkScalar width = SkScalarMul(SkIntToScalar(gm->getISize().width()), scale); 1015 SkScalar height = SkScalarMul(SkIntToScalar(gm->getISize().height()), scale); 1016 1017 SkAutoTDelete<SkBBHFactory> factory; 1018 if (kTileGrid_BbhType == bbhType) { 1019 SkTileGridFactory::TileGridInfo info; 1020 info.fMargin.setEmpty(); 1021 info.fOffset.setZero(); 1022 info.fTileInterval.set(16, 16); 1023 factory.reset(SkNEW_ARGS(SkTileGridFactory, (info))); 1024 } else if (kRTree_BbhType == bbhType) { 1025 factory.reset(SkNEW(SkRTreeFactory)); 1026 } 1027 SkPictureRecorder recorder; 1028 SkCanvas* cv = recorder.beginRecording(width, height, factory.get(), recordFlags); 1029 cv->scale(scale, scale); 1030 invokeGM(gm, cv, false, false); 1031 return recorder.endRecording(); 1032 } 1033 1034 static SkPicture* stream_to_new_picture(const SkPicture& src) { 1035 SkDynamicMemoryWStream storage; 1036 src.serialize(&storage, NULL); 1037 SkAutoTUnref<SkStreamAsset> pictReadback(storage.detachAsStream()); 1038 SkPicture* retval = SkPicture::CreateFromStream(pictReadback, 1039 &SkImageDecoder::DecodeMemory); 1040 return retval; 1041 } 1042 1043 // Test: draw into a bitmap or pdf. 1044 // Depending on flags, possibly compare to an expected image. 1045 // If writePath is not NULL, also write images (or documents) to the specified path. 1046 ErrorCombination test_drawing(GM* gm, const ConfigData& gRec, 1047 const SkTDArray<const PDFRasterizerData*> &pdfRasterizers, 1048 const char writePath [], 1049 GrSurface* gpuTarget, 1050 SkBitmap* bitmap) { 1051 ErrorCombination errors; 1052 SkDynamicMemoryWStream document; 1053 SkString path; 1054 1055 if (gRec.fBackend == kRaster_Backend || 1056 gRec.fBackend == kGPU_Backend) { 1057 // Early exit if we can't generate the image. 1058 errors.add(generate_image(gm, gRec, gpuTarget, bitmap, false)); 1059 if (!errors.isEmpty()) { 1060 // TODO: Add a test to exercise what the stdout and 1061 // JSON look like if we get an "early error" while 1062 // trying to generate the image. 1063 return errors; 1064 } 1065 BitmapAndDigest bitmapAndDigest(*bitmap); 1066 errors.add(compare_test_results_to_stored_expectations( 1067 gm, gRec, gRec.fName, &bitmapAndDigest)); 1068 1069 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { 1070 path = make_bitmap_filename(writePath, gm->getName(), gRec.fName, 1071 "", bitmapAndDigest.fDigest); 1072 errors.add(write_bitmap(path, bitmapAndDigest.fBitmap)); 1073 } 1074 } else if (gRec.fBackend == kPDF_Backend) { 1075 if (!generate_pdf(gm, document)) { 1076 errors.add(kGeneratePdfFailed_ErrorType); 1077 } else { 1078 SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream()); 1079 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { 1080 path = make_filename(writePath, gm->getName(), gRec.fName, "", "pdf"); 1081 errors.add(write_document(path, documentStream)); 1082 } 1083 1084 if (!(gm->getFlags() & GM::kSkipPDFRasterization_Flag)) { 1085 for (int i = 0; i < pdfRasterizers.count(); i++) { 1086 SkBitmap pdfBitmap; 1087 documentStream->rewind(); 1088 bool success = (*pdfRasterizers[i]->fRasterizerFunction)( 1089 documentStream.get(), &pdfBitmap); 1090 if (!success) { 1091 SkDebugf("FAILED to render PDF for %s using renderer %s\n", 1092 gm->getName(), 1093 pdfRasterizers[i]->fName); 1094 continue; 1095 } 1096 1097 SkString configName(gRec.fName); 1098 configName.append("-"); 1099 configName.append(pdfRasterizers[i]->fName); 1100 1101 BitmapAndDigest bitmapAndDigest(pdfBitmap); 1102 errors.add(compare_test_results_to_stored_expectations( 1103 gm, gRec, configName.c_str(), &bitmapAndDigest)); 1104 1105 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { 1106 path = make_bitmap_filename(writePath, gm->getName(), 1107 configName.c_str(), 1108 "", bitmapAndDigest.fDigest); 1109 errors.add(write_bitmap(path, bitmapAndDigest.fBitmap)); 1110 } 1111 } 1112 } else { 1113 errors.add(kIntentionallySkipped_ErrorType); 1114 } 1115 } 1116 } else if (gRec.fBackend == kXPS_Backend) { 1117 generate_xps(gm, document); 1118 SkAutoTUnref<SkStreamAsset> documentStream(document.detachAsStream()); 1119 1120 errors.add(compare_test_results_to_stored_expectations( 1121 gm, gRec, gRec.fName, NULL)); 1122 1123 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { 1124 path = make_filename(writePath, gm->getName(), gRec.fName, "", "xps"); 1125 errors.add(write_document(path, documentStream)); 1126 } 1127 } else { 1128 SkASSERT(false); 1129 } 1130 return errors; 1131 } 1132 1133 ErrorCombination test_deferred_drawing(GM* gm, 1134 const ConfigData& gRec, 1135 const SkBitmap& referenceBitmap, 1136 GrSurface* gpuTarget) { 1137 if (gRec.fBackend == kRaster_Backend || 1138 gRec.fBackend == kGPU_Backend) { 1139 const char renderModeDescriptor[] = "-deferred"; 1140 SkBitmap bitmap; 1141 // Early exit if we can't generate the image, but this is 1142 // expected in some cases, so don't report a test failure. 1143 ErrorCombination errors = generate_image(gm, gRec, gpuTarget, &bitmap, true); 1144 // TODO(epoger): This logic is the opposite of what is 1145 // described above... if we succeeded in generating the 1146 // -deferred image, we exit early! We should fix this 1147 // ASAP, because it is hiding -deferred errors... but for 1148 // now, I'm leaving the logic as it is so that the 1149 // refactoring change 1150 // https://codereview.chromium.org/12992003/ is unblocked. 1151 // 1152 // Filed as https://code.google.com/p/skia/issues/detail?id=1180 1153 // ('image-surface gm test is failing in "deferred" mode, 1154 // and gm is not reporting the failure') 1155 if (errors.isEmpty()) { 1156 // TODO(epoger): Report this as a new ErrorType, 1157 // something like kImageGeneration_ErrorType? 1158 return kEmpty_ErrorCombination; 1159 } 1160 return compare_test_results_to_reference_bitmap( 1161 gm->getName(), gRec.fName, renderModeDescriptor, bitmap, &referenceBitmap); 1162 } 1163 return kEmpty_ErrorCombination; 1164 } 1165 1166 ErrorCombination test_pipe_playback(GM* gm, const ConfigData& gRec, 1167 const SkBitmap& referenceBitmap, bool simulateFailure) { 1168 const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(), 1169 gRec.fName); 1170 ErrorCombination errors; 1171 for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { 1172 SkString renderModeDescriptor("-pipe"); 1173 renderModeDescriptor.append(gPipeWritingFlagCombos[i].name); 1174 1175 if (gm->getFlags() & GM::kSkipPipe_Flag 1176 || (gPipeWritingFlagCombos[i].flags == SkGPipeWriter::kCrossProcess_Flag 1177 && gm->getFlags() & GM::kSkipPipeCrossProcess_Flag)) { 1178 RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1179 renderModeDescriptor.c_str()); 1180 errors.add(kIntentionallySkipped_ErrorType); 1181 } else { 1182 SkBitmap bitmap; 1183 SkISize size = gm->getISize(); 1184 setup_bitmap(gRec, size, &bitmap); 1185 SkCanvas canvas(bitmap); 1186 installFilter(&canvas); 1187 // Pass a decoding function so the factory GM (which has an SkBitmap 1188 // with encoded data) will not fail playback. 1189 PipeController pipeController(&canvas, &SkImageDecoder::DecodeMemory); 1190 SkGPipeWriter writer; 1191 SkCanvas* pipeCanvas = writer.startRecording(&pipeController, 1192 gPipeWritingFlagCombos[i].flags, 1193 size.width(), size.height()); 1194 if (!simulateFailure) { 1195 invokeGM(gm, pipeCanvas, false, false); 1196 } 1197 complete_bitmap(&bitmap); 1198 writer.endRecording(); 1199 errors.add(compare_test_results_to_reference_bitmap( 1200 gm->getName(), gRec.fName, renderModeDescriptor.c_str(), bitmap, 1201 &referenceBitmap)); 1202 if (!errors.isEmpty()) { 1203 break; 1204 } 1205 } 1206 } 1207 return errors; 1208 } 1209 1210 ErrorCombination test_tiled_pipe_playback(GM* gm, const ConfigData& gRec, 1211 const SkBitmap& referenceBitmap) { 1212 const SkString shortNamePlusConfig = make_shortname_plus_config(gm->getName(), 1213 gRec.fName); 1214 ErrorCombination errors; 1215 for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { 1216 SkString renderModeDescriptor("-tiled pipe"); 1217 renderModeDescriptor.append(gPipeWritingFlagCombos[i].name); 1218 1219 if ((gm->getFlags() & GM::kSkipPipe_Flag) || 1220 (gm->getFlags() & GM::kSkipTiled_Flag)) { 1221 RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1222 renderModeDescriptor.c_str()); 1223 errors.add(kIntentionallySkipped_ErrorType); 1224 } else { 1225 SkBitmap bitmap; 1226 SkISize size = gm->getISize(); 1227 setup_bitmap(gRec, size, &bitmap); 1228 SkCanvas canvas(bitmap); 1229 installFilter(&canvas); 1230 TiledPipeController pipeController(bitmap, &SkImageDecoder::DecodeMemory); 1231 SkGPipeWriter writer; 1232 SkCanvas* pipeCanvas = writer.startRecording(&pipeController, 1233 gPipeWritingFlagCombos[i].flags, 1234 size.width(), size.height()); 1235 invokeGM(gm, pipeCanvas, false, false); 1236 complete_bitmap(&bitmap); 1237 writer.endRecording(); 1238 errors.add(compare_test_results_to_reference_bitmap(gm->getName(), gRec.fName, 1239 renderModeDescriptor.c_str(), 1240 bitmap, &referenceBitmap)); 1241 if (!errors.isEmpty()) { 1242 break; 1243 } 1244 } 1245 } 1246 return errors; 1247 } 1248 1249 // 1250 // member variables. 1251 // They are public for now, to allow easier setting by tool_main(). 1252 // 1253 1254 bool fUseFileHierarchy, fWriteChecksumBasedFilenames; 1255 ErrorCombination fIgnorableErrorTypes; 1256 SkTArray<SkString> fIgnorableTestNames; 1257 1258 const char* fMismatchPath; 1259 const char* fMissingExpectationsPath; 1260 1261 // collection of tests that have failed with each ErrorType 1262 SkTArray<SkString> fFailedTests[kLast_ErrorType+1]; 1263 SkTArray<SkString> fTestsSkippedOnAllRenderModes; 1264 int fTestsRun; 1265 SkTDict<int> fRenderModesEncountered; 1266 1267 // Where to read expectations (expected image hash digests, etc.) from. 1268 // If unset, we don't do comparisons. 1269 SkAutoTUnref<ExpectationsSource> fExpectationsSource; 1270 1271 // JSON summaries that we generate as we go (just for output). 1272 Json::Value fJsonExpectedResults; 1273 Json::Value fJsonActualResults_Failed; 1274 Json::Value fJsonActualResults_FailureIgnored; 1275 Json::Value fJsonActualResults_NoComparison; 1276 Json::Value fJsonActualResults_Succeeded; 1277 }; // end of GMMain class definition 1278 1279 #if SK_SUPPORT_GPU 1280 static const GLContextType kDontCare_GLContextType = GrContextFactory::kNative_GLContextType; 1281 #else 1282 static const GLContextType kDontCare_GLContextType = 0; 1283 #endif 1284 1285 static const ConfigData gRec[] = { 1286 { kN32_SkColorType, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "8888", true }, 1287 { kRGB_565_SkColorType, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "565", true }, 1288 #if SK_SUPPORT_GPU 1289 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 0, kRW_ConfigFlag, "gpu", true }, 1290 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 16, kRW_ConfigFlag, "msaa16", false}, 1291 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNative_GLContextType, 4, kRW_ConfigFlag, "msaa4", false}, 1292 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNVPR_GLContextType, 4, kRW_ConfigFlag, "nvprmsaa4", true }, 1293 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNVPR_GLContextType, 16, kRW_ConfigFlag, "nvprmsaa16", false}, 1294 /* The gpudebug context does not generate meaningful images, so don't record 1295 * the images it generates! We only run it to look for asserts. */ 1296 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kDebug_GLContextType, 0, kNone_ConfigFlag, "gpudebug", kDebugOnly}, 1297 /* The gpunull context does the least amount of work possible and doesn't 1298 generate meaninful images, so don't record them!. It can be run to 1299 isolate the CPU-side processing expense from the GPU-side. 1300 */ 1301 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kNull_GLContextType, 0, kNone_ConfigFlag, "gpunull", kDebugOnly}, 1302 #if SK_ANGLE 1303 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 0, kRW_ConfigFlag, "angle", true }, 1304 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kANGLE_GLContextType, 16, kRW_ConfigFlag, "anglemsaa16", true }, 1305 #endif // SK_ANGLE 1306 #ifdef SK_MESA 1307 { kN32_SkColorType, kGPU_Backend, GrContextFactory::kMESA_GLContextType, 0, kRW_ConfigFlag, "mesa", true }, 1308 #endif // SK_MESA 1309 #endif // SK_SUPPORT_GPU 1310 #ifdef SK_SUPPORT_XPS 1311 /* At present we have no way of comparing XPS files (either natively or by converting to PNG). */ 1312 { kN32_SkColorType, kXPS_Backend, kDontCare_GLContextType, 0, kWrite_ConfigFlag, "xps", true }, 1313 #endif // SK_SUPPORT_XPS 1314 #ifdef SK_SUPPORT_PDF 1315 { kN32_SkColorType, kPDF_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "pdf", true }, 1316 #endif // SK_SUPPORT_PDF 1317 }; 1318 1319 static bool SkNoRasterizePDF(SkStream*, SkBitmap*) { return false; } 1320 1321 static const PDFRasterizerData kPDFRasterizers[] = { 1322 #ifdef SK_BUILD_FOR_MAC 1323 { &SkPDFDocumentToBitmap, "mac", true }, 1324 #endif 1325 #ifdef SK_BUILD_POPPLER 1326 { &SkPopplerRasterizePDF, "poppler", true }, 1327 #endif 1328 #ifdef SK_BUILD_NATIVE_PDF_RENDERER 1329 { &SkNativeRasterizePDF, "native", true }, 1330 #endif // SK_BUILD_NATIVE_PDF_RENDERER 1331 // The following exists so that this array is never zero length. 1332 { &SkNoRasterizePDF, "none", false}, 1333 }; 1334 1335 static const char kDefaultsConfigStr[] = "defaults"; 1336 static const char kExcludeConfigChar = '~'; 1337 #if SK_SUPPORT_GPU 1338 static const char kGpuAPINameGL[] = "gl"; 1339 static const char kGpuAPINameGLES[] = "gles"; 1340 #endif 1341 1342 static SkString configUsage() { 1343 SkString result; 1344 result.appendf("Space delimited list of which configs to run. Possible options: ["); 1345 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 1346 SkASSERT(gRec[i].fName != kDefaultsConfigStr); 1347 if (i > 0) { 1348 result.append("|"); 1349 } 1350 result.appendf("%s", gRec[i].fName); 1351 } 1352 result.append("]\n"); 1353 result.appendf("The default value is: \""); 1354 SkString firstDefault; 1355 SkString allButFirstDefaults; 1356 SkString nonDefault; 1357 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 1358 if (gRec[i].fRunByDefault) { 1359 if (i > 0) { 1360 result.append(" "); 1361 } 1362 result.append(gRec[i].fName); 1363 if (firstDefault.isEmpty()) { 1364 firstDefault = gRec[i].fName; 1365 } else { 1366 if (!allButFirstDefaults.isEmpty()) { 1367 allButFirstDefaults.append(" "); 1368 } 1369 allButFirstDefaults.append(gRec[i].fName); 1370 } 1371 } else { 1372 nonDefault = gRec[i].fName; 1373 } 1374 } 1375 result.append("\"\n"); 1376 result.appendf("\"%s\" evaluates to the default set of configs.\n", kDefaultsConfigStr); 1377 result.appendf("Prepending \"%c\" on a config name excludes it from the set of configs to run.\n" 1378 "Exclusions always override inclusions regardless of order.\n", 1379 kExcludeConfigChar); 1380 result.appendf("E.g. \"--config %s %c%s %s\" will run these configs:\n\t%s %s", 1381 kDefaultsConfigStr, 1382 kExcludeConfigChar, 1383 firstDefault.c_str(), 1384 nonDefault.c_str(), 1385 allButFirstDefaults.c_str(), 1386 nonDefault.c_str()); 1387 return result; 1388 } 1389 1390 static SkString pdfRasterizerUsage() { 1391 SkString result; 1392 result.appendf("Space delimited list of which PDF rasterizers to run. Possible options: ["); 1393 // For this (and further) loops through kPDFRasterizers, there is a typecast to int to avoid 1394 // the compiler giving an "comparison of unsigned expression < 0 is always false" warning 1395 // and turning it into a build-breaking error. 1396 for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) { 1397 if (i > 0) { 1398 result.append(" "); 1399 } 1400 result.append(kPDFRasterizers[i].fName); 1401 } 1402 result.append("]\n"); 1403 result.append("The default value is: \""); 1404 for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) { 1405 if (kPDFRasterizers[i].fRunByDefault) { 1406 if (i > 0) { 1407 result.append(" "); 1408 } 1409 result.append(kPDFRasterizers[i].fName); 1410 } 1411 } 1412 result.append("\""); 1413 return result; 1414 } 1415 1416 // Macro magic to convert a numeric preprocessor token into a string. 1417 // Adapted from http://stackoverflow.com/questions/240353/convert-a-preprocessor-token-to-a-string 1418 // This should probably be moved into one of our common headers... 1419 #define TOSTRING_INTERNAL(x) #x 1420 #define TOSTRING(x) TOSTRING_INTERNAL(x) 1421 1422 // Alphabetized ignoring "no" prefix ("readPath", "noreplay", "resourcePath"). 1423 DEFINE_string(config, "", configUsage().c_str()); 1424 DEFINE_bool(cpu, true, "Allows non-GPU configs to be run. Applied after --config."); 1425 DEFINE_string(pdfRasterizers, "default", pdfRasterizerUsage().c_str()); 1426 DEFINE_bool(deferred, false, "Exercise the deferred rendering test pass."); 1427 DEFINE_bool(dryRun, false, "Don't actually run the tests, just print what would have been done."); 1428 DEFINE_string(excludeConfig, "", "Space delimited list of configs to skip."); 1429 DEFINE_bool(forceBWtext, false, "Disable text anti-aliasing."); 1430 #if SK_SUPPORT_GPU 1431 DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" " 1432 "forces OpenGL API. Using \"gles\" forces OpenGL ES API. " 1433 "Defaults to empty string, which selects the API native to the " 1434 "system."); 1435 DEFINE_string(gpuCacheSize, "", "<bytes> <count>: Limit the gpu cache to byte size or " 1436 "object count. " TOSTRING(DEFAULT_CACHE_VALUE) " for either value means " 1437 "use the default. 0 for either disables the cache."); 1438 DEFINE_bool(gpu, true, "Allows GPU configs to be run. Applied after --config."); 1439 DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to " 1440 "software path rendering."); 1441 #endif 1442 DEFINE_bool(hierarchy, false, "Whether to use multilevel directory structure " 1443 "when reading/writing files."); 1444 DEFINE_string(ignoreErrorTypes, kDefaultIgnorableErrorTypes.asString(" ").c_str(), 1445 "Space-separated list of ErrorTypes that should be ignored. If any *other* error " 1446 "types are encountered, the tool will exit with a nonzero return value."); 1447 DEFINE_string(ignoreFailuresFile, "", "Path to file containing a list of tests for which we " 1448 "should ignore failures.\n" 1449 "The file should list one test per line, except for comment lines starting with #"); 1450 DEFINE_bool2(leaks, l, false, "show leaked ref cnt'd objects."); 1451 DEFINE_string(match, "", "[~][^]substring[$] [...] of test name to run.\n" 1452 "Multiple matches may be separated by spaces.\n" 1453 "~ causes a matching test to always be skipped\n" 1454 "^ requires the start of the test to match\n" 1455 "$ requires the end of the test to match\n" 1456 "^ and $ requires an exact match\n" 1457 "If a test does not match any list entry,\n" 1458 "it is skipped unless some list entry starts with ~"); 1459 DEFINE_string(missingExpectationsPath, "", "Write images for tests without expectations " 1460 "into this directory."); 1461 DEFINE_string(mismatchPath, "", "Write images for tests that failed due to " 1462 "pixel mismatches into this directory."); 1463 DEFINE_string(modulo, "", "[--modulo <remainder> <divisor>]: only run tests for which " 1464 "testIndex %% divisor == remainder."); 1465 DEFINE_bool(pipe, false, "Exercise the SkGPipe replay test pass."); 1466 DEFINE_string2(readPath, r, "", "Read reference images from this dir, and report " 1467 "any differences between those and the newly generated ones."); 1468 DEFINE_bool(replay, false, "Exercise the SkPicture replay test pass."); 1469 #if SK_SUPPORT_GPU 1470 DEFINE_bool(resetGpuContext, false, "Reset the GrContext prior to running each GM."); 1471 #endif 1472 DEFINE_bool(rtree, false, "Exercise the R-Tree variant of SkPicture test pass."); 1473 DEFINE_bool(serialize, false, "Exercise the SkPicture serialization & deserialization test pass."); 1474 DEFINE_bool(simulatePipePlaybackFailure, false, "Simulate a rendering failure in pipe mode only."); 1475 DEFINE_bool(tiledPipe, false, "Exercise tiled SkGPipe replay."); 1476 DEFINE_bool(tileGrid, false, "Exercise the tile grid variant of SkPicture."); 1477 DEFINE_string(tileGridReplayScales, "", "Space separated list of floating-point scale " 1478 "factors to be used for tileGrid playback testing. Default value: 1.0"); 1479 DEFINE_bool2(verbose, v, false, "Give more detail (e.g. list all GMs run, more info about " 1480 "each test)."); 1481 DEFINE_bool(writeChecksumBasedFilenames, false, "When writing out actual images, use checksum-" 1482 "based filenames, as rebaseline.py will use when downloading them from Google Storage"); 1483 DEFINE_string(writeJsonSummaryPath, "", "Write a JSON-formatted result summary to this file."); 1484 DEFINE_string2(writePath, w, "", "Write rendered images into this directory."); 1485 DEFINE_string2(writePicturePath, p, "", "Write .skp files into this directory."); 1486 DEFINE_int32(pdfJpegQuality, -1, "Encodes images in JPEG at quality level N, " 1487 "which can be in range 0-100). N = -1 will disable JPEG compression. " 1488 "Default is N = 100, maximum quality."); 1489 // TODO(edisonn): pass a matrix instead of forcePerspectiveMatrix 1490 // Either the 9 numbers defining the matrix 1491 // or probably more readable would be to replace it with a set of a few predicates 1492 // Like --prerotate 100 200 10 --posttranslate 10, 10 1493 // Probably define spacial names like centerx, centery, top, bottom, left, right 1494 // then we can write something reabable like --rotate centerx centery 90 1495 DEFINE_bool(forcePerspectiveMatrix, false, "Force a perspective matrix."); 1496 DEFINE_bool(useDocumentInsteadOfDevice, false, "Use SkDocument::CreateFoo instead of SkFooDevice."); 1497 DEFINE_int32(pdfRasterDpi, 72, "Scale at which at which the non suported " 1498 "features in PDF are rasterized. Must be be in range 0-10000. " 1499 "Default is 72. N = 0 will disable rasterizing features like " 1500 "text shadows or perspective bitmaps."); 1501 static SkData* encode_to_dct_data(size_t*, const SkBitmap& bitmap) { 1502 // Filter output of warnings that JPEG is not available for the image. 1503 if (bitmap.width() >= 65500 || bitmap.height() >= 65500) return NULL; 1504 if (FLAGS_pdfJpegQuality == -1) return NULL; 1505 1506 SkBitmap bm = bitmap; 1507 #if defined(SK_BUILD_FOR_MAC) 1508 // Workaround bug #1043 where bitmaps with referenced pixels cause 1509 // CGImageDestinationFinalize to crash 1510 SkBitmap copy; 1511 bitmap.deepCopyTo(©); 1512 bm = copy; 1513 #endif 1514 1515 SkPixelRef* pr = bm.pixelRef(); 1516 if (pr != NULL) { 1517 SkData* data = pr->refEncodedData(); 1518 if (data != NULL) { 1519 return data; 1520 } 1521 } 1522 1523 return SkImageEncoder::EncodeData(bm, 1524 SkImageEncoder::kJPEG_Type, 1525 FLAGS_pdfJpegQuality); 1526 } 1527 1528 static int findConfig(const char config[]) { 1529 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { 1530 if (!strcmp(config, gRec[i].fName)) { 1531 return (int) i; 1532 } 1533 } 1534 return -1; 1535 } 1536 1537 static const PDFRasterizerData* findPDFRasterizer(const char rasterizer[]) { 1538 for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); i++) { 1539 if (!strcmp(rasterizer, kPDFRasterizers[i].fName)) { 1540 return &kPDFRasterizers[i]; 1541 } 1542 } 1543 return NULL; 1544 } 1545 1546 template <typename T> void appendUnique(SkTDArray<T>* array, const T& value) { 1547 int index = array->find(value); 1548 if (index < 0) { 1549 *array->append() = value; 1550 } 1551 } 1552 1553 /** 1554 * Run this test in a number of different drawing modes (pipe, 1555 * deferred, tiled, etc.), confirming that the resulting bitmaps all 1556 * *exactly* match comparisonBitmap. 1557 * 1558 * Returns all errors encountered while doing so. 1559 */ 1560 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig, 1561 const SkBitmap &comparisonBitmap, 1562 const SkTDArray<SkScalar> &tileGridReplayScales); 1563 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig, 1564 const SkBitmap &comparisonBitmap, 1565 const SkTDArray<SkScalar> &tileGridReplayScales) { 1566 ErrorCombination errorsForAllModes; 1567 uint32_t gmFlags = gm->getFlags(); 1568 const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(), 1569 compareConfig.fName); 1570 1571 SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); 1572 SkAutoUnref aur(pict); 1573 if (FLAGS_replay) { 1574 const char renderModeDescriptor[] = "-replay"; 1575 if (gmFlags & GM::kSkipPicture_Flag) { 1576 gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1577 renderModeDescriptor); 1578 errorsForAllModes.add(kIntentionallySkipped_ErrorType); 1579 } else { 1580 SkBitmap bitmap; 1581 gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap); 1582 errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap( 1583 gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap, 1584 &comparisonBitmap)); 1585 } 1586 } 1587 1588 if (FLAGS_serialize) { 1589 const char renderModeDescriptor[] = "-serialize"; 1590 if (gmFlags & GM::kSkipPicture_Flag) { 1591 gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1592 renderModeDescriptor); 1593 errorsForAllModes.add(kIntentionallySkipped_ErrorType); 1594 } else { 1595 SkPicture* repict = gmmain.stream_to_new_picture(*pict); 1596 SkAutoUnref aurr(repict); 1597 SkBitmap bitmap; 1598 gmmain.generate_image_from_picture(gm, compareConfig, repict, &bitmap); 1599 errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap( 1600 gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap, 1601 &comparisonBitmap)); 1602 } 1603 } 1604 1605 if ((1 == FLAGS_writePicturePath.count()) && 1606 !(gmFlags & GM::kSkipPicture_Flag)) { 1607 const char* pictureSuffix = "skp"; 1608 // TODO(epoger): Make sure this still works even though the 1609 // filename now contains the config name (it used to contain 1610 // just the shortName). I think this is actually an 1611 // *improvement*, because now runs with different configs will 1612 // write out their SkPictures to separate files rather than 1613 // overwriting each other. But we should make sure it doesn't 1614 // break anybody. 1615 SkString path = gmmain.make_filename(FLAGS_writePicturePath[0], gm->getName(), 1616 compareConfig.fName, "", pictureSuffix); 1617 SkFILEWStream stream(path.c_str()); 1618 pict->serialize(&stream); 1619 } 1620 1621 if (FLAGS_rtree) { 1622 const char renderModeDescriptor[] = "-rtree"; 1623 if ((gmFlags & GM::kSkipPicture_Flag) || (gmFlags & GM::kSkipTiled_Flag)) { 1624 gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1625 renderModeDescriptor); 1626 errorsForAllModes.add(kIntentionallySkipped_ErrorType); 1627 } else { 1628 SkPicture* pict = gmmain.generate_new_picture(gm, kRTree_BbhType, 0); 1629 SkAutoUnref aur(pict); 1630 SkBitmap bitmap; 1631 gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap); 1632 errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap( 1633 gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap, 1634 &comparisonBitmap)); 1635 } 1636 } 1637 1638 if (FLAGS_tileGrid) { 1639 for(int scaleIndex = 0; scaleIndex < tileGridReplayScales.count(); ++scaleIndex) { 1640 SkScalar replayScale = tileGridReplayScales[scaleIndex]; 1641 SkString renderModeDescriptor("-tilegrid"); 1642 if (SK_Scalar1 != replayScale) { 1643 renderModeDescriptor += "-scale-"; 1644 renderModeDescriptor.appendScalar(replayScale); 1645 } 1646 1647 if ((gmFlags & GM::kSkipPicture_Flag) || 1648 (gmFlags & GM::kSkipTiled_Flag) || 1649 ((gmFlags & GM::kSkipScaledReplay_Flag) && replayScale != 1)) { 1650 gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 1651 renderModeDescriptor.c_str()); 1652 errorsForAllModes.add(kIntentionallySkipped_ErrorType); 1653 } else { 1654 // We record with the reciprocal scale to obtain a replay 1655 // result that can be validated against comparisonBitmap. 1656 SkScalar recordScale = SkScalarInvert(replayScale); 1657 SkPicture* pict = gmmain.generate_new_picture( 1658 gm, kTileGrid_BbhType, 0, recordScale); 1659 SkAutoUnref aur(pict); 1660 SkBitmap bitmap; 1661 // We cannot yet pass 'true' to generate_image_from_picture to 1662 // perform actual tiled rendering (see Issue 1198 - 1663 // https://code.google.com/p/skia/issues/detail?id=1198) 1664 gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap, 1665 replayScale /*, true */); 1666 errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap( 1667 gm->getName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap, 1668 &comparisonBitmap)); 1669 } 1670 } 1671 } 1672 1673 // run the pipe centric GM steps 1674 if (FLAGS_pipe) { 1675 errorsForAllModes.add(gmmain.test_pipe_playback(gm, compareConfig, comparisonBitmap, 1676 FLAGS_simulatePipePlaybackFailure)); 1677 if (FLAGS_tiledPipe) { 1678 errorsForAllModes.add(gmmain.test_tiled_pipe_playback(gm, compareConfig, 1679 comparisonBitmap)); 1680 } 1681 } 1682 return errorsForAllModes; 1683 } 1684 1685 1686 /** 1687 * Run this test in a number of different configs (8888, 565, PDF, 1688 * etc.), confirming that the resulting bitmaps match expectations 1689 * (which may be different for each config). 1690 * 1691 * Returns all errors encountered while doing so. 1692 */ 1693 ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm, 1694 const SkTDArray<size_t> &configs, 1695 const SkTDArray<const PDFRasterizerData*> &pdfRasterizers, 1696 const SkTDArray<SkScalar> &tileGridReplayScales, 1697 GrContextFactory *grFactory, 1698 GrGLStandard gpuAPI); 1699 ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm, 1700 const SkTDArray<size_t> &configs, 1701 const SkTDArray<const PDFRasterizerData*> &pdfRasterizers, 1702 const SkTDArray<SkScalar> &tileGridReplayScales, 1703 GrContextFactory *grFactory, 1704 GrGLStandard gpuAPI) { 1705 const char renderModeDescriptor[] = ""; 1706 ErrorCombination errorsForAllConfigs; 1707 uint32_t gmFlags = gm->getFlags(); 1708 1709 for (int i = 0; i < configs.count(); i++) { 1710 ConfigData config = gRec[configs[i]]; 1711 const SkString shortNamePlusConfig = gmmain.make_shortname_plus_config(gm->getName(), 1712 config.fName); 1713 1714 // Skip any tests that we don't even need to try. 1715 // If any of these were skipped on a per-GM basis, record them as 1716 // kIntentionallySkipped. 1717 if (kPDF_Backend == config.fBackend) { 1718 if (gmFlags & GM::kSkipPDF_Flag) { 1719 gmmain.RecordSkippedTest(shortNamePlusConfig, 1720 renderModeDescriptor, 1721 config.fBackend); 1722 errorsForAllConfigs.add(kIntentionallySkipped_ErrorType); 1723 continue; 1724 } 1725 } 1726 if ((gmFlags & GM::kSkip565_Flag) && 1727 (kRaster_Backend == config.fBackend) && 1728 (kRGB_565_SkColorType == config.fColorType)) { 1729 gmmain.RecordSkippedTest(shortNamePlusConfig, 1730 renderModeDescriptor, 1731 config.fBackend); 1732 errorsForAllConfigs.add(kIntentionallySkipped_ErrorType); 1733 continue; 1734 } 1735 if (((gmFlags & GM::kSkipGPU_Flag) && kGPU_Backend == config.fBackend) || 1736 ((gmFlags & GM::kGPUOnly_Flag) && kGPU_Backend != config.fBackend)) { 1737 gmmain.RecordSkippedTest(shortNamePlusConfig, 1738 renderModeDescriptor, 1739 config.fBackend); 1740 errorsForAllConfigs.add(kIntentionallySkipped_ErrorType); 1741 continue; 1742 } 1743 1744 // Now we know that we want to run this test and record its 1745 // success or failure. 1746 ErrorCombination errorsForThisConfig; 1747 GrSurface* gpuTarget = NULL; 1748 #if SK_SUPPORT_GPU 1749 SkAutoTUnref<GrSurface> auGpuTarget; 1750 if ((errorsForThisConfig.isEmpty()) && (kGPU_Backend == config.fBackend)) { 1751 if (FLAGS_resetGpuContext) { 1752 grFactory->destroyContexts(); 1753 } 1754 GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI); 1755 bool grSuccess = false; 1756 if (gr) { 1757 // create a render target to back the device 1758 GrTextureDesc desc; 1759 desc.fConfig = kSkia8888_GrPixelConfig; 1760 desc.fFlags = kRenderTarget_GrTextureFlagBit; 1761 desc.fWidth = gm->getISize().width(); 1762 desc.fHeight = gm->getISize().height(); 1763 desc.fSampleCnt = config.fSampleCnt; 1764 auGpuTarget.reset(gr->createUncachedTexture(desc, NULL, 0)); 1765 if (auGpuTarget) { 1766 gpuTarget = auGpuTarget; 1767 grSuccess = true; 1768 // Set the user specified cache limits if non-default. 1769 size_t bytes; 1770 int count; 1771 gr->getResourceCacheLimits(&count, &bytes); 1772 if (DEFAULT_CACHE_VALUE != gGpuCacheSizeBytes) { 1773 bytes = static_cast<size_t>(gGpuCacheSizeBytes); 1774 } 1775 if (DEFAULT_CACHE_VALUE != gGpuCacheSizeCount) { 1776 count = gGpuCacheSizeCount; 1777 } 1778 gr->setResourceCacheLimits(count, bytes); 1779 } 1780 } 1781 if (!grSuccess) { 1782 errorsForThisConfig.add(kNoGpuContext_ErrorType); 1783 } 1784 } 1785 #endif 1786 1787 SkBitmap comparisonBitmap; 1788 1789 const char* writePath; 1790 if (FLAGS_writePath.count() == 1) { 1791 writePath = FLAGS_writePath[0]; 1792 } else { 1793 writePath = NULL; 1794 } 1795 1796 if (errorsForThisConfig.isEmpty()) { 1797 errorsForThisConfig.add(gmmain.test_drawing(gm, config, pdfRasterizers, 1798 writePath, gpuTarget, 1799 &comparisonBitmap)); 1800 gmmain.RecordTestResults(errorsForThisConfig, shortNamePlusConfig, ""); 1801 } 1802 1803 // TODO: run only if gmmain.test_drawing succeeded. 1804 if (kRaster_Backend == config.fBackend) { 1805 run_multiple_modes(gmmain, gm, config, comparisonBitmap, tileGridReplayScales); 1806 } 1807 1808 if (FLAGS_deferred && errorsForThisConfig.isEmpty() && 1809 (kGPU_Backend == config.fBackend || kRaster_Backend == config.fBackend)) { 1810 errorsForThisConfig.add(gmmain.test_deferred_drawing(gm, config, comparisonBitmap, 1811 gpuTarget)); 1812 } 1813 1814 errorsForAllConfigs.add(errorsForThisConfig); 1815 } 1816 return errorsForAllConfigs; 1817 } 1818 1819 1820 /** 1821 * Read individual lines from a file, pushing them into the given array. 1822 * 1823 * @param filename path to the file to read 1824 * @param lines array of strings to add the lines to 1825 * @returns true if able to read lines from the file 1826 */ 1827 static bool read_lines_from_file(const char* filename, SkTArray<SkString> &lines) { 1828 SkAutoTUnref<SkStream> streamWrapper(SkStream::NewFromFile(filename)); 1829 SkStream *stream = streamWrapper.get(); 1830 if (!stream) { 1831 SkDebugf("unable to read file '%s'\n", filename); 1832 return false; 1833 } 1834 1835 char c; 1836 SkString line; 1837 while (1 == stream->read(&c, 1)) { 1838 // If we hit either CR or LF, we've completed a line. 1839 // 1840 // TODO: If the file uses both CR and LF, this will return an extra blank 1841 // line for each line of the file. Which is OK for current purposes... 1842 // 1843 // TODO: Does this properly handle unicode? It doesn't matter for 1844 // current purposes... 1845 if ((c == 0x0d) || (c == 0x0a)) { 1846 lines.push_back(line); 1847 line.reset(); 1848 } else { 1849 line.append(&c, 1); 1850 } 1851 } 1852 lines.push_back(line); 1853 return true; 1854 } 1855 1856 /** 1857 * Return a list of all entries in an array of strings as a single string 1858 * of this form: 1859 * "item1", "item2", "item3" 1860 */ 1861 SkString list_all(const SkTArray<SkString> &stringArray); 1862 SkString list_all(const SkTArray<SkString> &stringArray) { 1863 SkString total; 1864 for (int i = 0; i < stringArray.count(); i++) { 1865 if (i > 0) { 1866 total.append(", "); 1867 } 1868 total.append("\""); 1869 total.append(stringArray[i]); 1870 total.append("\""); 1871 } 1872 return total; 1873 } 1874 1875 /** 1876 * Return a list of configuration names, as a single string of this form: 1877 * "item1", "item2", "item3" 1878 * 1879 * @param configs configurations, as a list of indices into gRec 1880 */ 1881 SkString list_all_config_names(const SkTDArray<size_t> &configs); 1882 SkString list_all_config_names(const SkTDArray<size_t> &configs) { 1883 SkString total; 1884 for (int i = 0; i < configs.count(); i++) { 1885 if (i > 0) { 1886 total.append(", "); 1887 } 1888 total.append("\""); 1889 total.append(gRec[configs[i]].fName); 1890 total.append("\""); 1891 } 1892 return total; 1893 } 1894 1895 static bool prepare_subdirectories(const char *root, bool useFileHierarchy, 1896 const SkTDArray<size_t> &configs, 1897 const SkTDArray<const PDFRasterizerData*>& pdfRasterizers) { 1898 if (!sk_mkdir(root)) { 1899 return false; 1900 } 1901 if (useFileHierarchy) { 1902 for (int i = 0; i < configs.count(); i++) { 1903 ConfigData config = gRec[configs[i]]; 1904 SkString subdir; 1905 subdir.appendf("%s%c%s", root, SkPATH_SEPARATOR, config.fName); 1906 if (!sk_mkdir(subdir.c_str())) { 1907 return false; 1908 } 1909 1910 if (config.fBackend == kPDF_Backend) { 1911 for (int j = 0; j < pdfRasterizers.count(); j++) { 1912 SkString pdfSubdir = subdir; 1913 pdfSubdir.appendf("-%s", pdfRasterizers[j]->fName); 1914 if (!sk_mkdir(pdfSubdir.c_str())) { 1915 return false; 1916 } 1917 } 1918 } 1919 } 1920 } 1921 return true; 1922 } 1923 1924 static bool parse_flags_configs(SkTDArray<size_t>* outConfigs, 1925 GrContextFactory* grFactory, GrGLStandard gpuAPI) { 1926 SkTDArray<size_t> excludeConfigs; 1927 1928 for (int i = 0; i < FLAGS_config.count(); i++) { 1929 const char* config = FLAGS_config[i]; 1930 bool exclude = false; 1931 if (*config == kExcludeConfigChar) { 1932 exclude = true; 1933 config += 1; 1934 } 1935 int index = findConfig(config); 1936 if (index >= 0) { 1937 if (exclude) { 1938 *excludeConfigs.append() = index; 1939 } else { 1940 appendUnique<size_t>(outConfigs, index); 1941 } 1942 } else if (0 == strcmp(kDefaultsConfigStr, config)) { 1943 if (exclude) { 1944 SkDebugf("%c%s is not allowed.\n", 1945 kExcludeConfigChar, kDefaultsConfigStr); 1946 return false; 1947 } 1948 for (size_t c = 0; c < SK_ARRAY_COUNT(gRec); ++c) { 1949 if (gRec[c].fRunByDefault) { 1950 appendUnique<size_t>(outConfigs, c); 1951 } 1952 } 1953 } else { 1954 SkDebugf("unrecognized config %s\n", config); 1955 return false; 1956 } 1957 } 1958 1959 for (int i = 0; i < FLAGS_excludeConfig.count(); i++) { 1960 int index = findConfig(FLAGS_excludeConfig[i]); 1961 if (index >= 0) { 1962 *excludeConfigs.append() = index; 1963 } else { 1964 SkDebugf("unrecognized excludeConfig %s\n", FLAGS_excludeConfig[i]); 1965 return false; 1966 } 1967 } 1968 1969 if (outConfigs->count() == 0) { 1970 // if no config is specified by user, add the defaults 1971 for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { 1972 if (gRec[i].fRunByDefault) { 1973 *outConfigs->append() = i; 1974 } 1975 } 1976 } 1977 // now remove any explicitly excluded configs 1978 for (int i = 0; i < excludeConfigs.count(); ++i) { 1979 int index = outConfigs->find(excludeConfigs[i]); 1980 if (index >= 0) { 1981 outConfigs->remove(index); 1982 // now assert that there was only one copy in configs[] 1983 SkASSERT(outConfigs->find(excludeConfigs[i]) < 0); 1984 } 1985 } 1986 1987 for (int i = 0; i < outConfigs->count(); ++i) { 1988 size_t index = (*outConfigs)[i]; 1989 if (kGPU_Backend == gRec[index].fBackend) { 1990 #if SK_SUPPORT_GPU 1991 if (!FLAGS_gpu) { 1992 outConfigs->remove(i); 1993 --i; 1994 continue; 1995 } 1996 #endif 1997 } else if (!FLAGS_cpu) { 1998 outConfigs->remove(i); 1999 --i; 2000 continue; 2001 } 2002 #if SK_SUPPORT_GPU 2003 SkASSERT(grFactory != NULL); 2004 if (kGPU_Backend == gRec[index].fBackend) { 2005 GrContext* ctx = grFactory->get(gRec[index].fGLContextType, gpuAPI); 2006 if (NULL == ctx) { 2007 SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n", 2008 gRec[index].fName); 2009 outConfigs->remove(i); 2010 --i; 2011 continue; 2012 } 2013 if (gRec[index].fSampleCnt > ctx->getMaxSampleCount()) { 2014 SkDebugf("Sample count (%d) of config %s is not supported." 2015 " Config will be skipped.\n", 2016 gRec[index].fSampleCnt, gRec[index].fName); 2017 outConfigs->remove(i); 2018 --i; 2019 } 2020 } 2021 #endif 2022 } 2023 2024 if (outConfigs->isEmpty()) { 2025 SkDebugf("No configs to run."); 2026 return false; 2027 } 2028 2029 // now show the user the set of configs that will be run. 2030 SkString configStr("These configs will be run:"); 2031 // show the user the config that will run. 2032 for (int i = 0; i < outConfigs->count(); ++i) { 2033 configStr.appendf(" %s", gRec[(*outConfigs)[i]].fName); 2034 } 2035 SkDebugf("%s\n", configStr.c_str()); 2036 2037 return true; 2038 } 2039 2040 static bool parse_flags_pdf_rasterizers(const SkTDArray<size_t>& configs, 2041 SkTDArray<const PDFRasterizerData*>* outRasterizers) { 2042 // No need to run this check (and display the PDF rasterizers message) 2043 // if no PDF backends are in the configs. 2044 bool configHasPDF = false; 2045 for (int i = 0; i < configs.count(); i++) { 2046 if (gRec[configs[i]].fBackend == kPDF_Backend) { 2047 configHasPDF = true; 2048 break; 2049 } 2050 } 2051 if (!configHasPDF) { 2052 return true; 2053 } 2054 2055 if (FLAGS_pdfRasterizers.count() == 1 && 2056 !strcmp(FLAGS_pdfRasterizers[0], "default")) { 2057 for (int i = 0; i < (int)SK_ARRAY_COUNT(kPDFRasterizers); ++i) { 2058 if (kPDFRasterizers[i].fRunByDefault) { 2059 *outRasterizers->append() = &kPDFRasterizers[i]; 2060 } 2061 } 2062 } else { 2063 for (int i = 0; i < FLAGS_pdfRasterizers.count(); i++) { 2064 const char* rasterizer = FLAGS_pdfRasterizers[i]; 2065 const PDFRasterizerData* rasterizerPtr = 2066 findPDFRasterizer(rasterizer); 2067 if (rasterizerPtr == NULL) { 2068 SkDebugf("unrecognized rasterizer %s\n", rasterizer); 2069 return false; 2070 } 2071 appendUnique<const PDFRasterizerData*>(outRasterizers, 2072 rasterizerPtr); 2073 } 2074 } 2075 2076 // now show the user the set of configs that will be run. 2077 SkString configStr("These PDF rasterizers will be run:"); 2078 // show the user the config that will run. 2079 for (int i = 0; i < outRasterizers->count(); ++i) { 2080 configStr.appendf(" %s", (*outRasterizers)[i]->fName); 2081 } 2082 SkDebugf("%s\n", configStr.c_str()); 2083 2084 return true; 2085 } 2086 2087 static bool parse_flags_ignore_error_types(ErrorCombination* outErrorTypes) { 2088 if (FLAGS_ignoreErrorTypes.count() > 0) { 2089 *outErrorTypes = ErrorCombination(); 2090 for (int i = 0; i < FLAGS_ignoreErrorTypes.count(); i++) { 2091 ErrorType type; 2092 const char *name = FLAGS_ignoreErrorTypes[i]; 2093 if (!getErrorTypeByName(name, &type)) { 2094 SkDebugf("cannot find ErrorType with name '%s'\n", name); 2095 return false; 2096 } else { 2097 outErrorTypes->add(type); 2098 } 2099 } 2100 } 2101 return true; 2102 } 2103 2104 /** 2105 * Replace contents of ignoreTestNames with a list of test names, indicating 2106 * which tests' failures should be ignored. 2107 */ 2108 static bool parse_flags_ignore_tests(SkTArray<SkString> &ignoreTestNames) { 2109 ignoreTestNames.reset(); 2110 2111 // Parse --ignoreFailuresFile 2112 for (int i = 0; i < FLAGS_ignoreFailuresFile.count(); i++) { 2113 SkTArray<SkString> linesFromFile; 2114 if (!read_lines_from_file(FLAGS_ignoreFailuresFile[i], linesFromFile)) { 2115 return false; 2116 } else { 2117 for (int j = 0; j < linesFromFile.count(); j++) { 2118 SkString thisLine = linesFromFile[j]; 2119 if (thisLine.isEmpty() || thisLine.startsWith('#')) { 2120 // skip this line 2121 } else { 2122 ignoreTestNames.push_back(thisLine); 2123 } 2124 } 2125 } 2126 } 2127 2128 return true; 2129 } 2130 2131 static bool parse_flags_modulo(int* moduloRemainder, int* moduloDivisor) { 2132 if (FLAGS_modulo.count() == 2) { 2133 *moduloRemainder = atoi(FLAGS_modulo[0]); 2134 *moduloDivisor = atoi(FLAGS_modulo[1]); 2135 if (*moduloRemainder < 0 || *moduloDivisor <= 0 || 2136 *moduloRemainder >= *moduloDivisor) { 2137 SkDebugf("invalid modulo values."); 2138 return false; 2139 } 2140 } 2141 return true; 2142 } 2143 2144 #if SK_SUPPORT_GPU 2145 static bool parse_flags_gpu_cache(int* sizeBytes, int* sizeCount) { 2146 if (FLAGS_gpuCacheSize.count() > 0) { 2147 if (FLAGS_gpuCacheSize.count() != 2) { 2148 SkDebugf("--gpuCacheSize requires two arguments\n"); 2149 return false; 2150 } 2151 *sizeBytes = atoi(FLAGS_gpuCacheSize[0]); 2152 *sizeCount = atoi(FLAGS_gpuCacheSize[1]); 2153 } else { 2154 *sizeBytes = DEFAULT_CACHE_VALUE; 2155 *sizeCount = DEFAULT_CACHE_VALUE; 2156 } 2157 return true; 2158 } 2159 2160 static bool parse_flags_gl_standard(GrGLStandard* gpuAPI) { 2161 if (0 == FLAGS_gpuAPI.count()) { 2162 *gpuAPI = kNone_GrGLStandard; 2163 return true; 2164 } 2165 if (1 == FLAGS_gpuAPI.count()) { 2166 if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) { 2167 *gpuAPI = kGL_GrGLStandard; 2168 return true; 2169 } 2170 if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) { 2171 *gpuAPI = kGLES_GrGLStandard; 2172 return true; 2173 } 2174 } 2175 SkDebugf("--gpuAPI invalid api value"); 2176 return false; 2177 } 2178 #endif 2179 2180 static bool parse_flags_tile_grid_replay_scales(SkTDArray<SkScalar>* outScales) { 2181 *outScales->append() = SK_Scalar1; // By default only test at scale 1.0 2182 if (FLAGS_tileGridReplayScales.count() > 0) { 2183 outScales->reset(); 2184 for (int i = 0; i < FLAGS_tileGridReplayScales.count(); i++) { 2185 double val = atof(FLAGS_tileGridReplayScales[i]); 2186 if (0 < val) { 2187 *outScales->append() = SkDoubleToScalar(val); 2188 } 2189 } 2190 if (0 == outScales->count()) { 2191 // Should have at least one scale 2192 SkDebugf("--tileGridReplayScales requires at least one scale.\n"); 2193 return false; 2194 } 2195 } 2196 return true; 2197 } 2198 2199 static bool parse_flags_gmmain_paths(GMMain* gmmain) { 2200 gmmain->fUseFileHierarchy = FLAGS_hierarchy; 2201 gmmain->fWriteChecksumBasedFilenames = FLAGS_writeChecksumBasedFilenames; 2202 2203 if (FLAGS_mismatchPath.count() == 1) { 2204 gmmain->fMismatchPath = FLAGS_mismatchPath[0]; 2205 } 2206 2207 if (FLAGS_missingExpectationsPath.count() == 1) { 2208 gmmain->fMissingExpectationsPath = FLAGS_missingExpectationsPath[0]; 2209 } 2210 2211 if (FLAGS_readPath.count() == 1) { 2212 const char* readPath = FLAGS_readPath[0]; 2213 if (!sk_exists(readPath)) { 2214 SkDebugf("readPath %s does not exist!\n", readPath); 2215 return false; 2216 } 2217 if (sk_isdir(readPath)) { 2218 if (FLAGS_verbose) { 2219 SkDebugf("reading from %s\n", readPath); 2220 } 2221 gmmain->fExpectationsSource.reset(SkNEW_ARGS( 2222 IndividualImageExpectationsSource, (readPath))); 2223 } else { 2224 if (FLAGS_verbose) { 2225 SkDebugf("reading expectations from JSON summary file %s\n", readPath); 2226 } 2227 gmmain->fExpectationsSource.reset(SkNEW_ARGS(JsonExpectationsSource, (readPath))); 2228 } 2229 } 2230 return true; 2231 } 2232 2233 static bool parse_flags_jpeg_quality() { 2234 if (FLAGS_pdfJpegQuality < -1 || FLAGS_pdfJpegQuality > 100) { 2235 SkDebugf("%s\n", "pdfJpegQuality must be in [-1 .. 100] range."); 2236 return false; 2237 } 2238 return true; 2239 } 2240 2241 int tool_main(int argc, char** argv); 2242 int tool_main(int argc, char** argv) { 2243 SetupCrashHandler(); 2244 2245 SkString usage; 2246 usage.printf("Run the golden master tests.\n"); 2247 SkCommandLineFlags::SetUsage(usage.c_str()); 2248 SkCommandLineFlags::Parse(argc, argv); 2249 2250 #if SK_ENABLE_INST_COUNT 2251 if (FLAGS_leaks) { 2252 gPrintInstCount = true; 2253 } 2254 #endif 2255 2256 SkGraphics::Init(); 2257 2258 setSystemPreferences(); 2259 GMMain gmmain; 2260 2261 SkTDArray<size_t> configs; 2262 2263 int moduloRemainder = -1; 2264 int moduloDivisor = -1; 2265 SkTDArray<const PDFRasterizerData*> pdfRasterizers; 2266 SkTDArray<SkScalar> tileGridReplayScales; 2267 #if SK_SUPPORT_GPU 2268 GrGLStandard gpuAPI = kNone_GrGLStandard; 2269 GrContext::Options grContextOpts; 2270 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks; 2271 GrContextFactory* grFactory = new GrContextFactory(grContextOpts); 2272 #else 2273 GrGLStandard gpuAPI = 0; 2274 GrContextFactory* grFactory = NULL; 2275 #endif 2276 2277 if (FLAGS_dryRun) { 2278 SkDebugf( "Doing a dry run; no tests will actually be executed.\n"); 2279 } 2280 2281 if (!parse_flags_modulo(&moduloRemainder, &moduloDivisor) || 2282 !parse_flags_ignore_error_types(&gmmain.fIgnorableErrorTypes) || 2283 !parse_flags_ignore_tests(gmmain.fIgnorableTestNames) || 2284 #if SK_SUPPORT_GPU 2285 !parse_flags_gpu_cache(&gGpuCacheSizeBytes, &gGpuCacheSizeCount) || 2286 !parse_flags_gl_standard(&gpuAPI) || 2287 #endif 2288 !parse_flags_tile_grid_replay_scales(&tileGridReplayScales) || 2289 !parse_flags_jpeg_quality() || 2290 !parse_flags_configs(&configs, grFactory, gpuAPI) || 2291 !parse_flags_pdf_rasterizers(configs, &pdfRasterizers) || 2292 !parse_flags_gmmain_paths(&gmmain)) { 2293 return -1; 2294 } 2295 2296 if (FLAGS_verbose) { 2297 if (FLAGS_writePath.count() == 1) { 2298 SkDebugf("writing to %s\n", FLAGS_writePath[0]); 2299 } 2300 if (gmmain.fMismatchPath) { 2301 SkDebugf("writing mismatches to %s\n", gmmain.fMismatchPath); 2302 } 2303 if (gmmain.fMissingExpectationsPath) { 2304 SkDebugf("writing images without expectations to %s\n", 2305 gmmain.fMissingExpectationsPath); 2306 } 2307 if (FLAGS_writePicturePath.count() == 1) { 2308 SkDebugf("writing pictures to %s\n", FLAGS_writePicturePath[0]); 2309 } 2310 if (!GetResourcePath().isEmpty()) { 2311 SkDebugf("reading resources from %s\n", GetResourcePath().c_str()); 2312 } 2313 } 2314 2315 int gmsRun = 0; 2316 int gmIndex = -1; 2317 SkString moduloStr; 2318 2319 if (!FLAGS_dryRun) { 2320 // If we will be writing out files, prepare subdirectories. 2321 if (FLAGS_writePath.count() == 1) { 2322 if (!prepare_subdirectories(FLAGS_writePath[0], gmmain.fUseFileHierarchy, 2323 configs, pdfRasterizers)) { 2324 return -1; 2325 } 2326 } 2327 if (gmmain.fMismatchPath) { 2328 if (!prepare_subdirectories(gmmain.fMismatchPath, gmmain.fUseFileHierarchy, 2329 configs, pdfRasterizers)) { 2330 return -1; 2331 } 2332 } 2333 if (gmmain.fMissingExpectationsPath) { 2334 if (!prepare_subdirectories(gmmain.fMissingExpectationsPath, gmmain.fUseFileHierarchy, 2335 configs, pdfRasterizers)) { 2336 return -1; 2337 } 2338 } 2339 } 2340 Iter iter; 2341 GM* gm; 2342 while ((gm = iter.next()) != NULL) { 2343 if (FLAGS_forcePerspectiveMatrix) { 2344 SkMatrix perspective; 2345 perspective.setIdentity(); 2346 perspective.setPerspY(SkScalarDiv(SK_Scalar1, SkIntToScalar(1000))); 2347 perspective.setSkewX(SkScalarDiv(SkIntToScalar(8), 2348 SkIntToScalar(25))); 2349 2350 gm->setStarterMatrix(perspective); 2351 } 2352 SkAutoTDelete<GM> adgm(gm); 2353 ++gmIndex; 2354 if (moduloRemainder >= 0) { 2355 if ((gmIndex % moduloDivisor) != moduloRemainder) { 2356 continue; 2357 } 2358 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor); 2359 } 2360 2361 const char* shortName = gm->getName(); 2362 2363 if (SkCommandLineFlags::ShouldSkip(FLAGS_match, shortName)) { 2364 continue; 2365 } 2366 2367 gmsRun++; 2368 SkISize size = gm->getISize(); 2369 SkDebugf("%4dM %sdrawing... %s [%d %d]\n", 2370 sk_tools::getMaxResidentSetSizeMB(), moduloStr.c_str(), shortName, 2371 size.width(), size.height()); 2372 if (!FLAGS_dryRun) 2373 run_multiple_configs(gmmain, gm, configs, pdfRasterizers, tileGridReplayScales, 2374 grFactory, gpuAPI); 2375 } 2376 2377 if (FLAGS_dryRun) 2378 return 0; 2379 2380 SkTArray<SkString> modes; 2381 gmmain.GetRenderModesEncountered(modes); 2382 int modeCount = modes.count(); 2383 2384 // Now that we have run all the tests and thus know the full set of renderModes that we 2385 // tried to run, we can call RecordTestResults() to record the cases in which we skipped 2386 // ALL renderModes. 2387 // See http://skbug.com/1994 and https://codereview.chromium.org/129203002/ 2388 int testCount = gmmain.fTestsSkippedOnAllRenderModes.count(); 2389 for (int testNum = 0; testNum < testCount; ++testNum) { 2390 const SkString &shortNamePlusConfig = gmmain.fTestsSkippedOnAllRenderModes[testNum]; 2391 for (int modeNum = 0; modeNum < modeCount; ++modeNum) { 2392 gmmain.RecordTestResults(kIntentionallySkipped_ErrorType, shortNamePlusConfig, 2393 modes[modeNum].c_str()); 2394 } 2395 } 2396 2397 bool reportError = false; 2398 if (gmmain.NumSignificantErrors() > 0) { 2399 reportError = true; 2400 } 2401 2402 // We test every GM against every config, and for every raster config also test every mode. 2403 int rasterConfigs = 0; 2404 for (int i = 0; i < configs.count(); i++) { 2405 if (gRec[configs[i]].fBackend == kRaster_Backend) { 2406 rasterConfigs++; 2407 } 2408 } 2409 // For raster configs, we run all renderModes; for non-raster configs, just default renderMode 2410 const int expectedNumberOfTests = rasterConfigs * gmsRun * modeCount 2411 + (configs.count() - rasterConfigs) * gmsRun; 2412 2413 // Output summary to stdout. 2414 if (FLAGS_verbose) { 2415 SkDebugf("Ran %d GMs\n", gmsRun); 2416 SkDebugf("... over %2d configs [%s]\n", configs.count(), 2417 list_all_config_names(configs).c_str()); 2418 SkDebugf("... and %2d modes [%s]\n", modeCount, list_all(modes).c_str()); 2419 SkDebugf("... so there should be a total of %d tests.\n", expectedNumberOfTests); 2420 } 2421 gmmain.ListErrors(FLAGS_verbose); 2422 2423 // TODO(epoger): Enable this check for Android, too, once we resolve 2424 // https://code.google.com/p/skia/issues/detail?id=1222 2425 // ('GM is unexpectedly skipping tests on Android') 2426 #ifndef SK_BUILD_FOR_ANDROID 2427 if (expectedNumberOfTests != gmmain.fTestsRun) { 2428 SkDebugf("expected %d tests, but ran or skipped %d tests\n", 2429 expectedNumberOfTests, gmmain.fTestsRun); 2430 reportError = true; 2431 } 2432 #endif 2433 2434 if (FLAGS_writeJsonSummaryPath.count() == 1) { 2435 Json::Value root = CreateJsonTree( 2436 gmmain.fJsonExpectedResults, 2437 gmmain.fJsonActualResults_Failed, gmmain.fJsonActualResults_FailureIgnored, 2438 gmmain.fJsonActualResults_NoComparison, gmmain.fJsonActualResults_Succeeded); 2439 std::string jsonStdString = root.toStyledString(); 2440 SkFILEWStream stream(FLAGS_writeJsonSummaryPath[0]); 2441 stream.write(jsonStdString.c_str(), jsonStdString.length()); 2442 } 2443 2444 #if SK_SUPPORT_GPU 2445 2446 #if GR_CACHE_STATS 2447 for (int i = 0; i < configs.count(); i++) { 2448 ConfigData config = gRec[configs[i]]; 2449 2450 if (FLAGS_verbose && (kGPU_Backend == config.fBackend)) { 2451 GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI); 2452 2453 SkDebugf("config: %s %x\n", config.fName, gr); 2454 gr->printCacheStats(); 2455 } 2456 } 2457 #endif 2458 2459 #if GR_DUMP_FONT_CACHE 2460 for (int i = 0; i < configs.count(); i++) { 2461 ConfigData config = gRec[configs[i]]; 2462 2463 if (kGPU_Backend == config.fBackend) { 2464 GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI); 2465 2466 gr->dumpFontCache(); 2467 } 2468 } 2469 #endif 2470 2471 delete grFactory; 2472 #endif 2473 SkGraphics::Term(); 2474 2475 return (reportError) ? -1 : 0; 2476 } 2477 2478 void GMMain::installFilter(SkCanvas* canvas) { 2479 if (FLAGS_forceBWtext) { 2480 canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref(); 2481 } 2482 } 2483 2484 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) 2485 int main(int argc, char * const argv[]) { 2486 return tool_main(argc, (char**) argv); 2487 } 2488 #endif 2489