From b6e806bf17ffcca0c147a7dab4fba104fe928a58 Mon Sep 17 00:00:00 2001 From: "scroggo@google.com" Date: Wed, 3 Oct 2012 17:32:33 +0000 Subject: Allow render_pictures to render using multiple threads. Make write() a static function so it can be used by the thread entry functions. Add a helper function to append a number to a string and call write to share code. Review URL: https://codereview.appspot.com/6589062 git-svn-id: http://skia.googlecode.com/svn/trunk@5789 2bbb7eff-a529-9590-31e7-b0007b416f81 --- tools/PictureRenderer.cpp | 98 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 31 deletions(-) (limited to 'tools/PictureRenderer.cpp') diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp index 2eb89b2370..247875250d 100644 --- a/tools/PictureRenderer.cpp +++ b/tools/PictureRenderer.cpp @@ -99,10 +99,16 @@ void PictureRenderer::resetState() { #endif } -bool PictureRenderer::write(SkCanvas* canvas, SkString path) const { +/** + * 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. + * @return bool True if the Canvas is written to a file. + */ +static bool write(SkCanvas* canvas, SkString path) { SkASSERT(canvas != NULL); - SkASSERT(fPicture != NULL); - if (NULL == canvas || NULL == fPicture) { + if (NULL == canvas) { return false; } @@ -118,6 +124,19 @@ bool PictureRenderer::write(SkCanvas* canvas, SkString path) const { return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); } +/** + * If path is non NULL, append number to it, and call write(SkCanvas*, SkString) 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) { + if (NULL == path) { + return true; + } + SkString pathWithNumber(*path); + pathWithNumber.appendf("%i", number); + return write(canvas, pathWithNumber); +} + /////////////////////////////////////////////////////////////////////////////////////////////// bool RecordPictureRenderer::render(const SkString*) { @@ -144,7 +163,7 @@ bool PipePictureRenderer::render(const SkString* path) { pipeCanvas->drawPicture(*fPicture); writer.endRecording(); fCanvas->flush(); - return path != NULL && this->write(fCanvas, *path); + return path != NULL && write(fCanvas, *path); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -158,7 +177,7 @@ bool SimplePictureRenderer::render(const SkString* path) { fCanvas->drawPicture(*fPicture); fCanvas->flush(); - return path != NULL && this->write(fCanvas, *path); + return path != NULL && write(fCanvas, *path); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -307,23 +326,32 @@ static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playba // Base class for data used both by pipe and clone picture multi threaded drawing. struct ThreadData { - ThreadData(SkCanvas* target, int* tileCounter, SkTDArray* tileRects) + ThreadData(SkCanvas* target, int* tileCounter, SkTDArray* tileRects, + const SkString* path, bool* success) : fCanvas(target) , fTileCounter(tileCounter) - , fTileRects(tileRects) { + , fTileRects(tileRects) + , fPath(path) + , fSuccess(success) { SkASSERT(target != NULL && tileCounter != NULL && tileRects != NULL); + // Success must start off true, and it will be set to false upon failure. + SkASSERT(success != NULL && *success); } - const SkRect* nextTile() { + int32_t nextTile(SkRect* rect) { int32_t i = sk_atomic_inc(fTileCounter); if (i < fTileRects->count()) { - return &fTileRects->operator[](i); + SkASSERT(rect != NULL); + *rect = fTileRects->operator[](i); + return i; } - return NULL; + return -1; } // All of these are pointers to objects owned elsewhere SkCanvas* fCanvas; + const SkString* fPath; + bool* fSuccess; private: // Shared by all threads, this states which is the next tile to be drawn. int32_t* fTileCounter; @@ -337,8 +365,8 @@ private: struct TileData : public ThreadData { TileData(ThreadSafePipeController* controller, SkCanvas* canvas, int* tileCounter, - SkTDArray* tileRects) - : INHERITED(canvas, tileCounter, tileRects) + SkTDArray* tileRects, const SkString* path, bool* success) + : INHERITED(canvas, tileCounter, tileRects, path, success) , fController(controller) {} ThreadSafePipeController* fController; @@ -350,9 +378,14 @@ static void DrawTile(void* data) { SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024); TileData* tileData = static_cast(data); - const SkRect* tileRect; - while ((tileRect = tileData->nextTile()) != NULL) { - DrawTileToCanvas(tileData->fCanvas, *tileRect, tileData->fController); + SkRect tileRect; + int32_t i; + while ((i = tileData->nextTile(&tileRect)) != -1) { + DrawTileToCanvas(tileData->fCanvas, tileRect, tileData->fController); + if (!writeAppendNumber(tileData->fCanvas, tileData->fPath, i)) { + *tileData->fSuccess = false; + break; + } } SkDELETE(tileData); } @@ -361,8 +394,9 @@ static void DrawTile(void* data) { // Draw using Picture struct CloneData : public ThreadData { - CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray* tileRects) - : INHERITED(target, tileCounter, tileRects) + CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray* tileRects, + const SkString* path, bool* success) + : INHERITED(target, tileCounter, tileRects, path, success) , fClone(clone) {} SkPicture* fClone; @@ -374,9 +408,14 @@ static void DrawClonedTiles(void* data) { SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024); CloneData* cloneData = static_cast(data); - const SkRect* tileRect; - while ((tileRect = cloneData->nextTile()) != NULL) { - DrawTileToCanvas(cloneData->fCanvas, *tileRect, cloneData->fClone); + SkRect tileRect; + int32_t i; + while ((i = cloneData->nextTile(&tileRect)) != -1) { + DrawTileToCanvas(cloneData->fCanvas, tileRect, cloneData->fClone); + if (!writeAppendNumber(cloneData->fCanvas, cloneData->fPath, i)) { + *cloneData->fSuccess = false; + break; + } } SkDELETE(cloneData); } @@ -416,15 +455,17 @@ bool TiledPictureRenderer::render(const SkString* path) { SkASSERT(fCanvasPool.count() == fNumThreads); SkTDArray threads; SkThread::entryPointProc proc = fUsePipe ? DrawTile : DrawClonedTiles; + bool success = true; for (int i = 0; i < fNumThreads; ++i) { // data will be deleted by the entryPointProc. ThreadData* data; if (fUsePipe) { - data = SkNEW_ARGS(TileData, - (fPipeController, fCanvasPool[i], &fTileCounter, &fTileRects)); + data = SkNEW_ARGS(TileData, (fPipeController, fCanvasPool[i], &fTileCounter, + &fTileRects, path, &success)); } else { SkPicture* pic = (0 == i) ? fPicture : &fPictureClones[i-1]; - data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects)); + data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects, path, + &success)); } SkThread* thread = SkNEW_ARGS(SkThread, (proc, data)); if (!thread->start()) { @@ -439,8 +480,7 @@ bool TiledPictureRenderer::render(const SkString* path) { SkDELETE(thread); } threads.reset(); - // Currently multithreaded is not an option for render_pictures - return false; + return success; } else { // For single thread, we really only need one canvas total. SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight); @@ -448,12 +488,8 @@ bool TiledPictureRenderer::render(const SkString* path) { for (int i = 0; i < fTileRects.count(); ++i) { DrawTileToCanvas(canvas, fTileRects[i], fPicture); - if (path != NULL) { - SkString tilePath(*path); - tilePath.appendf("%i", i); - if (!this->write(canvas, tilePath)) { - return false; - } + if (!writeAppendNumber(canvas, path, i)) { + return false; } } return path != NULL; -- cgit v1.2.3