mirror of
				https://github.com/Ryujinx/Ryujinx.git
				synced 2025-11-04 04:03:41 +00:00 
			
		
		
		
	Implement scaled vertex format emulation (#5564)
* Implement scaled vertex format emulation * Auto-format (whitespace) * Delete ToVec4Type
This commit is contained in:
		
							parent
							
								
									492a046335
								
							
						
					
					
						commit
						effd546331
					
				@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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)
 | 
			
		||||
                {
 | 
			
		||||
                    VertexAttribType.Sint => AttributeType.Sint,
 | 
			
		||||
                    VertexAttribType.Uint => AttributeType.Uint,
 | 
			
		||||
                    _ => AttributeType.Float,
 | 
			
		||||
                };
 | 
			
		||||
                    value = type switch
 | 
			
		||||
                    {
 | 
			
		||||
                        VertexAttribType.Sint => AttributeType.Sint,
 | 
			
		||||
                        VertexAttribType.Uint => AttributeType.Uint,
 | 
			
		||||
                        _ => AttributeType.Float,
 | 
			
		||||
                    };
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    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)
 | 
			
		||||
                {
 | 
			
		||||
 | 
			
		||||
@ -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}.");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
@ -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}\"."),
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -266,6 +266,15 @@ namespace Ryujinx.Graphics.Shader
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /// <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>
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
 | 
			
		||||
@ -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];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -116,6 +116,7 @@ namespace Ryujinx.Graphics.Shader.Translation
 | 
			
		||||
                header.OmapTargets,
 | 
			
		||||
                header.OmapSampleMask,
 | 
			
		||||
                header.OmapDepth,
 | 
			
		||||
                gpuAccessor.QueryHostSupportsScaledVertexFormats(),
 | 
			
		||||
                transformFeedbackEnabled,
 | 
			
		||||
                transformFeedbackVecMap,
 | 
			
		||||
                transformFeedbackOutputs);
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user