From dc0dbc50abdaedfdcca05e5a5c1a5f26f70e3b79 Mon Sep 17 00:00:00 2001 From: cstamford Date: Sun, 28 May 2023 22:31:56 +0100 Subject: [PATCH] Add support for VK_EXT_depth_clip_control. (#5027) * Add support for VK_EXT_depth_clip_control. * Code review feedback Minor formatting Co-authored-by: gdkchan * Check .DepthClipControl to make sure the host actually supports the feature. * Review feedback: remove Vulkan platform switch, relying on QueryHostSupportsDepthClipControl to drive the behaviour - OpenGL returns true, and any future platforms that don't support the [-1, 1] depth mode can return false for the transformation. --------- Co-authored-by: gdkchan --- src/Ryujinx.Graphics.GAL/Capabilities.cs | 3 +++ .../Shader/DiskCache/DiskCacheHostStorage.cs | 2 +- .../Shader/GpuAccessorBase.cs | 2 ++ src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs | 1 + src/Ryujinx.Graphics.Shader/IGpuAccessor.cs | 9 +++++++ .../Translation/EmitterContext.cs | 4 +-- .../HardwareCapabilities.cs | 3 +++ src/Ryujinx.Graphics.Vulkan/PipelineBase.cs | 8 ++++-- src/Ryujinx.Graphics.Vulkan/PipelineState.cs | 18 +++++++++++++ .../VulkanInitialization.cs | 27 +++++++++++++++++++ src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs | 15 +++++++++++ 11 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs index a93d384667..48b37d35d4 100644 --- a/src/Ryujinx.Graphics.GAL/Capabilities.cs +++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs @@ -39,6 +39,7 @@ namespace Ryujinx.Graphics.GAL public readonly bool SupportsViewportMask; public readonly bool SupportsViewportSwizzle; public readonly bool SupportsIndirectParameters; + public readonly bool SupportsDepthClipControl; public readonly uint MaximumUniformBuffersPerStage; public readonly uint MaximumStorageBuffersPerStage; @@ -85,6 +86,7 @@ namespace Ryujinx.Graphics.GAL bool supportsViewportMask, bool supportsViewportSwizzle, bool supportsIndirectParameters, + bool supportsDepthClipControl, uint maximumUniformBuffersPerStage, uint maximumStorageBuffersPerStage, uint maximumTexturesPerStage, @@ -127,6 +129,7 @@ namespace Ryujinx.Graphics.GAL SupportsViewportMask = supportsViewportMask; SupportsViewportSwizzle = supportsViewportSwizzle; SupportsIndirectParameters = supportsIndirectParameters; + SupportsDepthClipControl = supportsDepthClipControl; MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage; MaximumStorageBuffersPerStage = maximumStorageBuffersPerStage; MaximumTexturesPerStage = maximumTexturesPerStage; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs index e2346bd0b8..7f83f58800 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs @@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache private const ushort FileFormatVersionMajor = 1; private const ushort FileFormatVersionMinor = 2; private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor; - private const uint CodeGenVersion = 5110; + private const uint CodeGenVersion = 5027; private const string SharedTocFileName = "shared.toc"; private const string SharedDataFileName = "shared.data"; diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs index e4e1e0d611..d206aad0b8 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs @@ -165,6 +165,8 @@ namespace Ryujinx.Graphics.Gpu.Shader public bool QueryHostSupportsViewportMask() => _context.Capabilities.SupportsViewportMask; + public bool QueryHostSupportsDepthClipControl() => _context.Capabilities.SupportsDepthClipControl; + /// /// Converts a packed Maxwell texture format to the shader translator texture format. /// diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs index 7d5fe8931b..161191b854 100644 --- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs +++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs @@ -163,6 +163,7 @@ namespace Ryujinx.Graphics.OpenGL supportsViewportMask: HwCapabilities.SupportsViewportArray2, supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle, supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters, + supportsDepthClipControl: true, maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver? maximumStorageBuffersPerStage: 16, maximumTexturesPerStage: 32, diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs index 2207156cdb..3be5088e45 100644 --- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs +++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs @@ -367,6 +367,15 @@ namespace Ryujinx.Graphics.Shader return true; } + /// + /// Queries whether the host supports depth clip control. + /// + /// True if the GPU and driver supports depth clip control, false otherwise + bool QueryHostSupportsDepthClipControl() + { + return true; + } + /// /// Queries the point size from the GPU state, used when it is not explicitly set on the shader. /// diff --git a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index 2786caaa0a..6ca74a379a 100644 --- a/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/src/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -246,7 +246,7 @@ namespace Ryujinx.Graphics.Shader.Translation this.Store(StorageKind.Output, IoVariable.Position, null, Const(1), this.FPFusedMultiplyAdd(y, yScale, negativeOne)); } - if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne()) + if (Config.GpuAccessor.QueryTransformDepthMinusOneToOne() && !Config.GpuAccessor.QueryHostSupportsDepthClipControl()) { Operand z = this.Load(StorageKind.Output, IoVariable.Position, null, Const(2)); Operand w = this.Load(StorageKind.Output, IoVariable.Position, null, Const(3)); @@ -283,7 +283,7 @@ namespace Ryujinx.Graphics.Shader.Translation oldYLocal = null; } - if (Config.Options.TargetApi == TargetApi.Vulkan && Config.GpuAccessor.QueryTransformDepthMinusOneToOne()) + if (Config.GpuAccessor.QueryTransformDepthMinusOneToOne() && !Config.GpuAccessor.QueryHostSupportsDepthClipControl()) { oldZLocal = Local(); this.Copy(oldZLocal, this.Load(StorageKind.Output, IoVariable.Position, null, Const(2))); diff --git a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs index 4b9ace3aa3..f600d93f00 100644 --- a/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/HardwareCapabilities.cs @@ -43,6 +43,7 @@ namespace Ryujinx.Graphics.Vulkan public readonly bool SupportsGeometryShader; public readonly bool SupportsViewportArray2; public readonly bool SupportsHostImportedMemory; + public readonly bool SupportsDepthClipControl; public readonly uint MinSubgroupSize; public readonly uint MaxSubgroupSize; public readonly ShaderStageFlags RequiredSubgroupSizeStages; @@ -79,6 +80,7 @@ namespace Ryujinx.Graphics.Vulkan bool supportsGeometryShader, bool supportsViewportArray2, bool supportsHostImportedMemory, + bool supportsDepthClipControl, uint minSubgroupSize, uint maxSubgroupSize, ShaderStageFlags requiredSubgroupSizeStages, @@ -114,6 +116,7 @@ namespace Ryujinx.Graphics.Vulkan SupportsGeometryShader = supportsGeometryShader; SupportsViewportArray2 = supportsViewportArray2; SupportsHostImportedMemory = supportsHostImportedMemory; + SupportsDepthClipControl = supportsDepthClipControl; MinSubgroupSize = minSubgroupSize; MaxSubgroupSize = maxSubgroupSize; RequiredSubgroupSizeStages = requiredSubgroupSizeStages; diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs index ce6148e2f7..b4eccfbb22 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineBase.cs @@ -813,8 +813,12 @@ namespace Ryujinx.Graphics.Vulkan public void SetDepthMode(DepthMode mode) { - // Currently this is emulated on the shader, because Vulkan had no support for changing the depth mode. - // In the future, we may want to use the VK_EXT_depth_clip_control extension to change it here. + bool oldMode = _newState.DepthMode; + _newState.DepthMode = mode == DepthMode.MinusOneToOne; + if (_newState.DepthMode != oldMode) + { + SignalStateChange(); + } } public void SetDepthTest(DepthTestDescriptor depthTest) diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs index a3d8dd6fbe..aff3f13f01 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineState.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineState.cs @@ -304,6 +304,12 @@ namespace Ryujinx.Graphics.Vulkan set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4); } + public bool DepthMode + { + get => ((Internal.Id9 >> 6) & 0x1) != 0UL; + set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6); + } + public NativeArray Stages; public NativeArray StageRequiredSubgroupSizes; public PipelineLayout PipelineLayout; @@ -331,6 +337,7 @@ namespace Ryujinx.Graphics.Vulkan LineWidth = 1f; SamplesCount = 1; + DepthMode = true; } public unsafe Auto CreateComputePipeline( @@ -482,6 +489,17 @@ namespace Ryujinx.Graphics.Vulkan PScissors = pScissors }; + if (gd.Capabilities.SupportsDepthClipControl) + { + var viewportDepthClipControlState = new PipelineViewportDepthClipControlCreateInfoEXT() + { + SType = StructureType.PipelineViewportDepthClipControlCreateInfoExt, + NegativeOneToOne = DepthMode + }; + + viewportState.PNext = &viewportDepthClipControlState; + } + var multisampleState = new PipelineMultisampleStateCreateInfo { SType = StructureType.PipelineMultisampleStateCreateInfo, diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs index 499a9ef78c..51a3b129ac 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanInitialization.cs @@ -41,6 +41,7 @@ namespace Ryujinx.Graphics.Vulkan "VK_EXT_subgroup_size_control", "VK_NV_geometry_shader_passthrough", "VK_NV_viewport_array2", + "VK_EXT_depth_clip_control", "VK_KHR_portability_subset" // As per spec, we should enable this if present. }; @@ -345,6 +346,17 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &supportedFeaturesRobustness2; } + PhysicalDeviceDepthClipControlFeaturesEXT supportedFeaturesDepthClipControl = new PhysicalDeviceDepthClipControlFeaturesEXT() + { + SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt, + PNext = features2.PNext + }; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_depth_clip_control")) + { + features2.PNext = &supportedFeaturesDepthClipControl; + } + api.GetPhysicalDeviceFeatures2(physicalDevice.PhysicalDevice, &features2); var supportedFeatures = features2.Features; @@ -507,6 +519,21 @@ namespace Ryujinx.Graphics.Vulkan pExtendedFeatures = &featuresCustomBorderColor; } + PhysicalDeviceDepthClipControlFeaturesEXT featuresDepthClipControl; + + if (physicalDevice.IsDeviceExtensionPresent("VK_EXT_depth_clip_control") && + supportedFeaturesDepthClipControl.DepthClipControl) + { + featuresDepthClipControl = new PhysicalDeviceDepthClipControlFeaturesEXT() + { + SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt, + PNext = pExtendedFeatures, + DepthClipControl = true + }; + + pExtendedFeatures = &featuresDepthClipControl; + } + var enabledExtensions = _requiredExtensions.Union(_desirableExtensions.Intersect(physicalDevice.DeviceExtensions)).ToArray(); IntPtr* ppEnabledExtensions = stackalloc IntPtr[enabledExtensions.Length]; diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 4f3f72345b..3987be9b47 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -216,6 +216,11 @@ namespace Ryujinx.Graphics.Vulkan SType = StructureType.PhysicalDeviceCustomBorderColorFeaturesExt }; + PhysicalDeviceDepthClipControlFeaturesEXT featuresDepthClipControl = new PhysicalDeviceDepthClipControlFeaturesEXT() + { + SType = StructureType.PhysicalDeviceDepthClipControlFeaturesExt + }; + PhysicalDevicePortabilitySubsetFeaturesKHR featuresPortabilitySubset = new PhysicalDevicePortabilitySubsetFeaturesKHR() { SType = StructureType.PhysicalDevicePortabilitySubsetFeaturesKhr @@ -244,6 +249,14 @@ namespace Ryujinx.Graphics.Vulkan features2.PNext = &featuresCustomBorderColor; } + bool supportsDepthClipControl = _physicalDevice.IsDeviceExtensionPresent("VK_EXT_depth_clip_control"); + + if (supportsDepthClipControl) + { + featuresDepthClipControl.PNext = features2.PNext; + features2.PNext = &featuresDepthClipControl; + } + bool usePortability = _physicalDevice.IsDeviceExtensionPresent("VK_KHR_portability_subset"); if (usePortability) @@ -310,6 +323,7 @@ namespace Ryujinx.Graphics.Vulkan _physicalDevice.PhysicalDeviceFeatures.GeometryShader, _physicalDevice.IsDeviceExtensionPresent("VK_NV_viewport_array2"), _physicalDevice.IsDeviceExtensionPresent(ExtExternalMemoryHost.ExtensionName), + supportsDepthClipControl && featuresDepthClipControl.DepthClipControl, propertiesSubgroupSizeControl.MinSubgroupSize, propertiesSubgroupSizeControl.MaxSubgroupSize, propertiesSubgroupSizeControl.RequiredSubgroupSizeStages, @@ -585,6 +599,7 @@ namespace Ryujinx.Graphics.Vulkan supportsViewportMask: Capabilities.SupportsViewportArray2, supportsViewportSwizzle: false, supportsIndirectParameters: true, + supportsDepthClipControl: Capabilities.SupportsDepthClipControl, maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage, maximumStorageBuffersPerStage: Constants.MaxStorageBuffersPerStage, maximumTexturesPerStage: Constants.MaxTexturesPerStage,