[Chore] (MG_Backend/DirectVulkan): simplify FrameContext interface

This commit is contained in:
2026-02-17 00:08:48 +08:00
parent 2ad1207a31
commit 876d5e13af
3 changed files with 87 additions and 200 deletions
@@ -11,13 +11,10 @@
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
VkResult FrameContext::Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount) { VkResult FrameContext::Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount) {
Destroy(device, commandPool); Destroy(device, commandPool);
commandBuffers.resize(frameCount, VK_NULL_HANDLE); m_frames.assign(frameCount, {});
imageAvailableSemaphores.resize(frameCount, VK_NULL_HANDLE);
renderFinishedSemaphores.resize(frameCount, VK_NULL_HANDLE);
imageInFlightFences.resize(frameCount, VK_NULL_HANDLE);
hasCommandBufferRecorded.assign(frameCount, false);
currentFrameIndex = 0; currentFrameIndex = 0;
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.commandPool = commandPool; allocInfo.commandPool = commandPool;
@@ -27,6 +24,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
return result; return result;
} }
for (Uint32 i = 0; i < frameCount; ++i) {
m_frames[i].commandBuffer = commandBuffers[i];
}
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO}; VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
@@ -44,24 +44,36 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void FrameContext::Destroy(VkDevice device, VkCommandPool commandPool) { void FrameContext::Destroy(VkDevice device, VkCommandPool commandPool) {
const Uint32 frameCount = static_cast<Uint32>(commandBuffers.size()); const Uint32 frameCount = static_cast<Uint32>(m_frames.size());
Vector<VkCommandBuffer> commandBuffers(frameCount, VK_NULL_HANDLE);
for (Uint32 i = 0; i < frameCount; ++i) {
commandBuffers[i] = m_frames[i].commandBuffer;
}
for (Uint32 i = 0; i < frameCount; ++i) { for (Uint32 i = 0; i < frameCount; ++i) {
DestroySyncObjectsForFrame(device, i); DestroySyncObjectsForFrame(device, i);
} }
if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !commandBuffers.empty()) { if (device != VK_NULL_HANDLE && commandPool != VK_NULL_HANDLE && !m_frames.empty()) {
vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data()); vkFreeCommandBuffers(device, commandPool, frameCount, commandBuffers.data());
} }
commandBuffers.clear(); m_frames.clear();
imageAvailableSemaphores.clear();
renderFinishedSemaphores.clear();
imageInFlightFences.clear();
hasCommandBufferRecorded.clear();
currentFrameIndex = 0; currentFrameIndex = 0;
} }
void FrameContext::AdvanceFrame() { FrameContext::FrameData& FrameContext::GetCurrent() {
MOBILEGL_ASSERT(!commandBuffers.empty(), "FrameContext is not initialized"); MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
currentFrameIndex = (currentFrameIndex + 1) % static_cast<Uint32>(commandBuffers.size()); return m_frames[currentFrameIndex];
}
const FrameContext::FrameData& FrameContext::GetCurrent() const {
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
return m_frames[currentFrameIndex];
}
void FrameContext::AdvanceToNext() {
MOBILEGL_ASSERT(!m_frames.empty(), "FrameContext is not initialized");
currentFrameIndex = (currentFrameIndex + 1) % static_cast<Uint32>(m_frames.size());
GetCurrent().hasCommandBufferRecorded = false;
} }
Uint32 FrameContext::GetCurrentFrameIndex() const { Uint32 FrameContext::GetCurrentFrameIndex() const {
@@ -69,172 +81,63 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
Uint32 FrameContext::GetFrameCount() const { Uint32 FrameContext::GetFrameCount() const {
return static_cast<Uint32>(commandBuffers.size()); return static_cast<Uint32>(m_frames.size());
}
VkCommandBuffer& FrameContext::GetCommandBuffer(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
return commandBuffers[frameIndex];
}
VkSemaphore& FrameContext::GetImageAvailableSemaphore(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
return imageAvailableSemaphores[frameIndex];
}
VkSemaphore& FrameContext::GetRenderFinishedSemaphore(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
return renderFinishedSemaphores[frameIndex];
}
VkFence& FrameContext::GetImageInFlightFence(Uint32 frameIndex) {
AssertValidFrameIndex(frameIndex);
return imageInFlightFences[frameIndex];
}
void FrameContext::SetHasCommandBufferRecorded(Uint32 frameIndex, Bool value) {
AssertValidFrameIndex(frameIndex);
hasCommandBufferRecorded[frameIndex] = value;
}
void FrameContext::SetCurrentCommandBuffer(VkCommandBuffer value) {
SetCurrentCommandBufferRecorded(false);
GetCommandBuffer(GetCurrentFrameIndex()) = value;
}
void FrameContext::SetCurrentImageAvailableSemaphore(VkSemaphore value) {
GetImageAvailableSemaphore(GetCurrentFrameIndex()) = value;
}
void FrameContext::SetCurrentRenderFinishedSemaphore(VkSemaphore value) {
GetRenderFinishedSemaphore(GetCurrentFrameIndex()) = value;
}
void FrameContext::SetCurrentImageInFlightFence(VkFence value) {
GetImageInFlightFence(GetCurrentFrameIndex()) = value;
}
void FrameContext::SetCurrentCommandBufferRecorded(Bool value) {
SetHasCommandBufferRecorded(GetCurrentFrameIndex(), value);
}
VkCommandBuffer& FrameContext::GetCurrentCommandBuffer() {
return GetCommandBuffer(GetCurrentFrameIndex());
}
VkSemaphore& FrameContext::GetCurrentImageAvailableSemaphore() {
return GetImageAvailableSemaphore(GetCurrentFrameIndex());
}
VkSemaphore& FrameContext::GetCurrentRenderFinishedSemaphore() {
return GetRenderFinishedSemaphore(GetCurrentFrameIndex());
}
VkFence& FrameContext::GetCurrentImageInFlightFence() {
return GetImageInFlightFence(GetCurrentFrameIndex());
}
Bool FrameContext::HasCurrentCommandBufferRecorded() const {
return HasCommandBufferRecorded(GetCurrentFrameIndex());
}
const VkCommandBuffer& FrameContext::GetCommandBuffer(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return commandBuffers[frameIndex];
}
const VkSemaphore& FrameContext::GetImageAvailableSemaphore(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return imageAvailableSemaphores[frameIndex];
}
const VkSemaphore& FrameContext::GetRenderFinishedSemaphore(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return renderFinishedSemaphores[frameIndex];
}
const VkFence& FrameContext::GetImageInFlightFence(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return imageInFlightFences[frameIndex];
}
Bool FrameContext::HasCommandBufferRecorded(Uint32 frameIndex) const {
AssertValidFrameIndex(frameIndex);
return hasCommandBufferRecorded[frameIndex];
}
const VkCommandBuffer& FrameContext::GetCurrentCommandBuffer() const {
return GetCommandBuffer(GetCurrentFrameIndex());
}
const VkSemaphore& FrameContext::GetCurrentImageAvailableSemaphore() const {
return GetImageAvailableSemaphore(GetCurrentFrameIndex());
}
const VkSemaphore& FrameContext::GetCurrentRenderFinishedSemaphore() const {
return GetRenderFinishedSemaphore(GetCurrentFrameIndex());
}
const VkFence& FrameContext::GetCurrentImageInFlightFence() const {
return GetImageInFlightFence(GetCurrentFrameIndex());
}
void FrameContext::ResetPerFrameState() {
for (SizeT i = 0; i < hasCommandBufferRecorded.size(); ++i) {
hasCommandBufferRecorded[i] = false;
}
} }
void FrameContext::AssertValidFrameIndex(Uint32 frameIndex) const { void FrameContext::AssertValidFrameIndex(Uint32 frameIndex) const {
MOBILEGL_ASSERT(frameIndex < commandBuffers.size(), "FrameContext index out of range"); MOBILEGL_ASSERT(frameIndex < m_frames.size(), "FrameContext index out of range");
} }
VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex, VkResult FrameContext::CreateSyncObjectsForFrame(VkDevice device, Uint32 frameIndex,
const VkSemaphoreCreateInfo& semaphoreInfo, const VkSemaphoreCreateInfo& semaphoreInfo,
const VkFenceCreateInfo& fenceInfo) { const VkFenceCreateInfo& fenceInfo) {
AssertValidFrameIndex(frameIndex);
DestroySyncObjectsForFrame(device, frameIndex); DestroySyncObjectsForFrame(device, frameIndex);
auto& frame = m_frames[frameIndex];
VkResult result = VkResult result =
vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[frameIndex]); vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.imageAvailableSemaphore);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
return result; return result;
} }
result = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[frameIndex]); result = vkCreateSemaphore(device, &semaphoreInfo, nullptr, &frame.renderFinishedSemaphore);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
vkDestroySemaphore(device, imageAvailableSemaphores[frameIndex], nullptr); vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
imageAvailableSemaphores[frameIndex] = VK_NULL_HANDLE; frame.imageAvailableSemaphore = VK_NULL_HANDLE;
return result; return result;
} }
result = vkCreateFence(device, &fenceInfo, nullptr, &imageInFlightFences[frameIndex]); result = vkCreateFence(device, &fenceInfo, nullptr, &frame.imageInFlightFence);
if (result != VK_SUCCESS) { if (result != VK_SUCCESS) {
vkDestroySemaphore(device, renderFinishedSemaphores[frameIndex], nullptr); vkDestroySemaphore(device, frame.renderFinishedSemaphore, nullptr);
vkDestroySemaphore(device, imageAvailableSemaphores[frameIndex], nullptr); vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
renderFinishedSemaphores[frameIndex] = VK_NULL_HANDLE; frame.renderFinishedSemaphore = VK_NULL_HANDLE;
imageAvailableSemaphores[frameIndex] = VK_NULL_HANDLE; frame.imageAvailableSemaphore = VK_NULL_HANDLE;
return result; return result;
} }
hasCommandBufferRecorded[frameIndex] = false; frame.hasCommandBufferRecorded = false;
return VK_SUCCESS; return VK_SUCCESS;
} }
void FrameContext::DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex) { void FrameContext::DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex) {
if (device != VK_NULL_HANDLE && imageInFlightFences[frameIndex] != VK_NULL_HANDLE) { AssertValidFrameIndex(frameIndex);
vkDestroyFence(device, imageInFlightFences[frameIndex], nullptr); auto& frame = m_frames[frameIndex];
if (device != VK_NULL_HANDLE && frame.imageInFlightFence != VK_NULL_HANDLE) {
vkDestroyFence(device, frame.imageInFlightFence, nullptr);
} }
imageInFlightFences[frameIndex] = VK_NULL_HANDLE; frame.imageInFlightFence = VK_NULL_HANDLE;
if (device != VK_NULL_HANDLE && renderFinishedSemaphores[frameIndex] != VK_NULL_HANDLE) { if (device != VK_NULL_HANDLE && frame.renderFinishedSemaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, renderFinishedSemaphores[frameIndex], nullptr); vkDestroySemaphore(device, frame.renderFinishedSemaphore, nullptr);
} }
renderFinishedSemaphores[frameIndex] = VK_NULL_HANDLE; frame.renderFinishedSemaphore = VK_NULL_HANDLE;
if (device != VK_NULL_HANDLE && imageAvailableSemaphores[frameIndex] != VK_NULL_HANDLE) { if (device != VK_NULL_HANDLE && frame.imageAvailableSemaphore != VK_NULL_HANDLE) {
vkDestroySemaphore(device, imageAvailableSemaphores[frameIndex], nullptr); vkDestroySemaphore(device, frame.imageAvailableSemaphore, nullptr);
} }
imageAvailableSemaphores[frameIndex] = VK_NULL_HANDLE; frame.imageAvailableSemaphore = VK_NULL_HANDLE;
hasCommandBufferRecorded[frameIndex] = false; frame.hasCommandBufferRecorded = false;
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -14,41 +14,23 @@
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
class FrameContext { class FrameContext {
public: public:
struct FrameData {
VkCommandBuffer commandBuffer = VK_NULL_HANDLE;
VkSemaphore imageAvailableSemaphore = VK_NULL_HANDLE;
VkSemaphore renderFinishedSemaphore = VK_NULL_HANDLE;
VkFence imageInFlightFence = VK_NULL_HANDLE;
Bool hasCommandBufferRecorded = false;
};
VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount); VkResult Initialize(VkDevice device, VkCommandPool commandPool, Uint32 frameCount);
void Destroy(VkDevice device, VkCommandPool commandPool); void Destroy(VkDevice device, VkCommandPool commandPool);
void AdvanceFrame(); FrameData& GetCurrent();
void ResetPerFrameState(); const FrameData& GetCurrent() const;
void AdvanceToNext();
Uint32 GetCurrentFrameIndex() const; Uint32 GetCurrentFrameIndex() const;
Uint32 GetFrameCount() const; Uint32 GetFrameCount() const;
VkCommandBuffer& GetCommandBuffer(Uint32 frameIndex);
VkSemaphore& GetImageAvailableSemaphore(Uint32 frameIndex);
VkSemaphore& GetRenderFinishedSemaphore(Uint32 frameIndex);
VkFence& GetImageInFlightFence(Uint32 frameIndex);
void SetHasCommandBufferRecorded(Uint32 frameIndex, Bool value);
void SetCurrentCommandBuffer(VkCommandBuffer value);
void SetCurrentImageAvailableSemaphore(VkSemaphore value);
void SetCurrentRenderFinishedSemaphore(VkSemaphore value);
void SetCurrentImageInFlightFence(VkFence value);
void SetCurrentCommandBufferRecorded(Bool value);
VkCommandBuffer& GetCurrentCommandBuffer();
VkSemaphore& GetCurrentImageAvailableSemaphore();
VkSemaphore& GetCurrentRenderFinishedSemaphore();
VkFence& GetCurrentImageInFlightFence();
Bool HasCurrentCommandBufferRecorded() const;
const VkCommandBuffer& GetCommandBuffer(Uint32 frameIndex) const;
const VkSemaphore& GetImageAvailableSemaphore(Uint32 frameIndex) const;
const VkSemaphore& GetRenderFinishedSemaphore(Uint32 frameIndex) const;
const VkFence& GetImageInFlightFence(Uint32 frameIndex) const;
Bool HasCommandBufferRecorded(Uint32 frameIndex) const;
const VkCommandBuffer& GetCurrentCommandBuffer() const;
const VkSemaphore& GetCurrentImageAvailableSemaphore() const;
const VkSemaphore& GetCurrentRenderFinishedSemaphore() const;
const VkFence& GetCurrentImageInFlightFence() const;
private: private:
void AssertValidFrameIndex(Uint32 frameIndex) const; void AssertValidFrameIndex(Uint32 frameIndex) const;
@@ -57,11 +39,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
const VkFenceCreateInfo& fenceInfo); const VkFenceCreateInfo& fenceInfo);
void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex); void DestroySyncObjectsForFrame(VkDevice device, Uint32 frameIndex);
Vector<VkCommandBuffer> commandBuffers; Vector<FrameData> m_frames;
Vector<VkSemaphore> imageAvailableSemaphores;
Vector<VkSemaphore> renderFinishedSemaphores;
Vector<VkFence> imageInFlightFences;
Vector<Bool> hasCommandBufferRecorded;
Uint32 currentFrameIndex = 0; Uint32 currentFrameIndex = 0;
}; };
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -197,10 +197,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
CreateFrameContexts(); CreateFrameContexts();
// Prime the first frame so Render() always targets an acquired swapchain image. // Prime the first frame so Render() always targets an acquired swapchain image.
VK_VERIFY(vkWaitForFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence(), VK_TRUE, UINT64_MAX)); auto& frame = m_frameContext.GetCurrent();
VK_VERIFY(vkResetFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence())); VK_VERIFY(vkWaitForFences(m_device, 1, &frame.imageInFlightFence, VK_TRUE, UINT64_MAX));
VK_VERIFY(vkResetFences(m_device, 1, &frame.imageInFlightFence));
VK_VERIFY(vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX, VK_VERIFY(vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX,
m_frameContext.GetCurrentImageAvailableSemaphore(), VK_NULL_HANDLE, frame.imageAvailableSemaphore, VK_NULL_HANDLE,
&m_imageIndexAcquired)); &m_imageIndexAcquired));
MGLOG_D("VulkanRenderer initialized"); MGLOG_D("VulkanRenderer initialized");
@@ -251,7 +252,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void VulkanRenderer::Render() { void VulkanRenderer::Render() {
VkCommandBuffer& commandBuffer = m_frameContext.GetCurrentCommandBuffer(); auto& frame = m_frameContext.GetCurrent();
VkCommandBuffer& commandBuffer = frame.commandBuffer;
VK_VERIFY(vkResetCommandBuffer(commandBuffer, 0)); VK_VERIFY(vkResetCommandBuffer(commandBuffer, 0));
// Begin command buffer // Begin command buffer
@@ -298,14 +300,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// End command buffer // End command buffer
VK_VERIFY(vkEndCommandBuffer(commandBuffer)); VK_VERIFY(vkEndCommandBuffer(commandBuffer));
m_frameContext.SetCurrentCommandBufferRecorded(true); frame.hasCommandBufferRecorded = true;
} }
void VulkanRenderer::Present() { void VulkanRenderer::Present() {
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(), MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
"Present, acquired image index out of range"); "Present, acquired image index out of range");
VkCommandBuffer& commandBuffer = m_frameContext.GetCurrentCommandBuffer(); auto& frame = m_frameContext.GetCurrent();
const Bool hasRecordedWork = m_frameContext.HasCurrentCommandBufferRecorded(); VkCommandBuffer& commandBuffer = frame.commandBuffer;
const Bool hasRecordedWork = frame.hasCommandBufferRecorded;
Bool needsLayoutTransitionForPresent = false; Bool needsLayoutTransitionForPresent = false;
if (!hasRecordedWork) { if (!hasRecordedWork) {
@@ -350,18 +353,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
// 1) Submit current frame work. // 1) Submit current frame work.
VkSubmitInfo submitInfo{}; VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
VkSemaphore waitSemaphores[] = {m_frameContext.GetCurrentImageAvailableSemaphore()}; VkSemaphore waitSemaphores[] = {frame.imageAvailableSemaphore};
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT}; VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
submitInfo.waitSemaphoreCount = 1; submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = waitSemaphores; submitInfo.pWaitSemaphores = waitSemaphores;
submitInfo.pWaitDstStageMask = waitStages; submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U; submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &commandBuffer : nullptr; submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &commandBuffer : nullptr;
VkSemaphore signalSemaphores[] = {m_frameContext.GetCurrentRenderFinishedSemaphore()}; VkSemaphore signalSemaphores[] = {frame.renderFinishedSemaphore};
submitInfo.signalSemaphoreCount = 1; submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = signalSemaphores; submitInfo.pSignalSemaphores = signalSemaphores;
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_frameContext.GetCurrentImageInFlightFence())); VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, frame.imageInFlightFence));
m_frameContext.SetCurrentCommandBufferRecorded(false); frame.hasCommandBufferRecorded = false;
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
// 2) Present current frame. // 2) Present current frame.
@@ -383,16 +386,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(result, "Present, vkQueuePresentKHR"); VK_VERIFY(result, "Present, vkQueuePresentKHR");
// 3) Advance frame slot. // 3) Advance frame slot.
m_frameContext.AdvanceFrame(); m_frameContext.AdvanceToNext();
// 4) Wait/reset/acquire for next frame. // 4) Wait/reset/acquire for next frame.
VK_VERIFY(vkWaitForFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence(), VK_TRUE, UINT64_MAX), auto& nextFrame = m_frameContext.GetCurrent();
VK_VERIFY(vkWaitForFences(m_device, 1, &nextFrame.imageInFlightFence, VK_TRUE, UINT64_MAX),
"Present, vkWaitForFences"); "Present, vkWaitForFences");
VK_VERIFY(vkResetFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence()), VK_VERIFY(vkResetFences(m_device, 1, &nextFrame.imageInFlightFence),
"Present, vkResetFences"); "Present, vkResetFences");
result = result =
vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX, vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX,
m_frameContext.GetCurrentImageAvailableSemaphore(), VK_NULL_HANDLE, nextFrame.imageAvailableSemaphore, VK_NULL_HANDLE,
&m_imageIndexAcquired); &m_imageIndexAcquired);
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) { if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result); MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result);
@@ -912,7 +916,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
CreateSwapchain(); CreateSwapchain();
CreateDefaultRenderPass(); CreateDefaultRenderPass();
CreateDefaultFramebuffers(); CreateDefaultFramebuffers();
m_frameContext.ResetPerFrameState(); if (m_frameContext.GetFrameCount() > 0) {
m_frameContext.GetCurrent().hasCommandBufferRecorded = false;
}
} }
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan