Release the global texture manager with the last referencing context.

This ensures that when the global texture manager is released, there is a valid
context.

BUG=angleproject:1639

Change-Id: I1b75885e9dc02b607bb1a386de394f6087429f5d
Reviewed-on: https://chromium-review.googlesource.com/442074
Reviewed-by: Jamie Madill <jmadill@chromium.org>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
Commit-Queue: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
Geoff Lang
2017-02-14 10:41:32 -05:00
committed by Commit Bot
parent b5c3d27ae1
commit 40dc8c107f
4 changed files with 87 additions and 12 deletions

View File

@@ -66,7 +66,16 @@ Additions to the EGL 1.5 Specification
Issues
None
(1) What happens to the shared textures when a context in the global share
group is destroyed?
RESOLOVED: When the last context in the global texture share group is
destroyed, all textures in the global texture share group are released. If
a new context is created in the global texture share group, no textures
will exist.
This mirrors how regular share groups work, releasing all objects when the
last context is destroyed.
Revision History

View File

@@ -360,7 +360,8 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mVendorString(),
mDevice(eglDevice),
mPlatform(platform),
mTextureManager(nullptr)
mTextureManager(nullptr),
mGlobalTextureShareGroupUsers(0)
{
}
@@ -464,9 +465,6 @@ Error Display::initialize()
ASSERT(mDevice != nullptr);
}
ASSERT(mTextureManager == nullptr);
mTextureManager = new gl::TextureManager();
mInitialized = true;
return egl::Error(EGL_SUCCESS);
@@ -474,12 +472,6 @@ Error Display::initialize()
void Display::terminate()
{
if (mTextureManager)
{
mTextureManager->release();
mTextureManager = nullptr;
}
makeCurrent(nullptr, nullptr, nullptr);
while (!mContextSet.empty())
@@ -487,6 +479,9 @@ void Display::terminate()
destroyContext(*mContextSet.begin());
}
// The global texture manager should be deleted with the last context that uses it.
ASSERT(mGlobalTextureShareGroupUsers == 0 && mTextureManager == nullptr);
while (!mImageSet.empty())
{
destroyImage(*mImageSet.begin());
@@ -686,7 +681,19 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont
bool usingDisplayTextureShareGroup =
attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE;
gl::TextureManager *shareTextures = usingDisplayTextureShareGroup ? mTextureManager : nullptr;
gl::TextureManager *shareTextures = nullptr;
if (usingDisplayTextureShareGroup)
{
ASSERT((mTextureManager == nullptr) == (mGlobalTextureShareGroupUsers == 0));
if (mTextureManager == nullptr)
{
mTextureManager = new gl::TextureManager();
}
mGlobalTextureShareGroupUsers++;
shareTextures = mTextureManager;
}
gl::Context *context = new gl::Context(mImplementation, configuration, shareContext,
shareTextures, attribs, mDisplayExtensions);
@@ -767,6 +774,19 @@ void Display::destroyStream(egl::Stream *stream)
void Display::destroyContext(gl::Context *context)
{
if (context->usingDisplayTextureShareGroup())
{
ASSERT(mGlobalTextureShareGroupUsers >= 1 && mTextureManager != nullptr);
if (mGlobalTextureShareGroupUsers == 1)
{
// If this is the last context using the global share group, destroy the global texture
// manager so that the textures can be destroyed while a context still exists
mTextureManager->release();
mTextureManager = nullptr;
}
mGlobalTextureShareGroupUsers--;
}
context->destroy(this);
mContextSet.erase(context);
SafeDelete(context);

View File

@@ -175,6 +175,7 @@ class Display final : angle::NonCopyable
angle::LoggingAnnotator mAnnotator;
gl::TextureManager *mTextureManager;
size_t mGlobalTextureShareGroupUsers;
};
}

View File

@@ -199,6 +199,51 @@ TEST_P(EGLContextSharingTest, DisplayShareGroupObjectSharing)
ASSERT_GL_NO_ERROR();
}
// Tests that shared textures using EGL_ANGLE_display_texture_share_group are released when the last
// context is destroyed
TEST_P(EGLContextSharingTest, DisplayShareGroupReleasedWithLastContext)
{
EGLDisplay display = getEGLWindow()->getDisplay();
if (!ANGLETest::eglDisplayExtensionEnabled(display, "EGL_ANGLE_display_texture_share_group"))
{
std::cout << "Test skipped because EGL_ANGLE_display_texture_share_group is not present."
<< std::endl;
return;
}
EGLConfig config = getEGLWindow()->getConfig();
EGLSurface surface = getEGLWindow()->getSurface();
const EGLint inShareGroupContextAttribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2, EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_TRUE, EGL_NONE};
// Create two contexts in the global share group but not in the same context share group
mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
mContexts[1] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
// Create a texture and buffer in ctx 0
ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[0]));
GLuint textureFromCtx0 = 0;
glGenTextures(1, &textureFromCtx0);
glBindTexture(GL_TEXTURE_2D, textureFromCtx0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
// Switch to context 1 and verify that the texture is accessible
ASSERT_EGL_TRUE(eglMakeCurrent(display, surface, surface, mContexts[1]));
ASSERT_GL_TRUE(glIsTexture(textureFromCtx0));
// Destroy both contexts, the texture should be cleaned up automatically
ASSERT_EGL_TRUE(eglDestroyContext(display, mContexts[0]));
ASSERT_EGL_TRUE(eglDestroyContext(display, mContexts[1]));
// Create a new context and verify it cannot access the texture previously created
mContexts[0] = eglCreateContext(display, config, nullptr, inShareGroupContextAttribs);
ASSERT_GL_FALSE(glIsTexture(textureFromCtx0));
}
} // anonymous namespace
ANGLE_INSTANTIATE_TEST(EGLContextSharingTest,