diff --git a/gyp/tools.gyp b/gyp/tools.gyp index 4deffc2fbc..8084c7b112 100644 --- a/gyp/tools.gyp +++ b/gyp/tools.gyp @@ -106,6 +106,7 @@ '../src/pipe/utils/SamplePipeControllers.cpp', ], 'include_dirs': [ + '../src/core/', '../src/pipe/utils/', '../src/utils/', ], diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp index e6d86dda2e..064557b8b2 100644 --- a/tools/PictureRenderer.cpp +++ b/tools/PictureRenderer.cpp @@ -18,6 +18,7 @@ #include "SkImageEncoder.h" #include "SkMatrix.h" #include "SkPicture.h" +#include "SkRTree.h" #include "SkScalar.h" #include "SkString.h" #include "SkTemplates.h" @@ -45,6 +46,7 @@ void PictureRenderer::init(SkPicture* pict) { } fPicture = pict; + fPicture->ref(); fCanvas.reset(this->setupCanvas()); } @@ -78,10 +80,28 @@ SkCanvas* PictureRenderer::setupCanvas(int width, int height) { void PictureRenderer::end() { this->resetState(); + SkSafeUnref(fPicture); fPicture = NULL; fCanvas.reset(NULL); } +/** Converts fPicture to a picture that uses a BBoxHierarchy. + * PictureRenderer subclasses that are used to test picture playback + * should call this method during init. + */ +void PictureRenderer::buildBBoxHierarchy() { + SkASSERT(NULL != fPicture); + if (kNone_BBoxHierarchyType != fBBoxHierarchyType && NULL != fPicture) { + SkPicture* newPicture = this->createPicture(); + SkCanvas* recorder = newPicture->beginRecording(fPicture->width(), fPicture->height(), + this->recordFlags()); + fPicture->draw(recorder); + newPicture->endRecording(); + fPicture->unref(); + fPicture = newPicture; + } +} + void PictureRenderer::resetState() { #if SK_SUPPORT_GPU if (this->isUsingGpuDevice()) { @@ -99,6 +119,11 @@ void PictureRenderer::resetState() { #endif } +uint32_t PictureRenderer::recordFlags() { + return kNone_BBoxHierarchyType == fBBoxHierarchyType ? 0 : + SkPicture::kOptimizeForClippedPlayback_RecordingFlag; +} + /** * Write the canvas to the specified path. * @param canvas Must be non-null. Canvas to be written to a file. @@ -140,10 +165,11 @@ static bool writeAppendNumber(SkCanvas* canvas, const SkString* path, int number /////////////////////////////////////////////////////////////////////////////////////////////// bool RecordPictureRenderer::render(const SkString*) { - SkPicture replayer; - SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height()); + SkAutoTUnref replayer(this->createPicture()); + SkCanvas* recorder = replayer->beginRecording(fPicture->width(), fPicture->height(), + this->recordFlags()); fPicture->draw(recorder); - replayer.endRecording(); + replayer->endRecording(); // Since this class does not actually render, return false. return false; } @@ -171,6 +197,11 @@ bool PipePictureRenderer::render(const SkString* path) { /////////////////////////////////////////////////////////////////////////////////////////////// +void SimplePictureRenderer::init(SkPicture* picture) { + INHERITED::init(picture); + this->buildBBoxHierarchy(); +} + bool SimplePictureRenderer::render(const SkString* path) { SkASSERT(fCanvas.get() != NULL); SkASSERT(fPicture != NULL); @@ -210,6 +241,10 @@ 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; + fPicture->ref(); + if (!fUsePipe) { + this->buildBBoxHierarchy(); + } if (fTileWidthPercentage > 0) { fTileWidth = sk_float_ceil2int(float(fTileWidthPercentage * fPicture->width() / 100)); @@ -521,14 +556,42 @@ SkCanvas* TiledPictureRenderer::setupCanvas(int width, int height) { /////////////////////////////////////////////////////////////////////////////////////////////// void PlaybackCreationRenderer::setup() { - SkCanvas* recorder = fReplayer.beginRecording(fPicture->width(), fPicture->height()); + fReplayer.reset(this->createPicture()); + SkCanvas* recorder = fReplayer->beginRecording(fPicture->width(), fPicture->height(), + this->recordFlags()); fPicture->draw(recorder); } bool PlaybackCreationRenderer::render(const SkString*) { - fReplayer.endRecording(); + fReplayer->endRecording(); // Since this class does not actually render, return false. return false; } +/////////////////////////////////////////////////////////////////////////////////////////////// +// SkPicture variants for each BBoxHierarchy type + +class RTreePicture : public SkPicture { +public: + virtual SkBBoxHierarchy* createBBoxHierarchy() const SK_OVERRIDE{ + static const int kRTreeMinChildren = 6; + static const int kRTreeMaxChildren = 11; + SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(fWidth), + SkIntToScalar(fHeight)); + return SkRTree::Create(kRTreeMinChildren, kRTreeMaxChildren, + aspectRatio); + } +}; + +SkPicture* PictureRenderer::createPicture() { + switch (fBBoxHierarchyType) { + case kNone_BBoxHierarchyType: + return SkNEW(SkPicture); + case kRTree_BBoxHierarchyType: + return SkNEW(RTreePicture); + } + SkASSERT(0); // invalid bbhType + return NULL; } + +} // namespace sk_tools diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h index 5d32203b3c..579e413ad2 100644 --- a/tools/PictureRenderer.h +++ b/tools/PictureRenderer.h @@ -36,6 +36,11 @@ public: #endif }; + enum BBoxHierarchyType { + kNone_BBoxHierarchyType = 0, + kRTree_BBoxHierarchyType, + }; + virtual void init(SkPicture* pict); /** @@ -62,6 +67,10 @@ public: fDeviceType = deviceType; } + void setBBoxHierarchyType(BBoxHierarchyType bbhType) { + fBBoxHierarchyType = bbhType; + } + bool isUsingBitmapDevice() { return kBitmap_DeviceType == fDeviceType; } @@ -97,12 +106,17 @@ public: {} protected: + void buildBBoxHierarchy(); + SkPicture* createPicture(); + uint32_t recordFlags(); SkCanvas* setupCanvas(); virtual SkCanvas* setupCanvas(int width, int height); SkAutoTUnref fCanvas; SkPicture* fPicture; SkDeviceTypes fDeviceType; + BBoxHierarchyType fBBoxHierarchyType; + #if SK_SUPPORT_GPU GrContextFactory fGrContextFactory; @@ -135,6 +149,8 @@ private: class SimplePictureRenderer : public PictureRenderer { public: + virtual void init(SkPicture* pict) SK_OVERRIDE; + virtual bool render(const SkString*) SK_OVERRIDE; private: @@ -255,7 +271,7 @@ public: virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); } private: - SkPicture fReplayer; + SkAutoTUnref fReplayer; typedef PictureRenderer INHERITED; }; diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp index e602bd923d..25fd5fca7f 100644 --- a/tools/bench_pictures_main.cpp +++ b/tools/bench_pictures_main.cpp @@ -30,6 +30,7 @@ static void usage(const char* argv0) { " [--mode pow2tile minWidth height[] | record | simple\n" " | tile width[] height[] | playbackCreation]\n" " [--pipe]\n" +" [--bbh bbhType]\n" " [--multi numThreads]\n" " [--device bitmap" #if SK_SUPPORT_GPU @@ -77,6 +78,10 @@ static void usage(const char* argv0) { " than 1. Only works with tiled rendering.\n" " --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n"); SkDebugf( +" --bbh bbhType: Set the bounding box hierarchy type to be used. Accepted\n" +" values are: none, rtree. Default value is none.\n" +" Not compatible with --pipe.\n"); + SkDebugf( " --device bitmap" #if SK_SUPPORT_GPU " | gpu" @@ -156,6 +161,8 @@ static void parse_commandline(int argc, char* const argv[], SkTArray* const char* heightString = NULL; bool isPowerOf2Mode = false; const char* mode = NULL; + sk_tools::PictureRenderer::BBoxHierarchyType bbhType = + sk_tools::PictureRenderer::kNone_BBoxHierarchyType; for (++argv; argv < stop; ++argv) { if (0 == strcmp(*argv, "--repeat")) { ++argv; @@ -203,6 +210,25 @@ static void parse_commandline(int argc, char* const argv[], SkTArray* usage(argv0); exit(-1); } + } else if (0 == strcmp(*argv, "--bbh")) { + ++argv; + if (argv >= stop) { + gLogger.logError("Missing value for --bbh\n"); + usage(argv0); + exit(-1); + } + if (0 == strcmp(*argv, "none")) { + bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType; + } else if (0 == strcmp(*argv, "rtree")) { + bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType; + } else { + SkString err; + err.printf("%s is not a valid value for --bbhType\n", *argv); + gLogger.logError(err); + usage(argv0); + exit(-1); + } + } else if (0 == strcmp(*argv, "--mode")) { ++argv; @@ -336,6 +362,12 @@ static void parse_commandline(int argc, char* const argv[], SkTArray* exit(-1); } + if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) { + gLogger.logError("--pipe and --bbh cannot be used together\n"); + usage(argv0); + exit(-1); + } + if (useTiles) { SkASSERT(NULL == renderer); sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer); @@ -411,6 +443,8 @@ static void parse_commandline(int argc, char* const argv[], SkTArray* if (NULL == renderer) { renderer = SkNEW(sk_tools::SimplePictureRenderer); } + + renderer->setBBoxHierarchyType(bbhType); benchmark->setRenderer(renderer)->unref(); benchmark->setRepeats(repeats); benchmark->setDeviceType(deviceType);