Switch GPU Optimization code to SkRecord
authorrobertphillips <robertphillips@google.com>
Wed, 27 Aug 2014 18:53:28 +0000 (11:53 -0700)
committerCommit bot <commit-bot@chromium.org>
Wed, 27 Aug 2014 18:53:28 +0000 (11:53 -0700)
R=mtklein@google.com, bsalomon@google.com

Author: robertphillips@google.com

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

include/core/SkPicture.h
src/gpu/GrPictureUtils.cpp
src/gpu/GrPictureUtils.h
src/gpu/SkGpuDevice.cpp
tests/PictureTest.cpp

index 936291a58a941ea1378a3f93e453127f97667301..30d08211db97edf3cee613cacac6fdc568737d6e 100644 (file)
@@ -296,7 +296,7 @@ private:
     friend class SkPictureData;                // to access OperationList
     friend class SkPictureRecorder;            // just for SkPicture-based constructor
     friend class SkGpuDevice;                  // for EXPERIMENTAL_getActiveOps/OperationList
-    friend class GrGatherCanvas;               // needs to know if old or new picture
+    friend class CollectLayers;                // access to fRecord
     friend class SkPicturePlayback;            // to get fData & OperationList
     friend class SkPictureReplacementPlayback; // to access OperationList
 
index 7295089e821cefff413d55c425c69c082794c37b..521160ac8afd172d34b4d79ab8914fbbb2e20102 100644 (file)
@@ -6,12 +6,10 @@
  */
 
 #include "GrPictureUtils.h"
-#include "SkCanvasPriv.h"
-#include "SkDevice.h"
-#include "SkDraw.h"
+
 #include "SkPaintPriv.h"
-#include "SkPictureData.h"
-#include "SkPicturePlayback.h"
+#include "SkRecord.h"
+#include "SkRecords.h"
 
 SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
     static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
@@ -19,261 +17,261 @@ SkPicture::AccelData::Key GrAccelData::ComputeAccelDataKey() {
     return gGPUID;
 }
 
-// The GrGather device performs GPU-backend-specific preprocessing on
-// a picture. The results are stored in a GrAccelData.
-//
-// Currently the only interesting work is done in drawDevice (i.e., when a
-// saveLayer is collapsed back into its parent) and, maybe, in onCreateDevice.
-// All the current work could be done much more efficiently by just traversing the
-// raw op codes in the SkPicture (although we would still need to replay all the
-// clip calls).
-class GrGatherDevice : public SkBaseDevice {
+// SkRecord visitor to gather saveLayer/restore information.
+class CollectLayers {
 public:
-    SK_DECLARE_INST_COUNT(GrGatherDevice)
-
-    GrGatherDevice(int width, int height, SkPicturePlayback* playback, GrAccelData* accelData,
-                   int saveLayerDepth) {
-        fPlayback = playback;
-        fSaveLayerDepth = saveLayerDepth;
-        fInfo.fValid = true;
-        fInfo.fSize.set(width, height);
-        fInfo.fPaint = NULL;
-        fInfo.fSaveLayerOpID = fPlayback->curOpID();
-        fInfo.fRestoreOpID = 0;
-        fInfo.fHasNestedLayers = false;
-        fInfo.fIsNested = (2 == fSaveLayerDepth);
-
-        fEmptyBitmap.setInfo(SkImageInfo::MakeUnknown(fInfo.fSize.fWidth, fInfo.fSize.fHeight));
-        fAccelData = accelData;
-        fAlreadyDrawn = false;
-    }
-
-    virtual ~GrGatherDevice() { }
+    CollectLayers(const SkPicture* pict, GrAccelData* accelData)
+        : fPictureID(pict->uniqueID())
+        , fCTM(&SkMatrix::I())
+        , fCurrentClipBounds(SkIRect::MakeXYWH(0, 0, pict->width(), pict->height()))
+        , fSaveLayersInStack(0)
+        , fAccelData(accelData) {
+
+        if (NULL == pict->fRecord.get()) {
+            return;
+        }
 
-    virtual SkImageInfo imageInfo() const SK_OVERRIDE {
-        return fEmptyBitmap.info();
-    }
+        for (fCurrentOp = 0; fCurrentOp < pict->fRecord->count(); ++fCurrentOp) {
+            pict->fRecord->visit<void>(fCurrentOp, *this);
+        }
 
-#ifdef SK_SUPPORT_LEGACY_WRITEPIXELSCONFIG
-    virtual void writePixels(const SkBitmap& bitmap, int x, int y,
-                             SkCanvas::Config8888 config8888) SK_OVERRIDE {
-        NotSupported();
+        while (!fSaveStack.isEmpty()) {
+            this->popSaveBlock();
+        }
     }
-#endif
-    virtual GrRenderTarget* accessRenderTarget() SK_OVERRIDE { return NULL; }
 
-protected:
-    virtual bool filterTextFlags(const SkPaint& paint, TextFlags*) SK_OVERRIDE {
-        return false;
-    }
-    virtual void clear(SkColor color) SK_OVERRIDE {
-        NothingToDo();
-    }
-    virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawPoints(const SkDraw& draw, SkCanvas::PointMode mode, size_t count,
-                            const SkPoint points[], const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawRect(const SkDraw& draw, const SkRect& rect,
-                          const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawOval(const SkDraw& draw, const SkRect& rect,
-                          const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawRRect(const SkDraw& draw, const SkRRect& rrect,
-                           const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawPath(const SkDraw& draw, const SkPath& path,
-                          const SkPaint& paint, const SkMatrix* prePathMatrix,
-                          bool pathIsMutable) SK_OVERRIDE {
+    template <typename T> void operator()(const T& op) {
+        this->updateCTM(op);
+        this->updateClipBounds(op);
+        this->trackSaveLayers(op);
     }
-    virtual void drawBitmap(const SkDraw& draw, const SkBitmap& bitmap,
-                            const SkMatrix& matrix, const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawSprite(const SkDraw&, const SkBitmap& bitmap,
-                            int x, int y, const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawBitmapRect(const SkDraw& draw, const SkBitmap& bitmap,
-                                const SkRect* srcOrNull, const SkRect& dst,
-                                const SkPaint& paint,
-                                SkCanvas::DrawBitmapRectFlags flags) SK_OVERRIDE {
-    }
-    virtual void drawText(const SkDraw& draw, const void* text, size_t len,
-                          SkScalar x, SkScalar y,
-                          const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawPosText(const SkDraw& draw, const void* text, size_t len,
-                             const SkScalar pos[], SkScalar constY,
-                             int scalarsPerPos, const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawTextOnPath(const SkDraw& draw, const void* text, size_t len,
-                                const SkPath& path, const SkMatrix* matrix,
-                                const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawVertices(const SkDraw& draw, SkCanvas::VertexMode, int vertexCount,
-                              const SkPoint verts[], const SkPoint texs[],
-                              const SkColor colors[], SkXfermode* xmode,
-                              const uint16_t indices[], int indexCount,
-                              const SkPaint& paint) SK_OVERRIDE {
-    }
-    virtual void drawDevice(const SkDraw& draw, SkBaseDevice* deviceIn, int x, int y,
-                            const SkPaint& paint) SK_OVERRIDE {
-        // deviceIn is the one that is being "restored" back to its parent
-        GrGatherDevice* device = static_cast<GrGatherDevice*>(deviceIn);
 
-        if (device->fAlreadyDrawn) {
-            return;
-        }
+private:
 
-        device->fInfo.fRestoreOpID = fPlayback->curOpID();
-        device->fInfo.fCTM = *draw.fMatrix;
-        device->fInfo.fCTM.postTranslate(SkIntToScalar(-device->getOrigin().fX),
-                                         SkIntToScalar(-device->getOrigin().fY));
+    class SaveInfo {
+    public:
+        SaveInfo() { }
+        SaveInfo(int opIndex, bool isSaveLayer, const SkPaint* paint, const SkIRect& bounds) 
+            : fStartIndex(opIndex)
+            , fIsSaveLayer(isSaveLayer)
+            , fHasNestedSaveLayer(false)
+            , fPaint(paint)
+            , fBounds(bounds) {
 
-        device->fInfo.fOffset = device->getOrigin();
+        }
 
-        if (NeedsDeepCopy(paint)) {
-            // This NULL acts as a signal that the paint was uncopyable (for now)
-            device->fInfo.fPaint = NULL;
-            device->fInfo.fValid = false;
-        } else {
-            device->fInfo.fPaint = SkNEW_ARGS(SkPaint, (paint));
+        int            fStartIndex;
+        bool           fIsSaveLayer;
+        bool           fHasNestedSaveLayer;
+        const SkPaint* fPaint;
+        SkIRect        fBounds;
+    };
+
+    uint32_t            fPictureID;
+    unsigned int        fCurrentOp;
+    const SkMatrix*     fCTM;
+    SkIRect             fCurrentClipBounds;
+    int                 fSaveLayersInStack;
+    SkTDArray<SaveInfo> fSaveStack;
+    GrAccelData*        fAccelData;
+
+    template <typename T> void updateCTM(const T&) { /* most ops don't change the CTM */ }
+    void updateCTM(const SkRecords::Restore& op)   { fCTM = &op.matrix; }
+    void updateCTM(const SkRecords::SetMatrix& op) { fCTM = &op.matrix; }
+
+    template <typename T> void updateClipBounds(const T&) { /* most ops don't change the clip */ }
+    // Each of these devBounds fields is the state of the device bounds after the op.
+    // So Restore's devBounds are those bounds saved by its paired Save or SaveLayer.
+    void updateClipBounds(const SkRecords::Restore& op)    { fCurrentClipBounds = op.devBounds; }
+    void updateClipBounds(const SkRecords::ClipPath& op)   { fCurrentClipBounds = op.devBounds; }
+    void updateClipBounds(const SkRecords::ClipRRect& op)  { fCurrentClipBounds = op.devBounds; }
+    void updateClipBounds(const SkRecords::ClipRect& op)   { fCurrentClipBounds = op.devBounds; }
+    void updateClipBounds(const SkRecords::ClipRegion& op) { fCurrentClipBounds = op.devBounds; }
+    void updateClipBounds(const SkRecords::SaveLayer& op)  {
+        if (NULL != op.bounds) {
+            fCurrentClipBounds.intersect(this->adjustAndMap(*op.bounds, op.paint));
         }
+    }
 
-        fAccelData->addSaveLayerInfo(device->fInfo);
-        device->fAlreadyDrawn = true;
+    template <typename T> void trackSaveLayers(const T& op) { 
+        /* most ops aren't involved in saveLayers */ 
     }
-    // TODO: allow this call to return failure, or move to SkBitmapDevice only.
-    virtual const SkBitmap& onAccessBitmap() SK_OVERRIDE {
-        return fEmptyBitmap;
+    void trackSaveLayers(const SkRecords::Save& s) { this->pushSaveBlock(); }
+    void trackSaveLayers(const SkRecords::SaveLayer& sl) { this->pushSaveLayerBlock(sl.paint); }
+    void trackSaveLayers(const SkRecords::Restore& r) { this->popSaveBlock(); }
+    void trackSaveLayers(const SkRecords::DrawPicture& dp) {
+        // For sub-pictures, we wrap their layer information within the parent
+        // picture's rendering hierarchy
+        const GrAccelData* childData = GPUOptimize(dp.picture);
+
+        for (int i = 0; i < childData->numSaveLayers(); ++i) {
+            const GrAccelData::SaveLayerInfo& src = childData->saveLayerInfo(i);
+
+            this->updateStackForSaveLayer();
+
+            GrAccelData::SaveLayerInfo dst;
+
+            // TODO: need to store an SkRect in GrAccelData::SaveLayerInfo?
+            SkRect srcRect = SkRect::MakeXYWH(SkIntToScalar(src.fOffset.fX),
+                                              SkIntToScalar(src.fOffset.fY),
+                                              SkIntToScalar(src.fSize.width()),
+                                              SkIntToScalar(src.fSize.height()));
+            SkIRect newClip(fCurrentClipBounds);
+            newClip.intersect(this->adjustAndMap(srcRect, dp.paint));
+
+            dst.fValid = true;
+            dst.fPictureID = dp.picture->uniqueID();
+            dst.fSize = SkISize::Make(newClip.width(), newClip.height());
+            dst.fOffset = SkIPoint::Make(newClip.fLeft, newClip.fTop);
+            dst.fOriginXform = *fCTM;
+            dst.fOriginXform.postConcat(src.fOriginXform);
+            dst.fOriginXform.postTranslate(SkIntToScalar(-newClip.fLeft), 
+                                           SkIntToScalar(-newClip.fTop));
+
+            if (NULL == src.fPaint) {
+                dst.fPaint = NULL;
+            } else {
+                dst.fPaint = SkNEW_ARGS(SkPaint, (*src.fPaint));
+            }
+
+            dst.fSaveLayerOpID = src.fSaveLayerOpID;
+            dst.fRestoreOpID = src.fRestoreOpID;
+            dst.fHasNestedLayers = src.fHasNestedLayers;
+            dst.fIsNested = fSaveLayersInStack > 0 || src.fIsNested;
+
+            fAccelData->addSaveLayerInfo(dst);
+        }
     }
-#ifdef SK_SUPPORT_LEGACY_READPIXELSCONFIG
-    virtual bool onReadPixels(const SkBitmap& bitmap,
-                              int x, int y,
-                              SkCanvas::Config8888 config8888) SK_OVERRIDE {
-        NotSupported();
-        return false;
+
+    void pushSaveBlock() {
+        fSaveStack.push(SaveInfo(fCurrentOp, false, NULL, SkIRect::MakeEmpty()));
     }
-#endif
-    virtual void lockPixels() SK_OVERRIDE { NothingToDo(); }
-    virtual void unlockPixels() SK_OVERRIDE { NothingToDo(); }
-    virtual bool allowImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
-    virtual bool canHandleImageFilter(const SkImageFilter*) SK_OVERRIDE { return false; }
-    virtual bool filterImage(const SkImageFilter*, const SkBitmap&, const SkImageFilter::Context&,
-                             SkBitmap* result, SkIPoint* offset) SK_OVERRIDE {
-        return false;
+
+    // Inform all the saveLayers already on the stack that they now have a
+    // nested saveLayer inside them
+    void updateStackForSaveLayer() {
+        for (int index = fSaveStack.count() - 1; index >= 0; --index) {
+            if (fSaveStack[index].fHasNestedSaveLayer) {
+                break;
+            }
+            fSaveStack[index].fHasNestedSaveLayer = true;
+            if (fSaveStack[index].fIsSaveLayer) {
+                break;
+            }
+        }
     }
 
-private:
-    // The playback object driving this rendering
-    SkPicturePlayback *fPlayback;
+    void pushSaveLayerBlock(const SkPaint* paint) {
+        this->updateStackForSaveLayer();
 
-    SkBitmap fEmptyBitmap; // legacy -- need to remove
+        fSaveStack.push(SaveInfo(fCurrentOp, true, paint, fCurrentClipBounds));
+        ++fSaveLayersInStack;
+    }
 
-    // All information gathered during the gather process is stored here
-    GrAccelData* fAccelData;
+    void popSaveBlock() {
+        if (fSaveStack.count() <= 0) {
+            SkASSERT(false);
+            return;
+        }
 
-    // true if this device has already been drawn back to its parent(s) at least
-    // once.
-    bool   fAlreadyDrawn;
+        SaveInfo si;
+        fSaveStack.pop(&si);
 
-    // The information regarding the saveLayer call this device represents.
-    GrAccelData::SaveLayerInfo fInfo;
+        if (!si.fIsSaveLayer) {
+            return;
+        }
 
-    // The depth of this device in the saveLayer stack
-    int fSaveLayerDepth;
+        --fSaveLayersInStack;
 
-    virtual void replaceBitmapBackendForRasterSurface(const SkBitmap&) SK_OVERRIDE {
-        NotSupported();
-    }
+        GrAccelData::SaveLayerInfo slInfo;
 
-    virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) SK_OVERRIDE {
-        // we expect to only get called via savelayer, in which case it is fine.
-        SkASSERT(kSaveLayer_Usage == usage);
+        slInfo.fValid = true;
+        slInfo.fPictureID = fPictureID;
+        slInfo.fSize = SkISize::Make(si.fBounds.width(), si.fBounds.height());
+        slInfo.fOffset = SkIPoint::Make(si.fBounds.fLeft, si.fBounds.fTop);
+        slInfo.fOriginXform = *fCTM;
+        slInfo.fOriginXform.postTranslate(SkIntToScalar(-si.fBounds.fLeft),
+                                          SkIntToScalar(-si.fBounds.fTop));
 
-        fInfo.fHasNestedLayers = true;
-        return SkNEW_ARGS(GrGatherDevice, (info.width(), info.height(), fPlayback,
-                                           fAccelData, fSaveLayerDepth+1));
-    }
+        if (NULL == si.fPaint) {
+            slInfo.fPaint = NULL;
+        } else {
+            slInfo.fPaint = SkNEW_ARGS(SkPaint, (*si.fPaint));
+        }
 
-    virtual void flush() SK_OVERRIDE {}
+        slInfo.fSaveLayerOpID = si.fStartIndex;
+        slInfo.fRestoreOpID = fCurrentOp;
+        slInfo.fHasNestedLayers = si.fHasNestedSaveLayer;
+        slInfo.fIsNested = fSaveLayersInStack > 0;
 
-    static void NotSupported() {
-        SkDEBUGFAIL("this method should never be called");
+        fAccelData->addSaveLayerInfo(slInfo);
     }
 
-    static void NothingToDo() {}
+    // Returns true if rect was meaningfully adjusted for the effects of paint,
+    // false if the paint could affect the rect in unknown ways.
+    static bool AdjustForPaint(const SkPaint* paint, SkRect* rect) {
+        if (paint) {
+            if (paint->canComputeFastBounds()) {
+                *rect = paint->computeFastBounds(*rect, rect);
+                return true;
+            }
+            return false;
+        }
+        return true;
+    }
 
-    typedef SkBaseDevice INHERITED;
-};
+    // Adjust rect for all paints that may affect its geometry, then map it to device space.
+    SkIRect adjustAndMap(SkRect rect, const SkPaint* paint) const {
+        // Inverted rectangles really confuse our BBHs.
+        rect.sort();
 
-// The GrGatherCanvas allows saveLayers but simplifies clipping. It is really
-// only intended to be used as:
-//
-//      GrGatherDevice dev(w, h, picture, accelData);
-//      GrGatherCanvas canvas(..., picture);
-//      canvas.gather();
-//
-// which is all just to fill in 'accelData'
-class SK_API GrGatherCanvas : public SkCanvas {
-public:
-    GrGatherCanvas(GrGatherDevice* device) : INHERITED(device) {}
+        // Adjust the rect for its own paint.
+        if (!AdjustForPaint(paint, &rect)) {
+            // The paint could do anything to our bounds.  The only safe answer is the current clip.
+            return fCurrentClipBounds;
+        }
 
-protected:
-    // disable aa for speed
-    virtual void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
-        this->INHERITED::onClipRect(rect, op, kHard_ClipEdgeStyle);
-    }
+        // Adjust rect for all the paints from the SaveLayers we're inside.
+        for (int i = fSaveStack.count() - 1; i >= 0; i--) {
+            if (!AdjustForPaint(fSaveStack[i].fPaint, &rect)) {
+                // Same deal as above.
+                return fCurrentClipBounds;
+            }
+        }
 
-    // for speed, just respect the bounds, and disable AA. May give us a few
-    // false positives and negatives.
-    virtual void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
-        this->updateClipConservativelyUsingBounds(path.getBounds(), op,
-                                                  path.isInverseFillType());
-    }
-    virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle) SK_OVERRIDE {
-        this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
-    }
+        // Map the rect back to device space.
+        fCTM->mapRect(&rect);
+        SkIRect devRect;
+        rect.roundOut(&devRect);
 
-    virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
-                               const SkPaint* paint) SK_OVERRIDE {
-        SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
-
-        if (NULL != picture->fData.get()) {
-            // Disable the BBH for the old path so all the draw calls
-            // will be seen. The stock SkPicture::draw method can't be
-            // invoked since it just uses a vanilla SkPicturePlayback.
-            SkPicturePlayback playback(picture);
-            playback.setUseBBH(false);
-            playback.draw(this, NULL);
-        } else {
-            // Since we know this is the SkRecord path we can just call
-            // SkPicture::draw.
-            picture->draw(this);
-        }
+        // Nothing can draw outside the current clip.
+        // (Only bounded ops call into this method, so oddballs like Clear don't matter here.)
+        devRect.intersect(fCurrentClipBounds);
+        return devRect;
     }
-
-private:
-    typedef SkCanvas INHERITED;
 };
 
-// GatherGPUInfo is only intended to be called within the context of SkGpuDevice's
+
+// GPUOptimize is only intended to be called within the context of SkGpuDevice's
 // EXPERIMENTAL_optimize method.
-void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData) {
+const GrAccelData* GPUOptimize(const SkPicture* pict) {
     if (NULL == pict || 0 == pict->width() || 0 == pict->height()) {
-        return ;
+        return NULL;
     }
 
-    // BBH-based rendering doesn't re-issue many of the operations the gather
-    // process cares about (e.g., saves and restores) so it must be disabled.
-    SkPicturePlayback playback(pict);
-    playback.setUseBBH(false);
+    SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey();
+
+    const GrAccelData* existing = 
+                            static_cast<const GrAccelData*>(pict->EXPERIMENTAL_getAccelData(key));
+    if (NULL != existing) {
+        return existing;
+    }
+
+    SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
+
+    pict->EXPERIMENTAL_addAccelData(data);
 
-    GrGatherDevice device(pict->width(), pict->height(), &playback, accelData, 0);
-    GrGatherCanvas canvas(&device);
+    CollectLayers collector(pict, data);
 
-    canvas.clipRect(SkRect::MakeWH(SkIntToScalar(pict->width()),
-                                   SkIntToScalar(pict->height())),
-                    SkRegion::kIntersect_Op, false);
-    playback.draw(&canvas, NULL);
+    return data;
 }
index 46af12d2f1a43b053aef59efc50c75ef05f22560..1c6897ce773c78a84808fe39ae589588e5861fbb 100644 (file)
@@ -21,11 +21,14 @@ public:
         // invalid (due to a non-invertible CTM) or 'fPaint' is NULL (due
         // to a non-copyable paint).
         bool fValid;
+        // ID of the picture containing the layer. This can be the ID of
+        // a sub-picture embedded within the picture owning the GrAccelData
+        uint32_t fPictureID;
         // The size of the saveLayer
         SkISize fSize;
-        // The CTM in which this layer's draws must occur. It already incorporates
+        // The matrix state in which this layer's draws must occur. It already incorporates
         // the translation needed to map the layer's top-left point to the origin.
-        SkMatrix fCTM;
+        SkMatrix fOriginXform;
         // The offset that needs to be passed to drawBitmap to correctly
         // position the pre-rendered layer. It is in device space.
         SkIPoint fOffset;
@@ -74,6 +77,6 @@ private:
     typedef SkPicture::AccelData INHERITED;
 };
 
-void GatherGPUInfo(const SkPicture* pict, GrAccelData* accelData);
+const GrAccelData* GPUOptimize(const SkPicture* pict);
 
 #endif // GrPictureUtils_DEFINED
index 61ae5ce829ea6c6f5a57b444be31e1d1e84bd50a..b3d154b7e21d23cd5f579d24c35c3a4a1ede58e2 100644 (file)
@@ -1861,11 +1861,7 @@ void SkGpuDevice::EXPERIMENTAL_optimize(const SkPicture* picture) {
         return;
     }
 
-    SkAutoTUnref<GrAccelData> data(SkNEW_ARGS(GrAccelData, (key)));
-
-    picture->EXPERIMENTAL_addAccelData(data);
-
-    GatherGPUInfo(picture, data);
+    GPUOptimize(picture);
 
     fContext->getLayerCache()->trackPicture(picture);
 }
@@ -2004,10 +2000,10 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
         if (pullForward[i]) {
             const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i);
 
-            GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(),
-                                                                                info.fSaveLayerOpID,
-                                                                                info.fRestoreOpID,
-                                                                                info.fCTM);
+            GrCachedLayer* layer = fContext->getLayerCache()->findLayerOrCreate(picture->uniqueID(), 
+                                                                                info.fSaveLayerOpID, 
+                                                                                info.fRestoreOpID, 
+                                                                                info.fOriginXform);
 
             SkPictureReplacementPlayback::PlaybackReplacements::ReplacementInfo* layerInfo =
                                                                         replacements.push();
@@ -2165,7 +2161,7 @@ void SkGpuDevice::unlockLayers(const SkPicture* picture) {
         GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture->uniqueID(),
                                                                     info.fSaveLayerOpID,
                                                                     info.fRestoreOpID,
-                                                                    info.fCTM);
+                                                                    info.fOriginXform);
         fContext->getLayerCache()->unlock(layer);
     }
 
index 3535e8e3bfd9a33d93395266e668930a5225f7c9..a189c1a4aebf8351116691beb5f3b9156f98190d 100644 (file)
@@ -876,7 +876,18 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
         static const int kWidth = 100;
         static const int kHeight = 100;
 
-        SkAutoTUnref<SkPicture> pict;
+        SkAutoTUnref<SkPicture> pict, child;
+
+        {
+            SkPictureRecorder recorder;
+
+            SkCanvas* c = recorder.beginRecording(kWidth, kHeight);
+
+            c->saveLayer(NULL, NULL);
+            c->restore();
+
+            child.reset(recorder.endRecording());
+        }
 
         // create a picture with the structure:
         // 1)
@@ -892,21 +903,26 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
         //      SaveLayer w/ copyable paint
         //      Restore
         // 4)
-        //      SaveLayer w/ non-copyable paint
+        //      SaveLayer
+        //          DrawPicture (which has a SaveLayer/Restore pair)
+        //      Restore
+        // 5)
+        //      SaveLayer
+        //          DrawPicture with Matrix & Paint (with SaveLayer/Restore pair)
         //      Restore
         {
             SkPictureRecorder recorder;
 
-            SkCanvas* c = recorder.DEPRECATED_beginRecording(kWidth, kHeight);
+            SkCanvas* c = recorder.beginRecording(kWidth, kHeight);
             // 1)
-            c->saveLayer(NULL, NULL);
+            c->saveLayer(NULL, NULL); // layer #0
             c->restore();
 
             // 2)
-            c->saveLayer(NULL, NULL);
-                c->translate(kWidth/2, kHeight/2);
+            c->saveLayer(NULL, NULL); // layer #1
+                c->translate(kWidth/2.0f, kHeight/2.0f);
                 SkRect r = SkRect::MakeXYWH(0, 0, kWidth/2, kHeight/2);
-                c->saveLayer(&r, NULL);
+                c->saveLayer(&r, NULL); // layer #2
                 c->restore();
             c->restore();
 
@@ -914,16 +930,23 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
             {
                 SkPaint p;
                 p.setColor(SK_ColorRED);
-                c->saveLayer(NULL, &p);
+                c->saveLayer(NULL, &p); // layer #3
                 c->restore();
             }
             // 4)
-            // TODO: this case will need to be removed once the paint's are immutable
+            {
+                c->saveLayer(NULL, NULL);  // layer #4
+                    c->drawPicture(child);  // layer #5 inside picture
+                c->restore();
+            }
+            // 5
             {
                 SkPaint p;
-                SkAutoTUnref<SkColorFilter> cf(SkLumaColorFilter::Create());
-                p.setImageFilter(SkColorFilterImageFilter::Create(cf.get()))->unref();
-                c->saveLayer(NULL, &p);
+                SkMatrix trans;
+                trans.setTranslate(10, 10);
+
+                c->saveLayer(NULL, NULL);  // layer #6
+                    c->drawPicture(child, &trans, &p); // layer #7 inside picture
                 c->restore();
             }
 
@@ -946,53 +969,98 @@ static void test_gpu_picture_optimization(skiatest::Reporter* reporter,
             REPORTER_ASSERT(reporter, NULL != data);
 
             const GrAccelData *gpuData = static_cast<const GrAccelData*>(data);
-            REPORTER_ASSERT(reporter, 5 == gpuData->numSaveLayers());
+            REPORTER_ASSERT(reporter, 8 == gpuData->numSaveLayers());
 
             const GrAccelData::SaveLayerInfo& info0 = gpuData->saveLayerInfo(0);
-            // The parent/child layer appear in reverse order
+            // The parent/child layers appear in reverse order
             const GrAccelData::SaveLayerInfo& info1 = gpuData->saveLayerInfo(2);
             const GrAccelData::SaveLayerInfo& info2 = gpuData->saveLayerInfo(1);
+
             const GrAccelData::SaveLayerInfo& info3 = gpuData->saveLayerInfo(3);
-//        const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(4);
+
+            // The parent/child layers appear in reverse order
+            const GrAccelData::SaveLayerInfo& info4 = gpuData->saveLayerInfo(5);
+            const GrAccelData::SaveLayerInfo& info5 = gpuData->saveLayerInfo(4);
+
+            // The parent/child layers appear in reverse order
+            const GrAccelData::SaveLayerInfo& info6 = gpuData->saveLayerInfo(7);
+            const GrAccelData::SaveLayerInfo& info7 = gpuData->saveLayerInfo(6);
 
             REPORTER_ASSERT(reporter, info0.fValid);
-            REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && kHeight == info0.fSize.fHeight);
-            REPORTER_ASSERT(reporter, info0.fCTM.isIdentity());
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info0.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth == info0.fSize.fWidth && 
+                                      kHeight == info0.fSize.fHeight);
+            REPORTER_ASSERT(reporter, info0.fOriginXform.isIdentity());
             REPORTER_ASSERT(reporter, 0 == info0.fOffset.fX && 0 == info0.fOffset.fY);
-            REPORTER_ASSERT(reporter, NULL != info0.fPaint);
+            REPORTER_ASSERT(reporter, NULL == info0.fPaint);
             REPORTER_ASSERT(reporter, !info0.fIsNested && !info0.fHasNestedLayers);
 
             REPORTER_ASSERT(reporter, info1.fValid);
-            REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && kHeight == info1.fSize.fHeight);
-            REPORTER_ASSERT(reporter, info1.fCTM.isIdentity());
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info1.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth == info1.fSize.fWidth && 
+                                      kHeight == info1.fSize.fHeight);
+            REPORTER_ASSERT(reporter, info1.fOriginXform.isIdentity());
             REPORTER_ASSERT(reporter, 0 == info1.fOffset.fX && 0 == info1.fOffset.fY);
-            REPORTER_ASSERT(reporter, NULL != info1.fPaint);
-            REPORTER_ASSERT(reporter, !info1.fIsNested && info1.fHasNestedLayers); // has a nested SL
+            REPORTER_ASSERT(reporter, NULL == info1.fPaint);
+            REPORTER_ASSERT(reporter, !info1.fIsNested && 
+                                      info1.fHasNestedLayers); // has a nested SL
 
             REPORTER_ASSERT(reporter, info2.fValid);
-            REPORTER_ASSERT(reporter, kWidth/2 == info2.fSize.fWidth &&
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info2.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth / 2 == info2.fSize.fWidth &&
                                       kHeight/2 == info2.fSize.fHeight); // bound reduces size
-            REPORTER_ASSERT(reporter, info2.fCTM.isIdentity());         // translated
-            REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX &&
-                                      kHeight/2 == info2.fOffset.fY);
-            REPORTER_ASSERT(reporter, NULL != info1.fPaint);
+            REPORTER_ASSERT(reporter, info2.fOriginXform.isIdentity());
+            REPORTER_ASSERT(reporter, kWidth/2 == info2.fOffset.fX &&   // translated
+                                      kHeight/2 == info2.fOffset.fY); 
+            REPORTER_ASSERT(reporter, NULL == info1.fPaint);
             REPORTER_ASSERT(reporter, info2.fIsNested && !info2.fHasNestedLayers); // is nested
 
             REPORTER_ASSERT(reporter, info3.fValid);
-            REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && kHeight == info3.fSize.fHeight);
-            REPORTER_ASSERT(reporter, info3.fCTM.isIdentity());
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info3.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth == info3.fSize.fWidth && 
+                                      kHeight == info3.fSize.fHeight);
+            REPORTER_ASSERT(reporter, info3.fOriginXform.isIdentity());
             REPORTER_ASSERT(reporter, 0 == info3.fOffset.fX && 0 == info3.fOffset.fY);
             REPORTER_ASSERT(reporter, NULL != info3.fPaint);
             REPORTER_ASSERT(reporter, !info3.fIsNested && !info3.fHasNestedLayers);
 
-    #if 0 // needs more though for GrGatherCanvas
-            REPORTER_ASSERT(reporter, !info4.fValid);                 // paint is/was uncopyable
-            REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && kHeight == info4.fSize.fHeight);
+            REPORTER_ASSERT(reporter, info4.fValid);
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info4.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth == info4.fSize.fWidth && 
+                                      kHeight == info4.fSize.fHeight);
             REPORTER_ASSERT(reporter, 0 == info4.fOffset.fX && 0 == info4.fOffset.fY);
-            REPORTER_ASSERT(reporter, info4.fCTM.isIdentity());
-            REPORTER_ASSERT(reporter, NULL == info4.fPaint);     // paint is/was uncopyable
-            REPORTER_ASSERT(reporter, !info4.fIsNested && !info4.fHasNestedLayers);
-    #endif
+            REPORTER_ASSERT(reporter, info4.fOriginXform.isIdentity());
+            REPORTER_ASSERT(reporter, NULL == info4.fPaint);
+            REPORTER_ASSERT(reporter, !info4.fIsNested && 
+                                      info4.fHasNestedLayers); // has a nested SL
+
+            REPORTER_ASSERT(reporter, info5.fValid);
+            REPORTER_ASSERT(reporter, child->uniqueID() == info5.fPictureID); // in a child picture
+            REPORTER_ASSERT(reporter, kWidth == info5.fSize.fWidth && 
+                                      kHeight == info5.fSize.fHeight);
+            REPORTER_ASSERT(reporter, 0 == info5.fOffset.fX && 0 == info5.fOffset.fY);
+            REPORTER_ASSERT(reporter, info5.fOriginXform.isIdentity());
+            REPORTER_ASSERT(reporter, NULL == info5.fPaint);
+            REPORTER_ASSERT(reporter, info5.fIsNested && !info5.fHasNestedLayers); // is nested
+
+            REPORTER_ASSERT(reporter, info6.fValid);
+            REPORTER_ASSERT(reporter, pict->uniqueID() == info6.fPictureID);
+            REPORTER_ASSERT(reporter, kWidth == info6.fSize.fWidth && 
+                                      kHeight == info6.fSize.fHeight);
+            REPORTER_ASSERT(reporter, 0 == info6.fOffset.fX && 0 == info6.fOffset.fY);
+            REPORTER_ASSERT(reporter, info6.fOriginXform.isIdentity());
+            REPORTER_ASSERT(reporter, NULL == info6.fPaint);
+            REPORTER_ASSERT(reporter, !info6.fIsNested && 
+                                      info6.fHasNestedLayers); // has a nested SL
+
+            REPORTER_ASSERT(reporter, info7.fValid);
+            REPORTER_ASSERT(reporter, child->uniqueID() == info7.fPictureID); // in a child picture
+            REPORTER_ASSERT(reporter, kWidth == info7.fSize.fWidth && 
+                                      kHeight == info7.fSize.fHeight);
+            REPORTER_ASSERT(reporter, 0 == info7.fOffset.fX && 0 == info7.fOffset.fY);
+            REPORTER_ASSERT(reporter, info7.fOriginXform.isIdentity());
+            REPORTER_ASSERT(reporter, NULL == info7.fPaint);
+            REPORTER_ASSERT(reporter, info7.fIsNested && !info7.fHasNestedLayers); // is nested
         }
     }
 }