[Feat] (MG_Test/Backend/DirectVulkan): RecreateSwapchain()

This commit is contained in:
2026-02-15 19:34:25 +08:00
parent 7c67c99717
commit 1357435e94
2 changed files with 80 additions and 42 deletions
@@ -10,6 +10,18 @@
#include "MG_State/GLState/ProgramState/ProgramObject.h" #include "MG_State/GLState/ProgramState/ProgramObject.h"
//#ifndef VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR
//#define VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR 0x00000001
//#endif
//
//#ifndef VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME
//#define VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME "VK_KHR_portability_enumeration"
//#endif
//
//#ifndef VK_EXT_METAL_SURFACE_EXTENSION_NAME
//#define VK_EXT_METAL_SURFACE_EXTENSION_NAME "VK_EXT_metal_surface"
//#endif
namespace MobileGL::MG_Backend::DirectVulkan { namespace MobileGL::MG_Backend::DirectVulkan {
VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, VkBool32 VulkanRenderer::DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
VkDebugUtilsMessageTypeFlagsEXT messageType, VkDebugUtilsMessageTypeFlagsEXT messageType,
@@ -155,11 +167,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkViewport vp{}; VkViewport vp{};
vp.x = 0; vp.x = 0;
vp.y = 0; vp.y = 0;
vp.width = (float)m_swapChainExtent.width; vp.width = (float)m_swapchainExtent.width;
vp.height = (float)m_swapChainExtent.height; vp.height = (float)m_swapchainExtent.height;
vp.minDepth = 0; vp.minDepth = 0;
vp.maxDepth = 1; vp.maxDepth = 1;
VkRect2D scissor{{0, 0}, m_swapChainExtent}; VkRect2D scissor{{0, 0}, m_swapchainExtent};
VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO}; VkPipelineViewportStateCreateInfo vpci{VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO};
vpci.viewportCount = 1; vpci.viewportCount = 1;
vpci.pViewports = &vp; vpci.pViewports = &vp;
@@ -212,11 +224,11 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO}; VkFenceCreateInfo fenceInfo{VK_STRUCTURE_TYPE_FENCE_CREATE_INFO};
fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
m_imageAvailableSemaphores.resize(m_swapchainImages.size(), VK_NULL_HANDLE); m_imageAvailableSemaphores.resize(m_config.MaxFramesInFlight, VK_NULL_HANDLE);
m_renderFinishedSemaphores.resize(m_swapchainImages.size(), VK_NULL_HANDLE); m_renderFinishedSemaphores.resize(m_config.MaxFramesInFlight, VK_NULL_HANDLE);
m_imageInFlightFences.resize(m_swapchainImages.size(), VK_NULL_HANDLE); m_imageInFlightFences.resize(m_config.MaxFramesInFlight, VK_NULL_HANDLE);
for (SizeT i = 0; i < m_swapchainImages.size(); i++) { for (SizeT i = 0; i < m_config.MaxFramesInFlight; i++) {
VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i])); VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_imageAvailableSemaphores[i]));
VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i])); VK_VERIFY(vkCreateSemaphore(m_device, &semaphoreInfo, nullptr, &m_renderFinishedSemaphores[i]));
VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &m_imageInFlightFences[i])); VK_VERIFY(vkCreateFence(m_device, &fenceInfo, nullptr, &m_imageInFlightFences[i]));
@@ -230,11 +242,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
CreateSurface(); CreateSurface();
PickPhysicalDevice(); PickPhysicalDevice();
CreateLogicalDeviceAndQueues(); CreateLogicalDeviceAndQueues();
CreateSwapchain();
CreateSwapchainImageViews();
CreateCommandPool(); CreateCommandPool();
CreateCommandBuffers(); CreateCommandBuffers();
CreateDefaultRenderPass();
RecreateSwapchain();
PrepareDemoPipeline(); PrepareDemoPipeline();
CreateSyncObjects(); CreateSyncObjects();
@@ -274,31 +287,13 @@ namespace MobileGL::MG_Backend::DirectVulkan {
vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr); vkDestroyPipelineLayout(m_device, m_pipelineLayout, nullptr);
} }
for (auto fb : m_framebuffers) { ShutdownSwapchain();
vkDestroyFramebuffer(m_device, fb, nullptr);
}
m_framebuffers.clear();
if (m_renderPass != VK_NULL_HANDLE) {
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
m_renderPass = VK_NULL_HANDLE;
}
if (m_commandPool != VK_NULL_HANDLE) { if (m_commandPool != VK_NULL_HANDLE) {
vkDestroyCommandPool(m_device, m_commandPool, nullptr); vkDestroyCommandPool(m_device, m_commandPool, nullptr);
m_commandPool = VK_NULL_HANDLE; m_commandPool = VK_NULL_HANDLE;
} }
for (auto imageView : m_swapchainImageViews) {
vkDestroyImageView(m_device, imageView, nullptr);
}
m_swapchainImageViews.clear();
if (m_swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE;
}
if (m_device != VK_NULL_HANDLE) { if (m_device != VK_NULL_HANDLE) {
vkDestroyDevice(m_device, nullptr); vkDestroyDevice(m_device, nullptr);
m_device = VK_NULL_HANDLE; m_device = VK_NULL_HANDLE;
@@ -337,7 +332,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
renderPassInfo.renderPass = m_renderPass; renderPassInfo.renderPass = m_renderPass;
renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired]; renderPassInfo.framebuffer = m_framebuffers[m_imageIndexAcquired];
renderPassInfo.renderArea.offset = {0, 0}; renderPassInfo.renderArea.offset = {0, 0};
renderPassInfo.renderArea.extent = m_swapChainExtent; renderPassInfo.renderArea.extent = m_swapchainExtent;
VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}}; VkClearValue clearColor = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
renderPassInfo.clearValueCount = 1; renderPassInfo.clearValueCount = 1;
renderPassInfo.pClearValues = &clearColor; renderPassInfo.pClearValues = &clearColor;
@@ -349,15 +344,15 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = static_cast<float>(m_swapChainExtent.width); viewport.width = static_cast<float>(m_swapchainExtent.width);
viewport.height = static_cast<float>(m_swapChainExtent.height); viewport.height = static_cast<float>(m_swapchainExtent.height);
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
vkCmdSetViewport(m_commandBuffers[m_currentFrameIndex], 0, 1, &viewport); vkCmdSetViewport(m_commandBuffers[m_currentFrameIndex], 0, 1, &viewport);
VkRect2D scissor{}; VkRect2D scissor{};
scissor.offset = {0, 0}; scissor.offset = {0, 0};
scissor.extent = m_swapChainExtent; scissor.extent = m_swapchainExtent;
vkCmdSetScissor(m_commandBuffers[m_currentFrameIndex], 0, 1, &scissor); vkCmdSetScissor(m_commandBuffers[m_currentFrameIndex], 0, 1, &scissor);
vkCmdDraw(m_commandBuffers[m_currentFrameIndex], 3, 1, 0, 0); vkCmdDraw(m_commandBuffers[m_currentFrameIndex], 3, 1, 0, 0);
@@ -398,7 +393,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(vkQueuePresentKHR(m_presentQueue, &presentInfo)); VK_VERIFY(vkQueuePresentKHR(m_presentQueue, &presentInfo));
// 3) Advance frame slot. // 3) Advance frame slot.
m_currentFrameIndex = (m_currentFrameIndex + 1) % m_swapchainImages.size(); m_currentFrameIndex = (m_currentFrameIndex + 1) % m_config.MaxFramesInFlight;
// 4) Wait/reset/acquire for next frame. // 4) Wait/reset/acquire for next frame.
VK_VERIFY(vkWaitForFences(m_device, 1, &m_imageInFlightFences[m_currentFrameIndex], VK_TRUE, UINT64_MAX)); VK_VERIFY(vkWaitForFences(m_device, 1, &m_imageInFlightFences[m_currentFrameIndex], VK_TRUE, UINT64_MAX));
@@ -1141,9 +1136,9 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(vkGetSwapchainImagesKHR(m_device, m_swapchain, &gotImageCount, nullptr)); VK_VERIFY(vkGetSwapchainImagesKHR(m_device, m_swapchain, &gotImageCount, nullptr));
m_swapchainImages.resize(gotImageCount, VK_NULL_HANDLE); m_swapchainImages.resize(gotImageCount, VK_NULL_HANDLE);
VK_VERIFY(vkGetSwapchainImagesKHR(m_device, m_swapchain, &gotImageCount, m_swapchainImages.data())); VK_VERIFY(vkGetSwapchainImagesKHR(m_device, m_swapchain, &gotImageCount, m_swapchainImages.data()));
m_swapChainExtent = swapchainCaps.currentExtent; m_swapchainExtent = swapchainCaps.currentExtent;
MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_swapChainExtent.width, m_swapChainExtent.height, gotImageCount); MGLOG_I("Swapchain created, extent = %dx%d, swapchain imageCount = %d", m_swapchainExtent.width, m_swapchainExtent.height, gotImageCount);
} }
void VulkanRenderer::CreateSwapchainImageViews() { void VulkanRenderer::CreateSwapchainImageViews() {
@@ -1177,12 +1172,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
} }
void VulkanRenderer::CreateCommandBuffers() { void VulkanRenderer::CreateCommandBuffers() {
m_commandBuffers.resize(m_swapchainImages.size(), VK_NULL_HANDLE); m_commandBuffers.resize(m_config.MaxFramesInFlight, 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 = m_commandPool; allocInfo.commandPool = m_commandPool;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandBufferCount = m_swapchainImages.size(); allocInfo.commandBufferCount = m_config.MaxFramesInFlight;
VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data())); VK_VERIFY(vkAllocateCommandBuffers(m_device, &allocInfo, m_commandBuffers.data()));
MGLOG_I("Command buffer created"); MGLOG_I("Command buffer created");
} }
@@ -1210,6 +1205,10 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VK_VERIFY(vkCreateRenderPass(m_device, &rpci, nullptr, &m_renderPass), "vkCreateRenderPass"); VK_VERIFY(vkCreateRenderPass(m_device, &rpci, nullptr, &m_renderPass), "vkCreateRenderPass");
MGLOG_D("RenderPass created.");
}
void VulkanRenderer::CreateDefaultFramebuffers() {
// Create framebuffers now (use swapchain imageviews) // Create framebuffers now (use swapchain imageviews)
const auto& imageViews = m_swapchainImageViews; const auto& imageViews = m_swapchainImageViews;
Vector<VkFramebuffer>& fbs = m_framebuffers; Vector<VkFramebuffer>& fbs = m_framebuffers;
@@ -1220,14 +1219,14 @@ namespace MobileGL::MG_Backend::DirectVulkan {
fbci.renderPass = m_renderPass; fbci.renderPass = m_renderPass;
fbci.attachmentCount = 1; fbci.attachmentCount = 1;
fbci.pAttachments = attachments; fbci.pAttachments = attachments;
fbci.width = m_swapChainExtent.width; fbci.width = m_swapchainExtent.width;
fbci.height = m_swapChainExtent.height; fbci.height = m_swapchainExtent.height;
fbci.layers = 1; fbci.layers = 1;
VkFramebuffer fb; VkFramebuffer fb;
VK_VERIFY(vkCreateFramebuffer(m_device, &fbci, nullptr, &fb), "vkCreateFramebuffer"); VK_VERIFY(vkCreateFramebuffer(m_device, &fbci, nullptr, &fb), "vkCreateFramebuffer");
fbs.push_back(fb); fbs.push_back(fb);
} }
MGLOG_D("RenderPass created and framebuffers set"); MGLOG_D("Default framebuffer created.");
} }
void VulkanRenderer::CreateSurface() { void VulkanRenderer::CreateSurface() {
@@ -1321,4 +1320,38 @@ namespace MobileGL::MG_Backend::DirectVulkan {
return false; return false;
} }
void VulkanRenderer::ShutdownSwapchain() {
for (auto fb : m_framebuffers) {
vkDestroyFramebuffer(m_device, fb, nullptr);
}
m_framebuffers.clear();
if (m_renderPass != VK_NULL_HANDLE) {
vkDestroyRenderPass(m_device, m_renderPass, nullptr);
m_renderPass = VK_NULL_HANDLE;
}
for (auto imageView : m_swapchainImageViews) {
vkDestroyImageView(m_device, imageView, nullptr);
}
m_swapchainImageViews.clear();
if (m_swapchain != VK_NULL_HANDLE) {
vkDestroySwapchainKHR(m_device, m_swapchain, nullptr);
m_swapchain = VK_NULL_HANDLE;
}
}
void VulkanRenderer::RecreateSwapchain() {
vkDeviceWaitIdle(m_device);
ShutdownSwapchain();
CreateSwapchain();
CreateSwapchainImageViews();
CreateDefaultRenderPass();
CreateDefaultFramebuffers();
}
} // namespace MobileGL::MG_Backend::DirectVulkan } // namespace MobileGL::MG_Backend::DirectVulkan
@@ -40,6 +40,8 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void Render(); void Render();
void Present(); void Present();
void RecreateSwapchain();
private: private:
struct QueueFamilyIndices { struct QueueFamilyIndices {
Int32 graphicsFamily = -1; Int32 graphicsFamily = -1;
@@ -84,7 +86,7 @@ namespace MobileGL::MG_Backend::DirectVulkan {
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE; VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
VkSurfaceFormatKHR m_swapchainSurfaceFormat; VkSurfaceFormatKHR m_swapchainSurfaceFormat;
Vector<VkImage> m_swapchainImages; Vector<VkImage> m_swapchainImages;
VkExtent2D m_swapChainExtent; VkExtent2D m_swapchainExtent;
Vector<VkImageView> m_swapchainImageViews; Vector<VkImageView> m_swapchainImageViews;
// Vector<VkQueueFamilyProperties> m_queueFamilies; // Vector<VkQueueFamilyProperties> m_queueFamilies;
@@ -120,9 +122,12 @@ namespace MobileGL::MG_Backend::DirectVulkan {
void CreateCommandPool(); void CreateCommandPool();
void CreateCommandBuffers(); void CreateCommandBuffers();
void CreateDefaultRenderPass(); void CreateDefaultRenderPass();
void CreateDefaultFramebuffers();
void PrepareDemoPipeline(); void PrepareDemoPipeline();
void CreateSyncObjects(); void CreateSyncObjects();
void ShutdownSwapchain();
static Int GetPresentQueueFamilyIndex( static Int GetPresentQueueFamilyIndex(
const PhysicalDevice& physicalDevice, VkSurfaceKHR surface, const PhysicalDevice& physicalDevice, VkSurfaceKHR surface,
const Vector<VkQueueFamilyProperties>& queueFamilies, Int preferredFamilyIndex = -1); const Vector<VkQueueFamilyProperties>& queueFamilies, Int preferredFamilyIndex = -1);