Răsfoiți Sursa

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 <gab.dark.100@gmail.com>

* 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 <gab.dark.100@gmail.com>
cstamford 2 ani în urmă
părinte
comite
dc0dbc50ab

+ 3 - 0
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;

+ 1 - 1
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";

+ 2 - 0
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;
+
         /// <summary>
         /// Converts a packed Maxwell texture format to the shader translator texture format.
         /// </summary>

+ 1 - 0
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,

+ 9 - 0
src/Ryujinx.Graphics.Shader/IGpuAccessor.cs

@@ -367,6 +367,15 @@ namespace Ryujinx.Graphics.Shader
             return true;
         }
 
+        /// <summary>
+        /// Queries whether the host supports depth clip control.
+        /// </summary>
+        /// <returns>True if the GPU and driver supports depth clip control, false otherwise</returns>
+        bool QueryHostSupportsDepthClipControl()
+        {
+            return true;
+        }
+
         /// <summary>
         /// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
         /// </summary>

+ 2 - 2
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)));

+ 3 - 0
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;

+ 6 - 2
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)

+ 18 - 0
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<PipelineShaderStageCreateInfo> Stages;
         public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
         public PipelineLayout PipelineLayout;
@@ -331,6 +337,7 @@ namespace Ryujinx.Graphics.Vulkan
 
             LineWidth = 1f;
             SamplesCount = 1;
+            DepthMode = true;
         }
 
         public unsafe Auto<DisposablePipeline> 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,

+ 27 - 0
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];

+ 15 - 0
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,