Update old tools to allow MultiPictureDraw rendering

I'll post a separate patch for nanobench and dm

Review URL: https://codereview.chromium.org/639013003
diff --git a/debugger/QT/SkDebuggerGUI.cpp b/debugger/QT/SkDebuggerGUI.cpp
index b03b8f3..59bfcca 100644
--- a/debugger/QT/SkDebuggerGUI.cpp
+++ b/debugger/QT/SkDebuggerGUI.cpp
@@ -356,7 +356,7 @@
         return;
     }
 
-    renderer->init(pict, NULL, NULL, NULL, false);
+    renderer->init(pict, NULL, NULL, NULL, false, false);
 
     renderer->setup();
     renderer->render();
diff --git a/tools/CopyTilesRenderer.cpp b/tools/CopyTilesRenderer.cpp
index 30a3256..6f95da7 100644
--- a/tools/CopyTilesRenderer.cpp
+++ b/tools/CopyTilesRenderer.cpp
@@ -10,6 +10,7 @@
 #include "SkCanvas.h"
 #include "SkDevice.h"
 #include "SkImageEncoder.h"
+#include "SkMultiPictureDraw.h"
 #include "SkPicture.h"
 #include "SkPixelRef.h"
 #include "SkRect.h"
@@ -28,7 +29,7 @@
 #endif
     void CopyTilesRenderer::init(const SkPicture* pict, const SkString* writePath,
                                  const SkString* mismatchPath, const SkString* inputFilename,
-                                 bool useChecksumBasedFilenames) {
+                                 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
         // Do not call INHERITED::init(), which would create a (potentially large) canvas which is
         // not used by bench_pictures.
         SkASSERT(pict != NULL);
@@ -39,6 +40,7 @@
         this->CopyString(&fMismatchPath, mismatchPath);
         this->CopyString(&fInputFilename, inputFilename);
         fUseChecksumBasedFilenames = useChecksumBasedFilenames;
+        fUseMultiPictureDraw = useMultiPictureDraw;
         this->buildBBoxHierarchy();
         // In order to avoid allocating a large canvas (particularly important for GPU), create one
         // canvas that is a multiple of the tile size, and draw portions of the picture.
@@ -61,7 +63,15 @@
                 mat.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
                 fCanvas->setMatrix(mat);
                 // Draw the picture
-                fCanvas->drawPicture(fPicture);
+                if (fUseMultiPictureDraw) {
+                    SkMultiPictureDraw mpd;
+
+                    mpd.add(fCanvas, fPicture);
+
+                    mpd.draw();
+                } else {
+                    fCanvas->drawPicture(fPicture);
+                }
                 // Now extract the picture into tiles
                 SkBitmap baseBitmap;
                 fCanvas->readPixels(SkIRect::MakeSize(fCanvas->getBaseLayerSize()), &baseBitmap);
diff --git a/tools/CopyTilesRenderer.h b/tools/CopyTilesRenderer.h
index b244142..92996bb 100644
--- a/tools/CopyTilesRenderer.h
+++ b/tools/CopyTilesRenderer.h
@@ -31,7 +31,8 @@
                           const SkString* writePath, 
                           const SkString* mismatchPath,
                           const SkString* inputFilename,
-                          bool useChecksumBasedFilenames) SK_OVERRIDE;
+                          bool useChecksumBasedFilenames,
+                          bool useMultiPictureDraw) SK_OVERRIDE;
 
         /**
          *  Similar to TiledPictureRenderer, this will draw a PNG for each tile. However, the
diff --git a/tools/PictureBenchmark.cpp b/tools/PictureBenchmark.cpp
index 15b6173..f708f53 100644
--- a/tools/PictureBenchmark.cpp
+++ b/tools/PictureBenchmark.cpp
@@ -15,15 +15,14 @@
 namespace sk_tools {
 
 PictureBenchmark::PictureBenchmark()
-: fRepeats(1)
-, fRenderer(NULL)
-, fTimerResult(TimerData::kAvg_Result)
-, fTimerTypes(0)
-, fTimeIndividualTiles(false)
-, fPurgeDecodedTex(false)
-, fPreprocess(false)
-, fWriter(NULL)
-{}
+    : fRepeats(1)
+    , fRenderer(NULL)
+    , fTimerResult(TimerData::kAvg_Result)
+    , fTimerTypes(0)
+    , fTimeIndividualTiles(false)
+    , fPurgeDecodedTex(false)
+    , fWriter(NULL) {
+}
 
 PictureBenchmark::~PictureBenchmark() {
     SkSafeUnref(fRenderer);
@@ -56,7 +55,7 @@
     return renderer;
 }
 
-void PictureBenchmark::run(SkPicture* pict) {
+void PictureBenchmark::run(SkPicture* pict, bool useMultiPictureDraw) {
     SkASSERT(pict);
     if (NULL == pict) {
         return;
@@ -67,17 +66,11 @@
         return;
     }
 
-    fRenderer->init(pict, NULL, NULL, NULL, false);
+    fRenderer->init(pict, NULL, NULL, NULL, false, useMultiPictureDraw);
 
     // We throw this away to remove first time effects (such as paging in this program)
     fRenderer->setup();
 
-    if (fPreprocess) {
-        if (fRenderer->getCanvas()) {
-            fRenderer->getCanvas()->EXPERIMENTAL_optimize(fRenderer->getPicture());
-        }
-    }
-
     fRenderer->render(NULL);
     fRenderer->resetState(true);   // flush, swapBuffers and Finish
 
diff --git a/tools/PictureBenchmark.h b/tools/PictureBenchmark.h
index 2b1ccb5..99eca6b 100644
--- a/tools/PictureBenchmark.h
+++ b/tools/PictureBenchmark.h
@@ -28,7 +28,7 @@
      * Draw the provided SkPicture fRepeats times while collecting timing data, and log the output
      * via fWriter.
      */
-    void run(SkPicture* pict);
+    void run(SkPicture* pict, bool useMultiPictureDraw);
 
     void setRepeats(int repeats) {
         fRepeats = repeats;
@@ -45,9 +45,6 @@
     void setPurgeDecodedTex(bool purgeDecodedTex) { fPurgeDecodedTex = purgeDecodedTex; }
     bool purgeDecodedText() const { return fPurgeDecodedTex; }
 
-    void setPreprocess(bool preprocess) { fPreprocess = preprocess; }
-    bool preprocess() const { return fPreprocess; }
-
     PictureRenderer* setRenderer(PictureRenderer*);
     PictureRenderer* renderer() { return fRenderer; }
 
@@ -64,7 +61,6 @@
     uint32_t          fTimerTypes; // bitfield of TimerData::TimerFlags values
     bool              fTimeIndividualTiles;
     bool              fPurgeDecodedTex;
-    bool              fPreprocess;
 
     PictureResultsWriter* fWriter;
 
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index 705849d..89f2cda 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -22,6 +22,7 @@
 #include "SkImageEncoder.h"
 #include "SkMaskFilter.h"
 #include "SkMatrix.h"
+#include "SkMultiPictureDraw.h"
 #include "SkOSFile.h"
 #include "SkPicture.h"
 #include "SkPictureRecorder.h"
@@ -30,6 +31,7 @@
 #include "SkScalar.h"
 #include "SkStream.h"
 #include "SkString.h"
+#include "SkSurface.h"
 #include "SkTemplates.h"
 #include "SkTDArray.h"
 #include "SkThreadUtils.h"
@@ -52,11 +54,13 @@
                            const SkString* writePath,
                            const SkString* mismatchPath,
                            const SkString* inputFilename,
-                           bool useChecksumBasedFilenames) {
+                           bool useChecksumBasedFilenames,
+                           bool useMultiPictureDraw) {
     this->CopyString(&fWritePath, writePath);
     this->CopyString(&fMismatchPath, mismatchPath);
     this->CopyString(&fInputFilename, inputFilename);
     fUseChecksumBasedFilenames = useChecksumBasedFilenames;
+    fUseMultiPictureDraw = useMultiPictureDraw;
 
     SkASSERT(NULL == fPicture);
     SkASSERT(NULL == fCanvas.get());
@@ -415,8 +419,9 @@
 
 void SimplePictureRenderer::init(const SkPicture* picture, const SkString* writePath,
                                  const SkString* mismatchPath, const SkString* inputFilename,
-                                 bool useChecksumBasedFilenames) {
-    INHERITED::init(picture, writePath, mismatchPath, inputFilename, useChecksumBasedFilenames);
+                                 bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
+    INHERITED::init(picture, writePath, mismatchPath, inputFilename, 
+                    useChecksumBasedFilenames, useMultiPictureDraw);
     this->buildBBoxHierarchy();
 }
 
@@ -427,7 +432,15 @@
         return false;
     }
 
-    fCanvas->drawPicture(fPicture);
+    if (fUseMultiPictureDraw) {
+        SkMultiPictureDraw mpd;
+
+        mpd.add(fCanvas, fPicture);
+
+        mpd.draw();
+    } else {
+        fCanvas->drawPicture(fPicture);
+    }
     fCanvas->flush();
     if (out) {
         *out = SkNEW(SkBitmap);
@@ -467,7 +480,7 @@
 
 void TiledPictureRenderer::init(const SkPicture* pict, const SkString* writePath,
                                 const SkString* mismatchPath, const SkString* inputFilename,
-                                bool useChecksumBasedFilenames) {
+                                bool useChecksumBasedFilenames, bool useMultiPictureDraw) {
     SkASSERT(pict);
     SkASSERT(0 == fTileRects.count());
     if (NULL == pict || fTileRects.count() != 0) {
@@ -481,6 +494,7 @@
     this->CopyString(&fMismatchPath, mismatchPath);
     this->CopyString(&fInputFilename, inputFilename);
     fUseChecksumBasedFilenames = useChecksumBasedFilenames;
+    fUseMultiPictureDraw = useMultiPictureDraw;
     this->buildBBoxHierarchy();
 
     if (fTileWidthPercentage > 0) {
@@ -519,10 +533,8 @@
                 // Only count tiles in the X direction on the first pass.
                 fTilesX++;
             }
-            *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
-                                                    SkIntToScalar(tile_y_start),
-                                                    SkIntToScalar(fTileWidth),
-                                                    SkIntToScalar(fTileHeight));
+            *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
+                                                     fTileWidth, fTileHeight);
         }
     }
 }
@@ -575,10 +587,8 @@
                     // Only count tiles in the X direction on the first pass.
                     fTilesX++;
                 }
-                *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
-                                                        SkIntToScalar(tile_y_start),
-                                                        SkIntToScalar(current_width),
-                                                        SkIntToScalar(fTileHeight));
+                *fTileRects.append() = SkIRect::MakeXYWH(tile_x_start, tile_y_start,
+                                                         current_width, fTileHeight);
                 tile_x_start += current_width;
             }
 
@@ -594,13 +604,13 @@
  * is called.
  */
 static void draw_tile_to_canvas(SkCanvas* canvas,
-                                const SkRect& tileRect,
+                                const SkIRect& tileRect,
                                 const SkPicture* picture) {
     int saveCount = canvas->save();
     // Translate so that we draw the correct portion of the picture.
     // Perform a postTranslate so that the scaleFactor does not interfere with the positioning.
     SkMatrix mat(canvas->getTotalMatrix());
-    mat.postTranslate(-tileRect.fLeft, -tileRect.fTop);
+    mat.postTranslate(-SkIntToScalar(tileRect.fLeft), -SkIntToScalar(tileRect.fTop));
     canvas->setMatrix(mat);
     canvas->drawPicture(picture);
     canvas->restoreToCount(saveCount);
@@ -643,6 +653,27 @@
     draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
 }
 
+bool TiledPictureRenderer::postRender(SkCanvas* canvas, const SkIRect& tileRect, 
+                                      SkBitmap* tempBM, SkBitmap** out,
+                                      int tileNumber) {
+    bool success = true;
+
+    if (fEnableWrites) {
+        success &= write(canvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
+                         fUseChecksumBasedFilenames, &tileNumber);
+    }
+    if (out) {
+        if (canvas->readPixels(tempBM, 0, 0)) {
+            // Add this tile to the entire bitmap.
+            bitmapCopyAtOffset(*tempBM, *out, tileRect.left(), tileRect.top());
+        } else {
+            success = false;
+        }
+    }
+
+    return success;
+}
+
 bool TiledPictureRenderer::render(SkBitmap** out) {
     SkASSERT(fPicture != NULL);
     if (NULL == fPicture) {
@@ -650,29 +681,59 @@
     }
 
     SkBitmap bitmap;
-    if (out){
+    if (out) {
         *out = SkNEW(SkBitmap);
         setup_bitmap(*out, SkScalarCeilToInt(fPicture->cullRect().width()), 
                            SkScalarCeilToInt(fPicture->cullRect().height()));
         setup_bitmap(&bitmap, fTileWidth, fTileHeight);
     }
     bool success = true;
-    for (int i = 0; i < fTileRects.count(); ++i) {
-        draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
-        if (fEnableWrites) {
-            success &= write(fCanvas, fWritePath, fMismatchPath, fInputFilename, fJsonSummaryPtr,
-                             fUseChecksumBasedFilenames, &i);
+
+    if (fUseMultiPictureDraw) {
+        SkMultiPictureDraw mpd;
+        SkTDArray<SkSurface*> surfaces;
+        surfaces.setReserve(fTileRects.count());
+
+        // Create a separate SkSurface/SkCanvas for each tile along with a
+        // translated version of the skp (to mimic Chrome's behavior) and
+        // feed all such pairs to the MultiPictureDraw.
+        for (int i = 0; i < fTileRects.count(); ++i) {
+            SkImageInfo ii = fCanvas->imageInfo().makeWH(fTileRects[i].width(),
+                                                         fTileRects[i].height());
+            *surfaces.append() = fCanvas->newSurface(ii);
+            surfaces[i]->getCanvas()->setMatrix(fCanvas->getTotalMatrix());
+
+            SkPictureRecorder recorder;
+            SkCanvas* c = recorder.beginRecording(SkIntToScalar(fTileRects[i].width()),
+                                                  SkIntToScalar(fTileRects[i].height()));
+            c->save();
+            SkMatrix mat;
+            mat.setTranslate(-SkIntToScalar(fTileRects[i].fLeft),
+                             -SkIntToScalar(fTileRects[i].fTop));
+            c->setMatrix(mat);
+            c->drawPicture(fPicture);
+            c->restore();
+
+            SkAutoTUnref<SkPicture> xlatedPicture(recorder.endRecording());
+
+            mpd.add(surfaces[i]->getCanvas(), xlatedPicture);
         }
-        if (out) {
-            if (fCanvas->readPixels(&bitmap, 0, 0)) {
-                // Add this tile to the entire bitmap.
-                bitmapCopyAtOffset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()),
-                                   SkScalarFloorToInt(fTileRects[i].top()));
-            } else {
-                success = false;
-            }
+
+        // Render all the buffered SkCanvases/SkPictures
+        mpd.draw();
+
+        // Sort out the results and cleanup the allocated surfaces
+        for (int i = 0; i < fTileRects.count(); ++i) {
+            success &= this->postRender(surfaces[i]->getCanvas(), fTileRects[i], &bitmap, out, i);
+            surfaces[i]->unref();
+        }
+    } else {
+        for (int i = 0; i < fTileRects.count(); ++i) {
+            draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
+            success &= this->postRender(fCanvas, fTileRects[i], &bitmap, out, i);
         }
     }
+
     return success;
 }
 
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 04ac20f..3f58b18 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -88,12 +88,14 @@
      * @param inputFilename The name of the input file we are rendering.
      * @param useChecksumBasedFilenames Whether to use checksum-based filenames when writing
      *     bitmap images to disk.
+     * @param useMultiPictureDraw true if MultiPictureDraw should be used for rendering
      */
     virtual void init(const SkPicture* pict,
                       const SkString* writePath,
                       const SkString* mismatchPath,
                       const SkString* inputFilename,
-                      bool useChecksumBasedFilenames);
+                      bool useChecksumBasedFilenames,
+                      bool useMultiPictureDraw);
 
     /**
      * TODO(epoger): Temporary hack, while we work on http://skbug.com/2584 ('bench_pictures is
@@ -445,6 +447,7 @@
     SkAutoTUnref<SkCanvas> fCanvas;
     SkAutoTUnref<const SkPicture> fPicture;
     bool                   fUseChecksumBasedFilenames;
+    bool                   fUseMultiPictureDraw;
     ImageResultsAndExpectations*   fJsonSummaryPtr;
     SkDeviceTypes          fDeviceType;
     bool                   fEnableWrites;
@@ -548,7 +551,8 @@
                       const SkString* writePath,
                       const SkString* mismatchPath,
                       const SkString* inputFilename,
-                      bool useChecksumBasedFilenames) SK_OVERRIDE;
+                      bool useChecksumBasedFilenames,
+                      bool useMultiPictureDraw) SK_OVERRIDE;
 
     virtual bool render(SkBitmap** out = NULL) SK_OVERRIDE;
 
@@ -570,7 +574,8 @@
                       const SkString* writePath,
                       const SkString* mismatchPath,
                       const SkString* inputFilename,
-                      bool useChecksumBasedFilenames) SK_OVERRIDE;
+                      bool useChecksumBasedFilenames,
+                      bool useMultiPictureDraw) SK_OVERRIDE;
 
     /**
      * Renders to tiles, rather than a single canvas.
@@ -659,7 +664,7 @@
     void drawCurrentTile();
 
 protected:
-    SkTDArray<SkRect> fTileRects;
+    SkTDArray<SkIRect> fTileRects;
 
     virtual SkCanvas* setupCanvas(int width, int height) SK_OVERRIDE;
     virtual SkString getConfigNameInternal() SK_OVERRIDE;
@@ -681,6 +686,9 @@
 
     void setupTiles();
     void setupPowerOf2Tiles();
+    bool postRender(SkCanvas*, const SkIRect& tileRect, 
+                    SkBitmap* tempBM, SkBitmap** out,
+                    int tileNumber);
 
     typedef PictureRenderer INHERITED;
 };
diff --git a/tools/bbh_shootout.cpp b/tools/bbh_shootout.cpp
index 2a827fd..d4b290d 100644
--- a/tools/bbh_shootout.cpp
+++ b/tools/bbh_shootout.cpp
@@ -60,13 +60,13 @@
  * @param timer The timer used to benchmark the work.
  */
 static void do_benchmark_work(sk_tools::PictureRenderer* renderer,
-        BBoxType bBoxType,
-        SkPicture* pic,
-        const int numRepeats,
-        Timer* timer) {
+                              BBoxType bBoxType,
+                              SkPicture* pic,
+                              const int numRepeats,
+                              Timer* timer) {
     renderer->setBBoxHierarchyType(bBoxType);
     renderer->setGridSize(FLAGS_tilesize, FLAGS_tilesize);
-    renderer->init(pic, NULL, NULL, NULL, false);
+    renderer->init(pic, NULL, NULL, NULL, false, false);
 
     SkDebugf("%s %d times...\n", renderer->getConfigName().c_str(), numRepeats);
     for (int i = 0; i < numRepeats; ++i) {
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index ade93fc..93ee308 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -59,7 +59,7 @@
             "Report some GPU call statistics.");
 #endif
 
-DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before timing.");
+DEFINE_bool(mpd, false, "If true, use MultiPictureDraw to render.");
 
 // Buildbot-specific parameters
 DEFINE_string(builderName, "", "Name of the builder this is running on.");
@@ -202,23 +202,13 @@
         return false;
     }
 
-    if (FLAGS_preprocess) {
-        // Because the GPU preprocessing step relies on the in-memory picture
-        // statistics we need to rerecord the picture here
-        SkPictureRecorder recorder;
-        picture->playback(recorder.beginRecording(picture->cullRect().width(), 
-                                                  picture->cullRect().height(), 
-                                                  NULL, 0));
-        picture.reset(recorder.endRecording());
-    }
-
     SkString filename = SkOSPath::Basename(inputPath.c_str());
 
     gWriter.bench(filename.c_str(), 
                   SkScalarCeilToInt(picture->cullRect().width()), 
                   SkScalarCeilToInt(picture->cullRect().height()));
 
-    benchmark.run(picture);
+    benchmark.run(picture, FLAGS_mpd);
 
 #if SK_LAZY_CACHE_STATS
     if (FLAGS_trackDeferredCaching) {
@@ -365,7 +355,6 @@
     }
 
     benchmark->setPurgeDecodedTex(FLAGS_purgeDecodedTex);
-    benchmark->setPreprocess(FLAGS_preprocess);
 
     if (FLAGS_readPath.count() < 1) {
         gLogger.logError(".skp files or directories are required.\n");
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index d7a213c..6faa81a 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -40,7 +40,7 @@
 DEFINE_bool(gpuStats, false, "Only meaningful with gpu configurations. "
             "Report some GPU call statistics.");
 #endif
-DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before rendering.");
+DEFINE_bool(mpd, false, "If true, use MultiPictureDraw for rendering.");
 DEFINE_string(readJsonSummaryPath, "", "JSON file to read image expectations from.");
 DECLARE_string(readPath);
 DEFINE_bool(writeChecksumBasedFilenames, false,
@@ -184,16 +184,6 @@
         return false;
     }
 
-    if (FLAGS_preprocess) {
-        // Because the GPU preprocessing step relies on the in-memory picture
-        // statistics we need to rerecord the picture here
-        SkPictureRecorder recorder;
-        picture->playback(recorder.beginRecording(picture->cullRect().width(), 
-                                                  picture->cullRect().height(), 
-                                                  NULL, 0));
-        picture.reset(recorder.endRecording());
-    }
-
     while (FLAGS_bench_record) {
         SkPictureRecorder recorder;
         picture->playback(recorder.beginRecording(picture->cullRect().width(), 
@@ -208,13 +198,7 @@
              inputPath.c_str());
 
     renderer.init(picture, &writePathString, &mismatchPathString, &inputFilename,
-                  FLAGS_writeChecksumBasedFilenames);
-
-    if (FLAGS_preprocess) {
-        if (renderer.getCanvas()) {
-            renderer.getCanvas()->EXPERIMENTAL_optimize(renderer.getPicture());
-        }
-    }
+                  FLAGS_writeChecksumBasedFilenames, FLAGS_mpd);
 
     renderer.setup();
     renderer.enableWrites();