mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +00:00
- clean up swapchain class
This commit is contained in:
parent
b0bd8f800c
commit
20fde9f8be
2 changed files with 211 additions and 151 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue