Revert of Sketch splitting SkPicture into an interface and SkBigPicture. (patchset...
authorreed <reed@chromium.org>
Fri, 8 May 2015 00:30:13 +0000 (17:30 -0700)
committerCommit bot <commit-bot@chromium.org>
Fri, 8 May 2015 00:30:13 +0000 (17:30 -0700)
Reason for revert:
speculative revert to fix failures in DEPS roll

Original issue's description:
> Sketch splitting SkPicture into an interface and SkBigPicture.
>
> Adds small pictures for drawRect(), drawTextBlob(), and drawPath().
> These cover about 89% of draw calls from Blink SKPs,
> and about 25% of draw calls from our GMs.
>
> SkPicture handles:
>   - serialization and deserialization
>   - unique IDs
>
> Everything else is left to the subclasses:
>   - playback(), cullRect()
>   - hasBitmap(), hasText(), suitableForGPU(), etc.
>   - LayerInfo / AccelData if applicable.
>
> The time to record a 1-op picture improves a good chunk
> (2 mallocs to 1), and the time to record a 0-op picture
> greatly improves (2 mallocs to none):
>
>     picture_overhead_draw:   450ns -> 350ns
>     picture_overhead_nodraw: 300ns -> 90ns
>
> BUG=skia:
>
> Committed: https://skia.googlesource.com/skia/+/c92c129ff85b05a714bd1bf921c02d5e14651f8b

TBR=reed@google.com,robertphillips@google.com,mtklein@google.com,mtklein@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:

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

26 files changed:
gyp/core.gypi
gyp/utils.gypi
include/core/SkPicture.h
include/core/SkPictureRecorder.h
include/utils/SkPictureUtils.h
src/core/SkBigPicture.cpp [deleted file]
src/core/SkBigPicture.h [deleted file]
src/core/SkLayerInfo.cpp [new file with mode: 0644]
src/core/SkLayerInfo.h
src/core/SkMiniRecorder.cpp [deleted file]
src/core/SkMiniRecorder.h [deleted file]
src/core/SkPicture.cpp
src/core/SkPictureCommon.h [deleted file]
src/core/SkPictureRecorder.cpp
src/core/SkRecordDraw.cpp
src/core/SkRecordDraw.h
src/core/SkRecorder.cpp
src/core/SkRecorder.h
src/core/SkRecords.h
src/gpu/GrLayerHoister.cpp
src/gpu/GrRecordReplaceDraw.cpp
src/gpu/SkGpuDevice.cpp
src/gpu/SkGpuDevice.h
src/utils/SkPictureUtils.cpp [new file with mode: 0644]
tests/GpuLayerCacheTest.cpp
tests/PictureTest.cpp

index edf661b..fef6fe4 100644 (file)
@@ -22,7 +22,6 @@
         '<(skia_src_path)/core/SkAntiRun.h',
         '<(skia_src_path)/core/SkBBHFactory.cpp',
         '<(skia_src_path)/core/SkBBoxHierarchy.h',
-        '<(skia_src_path)/core/SkBigPicture.cpp',
         '<(skia_src_path)/core/SkBitmap.cpp',
         '<(skia_src_path)/core/SkBitmapCache.cpp',
         '<(skia_src_path)/core/SkBitmapDevice.cpp',
         '<(skia_src_path)/core/SkImageInfo.cpp',
         '<(skia_src_path)/core/SkImageGenerator.cpp',
         '<(skia_src_path)/core/SkLayerInfo.h',
+        '<(skia_src_path)/core/SkLayerInfo.cpp',
         '<(skia_src_path)/core/SkLocalMatrixShader.cpp',
         '<(skia_src_path)/core/SkLineClipper.cpp',
         '<(skia_src_path)/core/SkMallocPixelRef.cpp',
         '<(skia_src_path)/core/SkMessageBus.h',
         '<(skia_src_path)/core/SkMetaData.cpp',
         '<(skia_src_path)/core/SkMipMap.cpp',
-        '<(skia_src_path)/core/SkMiniRecorder.cpp',
         '<(skia_src_path)/core/SkMultiPictureDraw.cpp',
         '<(skia_src_path)/core/SkPackBits.cpp',
         '<(skia_src_path)/core/SkPaint.cpp',
index 1193507..f382e10 100644 (file)
@@ -79,6 +79,7 @@
         '<(skia_src_path)/utils/SkParse.cpp',
         '<(skia_src_path)/utils/SkParseColor.cpp',
         '<(skia_src_path)/utils/SkParsePath.cpp',
+        '<(skia_src_path)/utils/SkPictureUtils.cpp',
         '<(skia_src_path)/utils/SkPatchGrid.cpp',
         '<(skia_src_path)/utils/SkPatchGrid.h',
         '<(skia_src_path)/utils/SkPatchUtils.cpp',
index 7ff551b..88dfdf1 100644 (file)
@@ -5,31 +5,61 @@
  * found in the LICENSE file.
  */
 
+
 #ifndef SkPicture_DEFINED
 #define SkPicture_DEFINED
 
 #include "SkImageDecoder.h"
 #include "SkRefCnt.h"
-#include "SkTypes.h"
+#include "SkTDArray.h"
 
+#if SK_SUPPORT_GPU
 class GrContext;
-class SkBigPicture;
+#endif
+
 class SkBitmap;
+class SkBBoxHierarchy;
 class SkCanvas;
+class SkData;
 class SkPictureData;
 class SkPixelSerializer;
 class SkStream;
 class SkWStream;
+
 struct SkPictInfo;
 
+class SkRecord;
+
+namespace SkRecords {
+    class CollectLayers;
+};
+
 /** \class SkPicture
 
-    An SkPicture records drawing commands made to a canvas to be played back at a later time.
-    This base class handles serialization and a few other miscellany.
+    The SkPicture class records the drawing commands made to a canvas, to
+    be played back at a later time.
 */
-class SK_API SkPicture : public SkRefCnt {
+class SK_API SkPicture : public SkNVRefCnt<SkPicture> {
 public:
-    virtual ~SkPicture();
+    // AccelData provides a base class for device-specific acceleration data.
+    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;
+    };
+
+    /**  PRIVATE / EXPERIMENTAL -- do not call */
+    const AccelData* EXPERIMENTAL_getAccelData(AccelData::Key) const;
 
     /**
      *  Function signature defining a function that sets up an SkBitmap from encoded data. On
@@ -65,6 +95,8 @@ public:
      */
     static SkPicture* CreateFromBuffer(SkReadBuffer&);
 
+    ~SkPicture();
+
     /**
     *  Subclasses of this can be passed to playback(). During the playback
     *  of the picture, this callback will periodically be invoked. If its
@@ -79,6 +111,7 @@ public:
     public:
         AbortCallback() {}
         virtual ~AbortCallback() {}
+
         virtual bool abort() = 0;
     };
 
@@ -89,14 +122,16 @@ public:
         @param canvas the canvas receiving the drawing commands.
         @param callback a callback that allows interruption of playback
     */
-    virtual void playback(SkCanvas*, AbortCallback* = NULL) const = 0;
+    void playback(SkCanvas* canvas, AbortCallback* = NULL) const;
 
-    /** Return a cull rect for this picture.
-        Ops recorded into this picture that attempt to draw outside the cull might not be drawn.
-     */
-    virtual SkRect cullRect() const = 0;
+    /** Return the cull rect used when creating this picture: { 0, 0, cullWidth, cullHeight }.
+        It does not necessarily reflect the bounds of what has been recorded into the picture.
+        @return the cull rect used to create this picture
+    */
+    SkRect cullRect() const { return fCullRect; }
 
-    /** Returns a non-zero value unique among all pictures. */
+    /** Return a non-zero, unique value representing the picture.
+     */
     uint32_t uniqueID() const;
 
     /**
@@ -105,7 +140,7 @@ public:
      *
      *  TODO: Use serializer to serialize SkImages as well.
      */
-    void serialize(SkWStream*, SkPixelSerializer* = NULL) const;
+    void serialize(SkWStream*, SkPixelSerializer* serializer = NULL) const;
 
     /**
      *  Serialize to a buffer.
@@ -116,21 +151,7 @@ public:
      * Returns true if any bitmaps may be produced when this SkPicture
      * is replayed.
      */
-    virtual bool willPlayBackBitmaps() const = 0;
-
-    /** Return the approximate number of operations in this picture.  This
-     *  number may be greater or less than the number of SkCanvas calls
-     *  recorded: some calls may be recorded as more than one operation, or some
-     *  calls may be optimized away.
-     */
-    virtual int approximateOpCount() const = 0;
-
-    /** Return true if this picture contains text.
-     */
-    virtual bool hasText() const = 0;
-
-    /** Returns the approximate byte size of this picture, not including large ref'd objects. */
-    virtual size_t approximateBytesUsed() const = 0;
+    bool willPlayBackBitmaps() const;
 
     /** Return true if the SkStream/Buffer represents a serialized picture, and
         fills out SkPictInfo. After this function returns, the data source is not
@@ -143,24 +164,76 @@ public:
     static bool InternalOnly_StreamIsSKP(SkStream*, SkPictInfo*);
     static bool InternalOnly_BufferIsSKP(SkReadBuffer*, SkPictInfo*);
 
-    /** Return true if the picture is suitable for rendering on the GPU.  */
-    virtual bool suitableForGpuRasterization(GrContext*, const char** whyNot = NULL) const = 0;
+    /** Return true if the picture is suitable for rendering on the GPU.
+     */
 
-    // Sent via SkMessageBus from destructor.
-    struct DeletionMessage { int32_t fUniqueID; };  // TODO: -> uint32_t?
+#if SK_SUPPORT_GPU
+    bool suitableForGpuRasterization(GrContext*, const char ** = NULL) const;
+#endif
 
-    // Returns NULL if this is not an SkBigPicture.
-    virtual const SkBigPicture* asSkBigPicture() const { return NULL; }
+    /** Return the approximate number of operations in this picture.  This
+     *  number may be greater or less than the number of SkCanvas calls
+     *  recorded: some calls may be recorded as more than one operation, or some
+     *  calls may be optimized away.
+     */
+    int approximateOpCount() const;
 
-private:
-    // Subclass whitelist.
-    SkPicture();
-    friend class SkBigPicture;
-    friend class SkEmptyPicture;
-    template <typename> friend class SkMiniPicture;
+    /** Return true if this picture contains text.
+     */
+    bool hasText() const;
+
+    // An array of refcounted const SkPicture pointers.
+    class SnapshotArray : ::SkNoncopyable {
+    public:
+        SnapshotArray(const SkPicture* pics[], int count) : fPics(pics), fCount(count) {}
+        ~SnapshotArray() { for (int i = 0; i < fCount; i++) { fPics[i]->unref(); } }
+
+        const SkPicture* const* begin() const { return fPics; }
+        int count() const { return fCount; }
+    private:
+        SkAutoTMalloc<const SkPicture*> fPics;
+        int fCount;
+    };
 
-    virtual int numSlowPaths() const = 0;
+    // Sent via SkMessageBus from destructor.
+    struct DeletionMessage { int32_t fUniqueID; };
 
+private:
+    // V2 : adds SkPixelRef's generation ID.
+    // V3 : PictInfo tag at beginning, and EOF tag at the end
+    // V4 : move SkPictInfo to be the header
+    // V5 : don't read/write FunctionPtr on cross-process (we can detect that)
+    // V6 : added serialization of SkPath's bounds (and packed its flags tighter)
+    // V7 : changed drawBitmapRect(IRect) to drawBitmapRectToRect(Rect)
+    // V8 : Add an option for encoding bitmaps
+    // V9 : Allow the reader and writer of an SKP disagree on whether to support
+    //      SK_SUPPORT_HINTING_SCALE_FACTOR
+    // V10: add drawRRect, drawOval, clipRRect
+    // V11: modify how readBitmap and writeBitmap store their info.
+    // V12: add conics to SkPath, use new SkPathRef flattening
+    // V13: add flag to drawBitmapRectToRect
+    //      parameterize blurs by sigma rather than radius
+    // V14: Add flags word to PathRef serialization
+    // V15: Remove A1 bitmap config (and renumber remaining configs)
+    // V16: Move SkPath's isOval flag to SkPathRef
+    // V17: SkPixelRef now writes SkImageInfo
+    // V18: SkBitmap now records x,y for its pixelref origin, instead of offset.
+    // V19: encode matrices and regions into the ops stream
+    // V20: added bool to SkPictureImageFilter's serialization (to allow SkPicture serialization)
+    // V21: add pushCull, popCull
+    // V22: SK_PICT_FACTORY_TAG's size is now the chunk size in bytes
+    // V23: SkPaint::FilterLevel became a real enum
+    // V24: SkTwoPointConicalGradient now has fFlipped flag for gradient flipping
+    // V25: SkDashPathEffect now only writes phase and interval array when flattening
+    // V26: Removed boolean from SkColorShader for inheriting color from SkPaint.
+    // V27: Remove SkUnitMapper from gradients (and skia).
+    // V28: No longer call bitmap::flatten inside SkWriteBuffer::writeBitmap.
+    // V29: Removed SaveFlags parameter from save().
+    // V30: Remove redundant SkMatrix from SkLocalMatrixShader.
+    // V31: Add a serialized UniqueID to SkImageFilter.
+    // V32: Removed SkPaintOptionsAndroid from SkPaint
+    // V33: Serialize only public API of effects.
+    // V34: Add SkTextBlob serialization.
     // V35: Store SkRect (rather then width & height) in header
     // V36: Remove (obsolete) alphatype from SkColorTable
     // V37: Added shadow only option to SkDropShadowImageFilter (last version to record CLEAR)
@@ -169,20 +242,65 @@ private:
     // V40: Remove UniqueID serialization from SkImageFilter.
     // V41: Added serialization of SkBitmapSource's filterQuality parameter
 
+    // Note: If the picture version needs to be increased then please follow the
+    // steps to generate new SKPs in (only accessible to Googlers): http://goo.gl/qATVcw
+
     // Only SKPs within the min/current picture version range (inclusive) can be read.
-    static const uint32_t MIN_PICTURE_VERSION = 35,     // Produced by Chrome M39.
-                      CURRENT_PICTURE_VERSION = 41;
+    static const uint32_t MIN_PICTURE_VERSION = 35;     // Produced by Chrome M39.
+    static const uint32_t CURRENT_PICTURE_VERSION = 41;
 
     static_assert(MIN_PICTURE_VERSION <= 41,
                   "Remove kFontFileName and related code from SkFontDescriptor.cpp.");
 
+    void createHeader(SkPictInfo* info) const;
     static bool IsValidPictInfo(const SkPictInfo& info);
+
+    // Takes ownership of the (optional) SnapshotArray.
+    // For performance, we take ownership of the caller's refs on the SkRecord, BBH, and AccelData.
+    SkPicture(const SkRect& cullRect,
+              SkRecord*,
+              SnapshotArray*,
+              SkBBoxHierarchy*,
+              AccelData*,
+              size_t approxBytesUsedBySubPictures);
+
     static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);
+    static SkPictureData* Backport(const SkRecord&, const SkPictInfo&,
+                                   SkPicture const* const drawablePics[], int drawableCount);
+
+    // uint32_t fRefCnt; from SkNVRefCnt<SkPicture>
+    mutable uint32_t                      fUniqueID;
+    const SkRect                          fCullRect;
+    SkAutoTUnref<const SkRecord>          fRecord;
+    SkAutoTDelete<const SnapshotArray>    fDrawablePicts;
+    SkAutoTUnref<const SkBBoxHierarchy>   fBBH;
+    SkAutoTUnref<const AccelData>         fAccelData;
+    const size_t                          fApproxBytesUsedBySubPictures;
+
+    // helpers for fDrawablePicts
+    int drawableCount() const;
+    // will return NULL if drawableCount() returns 0
+    SkPicture const* const* drawablePicts() const;
+
+    struct PathCounter;
+
+    struct Analysis {
+        Analysis() {}  // Only used by SkPictureData codepath.
+        explicit Analysis(const SkRecord&);
+
+        bool suitableForGpuRasterization(const char** reason, int sampleCount) const;
 
-    SkPictInfo createHeader() const;
-    SkPictureData* backport() const;
+        uint8_t     fNumSlowPathsAndDashEffects;
+        bool        fWillPlaybackBitmaps : 1;
+        bool        fHasText             : 1;
+    } fAnalysis;
 
-    mutable uint32_t fUniqueID;
+    friend class SkPictureRecorder;            // SkRecord-based constructor.
+    friend class GrLayerHoister;               // access to fRecord
+    friend class ReplaceDraw;
+    friend class SkPictureUtils;
+    friend class SkRecordedDrawable;
 };
+SK_COMPILE_ASSERT(sizeof(SkPicture) <= 88, SkPictureSize);
 
 #endif
index a84b721..2cf7909 100644 (file)
@@ -8,7 +8,6 @@
 #ifndef SkPictureRecorder_DEFINED
 #define SkPictureRecorder_DEFINED
 
-#include "../../src/core/SkMiniRecorder.h"
 #include "SkBBHFactory.h"
 #include "SkPicture.h"
 #include "SkRefCnt.h"
@@ -103,7 +102,6 @@ private:
     SkAutoTUnref<SkBBoxHierarchy> fBBH;
     SkAutoTUnref<SkRecorder>      fRecorder;
     SkAutoTUnref<SkRecord>        fRecord;
-    SkMiniRecorder                fMiniRecorder;
 
     typedef SkNoncopyable INHERITED;
 };
index b65a64d..10607da 100644 (file)
@@ -10,8 +10,6 @@
 
 #include "SkPicture.h"
 
-// TODO: remove this file?
-
 class SK_API SkPictureUtils {
 public:
     /**
@@ -20,9 +18,7 @@ public:
      *  includes nested SkPictures, but does not include large objects that
      *  SkRecord holds a reference to (e.g. paths, or pixels backing bitmaps).
      */
-    static size_t ApproximateBytesUsed(const SkPicture* pict) {
-        return pict->approximateBytesUsed();
-    }
+    static size_t ApproximateBytesUsed(const SkPicture* pict);
 };
 
 #endif
diff --git a/src/core/SkBigPicture.cpp b/src/core/SkBigPicture.cpp
deleted file mode 100644 (file)
index 33be192..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkBBoxHierarchy.h"
-#include "SkBigPicture.h"
-#include "SkPathEffect.h"
-#include "SkPictureCommon.h"
-#include "SkRecord.h"
-#include "SkRecordDraw.h"
-
-SkBigPicture::SkBigPicture(const SkRect& cull,
-                           SkRecord* record,
-                           SnapshotArray* drawablePicts,
-                           SkBBoxHierarchy* bbh,
-                           AccelData* accelData,
-                           size_t approxBytesUsedBySubPictures)
-    : fCullRect(cull)
-    , fAnalysis(*record)
-    , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
-    , fRecord(record)               // Take ownership of caller's ref.
-    , fDrawablePicts(drawablePicts) // Take ownership.
-    , fBBH(bbh)                     // Take ownership of caller's ref.
-    , fAccelData(accelData)         // Take ownership of caller's ref.
-{}
-
-void SkBigPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
-    SkASSERT(canvas);
-
-    // If the query contains the whole picture, don't bother with the BBH.
-    SkRect clipBounds = { 0, 0, 0, 0 };
-    (void)canvas->getClipBounds(&clipBounds);
-    const bool useBBH = !clipBounds.contains(this->cullRect());
-
-    SkRecordDraw(*fRecord,
-                 canvas,
-                 this->drawablePicts(),
-                 nullptr,
-                 this->drawableCount(),
-                 useBBH ? fBBH.get() : nullptr,
-                 callback);
-}
-
-void SkBigPicture::partialPlayback(SkCanvas* canvas,
-                                   unsigned start,
-                                   unsigned stop,
-                                   const SkMatrix& initialCTM) const {
-    SkASSERT(canvas);
-    SkRecordPartialDraw(*fRecord,
-                        canvas,
-                        this->drawablePicts(),
-                        this->drawableCount(),
-                        start,
-                        stop,
-                        initialCTM);
-}
-
-SkRect SkBigPicture::cullRect()             const { return fCullRect; }
-bool   SkBigPicture::hasText()              const { return fAnalysis.fHasText; }
-bool   SkBigPicture::willPlayBackBitmaps()  const { return fAnalysis.fWillPlaybackBitmaps; }
-int    SkBigPicture::numSlowPaths()         const { return fAnalysis.fNumSlowPathsAndDashEffects; }
-int    SkBigPicture::approximateOpCount()   const { return fRecord->count(); }
-size_t SkBigPicture::approximateBytesUsed() const {
-    size_t bytes = sizeof(*this) + fRecord->bytesUsed() + fApproxBytesUsedBySubPictures;
-    if (fBBH) { bytes += fBBH->bytesUsed(); }
-    return bytes;
-}
-bool SkBigPicture::suitableForGpuRasterization(GrContext*, const char** reason) const {
-    return fAnalysis.suitableForGpuRasterization(reason);
-}
-
-int SkBigPicture::drawableCount() const {
-    return fDrawablePicts ? fDrawablePicts->count() : 0;
-}
-SkPicture const* const* SkBigPicture::drawablePicts() const {
-    return fDrawablePicts ? fDrawablePicts->begin() : nullptr;
-}
-
-// Some ops have a paint, some have an optional paint.  Either way, get back a pointer.
-static const SkPaint* as_ptr(const SkPaint& p) { return &p; }
-static const SkPaint* as_ptr(const SkRecords::Optional<SkPaint>& p) { return p; }
-
-struct SkBigPicture::PathCounter {
-    SK_CREATE_MEMBER_DETECTOR(paint);
-
-    PathCounter() : fNumSlowPathsAndDashEffects(0) {}
-
-    // Recurse into nested pictures.
-    void operator()(const SkRecords::DrawPicture& op) {
-        fNumSlowPathsAndDashEffects += op.picture->numSlowPaths();
-    }
-
-    void checkPaint(const SkPaint* paint) {
-        if (paint && paint->getPathEffect()) {
-            // Initially assume it's slow.
-            fNumSlowPathsAndDashEffects++;
-        }
-    }
-
-    void operator()(const SkRecords::DrawPoints& op) {
-        this->checkPaint(&op.paint);
-        const SkPathEffect* effect = op.paint.getPathEffect();
-        if (effect) {
-            SkPathEffect::DashInfo info;
-            SkPathEffect::DashType dashType = effect->asADash(&info);
-            if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
-                SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
-                fNumSlowPathsAndDashEffects--;
-            }
-        }
-    }
-
-    void operator()(const SkRecords::DrawPath& op) {
-        this->checkPaint(&op.paint);
-        if (op.paint.isAntiAlias() && !op.path.isConvex()) {
-            SkPaint::Style paintStyle = op.paint.getStyle();
-            const SkRect& pathBounds = op.path.getBounds();
-            if (SkPaint::kStroke_Style == paintStyle &&
-                0 == op.paint.getStrokeWidth()) {
-                // AA hairline concave path is not slow.
-            } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
-                       pathBounds.height() < 64.f && !op.path.isVolatile()) {
-                // AADF eligible concave path is not slow.
-            } else {
-                fNumSlowPathsAndDashEffects++;
-            }
-        }
-    }
-
-    template <typename T>
-    SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
-        this->checkPaint(as_ptr(op.paint));
-    }
-
-    template <typename T>
-    SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
-
-    int fNumSlowPathsAndDashEffects;
-};
-
-SkBigPicture::Analysis::Analysis(const SkRecord& record) {
-    SkTextHunter   text;
-    SkBitmapHunter bitmap;
-    PathCounter    path;
-
-    bool hasText = false, hasBitmap = false;
-    for (unsigned i = 0; i < record.count(); i++) {
-        hasText   = hasText   || record.visit<bool>(i,   text);
-        hasBitmap = hasBitmap || record.visit<bool>(i, bitmap);
-        record.visit<void>(i, path);
-    }
-
-    fHasText                    = hasText;
-    fWillPlaybackBitmaps        = hasBitmap;
-    fNumSlowPathsAndDashEffects = SkTMin<int>(path.fNumSlowPathsAndDashEffects, 255);
-}
-
-bool SkBigPicture::Analysis::suitableForGpuRasterization(const char** reason) const {
-    if (fNumSlowPathsAndDashEffects > 5) {
-        if (reason) { *reason = "Too many slow paths (either concave or dashed)."; }
-        return false;
-    }
-    return true;
-}
diff --git a/src/core/SkBigPicture.h b/src/core/SkBigPicture.h
deleted file mode 100644 (file)
index fb3b62c..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkBigPicture_DEFINED
-#define SkBigPicture_DEFINED
-
-#include "SkPicture.h"
-
-class SkBBoxHierarchy;
-class SkRecord;
-
-// An implementation of SkPicture supporting an arbitrary number of drawing commands.
-class SkBigPicture final : public SkPicture {
-public:
-    // AccelData provides a base class for device-specific acceleration data.
-    class AccelData : public SkRefCnt { };
-
-    // An array of refcounted const SkPicture pointers.
-    class SnapshotArray : ::SkNoncopyable {
-    public:
-        SnapshotArray(const SkPicture* pics[], int count) : fPics(pics), fCount(count) {}
-        ~SnapshotArray() { for (int i = 0; i < fCount; i++) { fPics[i]->unref(); } }
-
-        const SkPicture* const* begin() const { return fPics; }
-        int count() const { return fCount; }
-    private:
-        SkAutoTMalloc<const SkPicture*> fPics;
-        int fCount;
-    };
-
-    SkBigPicture(const SkRect& cull,
-                 SkRecord*,            // We take ownership of the caller's ref.
-                 SnapshotArray*,       // We take exclusive ownership.
-                 SkBBoxHierarchy*,     // We take ownership of the caller's ref.
-                 AccelData*,           // We take ownership of the caller's ref.
-                 size_t approxBytesUsedBySubPictures);
-
-
-// SkPicture overrides
-    void playback(SkCanvas*, AbortCallback*) const override;
-    SkRect cullRect() const override;
-    bool hasText() const override;
-    bool willPlayBackBitmaps() const override;
-    int approximateOpCount() const override;
-    size_t approximateBytesUsed() const override;
-    bool suitableForGpuRasterization(GrContext*, const char** whyNot) const override;
-    const SkBigPicture* asSkBigPicture() const override { return this; }
-
-// Used by GrLayerHoister
-    void partialPlayback(SkCanvas*,
-                         unsigned start,
-                         unsigned stop,
-                         const SkMatrix& initialCTM) const;
-// Used by GrRecordReplaceDraw
-    const SkBBoxHierarchy* bbh() const { return fBBH; }
-    const SkRecord*     record() const { return fRecord; }
-    const AccelData* accelData() const { return fAccelData; }
-
-private:
-    struct Analysis {
-        explicit Analysis(const SkRecord&);
-
-        bool suitableForGpuRasterization(const char** reason) const;
-
-        uint8_t fNumSlowPathsAndDashEffects;
-        bool    fWillPlaybackBitmaps : 1;
-        bool    fHasText             : 1;
-    };
-    struct PathCounter;
-
-    int numSlowPaths() const override;
-
-    int drawableCount() const;
-    SkPicture const* const* drawablePicts() const;
-
-    const SkRect   fCullRect;
-    const Analysis fAnalysis;
-    const size_t                          fApproxBytesUsedBySubPictures;
-    SkAutoTUnref<const SkRecord>          fRecord;
-    SkAutoTDelete<const SnapshotArray>    fDrawablePicts;
-    SkAutoTUnref<const SkBBoxHierarchy>   fBBH;
-    SkAutoTUnref<const AccelData>         fAccelData;
-};
-
-#endif//SkBigPicture_DEFINED
diff --git a/src/core/SkLayerInfo.cpp b/src/core/SkLayerInfo.cpp
new file mode 100644 (file)
index 0000000..d427fa7
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkLayerInfo.h"
+
+SkPicture::AccelData::Key SkLayerInfo::ComputeKey() {
+    static const SkPicture::AccelData::Key gGPUID = SkPicture::AccelData::GenerateDomain();
+
+    return gGPUID;
+}
+
index 3d4b269..a47c3f1 100644 (file)
@@ -8,12 +8,12 @@
 #ifndef SkLayerInfo_DEFINED
 #define SkLayerInfo_DEFINED
 
-#include "SkBigPicture.h"
+#include "SkPicture.h"
 #include "SkTArray.h"
 
 // This class stores information about the saveLayer/restore pairs found
 // within an SkPicture. It is used by Ganesh to perform layer hoisting.
-class SkLayerInfo : public SkBigPicture::AccelData {
+class SkLayerInfo : public SkPicture::AccelData {
 public:
     // Information about a given saveLayer/restore block in an SkPicture
     class BlockInfo {
@@ -33,12 +33,12 @@ public:
         SkRect fSrcBounds;
         // The pre-matrix begins as the identity and accumulates the transforms
         // of the containing SkPictures (if any). This matrix state has to be
-        // part of the initial matrix during replay so that it will be
+        // part of the initial matrix during replay so that it will be 
         // preserved across setMatrix calls.
         SkMatrix fPreMat;
-        // The matrix state (in the leaf picture) in which this layer's draws
+        // The matrix state (in the leaf picture) in which this layer's draws 
         // must occur. It will/can be overridden by setMatrix calls in the
-        // layer itself. It does not include the translation needed to map the
+        // layer itself. It does not include the translation needed to map the 
         // layer's top-left point to the origin (which must be part of the
         // initial matrix).
         SkMatrix fLocalMat;
@@ -60,7 +60,7 @@ public:
         int     fKeySize;  // # of ints
     };
 
-    SkLayerInfo() {}
+    SkLayerInfo(Key key) : INHERITED(key) { }
 
     BlockInfo& addBlock() { return fBlocks.push_back(); }
 
@@ -72,10 +72,14 @@ public:
         return fBlocks[index];
     }
 
+    // We may, in the future, need to pass in the GPUDevice in order to
+    // incorporate the clip and matrix state into the key
+    static SkPicture::AccelData::Key ComputeKey();
+
 private:
     SkTArray<BlockInfo, true> fBlocks;
 
-    typedef SkBigPicture::AccelData INHERITED;
+    typedef SkPicture::AccelData INHERITED;
 };
 
 #endif // SkLayerInfo_DEFINED
diff --git a/src/core/SkMiniRecorder.cpp b/src/core/SkMiniRecorder.cpp
deleted file mode 100644 (file)
index fab6253..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkCanvas.h"
-#include "SkLazyPtr.h"
-#include "SkMiniRecorder.h"
-#include "SkPicture.h"
-#include "SkPictureCommon.h"
-#include "SkRecordDraw.h"
-#include "SkTextBlob.h"
-
-using namespace SkRecords;
-
-class SkEmptyPicture final : public SkPicture {
-public:
-    void playback(SkCanvas*, AbortCallback*) const override { }
-
-    size_t approximateBytesUsed() const override { return sizeof(*this); }
-    int    approximateOpCount()   const override { return 0; }
-    SkRect cullRect()             const override { return SkRect::MakeEmpty(); }
-    bool   hasText()              const override { return false; }
-    int    numSlowPaths()         const override { return 0; }
-    bool   willPlayBackBitmaps()  const override { return false; }
-    bool   suitableForGpuRasterization(GrContext*, const char**) const override { return true; }
-};
-SK_DECLARE_STATIC_LAZY_PTR(SkEmptyPicture, gEmptyPicture);
-
-template <typename T>
-class SkMiniPicture final : public SkPicture {
-public:
-    SkMiniPicture(SkRect cull, T* op) : fCull(cull) {
-        memcpy(&fOp, op, sizeof(fOp));  // We take ownership of op's guts.
-    }
-
-    void playback(SkCanvas* c, AbortCallback*) const override {
-        SkRecords::Draw(c, nullptr, nullptr, 0, nullptr)(fOp);
-    }
-
-    size_t approximateBytesUsed() const override { return sizeof(*this); }
-    int    approximateOpCount()   const override { return 1; }
-    SkRect cullRect()             const override { return fCull; }
-    bool   hasText()              const override { return SkTextHunter()(fOp); }
-    bool   willPlayBackBitmaps()  const override { return SkBitmapHunter()(fOp); }
-
-    // TODO: These trivial implementations are not all correct for all types.
-    // But I suspect these will never be called on SkMiniPictures, so assert for now.
-    int    numSlowPaths()         const override { SkASSERT(false); return 0; }
-    bool   suitableForGpuRasterization(GrContext*, const char**) const override {
-        SkASSERT(false);
-        return true;
-    }
-
-private:
-    SkRect fCull;
-    T      fOp;
-};
-
-
-SkMiniRecorder::SkMiniRecorder() : fState(State::kEmpty) {}
-SkMiniRecorder::~SkMiniRecorder() {
-    // We've done something wrong if no one's called detachAsPicture().
-    SkASSERT(fState == State::kEmpty);
-}
-
-#define TRY_TO_STORE(Type, ...)                    \
-    if (fState != State::kEmpty) { return false; } \
-    fState = State::k##Type;                       \
-    new (fBuffer.get()) Type(__VA_ARGS__);         \
-    return true
-
-bool SkMiniRecorder::drawRect(const SkRect& rect, const SkPaint& paint) {
-    TRY_TO_STORE(DrawRect, paint, rect);
-}
-
-bool SkMiniRecorder::drawPath(const SkPath& path, const SkPaint& paint) {
-    TRY_TO_STORE(DrawPath, paint, path);
-}
-
-bool SkMiniRecorder::drawTextBlob(const SkTextBlob* b, SkScalar x, SkScalar y, const SkPaint& p) {
-    TRY_TO_STORE(DrawTextBlob, p, b, x, y);
-}
-#undef TRY_TO_STORE
-
-#define CASE(Type)               \
-    case State::k##Type:         \
-        fState = State::kEmpty;  \
-        return SkNEW_ARGS(SkMiniPicture<Type>, (cull, reinterpret_cast<Type*>(fBuffer.get())))
-
-SkPicture* SkMiniRecorder::detachAsPicture(const SkRect& cull) {
-    switch (fState) {
-        case State::kEmpty: return SkRef(gEmptyPicture.get());
-        CASE(DrawPath);
-        CASE(DrawRect);
-        CASE(DrawTextBlob);
-    }
-    SkASSERT(false);
-    return NULL;
-}
-#undef CASE
diff --git a/src/core/SkMiniRecorder.h b/src/core/SkMiniRecorder.h
deleted file mode 100644 (file)
index d01aeda..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkMiniRecorder_DEFINED
-#define SkMiniRecorder_DEFINED
-
-#include "SkRecords.h"
-#include "SkScalar.h"
-#include "SkTypes.h"
-class SkCanvas;
-
-// Records small pictures, but only a limited subset of the canvas API, and may fail.
-class SkMiniRecorder : SkNoncopyable {
-public:
-    SkMiniRecorder();
-    ~SkMiniRecorder();
-
-    // Try to record an op.  Returns false on failure.
-    bool drawPath(const SkPath&, const SkPaint&);
-    bool drawRect(const SkRect&, const SkPaint&);
-    bool drawTextBlob(const SkTextBlob*, SkScalar x, SkScalar y, const SkPaint&);
-
-    // Detach anything we've recorded as a picture, resetting this SkMiniRecorder.
-    SkPicture* detachAsPicture(const SkRect& cull);
-
-private:
-    enum class State { kEmpty, kDrawPath, kDrawRect, kDrawTextBlob };
-
-    State fState;
-
-    template <size_t A, size_t B>
-    struct Max { static const size_t val = A > B ? A : B; };
-
-    static const size_t kInlineStorage = Max<sizeof(SkRecords::DrawPath),
-                                         Max<sizeof(SkRecords::DrawRect),
-                                             sizeof(SkRecords::DrawTextBlob)>::val>::val;
-    SkAlignedSStorage<kInlineStorage> fBuffer;
-};
-
-#endif//SkMiniRecorder_DEFINED
index c568e80..c014879 100644 (file)
  * found in the LICENSE file.
  */
 
-#include "SkAtomics.h"
-#include "SkMessageBus.h"
-#include "SkPicture.h"
+
+#include "SkPictureFlat.h"
 #include "SkPictureData.h"
 #include "SkPicturePlayback.h"
 #include "SkPictureRecord.h"
 #include "SkPictureRecorder.h"
 
+#include "SkAtomics.h"
+#include "SkBitmapDevice.h"
+#include "SkCanvas.h"
+#include "SkChunkAlloc.h"
+#include "SkMessageBus.h"
+#include "SkPaintPriv.h"
+#include "SkPathEffect.h"
+#include "SkPicture.h"
+#include "SkRegion.h"
+#include "SkShader.h"
+#include "SkStream.h"
+#include "SkTDArray.h"
+#include "SkTLogic.h"
+#include "SkTSearch.h"
+#include "SkTime.h"
+
+#include "SkReader32.h"
+#include "SkWriter32.h"
+#include "SkRTree.h"
+
+#if SK_SUPPORT_GPU
+#include "GrContext.h"
+#endif
+
+#include "SkRecord.h"
+#include "SkRecordDraw.h"
+#include "SkRecordOpts.h"
+#include "SkRecorder.h"
+
 DECLARE_SKMESSAGEBUS_MESSAGE(SkPicture::DeletionMessage);
 
-/* SkPicture impl.  This handles generic responsibilities like unique IDs and serialization. */
+template <typename T> int SafeCount(const T* obj) {
+    return obj ? obj->count() : 0;
+}
 
-SkPicture::SkPicture() : fUniqueID(0) {}
+///////////////////////////////////////////////////////////////////////////////
 
-SkPicture::~SkPicture() {
-    // TODO: move this to ~SkBigPicture() only?
+namespace {
+
+// Some commands have a paint, some have an optional paint.  Either way, get back a pointer.
+static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
+static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
+
+/** SkRecords visitor to determine whether an instance may require an
+    "external" bitmap to rasterize. May return false positives.
+    Does not return true for bitmap text.
+
+    Expected use is to determine whether images need to be decoded before
+    rasterizing a particular SkRecord.
+ */
+struct BitmapTester {
+    // Helpers.  These create HasMember_bitmap and HasMember_paint.
+    SK_CREATE_MEMBER_DETECTOR(bitmap);
+    SK_CREATE_MEMBER_DETECTOR(paint);
+
+
+    // Main entry for visitor:
+    // If the command is a DrawPicture, recurse.
+    // If the command has a bitmap directly, return true.
+    // If the command has a paint and the paint has a bitmap, return true.
+    // Otherwise, return false.
+    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
+
+    template <typename T>
+    bool operator()(const T& r) { return CheckBitmap(r); }
+
+
+    // If the command has a bitmap, of course we're going to play back bitmaps.
+    template <typename T>
+    static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
+
+    // If not, look for one in its paint (if it has a paint).
+    template <typename T>
+    static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
+
+    // If we have a paint, dig down into the effects looking for a bitmap.
+    template <typename T>
+    static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
+        const SkPaint* paint = AsPtr(r.paint);
+        if (paint) {
+            const SkShader* shader = paint->getShader();
+            if (shader &&
+                shader->asABitmap(NULL, NULL, NULL) == SkShader::kDefault_BitmapType) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // If we don't have a paint, that non-paint has no bitmap.
+    template <typename T>
+    static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
+};
+
+bool WillPlaybackBitmaps(const SkRecord& record) {
+    BitmapTester tester;
+    for (unsigned i = 0; i < record.count(); i++) {
+        if (record.visit<bool>(i, tester)) {
+            return true;
+        }
+    }
+    return false;
+}
+
+// SkRecord visitor to find recorded text.
+struct TextHunter {
+    // All ops with text have that text as a char array member named "text".
+    SK_CREATE_MEMBER_DETECTOR(text);
+    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
+    template <typename T> SK_WHEN(HasMember_text<T>,  bool) operator()(const T&) { return true;  }
+    template <typename T> SK_WHEN(!HasMember_text<T>, bool) operator()(const T&) { return false; }
+};
+
+} // namespace
+
+/** SkRecords visitor to determine heuristically whether or not a SkPicture
+    will be performant when rasterized on the GPU.
+ */
+struct SkPicture::PathCounter {
+    SK_CREATE_MEMBER_DETECTOR(paint);
 
+    PathCounter() : fNumSlowPathsAndDashEffects(0) {}
+
+    // Recurse into nested pictures.
+    void operator()(const SkRecords::DrawPicture& op) {
+        const SkPicture::Analysis& analysis = op.picture->fAnalysis;
+        fNumSlowPathsAndDashEffects += analysis.fNumSlowPathsAndDashEffects;
+    }
+
+    void checkPaint(const SkPaint* paint) {
+        if (paint && paint->getPathEffect()) {
+            // Initially assume it's slow.
+            fNumSlowPathsAndDashEffects++;
+        }
+    }
+
+    void operator()(const SkRecords::DrawPoints& op) {
+        this->checkPaint(&op.paint);
+        const SkPathEffect* effect = op.paint.getPathEffect();
+        if (effect) {
+            SkPathEffect::DashInfo info;
+            SkPathEffect::DashType dashType = effect->asADash(&info);
+            if (2 == op.count && SkPaint::kRound_Cap != op.paint.getStrokeCap() &&
+                SkPathEffect::kDash_DashType == dashType && 2 == info.fCount) {
+                fNumSlowPathsAndDashEffects--;
+            }
+        }
+    }
+
+    void operator()(const SkRecords::DrawPath& op) {
+        this->checkPaint(&op.paint);
+        if (op.paint.isAntiAlias() && !op.path.isConvex()) {
+            SkPaint::Style paintStyle = op.paint.getStyle();
+            const SkRect& pathBounds = op.path.getBounds();
+            if (SkPaint::kStroke_Style == paintStyle &&
+                0 == op.paint.getStrokeWidth()) {
+                // AA hairline concave path is not slow.
+            } else if (SkPaint::kFill_Style == paintStyle && pathBounds.width() < 64.f &&
+                       pathBounds.height() < 64.f && !op.path.isVolatile()) {
+                // AADF eligible concave path is not slow.
+            } else {
+                fNumSlowPathsAndDashEffects++;
+            }
+        }
+    }
+
+    template <typename T>
+    SK_WHEN(HasMember_paint<T>, void) operator()(const T& op) {
+        this->checkPaint(AsPtr(op.paint));
+    }
+
+    template <typename T>
+    SK_WHEN(!HasMember_paint<T>, void) operator()(const T& op) { /* do nothing */ }
+
+    int fNumSlowPathsAndDashEffects;
+};
+
+SkPicture::Analysis::Analysis(const SkRecord& record) {
+    fWillPlaybackBitmaps = WillPlaybackBitmaps(record);
+
+    PathCounter counter;
+    for (unsigned i = 0; i < record.count(); i++) {
+        record.visit<void>(i, counter);
+    }
+    fNumSlowPathsAndDashEffects = SkTMin<int>(counter.fNumSlowPathsAndDashEffects, 255);
+
+    fHasText = false;
+    TextHunter text;
+    for (unsigned i = 0; i < record.count(); i++) {
+        if (record.visit<bool>(i, text)) {
+            fHasText = true;
+            break;
+        }
+    }
+}
+
+bool SkPicture::Analysis::suitableForGpuRasterization(const char** reason,
+                                                      int sampleCount) const {
+    // TODO: the heuristic used here needs to be refined
+    static const int kNumSlowPathsTol = 6;
+
+    bool ret = fNumSlowPathsAndDashEffects < kNumSlowPathsTol;
+
+    if (!ret && reason) {
+        *reason = "Too many slow paths (either concave or dashed).";
+    }
+    return ret;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+int SkPicture::drawableCount() const {
+    return fDrawablePicts.get() ? fDrawablePicts->count() : 0;
+}
+
+SkPicture const* const* SkPicture::drawablePicts() const {
+    return fDrawablePicts.get() ? fDrawablePicts->begin() : NULL;
+}
+
+SkPicture::~SkPicture() {
     // If the ID is still zero, no one has read it, so no need to send this message.
     uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
     if (id != 0) {
-        SkPicture::DeletionMessage msg = { (int32_t)id };
+        SkPicture::DeletionMessage msg;
+        msg.fUniqueID = id;
         SkMessageBus<SkPicture::DeletionMessage>::Post(msg);
     }
 }
 
-uint32_t SkPicture::uniqueID() const {
-    static uint32_t gNextID = 1;
-    uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
-    while (id == 0) {
-        uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
-        if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
-                                       sk_memory_order_relaxed,
-                                       sk_memory_order_relaxed)) {
-            id = next;
-        } else {
-            // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
-        }
+const SkPicture::AccelData* SkPicture::EXPERIMENTAL_getAccelData(
+        SkPicture::AccelData::Key key) const {
+    if (fAccelData.get() && fAccelData->getKey() == key) {
+        return fAccelData.get();
     }
-    return id;
+    return NULL;
 }
 
-static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
+SkPicture::AccelData::Domain SkPicture::AccelData::GenerateDomain() {
+    static int32_t gNextID = 0;
 
-SkPictInfo SkPicture::createHeader() const {
-    SkPictInfo info;
-    // Copy magic bytes at the beginning of the header
-    static_assert(sizeof(kMagic) == 8, "");
-    static_assert(sizeof(kMagic) == sizeof(info.fMagic), "");
-    memcpy(info.fMagic, kMagic, sizeof(kMagic));
+    int32_t id = sk_atomic_inc(&gNextID);
+    if (id >= 1 << (8 * sizeof(Domain))) {
+        SK_CRASH();
+    }
 
-    // Set picture info after magic bytes in the header
-    info.fVersion = CURRENT_PICTURE_VERSION;
-    info.fCullRect = this->cullRect();
-    info.fFlags = SkPictInfo::kCrossProcess_Flag;
-    // TODO: remove this flag, since we're always float (now)
-    info.fFlags |= SkPictInfo::kScalarIsFloat_Flag;
+    return static_cast<Domain>(id);
+}
 
-    if (8 == sizeof(void*)) {
-        info.fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
-    }
-    return info;
+///////////////////////////////////////////////////////////////////////////////
+
+void SkPicture::playback(SkCanvas* canvas, AbortCallback* callback) const {
+    SkASSERT(canvas);
+
+    // If the query contains the whole picture, don't bother with the BBH.
+    SkRect clipBounds = { 0, 0, 0, 0 };
+    (void)canvas->getClipBounds(&clipBounds);
+    const bool useBBH = !clipBounds.contains(this->cullRect());
+
+    SkRecordDraw(*fRecord, canvas, this->drawablePicts(), NULL, this->drawableCount(),
+                 useBBH ? fBBH.get() : NULL, callback);
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkStream.h"
+
+static const char kMagic[] = { 's', 'k', 'i', 'a', 'p', 'i', 'c', 't' };
+
 bool SkPicture::IsValidPictInfo(const SkPictInfo& info) {
     if (0 != memcmp(info.fMagic, kMagic, sizeof(kMagic))) {
         return false;
     }
-    if (info.fVersion < MIN_PICTURE_VERSION || info.fVersion > CURRENT_PICTURE_VERSION) {
+
+    if (info.fVersion < MIN_PICTURE_VERSION ||
+        info.fVersion > CURRENT_PICTURE_VERSION) {
         return false;
     }
+
     return true;
 }
 
 bool SkPicture::InternalOnly_StreamIsSKP(SkStream* stream, SkPictInfo* pInfo) {
-    if (!stream) {
+    if (NULL == stream) {
         return false;
     }
 
+    // Check magic bytes.
     SkPictInfo info;
     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
+
     if (!stream->read(&info.fMagic, sizeof(kMagic))) {
         return false;
     }
 
-    info.fVersion          = stream->readU32();
-    info.fCullRect.fLeft   = stream->readScalar();
-    info.fCullRect.fTop    = stream->readScalar();
-    info.fCullRect.fRight  = stream->readScalar();
+    info.fVersion = stream->readU32();
+    info.fCullRect.fLeft = stream->readScalar();
+    info.fCullRect.fTop = stream->readScalar();
+    info.fCullRect.fRight = stream->readScalar();
     info.fCullRect.fBottom = stream->readScalar();
-    info.fFlags            = stream->readU32();
 
-    if (IsValidPictInfo(info)) {
-        if (pInfo) { *pInfo = info; }
-        return true;
+    info.fFlags = stream->readU32();
+
+    if (!IsValidPictInfo(info)) {
+        return false;
     }
-    return false;
+
+    if (pInfo != NULL) {
+        *pInfo = info;
+    }
+    return true;
 }
 
 bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
+    // Check magic bytes.
     SkPictInfo info;
     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
+
     if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
         return false;
     }
@@ -114,29 +337,32 @@ bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo
     buffer->readRect(&info.fCullRect);
     info.fFlags = buffer->readUInt();
 
-    if (IsValidPictInfo(info)) {
-        if (pInfo) { *pInfo = info; }
-        return true;
+    if (!IsValidPictInfo(info)) {
+        return false;
     }
-    return false;
+
+    if (pInfo != NULL) {
+        *pInfo = info;
+    }
+    return true;
 }
 
 SkPicture* SkPicture::Forwardport(const SkPictInfo& info, const SkPictureData* data) {
     if (!data) {
-        return nullptr;
+        return NULL;
     }
     SkPicturePlayback playback(data);
     SkPictureRecorder r;
     playback.draw(r.beginRecording(SkScalarCeilToInt(info.fCullRect.width()),
                                    SkScalarCeilToInt(info.fCullRect.height())),
-                  nullptr/*no callback*/);
+                  NULL/*no callback*/);
     return r.endRecording();
 }
 
 SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc proc) {
     SkPictInfo info;
     if (!InternalOnly_StreamIsSKP(stream, &info) || !stream->readBool()) {
-        return nullptr;
+        return NULL;
     }
     SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromStream(stream, info, proc));
     return Forwardport(info, data);
@@ -145,24 +371,45 @@ SkPicture* SkPicture::CreateFromStream(SkStream* stream, InstallPixelRefProc pro
 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
     SkPictInfo info;
     if (!InternalOnly_BufferIsSKP(&buffer, &info) || !buffer.readBool()) {
-        return nullptr;
+        return NULL;
     }
     SkAutoTDelete<SkPictureData> data(SkPictureData::CreateFromBuffer(buffer, info));
     return Forwardport(info, data);
 }
 
-SkPictureData* SkPicture::backport() const {
-    SkPictInfo info = this->createHeader();
+void SkPicture::createHeader(SkPictInfo* info) const {
+    // Copy magic bytes at the beginning of the header
+    SkASSERT(sizeof(kMagic) == 8);
+    SkASSERT(sizeof(kMagic) == sizeof(info->fMagic));
+    memcpy(info->fMagic, kMagic, sizeof(kMagic));
+
+    // Set picture info after magic bytes in the header
+    info->fVersion = CURRENT_PICTURE_VERSION;
+    info->fCullRect = this->cullRect();
+    info->fFlags = SkPictInfo::kCrossProcess_Flag;
+    // TODO: remove this flag, since we're always float (now)
+    info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
+
+    if (8 == sizeof(void*)) {
+        info->fFlags |= SkPictInfo::kPtrIs64Bit_Flag;
+    }
+}
+
+// This for compatibility with serialization code only.  This is not cheap.
+SkPictureData* SkPicture::Backport(const SkRecord& src, const SkPictInfo& info,
+                                   SkPicture const* const drawablePicts[], int drawableCount) {
     SkPictureRecord rec(SkISize::Make(info.fCullRect.width(), info.fCullRect.height()), 0/*flags*/);
     rec.beginRecording();
-        this->playback(&rec);
+        SkRecordDraw(src, &rec, drawablePicts, NULL, drawableCount, NULL/*bbh*/, NULL/*callback*/);
     rec.endRecording();
     return SkNEW_ARGS(SkPictureData, (rec, info, false/*deep copy ops?*/));
 }
 
 void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer) const {
-    SkPictInfo info = this->createHeader();
-    SkAutoTDelete<SkPictureData> data(this->backport());
+    SkPictInfo info;
+    this->createHeader(&info);
+    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
+                                               this->drawableCount()));
 
     stream->write(&info, sizeof(info));
     if (data) {
@@ -174,8 +421,10 @@ void SkPicture::serialize(SkWStream* stream, SkPixelSerializer* pixelSerializer)
 }
 
 void SkPicture::flatten(SkWriteBuffer& buffer) const {
-    SkPictInfo info = this->createHeader();
-    SkAutoTDelete<SkPictureData> data(this->backport());
+    SkPictInfo info;
+    this->createHeader(&info);
+    SkAutoTDelete<SkPictureData> data(Backport(*fRecord, info, this->drawablePicts(),
+                                               this->drawableCount()));
 
     buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
     buffer.writeUInt(info.fVersion);
@@ -188,3 +437,46 @@ void SkPicture::flatten(SkWriteBuffer& buffer) const {
         buffer.writeBool(false);
     }
 }
+
+#if SK_SUPPORT_GPU
+bool SkPicture::suitableForGpuRasterization(GrContext*, const char **reason) const {
+    return fAnalysis.suitableForGpuRasterization(reason, 0);
+}
+#endif
+
+bool SkPicture::hasText()             const { return fAnalysis.fHasText; }
+bool SkPicture::willPlayBackBitmaps() const { return fAnalysis.fWillPlaybackBitmaps; }
+int  SkPicture::approximateOpCount()  const { return fRecord->count(); }
+
+SkPicture::SkPicture(const SkRect& cullRect,
+                     SkRecord* record,
+                     SnapshotArray* drawablePicts,
+                     SkBBoxHierarchy* bbh,
+                     AccelData* accelData,
+                     size_t approxBytesUsedBySubPictures)
+    : fUniqueID(0)
+    , fCullRect(cullRect)
+    , fRecord(record)               // Take ownership of caller's ref.
+    , fDrawablePicts(drawablePicts) // Take ownership.
+    , fBBH(bbh)                     // Take ownership of caller's ref.
+    , fAccelData(accelData)         // Take ownership of caller's ref.
+    , fApproxBytesUsedBySubPictures(approxBytesUsedBySubPictures)
+    , fAnalysis(*fRecord)
+{}
+
+
+static uint32_t gNextID = 1;
+uint32_t SkPicture::uniqueID() const {
+    uint32_t id = sk_atomic_load(&fUniqueID, sk_memory_order_relaxed);
+    while (id == 0) {
+        uint32_t next = sk_atomic_fetch_add(&gNextID, 1u);
+        if (sk_atomic_compare_exchange(&fUniqueID, &id, next,
+                                       sk_memory_order_relaxed,
+                                       sk_memory_order_relaxed)) {
+            id = next;
+        } else {
+            // sk_atomic_compare_exchange replaced id with the current value of fUniqueID.
+        }
+    }
+    return id;
+}
diff --git a/src/core/SkPictureCommon.h b/src/core/SkPictureCommon.h
deleted file mode 100644 (file)
index e987234..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2015 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-// Some shared code used by both SkBigPicture and SkMiniPicture.
-
-#include "SkRecords.h"
-#include "SkTLogic.h"
-
-struct SkTextHunter {
-    // Most ops never have text.  Some always do.  Subpictures know themeselves.
-    template <typename T> bool operator()(const T&) { return false; }
-    bool operator()(const SkRecords::DrawPosText&)    { return true; }
-    bool operator()(const SkRecords::DrawPosTextH&)   { return true; }
-    bool operator()(const SkRecords::DrawText&)       { return true; }
-    bool operator()(const SkRecords::DrawTextBlob&)   { return true; }
-    bool operator()(const SkRecords::DrawTextOnPath&) { return true; }
-    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->hasText(); }
-};
-
-
-struct SkBitmapHunter {
-    // Helpers.  These create HasMember_bitmap and HasMember_paint.
-    SK_CREATE_MEMBER_DETECTOR(bitmap);
-    SK_CREATE_MEMBER_DETECTOR(paint);
-
-    // Some ops have a paint, some have an optional paint.  Either way, get back a pointer.
-    static const SkPaint* AsPtr(const SkPaint& p) { return &p; }
-    static const SkPaint* AsPtr(const SkRecords::Optional<SkPaint>& p) { return p; }
-
-    // Main entry for visitor:
-    // If the op is a DrawPicture, recurse.
-    // If the op has a bitmap directly, return true.
-    // If the op has a paint and the paint has a bitmap, return true.
-    // Otherwise, return false.
-    bool operator()(const SkRecords::DrawPicture& op) { return op.picture->willPlayBackBitmaps(); }
-
-    template <typename T>
-    bool operator()(const T& r) { return CheckBitmap(r); }
-
-    // If the op has a bitmap, of course we're going to play back bitmaps.
-    template <typename T>
-    static SK_WHEN(HasMember_bitmap<T>, bool) CheckBitmap(const T&) { return true; }
-
-    // If not, look for one in its paint (if it has a paint).
-    template <typename T>
-    static SK_WHEN(!HasMember_bitmap<T>, bool) CheckBitmap(const T& r) { return CheckPaint(r); }
-
-    // If we have a paint, dig down into the effects looking for a bitmap.
-    template <typename T>
-    static SK_WHEN(HasMember_paint<T>, bool) CheckPaint(const T& r) {
-        const SkPaint* paint = AsPtr(r.paint);
-        if (paint) {
-            const SkShader* shader = paint->getShader();
-            if (shader &&
-                shader->asABitmap(nullptr, nullptr, nullptr) == SkShader::kDefault_BitmapType) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    // If we don't have a paint, that non-paint has no bitmap.
-    template <typename T>
-    static SK_WHEN(!HasMember_paint<T>, bool) CheckPaint(const T&) { return false; }
-};
-
index c110e0a..282e2c2 100644 (file)
@@ -5,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-#include "SkBigPicture.h"
 #include "SkData.h"
 #include "SkDrawable.h"
 #include "SkLayerInfo.h"
@@ -19,7 +18,7 @@
 
 SkPictureRecorder::SkPictureRecorder() {
     fActivelyRecording = false;
-    fRecorder.reset(SkNEW_ARGS(SkRecorder, (nullptr, SkRect::MakeWH(0,0), &fMiniRecorder)));
+    fRecorder.reset(SkNEW_ARGS(SkRecorder, (nullptr, SkRect::MakeWH(0,0))));
 }
 
 SkPictureRecorder::~SkPictureRecorder() {}
@@ -35,10 +34,8 @@ SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
         SkASSERT(fBBH.get());
     }
 
-    if (!fRecord) {
-        fRecord.reset(SkNEW(SkRecord));
-    }
-    fRecorder->reset(fRecord.get(), cullRect, &fMiniRecorder);
+    fRecord.reset(SkNEW(SkRecord));
+    fRecorder->reset(fRecord.get(), cullRect);
     fActivelyRecording = true;
     return this->getRecordingCanvas();
 }
@@ -50,23 +47,19 @@ SkCanvas* SkPictureRecorder::getRecordingCanvas() {
 SkPicture* SkPictureRecorder::endRecordingAsPicture() {
     fActivelyRecording = false;
     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
-
-    if (fRecord->count() == 0) {
-        return fMiniRecorder.detachAsPicture(fCullRect);
-    }
-
     // TODO: delay as much of this work until just before first playback?
     SkRecordOptimize(fRecord);
 
     SkAutoTUnref<SkLayerInfo> saveLayerData;
 
     if (fBBH && (fFlags & kComputeSaveLayerInfo_RecordFlag)) {
-        saveLayerData.reset(SkNEW(SkLayerInfo));
+        SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+        saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
     }
 
     SkDrawableList* drawableList = fRecorder->getDrawableList();
-    SkBigPicture::SnapshotArray* pictList =
-        drawableList ? drawableList->newDrawableSnapshot() : NULL;
+    SkPicture::SnapshotArray* pictList = drawableList ? drawableList->newDrawableSnapshot() : NULL;
 
     if (fBBH.get()) {
         if (saveLayerData) {
@@ -84,12 +77,12 @@ SkPicture* SkPictureRecorder::endRecordingAsPicture() {
     for (int i = 0; pictList && i < pictList->count(); i++) {
         subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
     }
-    return SkNEW_ARGS(SkBigPicture, (fCullRect,
-                                     fRecord.detach(),
-                                     pictList,
-                                     fBBH.detach(),
-                                     saveLayerData.detach(),
-                                     subPictureBytes));
+    return SkNEW_ARGS(SkPicture, (fCullRect,
+                                  fRecord.detach(),
+                                  pictList,
+                                  fBBH.detach(),
+                                  saveLayerData.detach(),
+                                  subPictureBytes));
 }
 
 void SkPictureRecorder::partialReplay(SkCanvas* canvas) const {
@@ -140,7 +133,7 @@ protected:
     }
 
     SkPicture* onNewPictureSnapshot() override {
-        SkBigPicture::SnapshotArray* pictList = NULL;
+        SkPicture::SnapshotArray* pictList = NULL;
         if (fDrawableList) {
             // TODO: should we plumb-down the BBHFactory and recordFlags from our host
             //       PictureRecorder?
@@ -150,7 +143,9 @@ protected:
         SkAutoTUnref<SkLayerInfo> saveLayerData;
 
         if (fBBH && fDoSaveLayerInfo) {
-            saveLayerData.reset(SkNEW(SkLayerInfo));
+            SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+            saveLayerData.reset(SkNEW_ARGS(SkLayerInfo, (key)));
 
             SkBBoxHierarchy* bbh = NULL;    // we've already computed fBBH (received in constructor)
             // TODO: update saveLayer info computation to reuse the already computed
@@ -162,22 +157,20 @@ protected:
         for (int i = 0; pictList && i < pictList->count(); i++) {
             subPictureBytes += SkPictureUtils::ApproximateBytesUsed(pictList->begin()[i]);
         }
-        // SkBigPicture will take ownership of a ref on both fRecord and fBBH.
+        // SkPicture will take ownership of a ref on both fRecord and fBBH.
         // We're not willing to give up our ownership, so we must ref them for SkPicture.
-        return SkNEW_ARGS(SkBigPicture, (fBounds,
-                                         SkRef(fRecord.get()),
-                                         pictList,
-                                         SkSafeRef(fBBH.get()),
-                                         saveLayerData.detach(),
-                                         subPictureBytes));
+        return SkNEW_ARGS(SkPicture, (fBounds,
+                                      SkRef(fRecord.get()),
+                                      pictList,
+                                      SkSafeRef(fBBH.get()),
+                                      saveLayerData.detach(),
+                                      subPictureBytes));
     }
 };
 
 SkDrawable* SkPictureRecorder::endRecordingAsDrawable() {
     fActivelyRecording = false;
-    fRecorder->flushMiniRecorder();
     fRecorder->restoreToCount(1);  // If we were missing any restores, add them now.
-
     // TODO: delay as much of this work until just before first playback?
     SkRecordOptimize(fRecord);
 
index 65e6d49..ba15c1b 100644 (file)
@@ -587,7 +587,7 @@ private:
 class CollectLayers : SkNoncopyable {
 public:
     CollectLayers(const SkRect& cullRect, const SkRecord& record,
-                  const SkBigPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
+                  const SkPicture::SnapshotArray* pictList, SkLayerInfo* accelData)
         : fSaveLayersInStack(0)
         , fAccelData(accelData)
         , fPictList(pictList)
@@ -640,10 +640,10 @@ private:
     void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
         // For sub-pictures, we wrap their layer information within the parent
         // picture's rendering hierarchy
-        const SkLayerInfo* childData = NULL;
-        if (const SkBigPicture* bp = picture->asSkBigPicture()) {
-            childData = static_cast<const SkLayerInfo*>(bp->accelData());
-        }
+        SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+        const SkLayerInfo* childData =
+            static_cast<const SkLayerInfo*>(picture->EXPERIMENTAL_getAccelData(key));
         if (!childData) {
             // If the child layer hasn't been generated with saveLayer data we
             // assume the worst (i.e., that it does contain layers which nest
@@ -774,7 +774,7 @@ private:
     // The op code indices of all the currently active saveLayers
     SkTDArray<unsigned>      fSaveLayerOpStack;
     SkLayerInfo*             fAccelData;
-    const SkBigPicture::SnapshotArray* fPictList;
+    const SkPicture::SnapshotArray* fPictList;
 
     SkRecords::FillBounds fFillBounds;
 };
@@ -793,7 +793,7 @@ void SkRecordFillBounds(const SkRect& cullRect, const SkRecord& record, SkBBoxHi
 }
 
 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
-                           const SkBigPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
+                           const SkPicture::SnapshotArray* pictList, SkBBoxHierarchy* bbh,
                            SkLayerInfo* data) {
     SkRecords::CollectLayers visitor(cullRect, record, pictList, data);
 
index 5b248cf..7bbab81 100644 (file)
@@ -9,7 +9,6 @@
 #define SkRecordDraw_DEFINED
 
 #include "SkBBoxHierarchy.h"
-#include "SkBigPicture.h"
 #include "SkCanvas.h"
 #include "SkMatrix.h"
 #include "SkRecord.h"
@@ -21,7 +20,7 @@ class SkLayerInfo;
 void SkRecordFillBounds(const SkRect& cullRect, const SkRecord&, SkBBoxHierarchy*);
 
 void SkRecordComputeLayers(const SkRect& cullRect, const SkRecord& record,
-                           const SkBigPicture::SnapshotArray*,
+                           const SkPicture::SnapshotArray*,
                            SkBBoxHierarchy* bbh, SkLayerInfo* data);
 
 // Draw an SkRecord into an SkCanvas.  A convenience wrapper around SkRecords::Draw.
index 45283f8..0a2d43e 100644 (file)
@@ -5,7 +5,6 @@
  * found in the LICENSE file.
  */
 
-#include "SkBigPicture.h"
 #include "SkPatchUtils.h"
 #include "SkPicture.h"
 #include "SkPictureUtils.h"
@@ -15,7 +14,7 @@ SkDrawableList::~SkDrawableList() {
     fArray.unrefAll();
 }
 
-SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
+SkPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
     const int count = fArray.count();
     if (0 == count) {
         return NULL;
@@ -24,7 +23,7 @@ SkBigPicture::SnapshotArray* SkDrawableList::newDrawableSnapshot() {
     for (int i = 0; i < count; ++i) {
         pics[i] = fArray[i]->newPictureSnapshot();
     }
-    return SkNEW_ARGS(SkBigPicture::SnapshotArray, (pics.detach(), count));
+    return SkNEW_ARGS(SkPicture::SnapshotArray, (pics.detach(), count));
 }
 
 void SkDrawableList::append(SkDrawable* drawable) {
@@ -33,23 +32,20 @@ void SkDrawableList::append(SkDrawable* drawable) {
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-SkRecorder::SkRecorder(SkRecord* record, int width, int height, SkMiniRecorder* mr)
+SkRecorder::SkRecorder(SkRecord* record, int width, int height)
     : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
     , fApproxBytesUsedBySubPictures(0)
-    , fRecord(record)
-    , fMiniRecorder(mr) {}
+    , fRecord(record) {}
 
-SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr)
+SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
     : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
     , fApproxBytesUsedBySubPictures(0)
-    , fRecord(record)
-    , fMiniRecorder(mr) {}
+    , fRecord(record) {}
 
-void SkRecorder::reset(SkRecord* record, const SkRect& bounds, SkMiniRecorder* mr) {
+void SkRecorder::reset(SkRecord* record, const SkRect& bounds) {
     this->forgetRecord();
     fRecord = record;
     this->resetForNextPicture(bounds.roundOut());
-    fMiniRecorder = mr;
 }
 
 void SkRecorder::forgetRecord() {
@@ -59,13 +55,9 @@ void SkRecorder::forgetRecord() {
 }
 
 // To make appending to fRecord a little less verbose.
-#define APPEND(T, ...)                                    \
-        if (fMiniRecorder) { this->flushMiniRecorder(); } \
+#define APPEND(T, ...) \
         SkNEW_PLACEMENT_ARGS(fRecord->append<SkRecords::T>(), SkRecords::T, (__VA_ARGS__))
 
-#define TRY_MINIRECORDER(method, ...)                       \
-    if (fMiniRecorder && fMiniRecorder->method(__VA_ARGS__)) { return; }
-
 // For methods which must call back into SkCanvas.
 #define INHERITED(method, ...) this->SkCanvas::method(__VA_ARGS__)
 
@@ -133,15 +125,6 @@ char* SkRecorder::copy(const char* src) {
     return this->copy(src, strlen(src)+1);
 }
 
-void SkRecorder::flushMiniRecorder() {
-    if (fMiniRecorder) {
-        SkMiniRecorder* mr = fMiniRecorder;
-        fMiniRecorder = nullptr;  // Needs to happen before p->playback(this) or we loop forever.
-        // TODO: this can probably be done more efficiently by SkMiniRecorder if it matters.
-        SkAutoTUnref<SkPicture> p(mr->detachAsPicture(SkRect::MakeEmpty()));
-        p->playback(this);
-    }
-}
 
 void SkRecorder::onDrawPaint(const SkPaint& paint) {
     APPEND(DrawPaint, delay_copy(paint));
@@ -155,7 +138,6 @@ void SkRecorder::onDrawPoints(PointMode mode,
 }
 
 void SkRecorder::onDrawRect(const SkRect& rect, const SkPaint& paint) {
-    TRY_MINIRECORDER(drawRect, rect, paint);
     APPEND(DrawRect, delay_copy(paint), rect);
 }
 
@@ -180,7 +162,6 @@ void SkRecorder::onDrawDrawable(SkDrawable* drawable) {
 }
 
 void SkRecorder::onDrawPath(const SkPath& path, const SkPaint& paint) {
-    TRY_MINIRECORDER(drawPath, path, paint);
     APPEND(DrawPath, delay_copy(paint), delay_copy(path));
 }
 
@@ -267,7 +248,6 @@ void SkRecorder::onDrawTextOnPath(const void* text, size_t byteLength, const SkP
 
 void SkRecorder::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
                                 const SkPaint& paint) {
-    TRY_MINIRECORDER(drawTextBlob, blob, x, y, paint);
     APPEND(DrawTextBlob, delay_copy(paint), blob, x, y);
 }
 
index b6f153d..d0a992f 100644 (file)
@@ -8,9 +8,7 @@
 #ifndef SkRecorder_DEFINED
 #define SkRecorder_DEFINED
 
-#include "SkBigPicture.h"
 #include "SkCanvas.h"
-#include "SkMiniRecorder.h"
 #include "SkRecord.h"
 #include "SkRecords.h"
 #include "SkTDArray.h"
@@ -27,7 +25,7 @@ public:
     void append(SkDrawable* drawable);
 
     // Return a new or ref'd array of pictures that were snapped from our drawables.
-    SkBigPicture::SnapshotArray* newDrawableSnapshot();
+    SkPicture::SnapshotArray* newDrawableSnapshot();
 
 private:
     SkTDArray<SkDrawable*> fArray;
@@ -38,10 +36,10 @@ private:
 class SkRecorder : public SkCanvas {
 public:
     // Does not take ownership of the SkRecord.
-    SkRecorder(SkRecord*, int width, int height, SkMiniRecorder* = nullptr);   // legacy version
-    SkRecorder(SkRecord*, const SkRect& bounds, SkMiniRecorder* = nullptr);
+    SkRecorder(SkRecord*, int width, int height);   // legacy version
+    SkRecorder(SkRecord*, const SkRect& bounds);
 
-    void reset(SkRecord*, const SkRect& bounds, SkMiniRecorder* = nullptr);
+    void reset(SkRecord*, const SkRect& bounds);
 
     size_t approxBytesUsedBySubPictures() const { return fApproxBytesUsedBySubPictures; }
 
@@ -122,8 +120,6 @@ public:
 
     SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override { return NULL; }
 
-    void flushMiniRecorder();
-
 private:
     template <typename T>
     T* copy(const T*);
@@ -140,8 +136,6 @@ private:
     size_t fApproxBytesUsedBySubPictures;
     SkRecord* fRecord;
     SkAutoTDelete<SkDrawableList> fDrawableList;
-
-    SkMiniRecorder* fMiniRecorder;
 };
 
 #endif//SkRecorder_DEFINED
index 6e25dd2..319d155 100644 (file)
@@ -81,7 +81,6 @@ struct T {                              \
 #define RECORD1(T, A, a)                \
 struct T {                              \
     static const Type kType = T##_Type; \
-    T() {}                              \
     template <typename Z>               \
     T(Z a) : a(a) {}                    \
     A a;                                \
@@ -90,7 +89,6 @@ struct T {                              \
 #define RECORD2(T, A, a, B, b)          \
 struct T {                              \
     static const Type kType = T##_Type; \
-    T() {}                              \
     template <typename Z, typename Y>   \
     T(Z a, Y b) : a(a), b(b) {}         \
     A a; B b;                           \
@@ -99,7 +97,6 @@ struct T {                              \
 #define RECORD3(T, A, a, B, b, C, c)              \
 struct T {                                        \
     static const Type kType = T##_Type;           \
-    T() {}                                        \
     template <typename Z, typename Y, typename X> \
     T(Z a, Y b, X c) : a(a), b(b), c(c) {}        \
     A a; B b; C c;                                \
@@ -108,7 +105,6 @@ struct T {                                        \
 #define RECORD4(T, A, a, B, b, C, c, D, d)                    \
 struct T {                                                    \
     static const Type kType = T##_Type;                       \
-    T() {}                                                    \
     template <typename Z, typename Y, typename X, typename W> \
     T(Z a, Y b, X c, W d) : a(a), b(b), c(c), d(d) {}         \
     A a; B b; C c; D d;                                       \
@@ -117,7 +113,6 @@ struct T {                                                    \
 #define RECORD5(T, A, a, B, b, C, c, D, d, E, e)                          \
 struct T {                                                                \
     static const Type kType = T##_Type;                                   \
-    T() {}                                                                \
     template <typename Z, typename Y, typename X, typename W, typename V> \
     T(Z a, Y b, X c, W d, V e) : a(a), b(b), c(c), d(d), e(e) {}          \
     A a; B b; C c; D d; E e;                                              \
@@ -130,7 +125,6 @@ struct T {                                                                \
 template <typename T>
 class RefBox : SkNoncopyable {
 public:
-    RefBox() {}
     RefBox(T* obj) : fObj(SkSafeRef(obj)) {}
     ~RefBox() { SkSafeUnref(fObj); }
 
@@ -144,7 +138,6 @@ private:
 template <typename T>
 class Optional : SkNoncopyable {
 public:
-    Optional() : fPtr(nullptr) {}
     Optional(T* ptr) : fPtr(ptr) {}
     ~Optional() { if (fPtr) fPtr->~T(); }
 
@@ -174,7 +167,6 @@ private:
 template <typename T>
 class PODArray {
 public:
-    PODArray() {}
     PODArray(T* ptr) : fPtr(ptr) {}
     // Default copy and assign.
 
@@ -189,7 +181,6 @@ private:
 // Using this, we guarantee the immutability of all bitmaps we record.
 class ImmutableBitmap : SkNoncopyable {
 public:
-    ImmutableBitmap() {}
     explicit ImmutableBitmap(const SkBitmap& bitmap) {
         if (bitmap.isImmutable()) {
             fBitmap = bitmap;
@@ -212,7 +203,6 @@ private:
 // SkPath::cheapComputeDirection() is similar.
 // Recording is a convenient time to cache these, or we can delay it to between record and playback.
 struct PreCachedPath : public SkPath {
-    PreCachedPath() {}
     explicit PreCachedPath(const SkPath& path) : SkPath(path) {
         this->updateBoundsCache();
         SkPath::Direction junk;
@@ -223,7 +213,6 @@ struct PreCachedPath : public SkPath {
 // Like SkPath::getBounds(), SkMatrix::getType() isn't thread safe unless we precache it.
 // This may not cover all SkMatrices used by the picture (e.g. some could be hiding in a shader).
 struct TypedMatrix : public SkMatrix {
-    TypedMatrix() {}
     explicit TypedMatrix(const SkMatrix& matrix) : SkMatrix(matrix) {
         (void)this->getType();
     }
@@ -238,7 +227,6 @@ RECORD3(SaveLayer, Optional<SkRect>, bounds, Optional<SkPaint>, paint, SkCanvas:
 RECORD1(SetMatrix, TypedMatrix, matrix);
 
 struct RegionOpAndAA {
-    RegionOpAndAA() {}
     RegionOpAndAA(SkRegion::Op op, bool aa) : op(op), aa(aa) {}
     SkRegion::Op op : 31;  // This really only needs to be 3, but there's no win today to do so.
     unsigned     aa :  1;  // MSVC won't pack an enum with an bool, so we call this an unsigned.
index 67e3c19..70c10d7 100644 (file)
@@ -9,7 +9,6 @@
 #include "GrLayerHoister.h"
 #include "GrRecordReplaceDraw.h"
 
-#include "SkBigPicture.h"
 #include "SkCanvas.h"
 #include "SkDeviceImageFilterProxy.h"
 #include "SkDeviceProperties.h"
@@ -22,7 +21,7 @@
 
 // Create the layer information for the hoisted layer and secure the
 // required texture/render target resources.
-static void prepare_for_hoisting(GrLayerCache* layerCache,
+static void prepare_for_hoisting(GrLayerCache* layerCache, 
                                  const SkPicture* topLevelPicture,
                                  const SkMatrix& initialMat,
                                  const SkLayerInfo::BlockInfo& info,
@@ -75,7 +74,7 @@ static void prepare_for_hoisting(GrLayerCache* layerCache,
     } else {
         hl = recycled->append();
     }
-
+    
     layerCache->addUse(layer);
     hl->fLayer = layer;
     hl->fPicture = pict;
@@ -130,12 +129,12 @@ void GrLayerHoister::FindLayersToAtlas(GrContext* context,
     }
 
     GrLayerCache* layerCache = context->getLayerCache();
+
     layerCache->processDeletedPictures();
 
-    const SkBigPicture::AccelData* topLevelData = NULL;
-    if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
-        topLevelData = bp->accelData();
-    }
+    SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+    const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
     if (!topLevelData) {
         return;
     }
@@ -190,10 +189,9 @@ void GrLayerHoister::FindLayersToHoist(GrContext* context,
 
     layerCache->processDeletedPictures();
 
-    const SkBigPicture::AccelData* topLevelData = NULL;
-    if (const SkBigPicture* bp = topLevelPicture->asSkBigPicture()) {
-        topLevelData = bp->accelData();
-    }
+    SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+    const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key);
     if (!topLevelData) {
         return;
     }
@@ -241,11 +239,7 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
 
         for (int i = 0; i < atlased.count(); ++i) {
             const GrCachedLayer* layer = atlased[i].fLayer;
-            const SkBigPicture* pict = atlased[i].fPicture->asSkBigPicture();
-            if (!pict) {
-                // TODO: can we assume / assert this?
-                continue;
-            }
+            const SkPicture* pict = atlased[i].fPicture;
             const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
             SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();)
 
@@ -271,7 +265,10 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context,
             atlasCanvas->setMatrix(initialCTM);
             atlasCanvas->concat(atlased[i].fLocalMat);
 
-            pict->partialPlayback(atlasCanvas, layer->start() + 1, layer->stop(), initialCTM);
+            SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas,
+                                pict->drawablePicts(), pict->drawableCount(),
+                                layer->start() + 1, layer->stop(), initialCTM);
+
             atlasCanvas->restore();
         }
 
@@ -331,11 +328,7 @@ void GrLayerHoister::FilterLayer(GrContext* context,
 void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) {
     for (int i = 0; i < layers.count(); ++i) {
         GrCachedLayer* layer = layers[i].fLayer;
-        const SkBigPicture* pict = layers[i].fPicture->asSkBigPicture();
-        if (!pict) {
-            // TODO: can we assume / assert this?
-            continue;
-        }
+        const SkPicture* pict = layers[i].fPicture;
         const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop);
 
         // Each non-atlased layer has its own GrTexture
@@ -360,7 +353,10 @@ void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLay
         layerCanvas->setMatrix(initialCTM);
         layerCanvas->concat(layers[i].fLocalMat);
 
-        pict->partialPlayback(layerCanvas, layer->start()+1, layer->stop(), initialCTM);
+        SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas,
+                            pict->drawablePicts(), pict->drawableCount(),
+                            layer->start()+1, layer->stop(), initialCTM);
+
         layerCanvas->flush();
 
         if (layer->filter()) {
index 6f05206..dacc939 100644 (file)
@@ -8,7 +8,6 @@
 #include "GrContext.h"
 #include "GrLayerCache.h"
 #include "GrRecordReplaceDraw.h"
-#include "SkBigPicture.h"
 #include "SkCanvasPriv.h"
 #include "SkGrPixelRef.h"
 #include "SkImage.h"
@@ -46,7 +45,7 @@ static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canva
         canvas->drawBitmapRectToRect(bm, &src, dst, layer->paint());
         canvas->restore();
     } else {
-        canvas->drawSprite(bm,
+        canvas->drawSprite(bm, 
                            layer->srcIR().fLeft + layer->offset().fX,
                            layer->srcIR().fTop + layer->offset().fY,
                            layer->paint());
@@ -60,7 +59,7 @@ public:
     ReplaceDraw(SkCanvas* canvas, GrLayerCache* layerCache,
                 SkPicture const* const drawablePicts[], int drawableCount,
                 const SkPicture* topLevelPicture,
-                const SkBigPicture* picture,
+                const SkPicture* picture,
                 const SkMatrix& initialMatrix,
                 SkPicture::AbortCallback* callback,
                 const unsigned* opIndices, int numIndices)
@@ -77,8 +76,8 @@ public:
     }
 
     int draw() {
-        const SkBBoxHierarchy* bbh = fPicture->bbh();
-        const SkRecord* record = fPicture->record();
+        const SkBBoxHierarchy* bbh = fPicture->fBBH.get();
+        const SkRecord* record = fPicture->fRecord.get();
         if (NULL == record) {
             return 0;
         }
@@ -136,17 +135,13 @@ public:
 
         SkAutoCanvasMatrixPaint acmp(fCanvas, &dp.matrix, dp.paint, dp.picture->cullRect());
 
-        if (const SkBigPicture* bp = dp.picture->asSkBigPicture()) {
-            // Draw sub-pictures with the same replacement list but a different picture
-            ReplaceDraw draw(fCanvas, fLayerCache,
-                             this->drawablePicts(), this->drawableCount(),
-                             fTopLevelPicture, bp, fInitialMatrix, fCallback,
-                             fOpIndexStack.begin(), fOpIndexStack.count());
-            fNumReplaced += draw.draw();
-        } else {
-            // TODO: can we assume / assert this doesn't happen?
-            dp.picture->playback(fCanvas, fCallback);
-        }
+        // Draw sub-pictures with the same replacement list but a different picture
+        ReplaceDraw draw(fCanvas, fLayerCache, 
+                         this->drawablePicts(), this->drawableCount(),
+                         fTopLevelPicture, dp.picture, fInitialMatrix, fCallback,
+                         fOpIndexStack.begin(), fOpIndexStack.count());
+
+        fNumReplaced += draw.draw();
 
         fOpIndexStack.pop();
     }
@@ -173,7 +168,7 @@ public:
 
             draw_replacement_bitmap(layer, fCanvas);
 
-            if (fPicture->bbh()) {
+            if (fPicture->fBBH.get()) {
                 while (fOps[fIndex] < layer->stop()) {
                     ++fIndex;
                 }
@@ -195,7 +190,7 @@ private:
     SkCanvas*                 fCanvas;
     GrLayerCache*             fLayerCache;
     const SkPicture*          fTopLevelPicture;
-    const SkBigPicture*       fPicture;
+    const SkPicture*          fPicture;
     const SkMatrix            fInitialMatrix;
     SkPicture::AbortCallback* fCallback;
 
@@ -216,15 +211,9 @@ int GrRecordReplaceDraw(const SkPicture* picture,
                         SkPicture::AbortCallback* callback) {
     SkAutoCanvasRestore saveRestore(canvas, true /*save now, restore at exit*/);
 
-    if (const SkBigPicture* bp = picture->asSkBigPicture()) {
-        // TODO: drawablePicts?
-        ReplaceDraw draw(canvas, layerCache, NULL, 0,
-                         bp, bp,
-                         initialMatrix, callback, NULL, 0);
-        return draw.draw();
-    } else {
-        // TODO: can we assume / assert this doesn't happen?
-        picture->playback(canvas, callback);
-        return 0;
-    }
+    // TODO: drawablePicts?
+    ReplaceDraw draw(canvas, layerCache, NULL, 0,
+                     picture, picture,
+                     initialMatrix, callback, NULL, 0);
+    return draw.draw();
 }
index 13287c8..7a50e04 100644 (file)
@@ -1999,10 +1999,9 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture
         return false;
     }
 
-    const SkBigPicture::AccelData* data = NULL;
-    if (const SkBigPicture* bp = mainPicture->asSkBigPicture()) {
-        data = bp->accelData();
-    }
+    SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
+
+    const SkPicture::AccelData* data = mainPicture->EXPERIMENTAL_getAccelData(key);
     if (!data) {
         return false;
     }
index c1ea4fe..89959e1 100644 (file)
@@ -217,6 +217,8 @@ private:
 
     bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
 
+    static SkPicture::AccelData::Key ComputeAccelDataKey();
+
     static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&,
                                               int sampleCount);
 
diff --git a/src/utils/SkPictureUtils.cpp b/src/utils/SkPictureUtils.cpp
new file mode 100644 (file)
index 0000000..a8a251c
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBBoxHierarchy.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkPictureUtils.h"
+#include "SkRecord.h"
+#include "SkShader.h"
+
+size_t SkPictureUtils::ApproximateBytesUsed(const SkPicture* pict) {
+    size_t byteCount = sizeof(*pict);
+
+    byteCount += pict->fRecord->bytesUsed();
+    if (pict->fBBH.get()) {
+        byteCount += pict->fBBH->bytesUsed();
+    }
+    byteCount += pict->fApproxBytesUsedBySubPictures;
+
+    return byteCount;
+}
index efb1ec1..6b3084b 100644 (file)
@@ -111,10 +111,7 @@ DEF_GPUTEST(GpuLayerCache, reporter, factory) {
         }
 
         SkPictureRecorder recorder;
-        SkCanvas* c = recorder.beginRecording(1, 1);
-            // Draw something, anything, to prevent an empty-picture optimization,
-            // which is a singleton and never purged.
-            c->drawRect(SkRect::MakeWH(1,1), SkPaint());
+        recorder.beginRecording(1, 1);
         SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
 
         GrLayerCache cache(context);
index cc96b91..16d98b3 100644 (file)
@@ -363,10 +363,9 @@ static void test_savelayer_extraction(skiatest::Reporter* reporter) {
 
     // Now test out the SaveLayer extraction
     if (!SkCanvas::Internal_Private_GetIgnoreSaveLayerBounds()) {
-        const SkBigPicture* bp = pict->asSkBigPicture();
-        REPORTER_ASSERT(reporter, bp);
+        SkPicture::AccelData::Key key = SkLayerInfo::ComputeKey();
 
-        const SkBigPicture::AccelData* data = bp->accelData();
+        const SkPicture::AccelData* data = pict->EXPERIMENTAL_getAccelData(key);
         REPORTER_ASSERT(reporter, data);
 
         const SkLayerInfo *gpuData = static_cast<const SkLayerInfo*>(data);
@@ -1108,6 +1107,30 @@ static void test_gen_id(skiatest::Reporter* reporter) {
     REPORTER_ASSERT(reporter, hasData->uniqueID() != empty->uniqueID());
 }
 
+static void test_bytes_used(skiatest::Reporter* reporter) {
+    SkPictureRecorder recorder;
+
+    recorder.beginRecording(0, 0);
+    SkAutoTUnref<SkPicture> empty(recorder.endRecording());
+
+    // Sanity check to make sure we aren't under-measuring.
+    REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(empty.get()) >=
+                              sizeof(SkPicture) + sizeof(SkRecord));
+
+    // Protect against any unintentional bloat.
+    size_t approxUsed = SkPictureUtils::ApproximateBytesUsed(empty.get());
+    REPORTER_ASSERT(reporter, approxUsed <= 432);
+
+    // Sanity check of nested SkPictures.
+    SkPictureRecorder r2;
+    r2.beginRecording(0, 0);
+    r2.getRecordingCanvas()->drawPicture(empty.get());
+    SkAutoTUnref<SkPicture> nested(r2.endRecording());
+
+    REPORTER_ASSERT(reporter, SkPictureUtils::ApproximateBytesUsed(nested.get()) >=
+                              SkPictureUtils::ApproximateBytesUsed(empty.get()));
+}
+
 DEF_TEST(Picture, reporter) {
 #ifdef SK_DEBUG
     test_deleting_empty_picture();
@@ -1128,6 +1151,7 @@ DEF_TEST(Picture, reporter) {
     test_hierarchical(reporter);
     test_gen_id(reporter);
     test_savelayer_extraction(reporter);
+    test_bytes_used(reporter);
 }
 
 static void draw_bitmaps(const SkBitmap bitmap, SkCanvas* canvas) {
@@ -1243,10 +1267,7 @@ DEF_TEST(Picture_SkipBBH, r) {
     SpoonFedBBHFactory factory(&bbh);
 
     SkPictureRecorder recorder;
-    SkCanvas* c = recorder.beginRecording(bound, &factory);
-    // Record a few ops so we don't hit a small- or empty- picture optimization.
-        c->drawRect(bound, SkPaint());
-        c->drawRect(bound, SkPaint());
+    recorder.beginRecording(bound, &factory);
     SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
 
     SkCanvas big(640, 480), small(300, 200);