Optimizing display lists by referencing pointers to resources instead of copying them

Change-Id: I81ad3551d74aa1e5bb64d69e33d2eb29a6c1eb6a
diff --git a/core/java/android/animation/TimeInterpolator.java b/core/java/android/animation/TimeInterpolator.java
index 8d795a8..0f5d8bf 100644
--- a/core/java/android/animation/TimeInterpolator.java
+++ b/core/java/android/animation/TimeInterpolator.java
@@ -23,7 +23,7 @@
 public interface TimeInterpolator {
 
     /**
-     * Maps a value representing the elapsed fraciton of an animation to a value that represents
+     * Maps a value representing the elapsed fraction of an animation to a value that represents
      * the interpolated fraction. This interpolated value is then multiplied by the change in
      * value of an animation to derive the animated value at the current elapsed animation time.
      *
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index 79754b8..d60a598 100755
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -523,7 +523,6 @@
             for (int i = 0; i < numValues; ++i) {
                 mValues[i].init();
             }
-            mCurrentIteration = 0;
             mInitialized = true;
         }
     }
@@ -933,6 +932,7 @@
             // This sets the initial value of the animation, prior to actually starting it running
             setCurrentPlayTime(getCurrentPlayTime());
         }
+        mCurrentIteration = 0;
         mPlayingState = STOPPED;
         mStartedDelay = false;
         sPendingAnimations.add(this);
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index b1160f0..e7c2231 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -39,12 +39,6 @@
     abstract void end();
 
     /**
-     * Frees resources taken by this display list. This method must be called
-     * before releasing all references.
-     */
-    abstract void destroy();
-
-    /**
      * Indicates whether this display list can be replayed or not.
      * 
      * @return True if the display list can be replayed, false otherwise.
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index d78c68a..5d9bd1e 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -34,6 +34,11 @@
 import android.text.SpannableString;
 import android.text.SpannedString;
 import android.text.TextUtils;
+import android.util.Finalizers;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * An implementation of Canvas on top of OpenGL ES 2.0.
@@ -84,22 +89,35 @@
        
         if (mRenderer == 0) {
             throw new IllegalStateException("Could not create GLES20Canvas renderer");
+        } else {
+            new CanvasFinalizer(this);
         }
     }
 
     private native int nCreateRenderer();    
     private native int nCreateDisplayListRenderer();    
 
-    @Override
-    public synchronized void destroy() {
-        if (mRenderer != 0) {
+    private static native void nDestroyRenderer(int renderer);
+
+    private static class CanvasFinalizer extends Finalizers.ReclaimableReference<GLES20Canvas> {
+        private static final Set<CanvasFinalizer> sFinalizers = Collections.synchronizedSet(
+                new HashSet<CanvasFinalizer>());
+
+        private int mRenderer;
+
+        CanvasFinalizer(GLES20Canvas canvas) {
+            super(canvas, Finalizers.getQueue());
+            mRenderer = canvas.mRenderer;
+            sFinalizers.add(this);
+        }
+
+        @Override
+        public void reclaim() {
             nDestroyRenderer(mRenderer);
-            mRenderer = 0;
+            sFinalizers.remove(this);
         }
     }
 
-    private native void nDestroyRenderer(int renderer);
-
     ///////////////////////////////////////////////////////////////////////////
     // Canvas management
     ///////////////////////////////////////////////////////////////////////////
@@ -178,11 +196,11 @@
 
     private native int nCreateDisplayList(int renderer);
     
-    void destroyDisplayList(int displayList) {
+    static void destroyDisplayList(int displayList) {
         nDestroyDisplayList(displayList);
     }
 
-    private native void nDestroyDisplayList(int displayList);
+    private static native void nDestroyDisplayList(int displayList);
 
     @Override
     public void drawDisplayList(DisplayList displayList) {
diff --git a/core/java/android/view/GLES20DisplayList.java b/core/java/android/view/GLES20DisplayList.java
index 2886bf3..11e6d30 100644
--- a/core/java/android/view/GLES20DisplayList.java
+++ b/core/java/android/view/GLES20DisplayList.java
@@ -16,6 +16,12 @@
 
 package android.view;
 
+import android.util.Finalizers;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
 /**
  * An implementation of display list for OpenGL ES 2.0.
  */
@@ -33,8 +39,6 @@
             throw new IllegalStateException("Recording has already started");
         }
 
-        destroyCanvas();
-
         mCanvas = new GLES20Canvas(true, true);
         mStarted = true;
         mRecorded = false;
@@ -42,16 +46,6 @@
         return mCanvas;
     }
 
-    private void destroyCanvas() {
-        if (mCanvas != null) {
-            mCanvas.destroyDisplayList(mNativeDisplayList);
-            mCanvas.destroy();
-
-            mCanvas = null;
-            mNativeDisplayList = 0;
-        }
-    }
-
     @Override
     void end() {
         if (mCanvas != null) {
@@ -59,16 +53,31 @@
             mRecorded = true;
 
             mNativeDisplayList = mCanvas.getDisplayList();
+            new DisplayListFinalizer(this);
         }
     }
 
     @Override
-    void destroy() {
-        destroyCanvas();
-    }
-
-    @Override
     boolean isReady() {
         return !mStarted && mRecorded;
     }
+
+    private static class DisplayListFinalizer extends Finalizers.ReclaimableReference<DisplayList> {
+        private static final Set<DisplayListFinalizer> sFinalizers = Collections.synchronizedSet(
+                new HashSet<DisplayListFinalizer>());
+
+        private int mNativeDisplayList;
+
+        DisplayListFinalizer(GLES20DisplayList displayList) {
+            super(displayList, Finalizers.getQueue());
+            mNativeDisplayList = displayList.mNativeDisplayList;
+            sFinalizers.add(this);
+        }
+
+        @Override
+        public void reclaim() {
+            GLES20Canvas.destroyDisplayList(mNativeDisplayList);
+            sFinalizers.remove(this);
+        }
+    }
 }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 22d2fe6..8b8d15e 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -34,14 +34,6 @@
     }
     
     /**
-     * This method <strong>must</strong> be called before releasing a
-     * reference to a hardware canvas. This method is responsible for
-     * freeing native resources associated with the hardware. Not
-     * invoking this method properly can result in memory leaks.
-     */    
-    public abstract void destroy();
-
-    /**
      * Invoked before any drawing operation is performed in this canvas.
      */
     abstract void onPreDraw();
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 0247f6a..6f4abef 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -414,7 +414,6 @@
         @Override
         void destroy(boolean full) {
             if (full && mCanvas != null) {
-                mCanvas.destroy();
                 mCanvas = null;
             }
             
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index baa749a..0456463 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7417,7 +7417,6 @@
         if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) {
             return null;
         }
-        
         if (mAttachInfo == null || mAttachInfo.mHardwareRenderer == null) {
             return null;
         }
@@ -7425,10 +7424,6 @@
         if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED &&
                 ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDisplayList == null)) {
 
-            if (mDisplayList != null) {
-                mDisplayList.destroy();
-            }
-
             mDisplayList = mAttachInfo.mHardwareRenderer.createDisplayList();
 
             final HardwareCanvas canvas = mDisplayList.start();
@@ -7456,8 +7451,6 @@
                 canvas.onPostDraw();
 
                 mDisplayList.end();
-
-                canvas.destroy();                
             }
         }
 
@@ -7532,7 +7525,6 @@
             mUnscaledDrawingCache = null;
         }
         if (mDisplayList != null) {
-            mDisplayList.destroy();
             mDisplayList = null;
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index f34fd63..7b2703b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1700,10 +1700,10 @@
         }
         return false;
     }
-    
+
     /**
      * {@inheritDoc}
-     * 
+     *
      * @hide
      */
     @Override
@@ -1715,10 +1715,10 @@
             children[i].dispatchStartTemporaryDetach();
         }
     }
-    
+
     /**
      * {@inheritDoc}
-     * 
+     *
      * @hide
      */
     @Override
@@ -1915,7 +1915,7 @@
         if (skipChildren) {
             for (int i = 0; i < count; i++) {
                 getChildAt(i).setVisibility(visibilities[i]);
-            }        
+            }
         }
 
         return b;
@@ -2045,7 +2045,7 @@
      *
      * @param i The current iteration.
      * @return The index of the child to draw this iteration.
-     * 
+     *
      * @see #setChildrenDrawingOrderEnabled(boolean)
      * @see #isChildrenDrawingOrderEnabled()
      */
@@ -2186,7 +2186,7 @@
                 (child.mPrivateFlags & DRAW_ANIMATION) == 0) {
             return more;
         }
-        
+
         float alpha = child.getAlpha();
         // Bail out early if the view does not need to be drawn
         if (alpha <= ViewConfiguration.ALPHA_THRESHOLD && (child.mPrivateFlags & ALPHA_SET) == 0 &&
@@ -2360,7 +2360,7 @@
         final View[] children = mChildren;
         final int count = mChildrenCount;
         for (int i = 0; i < count; i++) {
-            
+
             children[i].setSelected(selected);
         }
     }
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 880fb6e..f8a80b0 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -255,14 +255,21 @@
 static void Bitmap_destructor(JNIEnv* env, jobject, SkBitmap* bitmap) {

 #ifdef USE_OPENGL_RENDERER

     if (android::uirenderer::Caches::hasInstance()) {

-        android::uirenderer::Caches::getInstance().textureCache.remove(bitmap);

+        android::uirenderer::Caches::getInstance().resourceCache.destructor(bitmap);

     }

-#endif

+#else // !USE_OPENGL_RENDERER

     delete bitmap;

+#endif

 }

 

 static void Bitmap_recycle(JNIEnv* env, jobject, SkBitmap* bitmap) {

+#ifdef USE_OPENGL_RENDERER

+    if (android::uirenderer::Caches::hasInstance()) {

+        android::uirenderer::Caches::getInstance().resourceCache.recycle(bitmap);

+    }

+#else // !USE_OPENGL_RENDERER

     bitmap->setPixels(NULL, NULL);

+#endif // USE_OPENGL_RENDERER

 }

 

 // These must match the int values in Bitmap.java

diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index cafceab..6667756 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -15,11 +15,6 @@
 ** limitations under the License.
 */
 
-// This file was generated from the C++ include file: SkMatrix.h
-// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, 
-// or one of the auxilary file specifications in device/tools/gluemaker.
-
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -29,13 +24,21 @@
 
 #include "Matrix.h"
 
+#include <Caches.h>
+
 namespace android {
 
 class SkMatrixGlue {
 public:
 
     static void finalizer(JNIEnv* env, jobject clazz, SkMatrix* obj) {
+#ifdef USE_OPENGL_RENDERER
+        if (android::uirenderer::Caches::hasInstance()) {
+            android::uirenderer::Caches::getInstance().resourceCache.destructor(obj);
+        }
+#else // !USE_OPENGL_RENDERER
         delete obj;
+#endif
     }
 
     static SkMatrix* create(JNIEnv* env, jobject clazz, const SkMatrix* src) {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index ca9f371..339c1a4 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -15,11 +15,6 @@
 ** limitations under the License.
 */
 
-// This file was generated from the C++ include file: SkPaint.h
-// Any changes made to this file will be discarded by the build.
-// To change this file, either edit the include, or device/tools/gluemaker/main.cpp, 
-// or one of the auxilary file specifications in device/tools/gluemaker.
-
 #include "jni.h"
 #include "GraphicsJNI.h"
 #include <android_runtime/AndroidRuntime.h>
@@ -35,6 +30,7 @@
 #include "TextLayout.h"
 
 // temporary for debugging
+#include <Caches.h>
 #include <utils/Log.h>
 
 namespace android {
@@ -67,7 +63,13 @@
     };
 
     static void finalizer(JNIEnv* env, jobject clazz, SkPaint* obj) {
+#ifdef USE_OPENGL_RENDERER
+        if (android::uirenderer::Caches::hasInstance()) {
+            android::uirenderer::Caches::getInstance().resourceCache.destructor(obj);
+        }
+#else // !USE_OPENGL_RENDERER
         delete obj;
+#endif
     }
 
     static SkPaint* init(JNIEnv* env, jobject clazz) {
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index ee44747..79051c2 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -53,13 +53,13 @@
 
 static void Shader_destructor(JNIEnv* env, jobject o, SkShader* shader, SkiaShader* skiaShader)
 {
+    shader->safeUnref();
+    // skiaShader == NULL when not !USE_OPENGL_RENDERER, so no need to delete it outside the ifdef
 #ifdef USE_OPENGL_RENDERER
     if (android::uirenderer::Caches::hasInstance()) {
-        android::uirenderer::Caches::getInstance().gradientCache.remove(shader);
+        android::uirenderer::Caches::getInstance().resourceCache.destructor(skiaShader);
     }
 #endif
-    delete skiaShader;
-    shader->safeUnref();
 }
 
 static bool Shader_getLocalMatrix(JNIEnv* env, jobject, const SkShader* shader, SkMatrix* matrix)
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index cfa9a27..6d848a4 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -87,7 +87,7 @@
 #endif
 }
 
-static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject canvas,
+static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer) {
     RENDERER_LOGD("Destroy OpenGLRenderer");
     delete renderer;
@@ -415,7 +415,7 @@
 }
 
 static void android_view_GLES20Canvas_destroyDisplayList(JNIEnv* env,
-        jobject canvas, DisplayList* displayList) {
+        jobject clazz, DisplayList* displayList) {
     delete displayList;
 }
 
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 5bf0ccc..f314b09 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -20,6 +20,7 @@
 		PathCache.cpp \
 		Program.cpp \
 		ProgramCache.cpp \
+		ResourceCache.cpp \
 		SkiaColorFilter.cpp \
 		SkiaShader.cpp \
 		TextureCache.cpp \
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index e6e494d..0c704da 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -34,6 +34,7 @@
 #include "TextDropShadowCache.h"
 #include "FboCache.h"
 #include "Line.h"
+#include "ResourceCache.h"
 
 namespace android {
 namespace uirenderer {
@@ -138,6 +139,7 @@
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
     GammaFontRenderer fontRenderer;
+    ResourceCache resourceCache;
 
     Line line;
 }; // class Caches
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index b3517c4..a43f164 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -100,39 +100,31 @@
     mTFPlayback.reset(&recorder.mTFRecorder);
     mTFPlayback.setupBuffer(mReader);
 
-    const SkTDArray<const SkFlatBitmap*>& bitmaps = recorder.getBitmaps();
-    mBitmapCount = bitmaps.count();
-    if (mBitmapCount > 0) {
-        mBitmaps = new SkBitmap[mBitmapCount];
-        for (const SkFlatBitmap** flatBitmapPtr = bitmaps.begin();
-                flatBitmapPtr != bitmaps.end(); flatBitmapPtr++) {
-            const SkFlatBitmap* flatBitmap = *flatBitmapPtr;
-            int index = flatBitmap->index() - 1;
-            flatBitmap->unflatten(&mBitmaps[index], &mRCPlayback);
-        }
-    }
+    Caches& caches = Caches::getInstance();
 
-    const SkTDArray<const SkFlatMatrix*>& matrices = recorder.getMatrices();
-    mMatrixCount = matrices.count();
-    if (mMatrixCount > 0) {
-        mMatrices = new SkMatrix[mMatrixCount];
-        for (const SkFlatMatrix** matrixPtr = matrices.begin();
-                matrixPtr != matrices.end(); matrixPtr++) {
-            const SkFlatMatrix* flatMatrix = *matrixPtr;
-            flatMatrix->unflatten(&mMatrices[flatMatrix->index() - 1]);
-        }
+    const Vector<SkBitmap*> &bitmapResources = recorder.getBitmapResources();
+    for (size_t i = 0; i < bitmapResources.size(); i++) {
+        SkBitmap* resource = bitmapResources.itemAt(i);
+        mBitmapResources.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
     }
-
-    const SkTDArray<const SkFlatPaint*>& paints = recorder.getPaints();
-    mPaintCount = paints.count();
-    if (mPaintCount > 0) {
-        mPaints = new SkPaint[mPaintCount];
-        for (const SkFlatPaint** flatPaintPtr = paints.begin();
-                flatPaintPtr != paints.end(); flatPaintPtr++) {
-            const SkFlatPaint* flatPaint = *flatPaintPtr;
-            int index = flatPaint->index() - 1;
-            flatPaint->unflatten(&mPaints[index], &mRCPlayback, &mTFPlayback);
-        }
+    const Vector<SkMatrix*> &matrixResources = recorder.getMatrixResources();
+    for (size_t i = 0; i < matrixResources.size(); i++) {
+        SkMatrix* resource = matrixResources.itemAt(i);
+        mMatrixResources.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
+    }
+    const Vector<SkPaint*> &paintResources = recorder.getPaintResources();
+    for (size_t i = 0; i < paintResources.size(); i++) {
+        SkPaint* resource = paintResources.itemAt(i);
+        mPaintResources.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
+    }
+    const Vector<SkiaShader*> &shaderResources = recorder.getShaderResources();
+    for (size_t i = 0; i < shaderResources.size(); i++) {
+        SkiaShader* resource = shaderResources.itemAt(i);
+        mShaderResources.add(resource);
+        caches.resourceCache.incrementRefcount(resource);
     }
 
     mPathHeap = recorder.mPathHeap;
@@ -143,23 +135,32 @@
     sk_free((void*) mReader.base());
 
     Caches& caches = Caches::getInstance();
-    for (int i = 0; i < mBitmapCount; i++) {
-        caches.textureCache.remove(&mBitmaps[i]);
+
+    for (size_t i = 0; i < mBitmapResources.size(); i++) {
+        SkBitmap* resource = mBitmapResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
     }
-
-    delete[] mBitmaps;
-    delete[] mMatrices;
-    delete[] mPaints;
-
+    mBitmapResources.clear();
+    for (size_t i = 0; i < mMatrixResources.size(); i++) {
+        SkMatrix* resource = mMatrixResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mMatrixResources.clear();
+    for (size_t i = 0; i < mPaintResources.size(); i++) {
+        SkPaint* resource = mPaintResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mPaintResources.clear();
+    for (size_t i = 0; i < mShaderResources.size(); i++) {
+        SkiaShader* resource = mShaderResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mShaderResources.clear();
     mPathHeap->safeUnref();
 }
 
 void DisplayList::init() {
-    mBitmaps = NULL;
-    mMatrices = NULL;
-    mPaints = NULL;
     mPathHeap = NULL;
-    mBitmapCount = mMatrixCount = mPaintCount = 0;
 }
 
 void DisplayList::replay(OpenGLRenderer& renderer) {
@@ -280,7 +281,7 @@
             }
             break;
             case SetupShader: {
-                // TODO: Implement
+                renderer.setupShader(getShader());
             }
             break;
             case ResetColorFilter: {
@@ -309,7 +310,6 @@
 
 DisplayListRenderer::DisplayListRenderer():
         mHeap(HEAP_BLOCK_SIZE), mWriter(MIN_WRITER_SIZE) {
-    mBitmapIndex = mMatrixIndex = mPaintIndex = 1;
     mPathHeap = NULL;
 }
 
@@ -323,15 +323,33 @@
         mPathHeap = NULL;
     }
 
-    mBitmaps.reset();
-    mMatrices.reset();
-    mPaints.reset();
-
     mWriter.reset();
     mHeap.reset();
 
     mRCRecorder.reset();
     mTFRecorder.reset();
+
+    Caches& caches = Caches::getInstance();
+    for (size_t i = 0; i < mBitmapResources.size(); i++) {
+        SkBitmap* resource = mBitmapResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mBitmapResources.clear();
+    for (size_t i = 0; i < mMatrixResources.size(); i++) {
+        SkMatrix* resource = mMatrixResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mMatrixResources.clear();
+    for (size_t i = 0; i < mPaintResources.size(); i++) {
+        SkPaint* resource = mPaintResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mPaintResources.clear();
+    for (size_t i = 0; i < mShaderResources.size(); i++) {
+        SkiaShader* resource = mShaderResources.itemAt(i);
+        caches.resourceCache.decrementRefcount(resource);
+    }
+    mShaderResources.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -380,7 +398,7 @@
 }
 
 int DisplayListRenderer::saveLayer(float left, float top, float right, float bottom,
-        const SkPaint* p, int flags) {
+        SkPaint* p, int flags) {
     addOp(DisplayList::SaveLayer);
     addBounds(left, top, right, bottom);
     addPaint(p);
@@ -427,15 +445,15 @@
 }
 
 void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
+        SkPaint* paint) {
     addOp(DisplayList::DrawBitmap);
     addBitmap(bitmap);
     addPoint(left, top);
     addPaint(paint);
 }
 
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix,
-        const SkPaint* paint) {
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
+        SkPaint* paint) {
     addOp(DisplayList::DrawBitmapMatrix);
     addBitmap(bitmap);
     addMatrix(matrix);
@@ -444,7 +462,7 @@
 
 void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
-        float dstRight, float dstBottom, const SkPaint* paint) {
+        float dstRight, float dstBottom, SkPaint* paint) {
     addOp(DisplayList::DrawBitmapRect);
     addBitmap(bitmap);
     addBounds(srcLeft, srcTop, srcRight, srcBottom);
@@ -454,7 +472,7 @@
 
 void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
+        float left, float top, float right, float bottom, SkPaint* paint) {
     addOp(DisplayList::DrawPatch);
     addBitmap(bitmap);
     addInts(xDivs, width);
@@ -471,7 +489,7 @@
 }
 
 void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
-        const SkPaint* paint) {
+        SkPaint* paint) {
     addOp(DisplayList::DrawRect);
     addBounds(left, top, right, bottom);
     addPaint(paint);
@@ -483,7 +501,7 @@
     addPaint(paint);
 }
 
-void DisplayListRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
     addOp(DisplayList::DrawLines);
     addFloats(points, count);
     addPaint(paint);
@@ -504,8 +522,8 @@
 }
 
 void DisplayListRenderer::setupShader(SkiaShader* shader) {
-    // TODO: Implement
-    OpenGLRenderer::setupShader(shader);
+    addOp(DisplayList::SetupShader);
+    addShader(shader);
 }
 
 void DisplayListRenderer::resetColorFilter() {
@@ -531,58 +549,5 @@
     OpenGLRenderer::setupShadow(radius, dx, dy, color);
 }
 
-///////////////////////////////////////////////////////////////////////////////
-// Recording management
-///////////////////////////////////////////////////////////////////////////////
-
-int DisplayListRenderer::find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint) {
-    if (paint == NULL) {
-        return 0;
-    }
-
-    SkFlatPaint* flat = SkFlatPaint::Flatten(&mHeap, *paint, mPaintIndex,
-            &mRCRecorder, &mTFRecorder);
-    int index = SkTSearch<SkFlatData>((const SkFlatData**) paints.begin(),
-            paints.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
-    if (index >= 0) {
-        (void) mHeap.unalloc(flat);
-        return paints[index]->index();
-    }
-
-    index = ~index;
-    *paints.insert(index) = flat;
-    return mPaintIndex++;
-}
-
-int DisplayListRenderer::find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix) {
-    if (matrix == NULL) {
-        return 0;
-    }
-
-    SkFlatMatrix* flat = SkFlatMatrix::Flatten(&mHeap, *matrix, mMatrixIndex);
-    int index = SkTSearch<SkFlatData>((const SkFlatData**) matrices.begin(),
-            matrices.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
-    if (index >= 0) {
-        (void) mHeap.unalloc(flat);
-        return matrices[index]->index();
-    }
-    index = ~index;
-    *matrices.insert(index) = flat;
-    return mMatrixIndex++;
-}
-
-int DisplayListRenderer::find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap) {
-    SkFlatBitmap* flat = SkFlatBitmap::Flatten(&mHeap, bitmap, mBitmapIndex, &mRCRecorder);
-    int index = SkTSearch<SkFlatData>((const SkFlatData**) bitmaps.begin(),
-            bitmaps.count(), (SkFlatData*) flat, sizeof(flat), &SkFlatData::Compare);
-    if (index >= 0) {
-        (void) mHeap.unalloc(flat);
-        return bitmaps[index]->index();
-    }
-    index = ~index;
-    *bitmaps.insert(index) = flat;
-    return mBitmapIndex++;
-}
-
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 9e6d5b1..c8cd801 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -128,8 +128,11 @@
     };
 
     SkBitmap* getBitmap() {
-        int index = getInt();
-        return &mBitmaps[index - 1];
+        return (SkBitmap*) getInt();
+    }
+
+    SkiaShader* getShader() {
+        return (SkiaShader*) getInt();
     }
 
     inline int getIndex() {
@@ -141,11 +144,7 @@
     }
 
     SkMatrix* getMatrix() {
-        int index = getInt();
-        if (index == 0) {
-            return NULL;
-        }
-        return &mMatrices[index - 1];
+        return (SkMatrix*) getInt();
     }
 
     SkPath* getPath() {
@@ -153,11 +152,7 @@
     }
 
     SkPaint* getPaint() {
-        int index = getInt();
-        if (index == 0) {
-            return NULL;
-        }
-        return &mPaints[index - 1];
+        return (SkPaint*) getInt();
     }
 
     inline float getFloat() {
@@ -186,14 +181,10 @@
 
     PathHeap* mPathHeap;
 
-    SkBitmap* mBitmaps;
-    int mBitmapCount;
-
-    SkMatrix* mMatrices;
-    int mMatrixCount;
-
-    SkPaint* mPaints;
-    int mPaintCount;
+    Vector<SkBitmap*> mBitmapResources;
+    Vector<SkMatrix*> mMatrixResources;
+    Vector<SkPaint*> mPaintResources;
+    Vector<SkiaShader*> mShaderResources;
 
     mutable SkFlattenableReadBuffer mReader;
 
@@ -224,7 +215,7 @@
     void restoreToCount(int saveCount);
 
     int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* p, int flags);
+            SkPaint* p, int flags);
 
     void translate(float dx, float dy);
     void rotate(float degrees);
@@ -235,18 +226,18 @@
 
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
+            float dstRight, float dstBottom, SkPaint* paint);
     void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
             const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, const SkPaint* paint);
+            float left, float top, float right, float bottom, SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, const SkPaint* paint);
+    void drawLines(float* points, int count, SkPaint* paint);
     void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
 
     void resetShader();
@@ -268,16 +259,20 @@
         return mWriter;
     }
 
-    const SkTDArray<const SkFlatBitmap*>& getBitmaps() const {
-        return mBitmaps;
+    const Vector<SkBitmap*>& getBitmapResources() const {
+        return mBitmapResources;
     }
 
-    const SkTDArray<const SkFlatMatrix*>& getMatrices() const {
-        return mMatrices;
+    const Vector<SkMatrix*>& getMatrixResources() const {
+        return mMatrixResources;
     }
 
-    const SkTDArray<const SkFlatPaint*>& getPaints() const {
-        return mPaints;
+    const Vector<SkPaint*>& getPaintResources() const {
+        return mPaintResources;
+    }
+
+    const Vector<SkiaShader*>& getShaderResources() const {
+        return mShaderResources;
     }
 
 private:
@@ -338,34 +333,40 @@
         addInt(mPathHeap->append(*path));
     }
 
-    int find(SkTDArray<const SkFlatPaint*>& paints, const SkPaint* paint);
-
-    inline void addPaint(const SkPaint* paint) {
-        addInt(find(mPaints, paint));
+    inline void addPaint(SkPaint* paint) {
+        addInt((int)paint);
+        mPaintResources.add(paint);
+        Caches& caches = Caches::getInstance();
+        caches.resourceCache.incrementRefcount(paint);
     }
 
-    int find(SkTDArray<const SkFlatMatrix*>& matrices, const SkMatrix* matrix);
-
-    inline void addMatrix(const SkMatrix* matrix) {
-        addInt(find(mMatrices, matrix));
+    inline void addMatrix(SkMatrix* matrix) {
+        addInt((int)matrix);
+        mMatrixResources.add(matrix);
+        Caches& caches = Caches::getInstance();
+        caches.resourceCache.incrementRefcount(matrix);
     }
 
-    int find(SkTDArray<const SkFlatBitmap*>& bitmaps, const SkBitmap& bitmap);
+    inline void addBitmap(SkBitmap* bitmap) {
+        addInt((int)bitmap);
+        mBitmapResources.add(bitmap);
+        Caches& caches = Caches::getInstance();
+        caches.resourceCache.incrementRefcount(bitmap);
+    }
 
-    inline void addBitmap(const SkBitmap* bitmap) {
-        addInt(find(mBitmaps, *bitmap));
+    inline void addShader(SkiaShader* shader) {
+        addInt((int)shader);
+        mShaderResources.add(shader);
+        Caches& caches = Caches::getInstance();
+        caches.resourceCache.incrementRefcount(shader);
     }
 
     SkChunkAlloc mHeap;
 
-    int mBitmapIndex;
-    SkTDArray<const SkFlatBitmap*> mBitmaps;
-
-    int mMatrixIndex;
-    SkTDArray<const SkFlatMatrix*> mMatrices;
-
-    int mPaintIndex;
-    SkTDArray<const SkFlatPaint*> mPaints;
+    Vector<SkBitmap*> mBitmapResources;
+    Vector<SkMatrix*> mMatrixResources;
+    Vector<SkPaint*> mPaintResources;
+    Vector<SkiaShader*> mShaderResources;
 
     PathHeap* mPathHeap;
     SkWriter32 mWriter;
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
index d492e23..fe75ca2 100644
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ b/libs/hwui/OpenGLDebugRenderer.cpp
@@ -42,21 +42,21 @@
 }
 
 int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom,
-        const SkPaint* p, int flags) {
+        SkPaint* p, int flags) {
     mPrimitivesCount++;
     StopWatch w("saveLayer");
     return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
 }
 
 void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        const SkPaint* paint) {
+        SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawBitmap");
     OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
 }
 
-void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix,
-        const SkPaint* paint) {
+void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
+        SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawBitmapMatrix");
     OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
@@ -64,7 +64,7 @@
 
 void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
-        float dstRight, float dstBottom, const SkPaint* paint) {
+        float dstRight, float dstBottom, SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawBitmapRect");
     OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
@@ -73,7 +73,7 @@
 
 void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
+        float left, float top, float right, float bottom, SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawPatch");
     OpenGLRenderer::drawPatch(bitmap, xDivs, yDivs, colors, width, height, numColors,
@@ -87,7 +87,7 @@
 }
 
 void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom,
-        const SkPaint* paint) {
+        SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawRect");
     OpenGLRenderer::drawRect(left, top, right, bottom, paint);
@@ -99,7 +99,7 @@
     OpenGLRenderer::drawPath(path, paint);
 }
 
-void OpenGLDebugRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+void OpenGLDebugRenderer::drawLines(float* points, int count, SkPaint* paint) {
     mPrimitivesCount++;
     StopWatch w("drawLines");
     OpenGLRenderer::drawLines(points, count, paint);
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index 4997ef3..ce6a4aa 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -38,20 +38,20 @@
     void finish();
 
     int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* p, int flags);
+            SkPaint* p, int flags);
 
-    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
+            float dstRight, float dstBottom, SkPaint* paint);
     void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
             const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, const SkPaint* paint);
+            float left, float top, float right, float bottom, SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
     void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, const SkPaint* paint);
+    void drawLines(float* points, int count, SkPaint* paint);
     void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint);
 
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 633d778..17ef598 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -252,7 +252,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
-        const SkPaint* p, int flags) {
+        SkPaint* p, int flags) {
     const GLuint previousFbo = mSnapshot->fbo;
     const int count = saveSnapshot(flags);
 
@@ -623,7 +623,7 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
-void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
+void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
     const float right = left + bitmap->width();
     const float bottom = top + bitmap->height();
 
@@ -639,7 +639,7 @@
     drawTextureRect(left, top, right, bottom, texture, paint);
 }
 
-void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint) {
+void OpenGLRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
     Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
     const mat4 transform(*matrix);
     transform.mapRect(r);
@@ -659,7 +659,7 @@
 void OpenGLRenderer::drawBitmap(SkBitmap* bitmap,
          float srcLeft, float srcTop, float srcRight, float srcBottom,
          float dstLeft, float dstTop, float dstRight, float dstBottom,
-         const SkPaint* paint) {
+         SkPaint* paint) {
     if (quickReject(dstLeft, dstTop, dstRight, dstBottom)) {
         return;
     }
@@ -693,7 +693,7 @@
 
 void OpenGLRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-        float left, float top, float right, float bottom, const SkPaint* paint) {
+        float left, float top, float right, float bottom, SkPaint* paint) {
     if (quickReject(left, top, right, bottom)) {
         return;
     }
@@ -719,7 +719,7 @@
     }
 }
 
-void OpenGLRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+void OpenGLRenderer::drawLines(float* points, int count, SkPaint* paint) {
     if (mSnapshot->invisible) return;
 
     int alpha;
@@ -791,7 +791,7 @@
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode, true);
 }
 
-void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
+void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
     if (quickReject(left, top, right, bottom)) {
         return;
     }
@@ -1206,7 +1206,7 @@
 }
 
 void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
-        const Texture* texture, const SkPaint* paint) {
+        const Texture* texture, SkPaint* paint) {
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
@@ -1334,7 +1334,7 @@
     TextureVertex::setUV(v++, u2, v2);
 }
 
-void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
+void OpenGLRenderer::getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode) {
     if (paint) {
         if (!mExtensions.hasFramebufferFetch()) {
             const bool isMode = SkXfermode::IsMode(paint->getXfermode(), mode);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 1d8a3d9..b7615fe 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -79,7 +79,7 @@
     virtual void restoreToCount(int saveCount);
 
     virtual int saveLayer(float left, float top, float right, float bottom,
-            const SkPaint* p, int flags);
+            SkPaint* p, int flags);
     virtual int saveLayerAlpha(float left, float top, float right, float bottom,
             int alpha, int flags);
 
@@ -96,18 +96,18 @@
     bool quickReject(float left, float top, float right, float bottom);
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    virtual void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
-    virtual void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
+    virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop,
-            float dstRight, float dstBottom, const SkPaint* paint);
+            float dstRight, float dstBottom, SkPaint* paint);
     virtual void drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
             const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
-            float left, float top, float right, float bottom, const SkPaint* paint);
+            float left, float top, float right, float bottom, SkPaint* paint);
     virtual void drawColor(int color, SkXfermode::Mode mode);
-    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    virtual void drawRect(float left, float top, float right, float bottom, SkPaint* paint);
     virtual void drawPath(SkPath* path, SkPaint* paint);
-    virtual void drawLines(float* points, int count, const SkPaint* paint);
+    virtual void drawLines(float* points, int count, SkPaint* paint);
     virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
             SkPaint* paint);
 
@@ -231,7 +231,7 @@
      * @param paint The paint containing the alpha, blending mode, etc.
      */
     void drawTextureRect(float left, float top, float right, float bottom,
-            const Texture* texture, const SkPaint* paint);
+            const Texture* texture, SkPaint* paint);
 
     /**
      * Draws a textured mesh with the specified texture. If the indices are omitted,
@@ -357,7 +357,7 @@
      * @param alpha Where to store the resulting alpha
      * @param mode Where to store the resulting xfermode
      */
-    inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
+    inline void getAlphaAndMode(SkPaint* paint, int* alpha, SkXfermode::Mode* mode);
 
     /**
      * Binds the specified texture with the specified wrap modes.
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
new file mode 100644
index 0000000..20b8d6c
--- /dev/null
+++ b/libs/hwui/ResourceCache.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <SkPixelRef.h>
+#include "ResourceCache.h"
+#include "Caches.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Resource cache
+///////////////////////////////////////////////////////////////////////////////
+
+void ResourceCache::logCache() {
+    LOGD("ResourceCache: cacheReport:");
+    for (size_t i = 0; i < mCache->size(); ++i) {
+        ResourceReference* ref = mCache->valueAt(i);
+        LOGD("  ResourceCache: mCache(%d): resource, ref = 0x%p, 0x%p",
+                i, mCache->keyAt(i), mCache->valueAt(i));
+        LOGD("  ResourceCache: mCache(%d): refCount, recycled, destroyed, type = %d, %d, %d, %d",
+                i, ref->refCount, ref->recycled, ref->destroyed, ref->resourceType);
+    }
+}
+
+ResourceCache::ResourceCache() {
+    mCache = new KeyedVector<void *, ResourceReference *>();
+}
+
+ResourceCache::~ResourceCache() {
+    delete mCache;
+}
+
+void ResourceCache::incrementRefcount(void* resource, ResourceType resourceType) {
+    for (size_t i = 0; i < mCache->size(); ++i) {
+        void* ref = mCache->valueAt(i);
+    }
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL || mCache->size() == 0) {
+        ref = new ResourceReference(resourceType);
+        mCache->add(resource, ref);
+    }
+    ref->refCount++;
+}
+
+void ResourceCache::incrementRefcount(SkBitmap* bitmapResource) {
+    bitmapResource->pixelRef()->safeRef();
+    bitmapResource->getColorTable()->safeRef();
+    incrementRefcount((void*)bitmapResource, kBitmap);
+}
+
+void ResourceCache::incrementRefcount(SkMatrix* matrixResource) {
+    incrementRefcount((void*)matrixResource, kMatrix);
+}
+
+void ResourceCache::incrementRefcount(SkPaint* paintResource) {
+    incrementRefcount((void*)paintResource, kPaint);
+}
+
+void ResourceCache::incrementRefcount(SkiaShader* shaderResource) {
+    shaderResource->getSkShader()->safeRef();
+    incrementRefcount((void*)shaderResource, kShader);
+}
+
+void ResourceCache::decrementRefcount(void* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // Should not get here - shouldn't get a call to decrement if we're not yet tracking it
+        return;
+    }
+    ref->refCount--;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+    }
+}
+
+void ResourceCache::decrementRefcount(SkBitmap* bitmapResource) {
+    bitmapResource->pixelRef()->safeUnref();
+    bitmapResource->getColorTable()->safeUnref();
+    decrementRefcount((void*)bitmapResource);
+}
+
+void ResourceCache::decrementRefcount(SkiaShader* shaderResource) {
+    shaderResource->getSkShader()->safeUnref();
+    decrementRefcount((void*)shaderResource);
+}
+
+void ResourceCache::recycle(SkBitmap* resource) {
+    if (mCache->indexOfKey(resource) < 0) {
+        // not tracking this resource; just recycle the pixel data
+        resource->setPixels(NULL, NULL);
+        return;
+    }
+    recycle((void*) resource);
+}
+
+void ResourceCache::recycle(void* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // Should not get here - shouldn't get a call to recycle if we're not yet tracking it
+        return;
+    }
+    ref->recycled = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+    }
+}
+
+void ResourceCache::destructor(SkBitmap* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
+        if (Caches::hasInstance()) {
+            Caches::getInstance().textureCache.remove(resource);
+        }
+        delete resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+        return;
+    }
+}
+
+void ResourceCache::destructor(SkMatrix* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
+        delete resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+        return;
+    }
+}
+
+void ResourceCache::destructor(SkPaint* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
+        delete resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+        return;
+    }
+}
+
+void ResourceCache::destructor(SkiaShader* resource) {
+    ResourceReference* ref = mCache->indexOfKey(resource) >= 0 ? mCache->valueFor(resource) : NULL;
+    if (ref == NULL) {
+        // If we're not tracking this resource, just delete it
+        if (Caches::hasInstance()) {
+            Caches::getInstance().gradientCache.remove(resource->getSkShader());
+        }
+        delete resource;
+        return;
+    }
+    ref->destroyed = true;
+    if (ref->refCount == 0) {
+        deleteResourceReference(resource, ref);
+        return;
+    }
+}
+
+void ResourceCache::deleteResourceReference(void* resource, ResourceReference* ref) {
+    if (ref->recycled && ref->resourceType == kBitmap) {
+        ((SkBitmap*) resource)->setPixels(NULL, NULL);
+    }
+    if (ref->destroyed) {
+        switch (ref->resourceType) {
+            case kBitmap:
+            {
+                SkBitmap* bitmap = (SkBitmap*)resource;
+                if (Caches::hasInstance()) {
+                    Caches::getInstance().textureCache.remove(bitmap);
+                }
+                delete bitmap;
+            }
+            break;
+            case kMatrix:
+                delete (SkMatrix*) resource;
+                break;
+            case kPaint:
+                delete (SkPaint*) resource;
+                break;
+            case kShader:
+                SkiaShader* shader = (SkiaShader*)resource;
+                if (Caches::hasInstance()) {
+                    Caches::getInstance().gradientCache.remove(shader->getSkShader());
+                }
+                delete shader;
+                break;
+        }
+    }
+    mCache->removeItem(resource);
+    delete ref;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
new file mode 100644
index 0000000..cda2718
--- /dev/null
+++ b/libs/hwui/ResourceCache.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_RESOURCE_CACHE_H
+#define ANDROID_UI_RESOURCE_CACHE_H
+
+#include <SkBitmap.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkiaShader.h>
+#include <utils/KeyedVector.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Type of Resource being cached
+ */
+enum ResourceType {
+    kBitmap,
+    kMatrix,
+    kPaint,
+    kShader,
+};
+
+class ResourceReference {
+public:
+
+    ResourceReference() { refCount = 0; recycled = false; destroyed = false;}
+    ResourceReference(ResourceType type) {
+        refCount = 0; recycled = false; destroyed = false; resourceType = type;
+    }
+
+    int refCount;
+    bool recycled;
+    bool destroyed;
+    ResourceType resourceType;
+};
+
+class ResourceCache {
+    KeyedVector<void *, ResourceReference *>* mCache;
+public:
+    ResourceCache();
+    ~ResourceCache();
+    void incrementRefcount(SkBitmap* resource);
+    void incrementRefcount(SkMatrix* resource);
+    void incrementRefcount(SkPaint* resource);
+    void incrementRefcount(SkiaShader* resource);
+    void incrementRefcount(const void* resource, ResourceType resourceType);
+    void decrementRefcount(void* resource);
+    void decrementRefcount(SkBitmap* resource);
+    void decrementRefcount(SkiaShader* resource);
+    void recycle(void* resource);
+    void recycle(SkBitmap* resource);
+    void destructor(SkBitmap* resource);
+    void destructor(SkMatrix* resource);
+    void destructor(SkPaint* resource);
+    void destructor(SkiaShader* resource);
+private:
+    void deleteResourceReference(void* resource, ResourceReference* ref);
+    void incrementRefcount(void* resource, ResourceType resourceType);
+    void logCache();
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_RESOURCE_CACHE_H
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 2565e65..011991a 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -60,6 +60,10 @@
     virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
             GLuint* textureUnit);
 
+    inline SkShader *getSkShader() {
+        return mKey;
+    }
+
     inline bool blend() const {
         return mBlend;
     }