浏览代码

Vulkan: Fix HDR crash (#18928)

* Fix VK HDR

Signed-off-by: Reece Hagan <[email protected]>

* Add CVar to control HDR.

Signed-off-by: Reece Hagan <[email protected]>

* Dont use designated initializers

Signed-off-by: Reece Hagan <[email protected]>

* Check for 10 bit instead of ext

Signed-off-by: Reece Hagan <[email protected]>

* Remove check for ext in BuildNativeSwapChain.

Vulkan Device already ensures us when we get the 10 bit format that the needed extensions exist.

Signed-off-by: Reece Hagan <[email protected]>

* Fix improper check for format in GetSupportedSurfaceFormat

Signed-off-by: Reece Hagan <[email protected]>

---------

Signed-off-by: Reece Hagan <[email protected]>
Reece Hagan 3 月之前
父节点
当前提交
6bfdbb302e

+ 3 - 0
Gems/Atom/RHI/Code/Include/Atom/RHI/DeviceSwapChain.h

@@ -11,6 +11,9 @@
 #include <Atom/RHI/DeviceImagePoolBase.h>
 #include <Atom/RHI/XRRenderingInterface.h>
 
+#include <AzCore/Console/IConsole.h>
+AZ_CVAR_EXTERNED(bool, r_hdrOutput);
+
 namespace AZ::RHI
 {
     //! The platform-independent swap chain base class. Swap chains contain a "chain" of images which

+ 3 - 0
Gems/Atom/RHI/Code/Source/RHI/DeviceSwapChain.cpp

@@ -9,6 +9,9 @@
 #include <Atom/RHI/Factory.h>
 #include <Atom/RHI/MemoryStatisticsBuilder.h>
 #include <Atom/RHI/RHISystemInterface.h>
+
+AZ_CVAR(bool, r_hdrOutput, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Enable HDR output. Restart required");
+
 namespace AZ::RHI
 {
     DeviceSwapChain::DeviceSwapChain() {}

+ 14 - 1
Gems/Atom/RHI/Vulkan/Code/Source/RHI/Device.cpp

@@ -925,13 +925,26 @@ namespace AZ
             AssertSuccess(GetContext().GetPhysicalDeviceSurfaceFormatsKHR(
                 physicalDevice.GetNativePhysicalDevice(), vkSurface, &surfaceFormatCount, surfaceFormats.data()));
 
+            bool colorSpaceExt = false;
+            if (r_hdrOutput)
+            {
+                for (const char* loaded_extension : Instance::GetInstance().GetLoadedExtensions())
+                {
+                    if (strcmp(loaded_extension, VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME) == 0)
+                    {
+                        colorSpaceExt = true;
+                        break;
+                    }
+                }
+            }
+
             AZStd::set<RHI::Format> formats;
             for (const VkSurfaceFormatKHR& surfaceFormat : surfaceFormats)
             {
                 // Don't expose formats for HDR output when the extension is missing
                 // This can happen on Linux with Wayland.
                 if (surfaceFormat.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32 &&
-                    m_loaderContext->GetContext().SetHdrMetadataEXT == nullptr)
+                    (m_loaderContext->GetContext().SetHdrMetadataEXT == nullptr || colorSpaceExt == false))
                 {
                     continue;
                 }

+ 1 - 0
Gems/Atom/RHI/Vulkan/Code/Source/RHI/Instance.cpp

@@ -81,6 +81,7 @@ namespace AZ
             m_descriptor.m_optionalExtensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
 #endif
             m_descriptor.m_optionalExtensions.push_back(VK_EXT_HDR_METADATA_EXTENSION_NAME);
+            m_descriptor.m_optionalExtensions.push_back(VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME);
 
             uint32_t appApiVersion = VK_API_VERSION_1_0;
             m_instanceVersion = VK_API_VERSION_1_0;

+ 29 - 9
Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.cpp

@@ -7,6 +7,8 @@
  */
 
 #include "Atom_RHI_Vulkan_Platform.h"
+#include "Instance.h"
+
 #include <Atom/RHI/PipelineStateDescriptor.h>
 #include <Atom/RHI/RHISystemInterface.h>
 #include <Atom/RHI/XRRenderingInterface.h>
@@ -387,7 +389,7 @@ namespace AZ
             }
 
             const DisplayChromacities& Chroma = DisplayChromacityList[selectedChroma];
-            VkHdrMetadataEXT hdrMetadata;
+            VkHdrMetadataEXT hdrMetadata = {};
             hdrMetadata.sType = VK_STRUCTURE_TYPE_HDR_METADATA_EXT;
             //DX12 RHI scales these by 50000 but VKD3D removes that so just use the raw values.
             hdrMetadata.displayPrimaryRed = {Chroma.RedX, Chroma.RedY};
@@ -426,7 +428,7 @@ namespace AZ
                 dimensions.m_imageHeight <= m_surfaceCapabilities.maxImageExtent.height);
         }
 
-        VkSurfaceFormatKHR SwapChain::GetSupportedSurfaceFormat(const RHI::Format rhiFormat) const
+        VkSurfaceFormatKHR SwapChain::GetSupportedSurfaceFormat(const RHI::Format rhiFormat, const VkColorSpaceKHR preferredColorSpace) const
         {
             AZ_Assert(m_surface, "Surface has not been initialized.");
             auto& device = static_cast<Device&>(GetDevice());
@@ -440,13 +442,27 @@ namespace AZ
                 physicalDevice.GetNativePhysicalDevice(), m_surface->GetNativeSurface(), &surfaceFormatCount, surfaceFormats.data()));
 
             const VkFormat format = ConvertFormat(rhiFormat);
+            VkSurfaceFormatKHR matchedFormat = {};
+            matchedFormat.format = VK_FORMAT_UNDEFINED;
             for (uint32_t index = 0; index < surfaceFormatCount; ++index)
             {
                 if (surfaceFormats[index].format == format)
                 {
-                    return surfaceFormats[index];
+                    if (surfaceFormats[index].colorSpace == preferredColorSpace)
+                    {
+                        return surfaceFormats[index];
+                    }
+
+                    if (matchedFormat.format == VK_FORMAT_UNDEFINED)
+                    {
+                        matchedFormat = surfaceFormats[index];
+                    }
                 }
             }
+            if (matchedFormat.format != VK_FORMAT_UNDEFINED)
+            {
+                return matchedFormat;
+            }
             AZ_Warning("Vulkan", false, "Given format is not supported, so it uses a supported format.");
             return surfaceFormats[0];
         }
@@ -557,13 +573,11 @@ namespace AZ
                 }
             }
 
-            VkColorSpaceKHR colorSpace = m_surfaceFormat.colorSpace;
             bool hdrEnabled = false;
 
-            if(device.GetContext().SetHdrMetadataEXT != nullptr &&
-                dimensions.m_imageFormat == RHI::Format::R10G10B10A2_UNORM)
+            if (m_surfaceFormat.format == VK_FORMAT_A2R10G10B10_UNORM_PACK32 &&
+                m_surfaceFormat.colorSpace == VK_COLOR_SPACE_HDR10_ST2084_EXT)
             {
-                colorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT;
                 hdrEnabled = true;
             }
 
@@ -576,7 +590,7 @@ namespace AZ
             // need to be less than or equal to the difference between the number of images in swapchain and the value of VkSurfaceCapabilitiesKHR::minImageCount
             createInfo.minImageCount = AZStd::max(dimensions.m_imageCount, simultaneousAcquiredImages + m_surfaceCapabilities.minImageCount);
             createInfo.imageFormat = m_surfaceFormat.format;
-            createInfo.imageColorSpace = colorSpace;
+            createInfo.imageColorSpace = m_surfaceFormat.colorSpace;
             createInfo.imageExtent = extent;
             createInfo.imageArrayLayers = 1; // non-stereoscopic
             createInfo.imageUsage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
@@ -663,8 +677,14 @@ namespace AZ
         {
             auto& device = static_cast<Device&>(GetDevice());
 
+            VkColorSpaceKHR preferredColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
+            if (r_hdrOutput && m_dimensions.m_imageFormat == RHI::Format::R10G10B10A2_UNORM)
+            {
+                preferredColorSpace = VK_COLOR_SPACE_HDR10_ST2084_EXT;
+            }
+
             m_surfaceCapabilities = GetSurfaceCapabilities();
-            m_surfaceFormat = GetSupportedSurfaceFormat(m_dimensions.m_imageFormat);
+            m_surfaceFormat = GetSupportedSurfaceFormat(m_dimensions.m_imageFormat, preferredColorSpace);
             m_presentMode = GetSupportedPresentMode(GetDescriptor().m_verticalSyncInterval);
             m_compositeAlphaFlagBits = GetSupportedCompositeAlpha();
 

+ 1 - 1
Gems/Atom/RHI/Vulkan/Code/Source/RHI/SwapChain.h

@@ -78,7 +78,7 @@ namespace AZ
             bool ValidateSurfaceDimensions(const RHI::SwapChainDimensions& dimensions);
             //! Returns the corresponding Vulkan format that is supported by the surface.
             //! If such format is not found, return the first supported format from the surface.
-            VkSurfaceFormatKHR GetSupportedSurfaceFormat(const RHI::Format format) const;
+            VkSurfaceFormatKHR GetSupportedSurfaceFormat(const RHI::Format format, const VkColorSpaceKHR preferredColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) const;
             //! Returns the correct presentation mode.
             //! If verticalSyncInterval is non-zero, returns VK_PRESENT_MODE_FIFO_KHR.
             //! Otherwise, choose preferred mode if they are supported.