Cleanup GL objects on the correct thread.

Change-Id: Iddfea6e08a6591a4fab147151098ef27005f373d
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 8c4e654..7dd6cc6 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -160,7 +160,8 @@
     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);    
+
     ///////////////////////////////////////////////////////////////////////////
     // Canvas management
     ///////////////////////////////////////////////////////////////////////////
diff --git a/core/java/android/view/GLES20Layer.java b/core/java/android/view/GLES20Layer.java
index 336e07a..7587657 100644
--- a/core/java/android/view/GLES20Layer.java
+++ b/core/java/android/view/GLES20Layer.java
@@ -128,7 +128,7 @@
         protected void finalize() throws Throwable {
             try {
                 if (mLayerId != 0 || mLayerTextureId != 0) {
-                    GLES20Canvas.nDestroyLayer(mLayerId, mLayerTextureId);
+                    GLES20Canvas.nDestroyLayerDeferred(mLayerId, mLayerTextureId);
                 }
             } finally {
                 super.finalize();
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index d6991e6..4aed9b1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -501,6 +501,11 @@
     LayerRenderer::destroyLayer(layerId, layerTextureId);
 }
 
+static void android_view_GLES20Canvas_destroyLayerDeferred(JNIEnv* env,
+        jobject clazz, jint layerId, jint layerTextureId) {
+    LayerRenderer::destroyLayerDeferred(layerId, layerTextureId);
+}
+
 static void android_view_GLES20Canvas_drawLayer(JNIEnv* env,
         jobject canvas, OpenGLRenderer* renderer,
         jfloat left, jfloat top, jfloat right, jfloat bottom,
@@ -593,13 +598,14 @@
     { "nGetDisplayListRenderer", "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListRenderer },
     { "nDrawDisplayList",        "(II)V",      (void*) android_view_GLES20Canvas_drawDisplayList },
 
-    { "nInterrupt",              "(I)V",        (void*) android_view_GLES20Canvas_interrupt },
-    { "nResume",                 "(I)V",        (void*) android_view_GLES20Canvas_resume },
+    { "nInterrupt",              "(I)V",       (void*) android_view_GLES20Canvas_interrupt },
+    { "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 },
 
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 406d09f..3563064 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -106,6 +106,32 @@
     textureCache.clearGarbage();
     gradientCache.clearGarbage();
     pathCache.clearGarbage();
+
+    Mutex::Autolock _l(mGarbageLock);
+
+    size_t count = mFboGarbage.size();
+    for (size_t i = 0; i < count; i++) {
+        GLuint fbo = mFboGarbage.itemAt(i);
+        if (fbo) glDeleteFramebuffers(1, &fbo);
+    }
+    mFboGarbage.clear();
+
+    count = mTextureGarbage.size();
+    for (size_t i = 0; i < count; i++) {
+        GLuint texture = mTextureGarbage.itemAt(i);
+        if (texture) glDeleteTextures(1, &texture);
+    }
+    mTextureGarbage.clear();
+}
+
+void Caches::deleteFboDeferred(GLuint fbo) {
+    Mutex::Autolock _l(mGarbageLock);
+    mFboGarbage.push(fbo);
+}
+
+void Caches::deleteTextureDeferred(GLuint texture) {
+    Mutex::Autolock _l(mGarbageLock);
+    mTextureGarbage.push(texture);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 318c120..34f48c9 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -90,6 +90,10 @@
     TextureVertex* mRegionMesh;
     GLuint mRegionMeshIndices;
 
+    mutable Mutex mGarbageLock;
+    Vector<GLuint> mFboGarbage;
+    Vector<GLuint> mTextureGarbage;
+
 public:
     /**
      * Indicates whether the renderer is in debug mode.
@@ -106,6 +110,16 @@
     void clearGarbage();
 
     /**
+     * Can be used to delete an FBO 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);
+
+    /**
      * Binds the VBO used to render simple textured quads.
      */
     void bindMeshBuffer();
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index a15165d..d309ade 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -116,5 +116,11 @@
     if (texture) glDeleteTextures(1, &texture);
 }
 
+void LayerRenderer::destroyLayerDeferred(GLuint fbo, GLuint texture) {
+    Caches& caches = Caches::getInstance();
+    if (fbo) caches.deleteFboDeferred(fbo);
+    if (texture) caches.deleteTextureDeferred(texture);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index a8f1ff7..800931a 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -42,6 +42,7 @@
     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);
 
 private:
     GLuint mFbo;