Commit 40dc8c10 by Geoff Lang Committed by Commit Bot

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/442074Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarCorentin Wallez <cwallez@chromium.org> Commit-Queue: Geoff Lang <geofflang@chromium.org>
parent b5c3d27a
...@@ -66,7 +66,16 @@ Additions to the EGL 1.5 Specification ...@@ -66,7 +66,16 @@ Additions to the EGL 1.5 Specification
Issues 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 Revision History
......
...@@ -360,7 +360,8 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe ...@@ -360,7 +360,8 @@ Display::Display(EGLenum platform, EGLNativeDisplayType displayId, Device *eglDe
mVendorString(), mVendorString(),
mDevice(eglDevice), mDevice(eglDevice),
mPlatform(platform), mPlatform(platform),
mTextureManager(nullptr) mTextureManager(nullptr),
mGlobalTextureShareGroupUsers(0)
{ {
} }
...@@ -464,9 +465,6 @@ Error Display::initialize() ...@@ -464,9 +465,6 @@ Error Display::initialize()
ASSERT(mDevice != nullptr); ASSERT(mDevice != nullptr);
} }
ASSERT(mTextureManager == nullptr);
mTextureManager = new gl::TextureManager();
mInitialized = true; mInitialized = true;
return egl::Error(EGL_SUCCESS); return egl::Error(EGL_SUCCESS);
...@@ -474,12 +472,6 @@ Error Display::initialize() ...@@ -474,12 +472,6 @@ Error Display::initialize()
void Display::terminate() void Display::terminate()
{ {
if (mTextureManager)
{
mTextureManager->release();
mTextureManager = nullptr;
}
makeCurrent(nullptr, nullptr, nullptr); makeCurrent(nullptr, nullptr, nullptr);
while (!mContextSet.empty()) while (!mContextSet.empty())
...@@ -487,6 +479,9 @@ void Display::terminate() ...@@ -487,6 +479,9 @@ void Display::terminate()
destroyContext(*mContextSet.begin()); 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()) while (!mImageSet.empty())
{ {
destroyImage(*mImageSet.begin()); destroyImage(*mImageSet.begin());
...@@ -686,7 +681,19 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont ...@@ -686,7 +681,19 @@ Error Display::createContext(const Config *configuration, gl::Context *shareCont
bool usingDisplayTextureShareGroup = bool usingDisplayTextureShareGroup =
attribs.get(EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE, EGL_FALSE) == EGL_TRUE; 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, gl::Context *context = new gl::Context(mImplementation, configuration, shareContext,
shareTextures, attribs, mDisplayExtensions); shareTextures, attribs, mDisplayExtensions);
...@@ -767,6 +774,19 @@ void Display::destroyStream(egl::Stream *stream) ...@@ -767,6 +774,19 @@ void Display::destroyStream(egl::Stream *stream)
void Display::destroyContext(gl::Context *context) 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); context->destroy(this);
mContextSet.erase(context); mContextSet.erase(context);
SafeDelete(context); SafeDelete(context);
......
...@@ -175,6 +175,7 @@ class Display final : angle::NonCopyable ...@@ -175,6 +175,7 @@ class Display final : angle::NonCopyable
angle::LoggingAnnotator mAnnotator; angle::LoggingAnnotator mAnnotator;
gl::TextureManager *mTextureManager; gl::TextureManager *mTextureManager;
size_t mGlobalTextureShareGroupUsers;
}; };
} }
......
...@@ -199,6 +199,51 @@ TEST_P(EGLContextSharingTest, DisplayShareGroupObjectSharing) ...@@ -199,6 +199,51 @@ TEST_P(EGLContextSharingTest, DisplayShareGroupObjectSharing)
ASSERT_GL_NO_ERROR(); 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 } // anonymous namespace
ANGLE_INSTANTIATE_TEST(EGLContextSharingTest, ANGLE_INSTANTIATE_TEST(EGLContextSharingTest,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment