src/core/VulkanSwapchain.cpp
void VulkanSwapchain::create(uint32_t *width, uint32_t *height, bool vsync)
{
    // Store the current swap chain handle so we can use it later on to ease up recreation
    VkSwapchainKHR oldSwapchain = swapChain;

    // Get physical device surface properties and formats
    VkSurfaceCapabilitiesKHR surfCaps;
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get device surface formats");

    // Get available present modes
    uint32_t presentModeCount;
     result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get present modes ");
    assert(presentModeCount > 0);

    std::vector<VkPresentModeKHR> presentModes(presentModeCount);
     result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get present modes ");

    VkExtent2D swapchainExtent = {};
    // If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain
    if (surfCaps.currentExtent.width == (uint32_t)-1)
    {
        // If the surface size is undefined, the size is set to
        // the size of the images requested.
        swapchainExtent.width = *width;
        swapchainExtent.height = *height;
    }
    else
    {
        // If the surface size is defined, the swap chain size must match
        swapchainExtent = surfCaps.currentExtent;
        *width = surfCaps.currentExtent.width;
        *height = surfCaps.currentExtent.height;
    }


    // Select a present mode for the swapchain

    // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec
    // This mode waits for the vertical blank ("v-sync")
    VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;

    // If v-sync is not requested, try to find a mailbox mode
    // It's the lowest latency non-tearing present mode available
    if (!vsync)
    {
        for (size_t i = 0; i < presentModeCount; i++)
        {
            if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
            {
                swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
                break;
            }
            if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
            {
                swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
            }
        }
    }

    // Determine the number of images
    uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
    if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
    {
        desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
    }

    // Find the transformation of the surface
    VkSurfaceTransformFlagsKHR preTransform;
    if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
    {
        // We prefer a non-rotated transform
        preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    }
    else
    {
        preTransform = surfCaps.currentTransform;
    }

    // Find a supported composite alpha format (not all devices support alpha opaque)
    VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    // Simply select the first composite alpha format available
    std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
            VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
            VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
            VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
            VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
    };
    for (auto& compositeAlphaFlag : compositeAlphaFlags) {
        if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
            compositeAlpha = compositeAlphaFlag;
            break;
        };
    }

    VkSwapchainCreateInfoKHR swapchainCI = {};
    swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    swapchainCI.surface = surface;
    swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
    swapchainCI.imageFormat = colorFormat;
    swapchainCI.imageColorSpace = colorSpace;
    swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
    swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
    swapchainCI.imageArrayLayers = 1;
    swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
    swapchainCI.queueFamilyIndexCount = 0;
    swapchainCI.presentMode = swapchainPresentMode;
    // Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images
    swapchainCI.oldSwapchain = oldSwapchain;
    // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area
    swapchainCI.clipped = VK_TRUE;
    swapchainCI.compositeAlpha = compositeAlpha;

    // Enable transfer source on swap chain images if supported
    if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
        swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
    }

    // Enable transfer destination on swap chain images if supported
    if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
        swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    }

    result = vkCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to create swapchain");

    // If an existing swap chain is re-created, destroy the old swap chain
    // This also cleans up all the presentable images
    if (oldSwapchain != VK_NULL_HANDLE)
    {
        for (uint32_t i = 0; i < imageCount; i++)
        {
            vkDestroyImageView(device, buffers[i].view, nullptr);
        }
        vkDestroySwapchainKHR(device, oldSwapchain, nullptr);
    }
    result = vkGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get swapchain images");

    // Get the swap chain images
    images.resize(imageCount);
    result = vkGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data());
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get swapchain images");

    // Get the swap chain buffers containing the image and imageview
    buffers.resize(imageCount);
    for (uint32_t i = 0; i < imageCount; i++)
    {
        VkImageViewCreateInfo colorAttachmentView = {};
        colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        colorAttachmentView.pNext = NULL;
        colorAttachmentView.format = colorFormat;
        colorAttachmentView.components = {
                VK_COMPONENT_SWIZZLE_R,
                VK_COMPONENT_SWIZZLE_G,
                VK_COMPONENT_SWIZZLE_B,
                VK_COMPONENT_SWIZZLE_A
        };
        colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        colorAttachmentView.subresourceRange.baseMipLevel = 0;
        colorAttachmentView.subresourceRange.levelCount = 1;
        colorAttachmentView.subresourceRange.baseArrayLayer = 0;
        colorAttachmentView.subresourceRange.layerCount = 1;
        colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
        colorAttachmentView.flags = 0;

        buffers[i].image = images[i];

        colorAttachmentView.image = buffers[i].image;

        result = vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view);
        if (result != VK_SUCCESS) throw std::runtime_error("Failed to create swapchain image views");

    }
}
/**
* Create the swapchain and get its images with given width and height
*
* @param width Pointer to the width of the swapchain (may be adjusted to fit the requirements of the swapchain)
* @param height Pointer to the height of the swapchain (may be adjusted to fit the requirements of the swapchain)
* @param vsync (Optional) Can be used to force vsync-ed rendering (by using VK_PRESENT_MODE_FIFO_KHR as presentation mode)
*/
Create the swapchain and get its images with given width and height
Create the swapchain and get its images with given width and height
void VulkanSwapchain::create(uint32_t *width, uint32_t *height, bool vsync)
{
    VkSwapchainKHR oldSwapchain = swapChain;
    VkSurfaceCapabilitiesKHR surfCaps;
    VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &surfCaps);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get device surface formats");
    uint32_t presentModeCount;
     result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, NULL);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get present modes ");
    assert(presentModeCount > 0);
    std::vector<VkPresentModeKHR> presentModes(presentModeCount);
     result = vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data());
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get present modes ");
    VkExtent2D swapchainExtent = {};
    if (surfCaps.currentExtent.width == (uint32_t)-1)
    {
        swapchainExtent.width = *width;
        swapchainExtent.height = *height;
    }
    else
    {
        swapchainExtent = surfCaps.currentExtent;
        *width = surfCaps.currentExtent.width;
        *height = surfCaps.currentExtent.height;
    }
    VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
    if (!vsync)
    {
        for (size_t i = 0; i < presentModeCount; i++)
        {
            if (presentModes[i] == VK_PRESENT_MODE_MAILBOX_KHR)
            {
                swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR;
                break;
            }
            if (presentModes[i] == VK_PRESENT_MODE_IMMEDIATE_KHR)
            {
                swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR;
            }
        }
    }
    uint32_t desiredNumberOfSwapchainImages = surfCaps.minImageCount + 1;
    if ((surfCaps.maxImageCount > 0) && (desiredNumberOfSwapchainImages > surfCaps.maxImageCount))
    {
        desiredNumberOfSwapchainImages = surfCaps.maxImageCount;
    }
    VkSurfaceTransformFlagsKHR preTransform;
    if (surfCaps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)
    {
        preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    }
    else
    {
        preTransform = surfCaps.currentTransform;
    }
    VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    std::vector<VkCompositeAlphaFlagBitsKHR> compositeAlphaFlags = {
            VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
            VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR,
            VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR,
            VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
    };
    for (auto& compositeAlphaFlag : compositeAlphaFlags) {
        if (surfCaps.supportedCompositeAlpha & compositeAlphaFlag) {
            compositeAlpha = compositeAlphaFlag;
            break;
        };
    }
    VkSwapchainCreateInfoKHR swapchainCI = {};
    swapchainCI.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    swapchainCI.surface = surface;
    swapchainCI.minImageCount = desiredNumberOfSwapchainImages;
    swapchainCI.imageFormat = colorFormat;
    swapchainCI.imageColorSpace = colorSpace;
    swapchainCI.imageExtent = { swapchainExtent.width, swapchainExtent.height };
    swapchainCI.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
    swapchainCI.preTransform = (VkSurfaceTransformFlagBitsKHR)preTransform;
    swapchainCI.imageArrayLayers = 1;
    swapchainCI.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
    swapchainCI.queueFamilyIndexCount = 0;
    swapchainCI.presentMode = swapchainPresentMode;
    swapchainCI.oldSwapchain = oldSwapchain;
    swapchainCI.clipped = VK_TRUE;
    swapchainCI.compositeAlpha = compositeAlpha;
    if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) {
        swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
    }
    if (surfCaps.supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) {
        swapchainCI.imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    }
    result = vkCreateSwapchainKHR(device, &swapchainCI, nullptr, &swapChain);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to create swapchain");
    if (oldSwapchain != VK_NULL_HANDLE)
    {
        for (uint32_t i = 0; i < imageCount; i++)
        {
            vkDestroyImageView(device, buffers[i].view, nullptr);
        }
        vkDestroySwapchainKHR(device, oldSwapchain, nullptr);
    }
    result = vkGetSwapchainImagesKHR(device, swapChain, &imageCount, NULL);
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get swapchain images");
    images.resize(imageCount);
    result = vkGetSwapchainImagesKHR(device, swapChain, &imageCount, images.data());
    if (result != VK_SUCCESS) throw std::runtime_error("Failed to get swapchain images");
    buffers.resize(imageCount);
    for (uint32_t i = 0; i < imageCount; i++)
    {
        VkImageViewCreateInfo colorAttachmentView = {};
        colorAttachmentView.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        colorAttachmentView.pNext = NULL;
        colorAttachmentView.format = colorFormat;
        colorAttachmentView.components = {
                VK_COMPONENT_SWIZZLE_R,
                VK_COMPONENT_SWIZZLE_G,
                VK_COMPONENT_SWIZZLE_B,
                VK_COMPONENT_SWIZZLE_A
        };
        colorAttachmentView.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
        colorAttachmentView.subresourceRange.baseMipLevel = 0;
        colorAttachmentView.subresourceRange.levelCount = 1;
        colorAttachmentView.subresourceRange.baseArrayLayer = 0;
        colorAttachmentView.subresourceRange.layerCount = 1;
        colorAttachmentView.viewType = VK_IMAGE_VIEW_TYPE_2D;
        colorAttachmentView.flags = 0;
        buffers[i].image = images[i];
        colorAttachmentView.image = buffers[i].image;
        result = vkCreateImageView(device, &colorAttachmentView, nullptr, &buffers[i].view);
        if (result != VK_SUCCESS) throw std::runtime_error("Failed to create swapchain image views");
    }
}
void VulkanSwapchain :: create ( uint32_t * width , uint32_t * height , bool vsync ) { VkSwapchainKHR oldSwapchain = swapChain ; VkSurfaceCapabilitiesKHR surfCaps ; VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR ( physicalDevice , surface , & surfCaps ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; uint32_t presentModeCount ; result = vkGetPhysicalDeviceSurfacePresentModesKHR ( physicalDevice , surface , & presentModeCount , NULL ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; assert ( presentModeCount > 0 ) ; std :: vector < VkPresentModeKHR > presentModes ( presentModeCount ) ; result = vkGetPhysicalDeviceSurfacePresentModesKHR ( physicalDevice , surface , & presentModeCount , presentModes . data ( ) ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; VkExtent2D swapchainExtent = { } ; if ( surfCaps . currentExtent . width == ( uint32_t ) -1 ) { swapchainExtent . width = * width ; swapchainExtent . height = * height ; } else { swapchainExtent = surfCaps . currentExtent ; * width = surfCaps . currentExtent . width ; * height = surfCaps . currentExtent . height ; } VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR ; if ( ! vsync ) { for ( size_t i = 0 ; i < presentModeCount ; i ++ ) { if ( presentModes [ i ] == VK_PRESENT_MODE_MAILBOX_KHR ) { swapchainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR ; break ; } if ( presentModes [ i ] == VK_PRESENT_MODE_IMMEDIATE_KHR ) { swapchainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR ; } } } uint32_t desiredNumberOfSwapchainImages = surfCaps . minImageCount + 1 ; if ( ( surfCaps . maxImageCount > 0 ) && ( desiredNumberOfSwapchainImages > surfCaps . maxImageCount ) ) { desiredNumberOfSwapchainImages = surfCaps . maxImageCount ; } VkSurfaceTransformFlagsKHR preTransform ; if ( surfCaps . supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ) { preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR ; } else { preTransform = surfCaps . currentTransform ; } VkCompositeAlphaFlagBitsKHR compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR ; std :: vector < VkCompositeAlphaFlagBitsKHR > compositeAlphaFlags = { VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR , VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR , VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR , VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR , } ; for ( auto & compositeAlphaFlag : compositeAlphaFlags ) { if ( surfCaps . supportedCompositeAlpha & compositeAlphaFlag ) { compositeAlpha = compositeAlphaFlag ; break ; } ; } VkSwapchainCreateInfoKHR swapchainCI = { } ; swapchainCI . sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR ; swapchainCI . surface = surface ; swapchainCI . minImageCount = desiredNumberOfSwapchainImages ; swapchainCI . imageFormat = colorFormat ; swapchainCI . imageColorSpace = colorSpace ; swapchainCI . imageExtent = { swapchainExtent . width , swapchainExtent . height } ; swapchainCI . imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT ; swapchainCI . preTransform = ( VkSurfaceTransformFlagBitsKHR ) preTransform ; swapchainCI . imageArrayLayers = 1 ; swapchainCI . imageSharingMode = VK_SHARING_MODE_EXCLUSIVE ; swapchainCI . queueFamilyIndexCount = 0 ; swapchainCI . presentMode = swapchainPresentMode ; swapchainCI . oldSwapchain = oldSwapchain ; swapchainCI . clipped = VK_TRUE ; swapchainCI . compositeAlpha = compositeAlpha ; if ( surfCaps . supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT ) { swapchainCI . imageUsage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT ; } if ( surfCaps . supportedUsageFlags & VK_IMAGE_USAGE_TRANSFER_DST_BIT ) { swapchainCI . imageUsage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT ; } result = vkCreateSwapchainKHR ( device , & swapchainCI , nullptr , & swapChain ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; if ( oldSwapchain != VK_NULL_HANDLE ) { for ( uint32_t i = 0 ; i < imageCount ; i ++ ) { vkDestroyImageView ( device , buffers [ i ] . view , nullptr ) ; } vkDestroySwapchainKHR ( device , oldSwapchain , nullptr ) ; } result = vkGetSwapchainImagesKHR ( device , swapChain , & imageCount , NULL ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; images . resize ( imageCount ) ; result = vkGetSwapchainImagesKHR ( device , swapChain , & imageCount , images . data ( ) ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; buffers . resize ( imageCount ) ; for ( uint32_t i = 0 ; i < imageCount ; i ++ ) { VkImageViewCreateInfo colorAttachmentView = { } ; colorAttachmentView . sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO ; colorAttachmentView . pNext = NULL ; colorAttachmentView . format = colorFormat ; colorAttachmentView . components = { VK_COMPONENT_SWIZZLE_R , VK_COMPONENT_SWIZZLE_G , VK_COMPONENT_SWIZZLE_B , VK_COMPONENT_SWIZZLE_A } ; colorAttachmentView . subresourceRange . aspectMask = VK_IMAGE_ASPECT_COLOR_BIT ; colorAttachmentView . subresourceRange . baseMipLevel = 0 ; colorAttachmentView . subresourceRange . levelCount = 1 ; colorAttachmentView . subresourceRange . baseArrayLayer = 0 ; colorAttachmentView . subresourceRange . layerCount = 1 ; colorAttachmentView . viewType = VK_IMAGE_VIEW_TYPE_2D ; colorAttachmentView . flags = 0 ; buffers [ i ] . image = images [ i ] ; colorAttachmentView . image = buffers [ i ] . image ; result = vkCreateImageView ( device , & colorAttachmentView , nullptr , & buffers [ i ] . view ) ; if ( result != VK_SUCCESS ) throw std :: runtime_error ( " " ) ; } }
Create the swapchain and get its images with given width and height
Create the swapchain and get its images with given width and height
// Store the current swap chain handle so we can use it later on to ease up recreation // Get physical device surface properties and formats // Get available present modes // If width (and height) equals the special value 0xFFFFFFFF, the size of the surface will be set by the swapchain // If the surface size is undefined, the size is set to // the size of the images requested. // If the surface size is defined, the swap chain size must match // Select a present mode for the swapchain // The VK_PRESENT_MODE_FIFO_KHR mode must always be present as per spec // This mode waits for the vertical blank ("v-sync") // If v-sync is not requested, try to find a mailbox mode // It's the lowest latency non-tearing present mode available // Determine the number of images // Find the transformation of the surface // We prefer a non-rotated transform // Find a supported composite alpha format (not all devices support alpha opaque) // Simply select the first composite alpha format available // Setting oldSwapChain to the saved handle of the previous swapchain aids in resource reuse and makes sure that we can still present already acquired images // Setting clipped to VK_TRUE allows the implementation to discard rendering outside of the surface area // Enable transfer source on swap chain images if supported // Enable transfer destination on swap chain images if supported // If an existing swap chain is re-created, destroy the old swap chain // This also cleans up all the presentable images // Get the swap chain images // Get the swap chain buffers containing the image and imageview