[Fix] (MG_Backend/DirectVulkan): separate EGL surface lifecycle

This commit is contained in:
2026-07-03 12:20:40 +08:00
parent afdbf0a194
commit 45f1a13cc3
4 changed files with 147 additions and 49 deletions
+26 -11
View File
@@ -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");
@@ -356,9 +356,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
auto nativeWindow = reinterpret_cast<NativeWindowType>(m_windowHandle.Handle);
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(nativeWindow);
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitWindowSurface: VulkanRenderer creation failed");
pVulkanRenderer->Initialize();
VulkanRendererConfig config;
config.SurfaceWidth = std::max<Uint32>(m_windowHandle.Width, 1);
config.SurfaceHeight = std::max<Uint32>(m_windowHandle.Height, 1);
if (pVulkanRenderer) {
pVulkanRenderer->BindSurface(nativeWindow, config);
} else {
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(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<Uint32>(std::max<EGLint>(width, 1));
config.SurfaceHeight = static_cast<Uint32>(std::max<EGLint>(height, 1));
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(NativeWindowType{}, config);
MOBILEGL_ASSERT(pVulkanRenderer != nullptr, "InitPbufferSurface: VulkanRenderer creation failed");
pVulkanRenderer->Initialize();
if (pVulkanRenderer) {
pVulkanRenderer->BindSurface(NativeWindowType{}, config);
} else {
pVulkanRenderer = MakeUnique<MG_Backend::DirectVulkan::VulkanRenderer>(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 {
@@ -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<id>(m_platformLibrary));
m_platformLibrary = nullptr;
}
if (m_platformDisplay != nullptr) {
Release(reinterpret_cast<id>(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<XCloseDisplayFn>(m_platformCloseDisplay);
if (closeDisplay) {
closeDisplay(static_cast<Display*>(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<Uint32>(cfg.SurfaceWidth, 1);
m_config.SurfaceHeight = std::max<Uint32>(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<id>(m_platformLibrary));
m_platformLibrary = nullptr;
}
if (m_platformDisplay != nullptr) {
Release(reinterpret_cast<id>(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<XCloseDisplayFn>(m_platformCloseDisplay);
if (closeDisplay) {
closeDisplay(static_cast<Display*>(m_platformDisplay));
}
m_platformDisplay = nullptr;
}
m_platformCloseDisplay = nullptr;
if (m_platformLibrary != nullptr) {
dlclose(m_platformLibrary);
m_platformLibrary = nullptr;
}
#endif
m_window = 0;
}
Vector<VkQueueFamilyProperties> VulkanRenderer::GetQueueFamilyFromPhysicalDevice(VkPhysicalDevice device) {
Uint32 queueFamilyCount = 0;
vkGetPhysicalDeviceQueueFamilyProperties(device, &queueFamilyCount, nullptr);
@@ -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<DrawSetupAspect> 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();