diff options
-rw-r--r-- | gm/gmmain.cpp | 1088 |
1 files changed, 555 insertions, 533 deletions
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp index 956f687e0b..bf0321460a 100644 --- a/gm/gmmain.cpp +++ b/gm/gmmain.cpp @@ -11,6 +11,7 @@ #include "SkData.h" #include "SkDeferredCanvas.h" #include "SkDevice.h" +#include "SkDrawFilter.h" #include "SkGPipe.h" #include "SkGraphics.h" #include "SkImageDecoder.h" @@ -105,144 +106,6 @@ private: const GMRegistry* fReg; }; -static SkString make_name(const char shortName[], const char configName[]) { - SkString name(shortName); - name.appendf("_%s", configName); - return name; -} - -static SkString make_filename(const char path[], - const char pathSuffix[], - const SkString& name, - const char suffix[]) { - SkString filename(path); - if (filename.endsWith(PATH_SEPARATOR)) { - filename.remove(filename.size() - 1, 1); - } - filename.append(pathSuffix); - filename.append(PATH_SEPARATOR); - filename.appendf("%s.%s", name.c_str(), suffix); - return filename; -} - -/* since PNG insists on unpremultiplying our alpha, we take no precision chances - and force all pixels to be 100% opaque, otherwise on compare we may not get - a perfect match. - */ -static void force_all_opaque(const SkBitmap& bitmap) { - SkAutoLockPixels lock(bitmap); - for (int y = 0; y < bitmap.height(); y++) { - for (int x = 0; x < bitmap.width(); x++) { - *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); - } - } -} - -static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) { - SkBitmap copy; - bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); - force_all_opaque(copy); - return SkImageEncoder::EncodeFile(path.c_str(), copy, - SkImageEncoder::kPNG_Type, 100); -} - -static inline SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1) { - int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1); - int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1); - int db = SkGetPackedB32(c0) - SkGetPackedB32(c1); - return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db)); -} - -static void compute_diff(const SkBitmap& target, const SkBitmap& base, - SkBitmap* diff) { - SkAutoLockPixels alp(*diff); - - const int w = target.width(); - const int h = target.height(); - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - SkPMColor c0 = *base.getAddr32(x, y); - SkPMColor c1 = *target.getAddr32(x, y); - SkPMColor d = 0; - if (c0 != c1) { - d = compute_diff_pmcolor(c0, c1); - } - *diff->getAddr32(x, y) = d; - } - } -} - -// Compares "target" and "base" bitmaps, returning the result (ERROR_NONE -// if the two bitmaps are identical). -// -// If a "diff" bitmap is passed in, pixel diffs (if any) will be written -// into it. -// -// The "name" and "renderModeDescriptor" arguments are only used in the debug -// output. -static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base, - const SkString& name, - const char* renderModeDescriptor, - SkBitmap* diff) { - SkBitmap copy; - const SkBitmap* bm = ⌖ - if (target.config() != SkBitmap::kARGB_8888_Config) { - target.copyTo(©, SkBitmap::kARGB_8888_Config); - bm = © - } - SkBitmap baseCopy; - const SkBitmap* bp = &base; - if (base.config() != SkBitmap::kARGB_8888_Config) { - base.copyTo(&baseCopy, SkBitmap::kARGB_8888_Config); - bp = &baseCopy; - } - - force_all_opaque(*bm); - force_all_opaque(*bp); - - const int w = bm->width(); - const int h = bm->height(); - if (w != bp->width() || h != bp->height()) { - SkDebugf( -"---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", - renderModeDescriptor, name.c_str(), - bp->width(), bp->height(), w, h); - return ERROR_DIMENSION_MISMATCH; - } - - SkAutoLockPixels bmLock(*bm); - SkAutoLockPixels baseLock(*bp); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - SkPMColor c0 = *bp->getAddr32(x, y); - SkPMColor c1 = *bm->getAddr32(x, y); - if (c0 != c1) { - SkDebugf( -"----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", - renderModeDescriptor, name.c_str(), x, y, c0, c1); - - if (diff) { - diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); - diff->allocPixels(); - compute_diff(*bm, *bp, diff); - } - return ERROR_PIXEL_MISMATCH; - } - } - } - - // they're equal - return ERROR_NONE; -} - -static bool write_document(const SkString& path, - const SkDynamicMemoryWStream& document) { - SkFILEWStream stream(path.c_str()); - SkAutoDataUnref data(document.copyToData()); - return stream.writeData(data.get()); -} - enum Backend { kRaster_Backend, kGPU_Backend, @@ -268,20 +131,6 @@ struct ConfigData { const char* fName; }; -/// Returns true if processing should continue, false to skip the -/// remainder of this config for this GM. -//@todo thudson 22 April 2011 - could refactor this to take in -// a factory to generate the context, always call readPixels() -// (logically a noop for rasters, if wasted time), and thus collapse the -// GPU special case and also let this be used for SkPicture testing. -static void setup_bitmap(const ConfigData& gRec, SkISize& size, - SkBitmap* bitmap) { - bitmap->setConfig(gRec.fConfig, size.width(), size.height()); - bitmap->allocPixels(); - bitmap->eraseColor(0); -} - -#include "SkDrawFilter.h" class BWTextDrawFilter : public SkDrawFilter { public: virtual void filter(SkPaint*, Type) SK_OVERRIDE; @@ -292,403 +141,556 @@ void BWTextDrawFilter::filter(SkPaint* p, Type t) { } } -static void installFilter(SkCanvas* canvas) { - if (gForceBWtext) { - canvas->setDrawFilter(new BWTextDrawFilter)->unref(); +struct PipeFlagComboData { + const char* name; + uint32_t flags; +}; + +static PipeFlagComboData gPipeWritingFlagCombos[] = { + { "", 0 }, + { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, + { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag + | SkGPipeWriter::kSharedAddressSpace_Flag } +}; + + +class GMMain { +public: + static SkString make_name(const char shortName[], const char configName[]) { + SkString name(shortName); + name.appendf("_%s", configName); + return name; } -} -static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF = false) { - SkAutoCanvasRestore acr(canvas, true); + static SkString make_filename(const char path[], + const char pathSuffix[], + const SkString& name, + const char suffix[]) { + SkString filename(path); + if (filename.endsWith(PATH_SEPARATOR)) { + filename.remove(filename.size() - 1, 1); + } + filename.append(pathSuffix); + filename.append(PATH_SEPARATOR); + filename.appendf("%s.%s", name.c_str(), suffix); + return filename; + } - if (!isPDF) { - canvas->concat(gm->getInitialTransform()); + /* since PNG insists on unpremultiplying our alpha, we take no + precision chances and force all pixels to be 100% opaque, + otherwise on compare we may not get a perfect match. + */ + static void force_all_opaque(const SkBitmap& bitmap) { + SkAutoLockPixels lock(bitmap); + for (int y = 0; y < bitmap.height(); y++) { + for (int x = 0; x < bitmap.width(); x++) { + *bitmap.getAddr32(x, y) |= (SK_A32_MASK << SK_A32_SHIFT); + } + } } - installFilter(canvas); - gm->draw(canvas); - canvas->setDrawFilter(NULL); -} -static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec, - GrContext* context, - GrRenderTarget* rt, - SkBitmap* bitmap, - bool deferred) { - SkISize size (gm->getISize()); - setup_bitmap(gRec, size, bitmap); + static bool write_bitmap(const SkString& path, const SkBitmap& bitmap) { + SkBitmap copy; + bitmap.copyTo(©, SkBitmap::kARGB_8888_Config); + force_all_opaque(copy); + return SkImageEncoder::EncodeFile(path.c_str(), copy, + SkImageEncoder::kPNG_Type, 100); + } - SkAutoTUnref<SkCanvas> canvas; + static inline SkPMColor compute_diff_pmcolor(SkPMColor c0, SkPMColor c1) { + int dr = SkGetPackedR32(c0) - SkGetPackedR32(c1); + int dg = SkGetPackedG32(c0) - SkGetPackedG32(c1); + int db = SkGetPackedB32(c0) - SkGetPackedB32(c1); + return SkPackARGB32(0xFF, SkAbs32(dr), SkAbs32(dg), SkAbs32(db)); + } - if (gRec.fBackend == kRaster_Backend) { - SkAutoTUnref<SkDevice> device(new SkDevice(*bitmap)); - if (deferred) { - canvas.reset(new SkDeferredCanvas(device)); - } else { - canvas.reset(new SkCanvas(device)); + static void compute_diff(const SkBitmap& target, const SkBitmap& base, + SkBitmap* diff) { + SkAutoLockPixels alp(*diff); + + const int w = target.width(); + const int h = target.height(); + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + SkPMColor c0 = *base.getAddr32(x, y); + SkPMColor c1 = *target.getAddr32(x, y); + SkPMColor d = 0; + if (c0 != c1) { + d = compute_diff_pmcolor(c0, c1); + } + *diff->getAddr32(x, y) = d; + } } - invokeGM(gm, canvas); - canvas->flush(); } -#if SK_SUPPORT_GPU - else { // GPU - if (NULL == context) { - return ERROR_NO_GPU_CONTEXT; + + // Compares "target" and "base" bitmaps, returning the result + // (ERROR_NONE if the two bitmaps are identical). + // + // If a "diff" bitmap is passed in, pixel diffs (if any) will be written + // into it. + // + // The "name" and "renderModeDescriptor" arguments are only used + // in the debug output. + static ErrorBitfield compare(const SkBitmap& target, const SkBitmap& base, + const SkString& name, + const char* renderModeDescriptor, + SkBitmap* diff) { + SkBitmap copy; + const SkBitmap* bm = ⌖ + if (target.config() != SkBitmap::kARGB_8888_Config) { + target.copyTo(©, SkBitmap::kARGB_8888_Config); + bm = © } - SkAutoTUnref<SkDevice> device(new SkGpuDevice(context, rt)); - if (deferred) { - canvas.reset(new SkDeferredCanvas(device)); - } else { - canvas.reset(new SkCanvas(device)); + SkBitmap baseCopy; + const SkBitmap* bp = &base; + if (base.config() != SkBitmap::kARGB_8888_Config) { + base.copyTo(&baseCopy, SkBitmap::kARGB_8888_Config); + bp = &baseCopy; + } + + force_all_opaque(*bm); + force_all_opaque(*bp); + + const int w = bm->width(); + const int h = bm->height(); + if (w != bp->width() || h != bp->height()) { + SkDebugf( + "---- %s dimensions mismatch for %s base [%d %d] current [%d %d]\n", + renderModeDescriptor, name.c_str(), + bp->width(), bp->height(), w, h); + return ERROR_DIMENSION_MISMATCH; } - invokeGM(gm, canvas); - // the device is as large as the current rendertarget, so we explicitly - // only readback the amount we expect (in size) - // overwrite our previous allocation - bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth, - size.fHeight); - canvas->readPixels(bitmap, 0, 0); + + SkAutoLockPixels bmLock(*bm); + SkAutoLockPixels baseLock(*bp); + + for (int y = 0; y < h; y++) { + for (int x = 0; x < w; x++) { + SkPMColor c0 = *bp->getAddr32(x, y); + SkPMColor c1 = *bm->getAddr32(x, y); + if (c0 != c1) { + SkDebugf( + "----- %s pixel mismatch for %s at [%d %d] base 0x%08X current 0x%08X\n", + renderModeDescriptor, name.c_str(), x, y, c0, c1); + + if (diff) { + diff->setConfig(SkBitmap::kARGB_8888_Config, w, h); + diff->allocPixels(); + compute_diff(*bm, *bp, diff); + } + return ERROR_PIXEL_MISMATCH; + } + } + } + + // they're equal + return ERROR_NONE; } -#endif - return ERROR_NONE; -} -static void generate_image_from_picture(GM* gm, const ConfigData& gRec, - SkPicture* pict, SkBitmap* bitmap) { - SkISize size = gm->getISize(); - setup_bitmap(gRec, size, bitmap); - SkCanvas canvas(*bitmap); - installFilter(&canvas); - canvas.drawPicture(*pict); -} + static bool write_document(const SkString& path, + const SkDynamicMemoryWStream& document) { + SkFILEWStream stream(path.c_str()); + SkAutoDataUnref data(document.copyToData()); + return stream.writeData(data.get()); + } -static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { -#ifdef SK_SUPPORT_PDF - SkMatrix initialTransform = gm->getInitialTransform(); - SkISize pageSize = gm->getISize(); - SkPDFDevice* dev = NULL; - if (initialTransform.isIdentity()) { - dev = new SkPDFDevice(pageSize, pageSize, initialTransform); - } else { - SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()), - SkIntToScalar(pageSize.height())); - initialTransform.mapRect(&content); - content.intersect(0, 0, SkIntToScalar(pageSize.width()), - SkIntToScalar(pageSize.height())); - SkISize contentSize = - SkISize::Make(SkScalarRoundToInt(content.width()), - SkScalarRoundToInt(content.height())); - dev = new SkPDFDevice(pageSize, contentSize, initialTransform); + /// Returns true if processing should continue, false to skip the + /// remainder of this config for this GM. + //@todo thudson 22 April 2011 - could refactor this to take in + // a factory to generate the context, always call readPixels() + // (logically a noop for rasters, if wasted time), and thus collapse the + // GPU special case and also let this be used for SkPicture testing. + static void setup_bitmap(const ConfigData& gRec, SkISize& size, + SkBitmap* bitmap) { + bitmap->setConfig(gRec.fConfig, size.width(), size.height()); + bitmap->allocPixels(); + bitmap->eraseColor(0); } - SkAutoUnref aur(dev); - SkCanvas c(dev); - invokeGM(gm, &c, true); + static void installFilter(SkCanvas* canvas) { + if (gForceBWtext) { + canvas->setDrawFilter(new BWTextDrawFilter)->unref(); + } + } - SkPDFDocument doc; - doc.appendPage(dev); - doc.emitPDF(&pdf); -#endif -} + static void invokeGM(GM* gm, SkCanvas* canvas, bool isPDF = false) { + SkAutoCanvasRestore acr(canvas, true); -static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) { -#ifdef SK_SUPPORT_XPS - SkISize size = gm->getISize(); - - SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()), - SkIntToScalar(size.height())); - static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254); - static const SkScalar upm = 72 * inchesPerMeter; - SkVector unitsPerMeter = SkPoint::Make(upm, upm); - static const SkScalar ppm = 200 * inchesPerMeter; - SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm); - - SkXPSDevice* dev = new SkXPSDevice(); - SkAutoUnref aur(dev); - - SkCanvas c(dev); - dev->beginPortfolio(&xps); - dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize); - invokeGM(gm, &c); - dev->endSheet(); - dev->endPortfolio(); + if (!isPDF) { + canvas->concat(gm->getInitialTransform()); + } + installFilter(canvas); + gm->draw(canvas); + canvas->setDrawFilter(NULL); + } -#endif -} + static ErrorBitfield generate_image(GM* gm, const ConfigData& gRec, + GrContext* context, + GrRenderTarget* rt, + SkBitmap* bitmap, + bool deferred) { + SkISize size (gm->getISize()); + setup_bitmap(gRec, size, bitmap); + + SkAutoTUnref<SkCanvas> canvas; -static ErrorBitfield write_reference_image(const ConfigData& gRec, - const char writePath [], - const char renderModeDescriptor [], - const SkString& name, - SkBitmap& bitmap, - SkDynamicMemoryWStream* document) { - SkString path; - bool success = false; - if (gRec.fBackend == kRaster_Backend || - gRec.fBackend == kGPU_Backend || - (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) { - - path = make_filename(writePath, renderModeDescriptor, name, "png"); - success = write_bitmap(path, bitmap); + if (gRec.fBackend == kRaster_Backend) { + SkAutoTUnref<SkDevice> device(new SkDevice(*bitmap)); + if (deferred) { + canvas.reset(new SkDeferredCanvas(device)); + } else { + canvas.reset(new SkCanvas(device)); + } + invokeGM(gm, canvas); + canvas->flush(); + } +#if SK_SUPPORT_GPU + else { // GPU + if (NULL == context) { + return ERROR_NO_GPU_CONTEXT; + } + SkAutoTUnref<SkDevice> device(new SkGpuDevice(context, rt)); + if (deferred) { + canvas.reset(new SkDeferredCanvas(device)); + } else { + canvas.reset(new SkCanvas(device)); + } + invokeGM(gm, canvas); + // the device is as large as the current rendertarget, so + // we explicitly only readback the amount we expect (in + // size) overwrite our previous allocation + bitmap->setConfig(SkBitmap::kARGB_8888_Config, size.fWidth, + size.fHeight); + canvas->readPixels(bitmap, 0, 0); + } +#endif + return ERROR_NONE; } - if (kPDF_Backend == gRec.fBackend) { - path = make_filename(writePath, renderModeDescriptor, name, "pdf"); - success = write_document(path, *document); + + static void generate_image_from_picture(GM* gm, const ConfigData& gRec, + SkPicture* pict, SkBitmap* bitmap) { + SkISize size = gm->getISize(); + setup_bitmap(gRec, size, bitmap); + SkCanvas canvas(*bitmap); + installFilter(&canvas); + canvas.drawPicture(*pict); } - if (kXPS_Backend == gRec.fBackend) { - path = make_filename(writePath, renderModeDescriptor, name, "xps"); - success = write_document(path, *document); + + static void generate_pdf(GM* gm, SkDynamicMemoryWStream& pdf) { +#ifdef SK_SUPPORT_PDF + SkMatrix initialTransform = gm->getInitialTransform(); + SkISize pageSize = gm->getISize(); + SkPDFDevice* dev = NULL; + if (initialTransform.isIdentity()) { + dev = new SkPDFDevice(pageSize, pageSize, initialTransform); + } else { + SkRect content = SkRect::MakeWH(SkIntToScalar(pageSize.width()), + SkIntToScalar(pageSize.height())); + initialTransform.mapRect(&content); + content.intersect(0, 0, SkIntToScalar(pageSize.width()), + SkIntToScalar(pageSize.height())); + SkISize contentSize = + SkISize::Make(SkScalarRoundToInt(content.width()), + SkScalarRoundToInt(content.height())); + dev = new SkPDFDevice(pageSize, contentSize, initialTransform); + } + SkAutoUnref aur(dev); + + SkCanvas c(dev); + invokeGM(gm, &c, true); + + SkPDFDocument doc; + doc.appendPage(dev); + doc.emitPDF(&pdf); +#endif } - if (success) { - return ERROR_NONE; - } else { - fprintf(stderr, "FAILED to write %s\n", path.c_str()); - return ERROR_WRITING_REFERENCE_IMAGE; + + static void generate_xps(GM* gm, SkDynamicMemoryWStream& xps) { +#ifdef SK_SUPPORT_XPS + SkISize size = gm->getISize(); + + SkSize trimSize = SkSize::Make(SkIntToScalar(size.width()), + SkIntToScalar(size.height())); + static const SkScalar inchesPerMeter = SkScalarDiv(10000, 254); + static const SkScalar upm = 72 * inchesPerMeter; + SkVector unitsPerMeter = SkPoint::Make(upm, upm); + static const SkScalar ppm = 200 * inchesPerMeter; + SkVector pixelsPerMeter = SkPoint::Make(ppm, ppm); + + SkXPSDevice* dev = new SkXPSDevice(); + SkAutoUnref aur(dev); + + SkCanvas c(dev); + dev->beginPortfolio(&xps); + dev->beginSheet(unitsPerMeter, pixelsPerMeter, trimSize); + invokeGM(gm, &c); + dev->endSheet(); + dev->endPortfolio(); + +#endif } -} -// Compares bitmap "bitmap" to "referenceBitmap"; if they are -// different, writes out "bitmap" (in PNG format) within the diffPath subdir. -// -// Returns the ErrorBitfield from compare(), describing any differences -// between "bitmap" and "referenceBitmap" (or ERROR_NONE if there are none). -static ErrorBitfield compare_to_reference_image_in_memory(const SkString& name, - SkBitmap &bitmap, - const SkBitmap& referenceBitmap, - const char diffPath [], - const char renderModeDescriptor []) { - ErrorBitfield errors; - SkBitmap diffBitmap; - errors = compare(bitmap, referenceBitmap, name, renderModeDescriptor, - diffPath ? &diffBitmap : NULL); - if ((ERROR_NONE != errors) && diffPath) { - // write out the generated image - SkString genName = make_filename(diffPath, "", name, "png"); - if (!write_bitmap(genName, bitmap)) { - errors |= ERROR_WRITING_REFERENCE_IMAGE; + static ErrorBitfield write_reference_image( + const ConfigData& gRec, const char writePath [], + const char renderModeDescriptor [], const SkString& name, + SkBitmap& bitmap, SkDynamicMemoryWStream* document) { + SkString path; + bool success = false; + if (gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend || + (gRec.fBackend == kPDF_Backend && CAN_IMAGE_PDF)) { + + path = make_filename(writePath, renderModeDescriptor, name, "png"); + success = write_bitmap(path, bitmap); + } + if (kPDF_Backend == gRec.fBackend) { + path = make_filename(writePath, renderModeDescriptor, name, "pdf"); + success = write_document(path, *document); + } + if (kXPS_Backend == gRec.fBackend) { + path = make_filename(writePath, renderModeDescriptor, name, "xps"); + success = write_document(path, *document); + } + if (success) { + return ERROR_NONE; + } else { + fprintf(stderr, "FAILED to write %s\n", path.c_str()); + return ERROR_WRITING_REFERENCE_IMAGE; } } - return errors; -} -// Compares bitmap "bitmap" to a reference bitmap read from disk; if they are -// different, writes out "bitmap" (in PNG format) within the diffPath subdir. -// -// Returns a description of the difference between "bitmap" and the reference -// bitmap, or ERROR_READING_REFERENCE_IMAGE if unable to read the reference -// bitmap from disk. -static ErrorBitfield compare_to_reference_image_on_disk(const char readPath [], - const SkString& name, - SkBitmap &bitmap, - const char diffPath [], - const char renderModeDescriptor []) { - SkString path = make_filename(readPath, "", name, "png"); - SkBitmap referenceBitmap; - if (SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, - SkBitmap::kARGB_8888_Config, - SkImageDecoder::kDecodePixels_Mode, NULL)) { - return compare_to_reference_image_in_memory(name, bitmap, - referenceBitmap, diffPath, - renderModeDescriptor); - } else { - if (gNotifyMissingReadReference) { - fprintf(stderr, "FAILED to read %s\n", path.c_str()); + // Compares bitmap "bitmap" to "referenceBitmap"; if they are + // different, writes out "bitmap" (in PNG format) within the + // diffPath subdir. + // + // Returns the ErrorBitfield from compare(), describing any differences + // between "bitmap" and "referenceBitmap" (or ERROR_NONE if there are none). + static ErrorBitfield compare_to_reference_image_in_memory( + const SkString& name, SkBitmap &bitmap, const SkBitmap& referenceBitmap, + const char diffPath [], const char renderModeDescriptor []) { + ErrorBitfield errors; + SkBitmap diffBitmap; + errors = compare(bitmap, referenceBitmap, name, renderModeDescriptor, + diffPath ? &diffBitmap : NULL); + if ((ERROR_NONE != errors) && diffPath) { + // write out the generated image + SkString genName = make_filename(diffPath, "", name, "png"); + if (!write_bitmap(genName, bitmap)) { + errors |= ERROR_WRITING_REFERENCE_IMAGE; + } } - return ERROR_READING_REFERENCE_IMAGE; + return errors; } -} -// NOTE: As far as I can tell, this function is NEVER called with a -// non-blank renderModeDescriptor, EXCEPT with readPath and writePath are -// both NULL (and thus no images are read from or written to disk). -// So I don't trust that the renderModeDescriptor is being used for -// anything other than debug output these days. -static ErrorBitfield handle_test_results(GM* gm, - const ConfigData& gRec, - const char writePath [], - const char readPath [], - const char diffPath [], - const char renderModeDescriptor [], - SkBitmap& bitmap, - SkDynamicMemoryWStream* pdf, - const SkBitmap* referenceBitmap) { - SkString name = make_name(gm->shortName(), gRec.fName); - ErrorBitfield retval = ERROR_NONE; - - if (readPath && (gRec.fFlags & kRead_ConfigFlag)) { - retval |= compare_to_reference_image_on_disk(readPath, name, bitmap, - diffPath, renderModeDescriptor); - } - if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { - retval |= write_reference_image(gRec, writePath, renderModeDescriptor, - name, bitmap, pdf); + // Compares bitmap "bitmap" to a reference bitmap read from disk; + // if they are different, writes out "bitmap" (in PNG format) + // within the diffPath subdir. + // + // Returns a description of the difference between "bitmap" and + // the reference bitmap, or ERROR_READING_REFERENCE_IMAGE if + // unable to read the reference bitmap from disk. + static ErrorBitfield compare_to_reference_image_on_disk( + const char readPath [], const SkString& name, SkBitmap &bitmap, + const char diffPath [], const char renderModeDescriptor []) { + SkString path = make_filename(readPath, "", name, "png"); + SkBitmap referenceBitmap; + if (SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, + SkBitmap::kARGB_8888_Config, + SkImageDecoder::kDecodePixels_Mode, + NULL)) { + return compare_to_reference_image_in_memory(name, bitmap, + referenceBitmap, + diffPath, + renderModeDescriptor); + } else { + if (gNotifyMissingReadReference) { + fprintf(stderr, "FAILED to read %s\n", path.c_str()); + } + return ERROR_READING_REFERENCE_IMAGE; + } } - if (referenceBitmap) { - retval |= compare_to_reference_image_in_memory(name, bitmap, - *referenceBitmap, diffPath, - renderModeDescriptor); + + // NOTE: As far as I can tell, this function is NEVER called with a + // non-blank renderModeDescriptor, EXCEPT when readPath and writePath are + // both NULL (and thus no images are read from or written to disk). + // So I don't trust that the renderModeDescriptor is being used for + // anything other than debug output these days. + static ErrorBitfield handle_test_results(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + const char renderModeDescriptor [], + SkBitmap& bitmap, + SkDynamicMemoryWStream* pdf, + const SkBitmap* referenceBitmap) { + SkString name = make_name(gm->shortName(), gRec.fName); + ErrorBitfield retval = ERROR_NONE; + + if (readPath && (gRec.fFlags & kRead_ConfigFlag)) { + retval |= compare_to_reference_image_on_disk(readPath, name, bitmap, + diffPath, + renderModeDescriptor); + } + if (writePath && (gRec.fFlags & kWrite_ConfigFlag)) { + retval |= write_reference_image(gRec, writePath, + renderModeDescriptor, + name, bitmap, pdf); + } + if (referenceBitmap) { + retval |= compare_to_reference_image_in_memory( + name, bitmap, *referenceBitmap, diffPath, renderModeDescriptor); + } + return retval; } - return retval; -} -static SkPicture* generate_new_picture(GM* gm) { - // Pictures are refcounted so must be on heap - SkPicture* pict = new SkPicture; - SkISize size = gm->getISize(); - SkCanvas* cv = pict->beginRecording(size.width(), size.height()); - invokeGM(gm, cv); - pict->endRecording(); + static SkPicture* generate_new_picture(GM* gm) { + // Pictures are refcounted so must be on heap + SkPicture* pict = new SkPicture; + SkISize size = gm->getISize(); + SkCanvas* cv = pict->beginRecording(size.width(), size.height()); + invokeGM(gm, cv); + pict->endRecording(); - return pict; -} + return pict; + } -static SkPicture* stream_to_new_picture(const SkPicture& src) { - - // To do in-memory commiunications with a stream, we need to: - // * create a dynamic memory stream - // * copy it into a buffer - // * create a read stream from it - // ?!?! - - SkDynamicMemoryWStream storage; - src.serialize(&storage); - - int streamSize = storage.getOffset(); - SkAutoMalloc dstStorage(streamSize); - void* dst = dstStorage.get(); - //char* dst = new char [streamSize]; - //@todo thudson 22 April 2011 when can we safely delete [] dst? - storage.copyTo(dst); - SkMemoryStream pictReadback(dst, streamSize); - SkPicture* retval = new SkPicture (&pictReadback); - return retval; -} + static SkPicture* stream_to_new_picture(const SkPicture& src) { + + // To do in-memory commiunications with a stream, we need to: + // * create a dynamic memory stream + // * copy it into a buffer + // * create a read stream from it + // ?!?! + + SkDynamicMemoryWStream storage; + src.serialize(&storage); + + int streamSize = storage.getOffset(); + SkAutoMalloc dstStorage(streamSize); + void* dst = dstStorage.get(); + //char* dst = new char [streamSize]; + //@todo thudson 22 April 2011 when can we safely delete [] dst? + storage.copyTo(dst); + SkMemoryStream pictReadback(dst, streamSize); + SkPicture* retval = new SkPicture (&pictReadback); + return retval; + } -// Test: draw into a bitmap or pdf. -// Depending on flags, possibly compare to an expected image -// and possibly output a diff image if it fails to match. -static ErrorBitfield test_drawing(GM* gm, - const ConfigData& gRec, - const char writePath [], - const char readPath [], - const char diffPath [], - GrContext* context, - GrRenderTarget* rt, - SkBitmap* bitmap) { - SkDynamicMemoryWStream document; - - if (gRec.fBackend == kRaster_Backend || - gRec.fBackend == kGPU_Backend) { - // Early exit if we can't generate the image. - ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap, - false); - if (ERROR_NONE != errors) { - return errors; - } - } else if (gRec.fBackend == kPDF_Backend) { - generate_pdf(gm, document); + // Test: draw into a bitmap or pdf. + // Depending on flags, possibly compare to an expected image + // and possibly output a diff image if it fails to match. + static ErrorBitfield test_drawing(GM* gm, + const ConfigData& gRec, + const char writePath [], + const char readPath [], + const char diffPath [], + GrContext* context, + GrRenderTarget* rt, + SkBitmap* bitmap) { + SkDynamicMemoryWStream document; + + if (gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend) { + // Early exit if we can't generate the image. + ErrorBitfield errors = generate_image(gm, gRec, context, rt, bitmap, + false); + if (ERROR_NONE != errors) { + return errors; + } + } else if (gRec.fBackend == kPDF_Backend) { + generate_pdf(gm, document); #if CAN_IMAGE_PDF - SkAutoDataUnref data(document.copyToData()); - SkMemoryStream stream(data->data(), data->size()); - SkPDFDocumentToBitmap(&stream, bitmap); + SkAutoDataUnref data(document.copyToData()); + SkMemoryStream stream(data->data(), data->size()); + SkPDFDocumentToBitmap(&stream, bitmap); #endif - } else if (gRec.fBackend == kXPS_Backend) { - generate_xps(gm, document); + } else if (gRec.fBackend == kXPS_Backend) { + generate_xps(gm, document); + } + return handle_test_results(gm, gRec, writePath, readPath, diffPath, + "", *bitmap, &document, NULL); } - return handle_test_results(gm, gRec, writePath, readPath, diffPath, - "", *bitmap, &document, NULL); -} -static ErrorBitfield test_deferred_drawing(GM* gm, - const ConfigData& gRec, - const SkBitmap& referenceBitmap, - const char diffPath [], - GrContext* context, - GrRenderTarget* rt) { - SkDynamicMemoryWStream document; - - if (gRec.fBackend == kRaster_Backend || - gRec.fBackend == kGPU_Backend) { - SkBitmap bitmap; - // Early exit if we can't generate the image, but this is - // expected in some cases, so don't report a test failure. - if (!generate_image(gm, gRec, context, rt, &bitmap, true)) { - return ERROR_NONE; + static ErrorBitfield test_deferred_drawing(GM* gm, + const ConfigData& gRec, + const SkBitmap& referenceBitmap, + const char diffPath [], + GrContext* context, + GrRenderTarget* rt) { + SkDynamicMemoryWStream document; + + if (gRec.fBackend == kRaster_Backend || + gRec.fBackend == kGPU_Backend) { + SkBitmap bitmap; + // Early exit if we can't generate the image, but this is + // expected in some cases, so don't report a test failure. + if (!generate_image(gm, gRec, context, rt, &bitmap, true)) { + return ERROR_NONE; + } + return handle_test_results(gm, gRec, NULL, NULL, diffPath, + "-deferred", bitmap, NULL, + &referenceBitmap); } - return handle_test_results(gm, gRec, NULL, NULL, diffPath, - "-deferred", bitmap, NULL, &referenceBitmap); + return ERROR_NONE; } - return ERROR_NONE; -} -struct PipeFlagComboData { - const char* name; - uint32_t flags; -}; - -static PipeFlagComboData gPipeWritingFlagCombos[] = { - { "", 0 }, - { " cross-process", SkGPipeWriter::kCrossProcess_Flag }, - { " cross-process, shared address", SkGPipeWriter::kCrossProcess_Flag - | SkGPipeWriter::kSharedAddressSpace_Flag } -}; - -static ErrorBitfield test_pipe_playback(GM* gm, - const ConfigData& gRec, - const SkBitmap& referenceBitmap, - const char readPath [], - const char diffPath []) { - ErrorBitfield errors = ERROR_NONE; - for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { - SkBitmap bitmap; - SkISize size = gm->getISize(); - setup_bitmap(gRec, size, &bitmap); - SkCanvas canvas(bitmap); - PipeController pipeController(&canvas); - SkGPipeWriter writer; - SkCanvas* pipeCanvas = writer.startRecording( - &pipeController, gPipeWritingFlagCombos[i].flags); - invokeGM(gm, pipeCanvas); - writer.endRecording(); - SkString string("-pipe"); - string.append(gPipeWritingFlagCombos[i].name); - errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath, - string.c_str(), bitmap, NULL, - &referenceBitmap); - if (errors != ERROR_NONE) { - break; + static ErrorBitfield test_pipe_playback(GM* gm, + const ConfigData& gRec, + const SkBitmap& referenceBitmap, + const char readPath [], + const char diffPath []) { + ErrorBitfield errors = ERROR_NONE; + for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { + SkBitmap bitmap; + SkISize size = gm->getISize(); + setup_bitmap(gRec, size, &bitmap); + SkCanvas canvas(bitmap); + PipeController pipeController(&canvas); + SkGPipeWriter writer; + SkCanvas* pipeCanvas = writer.startRecording( + &pipeController, gPipeWritingFlagCombos[i].flags); + invokeGM(gm, pipeCanvas); + writer.endRecording(); + SkString string("-pipe"); + string.append(gPipeWritingFlagCombos[i].name); + errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath, + string.c_str(), bitmap, NULL, + &referenceBitmap); + if (errors != ERROR_NONE) { + break; + } } + return errors; } - return errors; -} -static ErrorBitfield test_tiled_pipe_playback(GM* gm, - const ConfigData& gRec, - const SkBitmap& referenceBitmap, - const char readPath [], - const char diffPath []) { - ErrorBitfield errors = ERROR_NONE; - for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { - SkBitmap bitmap; - SkISize size = gm->getISize(); - setup_bitmap(gRec, size, &bitmap); - SkCanvas canvas(bitmap); - TiledPipeController pipeController(bitmap); - SkGPipeWriter writer; - SkCanvas* pipeCanvas = writer.startRecording( - &pipeController, gPipeWritingFlagCombos[i].flags); - invokeGM(gm, pipeCanvas); - writer.endRecording(); - SkString string("-tiled pipe"); - string.append(gPipeWritingFlagCombos[i].name); - errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath, - string.c_str(), bitmap, NULL, - &referenceBitmap); - if (errors != ERROR_NONE) { - break; + static ErrorBitfield test_tiled_pipe_playback( + GM* gm, const ConfigData& gRec, const SkBitmap& referenceBitmap, + const char readPath [], const char diffPath []) { + ErrorBitfield errors = ERROR_NONE; + for (size_t i = 0; i < SK_ARRAY_COUNT(gPipeWritingFlagCombos); ++i) { + SkBitmap bitmap; + SkISize size = gm->getISize(); + setup_bitmap(gRec, size, &bitmap); + SkCanvas canvas(bitmap); + TiledPipeController pipeController(bitmap); + SkGPipeWriter writer; + SkCanvas* pipeCanvas = writer.startRecording( + &pipeController, gPipeWritingFlagCombos[i].flags); + invokeGM(gm, pipeCanvas); + writer.endRecording(); + SkString string("-tiled pipe"); + string.append(gPipeWritingFlagCombos[i].name); + errors |= handle_test_results(gm, gRec, NULL, NULL, diffPath, + string.c_str(), bitmap, NULL, + &referenceBitmap); + if (errors != ERROR_NONE) { + break; + } } + return errors; } - return errors; -} +}; // end of GMMain class definition #if SK_SUPPORT_GPU static const GLContextType kDontCare_GLContextType = GrContextFactory::kNative_GLContextType; @@ -847,6 +849,7 @@ int tool_main(int argc, char** argv) { gSkSuppressFontCachePurgeSpew = true; setSystemPreferences(); + GMMain gmmain; const char* writePath = NULL; // if non-null, where we write the originals const char* writePicturePath = NULL; // if non-null, where we write serialized pictures @@ -928,8 +931,8 @@ int tool_main(int argc, char** argv) { } else if (strcmp(*argv, "--enable-missing-warning") == 0) { gNotifyMissingReadReference = true; } else if (strcmp(*argv, "--serialize") == 0) { - // Leaving in this option so that a user need not modify their command line arguments - // to still run. + // Leaving in this option so that a user need not modify + // their command line arguments to still run. doSerialize = true; } else if (strcmp(*argv, "--noserialize") == 0) { doSerialize = false; @@ -1050,9 +1053,9 @@ int tool_main(int argc, char** argv) { // Skip any tests that we don't even need to try. if ((kPDF_Backend == config.fBackend) && (!doPDF || (gmFlags & GM::kSkipPDF_Flag))) - { - continue; - } + { + continue; + } if ((gmFlags & GM::kSkip565_Flag) && (kRaster_Backend == config.fBackend) && (SkBitmap::kRGB_565_Config == config.fConfig)) { @@ -1097,28 +1100,32 @@ int tool_main(int argc, char** argv) { SkBitmap comparisonBitmap; if (ERROR_NONE == renderErrors) { - renderErrors |= test_drawing(gm, config, - writePath, readPath, diffPath, - GetGr(), renderTarget, &comparisonBitmap); + renderErrors |= gmmain.test_drawing(gm, config, writePath, + readPath, diffPath, GetGr(), + renderTarget, + &comparisonBitmap); } if (doDeferred && !renderErrors && (kGPU_Backend == config.fBackend || kRaster_Backend == config.fBackend)) { - renderErrors |= test_deferred_drawing(gm, config, comparisonBitmap, - diffPath, GetGr(), renderTarget); + renderErrors |= gmmain.test_deferred_drawing(gm, config, + comparisonBitmap, + diffPath, GetGr(), + renderTarget); } testErrors |= renderErrors; if (is_recordable_failure(renderErrors)) { - failedTests.push_back(make_name(shortName, config.fName)); + failedTests.push_back(gmmain.make_name(shortName, + config.fName)); } } SkBitmap comparisonBitmap; const ConfigData compareConfig = { SkBitmap::kARGB_8888_Config, kRaster_Backend, kDontCare_GLContextType, 0, kRW_ConfigFlag, "comparison" }; - testErrors |= generate_image(gm, compareConfig, NULL, NULL, &comparisonBitmap, false); + testErrors |= gmmain.generate_image(gm, compareConfig, NULL, NULL, &comparisonBitmap, false); // run the picture centric GM steps if (!(gmFlags & GM::kSkipPicture_Flag)) { @@ -1126,36 +1133,49 @@ int tool_main(int argc, char** argv) { ErrorBitfield pictErrors = ERROR_NONE; //SkAutoTUnref<SkPicture> pict(generate_new_picture(gm)); - SkPicture* pict = generate_new_picture(gm); + SkPicture* pict = gmmain.generate_new_picture(gm); SkAutoUnref aur(pict); if ((ERROR_NONE == testErrors) && doReplay) { SkBitmap bitmap; - generate_image_from_picture(gm, compareConfig, pict, &bitmap); - pictErrors |= handle_test_results(gm, compareConfig, NULL, NULL, diffPath, - "-replay", bitmap, NULL, &comparisonBitmap); + gmmain.generate_image_from_picture(gm, compareConfig, pict, + &bitmap); + pictErrors |= gmmain.handle_test_results(gm, compareConfig, + NULL, NULL, diffPath, + "-replay", bitmap, + NULL, + &comparisonBitmap); if (is_recordable_failure(pictErrors)) { - failedTests.push_back(make_name(shortName, "pict-replay")); + failedTests.push_back(gmmain.make_name(shortName, + "pict-replay")); } } - if ((ERROR_NONE == testErrors) && (ERROR_NONE == pictErrors) && doSerialize) { - SkPicture* repict = stream_to_new_picture(*pict); + if ((ERROR_NONE == testErrors) && + (ERROR_NONE == pictErrors) && + doSerialize) { + SkPicture* repict = gmmain.stream_to_new_picture(*pict); SkAutoUnref aurr(repict); SkBitmap bitmap; - generate_image_from_picture(gm, compareConfig, repict, &bitmap); - pictErrors |= handle_test_results(gm, compareConfig, NULL, NULL, diffPath, - "-serialize", bitmap, NULL, &comparisonBitmap); + gmmain.generate_image_from_picture(gm, compareConfig, repict, + &bitmap); + pictErrors |= gmmain.handle_test_results(gm, compareConfig, + NULL, NULL, diffPath, + "-serialize", bitmap, + NULL, + &comparisonBitmap); if (is_recordable_failure(pictErrors)) { - failedTests.push_back(make_name(shortName, "pict-serialize")); + failedTests.push_back(gmmain.make_name(shortName, + "pict-serialize")); } } if (writePicturePath) { const char* pictureSuffix = "skp"; - SkString path = make_filename(writePicturePath, "", - SkString(gm->shortName()), pictureSuffix); + SkString path = gmmain.make_filename(writePicturePath, "", + SkString(gm->shortName()), + pictureSuffix); SkFILEWStream stream(path.c_str()); pict->serialize(&stream); } @@ -1169,22 +1189,24 @@ int tool_main(int argc, char** argv) { ErrorBitfield pipeErrors = ERROR_NONE; if ((ERROR_NONE == testErrors) && doPipe) { - pipeErrors |= test_pipe_playback(gm, compareConfig, - comparisonBitmap, - readPath, diffPath); + pipeErrors |= gmmain.test_pipe_playback(gm, compareConfig, + comparisonBitmap, + readPath, diffPath); if (is_recordable_failure(pipeErrors)) { - failedTests.push_back(make_name(shortName, "pipe")); + failedTests.push_back(gmmain.make_name(shortName, "pipe")); } } if ((ERROR_NONE == testErrors) && (ERROR_NONE == pipeErrors) && doTiledPipe && !(gmFlags & GM::kSkipTiled_Flag)) { - pipeErrors |= test_tiled_pipe_playback(gm, compareConfig, - comparisonBitmap, - readPath, diffPath); + pipeErrors |= gmmain.test_tiled_pipe_playback(gm, compareConfig, + comparisonBitmap, + readPath, + diffPath); if (is_recordable_failure(pipeErrors)) { - failedTests.push_back(make_name(shortName, "pipe-tiled")); + failedTests.push_back(gmmain.make_name(shortName, + "pipe-tiled")); } } |