From ad47bd2d4ef72e4489f037056ead0a5d021694cc Mon Sep 17 00:00:00 2001 From: gdkchan Date: Thu, 11 Aug 2022 18:23:25 -0300 Subject: [PATCH] Fix blend with RGBX color formats (#3553) --- Ryujinx.Graphics.GAL/Format.cs | 26 ---- .../Engine/Threed/StateUpdater.cs | 111 ++++++++++++++---- .../Engine/Types/ColorFormat.cs | 33 +++++- Ryujinx.Graphics.OpenGL/FormatTable.cs | 16 --- Ryujinx.Graphics.Vulkan/FormatTable.cs | 16 --- 5 files changed, 117 insertions(+), 85 deletions(-) diff --git a/Ryujinx.Graphics.GAL/Format.cs b/Ryujinx.Graphics.GAL/Format.cs index db944844..f6abacaf 100644 --- a/Ryujinx.Graphics.GAL/Format.cs +++ b/Ryujinx.Graphics.GAL/Format.cs @@ -56,7 +56,6 @@ namespace Ryujinx.Graphics.GAL D32Float, D24UnormS8Uint, D32FloatS8Uint, - R8G8B8X8Srgb, R8G8B8A8Srgb, R4G4Unorm, R4G4B4A4Unorm, @@ -113,18 +112,6 @@ namespace Ryujinx.Graphics.GAL R10G10B10A2Sint, R10G10B10A2Uscaled, R10G10B10A2Sscaled, - R8G8B8X8Unorm, - R8G8B8X8Snorm, - R8G8B8X8Uint, - R8G8B8X8Sint, - R16G16B16X16Float, - R16G16B16X16Unorm, - R16G16B16X16Snorm, - R16G16B16X16Uint, - R16G16B16X16Sint, - R32G32B32X32Float, - R32G32B32X32Uint, - R32G32B32X32Sint, Astc4x4Unorm, Astc5x4Unorm, Astc5x5Unorm, @@ -154,12 +141,9 @@ namespace Ryujinx.Graphics.GAL Astc12x10Srgb, Astc12x12Srgb, B5G6R5Unorm, - B5G5R5X1Unorm, B5G5R5A1Unorm, A1B5G5R5Unorm, - B8G8R8X8Unorm, B8G8R8A8Unorm, - B8G8R8X8Srgb, B8G8R8A8Srgb } @@ -272,7 +256,6 @@ namespace Ryujinx.Graphics.GAL case Format.R8Snorm: case Format.R8Sint: case Format.R8Uint: - case Format.B5G5R5X1Unorm: return true; } @@ -357,11 +340,8 @@ namespace Ryujinx.Graphics.GAL switch (format) { case Format.B5G6R5Unorm: - case Format.B5G5R5X1Unorm: case Format.B5G5R5A1Unorm: - case Format.B8G8R8X8Unorm: case Format.B8G8R8A8Unorm: - case Format.B8G8R8X8Srgb: case Format.B8G8R8A8Srgb: return true; } @@ -412,9 +392,6 @@ namespace Ryujinx.Graphics.GAL case Format.R16G16B16A16Uint: case Format.R32G32B32A32Uint: case Format.R10G10B10A2Uint: - case Format.R8G8B8X8Uint: - case Format.R16G16B16X16Uint: - case Format.R32G32B32X32Uint: return true; } @@ -443,9 +420,6 @@ namespace Ryujinx.Graphics.GAL case Format.R16G16B16A16Sint: case Format.R32G32B32A32Sint: case Format.R10G10B10A2Sint: - case Format.R8G8B8X8Sint: - case Format.R16G16B16X16Sint: - case Format.R32G32B32X32Sint: return true; } diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs index 10d5cd8c..bb43309b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs @@ -42,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed private uint _prevFirstVertex; private bool _prevTfEnable; + private uint _prevRtNoAlphaMask; + /// /// Creates a new instance of the state updater. /// @@ -398,6 +400,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed int clipRegionHeight = int.MaxValue; bool changedScale = false; + uint rtNoAlphaMask = 0; for (int index = 0; index < Constants.TotalRenderTargets; index++) { @@ -412,6 +415,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed continue; } + if (colorState.Format.NoAlpha()) + { + rtNoAlphaMask |= 1u << index; + } + Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture( memoryManager, colorState, @@ -485,6 +493,13 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed } _channel.TextureManager.SetClipRegion(clipRegionWidth, clipRegionHeight); + + if (useControl && _prevRtNoAlphaMask != rtNoAlphaMask) + { + _prevRtNoAlphaMask = rtNoAlphaMask; + + UpdateBlendState(); + } } /// @@ -1056,44 +1071,80 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed bool blendIndependent = _state.State.BlendIndependent; ColorF blendConstant = _state.State.BlendConstant; - for (int index = 0; index < Constants.TotalRenderTargets; index++) + if (blendIndependent) { - BlendDescriptor descriptor; - - if (blendIndependent) + for (int index = 0; index < Constants.TotalRenderTargets; index++) { bool enable = _state.State.BlendEnable[index]; var blend = _state.State.BlendState[index]; - descriptor = new BlendDescriptor( + var descriptor = new BlendDescriptor( enable, blendConstant, blend.ColorOp, - blend.ColorSrcFactor, - blend.ColorDstFactor, + FilterBlendFactor(blend.ColorSrcFactor, index), + FilterBlendFactor(blend.ColorDstFactor, index), blend.AlphaOp, - blend.AlphaSrcFactor, - blend.AlphaDstFactor); - } - else - { - bool enable = _state.State.BlendEnable[0]; - var blend = _state.State.BlendStateCommon; + FilterBlendFactor(blend.AlphaSrcFactor, index), + FilterBlendFactor(blend.AlphaDstFactor, index)); - descriptor = new BlendDescriptor( - enable, - blendConstant, - blend.ColorOp, - blend.ColorSrcFactor, - blend.ColorDstFactor, - blend.AlphaOp, - blend.AlphaSrcFactor, - blend.AlphaDstFactor); + _pipeline.BlendDescriptors[index] = descriptor; + _context.Renderer.Pipeline.SetBlendState(index, descriptor); } - - _pipeline.BlendDescriptors[index] = descriptor; - _context.Renderer.Pipeline.SetBlendState(index, descriptor); } + else + { + bool enable = _state.State.BlendEnable[0]; + var blend = _state.State.BlendStateCommon; + + var descriptor = new BlendDescriptor( + enable, + blendConstant, + blend.ColorOp, + FilterBlendFactor(blend.ColorSrcFactor, 0), + FilterBlendFactor(blend.ColorDstFactor, 0), + blend.AlphaOp, + FilterBlendFactor(blend.AlphaSrcFactor, 0), + FilterBlendFactor(blend.AlphaDstFactor, 0)); + + for (int index = 0; index < Constants.TotalRenderTargets; index++) + { + _pipeline.BlendDescriptors[index] = descriptor; + _context.Renderer.Pipeline.SetBlendState(index, descriptor); + } + } + } + + /// + /// Gets a blend factor for the color target currently. + /// This will return unless the target format has no alpha component, + /// in which case it will replace destination alpha factor with a constant factor of one or zero. + /// + /// Input factor + /// Color target index + /// New blend factor + private BlendFactor FilterBlendFactor(BlendFactor factor, int index) + { + // If any color target format without alpha is being used, we need to make sure that + // if blend is active, it will not use destination alpha as a factor. + // That is required because RGBX formats are emulated using host RGBA formats. + + if (_state.State.RtColorState[index].Format.NoAlpha()) + { + switch (factor) + { + case BlendFactor.DstAlpha: + case BlendFactor.DstAlphaGl: + factor = BlendFactor.One; + break; + case BlendFactor.OneMinusDstAlpha: + case BlendFactor.OneMinusDstAlphaGl: + factor = BlendFactor.Zero; + break; + } + } + + return factor; } /// @@ -1242,6 +1293,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers); } + /// + /// Gets the current texture pool state. + /// + /// Texture pool state private GpuChannelPoolState GetPoolState() { return new GpuChannelPoolState( @@ -1286,6 +1341,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed ref attributeTypes); } + /// + /// Gets the depth mode that is currently being used (zero to one or minus one to one). + /// + /// Current depth mode private DepthMode GetDepthMode() { ref var transform = ref _state.State.ViewportTransform[0]; diff --git a/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs b/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs index e780ec23..889b5c8b 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs @@ -124,11 +124,42 @@ namespace Ryujinx.Graphics.Gpu.Engine.Types ColorFormat.R8Snorm => new FormatInfo(Format.R8Snorm, 1, 1, 1, 1), ColorFormat.R8Sint => new FormatInfo(Format.R8Sint, 1, 1, 1, 1), ColorFormat.R8Uint => new FormatInfo(Format.R8Uint, 1, 1, 1, 1), - ColorFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5X1Unorm, 1, 1, 2, 4), + ColorFormat.B5G5R5X1Unorm => new FormatInfo(Format.B5G5R5A1Unorm, 1, 1, 2, 4), ColorFormat.R8G8B8X8Unorm => new FormatInfo(Format.R8G8B8A8Unorm, 1, 1, 4, 4), ColorFormat.R8G8B8X8Srgb => new FormatInfo(Format.R8G8B8A8Srgb, 1, 1, 4, 4), _ => FormatInfo.Default }; } + + /// + /// Checks if a format has an alpha component. + /// + /// Format to be checked + /// True if the format has no alpha component (RGBX), false if it does (RGBA) + public static bool NoAlpha(this ColorFormat format) + { + switch (format) + { + case ColorFormat.R32G32B32X32Float: + case ColorFormat.R32G32B32X32Sint: + case ColorFormat.R32G32B32X32Uint: + case ColorFormat.R16G16B16X16Unorm: + case ColorFormat.R16G16B16X16Snorm: + case ColorFormat.R16G16B16X16Sint: + case ColorFormat.R16G16B16X16Uint: + case ColorFormat.R16G16B16X16Float: + case ColorFormat.R8G8B8X8Snorm: + case ColorFormat.R8G8B8X8Sint: + case ColorFormat.R8G8B8X8Uint: + case ColorFormat.B8G8R8X8Unorm: + case ColorFormat.B8G8R8X8Srgb: + case ColorFormat.B5G5R5X1Unorm: + case ColorFormat.R8G8B8X8Unorm: + case ColorFormat.R8G8B8X8Srgb: + return true; + } + + return false; + } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.OpenGL/FormatTable.cs b/Ryujinx.Graphics.OpenGL/FormatTable.cs index e6717eb4..25043077 100644 --- a/Ryujinx.Graphics.OpenGL/FormatTable.cs +++ b/Ryujinx.Graphics.OpenGL/FormatTable.cs @@ -70,7 +70,6 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.D32Float, new FormatInfo(1, false, false, All.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float)); Add(Format.D24UnormS8Uint, new FormatInfo(1, false, false, All.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248)); Add(Format.D32FloatS8Uint, new FormatInfo(1, false, false, All.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev)); - Add(Format.R8G8B8X8Srgb, new FormatInfo(4, false, false, All.Srgb8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.R8G8B8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.R4G4B4A4Unorm, new FormatInfo(4, true, false, All.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed)); Add(Format.R5G5B5X1Unorm, new FormatInfo(4, true, false, All.Rgb5, PixelFormat.Rgb, PixelType.UnsignedShort1555Reversed)); @@ -124,18 +123,6 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.R10G10B10A2Sint, new FormatInfo(4, false, false, All.Rgb10A2, PixelFormat.RgbaInteger, (PixelType)All.Int2101010Rev)); Add(Format.R10G10B10A2Uscaled, new FormatInfo(4, false, true, All.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed)); Add(Format.R10G10B10A2Sscaled, new FormatInfo(4, false, true, All.Rgb10A2, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed)); - Add(Format.R8G8B8X8Unorm, new FormatInfo(4, true, false, All.Rgb8, PixelFormat.Rgba, PixelType.UnsignedByte)); - Add(Format.R8G8B8X8Snorm, new FormatInfo(4, true, false, All.Rgb8Snorm, PixelFormat.Rgba, PixelType.Byte)); - Add(Format.R8G8B8X8Uint, new FormatInfo(4, false, false, All.Rgb8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte)); - Add(Format.R8G8B8X8Sint, new FormatInfo(4, false, false, All.Rgb8i, PixelFormat.RgbaInteger, PixelType.Byte)); - Add(Format.R16G16B16X16Float, new FormatInfo(4, false, false, All.Rgb16f, PixelFormat.Rgba, PixelType.HalfFloat)); - Add(Format.R16G16B16X16Unorm, new FormatInfo(4, true, false, All.Rgb16, PixelFormat.Rgba, PixelType.UnsignedShort)); - Add(Format.R16G16B16X16Snorm, new FormatInfo(4, true, false, All.Rgb16Snorm, PixelFormat.Rgba, PixelType.Short)); - Add(Format.R16G16B16X16Uint, new FormatInfo(4, false, false, All.Rgb16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort)); - Add(Format.R16G16B16X16Sint, new FormatInfo(4, false, false, All.Rgb16i, PixelFormat.RgbaInteger, PixelType.Short)); - Add(Format.R32G32B32X32Float, new FormatInfo(4, false, false, All.Rgb32f, PixelFormat.Rgba, PixelType.Float)); - Add(Format.R32G32B32X32Uint, new FormatInfo(4, false, false, All.Rgb32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt)); - Add(Format.R32G32B32X32Sint, new FormatInfo(4, false, false, All.Rgb32i, PixelFormat.RgbaInteger, PixelType.Int)); Add(Format.Astc4x4Unorm, new FormatInfo(4, true, false, All.CompressedRgbaAstc4X4Khr)); Add(Format.Astc5x4Unorm, new FormatInfo(4, true, false, All.CompressedRgbaAstc5X4Khr)); Add(Format.Astc5x5Unorm, new FormatInfo(4, true, false, All.CompressedRgbaAstc5X5Khr)); @@ -165,12 +152,9 @@ namespace Ryujinx.Graphics.OpenGL Add(Format.Astc12x10Srgb, new FormatInfo(4, false, false, All.CompressedSrgb8Alpha8Astc12X10Khr)); Add(Format.Astc12x12Srgb, new FormatInfo(4, false, false, All.CompressedSrgb8Alpha8Astc12X12Khr)); Add(Format.B5G6R5Unorm, new FormatInfo(3, true, false, All.Rgb565, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed)); - Add(Format.B5G5R5X1Unorm, new FormatInfo(4, true, false, All.Rgb5, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed)); Add(Format.B5G5R5A1Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed)); Add(Format.A1B5G5R5Unorm, new FormatInfo(4, true, false, All.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort5551)); - Add(Format.B8G8R8X8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.B8G8R8A8Unorm, new FormatInfo(4, true, false, All.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte)); - Add(Format.B8G8R8X8Srgb, new FormatInfo(4, false, false, All.Srgb8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.B8G8R8A8Srgb, new FormatInfo(4, false, false, All.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte)); Add(Format.R8Unorm, SizedInternalFormat.R8); diff --git a/Ryujinx.Graphics.Vulkan/FormatTable.cs b/Ryujinx.Graphics.Vulkan/FormatTable.cs index 439d492c..446fea0a 100644 --- a/Ryujinx.Graphics.Vulkan/FormatTable.cs +++ b/Ryujinx.Graphics.Vulkan/FormatTable.cs @@ -66,7 +66,6 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.D32Float, VkFormat.D32Sfloat); Add(Format.D24UnormS8Uint, VkFormat.D24UnormS8Uint); Add(Format.D32FloatS8Uint, VkFormat.D32SfloatS8Uint); - Add(Format.R8G8B8X8Srgb, VkFormat.R8G8B8Srgb); Add(Format.R8G8B8A8Srgb, VkFormat.R8G8B8A8Srgb); Add(Format.R4G4Unorm, VkFormat.R4G4UnormPack8); Add(Format.R4G4B4A4Unorm, VkFormat.R4G4B4A4UnormPack16); @@ -119,18 +118,6 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.R10G10B10A2Sint, VkFormat.A2B10G10R10SintPack32); Add(Format.R10G10B10A2Uscaled, VkFormat.A2B10G10R10UscaledPack32); Add(Format.R10G10B10A2Sscaled, VkFormat.A2B10G10R10SscaledPack32); - Add(Format.R8G8B8X8Unorm, VkFormat.R8G8B8Unorm); - Add(Format.R8G8B8X8Snorm, VkFormat.R8G8B8SNorm); - Add(Format.R8G8B8X8Uint, VkFormat.R8G8B8Uint); - Add(Format.R8G8B8X8Sint, VkFormat.R8G8B8Sint); - Add(Format.R16G16B16X16Float, VkFormat.R16G16B16Sfloat); - Add(Format.R16G16B16X16Unorm, VkFormat.R16G16B16Unorm); - Add(Format.R16G16B16X16Snorm, VkFormat.R16G16B16SNorm); - Add(Format.R16G16B16X16Uint, VkFormat.R16G16B16Uint); - Add(Format.R16G16B16X16Sint, VkFormat.R16G16B16Sint); - Add(Format.R32G32B32X32Float, VkFormat.R32G32B32Sfloat); - Add(Format.R32G32B32X32Uint, VkFormat.R32G32B32Uint); - Add(Format.R32G32B32X32Sint, VkFormat.R32G32B32Sint); Add(Format.Astc4x4Unorm, VkFormat.Astc4x4UnormBlock); Add(Format.Astc5x4Unorm, VkFormat.Astc5x4UnormBlock); Add(Format.Astc5x5Unorm, VkFormat.Astc5x5UnormBlock); @@ -160,12 +147,9 @@ namespace Ryujinx.Graphics.Vulkan Add(Format.Astc12x10Srgb, VkFormat.Astc12x10SrgbBlock); Add(Format.Astc12x12Srgb, VkFormat.Astc12x12SrgbBlock); Add(Format.B5G6R5Unorm, VkFormat.R5G6B5UnormPack16); - Add(Format.B5G5R5X1Unorm, VkFormat.A1R5G5B5UnormPack16); Add(Format.B5G5R5A1Unorm, VkFormat.A1R5G5B5UnormPack16); Add(Format.A1B5G5R5Unorm, VkFormat.R5G5B5A1UnormPack16); - Add(Format.B8G8R8X8Unorm, VkFormat.B8G8R8Unorm); Add(Format.B8G8R8A8Unorm, VkFormat.B8G8R8A8Unorm); - Add(Format.B8G8R8X8Srgb, VkFormat.B8G8R8Srgb); Add(Format.B8G8R8A8Srgb, VkFormat.B8G8R8A8Srgb); }