Reduce, reuse, recycle SNAPSHOTS!

Shaves like, 1 whole us off of reset

Change-Id: I459370448583d5e22fd302ba1353319564a814be
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index c128ca7..eca71c6 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -28,10 +28,21 @@
         , mWidth(-1)
         , mHeight(-1)
         , mSaveCount(1)
-        , mFirstSnapshot(new Snapshot)
         , mCanvas(renderer)
-        , mSnapshot(mFirstSnapshot) {
+        , mSnapshot(&mFirstSnapshot) {
+}
 
+CanvasState::~CanvasState() {
+    // First call freeSnapshot on all but mFirstSnapshot
+    // to invoke all the dtors
+    freeAllSnapshots();
+
+    // Now actually release the memory
+    while (mSnapshotPool) {
+        void* temp = mSnapshotPool;
+        mSnapshotPool = mSnapshotPool->previous;
+        free(temp);
+    }
 }
 
 void CanvasState::initializeSaveStack(
@@ -41,11 +52,12 @@
     if (mWidth != viewportWidth || mHeight != viewportHeight) {
         mWidth = viewportWidth;
         mHeight = viewportHeight;
-        mFirstSnapshot->initializeViewport(viewportWidth, viewportHeight);
+        mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
         mCanvas.onViewportInitialized();
     }
 
-    mSnapshot = new Snapshot(mFirstSnapshot,
+    freeAllSnapshots();
+    mSnapshot = allocSnapshot(&mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
     mSnapshot->setClip(clipLeft, clipTop, clipRight, clipBottom);
     mSnapshot->fbo = mCanvas.getTargetFbo();
@@ -53,6 +65,38 @@
     mSaveCount = 1;
 }
 
+Snapshot* CanvasState::allocSnapshot(Snapshot* previous, int savecount) {
+    void* memory;
+    if (mSnapshotPool) {
+        memory = mSnapshotPool;
+        mSnapshotPool = mSnapshotPool->previous;
+        mSnapshotPoolCount--;
+    } else {
+        memory = malloc(sizeof(Snapshot));
+    }
+    return new (memory) Snapshot(previous, savecount);
+}
+
+void CanvasState::freeSnapshot(Snapshot* snapshot) {
+    snapshot->~Snapshot();
+    // Arbitrary number, just don't let this grown unbounded
+    if (mSnapshotPoolCount > 10) {
+        free((void*) snapshot);
+    } else {
+        snapshot->previous = mSnapshotPool;
+        mSnapshotPool = snapshot;
+        mSnapshotPoolCount++;
+    }
+}
+
+void CanvasState::freeAllSnapshots() {
+    while (mSnapshot != &mFirstSnapshot) {
+        Snapshot* temp = mSnapshot;
+        mSnapshot = mSnapshot->previous;
+        freeSnapshot(temp);
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Save (layer)
 ///////////////////////////////////////////////////////////////////////////////
@@ -64,7 +108,7 @@
  * stack, and ensures restoreToCount() doesn't call back into subclass overrides.
  */
 int CanvasState::saveSnapshot(int flags) {
-    mSnapshot = new Snapshot(mSnapshot, flags);
+    mSnapshot = allocSnapshot(mSnapshot, flags);
     return mSaveCount++;
 }
 
@@ -76,14 +120,16 @@
  * Guaranteed to restore without side-effects.
  */
 void CanvasState::restoreSnapshot() {
-    sp<Snapshot> toRemove = mSnapshot;
-    sp<Snapshot> toRestore = mSnapshot->previous;
+    Snapshot* toRemove = mSnapshot;
+    Snapshot* toRestore = mSnapshot->previous;
 
     mSaveCount--;
     mSnapshot = toRestore;
 
     // subclass handles restore implementation
     mCanvas.onSnapshotRestored(*toRemove, *toRestore);
+
+    freeSnapshot(toRemove);
 }
 
 void CanvasState::restore() {
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index f0fb9ba..be57f44 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -17,12 +17,12 @@
 #ifndef ANDROID_HWUI_CANVAS_STATE_H
 #define ANDROID_HWUI_CANVAS_STATE_H
 
+#include "Snapshot.h"
+
 #include <SkMatrix.h>
 #include <SkPath.h>
 #include <SkRegion.h>
 
-#include "Snapshot.h"
-
 namespace android {
 namespace uirenderer {
 
@@ -74,6 +74,7 @@
 class CanvasState {
 public:
     CanvasState(CanvasStateClient& renderer);
+    ~CanvasState();
 
     /**
      * Initializes the first snapshot, computing the projection matrix,
@@ -157,11 +158,15 @@
     int getHeight() const { return mHeight; }
     bool clipIsSimple() const { return currentSnapshot()->clipIsSimple(); }
 
-    inline const Snapshot* currentSnapshot() const { return mSnapshot.get(); }
-    inline Snapshot* writableSnapshot() { return mSnapshot.get(); }
-    inline const Snapshot* firstSnapshot() const { return mFirstSnapshot.get(); }
+    inline const Snapshot* currentSnapshot() const { return mSnapshot; }
+    inline Snapshot* writableSnapshot() { return mSnapshot; }
+    inline const Snapshot* firstSnapshot() const { return &mFirstSnapshot; }
 
 private:
+    Snapshot* allocSnapshot(Snapshot* previous, int savecount);
+    void freeSnapshot(Snapshot* snapshot);
+    void freeAllSnapshots();
+
     /// indicates that the clip has been changed since the last time it was consumed
     bool mDirtyClip;
 
@@ -172,13 +177,18 @@
     int mSaveCount;
 
     /// Base state
-    sp<Snapshot> mFirstSnapshot;
+    Snapshot mFirstSnapshot;
 
     /// Host providing callbacks
     CanvasStateClient& mCanvas;
 
     /// Current state
-    sp<Snapshot> mSnapshot;
+    Snapshot* mSnapshot;
+
+    // Pool of allocated snapshots to re-use
+    // NOTE: The dtors have already been invoked!
+    Snapshot* mSnapshotPool = nullptr;
+    int mSnapshotPoolCount = 0;
 
 }; // class CanvasState
 
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 4d60b8d..0a58f4b 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -44,7 +44,7 @@
  * Copies the specified snapshot/ The specified snapshot is stored as
  * the previous snapshot.
  */
-Snapshot::Snapshot(const sp<Snapshot>& s, int saveFlags)
+Snapshot::Snapshot(Snapshot* s, int saveFlags)
         : flags(0)
         , previous(s)
         , layer(s->layer)
@@ -148,7 +148,7 @@
     const Snapshot* current = this;
     do {
         snapshotList.push(current);
-        current = current->previous.get();
+        current = current->previous;
     } while (current);
 
     // traverse the list, adding in each transform that contributes to the total transform
@@ -240,7 +240,7 @@
 
 void Snapshot::dump() const {
     ALOGD("Snapshot %p, flags %x, prev %p, height %d, ignored %d, hasComplexClip %d",
-            this, flags, previous.get(), getViewportHeight(), isIgnored(), !mClipArea->isSimple());
+            this, flags, previous, getViewportHeight(), isIgnored(), !mClipArea->isSimple());
     const Rect& clipRect(mClipArea->getClipRect());
     ALOGD("  ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
             clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index cf8f11c..aeeda96 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -83,11 +83,11 @@
  * Each snapshot has a link to a previous snapshot, indicating the previous
  * state of the renderer.
  */
-class Snapshot: public LightRefBase<Snapshot> {
+class Snapshot {
 public:
 
     Snapshot();
-    Snapshot(const sp<Snapshot>& s, int saveFlags);
+    Snapshot(Snapshot* s, int saveFlags);
 
     /**
      * Various flags set on ::flags.
@@ -229,7 +229,7 @@
     /**
      * Previous snapshot.
      */
-    sp<Snapshot> previous;
+    Snapshot* previous;
 
     /**
      * A pointer to the currently active layer.