From 2d885d4e4c82e1d2d917912436e93ad5a63bcb3e Mon Sep 17 00:00:00 2001 From: Magnus Norddahl <dpjudas@users.noreply.github.com> Date: Thu, 14 Mar 2019 00:21:53 +0100 Subject: [PATCH] - add some support for using the HDR10 ST2084 color space on monitors that support it (unfortunately it doesn't work, and with virtually no documentation either from nvidia or khronos it is hard to say why) --- src/rendering/vulkan/system/vk_device.cpp | 24 ++++++++ src/rendering/vulkan/system/vk_device.h | 2 + src/rendering/vulkan/system/vk_swapchain.cpp | 59 ++++++++++++++++++-- 3 files changed, 80 insertions(+), 5 deletions(-) diff --git a/src/rendering/vulkan/system/vk_device.cpp b/src/rendering/vulkan/system/vk_device.cpp index a8b54ed48..57877ac0a 100644 --- a/src/rendering/vulkan/system/vk_device.cpp +++ b/src/rendering/vulkan/system/vk_device.cpp @@ -184,6 +184,18 @@ void VulkanDevice::SelectPhysicalDevice() if (selected >= SupportedDevices.size()) selected = 0; + // Enable optional extensions we are interested in, if they are available on this device + for (const auto &ext : SupportedDevices[selected].device->Extensions) + { + for (const auto &opt : OptionalDeviceExtensions) + { + if (strcmp(ext.extensionName, opt) == 0) + { + EnabledDeviceExtensions.push_back(opt); + } + } + } + PhysicalDevice = *SupportedDevices[selected].device; graphicsFamily = SupportedDevices[selected].graphicsFamily; presentFamily = SupportedDevices[selected].presentFamily; @@ -313,6 +325,18 @@ void VulkanDevice::CreateInstance() } } + // Enable optional instance extensions we are interested in + for (const auto &ext : Extensions) + { + for (const auto &opt : OptionalExtensions) + { + if (strcmp(ext.extensionName, opt) == 0) + { + EnabledExtensions.push_back(opt); + } + } + } + VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pApplicationName = "GZDoom"; diff --git a/src/rendering/vulkan/system/vk_device.h b/src/rendering/vulkan/system/vk_device.h index 9432c700a..9f880d33e 100644 --- a/src/rendering/vulkan/system/vk_device.h +++ b/src/rendering/vulkan/system/vk_device.h @@ -62,11 +62,13 @@ public: std::vector<VkLayerProperties> AvailableLayers; std::vector<VkExtensionProperties> Extensions; std::vector<const char *> EnabledExtensions; + std::vector<const char *> OptionalExtensions = { VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME }; std::vector<const char*> EnabledValidationLayers; // Device setup VkPhysicalDeviceFeatures UsedDeviceFeatures = {}; std::vector<const char *> EnabledDeviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + std::vector<const char *> OptionalDeviceExtensions = { VK_EXT_HDR_METADATA_EXTENSION_NAME }; VulkanPhysicalDevice PhysicalDevice; bool DebugLayerActive = false; diff --git a/src/rendering/vulkan/system/vk_swapchain.cpp b/src/rendering/vulkan/system/vk_swapchain.cpp index 4bd46d8f1..1b10cfdc9 100644 --- a/src/rendering/vulkan/system/vk_swapchain.cpp +++ b/src/rendering/vulkan/system/vk_swapchain.cpp @@ -1,5 +1,12 @@ #include "vk_swapchain.h" +#include "c_cvars.h" +#include "version.h" + +CUSTOM_CVAR(Bool, vk_hdr, false, /*CVAR_ARCHIVE | CVAR_GLOBALCONFIG |*/ CVAR_NOINITCALL) +{ + Printf("This won't take effect until " GAMENAME " is restarted.\n"); +} VulkanSwapChain::VulkanSwapChain(VulkanDevice *device, int width, int height, bool vsync) : vsync(vsync), device(device) { @@ -40,12 +47,30 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device, int width, int height, bo else { swapChainFormat = surfaceFormats.front(); - for (const auto &format : surfaceFormats) + + bool found = false; + if (vk_hdr) { - if (format.format == VK_FORMAT_B8G8R8A8_UNORM && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) + for (const auto &format : surfaceFormats) { - swapChainFormat = format; - break; + 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; + } } } } @@ -85,7 +110,7 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device, int width, int height, bo swapChainCreateInfo.imageColorSpace = swapChainFormat.colorSpace; swapChainCreateInfo.imageExtent = actualExtent; swapChainCreateInfo.imageArrayLayers = 1; - swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT; + swapChainCreateInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; uint32_t queueFamilyIndices[] = { (uint32_t)device->graphicsFamily, (uint32_t)device->presentFamily }; if (device->graphicsFamily != device->presentFamily) @@ -143,6 +168,30 @@ VulkanSwapChain::VulkanSwapChain(VulkanDevice *device, int width, int height, bo device->SetDebugObjectName("SwapChainImageView", (uint64_t)swapChainImageViews[i], VK_OBJECT_TYPE_IMAGE_VIEW); } + + if (swapChainFormat.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT) + { + // Mastering display with DCI-P3 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.680f; + metadata.displayPrimaryRed.y = 0.320f; + metadata.displayPrimaryGreen.x = 0.265f; + metadata.displayPrimaryGreen.y = 0.690f; + metadata.displayPrimaryBlue.x = 0.150f; + metadata.displayPrimaryBlue.y = 0.060f; + 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); + } } catch (...) {