From b2f33a76fb03756db0a655e439cf7bd6135984b4 Mon Sep 17 00:00:00 2001 From: Pasha Bibko <156938226+PashaBibko@users.noreply.github.com> Date: Sat, 15 Nov 2025 21:54:02 +0000 Subject: [PATCH] Added swapchain --- src/managers/VulkanManager.cpp | 149 +++++++++++++++++++++++++++++++-- src/managers/VulkanManager.h | 19 +++++ 2 files changed, 162 insertions(+), 6 deletions(-) diff --git a/src/managers/VulkanManager.cpp b/src/managers/VulkanManager.cpp index 73e9d01..39f585d 100644 --- a/src/managers/VulkanManager.cpp +++ b/src/managers/VulkanManager.cpp @@ -13,6 +13,12 @@ namespace PB::Renderer VkQueue VulkanManager::s_GraphicsQueue = VK_NULL_HANDLE; VkQueue VulkanManager::s_PresentQueue = VK_NULL_HANDLE; + VkSwapchainKHR VulkanManager::s_SwapChain = VK_NULL_HANDLE; + std::vector VulkanManager::s_SwapChainImages = {}; + std::vector VulkanManager::s_SwapChainImageViews = {}; + VkFormat VulkanManager::s_SwapChainImageFormat = {}; + VkExtent2D VulkanManager::s_SwapChainExtent = {}; + bool VulkanManager::InitAll(GLFWwindow* window) { if (const std::optional instance = VulkanManager::Init(); !instance) @@ -70,6 +76,18 @@ namespace PB::Renderer return instance; } + bool VulkanManager::Cleanup() + { + if (s_Surface != std::nullopt) + vkDestroySurfaceKHR(s_Instance.value(), s_Surface.value(), nullptr); + + if (s_Instance != std::nullopt) + vkDestroyInstance(s_Instance.value(), nullptr); + + s_Instance = std::nullopt; + return true; + } + std::optional VulkanManager::CreateSurface(GLFWwindow* window) { if (s_Instance == std::nullopt) @@ -256,15 +274,134 @@ namespace PB::Renderer return true; } - bool VulkanManager::Cleanup() + bool VulkanManager::CreateSwapChain(GLFWwindow* window) { - if (s_Surface != std::nullopt) - vkDestroySurfaceKHR(s_Instance.value(), s_Surface.value(), nullptr); + auto [capabilities, formats, presentModes] = QuerySwapChainSupport(); + auto [format, colorSpace] = ChooseSurfaceFormat(formats); - if (s_Instance != std::nullopt) - vkDestroyInstance(s_Instance.value(), nullptr); + const VkPresentModeKHR presentMode = ChoosePresentMode(presentModes); + s_SwapChainExtent = ChooseSwapExtent(capabilities, window); + + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) + imageCount = capabilities.maxImageCount; + + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = s_Surface.value(); + + createInfo.minImageCount = imageCount; + createInfo.imageFormat = format; + createInfo.imageColorSpace = colorSpace; + createInfo.imageExtent = s_SwapChainExtent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + + const uint32_t queueFamilyIndices[] = + { + s_QueueIndices.graphicsFamily.value(), + s_QueueIndices.presentFamily.value() + }; + + if (queueFamilyIndices[0] != queueFamilyIndices[1]) + { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = 2; + createInfo.pQueueFamilyIndices = queueFamilyIndices; + } + + else + { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + } + + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; + + if (!vkCreateSwapchainKHR(s_Device, &createInfo, nullptr, &s_SwapChain)) + { + std::cout << "PB::Renderer::VulkanManager::CreateSwapChain(): Failed to create swap chain" << std::endl; + return false; + } + + vkGetSwapchainImagesKHR(s_Device, s_SwapChain, &imageCount, nullptr); + s_SwapChainImages.resize(imageCount); + + vkGetSwapchainImagesKHR(s_Device, s_SwapChain, &imageCount, s_SwapChainImages.data()); + s_SwapChainImageFormat = format; - s_Instance = std::nullopt; return true; } + + SwapChainSupportDetails VulkanManager::QuerySwapChainSupport() + { + SwapChainSupportDetails details; + const VkSurfaceKHR surface = s_Surface.value(); + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(s_PhysicalDevice, surface, &details.capabilities); + + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(s_PhysicalDevice, surface, &formatCount, nullptr); + details.formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(s_PhysicalDevice, surface, &formatCount, details.formats.data()); + + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(s_PhysicalDevice, surface, &presentModeCount, nullptr); + details.presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(s_PhysicalDevice, surface, &presentModeCount, details.presentModes.data()); + + return details; + } + + VkSurfaceFormatKHR VulkanManager::ChooseSurfaceFormat(const std::vector& availableFormats) + { + for (const auto& format : availableFormats) + { + if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + return format; + } + } + + return availableFormats[0]; + } + + VkPresentModeKHR VulkanManager::ChoosePresentMode(const std::vector& availablePresentModes) + { + for (const auto& mode : availablePresentModes) + { + if (mode == VK_PRESENT_MODE_MAILBOX_KHR) + { + return mode; + } + } + + return VK_PRESENT_MODE_FIFO_KHR; + } + + VkExtent2D VulkanManager::ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) + { + if (capabilities.currentExtent.width != UINT32_MAX) + { + return capabilities.currentExtent; + } + + int width, height; + glfwGetFramebufferSize(window, &width, &height); + + VkExtent2D actualExtent = + { + static_cast(width), + static_cast(height) + }; + + actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width)); + actualExtent.height = std::max(capabilities.minImageExtent.height, std::min(capabilities.maxImageExtent.height, actualExtent.height)); + + return actualExtent; + } } diff --git a/src/managers/VulkanManager.h b/src/managers/VulkanManager.h index 0a8a2f5..cb9d7a6 100644 --- a/src/managers/VulkanManager.h +++ b/src/managers/VulkanManager.h @@ -15,6 +15,13 @@ namespace PB::Renderer } }; + struct SwapChainSupportDetails + { + VkSurfaceCapabilitiesKHR capabilities; + std::vector formats; + std::vector presentModes; + }; + class VulkanManager { public: @@ -25,12 +32,18 @@ namespace PB::Renderer static std::optional CreateSurface(GLFWwindow* window); static bool PickPhysicalDevice(); static bool CreateLogicalDevice(); + static bool CreateSwapChain(GLFWwindow* window); private: static bool IsDeviceSuitable(VkPhysicalDevice device, VkSurfaceKHR surface); static QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device, VkSurfaceKHR surface); static bool CheckDeviceExtensionSupport(VkPhysicalDevice device); + static SwapChainSupportDetails QuerySwapChainSupport(); + static VkSurfaceFormatKHR ChooseSurfaceFormat(const std::vector& availableFormats); + static VkPresentModeKHR ChoosePresentMode(const std::vector& availablePresentModes); + static VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window); + static std::optional s_Instance; static std::optional s_Surface; @@ -41,5 +54,11 @@ namespace PB::Renderer static VkQueue s_GraphicsQueue; static VkQueue s_PresentQueue; + + static VkSwapchainKHR s_SwapChain; + static std::vector s_SwapChainImages; + static std::vector s_SwapChainImageViews; + static VkFormat s_SwapChainImageFormat; + static VkExtent2D s_SwapChainExtent; }; }