[Fix] (MG_Backend/DirectVulkan): fixing inter-frame swapchain sync?

This commit is contained in:
2026-02-17 17:43:28 +08:00
parent fe6e7902d3
commit 49a18f68e1
3 changed files with 54 additions and 21 deletions
@@ -53,6 +53,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
for (Uint32 i = 0; i < frameCount; ++i) {
DestroySyncObjectsForFrame(device, i);
}
DestroySwapchainSemaphores(device);
if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !m_frames.empty()) {
vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data());
}
@@ -107,6 +108,36 @@ namespace MobileGL::MG_Backend::DirectVulkan {
frame.hasCommandBufferRecorded = true;
}
VkResult FrameContext::InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount) {
DestroySwapchainSemaphores(device);
if (swapchainImageCount == 0) {
return VK_SUCCESS;
}
m_swapchainImageRenderFinishedSemaphores.assign(swapchainImageCount, VK_NULL_HANDLE);
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
for (Uint32 imageIndex = 0; imageIndex < swapchainImageCount; ++imageIndex) {
VkResult result =
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &m_swapchainImageRenderFinishedSemaphores[imageIndex]);
if (result != VK_SUCCESS) {
DestroySwapchainSemaphores(device);
return result;
}
}
return VK_SUCCESS;
}
void FrameContext::DestroySwapchainSemaphores(VkDevice device) {
if (device != VK_NULL_HANDLE) {
for (auto semaphore : m_swapchainImageRenderFinishedSemaphores) {
if (semaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, semaphore, nullptr);
}
}
}
m_swapchainImageRenderFinishedSemaphores.clear();
}
Bool FrameContext::TransitionToPresent(VkImage image, VkImageLayout oldLayout, VkImageLayout presentLayout) {
auto& frame = GetCurrent();
if (frame.hasCommandBufferRecorded || frame.isCommandRecording || oldLayout == presentLayout ||
@@ -137,12 +168,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return true;
}
FrameContext::SubmitInfoPacket FrameContext::GetSubmitInfo(Bool shouldSubmitCommandBuffer) const {
FrameContext::SubmitInfoPacket FrameContext::GetSubmitInfo(Bool shouldSubmitCommandBuffer,
Uint32 swapchainImageIndex) const {
const auto& frame = GetCurrent();
MOBILEGL_ASSERT(!frame.isCommandRecording, "GetSubmitInfo called while command buffer recording is still active");
AssertValidSwapchainImageIndex(swapchainImageIndex);
SubmitInfoPacket packet{};
packet.waitSemaphore = frame.imageAvailableSemaphore;
packet.signalSemaphore = frame.renderFinishedSemaphore;
packet.signalSemaphore = m_swapchainImageRenderFinishedSemaphores[swapchainImageIndex];
packet.commandBuffer = frame.commandBuffer;
packet.submitInfo.waitSemaphoreCount = 1;
@@ -156,9 +189,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
FrameContext::PresentInfoPacket FrameContext::GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const {
const auto& frame = GetCurrent();
AssertValidSwapchainImageIndex(imageIndex);
PresentInfoPacket packet{};
packet.waitSemaphore = frame.renderFinishedSemaphore;
packet.waitSemaphore = m_swapchainImageRenderFinishedSemaphores[imageIndex];
packet.swapchain = swapchain;
packet.imageIndex = &imageIndex;
@@ -200,6 +233,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
MOBILEGL_ASSERT(frameIndex < m_frames.size(), "FrameContext index out of range");
}
void FrameContext::AssertValidSwapchainImageIndex(Uint32 imageIndex) const {
MOBILEGL_ASSERT(imageIndex < m_swapchainImageRenderFinishedSemaphores.size(),
"FrameContext swapchain image index out of range");
}
VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
const VkSemaphoreCreateInfo& semaphoreInfo,
const VkFenceCreateInfo& fenceInfo) {
@@ -213,18 +251,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return result;
}
result = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.renderFinishedSemaphore);
if (result != VK_SUCCESS) {
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
return result;
}
result = vkCreateFence(device, &fenceInfo, nullptr, &frame.imageInFlightFence);
if (result != VK_SUCCESS) {
vkDestroySemaphore(device, frame.renderFinishedSemaphore, nullptr);
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
frame.renderFinishedSemaphore = VK_NULL_HANDLE;
frame.imageAvailableSemaphore = VK_NULL_HANDLE;
return result;
}
@@ -242,11 +271,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
}
frame.imageInFlightFence = VK_NULL_HANDLE;
if (device != VK_NULL_HANDLE && frame.renderFinishedSemaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, frame.renderFinishedSemaphore, nullptr);
}
frame.renderFinishedSemaphore = VK_NULL_HANDLE;
if (device != VK_NULL_HANDLE && frame.imageAvailableSemaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
}
@@ -32,7 +32,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
struct FrameData {
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE;
VkFence imageInFlightFence = VK_NULL_HANDLE;
Bool isCommandRecording = false;
Bool hasCommandBufferRecorded = false;
@@ -49,9 +48,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkCommandBuffer& BeginCommandRecording(VkCommandBufferUsageFlags flags = 0,
const VkCommandBufferInheritanceInfo* pInheritanceInfo = nullptr);
void EndCommandRecording();
VkResult InitializeSwapchainSemaphores(VkDevice device, Uint32 swapchainImageCount);
void DestroySwapchainSemaphores(VkDevice device);
Bool TransitionToPresent(VkImage image, VkImageLayout oldLayout,
VkImageLayout presentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer) const;
SubmitInfoPacket GetSubmitInfo(Bool shouldSubmitCommandBuffer, Uint32 swapchainImageIndex) const;
PresentInfoPacket GetPresentInfo(VkSwapchainKHR swapchain, const Uint32& imageIndex) const;
VkResult WaitAndAcquireNextImage(VkDevice device, VkSwapchainKHR swapchain, Uint32& outImageIndex,
Uint64 timeout = UINT64_MAX, VkFence acquireFence = VK_NULL_HANDLE);
@@ -61,6 +62,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
private:
void AssertValidFrameIndex(Uint32 frameIndex) const;
void AssertValidSwapchainImageIndex(Uint32 imageIndex) const;
VkResult CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
const VkSemaphoreCreateInfo& semaphoreInfo,
@@ -68,6 +70,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex);
Vector<FrameData> m_frames;
Vector<VkSemaphore> m_swapchainImageRenderFinishedSemaphores;
Uint32 currentFrameIndex = 0;
};
} // namespace MobileGL::MG_Backend::DirectVulkan
@@ -103,6 +103,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void VulkanRenderer::CreateFrameContexts() {
VK_VERIFY(m_frameContext.Initialize(m_device, m_commandPool, m_config.MaxFramesInFlight),
"CreateFrameContexts");
VK_VERIFY(m_frameContext.InitializeSwapchainSemaphores(
m_device, static_cast<Uint32>(m_swapchainObject.GetImageCount())),
"CreateFrameContexts, InitializeSwapchainSemaphores");
MGLOG_I("CreateFrameContexts completed");
}
@@ -688,7 +691,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const Bool shouldSubmitCommandBuffer = frame.hasCommandBufferRecorded || needsLayoutTransitionForPresent;
// 1) Submit current frame work.
auto submitPacket = m_frameContext.GetSubmitInfo(shouldSubmitCommandBuffer);
auto submitPacket = m_frameContext.GetSubmitInfo(shouldSubmitCommandBuffer, m_imageIndexAcquired);
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitPacket.submitInfo, frame.imageInFlightFence));
frame.isCommandRecording = false;
frame.hasCommandBufferRecorded = false;
@@ -1399,6 +1402,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
ShutdownSwapchain();
CreateSwapchain();
VK_VERIFY(m_frameContext.InitializeSwapchainSemaphores(
m_device, static_cast<Uint32>(m_swapchainObject.GetImageCount())),
"RecreateSwapchain, InitializeSwapchainSemaphores");
CreateDepthStencilResources();
CreateDefaultRenderPass();
CreateDefaultFramebuffers();