Discard framebuffer rendering queues when discarding layers
Bug #5581817

Change-Id: Ie30700a29059d2ea60eb7bd3f8bd20ac48a149ab
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index aa0bfd2..43a451d 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -154,6 +154,7 @@
     static native void nSetTextureLayerTransform(int layerId, int matrix);
     static native void nDestroyLayer(int layerId);
     static native void nDestroyLayerDeferred(int layerId);
+    static native void nFlushLayer(int layerId);
     static native boolean nCopyLayer(int layerId, int bitmap);
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index fd3b9e5..4f25792 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -60,6 +60,13 @@
         }
         mLayer = 0;
     }
+    
+    @Override
+    void flush() {
+        if (mLayer != 0) {
+            GLES20Canvas.nFlushLayer(mLayer);
+        }
+    }
 
     static class Finalizer {
         private int mLayerId;
diff --git a/core/java/android/view/HardwareLayer.java b/core/java/android/view/HardwareLayer.java
index 28389ab..d5666f3 100644
--- a/core/java/android/view/HardwareLayer.java
+++ b/core/java/android/view/HardwareLayer.java
@@ -116,6 +116,11 @@
     abstract void destroy();
 
     /**
+     * Flush the render queue associated with this layer.
+     */
+    abstract void flush();
+
+    /**
      * This must be invoked before drawing onto this layer.
      * @param currentCanvas
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 304a9a1..af8f8cb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10207,6 +10207,13 @@
                 break;
         }
     }
+    
+    // Make sure the HardwareRenderer.validate() was invoked before calling this method
+    void flushLayer() {
+        if (mLayerType == LAYER_TYPE_HARDWARE && mHardwareLayer != null) {
+            mHardwareLayer.flush();
+        }
+    }
 
     /**
      * <p>Returns a hardware layer that can be used to draw this view again
@@ -10219,6 +10226,8 @@
                 !mAttachInfo.mHardwareRenderer.isEnabled()) {
             return null;
         }
+        
+        if (!mAttachInfo.mHardwareRenderer.validate()) return null;
 
         final int width = mRight - mLeft;
         final int height = mBottom - mTop;
@@ -10293,12 +10302,15 @@
      */
     boolean destroyLayer() {
         if (mHardwareLayer != null) {
-            mHardwareLayer.destroy();
-            mHardwareLayer = null;
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled() && info.mHardwareRenderer.validate()) {
+                mHardwareLayer.destroy();
+                mHardwareLayer = null;
 
-            invalidate(true);
-            invalidateParentCaches();
-
+                invalidate(true);
+                invalidateParentCaches();
+            }
             return true;
         }
         return false;
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 2a041f7..5035cae 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2958,6 +2958,17 @@
             mDrawLayers = enabled;
             invalidate(true);
 
+            boolean flushLayers = !enabled;
+            AttachInfo info = mAttachInfo;
+            if (info != null && info.mHardwareRenderer != null &&
+                    info.mHardwareRenderer.isEnabled()) {
+                if (!info.mHardwareRenderer.validate()) {
+                    flushLayers = false;
+                }
+            } else {
+                flushLayers = false;
+            }
+
             // We need to invalidate any child with a layer. For instance,
             // if a child is backed by a hardware layer and we disable layers
             // the child is marked as not dirty (flags cleared the last time
@@ -2968,6 +2979,7 @@
             for (int i = 0; i < mChildrenCount; i++) {
                 View child = mChildren[i];
                 if (child.mLayerType != LAYER_TYPE_NONE) {
+                    if (flushLayers) child.flushLayer();
                     child.invalidate(true);
                 }
             }
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 426f4f7..9c7b108 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -719,6 +719,10 @@
     LayerRenderer::destroyLayerDeferred(layer);
 }
 
+static void android_view_GLES20Canvas_flushLayer(JNIEnv* env, jobject clazz, Layer* layer) {
+    LayerRenderer::flushLayer(layer);
+}
+
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
         OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
     renderer->drawLayer(layer, x, y, paint);
@@ -869,6 +873,7 @@
     { "nSetTextureLayerTransform", "(II)V",    (void*) android_view_GLES20Canvas_setTextureLayerTransform },
     { "nDestroyLayer",           "(I)V",       (void*) android_view_GLES20Canvas_destroyLayer },
     { "nDestroyLayerDeferred",   "(I)V",       (void*) android_view_GLES20Canvas_destroyLayerDeferred },
+    { "nFlushLayer",             "(I)V",       (void*) android_view_GLES20Canvas_flushLayer },
     { "nDrawLayer",              "(IIFFI)V",   (void*) android_view_GLES20Canvas_drawLayer },
     { "nCopyLayer",              "(II)Z",      (void*) android_view_GLES20Canvas_copyLayer },