[Fix] (MG_Impl/EGLImpl, MG_Backend): track EGL surface lifecycle

This commit is contained in:
2026-07-03 07:45:40 +08:00
parent 03696f8a1a
commit 5cdc6c902e
7 changed files with 128 additions and 50 deletions
+38 -7
View File
@@ -200,18 +200,22 @@ namespace MobileGL::MG_Backend {
return true;
}
Bool BackendObject::CreateEGLWindowSurface(const WindowHandle& handle) {
Bool BackendObject::CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglDisplayInitialized) {
MGLOG_E("CreateEGLWindowSurface failed: EGL display is not initialized");
return false;
}
if (surface == EGL_NO_SURFACE) {
MGLOG_E("CreateEGLWindowSurface failed: invalid EGLSurface");
return false;
}
if (handle.Backend == WindowBackend::Unknown || !handle.Handle) {
MGLOG_E("CreateEGLWindowSurface failed: invalid native window handle");
return false;
}
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
if (m_eglSurfaceInitialized && m_eglSurface == surface && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle &&
m_windowHandle.Width == handle.Width && m_windowHandle.Height == handle.Height) {
return true;
@@ -223,6 +227,7 @@ namespace MobileGL::MG_Backend {
return false;
}
m_eglSurface = surface;
m_eglSurfaceInitialized = true;
m_eglSurfaceKind = SurfaceKind::Window;
m_eglCurrentThreads.clear();
@@ -230,9 +235,9 @@ namespace MobileGL::MG_Backend {
return true;
}
Bool BackendObject::ResizeEGLWindowSurface(Uint32 width, Uint32 height) {
Bool BackendObject::ResizeEGLWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglSurfaceInitialized || m_eglSurfaceKind != SurfaceKind::Window) {
if (!m_eglSurfaceInitialized || m_eglSurface != surface || m_eglSurfaceKind != SurfaceKind::Window) {
MGLOG_E("ResizeEGLWindowSurface failed: no window surface is initialized");
return false;
}
@@ -241,18 +246,22 @@ namespace MobileGL::MG_Backend {
return true;
}
Bool BackendObject::CreateEGLPbufferSurface(EGLint width, EGLint height) {
Bool BackendObject::CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_eglDisplayInitialized) {
MGLOG_E("CreateEGLPbufferSurface failed: EGL display is not initialized");
return false;
}
if (surface == EGL_NO_SURFACE) {
MGLOG_E("CreateEGLPbufferSurface failed: invalid EGLSurface");
return false;
}
if (width <= 0 || height <= 0) {
MGLOG_E("CreateEGLPbufferSurface failed: invalid size %dx%d", width, height);
return false;
}
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
if (m_eglSurfaceInitialized && m_eglSurface == surface && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
return true;
}
@@ -261,6 +270,7 @@ namespace MobileGL::MG_Backend {
return false;
}
m_eglSurface = surface;
m_eglSurfaceInitialized = true;
m_eglSurfaceKind = SurfaceKind::Pbuffer;
m_eglCurrentThreads.clear();
@@ -284,6 +294,10 @@ namespace MobileGL::MG_Backend {
MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized");
return false;
}
if (draw != m_eglSurface || read != m_eglSurface) {
MGLOG_E("MakeEGLCurrent failed: EGL surface is not backed by this backend");
return false;
}
if (draw == EGL_NO_SURFACE || read == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
MGLOG_E("MakeEGLCurrent failed: draw/read/context is invalid");
return false;
@@ -311,6 +325,7 @@ namespace MobileGL::MG_Backend {
m_eglSurfaceInitialized = false;
m_backendCapabilitiesInitialized = false;
m_eglSurfaceKind = SurfaceKind::None;
m_eglSurface = EGL_NO_SURFACE;
m_eglCurrentThreads.clear();
}
@@ -330,7 +345,7 @@ namespace MobileGL::MG_Backend {
MGLOG_E("SwapEGLBuffers failed: draw surface is not current on this thread");
return false;
}
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE) {
if (!m_eglSurfaceInitialized || draw == EGL_NO_SURFACE || draw != m_eglSurface) {
MGLOG_E("SwapEGLBuffers failed: invalid draw surface");
return false;
}
@@ -345,6 +360,22 @@ namespace MobileGL::MG_Backend {
return true;
}
void BackendObject::ReleaseEGLSurface(EGLSurface surface) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
for (auto currentIt = m_eglCurrentThreads.begin(); currentIt != m_eglCurrentThreads.end();) {
if (currentIt->second.DrawSurface == surface || currentIt->second.ReadSurface == surface) {
currentIt = m_eglCurrentThreads.erase(currentIt);
continue;
}
++currentIt;
}
if (m_eglSurface == surface) {
ResetEGLRuntimeState();
m_windowHandle = {};
}
}
void BackendObject::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
ResetEGLRuntimeState();
+5 -3
View File
@@ -245,11 +245,12 @@ namespace MobileGL {
virtual Bool InitWindowSurface() = 0;
virtual Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor);
virtual Bool CreateEGLWindowSurface(const WindowHandle& handle);
virtual Bool ResizeEGLWindowSurface(Uint32 width, Uint32 height);
virtual Bool CreateEGLPbufferSurface(EGLint width, EGLint height);
virtual Bool CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle);
virtual Bool ResizeEGLWindowSurface(EGLSurface surface, Uint32 width, Uint32 height);
virtual Bool CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height);
virtual Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw);
virtual void ReleaseEGLSurface(EGLSurface surface);
virtual void ReleaseEGLResources();
void SetWindowHandle(const WindowHandle& handle);
@@ -283,6 +284,7 @@ namespace MobileGL {
FormatCapabilityCache m_formatCapabilities;
WindowHandle m_windowHandle;
EGLDisplay m_eglDisplay = EGL_NO_DISPLAY;
EGLSurface m_eglSurface = EGL_NO_SURFACE;
Bool m_eglDisplayInitialized = false;
Bool m_eglSurfaceInitialized = false;
Bool m_backendCapabilitiesInitialized = false;
@@ -660,7 +660,7 @@ namespace MobileGL::MG_Backend::DirectGLES {
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
}
Bool BackendObject_DirectGLES::CreateEGLWindowSurface(const WindowHandle& handle) {
Bool BackendObject_DirectGLES::CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized");
@@ -675,8 +675,9 @@ namespace MobileGL::MG_Backend::DirectGLES {
return false;
}
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle;
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurface == surface &&
m_eglSurfaceKind == SurfaceKind::Window && m_windowHandle.Backend == handle.Backend &&
m_windowHandle.Handle == handle.Handle;
if (sameHandle) {
return true;
}
@@ -686,22 +687,26 @@ namespace MobileGL::MG_Backend::DirectGLES {
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLWindowSurface(handle);
return BackendObject::CreateEGLWindowSurface(surface, handle);
}
Bool BackendObject_DirectGLES::CreateEGLPbufferSurface(EGLint width, EGLint height) {
Bool BackendObject_DirectGLES::CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectGLES backend not initialized");
return false;
}
if (m_eglSurfaceInitialized && m_eglSurface == surface && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
return true;
}
if (m_eglSurfaceInitialized) {
DestroyEGLContext();
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLPbufferSurface(width, height);
return BackendObject::CreateEGLPbufferSurface(surface, width, height);
}
Bool BackendObject_DirectGLES::InitPbufferSurface(EGLint width, EGLint height) {
@@ -749,6 +754,14 @@ namespace MobileGL::MG_Backend::DirectGLES {
return BackendObject::SwapEGLBuffers(dpy, draw);
}
void BackendObject_DirectGLES::ReleaseEGLSurface(EGLSurface surface) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (m_eglSurface == surface) {
DestroyEGLContext();
}
BackendObject::ReleaseEGLSurface(surface);
}
void BackendObject_DirectGLES::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
DestroyEGLContext();
@@ -20,10 +20,11 @@ namespace MobileGL::MG_Backend::DirectGLES {
Bool InitCapabilities() override;
Bool InitWindowSurface() override;
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
Bool CreateEGLPbufferSurface(EGLint width, EGLint height) override;
Bool CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle) override;
Bool CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height) override;
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
void ReleaseEGLSurface(EGLSurface surface) override;
void ReleaseEGLResources() override;
const RendererInfo& GetRendererInfo() const override;
@@ -407,7 +407,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return BackendObject::InitializeEGLDisplay(dpy, major, minor);
}
Bool BackendObject_DirectVulkan::CreateEGLWindowSurface(const WindowHandle& handle) {
Bool BackendObject_DirectVulkan::CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectVulkan backend not initialized");
@@ -420,9 +420,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false;
}
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Window &&
m_windowHandle.Backend == handle.Backend && m_windowHandle.Handle == handle.Handle &&
m_windowHandle.Width == handle.Width && m_windowHandle.Height == handle.Height;
const Bool sameHandle = m_eglSurfaceInitialized && m_eglSurface == surface &&
m_eglSurfaceKind == SurfaceKind::Window && m_windowHandle.Backend == handle.Backend &&
m_windowHandle.Handle == handle.Handle && m_windowHandle.Width == handle.Width &&
m_windowHandle.Height == handle.Height;
if (sameHandle) {
return true;
}
@@ -432,10 +433,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLWindowSurface(handle);
return BackendObject::CreateEGLWindowSurface(surface, handle);
}
Bool BackendObject_DirectVulkan::ResizeEGLWindowSurface(Uint32 width, Uint32 height) {
Bool BackendObject_DirectVulkan::ResizeEGLWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectVulkan backend not initialized");
@@ -445,27 +446,27 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MGLOG_E("DirectVulkan renderer is not initialized");
return false;
}
if (!BackendObject::ResizeEGLWindowSurface(width, height)) {
if (!BackendObject::ResizeEGLWindowSurface(surface, width, height)) {
return false;
}
pVulkanRenderer->RequestSwapchainResize(width, height);
return true;
}
Bool BackendObject_DirectVulkan::CreateEGLPbufferSurface(EGLint width, EGLint height) {
Bool BackendObject_DirectVulkan::CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (!m_initialized) {
MGLOG_E("DirectVulkan backend not initialized");
return false;
}
if (m_eglSurfaceInitialized && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
if (m_eglSurfaceInitialized && m_eglSurface == surface && m_eglSurfaceKind == SurfaceKind::Pbuffer) {
return true;
}
if (m_eglSurfaceInitialized || pVulkanRenderer) {
pVulkanRenderer.reset();
ResetEGLRuntimeState();
}
return BackendObject::CreateEGLPbufferSurface(width, height);
return BackendObject::CreateEGLPbufferSurface(surface, width, height);
}
Bool BackendObject_DirectVulkan::MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
@@ -489,6 +490,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return BackendObject::SwapEGLBuffers(dpy, draw);
}
void BackendObject_DirectVulkan::ReleaseEGLSurface(EGLSurface surface) {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
if (m_eglSurface == surface) {
pVulkanRenderer.reset();
}
BackendObject::ReleaseEGLSurface(surface);
}
void BackendObject_DirectVulkan::ReleaseEGLResources() {
const std::lock_guard<std::recursive_mutex> lock(m_eglStateMutex);
pVulkanRenderer.reset();
@@ -21,11 +21,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
Bool InitWindowSurface() override;
Bool InitCapabilities() override;
Bool InitializeEGLDisplay(EGLDisplay dpy, EGLint* major, EGLint* minor) override;
Bool CreateEGLWindowSurface(const WindowHandle& handle) override;
Bool ResizeEGLWindowSurface(Uint32 width, Uint32 height) override;
Bool CreateEGLPbufferSurface(EGLint width, EGLint height) override;
Bool CreateEGLWindowSurface(EGLSurface surface, const WindowHandle& handle) override;
Bool ResizeEGLWindowSurface(EGLSurface surface, Uint32 width, Uint32 height) override;
Bool CreateEGLPbufferSurface(EGLSurface surface, EGLint width, EGLint height) override;
Bool MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override;
Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override;
void ReleaseEGLSurface(EGLSurface surface) override;
void ReleaseEGLResources() override;
const RendererInfo& GetRendererInfo() const override;
+40 -19
View File
@@ -118,24 +118,31 @@ namespace MobileGL::MG_Impl::EGLImpl {
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
return EGL_NO_SURFACE;
}
const MG_Backend::WindowHandle windowHandle = {
.Backend = DetectWindowBackend(),
.Handle = ToVoidHandle(window),
.Width = static_cast<Uint32>(std::max<EGLint>(GetAttribValue(attrib_list, EGL_WIDTH, 0), 0)),
.Height = static_cast<Uint32>(std::max<EGLint>(GetAttribValue(attrib_list, EGL_HEIGHT, 0), 0)),
};
if (!backendObject->CreateEGLWindowSurface(windowHandle)) {
EGLSurface surface = state->CreateWindowSurface(dpy, config, window, attrib_list);
if (surface == EGL_NO_SURFACE) {
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
state->DestroySurface(dpy, surface);
return EGL_NO_SURFACE;
}
if (!backendObject->CreateEGLWindowSurface(surface, windowHandle)) {
state->DestroySurface(dpy, surface);
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
return state->CreateWindowSurface(dpy, config, window, attrib_list);
return surface;
}
EGLBoolean SwapBuffers(EGLDisplay dpy, EGLSurface draw) {
@@ -281,11 +288,18 @@ namespace MobileGL::MG_Impl::EGLImpl {
}
EGLBoolean DestroySurface(EGLDisplay dpy, EGLSurface surface) {
const std::lock_guard<std::recursive_mutex> operationLock(EGLOperationMutex());
auto* state = GetState();
if (!state) {
return EGL_FALSE;
}
return state->DestroySurface(dpy, surface) ? EGL_TRUE : EGL_FALSE;
if (!state->DestroySurface(dpy, surface)) {
return EGL_FALSE;
}
if (auto* backendObject = MG_Backend::pActiveBackendObject.get()) {
backendObject->ReleaseEGLSurface(surface);
}
return EGL_TRUE;
}
EGLBoolean Terminate(EGLDisplay dpy) {
@@ -420,7 +434,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
if (!backendObject) {
return EGL_NO_SURFACE;
}
if (!backendObject->CreateEGLPbufferSurface(width, height)) {
if (!backendObject->CreateEGLPbufferSurface(surface, width, height)) {
state->DestroySurface(dpy, surface);
state->SetError(EGL_BAD_ALLOC);
return EGL_NO_SURFACE;
@@ -643,24 +657,31 @@ namespace MobileGL::MG_Impl::EGLImpl {
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
return EGL_NO_SURFACE;
}
const MG_Backend::WindowHandle windowHandle = {
.Backend = DetectWindowBackend(),
.Handle = native_window,
.Width = static_cast<Uint32>(std::max<EGLint>(GetAttribValueAttrib(attrib_list, EGL_WIDTH, 0), 0)),
.Height = static_cast<Uint32>(std::max<EGLint>(GetAttribValueAttrib(attrib_list, EGL_HEIGHT, 0), 0)),
};
if (!backendObject->CreateEGLWindowSurface(windowHandle)) {
EGLSurface surface = state->CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
if (surface == EGL_NO_SURFACE) {
return EGL_NO_SURFACE;
}
auto* backendObject = GetBackendObject(state);
if (!backendObject) {
MGLOG_E("activeBackendObject not initialized!");
state->DestroySurface(dpy, surface);
return EGL_NO_SURFACE;
}
if (!backendObject->CreateEGLWindowSurface(surface, windowHandle)) {
state->DestroySurface(dpy, surface);
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_NO_SURFACE;
}
return state->CreatePlatformWindowSurface(dpy, config, native_window, attrib_list);
return surface;
}
EGLBoolean ResizePlatformWindowSurface(EGLDisplay dpy, EGLSurface surface, EGLint width, EGLint height) {
@@ -678,7 +699,7 @@ namespace MobileGL::MG_Impl::EGLImpl {
}
width = std::max<EGLint>(width, 1);
height = std::max<EGLint>(height, 1);
if (!backendObject->ResizeEGLWindowSurface(static_cast<Uint32>(width), static_cast<Uint32>(height))) {
if (!backendObject->ResizeEGLWindowSurface(surface, static_cast<Uint32>(width), static_cast<Uint32>(height))) {
state->SetError(EGL_BAD_NATIVE_WINDOW);
return EGL_FALSE;
}