aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/PictureRenderer.cpp329
-rw-r--r--tools/PictureRenderer.h74
-rw-r--r--tools/bench_pictures_main.cpp120
-rw-r--r--tools/render_pictures_main.cpp37
4 files changed, 264 insertions, 296 deletions
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index 064557b8b2..745bec00f1 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -220,16 +220,11 @@ bool SimplePictureRenderer::render(const SkString* path) {
///////////////////////////////////////////////////////////////////////////////////////////////
TiledPictureRenderer::TiledPictureRenderer()
- : fUsePipe(false)
- , fTileWidth(kDefaultTileWidth)
+ : fTileWidth(kDefaultTileWidth)
, fTileHeight(kDefaultTileHeight)
, fTileWidthPercentage(0.0)
, fTileHeightPercentage(0.0)
- , fTileMinPowerOf2Width(0)
- , fTileCounter(0)
- , fNumThreads(1)
- , fPictureClones(NULL)
- , fPipeController(NULL) { }
+ , fTileMinPowerOf2Width(0) { }
void TiledPictureRenderer::init(SkPicture* pict) {
SkASSERT(pict != NULL);
@@ -242,9 +237,7 @@ void TiledPictureRenderer::init(SkPicture* pict) {
// used by bench_pictures.
fPicture = pict;
fPicture->ref();
- if (!fUsePipe) {
- this->buildBBoxHierarchy();
- }
+ this->buildBBoxHierarchy();
if (fTileWidthPercentage > 0) {
fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100));
@@ -258,42 +251,13 @@ void TiledPictureRenderer::init(SkPicture* pict) {
} else {
this->setupTiles();
}
-
- if (this->multiThreaded()) {
- for (int i = 0; i < fNumThreads; ++i) {
- *fCanvasPool.append() = this->setupCanvas(fTileWidth, fTileHeight);
- }
- if (!fUsePipe) {
- SkASSERT(NULL == fPictureClones);
- // Only need to create fNumThreads - 1 clones, since one thread will use the base
- // picture.
- int numberOfClones = fNumThreads - 1;
- // This will be deleted in end().
- fPictureClones = SkNEW_ARRAY(SkPicture, numberOfClones);
- fPicture->clone(fPictureClones, numberOfClones);
- }
- }
}
void TiledPictureRenderer::end() {
fTileRects.reset();
- SkDELETE_ARRAY(fPictureClones);
- fPictureClones = NULL;
- fCanvasPool.unrefAll();
- if (fPipeController != NULL) {
- SkASSERT(fUsePipe);
- SkDELETE(fPipeController);
- fPipeController = NULL;
- }
this->INHERITED::end();
}
-TiledPictureRenderer::~TiledPictureRenderer() {
- // end() must be called to delete fPictureClones and fPipeController
- SkASSERT(NULL == fPictureClones);
- SkASSERT(NULL == fPipeController);
-}
-
void TiledPictureRenderer::setupTiles() {
for (int tile_y_start = 0; tile_y_start < fPicture->height(); tile_y_start += fTileHeight) {
for (int tile_x_start = 0; tile_x_start < fPicture->width(); tile_x_start += fTileWidth) {
@@ -364,193 +328,160 @@ 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<SkRect>* tileRects,
- const SkString* path, bool* success)
- : fCanvas(target)
- , fPath(path)
- , fSuccess(success)
- , fTileCounter(tileCounter)
- , fTileRects(tileRects) {
- 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);
+
+bool TiledPictureRenderer::render(const SkString* path) {
+ SkASSERT(fPicture != NULL);
+ if (NULL == fPicture) {
+ return false;
}
- int32_t nextTile(SkRect* rect) {
- int32_t i = sk_atomic_inc(fTileCounter);
- if (i < fTileRects->count()) {
- SkASSERT(rect != NULL);
- *rect = fTileRects->operator[](i);
- return i;
+ // Reuse one canvas for all tiles.
+ SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
+ SkAutoUnref aur(canvas);
+
+ bool success = true;
+ for (int i = 0; i < fTileRects.count(); ++i) {
+ DrawTileToCanvas(canvas, fTileRects[i], fPicture);
+ if (NULL != path) {
+ success &= writeAppendNumber(canvas, path, i);
}
- return -1;
}
+ return success;
+}
- // 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;
- // Points to the array of rectangles. The array is already created before any threads are
- // started and then it is unmodified, so there is no danger of race conditions.
- const SkTDArray<SkRect>* fTileRects;
-};
-
+SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
+ SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
+ SkASSERT(fPicture != NULL);
+ // Clip the tile to an area that is completely in what the SkPicture says is the
+ // drawn-to area. This is mostly important for tiles on the right and bottom edges
+ // as they may go over this area and the picture may have some commands that
+ // draw outside of this area and so should not actually be written.
+ SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
+ SkIntToScalar(fPicture->height()));
+ canvas->clipRect(clip);
+ return canvas;
+}
///////////////////////////////////////////////////////////////////////////////////////////////
-// Draw using Pipe
-
-struct TileData : public ThreadData {
- TileData(ThreadSafePipeController* controller, SkCanvas* canvas, int* tileCounter,
- SkTDArray<SkRect>* tileRects, const SkString* path, bool* success)
- : INHERITED(canvas, tileCounter, tileRects, path, success)
- , fController(controller) {}
- ThreadSafePipeController* fController;
+// Holds all of the information needed to draw a set of tiles.
+class CloneData : public SkRunnable {
- typedef ThreadData INHERITED;
-};
+public:
+ CloneData(SkPicture* clone, SkCanvas* canvas, SkTDArray<SkRect>& rects, int start, int end,
+ SkRunnable* done)
+ : fClone(clone)
+ , fCanvas(canvas)
+ , fPath(NULL)
+ , fRects(rects)
+ , fStart(start)
+ , fEnd(end)
+ , fSuccess(NULL)
+ , fDone(done) {
+ SkASSERT(fDone != NULL);
+ }
-static void DrawTile(void* data) {
- SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
- TileData* tileData = static_cast<TileData*>(data);
-
- SkRect tileRect;
- int32_t i;
- while ((i = tileData->nextTile(&tileRect)) != -1) {
- DrawTileToCanvas(tileData->fCanvas, tileRect, tileData->fController);
- if (NULL != tileData->fPath &&
- !writeAppendNumber(tileData->fCanvas, tileData->fPath, i)) {
- *tileData->fSuccess = false;
- break;
+ virtual void run() SK_OVERRIDE {
+ SkGraphics::SetTLSFontCacheLimit(1024 * 1024);
+ for (int i = fStart; i < fEnd; i++) {
+ DrawTileToCanvas(fCanvas, fRects[i], fClone);
+ if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i)
+ && fSuccess != NULL) {
+ *fSuccess = false;
+ // If one tile fails to write to a file, do not continue drawing the rest.
+ break;
+ }
}
+ fDone->run();
}
- SkDELETE(tileData);
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Draw using Picture
-
-struct CloneData : public ThreadData {
- CloneData(SkPicture* clone, SkCanvas* target, int* tileCounter, SkTDArray<SkRect>* tileRects,
- const SkString* path, bool* success)
- : INHERITED(target, tileCounter, tileRects, path, success)
- , fClone(clone) {}
- SkPicture* fClone;
+ void setPathAndSuccess(const SkString* path, bool* success) {
+ fPath = path;
+ fSuccess = success;
+ }
- typedef ThreadData INHERITED;
+private:
+ // All pointers unowned.
+ 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.
+ SkTDArray<SkRect>& fRects; // All tiles of the picture.
+ const int fStart; // Range of tiles drawn by this thread.
+ const int fEnd;
+ bool* fSuccess; // Only meaningful if path is non-null. Shared by all threads,
+ // and only set to false upon failure to write to a PNG.
+ SkRunnable* fDone;
};
-static void DrawClonedTiles(void* data) {
- SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
- CloneData* cloneData = static_cast<CloneData*>(data);
-
- SkRect tileRect;
- int32_t i;
- while ((i = cloneData->nextTile(&tileRect)) != -1) {
- DrawTileToCanvas(cloneData->fCanvas, tileRect, cloneData->fClone);
- if (NULL != cloneData->fPath &&
- !writeAppendNumber(cloneData->fCanvas, cloneData->fPath, i)) {
- *cloneData->fSuccess = false;
- break;
+MultiCorePictureRenderer::MultiCorePictureRenderer(int threadCount)
+: fNumThreads(threadCount)
+, fThreadPool(threadCount)
+, fCountdown(threadCount) {
+ // Only need to create fNumThreads - 1 clones, since one thread will use the base
+ // picture.
+ fPictureClones = SkNEW_ARRAY(SkPicture, fNumThreads - 1);
+ fCloneData = SkNEW_ARRAY(CloneData*, fNumThreads);
+}
+
+void MultiCorePictureRenderer::init(SkPicture *pict) {
+ // Set fPicture and the tiles.
+ this->INHERITED::init(pict);
+ for (int i = 0; i < fNumThreads; ++i) {
+ *fCanvasPool.append() = this->setupCanvas(this->getTileWidth(), this->getTileHeight());
+ }
+ // Only need to create fNumThreads - 1 clones, since one thread will use the base picture.
+ fPicture->clone(fPictureClones, fNumThreads - 1);
+ // Populate each thread with the appropriate data.
+ // Group the tiles into nearly equal size chunks, rounding up so we're sure to cover them all.
+ const int chunkSize = (fTileRects.count() + fNumThreads - 1) / fNumThreads;
+
+ for (int i = 0; i < fNumThreads; i++) {
+ SkPicture* pic;
+ if (i == fNumThreads-1) {
+ // The last set will use the original SkPicture.
+ pic = fPicture;
+ } else {
+ pic = &fPictureClones[i];
}
+ const int start = i * chunkSize;
+ const int end = SkMin32(start + chunkSize, fTileRects.count());
+ fCloneData[i] = SkNEW_ARGS(CloneData,
+ (pic, fCanvasPool[i], fTileRects, start, end, &fCountdown));
}
- SkDELETE(cloneData);
}
-///////////////////////////////////////////////////////////////////////////////////////////////
-
-void TiledPictureRenderer::setup() {
- if (this->multiThreaded()) {
- // Reset to zero so we start with the first tile.
- fTileCounter = 0;
- if (fUsePipe) {
- // Record the picture into the pipe controller. It is done here because unlike
- // SkPicture, the pipe is modified (bitmaps can be removed) by drawing.
- // fPipeController is deleted here after each call to render() except the last one and
- // in end() for the last one.
- if (fPipeController != NULL) {
- SkDELETE(fPipeController);
- }
- fPipeController = SkNEW_ARGS(ThreadSafePipeController, (fTileRects.count()));
- SkGPipeWriter writer;
- SkCanvas* pipeCanvas = writer.startRecording(fPipeController,
- SkGPipeWriter::kSimultaneousReaders_Flag);
- SkASSERT(fPicture != NULL);
- fPicture->draw(pipeCanvas);
- writer.endRecording();
+bool MultiCorePictureRenderer::render(const SkString *path) {
+ bool success = true;
+ if (path != NULL) {
+ for (int i = 0; i < fNumThreads-1; i++) {
+ fCloneData[i]->setPathAndSuccess(path, &success);
}
}
-}
-bool TiledPictureRenderer::render(const SkString* path) {
- SkASSERT(fPicture != NULL);
- if (NULL == fPicture) {
- return false;
+ fCountdown.reset(fNumThreads);
+ for (int i = 0; i < fNumThreads; i++) {
+ fThreadPool.add(fCloneData[i]);
}
+ fCountdown.wait();
- if (this->multiThreaded()) {
- SkASSERT(fCanvasPool.count() == fNumThreads);
- SkTDArray<SkThread*> 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, path, &success));
- } else {
- SkPicture* pic = (0 == i) ? fPicture : &fPictureClones[i-1];
- data = SkNEW_ARGS(CloneData, (pic, fCanvasPool[i], &fTileCounter, &fTileRects, path,
- &success));
- }
- SkThread* thread = SkNEW_ARGS(SkThread, (proc, data));
- if (!thread->start()) {
- SkDebugf("Could not start %s thread %i.\n", (fUsePipe ? "pipe" : "picture"), i);
- }
- *threads.append() = thread;
- }
- SkASSERT(threads.count() == fNumThreads);
- for (int i = 0; i < fNumThreads; ++i) {
- SkThread* thread = threads[i];
- thread->join();
- SkDELETE(thread);
- }
- threads.reset();
- return success;
- } else {
- // For single thread, we really only need one canvas total.
- SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
- SkAutoUnref aur(canvas);
-
- bool success = true;
- for (int i = 0; i < fTileRects.count(); ++i) {
- DrawTileToCanvas(canvas, fTileRects[i], fPicture);
- if (NULL != path) {
- success &= writeAppendNumber(canvas, path, i);
- }
- }
- return success;
+ return success;
+}
+
+void MultiCorePictureRenderer::end() {
+ for (int i = 0; i < fNumThreads - 1; i++) {
+ SkDELETE(fCloneData[i]);
+ fCloneData[i] = NULL;
}
+
+ fCanvasPool.unrefAll();
+
+ this->INHERITED::end();
}
-SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) {
- SkCanvas* canvas = this->INHERITED::setupCanvas(width, height);
- SkASSERT(fPicture != NULL);
- // Clip the tile to an area that is completely in what the SkPicture says is the
- // drawn-to area. This is mostly important for tiles on the right and bottom edges
- // as they may go over this area and the picture may have some commands that
- // draw outside of this area and so should not actually be written.
- SkRect clip = SkRect::MakeWH(SkIntToScalar(fPicture->width()),
- SkIntToScalar(fPicture->height()));
- canvas->clipRect(clip);
- return canvas;
+MultiCorePictureRenderer::~MultiCorePictureRenderer() {
+ // Each individual CloneData was deleted in end.
+ SkDELETE_ARRAY(fCloneData);
+ SkDELETE_ARRAY(fPictureClones);
}
///////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 9cafdc8c54..3ff8967d44 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -7,13 +7,17 @@
#ifndef PictureRenderer_DEFINED
#define PictureRenderer_DEFINED
+
+#include "SkCountdown.h"
#include "SkMath.h"
#include "SkPicture.h"
-#include "SkTypes.h"
-#include "SkTDArray.h"
#include "SkRect.h"
#include "SkRefCnt.h"
+#include "SkRunnable.h"
#include "SkString.h"
+#include "SkTDArray.h"
+#include "SkThreadPool.h"
+#include "SkTypes.h"
#if SK_SUPPORT_GPU
#include "GrContextFactory.h"
@@ -23,7 +27,7 @@
class SkBitmap;
class SkCanvas;
class SkGLContext;
-class ThreadSafePipeController;
+class SkThread;
namespace sk_tools {
@@ -41,6 +45,9 @@ public:
kRTree_BBoxHierarchyType,
};
+ /**
+ * Called with each new SkPicture to render.
+ */
virtual void init(SkPicture* pict);
/**
@@ -60,7 +67,12 @@ public:
*/
virtual bool render(const SkString* path) = 0;
+ /**
+ * Called once finished with a particular SkPicture, before calling init again, and before
+ * being done with this Renderer.
+ */
virtual void end();
+
void resetState();
void setDeviceType(SkDeviceTypes deviceType) {
@@ -164,8 +176,6 @@ public:
virtual void init(SkPicture* pict) SK_OVERRIDE;
- virtual void setup() SK_OVERRIDE;
-
/**
* Renders to tiles, rather than a single canvas. If a path is provided, a separate file is
* created for each tile, named "path0.png", "path1.png", etc.
@@ -220,43 +230,51 @@ public:
return fTileMinPowerOf2Width;
}
- /**
- * Set the number of threads to use for drawing. Non-positive numbers will set it to 1.
- */
- void setNumberOfThreads(int num) {
- fNumThreads = SkMax32(num, 1);
- }
-
- void setUsePipe(bool usePipe) {
- fUsePipe = usePipe;
- }
-
- ~TiledPictureRenderer();
+protected:
+ virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
+ SkTDArray<SkRect> fTileRects;
private:
- bool fUsePipe;
int fTileWidth;
int fTileHeight;
double fTileWidthPercentage;
double fTileHeightPercentage;
int fTileMinPowerOf2Width;
- SkTDArray<SkRect> fTileRects;
-
- // These are only used for multithreaded rendering
- int32_t fTileCounter;
- int fNumThreads;
- SkTDArray<SkCanvas*> fCanvasPool;
- SkPicture* fPictureClones;
- ThreadSafePipeController* fPipeController;
void setupTiles();
void setupPowerOf2Tiles();
- virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
- bool multiThreaded() { return fNumThreads > 1; }
typedef PictureRenderer INHERITED;
};
+class CloneData;
+
+class MultiCorePictureRenderer : public TiledPictureRenderer {
+public:
+ explicit MultiCorePictureRenderer(int threadCount);
+
+ ~MultiCorePictureRenderer();
+
+ virtual void init(SkPicture* pict) SK_OVERRIDE;
+
+ /**
+ * Behaves like TiledPictureRenderer::render(), only using multiple threads.
+ */
+ virtual bool render(const SkString* path) SK_OVERRIDE;
+
+ virtual void end() SK_OVERRIDE;
+
+private:
+ const int fNumThreads;
+ SkTDArray<SkCanvas*> fCanvasPool;
+ SkThreadPool fThreadPool;
+ SkPicture* fPictureClones;
+ CloneData** fCloneData;
+ SkCountdown fCountdown;
+
+ typedef TiledPictureRenderer INHERITED;
+};
+
/**
* This class does not do any rendering, but its render function executes turning an SkPictureRecord
* into an SkPicturePlayback, which we want to time.
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 25fd5fca7f..87149e9af9 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -76,7 +76,7 @@ static void usage(const char* argv0) {
SkDebugf(
" --multi numThreads : Set the number of threads for multi threaded drawing. Must be greater\n"
" than 1. Only works with tiled rendering.\n"
-" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
+" --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
SkDebugf(
" --bbh bbhType: Set the bounding box hierarchy type to be used. Accepted\n"
" values are: none, rtree. Default value is none.\n"
@@ -135,6 +135,12 @@ static bool run_single_benchmark(const SkString& inputPath,
return true;
}
+#define PRINT_USAGE_AND_EXIT \
+ do { \
+ usage(argv0); \
+ exit(-1); \
+ } while (0)
+
static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
sk_tools::PictureBenchmark* benchmark) {
const char* argv0 = argv[0];
@@ -144,7 +150,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
sk_tools::PictureRenderer::SkDeviceTypes deviceType =
sk_tools::PictureRenderer::kBitmap_DeviceType;
- sk_tools::PictureRenderer* renderer = NULL;
+ SkAutoTUnref<sk_tools::PictureRenderer> renderer(NULL);
// Create a string to show our current settings.
// TODO: Make it prettier. Currently it just repeats the command line.
@@ -170,12 +176,11 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
repeats = atoi(*argv);
if (repeats < 1) {
gLogger.logError("--repeat must be given a value > 0\n");
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else {
gLogger.logError("Missing arg for --repeat\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--pipe")) {
usePipe = true;
@@ -194,28 +199,24 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
}
} else {
gLogger.logError("Missing arg for --logFile\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--multi")) {
++argv;
if (argv >= stop) {
gLogger.logError("Missing arg for --multi\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
numThreads = atoi(*argv);
if (numThreads < 2) {
gLogger.logError("Number of threads must be at least 2.\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--bbh")) {
++argv;
if (argv >= stop) {
gLogger.logError("Missing value for --bbh\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (0 == strcmp(*argv, "none")) {
bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
@@ -225,23 +226,25 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
SkString err;
err.printf("%s is not a valid value for --bbhType\n", *argv);
gLogger.logError(err);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--mode")) {
+ if (renderer.get() != NULL) {
+ SkDebugf("Cannot combine modes.\n");
+ PRINT_USAGE_AND_EXIT;
+ }
++argv;
if (argv >= stop) {
gLogger.logError("Missing mode for --mode\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (0 == strcmp(*argv, "record")) {
- renderer = SkNEW(sk_tools::RecordPictureRenderer);
+ renderer.reset(SkNEW(sk_tools::RecordPictureRenderer));
} else if (0 == strcmp(*argv, "simple")) {
- renderer = SkNEW(sk_tools::SimplePictureRenderer);
+ renderer.reset(SkNEW(sk_tools::SimplePictureRenderer));
} else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
useTiles = true;
mode = *argv;
@@ -255,33 +258,29 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
SkString err;
err.printf("Missing width for --mode %s\n", mode);
gLogger.logError(err);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
widthString = *argv;
++argv;
if (argv >= stop) {
gLogger.logError("Missing height for --mode tile\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
heightString = *argv;
} else if (0 == strcmp(*argv, "playbackCreation")) {
- renderer = SkNEW(sk_tools::PlaybackCreationRenderer);
+ renderer.reset(SkNEW(sk_tools::PlaybackCreationRenderer));
} else {
SkString err;
err.printf("%s is not a valid mode for --mode\n", *argv);
gLogger.logError(err);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--device")) {
++argv;
if (argv >= stop) {
gLogger.logError("Missing mode for --device\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (0 == strcmp(*argv, "bitmap")) {
@@ -296,8 +295,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
SkString err;
err.printf("%s is not a valid mode for --device\n", *argv);
gLogger.logError(err);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--timers")) {
++argv;
@@ -333,8 +331,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
truncatedTimerCpu, timerGpu);
} else {
gLogger.logError("Missing arg for --timers\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--min")) {
benchmark->setPrintMin(true);
@@ -345,12 +342,10 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
benchmark->setLogPerIter(log);
} else {
gLogger.logError("Missing arg for --logPerIter\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) {
- usage(argv0);
- exit(0);
+ PRINT_USAGE_AND_EXIT;
} else {
inputs->push_back(SkString(*argv));
}
@@ -358,19 +353,22 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
if (numThreads > 1 && !useTiles) {
gLogger.logError("Multithreaded drawing requires tiled rendering.\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
gLogger.logError("--pipe and --bbh cannot be used together\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (useTiles) {
SkASSERT(NULL == renderer);
- sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
+ sk_tools::TiledPictureRenderer* tiledRenderer;
+ if (numThreads > 1) {
+ tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
+ } else {
+ tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
+ }
if (isPowerOf2Mode) {
int minWidth = atoi(widthString);
if (!SkIsPow2(minWidth) || minWidth < 0) {
@@ -379,8 +377,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
err.printf("-mode %s must be given a width"
" value that is a power of two\n", mode);
gLogger.logError(err);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
tiledRenderer->setTileMinPowerOf2Width(minWidth);
} else if (sk_tools::is_percentage(widthString)) {
@@ -388,16 +385,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
tiledRenderer->unref();
gLogger.logError("--mode tile must be given a width percentage > 0\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else {
tiledRenderer->setTileWidth(atoi(widthString));
if (!(tiledRenderer->getTileWidth() > 0)) {
tiledRenderer->unref();
gLogger.logError("--mode tile must be given a width > 0\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
}
@@ -406,16 +401,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
tiledRenderer->unref();
gLogger.logError("--mode tile must be given a height percentage > 0\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
} else {
tiledRenderer->setTileHeight(atoi(heightString));
if (!(tiledRenderer->getTileHeight() > 0)) {
tiledRenderer->unref();
gLogger.logError("--mode tile must be given a height > 0\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
}
if (numThreads > 1) {
@@ -423,29 +416,32 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
tiledRenderer->unref();
gLogger.logError("GPU not compatible with multithreaded tiling.\n");
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
#endif
- tiledRenderer->setNumberOfThreads(numThreads);
}
- tiledRenderer->setUsePipe(usePipe);
- renderer = tiledRenderer;
+ renderer.reset(tiledRenderer);
+ if (usePipe) {
+ SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
+ "Turning off pipe.\n");
+ }
} else if (usePipe) {
- renderer = SkNEW(sk_tools::PipePictureRenderer);
+ if (renderer.get() != NULL) {
+ SkDebugf("Pipe is incompatible with other modes.\n");
+ PRINT_USAGE_AND_EXIT;
+ }
+ renderer.reset(SkNEW(sk_tools::PipePictureRenderer));
}
if (inputs->count() < 1) {
- SkSafeUnref(renderer);
- usage(argv0);
- exit(-1);
+ PRINT_USAGE_AND_EXIT;
}
if (NULL == renderer) {
- renderer = SkNEW(sk_tools::SimplePictureRenderer);
+ renderer.reset(SkNEW(sk_tools::SimplePictureRenderer));
}
renderer->setBBoxHierarchyType(bbhType);
- benchmark->setRenderer(renderer)->unref();
+ benchmark->setRenderer(renderer);
benchmark->setRepeats(repeats);
benchmark->setDeviceType(deviceType);
benchmark->setLogger(&gLogger);
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index ae9e94d4cc..521bbf8209 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -63,7 +63,7 @@ static void usage(const char* argv0) {
SkDebugf(
" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
" than 1. Only works with tiled rendering.\n"
-" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
+" --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
SkDebugf(
" --device bitmap"
#if SK_SUPPORT_GPU
@@ -174,7 +174,12 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
for (++argv; argv < stop; ++argv) {
if (0 == strcmp(*argv, "--mode")) {
- SkDELETE(renderer);
+ if (renderer != NULL) {
+ renderer->unref();
+ SkDebugf("Cannot combine modes.\n");
+ usage(argv0);
+ exit(-1);
+ }
++argv;
if (argv >= stop) {
@@ -218,12 +223,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
} else if (0 == strcmp(*argv, "--multi")) {
++argv;
if (argv >= stop) {
+ SkSafeUnref(renderer);
SkDebugf("Missing arg for --multi\n");
usage(argv0);
exit(-1);
}
numThreads = atoi(*argv);
if (numThreads < 2) {
+ SkSafeUnref(renderer);
SkDebugf("Number of threads must be at least 2.\n");
usage(argv0);
exit(-1);
@@ -231,6 +238,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
} else if (0 == strcmp(*argv, "--device")) {
++argv;
if (argv >= stop) {
+ SkSafeUnref(renderer);
SkDebugf("Missing mode for --device\n");
usage(argv0);
exit(-1);
@@ -245,13 +253,14 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
}
#endif
else {
+ SkSafeUnref(renderer);
SkDebugf("%s is not a valid mode for --device\n", *argv);
usage(argv0);
exit(-1);
}
} else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
- SkDELETE(renderer);
+ SkSafeUnref(renderer);
usage(argv0);
exit(-1);
} else if (0 == strcmp(*argv, "-w")) {
@@ -268,6 +277,7 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
}
if (numThreads > 1 && !useTiles) {
+ SkSafeUnref(renderer);
SkDebugf("Multithreaded drawing requires tiled rendering.\n");
usage(argv0);
exit(-1);
@@ -275,7 +285,12 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
if (useTiles) {
SkASSERT(NULL == renderer);
- sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
+ sk_tools::TiledPictureRenderer* tiledRenderer;
+ if (numThreads > 1) {
+ tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
+ } else {
+ tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
+ }
if (isPowerOf2Mode) {
int minWidth = atoi(widthString);
if (!SkIsPow2(minWidth) || minWidth < 0) {
@@ -332,16 +347,24 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
exit(-1);
}
#endif
- tiledRenderer->setNumberOfThreads(numThreads);
}
- tiledRenderer->setUsePipe(usePipe);
renderer = tiledRenderer;
+ if (usePipe) {
+ SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
+ "Turning off pipe.\n");
+ }
} else if (usePipe) {
+ if (renderer != NULL) {
+ renderer->unref();
+ SkDebugf("Pipe is incompatible with other modes.\n");
+ usage(argv0);
+ exit(-1);
+ }
renderer = SkNEW(sk_tools::PipePictureRenderer);
}
if (inputs->empty()) {
- SkDELETE(renderer);
+ SkSafeUnref(renderer);
if (NULL != outputDir) {
SkDELETE(outputDir);
}