mirror of
https://github.com/MobileGL-Dev/MobileGL
synced 2026-09-09 20:58:31 +09:00
[Chore] (MG_Test/Backend/DirectVulkan): encapsulate FrameContext (cont.)
This commit is contained in:
@@ -209,22 +209,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_I("PrepareDemoPipeline completed");
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateSyncObjects() {
|
||||
VkSemaphoreCreateInfo semaphoreInfo{VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
|
||||
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
m_frameContexts.resize(m_config.MaxFramesInFlight);
|
||||
|
||||
for (SizeT i = 0; i < m_config.MaxFramesInFlight; i++) {
|
||||
auto& frameContext = m_frameContexts[i];
|
||||
VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &frameContext.imageAvailableSemaphore));
|
||||
VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &frameContext.renderFinishedSemaphore));
|
||||
VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &frameContext.imageInFlightFence));
|
||||
frameContext.hasCommandBufferRecorded = false;
|
||||
}
|
||||
|
||||
MGLOG_I("CreateSyncObjects completed");
|
||||
void VulkanRenderer::CreateFrameContexts() {
|
||||
VK_VERIFY(m_frameContext.Initialize(m_device, m_commandPool, m_config.MaxFramesInFlight),
|
||||
"CreateFrameContexts");
|
||||
MGLOG_I("CreateFrameContexts completed");
|
||||
}
|
||||
|
||||
void VulkanRenderer::Initialize() {
|
||||
@@ -234,19 +222,17 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
CreateLogicalDeviceAndQueues();
|
||||
|
||||
CreateCommandPool();
|
||||
CreateCommandBuffers();
|
||||
|
||||
RecreateSwapchain();
|
||||
|
||||
PrepareDemoPipeline();
|
||||
CreateSyncObjects();
|
||||
CreateFrameContexts();
|
||||
|
||||
// Prime the first frame so Render() always targets an acquired swapchain image.
|
||||
auto& frameContext = m_frameContexts[m_currentFrameIndex];
|
||||
VK_VERIFY(vkWaitForFences(m_device, 1, &frameContext.imageInFlightFence, VK_TRUE, UINT64_MAX));
|
||||
VK_VERIFY(vkResetFences(m_device, 1, &frameContext.imageInFlightFence));
|
||||
VK_VERIFY(vkWaitForFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence(), VK_TRUE, UINT64_MAX));
|
||||
VK_VERIFY(vkResetFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence()));
|
||||
VK_VERIFY(vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX,
|
||||
frameContext.imageAvailableSemaphore, VK_NULL_HANDLE,
|
||||
m_frameContext.GetCurrentImageAvailableSemaphore(), VK_NULL_HANDLE,
|
||||
&m_imageIndexAcquired));
|
||||
|
||||
MGLOG_D("VulkanRenderer initialized");
|
||||
@@ -255,22 +241,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
void VulkanRenderer::Shutdown() {
|
||||
VK_VERIFY(vkDeviceWaitIdle(m_device));
|
||||
|
||||
for (auto& frameContext : m_frameContexts) {
|
||||
if (frameContext.imageInFlightFence != VK_NULL_HANDLE) {
|
||||
vkDestroyFence(m_device, frameContext.imageInFlightFence, nullptr);
|
||||
frameContext.imageInFlightFence = VK_NULL_HANDLE;
|
||||
}
|
||||
if (frameContext.renderFinishedSemaphore != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(m_device, frameContext.renderFinishedSemaphore, nullptr);
|
||||
frameContext.renderFinishedSemaphore = VK_NULL_HANDLE;
|
||||
}
|
||||
if (frameContext.imageAvailableSemaphore != VK_NULL_HANDLE) {
|
||||
vkDestroySemaphore(m_device, frameContext.imageAvailableSemaphore, nullptr);
|
||||
frameContext.imageAvailableSemaphore = VK_NULL_HANDLE;
|
||||
}
|
||||
frameContext.hasCommandBufferRecorded = false;
|
||||
}
|
||||
m_frameContexts.clear();
|
||||
m_frameContext.Destroy(m_device, m_commandPool);
|
||||
|
||||
if (m_pipeline != VK_NULL_HANDLE) {
|
||||
vkDestroyPipeline(m_device, m_pipeline, nullptr);
|
||||
@@ -310,15 +281,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
}
|
||||
|
||||
void VulkanRenderer::Render() {
|
||||
auto& frameContext = m_frameContexts[m_currentFrameIndex];
|
||||
VK_VERIFY(vkResetCommandBuffer(frameContext.commandBuffer, 0));
|
||||
VkCommandBuffer& commandBuffer = m_frameContext.GetCurrentCommandBuffer();
|
||||
VK_VERIFY(vkResetCommandBuffer(commandBuffer, 0));
|
||||
|
||||
// Begin command buffer
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = 0;
|
||||
beginInfo.pInheritanceInfo = nullptr;
|
||||
VK_VERIFY(vkBeginCommandBuffer(frameContext.commandBuffer, &beginInfo));
|
||||
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo));
|
||||
|
||||
// Begin render pass
|
||||
VkRenderPassBeginInfo renderPassInfo{};
|
||||
@@ -331,10 +302,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
renderPassInfo.clearValueCount = 1;
|
||||
renderPassInfo.pClearValues = &clearColor;
|
||||
vkCmdBeginRenderPass(frameContext.commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
// Render commands
|
||||
vkCmdBindPipeline(frameContext.commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
||||
vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline);
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
@@ -343,28 +314,28 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
viewport.height = static_cast<float>(swapchainExtent.height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(frameContext.commandBuffer, 0, 1, &viewport);
|
||||
vkCmdSetViewport(commandBuffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = swapchainExtent;
|
||||
vkCmdSetScissor(frameContext.commandBuffer, 0, 1, &scissor);
|
||||
vkCmdSetScissor(commandBuffer, 0, 1, &scissor);
|
||||
|
||||
vkCmdDraw(frameContext.commandBuffer, 3, 1, 0, 0);
|
||||
vkCmdDraw(commandBuffer, 3, 1, 0, 0);
|
||||
|
||||
// End render pass
|
||||
vkCmdEndRenderPass(frameContext.commandBuffer);
|
||||
vkCmdEndRenderPass(commandBuffer);
|
||||
|
||||
// End command buffer
|
||||
VK_VERIFY(vkEndCommandBuffer(frameContext.commandBuffer));
|
||||
frameContext.hasCommandBufferRecorded = true;
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer));
|
||||
m_frameContext.SetCurrentHasCommandBufferRecorded(true);
|
||||
}
|
||||
|
||||
void VulkanRenderer::Present() {
|
||||
MOBILEGL_ASSERT(m_imageIndexAcquired < m_swapchainObject.GetImageCount(),
|
||||
"Present, acquired image index out of range");
|
||||
auto& frameContext = m_frameContexts[m_currentFrameIndex];
|
||||
const Bool hasRecordedWork = frameContext.hasCommandBufferRecorded;
|
||||
VkCommandBuffer& commandBuffer = m_frameContext.GetCurrentCommandBuffer();
|
||||
const Bool hasRecordedWork = m_frameContext.GetCurrentHasCommandBufferRecorded();
|
||||
Bool needsLayoutTransitionForPresent = false;
|
||||
|
||||
if (!hasRecordedWork) {
|
||||
@@ -373,12 +344,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
acquiredImageLayout != VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR) {
|
||||
needsLayoutTransitionForPresent = true;
|
||||
|
||||
VK_VERIFY(vkResetCommandBuffer(frameContext.commandBuffer, 0),
|
||||
VK_VERIFY(vkResetCommandBuffer(commandBuffer, 0),
|
||||
"Present, vkResetCommandBuffer(layout transition)");
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
VK_VERIFY(vkBeginCommandBuffer(frameContext.commandBuffer, &beginInfo),
|
||||
VK_VERIFY(vkBeginCommandBuffer(commandBuffer, &beginInfo),
|
||||
"Present, vkBeginCommandBuffer(layout transition)");
|
||||
|
||||
VkImageMemoryBarrier presentBarrier{};
|
||||
@@ -395,11 +366,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
presentBarrier.subresourceRange.levelCount = 1;
|
||||
presentBarrier.subresourceRange.baseArrayLayer = 0;
|
||||
presentBarrier.subresourceRange.layerCount = 1;
|
||||
vkCmdPipelineBarrier(frameContext.commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
|
||||
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
|
||||
&presentBarrier);
|
||||
|
||||
VK_VERIFY(vkEndCommandBuffer(frameContext.commandBuffer),
|
||||
VK_VERIFY(vkEndCommandBuffer(commandBuffer),
|
||||
"Present, vkEndCommandBuffer(layout transition)");
|
||||
}
|
||||
}
|
||||
@@ -409,18 +380,18 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
// 1) Submit current frame work.
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
VkSemaphore waitSemaphores[] = {frameContext.imageAvailableSemaphore};
|
||||
VkSemaphore waitSemaphores[] = {m_frameContext.GetCurrentImageAvailableSemaphore()};
|
||||
VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT};
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pWaitSemaphores = waitSemaphores;
|
||||
submitInfo.pWaitDstStageMask = waitStages;
|
||||
submitInfo.commandBufferCount = shouldSubmitCommandBuffer ? 1U : 0U;
|
||||
submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &frameContext.commandBuffer : nullptr;
|
||||
VkSemaphore signalSemaphores[] = {frameContext.renderFinishedSemaphore};
|
||||
submitInfo.pCommandBuffers = shouldSubmitCommandBuffer ? &commandBuffer : nullptr;
|
||||
VkSemaphore signalSemaphores[] = {m_frameContext.GetCurrentRenderFinishedSemaphore()};
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = signalSemaphores;
|
||||
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, frameContext.imageInFlightFence));
|
||||
frameContext.hasCommandBufferRecorded = false;
|
||||
VK_VERIFY(vkQueueSubmit(m_graphicsQueue, 1, &submitInfo, m_frameContext.GetCurrentImageInFlightFence()));
|
||||
m_frameContext.SetCurrentHasCommandBufferRecorded(false);
|
||||
m_swapchainObject.SetImageLayout(m_imageIndexAcquired, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
|
||||
// 2) Present current frame.
|
||||
@@ -442,16 +413,16 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
VK_VERIFY(result, "Present, vkQueuePresentKHR");
|
||||
|
||||
// 3) Advance frame slot.
|
||||
m_currentFrameIndex = (m_currentFrameIndex + 1) % m_config.MaxFramesInFlight;
|
||||
m_frameContext.AdvanceFrame();
|
||||
|
||||
// 4) Wait/reset/acquire for next frame.
|
||||
auto& nextFrameContext = m_frameContexts[m_currentFrameIndex];
|
||||
VK_VERIFY(vkWaitForFences(m_device, 1, &nextFrameContext.imageInFlightFence, VK_TRUE, UINT64_MAX),
|
||||
VK_VERIFY(vkWaitForFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence(), VK_TRUE, UINT64_MAX),
|
||||
"Present, vkWaitForFences");
|
||||
VK_VERIFY(vkResetFences(m_device, 1, &nextFrameContext.imageInFlightFence), "Present, vkResetFences");
|
||||
VK_VERIFY(vkResetFences(m_device, 1, &m_frameContext.GetCurrentImageInFlightFence()),
|
||||
"Present, vkResetFences");
|
||||
result =
|
||||
vkAcquireNextImageKHR(m_device, m_swapchainObject.GetHandle(), UINT64_MAX,
|
||||
nextFrameContext.imageAvailableSemaphore, VK_NULL_HANDLE,
|
||||
m_frameContext.GetCurrentImageAvailableSemaphore(), VK_NULL_HANDLE,
|
||||
&m_imageIndexAcquired);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR) {
|
||||
MGLOG_D("Present, vkAcquireNextImageKHR got %d, recreating swapchain", result);
|
||||
@@ -804,21 +775,6 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
MGLOG_I("Command pool created");
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateCommandBuffers() {
|
||||
m_frameContexts.resize(m_config.MaxFramesInFlight);
|
||||
Vector<VkCommandBuffer> commandBuffers(m_config.MaxFramesInFlight, VK_NULL_HANDLE);
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.commandPool = m_commandPool;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandBufferCount = m_config.MaxFramesInFlight;
|
||||
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, commandBuffers.data()));
|
||||
for (SizeT i = 0; i < m_config.MaxFramesInFlight; ++i) {
|
||||
m_frameContexts[i].commandBuffer = commandBuffers[i];
|
||||
}
|
||||
MGLOG_I("Command buffer created");
|
||||
}
|
||||
|
||||
void VulkanRenderer::CreateDefaultRenderPass() {
|
||||
VkAttachmentDescription color{};
|
||||
color.format = m_swapchainObject.GetSurfaceFormat().format;
|
||||
@@ -986,9 +942,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
|
||||
CreateSwapchain();
|
||||
CreateDefaultRenderPass();
|
||||
CreateDefaultFramebuffers();
|
||||
for (auto& frameContext : m_frameContexts) {
|
||||
frameContext.hasCommandBufferRecorded = false;
|
||||
}
|
||||
m_frameContext.ResetPerFrameState();
|
||||
}
|
||||
|
||||
} // namespace MobileGL::MG_Backend::DirectVulkan
|
||||
|
||||
Reference in New Issue
Block a user