diff --git a/MobileGL/MG_Backend/BackendObject.cpp b/MobileGL/MG_Backend/BackendObject.cpp index 6c8cb60a..11118554 100644 --- a/MobileGL/MG_Backend/BackendObject.cpp +++ b/MobileGL/MG_Backend/BackendObject.cpp @@ -229,6 +229,17 @@ namespace MobileGL::MG_Backend { return true; } + Bool BackendObject::ResizeEGLWindowSurface(Uint32 width, Uint32 height) { + const std::lock_guard lock(m_eglStateMutex); + if (!m_eglSurfaceInitialized || m_eglSurfaceKind != SurfaceKind::Window) { + MGLOG_E("ResizeEGLWindowSurface failed: no window surface is initialized"); + return false; + } + m_windowHandle.Width = width; + m_windowHandle.Height = height; + return true; + } + Bool BackendObject::CreateEGLPbufferSurface(EGLint width, EGLint height) { const std::lock_guard lock(m_eglStateMutex); if (!m_eglDisplayInitialized) { diff --git a/MobileGL/MG_Backend/BackendObject.h b/MobileGL/MG_Backend/BackendObject.h index 8c76d7ea..7e6523f0 100644 --- a/MobileGL/MG_Backend/BackendObject.h +++ b/MobileGL/MG_Backend/BackendObject.h @@ -246,6 +246,7 @@ namespace MobileGL { 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 MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx); virtual Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw); diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp index 0e98b6a9..693175e3 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.cpp @@ -434,6 +434,23 @@ namespace MobileGL::MG_Backend::DirectVulkan { return BackendObject::CreateEGLWindowSurface(handle); } + Bool BackendObject_DirectVulkan::ResizeEGLWindowSurface(Uint32 width, Uint32 height) { + const std::lock_guard lock(m_eglStateMutex); + if (!m_initialized) { + MGLOG_E("DirectVulkan backend not initialized"); + return false; + } + if (!pVulkanRenderer) { + MGLOG_E("DirectVulkan renderer is not initialized"); + return false; + } + if (!BackendObject::ResizeEGLWindowSurface(width, height)) { + return false; + } + pVulkanRenderer->RequestSwapchainResize(width, height); + return true; + } + Bool BackendObject_DirectVulkan::CreateEGLPbufferSurface(EGLint width, EGLint height) { const std::lock_guard lock(m_eglStateMutex); if (!m_initialized) { diff --git a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h index 73571aa2..898a0a68 100644 --- a/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h +++ b/MobileGL/MG_Backend/DirectVulkan/BackendObject_DirectVulkan.h @@ -22,6 +22,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { 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 MakeEGLCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) override; Bool SwapEGLBuffers(EGLDisplay dpy, EGLSurface draw) override; diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index b7ce0d5a..6d3c6a35 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -5389,9 +5389,15 @@ void main() { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { MGLOG_D("Present, vkQueuePresentKHR got %d, recreating swapchain", result); RecreateSwapchain(); + m_swapchainResizeRequested = false; result = VK_SUCCESS; } VK_VERIFY(result, "Present, vkQueuePresentKHR"); + if (m_swapchainResizeRequested) { + MGLOG_D("Present, processing requested swapchain resize"); + RecreateSwapchain(); + m_swapchainResizeRequested = false; + } // 3) Advance frame slot. m_frameContext.AdvanceToNext(); @@ -5401,6 +5407,7 @@ void main() { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result); RecreateSwapchain(); + m_swapchainResizeRequested = false; result = m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); } @@ -6105,6 +6112,17 @@ void main() { return m_physicalDevice; } + void VulkanRenderer::RequestSwapchainResize(Uint32 width, Uint32 height) { + width = std::max(width, 1); + height = std::max(height, 1); + if (m_config.SurfaceWidth == width && m_config.SurfaceHeight == height) { + return; + } + m_config.SurfaceWidth = width; + m_config.SurfaceHeight = height; + m_swapchainResizeRequested = true; + } + VkInstance VulkanRenderer::GetInstance() const { return m_instance; } diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 5beed723..dc316088 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -160,6 +160,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { VkInstance GetInstance() const; Bool IsDrawIndirectCountExtensionEnabled() const; + void RequestSwapchainResize(Uint32 width, Uint32 height); void RecreateSwapchain(); private: @@ -206,6 +207,7 @@ namespace MobileGL::MG_Backend::DirectVulkan { void* m_platformLibrary = nullptr; void* m_platformCloseDisplay = nullptr; VulkanRendererConfig m_config; + Bool m_swapchainResizeRequested = false; // Vulkan objects Bool m_validationLayersEnabled = false; diff --git a/MobileGL/MG_Impl/CGLImpl/CGLImpl.cpp b/MobileGL/MG_Impl/CGLImpl/CGLImpl.cpp index ae09a832..e1e6e9af 100644 --- a/MobileGL/MG_Impl/CGLImpl/CGLImpl.cpp +++ b/MobileGL/MG_Impl/CGLImpl/CGLImpl.cpp @@ -256,6 +256,18 @@ namespace MobileGL::MG_Impl::CGLImpl { object.HasDrawable = true; return GetCurrentContext() == ctx ? MakeCurrentLocked(ctx, object) : kCGLNoError; } + + CGLError ResizeSurfaceLocked(ContextObject& object) { + if (object.Surface == EGL_NO_SURFACE) { + return kCGLBadDrawable; + } + return EGLImpl::ResizePlatformWindowSurface( + object.Display, object.Surface, + std::max(object.SurfaceBackingSize[0], 1), + std::max(object.SurfaceBackingSize[1], 1)) + ? kCGLNoError + : kCGLBadDrawable; + } } // namespace CGLError ChoosePixelFormat(const CGLPixelFormatAttribute* attribs, CGLPixelFormatObj* pix, GLint* npix) { @@ -492,8 +504,8 @@ namespace MobileGL::MG_Impl::CGLImpl { } object->SurfaceBackingSize[0] = width; object->SurfaceBackingSize[1] = height; - if (object->MetalLayer) { - return RecreateSurfaceLocked(ctx, *object); + if (object->MetalLayer && object->Surface != EGL_NO_SURFACE) { + return ResizeSurfaceLocked(*object); } return kCGLNoError; } @@ -653,6 +665,11 @@ namespace MobileGL::MG_Impl::CGLImpl { object->HasDrawable = true; return kCGLNoError; } + if (object->Surface != EGL_NO_SURFACE && object->MetalLayer == metalLayer) { + object->View = nsView; + object->HasDrawable = true; + return ResizeSurfaceLocked(*object); + } if (object->Surface != EGL_NO_SURFACE) { EGLImpl::DestroySurface(object->Display, object->Surface); object->Surface = EGL_NO_SURFACE; diff --git a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp index f73e3846..01557cf5 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLImpl.cpp @@ -623,6 +623,28 @@ namespace MobileGL::MG_Impl::EGLImpl { return state->CreatePlatformWindowSurface(dpy, config, native_window, attrib_list); } + EGLBoolean ResizePlatformWindowSurface(EGLDisplay dpy, EGLSurface surface, EGLint width, EGLint height) { + auto* state = GetState(); + if (!state) { + return EGL_FALSE; + } + if (!state->ResizeSurface(dpy, surface, width, height)) { + return EGL_FALSE; + } + auto* backendObject = GetBackendObject(state); + if (!backendObject) { + MGLOG_E("activeBackendObject not initialized!"); + return EGL_FALSE; + } + width = std::max(width, 1); + height = std::max(height, 1); + if (!backendObject->ResizeEGLWindowSurface(static_cast(width), static_cast(height))) { + state->SetError(EGL_BAD_NATIVE_WINDOW); + return EGL_FALSE; + } + return EGL_TRUE; + } + EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap, const EGLAttrib* attrib_list) { auto* state = GetState(); diff --git a/MobileGL/MG_Impl/EGLImpl/EGLImpl.h b/MobileGL/MG_Impl/EGLImpl/EGLImpl.h index 02d72f74..0a658ea1 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLImpl.h +++ b/MobileGL/MG_Impl/EGLImpl/EGLImpl.h @@ -57,6 +57,7 @@ namespace MobileGL::MG_Impl::EGLImpl { EGLDisplay GetPlatformDisplay(EGLenum platform, void* native_display, const EGLAttrib* attrib_list); EGLSurface CreatePlatformWindowSurface(EGLDisplay dpy, EGLConfig config, void* native_window, const EGLAttrib* attrib_list); + EGLBoolean ResizePlatformWindowSurface(EGLDisplay dpy, EGLSurface surface, EGLint width, EGLint height); EGLSurface CreatePlatformPixmapSurface(EGLDisplay dpy, EGLConfig config, void* native_pixmap, const EGLAttrib* attrib_list); EGLBoolean WaitSync(EGLDisplay dpy, EGLSync sync, EGLint flags); diff --git a/MobileGL/MG_State/EGLState/Core.cpp b/MobileGL/MG_State/EGLState/Core.cpp index 8240898b..2390e488 100644 --- a/MobileGL/MG_State/EGLState/Core.cpp +++ b/MobileGL/MG_State/EGLState/Core.cpp @@ -935,6 +935,23 @@ namespace MobileGL { return true; } + Bool EGLContext::ResizeSurface(EGLDisplayHandle display, EGLSurfaceHandle surface, + EGLint width, EGLint height) { + const std::lock_guard lock(m_mutex); + auto surfaceIt = m_surfaces.find(surface); + if (surfaceIt == m_surfaces.end()) { + SetError(EGL_BAD_SURFACE); + return false; + } + if (surfaceIt->second.Display != display) { + SetError(EGL_BAD_MATCH); + return false; + } + surfaceIt->second.Width = std::max(width, 1); + surfaceIt->second.Height = std::max(height, 1); + return true; + } + Bool EGLContext::QuerySurface(EGLDisplayHandle display, EGLSurfaceHandle surface, EGLint attribute, EGLint* value) const { const std::lock_guard lock(m_mutex); diff --git a/MobileGL/MG_State/EGLState/Core.h b/MobileGL/MG_State/EGLState/Core.h index 6867e68d..84f86841 100644 --- a/MobileGL/MG_State/EGLState/Core.h +++ b/MobileGL/MG_State/EGLState/Core.h @@ -74,6 +74,7 @@ namespace MobileGL { EGLSurfaceHandle CreatePlatformPixmapSurface(EGLDisplayHandle display, EGLConfigHandle config, void* nativePixmap, const EGLAttrib* attribList); Bool DestroySurface(EGLDisplayHandle display, EGLSurfaceHandle surface); + Bool ResizeSurface(EGLDisplayHandle display, EGLSurfaceHandle surface, EGLint width, EGLint height); Bool QuerySurface(EGLDisplayHandle display, EGLSurfaceHandle surface, EGLint attribute, EGLint* value) const; Bool ValidateSurface(EGLSurfaceHandle surface) const;