[Fix] (MG_Backend/DirectVulkan): fix validation error on Windows

This commit is contained in:
2026-02-10 14:16:23 +08:00
parent ceaa6ff5f8
commit 43e59d8fce
4 changed files with 39 additions and 24 deletions
@@ -14,6 +14,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void Clear(GLbitfield mask) {} void Clear(GLbitfield mask) {}
void DrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) { 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 } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -34,7 +34,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
CreateCommandPool(); CreateCommandPool();
CreateFrameResources(); CreateFrameResources();
FrameBegin();
MGLOG_D("VulkanRenderer initialized"); MGLOG_D("VulkanRenderer initialized");
} }
@@ -191,8 +190,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (!Ctx) throw RuntimeError("Renderer not initialized"); if (!Ctx) throw RuntimeError("Renderer not initialized");
FrameContext& frame = *Frames[CurrentFrame]; 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"); 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"); VK_VERIFY(vkResetFences(Ctx->GetDevice(), 1, &frame.InFlightFence), "vkResetFences");
// Record commands // Record commands
@@ -215,25 +219,33 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(vkQueueSubmit(Ctx->GetGraphicsQueue(), 1, &si, frame.InFlightFence), "vkQueueSubmit"); VK_VERIFY(vkQueueSubmit(Ctx->GetGraphicsQueue(), 1, &si, frame.InFlightFence), "vkQueueSubmit");
} }
void VulkanRenderer::FrameBegin() { bool VulkanRenderer::FrameBegin() {
FrameContext& frame = *Frames[CurrentFrame]; FrameContext& frame = *Frames[CurrentFrame];
// Acquire image while (true) {
auto& imagesInFlight = Swapchain->GetImagesInFlight(); // Acquire image for this frame. Acquire can fail with OUT_OF_DATE during resize/minimize.
Uint32 imageIndex = 0; Uint32 imageIndex = 0;
VkResult res = vkAcquireNextImageKHR(Ctx->GetDevice(), Swapchain->GetSwapchain(), UINT64_MAX, VkResult res = vkAcquireNextImageKHR(Ctx->GetDevice(), Swapchain->GetSwapchain(), UINT64_MAX,
frame.ImageAvailable, VK_NULL_HANDLE, &imageIndex); frame.ImageAvailable, VK_NULL_HANDLE, &imageIndex);
if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) {
vkWaitForFences(Ctx->GetDevice(), 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); 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() { void VulkanRenderer::Present() {
@@ -258,8 +270,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
CurrentFrame = (CurrentFrame + 1) % Frames.size(); CurrentFrame = (CurrentFrame + 1) % Frames.size();
FrameBegin();
} }
void VulkanRenderer::RegisterRenderCallback(const std::string& name, RenderCallback cb) { void VulkanRenderer::RegisterRenderCallback(const std::string& name, RenderCallback cb) {
@@ -69,6 +69,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DestroyFrameResources(); void DestroyFrameResources();
void RecordFrameCommandBuffer(FrameContext& frame, uint32_t imageIndex); void RecordFrameCommandBuffer(FrameContext& frame, uint32_t imageIndex);
void RecreateSwapchainIfNeeded(); void RecreateSwapchainIfNeeded();
void FrameBegin(); bool FrameBegin();
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -106,6 +106,8 @@ namespace MobileGL {
MGLOG_E("EGLForVulkan::SwapBuffers called but VulkanRenderer is null"); MGLOG_E("EGLForVulkan::SwapBuffers called but VulkanRenderer is null");
return EGL_FALSE; return EGL_FALSE;
} }
// TODO: replace this with real rendering code
MG_Backend::DirectVulkan::pVulkanRenderer->RenderFrame();
MG_Backend::DirectVulkan::pVulkanRenderer->Present(); MG_Backend::DirectVulkan::pVulkanRenderer->Present();
return EGL_TRUE; return EGL_TRUE;
} }