In render_pictures tiled rendering, draw a separate PNG for each tile.
authorscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 20 Sep 2012 14:54:21 +0000 (14:54 +0000)
committerscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 20 Sep 2012 14:54:21 +0000 (14:54 +0000)
Since the passed in picture may represent an image which is too large
to be represented on the GPU, never create such a large canvas. Instead,
after drawing to each tile, create a file showing just that tile.

Review URL: https://codereview.appspot.com/6532056

git-svn-id: http://skia.googlecode.com/svn/trunk@5603 2bbb7eff-a529-9590-31e7-b0007b416f81

tools/PictureBenchmark.cpp
tools/PictureRenderer.cpp
tools/PictureRenderer.h
tools/render_pictures_main.cpp

index 7879414..0b4f56e 100644 (file)
@@ -71,7 +71,7 @@ void PictureBenchmark::run(SkPicture* pict) {
 
     // We throw this away to remove first time effects (such as paging in this program)
     fRenderer->setup();
-    fRenderer->render(false);
+    fRenderer->render(NULL);
     fRenderer->resetState();
 
     BenchTimer* timer = this->setupTimer();
index 96649de..85bd194 100644 (file)
@@ -99,38 +99,43 @@ void PictureRenderer::resetState() {
 #endif
 }
 
-bool PictureRenderer::write(const SkString& path) const {
-    SkASSERT(fCanvas.get() != NULL);
+bool PictureRenderer::write(SkCanvas* canvas, SkString path) const {
+    SkASSERT(canvas != NULL);
     SkASSERT(fPicture != NULL);
-    if (NULL == fCanvas.get() || NULL == fPicture) {
+    if (NULL == canvas || NULL == fPicture) {
         return false;
     }
 
     SkBitmap bitmap;
-    sk_tools::setup_bitmap(&bitmap, fPicture->width(), fPicture->height());
+    SkISize size = canvas->getDeviceSize();
+    sk_tools::setup_bitmap(&bitmap, size.width(), size.height());
 
-    fCanvas->readPixels(&bitmap, 0, 0);
+    canvas->readPixels(&bitmap, 0, 0);
     sk_tools::force_all_opaque(bitmap);
 
+    // Since path is passed in by value, it is okay to modify it.
+    path.append(".png");
     return SkImageEncoder::EncodeFile(path.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-void RecordPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
+bool RecordPictureRenderer::render(const SkString*) {
     SkPicture replayer;
     SkCanvas* recorder = replayer.beginRecording(fPicture->width(), fPicture->height());
     fPicture->draw(recorder);
     replayer.endRecording();
+    // Since this class does not actually render, return false.
+    return false;
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
+bool PipePictureRenderer::render(const SkString* path) {
     SkASSERT(fCanvas.get() != NULL);
     SkASSERT(fPicture != NULL);
     if (NULL == fCanvas.get() || NULL == fPicture) {
-        return;
+        return false;
     }
 
     PipeController pipeController(fCanvas.get());
@@ -139,19 +144,21 @@ void PipePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
     pipeCanvas->drawPicture(*fPicture);
     writer.endRecording();
     fCanvas->flush();
+    return path != NULL && this->write(fCanvas, *path);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-void SimplePictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
+bool SimplePictureRenderer::render(const SkString* path) {
     SkASSERT(fCanvas.get() != NULL);
     SkASSERT(fPicture != NULL);
     if (NULL == fCanvas.get() || NULL == fPicture) {
-        return;
+        return false;
     }
 
     fCanvas->drawPicture(*fPicture);
     fCanvas->flush();
+    return path != NULL && this->write(fCanvas, *path);
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
@@ -398,16 +405,10 @@ void TiledPictureRenderer::setup() {
     }
 }
 
-void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
+bool TiledPictureRenderer::render(const SkString* path) {
     SkASSERT(fPicture != NULL);
     if (NULL == fPicture) {
-        return;
-    }
-
-    if (doExtraWorkToDrawToBaseCanvas) {
-        if (NULL == fCanvas.get()) {
-            fCanvas.reset(this->INHERITED::setupCanvas());
-        }
+        return false;
     }
 
     if (this->multiThreaded()) {
@@ -437,6 +438,8 @@ void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
             SkDELETE(thread);
         }
         threads.reset();
+        // Currently multithreaded is not an option for render_pictures
+        return false;
     } else {
         // For single thread, we really only need one canvas total.
         SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
@@ -444,13 +447,15 @@ void TiledPictureRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
 
         for (int i = 0; i < fTileRects.count(); ++i) {
             DrawTileToCanvas(canvas, fTileRects[i], fPicture);
-            if (doExtraWorkToDrawToBaseCanvas) {
-                SkASSERT(fCanvas.get() != NULL);
-                SkBitmap source = canvas->getDevice()->accessBitmap(false);
-                fCanvas->drawBitmap(source, fTileRects[i].fLeft, fTileRects[i].fTop);
-                fCanvas->flush();
+            if (path != NULL) {
+                SkString tilePath(*path);
+                tilePath.appendf("%i", i);
+                if (!this->write(canvas, tilePath)) {
+                    return false;
+                }
             }
         }
+        return path != NULL;
     }
 }
 
@@ -474,8 +479,10 @@ void PlaybackCreationRenderer::setup() {
     fPicture->draw(recorder);
 }
 
-void PlaybackCreationRenderer::render(bool doExtraWorkToDrawToBaseCanvas) {
+bool PlaybackCreationRenderer::render(const SkString*) {
     fReplayer.endRecording();
+    // Since this class does not actually render, return false.
+    return false;
 }
 
 }
index 845aa9f..f8133ea 100644 (file)
@@ -47,12 +47,12 @@ public:
     /**
      * Perform work that is to be timed. Typically this is rendering, but is also used for recording
      * and preparing picture for playback by the subclasses which do those.
-     * @param doExtraWorkToDrawToBaseCanvas Perform extra work to draw to fCanvas. Some subclasses
-     *                                      will automatically draw to fCanvas, but in the tiled
-     *                                      case, for example, true needs to be passed so that
-     *                                      the tiles will be stitched together on fCanvas.
+     * If path is non-null, subclass implementations should call write().
+     * @param path If non-null, also write the output to the file specified by path. path should
+     *             have no extension; it will be added by write().
+     * @return bool True if path is non-null and the output is successfully written to a file.
      */
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) = 0;
+    virtual bool render(const SkString* path) = 0;
 
     virtual void end();
     void resetState();
@@ -95,9 +95,14 @@ public:
 #endif
         {}
 
-    bool write(const SkString& path) const;
-
 protected:
+    /**
+     * Write the canvas to the specified path.
+     * @param canvas Must be non-null. Canvas to be written to a file.
+     * @param path Path for the file to be written. Should have no extension; write() will append
+     *             an appropriate one.
+     */
+    bool write(SkCanvas* canvas, SkString path) const;
     SkCanvas* setupCanvas();
     virtual SkCanvas* setupCanvas(int width, int height);
 
@@ -119,7 +124,7 @@ private:
  * to time.
  */
 class RecordPictureRenderer : public PictureRenderer {
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE;
+    virtual bool render(const SkString*) SK_OVERRIDE;
 
     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
 
@@ -128,7 +133,7 @@ class RecordPictureRenderer : public PictureRenderer {
 
 class PipePictureRenderer : public PictureRenderer {
 public:
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE;
+    virtual bool render(const SkString*) SK_OVERRIDE;
 
 private:
     typedef PictureRenderer INHERITED;
@@ -136,7 +141,7 @@ private:
 
 class SimplePictureRenderer : public PictureRenderer {
 public:
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE;
+    virtual bool render(const SkString*) SK_OVERRIDE;
 
 private:
     typedef PictureRenderer INHERITED;
@@ -147,8 +152,16 @@ public:
     TiledPictureRenderer();
 
     virtual void init(SkPicture* pict) SK_OVERRIDE;
+
     virtual void setup() SK_OVERRIDE;
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) 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.
+     * Multithreaded mode currently does not support writing to a file.
+     */
+    virtual bool render(const SkString* path) SK_OVERRIDE;
+
     virtual void end() SK_OVERRIDE;
 
     void setTileWidth(int width) {
@@ -241,7 +254,7 @@ class PlaybackCreationRenderer : public PictureRenderer {
 public:
     virtual void setup() SK_OVERRIDE;
 
-    virtual void render(bool doExtraWorkToDrawToBaseCanvas) SK_OVERRIDE;
+    virtual bool render(const SkString*) SK_OVERRIDE;
 
     virtual SkString getPerIterTimeFormat() SK_OVERRIDE { return SkString("%.4f"); }
 
index 178d9ba..5a7ff44 100644 (file)
@@ -75,19 +75,8 @@ static void usage(const char* argv0) {
 static void make_output_filepath(SkString* path, const SkString& dir,
                                  const SkString& name) {
     sk_tools::make_filepath(path, dir, name);
-    path->remove(path->size() - 3, 3);
-    path->append("png");
-}
-
-static bool write_output(const SkString& outputDir, const SkString& inputFilename,
-                         const sk_tools::PictureRenderer& renderer) {
-    SkString outputPath;
-    make_output_filepath(&outputPath, outputDir, inputFilename);
-    bool isWritten = renderer.write(outputPath);
-    if (!isWritten) {
-        SkDebugf("Could not write to file %s\n", outputPath.c_str());
-    }
-    return isWritten;
+    // Remove ".skp"
+    path->remove(path->size() - 4, 4);
 }
 
 static bool render_picture(const SkString& inputPath, const SkString& outputDir,
@@ -118,11 +107,15 @@ static bool render_picture(const SkString& inputPath, const SkString& outputDir,
 
     renderer.init(aur);
 
-    renderer.render(true);
+    SkString outputPath;
+    make_output_filepath(&outputPath, outputDir, inputFilename);
 
-    renderer.resetState();
+    success = renderer.render(&outputPath);
+    if (!success) {
+        SkDebugf("Could not write to file %s\n", outputPath.c_str());
+    }
 
-    success = write_output(outputDir, inputFilename, renderer);
+    renderer.resetState();
 
     renderer.end();
     return success;