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
This commit is contained in:
gdkchan 2022-08-20 16:20:27 -03:00 committed by GitHub
parent 53cc9e0561
commit 88a0e720cb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 172 additions and 52 deletions

View file

@ -1317,10 +1317,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
for (int location = 0; location < attributeTypes.Length; location++) 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, VertexAttribType.Sint => AttributeType.Sint,
4 => AttributeType.Uint, VertexAttribType.Uint => AttributeType.Uint,
_ => AttributeType.Float _ => AttributeType.Float
}; };
} }

View file

@ -267,6 +267,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
#pragma warning restore CS0649 #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> /// <summary>
/// Vertex buffer attribute state. /// Vertex buffer attribute state.
/// </summary> /// </summary>
@ -312,13 +347,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
return Attribute & 0x3fe00000; return Attribute & 0x3fe00000;
} }
/// <summary>
/// Unpacks the Maxwell attribute size.
/// </summary>
/// <returns>Attribute size</returns>
public VertexAttribSize UnpackSize()
{
return (VertexAttribSize)((Attribute >> 21) & 0x3f);
}
/// <summary> /// <summary>
/// Unpacks the Maxwell attribute component type. /// Unpacks the Maxwell attribute component type.
/// </summary> /// </summary>
/// <returns>Attribute component type</returns> /// <returns>Attribute component type</returns>
public uint UnpackType() public VertexAttribType UnpackType()
{ {
return (Attribute >> 27) & 7; return (VertexAttribType)((Attribute >> 27) & 7);
} }
} }

View file

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

View file

@ -573,9 +573,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
RecompileGraphicsFromGuestCode(guestShaders, specState, programIndex); 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++; ErrorCount++;
SignalCompiled(); SignalCompiled();

View file

@ -1,9 +1,12 @@
using Ryujinx.Graphics.Shader.StructuredIr;
using Ryujinx.Graphics.Shader.Translation;
using System; using System;
namespace Ryujinx.Graphics.Shader namespace Ryujinx.Graphics.Shader
{ {
public enum AttributeType : byte public enum AttributeType : byte
{ {
// Generic types.
Float, Float,
Sint, Sint,
Uint Uint
@ -11,18 +14,7 @@ namespace Ryujinx.Graphics.Shader
static class AttributeTypeExtensions 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",
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
};
}
public static string GetVec4Type(this AttributeType type)
{ {
return type switch return type switch
{ {
@ -32,5 +24,27 @@ namespace Ryujinx.Graphics.Shader
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".") _ => 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}\".")
};
}
} }
} }

View file

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

View file

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

View file

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

View file

@ -8,7 +8,8 @@ namespace Ryujinx.Graphics.Vulkan
{ {
class FormatCapabilities class FormatCapabilities
{ {
private readonly FormatFeatureFlags[] _table; private readonly FormatFeatureFlags[] _bufferTable;
private readonly FormatFeatureFlags[] _optimalTable;
private readonly Vk _api; private readonly Vk _api;
private readonly PhysicalDevice _physicalDevice; private readonly PhysicalDevice _physicalDevice;
@ -17,14 +18,18 @@ namespace Ryujinx.Graphics.Vulkan
{ {
_api = api; _api = api;
_physicalDevice = physicalDevice; _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) foreach (GAL.Format format in formats)
{ {
if (!FormatSupports(flags, format)) if (!BufferFormatSupports(flags, format))
{ {
return false; return false;
} }
@ -33,15 +38,42 @@ namespace Ryujinx.Graphics.Vulkan
return true; 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) if (formatFeatureFlags == 0)
{ {
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp); _api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
formatFeatureFlags = fp.OptimalTilingFeatures; formatFeatureFlags = fp.OptimalTilingFeatures;
_table[(int)format] = formatFeatureFlags; _optimalTable[(int)format] = formatFeatureFlags;
} }
return (formatFeatureFlags & flags) == flags; return (formatFeatureFlags & flags) == flags;
@ -69,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan
requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit; 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? // The format is not supported. Can we convert it to a higher precision format?
if (IsD24S8(srcFormat)) if (IsD24S8(srcFormat))
@ -85,9 +117,44 @@ namespace Ryujinx.Graphics.Vulkan
return format; 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) public static bool IsD24S8(GAL.Format format)
{ {
return format == GAL.Format.D24UnormS8Uint || format == GAL.Format.S8UintD24Unorm; 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;
}
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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