Assume a texture is unbound after deleting it
Bug #9316260

The GL specification indicates that deleting a bound texture has
the side effect of binding the default texture (name=0). This change
replaces all calls to glDeleteTextures() by Caches::deleteTexture()
to properly keep track of texture bindings.

Change-Id: Ifbc60ef433e0f9776a668dd5bd5f0adbc65a77a0
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 23b5d76..74aeddb 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -508,6 +508,28 @@
     }
 }
 
+void Caches::deleteTexture(GLuint texture) {
+    // When glDeleteTextures() is called on a currently bound texture,
+    // OpenGL ES specifies that the texture is then considered unbound
+    // Consider the following series of calls:
+    //
+    // glGenTextures -> creates texture name 2
+    // glBindTexture(2)
+    // glDeleteTextures(2) -> 2 is now unbound
+    // glGenTextures -> can return 2 again
+    //
+    // If we don't call glBindTexture(2) after the second glGenTextures
+    // call, any texture operation will be performed on the default
+    // texture (name=0)
+
+    for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
+        if (mBoundTextures[i] == texture) {
+            mBoundTextures[i] = 0;
+        }
+    }
+    glDeleteTextures(1, &texture);
+}
+
 void Caches::resetBoundTextures() {
     memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
 }
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index bd31ec3..bdde8fb 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -226,15 +226,26 @@
 
     /**
      * Binds the specified texture as a GL_TEXTURE_2D texture.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLenum, GLuint).
      */
     void bindTexture(GLuint texture);
 
     /**
-     * Binds the specified texture..
+     * Binds the specified texture with the specified render target.
+     * All texture bindings must be performed with this method or
+     * bindTexture(GLuint).
      */
     void bindTexture(GLenum target, GLuint texture);
 
     /**
+     * Deletes the specified texture and clears it from the cache
+     * of bound textures.
+     * All textures must be deleted using this method.
+     */
+    void deleteTexture(GLuint texture);
+
+    /**
      * Signals that the cache of bound textures should be cleared.
      * Other users of the context may have altered which textures are bound.
      */
diff --git a/libs/hwui/Dither.cpp b/libs/hwui/Dither.cpp
index 4dc85e0..649a7bc 100644
--- a/libs/hwui/Dither.cpp
+++ b/libs/hwui/Dither.cpp
@@ -77,7 +77,7 @@
 
 void Dither::clear() {
     if (mInitialized) {
-        glDeleteTextures(1, &mDitherTexture);
+        mCaches->deleteTexture(mDitherTexture);
         mInitialized = false;
     }
 }
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 1ed04fa..1815bff 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -120,7 +120,7 @@
         const uint32_t size = texture->width * texture->height * bytesPerPixel();
         mSize -= size;
 
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index 77c2300..edf3930 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -54,7 +54,7 @@
         eglDestroyImageKHR(eglGetDisplay(EGL_DEFAULT_DISPLAY), mImage);
         mImage = EGL_NO_IMAGE_KHR;
 
-        glDeleteTextures(1, &mTexture);
+        Caches::getInstance().deleteTexture(mTexture);
         mTexture = 0;
     }
 }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 60c38ba..134f452 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -167,7 +167,7 @@
 
 void Layer::deleteTexture() {
     if (texture.id) {
-        glDeleteTextures(1, &texture.id);
+        texture.deleteTexture();
         texture.id = 0;
     }
 }
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index 987daae..79e0b0c 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -498,7 +498,7 @@
         glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
         layer->setAlpha(alpha, mode);
         layer->setFbo(previousLayerFbo);
-        glDeleteTextures(1, &texture);
+        caches.deleteTexture(texture);
         caches.fboCache.put(fbo);
         glViewport(previousViewport[0], previousViewport[1],
                 previousViewport[2], previousViewport[3]);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 3f6485c..3ab40da 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -223,7 +223,7 @@
         }
 
         if (texture->id) {
-            glDeleteTextures(1, &texture->id);
+            Caches::getInstance().deleteTexture(texture->id);
         }
         delete texture;
     }
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index 3b6cb91..0b2c130 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -155,7 +155,7 @@
             ALOGD("Shadow texture deleted, size = %d", texture->bitmapSize);
         }
 
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index e06227c..7923ce7 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -76,5 +76,9 @@
     }
 }
 
+void Texture::deleteTexture() const {
+    mCaches.deleteTexture(id);
+}
+
 }; // namespace uirenderer
 }; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index d249741..d48ec59 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -52,6 +52,11 @@
             bool force = false, GLenum renderTarget = GL_TEXTURE_2D);
 
     /**
+     * Convenience method to call glDeleteTextures() on this texture's id.
+     */
+    void deleteTexture() const;
+
+    /**
      * Name of the texture.
      */
     GLuint id;
@@ -113,7 +118,7 @@
     AutoTexture(const Texture* texture): mTexture(texture) { }
     ~AutoTexture() {
         if (mTexture && mTexture->cleanup) {
-            glDeleteTextures(1, &mTexture->id);
+            mTexture->deleteTexture();
             delete mTexture;
         }
     }
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 7f5b80f..a63cac6 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -112,7 +112,7 @@
         if (mDebugEnabled) {
             ALOGD("Texture deleted, size = %d", texture->bitmapSize);
         }
-        glDeleteTextures(1, &texture->id);
+        texture->deleteTexture();
         delete texture;
     }
 }
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 2d58338..5f15724 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -156,7 +156,7 @@
         mTexture = NULL;
     }
     if (mTextureId) {
-        glDeleteTextures(1, &mTextureId);
+        mCaches.deleteTexture(mTextureId);
         mTextureId = 0;
     }
     mDirty = false;