From 20fde9f8bede5bc97718a1e5c48ae15793b099c5 Mon Sep 17 00:00:00 2001 From: Magnus Norddahl Date: Mon, 8 Apr 2019 18:14:07 +0200 Subject: [PATCH] - clean up swapchain class --- src/rendering/vulkan/system/vk_swapchain.cpp | 347 +++++++++++-------- src/rendering/vulkan/system/vk_swapchain.h | 15 +- 2 files changed, 211 insertions(+), 151 deletions(-) diff --git a/src/rendering/vulkan/system/vk_swapchain.cpp b/src/rendering/vulkan/system/vk_swapchain.cpp index b9ffe154fa..4309e946ab 100644 --- a/src/rendering/vulkan/system/vk_swapchain.cpp +++ b/src/rendering/vulkan/system/vk_swapchain.cpp @@ -13,91 +13,34 @@ CUSTOM_CVAR(Bool, vk_hdr, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITC void I_GetVulkanDrawableSize(int *width, int *height); VulkanSwapChain::VulkanSwapChain(VulkanDevice *device) : vsync(vid_vsync), device(device) +{ + try + { + SelectFormat(); + SelectPresentMode(); + CreateSwapChain(); + GetImages(); + CreateViews(); + // SetHdrMetadata(); // This isn't required it seems + } + catch (...) + { + ReleaseResources(); + throw; + } +} + +VulkanSwapChain::~VulkanSwapChain() +{ + ReleaseResources(); +} + +void VulkanSwapChain::CreateSwapChain() { int width, height; I_GetVulkanDrawableSize(&width, &height); - VkSurfaceCapabilitiesKHR surfaceCapabilities; - VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->surface, &surfaceCapabilities); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); - - uint32_t surfaceFormatCount = 0; - result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, nullptr); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); - else if (surfaceFormatCount == 0) - throw std::runtime_error("No surface formats supported"); - - std::vector surfaceFormats(surfaceFormatCount); - result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, surfaceFormats.data()); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); - - uint32_t presentModeCount = 0; - vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, nullptr); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); - else if (presentModeCount == 0) - throw std::runtime_error("No surface present modes supported"); - - std::vector presentModes(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, presentModes.data()); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); - - if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED) - { - swapChainFormat.format = VK_FORMAT_B8G8R8A8_UNORM; - swapChainFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; - } - else - { - swapChainFormat = surfaceFormats.front(); - - bool found = false; - if (vk_hdr) - { - for (const auto &format : surfaceFormats) - { - if (format.format == VK_FORMAT_R16G16B16A16_SFLOAT && format.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) - { - swapChainFormat = format; - found = true; - break; - } - } - } - - if (!found) - { - for (const auto &format : surfaceFormats) - { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - swapChainFormat = format; - break; - } - } - } - } - - VkPresentModeKHR swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - if (vsync) - { - bool supportsFifoRelaxed = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != presentModes.end(); - if (supportsFifoRelaxed) - swapChainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; - } - else - { - bool supportsMailbox = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != presentModes.end(); - bool supportsImmediate = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end(); - if (supportsMailbox) - swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; - else if (supportsImmediate) - swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; - } + VkSurfaceCapabilitiesKHR surfaceCapabilities = GetSurfaceCapabilities(); actualExtent = { static_cast(width), static_cast(height) }; actualExtent.width = std::max(surfaceCapabilities.minImageExtent.width, std::min(surfaceCapabilities.maxImageExtent.width, actualExtent.width)); @@ -139,87 +82,191 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device) : vsync(vid_vsync), devic swapChainCreateInfo.clipped = VK_TRUE; swapChainCreateInfo.oldSwapchain = VK_NULL_HANDLE; - result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain); + VkResult result = vkCreateSwapchainKHR(device->device, &swapChainCreateInfo, nullptr, &swapChain); if (result != VK_SUCCESS) throw std::runtime_error("Could not create vulkan swapchain"); +} - try +void VulkanSwapChain::CreateViews() +{ + swapChainImageViews.reserve(swapChainImages.size()); + for (size_t i = 0; i < swapChainImages.size(); i++) { - result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, nullptr); + device->SetDebugObjectName("SwapChainImage", (uint64_t)swapChainImages[i], VK_OBJECT_TYPE_IMAGE); + + VkImageViewCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + createInfo.image = swapChainImages[i]; + createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + createInfo.format = swapChainFormat.format; + createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + createInfo.subresourceRange.baseMipLevel = 0; + createInfo.subresourceRange.levelCount = 1; + createInfo.subresourceRange.baseArrayLayer = 0; + createInfo.subresourceRange.layerCount = 1; + + VkImageView view; + VkResult result = vkCreateImageView(device->device, &createInfo, nullptr, &view); if (result != VK_SUCCESS) - throw std::runtime_error("vkGetSwapchainImagesKHR failed"); + throw std::runtime_error("Could not create image view for swapchain image"); - swapChainImages.resize(imageCount); - result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, swapChainImages.data()); - if (result != VK_SUCCESS) - throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)"); + device->SetDebugObjectName("SwapChainImageView", (uint64_t)view, VK_OBJECT_TYPE_IMAGE_VIEW); - swapChainImageViews.resize(swapChainImages.size()); - for (size_t i = 0; i < swapChainImages.size(); i++) - { - device->SetDebugObjectName("SwapChainImage", (uint64_t)swapChainImages[i], VK_OBJECT_TYPE_IMAGE); - - VkImageViewCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = swapChainImages[i]; - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = swapChainFormat.format; - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - result = vkCreateImageView(device->device, &createInfo, nullptr, &swapChainImageViews[i]); - if (result != VK_SUCCESS) - throw std::runtime_error("Could not create image view for swapchain image"); - - device->SetDebugObjectName("SwapChainImageView", (uint64_t)swapChainImageViews[i], VK_OBJECT_TYPE_IMAGE_VIEW); - } - -#if 0 // This isn't required it seems - if (swapChainFormat.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) - { - // Mastering display with HDR10_ST2084 color primaries and D65 white point, - // maximum luminance of 1000 nits and minimum luminance of 0.001 nits; - // content has maximum luminance of 2000 nits and maximum frame average light level (MaxFALL) of 500 nits. - - VkHdrMetadataEXT metadata = {}; - metadata.sType = VK_STRUCTURE_TYPE_HDR_METADATA_EXT; - metadata.displayPrimaryRed.x = 0.708f; - metadata.displayPrimaryRed.y = 0.292f; - metadata.displayPrimaryGreen.x = 0.170f; - metadata.displayPrimaryGreen.y = 0.797f; - metadata.displayPrimaryBlue.x = 0.131f; - metadata.displayPrimaryBlue.y = 0.046f; - metadata.whitePoint.x = 0.3127f; - metadata.whitePoint.y = 0.3290f; - metadata.maxLuminance = 1000.0f; - metadata.minLuminance = 0.001f; - metadata.maxContentLightLevel = 2000.0f; - metadata.maxFrameAverageLightLevel = 500.0f; - - vkSetHdrMetadataEXT(device->device, 1, &swapChain, &metadata); - } -#endif - } - catch (...) - { - for (auto &view : swapChainImageViews) - { - if (view) - vkDestroyImageView(device->device, view, nullptr); - } - vkDestroySwapchainKHR(device->device, swapChain, nullptr); - throw; + swapChainImageViews.push_back(view); } } -VulkanSwapChain::~VulkanSwapChain() +void VulkanSwapChain::SelectFormat() +{ + std::vector surfaceFormats = GetSurfaceFormats(); + if (surfaceFormats.empty()) + throw std::runtime_error("No surface formats supported"); + + if (surfaceFormats.size() == 1 && surfaceFormats.front().format == VK_FORMAT_UNDEFINED) + { + swapChainFormat.format = VK_FORMAT_B8G8R8A8_UNORM; + swapChainFormat.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR; + return; + } + + if (vk_hdr) + { + for (const auto &format : surfaceFormats) + { + if (format.format == VK_FORMAT_R16G16B16A16_SFLOAT && format.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) + { + swapChainFormat = format; + return; + } + } + } + + for (const auto &format : surfaceFormats) + { + if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + { + swapChainFormat = format; + return; + } + } + + swapChainFormat = surfaceFormats.front(); +} + +void VulkanSwapChain::SelectPresentMode() +{ + std::vector presentModes = GetPresentModes(); + + if (presentModes.empty()) + throw std::runtime_error("No surface present modes supported"); + + swapChainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + if (vsync) + { + bool supportsFifoRelaxed = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_FIFO_RELAXED_KHR) != presentModes.end(); + if (supportsFifoRelaxed) + swapChainPresentMode = VK_PRESENT_MODE_FIFO_RELAXED_KHR; + } + else + { + bool supportsMailbox = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != presentModes.end(); + bool supportsImmediate = std::find(presentModes.begin(), presentModes.end(), VK_PRESENT_MODE_IMMEDIATE_KHR) != presentModes.end(); + if (supportsMailbox) + swapChainPresentMode = VK_PRESENT_MODE_MAILBOX_KHR; + else if (supportsImmediate) + swapChainPresentMode = VK_PRESENT_MODE_IMMEDIATE_KHR; + } +} + +void VulkanSwapChain::SetHdrMetadata() +{ + if (swapChainFormat.colorSpace != VK_COLOR_SPACE_HDR10_ST2084_EXT) + return; + + // Mastering display with HDR10_ST2084 color primaries and D65 white point, + // maximum luminance of 1000 nits and minimum luminance of 0.001 nits; + // content has maximum luminance of 2000 nits and maximum frame average light level (MaxFALL) of 500 nits. + + VkHdrMetadataEXT metadata = {}; + metadata.sType = VK_STRUCTURE_TYPE_HDR_METADATA_EXT; + metadata.displayPrimaryRed.x = 0.708f; + metadata.displayPrimaryRed.y = 0.292f; + metadata.displayPrimaryGreen.x = 0.170f; + metadata.displayPrimaryGreen.y = 0.797f; + metadata.displayPrimaryBlue.x = 0.131f; + metadata.displayPrimaryBlue.y = 0.046f; + metadata.whitePoint.x = 0.3127f; + metadata.whitePoint.y = 0.3290f; + metadata.maxLuminance = 1000.0f; + metadata.minLuminance = 0.001f; + metadata.maxContentLightLevel = 2000.0f; + metadata.maxFrameAverageLightLevel = 500.0f; + + vkSetHdrMetadataEXT(device->device, 1, &swapChain, &metadata); +} + +void VulkanSwapChain::GetImages() +{ + uint32_t imageCount; + VkResult result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, nullptr); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetSwapchainImagesKHR failed"); + + swapChainImages.resize(imageCount); + result = vkGetSwapchainImagesKHR(device->device, swapChain, &imageCount, swapChainImages.data()); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetSwapchainImagesKHR failed (2)"); +} + +void VulkanSwapChain::ReleaseResources() { for (auto &view : swapChainImageViews) { - if (view) - vkDestroyImageView(device->device, view, nullptr); + vkDestroyImageView(device->device, view, nullptr); } - vkDestroySwapchainKHR(device->device, swapChain, nullptr); + swapChainImageViews.clear(); + + if (swapChain) + vkDestroySwapchainKHR(device->device, swapChain, nullptr); +} + +VkSurfaceCapabilitiesKHR VulkanSwapChain::GetSurfaceCapabilities() +{ + VkSurfaceCapabilitiesKHR surfaceCapabilities; + VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device->PhysicalDevice.Device, device->surface, &surfaceCapabilities); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed"); + return surfaceCapabilities; +} + +std::vector VulkanSwapChain::GetSurfaceFormats() +{ + uint32_t surfaceFormatCount = 0; + VkResult result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, nullptr); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + else if (surfaceFormatCount == 0) + return {}; + + std::vector surfaceFormats(surfaceFormatCount); + result = vkGetPhysicalDeviceSurfaceFormatsKHR(device->PhysicalDevice.Device, device->surface, &surfaceFormatCount, surfaceFormats.data()); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetPhysicalDeviceSurfaceFormatsKHR failed"); + return surfaceFormats; +} + +std::vector VulkanSwapChain::GetPresentModes() +{ + uint32_t presentModeCount = 0; + VkResult result = vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, nullptr); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + else if (presentModeCount == 0) + return {}; + + std::vector presentModes(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, presentModes.data()); + if (result != VK_SUCCESS) + throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed"); + return presentModes; } diff --git a/src/rendering/vulkan/system/vk_swapchain.h b/src/rendering/vulkan/system/vk_swapchain.h index ef33054221..ce515c13e3 100644 --- a/src/rendering/vulkan/system/vk_swapchain.h +++ b/src/rendering/vulkan/system/vk_swapchain.h @@ -9,8 +9,9 @@ public: ~VulkanSwapChain(); bool vsync; - VkSwapchainKHR swapChain; + VkSwapchainKHR swapChain = VK_NULL_HANDLE; VkSurfaceFormatKHR swapChainFormat; + VkPresentModeKHR swapChainPresentMode; std::vector swapChainImages; std::vector swapChainImageViews; @@ -18,6 +19,18 @@ public: VkExtent2D actualExtent; private: + void SelectFormat(); + void SelectPresentMode(); + void CreateSwapChain(); + void CreateViews(); + void SetHdrMetadata(); + void GetImages(); + void ReleaseResources(); + + VkSurfaceCapabilitiesKHR GetSurfaceCapabilities(); + std::vector GetSurfaceFormats(); + std::vector GetPresentModes(); + VulkanDevice *device = nullptr; VulkanSwapChain(const VulkanSwapChain &) = delete;