Proposed SkCanvas API for preLoading textures to VRAM v2.0
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 14 Mar 2014 18:23:12 +0000 (18:23 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Fri, 14 Mar 2014 18:23:12 +0000 (18:23 +0000)
This is an update to (Proposed SkCanvas API for preLoading textures to VRAM - https://codereview.chromium.org/192853002/). It takes into account in-person feedback on the initial proposal. The main feedback was to land this closer to where we will ultimately wind up with the reordered rendering capability (and don't have an SkCanvas entry point (yet)).

R=reed@google.com, bsalomon@google.com

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/197123003

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

include/core/SkCanvas.h
include/core/SkDevice.h
include/core/SkPicture.h
include/gpu/SkGpuDevice.h
src/core/SkCanvas.cpp
src/core/SkDevice.cpp
src/core/SkPicture.cpp
src/gpu/SkGpuDevice.cpp
tools/PictureRenderer.cpp
tools/PictureRenderer.h
tools/render_pictures_main.cpp

index 716720b..7fd2135 100644 (file)
@@ -962,6 +962,14 @@ public:
                                 const SkPath& path, const SkMatrix* matrix,
                                 const SkPaint& paint);
 
+    /** PRIVATE / EXPERIMENTAL -- do not call
+        Perform back-end analysis/optimization of a picture. This may attach
+        optimization data to the picture which can be used by a later
+        drawPicture call.
+        @param picture The recorded drawing commands to analyze/optimize
+    */
+    void EXPERIMENTAL_optimize(SkPicture* picture);
+
     /** Draw the picture into this canvas. This method effective brackets the
         playback of the picture's draw calls with save/restore, so the state
         of this canvas will be unchanged after this call.
index 2d9b0fc..7161bb1 100644 (file)
@@ -423,6 +423,24 @@ protected:
      */
     SkDeviceProperties fLeakyProperties;
 
+    /**
+     *  PRIVATE / EXPERIMENTAL -- do not call
+     *  Construct an acceleration object and attach it to 'picture'
+     */
+    virtual void EXPERIMENTAL_optimize(SkPicture* picture);
+
+    /**
+     *  PRIVATE / EXPERIMENTAL -- do not call
+     *  This entry point gives the backend an opportunity to take over the rendering
+     *  of 'picture'. If optimization data is available (due to an earlier
+     *  'optimize' call) this entry point should make use of it and return true
+     *  if all rendering has been done. If false is returned, SkCanvas will
+     *  perform its own rendering pass. It is acceptable for the backend 
+     *  to perform some device-specific warm up tasks and then let SkCanvas
+     *  perform the main rendering loop (by return false from here).
+     */
+    virtual bool EXPERIMENTAL_drawPicture(const SkPicture& picture);
+
 private:
     friend class SkCanvas;
     friend struct DeviceCM; //for setMatrixClip
index ef6f4a2..8fa7777 100644 (file)
@@ -34,6 +34,27 @@ class SK_API SkPicture : public SkRefCnt {
 public:
     SK_DECLARE_INST_COUNT(SkPicture)
 
+    // AccelData provides a base class for device-specific acceleration
+    // data. It is added to the picture via a call to a device's optimize 
+    // method.
+    class AccelData : public SkRefCnt {
+    public:
+        typedef uint8_t Domain;
+        typedef uint32_t Key;
+
+        AccelData(Key key) : fKey(key) { }
+
+        const Key& getKey() const { return fKey; }
+
+        // This entry point allows user's to get a unique domain prefix
+        // for their keys
+        static Domain GenerateDomain();
+    private:
+        Key fKey;
+
+        typedef SkRefCnt INHERITED;
+    };
+
     /** The constructor prepares the picture to record.
         @param width the width of the virtual device the picture records.
         @param height the height of the virtual device the picture records.
@@ -44,6 +65,18 @@ public:
     */
     SkPicture(const SkPicture& src);
 
+    /**  PRIVATE / EXPERIMENTAL -- do not call */
+    void EXPERIMENTAL_addAccelData(const AccelData* data) { 
+        SkRefCnt_SafeAssign(fAccelData, data); 
+    }
+    /**  PRIVATE / EXPERIMENTAL -- do not call */
+    const AccelData* EXPERIMENTAL_getAccelData(AccelData::Key key) const { 
+        if (NULL != fAccelData && fAccelData->getKey() == key) {
+            return fAccelData; 
+        }
+        return NULL;
+    }
+
     /**
      *  Function signature defining a function that sets up an SkBitmap from encoded data. On
      *  success, the SkBitmap should have its Config, width, height, rowBytes and pixelref set.
@@ -262,9 +295,10 @@ protected:
     // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to
     // install their own SkPicturePlayback-derived players,SkPictureRecord-derived
     // recorders and set the picture size
-    SkPicturePlayback* fPlayback;
-    SkPictureRecord* fRecord;
-    int fWidth, fHeight;
+    SkPicturePlayback*    fPlayback;
+    SkPictureRecord*      fRecord;
+    int                   fWidth, fHeight;
+    const AccelData*      fAccelData;
 
     // Create a new SkPicture from an existing SkPicturePlayback. Ref count of
     // playback is unchanged.
index f8ee781..7394361 100644 (file)
@@ -14,6 +14,7 @@
 #include "SkGr.h"
 #include "SkBitmap.h"
 #include "SkBitmapDevice.h"
+#include "SkPicture.h"
 #include "SkRegion.h"
 #include "GrContext.h"
 
@@ -146,10 +147,16 @@ public:
 
     class SkAutoCachedTexture; // used internally
 
+
 protected:
     virtual bool onReadPixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) SK_OVERRIDE;
     virtual bool onWritePixels(const SkImageInfo&, const void*, size_t, int, int) SK_OVERRIDE;
 
+    /**  PRIVATE / EXPERIMENTAL -- do not call */
+    virtual void EXPERIMENTAL_optimize(SkPicture* picture) SK_OVERRIDE;
+    /**  PRIVATE / EXPERIMENTAL -- do not call */
+    virtual bool EXPERIMENTAL_drawPicture(const SkPicture& picture) SK_OVERRIDE;
+
 private:
     GrContext*      fContext;
 
@@ -215,6 +222,8 @@ private:
                          int tileSize,
                          bool bicubic);
 
+    static SkPicture::AccelData::Key ComputeAccelDataKey();
+
     typedef SkBitmapDevice INHERITED;
 };
 
index 4ac7b29..f2200a6 100644 (file)
@@ -2461,8 +2461,23 @@ void SkCanvas::drawTextOnPathHV(const void* text, size_t byteLength,
 }
 
 ///////////////////////////////////////////////////////////////////////////////
+void SkCanvas::EXPERIMENTAL_optimize(SkPicture* picture) {
+    SkBaseDevice* device = this->getDevice();
+    if (NULL != device) {
+        device->EXPERIMENTAL_optimize(picture);
+    }
+}
 
 void SkCanvas::drawPicture(SkPicture& picture) {
+    SkBaseDevice* device = this->getTopDevice();
+    if (NULL != device) {
+        // Canvas has to first give the device the opportunity to render
+        // the picture itself.
+        if (device->EXPERIMENTAL_drawPicture(picture)) {
+            return; // the device has rendered the entire picture
+        }
+    }
+
     picture.draw(this);
 }
 
index 5871813..3cfe89c 100644 (file)
@@ -213,3 +213,12 @@ void* SkBaseDevice::onAccessPixels(SkImageInfo* info, size_t* rowBytes) {
 #ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
 void SkBaseDevice::writePixels(const SkBitmap&, int x, int y, SkCanvas::Config8888) {}
 #endif
+
+void SkBaseDevice::EXPERIMENTAL_optimize(SkPicture* picture) {
+    // The base class doesn't perform any analysis but derived classes may
+}
+
+bool SkBaseDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) {
+    // The base class doesn't perform any accelerated picture rendering
+    return false;
+}
index 9270236..92311f3 100644 (file)
@@ -117,9 +117,12 @@ SkPicture::SkPicture() {
     fRecord = NULL;
     fPlayback = NULL;
     fWidth = fHeight = 0;
+    fAccelData = NULL;
 }
 
-SkPicture::SkPicture(const SkPicture& src) : INHERITED() {
+SkPicture::SkPicture(const SkPicture& src) 
+    : INHERITED()
+    , fAccelData(NULL) {
     fWidth = src.fWidth;
     fHeight = src.fHeight;
     fRecord = NULL;
@@ -141,6 +144,7 @@ SkPicture::SkPicture(const SkPicture& src) : INHERITED() {
 SkPicture::~SkPicture() {
     SkSafeUnref(fRecord);
     SkDELETE(fPlayback);
+    SkSafeUnref(fAccelData);
 }
 
 void SkPicture::internalOnly_EnableOpts(bool enableOpts) {
@@ -152,6 +156,7 @@ void SkPicture::internalOnly_EnableOpts(bool enableOpts) {
 void SkPicture::swap(SkPicture& other) {
     SkTSwap(fRecord, other.fRecord);
     SkTSwap(fPlayback, other.fPlayback);
+    SkTSwap(fAccelData, other.fAccelData);
     SkTSwap(fWidth, other.fWidth);
     SkTSwap(fHeight, other.fHeight);
 }
@@ -188,6 +193,17 @@ void SkPicture::clone(SkPicture* pictures, int count) const {
     }
 }
 
+SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
+    static int32_t gNextID = 0;
+
+    int32_t id = sk_atomic_inc(&gNextID);
+    if (id >= 1 << (8 * sizeof(Domain))) {
+        SK_CRASH();
+    }
+
+    return static_cast<Domain>(id);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkCanvas* SkPicture::beginRecording(int width, int height,
@@ -196,7 +212,7 @@ SkCanvas* SkPicture::beginRecording(int width, int height,
         SkDELETE(fPlayback);
         fPlayback = NULL;
     }
-
+    SkSafeUnref(fAccelData);
     SkSafeSetNull(fRecord);
 
     // Must be set before calling createBBoxHierarchy
@@ -250,7 +266,7 @@ void SkPicture::endRecording() {
 
 void SkPicture::draw(SkCanvas* surface, SkDrawPictureCallback* callback) {
     this->endRecording();
-    if (fPlayback) {
+    if (NULL != fPlayback) {
         fPlayback->draw(*surface, callback);
     }
 }
@@ -310,7 +326,8 @@ SkPicture::SkPicture(SkPicturePlayback* playback, int width, int height)
     : fPlayback(playback)
     , fRecord(NULL)
     , fWidth(width)
-    , fHeight(height) {}
+    , fHeight(height)
+    , fAccelData(NULL) {}
 
 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
     SkPictInfo info;
@@ -418,7 +435,9 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
 }
 
 bool SkPicture::willPlayBackBitmaps() const {
-    if (!fPlayback) return false;
+    if (!fPlayback) {
+        return false;
+    }
     return fPlayback->containsBitmaps();
 }
 
index e872f1a..a86170b 100644 (file)
@@ -25,6 +25,7 @@
 #include "SkImageFilter.h"
 #include "SkMaskFilter.h"
 #include "SkPathEffect.h"
+#include "SkPicture.h"
 #include "SkRRect.h"
 #include "SkStroke.h"
 #include "SkSurface.h"
@@ -2003,3 +2004,44 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
     this->initFromRenderTarget(context, texture->asRenderTarget(), true);
     fNeedClear = needClear;
 }
+
+class GPUAccelData : public SkPicture::AccelData {
+public:
+    GPUAccelData(Key key) : INHERITED(key) { }
+
+protected:
+
+private:
+    typedef SkPicture::AccelData INHERITED;
+};
+
+// In the future this may not be a static method if we need to incorporate the
+// clip and matrix state into the key
+SkPicture::AccelData::Key SkGpuDevice::ComputeAccelDataKey() {
+    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
+
+    return gGPUID;
+}
+
+void SkGpuDevice::EXPERIMENTAL_optimize(SkPicture* picture) {
+    SkPicture::AccelData::Key key = ComputeAccelDataKey();
+
+    GPUAccelData* data = SkNEW_ARGS(GPUAccelData, (key));
+
+    picture->EXPERIMENTAL_addAccelData(data);
+}
+
+bool SkGpuDevice::EXPERIMENTAL_drawPicture(const SkPicture& picture) {
+    SkPicture::AccelData::Key key = ComputeAccelDataKey();
+
+    const SkPicture::AccelData* data = picture.EXPERIMENTAL_getAccelData(key);
+    if (NULL == data) {
+        return false;
+    }
+
+#if 0
+    const GPUAccelData *gpuData = static_cast<const GPUAccelData*>(data);
+#endif
+
+    return false;
+}
index ebac9ca..466e31d 100644 (file)
@@ -570,20 +570,19 @@ void TiledPictureRenderer::setupPowerOf2Tiles() {
 }
 
 /**
- * Draw the specified playback to the canvas translated to rectangle provided, so that this mini
+ * Draw the specified picture to the canvas translated to rectangle provided, so that this mini
  * canvas represents the rectangle's portion of the overall picture.
  * Saves and restores so that the initial clip and matrix return to their state before this function
  * is called.
  */
-template<class T>
-static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playback) {
+static void draw_tile_to_canvas(SkCanvas* canvas, const SkRect& tileRect, 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);
     canvas->setMatrix(mat);
-    playback->draw(canvas);
+    canvas->drawPicture(*picture);
     canvas->restoreToCount(saveCount);
     canvas->flush();
 }
@@ -621,7 +620,7 @@ bool TiledPictureRenderer::nextTile(int &i, int &j) {
 
 void TiledPictureRenderer::drawCurrentTile() {
     SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
-    DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
+    draw_tile_to_canvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
 }
 
 bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
@@ -638,7 +637,7 @@ bool TiledPictureRenderer::render(const SkString* path, SkBitmap** out) {
     }
     bool success = true;
     for (int i = 0; i < fTileRects.count(); ++i) {
-        DrawTileToCanvas(fCanvas, fTileRects[i], fPicture);
+        draw_tile_to_canvas(fCanvas, fTileRects[i], fPicture);
         if (NULL != path) {
             success &= writeAppendNumber(fCanvas, path, i, fJsonSummaryPtr);
         }
@@ -722,7 +721,7 @@ public:
         }
 
         for (int i = fStart; i < fEnd; i++) {
-            DrawTileToCanvas(fCanvas, fRects[i], fClone);
+            draw_tile_to_canvas(fCanvas, fRects[i], fClone);
             if ((fPath != NULL) && !writeAppendNumber(fCanvas, fPath, i, fJsonSummaryPtr)
                 && fSuccess != NULL) {
                 *fSuccess = false;
index c3438c9..010aadf 100644 (file)
@@ -309,6 +309,10 @@ public:
         }
     }
 
+    SkCanvas* getCanvas() {
+        return fCanvas;
+    }
+
     SkGLContextHelper* getGLContext() {
         GrContextFactory::GLContextType glContextType
                 = GrContextFactory::kNull_GLContextType;
index f0609c9..245f995 100644 (file)
@@ -44,6 +44,8 @@ DEFINE_bool(validate, false, "Verify that the rendered image contains the same p
 
 DEFINE_bool(bench_record, false, "If true, drop into an infinite loop of recording the picture.");
 
+DEFINE_bool(preprocess, false, "If true, perform device specific preprocessing before rendering.");
+
 static void make_output_filepath(SkString* path, const SkString& dir,
                                  const SkString& name) {
     sk_tools::make_filepath(path, dir, name);
@@ -188,6 +190,13 @@ static bool render_picture_internal(const SkString& inputPath, const SkString* o
              inputPath.c_str());
 
     renderer.init(picture);
+    
+    if (FLAGS_preprocess) {
+        if (NULL != renderer.getCanvas()) {
+            renderer.getCanvas()->EXPERIMENTAL_optimize(picture);
+        }
+    }
+
     renderer.setup();
 
     SkString* outputPath = NULL;