#include "Swapchain.hpp" #include #include #include namespace { const char* presentModeName(VkPresentModeKHR mode) { switch (mode) { case VK_PRESENT_MODE_FIFO_KHR: return "fifo"; case VK_PRESENT_MODE_MAILBOX_KHR: return "mailbox"; case VK_PRESENT_MODE_IMMEDIATE_KHR: return "immediate"; default: return "other"; } } } Swapchain::Swapchain( VkDevice device, VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkRenderPass renderPass, VkPresentModeKHR preferredPresentMode, uint32_t windowWidth, uint32_t windowHeight) : m_device(device) , m_physicalDevice(physicalDevice) , m_surface(surface) , m_preferredPresentMode(preferredPresentMode) { createSwapchain(windowWidth, windowHeight); createImageViews(); createFramebuffers(renderPass); std::cout << "Swapchain created (" << m_imageCount << " images)" << std::endl; } Swapchain::~Swapchain() { destroy(); } void Swapchain::recreate( VkRenderPass renderPass, uint32_t windowWidth, uint32_t windowHeight) { destroy(); createSwapchain(windowWidth, windowHeight); createImageViews(); createFramebuffers(renderPass); std::cout << "Swapchain recreated (" << m_imageCount << " images)" << std::endl; } void Swapchain::createSwapchain( uint32_t windowWidth, uint32_t windowHeight) { SwapchainSupportDetails support = querySwapchainSupport( m_physicalDevice, m_surface ); m_surfaceFormat = support.formats[0]; for (const auto& availableFormat : support.formats) { if (availableFormat.format == VK_FORMAT_B8G8R8A8_SRGB && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { m_surfaceFormat = availableFormat; break; } } m_presentMode = VK_PRESENT_MODE_FIFO_KHR; for (const auto& availablePresentMode : support.presentModes) { if (availablePresentMode == m_preferredPresentMode) { m_presentMode = availablePresentMode; break; } } m_extent.width = windowWidth; m_extent.height = windowHeight; m_imageCount = support.capabilities.minImageCount + 1; if (support.capabilities.maxImageCount > 0 && m_imageCount > support.capabilities.maxImageCount) { m_imageCount = support.capabilities.maxImageCount; } VkSwapchainCreateInfoKHR swapchainInfo{}; swapchainInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; swapchainInfo.surface = m_surface; swapchainInfo.minImageCount = m_imageCount; swapchainInfo.imageFormat = m_surfaceFormat.format; swapchainInfo.imageColorSpace = m_surfaceFormat.colorSpace; swapchainInfo.imageExtent = m_extent; swapchainInfo.imageArrayLayers = 1; swapchainInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; QueueFamilyIndices indices = findQueueFamilies( m_physicalDevice, m_surface ); uint32_t queueFamilyIndices[] = { *indices.graphicsFamily, *indices.presentFamily }; if (*indices.graphicsFamily != *indices.presentFamily) { swapchainInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; swapchainInfo.queueFamilyIndexCount = 2; swapchainInfo.pQueueFamilyIndices = queueFamilyIndices; } else { swapchainInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; } swapchainInfo.preTransform = support.capabilities.currentTransform; swapchainInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; swapchainInfo.presentMode = m_presentMode; swapchainInfo.clipped = VK_TRUE; if (vkCreateSwapchainKHR( m_device, &swapchainInfo, nullptr, &m_swapchain) != VK_SUCCESS) { throw std::runtime_error( "Failed to create swapchain" ); } vkGetSwapchainImagesKHR( m_device, m_swapchain, &m_imageCount, nullptr ); m_swapchainImages.resize(m_imageCount); vkGetSwapchainImagesKHR( m_device, m_swapchain, &m_imageCount, m_swapchainImages.data() ); std::cout << "Present mode: " << presentModeName(m_presentMode) << std::endl; } void Swapchain::createImageViews() { m_imageViews.resize(m_swapchainImages.size()); for (size_t i = 0; i < m_swapchainImages.size(); ++i) { VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = m_swapchainImages[i]; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = m_surfaceFormat.format; viewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.baseMipLevel = 0; viewInfo.subresourceRange.levelCount = 1; viewInfo.subresourceRange.baseArrayLayer = 0; viewInfo.subresourceRange.layerCount = 1; if (vkCreateImageView( m_device, &viewInfo, nullptr, &m_imageViews[i]) != VK_SUCCESS) { throw std::runtime_error( "Failed to create image view" ); } } std::cout << "Image views created" << std::endl; } void Swapchain::createFramebuffers( VkRenderPass renderPass) { m_framebuffers.resize(m_imageViews.size()); for (size_t i = 0; i < m_imageViews.size(); ++i) { VkImageView attachments[] = { m_imageViews[i] }; VkFramebufferCreateInfo fbInfo{}; fbInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; fbInfo.renderPass = renderPass; fbInfo.attachmentCount = 1; fbInfo.pAttachments = attachments; fbInfo.width = m_extent.width; fbInfo.height = m_extent.height; fbInfo.layers = 1; if (vkCreateFramebuffer( m_device, &fbInfo, nullptr, &m_framebuffers[i]) != VK_SUCCESS) { throw std::runtime_error( "Failed to create framebuffer" ); } } std::cout << "Framebuffers created" << std::endl; } void Swapchain::destroy() { if (m_swapchain == VK_NULL_HANDLE) { return; } for (VkFramebuffer fb : m_framebuffers) { vkDestroyFramebuffer( m_device, fb, nullptr ); } m_framebuffers.clear(); for (VkImageView view : m_imageViews) { vkDestroyImageView( m_device, view, nullptr ); } m_imageViews.clear(); m_swapchainImages.clear(); vkDestroySwapchainKHR( m_device, m_swapchain, nullptr ); m_swapchain = VK_NULL_HANDLE; } void Swapchain::release() { destroy(); }