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>
Reviewed-on: https://chromium-review.googlesource.com/280906
diff --git a/src/libANGLE/Surface.cpp b/src/libANGLE/Surface.cpp
index ac455f3..cd06a09 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -33,8 +33,7 @@
// FIXME: Determine actual pixel aspect ratio
mPixelAspectRatio(static_cast<EGLint>(1.0 * EGL_DISPLAY_SCALING)),
mRenderBuffer(EGL_BACK_BUFFER),
- mSwapBehavior(EGL_BUFFER_PRESERVED),
- mTexture(NULL)
+ mSwapBehavior(EGL_BUFFER_PRESERVED)
{
addRef();
@@ -56,14 +55,14 @@
Surface::~Surface()
{
- if (mTexture)
+ if (mTexture.get())
{
if (mImplementation)
{
mImplementation->releaseTexImage(mTexture->id());
}
- mTexture->releaseTexImage();
- mTexture = NULL;
+ mTexture->releaseTexImageFromSurface();
+ mTexture.set(nullptr);
}
SafeDelete(mImplementation);
@@ -146,21 +145,26 @@
Error Surface::bindTexImage(gl::Texture *texture, EGLint buffer)
{
- ASSERT(!mTexture);
+ ASSERT(!mTexture.get());
- texture->bindTexImage(this);
- mTexture = texture;
+ texture->bindTexImageFromSurface(this);
+ mTexture.set(texture);
return mImplementation->bindTexImage(buffer);
}
Error Surface::releaseTexImage(EGLint buffer)
{
- ASSERT(mTexture);
- gl::Texture *boundTexture = mTexture;
- mTexture = NULL;
+ ASSERT(mTexture.get());
+ mTexture->releaseTexImageFromSurface();
+ mTexture.set(nullptr);
- boundTexture->releaseTexImage();
return mImplementation->releaseTexImage(buffer);
}
+void Surface::releaseTexImageFromTexture()
+{
+ ASSERT(mTexture.get());
+ mTexture.set(nullptr);
+}
+
}
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index 430bf01..9b42b52 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -64,13 +64,17 @@
EGLenum getTextureFormat() const;
EGLenum getTextureTarget() const;
- gl::Texture *getBoundTexture() const { return mTexture; }
+ gl::Texture *getBoundTexture() const { return mTexture.get(); }
EGLint isFixedSize() const;
private:
virtual ~Surface();
+ // ANGLE-only method, used internally
+ friend class gl::Texture;
+ void releaseTexImageFromTexture();
+
rx::SurfaceImpl *mImplementation;
EGLint mType;
@@ -90,7 +94,7 @@
EGLenum mRenderBuffer; // Render buffer
EGLenum mSwapBehavior; // Buffer swap behavior
- gl::Texture *mTexture;
+ BindingPointer<gl::Texture> mTexture;
};
}
diff --git a/src/libANGLE/Texture.cpp b/src/libANGLE/Texture.cpp
index 2d68bec..3f7c79e 100644
--- a/src/libANGLE/Texture.cpp
+++ b/src/libANGLE/Texture.cpp
@@ -181,14 +181,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);
@@ -207,14 +208,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);
@@ -233,14 +235,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)));
@@ -259,14 +262,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);
@@ -277,14 +281,15 @@
Error Texture::generateMipmaps()
{
+ // Release from previous calls to eglBindTexImage, to avoid calling the Impl after
+ releaseTexImageInternal();
+
Error error = mTexture->generateMipmaps();
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);
@@ -355,11 +360,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;
@@ -370,16 +379,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();
}
}
diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h
index b5a0717..bcdfb91 100644
--- a/src/libANGLE/Texture.h
+++ b/src/libANGLE/Texture.h
@@ -82,9 +82,6 @@
bool isImmutable() const;
GLsizei immutableLevelCount();
- void bindTexImage(egl::Surface *surface);
- void releaseTexImage();
-
rx::TextureImpl *getImplementation() { return mTexture; }
const rx::TextureImpl *getImplementation() const { return mTexture; }
@@ -93,6 +90,11 @@
private:
static unsigned int issueTextureSerial();
+ // ANGLE-only method, used internally
+ friend class egl::Surface;
+ void bindTexImageFromSurface(egl::Surface *surface);
+ void releaseTexImageFromSurface();
+
rx::TextureImpl *mTexture;
SamplerState mSamplerState;
@@ -127,6 +129,7 @@
void setImageDescChain(size_t levels, Extents baseSize, GLenum sizedInternalFormat);
void clearImageDesc(GLenum target, size_t level);
void clearImageDescs();
+ void releaseTexImageInternal();
std::vector<ImageDesc> mImageDescs;