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