From 5cdc6c902e8f62ba7ac221f7eb38a664390c1f90 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 3 Jul 2026 07:45:40 +0800 Subject: [PATCH] [Fix] (MG_Impl/EGLImpl, MG_Backend): track EGL surface lifecycle --- MobileGL/MG_Backend/BackendObject.cpp | 45 +++++++++++--- MobileGL/MG_Backend/BackendObject.h | 8 ++- .../DirectGLES/BackendObject_DirectGLES.cpp | 25 ++++++-- .../DirectGLES/BackendObject_DirectGLES.h | 5 +- .../BackendObject_DirectVulkan.cpp | 29 +++++---- .../DirectVulkan/BackendObject_DirectVulkan.h | 7 ++- MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp | 59 +++++++++++++------ 7 files changed, 128 insertions(+), 50 deletions(-) diff --git a/MobileGL/MG_Backend/BackendObject.cpp b/MobileGL/MG_Backend/BackendObject.cpp index 40cbd983..6a8a4f89 100644 --- a/MobileGL/MG_Backend/BackendObject.cpp +++ b/MobileGL/MG_Backend/BackendObject.cpp @@ -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 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 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 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 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 lock(m_eglStateMutex); ResetEGLRuntimeState(); diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index f1c77250..45c18893 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -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; diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp index 7d7f3dfb..e08c10b0 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.cpp @@ -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 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 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 lock(m_eglStateMutex); + if (m_eglSurface == surface) { + DestroyEGLContext(); + } + BackendObject::ReleaseEGLSurface(surface); + } + void BackendObject_DirectGLES::ReleaseEGLResources() { const std::lock_guard lock(m_eglStateMutex); DestroyEGLContext(); diff --git a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.h b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.h index 94e07d2b..219019ba 100644 --- a/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.h +++ b/MobileGL/MG_Backend/DirectGLES/BackendObject_DirectGLES.h @@ -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; diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index 23f15e11..3faa2571 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -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 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 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 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 lock(m_eglStateMutex); + if (m_eglSurface == surface) { + pVulkanRenderer.reset(); + } + BackendObject::ReleaseEGLSurface(surface); + } + void BackendObject_DirectVulkan::ReleaseEGLResources() { const std::lock_guard lock(m_eglStateMutex); pVulkanRenderer.reset(); diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h index 898a0a68..1d89828b 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h @@ -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; diff --git a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp index ecca9326..e30b54d1 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp @@ -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(std::max(GetAttribValue(attrib_list, EGL_WIDTH, 0), 0)), .Height = static_cast(std::max(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 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(std::max(GetAttribValueAttrib(attrib_list, EGL_WIDTH, 0), 0)), .Height = static_cast(std::max(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(width, 1); height = std::max(height, 1); - if (!backendObject->ResizeEGLWindowSurface(static_cast(width), static_cast(height))) { + if (!backendObject->ResizeEGLWindowSurface(surface, static_cast(width), static_cast(height))) { state->SetError(EGL_BAD_NATIVE_WINDOW); return EGL_FALSE; }