Ver código fonte

Use RGBA16 vertex format if RGB16 is not supported on Vulkan (#3552)

* Use RGBA16 vertex format if RGB16 is not supported on Vulkan

* Catch all shader compilation exceptions
gdkchan 3 anos atrás
pai
commit
88a0e720cb

+ 5 - 3
Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs

@@ -1317,10 +1317,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
             for (int location = 0; location < attributeTypes.Length; location++)
             {
-                attributeTypes[location] = vertexAttribState[location].UnpackType() switch
+                VertexAttribType type = vertexAttribState[location].UnpackType();
+
+                attributeTypes[location] = type switch
                 {
-                    3 => AttributeType.Sint,
-                    4 => AttributeType.Uint,
+                    VertexAttribType.Sint => AttributeType.Sint,
+                    VertexAttribType.Uint => AttributeType.Uint,
                     _ => AttributeType.Float
                 };
             }

+ 47 - 3
Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs

@@ -267,6 +267,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 #pragma warning restore CS0649
     }
 
+    /// <summary>
+    /// Vertex attribute vector and component size.
+    /// </summary>
+    enum VertexAttribSize
+    {
+        Size32x4 = 1,
+        Size32x3 = 2,
+        Size16x4 = 3,
+        Size32x2 = 4,
+        Size16x3 = 5,
+        Size8x4 = 0xa,
+        Size16x2 = 0xf,
+        Size32 = 0x12,
+        Size8x3 = 0x13,
+        Size8x2 = 0x18,
+        Size16 = 0x1b,
+        Size8 = 0x1d,
+        Rgb10A2 = 0x30,
+        Rg11B10 = 0x31
+    }
+
+    /// <summary>
+    /// Vertex attribute component type.
+    /// </summary>
+    enum VertexAttribType
+    {
+        Snorm = 1,
+        Unorm = 2,
+        Sint = 3,
+        Uint = 4,
+        Uscaled = 5,
+        Sscaled = 6,
+        Float = 7
+    }
+
     /// <summary>
     /// Vertex buffer attribute state.
     /// </summary>
@@ -312,13 +347,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
             return Attribute & 0x3fe00000;
         }
 
-         /// <summary>
+        /// <summary>
+        /// Unpacks the Maxwell attribute size.
+        /// </summary>
+        /// <returns>Attribute size</returns>
+        public VertexAttribSize UnpackSize()
+        {
+            return (VertexAttribSize)((Attribute >> 21) & 0x3f);
+        }
+
+        /// <summary>
         /// Unpacks the Maxwell attribute component type.
         /// </summary>
         /// <returns>Attribute component type</returns>
-        public uint UnpackType()
+        public VertexAttribType UnpackType()
         {
-            return (Attribute >> 27) & 7;
+            return (VertexAttribType)((Attribute >> 27) & 7);
         }
     }
 

+ 1 - 1
Ryujinx.Graphics.Gpu/GpuContext.cs

@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu
         /// <summary>
         /// Host hardware capabilities.
         /// </summary>
-        internal Capabilities Capabilities { get; private set; }
+        internal Capabilities Capabilities;
 
         /// <summary>
         /// Event for signalling shader cache loading progress.

+ 2 - 2
Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs

@@ -573,9 +573,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
                     RecompileGraphicsFromGuestCode(guestShaders, specState, programIndex);
                 }
             }
-            catch (DiskCacheLoadException diskCacheLoadException)
+            catch (Exception exception)
             {
-                Logger.Error?.Print(LogClass.Gpu, $"Error translating guest shader. {diskCacheLoadException.Message}");
+                Logger.Error?.Print(LogClass.Gpu, $"Error translating guest shader. {exception.Message}");
 
                 ErrorCount++;
                 SignalCompiled();

+ 22 - 8
Ryujinx.Graphics.Shader/AttributeType.cs

@@ -1,9 +1,12 @@
+using Ryujinx.Graphics.Shader.StructuredIr;
+using Ryujinx.Graphics.Shader.Translation;
 using System;
 
 namespace Ryujinx.Graphics.Shader
 {
     public enum AttributeType : byte
     {
+        // Generic types.
         Float,
         Sint,
         Uint
@@ -11,24 +14,35 @@ namespace Ryujinx.Graphics.Shader
 
     static class AttributeTypeExtensions
     {
-        public static string GetScalarType(this AttributeType type)
+        public static string ToVec4Type(this AttributeType type)
         {
             return type switch
             {
-                AttributeType.Float => "float",
-                AttributeType.Sint => "int",
-                AttributeType.Uint => "uint",
+                AttributeType.Float => "vec4",
+                AttributeType.Sint => "ivec4",
+                AttributeType.Uint => "uvec4",
                 _ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
             };
         }
 
-        public static string GetVec4Type(this AttributeType type)
+        public static VariableType ToVariableType(this AttributeType type)
         {
             return type switch
             {
-                AttributeType.Float => "vec4",
-                AttributeType.Sint => "ivec4",
-                AttributeType.Uint => "uvec4",
+                AttributeType.Float => VariableType.F32,
+                AttributeType.Sint => VariableType.S32,
+                AttributeType.Uint => VariableType.U32,
+                _ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
+            };
+        }
+
+        public static AggregateType ToAggregateType(this AttributeType type)
+        {
+            return type switch
+            {
+                AttributeType.Float => AggregateType.FP32,
+                AttributeType.Sint => AggregateType.S32,
+                AttributeType.Uint => AggregateType.U32,
                 _ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
             };
         }

+ 2 - 2
Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs

@@ -553,11 +553,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
                 if (context.Config.Stage == ShaderStage.Vertex)
                 {
-                    type = context.Config.GpuAccessor.QueryAttributeType(attr).GetVec4Type();
+                    type = context.Config.GpuAccessor.QueryAttributeType(attr).ToVec4Type();
                 }
                 else
                 {
-                    type = AttributeType.Float.GetVec4Type();
+                    type = AttributeType.Float.ToVec4Type();
                 }
 
                 context.AppendLine($"layout ({pass}location = {attr}) {iq}in {type} {name}{suffix};");

+ 1 - 6
Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs

@@ -454,12 +454,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
 
                     AttributeType type = context.Config.GpuAccessor.QueryAttributeType(location);
 
-                    return type switch
-                    {
-                        AttributeType.Sint => VariableType.S32,
-                        AttributeType.Uint => VariableType.U32,
-                        _ => VariableType.F32
-                    };
+                    return type.ToVariableType();
                 }
             }
 

+ 1 - 6
Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs

@@ -93,12 +93,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 
                 if (config.Stage == ShaderStage.Vertex && !isOutAttr)
                 {
-                    elemType = config.GpuAccessor.QueryAttributeType(location) switch
-                    {
-                        AttributeType.Sint => AggregateType.S32,
-                        AttributeType.Uint => AggregateType.U32,
-                        _ => AggregateType.FP32
-                    };
+                    elemType = config.GpuAccessor.QueryAttributeType(location).ToAggregateType();
                 }
                 else
                 {

+ 75 - 8
Ryujinx.Graphics.Vulkan/FormatCapabilities.cs

@@ -8,7 +8,8 @@ namespace Ryujinx.Graphics.Vulkan
 {
     class FormatCapabilities
     {
-        private readonly FormatFeatureFlags[] _table;
+        private readonly FormatFeatureFlags[] _bufferTable;
+        private readonly FormatFeatureFlags[] _optimalTable;
 
         private readonly Vk _api;
         private readonly PhysicalDevice _physicalDevice;
@@ -17,14 +18,18 @@ namespace Ryujinx.Graphics.Vulkan
         {
             _api = api;
             _physicalDevice = physicalDevice;
-            _table = new FormatFeatureFlags[Enum.GetNames(typeof(GAL.Format)).Length];
+
+            int totalFormats = Enum.GetNames(typeof(GAL.Format)).Length;
+
+            _bufferTable = new FormatFeatureFlags[totalFormats];
+            _optimalTable = new FormatFeatureFlags[totalFormats];
         }
 
-        public bool FormatsSupports(FormatFeatureFlags flags, params GAL.Format[] formats)
+        public bool BufferFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
         {
             foreach (GAL.Format format in formats)
             {
-                if (!FormatSupports(flags, format))
+                if (!BufferFormatSupports(flags, format))
                 {
                     return false;
                 }
@@ -33,15 +38,42 @@ namespace Ryujinx.Graphics.Vulkan
             return true;
         }
 
-        public bool FormatSupports(FormatFeatureFlags flags, GAL.Format format)
+        public bool OptimalFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
         {
-            var formatFeatureFlags = _table[(int)format];
+            foreach (GAL.Format format in formats)
+            {
+                if (!OptimalFormatSupports(flags, format))
+                {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public bool BufferFormatSupports(FormatFeatureFlags flags, GAL.Format format)
+        {
+            var formatFeatureFlags = _bufferTable[(int)format];
+
+            if (formatFeatureFlags == 0)
+            {
+                _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
+                formatFeatureFlags = fp.BufferFeatures;
+                _bufferTable[(int)format] = formatFeatureFlags;
+            }
+
+            return (formatFeatureFlags & flags) == flags;
+        }
+
+        public bool OptimalFormatSupports(FormatFeatureFlags flags, GAL.Format format)
+        {
+            var formatFeatureFlags = _optimalTable[(int)format];
 
             if (formatFeatureFlags == 0)
             {
                 _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
                 formatFeatureFlags = fp.OptimalTilingFeatures;
-                _table[(int)format] = formatFeatureFlags;
+                _optimalTable[(int)format] = formatFeatureFlags;
             }
 
             return (formatFeatureFlags & flags) == flags;
@@ -69,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan
                 requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
             }
 
-            if (!FormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
+            if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
             {
                 // The format is not supported. Can we convert it to a higher precision format?
                 if (IsD24S8(srcFormat))
@@ -85,9 +117,44 @@ namespace Ryujinx.Graphics.Vulkan
             return format;
         }
 
+        public VkFormat ConvertToVertexVkFormat(GAL.Format srcFormat)
+        {
+            var format = FormatTable.GetFormat(srcFormat);
+
+            if (!BufferFormatSupports(FormatFeatureFlags.FormatFeatureVertexBufferBit, srcFormat) ||
+                (IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
+            {
+                // The format is not supported. Can we convert it to an alternative format?
+                switch (srcFormat)
+                {
+                    case GAL.Format.R16G16B16Float:
+                        format = VkFormat.R16G16B16A16Sfloat;
+                        break;
+                    case GAL.Format.R16G16B16Sint:
+                        format = VkFormat.R16G16B16A16Sint;
+                        break;
+                    case GAL.Format.R16G16B16Uint:
+                        format = VkFormat.R16G16B16A16Uint;
+                        break;
+                    default:
+                        Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
+                        break;
+                }
+            }
+
+            return format;
+        }
+
         public static bool IsD24S8(GAL.Format format)
         {
             return format == GAL.Format.D24UnormS8Uint || format == GAL.Format.S8UintD24Unorm;
         }
+
+        private static bool IsRGB16IntFloat(GAL.Format format)
+        {
+            return format == GAL.Format.R16G16B16Float ||
+                   format == GAL.Format.R16G16B16Sint ||
+                   format == GAL.Format.R16G16B16Uint;
+        }
     }
 }

+ 3 - 1
Ryujinx.Graphics.Vulkan/PipelineBase.cs

@@ -730,6 +730,8 @@ namespace Ryujinx.Graphics.Vulkan
 
         public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
         {
+            var formatCapabilities = Gd.FormatCapabilities;
+
             int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
 
             for (int i = 0; i < count; i++)
@@ -740,7 +742,7 @@ namespace Ryujinx.Graphics.Vulkan
                 _newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
                     (uint)i,
                     (uint)bufferIndex,
-                    FormatTable.GetFormat(attribute.Format),
+                    formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
                     (uint)attribute.Offset);
             }
 

+ 1 - 1
Ryujinx.Graphics.Vulkan/PipelineConverter.cs

@@ -211,7 +211,7 @@ namespace Ryujinx.Graphics.Vulkan
                 pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
                     (uint)i,
                     (uint)bufferIndex,
-                    FormatTable.GetFormat(attribute.Format),
+                    gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
                     (uint)attribute.Offset);
             }
 

+ 4 - 4
Ryujinx.Graphics.Vulkan/TextureView.cs

@@ -451,8 +451,8 @@ namespace Ryujinx.Graphics.Vulkan
 
                     return;
                 }
-                else if (_gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
-                         _gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
+                else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
+                         _gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
                 {
                     TextureCopy.Blit(
                         _gd.Api,
@@ -761,8 +761,8 @@ namespace Ryujinx.Graphics.Vulkan
         private bool SupportsBlitFromD32FS8ToD32FAndS8()
         {
             var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
-            return _gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.D32Float)  &&
-                   _gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
+            return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float)  &&
+                   _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
         }
 
         public TextureView GetView(GAL.Format format)

+ 1 - 0
Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs

@@ -7,5 +7,6 @@
         public const bool UsePushDescriptors = false;
 
         public const bool ForceD24S8Unsupported = false;
+        public const bool ForceRGB16IntFloatUnsupported = false;
     }
 }

+ 3 - 3
Ryujinx.Graphics.Vulkan/VulkanRenderer.cs

@@ -377,7 +377,7 @@ namespace Ryujinx.Graphics.Vulkan
                 FormatFeatureFlags.FormatFeatureTransferSrcBit |
                 FormatFeatureFlags.FormatFeatureTransferDstBit;
 
-            bool supportsBc123CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
+            bool supportsBc123CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
                 GAL.Format.Bc1RgbaSrgb,
                 GAL.Format.Bc1RgbaUnorm,
                 GAL.Format.Bc2Srgb,
@@ -385,13 +385,13 @@ namespace Ryujinx.Graphics.Vulkan
                 GAL.Format.Bc3Srgb,
                 GAL.Format.Bc3Unorm);
 
-            bool supportsBc45CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
+            bool supportsBc45CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
                 GAL.Format.Bc4Snorm,
                 GAL.Format.Bc4Unorm,
                 GAL.Format.Bc5Snorm,
                 GAL.Format.Bc5Unorm);
 
-            bool supportsBc67CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
+            bool supportsBc67CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
                 GAL.Format.Bc6HSfloat,
                 GAL.Format.Bc6HUfloat,
                 GAL.Format.Bc7Srgb,