Fix blend with RGBX color formats (#3553)

This commit is contained in:
gdkchan 2022-08-11 18:23:25 -03:00 committed by GitHub
parent a5ff0024fb
commit ad47bd2d4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 117 additions and 85 deletions

View File

@ -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;
}

View File

@ -42,6 +42,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
private uint _prevFirstVertex;
private bool _prevTfEnable;
private uint _prevRtNoAlphaMask;
/// <summary>
/// Creates a new instance of the state updater.
/// </summary>
@ -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();
}
}
/// <summary>
@ -1056,45 +1071,81 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool blendIndependent = _state.State.BlendIndependent;
ColorF blendConstant = _state.State.BlendConstant;
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
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);
FilterBlendFactor(blend.AlphaSrcFactor, index),
FilterBlendFactor(blend.AlphaDstFactor, index));
_pipeline.BlendDescriptors[index] = descriptor;
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
}
}
else
{
bool enable = _state.State.BlendEnable[0];
var blend = _state.State.BlendStateCommon;
descriptor = new BlendDescriptor(
var descriptor = new BlendDescriptor(
enable,
blendConstant,
blend.ColorOp,
blend.ColorSrcFactor,
blend.ColorDstFactor,
FilterBlendFactor(blend.ColorSrcFactor, 0),
FilterBlendFactor(blend.ColorDstFactor, 0),
blend.AlphaOp,
blend.AlphaSrcFactor,
blend.AlphaDstFactor);
}
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);
}
}
}
/// <summary>
/// Gets a blend factor for the color target currently.
/// This will return <paramref name="factor"/> 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.
/// </summary>
/// <param name="factor">Input factor</param>
/// <param name="index">Color target index</param>
/// <returns>New blend factor</returns>
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;
}
/// <summary>
/// Updates host logical operation state, based on guest state.
@ -1242,6 +1293,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
_channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
}
/// <summary>
/// Gets the current texture pool state.
/// </summary>
/// <returns>Texture pool state</returns>
private GpuChannelPoolState GetPoolState()
{
return new GpuChannelPoolState(
@ -1286,6 +1341,10 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
ref attributeTypes);
}
/// <summary>
/// Gets the depth mode that is currently being used (zero to one or minus one to one).
/// </summary>
/// <returns>Current depth mode</returns>
private DepthMode GetDepthMode()
{
ref var transform = ref _state.State.ViewportTransform[0];

View File

@ -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
};
}
/// <summary>
/// Checks if a format has an alpha component.
/// </summary>
/// <param name="format">Format to be checked</param>
/// <returns>True if the format has no alpha component (RGBX), false if it does (RGBA)</returns>
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;
}
}
}

View File

@ -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);

View File

@ -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);
}