From 45f1a13cc3ca6ce5ba0cd8083c8f1e4a1c3b27ee Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Fri, 3 Jul 2026 12:20:40 +0800 Subject: [PATCH] [Fix] (MG_Backend/DirectVulkan): separate EGL surface lifecycle --- MobileGL/MG_Backend/BackendObject.cpp | 37 +++-- .../BackendObject_DirectVulkan.cpp | 27 +++- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 129 +++++++++++++----- .../DirectVulkan/Renderer/VulkanRenderer.h | 3 + 4 files changed, 147 insertions(+), 49 deletions(-) diff --git a/MobileGL/MG_Backend/BackendObject.cpp b/MobileGL/MG_Backend/BackendObject.cpp index 94da30bb..2b0a681d 100644 --- a/MobileGL/MG_Backend/BackendObject.cpp +++ b/MobileGL/MG_Backend/BackendObject.cpp @@ -291,6 +291,19 @@ namespace MobileGL::MG_Backend { return true; } + if (m_eglSurfaceInitialized) { + if (IsEGLSurfaceCurrent(m_eglSurface)) { + MGLOG_E("ActivateEGLSurface failed: current EGL surface is still in use"); + return false; + } + OnEGLSurfaceReleased(m_eglSurface); + m_eglSurfaceInitialized = false; + m_backendCapabilitiesInitialized = false; + m_eglSurfaceKind = SurfaceKind::None; + m_eglSurface = EGL_NO_SURFACE; + m_windowHandle = {}; + } + if (surfaceState->Kind == SurfaceKind::Window) { SetWindowHandle(surfaceState->Window); if (!InitWindowSurface()) { @@ -310,7 +323,6 @@ namespace MobileGL::MG_Backend { m_eglSurface = surface; m_eglSurfaceInitialized = true; m_eglSurfaceKind = surfaceState->Kind; - m_eglCurrentThreads.clear(); m_backendCapabilitiesInitialized = false; return true; } @@ -327,12 +339,6 @@ namespace MobileGL::MG_Backend { MGLOG_E("MakeEGLCurrent failed: EGL display mismatch or not initialized"); return false; } - if (!m_eglSurfaceInitialized) { - if (draw != read || !ActivateEGLSurface(draw)) { - MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized"); - return false; - } - } if (!GetRegisteredEGLSurface(draw) || !GetRegisteredEGLSurface(read)) { MGLOG_E("MakeEGLCurrent failed: EGL surface is not registered"); return false; @@ -341,15 +347,24 @@ namespace MobileGL::MG_Backend { MGLOG_E("MakeEGLCurrent failed: separate draw/read surfaces are not supported"); return false; } - if (draw != m_eglSurface && !ActivateEGLSurface(draw)) { - 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; } + if (m_eglSurfaceInitialized && draw != m_eglSurface) { + ReleaseEGLCurrentThread(threadKey); + } + if (!m_eglSurfaceInitialized) { + if (!ActivateEGLSurface(draw)) { + MGLOG_E("MakeEGLCurrent failed: EGL surface is not initialized"); + return false; + } + } + if (draw != m_eglSurface && !ActivateEGLSurface(draw)) { + MGLOG_E("MakeEGLCurrent failed: EGL surface is not backed by this backend"); + return false; + } if (!m_backendCapabilitiesInitialized) { if (!InitCapabilities()) { MGLOG_E("MakeEGLCurrent failed: InitCapabilities failed"); diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index 996167e0..7bc71482 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -356,9 +356,16 @@ namespace MobileGL::MG_Backend::DirectVulkan { auto nativeWindow = reinterpret_cast(m_windowHandle.Handle); - pVulkanRenderer = MakeUnique(nativeWindow); - MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed"); - pVulkanRenderer->Initialize(); + VulkanRendererConfig config; + config.SurfaceWidth = std::max(m_windowHandle.Width, 1); + config.SurfaceHeight = std::max(m_windowHandle.Height, 1); + if (pVulkanRenderer) { + pVulkanRenderer->BindSurface(nativeWindow, config); + } else { + pVulkanRenderer = MakeUnique(nativeWindow, config); + MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed"); + pVulkanRenderer->Initialize(); + } return true; } @@ -366,9 +373,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { VulkanRendererConfig config; config.SurfaceWidth = static_cast(std::max(width, 1)); config.SurfaceHeight = static_cast(std::max(height, 1)); - pVulkanRenderer = MakeUnique(NativeWindowType{}, config); - MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitPbufferSurface: VulkanRenderer creation failed"); - pVulkanRenderer->Initialize(); + if (pVulkanRenderer) { + pVulkanRenderer->BindSurface(NativeWindowType{}, config); + } else { + pVulkanRenderer = MakeUnique(NativeWindowType{}, config); + MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitPbufferSurface: VulkanRenderer creation failed"); + pVulkanRenderer->Initialize(); + } return true; } @@ -474,7 +485,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { void BackendObject_DirectVulkan::OnEGLSurfaceReleased(EGLSurface surface) { (void)surface; - pVulkanRenderer.reset(); + if (pVulkanRenderer) { + pVulkanRenderer->ReleaseSurface(); + } } const RendererInfo& BackendObject_DirectVulkan::GetRendererInfo() const { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index f4ce460f..7e6c096f 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -2021,37 +2021,7 @@ void main() { } s_vkCmdDrawIndexedIndirectCount = nullptr; - if (m_instance != VK_NULL_HANDLE && m_surface != VK_NULL_HANDLE) { - vkDestroySurfaceKHR(m_instance, m_surface, nullptr); - m_surface = VK_NULL_HANDLE; - } - -#if defined(VK_USE_PLATFORM_METAL_EXT) - if (m_platformLibrary != nullptr) { - Release(reinterpret_cast(m_platformLibrary)); - m_platformLibrary = nullptr; - } - if (m_platformDisplay != nullptr) { - Release(reinterpret_cast(m_platformDisplay)); - m_platformDisplay = nullptr; - } -#endif - -#if defined(VK_USE_PLATFORM_XLIB_KHR) - if (m_platformDisplay != nullptr) { - using XCloseDisplayFn = int (*)(Display*); - auto* closeDisplay = reinterpret_cast(m_platformCloseDisplay); - if (closeDisplay) { - closeDisplay(static_cast(m_platformDisplay)); - } - m_platformDisplay = nullptr; - } - m_platformCloseDisplay = nullptr; - if (m_platformLibrary != nullptr) { - dlclose(m_platformLibrary); - m_platformLibrary = nullptr; - } -#endif + DestroySurface(); if (m_debugMessenger != VK_NULL_HANDLE) { DestroyDebugMessenger(); @@ -2065,6 +2035,67 @@ void main() { MGLOG_I("VulkanRenderer shut down completed"); } + void VulkanRenderer::BindSurface(NativeWindowType window, const VulkanRendererConfig& cfg) { + if (m_instance == VK_NULL_HANDLE) { + m_window = window; + m_config = cfg; + Initialize(); + return; + } + + if (m_device != VK_NULL_HANDLE) { + VK_VERIFY(vkDeviceWaitIdle(m_device)); + } + + ReleaseSurface(); + m_window = window; + m_config.SurfaceWidth = std::max(cfg.SurfaceWidth, 1); + m_config.SurfaceHeight = std::max(cfg.SurfaceHeight, 1); + CreateSurface(); + + const auto queueFamilies = GetQueueFamilyFromPhysicalDevice(m_physicalDevice.handle); + const Int presentFamily = + GetPresentQueueFamilyIndex(m_physicalDevice, m_surface, queueFamilies, + m_physicalDevice.queueFamilies.presentFamily); + MOBILEGL_ASSERT(presentFamily == m_physicalDevice.queueFamilies.presentFamily, + "BindSurface: new EGL surface requires a different Vulkan present queue family"); + + RecreateSwapchain(); + VkResult acquireResult = + m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); + if (acquireResult == VK_ERROR_OUT_OF_DATE_KHR || acquireResult == VK_SUBOPTIMAL_KHR) { + RecreateSwapchain(); + acquireResult = + m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); + } + VK_VERIFY(acquireResult, "BindSurface, WaitAndAcquireNextImage"); + if (m_textureManager) { + m_textureManager->BeginFrame(m_frameContext.GetCurrentFrameIndex()); + } + m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex()); + m_transientVertexIndexBufferSlicesThisFrame.clear(); + m_swapchainResizeRequested = false; + } + + void VulkanRenderer::ReleaseSurface() { + if (m_surface == VK_NULL_HANDLE && m_swapchainObject.GetHandle() == VK_NULL_HANDLE) { + return; + } + + if (m_device != VK_NULL_HANDLE) { + VK_VERIFY(vkDeviceWaitIdle(m_device)); + DestroyDeferredDepthMipmapCleanup(); + if (m_renderPassManager) { + ShutdownSwapchain(); + } else { + m_swapchainObject.Shutdown(m_device); + } + } + DestroySurface(); + m_swapchainResizeRequested = false; + m_imageIndexAcquired = 0; + } + Bool VulkanRenderer::UploadAndBindVertexBuffers( VkCommandBuffer commandBuffer, const MG_State::GLState::VertexArrayObject& vao, const DrawCmdParam& drawParams) { auto& vertexInputState = m_vertexInputStateFactory->GetOrCreateVertexInputState(vao); @@ -6013,6 +6044,42 @@ void main() { #endif } + void VulkanRenderer::DestroySurface() { + if (m_instance != VK_NULL_HANDLE && m_surface != VK_NULL_HANDLE) { + vkDestroySurfaceKHR(m_instance, m_surface, nullptr); + m_surface = VK_NULL_HANDLE; + } + +#if defined(VK_USE_PLATFORM_METAL_EXT) + if (m_platformLibrary != nullptr) { + Release(reinterpret_cast(m_platformLibrary)); + m_platformLibrary = nullptr; + } + if (m_platformDisplay != nullptr) { + Release(reinterpret_cast(m_platformDisplay)); + m_platformDisplay = nullptr; + } +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) + if (m_platformDisplay != nullptr) { + using XCloseDisplayFn = int (*)(Display*); + auto* closeDisplay = reinterpret_cast(m_platformCloseDisplay); + if (closeDisplay) { + closeDisplay(static_cast(m_platformDisplay)); + } + m_platformDisplay = nullptr; + } + m_platformCloseDisplay = nullptr; + if (m_platformLibrary != nullptr) { + dlclose(m_platformLibrary); + m_platformLibrary = nullptr; + } +#endif + + m_window = 0; + } + Vector VulkanRenderer::GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device) { Uint32 queueFamilyCount = 0; vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr); diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index dc316088..37103b48 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -108,6 +108,8 @@ namespace MobileGL::MG_Backend::DirectVulkan { void Initialize(); void Shutdown(); + void BindSurface(NativeWindowType window, const VulkanRendererConfig& cfg); + void ReleaseSurface(); Bool SetupDraw(FrameContext::FrameData& frame, GLenum mode, Flags aspects, const DrawCmdParam& drawParams, @@ -264,6 +266,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkResult DestroyDebugMessenger(); VkDebugUtilsMessengerCreateInfoEXT PopulateDebugMessengerCreateInfo(); void CreateSurface(); + void DestroySurface(); void PickPhysicalDevice(); void CreateLogicalDeviceAndQueues(); void CreateAllocator();