mirror of
https://github.com/godotengine/godot-angle-static.git
synced 2026-01-07 06:09:57 +03:00
Perform Display terminate(InternalCleanup) from makeCurrent()
Current state: - Call to `eglTerminate()` is canceled if there are Contexts current. - All not current Contexts are invalidated in `eglTerminate()` call. - Full Display termination will happen only when last Context is actually destroyed in `eglDestroyContext()` or last active thread terminates (Android only). Problem: - Context is not marked invalid after it is unmade from current when `eglTerminate()` was already called. - If `eglDestroyContext()` was called while context was current, it will be destroyed when unmade from current - in this case actual Display termination will NOT happen. After this change: - Context immediately invalidated after it is unmade from current when `eglTerminate()` was already called. - Full Display termination will happen after the last Context is unmade from current (all Contexts are invalid). Bug: angleproject:6798 Test: angle_end2end_tests --gtest_filter=EGLDisplayTest.ContextLeakAfterTerminate* Change-Id: Idcce94b041649db58d3d879858fba99109347baf Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/4708328 Reviewed-by: Shahbaz Youssefi <syoussefi@chromium.org> Commit-Queue: Igor Nazarov <i.nazarov@samsung.com> Reviewed-by: Geoff Lang <geofflang@chromium.org>
This commit is contained in:
committed by
Angle LUCI CQ
parent
6fb3295db8
commit
c95ffadf76
@@ -1314,6 +1314,11 @@ Error Display::prepareForCall()
|
||||
|
||||
Error Display::releaseThread()
|
||||
{
|
||||
// Need to check if initialized, because makeCurrent() may terminate the Display.
|
||||
if (!mInitialized)
|
||||
{
|
||||
return NoError();
|
||||
}
|
||||
ANGLE_TRY(mImplementation->releaseThread());
|
||||
return destroyInvalidEglObjects();
|
||||
}
|
||||
@@ -1742,6 +1747,14 @@ Error Display::makeCurrent(Thread *thread,
|
||||
}
|
||||
}
|
||||
|
||||
// If eglTerminate() has previously been called and Context was changed, perform InternalCleanup
|
||||
// to invalidate any non-current Contexts, and possibly fully terminate the Display and release
|
||||
// all of its resources.
|
||||
if (mTerminatedByApi && contextChanged)
|
||||
{
|
||||
return terminate(thread, TerminateReason::InternalCleanup);
|
||||
}
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
@@ -1904,21 +1917,6 @@ Error Display::destroyContext(Thread *thread, gl::Context *context)
|
||||
makeCurrent(thread, context, currentDrawSurface, currentReadSurface, currentContext));
|
||||
}
|
||||
|
||||
// If eglTerminate() has previously been called and this is the last Context the Display owns,
|
||||
// we can now fully terminate the display and release all of its resources.
|
||||
if (mTerminatedByApi)
|
||||
{
|
||||
for (auto ctx : mState.contextMap)
|
||||
{
|
||||
if (ctx.second->isReferenced())
|
||||
{
|
||||
return NoError();
|
||||
}
|
||||
}
|
||||
|
||||
return terminate(thread, TerminateReason::InternalCleanup);
|
||||
}
|
||||
|
||||
return NoError();
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,49 @@
|
||||
using namespace angle;
|
||||
|
||||
class EGLDisplayTest : public ANGLETest<>
|
||||
{};
|
||||
{
|
||||
protected:
|
||||
EGLConfig chooseConfig(EGLDisplay display)
|
||||
{
|
||||
const EGLint attribs[] = {EGL_RED_SIZE,
|
||||
8,
|
||||
EGL_GREEN_SIZE,
|
||||
8,
|
||||
EGL_BLUE_SIZE,
|
||||
8,
|
||||
EGL_ALPHA_SIZE,
|
||||
8,
|
||||
EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES2_BIT,
|
||||
EGL_SURFACE_TYPE,
|
||||
EGL_PBUFFER_BIT,
|
||||
EGL_NONE};
|
||||
EGLConfig config = EGL_NO_CONFIG_KHR;
|
||||
EGLint count = 0;
|
||||
EXPECT_EGL_TRUE(eglChooseConfig(display, attribs, &config, 1, &count));
|
||||
EXPECT_EGL_TRUE(count > 0);
|
||||
return config;
|
||||
}
|
||||
|
||||
EGLContext createContext(EGLDisplay display, EGLConfig config)
|
||||
{
|
||||
const EGLint attribs[] = {EGL_CONTEXT_MAJOR_VERSION, 2, EGL_NONE};
|
||||
EGLContext context = eglCreateContext(display, config, nullptr, attribs);
|
||||
EXPECT_NE(context, EGL_NO_CONTEXT);
|
||||
return context;
|
||||
}
|
||||
|
||||
EGLSurface createSurface(EGLDisplay display, EGLConfig config)
|
||||
{
|
||||
const EGLint attribs[] = {EGL_WIDTH, 64, EGL_HEIGHT, 64, EGL_NONE};
|
||||
EGLSurface surface = eglCreatePbufferSurface(display, config, attribs);
|
||||
EXPECT_NE(surface, EGL_NO_SURFACE);
|
||||
return surface;
|
||||
}
|
||||
};
|
||||
|
||||
// Tests that an EGLDisplay can be re-initialized.
|
||||
TEST_P(EGLDisplayTest, InitalizeTerminateInitalize)
|
||||
TEST_P(EGLDisplayTest, InitializeTerminateInitialize)
|
||||
{
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
|
||||
@@ -23,6 +62,34 @@ TEST_P(EGLDisplayTest, InitalizeTerminateInitalize)
|
||||
EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr) != EGL_FALSE);
|
||||
}
|
||||
|
||||
// Tests current Context leaking when call eglTerminate() while it is current.
|
||||
TEST_P(EGLDisplayTest, ContextLeakAfterTerminate)
|
||||
{
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
EXPECT_EGL_TRUE(eglInitialize(display, nullptr, nullptr));
|
||||
|
||||
EGLConfig config = chooseConfig(display);
|
||||
EGLContext context = createContext(display, config);
|
||||
EGLSurface surface = createSurface(display, config);
|
||||
|
||||
// Make "context" current.
|
||||
EXPECT_EGL_TRUE(eglMakeCurrent(display, surface, surface, context));
|
||||
|
||||
// Terminate display while "context" is current.
|
||||
EXPECT_EGL_TRUE(eglTerminate(display));
|
||||
|
||||
// Unmake "context" from current and allow Display to actually terminate.
|
||||
(void)eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
// Get EGLDisplay again.
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
|
||||
// Check if Display was actually terminated.
|
||||
EGLint val;
|
||||
EXPECT_EGL_FALSE(eglQueryContext(display, context, EGL_CONTEXT_CLIENT_TYPE, &val));
|
||||
EXPECT_EQ(eglGetError(), EGL_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
ANGLE_INSTANTIATE_TEST(EGLDisplayTest,
|
||||
WithNoFixture(ES2_D3D9()),
|
||||
WithNoFixture(ES2_D3D11()),
|
||||
|
||||
Reference in New Issue
Block a user