Release egl::Surface on Texture image changes.

We would get into a broken state if the user would bind a Texture
to an egl::Surface, then change the Texture. This is valid in egl,
and should release the Surface when it happens.

BUG=485543

Change-Id: Idfaa305ac704f2bc579e79be816e88a23e69351b
Reviewed-on: https://chromium-review.googlesource.com/271986
Tested-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Geoff Lang <geofflang@chromium.org>
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index d17dd5d..4d4c32a 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -167,14 +167,15 @@
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
+    // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+    releaseTexImageInternal();
+
     Error error = mTexture->setImage(target, level, internalFormat, size, format, type, unpack, pixels);
     if (error.isError())
     {
         return error;
     }
 
-    releaseTexImage();
-
     setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, type)));
 
     return Error(GL_NO_ERROR);
@@ -193,14 +194,15 @@
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
+    // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+    releaseTexImageInternal();
+
     Error error = mTexture->setCompressedImage(target, level, internalFormat, size, unpack, pixels);
     if (error.isError())
     {
         return error;
     }
 
-    releaseTexImage();
-
     setImageDesc(target, level, ImageDesc(size, GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
 
     return Error(GL_NO_ERROR);
@@ -219,14 +221,15 @@
 {
     ASSERT(target == mTarget || (mTarget == GL_TEXTURE_CUBE_MAP && IsCubeMapTextureTarget(target)));
 
+    // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+    releaseTexImageInternal();
+
     Error error = mTexture->copyImage(target, level, sourceArea, internalFormat, source);
     if (error.isError())
     {
         return error;
     }
 
-    releaseTexImage();
-
     setImageDesc(target, level, ImageDesc(Extents(sourceArea.width, sourceArea.height, 1),
                                           GetSizedInternalFormat(internalFormat, GL_UNSIGNED_BYTE)));
 
@@ -245,14 +248,15 @@
 {
     ASSERT(target == mTarget);
 
+    // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+    releaseTexImageInternal();
+
     Error error = mTexture->setStorage(target, levels, internalFormat, size);
     if (error.isError())
     {
         return error;
     }
 
-    releaseTexImage();
-
     mImmutableLevelCount = levels;
     clearImageDescs();
     setImageDescChain(levels, size, internalFormat);
@@ -263,14 +267,15 @@
 
 Error Texture::generateMipmaps()
 {
+    // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+    releaseTexImageInternal();
+
     Error error = mTexture->generateMipmaps(getSamplerState());
     if (error.isError())
     {
         return error;
     }
 
-    releaseTexImage();
-
     const ImageDesc &baseImageInfo = getImageDesc(getBaseImageTarget(), 0);
     size_t mipLevels = log2(std::max(std::max(baseImageInfo.size.width, baseImageInfo.size.height), baseImageInfo.size.depth)) + 1;
     setImageDescChain(mipLevels, baseImageInfo.size, baseImageInfo.internalFormat);
@@ -341,11 +346,15 @@
     mCompletenessCache.cacheValid = false;
 }
 
-void Texture::bindTexImage(egl::Surface *surface)
+void Texture::bindTexImageFromSurface(egl::Surface *surface)
 {
     ASSERT(surface);
 
-    releaseTexImage();
+    if (mBoundSurface)
+    {
+        releaseTexImageFromSurface();
+    }
+
     mTexture->bindTexImage(surface);
     mBoundSurface = surface;
 
@@ -356,16 +365,26 @@
     setImageDesc(mTarget, 0, desc);
 }
 
-void Texture::releaseTexImage()
+void Texture::releaseTexImageFromSurface()
+{
+    ASSERT(mBoundSurface);
+    mBoundSurface = nullptr;
+    mTexture->releaseTexImage();
+
+    // Erase the image info for level 0
+    ASSERT(mTarget == GL_TEXTURE_2D);
+    clearImageDesc(mTarget, 0);
+}
+
+void Texture::releaseTexImageInternal()
 {
     if (mBoundSurface)
     {
-        mBoundSurface = NULL;
-        mTexture->releaseTexImage();
+        // Notify the surface
+        mBoundSurface->releaseTexImageFromTexture();
 
-        // Erase the image info for level 0
-        ASSERT(mTarget == GL_TEXTURE_2D);
-        clearImageDesc(mTarget, 0);
+        // Then, call the same method as from the surface
+        releaseTexImageFromSurface();
     }
 }