Adding rtree support to the bench_pictures utility
Review URL: https://codereview.appspot.com/6775080

git-svn-id: http://skia.googlecode.com/svn/trunk@6267 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gyp/tools.gyp b/gyp/tools.gyp
index 4deffc2..8084c7b 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 e6d86dd..064557b 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 @@
     }
 
     fPicture = pict;
+    fPicture->ref();
     fCanvas.reset(this->setupCanvas());
 }
 
@@ -78,10 +80,28 @@
 
 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 @@
 #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 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 bool RecordPictureRenderer::render(const SkString*) {
-    SkPicture replayer;
-    SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
+    SkAutoTUnref<SkPicture> 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 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
+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 @@
     // 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 @@
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
 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 5d32203..579e413 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -36,6 +36,11 @@
 #endif
     };
 
+    enum BBoxHierarchyType {
+        kNone_BBoxHierarchyType = 0,
+        kRTree_BBoxHierarchyType,
+    };
+
     virtual void init(SkPicture* pict);
 
     /**
@@ -62,6 +67,10 @@
         fDeviceType = deviceType;
     }
 
+    void setBBoxHierarchyType(BBoxHierarchyType bbhType) {
+        fBBoxHierarchyType = bbhType;
+    }
+
     bool isUsingBitmapDevice() {
         return kBitmap_DeviceType == fDeviceType;
     }
@@ -97,12 +106,17 @@
         {}
 
 protected:
+    void buildBBoxHierarchy();
+    SkPicture* createPicture();
+    uint32_t recordFlags();
     SkCanvas* setupCanvas();
     virtual SkCanvas* setupCanvas(int width, int height);
 
     SkAutoTUnref<SkCanvas> fCanvas;
     SkPicture* fPicture;
     SkDeviceTypes fDeviceType;
+    BBoxHierarchyType fBBoxHierarchyType;
+
 
 #if SK_SUPPORT_GPU
     GrContextFactory fGrContextFactory;
@@ -135,6 +149,8 @@
 
 class SimplePictureRenderer : public PictureRenderer {
 public:
+    virtual void init(SkPicture* pict) SK_OVERRIDE;
+
     virtual bool render(const SkString*) SK_OVERRIDE;
 
 private:
@@ -255,7 +271,7 @@
     virtual SkString getNormalTimeFormat() SK_OVERRIDE { return SkString("%6.4f"); }
 
 private:
-    SkPicture fReplayer;
+    SkAutoTUnref<SkPicture> fReplayer;
     typedef PictureRenderer INHERITED;
 };
 
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index e602bd9..25fd5fc 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -30,6 +30,7 @@
 "     [--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 @@
 "                          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 @@
     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 @@
                 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 @@
         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 @@
     if (NULL == renderer) {
         renderer = SkNEW(sk_tools::SimplePictureRenderer);
     }
+
+    renderer->setBBoxHierarchyType(bbhType);
     benchmark->setRenderer(renderer)->unref();
     benchmark->setRepeats(repeats);
     benchmark->setDeviceType(deviceType);