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