From 72fa1221a5b8dbc167359490fe13cb1da47c9bfe Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Sun, 26 Jul 2026 07:16:11 -0400 Subject: [PATCH] [Fix] (DirectVulkan): survive zero-area windows at renderer init - skip the eager first acquire when RecreateSwapchain's minimize guard left no swapchain (GLFW's hidden helper window), and let Present bring the swapchain up once the window has real size --- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index a7f34aaa..e7566207 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -2153,15 +2153,23 @@ void main() { MOBILEGL_ASSERT(m_vertexInputStateFactory != nullptr, "VertexInputStateFactory creation failed."); // Prime the first frame so Render() always targets an acquired swapchain image. - VkResult acquireResult = - m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); - if (acquireResult == VK_ERROR_OUT_OF_DATE_KHR || acquireResult == VK_SUBOPTIMAL_KHR) { - MGLOG_D("Initialize, vkAcquireNextImageKHR got %d, recreating swapchain", acquireResult); - RecreateSwapchain(); - acquireResult = + // A zero-area window (GLFW's hidden helper window during the WGL bootstrap, or a + // window that is already minimized) legitimately yields no swapchain here; defer + // the first acquire to Present in that case instead of acquiring from a null + // swapchain handle. + if (m_swapchainObject.GetHandle() != VK_NULL_HANDLE) { + VkResult acquireResult = m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); + if (acquireResult == VK_ERROR_OUT_OF_DATE_KHR || acquireResult == VK_SUBOPTIMAL_KHR) { + MGLOG_D("Initialize, vkAcquireNextImageKHR got %d, recreating swapchain", acquireResult); + RecreateSwapchain(); + acquireResult = + m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); + } + VK_VERIFY(acquireResult, "Initialize, WaitAndAcquireNextImage"); + } else { + MGLOG_W("DirectVulkan: no swapchain at initialization (zero-area window); deferring first acquire"); } - VK_VERIFY(acquireResult, "Initialize, WaitAndAcquireNextImage"); m_textureManager->BeginFrame(m_frameContext.GetCurrentFrameIndex()); m_bufferManager.BeginFrame(m_frameContext.GetCurrentFrameIndex()); m_convertedVertexStreams.clear(); @@ -6857,6 +6865,19 @@ void main() { } void VulkanRenderer::Present() { + if (m_swapchainObject.GetHandle() == VK_NULL_HANDLE) { + // No swapchain yet (the window had a zero-area surface at initialization). + // Try to bring one up now that the window may have a real size; if it is + // still zero-area there is nothing to present to. + RecreateSwapchain(); + if (m_swapchainObject.GetHandle() == VK_NULL_HANDLE) { + MGLOG_D("Present skipped: still no swapchain (zero-area window)"); + return; + } + const VkResult acquireResult = + m_frameContext.WaitAndAcquireNextImage(m_device, m_swapchainObject.GetHandle(), m_imageIndexAcquired); + VK_VERIFY(acquireResult, "Present, deferred first WaitAndAcquireNextImage"); + } MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(), "Present, acquired image index out of range"); m_renderPassManager->OnPresent(); @@ -7560,10 +7581,7 @@ void main() { MOBILEGL_ASSERT(hwnd, "HWND is null"); VkWin32SurfaceCreateInfoKHR sci{VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR}; - sci.hinstance = reinterpret_cast(GetWindowLongPtrW(hwnd, GWLP_HINSTANCE)); - if (!sci.hinstance) { - sci.hinstance = GetModuleHandleW(nullptr); - } + sci.hinstance = GetModuleHandleW(nullptr); sci.hwnd = hwnd; VK_VERIFY(vkCreateWin32SurfaceKHR(m_instance, &sci, nullptr, &m_surface), "vkCreateWin32SurfaceKHR failed"); #elif defined VK_USE_PLATFORM_METAL_EXT