From 43e59d8fce33d903d94dd32dcca8b47a07ebfb20 Mon Sep 17 00:00:00 2001 From: Swung0x48 Date: Tue, 10 Feb 2026 14:16:23 +0800 Subject: [PATCH] [Fix] (MG_Backend/DirectVulkan): fix validation error on Windows --- .../MG_Backend/DirectVulkan/DirectVulkan.cpp | 7 ++- .../DirectVulkan/Renderer/VulkanRenderer.cpp | 50 +++++++++++-------- .../DirectVulkan/Renderer/VulkanRenderer.h | 4 +- .../EGLImpl/EGLForVulkan/EGLForVulkan.cpp | 2 + 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp index 3de2fe4c..3c4705e1 100644 --- a/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/DirectVulkan.cpp @@ -14,6 +14,9 @@ namespace MobileGL::MG_Backend::DirectVulkan { void Clear(GLbitfield mask) {} void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { - pVulkanRenderer->RenderFrame(); + (void)mode; + (void)count; + (void)type; + (void)indices; } -} // namespace MobileGL::MG_Backend::DirectVulkan \ No newline at end of file +} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp index 6649aa61..48b7a0db 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.cpp @@ -34,7 +34,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { CreateCommandPool(); CreateFrameResources(); - FrameBegin(); MGLOG_D("VulkanRenderer initialized"); } @@ -191,8 +190,13 @@ namespace MobileGL::MG_Backend::DirectVulkan { if (!Ctx) throw RuntimeError("Renderer not initialized"); FrameContext& frame = *Frames[CurrentFrame]; - // Wait fence and reset + // Ensure the previous use of this frame context has fully completed + // before reusing its semaphores in vkAcquireNextImageKHR. VK_VERIFY(vkWaitForFences(Ctx->GetDevice(), 1, &frame.InFlightFence, VK_TRUE, UINT64_MAX), "vkWaitForFences"); + + if (!FrameBegin()) return; + + // Fence will be signaled by vkQueueSubmit below. VK_VERIFY(vkResetFences(Ctx->GetDevice(), 1, &frame.InFlightFence), "vkResetFences"); // Record commands @@ -215,25 +219,33 @@ namespace MobileGL::MG_Backend::DirectVulkan { VK_VERIFY(vkQueueSubmit(Ctx->GetGraphicsQueue(), 1, &si, frame.InFlightFence), "vkQueueSubmit"); } - void VulkanRenderer::FrameBegin() { + bool VulkanRenderer::FrameBegin() { FrameContext& frame = *Frames[CurrentFrame]; - // Acquire image - auto& imagesInFlight = Swapchain->GetImagesInFlight(); - Uint32 imageIndex = 0; - VkResult res = vkAcquireNextImageKHR(Ctx->GetDevice(), Swapchain->GetSwapchain(), UINT64_MAX, - frame.ImageAvailable, VK_NULL_HANDLE, &imageIndex); - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { - vkWaitForFences(Ctx->GetDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); + while (true) { + // Acquire image for this frame. Acquire can fail with OUT_OF_DATE during resize/minimize. + Uint32 imageIndex = 0; + VkResult res = vkAcquireNextImageKHR(Ctx->GetDevice(), Swapchain->GetSwapchain(), UINT64_MAX, + frame.ImageAvailable, VK_NULL_HANDLE, &imageIndex); + + if (res == VK_ERROR_OUT_OF_DATE_KHR) { + MGLOG_D("vkAcquireNextImageKHR: OUT_OF_DATE -> recreate"); + RecreateSwapchainIfNeeded(); + continue; + } + if (res != VK_SUCCESS && res != VK_SUBOPTIMAL_KHR) { + VK_VERIFY(res, "vkAcquireNextImageKHR"); + return false; + } + + auto& imagesInFlight = Swapchain->GetImagesInFlight(); + if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) { + vkWaitForFences(Ctx->GetDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); + } + imagesInFlight[imageIndex] = frame.InFlightFence; + frame.CurrentImageIndex = imageIndex; + return true; } - imagesInFlight[imageIndex] = frame.InFlightFence; - frame.CurrentImageIndex = imageIndex; - if (res == VK_ERROR_OUT_OF_DATE_KHR) { - MGLOG_D("vkAcquireNextImageKHR: OUT_OF_DATE -> recreate"); - RecreateSwapchainIfNeeded(); - return; - } - VK_VERIFY(res, "vkAcquireNextImageKHR"); } void VulkanRenderer::Present() { @@ -258,8 +270,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { } CurrentFrame = (CurrentFrame + 1) % Frames.size(); - - FrameBegin(); } void VulkanRenderer::RegisterRenderCallback(const std::string& name, RenderCallback cb) { diff --git a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h index 99dbba45..246ae6a9 100644 --- a/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h +++ b/MobileGL/MG_Backend/DirectVulkan/Renderer/VulkanRenderer.h @@ -69,6 +69,6 @@ namespace MobileGL::MG_Backend::DirectVulkan { void DestroyFrameResources(); void RecordFrameCommandBuffer(FrameContext& frame, uint32_t imageIndex); void RecreateSwapchainIfNeeded(); - void FrameBegin(); + bool FrameBegin(); }; -} // namespace MobileGL::MG_Backend::DirectVulkan \ No newline at end of file +} // namespace MobileGL::MG_Backend::DirectVulkan diff --git a/MobileGL/MG_Impl/EGLImpl/EGLForVulkan/EGLForVulkan.cpp b/MobileGL/MG_Impl/EGLImpl/EGLForVulkan/EGLForVulkan.cpp index 2a9f054e..266e6535 100644 --- a/MobileGL/MG_Impl/EGLImpl/EGLForVulkan/EGLForVulkan.cpp +++ b/MobileGL/MG_Impl/EGLImpl/EGLForVulkan/EGLForVulkan.cpp @@ -106,6 +106,8 @@ namespace MobileGL { MGLOG_E("EGLForVulkan::SwapBuffers called but VulkanRenderer is null"); return EGL_FALSE; } + // TODO: replace this with real rendering code + MG_Backend::DirectVulkan::pVulkanRenderer->RenderFrame(); MG_Backend::DirectVulkan::pVulkanRenderer->Present(); return EGL_TRUE; }