diff options
author | 2012-08-31 16:15:22 +0000 | |
---|---|---|
committer | 2012-08-31 16:15:22 +0000 | |
commit | 58b4ead36c62d8c0256ee4da554f3df2744d904c (patch) | |
tree | f06d09d531ee6b37df515ab83734111aad8cb5b0 | |
parent | b1d47e211c95779ed283b78a85abbd0bd5668871 (diff) |
Perform multi core rendering in bench_pictures.
Add a flag in SkGPipeWriter for threadsafe drawing.
Add a deferred pipe controller to SamplePipeControllers, which can
be called to play back in multiple threads.
Depends on http://codereview.appspot.com/6459105/
Review URL: https://codereview.appspot.com/6482068
git-svn-id: http://skia.googlecode.com/svn/trunk@5371 2bbb7eff-a529-9590-31e7-b0007b416f81
-rw-r--r-- | gyp/tools.gyp | 4 | ||||
-rw-r--r-- | include/core/SkTemplates.h | 4 | ||||
-rw-r--r-- | include/pipe/SkGPipe.h | 11 | ||||
-rw-r--r-- | src/pipe/SkGPipeRead.cpp | 23 | ||||
-rw-r--r-- | src/pipe/utils/SamplePipeControllers.cpp | 37 | ||||
-rw-r--r-- | src/pipe/utils/SamplePipeControllers.h | 40 | ||||
-rw-r--r-- | tools/PictureBenchmark.cpp | 13 | ||||
-rw-r--r-- | tools/PictureBenchmark.h | 8 | ||||
-rw-r--r-- | tools/PictureRenderer.cpp | 108 | ||||
-rw-r--r-- | tools/PictureRenderer.h | 18 | ||||
-rw-r--r-- | tools/bench_pictures_main.cpp | 162 | ||||
-rw-r--r-- | tools/picture_utils.cpp | 2 | ||||
-rw-r--r-- | tools/picture_utils.h | 2 |
13 files changed, 336 insertions, 96 deletions
diff --git a/gyp/tools.gyp b/gyp/tools.gyp index 347812f834..02be7cfbdc 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -125,12 +125,14 @@ '../src/pipe/utils/SamplePipeControllers.cpp', ], 'include_dirs': [ - '../src/pipe/utils', + '../src/pipe/utils/', + '../src/utils/', ], 'dependencies': [ 'core.gyp:core', 'images.gyp:images', 'tools.gyp:picture_utils', + 'utils.gyp:utils', ], 'export_dependent_settings': [ 'images.gyp:images', diff --git a/include/core/SkTemplates.h b/include/core/SkTemplates.h index e4c8bc44ca..3570946316 100644 --- a/include/core/SkTemplates.h +++ b/include/core/SkTemplates.h @@ -93,10 +93,10 @@ private: template <typename T> class SkAutoTDeleteArray : SkNoncopyable { public: SkAutoTDeleteArray(T array[]) : fArray(array) {} - ~SkAutoTDeleteArray() { delete[] fArray; } + ~SkAutoTDeleteArray() { SkDELETE_ARRAY(fArray); } T* get() const { return fArray; } - void free() { delete[] fArray; fArray = NULL; } + void free() { SkDELETE_ARRAY(fArray); fArray = NULL; } T* detach() { T* array = fArray; fArray = NULL; return array; } private: diff --git a/include/pipe/SkGPipe.h b/include/pipe/SkGPipe.h index bbe504aee6..f1fc4b0ede 100644 --- a/include/pipe/SkGPipe.h +++ b/include/pipe/SkGPipe.h @@ -95,12 +95,19 @@ public: * (for example) we cannot put function pointers in the stream. */ kCrossProcess_Flag = 1 << 0, + /** * Only meaningful if kCrossProcess_Flag is set. Tells the writer that * in spite of being cross process, it will have shared address space - * with the reader, so the two can share large objects (like SkBitmaps) + * with the reader, so the two can share large objects (like SkBitmaps). + */ + kSharedAddressSpace_Flag = 1 << 1, + + /** + * Tells the writer that there will be multiple threads reading the stream + * simultaneously. */ - kSharedAddressSpace_Flag = 1 << 1 + kSimultaneousReaders_Flag = 1 << 2, }; SkCanvas* startRecording(SkGPipeController*, uint32_t flags = 0, diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp index ce83c83e83..803685a07d 100644 --- a/src/pipe/SkGPipeRead.cpp +++ b/src/pipe/SkGPipeRead.cpp @@ -426,17 +426,32 @@ public: private: SkBitmapHeapEntry* fHeapEntry; const SkBitmap* fBitmap; + SkBitmap fBitmapStorage; }; BitmapHolder::BitmapHolder(SkReader32* reader, uint32_t op32, SkGPipeState* state) { - unsigned index = DrawOp_unpackData(op32); - if (shouldFlattenBitmaps(state->getFlags())) { + const unsigned flags = state->getFlags(); + const unsigned index = DrawOp_unpackData(op32); + if (shouldFlattenBitmaps(flags)) { fHeapEntry = NULL; fBitmap = state->getBitmap(index); } else { - fHeapEntry = state->getSharedHeap()->getEntry(index); - fBitmap = fHeapEntry->getBitmap(); + SkBitmapHeapEntry* entry = state->getSharedHeap()->getEntry(index); + if (SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag)) { + // Make a shallow copy for thread safety. Each thread will point to the same SkPixelRef, + // which is thread safe. + fBitmapStorage = *entry->getBitmap(); + fBitmap = &fBitmapStorage; + // Release the ref on the bitmap now, since we made our own copy. + entry->releaseRef(); + fHeapEntry = NULL; + } else { + SkASSERT(!shouldFlattenBitmaps(flags)); + SkASSERT(!SkToBool(flags & SkGPipeWriter::kSimultaneousReaders_Flag)); + fHeapEntry = entry; + fBitmap = fHeapEntry->getBitmap(); + } } } diff --git a/src/pipe/utils/SamplePipeControllers.cpp b/src/pipe/utils/SamplePipeControllers.cpp index 740d1b835f..c54bd1334a 100644 --- a/src/pipe/utils/SamplePipeControllers.cpp +++ b/src/pipe/utils/SamplePipeControllers.cpp @@ -76,3 +76,40 @@ void TiledPipeController::notifyWritten(size_t bytes) { } this->INHERITED::notifyWritten(bytes); } + +//////////////////////////////////////////////////////////////////////////////// + +DeferredPipeController::DeferredPipeController(int numberOfReaders) +: fAllocator(kMinBlockSize) +, fNumberOfReaders(numberOfReaders) { + fBlock = NULL; + fBytesWritten = 0; +} + +void* DeferredPipeController::requestBlock(size_t minRequest, size_t *actual) { + if (fBlock) { + // Save the previous block for later + PipeBlock previousBloc(fBlock, fBytesWritten); + fBlockList.push(previousBloc); + } + int32_t blockSize = SkMax32(minRequest, kMinBlockSize); + fBlock = fAllocator.allocThrow(blockSize); + fBytesWritten = 0; + *actual = blockSize; + return fBlock; +} + +void DeferredPipeController::notifyWritten(size_t bytes) { + fBytesWritten += bytes; +} + +void DeferredPipeController::playback(SkCanvas* target) { + SkGPipeReader reader(target); + for (int currentBlock = 0; currentBlock < fBlockList.count(); currentBlock++ ) { + reader.playback(fBlockList[currentBlock].fBlock, fBlockList[currentBlock].fBytes); + } + + if (fBlock) { + reader.playback(fBlock, fBytesWritten); + } +} diff --git a/src/pipe/utils/SamplePipeControllers.h b/src/pipe/utils/SamplePipeControllers.h index 715693cce5..bbd802422c 100644 --- a/src/pipe/utils/SamplePipeControllers.h +++ b/src/pipe/utils/SamplePipeControllers.h @@ -6,7 +6,9 @@ */ #include "SkBitmap.h" +#include "SkChunkAlloc.h" #include "SkGPipe.h" +#include "SkTDArray.h" class SkCanvas; class SkMatrix; @@ -43,3 +45,41 @@ private: SkBitmap fBitmaps[NumberOfTiles]; typedef PipeController INHERITED; }; + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Borrowed (and modified) from SkDeferredCanvas.cpp::DeferredPipeController. + * Allows playing back from multiple threads. + */ +class DeferredPipeController : public SkGPipeController { +public: + DeferredPipeController(int numberOfReaders); + virtual void* requestBlock(size_t minRequest, size_t* actual) SK_OVERRIDE; + virtual void notifyWritten(size_t bytes) SK_OVERRIDE; + virtual int numberOfReaders() const SK_OVERRIDE { return fNumberOfReaders; } + + /** + * Play the stored drawing commands to the specified canvas. If SkGPipeWriter::startRecording + * used the flag SkGPipeWriter::kSimultaneousReaders_Flag, this can be called from different + * threads simultaneously. + */ + void playback(SkCanvas*); +private: + enum { + kMinBlockSize = 4096 + }; + struct PipeBlock { + PipeBlock(void* block, size_t bytes) { fBlock = block, fBytes = bytes; } + // Stream of draw commands written by the SkGPipeWriter. Allocated by fAllocator, which will + // handle freeing it. + void* fBlock; + // Number of bytes that were written to fBlock. + size_t fBytes; + }; + void* fBlock; + size_t fBytesWritten; + SkChunkAlloc fAllocator; + SkTDArray<PipeBlock> fBlockList; + int fNumberOfReaders; +}; diff --git a/tools/PictureBenchmark.cpp b/tools/PictureBenchmark.cpp index d24bb8b550..29152f8d69 100644 --- a/tools/PictureBenchmark.cpp +++ b/tools/PictureBenchmark.cpp @@ -194,13 +194,16 @@ void TiledPictureBenchmark::run(SkPicture* pict) { } SkString result; + if (fRenderer.isMultiThreaded()) { + result.printf("multithreaded using %s ", (fRenderer.isUsePipe() ? "pipe" : "picture")); + } if (fRenderer.getTileMinPowerOf2Width() > 0) { - result.printf("%i_pow2tiles_%iminx%i: msecs = %6.2f", fRenderer.numTiles(), - fRenderer.getTileMinPowerOf2Width(), fRenderer.getTileHeight(), - wall_time / fRepeats); + result.appendf("%i_pow2tiles_%iminx%i: msecs = %6.2f", fRenderer.numTiles(), + fRenderer.getTileMinPowerOf2Width(), fRenderer.getTileHeight(), + wall_time / fRepeats); } else { - result.printf("%i_tiles_%ix%i: msecs = %6.2f", fRenderer.numTiles(), - fRenderer.getTileWidth(), fRenderer.getTileHeight(), wall_time / fRepeats); + result.appendf("%i_tiles_%ix%i: msecs = %6.2f", fRenderer.numTiles(), + fRenderer.getTileWidth(), fRenderer.getTileHeight(), wall_time / fRepeats); } #if SK_SUPPORT_GPU if (fRenderer.isUsingGpuDevice()) { diff --git a/tools/PictureBenchmark.h b/tools/PictureBenchmark.h index f020c8d7e7..2a14ea2888 100644 --- a/tools/PictureBenchmark.h +++ b/tools/PictureBenchmark.h @@ -125,6 +125,14 @@ public: return fRenderer.getTileMinPowerOf2Width(); } + void setThreading(bool multi) { + fRenderer.setMultiThreaded(multi); + } + + void setUsePipe(bool usePipe) { + fRenderer.setUsePipe(usePipe); + } + private: TiledPictureRenderer fRenderer; typedef PictureBenchmark INHERITED; diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp index b7958e2d2e..d5b72ab7ce 100644 --- a/tools/PictureRenderer.cpp +++ b/tools/PictureRenderer.cpp @@ -6,22 +6,24 @@ */ #include "PictureRenderer.h" +#include "picture_utils.h" #include "SamplePipeControllers.h" #include "SkCanvas.h" #include "SkDevice.h" -#include "SkImageEncoder.h" #include "SkGPipe.h" +#if SK_SUPPORT_GPU +#include "SkGpuDevice.h" +#endif +#include "SkGraphics.h" +#include "SkImageEncoder.h" #include "SkMatrix.h" #include "SkPicture.h" #include "SkScalar.h" #include "SkString.h" +#include "SkTemplates.h" #include "SkTDArray.h" +#include "SkThreadUtils.h" #include "SkTypes.h" -#include "picture_utils.h" - -#if SK_SUPPORT_GPU -#include "SkGpuDevice.h" -#endif namespace sk_tools { @@ -156,7 +158,9 @@ void SimplePictureRenderer::render() { } TiledPictureRenderer::TiledPictureRenderer() - : fTileWidth(kDefaultTileWidth) + : fMultiThreaded(false) + , fUsePipe(false) + , fTileWidth(kDefaultTileWidth) , fTileHeight(kDefaultTileHeight) , fTileMinPowerOf2Width(0) , fTileHeightPercentage(0.0) @@ -236,7 +240,7 @@ void TiledPictureRenderer::setupTiles() { // constraints are that every tile must have a pixel width that is a power of // two and also be of some minimal width (that is also a power of two). // -// This is sovled by first taking our picture size and rounding it up to the +// This is solved by first taking our picture size and rounding it up to the // multiple of the minimal width. The binary representation of this rounded // value gives us the tiles we need: a bit of value one means we need a tile of // that size. @@ -275,9 +279,93 @@ void TiledPictureRenderer::deleteTiles() { fTiles.reset(); } +/////////////////////////////////////////////////////////////////////////////////////////////// +// Draw using Pipe + +struct TileData { + TileData(SkCanvas* canvas, DeferredPipeController* controller); + SkCanvas* fCanvas; + DeferredPipeController* fController; + SkThread fThread; +}; + +static void DrawTile(void* data) { + SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024); + TileData* tileData = static_cast<TileData*>(data); + tileData->fController->playback(tileData->fCanvas); +} + +TileData::TileData(SkCanvas* canvas, DeferredPipeController* controller) +: fCanvas(canvas) +, fController(controller) +, fThread(&DrawTile, static_cast<void*>(this)) {} + +/////////////////////////////////////////////////////////////////////////////////////////////// +// Draw using Picture + +struct CloneData { + CloneData(SkCanvas* target, SkPicture* original); + SkCanvas* fCanvas; + SkPicture* fClone; + SkThread fThread; +}; + +static void DrawClonedTile(void* data) { + SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024); + CloneData* cloneData = static_cast<CloneData*>(data); + cloneData->fCanvas->drawPicture(*cloneData->fClone); +} + +CloneData::CloneData(SkCanvas* target, SkPicture* clone) +: fCanvas(target) +, fClone(clone) +, fThread(&DrawClonedTile, static_cast<void*>(this)) {} + +/////////////////////////////////////////////////////////////////////////////////////////////// + void TiledPictureRenderer::drawTiles() { - for (int i = 0; i < fTiles.count(); ++i) { - fTiles[i]->drawPicture(*(fPicture)); + if (fMultiThreaded) { + if (fUsePipe) { + // First, draw into a pipe controller + SkGPipeWriter writer; + DeferredPipeController controller(fTiles.count()); + SkCanvas* pipeCanvas = writer.startRecording(&controller, + SkGPipeWriter::kSimultaneousReaders_Flag); + pipeCanvas->drawPicture(*(fPicture)); + writer.endRecording(); + + // Create and start the threads. + TileData* tileData[fTiles.count()]; + for (int i = 0; i < fTiles.count(); i++) { + tileData[i] = SkNEW_ARGS(TileData, (fTiles[i], &controller)); + if (!tileData[i]->fThread.start()) { + SkDebugf("could not start thread %i\n", i); + } + } + for (int i = 0; i < fTiles.count(); i++) { + tileData[i]->fThread.join(); + SkDELETE(tileData[i]); + } + } else { + SkPicture* clones = SkNEW_ARRAY(SkPicture, fTiles.count()); + SkAutoTDeleteArray<SkPicture> autodelete(clones); + fPicture->clone(clones, fTiles.count()); + CloneData* cloneData[fTiles.count()]; + for (int i = 0; i < fTiles.count(); i++) { + cloneData[i] = SkNEW_ARGS(CloneData, (fTiles[i], &clones[i])); + if (!cloneData[i]->fThread.start()) { + SkDebugf("Could not start picture thread %i\n", i); + } + } + for (int i = 0; i < fTiles.count(); i++) { + cloneData[i]->fThread.join(); + SkDELETE(cloneData[i]); + } + } + } else { + for (int i = 0; i < fTiles.count(); ++i) { + fTiles[i]->drawPicture(*(fPicture)); + } } } diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h index 25e2ba4721..c901903cfe 100644 --- a/tools/PictureRenderer.h +++ b/tools/PictureRenderer.h @@ -163,12 +163,30 @@ public: return fTiles.count(); } + void setMultiThreaded(bool multi) { + fMultiThreaded = multi; + } + + bool isMultiThreaded() const { + return fMultiThreaded; + } + + void setUsePipe(bool usePipe) { + fUsePipe = usePipe; + } + + bool isUsePipe() const { + return fUsePipe; + } + ~TiledPictureRenderer(); protected: virtual void finishDraw(); private: + bool fMultiThreaded; + bool fUsePipe; int fTileWidth; int fTileHeight; double fTileWidthPercentage; diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp index 1579f692f4..084a971acd 100644 --- a/tools/bench_pictures_main.cpp +++ b/tools/bench_pictures_main.cpp @@ -23,8 +23,9 @@ static void usage(const char* argv0) { "Usage: \n" " %s <inputDir>...\n" " [--repeat] \n" -" [--mode pipe | pow2tile minWidth height[%] | record | simple\n" -" | tile width[%] height[%] | unflatten]\n" +" [--mode pow2tile minWidth height[] (multi) | record | simple\n" +" | tile width[] height[] (multi) | unflatten]\n" +" [--pipe]\n" " [--device bitmap" #if SK_SUPPORT_GPU " | gpu" @@ -36,32 +37,37 @@ static void usage(const char* argv0) { " inputDir: A list of directories and files to use as input. Files are\n" " expected to have the .skp extension.\n\n"); SkDebugf( -" --mode pipe | pow2tile minWidht height[%] | record | simple\n" -" | tile width[%] height[%] | unflatten: Run in the corresponding mode.\n" -" Default is simple.\n"); +" --mode pow2tile minWidht height[] (multi) | record | simple\n" +" | tile width[] height[] (multi) | unflatten:\n" +" Run in the corresponding mode.\n" +" Default is simple.\n"); SkDebugf( -" pipe, Benchmark SkGPipe rendering.\n"); - SkDebugf( -" pow2tile minWidth height[%], Creates tiles with widths\n" -" that are all a power of two\n" -" such that they minimize the\n" -" amount of wasted tile space.\n" -" minWidth is the minimum width\n" -" of these tiles and must be a\n" -" power of two. Simple\n" -" rendering using these tiles\n" -" is benchmarked.\n"); +" pow2tile minWidth height[], Creates tiles with widths\n" +" that are all a power of two\n" +" such that they minimize the\n" +" amount of wasted tile space.\n" +" minWidth is the minimum width\n" +" of these tiles and must be a\n" +" power of two. Simple\n" +" rendering using these tiles\n" +" is benchmarked.\n" +" Append \"multi\" for multithreaded\n" +" drawing.\n"); SkDebugf( " record, Benchmark picture to picture recording.\n"); SkDebugf( " simple, Benchmark a simple rendering.\n"); SkDebugf( -" tile width[%] height[%], Benchmark simple rendering using\n" -" tiles with the given dimensions.\n"); +" tile width[] height[], Benchmark simple rendering using\n" +" tiles with the given dimensions.\n" +" Append \"multi\" for multithreaded\n" +" drawing.\n"); SkDebugf( " unflatten, Benchmark picture unflattening.\n"); SkDebugf("\n"); SkDebugf( +" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n"); + SkDebugf( " --device bitmap" #if SK_SUPPORT_GPU " | gpu" @@ -112,6 +118,13 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* sk_tools::PictureRenderer::SkDeviceTypes deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType; + bool usePipe = false; + bool multiThreaded = false; + bool useTiles = false; + const char* widthString = NULL; + const char* heightString = NULL; + bool isPowerOf2Mode = false; + const char* mode = NULL; for (++argv; argv < stop; ++argv) { if (0 == strcmp(*argv, "--repeat")) { ++argv; @@ -128,6 +141,8 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* usage(argv0); exit(-1); } + } else if (0 == strcmp(*argv, "--pipe")) { + usePipe = true; } else if (0 == strcmp(*argv, "--mode")) { SkDELETE(benchmark); @@ -138,82 +153,40 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* exit(-1); } - if (0 == strcmp(*argv, "pipe")) { - benchmark = SkNEW(sk_tools::PipePictureBenchmark); - } else if (0 == strcmp(*argv, "record")) { + if (0 == strcmp(*argv, "record")) { benchmark = SkNEW(sk_tools::RecordPictureBenchmark); } else if (0 == strcmp(*argv, "simple")) { benchmark = SkNEW(sk_tools::SimplePictureBenchmark); } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) { - char* mode = *argv; - bool isPowerOf2Mode = false; + useTiles = true; + mode = *argv; if (0 == strcmp(*argv, "pow2tile")) { isPowerOf2Mode = true; } - sk_tools::TiledPictureBenchmark* tileBenchmark = - SkNEW(sk_tools::TiledPictureBenchmark); ++argv; if (argv >= stop) { - SkDELETE(tileBenchmark); SkDebugf("Missing width for --mode %s\n", mode); usage(argv0); exit(-1); } - if (isPowerOf2Mode) { - int minWidth = atoi(*argv); - - if (!SkIsPow2(minWidth) || minWidth <= 0) { - SkDELETE(tileBenchmark); - SkDebugf("--mode %s must be given a width" - " value that is a power of two\n", mode); - exit(-1); - } - - tileBenchmark->setTileMinPowerOf2Width(minWidth); - } else if (sk_tools::is_percentage(*argv)) { - tileBenchmark->setTileWidthPercentage(atof(*argv)); - if (!(tileBenchmark->getTileWidthPercentage() > 0)) { - SkDELETE(tileBenchmark); - SkDebugf("--mode %s must be given a width percentage > 0\n", mode); - exit(-1); - } - } else { - tileBenchmark->setTileWidth(atoi(*argv)); - if (!(tileBenchmark->getTileWidth() > 0)) { - SkDELETE(tileBenchmark); - SkDebugf("--mode %s must be given a width > 0\n", mode); - exit(-1); - } - } - + widthString = *argv; ++argv; if (argv >= stop) { - SkDELETE(tileBenchmark); - SkDebugf("Missing height for --mode %s\n", mode); + SkDebugf("Missing height for --mode tile\n"); usage(argv0); exit(-1); } + heightString = *argv; - if (sk_tools::is_percentage(*argv)) { - tileBenchmark->setTileHeightPercentage(atof(*argv)); - if (!(tileBenchmark->getTileHeightPercentage() > 0)) { - SkDELETE(tileBenchmark); - SkDebugf("--mode %s must be given a height percentage > 0\n", mode); - exit(-1); - } + ++argv; + if (argv < stop && 0 == strcmp(*argv, "multi")) { + multiThreaded = true; } else { - tileBenchmark->setTileHeight(atoi(*argv)); - if (!(tileBenchmark->getTileHeight() > 0)) { - SkDELETE(tileBenchmark); - SkDebugf("--mode %s must be given a height > 0\n", mode); - exit(-1); - } + --argv; } - - benchmark = tileBenchmark; } else if (0 == strcmp(*argv, "unflatten")) { benchmark = SkNEW(sk_tools::UnflattenPictureBenchmark); } else { @@ -252,6 +225,55 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* } } + if (useTiles) { + sk_tools::TiledPictureBenchmark* tileBenchmark = SkNEW(sk_tools::TiledPictureBenchmark); + if (isPowerOf2Mode) { + int minWidth = atoi(widthString); + if (!SkIsPow2(minWidth) || minWidth < 0) { + SkDELETE(tileBenchmark); + SkDebugf("--mode %s must be given a width" + " value that is a power of two\n", mode); + exit(-1); + } + tileBenchmark->setTileMinPowerOf2Width(minWidth); + } else if (sk_tools::is_percentage(widthString)) { + tileBenchmark->setTileWidthPercentage(atof(widthString)); + if (!(tileBenchmark->getTileWidthPercentage() > 0)) { + SkDELETE(tileBenchmark); + SkDebugf("--mode tile must be given a width percentage > 0\n"); + exit(-1); + } + } else { + tileBenchmark->setTileWidth(atoi(widthString)); + if (!(tileBenchmark->getTileWidth() > 0)) { + SkDELETE(tileBenchmark); + SkDebugf("--mode tile must be given a width > 0\n"); + exit(-1); + } + } + + if (sk_tools::is_percentage(heightString)) { + tileBenchmark->setTileHeightPercentage(atof(heightString)); + if (!(tileBenchmark->getTileHeightPercentage() > 0)) { + SkDELETE(tileBenchmark); + SkDebugf("--mode tile must be given a height percentage > 0\n"); + exit(-1); + } + } else { + tileBenchmark->setTileHeight(atoi(heightString)); + if (!(tileBenchmark->getTileHeight() > 0)) { + SkDELETE(tileBenchmark); + SkDebugf("--mode tile must be given a height > 0\n"); + exit(-1); + } + } + tileBenchmark->setThreading(multiThreaded); + tileBenchmark->setUsePipe(usePipe); + benchmark = tileBenchmark; + } else if (usePipe) { + SkDELETE(benchmark); + benchmark = SkNEW(sk_tools::PipePictureBenchmark); + } if (inputs->count() < 1) { SkDELETE(benchmark); usage(argv0); diff --git a/tools/picture_utils.cpp b/tools/picture_utils.cpp index d5caf0c7dd..fb5f37cbc3 100644 --- a/tools/picture_utils.cpp +++ b/tools/picture_utils.cpp @@ -80,7 +80,7 @@ namespace sk_tools { basename->set(path.c_str(), end + 1); } - bool is_percentage(char* const string) { + bool is_percentage(const char* const string) { SkString skString(string); return skString.endsWith("%"); } diff --git a/tools/picture_utils.h b/tools/picture_utils.h index 18352f2bdf..bbde7f2789 100644 --- a/tools/picture_utils.h +++ b/tools/picture_utils.h @@ -34,7 +34,7 @@ namespace sk_tools { void get_basename(SkString* basename, const SkString& path); // Returns true if the string ends with % - bool is_percentage(char* const string); + bool is_percentage(const char* const string); // Prints to STDOUT so that test results can be easily seperated from the // error stream. Note, that this still prints to the same stream as SkDebugf |