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/Surface.cpp b/src/libANGLE/Surface.cpp
index c42b69d..68ad4ca 100644
--- a/src/libANGLE/Surface.cpp
+++ b/src/libANGLE/Surface.cpp
@@ -32,8 +32,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();
@@ -55,14 +54,14 @@
Surface::~Surface()
{
- if (mTexture)
+ if (mTexture.get())
{
if (mImplementation)
{
mImplementation->releaseTexImage(EGL_BACK_BUFFER);
}
- mTexture->releaseTexImage();
- mTexture = NULL;
+ mTexture->releaseTexImageFromSurface();
+ mTexture.set(nullptr);
}
SafeDelete(mImplementation);
@@ -145,23 +144,28 @@
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);
+}
+
GLenum Surface::getAttachmentInternalFormat(const gl::FramebufferAttachment::Target &target) const
{
const egl::Config *config = getConfig();
diff --git a/src/libANGLE/Surface.h b/src/libANGLE/Surface.h
index e163060..1709311 100644
--- a/src/libANGLE/Surface.h
+++ b/src/libANGLE/Surface.h
@@ -60,7 +60,7 @@
EGLenum getTextureFormat() const;
EGLenum getTextureTarget() const;
- gl::Texture *getBoundTexture() const { return mTexture; }
+ gl::Texture *getBoundTexture() const { return mTexture.get(); }
EGLint isFixedSize() const;
@@ -74,6 +74,10 @@
virtual ~Surface();
rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mImplementation; }
+ // ANGLE-only method, used internally
+ friend class gl::Texture;
+ void releaseTexImageFromTexture();
+
rx::SurfaceImpl *mImplementation;
EGLint mType;
@@ -93,7 +97,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 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();
}
}
diff --git a/src/libANGLE/Texture.h b/src/libANGLE/Texture.h
index 8df1cde..d9280f2 100644
--- a/src/libANGLE/Texture.h
+++ b/src/libANGLE/Texture.h
@@ -78,9 +78,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:
rx::FramebufferAttachmentObjectImpl *getAttachmentImpl() const override { return mTexture; }
+ // ANGLE-only method, used internally
+ friend class egl::Surface;
+ void bindTexImageFromSurface(egl::Surface *surface);
+ void releaseTexImageFromSurface();
+
rx::TextureImpl *mTexture;
SamplerState mSamplerState;
@@ -123,6 +125,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;