Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 /* | 8 /* |
| 9 * Code for the "gm" (Golden Master) rendering comparison tool. | 9 * Code for the "gm" (Golden Master) rendering comparison tool. |
| 10 * | 10 * |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 27 #include "SkDrawFilter.h" | 27 #include "SkDrawFilter.h" |
| 28 #include "SkGPipe.h" | 28 #include "SkGPipe.h" |
| 29 #include "SkGraphics.h" | 29 #include "SkGraphics.h" |
| 30 #include "SkImageDecoder.h" | 30 #include "SkImageDecoder.h" |
| 31 #include "SkImageEncoder.h" | 31 #include "SkImageEncoder.h" |
| 32 #include "SkOSFile.h" | 32 #include "SkOSFile.h" |
| 33 #include "SkPicture.h" | 33 #include "SkPicture.h" |
| 34 #include "SkRefCnt.h" | 34 #include "SkRefCnt.h" |
| 35 #include "SkStream.h" | 35 #include "SkStream.h" |
| 36 #include "SkTArray.h" | 36 #include "SkTArray.h" |
| 37 #include "SkTDict.h" | |
| 37 #include "SkTileGridPicture.h" | 38 #include "SkTileGridPicture.h" |
| 38 #include "SamplePipeControllers.h" | 39 #include "SamplePipeControllers.h" |
| 39 | 40 |
| 40 #ifdef SK_BUILD_FOR_WIN | 41 #ifdef SK_BUILD_FOR_WIN |
| 41 // json includes xlocale which generates warning 4530 because we're compilin g without | 42 // json includes xlocale which generates warning 4530 because we're compilin g without |
| 42 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 | 43 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 |
| 43 #pragma warning(push) | 44 #pragma warning(push) |
| 44 #pragma warning(disable : 4530) | 45 #pragma warning(disable : 4530) |
| 45 #endif | 46 #endif |
| 46 #include "json/value.h" | 47 #include "json/value.h" |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 57 static int gGpuCacheSizeBytes; | 58 static int gGpuCacheSizeBytes; |
| 58 static int gGpuCacheSizeCount; | 59 static int gGpuCacheSizeCount; |
| 59 #else | 60 #else |
| 60 class GrContextFactory; | 61 class GrContextFactory; |
| 61 class GrContext; | 62 class GrContext; |
| 62 class GrRenderTarget; | 63 class GrRenderTarget; |
| 63 typedef int GLContextType; | 64 typedef int GLContextType; |
| 64 #endif | 65 #endif |
| 65 | 66 |
| 66 extern bool gSkSuppressFontCachePurgeSpew; | 67 extern bool gSkSuppressFontCachePurgeSpew; |
| 68 const static int kAnyIntValue = 1; // when it doesn't matter what int value, jus t SOMETHING | |
|
borenet
2013/04/03 12:46:48
What if we counted the number of times we encounte
epoger
2013/04/03 14:28:25
Done. Note that this now takes twice as long, sin
| |
| 67 | 69 |
| 68 #ifdef SK_SUPPORT_PDF | 70 #ifdef SK_SUPPORT_PDF |
| 69 #include "SkPDFDevice.h" | 71 #include "SkPDFDevice.h" |
| 70 #include "SkPDFDocument.h" | 72 #include "SkPDFDocument.h" |
| 71 #endif | 73 #endif |
| 72 | 74 |
| 73 // Until we resolve http://code.google.com/p/skia/issues/detail?id=455 , | 75 // Until we resolve http://code.google.com/p/skia/issues/detail?id=455 , |
| 74 // stop writing out XPS-format image baselines in gm. | 76 // stop writing out XPS-format image baselines in gm. |
| 75 #undef SK_SUPPORT_XPS | 77 #undef SK_SUPPORT_XPS |
| 76 #ifdef SK_SUPPORT_XPS | 78 #ifdef SK_SUPPORT_XPS |
| 77 #include "SkXPSDevice.h" | 79 #include "SkXPSDevice.h" |
| 78 #endif | 80 #endif |
| 79 | 81 |
| 80 #ifdef SK_BUILD_FOR_MAC | 82 #ifdef SK_BUILD_FOR_MAC |
| 81 #include "SkCGUtils.h" | 83 #include "SkCGUtils.h" |
| 82 #define CAN_IMAGE_PDF 1 | 84 #define CAN_IMAGE_PDF 1 |
| 83 #else | 85 #else |
| 84 #define CAN_IMAGE_PDF 0 | 86 #define CAN_IMAGE_PDF 0 |
| 85 #endif | 87 #endif |
| 86 | 88 |
| 87 using namespace skiagm; | 89 using namespace skiagm; |
| 88 | 90 |
| 89 struct FailRec { | |
| 90 SkString fName; | |
| 91 bool fIsPixelError; | |
| 92 | |
| 93 FailRec() : fIsPixelError(false) {} | |
| 94 FailRec(const SkString& name) : fName(name), fIsPixelError(false) {} | |
| 95 }; | |
| 96 | |
| 97 class Iter { | 91 class Iter { |
| 98 public: | 92 public: |
| 99 Iter() { | 93 Iter() { |
| 100 this->reset(); | 94 this->reset(); |
| 101 } | 95 } |
| 102 | 96 |
| 103 void reset() { | 97 void reset() { |
| 104 fReg = GMRegistry::Head(); | 98 fReg = GMRegistry::Head(); |
| 105 } | 99 } |
| 106 | 100 |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 177 | 171 |
| 178 static PipeFlagComboData gPipeWritingFlagCombos[] = { | 172 static PipeFlagComboData gPipeWritingFlagCombos[] = { |
| 179 { "", 0 }, | 173 { "", 0 }, |
| 180 { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, | 174 { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, |
| 181 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag | 175 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag |
| 182 | SkGPipeWriter::kSharedAddressSpace_Flag } | 176 | SkGPipeWriter::kSharedAddressSpace_Flag } |
| 183 }; | 177 }; |
| 184 | 178 |
| 185 class GMMain { | 179 class GMMain { |
| 186 public: | 180 public: |
| 187 GMMain() { | 181 GMMain() : fRenderModesEncountered(1) { |
|
borenet
2013/04/03 12:46:48
Do you mind moving fUseFileHierarchy, fMismatchPat
epoger
2013/04/03 14:28:25
Done.
| |
| 188 // Set default values of member variables, which tool_main() | 182 // Set default values of member variables, which tool_main() |
| 189 // may override. | 183 // may override. |
| 190 fUseFileHierarchy = false; | 184 fUseFileHierarchy = false; |
| 191 fIgnorableErrorCombination.add(kMissingExpectations_ErrorType); | 185 fIgnorableErrorCombination.add(kMissingExpectations_ErrorType); |
| 192 fMismatchPath = NULL; | 186 fMismatchPath = NULL; |
| 187 fTestsRun = 0; | |
| 188 fRenderModesEncountered.reset(); | |
| 193 } | 189 } |
| 194 | 190 |
| 195 SkString make_name(const char shortName[], const char configName[]) { | 191 SkString make_name(const char shortName[], const char configName[]) { |
| 196 SkString name; | 192 SkString name; |
| 197 if (0 == strlen(configName)) { | 193 if (0 == strlen(configName)) { |
| 198 name.append(shortName); | 194 name.append(shortName); |
| 199 } else if (fUseFileHierarchy) { | 195 } else if (fUseFileHierarchy) { |
| 200 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName); | 196 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName); |
| 201 } else { | 197 } else { |
| 202 name.appendf("%s_%s", shortName, configName); | 198 name.appendf("%s_%s", shortName, configName); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 236 // TODO(epoger): Now that we have removed force_all_opaque() | 232 // TODO(epoger): Now that we have removed force_all_opaque() |
| 237 // from this method, we should be able to get rid of the | 233 // from this method, we should be able to get rid of the |
| 238 // transformation to 8888 format also. | 234 // transformation to 8888 format also. |
| 239 SkBitmap copy; | 235 SkBitmap copy; |
| 240 bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); | 236 bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); |
| 241 return SkImageEncoder::EncodeFile(path.c_str(), copy, | 237 return SkImageEncoder::EncodeFile(path.c_str(), copy, |
| 242 SkImageEncoder::kPNG_Type, 100); | 238 SkImageEncoder::kPNG_Type, 100); |
| 243 } | 239 } |
| 244 | 240 |
| 245 /** | 241 /** |
| 246 * Records the errors encountered in fFailedTests, except for any error | 242 * Add all render modes encountered thus far to the "modes" array. |
| 247 * types we want to ignore. | |
| 248 */ | 243 */ |
| 249 void RecordError(const ErrorCombination& errorCombination, const SkString& n ame, | 244 void GetRenderModesEncountered(SkTArray<SkString> &modes) { |
| 250 const char renderModeDescriptor []) { | 245 SkTDict<int>::Iter iter(this->fRenderModesEncountered); |
| 251 // The common case: no error means nothing to record. | 246 const char* mode; |
| 247 while ((mode = iter.next(NULL)) != NULL) { | |
| 248 SkString modeAsString = SkString(mode); | |
| 249 // TODO(epoger): It seems a bit silly that all of these modes were | |
| 250 // recorded with a leading "-" which we have to remove here | |
| 251 // (except for mode "", which means plain old original mode). | |
| 252 // But that's how renderModeDescriptor has been passed into | |
| 253 // compare_test_results_to_reference_bitmap() historically, | |
| 254 // and changing that now may affect other parts of our code. | |
| 255 if (modeAsString.startsWith("-")) { | |
| 256 modeAsString.remove(0, 1); | |
| 257 modes.push_back(modeAsString); | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 /** | |
| 263 * Records the results of this test in fTestsRun and fFailedTests. | |
| 264 * | |
| 265 * We even record successes, and errors that we regard as | |
| 266 * "ignorable"; we can filter them out later. | |
| 267 */ | |
| 268 void RecordTestResults(const ErrorCombination& errorCombination, const SkStr ing& name, | |
| 269 const char renderModeDescriptor []) { | |
| 270 // Things to do regardless of errorCombination. | |
| 271 fTestsRun++; | |
| 272 this->fRenderModesEncountered.set(renderModeDescriptor, kAnyIntValue); | |
| 273 | |
| 252 if (errorCombination.isEmpty()) { | 274 if (errorCombination.isEmpty()) { |
| 253 return; | 275 return; |
| 254 } | 276 } |
| 255 | 277 |
| 256 // If only certain error type(s) were reported, we know we can ignore th em. | 278 // Things to do only if there is some error condition. |
| 257 if (errorCombination.minus(fIgnorableErrorCombination).isEmpty()) { | 279 SkString fullName = make_name(name.c_str(), renderModeDescriptor); |
| 258 return; | 280 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { |
| 259 } | 281 ErrorType type = static_cast<ErrorType>(typeInt); |
| 260 | 282 if (errorCombination.includes(type)) { |
| 261 FailRec& rec = fFailedTests.push_back(make_name(name.c_str(), renderMode Descriptor)); | 283 fFailedTests[type].push_back(fullName); |
| 262 rec.fIsPixelError = errorCombination.includes(kImageMismatch_ErrorType); | |
| 263 } | |
| 264 | |
| 265 // List contents of fFailedTests via SkDebug. | |
| 266 void ListErrors() { | |
| 267 for (int i = 0; i < fFailedTests.count(); ++i) { | |
| 268 if (fFailedTests[i].fIsPixelError) { | |
| 269 gm_fprintf(stderr, "\t\t%s pixel_error\n", fFailedTests[i].fName .c_str()); | |
| 270 } else { | |
| 271 gm_fprintf(stderr, "\t\t%s\n", fFailedTests[i].fName.c_str()); | |
| 272 } | 284 } |
| 273 } | 285 } |
| 274 } | 286 } |
| 275 | 287 |
| 288 /** | |
| 289 * Return the number of significant (non-ignorable) errors we have | |
| 290 * encountered so far. | |
| 291 */ | |
| 292 int NumSignificantErrors() { | |
| 293 int significantErrors = 0; | |
| 294 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
| 295 ErrorType type = static_cast<ErrorType>(typeInt); | |
| 296 if (!fIgnorableErrorCombination.includes(type)) { | |
| 297 significantErrors += fFailedTests[type].count(); | |
| 298 } | |
| 299 } | |
| 300 return significantErrors; | |
| 301 } | |
| 302 | |
| 303 /** | |
| 304 * List contents of fFailedTests to stdout. | |
| 305 */ | |
| 306 void ListErrors() { | |
| 307 // First, print a single summary line. | |
| 308 SkString summary; | |
| 309 summary.appendf("Ran %d tests:", fTestsRun); | |
| 310 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
| 311 ErrorType type = static_cast<ErrorType>(typeInt); | |
| 312 summary.appendf(" %s=%d", getErrorTypeName(type), fFailedTests[type] .count()); | |
| 313 } | |
| 314 gm_fprintf(stdout, "%s\n", summary.c_str()); | |
| 315 | |
| 316 // Now, for each failure type, list the tests that failed that way. | |
| 317 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
| 318 SkString line; | |
| 319 ErrorType type = static_cast<ErrorType>(typeInt); | |
| 320 if (fIgnorableErrorCombination.includes(type)) { | |
| 321 line.append("[ ] "); | |
| 322 } else { | |
| 323 line.append("[*] "); | |
| 324 } | |
| 325 | |
| 326 SkTArray<SkString> *failedTestsOfThisType = &fFailedTests[type]; | |
| 327 int count = failedTestsOfThisType->count(); | |
| 328 line.appendf("%d %s:", count, getErrorTypeName(type)); | |
| 329 for (int i = 0; i < count; ++i) { | |
| 330 line.append(" "); | |
| 331 line.append((*failedTestsOfThisType)[i]); | |
| 332 } | |
| 333 gm_fprintf(stdout, "%s\n", line.c_str()); | |
| 334 } | |
| 335 gm_fprintf(stdout, "(results marked with [*] will cause nonzero return v alue)\n"); | |
| 336 } | |
| 337 | |
| 276 static bool write_document(const SkString& path, | 338 static bool write_document(const SkString& path, |
| 277 const SkDynamicMemoryWStream& document) { | 339 const SkDynamicMemoryWStream& document) { |
| 278 SkFILEWStream stream(path.c_str()); | 340 SkFILEWStream stream(path.c_str()); |
| 279 SkAutoDataUnref data(document.copyToData()); | 341 SkAutoDataUnref data(document.copyToData()); |
| 280 return stream.writeData(data.get()); | 342 return stream.writeData(data.get()); |
| 281 } | 343 } |
| 282 | 344 |
| 283 /** | 345 /** |
| 284 * Prepare an SkBitmap to render a GM into. | 346 * Prepare an SkBitmap to render a GM into. |
| 285 * | 347 * |
| (...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 503 if (kXPS_Backend == gRec.fBackend) { | 565 if (kXPS_Backend == gRec.fBackend) { |
| 504 path = make_filename(writePath, renderModeDescriptor, name.c_str(), | 566 path = make_filename(writePath, renderModeDescriptor, name.c_str(), |
| 505 "xps"); | 567 "xps"); |
| 506 success = write_document(path, *document); | 568 success = write_document(path, *document); |
| 507 } | 569 } |
| 508 if (success) { | 570 if (success) { |
| 509 return kEmpty_ErrorCombination; | 571 return kEmpty_ErrorCombination; |
| 510 } else { | 572 } else { |
| 511 gm_fprintf(stderr, "FAILED to write %s\n", path.c_str()); | 573 gm_fprintf(stderr, "FAILED to write %s\n", path.c_str()); |
| 512 ErrorCombination errors(kWritingReferenceImage_ErrorType); | 574 ErrorCombination errors(kWritingReferenceImage_ErrorType); |
| 513 RecordError(errors, name, renderModeDescriptor); | 575 // TODO(epoger): Don't call RecordTestResults() here... |
| 576 // Instead, we should make sure to call RecordTestResults | |
| 577 // exactly ONCE per test. (Otherwise, gmmain.fTestsRun | |
| 578 // will be incremented twice for this test: once in | |
| 579 // compare_test_results_to_stored_expectations() before | |
| 580 // that method calls this one, and again here.) | |
| 581 // | |
| 582 // When we make that change, we should probably add a | |
| 583 // WritingReferenceImage test to the gm self-tests.) | |
| 584 RecordTestResults(errors, name, renderModeDescriptor); | |
| 514 return errors; | 585 return errors; |
| 515 } | 586 } |
| 516 } | 587 } |
| 517 | 588 |
| 518 /** | 589 /** |
| 519 * Log more detail about the mistmatch between expectedBitmap and | 590 * Log more detail about the mistmatch between expectedBitmap and |
| 520 * actualBitmap. | 591 * actualBitmap. |
| 521 */ | 592 */ |
| 522 void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& act ualBitmap, | 593 void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& act ualBitmap, |
| 523 const char *testName) { | 594 const char *testName) { |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 615 write_bitmap(path, actualBitmap); | 686 write_bitmap(path, actualBitmap); |
| 616 } | 687 } |
| 617 | 688 |
| 618 // If we have access to a single expected bitmap, log more | 689 // If we have access to a single expected bitmap, log more |
| 619 // detail about the mismatch. | 690 // detail about the mismatch. |
| 620 const SkBitmap *expectedBitmapPtr = expectations.asBitmap(); | 691 const SkBitmap *expectedBitmapPtr = expectations.asBitmap(); |
| 621 if (NULL != expectedBitmapPtr) { | 692 if (NULL != expectedBitmapPtr) { |
| 622 report_bitmap_diffs(*expectedBitmapPtr, actualBitmap, completeNa me); | 693 report_bitmap_diffs(*expectedBitmapPtr, actualBitmap, completeNa me); |
| 623 } | 694 } |
| 624 } | 695 } |
| 625 RecordError(errors, baseNameString, renderModeDescriptor); | 696 RecordTestResults(errors, baseNameString, renderModeDescriptor); |
| 626 | 697 |
| 627 if (addToJsonSummary) { | 698 if (addToJsonSummary) { |
| 628 add_actual_results_to_json_summary(completeName, actualChecksum, err ors, | 699 add_actual_results_to_json_summary(completeName, actualChecksum, err ors, |
| 629 expectations.ignoreFailure()); | 700 expectations.ignoreFailure()); |
| 630 add_expected_results_to_json_summary(completeName, expectations); | 701 add_expected_results_to_json_summary(completeName, expectations); |
| 631 } | 702 } |
| 632 | 703 |
| 633 return errors; | 704 return errors; |
| 634 } | 705 } |
| 635 | 706 |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 731 errors.add(compare_to_expectations(expectations, actualBitmap, | 802 errors.add(compare_to_expectations(expectations, actualBitmap, |
| 732 name, "", true)); | 803 name, "", true)); |
| 733 } else { | 804 } else { |
| 734 // If we are running without expectations, we still want to | 805 // If we are running without expectations, we still want to |
| 735 // record the actual results. | 806 // record the actual results. |
| 736 Checksum actualChecksum = | 807 Checksum actualChecksum = |
| 737 SkBitmapChecksummer::Compute64(actualBitmap); | 808 SkBitmapChecksummer::Compute64(actualBitmap); |
| 738 add_actual_results_to_json_summary(name.c_str(), actualChecksum, | 809 add_actual_results_to_json_summary(name.c_str(), actualChecksum, |
| 739 ErrorCombination(kMissingExpectat ions_ErrorType), | 810 ErrorCombination(kMissingExpectat ions_ErrorType), |
| 740 false); | 811 false); |
| 812 RecordTestResults(ErrorCombination(kMissingExpectations_ErrorType), name, ""); | |
| 741 } | 813 } |
| 742 | 814 |
| 743 // TODO: Consider moving this into compare_to_expectations(), | 815 // TODO: Consider moving this into compare_to_expectations(), |
| 744 // similar to fMismatchPath... for now, we don't do that, because | 816 // similar to fMismatchPath... for now, we don't do that, because |
| 745 // we don't want to write out the actual bitmaps for all | 817 // we don't want to write out the actual bitmaps for all |
| 746 // renderModes of all tests! That would be a lot of files. | 818 // renderModes of all tests! That would be a lot of files. |
| 747 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { | 819 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { |
| 748 errors.add(write_reference_image(gRec, writePath, "", | 820 errors.add(write_reference_image(gRec, writePath, "", |
| 749 name, actualBitmap, pdf)); | 821 name, actualBitmap, pdf)); |
| 750 } | 822 } |
| 751 | 823 |
| 752 return errors; | 824 return errors; |
| 753 } | 825 } |
| 754 | 826 |
| 755 /** | 827 /** |
| 756 * Compare actualBitmap to referenceBitmap. | 828 * Compare actualBitmap to referenceBitmap. |
| 757 * | 829 * |
| 758 * @param gm which test generated the bitmap | 830 * @param gm which test generated the bitmap |
| 759 * @param gRec | 831 * @param gRec |
| 760 * @param renderModeDescriptor | 832 * @param renderModeDescriptor |
| 761 * @param actualBitmap actual bitmap generated by this run | 833 * @param actualBitmap actual bitmap generated by this run |
| 762 * @param referenceBitmap bitmap we expected to be generated | 834 * @param referenceBitmap bitmap we expected to be generated |
| 763 */ | 835 */ |
| 764 ErrorCombination compare_test_results_to_reference_bitmap( | 836 ErrorCombination compare_test_results_to_reference_bitmap( |
| 765 GM* gm, const ConfigData& gRec, const char renderModeDescriptor [], | 837 GM* gm, const ConfigData& gRec, const char renderModeDescriptor [], |
| 766 SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) { | 838 SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) { |
| 767 | 839 |
| 840 // TODO(epoger): This method is run to compare results across | |
| 841 // different rendering modes (as opposed to | |
| 842 // compare_test_results_to_stored_expectations(), which | |
| 843 // compares results against expectations stored on disk). If | |
| 844 // we would like the GenerateGMs step to distinguish between | |
| 845 // those two types of mismatches, we should report image | |
| 846 // mismatches in here with a different ErrorType. | |
| 768 SkASSERT(referenceBitmap); | 847 SkASSERT(referenceBitmap); |
| 769 SkString name = make_name(gm->shortName(), gRec.fName); | 848 SkString name = make_name(gm->shortName(), gRec.fName); |
| 770 Expectations expectations(*referenceBitmap); | 849 Expectations expectations(*referenceBitmap); |
| 771 return compare_to_expectations(expectations, actualBitmap, | 850 return compare_to_expectations(expectations, actualBitmap, |
| 772 name, renderModeDescriptor); | 851 name, renderModeDescriptor); |
| 773 } | 852 } |
| 774 | 853 |
| 775 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t rec ordFlags, | 854 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t rec ordFlags, |
| 776 SkScalar scale = SK_Scalar1) { | 855 SkScalar scale = SK_Scalar1) { |
| 777 // Pictures are refcounted so must be on heap | 856 // Pictures are refcounted so must be on heap |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 873 // -deferred image, we exit early! We should fix this | 952 // -deferred image, we exit early! We should fix this |
| 874 // ASAP, because it is hiding -deferred errors... but for | 953 // ASAP, because it is hiding -deferred errors... but for |
| 875 // now, I'm leaving the logic as it is so that the | 954 // now, I'm leaving the logic as it is so that the |
| 876 // refactoring change | 955 // refactoring change |
| 877 // https://codereview.chromium.org/12992003/ is unblocked. | 956 // https://codereview.chromium.org/12992003/ is unblocked. |
| 878 // | 957 // |
| 879 // Filed as https://code.google.com/p/skia/issues/detail?id=1180 | 958 // Filed as https://code.google.com/p/skia/issues/detail?id=1180 |
| 880 // ('image-surface gm test is failing in "deferred" mode, | 959 // ('image-surface gm test is failing in "deferred" mode, |
| 881 // and gm is not reporting the failure') | 960 // and gm is not reporting the failure') |
| 882 if (errors.isEmpty()) { | 961 if (errors.isEmpty()) { |
| 962 // TODO(epoger): Report this as a new ErrorType, | |
| 963 // something like kImageGeneration_ErrorType? | |
| 883 return kEmpty_ErrorCombination; | 964 return kEmpty_ErrorCombination; |
| 884 } | 965 } |
| 885 return compare_test_results_to_reference_bitmap( | 966 return compare_test_results_to_reference_bitmap( |
| 886 gm, gRec, "-deferred", bitmap, &referenceBitmap); | 967 gm, gRec, "-deferred", bitmap, &referenceBitmap); |
| 887 } | 968 } |
| 888 return kEmpty_ErrorCombination; | 969 return kEmpty_ErrorCombination; |
| 889 } | 970 } |
| 890 | 971 |
| 891 ErrorCombination test_pipe_playback(GM* gm, | 972 ErrorCombination test_pipe_playback(GM* gm, |
| 892 const ConfigData& gRec, | 973 const ConfigData& gRec, |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 946 // | 1027 // |
| 947 // member variables. | 1028 // member variables. |
| 948 // They are public for now, to allow easier setting by tool_main(). | 1029 // They are public for now, to allow easier setting by tool_main(). |
| 949 // | 1030 // |
| 950 | 1031 |
| 951 bool fUseFileHierarchy; | 1032 bool fUseFileHierarchy; |
| 952 ErrorCombination fIgnorableErrorCombination; | 1033 ErrorCombination fIgnorableErrorCombination; |
| 953 | 1034 |
| 954 const char* fMismatchPath; | 1035 const char* fMismatchPath; |
| 955 | 1036 |
| 956 // information about all failed tests we have encountered so far | 1037 // collection of tests that have failed with each ErrorType |
| 957 SkTArray<FailRec> fFailedTests; | 1038 SkTArray<SkString> fFailedTests[kLast_ErrorType+1]; |
| 1039 int fTestsRun; | |
| 1040 SkTDict<int> fRenderModesEncountered; | |
| 958 | 1041 |
| 959 // Where to read expectations (expected image checksums, etc.) from. | 1042 // Where to read expectations (expected image checksums, etc.) from. |
| 960 // If unset, we don't do comparisons. | 1043 // If unset, we don't do comparisons. |
| 961 SkAutoTUnref<ExpectationsSource> fExpectationsSource; | 1044 SkAutoTUnref<ExpectationsSource> fExpectationsSource; |
| 962 | 1045 |
| 963 // JSON summaries that we generate as we go (just for output). | 1046 // JSON summaries that we generate as we go (just for output). |
| 964 Json::Value fJsonExpectedResults; | 1047 Json::Value fJsonExpectedResults; |
| 965 Json::Value fJsonActualResults_Failed; | 1048 Json::Value fJsonActualResults_Failed; |
| 966 Json::Value fJsonActualResults_FailureIgnored; | 1049 Json::Value fJsonActualResults_FailureIgnored; |
| 967 Json::Value fJsonActualResults_NoComparison; | 1050 Json::Value fJsonActualResults_NoComparison; |
| (...skipping 290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1258 */ | 1341 */ |
| 1259 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co mpareConfig, | 1342 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co mpareConfig, |
| 1260 const SkBitmap &comparisonBitmap, | 1343 const SkBitmap &comparisonBitmap, |
| 1261 const SkTDArray<SkScalar> &tileGridReplaySca les); | 1344 const SkTDArray<SkScalar> &tileGridReplaySca les); |
| 1262 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co mpareConfig, | 1345 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co mpareConfig, |
| 1263 const SkBitmap &comparisonBitmap, | 1346 const SkBitmap &comparisonBitmap, |
| 1264 const SkTDArray<SkScalar> &tileGridReplaySca les) { | 1347 const SkTDArray<SkScalar> &tileGridReplaySca les) { |
| 1265 ErrorCombination errorsForAllModes; | 1348 ErrorCombination errorsForAllModes; |
| 1266 uint32_t gmFlags = gm->getFlags(); | 1349 uint32_t gmFlags = gm->getFlags(); |
| 1267 | 1350 |
| 1268 // run the picture centric GM steps | 1351 // TODO(epoger): We should start recording any per-GM skipped |
| 1352 // modes (i.e. those we skipped due to gmFlags) with a new | |
| 1353 // ErrorType, perhaps named kIntentionallySkipped_ErrorType. | |
| 1269 if (!(gmFlags & GM::kSkipPicture_Flag)) { | 1354 if (!(gmFlags & GM::kSkipPicture_Flag)) { |
| 1270 | 1355 |
| 1271 ErrorCombination pictErrors; | 1356 ErrorCombination pictErrors; |
| 1272 | 1357 |
| 1273 //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); | 1358 //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); |
| 1274 SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); | 1359 SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); |
| 1275 SkAutoUnref aur(pict); | 1360 SkAutoUnref aur(pict); |
| 1276 | 1361 |
| 1277 if (FLAGS_replay) { | 1362 if (FLAGS_replay) { |
| 1278 SkBitmap bitmap; | 1363 SkBitmap bitmap; |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1352 if ((pipeErrors.isEmpty()) && | 1437 if ((pipeErrors.isEmpty()) && |
| 1353 FLAGS_tiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { | 1438 FLAGS_tiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { |
| 1354 pipeErrors.add(gmmain.test_tiled_pipe_playback(gm, compareConfig, co mparisonBitmap)); | 1439 pipeErrors.add(gmmain.test_tiled_pipe_playback(gm, compareConfig, co mparisonBitmap)); |
| 1355 } | 1440 } |
| 1356 | 1441 |
| 1357 errorsForAllModes.add(pipeErrors); | 1442 errorsForAllModes.add(pipeErrors); |
| 1358 } | 1443 } |
| 1359 return errorsForAllModes; | 1444 return errorsForAllModes; |
| 1360 } | 1445 } |
| 1361 | 1446 |
| 1447 /** | |
| 1448 * Return a list of all entries in an array of strings as a single string | |
| 1449 * of this form: | |
| 1450 * "item1", "item2", "item3" | |
| 1451 */ | |
| 1452 SkString list_all(const SkTArray<SkString> &stringArray); | |
| 1453 SkString list_all(const SkTArray<SkString> &stringArray) { | |
| 1454 SkString total; | |
| 1455 for (int i = 0; i < stringArray.count(); i++) { | |
| 1456 if (i > 0) { | |
| 1457 total.append(", "); | |
| 1458 } | |
| 1459 total.append("\""); | |
| 1460 total.append(stringArray[i]); | |
| 1461 total.append("\""); | |
| 1462 } | |
| 1463 return total; | |
| 1464 } | |
| 1465 | |
| 1466 /** | |
| 1467 * Return a list of configuration names, as a single string of this form: | |
| 1468 * "item1", "item2", "item3" | |
| 1469 * | |
| 1470 * @param configs configurations, as a list of indices into gRec | |
| 1471 */ | |
| 1472 SkString list_all_config_names(const SkTDArray<size_t> &configs); | |
| 1473 SkString list_all_config_names(const SkTDArray<size_t> &configs) { | |
| 1474 SkString total; | |
| 1475 for (int i = 0; i < configs.count(); i++) { | |
| 1476 if (i > 0) { | |
| 1477 total.append(", "); | |
| 1478 } | |
| 1479 total.append("\""); | |
| 1480 total.append(gRec[configs[i]].fName); | |
| 1481 total.append("\""); | |
| 1482 } | |
| 1483 return total; | |
| 1484 } | |
| 1485 | |
| 1362 int tool_main(int argc, char** argv); | 1486 int tool_main(int argc, char** argv); |
| 1363 int tool_main(int argc, char** argv) { | 1487 int tool_main(int argc, char** argv) { |
| 1364 | 1488 |
| 1365 #if SK_ENABLE_INST_COUNT | 1489 #if SK_ENABLE_INST_COUNT |
| 1366 gPrintInstCount = true; | 1490 gPrintInstCount = true; |
| 1367 #endif | 1491 #endif |
| 1368 | 1492 |
| 1369 SkGraphics::Init(); | 1493 SkGraphics::Init(); |
| 1370 // we don't need to see this during a run | 1494 // we don't need to see this during a run |
| 1371 gSkSuppressFontCachePurgeSpew = true; | 1495 gSkSuppressFontCachePurgeSpew = true; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1533 gm_fprintf(stderr, "reading resources from %s\n", FLAGS_resourcePath[0]) ; | 1657 gm_fprintf(stderr, "reading resources from %s\n", FLAGS_resourcePath[0]) ; |
| 1534 } | 1658 } |
| 1535 | 1659 |
| 1536 if (moduloDivisor <= 0) { | 1660 if (moduloDivisor <= 0) { |
| 1537 moduloRemainder = -1; | 1661 moduloRemainder = -1; |
| 1538 } | 1662 } |
| 1539 if (moduloRemainder < 0 || moduloRemainder >= moduloDivisor) { | 1663 if (moduloRemainder < 0 || moduloRemainder >= moduloDivisor) { |
| 1540 moduloRemainder = -1; | 1664 moduloRemainder = -1; |
| 1541 } | 1665 } |
| 1542 | 1666 |
| 1543 // Accumulate success of all tests. | 1667 int gmsRun = 0; |
| 1544 int testsRun = 0; | |
| 1545 int testsPassed = 0; | |
| 1546 int testsFailed = 0; | |
| 1547 int testsMissingReferenceImages = 0; | |
| 1548 | |
| 1549 int gmIndex = -1; | 1668 int gmIndex = -1; |
| 1550 SkString moduloStr; | 1669 SkString moduloStr; |
| 1551 | 1670 |
| 1552 // If we will be writing out files, prepare subdirectories. | 1671 // If we will be writing out files, prepare subdirectories. |
| 1553 if (FLAGS_writePath.count() == 1) { | 1672 if (FLAGS_writePath.count() == 1) { |
| 1554 if (!sk_mkdir(FLAGS_writePath[0])) { | 1673 if (!sk_mkdir(FLAGS_writePath[0])) { |
| 1555 return -1; | 1674 return -1; |
| 1556 } | 1675 } |
| 1557 if (gmmain.fUseFileHierarchy) { | 1676 if (gmmain.fUseFileHierarchy) { |
| 1558 for (int i = 0; i < configs.count(); i++) { | 1677 for (int i = 0; i < configs.count(); i++) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1578 } | 1697 } |
| 1579 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor); | 1698 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor); |
| 1580 } | 1699 } |
| 1581 | 1700 |
| 1582 const char* shortName = gm->shortName(); | 1701 const char* shortName = gm->shortName(); |
| 1583 if (skip_name(FLAGS_match, shortName)) { | 1702 if (skip_name(FLAGS_match, shortName)) { |
| 1584 SkDELETE(gm); | 1703 SkDELETE(gm); |
| 1585 continue; | 1704 continue; |
| 1586 } | 1705 } |
| 1587 | 1706 |
| 1707 gmsRun++; | |
| 1588 SkISize size = gm->getISize(); | 1708 SkISize size = gm->getISize(); |
| 1589 gm_fprintf(stdout, "%sdrawing... %s [%d %d]\n", moduloStr.c_str(), short Name, | 1709 gm_fprintf(stdout, "%sdrawing... %s [%d %d]\n", moduloStr.c_str(), short Name, |
| 1590 size.width(), size.height()); | 1710 size.width(), size.height()); |
| 1591 | 1711 |
| 1592 ErrorCombination testErrors; | 1712 run_multiple_configs(gmmain, gm, configs, grFactory); |
| 1593 testErrors.add(run_multiple_configs(gmmain, gm, configs, grFactory)); | |
| 1594 | 1713 |
| 1595 SkBitmap comparisonBitmap; | 1714 SkBitmap comparisonBitmap; |
| 1596 const ConfigData compareConfig = | 1715 const ConfigData compareConfig = |
| 1597 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextT ype, 0, kRW_ConfigFlag, "comparison", false }; | 1716 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextT ype, 0, kRW_ConfigFlag, "comparison", false }; |
| 1598 testErrors.add(gmmain.generate_image( | 1717 gmmain.generate_image(gm, compareConfig, NULL, NULL, &comparisonBitmap, false); |
| 1599 gm, compareConfig, NULL, NULL, &comparisonBitmap, false)); | |
| 1600 | 1718 |
| 1601 // TODO(epoger): only run this if gmmain.generate_image() succeeded? | 1719 // TODO(epoger): only run this if gmmain.generate_image() succeeded? |
| 1602 // Otherwise, what are we comparing against? | 1720 // Otherwise, what are we comparing against? |
| 1603 testErrors.add(run_multiple_modes(gmmain, gm, compareConfig, comparisonB itmap, | 1721 run_multiple_modes(gmmain, gm, compareConfig, comparisonBitmap, tileGrid ReplayScales); |
| 1604 tileGridReplayScales)); | |
| 1605 | |
| 1606 // Update overall results. | |
| 1607 // We only tabulate the particular error types that we currently | |
| 1608 // care about (e.g., missing reference images). Later on, if we | |
| 1609 // want to also tabulate other error types, we can do so. | |
| 1610 testsRun++; | |
| 1611 if (!gmmain.fExpectationsSource.get() || | |
| 1612 (testErrors.includes(kMissingExpectations_ErrorType))) { | |
| 1613 testsMissingReferenceImages++; | |
| 1614 } | |
| 1615 if (testErrors.minus(gmmain.fIgnorableErrorCombination).isEmpty()) { | |
| 1616 testsPassed++; | |
| 1617 } else { | |
| 1618 testsFailed++; | |
| 1619 } | |
| 1620 | 1722 |
| 1621 SkDELETE(gm); | 1723 SkDELETE(gm); |
| 1622 } | 1724 } |
| 1623 gm_fprintf(stdout, "Ran %d tests: %d passed, %d failed, %d missing reference images\n", | 1725 |
| 1624 testsRun, testsPassed, testsFailed, testsMissingReferenceImages); | 1726 SkTArray<SkString> modes; |
| 1727 gmmain.GetRenderModesEncountered(modes); | |
| 1728 | |
| 1729 // Output summary to stdout. | |
| 1730 gm_fprintf(stdout, "Ran %d GMs\n", gmsRun); | |
| 1731 gm_fprintf(stdout, "... over %2d configs [%s]\n", configs.count(), | |
| 1732 list_all_config_names(configs).c_str()); | |
| 1733 gm_fprintf(stdout, "... and %2d modes [%s]\n", modes.count(), list_all(mode s).c_str()); | |
| 1734 gm_fprintf(stdout, "... so there should be a total of %d tests.\n", | |
| 1735 gmsRun * (configs.count() + modes.count())); | |
| 1736 | |
| 1737 // TODO(epoger): Ultimately, we should signal an error if the | |
| 1738 // expected total number of tests (displayed above) does not match | |
| 1739 // gmmain.fTestsRun. But for now, there are cases where those | |
| 1740 // numbers won't match: specifically, if some configs/modes are | |
| 1741 // skipped on a per-GM basis (due to gm->getFlags() for a specific | |
| 1742 // GM). Later on, we should record tests like that using some new | |
| 1743 // ErrorType, like kIntentionallySkipped_ErrorType. Then we could | |
| 1744 // signal an error if the totals didn't match up. | |
| 1625 gmmain.ListErrors(); | 1745 gmmain.ListErrors(); |
| 1626 | 1746 |
| 1627 if (FLAGS_writeJsonSummaryPath.count() == 1) { | 1747 if (FLAGS_writeJsonSummaryPath.count() == 1) { |
| 1628 Json::Value actualResults; | 1748 Json::Value actualResults; |
| 1629 actualResults[kJsonKey_ActualResults_Failed] = | 1749 actualResults[kJsonKey_ActualResults_Failed] = |
| 1630 gmmain.fJsonActualResults_Failed; | 1750 gmmain.fJsonActualResults_Failed; |
| 1631 actualResults[kJsonKey_ActualResults_FailureIgnored] = | 1751 actualResults[kJsonKey_ActualResults_FailureIgnored] = |
| 1632 gmmain.fJsonActualResults_FailureIgnored; | 1752 gmmain.fJsonActualResults_FailureIgnored; |
| 1633 actualResults[kJsonKey_ActualResults_NoComparison] = | 1753 actualResults[kJsonKey_ActualResults_NoComparison] = |
| 1634 gmmain.fJsonActualResults_NoComparison; | 1754 gmmain.fJsonActualResults_NoComparison; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 1654 gm_fprintf(stdout, "config: %s %x\n", config.fName, gr); | 1774 gm_fprintf(stdout, "config: %s %x\n", config.fName, gr); |
| 1655 gr->printCacheStats(); | 1775 gr->printCacheStats(); |
| 1656 } | 1776 } |
| 1657 } | 1777 } |
| 1658 #endif | 1778 #endif |
| 1659 | 1779 |
| 1660 delete grFactory; | 1780 delete grFactory; |
| 1661 #endif | 1781 #endif |
| 1662 SkGraphics::Term(); | 1782 SkGraphics::Term(); |
| 1663 | 1783 |
| 1664 return (0 == testsFailed) ? 0 : -1; | 1784 return (0 == gmmain.NumSignificantErrors()) ? 0 : -1; |
| 1665 } | 1785 } |
| 1666 | 1786 |
| 1667 void GMMain::installFilter(SkCanvas* canvas) { | 1787 void GMMain::installFilter(SkCanvas* canvas) { |
| 1668 if (FLAGS_forceBWtext) { | 1788 if (FLAGS_forceBWtext) { |
| 1669 canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref(); | 1789 canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref(); |
| 1670 } | 1790 } |
| 1671 } | 1791 } |
| 1672 | 1792 |
| 1673 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 1793 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
| 1674 int main(int argc, char * const argv[]) { | 1794 int main(int argc, char * const argv[]) { |
| 1675 return tool_main(argc, (char**) argv); | 1795 return tool_main(argc, (char**) argv); |
| 1676 } | 1796 } |
| 1677 #endif | 1797 #endif |
| OLD | NEW |