diff --git a/src/main.cpp b/src/main.cpp index f61c1d9..b912ec2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -56,6 +56,11 @@ class VulkanApp { vk::UniqueSurfaceKHR mSurface; + vk::UniqueSwapchainKHR mSwapChain; + std::vector mSwapChainImages; + vk::Format mSwapChainImageFormat; + vk::Extent2D mSwapChainExtent; + struct QueueFamilyIndices { std::optional graphics_family; std::optional present_family; @@ -86,6 +91,7 @@ class VulkanApp { createSurface(); pickPhysicalDevice(); createLogicalDevice(); + createSwapChain(); } fn mainLoop() -> void { @@ -115,7 +121,9 @@ class VulkanApp { #endif vk::InstanceCreateInfo createInfo { - .flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, +#ifdef __APPLE__ + .flags = vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR, +#endif .pApplicationInfo = &appInfo, .enabledLayerCount = enableValidationLayers ? static_cast(validationLayers.size()) : 0, .ppEnabledLayerNames = enableValidationLayers ? validationLayers.data() : nullptr, @@ -258,6 +266,50 @@ class VulkanApp { return indices; } + fn createSwapChain() -> void { + SwapChainSupportDetails swapChainSupport = querySwapChainSupport(mPhysicalDevice); + + vk::SurfaceFormatKHR surfaceFormat = chooseSwapSurfaceFormat(swapChainSupport.formats); + vk::PresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.present_modes); + vk::Extent2D extent = chooseSwapExtent(swapChainSupport.capabilities); + + u32 imageCount = swapChainSupport.capabilities.minImageCount + 1; + + if (swapChainSupport.capabilities.maxImageCount > 0 && + imageCount > swapChainSupport.capabilities.maxImageCount) + imageCount = swapChainSupport.capabilities.maxImageCount; + + QueueFamilyIndices indices = findQueueFamilies(mPhysicalDevice); + std::array queueFamilyIndices = { indices.graphics_family.value(), + indices.present_family.value() }; + + vk::SwapchainCreateInfoKHR createInfo { + .surface = mSurface.get(), + .minImageCount = imageCount, + .imageFormat = surfaceFormat.format, + .imageColorSpace = surfaceFormat.colorSpace, + .imageExtent = extent, + .imageArrayLayers = 1, + .imageUsage = vk::ImageUsageFlagBits::eColorAttachment, + .imageSharingMode = indices.graphics_family != indices.present_family ? vk::SharingMode::eConcurrent + : vk::SharingMode::eExclusive, + .queueFamilyIndexCount = static_cast(indices.graphics_family != indices.present_family ? 2 : 0), + .pQueueFamilyIndices = + indices.graphics_family != indices.present_family ? queueFamilyIndices.data() : nullptr, + .preTransform = swapChainSupport.capabilities.currentTransform, + .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, + .presentMode = presentMode, + .clipped = VK_TRUE, + .oldSwapchain = nullptr, + }; + + mSwapChain = mDevice->createSwapchainKHRUnique(createInfo); + + mSwapChainImages = mDevice->getSwapchainImagesKHR(mSwapChain.get()); + mSwapChainImageFormat = surfaceFormat.format; + mSwapChainExtent = extent; + } + fn querySwapChainSupport(vk::PhysicalDevice device) -> SwapChainSupportDetails { SwapChainSupportDetails details; @@ -268,6 +320,42 @@ class VulkanApp { return details; } + static fn chooseSwapSurfaceFormat(const std::vector& availableFormats + ) -> vk::SurfaceFormatKHR { + for (const auto& availableFormat : availableFormats) + if (availableFormat.format == vk::Format::eB8G8R8A8Srgb && + availableFormat.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear) + return availableFormat; + + return availableFormats[0]; + } + + static fn chooseSwapPresentMode(const std::vector& availablePresentModes + ) -> vk::PresentModeKHR { + for (const auto& availablePresentMode : availablePresentModes) + if (availablePresentMode == vk::PresentModeKHR::eMailbox) + return availablePresentMode; + + return vk::PresentModeKHR::eFifo; + } + + fn chooseSwapExtent(const vk::SurfaceCapabilitiesKHR capabilities) -> vk::Extent2D { + if (capabilities.currentExtent.width != UINT32_MAX) + return capabilities.currentExtent; + + u32 width = 0, height = 0; + std::tie(width, height) = mWindow->getFramebufferSize(); + + vk::Extent2D actualExtent = { width, height }; + + actualExtent.width = + std::clamp(actualExtent.width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width); + actualExtent.height = + std::clamp(actualExtent.height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height); + + return actualExtent; + } + static fn getRequiredExtensions() -> std::vector { std::span extensionsSpan = vkfw::getRequiredInstanceExtensions();