aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-08-16 08:30:33 -0300
committerGitHub <noreply@github.com>2023-08-16 08:30:33 -0300
commiteffd546331371928bc38bc8a48b0c26c7c59f3e9 (patch)
treeec760ee09a3751abd3b5a261ad5be599942a3a35
parent492a0463358e7706e0fb34537d55810d833ae695 (diff)
Implement scaled vertex format emulation (#5564)1.1.989
* Implement scaled vertex format emulation * Auto-format (whitespace) * Delete ToVec4Type
-rw-r--r--src/Ryujinx.Graphics.GAL/Capabilities.cs3
-rw-r--r--src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs27
-rw-r--r--src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs15
-rw-r--r--src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs2
-rw-r--r--src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs1
-rw-r--r--src/Ryujinx.Graphics.Shader/AttributeType.cs15
-rw-r--r--src/Ryujinx.Graphics.Shader/IGpuAccessor.cs9
-rw-r--r--src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs26
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs11
-rw-r--r--src/Ryujinx.Graphics.Shader/Translation/Translator.cs1
-rw-r--r--src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs61
-rw-r--r--src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs1
12 files changed, 164 insertions, 8 deletions
diff --git a/src/Ryujinx.Graphics.GAL/Capabilities.cs b/src/Ryujinx.Graphics.GAL/Capabilities.cs
index 3c49a7dc..f4b1d4d1 100644
--- a/src/Ryujinx.Graphics.GAL/Capabilities.cs
+++ b/src/Ryujinx.Graphics.GAL/Capabilities.cs
@@ -21,6 +21,7 @@ namespace Ryujinx.Graphics.GAL
public readonly bool SupportsBgraFormat;
public readonly bool SupportsR4G4Format;
public readonly bool SupportsR4G4B4A4Format;
+ public readonly bool SupportsScaledVertexFormats;
public readonly bool SupportsSnormBufferTextureFormat;
public readonly bool Supports5BitComponentFormat;
public readonly bool SupportsBlendEquationAdvanced;
@@ -71,6 +72,7 @@ namespace Ryujinx.Graphics.GAL
bool supportsBgraFormat,
bool supportsR4G4Format,
bool supportsR4G4B4A4Format,
+ bool supportsScaledVertexFormats,
bool supportsSnormBufferTextureFormat,
bool supports5BitComponentFormat,
bool supportsBlendEquationAdvanced,
@@ -117,6 +119,7 @@ namespace Ryujinx.Graphics.GAL
SupportsBgraFormat = supportsBgraFormat;
SupportsR4G4Format = supportsR4G4Format;
SupportsR4G4B4A4Format = supportsR4G4B4A4Format;
+ SupportsScaledVertexFormats = supportsScaledVertexFormats;
SupportsSnormBufferTextureFormat = supportsSnormBufferTextureFormat;
Supports5BitComponentFormat = supports5BitComponentFormat;
SupportsBlendEquationAdvanced = supportsBlendEquationAdvanced;
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
index b2935a5b..e0607fbf 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/SpecializationStateUpdater.cs
@@ -218,17 +218,34 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
{
bool changed = false;
ref Array32<AttributeType> attributeTypes = ref _graphics.AttributeTypes;
+ bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats;
for (int location = 0; location < state.Length; location++)
{
VertexAttribType type = state[location].UnpackType();
- AttributeType value = type switch
+ AttributeType value;
+
+ if (supportsScaledFormats)
+ {
+ value = type switch
+ {
+ VertexAttribType.Sint => AttributeType.Sint,
+ VertexAttribType.Uint => AttributeType.Uint,
+ _ => AttributeType.Float,
+ };
+ }
+ else
{
- VertexAttribType.Sint => AttributeType.Sint,
- VertexAttribType.Uint => AttributeType.Uint,
- _ => AttributeType.Float,
- };
+ value = type switch
+ {
+ VertexAttribType.Sint => AttributeType.Sint,
+ VertexAttribType.Uint => AttributeType.Uint,
+ VertexAttribType.Uscaled => AttributeType.Uscaled,
+ VertexAttribType.Sscaled => AttributeType.Sscaled,
+ _ => AttributeType.Float,
+ };
+ }
if (attributeTypes[location] != value)
{
diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index b08e7f26..1f919d9b 100644
--- a/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -932,6 +932,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
/// </summary>
private void UpdateVertexAttribState()
{
+ bool supportsScaledFormats = _context.Capabilities.SupportsScaledVertexFormats;
uint vbEnableMask = _vbEnableMask;
Span<VertexAttribDescriptor> vertexAttribs = stackalloc VertexAttribDescriptor[Constants.TotalVertexAttribs];
@@ -949,7 +950,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
continue;
}
- if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
+ uint packedFormat = vertexAttrib.UnpackFormat();
+
+ if (!supportsScaledFormats)
+ {
+ packedFormat = vertexAttrib.UnpackType() switch
+ {
+ VertexAttribType.Uscaled => ((uint)VertexAttribType.Uint << 27) | (packedFormat & (0x3f << 21)),
+ VertexAttribType.Sscaled => ((uint)VertexAttribType.Sint << 27) | (packedFormat & (0x3f << 21)),
+ _ => packedFormat,
+ };
+ }
+
+ if (!FormatTable.TryGetAttribFormat(packedFormat, out Format format))
{
Logger.Debug?.Print(LogClass.Gpu, $"Invalid attribute format 0x{vertexAttrib.UnpackFormat():X}.");
diff --git a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
index 6d27f18d..e7a2d345 100644
--- a/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
+++ b/src/Ryujinx.Graphics.Gpu/Shader/GpuAccessorBase.cs
@@ -153,6 +153,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
+ public bool QueryHostSupportsScaledVertexFormats() => _context.Capabilities.SupportsScaledVertexFormats;
+
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
public bool QueryHostSupportsShaderBarrierDivergence() => _context.Capabilities.SupportsShaderBarrierDivergence;
diff --git a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
index 47b832f2..8a7ac855 100644
--- a/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
+++ b/src/Ryujinx.Graphics.OpenGL/OpenGLRenderer.cs
@@ -159,6 +159,7 @@ namespace Ryujinx.Graphics.OpenGL
supportsMismatchingViewFormat: HwCapabilities.SupportsMismatchingViewFormat,
supportsCubemapView: true,
supportsNonConstantTextureOffset: HwCapabilities.SupportsNonConstantTextureOffset,
+ supportsScaledVertexFormats: true,
supportsShaderBallot: HwCapabilities.SupportsShaderBallot,
supportsShaderBarrierDivergence: !(intelWindows || intelUnix),
supportsShaderFloat64: true,
diff --git a/src/Ryujinx.Graphics.Shader/AttributeType.cs b/src/Ryujinx.Graphics.Shader/AttributeType.cs
index e6adb4b8..1d950773 100644
--- a/src/Ryujinx.Graphics.Shader/AttributeType.cs
+++ b/src/Ryujinx.Graphics.Shader/AttributeType.cs
@@ -9,6 +9,8 @@ namespace Ryujinx.Graphics.Shader
Float,
Sint,
Uint,
+ Sscaled,
+ Uscaled,
}
static class AttributeTypeExtensions
@@ -23,5 +25,18 @@ namespace Ryujinx.Graphics.Shader
_ => throw new ArgumentException($"Invalid attribute type \"{type}\"."),
};
}
+
+ public static AggregateType ToAggregateType(this AttributeType type, bool supportsScaledFormats)
+ {
+ return type switch
+ {
+ AttributeType.Float => AggregateType.FP32,
+ AttributeType.Sint => AggregateType.S32,
+ AttributeType.Uint => AggregateType.U32,
+ AttributeType.Sscaled => supportsScaledFormats ? AggregateType.FP32 : AggregateType.S32,
+ AttributeType.Uscaled => supportsScaledFormats ? AggregateType.FP32 : AggregateType.U32,
+ _ => throw new ArgumentException($"Invalid attribute type \"{type}\"."),
+ };
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index 4c0adc3b..ee31f02d 100644
--- a/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/src/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -267,6 +267,15 @@ namespace Ryujinx.Graphics.Shader
}
/// <summary>
+ /// Queries host support scaled vertex formats, where a integer value is converted to floating-point.
+ /// </summary>
+ /// <returns>True if the host support scaled vertex formats, false otherwise</returns>
+ bool QueryHostSupportsScaledVertexFormats()
+ {
+ return true;
+ }
+
+ /// <summary>
/// Queries host GPU shader ballot support.
/// </summary>
/// <returns>True if the GPU and driver supports shader ballot, false otherwise</returns>
diff --git a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
index 542ec74a..53d774d6 100644
--- a/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
+++ b/src/Ryujinx.Graphics.Shader/Instructions/InstEmitAttribute.cs
@@ -61,7 +61,31 @@ namespace Ryujinx.Graphics.Shader.Instructions
}
else
{
- context.Copy(Register(rd), AttributeMap.GenerateAttributeLoad(context, primVertex, offset, isOutput, op.P));
+ value = AttributeMap.GenerateAttributeLoad(context, primVertex, offset, isOutput, op.P);
+
+ if (!context.TranslatorContext.Definitions.SupportsScaledVertexFormats &&
+ context.TranslatorContext.Stage == ShaderStage.Vertex &&
+ !op.O &&
+ offset >= 0x80 &&
+ offset < 0x280)
+ {
+ // The host does not support scaled vertex formats,
+ // the emulator should use a integer format, and
+ // we compensate here inserting the conversion to float.
+
+ AttributeType type = context.TranslatorContext.Definitions.GetAttributeType((offset - 0x80) >> 4);
+
+ if (type == AttributeType.Sscaled)
+ {
+ value = context.IConvertS32ToFP32(value);
+ }
+ else if (type == AttributeType.Uscaled)
+ {
+ value = context.IConvertU32ToFP32(value);
+ }
+ }
+
+ context.Copy(Register(rd), value);
}
}
else
diff --git a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
index d278c42e..204f4278 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/ShaderDefinitions.cs
@@ -53,6 +53,8 @@ namespace Ryujinx.Graphics.Shader.Translation
public bool OmapSampleMask { get; }
public bool OmapDepth { get; }
+ public bool SupportsScaledVertexFormats { get; }
+
public bool TransformFeedbackEnabled { get; }
private readonly TransformFeedbackOutput[] _transformFeedbackOutputs;
@@ -139,6 +141,7 @@ namespace Ryujinx.Graphics.Shader.Translation
int omapTargets,
bool omapSampleMask,
bool omapDepth,
+ bool supportsScaledVertexFormats,
bool transformFeedbackEnabled,
ulong transformFeedbackVecMap,
TransformFeedbackOutput[] transformFeedbackOutputs)
@@ -154,6 +157,7 @@ namespace Ryujinx.Graphics.Shader.Translation
OmapSampleMask = omapSampleMask;
OmapDepth = omapDepth;
LastInVertexPipeline = stage < ShaderStage.Fragment;
+ SupportsScaledVertexFormats = supportsScaledVertexFormats;
TransformFeedbackEnabled = transformFeedbackEnabled;
_transformFeedbackOutputs = transformFeedbackOutputs;
_transformFeedbackDefinitions = new();
@@ -302,7 +306,7 @@ namespace Ryujinx.Graphics.Shader.Translation
if (Stage == ShaderStage.Vertex && !isOutput)
{
- type |= _graphicsState.AttributeTypes[location].ToAggregateType();
+ type |= _graphicsState.AttributeTypes[location].ToAggregateType(SupportsScaledVertexFormats);
}
else
{
@@ -311,5 +315,10 @@ namespace Ryujinx.Graphics.Shader.Translation
return type;
}
+
+ public AttributeType GetAttributeType(int location)
+ {
+ return _graphicsState.AttributeTypes[location];
+ }
}
}
diff --git a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
index b609ac07..93a70ace 100644
--- a/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/src/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -116,6 +116,7 @@ namespace Ryujinx.Graphics.Shader.Translation
header.OmapTargets,
header.OmapSampleMask,
header.OmapDepth,
+ gpuAccessor.QueryHostSupportsScaledVertexFormats(),
transformFeedbackEnabled,
transformFeedbackVecMap,
transformFeedbackOutputs);
diff --git a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
index 5f7deeb6..7307a0ee 100644
--- a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
+++ b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs
@@ -9,6 +9,48 @@ namespace Ryujinx.Graphics.Vulkan
{
class FormatCapabilities
{
+ private static readonly GAL.Format[] _scaledFormats = {
+ GAL.Format.R8Uscaled,
+ GAL.Format.R8Sscaled,
+ GAL.Format.R16Uscaled,
+ GAL.Format.R16Sscaled,
+ GAL.Format.R8G8Uscaled,
+ GAL.Format.R8G8Sscaled,
+ GAL.Format.R16G16Uscaled,
+ GAL.Format.R16G16Sscaled,
+ GAL.Format.R8G8B8Uscaled,
+ GAL.Format.R8G8B8Sscaled,
+ GAL.Format.R16G16B16Uscaled,
+ GAL.Format.R16G16B16Sscaled,
+ GAL.Format.R8G8B8A8Uscaled,
+ GAL.Format.R8G8B8A8Sscaled,
+ GAL.Format.R16G16B16A16Uscaled,
+ GAL.Format.R16G16B16A16Sscaled,
+ GAL.Format.R10G10B10A2Uscaled,
+ GAL.Format.R10G10B10A2Sscaled,
+ };
+
+ private static readonly GAL.Format[] _intFormats = {
+ GAL.Format.R8Uint,
+ GAL.Format.R8Sint,
+ GAL.Format.R16Uint,
+ GAL.Format.R16Sint,
+ GAL.Format.R8G8Uint,
+ GAL.Format.R8G8Sint,
+ GAL.Format.R16G16Uint,
+ GAL.Format.R16G16Sint,
+ GAL.Format.R8G8B8Uint,
+ GAL.Format.R8G8B8Sint,
+ GAL.Format.R16G16B16Uint,
+ GAL.Format.R16G16B16Sint,
+ GAL.Format.R8G8B8A8Uint,
+ GAL.Format.R8G8B8A8Sint,
+ GAL.Format.R16G16B16A16Uint,
+ GAL.Format.R16G16B16A16Sint,
+ GAL.Format.R10G10B10A2Uint,
+ GAL.Format.R10G10B10A2Sint,
+ };
+
private readonly FormatFeatureFlags[] _bufferTable;
private readonly FormatFeatureFlags[] _optimalTable;
@@ -66,6 +108,25 @@ namespace Ryujinx.Graphics.Vulkan
return (formatFeatureFlags & flags) == flags;
}
+ public bool SupportsScaledVertexFormats()
+ {
+ // We want to check is all scaled formats are supported,
+ // but if the integer variant is not supported either,
+ // then the format is likely not supported at all,
+ // we ignore formats that are entirely unsupported here.
+
+ for (int i = 0; i < _scaledFormats.Length; i++)
+ {
+ if (!BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _scaledFormats[i]) &&
+ BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, _intFormats[i]))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
public bool BufferFormatSupports(FormatFeatureFlags flags, VkFormat format)
{
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, format, out var fp);
diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
index 20b32c70..3383d728 100644
--- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
+++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs
@@ -604,6 +604,7 @@ namespace Ryujinx.Graphics.Vulkan
supportsMismatchingViewFormat: true,
supportsCubemapView: !IsAmdGcn,
supportsNonConstantTextureOffset: false,
+ supportsScaledVertexFormats: FormatCapabilities.SupportsScaledVertexFormats(),
supportsShaderBallot: false,
supportsShaderBarrierDivergence: Vendor != Vendor.Intel,
supportsShaderFloat64: Capabilities.SupportsShaderFloat64,