- clean up swapchain class

This commit is contained in:
Magnus Norddahl 2019-04-08 18:14:07 +02:00
parent b0bd8f800c
commit 20fde9f8be
2 changed files with 211 additions and 151 deletions

View file

@ -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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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<uint32_t>(width), static_cast<uint32_t>(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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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<VkSurfaceFormatKHR> 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<VkSurfaceFormatKHR> 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<VkPresentModeKHR> 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<VkPresentModeKHR> presentModes(presentModeCount);
vkGetPhysicalDeviceSurfacePresentModesKHR(device->PhysicalDevice.Device, device->surface, &presentModeCount, presentModes.data());
if (result != VK_SUCCESS)
throw std::runtime_error("vkGetPhysicalDeviceSurfacePresentModesKHR failed");
return presentModes;
}

View file

@ -9,8 +9,9 @@ public:
~VulkanSwapChain();
bool vsync;
VkSwapchainKHR swapChain;
VkSwapchainKHR swapChain = VK_NULL_HANDLE;
VkSurfaceFormatKHR swapChainFormat;
VkPresentModeKHR swapChainPresentMode;
std::vector<VkImage> swapChainImages;
std::vector<VkImageView> 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<VkSurfaceFormatKHR> GetSurfaceFormats();
std::vector<VkPresentModeKHR> GetPresentModes();
VulkanDevice *device = nullptr;
VulkanSwapChain(const VulkanSwapChain &) = delete;