Refactor HardwareLayer

 Defer all the things!
 Groundwork to allow hardware layers to work in a renderthread world

Change-Id: Ib3aa47525f393083621254a743dbaa6352f933bd
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index b763888..2ed0cba 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -31,7 +31,6 @@
 import android.graphics.RectF;
 import android.graphics.Region;
 import android.graphics.Shader;
-import android.graphics.SurfaceTexture;
 import android.graphics.TemporaryBuffer;
 import android.text.GraphicsOperations;
 import android.text.SpannableString;
@@ -87,15 +86,6 @@
     GLES20Canvas(boolean translucent) {
         this(false, translucent);
     }
-
-    /**
-     * Creates a canvas to render into an FBO.
-     */
-    GLES20Canvas(long layer, boolean translucent) {
-        mOpaque = !translucent;
-        mRenderer = nCreateLayerRenderer(layer);
-        setupFinalizer();
-    }
     
     protected GLES20Canvas(boolean record, boolean translucent) {
         mOpaque = !translucent;
@@ -122,7 +112,6 @@
     }
 
     private static native long nCreateRenderer();
-    private static native long nCreateLayerRenderer(long layer);
     private static native long nCreateDisplayListRenderer();
     private static native void nResetDisplayListRenderer(long renderer);
     private static native void nDestroyRenderer(long renderer);
@@ -156,12 +145,12 @@
 
     @Override
     void pushLayerUpdate(HardwareLayer layer) {
-        nPushLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+        nPushLayerUpdate(mRenderer, layer.getLayer());
     }
 
     @Override
     void cancelLayerUpdate(HardwareLayer layer) {
-        nCancelLayerUpdate(mRenderer, ((GLES20RenderLayer) layer).mLayer);
+        nCancelLayerUpdate(mRenderer, layer.getLayer());
     }
 
     @Override
@@ -174,22 +163,7 @@
         nClearLayerUpdates(mRenderer);
     }
 
-    static native long nCreateTextureLayer(boolean opaque, int[] layerInfo);
-    static native long nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
-    static native boolean nResizeLayer(long layerId, int width, int height, int[] layerInfo);
-    static native void nSetOpaqueLayer(long layerId, boolean isOpaque);
-    static native void nSetLayerPaint(long layerId, long nativePaint);
-    static native void nSetLayerColorFilter(long layerId, long nativeColorFilter);
-    static native void nUpdateTextureLayer(long layerId, int width, int height, boolean opaque,
-            SurfaceTexture surface);
-    static native void nClearLayerTexture(long layerId);
-    static native void nSetTextureLayerTransform(long layerId, long matrix);
-    static native void nDestroyLayer(long layerId);
-    static native void nDestroyLayerDeferred(long layerId);
-    static native void nUpdateRenderLayer(long layerId, long renderer, long displayList,
-            int left, int top, int right, int bottom);
     static native boolean nCopyLayer(long layerId, long bitmap);
-
     private static native void nClearLayerUpdates(long renderer);
     private static native void nFlushLayerUpdates(long renderer);
     private static native void nPushLayerUpdate(long renderer, long layer);
@@ -408,9 +382,7 @@
     
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         layer.setLayerPaint(paint);
-
-        final GLES20Layer glLayer = (GLES20Layer) layer;
-        nDrawLayer(mRenderer, glLayer.getLayer(), x, y);
+        nDrawLayer(mRenderer, layer.getLayer(), x, y);
     }
 
     private static native void nDrawLayer(long renderer, long layer, float x, float y);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
deleted file mode 100644
index 1d30824..0000000
--- a/core/java/android/view/GLES20Layer.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-
-package android.view;
-
-import android.graphics.Bitmap;
-import android.graphics.Paint;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
- */
-abstract class GLES20Layer extends HardwareLayer {
-    long mLayer;
-    Finalizer mFinalizer;
-
-    GLES20Layer() {
-    }
-
-    GLES20Layer(int width, int height, boolean opaque) {
-        super(width, height, opaque);
-    }
-
-    /**
-     * Returns the native layer object used to render this layer.
-     * 
-     * @return A pointer to the native layer object, or 0 if the object is NULL
-     */
-    public long getLayer() {
-        return mLayer;
-    }
-
-    @Override
-    void setLayerPaint(Paint paint) {
-        if (paint != null) {
-            GLES20Canvas.nSetLayerPaint(mLayer, paint.mNativePaint);
-            GLES20Canvas.nSetLayerColorFilter(mLayer, paint.getColorFilter() != null ?
-                    paint.getColorFilter().native_instance : 0);
-        }
-    }
-
-    @Override
-    public boolean copyInto(Bitmap bitmap) {
-        return GLES20Canvas.nCopyLayer(mLayer, bitmap.mNativeBitmap);
-    }
-
-    @Override
-    public void destroy() {
-        if (mDisplayList != null) {
-            mDisplayList.reset();
-        }
-        if (mFinalizer != null) {
-            mFinalizer.destroy();
-            mFinalizer = null;
-        }
-        mLayer = 0;
-    }
-
-    @Override
-    void clearStorage() {
-        if (mLayer != 0) GLES20Canvas.nClearLayerTexture(mLayer);
-    }
-
-    static class Finalizer {
-        private long mLayerId;
-
-        public Finalizer(long layerId) {
-            mLayerId = layerId;
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            try {
-                if (mLayerId != 0) {
-                    GLES20Canvas.nDestroyLayerDeferred(mLayerId);
-                }
-            } finally {
-                super.finalize();
-            }
-        }
-
-        void destroy() {
-            GLES20Canvas.nDestroyLayer(mLayerId);
-            mLayerId = 0;
-        }
-    }
-}
diff --git a/core/java/android/view/GLES20RenderLayer.java b/core/java/android/view/GLES20RenderLayer.java
deleted file mode 100644
index 8c97867..0000000
--- a/core/java/android/view/GLES20RenderLayer.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package android.view;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
- * implementation can be used a rendering target. It generates a
- * {@link Canvas} that can be used to render into an FBO using OpenGL.
- */
-class GLES20RenderLayer extends GLES20Layer {
-    private int mLayerWidth;
-    private int mLayerHeight;
-
-    private final GLES20Canvas mCanvas;
-
-    GLES20RenderLayer(int width, int height, boolean isOpaque) {
-        super(width, height, isOpaque);
-
-        int[] layerInfo = new int[2];
-        mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
-        if (mLayer != 0) {
-            mLayerWidth = layerInfo[0];
-            mLayerHeight = layerInfo[1];
-
-            mCanvas = new GLES20Canvas(mLayer, !isOpaque);
-            mFinalizer = new Finalizer(mLayer);
-        } else {
-            mCanvas = null;
-            mFinalizer = null;
-        }
-    }
-
-    @Override
-    boolean isValid() {
-        return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
-    }
-
-    @Override
-    boolean resize(int width, int height) {
-        if (!isValid() || width <= 0 || height <= 0) return false;
-
-        mWidth = width;
-        mHeight = height;
-        
-        if (width != mLayerWidth || height != mLayerHeight) {
-            int[] layerInfo = new int[2];
-
-            if (GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo)) {
-                mLayerWidth = layerInfo[0];
-                mLayerHeight = layerInfo[1];
-            } else {
-                // Failure: not enough GPU resources for requested size
-                mLayer = 0;
-                mLayerWidth = 0;
-                mLayerHeight = 0;
-            }
-        }
-        return isValid();
-    }
-
-    @Override
-    void setOpaque(boolean isOpaque) {
-        mOpaque = isOpaque;
-        GLES20Canvas.nSetOpaqueLayer(mLayer, isOpaque);
-    }
-
-    @Override
-    HardwareCanvas getCanvas() {
-        return mCanvas;
-    }
-
-    @Override
-    void end(Canvas currentCanvas) {
-        HardwareCanvas canvas = getCanvas();
-        if (canvas != null) {
-            canvas.onPostDraw();
-        }
-        if (currentCanvas instanceof GLES20Canvas) {
-            ((GLES20Canvas) currentCanvas).resume();
-        }
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas) {
-        return start(currentCanvas, null);
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
-        if (currentCanvas instanceof GLES20Canvas) {
-            ((GLES20Canvas) currentCanvas).interrupt();
-        }
-        HardwareCanvas canvas = getCanvas();
-        canvas.setViewport(mWidth, mHeight);
-        canvas.onPreDraw(dirty);
-        return canvas;
-    }
-
-    /**
-     * Ignored
-     */
-    @Override
-    void setTransform(Matrix matrix) {
-    }
-
-    @Override
-    void redrawLater(DisplayList displayList, Rect dirtyRect) {
-        GLES20Canvas.nUpdateRenderLayer(mLayer, mCanvas.getRenderer(),
-                displayList.getNativeDisplayList(),
-                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
-    }
-}
diff --git a/core/java/android/view/GLES20TextureLayer.java b/core/java/android/view/GLES20TextureLayer.java
deleted file mode 100644
index bb5a6eb..0000000
--- a/core/java/android/view/GLES20TextureLayer.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2011 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.
- */
-
-package android.view;
-
-import android.graphics.Canvas;
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.graphics.SurfaceTexture;
-
-/**
- * An OpenGL ES 2.0 implementation of {@link HardwareLayer}. This
- * implementation can be used as a texture. Rendering into this
- * layer is not controlled by a {@link HardwareCanvas}.
- */
-class GLES20TextureLayer extends GLES20Layer {
-    private int mTexture;
-    private SurfaceTexture mSurface;
-
-    GLES20TextureLayer(boolean isOpaque) {
-        int[] layerInfo = new int[2];
-        mLayer = GLES20Canvas.nCreateTextureLayer(isOpaque, layerInfo);
-
-        if (mLayer != 0) {
-            mTexture = layerInfo[0];
-            mFinalizer = new Finalizer(mLayer);
-        } else {
-            mFinalizer = null;
-        }
-    }
-
-    @Override
-    boolean isValid() {
-        return mLayer != 0 && mTexture != 0;
-    }
-
-    @Override
-    boolean resize(int width, int height) {
-        return isValid();
-    }
-
-    @Override
-    HardwareCanvas getCanvas() {
-        return null;
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas) {
-        return null;
-    }
-
-    @Override
-    HardwareCanvas start(Canvas currentCanvas, Rect dirty) {
-        return null;
-    }
-
-    @Override
-    void end(Canvas currentCanvas) {
-    }
-
-    SurfaceTexture getSurfaceTexture() {
-        if (mSurface == null) {
-            mSurface = new SurfaceTexture(mTexture);
-        }
-        return mSurface;
-    }
-
-    void setSurfaceTexture(SurfaceTexture surfaceTexture) {
-        if (mSurface != null) {
-            mSurface.release();
-        }
-        mSurface = surfaceTexture;
-        mSurface.attachToGLContext(mTexture);
-    }
-
-    @Override
-    void update(int width, int height, boolean isOpaque) {
-        super.update(width, height, isOpaque);
-        GLES20Canvas.nUpdateTextureLayer(mLayer, width, height, isOpaque, mSurface);
-    }
-
-    @Override
-    void setOpaque(boolean isOpaque) {
-        throw new UnsupportedOperationException("Use update(int, int, boolean) instead");
-    }
-
-    @Override
-    void setTransform(Matrix matrix) {
-        GLES20Canvas.nSetTextureLayerTransform(mLayer, matrix.native_instance);
-    }
-
-    @Override
-    void redrawLater(DisplayList displayList, Rect dirtyRect) {
-    }
-}
diff --git a/core/java/android/view/GLRenderer.java b/core/java/android/view/GLRenderer.java
index 5002fe5..40ad72c 100644
--- a/core/java/android/view/GLRenderer.java
+++ b/core/java/android/view/GLRenderer.java
@@ -40,7 +40,7 @@
 import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
 
 import android.content.ComponentCallbacks2;
-import android.graphics.Color;
+import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -62,6 +62,8 @@
 import com.google.android.gles_jni.EGLImpl;
 
 import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.concurrent.locks.ReentrantLock;
 
 import javax.microedition.khronos.egl.EGL10;
@@ -177,6 +179,8 @@
     private static EGLSurface sPbuffer;
     private static final Object[] sPbufferLock = new Object[0];
 
+    private List<HardwareLayer> mAttachedLayers = new ArrayList<HardwareLayer>();
+
     private static class GLRendererEglContext extends ManagedEGLContext {
         final Handler mHandler = new Handler();
 
@@ -472,33 +476,40 @@
     }
 
     @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
-        mGlCanvas.cancelLayerUpdate(layer);
-    }
-
-    @Override
     void flushLayerUpdates() {
         mGlCanvas.flushLayerUpdates();
     }
 
     @Override
-    HardwareLayer createHardwareLayer(boolean isOpaque) {
-        return new GLES20TextureLayer(isOpaque);
+    HardwareLayer createTextureLayer() {
+        return HardwareLayer.createTextureLayer(this);
     }
 
     @Override
-    public HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
-        return new GLES20RenderLayer(width, height, isOpaque);
+    public HardwareLayer createDisplayListLayer(int width, int height) {
+        return HardwareLayer.createRenderLayer(this, width, height);
+    }
+
+    @Override
+    void onLayerCreated(HardwareLayer hardwareLayer) {
+        mAttachedLayers.add(hardwareLayer);
+    }
+
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
+        mGlCanvas.cancelLayerUpdate(layer);
+        mAttachedLayers.remove(layer);
     }
 
     @Override
     public SurfaceTexture createSurfaceTexture(HardwareLayer layer) {
-        return ((GLES20TextureLayer) layer).getSurfaceTexture();
+        return layer.createSurfaceTexture();
     }
 
     @Override
-    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
-        ((GLES20TextureLayer) layer).setSurfaceTexture(surfaceTexture);
+    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
+        layer.flushChanges();
+        return GLES20Canvas.nCopyLayer(layer.getLayer(), bitmap.mNativeBitmap);
     }
 
     @Override
@@ -1127,6 +1138,8 @@
 
                 DisplayList displayList = buildDisplayList(view, canvas);
 
+                flushLayerChanges();
+
                 // buildDisplayList() calls into user code which can cause
                 // an eglMakeCurrent to happen with a different surface/context.
                 // We must therefore check again here.
@@ -1180,6 +1193,20 @@
         }
     }
 
+    private void flushLayerChanges() {
+        // Loop through and apply any pending layer changes
+        for (int i = 0; i < mAttachedLayers.size(); i++) {
+            HardwareLayer layer = mAttachedLayers.get(i);
+            layer.flushChanges();
+            if (!layer.isValid()) {
+                // The layer was removed from mAttachedLayers, rewind i by 1
+                // Note that this shouldn't actually happen as View.getHardwareLayer()
+                // is already flushing for error checking reasons
+                i--;
+            }
+        }
+    }
+
     private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
         if (mDrawDelta <= 0) {
             return view.mDisplayList;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 23383d9..9bbcf7c 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -17,10 +17,10 @@
 package android.view;
 
 import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.SurfaceTexture;
 
 /**
  * A hardware layer can be used to render graphics operations into a hardware
@@ -28,38 +28,35 @@
  * would use a Frame Buffer Object (FBO.) The hardware layer can be used as
  * a drawing cache when a complex set of graphics operations needs to be
  * drawn several times.
+ *
+ * @hide
  */
-abstract class HardwareLayer {
-    /**
-     * Indicates an unknown dimension (width or height.)
-     */
-    static final int DIMENSION_UNDEFINED = -1;
-    
-    int mWidth;
-    int mHeight;
-    DisplayList mDisplayList;
+final class HardwareLayer {
+    private static final int LAYER_TYPE_TEXTURE = 1;
+    private static final int LAYER_TYPE_RENDER = 2;
 
-    boolean mOpaque;
+    private HardwareRenderer mRenderer;
+    private Finalizer mFinalizer;
+    private DisplayList mDisplayList;
+    private final int mLayerType;
 
-    /**
-     * Creates a new hardware layer with undefined dimensions.
-     */
-    HardwareLayer() {
-        this(DIMENSION_UNDEFINED, DIMENSION_UNDEFINED, false);
+    private HardwareLayer(HardwareRenderer renderer, long deferredUpdater, int type) {
+        if (renderer == null || deferredUpdater == 0) {
+            throw new IllegalArgumentException("Either hardware renderer: " + renderer
+                    + " or deferredUpdater: " + deferredUpdater + " is invalid");
+        }
+        mRenderer = renderer;
+        mLayerType = type;
+        mFinalizer = new Finalizer(deferredUpdater);
+
+        // Layer is considered initialized at this point, notify the HardwareRenderer
+        mRenderer.onLayerCreated(this);
     }
 
-    /**
-     * Creates a new hardware layer at least as large as the supplied
-     * dimensions.
-     * 
-     * @param width The minimum width of the layer
-     * @param height The minimum height of the layer
-     * @param isOpaque Whether the layer should be opaque or not
-     */
-    HardwareLayer(int width, int height, boolean isOpaque) {
-        mWidth = width;
-        mHeight = height;
-        mOpaque = isOpaque;
+    private void assertType(int type) {
+        if (mLayerType != type) {
+            throw new IllegalAccessError("Method not appropriate for this layer type! " + mLayerType);
+        }
     }
 
     /**
@@ -68,158 +65,225 @@
      * @param paint The paint used when the layer is drawn into the destination canvas.
      * @see View#setLayerPaint(android.graphics.Paint)
      */
-    void setLayerPaint(Paint paint) { }
-
-    /**
-     * Returns the minimum width of the layer.
-     * 
-     * @return The minimum desired width of the hardware layer 
-     */
-    int getWidth() {
-        return mWidth;
+    public void setLayerPaint(Paint paint) {
+        nSetLayerPaint(mFinalizer.mDeferredUpdater, paint.mNativePaint,
+                paint.getColorFilter() != null ? paint.getColorFilter().native_instance : 0);
     }
 
     /**
-     * Returns the minimum height of the layer.
-     * 
-     * @return The minimum desired height of the hardware layer 
-     */
-    int getHeight() {
-        return mHeight;
-    }
-
-    /**
-     * Returns the DisplayList for the layer.
-     *
-     * @return The DisplayList of the hardware layer
-     */
-    DisplayList getDisplayList() {
-        return mDisplayList;
-    }
-
-    /**
-     * Sets the DisplayList for the layer.
-     *
-     * @param displayList The new DisplayList for this layer
-     */
-    void setDisplayList(DisplayList displayList) {
-        mDisplayList = displayList;
-    }
-
-    /**
-     * Returns whether or not this layer is opaque.
-     * 
-     * @return True if the layer is opaque, false otherwise
-     */
-    boolean isOpaque() {
-        return mOpaque;
-    }
-
-    /**
-     * Sets whether or not this layer should be considered opaque.
-     * 
-     * @param isOpaque True if the layer is opaque, false otherwise
-     */
-    abstract void setOpaque(boolean isOpaque);
-
-    /**
      * Indicates whether this layer can be rendered.
-     * 
+     *
      * @return True if the layer can be rendered into, false otherwise
      */
-    abstract boolean isValid();
+    public boolean isValid() {
+        return mFinalizer != null && mFinalizer.mDeferredUpdater != 0;
+    }
 
     /**
-     * Resize the layer, if necessary, to be at least as large
-     * as the supplied dimensions.
-     * 
-     * @param width The new desired minimum width for this layer
-     * @param height The new desired minimum height for this layer
-     * @return True if the resulting layer is valid, false otherwise
+     * Destroys resources without waiting for a GC.
      */
-    abstract boolean resize(int width, int height);
+    public void destroy() {
+        if (!isValid()) {
+            // Already destroyed
+            return;
+        }
+
+        if (mDisplayList != null) {
+            mDisplayList.reset();
+            mDisplayList = null;
+        }
+        if (mRenderer != null) {
+            mRenderer.onLayerDestroyed(this);
+            mRenderer = null;
+        }
+        doDestroyLayerUpdater();
+    }
 
     /**
-     * Returns a hardware canvas that can be used to render onto
-     * this layer.
-     * 
-     * @return A hardware canvas, or null if a canvas cannot be created
+     * Destroys the deferred layer updater but not the backing layer. The
+     * backing layer is instead returned and is the caller's responsibility
+     * to destroy/recycle as appropriate.
      *
-     * @see #start(android.graphics.Canvas)
-     * @see #end(android.graphics.Canvas)
+     * It is safe to call this in onLayerDestroyed only
      */
-    abstract HardwareCanvas getCanvas();
+    public long detachBackingLayer() {
+        long backingLayer = nDetachBackingLayer(mFinalizer.mDeferredUpdater);
+        doDestroyLayerUpdater();
+        return backingLayer;
+    }
 
-    /**
-     * Destroys resources without waiting for a GC. 
-     */
-    abstract void destroy();
+    private void doDestroyLayerUpdater() {
+        if (mFinalizer != null) {
+            mFinalizer.destroy();
+            mFinalizer = null;
+        }
+    }
 
-    /**
-     * This must be invoked before drawing onto this layer.
-     *
-     * @param currentCanvas The canvas whose rendering needs to be interrupted
-     */
-    abstract HardwareCanvas start(Canvas currentCanvas);
+    public DisplayList startRecording() {
+        assertType(LAYER_TYPE_RENDER);
 
-    /**
-     * This must be invoked before drawing onto this layer.
-     *
-     * @param dirty The dirty area to repaint
-     * @param currentCanvas The canvas whose rendering needs to be interrupted
-     */
-    abstract HardwareCanvas start(Canvas currentCanvas, Rect dirty);
+        if (mDisplayList == null) {
+            mDisplayList = DisplayList.create("HardwareLayer");
+        }
+        return mDisplayList;
+    }
 
-    /**
-     * This must be invoked after drawing onto this layer.
-     *
-     * @param currentCanvas The canvas whose rendering needs to be resumed
-     */
-    abstract void end(Canvas currentCanvas);
+    public void endRecording(Rect dirtyRect) {
+        nUpdateRenderLayer(mFinalizer.mDeferredUpdater, mDisplayList.getNativeDisplayList(),
+                dirtyRect.left, dirtyRect.top, dirtyRect.right, dirtyRect.bottom);
+        mRenderer.pushLayerUpdate(this);
+    }
 
     /**
      * Copies this layer into the specified bitmap.
-     * 
+     *
      * @param bitmap The bitmap to copy they layer into
-     * 
+     *
      * @return True if the copy was successful, false otherwise
      */
-    abstract boolean copyInto(Bitmap bitmap);
+    public boolean copyInto(Bitmap bitmap) {
+        return mRenderer.copyLayerInto(this, bitmap);
+    }
 
     /**
-     * Update the layer's properties. This method should be used
-     * when the underlying storage is modified by an external entity.
-     * To change the underlying storage, use the {@link #resize(int, int)}
-     * method instead.
-     * 
+     * Update the layer's properties. Note that after calling this isValid() may
+     * return false if the requested width/height cannot be satisfied
+     *
      * @param width The new width of this layer
      * @param height The new height of this layer
      * @param isOpaque Whether this layer is opaque
+     *
+     * @return true if the layer's properties will change, false if they already
+     *         match the desired values.
      */
-    void update(int width, int height, boolean isOpaque) {
-        mWidth = width;
-        mHeight = height;
-        mOpaque = isOpaque;
+    public boolean prepare(int width, int height, boolean isOpaque) {
+        return nPrepare(mFinalizer.mDeferredUpdater, width, height, isOpaque);
     }
 
     /**
      * Sets an optional transform on this layer.
-     * 
+     *
      * @param matrix The transform to apply to the layer.
      */
-    abstract void setTransform(Matrix matrix);
+    public void setTransform(Matrix matrix) {
+        nSetTransform(mFinalizer.mDeferredUpdater, matrix.native_instance);
+    }
 
     /**
-     * Specifies the display list to use to refresh the layer.
-     *
-     * @param displayList The display list containing the drawing commands to
-     *                    execute in this layer
-     * @param dirtyRect The dirty region of the layer that needs to be redrawn
+     * Indicates that this layer has lost its texture.
      */
-    abstract void redrawLater(DisplayList displayList, Rect dirtyRect);
+    public void onTextureDestroyed() {
+        assertType(LAYER_TYPE_TEXTURE);
+        nOnTextureDestroyed(mFinalizer.mDeferredUpdater);
+    }
 
     /**
-     * Indicates that this layer has lost its underlying storage.
+     * This exists to minimize impact into the current HardwareLayer paths as
+     * some of the specifics of how to handle error cases in the fully
+     * deferred model will work
      */
-    abstract void clearStorage();
+    @Deprecated
+    public void flushChanges() {
+        if (HardwareRenderer.sUseRenderThread) {
+            // Not supported, don't try.
+            return;
+        }
+
+        boolean success = nFlushChanges(mFinalizer.mDeferredUpdater);
+        if (!success) {
+            destroy();
+        }
+    }
+
+    public long getLayer() {
+        return nGetLayer(mFinalizer.mDeferredUpdater);
+    }
+
+    public void setSurfaceTexture(SurfaceTexture surface) {
+        assertType(LAYER_TYPE_TEXTURE);
+        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, surface, false);
+    }
+
+    public void updateSurfaceTexture() {
+        assertType(LAYER_TYPE_TEXTURE);
+        nUpdateSurfaceTexture(mFinalizer.mDeferredUpdater);
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    SurfaceTexture createSurfaceTexture() {
+        assertType(LAYER_TYPE_TEXTURE);
+        SurfaceTexture st = new SurfaceTexture(nGetTexName(mFinalizer.mDeferredUpdater));
+        nSetSurfaceTexture(mFinalizer.mDeferredUpdater, st, true);
+        return st;
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    static HardwareLayer createTextureLayer(HardwareRenderer renderer) {
+        return new HardwareLayer(renderer, nCreateTextureLayer(), LAYER_TYPE_TEXTURE);
+    }
+
+    /**
+     * This should only be used by HardwareRenderer! Do not call directly
+     */
+    static HardwareLayer createRenderLayer(HardwareRenderer renderer,
+            int width, int height) {
+        return new HardwareLayer(renderer, nCreateRenderLayer(width, height), LAYER_TYPE_RENDER);
+    }
+
+    /** This also creates the underlying layer */
+    private static native long nCreateTextureLayer();
+    private static native long nCreateRenderLayer(int width, int height);
+
+    private static native void nOnTextureDestroyed(long layerUpdater);
+    private static native long nDetachBackingLayer(long layerUpdater);
+
+    /** This also destroys the underlying layer if it is still attached.
+     *  Note it does not recycle the underlying layer, but instead queues it
+     *  for deferred deletion.
+     *  The HardwareRenderer should use detachBackingLayer() in the
+     *  onLayerDestroyed() callback to do recycling if desired.
+     */
+    private static native void nDestroyLayerUpdater(long layerUpdater);
+
+    private static native boolean nPrepare(long layerUpdater, int width, int height, boolean isOpaque);
+    private static native void nSetLayerPaint(long layerUpdater, long paint, long colorFilter);
+    private static native void nSetTransform(long layerUpdater, long matrix);
+    private static native void nSetSurfaceTexture(long layerUpdater,
+            SurfaceTexture surface, boolean isAlreadyAttached);
+    private static native void nUpdateSurfaceTexture(long layerUpdater);
+    private static native void nUpdateRenderLayer(long layerUpdater, long displayList,
+            int left, int top, int right, int bottom);
+
+    private static native boolean nFlushChanges(long layerUpdater);
+
+    private static native long nGetLayer(long layerUpdater);
+    private static native int nGetTexName(long layerUpdater);
+
+    private static class Finalizer {
+        private long mDeferredUpdater;
+
+        public Finalizer(long deferredUpdater) {
+            mDeferredUpdater = deferredUpdater;
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                destroy();
+            } finally {
+                super.finalize();
+            }
+        }
+
+        void destroy() {
+            if (mDeferredUpdater != 0) {
+                nDestroyLayerUpdater(mDeferredUpdater);
+                mDeferredUpdater = 0;
+            }
+        }
+    }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 352ab83..93cc9d1 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Bitmap;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
@@ -344,19 +345,20 @@
      * @param layer The hardware layer that needs an update
      *
      * @see #flushLayerUpdates()
-     * @see #cancelLayerUpdate(HardwareLayer)
      */
     abstract void pushLayerUpdate(HardwareLayer layer);
 
     /**
-     * Cancels a queued layer update. If the specified layer was not
-     * queued for update, this method has no effect.
-     *
-     * @param layer The layer whose update to cancel
-     *
-     * @see #pushLayerUpdate(HardwareLayer)
+     * Tells the HardwareRenderer that a layer was created. The renderer should
+     * make sure to apply any pending layer changes at the start of a new frame
      */
-    abstract void cancelLayerUpdate(HardwareLayer layer);
+    abstract void onLayerCreated(HardwareLayer hardwareLayer);
+
+    /**
+     * Tells the HardwareRenderer that the layer is destroyed. The renderer
+     * should remove the layer from any update queues.
+     */
+    abstract void onLayerDestroyed(HardwareLayer layer);
 
     /**
      * Forces all enqueued layer updates to be executed immediately.
@@ -403,22 +405,19 @@
      * Creates a new hardware layer. A hardware layer built by calling this
      * method will be treated as a texture layer, instead of as a render target.
      *
-     * @param isOpaque Whether the layer should be opaque or not
-     *
      * @return A hardware layer
      */
-    abstract HardwareLayer createHardwareLayer(boolean isOpaque);
+    abstract HardwareLayer createTextureLayer();
 
     /**
      * Creates a new hardware layer.
      *
      * @param width The minimum width of the layer
      * @param height The minimum height of the layer
-     * @param isOpaque Whether the layer should be opaque or not
      *
      * @return A hardware layer
      */
-    abstract HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque);
+    abstract HardwareLayer createDisplayListLayer(int width, int height);
 
     /**
      * Creates a new {@link SurfaceTexture} that can be used to render into the
@@ -430,14 +429,7 @@
      */
     abstract SurfaceTexture createSurfaceTexture(HardwareLayer layer);
 
-    /**
-     * Sets the {@link android.graphics.SurfaceTexture} that will be used to
-     * render into the specified hardware layer.
-     *
-     * @param layer The layer to render into using a {@link android.graphics.SurfaceTexture}
-     * @param surfaceTexture The {@link android.graphics.SurfaceTexture} to use for the layer
-     */
-    abstract void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture);
+    abstract boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap);
 
     /**
      * Detaches the specified functor from the current functor execution queue.
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 161fe33..e789407 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -250,7 +250,7 @@
             mSurface.detachFromGLContext();
             // SurfaceTexture owns the texture name and detachFromGLContext
             // should have deleted it
-            mLayer.clearStorage();
+            mLayer.onTextureDestroyed();
 
             boolean shouldRelease = true;
             if (mListener != null) {
@@ -375,7 +375,7 @@
                 return null;
             }
 
-            mLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(mOpaque);
+            mLayer = mAttachInfo.mHardwareRenderer.createTextureLayer();
             if (!mUpdateSurface) {
                 // Create a new SurfaceTexture for the layer.
                 mSurface = mAttachInfo.mHardwareRenderer.createSurfaceTexture(mLayer);
@@ -416,7 +416,7 @@
             updateLayer();
             mMatrixChanged = true;
 
-            mAttachInfo.mHardwareRenderer.setSurfaceTexture(mLayer, mSurface);
+            mLayer.setSurfaceTexture(mSurface);
             mSurface.setDefaultBufferSize(getWidth(), getHeight());
         }
 
@@ -469,7 +469,8 @@
             }
         }
         
-        mLayer.update(getWidth(), getHeight(), mOpaque);
+        mLayer.prepare(getWidth(), getHeight(), mOpaque);
+        mLayer.updateSurfaceTexture();
 
         if (mListener != null) {
             mListener.onSurfaceTextureUpdated(mSurface);
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2c9f1d9..1c20923 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.SurfaceTexture;
 import android.os.SystemClock;
@@ -155,7 +156,12 @@
     }
 
     @Override
-    void cancelLayerUpdate(HardwareLayer layer) {
+    void onLayerCreated(HardwareLayer layer) {
+        throw new NoSuchMethodError();
+    }
+
+    @Override
+    void onLayerDestroyed(HardwareLayer layer) {
         throw new NoSuchMethodError();
     }
 
@@ -197,12 +203,12 @@
     }
 
     @Override
-    HardwareLayer createHardwareLayer(boolean isOpaque) {
+    HardwareLayer createTextureLayer() {
         throw new NoSuchMethodError();
     }
 
     @Override
-    HardwareLayer createHardwareLayer(int width, int height, boolean isOpaque) {
+    HardwareLayer createDisplayListLayer(int width, int height) {
         throw new NoSuchMethodError();
     }
 
@@ -212,7 +218,7 @@
     }
 
     @Override
-    void setSurfaceTexture(HardwareLayer layer, SurfaceTexture surfaceTexture) {
+    boolean copyLayerInto(HardwareLayer layer, Bitmap bitmap) {
         throw new NoSuchMethodError();
     }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fbeddc8..393b166 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -87,7 +87,6 @@
 import com.android.internal.R;
 import com.android.internal.util.Predicate;
 import com.android.internal.view.menu.MenuBuilder;
-
 import com.google.android.collect.Lists;
 import com.google.android.collect.Maps;
 
@@ -13629,16 +13628,10 @@
 
         if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0 || mHardwareLayer == null) {
             if (mHardwareLayer == null) {
-                mHardwareLayer = mAttachInfo.mHardwareRenderer.createHardwareLayer(
-                        width, height, isOpaque());
+                mHardwareLayer = mAttachInfo.mHardwareRenderer.createDisplayListLayer(
+                        width, height);
                 mLocalDirtyRect.set(0, 0, width, height);
-            } else {
-                if (mHardwareLayer.getWidth() != width || mHardwareLayer.getHeight() != height) {
-                    if (mHardwareLayer.resize(width, height)) {
-                        mLocalDirtyRect.set(0, 0, width, height);
-                    }
-                }
-
+            } else if (mHardwareLayer.isValid()) {
                 // This should not be necessary but applications that change
                 // the parameters of their background drawable without calling
                 // this.setBackground(Drawable) can leave the view in a bad state
@@ -13646,23 +13639,24 @@
                 // not opaque.)
                 computeOpaqueFlags();
 
-                final boolean opaque = isOpaque();
-                if (mHardwareLayer.isValid() && mHardwareLayer.isOpaque() != opaque) {
-                    mHardwareLayer.setOpaque(opaque);
+                if (mHardwareLayer.prepare(width, height, isOpaque())) {
                     mLocalDirtyRect.set(0, 0, width, height);
                 }
             }
 
             // The layer is not valid if the underlying GPU resources cannot be allocated
+            mHardwareLayer.flushChanges();
             if (!mHardwareLayer.isValid()) {
                 return null;
             }
 
             mHardwareLayer.setLayerPaint(mLayerPaint);
-            mHardwareLayer.redrawLater(getHardwareLayerDisplayList(mHardwareLayer), mLocalDirtyRect);
-            ViewRootImpl viewRoot = getViewRootImpl();
-            if (viewRoot != null) viewRoot.pushHardwareLayerUpdate(mHardwareLayer);
-
+            DisplayList displayList = mHardwareLayer.startRecording();
+            if (getDisplayList(displayList, true) != displayList) {
+                throw new IllegalStateException("getDisplayList() didn't return"
+                        + " the input displaylist for a hardware layer!");
+            }
+            mHardwareLayer.endRecording(mLocalDirtyRect);
             mLocalDirtyRect.setEmpty();
         }
 
@@ -13679,18 +13673,11 @@
      */
     boolean destroyLayer(boolean valid) {
         if (mHardwareLayer != null) {
-            AttachInfo info = mAttachInfo;
-            if (info != null && info.mHardwareRenderer != null &&
-                    info.mHardwareRenderer.isEnabled() &&
-                    (valid || info.mHardwareRenderer.validate())) {
+            mHardwareLayer.destroy();
+            mHardwareLayer = null;
 
-                info.mHardwareRenderer.cancelLayerUpdate(mHardwareLayer);
-                mHardwareLayer.destroy();
-                mHardwareLayer = null;
-
-                invalidate(true);
-                invalidateParentCaches();
-            }
+            invalidate(true);
+            invalidateParentCaches();
             return true;
         }
         return false;
@@ -13911,19 +13898,6 @@
     }
 
     /**
-     * Get the DisplayList for the HardwareLayer
-     *
-     * @param layer The HardwareLayer whose DisplayList we want
-     * @return A DisplayList fopr the specified HardwareLayer
-     */
-    private DisplayList getHardwareLayerDisplayList(HardwareLayer layer) {
-        DisplayList displayList = getDisplayList(layer.getDisplayList(), true);
-        layer.setDisplayList(displayList);
-        return displayList;
-    }
-
-
-    /**
      * <p>Returns a display list that can be used to draw this view again
      * without executing its draw method.</p>
      *
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ccb85a6..ef69948 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -642,12 +642,6 @@
         }
     }
 
-    void pushHardwareLayerUpdate(HardwareLayer layer) {
-        if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
-            mAttachInfo.mHardwareRenderer.pushLayerUpdate(layer);
-        }
-    }
-
     void flushHardwareLayerUpdates() {
         if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled() &&
                 mAttachInfo.mHardwareRenderer.validate()) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index ff6e8f7..d8041c5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -57,6 +57,7 @@
 	android_view_GraphicBuffer.cpp \
 	android_view_GLRenderer.cpp \
 	android_view_GLES20Canvas.cpp \
+	android_view_HardwareLayer.cpp \
 	android_view_ThreadedRenderer.cpp \
 	android_view_MotionEvent.cpp \
 	android_view_PointerIcon.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7ed6641..77c5c18 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -123,6 +123,7 @@
 extern int register_android_view_GraphicBuffer(JNIEnv* env);
 extern int register_android_view_GLES20Canvas(JNIEnv* env);
 extern int register_android_view_GLRenderer(JNIEnv* env);
+extern int register_android_view_HardwareLayer(JNIEnv* env);
 extern int register_android_view_ThreadedRenderer(JNIEnv* env);
 extern int register_android_view_Surface(JNIEnv* env);
 extern int register_android_view_SurfaceControl(JNIEnv* env);
@@ -1127,6 +1128,7 @@
     REG_JNI(register_android_view_GraphicBuffer),
     REG_JNI(register_android_view_GLES20Canvas),
     REG_JNI(register_android_view_GLRenderer),
+    REG_JNI(register_android_view_HardwareLayer),
     REG_JNI(register_android_view_ThreadedRenderer),
     REG_JNI(register_android_view_Surface),
     REG_JNI(register_android_view_SurfaceControl),
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index b854fb9..dd089f2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -914,147 +914,6 @@
     renderer->resume();
 }
 
-static jint android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env,
-        jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        OpenGLRenderer* renderer = new LayerRenderer(layer);
-        renderer->initProperties();
-        return reinterpret_cast<jint>(renderer);
-    }
-    return NULL;
-}
-
-static jlong android_view_GLES20Canvas_createTextureLayer(JNIEnv* env, jobject clazz,
-        jboolean isOpaque, jintArray layerInfo) {
-    Layer* layer = LayerRenderer::createTextureLayer(isOpaque);
-
-    if (layer) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getTexture();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-    }
-
-    return reinterpret_cast<jlong>(layer);
-}
-
-static jlong android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
-        jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
-    Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
-
-    if (layer) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getWidth();
-        storage[1] = layer->getHeight();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-    }
-
-    return reinterpret_cast<jlong>(layer);
-}
-
-static jboolean android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jint width, jint height, jintArray layerInfo) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (LayerRenderer::resizeLayer(layer, width, height)) {
-        jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layer->getWidth();
-        storage[1] = layer->getHeight();
-        env->ReleaseIntArrayElements(layerInfo, storage, 0);
-        return JNI_TRUE;
-    }
-    return JNI_FALSE;
-}
-
-static void android_view_GLES20Canvas_setLayerPaint(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong paintPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
-        layer->setPaint(paint);
-    }
-}
-
-static void android_view_GLES20Canvas_setLayerColorFilter(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong colorFilterPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
-        layer->setColorFilter(colorFilter);
-    }
-}
-
-static void android_view_GLES20Canvas_setOpaqueLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jboolean isOpaque) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    if (layer) {
-        layer->setBlend(!isOpaque);
-    }
-}
-
-static void android_view_GLES20Canvas_updateTextureLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jint width, jint height, jboolean isOpaque, jobject surface) {
-    float transform[16];
-    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
-
-    if (surfaceTexture->updateTexImage() == NO_ERROR) {
-        int64_t frameNumber = surfaceTexture->getFrameNumber();
-        // If the GLConsumer queue is in synchronous mode, need to discard all
-        // but latest frame, using the frame number to tell when we no longer
-        // have newer frames to target. Since we can't tell which mode it is in,
-        // do this unconditionally.
-        int dropCounter = 0;
-        while (surfaceTexture->updateTexImage() == NO_ERROR) {
-            int64_t newFrameNumber = surfaceTexture->getFrameNumber();
-            if (newFrameNumber == frameNumber) break;
-            frameNumber = newFrameNumber;
-            dropCounter++;
-        }
-        #if DEBUG_RENDERER
-        if (dropCounter > 0) {
-            RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
-        }
-        #endif
-        surfaceTexture->getTransformMatrix(transform);
-        GLenum renderTarget = surfaceTexture->getCurrentTextureTarget();
-
-        Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-        LayerRenderer::updateTextureLayer(layer, width, height, isOpaque, renderTarget, transform);
-    }
-}
-
-static void android_view_GLES20Canvas_updateRenderLayer(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong rendererPtr, jlong displayListPtr,
-        jint left, jint top, jint right, jint bottom) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
-    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
-    layer->updateDeferred(renderer, displayList, left, top, right, bottom);
-}
-
-static void android_view_GLES20Canvas_clearLayerTexture(JNIEnv* env, jobject clazz,
-        jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    layer->clearTexture();
-}
-
-static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
-        jlong layerPtr, jlong matrixPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
-    layer->getTransform().load(*matrix);
-}
-
-static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    LayerRenderer::destroyLayer(layer);
-}
-
-static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
-        jobject clazz, jlong layerPtr) {
-    Layer* layer = reinterpret_cast<Layer*>(layerPtr);
-    LayerRenderer::destroyLayerDeferred(layer);
-}
-
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         jlong rendererPtr, jlong layerPtr, jfloat x, jfloat y) {
     OpenGLRenderer* renderer = reinterpret_cast<OpenGLRenderer*>(rendererPtr);
@@ -1247,19 +1106,6 @@
     { "nInterrupt",              "(J)V",       (void*) android_view_GLES20Canvas_interrupt },
     { "nResume",                 "(J)V",       (void*) android_view_GLES20Canvas_resume },
 
-    { "nCreateLayerRenderer",    "(J)J",       (void*) android_view_GLES20Canvas_createLayerRenderer },
-    { "nCreateLayer",            "(IIZ[I)J",   (void*) android_view_GLES20Canvas_createLayer },
-    { "nResizeLayer",            "(JII[I)Z" ,  (void*) android_view_GLES20Canvas_resizeLayer },
-    { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_GLES20Canvas_setLayerPaint },
-    { "nSetLayerColorFilter",    "(JJ)V",      (void*) android_view_GLES20Canvas_setLayerColorFilter },
-    { "nSetOpaqueLayer",         "(JZ)V",      (void*) android_view_GLES20Canvas_setOpaqueLayer },
-    { "nCreateTextureLayer",     "(Z[I)J",     (void*) android_view_GLES20Canvas_createTextureLayer },
-    { "nUpdateTextureLayer",     "(JIIZLandroid/graphics/SurfaceTexture;)V",
-            (void*) android_view_GLES20Canvas_updateTextureLayer },
-    { "nUpdateRenderLayer",      "(JJJIIII)V", (void*) android_view_GLES20Canvas_updateRenderLayer },
-    { "nClearLayerTexture",      "(J)V",       (void*) android_view_GLES20Canvas_clearLayerTexture },
-    { "nDestroyLayer",           "(J)V",       (void*) android_view_GLES20Canvas_destroyLayer },
-    { "nDestroyLayerDeferred",   "(J)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
     { "nDrawLayer",              "(JJFF)V",    (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(JJ)Z",      (void*) android_view_GLES20Canvas_copyLayer },
     { "nClearLayerUpdates",      "(J)V",       (void*) android_view_GLES20Canvas_clearLayerUpdates },
@@ -1267,8 +1113,6 @@
     { "nPushLayerUpdate",        "(JJ)V",      (void*) android_view_GLES20Canvas_pushLayerUpdate },
     { "nCancelLayerUpdate",      "(JJ)V",      (void*) android_view_GLES20Canvas_cancelLayerUpdate },
 
-    { "nSetTextureLayerTransform", "(JJ)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
-
     { "nGetMaximumTextureWidth",  "()I",       (void*) android_view_GLES20Canvas_getMaxTextureWidth },
     { "nGetMaximumTextureHeight", "()I",       (void*) android_view_GLES20Canvas_getMaxTextureHeight },
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
new file mode 100644
index 0000000..8a0a011
--- /dev/null
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "jni.h"
+#include "GraphicsJNI.h"
+#include <nativehelper/JNIHelp.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_graphics_SurfaceTexture.h>
+
+#include <gui/GLConsumer.h>
+
+#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <SkMatrix.h>
+#include <SkPaint.h>
+#include <SkXfermode.h>
+
+#include <DeferredLayerUpdater.h>
+#include <DisplayList.h>
+#include <LayerRenderer.h>
+#include <SkiaShader.h>
+#include <Rect.h>
+
+namespace android {
+
+using namespace uirenderer;
+
+#ifdef USE_OPENGL_RENDERER
+
+static jlong android_view_HardwareLayer_createTextureLayer(JNIEnv* env, jobject clazz) {
+    Layer* layer = LayerRenderer::createTextureLayer();
+    if (!layer) return 0;
+
+    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer) );
+}
+
+static jlong android_view_HardwareLayer_createRenderLayer(JNIEnv* env, jobject clazz,
+        jint width, jint height) {
+    Layer* layer = LayerRenderer::createRenderLayer(width, height);
+    if (!layer) return 0;
+
+    OpenGLRenderer* renderer = new LayerRenderer(layer);
+    renderer->initProperties();
+    return reinterpret_cast<jlong>( new DeferredLayerUpdater(layer, renderer) );
+}
+
+static void android_view_HardwareLayer_onTextureDestroyed(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    layer->backingLayer()->clearTexture();
+}
+
+static jlong android_view_HardwareLayer_detachBackingLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return reinterpret_cast<jlong>( layer->detachBackingLayer() );
+}
+
+static void android_view_HardwareLayer_destroyLayerUpdater(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    delete layer;
+}
+
+static jboolean android_view_HardwareLayer_prepare(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jint width, jint height, jboolean isOpaque) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    bool changed = false;
+    changed |= layer->setSize(width, height);
+    changed |= layer->setBlend(!isOpaque);
+    return changed;
+}
+
+static void android_view_HardwareLayer_setLayerPaint(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong paintPtr, jlong colorFilterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    if (layer) {
+        SkPaint* paint = reinterpret_cast<SkPaint*>(paintPtr);
+        SkColorFilter* colorFilter = reinterpret_cast<SkColorFilter*>(colorFilterPtr);
+        layer->setPaint(paint);
+        layer->setColorFilter(colorFilter);
+    }
+}
+
+static void android_view_HardwareLayer_setTransform(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong matrixPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixPtr);
+    layer->setTransform(matrix);
+}
+
+static void android_view_HardwareLayer_setSurfaceTexture(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jobject surface, jboolean isAlreadyAttached) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface));
+    layer->setSurfaceTexture(surfaceTexture, !isAlreadyAttached);
+}
+
+static void android_view_HardwareLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    layer->updateTexImage();
+}
+
+static void android_view_HardwareLayer_updateRenderLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr, jlong displayListPtr,
+        jint left, jint top, jint right, jint bottom) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    DisplayList* displayList = reinterpret_cast<DisplayList*>(displayListPtr);
+    layer->setDisplayList(displayList, left, top, right, bottom);
+}
+
+static jboolean android_view_HardwareLayer_flushChanges(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return layer->apply();
+}
+
+static jlong android_view_HardwareLayer_getLayer(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return reinterpret_cast<jlong>( layer->backingLayer() );
+}
+
+static jint android_view_HardwareLayer_getTexName(JNIEnv* env, jobject clazz,
+        jlong layerUpdaterPtr) {
+    DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr);
+    return layer->backingLayer()->getTexture();
+}
+
+#endif // USE_OPENGL_RENDERER
+
+// ----------------------------------------------------------------------------
+// JNI Glue
+// ----------------------------------------------------------------------------
+
+const char* const kClassPathName = "android/view/HardwareLayer";
+
+static JNINativeMethod gMethods[] = {
+#ifdef USE_OPENGL_RENDERER
+
+    { "nCreateTextureLayer",     "()J",        (void*) android_view_HardwareLayer_createTextureLayer },
+    { "nCreateRenderLayer",      "(II)J",      (void*) android_view_HardwareLayer_createRenderLayer },
+    { "nOnTextureDestroyed",     "(J)V",       (void*) android_view_HardwareLayer_onTextureDestroyed },
+    { "nDetachBackingLayer",     "(J)J",       (void*) android_view_HardwareLayer_detachBackingLayer },
+    { "nDestroyLayerUpdater",    "(J)V",       (void*) android_view_HardwareLayer_destroyLayerUpdater },
+
+    { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
+    { "nSetLayerPaint",          "(JJJ)V",     (void*) android_view_HardwareLayer_setLayerPaint },
+    { "nSetTransform",           "(JJ)V",      (void*) android_view_HardwareLayer_setTransform },
+    { "nSetSurfaceTexture",      "(JLandroid/graphics/SurfaceTexture;Z)V",
+            (void*) android_view_HardwareLayer_setSurfaceTexture },
+    { "nUpdateSurfaceTexture",   "(J)V",       (void*) android_view_HardwareLayer_updateSurfaceTexture },
+    { "nUpdateRenderLayer",      "(JJIIII)V",  (void*) android_view_HardwareLayer_updateRenderLayer },
+
+    { "nFlushChanges",           "(J)Z",       (void*) android_view_HardwareLayer_flushChanges },
+
+    { "nGetLayer",               "(J)J",       (void*) android_view_HardwareLayer_getLayer },
+    { "nGetTexName",             "(J)I",       (void*) android_view_HardwareLayer_getTexName },
+#endif
+};
+
+int register_android_view_HardwareLayer(JNIEnv* env) {
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+};
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 8c388d9..495ad19 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -17,6 +17,7 @@
 		Caches.cpp \
 		DisplayList.cpp \
 		DeferredDisplayList.cpp \
+		DeferredLayerUpdater.cpp \
 		DisplayListLogBuffer.cpp \
 		DisplayListRenderer.cpp \
 		Dither.cpp \
@@ -70,7 +71,7 @@
 	LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
 	LOCAL_CFLAGS += -Wno-unused-parameter
 	LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui
+	LOCAL_SHARED_LIBRARIES := liblog libcutils libutils libEGL libGLESv2 libskia libui libgui
 	LOCAL_MODULE := libhwui
 	LOCAL_MODULE_TAGS := optional
 
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
new file mode 100644
index 0000000..ed05d04
--- /dev/null
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2014 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 "DeferredLayerUpdater.h"
+
+#include "OpenGLRenderer.h"
+
+#include "LayerRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+DeferredLayerUpdater::DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer)
+        : mDisplayList(0)
+        , mSurfaceTexture(0)
+        , mTransform(0)
+        , mNeedsGLContextAttach(false)
+        , mUpdateTexImage(false)
+        , mLayer(layer)
+        , mRenderer(renderer)
+        , mCaches(Caches::getInstance()) {
+    mCaches.resourceCache.incrementRefcount(mLayer);
+    mWidth = mLayer->layer.getWidth();
+    mHeight = mLayer->layer.getHeight();
+    mBlend = mLayer->isBlend();
+    mColorFilter = mLayer->getColorFilter();
+    mAlpha = mLayer->getAlpha();
+    mMode = mLayer->getMode();
+    mDirtyRect.setEmpty();
+}
+
+DeferredLayerUpdater::~DeferredLayerUpdater() {
+    setColorFilter(NULL);
+    if (mLayer) {
+        mCaches.resourceCache.decrementRefcount(mLayer);
+    }
+    delete mRenderer;
+}
+
+void DeferredLayerUpdater::setColorFilter(SkColorFilter* colorFilter) {
+    SkRefCnt_SafeAssign(mColorFilter, colorFilter);
+}
+
+void DeferredLayerUpdater::setDisplayList(DisplayList* displayList,
+        int left, int top, int right, int bottom) {
+    mDisplayList = displayList;
+    if (mDirtyRect.isEmpty()) {
+        mDirtyRect.set(left, top, right, bottom);
+    } else {
+        mDirtyRect.unionWith(Rect(left, top, right, bottom));
+    }
+}
+
+bool DeferredLayerUpdater::apply() {
+    bool success = true;
+    // These properties are applied the same to both layer types
+    mLayer->setColorFilter(mColorFilter);
+    mLayer->setAlpha(mAlpha, mMode);
+
+    if (mDisplayList) {
+        if (mWidth != mLayer->layer.getWidth() || mHeight != mLayer->layer.getHeight()) {
+            success = LayerRenderer::resizeLayer(mLayer, mWidth, mHeight);
+        }
+        mLayer->setBlend(mBlend);
+        mLayer->updateDeferred(mRenderer, mDisplayList,
+                mDirtyRect.left, mDirtyRect.top, mDirtyRect.right, mDirtyRect.bottom);
+        mDirtyRect.setEmpty();
+        mDisplayList = 0;
+    } else if (mSurfaceTexture.get()) {
+        if (mNeedsGLContextAttach) {
+            mNeedsGLContextAttach = false;
+            mSurfaceTexture->attachToContext(mLayer->getTexture());
+        }
+        if (mUpdateTexImage) {
+            mUpdateTexImage = false;
+            doUpdateTexImage();
+        }
+        if (mTransform) {
+            mLayer->getTransform().load(*mTransform);
+            setTransform(0);
+        }
+    }
+    return success;
+}
+
+void DeferredLayerUpdater::doUpdateTexImage() {
+    if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
+        float transform[16];
+
+        int64_t frameNumber = mSurfaceTexture->getFrameNumber();
+        // If the GLConsumer queue is in synchronous mode, need to discard all
+        // but latest frame, using the frame number to tell when we no longer
+        // have newer frames to target. Since we can't tell which mode it is in,
+        // do this unconditionally.
+        int dropCounter = 0;
+        while (mSurfaceTexture->updateTexImage() == NO_ERROR) {
+            int64_t newFrameNumber = mSurfaceTexture->getFrameNumber();
+            if (newFrameNumber == frameNumber) break;
+            frameNumber = newFrameNumber;
+            dropCounter++;
+        }
+        #if DEBUG_RENDERER
+        if (dropCounter > 0) {
+            RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
+        }
+        #endif
+        mSurfaceTexture->getTransformMatrix(transform);
+        GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget();
+
+        LayerRenderer::updateTextureLayer(mLayer, mWidth, mHeight, !mBlend,
+                renderTarget, transform);
+    }
+}
+
+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
new file mode 100644
index 0000000..0350eef
--- /dev/null
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 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 DEFERREDLAYERUPDATE_H_
+#define DEFERREDLAYERUPDATE_H_
+
+#include <cutils/compiler.h>
+#include <gui/GLConsumer.h>
+#include <SkColorFilter.h>
+#include <SkMatrix.h>
+#include <utils/StrongPointer.h>
+
+#include "DisplayList.h"
+#include "Layer.h"
+#include "OpenGLRenderer.h"
+#include "Rect.h"
+
+namespace android {
+namespace uirenderer {
+
+// Container to hold the properties a layer should be set to at the start
+// of a render pass
+class DeferredLayerUpdater {
+public:
+    ANDROID_API DeferredLayerUpdater(Layer* layer, OpenGLRenderer* renderer = 0);
+    ANDROID_API ~DeferredLayerUpdater();
+
+    ANDROID_API bool setSize(uint32_t width, uint32_t height) {
+        if (mWidth != width || mHeight != height) {
+            mWidth = width;
+            mHeight = height;
+            return true;
+        }
+        return false;
+    }
+
+    ANDROID_API bool setBlend(bool blend) {
+        if (blend != mBlend) {
+            mBlend = blend;
+            return true;
+        }
+        return false;
+    }
+
+    ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture, bool needsAttach) {
+        if (texture.get() != mSurfaceTexture.get()) {
+            mNeedsGLContextAttach = needsAttach;
+            mSurfaceTexture = texture;
+        }
+    }
+
+    ANDROID_API void updateTexImage() {
+        mUpdateTexImage = true;
+    }
+
+    ANDROID_API void setTransform(const SkMatrix* matrix) {
+        delete mTransform;
+        mTransform = matrix ? new SkMatrix(*matrix) : 0;
+    }
+
+    ANDROID_API void setDisplayList(DisplayList* displayList,
+                int left, int top, int right, int bottom);
+
+    ANDROID_API void setPaint(const SkPaint* paint) {
+        OpenGLRenderer::getAlphaAndModeDirect(paint, &mAlpha, &mMode);
+    }
+
+    ANDROID_API void setColorFilter(SkColorFilter* colorFilter);
+
+    ANDROID_API bool apply();
+    ANDROID_API void applyDeferred(DeferredLayerUpdater* deferredApply);
+
+    ANDROID_API Layer* backingLayer() {
+        return mLayer;
+    }
+
+    ANDROID_API Layer* detachBackingLayer() {
+        Layer* layer = mLayer;
+        mLayer = 0;
+        return layer;
+    }
+
+private:
+    // Generic properties
+    uint32_t mWidth;
+    uint32_t mHeight;
+    bool mBlend;
+    SkColorFilter* mColorFilter;
+    int mAlpha;
+    SkXfermode::Mode mMode;
+
+    // Layer type specific properties
+    // displayList and surfaceTexture are mutually exclusive, only 1 may be set
+    // dirtyRect is only valid if displayList is set
+    DisplayList* mDisplayList;
+    Rect mDirtyRect;
+    sp<GLConsumer> mSurfaceTexture;
+    SkMatrix* mTransform;
+    bool mNeedsGLContextAttach;
+    bool mUpdateTexImage;
+
+    Layer* mLayer;
+    OpenGLRenderer* mRenderer;
+    Caches& mCaches;
+
+    void doUpdateTexImage();
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* DEFERREDLAYERUPDATE_H_ */
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 0b38c4d..ea8eb31 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -184,7 +184,7 @@
 // Layers management
 ///////////////////////////////////////////////////////////////////////////////
 
-Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
+Layer* LayerRenderer::createRenderLayer(uint32_t width, uint32_t height) {
     LAYER_RENDERER_LOGD("Requesting new render layer %dx%d", width, height);
 
     Caches& caches = Caches::getInstance();
@@ -221,7 +221,6 @@
     layer->texCoords.set(0.0f, height / float(layer->getHeight()),
             width / float(layer->getWidth()), 0.0f);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
-    layer->setBlend(!isOpaque);
     layer->setColorFilter(NULL);
     layer->setDirty(true);
     layer->region.clear();
@@ -270,13 +269,12 @@
     return true;
 }
 
-Layer* LayerRenderer::createTextureLayer(bool isOpaque) {
+Layer* LayerRenderer::createTextureLayer() {
     LAYER_RENDERER_LOGD("Creating new texture layer");
 
     Layer* layer = new Layer(0, 0);
     layer->setCacheable(false);
     layer->setTextureLayer(true);
-    layer->setBlend(!isOpaque);
     layer->setEmpty(true);
     layer->setFbo(0);
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index f24c8d4..84acd44 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -52,8 +52,8 @@
     virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
-    ANDROID_API static Layer* createTextureLayer(bool isOpaque);
-    ANDROID_API static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+    ANDROID_API static Layer* createTextureLayer();
+    ANDROID_API static Layer* createRenderLayer(uint32_t width, uint32_t height);
     ANDROID_API static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
     ANDROID_API static void updateTextureLayer(Layer* layer, uint32_t width, uint32_t height,
             bool isOpaque, GLenum renderTarget, float* transform);
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
index 0b85189..8d8d9de 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/CompareActivity.java
@@ -97,7 +97,7 @@
                 Log.d(LOG_TAG, "failure to access hardware layer");
                 return;
             }
-            Method copyInto = hardwareLayer.getClass().getSuperclass()
+            Method copyInto = hardwareLayer.getClass()
                     .getDeclaredMethod("copyInto", Bitmap.class);
             if (!copyInto.isAccessible())
                 copyInto.setAccessible(true);
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index a08b558f..c90b626 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -35,23 +35,24 @@
     private static final boolean LOG_TIMING = false;
     private static final boolean LOG_CALC = false;
 
-    private final RenderScript mRS;
+    private RenderScript mRS;
     private Allocation mIdealPixelsAllocation;
     private Allocation mGivenPixelsAllocation;
     private Allocation mOutputPixelsAllocation;
 
-    private final Allocation mInputRowsAllocation;
-    private final Allocation mOutputRegionsAllocation;
+    private Allocation mInputRowsAllocation;
+    private Allocation mOutputRegionsAllocation;
 
-    private final ScriptC_errorCalculator mScript;
+    private ScriptC_errorCalculator mScript;
 
-    private final int[] mOutputRowRegions;
+    private int[] mOutputRowRegions;
 
     public ErrorCalculator(Context c, Resources resources) {
         int width = resources.getDimensionPixelSize(R.dimen.layer_width);
         int height = resources.getDimensionPixelSize(R.dimen.layer_height);
         mOutputRowRegions = new int[height / REGION_SIZE];
 
+/*
         mRS = RenderScript.create(c);
         int[] rowIndices = new int[height / REGION_SIZE];
         for (int i = 0; i < rowIndices.length; i++)
@@ -67,12 +68,15 @@
         mInputRowsAllocation.copyFrom(rowIndices);
         mOutputRegionsAllocation = Allocation.createSized(mRS, Element.I32(mRS),
                 mOutputRowRegions.length, Allocation.USAGE_SCRIPT);
+*/
     }
 
 
     private static long startMillis, middleMillis;
 
     public float calcErrorRS(Bitmap ideal, Bitmap given) {
+        if (true)
+            return calcError(ideal, given);
         if (LOG_TIMING) {
             startMillis = System.currentTimeMillis();
         }