From 619ac86bd03fcafdcae19f8fc5ad7d90780c194b Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sat, 10 Sep 2022 10:20:23 -0300
Subject: [PATCH] Do not output ViewportIndex on SPIR-V if GPU does not support
 it (#3644)

* Do not output ViewportIndex on SPIR-V if GPU does not support it

* Bump shader cache version
---
 Ryujinx.Graphics.GAL/Capabilities.cs          |  3 +++
 .../Shader/DiskCache/DiskCacheHostStorage.cs  |  4 ++--
 .../Shader/GpuAccessorBase.cs                 |  2 ++
 Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs     |  1 +
 Ryujinx.Graphics.Shader/IGpuAccessor.cs       |  9 ++++++++
 .../Translation/AttributeInfo.cs              |  5 +++++
 Ryujinx.Graphics.Vulkan/VulkanRenderer.cs     | 21 +++++++++++++++----
 7 files changed, 39 insertions(+), 6 deletions(-)

diff --git a/Ryujinx.Graphics.GAL/Capabilities.cs b/Ryujinx.Graphics.GAL/Capabilities.cs
index 60f5f1f0d..3138a43b5 100644
--- a/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -26,6 +26,7 @@ namespace Ryujinx.Graphics.GAL
         public readonly bool SupportsNonConstantTextureOffset;
         public readonly bool SupportsShaderBallot;
         public readonly bool SupportsTextureShadowLod;
+        public readonly bool SupportsViewportIndex;
         public readonly bool SupportsViewportSwizzle;
         public readonly bool SupportsIndirectParameters;
 
@@ -59,6 +60,7 @@ namespace Ryujinx.Graphics.GAL
             bool supportsNonConstantTextureOffset,
             bool supportsShaderBallot,
             bool supportsTextureShadowLod,
+            bool supportsViewportIndex,
             bool supportsViewportSwizzle,
             bool supportsIndirectParameters,
             uint maximumUniformBuffersPerStage,
@@ -89,6 +91,7 @@ namespace Ryujinx.Graphics.GAL
             SupportsNonConstantTextureOffset = supportsNonConstantTextureOffset;
             SupportsShaderBallot = supportsShaderBallot;
             SupportsTextureShadowLod = supportsTextureShadowLod;
+            SupportsViewportIndex = supportsViewportIndex;
             SupportsViewportSwizzle = supportsViewportSwizzle;
             SupportsIndirectParameters = supportsIndirectParameters;
             MaximumUniformBuffersPerStage = maximumUniformBuffersPerStage;
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
index f020ec490..d257c1930 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/DiskCacheHostStorage.cs
+++ b/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 = 3672;
+        private const uint CodeGenVersion = 3644;
 
         private const string SharedTocFileName = "shared.toc";
         private const string SharedDataFileName = "shared.data";
@@ -827,4 +827,4 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
index a0c779b50..40c5ed64b 100644
--- a/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
@@ -134,6 +134,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
 
         public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
 
+        public bool QueryHostSupportsViewportIndex() => _context.Capabilities.SupportsViewportIndex;
+
         /// <summary>
         /// Converts a packed Maxwell texture format to the shader translator texture format.
         /// </summary>
diff --git a/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
index 4df81cef4..0b9acf10b 100644
--- a/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
+++ b/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
@@ -120,6 +120,7 @@ namespace Ryujinx.Graphics.OpenGL
                 supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
                 supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
                 supportsTextureShadowLod: HwCapabilities.SupportsTextureShadowLod,
+                supportsViewportIndex: true,
                 supportsViewportSwizzle: HwCapabilities.SupportsViewportSwizzle,
                 supportsIndirectParameters: HwCapabilities.SupportsIndirectParameters,
                 maximumUniformBuffersPerStage: 13, // TODO: Avoid hardcoding those limits here and get from driver?
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 7951e71b3..2cdc81fbc 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -267,6 +267,15 @@ namespace Ryujinx.Graphics.Shader
             return true;
         }
 
+        /// <summary>
+        /// Queries host GPU shader viewport index output support.
+        /// </summary>
+        /// <returns>True if the GPU and driver supports shader viewport index output, false otherwise</returns>
+        bool QueryHostSupportsViewportIndex()
+        {
+            return true;
+        }
+
         /// <summary>
         /// Queries the point size from the GPU state, used when it is not explicitly set on the shader.
         /// </summary>
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
index 2a97ee523..6680a3328 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
+++ b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
@@ -78,6 +78,11 @@ namespace Ryujinx.Graphics.Shader.Translation
 
         public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
         {
+            if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
+            {
+                return false;
+            }
+
             return From(config, value, isOutAttr).IsValid;
         }
 
diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index bacb74cc4..5abe1be15 100644
--- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
+++ b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
             return BufferManager.GetData(buffer, offset, size);
         }
 
-        public Capabilities GetCapabilities()
+        public unsafe Capabilities GetCapabilities()
         {
             FormatFeatureFlags compressedFormatFeatureFlags =
                 FormatFeatureFlags.FormatFeatureSampledImageBit |
@@ -409,7 +409,19 @@ namespace Ryujinx.Graphics.Vulkan
                 GAL.Format.Bc7Srgb,
                 GAL.Format.Bc7Unorm);
 
-            Api.GetPhysicalDeviceFeatures(_physicalDevice, out var features);
+
+            PhysicalDeviceVulkan12Features featuresVk12 = new PhysicalDeviceVulkan12Features()
+            {
+                SType = StructureType.PhysicalDeviceVulkan12Features
+            };
+
+            PhysicalDeviceFeatures2 features2 = new PhysicalDeviceFeatures2()
+            {
+                SType = StructureType.PhysicalDeviceFeatures2,
+                PNext = &featuresVk12
+            };
+
+            Api.GetPhysicalDeviceFeatures2(_physicalDevice, &features2);
             Api.GetPhysicalDeviceProperties(_physicalDevice, out var properties);
 
             var limits = properties.Limits;
@@ -419,7 +431,7 @@ namespace Ryujinx.Graphics.Vulkan
                 GpuVendor,
                 hasFrontFacingBug: IsIntelWindows,
                 hasVectorIndexingBug: Vendor == Vendor.Qualcomm,
-                supportsAstcCompression: features.TextureCompressionAstcLdr,
+                supportsAstcCompression: features2.Features.TextureCompressionAstcLdr,
                 supportsBc123Compression: supportsBc123CompressionFormat,
                 supportsBc45Compression: supportsBc45CompressionFormat,
                 supportsBc67Compression: supportsBc67CompressionFormat,
@@ -429,12 +441,13 @@ namespace Ryujinx.Graphics.Vulkan
                 supportsFragmentShaderInterlock: Capabilities.SupportsFragmentShaderInterlock,
                 supportsFragmentShaderOrderingIntel: false,
                 supportsGeometryShaderPassthrough: Capabilities.SupportsGeometryShaderPassthrough,
-                supportsImageLoadFormatted: features.ShaderStorageImageReadWithoutFormat,
+                supportsImageLoadFormatted: features2.Features.ShaderStorageImageReadWithoutFormat,
                 supportsMismatchingViewFormat: true,
                 supportsCubemapView: !IsAmdGcn,
                 supportsNonConstantTextureOffset: false,
                 supportsShaderBallot: false,
                 supportsTextureShadowLod: false,
+                supportsViewportIndex: featuresVk12.ShaderOutputViewportIndex,
                 supportsViewportSwizzle: false,
                 supportsIndirectParameters: Capabilities.SupportsIndirectParameters,
                 maximumUniformBuffersPerStage: Constants.MaxUniformBuffersPerStage,