| Index: tools/PictureRenderer.cpp
|
| diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
|
| index 466e31d28e159ba4bdeae3d080e0f50b9fa7458b..f62a05d846df9a2dd3882e81090d2e7ad5064d43 100644
|
| --- a/tools/PictureRenderer.cpp
|
| +++ b/tools/PictureRenderer.cpp
|
| @@ -58,15 +58,19 @@ const static char kJsonKey_ActualResults[] = "actual-results";
|
| const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
|
| const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
|
|
|
| -void ImageResultsSummary::add(const char *testName, const SkBitmap& bitmap) {
|
| - uint64_t hash;
|
| - SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash));
|
| +void ImageResultsSummary::add(const char *testName, uint64_t hash) {
|
| Json::Value jsonTypeValuePair;
|
| jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
|
| jsonTypeValuePair.append(Json::UInt64(hash));
|
| fActualResultsNoComparison[testName] = jsonTypeValuePair;
|
| }
|
|
|
| +void ImageResultsSummary::add(const char *testName, const SkBitmap& bitmap) {
|
| + uint64_t hash;
|
| + SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash));
|
| + this->add(testName, hash);
|
| +}
|
| +
|
| void ImageResultsSummary::writeToFile(const char *filename) {
|
| Json::Value actualResults;
|
| actualResults[kJsonKey_ActualResults_NoComparison] = fActualResultsNoComparison;
|
| @@ -77,7 +81,12 @@ void ImageResultsSummary::writeToFile(const char *filename) {
|
| stream.write(jsonStdString.c_str(), jsonStdString.length());
|
| }
|
|
|
| -void PictureRenderer::init(SkPicture* pict) {
|
| +void PictureRenderer::init(SkPicture* pict, const SkString* outputDir,
|
| + const SkString* inputFilename, bool useChecksumBasedFilenames) {
|
| + this->CopyString(&fOutputDir, outputDir);
|
| + this->CopyString(&fInputFilename, inputFilename);
|
| + fUseChecksumBasedFilenames = useChecksumBasedFilenames;
|
| +
|
| SkASSERT(NULL == fPicture);
|
| SkASSERT(NULL == fCanvas.get());
|
| if (fPicture != NULL || NULL != fCanvas.get()) {
|
| @@ -94,6 +103,14 @@ void PictureRenderer::init(SkPicture* pict) {
|
| fCanvas.reset(this->setupCanvas());
|
| }
|
|
|
| +void PictureRenderer::CopyString(SkString* dest, const SkString* src) {
|
| + if (NULL != src) {
|
| + dest->set(*src);
|
| + } else {
|
| + dest->reset();
|
| + }
|
| +}
|
| +
|
| class FlagsDrawFilter : public SkDrawFilter {
|
| public:
|
| FlagsDrawFilter(PictureRenderer::DrawFilterFlags* flags) :
|
| @@ -281,10 +298,13 @@ uint32_t PictureRenderer::recordFlags() {
|
|
|
| /**
|
| * Write the canvas to the specified path.
|
| + *
|
| * @param canvas Must be non-null. Canvas to be written to a file.
|
| - * @param path Path for the file to be written. Should have no extension; write() will append
|
| - * an appropriate one. Passed in by value so it can be modified.
|
| + * @param outputDir If nonempty, write the binary image to a file within this directory.
|
| + * @param inputFilename If we are writing out a binary image, use this to build its filename.
|
| * @param jsonSummaryPtr If not null, add image results to this summary.
|
| + * @param useChecksumBasedFilenames If true, use checksum-based filenames when writing to disk.
|
| + * @param numberToAppend If not null, append this number to the filename.
|
| * @return bool True if the Canvas is written to a file.
|
| *
|
| * TODO(epoger): Right now, all canvases must pass through this function in order to be appended
|
| @@ -295,51 +315,62 @@ uint32_t PictureRenderer::recordFlags() {
|
| * called even if --writePath was not specified...
|
| * const char *outputDir // NULL if we don't want to write image files to disk
|
| * const char *filename // name we use within JSON summary, and as the filename within outputDir
|
| + *
|
| + * UPDATE: Now that outputDir and inputFilename are passed separately, we should be able to do that.
|
| */
|
| -static bool write(SkCanvas* canvas, const SkString* path, ImageResultsSummary *jsonSummaryPtr) {
|
| +static bool write(SkCanvas* canvas, const SkString& outputDir, const SkString& inputFilename,
|
| + ImageResultsSummary *jsonSummaryPtr, bool useChecksumBasedFilenames,
|
| + const int* numberToAppend=NULL) {
|
| SkASSERT(canvas != NULL);
|
| if (NULL == canvas) {
|
| return false;
|
| }
|
|
|
| - SkASSERT(path != NULL); // TODO(epoger): we want to remove this constraint, as noted above
|
| - SkString fullPathname(*path);
|
| - fullPathname.append(".png");
|
| -
|
| SkBitmap bitmap;
|
| SkISize size = canvas->getDeviceSize();
|
| sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
|
|
|
| + // Make sure we only compute the bitmap hash once (at most).
|
| + uint64_t hash;
|
| + bool generatedHash = false;
|
| +
|
| canvas->readPixels(&bitmap, 0, 0);
|
| sk_tools::force_all_opaque(bitmap);
|
|
|
| - if (NULL != jsonSummaryPtr) {
|
| - // EPOGER: This is a hacky way of constructing the filename associated with the
|
| - // image checksum; we assume that outputDir is not NULL, and we remove outputDir
|
| - // from fullPathname.
|
| - //
|
| - // EPOGER: what about including the config type within hashFilename? That way,
|
| - // we could combine results of different config types without conflicting filenames.
|
| - SkString hashFilename;
|
| - sk_tools::get_basename(&hashFilename, fullPathname);
|
| - jsonSummaryPtr->add(hashFilename.c_str(), bitmap);
|
| + SkString outputFilename(inputFilename);
|
| + outputFilename.remove(outputFilename.size() - 4, 4);
|
| + if (NULL != numberToAppend) {
|
| + outputFilename.appendf("%i", *numberToAppend);
|
| }
|
| + outputFilename.append(".png");
|
| + // TODO(epoger): what about including the config type within outputFilename? That way,
|
| + // we could combine results of different config types without conflicting filenames.
|
|
|
| - return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
|
| -}
|
| + if (NULL != jsonSummaryPtr) {
|
| + if (!generatedHash) {
|
| + SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash));
|
| + generatedHash = true;
|
| + }
|
| + jsonSummaryPtr->add(outputFilename.c_str(), hash);
|
| + }
|
|
|
| -/**
|
| - * If path is non NULL, append number to it, and call write() to write the
|
| - * provided canvas to a file. Returns true if path is NULL or if write() succeeds.
|
| - */
|
| -static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number,
|
| - ImageResultsSummary *jsonSummaryPtr) {
|
| - if (NULL == path) {
|
| - return true;
|
| + // Update outputFilename AFTER adding to JSON summary, but BEFORE writing out the image file.
|
| + if (useChecksumBasedFilenames) {
|
| + if (!generatedHash) {
|
| + SkAssertResult(SkBitmapHasher::ComputeDigest(bitmap, &hash));
|
| + generatedHash = true;
|
| + }
|
| + outputFilename.set(kJsonKey_Hashtype_Bitmap_64bitMD5);
|
| + outputFilename.append("_");
|
| + outputFilename.appendU64(hash);
|
| + outputFilename.append(".png");
|
| }
|
| - SkString pathWithNumber(*path);
|
| - pathWithNumber.appendf("%i", number);
|
| - return write(canvas, &pathWithNumber, jsonSummaryPtr);
|
| +
|
| + SkASSERT(!outputDir.isEmpty()); // TODO(epoger): we want to remove this constraint,
|
| + // as noted above
|
| + SkString fullPathname;
|
| + make_filepath(&fullPathname, outputDir, outputFilename);
|
| + return SkImageEncoder::EncodeFile(fullPathname.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////////////////////
|
| @@ -354,18 +385,17 @@ static SkData* encode_bitmap_to_data(size_t*, const SkBitmap& bm) {
|
| return SkImageEncoder::EncodeData(bm, SkImageEncoder::kPNG_Type, 100);
|
| }
|
|
|
| -bool RecordPictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| +bool RecordPictureRenderer::render(SkBitmap** out) {
|
| SkAutoTUnref<SkPicture> replayer(this->createPicture());
|
| SkCanvas* recorder = replayer->beginRecording(this->getViewWidth(), this->getViewHeight(),
|
| this->recordFlags());
|
| this->scaleToScaleFactor(recorder);
|
| fPicture->draw(recorder);
|
| replayer->endRecording();
|
| - if (path != NULL) {
|
| + if (!fOutputDir.isEmpty()) {
|
| // Record the new picture as a new SKP with PNG encoded bitmaps.
|
| - SkString skpPath(*path);
|
| - // ".skp" was removed from 'path' before being passed in here.
|
| - skpPath.append(".skp");
|
| + SkString skpPath;
|
| + make_filepath(&skpPath, fOutputDir, fInputFilename);
|
| SkFILEWStream stream(skpPath.c_str());
|
| replayer->serialize(&stream, &encode_bitmap_to_data);
|
| return true;
|
| @@ -379,7 +409,7 @@ SkString RecordPictureRenderer::getConfigNameInternal() {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
| -bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| +bool PipePictureRenderer::render(SkBitmap** out) {
|
| SkASSERT(fCanvas.get() != NULL);
|
| SkASSERT(fPicture != NULL);
|
| if (NULL == fCanvas.get() || NULL == fPicture) {
|
| @@ -392,8 +422,9 @@ bool PipePictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| pipeCanvas->drawPicture(*fPicture);
|
| writer.endRecording();
|
| fCanvas->flush();
|
| - if (NULL != path) {
|
| - return write(fCanvas, path, fJsonSummaryPtr);
|
| + if (!fOutputDir.isEmpty()) {
|
| + return write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr,
|
| + fUseChecksumBasedFilenames);
|
| }
|
| if (NULL != out) {
|
| *out = SkNEW(SkBitmap);
|
| @@ -409,12 +440,13 @@ SkString PipePictureRenderer::getConfigNameInternal() {
|
|
|
| ///////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
| -void SimplePictureRenderer::init(SkPicture* picture) {
|
| - INHERITED::init(picture);
|
| +void SimplePictureRenderer::init(SkPicture* picture, const SkString* outputDir,
|
| + const SkString* inputFilename, bool useChecksumBasedFilenames) {
|
| + INHERITED::init(picture, outputDir, inputFilename, useChecksumBasedFilenames);
|
| this->buildBBoxHierarchy();
|
| }
|
|
|
| -bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| +bool SimplePictureRenderer::render(SkBitmap** out) {
|
| SkASSERT(fCanvas.get() != NULL);
|
| SkASSERT(fPicture != NULL);
|
| if (NULL == fCanvas.get() || NULL == fPicture) {
|
| @@ -423,8 +455,9 @@ bool SimplePictureRenderer::render(const SkString* path, SkBitmap** out) {
|
|
|
| fCanvas->drawPicture(*fPicture);
|
| fCanvas->flush();
|
| - if (NULL != path) {
|
| - return write(fCanvas, path, fJsonSummaryPtr);
|
| + if (!fOutputDir.isEmpty()) {
|
| + return write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr,
|
| + fUseChecksumBasedFilenames);
|
| }
|
|
|
| if (NULL != out) {
|
| @@ -452,7 +485,8 @@ TiledPictureRenderer::TiledPictureRenderer()
|
| , fTilesX(0)
|
| , fTilesY(0) { }
|
|
|
| -void TiledPictureRenderer::init(SkPicture* pict) {
|
| +void TiledPictureRenderer::init(SkPicture* pict, const SkString* outputDir,
|
| + const SkString* inputFilename, bool useChecksumBasedFilenames) {
|
| SkASSERT(pict != NULL);
|
| SkASSERT(0 == fTileRects.count());
|
| if (NULL == pict || fTileRects.count() != 0) {
|
| @@ -462,6 +496,9 @@ void TiledPictureRenderer::init(SkPicture* pict) {
|
| // Do not call INHERITED::init(), which would create a (potentially large) canvas which is not
|
| // used by bench_pictures.
|
| fPicture = pict;
|
| + this->CopyString(&fOutputDir, outputDir);
|
| + this->CopyString(&fInputFilename, inputFilename);
|
| + fUseChecksumBasedFilenames = useChecksumBasedFilenames;
|
| fPicture->ref();
|
| this->buildBBoxHierarchy();
|
|
|
| @@ -623,7 +660,7 @@ void TiledPictureRenderer::drawCurrentTile() {
|
| draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
|
| }
|
|
|
| -bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| +bool TiledPictureRenderer::render(SkBitmap** out) {
|
| SkASSERT(fPicture != NULL);
|
| if (NULL == fPicture) {
|
| return false;
|
| @@ -638,8 +675,9 @@ bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
|
| bool success = true;
|
| for (int i = 0; i < fTileRects.count(); ++i) {
|
| draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
|
| - if (NULL != path) {
|
| - success &= writeAppendNumber(fCanvas, path, i, fJsonSummaryPtr);
|
| + if (!fOutputDir.isEmpty()) {
|
| + success &= write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr,
|
| + fUseChecksumBasedFilenames, &i);
|
| }
|
| if (NULL != out) {
|
| if (fCanvas->readPixels(&bitmap, 0, 0)) {
|
| @@ -698,16 +736,16 @@ class CloneData : public SkRunnable {
|
|
|
| public:
|
| CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int start, int end,
|
| - SkRunnable* done, ImageResultsSummary* jsonSummaryPtr)
|
| + SkRunnable* done, ImageResultsSummary* jsonSummaryPtr, bool useChecksumBasedFilenames)
|
| : fClone(clone)
|
| , fCanvas(canvas)
|
| - , fPath(NULL)
|
| , fRects(rects)
|
| , fStart(start)
|
| , fEnd(end)
|
| , fSuccess(NULL)
|
| , fDone(done)
|
| - , fJsonSummaryPtr(jsonSummaryPtr) {
|
| + , fJsonSummaryPtr(jsonSummaryPtr)
|
| + , fUseChecksumBasedFilenames(useChecksumBasedFilenames) {
|
| SkASSERT(fDone != NULL);
|
| }
|
|
|
| @@ -722,7 +760,9 @@ public:
|
|
|
| for (int i = fStart; i < fEnd; i++) {
|
| draw_tile_to_canvas(fCanvas, fRects[i], fClone);
|
| - if ((fPath != NULL) && !writeAppendNumber(fCanvas, fPath, i, fJsonSummaryPtr)
|
| + if ((!fOutputDir.isEmpty())
|
| + && !write(fCanvas, fOutputDir, fInputFilename, fJsonSummaryPtr,
|
| + fUseChecksumBasedFilenames, &i)
|
| && fSuccess != NULL) {
|
| *fSuccess = false;
|
| // If one tile fails to write to a file, do not continue drawing the rest.
|
| @@ -743,8 +783,10 @@ public:
|
| fDone->run();
|
| }
|
|
|
| - void setPathAndSuccess(const SkString* path, bool* success) {
|
| - fPath = path;
|
| + void setPathsAndSuccess(const SkString& outputDir, const SkString& inputFilename,
|
| + bool* success) {
|
| + fOutputDir.set(outputDir);
|
| + fInputFilename.set(inputFilename);
|
| fSuccess = success;
|
| }
|
|
|
| @@ -757,7 +799,8 @@ private:
|
| SkPicture* fClone; // Picture to draw from. Each CloneData has a unique one which
|
| // is threadsafe.
|
| SkCanvas* fCanvas; // Canvas to draw to. Reused for each tile.
|
| - const SkString* fPath; // If non-null, path to write the result to as a PNG.
|
| + SkString fOutputDir; // If not empty, write results into this directory.
|
| + SkString fInputFilename; // Filename of input SkPicture file.
|
| SkTDArray<SkRect>& fRects; // All tiles of the picture.
|
| const int fStart; // Range of tiles drawn by this thread.
|
| const int fEnd;
|
| @@ -766,6 +809,7 @@ private:
|
| SkRunnable* fDone;
|
| SkBitmap* fBitmap;
|
| ImageResultsSummary* fJsonSummaryPtr;
|
| + bool fUseChecksumBasedFilenames;
|
| };
|
|
|
| MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
|
| @@ -778,9 +822,10 @@ MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
|
| fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads);
|
| }
|
|
|
| -void MultiCorePictureRenderer::init(SkPicture *pict) {
|
| +void MultiCorePictureRenderer::init(SkPicture *pict, const SkString* outputDir,
|
| + const SkString* inputFilename, bool useChecksumBasedFilenames) {
|
| // Set fPicture and the tiles.
|
| - this->INHERITED::init(pict);
|
| + this->INHERITED::init(pict, outputDir, inputFilename, useChecksumBasedFilenames);
|
| for (int i = 0; i < fNumThreads; ++i) {
|
| *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->getTileHeight());
|
| }
|
| @@ -802,15 +847,15 @@ void MultiCorePictureRenderer::init(SkPicture *pict) {
|
| const int end = SkMin32(start + chunkSize, fTileRects.count());
|
| fCloneData[i] = SkNEW_ARGS(CloneData,
|
| (pic, fCanvasPool[i], fTileRects, start, end, &fCountdown,
|
| - fJsonSummaryPtr));
|
| + fJsonSummaryPtr, useChecksumBasedFilenames));
|
| }
|
| }
|
|
|
| -bool MultiCorePictureRenderer::render(const SkString *path, SkBitmap** out) {
|
| +bool MultiCorePictureRenderer::render(SkBitmap** out) {
|
| bool success = true;
|
| - if (path != NULL) {
|
| + if (!fOutputDir.isEmpty()) {
|
| for (int i = 0; i < fNumThreads-1; i++) {
|
| - fCloneData[i]->setPathAndSuccess(path, &success);
|
| + fCloneData[i]->setPathsAndSuccess(fOutputDir, fInputFilename, &success);
|
| }
|
| }
|
|
|
| @@ -868,7 +913,7 @@ void PlaybackCreationRenderer::setup() {
|
| fPicture->draw(recorder);
|
| }
|
|
|
| -bool PlaybackCreationRenderer::render(const SkString*, SkBitmap** out) {
|
| +bool PlaybackCreationRenderer::render(SkBitmap** out) {
|
| fReplayer->endRecording();
|
| // Since this class does not actually render, return false.
|
| return false;
|
| @@ -915,14 +960,14 @@ SkPicture* PictureRenderer::createPicture() {
|
|
|
| class GatherRenderer : public PictureRenderer {
|
| public:
|
| - virtual bool render(const SkString* path, SkBitmap** out = NULL)
|
| + virtual bool render(SkBitmap** out = NULL)
|
| SK_OVERRIDE {
|
| SkRect bounds = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
|
| SkIntToScalar(fPicture->height()));
|
| SkData* data = SkPictureUtils::GatherPixelRefs(fPicture, bounds);
|
| SkSafeUnref(data);
|
|
|
| - return NULL == path; // we don't have anything to write
|
| + return (fOutputDir.isEmpty()); // we don't have anything to write
|
| }
|
|
|
| private:
|
| @@ -939,14 +984,14 @@ PictureRenderer* CreateGatherPixelRefsRenderer() {
|
|
|
| class PictureCloneRenderer : public PictureRenderer {
|
| public:
|
| - virtual bool render(const SkString* path, SkBitmap** out = NULL)
|
| + virtual bool render(SkBitmap** out = NULL)
|
| SK_OVERRIDE {
|
| for (int i = 0; i < 100; ++i) {
|
| SkPicture* clone = fPicture->clone();
|
| SkSafeUnref(clone);
|
| }
|
|
|
| - return NULL == path; // we don't have anything to write
|
| + return (fOutputDir.isEmpty()); // we don't have anything to write
|
| }
|
|
|
| private:
|
|
|