mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-08 04:08:32 +09:00
[Fix] (MG_Backend/DirectVulkan): separate EGL surface lifecycle
This commit is contained in:
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user