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" | |
38 #include "SkTileGridPicture.h" | 37 #include "SkTileGridPicture.h" |
39 #include "SamplePipeControllers.h" | 38 #include "SamplePipeControllers.h" |
40 | 39 |
41 #ifdef SK_BUILD_FOR_WIN | 40 #ifdef SK_BUILD_FOR_WIN |
42 // json includes xlocale which generates warning 4530 because we're compilin
g without | 41 // json includes xlocale which generates warning 4530 because we're compilin
g without |
43 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 | 42 // exceptions; see https://code.google.com/p/skia/issues/detail?id=1067 |
44 #pragma warning(push) | 43 #pragma warning(push) |
45 #pragma warning(disable : 4530) | 44 #pragma warning(disable : 4530) |
46 #endif | 45 #endif |
47 #include "json/value.h" | 46 #include "json/value.h" |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 | 78 |
80 #ifdef SK_BUILD_FOR_MAC | 79 #ifdef SK_BUILD_FOR_MAC |
81 #include "SkCGUtils.h" | 80 #include "SkCGUtils.h" |
82 #define CAN_IMAGE_PDF 1 | 81 #define CAN_IMAGE_PDF 1 |
83 #else | 82 #else |
84 #define CAN_IMAGE_PDF 0 | 83 #define CAN_IMAGE_PDF 0 |
85 #endif | 84 #endif |
86 | 85 |
87 using namespace skiagm; | 86 using namespace skiagm; |
88 | 87 |
| 88 struct FailRec { |
| 89 SkString fName; |
| 90 bool fIsPixelError; |
| 91 |
| 92 FailRec() : fIsPixelError(false) {} |
| 93 FailRec(const SkString& name) : fName(name), fIsPixelError(false) {} |
| 94 }; |
| 95 |
89 class Iter { | 96 class Iter { |
90 public: | 97 public: |
91 Iter() { | 98 Iter() { |
92 this->reset(); | 99 this->reset(); |
93 } | 100 } |
94 | 101 |
95 void reset() { | 102 void reset() { |
96 fReg = GMRegistry::Head(); | 103 fReg = GMRegistry::Head(); |
97 } | 104 } |
98 | 105 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
169 | 176 |
170 static PipeFlagComboData gPipeWritingFlagCombos[] = { | 177 static PipeFlagComboData gPipeWritingFlagCombos[] = { |
171 { "", 0 }, | 178 { "", 0 }, |
172 { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, | 179 { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, |
173 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag | 180 { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag |
174 | SkGPipeWriter::kSharedAddressSpace_Flag } | 181 | SkGPipeWriter::kSharedAddressSpace_Flag } |
175 }; | 182 }; |
176 | 183 |
177 class GMMain { | 184 class GMMain { |
178 public: | 185 public: |
179 GMMain() : fUseFileHierarchy(false), fMismatchPath(NULL), fTestsRun(0), | 186 GMMain() { |
180 fRenderModesEncountered(1) { | 187 // Set default values of member variables, which tool_main() |
| 188 // may override. |
| 189 fUseFileHierarchy = false; |
181 fIgnorableErrorCombination.add(kMissingExpectations_ErrorType); | 190 fIgnorableErrorCombination.add(kMissingExpectations_ErrorType); |
| 191 fMismatchPath = NULL; |
182 } | 192 } |
183 | 193 |
184 SkString make_name(const char shortName[], const char configName[]) { | 194 SkString make_name(const char shortName[], const char configName[]) { |
185 SkString name; | 195 SkString name; |
186 if (0 == strlen(configName)) { | 196 if (0 == strlen(configName)) { |
187 name.append(shortName); | 197 name.append(shortName); |
188 } else if (fUseFileHierarchy) { | 198 } else if (fUseFileHierarchy) { |
189 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName); | 199 name.appendf("%s%c%s", configName, SkPATH_SEPARATOR, shortName); |
190 } else { | 200 } else { |
191 name.appendf("%s_%s", shortName, configName); | 201 name.appendf("%s_%s", shortName, configName); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 // TODO(epoger): Now that we have removed force_all_opaque() | 235 // TODO(epoger): Now that we have removed force_all_opaque() |
226 // from this method, we should be able to get rid of the | 236 // from this method, we should be able to get rid of the |
227 // transformation to 8888 format also. | 237 // transformation to 8888 format also. |
228 SkBitmap copy; | 238 SkBitmap copy; |
229 bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); | 239 bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); |
230 return SkImageEncoder::EncodeFile(path.c_str(), copy, | 240 return SkImageEncoder::EncodeFile(path.c_str(), copy, |
231 SkImageEncoder::kPNG_Type, 100); | 241 SkImageEncoder::kPNG_Type, 100); |
232 } | 242 } |
233 | 243 |
234 /** | 244 /** |
235 * Add all render modes encountered thus far to the "modes" array. | 245 * Records the errors encountered in fFailedTests, except for any error |
| 246 * types we want to ignore. |
236 */ | 247 */ |
237 void GetRenderModesEncountered(SkTArray<SkString> &modes) { | 248 void RecordError(const ErrorCombination& errorCombination, const SkString& n
ame, |
238 SkTDict<int>::Iter iter(this->fRenderModesEncountered); | 249 const char renderModeDescriptor []) { |
239 const char* mode; | 250 // The common case: no error means nothing to record. |
240 while ((mode = iter.next(NULL)) != NULL) { | 251 if (errorCombination.isEmpty()) { |
241 SkString modeAsString = SkString(mode); | 252 return; |
242 // TODO(epoger): It seems a bit silly that all of these modes were | 253 } |
243 // recorded with a leading "-" which we have to remove here | 254 |
244 // (except for mode "", which means plain old original mode). | 255 // If only certain error type(s) were reported, we know we can ignore th
em. |
245 // But that's how renderModeDescriptor has been passed into | 256 if (errorCombination.minus(fIgnorableErrorCombination).isEmpty()) { |
246 // compare_test_results_to_reference_bitmap() historically, | 257 return; |
247 // and changing that now may affect other parts of our code. | 258 } |
248 if (modeAsString.startsWith("-")) { | 259 |
249 modeAsString.remove(0, 1); | 260 FailRec& rec = fFailedTests.push_back(make_name(name.c_str(), renderMode
Descriptor)); |
250 modes.push_back(modeAsString); | 261 rec.fIsPixelError = errorCombination.includes(kImageMismatch_ErrorType); |
| 262 } |
| 263 |
| 264 // List contents of fFailedTests via SkDebug. |
| 265 void ListErrors() { |
| 266 for (int i = 0; i < fFailedTests.count(); ++i) { |
| 267 if (fFailedTests[i].fIsPixelError) { |
| 268 gm_fprintf(stderr, "\t\t%s pixel_error\n", fFailedTests[i].fName
.c_str()); |
| 269 } else { |
| 270 gm_fprintf(stderr, "\t\t%s\n", fFailedTests[i].fName.c_str()); |
251 } | 271 } |
252 } | 272 } |
253 } | 273 } |
254 | 274 |
255 /** | |
256 * Records the results of this test in fTestsRun and fFailedTests. | |
257 * | |
258 * We even record successes, and errors that we regard as | |
259 * "ignorable"; we can filter them out later. | |
260 */ | |
261 void RecordTestResults(const ErrorCombination& errorCombination, const SkStr
ing& name, | |
262 const char renderModeDescriptor []) { | |
263 // Things to do regardless of errorCombination. | |
264 fTestsRun++; | |
265 int renderModeCount = 0; | |
266 this->fRenderModesEncountered.find(renderModeDescriptor, &renderModeCoun
t); | |
267 renderModeCount++; | |
268 this->fRenderModesEncountered.set(renderModeDescriptor, renderModeCount)
; | |
269 | |
270 if (errorCombination.isEmpty()) { | |
271 return; | |
272 } | |
273 | |
274 // Things to do only if there is some error condition. | |
275 SkString fullName = make_name(name.c_str(), renderModeDescriptor); | |
276 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
277 ErrorType type = static_cast<ErrorType>(typeInt); | |
278 if (errorCombination.includes(type)) { | |
279 fFailedTests[type].push_back(fullName); | |
280 } | |
281 } | |
282 } | |
283 | |
284 /** | |
285 * Return the number of significant (non-ignorable) errors we have | |
286 * encountered so far. | |
287 */ | |
288 int NumSignificantErrors() { | |
289 int significantErrors = 0; | |
290 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
291 ErrorType type = static_cast<ErrorType>(typeInt); | |
292 if (!fIgnorableErrorCombination.includes(type)) { | |
293 significantErrors += fFailedTests[type].count(); | |
294 } | |
295 } | |
296 return significantErrors; | |
297 } | |
298 | |
299 /** | |
300 * List contents of fFailedTests to stdout. | |
301 */ | |
302 void ListErrors() { | |
303 // First, print a single summary line. | |
304 SkString summary; | |
305 summary.appendf("Ran %d tests:", fTestsRun); | |
306 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
307 ErrorType type = static_cast<ErrorType>(typeInt); | |
308 summary.appendf(" %s=%d", getErrorTypeName(type), fFailedTests[type]
.count()); | |
309 } | |
310 gm_fprintf(stdout, "%s\n", summary.c_str()); | |
311 | |
312 // Now, for each failure type, list the tests that failed that way. | |
313 for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) { | |
314 SkString line; | |
315 ErrorType type = static_cast<ErrorType>(typeInt); | |
316 if (fIgnorableErrorCombination.includes(type)) { | |
317 line.append("[ ] "); | |
318 } else { | |
319 line.append("[*] "); | |
320 } | |
321 | |
322 SkTArray<SkString> *failedTestsOfThisType = &fFailedTests[type]; | |
323 int count = failedTestsOfThisType->count(); | |
324 line.appendf("%d %s:", count, getErrorTypeName(type)); | |
325 for (int i = 0; i < count; ++i) { | |
326 line.append(" "); | |
327 line.append((*failedTestsOfThisType)[i]); | |
328 } | |
329 gm_fprintf(stdout, "%s\n", line.c_str()); | |
330 } | |
331 gm_fprintf(stdout, "(results marked with [*] will cause nonzero return v
alue)\n"); | |
332 } | |
333 | |
334 static bool write_document(const SkString& path, | 275 static bool write_document(const SkString& path, |
335 const SkDynamicMemoryWStream& document) { | 276 const SkDynamicMemoryWStream& document) { |
336 SkFILEWStream stream(path.c_str()); | 277 SkFILEWStream stream(path.c_str()); |
337 SkAutoDataUnref data(document.copyToData()); | 278 SkAutoDataUnref data(document.copyToData()); |
338 return stream.writeData(data.get()); | 279 return stream.writeData(data.get()); |
339 } | 280 } |
340 | 281 |
341 /** | 282 /** |
342 * Prepare an SkBitmap to render a GM into. | 283 * Prepare an SkBitmap to render a GM into. |
343 * | 284 * |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 if (kXPS_Backend == gRec.fBackend) { | 535 if (kXPS_Backend == gRec.fBackend) { |
595 path = make_filename(writePath, renderModeDescriptor, name.c_str(), | 536 path = make_filename(writePath, renderModeDescriptor, name.c_str(), |
596 "xps"); | 537 "xps"); |
597 success = write_document(path, *document); | 538 success = write_document(path, *document); |
598 } | 539 } |
599 if (success) { | 540 if (success) { |
600 return kEmpty_ErrorCombination; | 541 return kEmpty_ErrorCombination; |
601 } else { | 542 } else { |
602 gm_fprintf(stderr, "FAILED to write %s\n", path.c_str()); | 543 gm_fprintf(stderr, "FAILED to write %s\n", path.c_str()); |
603 ErrorCombination errors(kWritingReferenceImage_ErrorType); | 544 ErrorCombination errors(kWritingReferenceImage_ErrorType); |
604 // TODO(epoger): Don't call RecordTestResults() here... | 545 RecordError(errors, name, renderModeDescriptor); |
605 // Instead, we should make sure to call RecordTestResults | |
606 // exactly ONCE per test. (Otherwise, gmmain.fTestsRun | |
607 // will be incremented twice for this test: once in | |
608 // compare_test_results_to_stored_expectations() before | |
609 // that method calls this one, and again here.) | |
610 // | |
611 // When we make that change, we should probably add a | |
612 // WritingReferenceImage test to the gm self-tests.) | |
613 RecordTestResults(errors, name, renderModeDescriptor); | |
614 return errors; | 546 return errors; |
615 } | 547 } |
616 } | 548 } |
617 | 549 |
618 /** | 550 /** |
619 * Log more detail about the mistmatch between expectedBitmap and | 551 * Log more detail about the mistmatch between expectedBitmap and |
620 * actualBitmap. | 552 * actualBitmap. |
621 */ | 553 */ |
622 void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& act
ualBitmap, | 554 void report_bitmap_diffs(const SkBitmap& expectedBitmap, const SkBitmap& act
ualBitmap, |
623 const char *testName) { | 555 const char *testName) { |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
715 write_bitmap(path, actualBitmap); | 647 write_bitmap(path, actualBitmap); |
716 } | 648 } |
717 | 649 |
718 // If we have access to a single expected bitmap, log more | 650 // If we have access to a single expected bitmap, log more |
719 // detail about the mismatch. | 651 // detail about the mismatch. |
720 const SkBitmap *expectedBitmapPtr = expectations.asBitmap(); | 652 const SkBitmap *expectedBitmapPtr = expectations.asBitmap(); |
721 if (NULL != expectedBitmapPtr) { | 653 if (NULL != expectedBitmapPtr) { |
722 report_bitmap_diffs(*expectedBitmapPtr, actualBitmap, completeNa
me); | 654 report_bitmap_diffs(*expectedBitmapPtr, actualBitmap, completeNa
me); |
723 } | 655 } |
724 } | 656 } |
725 RecordTestResults(errors, baseNameString, renderModeDescriptor); | 657 RecordError(errors, baseNameString, renderModeDescriptor); |
726 | 658 |
727 if (addToJsonSummary) { | 659 if (addToJsonSummary) { |
728 add_actual_results_to_json_summary(completeName, actualChecksum, err
ors, | 660 add_actual_results_to_json_summary(completeName, actualChecksum, err
ors, |
729 expectations.ignoreFailure()); | 661 expectations.ignoreFailure()); |
730 add_expected_results_to_json_summary(completeName, expectations); | 662 add_expected_results_to_json_summary(completeName, expectations); |
731 } | 663 } |
732 | 664 |
733 return errors; | 665 return errors; |
734 } | 666 } |
735 | 667 |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
831 errors.add(compare_to_expectations(expectations, actualBitmap, | 763 errors.add(compare_to_expectations(expectations, actualBitmap, |
832 name, "", true)); | 764 name, "", true)); |
833 } else { | 765 } else { |
834 // If we are running without expectations, we still want to | 766 // If we are running without expectations, we still want to |
835 // record the actual results. | 767 // record the actual results. |
836 Checksum actualChecksum = | 768 Checksum actualChecksum = |
837 SkBitmapChecksummer::Compute64(actualBitmap); | 769 SkBitmapChecksummer::Compute64(actualBitmap); |
838 add_actual_results_to_json_summary(name.c_str(), actualChecksum, | 770 add_actual_results_to_json_summary(name.c_str(), actualChecksum, |
839 ErrorCombination(kMissingExpectat
ions_ErrorType), | 771 ErrorCombination(kMissingExpectat
ions_ErrorType), |
840 false); | 772 false); |
841 RecordTestResults(ErrorCombination(kMissingExpectations_ErrorType),
name, ""); | |
842 } | 773 } |
843 | 774 |
844 // TODO: Consider moving this into compare_to_expectations(), | 775 // TODO: Consider moving this into compare_to_expectations(), |
845 // similar to fMismatchPath... for now, we don't do that, because | 776 // similar to fMismatchPath... for now, we don't do that, because |
846 // we don't want to write out the actual bitmaps for all | 777 // we don't want to write out the actual bitmaps for all |
847 // renderModes of all tests! That would be a lot of files. | 778 // renderModes of all tests! That would be a lot of files. |
848 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { | 779 if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { |
849 errors.add(write_reference_image(gRec, writePath, "", | 780 errors.add(write_reference_image(gRec, writePath, "", |
850 name, actualBitmap, pdf)); | 781 name, actualBitmap, pdf)); |
851 } | 782 } |
852 | 783 |
853 return errors; | 784 return errors; |
854 } | 785 } |
855 | 786 |
856 /** | 787 /** |
857 * Compare actualBitmap to referenceBitmap. | 788 * Compare actualBitmap to referenceBitmap. |
858 * | 789 * |
859 * @param gm which test generated the bitmap | 790 * @param gm which test generated the bitmap |
860 * @param gRec | 791 * @param gRec |
861 * @param renderModeDescriptor | 792 * @param renderModeDescriptor |
862 * @param actualBitmap actual bitmap generated by this run | 793 * @param actualBitmap actual bitmap generated by this run |
863 * @param referenceBitmap bitmap we expected to be generated | 794 * @param referenceBitmap bitmap we expected to be generated |
864 */ | 795 */ |
865 ErrorCombination compare_test_results_to_reference_bitmap( | 796 ErrorCombination compare_test_results_to_reference_bitmap( |
866 GM* gm, const ConfigData& gRec, const char renderModeDescriptor [], | 797 GM* gm, const ConfigData& gRec, const char renderModeDescriptor [], |
867 SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) { | 798 SkBitmap& actualBitmap, const SkBitmap* referenceBitmap) { |
868 | 799 |
869 // TODO(epoger): This method is run to compare results across | |
870 // different rendering modes (as opposed to | |
871 // compare_test_results_to_stored_expectations(), which | |
872 // compares results against expectations stored on disk). If | |
873 // we would like the GenerateGMs step to distinguish between | |
874 // those two types of mismatches, we should report image | |
875 // mismatches in here with a different ErrorType. | |
876 SkASSERT(referenceBitmap); | 800 SkASSERT(referenceBitmap); |
877 SkString name = make_name(gm->shortName(), gRec.fName); | 801 SkString name = make_name(gm->shortName(), gRec.fName); |
878 Expectations expectations(*referenceBitmap); | 802 Expectations expectations(*referenceBitmap); |
879 return compare_to_expectations(expectations, actualBitmap, | 803 return compare_to_expectations(expectations, actualBitmap, |
880 name, renderModeDescriptor); | 804 name, renderModeDescriptor); |
881 } | 805 } |
882 | 806 |
883 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t rec
ordFlags, | 807 static SkPicture* generate_new_picture(GM* gm, BbhType bbhType, uint32_t rec
ordFlags, |
884 SkScalar scale = SK_Scalar1) { | 808 SkScalar scale = SK_Scalar1) { |
885 // Pictures are refcounted so must be on heap | 809 // Pictures are refcounted so must be on heap |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
979 // -deferred image, we exit early! We should fix this | 903 // -deferred image, we exit early! We should fix this |
980 // ASAP, because it is hiding -deferred errors... but for | 904 // ASAP, because it is hiding -deferred errors... but for |
981 // now, I'm leaving the logic as it is so that the | 905 // now, I'm leaving the logic as it is so that the |
982 // refactoring change | 906 // refactoring change |
983 // https://codereview.chromium.org/12992003/ is unblocked. | 907 // https://codereview.chromium.org/12992003/ is unblocked. |
984 // | 908 // |
985 // Filed as https://code.google.com/p/skia/issues/detail?id=1180 | 909 // Filed as https://code.google.com/p/skia/issues/detail?id=1180 |
986 // ('image-surface gm test is failing in "deferred" mode, | 910 // ('image-surface gm test is failing in "deferred" mode, |
987 // and gm is not reporting the failure') | 911 // and gm is not reporting the failure') |
988 if (errors.isEmpty()) { | 912 if (errors.isEmpty()) { |
989 // TODO(epoger): Report this as a new ErrorType, | |
990 // something like kImageGeneration_ErrorType? | |
991 return kEmpty_ErrorCombination; | 913 return kEmpty_ErrorCombination; |
992 } | 914 } |
993 return compare_test_results_to_reference_bitmap( | 915 return compare_test_results_to_reference_bitmap( |
994 gm, gRec, "-deferred", bitmap, &referenceBitmap); | 916 gm, gRec, "-deferred", bitmap, &referenceBitmap); |
995 } | 917 } |
996 return kEmpty_ErrorCombination; | 918 return kEmpty_ErrorCombination; |
997 } | 919 } |
998 | 920 |
999 ErrorCombination test_pipe_playback(GM* gm, | 921 ErrorCombination test_pipe_playback(GM* gm, |
1000 const ConfigData& gRec, | 922 const ConfigData& gRec, |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1054 // | 976 // |
1055 // member variables. | 977 // member variables. |
1056 // They are public for now, to allow easier setting by tool_main(). | 978 // They are public for now, to allow easier setting by tool_main(). |
1057 // | 979 // |
1058 | 980 |
1059 bool fUseFileHierarchy; | 981 bool fUseFileHierarchy; |
1060 ErrorCombination fIgnorableErrorCombination; | 982 ErrorCombination fIgnorableErrorCombination; |
1061 | 983 |
1062 const char* fMismatchPath; | 984 const char* fMismatchPath; |
1063 | 985 |
1064 // collection of tests that have failed with each ErrorType | 986 // information about all failed tests we have encountered so far |
1065 SkTArray<SkString> fFailedTests[kLast_ErrorType+1]; | 987 SkTArray<FailRec> fFailedTests; |
1066 int fTestsRun; | |
1067 SkTDict<int> fRenderModesEncountered; | |
1068 | 988 |
1069 // Where to read expectations (expected image checksums, etc.) from. | 989 // Where to read expectations (expected image checksums, etc.) from. |
1070 // If unset, we don't do comparisons. | 990 // If unset, we don't do comparisons. |
1071 SkAutoTUnref<ExpectationsSource> fExpectationsSource; | 991 SkAutoTUnref<ExpectationsSource> fExpectationsSource; |
1072 | 992 |
1073 // JSON summaries that we generate as we go (just for output). | 993 // JSON summaries that we generate as we go (just for output). |
1074 Json::Value fJsonExpectedResults; | 994 Json::Value fJsonExpectedResults; |
1075 Json::Value fJsonActualResults_Failed; | 995 Json::Value fJsonActualResults_Failed; |
1076 Json::Value fJsonActualResults_FailureIgnored; | 996 Json::Value fJsonActualResults_FailureIgnored; |
1077 Json::Value fJsonActualResults_NoComparison; | 997 Json::Value fJsonActualResults_NoComparison; |
(...skipping 287 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1365 */ | 1285 */ |
1366 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
mpareConfig, | 1286 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
mpareConfig, |
1367 const SkBitmap &comparisonBitmap, | 1287 const SkBitmap &comparisonBitmap, |
1368 const SkTDArray<SkScalar> &tileGridReplaySca
les); | 1288 const SkTDArray<SkScalar> &tileGridReplaySca
les); |
1369 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
mpareConfig, | 1289 ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
mpareConfig, |
1370 const SkBitmap &comparisonBitmap, | 1290 const SkBitmap &comparisonBitmap, |
1371 const SkTDArray<SkScalar> &tileGridReplaySca
les) { | 1291 const SkTDArray<SkScalar> &tileGridReplaySca
les) { |
1372 ErrorCombination errorsForAllModes; | 1292 ErrorCombination errorsForAllModes; |
1373 uint32_t gmFlags = gm->getFlags(); | 1293 uint32_t gmFlags = gm->getFlags(); |
1374 | 1294 |
1375 // TODO(epoger): We should start recording any per-GM skipped | 1295 // run the picture centric GM steps |
1376 // modes (i.e. those we skipped due to gmFlags) with a new | |
1377 // ErrorType, perhaps named kIntentionallySkipped_ErrorType. | |
1378 if (!(gmFlags & GM::kSkipPicture_Flag)) { | 1296 if (!(gmFlags & GM::kSkipPicture_Flag)) { |
1379 | 1297 |
1380 ErrorCombination pictErrors; | 1298 ErrorCombination pictErrors; |
1381 | 1299 |
1382 //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); | 1300 //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); |
1383 SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); | 1301 SkPicture* pict = gmmain.generate_new_picture(gm, kNone_BbhType, 0); |
1384 SkAutoUnref aur(pict); | 1302 SkAutoUnref aur(pict); |
1385 | 1303 |
1386 if (FLAGS_replay) { | 1304 if (FLAGS_replay) { |
1387 SkBitmap bitmap; | 1305 SkBitmap bitmap; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1465 if ((pipeErrors.isEmpty()) && | 1383 if ((pipeErrors.isEmpty()) && |
1466 FLAGS_tiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { | 1384 FLAGS_tiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { |
1467 pipeErrors.add(gmmain.test_tiled_pipe_playback(gm, compareConfig, co
mparisonBitmap)); | 1385 pipeErrors.add(gmmain.test_tiled_pipe_playback(gm, compareConfig, co
mparisonBitmap)); |
1468 } | 1386 } |
1469 | 1387 |
1470 errorsForAllModes.add(pipeErrors); | 1388 errorsForAllModes.add(pipeErrors); |
1471 } | 1389 } |
1472 return errorsForAllModes; | 1390 return errorsForAllModes; |
1473 } | 1391 } |
1474 | 1392 |
1475 /** | |
1476 * Return a list of all entries in an array of strings as a single string | |
1477 * of this form: | |
1478 * "item1", "item2", "item3" | |
1479 */ | |
1480 SkString list_all(const SkTArray<SkString> &stringArray); | |
1481 SkString list_all(const SkTArray<SkString> &stringArray) { | |
1482 SkString total; | |
1483 for (int i = 0; i < stringArray.count(); i++) { | |
1484 if (i > 0) { | |
1485 total.append(", "); | |
1486 } | |
1487 total.append("\""); | |
1488 total.append(stringArray[i]); | |
1489 total.append("\""); | |
1490 } | |
1491 return total; | |
1492 } | |
1493 | |
1494 /** | |
1495 * Return a list of configuration names, as a single string of this form: | |
1496 * "item1", "item2", "item3" | |
1497 * | |
1498 * @param configs configurations, as a list of indices into gRec | |
1499 */ | |
1500 SkString list_all_config_names(const SkTDArray<size_t> &configs); | |
1501 SkString list_all_config_names(const SkTDArray<size_t> &configs) { | |
1502 SkString total; | |
1503 for (int i = 0; i < configs.count(); i++) { | |
1504 if (i > 0) { | |
1505 total.append(", "); | |
1506 } | |
1507 total.append("\""); | |
1508 total.append(gRec[configs[i]].fName); | |
1509 total.append("\""); | |
1510 } | |
1511 return total; | |
1512 } | |
1513 | |
1514 int tool_main(int argc, char** argv); | 1393 int tool_main(int argc, char** argv); |
1515 int tool_main(int argc, char** argv) { | 1394 int tool_main(int argc, char** argv) { |
1516 | 1395 |
1517 #if SK_ENABLE_INST_COUNT | 1396 #if SK_ENABLE_INST_COUNT |
1518 gPrintInstCount = true; | 1397 gPrintInstCount = true; |
1519 #endif | 1398 #endif |
1520 | 1399 |
1521 SkGraphics::Init(); | 1400 SkGraphics::Init(); |
1522 // we don't need to see this during a run | 1401 // we don't need to see this during a run |
1523 gSkSuppressFontCachePurgeSpew = true; | 1402 gSkSuppressFontCachePurgeSpew = true; |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1685 gm_fprintf(stderr, "reading resources from %s\n", FLAGS_resourcePath[0])
; | 1564 gm_fprintf(stderr, "reading resources from %s\n", FLAGS_resourcePath[0])
; |
1686 } | 1565 } |
1687 | 1566 |
1688 if (moduloDivisor <= 0) { | 1567 if (moduloDivisor <= 0) { |
1689 moduloRemainder = -1; | 1568 moduloRemainder = -1; |
1690 } | 1569 } |
1691 if (moduloRemainder < 0 || moduloRemainder >= moduloDivisor) { | 1570 if (moduloRemainder < 0 || moduloRemainder >= moduloDivisor) { |
1692 moduloRemainder = -1; | 1571 moduloRemainder = -1; |
1693 } | 1572 } |
1694 | 1573 |
1695 int gmsRun = 0; | 1574 // Accumulate success of all tests. |
| 1575 int testsRun = 0; |
| 1576 int testsPassed = 0; |
| 1577 int testsFailed = 0; |
| 1578 int testsMissingReferenceImages = 0; |
| 1579 |
1696 int gmIndex = -1; | 1580 int gmIndex = -1; |
1697 SkString moduloStr; | 1581 SkString moduloStr; |
1698 | 1582 |
1699 // If we will be writing out files, prepare subdirectories. | 1583 // If we will be writing out files, prepare subdirectories. |
1700 if (FLAGS_writePath.count() == 1) { | 1584 if (FLAGS_writePath.count() == 1) { |
1701 if (!sk_mkdir(FLAGS_writePath[0])) { | 1585 if (!sk_mkdir(FLAGS_writePath[0])) { |
1702 return -1; | 1586 return -1; |
1703 } | 1587 } |
1704 if (gmmain.fUseFileHierarchy) { | 1588 if (gmmain.fUseFileHierarchy) { |
1705 for (int i = 0; i < configs.count(); i++) { | 1589 for (int i = 0; i < configs.count(); i++) { |
(...skipping 19 matching lines...) Expand all Loading... |
1725 } | 1609 } |
1726 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor); | 1610 moduloStr.printf("[%d.%d] ", gmIndex, moduloDivisor); |
1727 } | 1611 } |
1728 | 1612 |
1729 const char* shortName = gm->shortName(); | 1613 const char* shortName = gm->shortName(); |
1730 if (skip_name(FLAGS_match, shortName)) { | 1614 if (skip_name(FLAGS_match, shortName)) { |
1731 SkDELETE(gm); | 1615 SkDELETE(gm); |
1732 continue; | 1616 continue; |
1733 } | 1617 } |
1734 | 1618 |
1735 gmsRun++; | |
1736 SkISize size = gm->getISize(); | 1619 SkISize size = gm->getISize(); |
1737 gm_fprintf(stdout, "%sdrawing... %s [%d %d]\n", moduloStr.c_str(), short
Name, | 1620 gm_fprintf(stdout, "%sdrawing... %s [%d %d]\n", moduloStr.c_str(), short
Name, |
1738 size.width(), size.height()); | 1621 size.width(), size.height()); |
1739 | 1622 |
1740 run_multiple_configs(gmmain, gm, configs, grFactory); | 1623 ErrorCombination testErrors; |
| 1624 testErrors.add(run_multiple_configs(gmmain, gm, configs, grFactory)); |
1741 | 1625 |
1742 SkBitmap comparisonBitmap; | 1626 SkBitmap comparisonBitmap; |
1743 const ConfigData compareConfig = | 1627 const ConfigData compareConfig = |
1744 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextT
ype, 0, kRW_ConfigFlag, "comparison", false }; | 1628 { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextT
ype, 0, kRW_ConfigFlag, "comparison", false }; |
1745 gmmain.generate_image(gm, compareConfig, NULL, &comparisonBitmap, false)
; | 1629 testErrors.add(gmmain.generate_image(gm, compareConfig, NULL, &compariso
nBitmap, false)); |
1746 | 1630 |
1747 // TODO(epoger): only run this if gmmain.generate_image() succeeded? | 1631 // TODO(epoger): only run this if gmmain.generate_image() succeeded? |
1748 // Otherwise, what are we comparing against? | 1632 // Otherwise, what are we comparing against? |
1749 run_multiple_modes(gmmain, gm, compareConfig, comparisonBitmap, tileGrid
ReplayScales); | 1633 testErrors.add(run_multiple_modes(gmmain, gm, compareConfig, comparisonB
itmap, |
| 1634 tileGridReplayScales)); |
| 1635 |
| 1636 // Update overall results. |
| 1637 // We only tabulate the particular error types that we currently |
| 1638 // care about (e.g., missing reference images). Later on, if we |
| 1639 // want to also tabulate other error types, we can do so. |
| 1640 testsRun++; |
| 1641 if (!gmmain.fExpectationsSource.get() || |
| 1642 (testErrors.includes(kMissingExpectations_ErrorType))) { |
| 1643 testsMissingReferenceImages++; |
| 1644 } |
| 1645 if (testErrors.minus(gmmain.fIgnorableErrorCombination).isEmpty()) { |
| 1646 testsPassed++; |
| 1647 } else { |
| 1648 testsFailed++; |
| 1649 } |
1750 | 1650 |
1751 SkDELETE(gm); | 1651 SkDELETE(gm); |
1752 } | 1652 } |
1753 | 1653 gm_fprintf(stdout, "Ran %d tests: %d passed, %d failed, %d missing reference
images\n", |
1754 SkTArray<SkString> modes; | 1654 testsRun, testsPassed, testsFailed, testsMissingReferenceImages); |
1755 gmmain.GetRenderModesEncountered(modes); | |
1756 | |
1757 // Output summary to stdout. | |
1758 gm_fprintf(stdout, "Ran %d GMs\n", gmsRun); | |
1759 gm_fprintf(stdout, "... over %2d configs [%s]\n", configs.count(), | |
1760 list_all_config_names(configs).c_str()); | |
1761 gm_fprintf(stdout, "... and %2d modes [%s]\n", modes.count(), list_all(mo
des).c_str()); | |
1762 gm_fprintf(stdout, "... so there should be a total of %d tests.\n", | |
1763 gmsRun * (configs.count() + modes.count())); | |
1764 | |
1765 // TODO(epoger): Ultimately, we should signal an error if the | |
1766 // expected total number of tests (displayed above) does not match | |
1767 // gmmain.fTestsRun. But for now, there are cases where those | |
1768 // numbers won't match: specifically, if some configs/modes are | |
1769 // skipped on a per-GM basis (due to gm->getFlags() for a specific | |
1770 // GM). Later on, we should record tests like that using some new | |
1771 // ErrorType, like kIntentionallySkipped_ErrorType. Then we could | |
1772 // signal an error if the totals didn't match up. | |
1773 gmmain.ListErrors(); | 1655 gmmain.ListErrors(); |
1774 | 1656 |
1775 if (FLAGS_writeJsonSummaryPath.count() == 1) { | 1657 if (FLAGS_writeJsonSummaryPath.count() == 1) { |
1776 Json::Value actualResults; | 1658 Json::Value actualResults; |
1777 actualResults[kJsonKey_ActualResults_Failed] = | 1659 actualResults[kJsonKey_ActualResults_Failed] = |
1778 gmmain.fJsonActualResults_Failed; | 1660 gmmain.fJsonActualResults_Failed; |
1779 actualResults[kJsonKey_ActualResults_FailureIgnored] = | 1661 actualResults[kJsonKey_ActualResults_FailureIgnored] = |
1780 gmmain.fJsonActualResults_FailureIgnored; | 1662 gmmain.fJsonActualResults_FailureIgnored; |
1781 actualResults[kJsonKey_ActualResults_NoComparison] = | 1663 actualResults[kJsonKey_ActualResults_NoComparison] = |
1782 gmmain.fJsonActualResults_NoComparison; | 1664 gmmain.fJsonActualResults_NoComparison; |
(...skipping 19 matching lines...) Expand all Loading... |
1802 gm_fprintf(stdout, "config: %s %x\n", config.fName, gr); | 1684 gm_fprintf(stdout, "config: %s %x\n", config.fName, gr); |
1803 gr->printCacheStats(); | 1685 gr->printCacheStats(); |
1804 } | 1686 } |
1805 } | 1687 } |
1806 #endif | 1688 #endif |
1807 | 1689 |
1808 delete grFactory; | 1690 delete grFactory; |
1809 #endif | 1691 #endif |
1810 SkGraphics::Term(); | 1692 SkGraphics::Term(); |
1811 | 1693 |
1812 return (0 == gmmain.NumSignificantErrors()) ? 0 : -1; | 1694 return (0 == testsFailed) ? 0 : -1; |
1813 } | 1695 } |
1814 | 1696 |
1815 void GMMain::installFilter(SkCanvas* canvas) { | 1697 void GMMain::installFilter(SkCanvas* canvas) { |
1816 if (FLAGS_forceBWtext) { | 1698 if (FLAGS_forceBWtext) { |
1817 canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref(); | 1699 canvas->setDrawFilter(SkNEW(BWTextDrawFilter))->unref(); |
1818 } | 1700 } |
1819 } | 1701 } |
1820 | 1702 |
1821 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) | 1703 #if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL) |
1822 int main(int argc, char * const argv[]) { | 1704 int main(int argc, char * const argv[]) { |
1823 return tool_main(argc, (char**) argv); | 1705 return tool_main(argc, (char**) argv); |
1824 } | 1706 } |
1825 #endif | 1707 #endif |
OLD | NEW |