Merge "Cleanup implementation of hardware layers." into honeycomb
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 7dd6cc6..5fac525 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -83,9 +83,9 @@
     /**
      * Creates a canvas to render into an FBO.
      */
-    GLES20Canvas(int fbo, boolean translucent) {
+    GLES20Canvas(int layer, boolean translucent) {
         mOpaque = !translucent;
-        mRenderer = nCreateLayerRenderer(fbo);
+        mRenderer = nCreateLayerRenderer(layer);
         setupFinalizer();
     }
     
@@ -114,7 +114,7 @@
     }
 
     private static native int nCreateRenderer();
-    private static native int nCreateLayerRenderer(int fbo);
+    private static native int nCreateLayerRenderer(int layer);
     private static native int nGetDisplayListRenderer(int renderer);
     private static native void nDestroyRenderer(int renderer);
 
@@ -156,11 +156,10 @@
     // Hardware layers
     ///////////////////////////////////////////////////////////////////////////
     
-    static native int nCreateLayer(int width, int height, int[] layerInfo);
-    static native void nResizeLayer(int layerId, int layerTextureId, int width, int height,
-            int[] layerInfo);
-    static native void nDestroyLayer(int layerId, int layerTextureId);    
-    static native void nDestroyLayerDeferred(int layerId, int layerTextureId);    
+    static native int nCreateLayer(int width, int height, boolean isOpaque, int[] layerInfo);
+    static native void nResizeLayer(int layerId, int width, int height, int[] layerInfo);
+    static native void nDestroyLayer(int layerId);
+    static native void nDestroyLayerDeferred(int layerId);
 
     ///////////////////////////////////////////////////////////////////////////
     // Canvas management
@@ -257,18 +256,15 @@
     // Hardware layer
     ///////////////////////////////////////////////////////////////////////////
     
-    void drawHardwareLayer(float left, float top, float right, float bottom,
-            HardwareLayer layer, Paint paint) {
+    void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         final GLES20Layer glLayer = (GLES20Layer) layer;
         boolean hasColorFilter = paint != null && setupColorFilter(paint);
         final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawLayer(mRenderer, left, top, right, bottom, glLayer.mLayerTextureId,
-                glLayer.getU(), glLayer.getV(), nativePaint);
+        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
         if (hasColorFilter) nResetModifiers(mRenderer);
     }
 
-    private native void nDrawLayer(int renderer, float left, float top, float right, float bottom,
-            int layerTexture, float u, float v, int paint);
+    private native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
     
     void interrupt() {
         nInterrupt(mRenderer);
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 7587657..0230430 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -22,52 +22,45 @@
  * An OpenGL ES 2.0 implementation of {@link HardwareLayer}.
  */
 class GLES20Layer extends HardwareLayer {
-    private int mLayerId;
-    int mLayerTextureId;
+    private int mLayer;
 
     private int mLayerWidth;
     private int mLayerHeight;
 
     private final GLES20Canvas mCanvas;
 
-    private float mU;
-    private float mV;
-
     @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"})
     private final Finalizer mFinalizer;
 
     GLES20Layer(int width, int height, boolean isOpaque) {
         super(width, height, isOpaque);
 
-        int[] layerInfo = new int[3];
-        mLayerId = GLES20Canvas.nCreateLayer(width, height, layerInfo);
-        if (mLayerId != 0) {
+        int[] layerInfo = new int[2];
+        mLayer = GLES20Canvas.nCreateLayer(width, height, isOpaque, layerInfo);
+        if (mLayer != 0) {
             mLayerWidth = layerInfo[0];
             mLayerHeight = layerInfo[1];
-            mLayerTextureId = layerInfo[2];
 
-            mCanvas = new GLES20Canvas(mLayerId, !isOpaque);
-            mFinalizer = new Finalizer(mLayerId, mLayerTextureId);
-            
-            mU = mWidth / (float) mLayerWidth;
-            mV = mHeight/ (float) mLayerHeight;
+            mCanvas = new GLES20Canvas(mLayer, !isOpaque);
+            mFinalizer = new Finalizer(mLayer);
         } else {
             mCanvas = null;
             mFinalizer = null;
         }
     }
 
-    float getU() {
-        return mU;
-    }
-
-    float getV() {
-        return mV;
+    /**
+     * 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 int getLayer() {
+        return mLayer;
     }
 
     @Override
     boolean isValid() {
-        return mLayerId != 0 && mLayerWidth > 0 && mLayerHeight > 0;
+        return mLayer != 0 && mLayerWidth > 0 && mLayerHeight > 0;
     }
 
     @Override
@@ -77,15 +70,12 @@
             mWidth = width;
             mHeight = height;
 
-            int[] layerInfo = new int[3];
+            int[] layerInfo = new int[2];
 
-            GLES20Canvas.nResizeLayer(mLayerId, mLayerTextureId, width, height, layerInfo);
+            GLES20Canvas.nResizeLayer(mLayer, width, height, layerInfo);
 
             mLayerWidth = layerInfo[0];
             mLayerHeight = layerInfo[1];
-
-            mU = mWidth / (float) mLayerWidth;
-            mV = mHeight/ (float) mLayerHeight;            
         }
     }
 
@@ -112,23 +102,21 @@
     @Override
     void destroy() {
         mFinalizer.destroy();
-        mLayerId = mLayerTextureId = 0;
+        mLayer = 0;
     }
 
     private static class Finalizer {
         private int mLayerId;
-        private int mLayerTextureId;
 
-        public Finalizer(int layerId, int layerTextureId) {
+        public Finalizer(int layerId) {
             mLayerId = layerId;
-            mLayerTextureId = layerTextureId;
         }
 
         @Override
         protected void finalize() throws Throwable {
             try {
-                if (mLayerId != 0 || mLayerTextureId != 0) {
-                    GLES20Canvas.nDestroyLayerDeferred(mLayerId, mLayerTextureId);
+                if (mLayerId != 0) {
+                    GLES20Canvas.nDestroyLayerDeferred(mLayerId);
                 }
             } finally {
                 super.finalize();
@@ -136,8 +124,8 @@
         }
 
         void destroy() {
-            GLES20Canvas.nDestroyLayer(mLayerId, mLayerTextureId);
-            mLayerId = mLayerTextureId = 0;
+            GLES20Canvas.nDestroyLayer(mLayerId);
+            mLayerId = 0;
         }
     }
 }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index 1a5df98..2273238 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -54,13 +54,10 @@
     /**
      * Draws the specified layer onto this canvas.
      *
-     * @param left The left coordinate of the layer
-     * @param top The top coordinate of the layer
-     * @param right The right coordinate of the layer
-     * @param bottom The bottom coordinate of the layer
      * @param layer The layer to composite on this canvas
+     * @param x The left coordinate of the layer
+     * @param y The top coordinate of the layer
      * @param paint The paint used to draw the layer
      */
-    abstract void drawHardwareLayer(float left, float top, float right, float bottom,
-            HardwareLayer layer, Paint paint); 
+    abstract void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint); 
 }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d586043..0186f21 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2397,8 +2397,7 @@
             if (!layerSaved && layerType == LAYER_TYPE_HARDWARE) {
                 final HardwareLayer layer = child.getHardwareLayer(canvas);
                 if (layer != null && layer.isValid()) {
-                    ((HardwareCanvas) canvas).drawHardwareLayer(0, 0, cr - cl, cb - ct,
-                            layer, child.mLayerPaint);
+                    ((HardwareCanvas) canvas).drawHardwareLayer(layer, 0, 0, child.mLayerPaint);
                     layerRendered = true;
                 } else {
                     canvas.saveLayer(sx, sy, sx + cr - cl, sy + cb - ct, child.mLayerPaint,
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 4aed9b1..40cec3e 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -458,59 +458,49 @@
 }
 
 static OpenGLRenderer* android_view_GLES20Canvas_createLayerRenderer(JNIEnv* env,
-        jobject clazz, jint fbo) {
-    return new LayerRenderer(fbo);
+        jobject clazz, Layer* layer) {
+    if (layer) {
+        return new LayerRenderer(layer);
+    }
+    return NULL;
 }
 
-static jint android_view_GLES20Canvas_createLayer(JNIEnv* env,
-        jobject clazz, jint width, jint height, jintArray layerInfo) {
-    uint32_t layerWidth = 0;
-    uint32_t layerHeight = 0;
-    GLuint textureId = 0;
+static Layer* android_view_GLES20Canvas_createLayer(JNIEnv* env, jobject clazz,
+        jint width, jint height, jboolean isOpaque, jintArray layerInfo) {
+    Layer* layer = LayerRenderer::createLayer(width, height, isOpaque);
 
-    jint layerId = LayerRenderer::createLayer(width, height,
-            &layerWidth, &layerHeight, &textureId);
-
-    if (layerId) {
+    if (layer) {
         jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-        storage[0] = layerWidth;
-        storage[1] = layerHeight;
-        storage[2] = textureId;
+        storage[0] = layer->width;
+        storage[1] = layer->height;
         env->ReleaseIntArrayElements(layerInfo, storage, 0);
     }
 
-    return layerId;
+    return layer;
 }
 
-static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env,
-        jobject clazz, jint layerId, jint layerTextureId, jint width, jint height,
-        jintArray layerInfo) {
-    uint32_t layerWidth = 0;
-    uint32_t layerHeight = 0;
-
-    LayerRenderer::resizeLayer(layerId, layerTextureId, width, height, &layerWidth, &layerHeight);
+static void android_view_GLES20Canvas_resizeLayer(JNIEnv* env, jobject clazz,
+        Layer* layer, jint width, jint height, jintArray layerInfo) {
+    LayerRenderer::resizeLayer(layer, width, height);
 
     jint* storage = env->GetIntArrayElements(layerInfo, NULL);
-    storage[0] = layerWidth;
-    storage[1] = layerHeight;
+    storage[0] = layer->width;
+    storage[1] = layer->height;
     env->ReleaseIntArrayElements(layerInfo, storage, 0);
 }
 
-static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env,
-        jobject clazz, jint layerId, jint layerTextureId) {
-    LayerRenderer::destroyLayer(layerId, layerTextureId);
+static void android_view_GLES20Canvas_destroyLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+    LayerRenderer::destroyLayer(layer);
 }
 
 static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
-        jobject clazz, jint layerId, jint layerTextureId) {
-    LayerRenderer::destroyLayerDeferred(layerId, layerTextureId);
+        jobject clazz, Layer* layer) {
+    LayerRenderer::destroyLayerDeferred(layer);
 }
 
-static void android_view_GLES20Canvas_drawLayer(JNIEnv* env,
-        jobject canvas, OpenGLRenderer* renderer,
-        jfloat left, jfloat top, jfloat right, jfloat bottom,
-        jint layerTexture, jfloat u, jfloat v, SkPaint* paint) {
-    renderer->drawLayer(layerTexture, left, top, right, bottom, u, v, paint);
+static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject canvas,
+        OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
+    renderer->drawLayer(layer, x, y, paint);
 }
 
 #endif // USE_OPENGL_RENDERER
@@ -602,12 +592,11 @@
     { "nResume",                 "(I)V",       (void*) android_view_GLES20Canvas_resume },
 
     { "nCreateLayerRenderer",    "(I)I",       (void*) android_view_GLES20Canvas_createLayerRenderer },
-    { "nCreateLayer",            "(II[I)I",    (void*) android_view_GLES20Canvas_createLayer },
-    { "nResizeLayer",            "(IIII[I)V",  (void*) android_view_GLES20Canvas_resizeLayer },
-    { "nDestroyLayer",           "(II)V",      (void*) android_view_GLES20Canvas_destroyLayer },
-    { "nDestroyLayerDeferred",   "(II)V",      (void*) android_view_GLES20Canvas_destroyLayerDeferred },
-    { "nDrawLayer",              "(IFFFFIFFI)V",
-            (void*) android_view_GLES20Canvas_drawLayer },
+    { "nCreateLayer",            "(IIZ[I)I",   (void*) android_view_GLES20Canvas_createLayer },
+    { "nResizeLayer",            "(III[I)V" ,  (void*) android_view_GLES20Canvas_resizeLayer },
+    { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
+    { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+    { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
 
 #endif
 };
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 3563064..fde4f96 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -109,29 +109,22 @@
 
     Mutex::Autolock _l(mGarbageLock);
 
-    size_t count = mFboGarbage.size();
+    size_t count = mLayerGarbage.size();
     for (size_t i = 0; i < count; i++) {
-        GLuint fbo = mFboGarbage.itemAt(i);
-        if (fbo) glDeleteFramebuffers(1, &fbo);
-    }
-    mFboGarbage.clear();
+        Layer* layer = mLayerGarbage.itemAt(i);
+        if (layer) {
+            if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo);
+            if (layer->texture) glDeleteTextures(1, &layer->texture);
 
-    count = mTextureGarbage.size();
-    for (size_t i = 0; i < count; i++) {
-        GLuint texture = mTextureGarbage.itemAt(i);
-        if (texture) glDeleteTextures(1, &texture);
+            delete layer;
+        }
     }
-    mTextureGarbage.clear();
+    mLayerGarbage.clear();
 }
 
-void Caches::deleteFboDeferred(GLuint fbo) {
+void Caches::deleteLayerDeferred(Layer* layer) {
     Mutex::Autolock _l(mGarbageLock);
-    mFboGarbage.push(fbo);
-}
-
-void Caches::deleteTextureDeferred(GLuint texture) {
-    Mutex::Autolock _l(mGarbageLock);
-    mTextureGarbage.push(texture);
+    mLayerGarbage.push(layer);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 34f48c9..a11b6bc 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -91,8 +91,7 @@
     GLuint mRegionMeshIndices;
 
     mutable Mutex mGarbageLock;
-    Vector<GLuint> mFboGarbage;
-    Vector<GLuint> mTextureGarbage;
+    Vector<Layer*> mLayerGarbage;
 
 public:
     /**
@@ -110,14 +109,9 @@
     void clearGarbage();
 
     /**
-     * Can be used to delete an FBO from a non EGL thread.
+     * Can be used to delete a layer from a non EGL thread.
      */
-    void deleteFboDeferred(GLuint fbo);
-
-    /**
-     * Can be used to delete a texture from a non EGL thread.
-     */
-    void deleteTextureDeferred(GLuint texture);
+    void deleteLayerDeferred(Layer* layer);
 
     /**
      * Binds the VBO used to render simple textured quads.
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index fdb4e8c..57df976 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -242,8 +242,7 @@
             }
             break;
             case DrawLayer: {
-                renderer.drawLayer(getInt(), getFloat(), getFloat(), getFloat(), getFloat(),
-                        getFloat(), getFloat(), getPaint());
+                renderer.drawLayer((Layer*) getInt(), getFloat(), getFloat(), getPaint());
             }
             break;
             case DrawBitmap: {
@@ -488,13 +487,10 @@
     addDisplayList(displayList);
 }
 
-void DisplayListRenderer::drawLayer(int texture, float left, float top, float right, float bottom,
-        float u, float v, SkPaint* paint) {
+void DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
     addOp(DisplayList::DrawLayer);
-    addInt(texture);
-    addBounds(left, top, right, bottom);
-    addFloat(u);
-    addFloat(v);
+    addInt((int) layer);
+    addPoint(x, y);
     addPaint(paint);
 }
 
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 62cb0e8..0822725 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -246,8 +246,7 @@
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     void drawDisplayList(DisplayList* displayList);
-    void drawLayer(int texture, float left, float top, float right, float bottom,
-            float u, float v, SkPaint* paint);
+    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index b838764..a25c95e 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -27,10 +27,10 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void LayerRenderer::prepare(bool opaque) {
-    LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mFbo);
+    LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->fbo);
 
     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &mPreviousFbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, mLayer->fbo);
 
     OpenGLRenderer::prepare(opaque);
 }
@@ -39,33 +39,33 @@
     OpenGLRenderer::finish();
     glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFbo);
 
-    LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mFbo);
+    LAYER_RENDERER_LOGD("Finished rendering into layer, fbo = %d", mLayer->mFbo);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 // Static functions
 ///////////////////////////////////////////////////////////////////////////////
 
-GLuint LayerRenderer::createLayer(uint32_t width, uint32_t height,
-        uint32_t* layerWidth, uint32_t* layerHeight, GLuint* texture) {
+Layer* LayerRenderer::createLayer(uint32_t width, uint32_t height, bool isOpaque) {
     LAYER_RENDERER_LOGD("Creating new layer %dx%d", width, height);
 
+    Layer* layer = new Layer(width, height);
+
     GLuint previousFbo;
     glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*) &previousFbo);
 
-    GLuint fbo = 0;
-    glGenFramebuffers(1, &fbo);
-    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+    glGenFramebuffers(1, &layer->fbo);
+    glBindFramebuffer(GL_FRAMEBUFFER, layer->fbo);
 
     if (glGetError() != GL_NO_ERROR) {
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-        glDeleteBuffers(1, &fbo);
+        glDeleteBuffers(1, &layer->fbo);
         return 0;
     }
 
     glActiveTexture(GL_TEXTURE0);
-    glGenTextures(1, texture);
-    glBindTexture(GL_TEXTURE_2D, *texture);
+    glGenTextures(1, &layer->texture);
+    glBindTexture(GL_TEXTURE_2D, layer->texture);
 
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 
@@ -80,66 +80,81 @@
 
     if (glGetError() != GL_NO_ERROR) {
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-        glDeleteBuffers(1, &fbo);
-        glDeleteTextures(1, texture);
+        glDeleteBuffers(1, &layer->fbo);
+        glDeleteTextures(1, &layer->texture);
+        delete layer;
         return 0;
     }
 
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
-                *texture, 0);
+            layer->texture, 0);
 
     if (glGetError() != GL_NO_ERROR) {
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
-        glDeleteBuffers(1, &fbo);
-        glDeleteTextures(1, texture);
+        glDeleteBuffers(1, &layer->fbo);
+        glDeleteTextures(1, &layer->texture);
+        delete layer;
         return 0;
     }
 
     glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
 
-    *layerWidth = width;
-    *layerHeight = height;
+    layer->layer.set(0.0f, 0.0f, width, height);
+    layer->texCoords.set(0.0f, 1.0f, 1.0f, 0.0f);
+    layer->alpha = 255;
+    layer->mode = SkXfermode::kSrcOver_Mode;
+    layer->blend = !isOpaque;
+    layer->empty = false;
+    layer->colorFilter = NULL;
 
-    return fbo;
+    return layer;
 }
 
-void LayerRenderer::resizeLayer(GLuint fbo, GLuint texture, uint32_t width, uint32_t height,
-        uint32_t* layerWidth, uint32_t* layerHeight) {
-    LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", fbo, width, height);
+bool LayerRenderer::resizeLayer(Layer* layer, uint32_t width, uint32_t height) {
+    if (layer) {
+        LAYER_RENDERER_LOGD("Resizing layer fbo = %d to %dx%d", layer->fbo, width, height);
 
-    glActiveTexture(GL_TEXTURE0);
-    glBindTexture(GL_TEXTURE_2D, texture);
+        glActiveTexture(GL_TEXTURE0);
+        glBindTexture(GL_TEXTURE_2D, layer->texture);
 
-    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
-            GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 
-    if (glGetError() != GL_NO_ERROR) {
-        glDeleteBuffers(1, &fbo);
-        glDeleteTextures(1, &texture);
+        if (glGetError() != GL_NO_ERROR) {
+            glDeleteBuffers(1, &layer->fbo);
+            glDeleteTextures(1, &layer->texture);
 
-        *layerWidth = 0;
-        *layerHeight = 0;
+            layer->width = 0;
+            layer->height = 0;
+            layer->fbo = 0;
+            layer->texture = 0;
 
-        return;
+            return false;
+        }
+
+        layer->width = width;
+        layer->height = height;
     }
-
-    *layerWidth = width;
-    *layerHeight = height;
+    return true;
 }
 
-void LayerRenderer::destroyLayer(GLuint fbo, GLuint texture) {
-    LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", fbo);
+void LayerRenderer::destroyLayer(Layer* layer) {
+    if (layer) {
+        LAYER_RENDERER_LOGD("Destroying layer, fbo = %d", layer->fbo);
 
-    if (fbo) glDeleteFramebuffers(1, &fbo);
-    if (texture) glDeleteTextures(1, &texture);
+        if (layer->fbo) glDeleteFramebuffers(1, &layer->fbo);
+        if (layer->texture) glDeleteTextures(1, &layer->texture);
+
+        delete layer;
+    }
 }
 
-void LayerRenderer::destroyLayerDeferred(GLuint fbo, GLuint texture) {
-    LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", fbo);
+void LayerRenderer::destroyLayerDeferred(Layer* layer) {
+    if (layer) {
+        LAYER_RENDERER_LOGD("Deferring layer destruction, fbo = %d", layer->fbo);
 
-    Caches& caches = Caches::getInstance();
-    if (fbo) caches.deleteFboDeferred(fbo);
-    if (texture) caches.deleteTextureDeferred(texture);
+        Caches::getInstance().deleteLayerDeferred(layer);
+    }
 }
 
 }; // namespace uirenderer
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index be68412..ed5d960 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -18,6 +18,7 @@
 #define ANDROID_HWUI_LAYER_RENDERER_H
 
 #include "OpenGLRenderer.h"
+#include "Layer.h"
 
 namespace android {
 namespace uirenderer {
@@ -39,7 +40,7 @@
 
 class LayerRenderer: public OpenGLRenderer {
 public:
-    LayerRenderer(GLuint fbo): mFbo(fbo) {
+    LayerRenderer(Layer* layer): mLayer(layer) {
     }
 
     ~LayerRenderer() {
@@ -48,15 +49,13 @@
     void prepare(bool opaque);
     void finish();
 
-    static GLuint createLayer(uint32_t width, uint32_t height,
-            uint32_t* layerWidth, uint32_t* layerHeight, GLuint* texture);
-    static void resizeLayer(GLuint fbo, GLuint texture, uint32_t width, uint32_t height,
-            uint32_t* layerWidth, uint32_t* layerHeight);
-    static void destroyLayer(GLuint fbo, GLuint texture);
-    static void destroyLayerDeferred(GLuint fbo, GLuint texture);
+    static Layer* createLayer(uint32_t width, uint32_t height, bool isOpaque = false);
+    static bool resizeLayer(Layer* layer, uint32_t width, uint32_t height);
+    static void destroyLayer(Layer* layer);
+    static void destroyLayerDeferred(Layer* layer);
 
 private:
-    GLuint mFbo;
+    Layer* mLayer;
     GLuint mPreviousFbo;
 
 }; // class LayerRenderer
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
index 1cf3d20..f71e5d6 100644
--- a/libs/hwui/OpenGLDebugRenderer.cpp
+++ b/libs/hwui/OpenGLDebugRenderer.cpp
@@ -54,6 +54,12 @@
     OpenGLRenderer::drawDisplayList(displayList);
 }
 
+void OpenGLDebugRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawLayer");
+    OpenGLRenderer::drawLayer(layer, x, y, paint);
+}
+
 void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
         SkPaint* paint) {
     mPrimitivesCount++;
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
index ee34d73..1cef267 100644
--- a/libs/hwui/OpenGLDebugRenderer.h
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -41,6 +41,7 @@
             SkPaint* p, int flags);
 
     void drawDisplayList(DisplayList* displayList);
+    void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 9beb227..7f7deec 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -622,10 +622,12 @@
         setupDraw();
         setupDrawWithTexture();
         setupDrawColor(alpha, alpha, alpha, alpha);
+        setupDrawColorFilter();
         setupDrawBlending(layer->blend || layer->alpha < 255, layer->mode, false);
         setupDrawProgram();
         setupDrawDirtyRegionsDisabled();
         setupDrawPureColorUniforms();
+        setupDrawColorFilterUniforms();
         setupDrawTexture(layer->texture);
         setupDrawModelViewTranslate(rect.left, rect.top, rect.right, rect.bottom);
         setupDrawMesh(&mesh[0].position[0], &mesh[0].texture[0]);
@@ -1485,28 +1487,22 @@
     finishDrawTexture();
 }
 
-void OpenGLRenderer::drawLayer(int texture, float left, float top, float right, float bottom,
-        float u, float v, SkPaint* paint) {
-    if (quickReject(left, top, right, bottom)) {
+void OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+    if (!layer || quickReject(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight())) {
         return;
     }
 
     glActiveTexture(gTextureUnits[0]);
-    if (!texture) return;
-
-    mCaches.unbindMeshBuffer();
-    resetDrawTextureTexCoords(0.0f, v, u, 0.0f);
 
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    // TODO: Should get the blend info from the caller
-    drawTextureMesh(left, top, right, bottom, texture, alpha / 255.0f, mode, true,
-            &mMeshVertices[0].position[0], &mMeshVertices[0].texture[0],
-            GL_TRIANGLE_STRIP, gMeshCount);
+    layer->alpha = alpha;
+    layer->mode = mode;
 
-    resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
+    const Rect r(x, y, x + layer->layer.getWidth(), y + layer->layer.getHeight());
+    composeLayerRect(layer, r);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 5f45915..da27dac 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -95,8 +95,7 @@
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     virtual void drawDisplayList(DisplayList* displayList);
-    virtual void drawLayer(int texture, float left, float top, float right, float bottom,
-            float u, float v, SkPaint* paint);
+    virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
@@ -133,6 +132,19 @@
      */
     virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
 
+    /**
+     * Mark the layer as dirty at the specified coordinates. The coordinates
+     * are transformed with the supplied matrix.
+     */
+    virtual void dirtyLayer(const float left, const float top,
+            const float right, const float bottom, const mat4 transform);
+
+    /**
+     * Mark the layer as dirty at the specified coordinates.
+     */
+    virtual void dirtyLayer(const float left, const float top,
+            const float right, const float bottom);
+
 private:
     /**
      * Saves the current state of the renderer as a new snapshot.
@@ -402,18 +414,6 @@
         mDirtyClip = true;
     }
 
-    /**
-     * Mark the layer as dirty at the specified coordinates. The coordinates
-     * are transformed with the supplied matrix.
-     */
-    void dirtyLayer(const float left, const float top, const float right, const float bottom,
-            const mat4 transform);
-
-    /**
-     * Mark the layer as dirty at the specified coordinates.
-     */
-    void dirtyLayer(const float left, const float top, const float right, const float bottom);
-
     // Dimensions of the drawing surface
     int mWidth, mHeight;