diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index bb43309bc..fdf8f8222 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/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
};
}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
index c90dea41e..e416cd583 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClassState.cs
@@ -267,6 +267,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
#pragma warning restore CS0649
}
+ ///
+ /// Vertex attribute vector and component size.
+ ///
+ 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
+ }
+
+ ///
+ /// Vertex attribute component type.
+ ///
+ enum VertexAttribType
+ {
+ Snorm = 1,
+ Unorm = 2,
+ Sint = 3,
+ Uint = 4,
+ Uscaled = 5,
+ Sscaled = 6,
+ Float = 7
+ }
+
///
/// Vertex buffer attribute state.
///
@@ -312,13 +347,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return Attribute & 0x3fe00000;
}
- ///
+ ///
+ /// Unpacks the Maxwell attribute size.
+ ///
+ /// Attribute size
+ public VertexAttribSize UnpackSize()
+ {
+ return (VertexAttribSize)((Attribute >> 21) & 0x3f);
+ }
+
+ ///
/// Unpacks the Maxwell attribute component type.
///
/// Attribute component type
- public uint UnpackType()
+ public VertexAttribType UnpackType()
{
- return (Attribute >> 27) & 7;
+ return (VertexAttribType)((Attribute >> 27) & 7);
}
}
diff --git a/Ryujinx.Graphics.Gpu/GpuContext.cs b/Ryujinx.Graphics.Gpu/GpuContext.cs
index 67edd8427..5913ac947 100644
--- a/Ryujinx.Graphics.Gpu/GpuContext.cs
+++ b/Ryujinx.Graphics.Gpu/GpuContext.cs
@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu
///
/// Host hardware capabilities.
///
- internal Capabilities Capabilities { get; private set; }
+ internal Capabilities Capabilities;
///
/// Event for signalling shader cache loading progress.
diff --git a/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs b/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
index cb70811b9..04d93bba5 100644
--- a/Ryujinx.Graphics.Gpu/Shader/DiskCache/ParallelDiskCacheLoader.cs
+++ b/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();
diff --git a/Ryujinx.Graphics.Shader/AttributeType.cs b/Ryujinx.Graphics.Shader/AttributeType.cs
index 466f06cc8..1ede15600 100644
--- a/Ryujinx.Graphics.Shader/AttributeType.cs
+++ b/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,18 +14,7 @@ namespace Ryujinx.Graphics.Shader
static class AttributeTypeExtensions
{
- public static string GetScalarType(this AttributeType type)
- {
- return type switch
- {
- AttributeType.Float => "float",
- AttributeType.Sint => "int",
- AttributeType.Uint => "uint",
- _ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
- };
- }
-
- public static string GetVec4Type(this AttributeType type)
+ public static string ToVec4Type(this AttributeType type)
{
return type switch
{
@@ -32,5 +24,27 @@ namespace Ryujinx.Graphics.Shader
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
};
}
+
+ public static VariableType ToVariableType(this AttributeType type)
+ {
+ return type switch
+ {
+ 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}\".")
+ };
+ }
}
}
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index f9dfb839f..65e781216 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/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};");
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
index da720f4dc..1ab91f77f 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs
+++ b/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();
}
}
diff --git a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs b/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
index 9af5bacfd..2a97ee523 100644
--- a/Ryujinx.Graphics.Shader/Translation/AttributeInfo.cs
+++ b/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
{
diff --git a/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
index 6159f2cca..741d89565 100644
--- a/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
+++ b/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;
+ }
}
}
diff --git a/Ryujinx.Graphics.Vulkan/PipelineBase.cs b/Ryujinx.Graphics.Vulkan/PipelineBase.cs
index b66124f5e..30eeafb86 100644
--- a/Ryujinx.Graphics.Vulkan/PipelineBase.cs
+++ b/Ryujinx.Graphics.Vulkan/PipelineBase.cs
@@ -730,6 +730,8 @@ namespace Ryujinx.Graphics.Vulkan
public void SetVertexAttribs(ReadOnlySpan 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);
}
diff --git a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
index ff194d717..315df1b19 100644
--- a/Ryujinx.Graphics.Vulkan/PipelineConverter.cs
+++ b/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);
}
diff --git a/Ryujinx.Graphics.Vulkan/TextureView.cs b/Ryujinx.Graphics.Vulkan/TextureView.cs
index bb79b09c6..d94587bd6 100644
--- a/Ryujinx.Graphics.Vulkan/TextureView.cs
+++ b/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)
diff --git a/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs b/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs
index 75b45809d..752d4f7cc 100644
--- a/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs
+++ b/Ryujinx.Graphics.Vulkan/VulkanConfiguration.cs
@@ -7,5 +7,6 @@
public const bool UsePushDescriptors = false;
public const bool ForceD24S8Unsupported = false;
+ public const bool ForceRGB16IntFloatUnsupported = false;
}
}
diff --git a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index c73966309..b2f69636f 100644
--- a/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
+++ b/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,