Support HardwareLayers in RenderThread

 Also has a few HardwareLayer lifecycle fixes

Change-Id: I6308cb05f8f199eed72189ace768013a46815941
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 30c1e62..3258585 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3949,6 +3949,7 @@
         ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
 
         // Cleanup hardware accelerated stuff
+        // TODO: Do we actually want to do this in response to all config changes?
         WindowManagerGlobal.getInstance().trimLocalMemory();
 
         freeTextLayoutCachesIfNeeded(configDiff);
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index c1eb6b7..859468a 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -477,17 +477,21 @@
 
     @Override
     void flushLayerUpdates() {
-        mGlCanvas.flushLayerUpdates();
+        if (validate()) {
+            mGlCanvas.flushLayerUpdates();
+        }
     }
 
     @Override
     HardwareLayer createTextureLayer() {
+        validate();
         return HardwareLayer.createTextureLayer(this);
     }
 
     @Override
     public HardwareLayer createDisplayListLayer(int width, int height) {
-        return HardwareLayer.createRenderLayer(this, width, height);
+        validate();
+        return HardwareLayer.createDisplayListLayer(this, width, height);
     }
 
     @Override
@@ -510,6 +514,9 @@
 
     @Override
     boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+        if (!validate()) {
+            throw new IllegalStateException("Could not acquire hardware rendering context");
+        }
         layer.flushChanges();
         return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
     }
@@ -538,35 +545,6 @@
     }
 
     @Override
-    void destroyLayers(final View view) {
-        if (view != null) {
-            safelyRun(new Runnable() {
-                @Override
-                public void run() {
-                    if (mCanvas != null) {
-                        mCanvas.clearLayerUpdates();
-                    }
-                    destroyHardwareLayer(view);
-                    GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
-                }
-            });
-        }
-    }
-
-    private static void destroyHardwareLayer(View view) {
-        view.destroyLayer(true);
-
-        if (view instanceof ViewGroup) {
-            ViewGroup group = (ViewGroup) view;
-
-            int count = group.getChildCount();
-            for (int i = 0; i < count; i++) {
-                destroyHardwareLayer(group.getChildAt(i));
-            }
-        }
-    }
-
-    @Override
     void destroyHardwareResources(final View view) {
         if (view != null) {
             safelyRun(new Runnable() {
@@ -1069,7 +1047,6 @@
         return true;
     }
 
-    @Override
     boolean validate() {
         return checkRenderContext() != SURFACE_STATE_ERROR;
     }
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 9bbcf7c..958c071 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -33,7 +33,7 @@
  */
 final class HardwareLayer {
     private static final int LAYER_TYPE_TEXTURE = 1;
-    private static final int LAYER_TYPE_RENDER = 2;
+    private static final int LAYER_TYPE_DISPLAY_LIST = 2;
 
     private HardwareRenderer mRenderer;
     private Finalizer mFinalizer;
@@ -99,6 +99,10 @@
         doDestroyLayerUpdater();
     }
 
+    public long getDeferredLayerUpdater() {
+        return mFinalizer.mDeferredUpdater;
+    }
+
     /**
      * Destroys the deferred layer updater but not the backing layer. The
      * backing layer is instead returned and is the caller's responsibility
@@ -120,7 +124,7 @@
     }
 
     public DisplayList startRecording() {
-        assertType(LAYER_TYPE_RENDER);
+        assertType(LAYER_TYPE_DISPLAY_LIST);
 
         if (mDisplayList == null) {
             mDisplayList = DisplayList.create("HardwareLayer");
@@ -172,9 +176,17 @@
     /**
      * Indicates that this layer has lost its texture.
      */
-    public void onTextureDestroyed() {
+    public void detachSurfaceTexture(final SurfaceTexture surface) {
         assertType(LAYER_TYPE_TEXTURE);
-        nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+        mRenderer.safelyRun(new Runnable() {
+            @Override
+            public void run() {
+                surface.detachFromGLContext();
+                // SurfaceTexture owns the texture name and detachFromGLContext
+                // should have deleted it
+                nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+            }
+        });
     }
 
     /**
@@ -226,12 +238,20 @@
         return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
     }
 
+    static HardwareLayer adoptTextureLayer(HardwareRenderer renderer, long layer) {
+        return new HardwareLayer(renderer, layer, LAYER_TYPE_TEXTURE);
+    }
+
     /**
      * This should only be used by HardwareRenderer! Do not call directly
      */
-    static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+    static HardwareLayer createDisplayListLayer(HardwareRenderer renderer,
             int width, int height) {
-        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_DISPLAY_LIST);
+    }
+
+    static HardwareLayer adoptDisplayListLayer(HardwareRenderer renderer, long layer) {
+        return new HardwareLayer(renderer, layer, LAYER_TYPE_DISPLAY_LIST);
     }
 
     /** This also creates the underlying layer */
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 93cc9d1..7a943f0 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -234,13 +234,6 @@
     abstract void updateSurface(Surface surface) throws OutOfResourcesException;
 
     /**
-     * Destroys the layers used by the specified view hierarchy.
-     *
-     * @param view The root of the view hierarchy
-     */
-    abstract void destroyLayers(View view);
-
-    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
@@ -257,15 +250,6 @@
     abstract void invalidate(Surface surface);
 
     /**
-     * This method should be invoked to ensure the hardware renderer is in
-     * valid state (for instance, to ensure the correct EGL context is bound
-     * to the current thread.)
-     *
-     * @return true if the renderer is now valid, false otherwise
-     */
-    abstract boolean validate();
-
-    /**
      * This method ensures the hardware renderer is in a valid state
      * before executing the specified action.
      *
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index e789407..ef0d80d 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -231,26 +231,12 @@
     @Override
     protected void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        if (mLayer != null) {
-            boolean success = executeHardwareAction(new Runnable() {
-                @Override
-                public void run() {
-                    destroySurface();
-                }
-            });
-
-            if (!success) {
-                Log.w(LOG_TAG, "TextureView was not able to destroy its surface: " + this);
-            }
-        }
+        destroySurface();
     }
 
     private void destroySurface() {
         if (mLayer != null) {
-            mSurface.detachFromGLContext();
-            // SurfaceTexture owns the texture name and detachFromGLContext
-            // should have deleted it
-            mLayer.onTextureDestroyed();
+            mLayer.detachSurfaceTexture(mSurface);
 
             boolean shouldRelease = true;
             if (mListener != null) {
@@ -608,14 +594,6 @@
      */
     public Bitmap getBitmap(Bitmap bitmap) {
         if (bitmap != null && isAvailable()) {
-            AttachInfo info = mAttachInfo;
-            if (info != null && info.mHardwareRenderer != null &&
-                    info.mHardwareRenderer.isEnabled()) {
-                if (!info.mHardwareRenderer.validate()) {
-                    throw new IllegalStateException("Could not acquire hardware rendering context");
-                }
-            }
-
             applyUpdate();
             applyTransformMatrix();
 
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 1d7e5b2..e8f5e45 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -76,13 +76,7 @@
     }
 
     @Override
-    void destroyLayers(View view) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
     void destroyHardwareResources(View view) {
-        // TODO: canvas.clearLayerUpdates()
         destroyResources(view);
         // TODO: GLES20Canvas.flushCaches(GLES20Canvas.FLUSH_CACHES_LAYERS);
     }
@@ -106,12 +100,6 @@
     }
 
     @Override
-    boolean validate() {
-        // TODO Remove users of this API
-        return false;
-    }
-
-    @Override
     boolean safelyRun(Runnable action) {
         nRunWithGlContext(mNativeProxy, action);
         return true;
@@ -150,26 +138,6 @@
         return false;
     }
 
-    @Override
-    void pushLayerUpdate(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void onLayerCreated(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void onLayerDestroyed(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    void flushLayerUpdates() {
-        throw new NoSuchMethodError();
-    }
-
     /**
      * TODO: Remove
      * Temporary hack to allow RenderThreadTest prototype app to trigger
@@ -203,26 +171,6 @@
     }
 
     @Override
-    HardwareLayer createTextureLayer() {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    HardwareLayer createDisplayListLayer(int width, int height) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
-    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
-        throw new NoSuchMethodError();
-    }
-
-    @Override
     void detachFunctor(long functor) {
         nDetachFunctor(mNativeProxy, functor);
     }
@@ -233,6 +181,56 @@
     }
 
     @Override
+    HardwareLayer createDisplayListLayer(int width, int height) {
+        long layer = nCreateDisplayListLayer(mNativeProxy, width, height);
+        return HardwareLayer.adoptDisplayListLayer(this, layer);
+    }
+
+    @Override
+    HardwareLayer createTextureLayer() {
+        long layer = nCreateTextureLayer(mNativeProxy);
+        return HardwareLayer.adoptTextureLayer(this, layer);
+    }
+
+    @Override
+    SurfaceTexture createSurfaceTexture(final HardwareLayer layer) {
+        final SurfaceTexture[] ret = new SurfaceTexture[1];
+        nRunWithGlContext(mNativeProxy, new Runnable() {
+            @Override
+            public void run() {
+                ret[0] = layer.createSurfaceTexture();
+            }
+        });
+        return ret[0];
+    }
+
+    @Override
+    boolean copyLayerInto(final HardwareLayer layer, final Bitmap bitmap) {
+        return nCopyLayerInto(mNativeProxy,
+                layer.getDeferredLayerUpdater(), bitmap.mNativeBitmap);
+    }
+
+    @Override
+    void pushLayerUpdate(HardwareLayer layer) {
+        // TODO: Remove this, it's not needed outside of GLRenderer
+    }
+
+    @Override
+    void onLayerCreated(HardwareLayer layer) {
+        // TODO: Is this actually useful?
+    }
+
+    @Override
+    void flushLayerUpdates() {
+        // TODO: Figure out what this should do or remove it
+    }
+
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
+        nDestroyLayer(mNativeProxy, layer.getDeferredLayerUpdater());
+    }
+
+    @Override
     void setName(String name) {
     }
 
@@ -261,4 +259,9 @@
 
     private static native void nAttachFunctor(long nativeProxy, long functor);
     private static native void nDetachFunctor(long nativeProxy, long functor);
+
+    private static native long nCreateDisplayListLayer(long nativeProxy, int width, int height);
+    private static native long nCreateTextureLayer(long nativeProxy);
+    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmap);
+    private static native void nDestroyLayer(long nativeProxy, long layer);
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 49dc572..9e7046e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -13584,19 +13584,15 @@
 
         switch (mLayerType) {
             case LAYER_TYPE_HARDWARE:
-                if (attachInfo.mHardwareRenderer != null &&
-                        attachInfo.mHardwareRenderer.isEnabled() &&
-                        attachInfo.mHardwareRenderer.validate()) {
-                    getHardwareLayer();
-                    // TODO: We need a better way to handle this case
-                    // If views have registered pre-draw listeners they need
-                    // to be notified before we build the layer. Those listeners
-                    // may however rely on other events to happen first so we
-                    // cannot just invoke them here until they don't cancel the
-                    // current frame
-                    if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
-                        attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
-                    }
+                getHardwareLayer();
+                // TODO: We need a better way to handle this case
+                // If views have registered pre-draw listeners they need
+                // to be notified before we build the layer. Those listeners
+                // may however rely on other events to happen first so we
+                // cannot just invoke them here until they don't cancel the
+                // current frame
+                if (!attachInfo.mTreeObserver.hasOnPreDrawListeners()) {
+                    attachInfo.mViewRootImpl.dispatchFlushHardwareLayerUpdates();
                 }
                 break;
             case LAYER_TYPE_SOFTWARE:
@@ -13617,8 +13613,6 @@
             return null;
         }
 
-        if (!mAttachInfo.mHardwareRenderer.validate()) return null;
-
         final int width = mRight - mLeft;
         final int height = mBottom - mTop;
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 11030d9..a68d06a 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -631,16 +631,25 @@
             }
         } else {
             invalidateDisplayLists();
-            if (mAttachInfo.mHardwareRenderer != null &&
-                    mAttachInfo.mHardwareRenderer.isEnabled()) {
-                mAttachInfo.mHardwareRenderer.destroyLayers(mView);
+            destroyHardwareLayer(mView);
+        }
+    }
+
+    private static void destroyHardwareLayer(View view) {
+        view.destroyLayer(true);
+
+        if (view instanceof ViewGroup) {
+            ViewGroup group = (ViewGroup) view;
+
+            int count = group.getChildCount();
+            for (int i = 0; i < count; i++) {
+                destroyHardwareLayer(group.getChildAt(i));
             }
         }
     }
 
     void flushHardwareLayerUpdates() {
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
-                mAttachInfo.mHardwareRenderer.validate()) {
+        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
             mAttachInfo.mHardwareRenderer.flushLayerUpdates();
         }
     }
@@ -2845,10 +2854,6 @@
 
     void dispatchDetachedFromWindow() {
         if (mView != null && mView.mAttachInfo != null) {
-            if (mAttachInfo.mHardwareRenderer != null &&
-                    mAttachInfo.mHardwareRenderer.isEnabled()) {
-                mAttachInfo.mHardwareRenderer.validate();
-            }
             mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(false);
             mView.dispatchDetachedFromWindow();
         }
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index e86a2d4..bc5c06e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -76,20 +76,20 @@
 
 static void android_view_ThreadedRenderer_deleteProxy(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     delete proxy;
 }
 
 static jboolean android_view_ThreadedRenderer_initialize(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window = android_view_Surface_getNativeWindow(env, jsurface);
     return proxy->initialize(window.get());
 }
 
 static void android_view_ThreadedRenderer_updateSurface(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jsurface) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     sp<ANativeWindow> window;
     if (jsurface) {
         window = android_view_Surface_getNativeWindow(env, jsurface);
@@ -99,45 +99,74 @@
 
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jint width, jint height) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height);
 }
 
 static void android_view_ThreadedRenderer_drawDisplayList(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong displayListPtr, jint dirtyLeft, jint dirtyTop,
         jint dirtyRight, jint dirtyBottom) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
-    DisplayList* displayList = reinterpret_cast<DisplayList*>( displayListPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
     proxy->drawDisplayList(displayList, dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
 }
 
 static void android_view_ThreadedRenderer_destroyCanvas(JNIEnv* env, jobject clazz,
         jlong proxyPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->destroyCanvas();
 }
 
 static void android_view_ThreadedRenderer_attachFunctor(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     proxy->attachFunctor(functor);
 }
 
 static void android_view_ThreadedRenderer_detachFunctor(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jlong functorPtr) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     Functor* functor = reinterpret_cast<Functor*>(functorPtr);
     proxy->detachFunctor(functor);
 }
 
 static void android_view_ThreadedRenderer_runWithGlContext(JNIEnv* env, jobject clazz,
         jlong proxyPtr, jobject jrunnable) {
-    RenderProxy* proxy = reinterpret_cast<RenderProxy*>( proxyPtr);
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     RenderTask* task = new JavaTask(env, jrunnable);
     proxy->runWithGlContext(task);
 }
 
+static jlong android_view_ThreadedRenderer_createDisplayListLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jint width, jint height) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = proxy->createDisplayListLayer(width, height);
+    return reinterpret_cast<jlong>(layer);
+}
+
+static jlong android_view_ThreadedRenderer_createTextureLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = proxy->createTextureLayer();
+    return reinterpret_cast<jlong>(layer);
+}
+
+static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    SkBitmap* bitmap = reinterpret_cast<SkBitmap*>(bitmapPtr);
+    return proxy->copyLayerInto(layer, bitmap);
+}
+
+static void android_view_ThreadedRenderer_destroyLayer(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jlong layerPtr) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
+    proxy->destroyLayer(layer);
+}
+
 #endif
 
 // ----------------------------------------------------------------------------
@@ -159,6 +188,10 @@
     { "nAttachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_attachFunctor},
     { "nDetachFunctor", "(JJ)V", (void*) android_view_ThreadedRenderer_detachFunctor},
     { "nRunWithGlContext", "(JLjava/lang/Runnable;)V", (void*) android_view_ThreadedRenderer_runWithGlContext },
+    { "nCreateDisplayListLayer", "(JII)J", (void*) android_view_ThreadedRenderer_createDisplayListLayer },
+    { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
+    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+    { "nDestroyLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_destroyLayer },
 #endif
 };
 
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 5d3d393..efb1298 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -123,27 +123,5 @@
     }
 }
 
-void DeferredLayerUpdater::applyDeferred(DeferredLayerUpdater* deferredApply) {
-    // Default assignment operator doesn't quite work, and fails due to mCaches anyway
-    deferredApply->mWidth = mWidth;
-    deferredApply->mHeight = mHeight;
-    deferredApply->mBlend = mBlend;
-    deferredApply->mAlpha = mAlpha;
-    deferredApply->mMode = mMode;
-    deferredApply->mDirtyRect.set(mDirtyRect);
-    deferredApply->mDisplayList = mDisplayList;
-    deferredApply->mSurfaceTexture = mSurfaceTexture;
-    deferredApply->mNeedsGLContextAttach = mNeedsGLContextAttach;
-    deferredApply->mUpdateTexImage = mUpdateTexImage;
-    deferredApply->setColorFilter(mColorFilter);
-    deferredApply->setTransform(mTransform);
-
-    mDisplayList = 0;
-    mDirtyRect.setEmpty();
-    mTransform = 0;
-    mNeedsGLContextAttach = false;
-    mUpdateTexImage = false;
-}
-
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 9800c2f..624db2c 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -82,7 +82,6 @@
     ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
 
     ANDROID_API bool apply();
-    ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
 
     ANDROID_API Layer* backingLayer() {
         return mLayer;
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 4e665d9..fe781bd 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -24,6 +24,8 @@
 
 #include "RenderThread.h"
 #include "../Caches.h"
+#include "../DeferredLayerUpdater.h"
+#include "../LayerRenderer.h"
 #include "../OpenGLRenderer.h"
 #include "../Stencil.h"
 
@@ -371,6 +373,17 @@
     mCanvas->setViewport(width, height);
 }
 
+void CanvasContext::processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters) {
+    mGlobalContext->makeCurrent(mEglSurface);
+    for (size_t i = 0; i < layerUpdaters->size(); i++) {
+        DeferredLayerUpdater* update = layerUpdaters->itemAt(i);
+        LOG_ALWAYS_FATAL_IF(!update->apply(), "Failed to update layer!");
+        if (update->backingLayer()->deferredUpdateScheduled) {
+            mCanvas->pushLayerUpdate(update->backingLayer());
+        }
+    }
+}
+
 void CanvasContext::drawDisplayList(DisplayList* displayList, Rect* dirty) {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawDisplayList called on a context with no canvas or surface!");
@@ -462,14 +475,23 @@
     mRenderThread.queueDelayed(&mInvokeFunctorsTask, delayMs);
 }
 
+bool CanvasContext::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    requireGlContext();
+    layer->apply();
+    return LayerRenderer::copyLayer(layer->backingLayer(), bitmap);
+}
+
 void CanvasContext::runWithGlContext(RenderTask* task) {
+    requireGlContext();
+    task->run();
+}
+
+void CanvasContext::requireGlContext() {
     if (mEglSurface != EGL_NO_SURFACE) {
         mGlobalContext->makeCurrent(mEglSurface);
     } else {
         mGlobalContext->usePBufferSurface();
     }
-
-    task->run();
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 3197df3..5fac582 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -19,7 +19,9 @@
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
+#include <SkBitmap.h>
 #include <utils/Functor.h>
+#include <utils/Vector.h>
 
 #include "RenderTask.h"
 
@@ -28,6 +30,7 @@
 namespace android {
 namespace uirenderer {
 
+class DeferredLayerUpdater;
 class DisplayList;
 class OpenGLRenderer;
 class Rect;
@@ -59,9 +62,12 @@
     bool initialize(EGLNativeWindowType window);
     void updateSurface(EGLNativeWindowType window);
     void setup(int width, int height);
+    void processLayerUpdates(const Vector<DeferredLayerUpdater*>* layerUpdaters);
     void drawDisplayList(DisplayList* displayList, Rect* dirty);
     void destroyCanvas();
 
+    bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+
     void attachFunctor(Functor* functor);
     void detachFunctor(Functor* functor);
 
@@ -78,6 +84,8 @@
     void removeFunctorsTask();
     void queueFunctorsTask(int delayMs = FUNCTOR_PROCESS_DELAY);
 
+    void requireGlContext();
+
     GlobalContext* mGlobalContext;
     RenderThread& mRenderThread;
     EGLSurface mEglSurface;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 34f1961..0c667fd 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,7 +22,9 @@
 #include "RenderTask.h"
 #include "RenderThread.h"
 
+#include "../DeferredLayerUpdater.h"
 #include "../DisplayList.h"
+#include "../LayerRenderer.h"
 #include "../Rect.h"
 
 namespace android {
@@ -31,6 +33,7 @@
 
 #define ARGS(method) method ## Args
 
+#define CREATE_BRIDGE0(name) CREATE_BRIDGE(name,,,,,,,,)
 #define CREATE_BRIDGE1(name, a1) CREATE_BRIDGE(name, a1,,,,,,,)
 #define CREATE_BRIDGE2(name, a1, a2) CREATE_BRIDGE(name, a1,a2,,,,,,)
 #define CREATE_BRIDGE3(name, a1, a2, a3) CREATE_BRIDGE(name, a1,a2,a3,,,,,)
@@ -114,13 +117,14 @@
     post(task);
 }
 
-CREATE_BRIDGE3(drawDisplayList, CanvasContext* context, DisplayList* displayList,
-        Rect dirty) {
+CREATE_BRIDGE4(drawDisplayList, CanvasContext* context, DisplayList* displayList,
+        Rect dirty, const Vector<DeferredLayerUpdater*>* layerUpdates) {
     Rect* dirty = &args->dirty;
     if (dirty->bottom == -1 && dirty->left == -1 &&
             dirty->top == -1 && dirty->right == -1) {
         dirty = 0;
     }
+    args->context->processLayerUpdates(args->layerUpdates);
     args->context->drawDisplayList(args->displayList, dirty);
     return NULL;
 }
@@ -131,6 +135,7 @@
     args->context = mContext;
     args->displayList = displayList;
     args->dirty.set(dirtyLeft, dirtyTop, dirtyRight, dirtyBottom);
+    args->layerUpdates = &mLayers;
     // TODO: Switch to post() once some form of thread safety strategy is in place
     postAndWait(task);
 }
@@ -182,6 +187,70 @@
     postAndWait(task);
 }
 
+CREATE_BRIDGE2(createDisplayListLayer, int width, int height) {
+    Layer* layer = LayerRenderer::createRenderLayer(args->width, args->height);
+    if (!layer) return 0;
+
+    OpenGLRenderer* renderer = new LayerRenderer(layer);
+    renderer->initProperties();
+    return new DeferredLayerUpdater(layer, renderer);
+}
+
+DeferredLayerUpdater* RenderProxy::createDisplayListLayer(int width, int height) {
+    SETUP_TASK(createDisplayListLayer);
+    args->width = width;
+    args->height = height;
+    void* retval = postAndWait(task);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+    mLayers.push(layer);
+    return layer;
+}
+
+CREATE_BRIDGE0(createTextureLayer) {
+    Layer* layer = LayerRenderer::createTextureLayer();
+    if (!layer) return 0;
+    return new DeferredLayerUpdater(layer);
+}
+
+DeferredLayerUpdater* RenderProxy::createTextureLayer() {
+    SETUP_TASK(createTextureLayer);
+    void* retval = postAndWait(task);
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(retval);
+    mLayers.push(layer);
+    return layer;
+}
+
+CREATE_BRIDGE1(destroyLayer, Layer* layer) {
+    LayerRenderer::destroyLayer(args->layer);
+    return NULL;
+}
+
+CREATE_BRIDGE3(copyLayerInto, CanvasContext* context, DeferredLayerUpdater* layer,
+        SkBitmap* bitmap) {
+    bool success = args->context->copyLayerInto(args->layer, args->bitmap);
+    return (void*) success;
+}
+
+bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) {
+    SETUP_TASK(copyLayerInto);
+    args->context = mContext;
+    args->layer = layer;
+    args->bitmap = bitmap;
+    return (bool) postAndWait(task);
+}
+
+void RenderProxy::destroyLayer(DeferredLayerUpdater* layer) {
+    for (size_t i = 0; i < mLayers.size(); i++) {
+        if (mLayers[i] == layer) {
+            mLayers.removeAt(i);
+            break;
+        }
+    }
+    SETUP_TASK(destroyLayer);
+    args->layer = layer->detachBackingLayer();
+    post(task);
+}
+
 MethodInvokeRenderTask* RenderProxy::createTask(RunnableMethod method) {
     // TODO: Consider having a small pool of these to avoid alloc churn
     return new MethodInvokeRenderTask(method);
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 1ad0c2d..8ff3d63 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -21,15 +21,19 @@
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
+#include <SkBitmap.h>
 #include <utils/Condition.h>
 #include <utils/Functor.h>
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
+#include <utils/Vector.h>
 
 namespace android {
 namespace uirenderer {
 
+class DeferredLayerUpdater;
 class DisplayList;
+class Layer;
 class Rect;
 
 namespace renderthread {
@@ -64,6 +68,11 @@
 
     ANDROID_API void runWithGlContext(RenderTask* task);
 
+    ANDROID_API DeferredLayerUpdater* createDisplayListLayer(int width, int height);
+    ANDROID_API DeferredLayerUpdater* createTextureLayer();
+    ANDROID_API bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap);
+    ANDROID_API void destroyLayer(DeferredLayerUpdater* layer);
+
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
@@ -71,6 +80,8 @@
     Mutex mSyncMutex;
     Condition mSyncCondition;
 
+    Vector<DeferredLayerUpdater*> mLayers;
+
     void destroyContext();
 
     MethodInvokeRenderTask* createTask(RunnableMethod method);