aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-31 16:15:22 +0000
committerGravatar scroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>2012-08-31 16:15:22 +0000
commit58b4ead36c62d8c0256ee4da554f3df2744d904c (patch)
treef06d09d531ee6b37df515ab83734111aad8cb5b0
parentb1d47e211c95779ed283b78a85abbd0bd5668871 (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.gyp4
-rw-r--r--include/core/SkTemplates.h4
-rw-r--r--include/pipe/SkGPipe.h11
-rw-r--r--src/pipe/SkGPipeRead.cpp23
-rw-r--r--src/pipe/utils/SamplePipeControllers.cpp37
-rw-r--r--src/pipe/utils/SamplePipeControllers.h40
-rw-r--r--tools/PictureBenchmark.cpp13
-rw-r--r--tools/PictureBenchmark.h8
-rw-r--r--tools/PictureRenderer.cpp108
-rw-r--r--tools/PictureRenderer.h18
-rw-r--r--tools/bench_pictures_main.cpp162
-rw-r--r--tools/picture_utils.cpp2
-rw-r--r--tools/picture_utils.h2
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