aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Gpu/Engine
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2022-08-11 18:23:25 -0300
committerGitHub <noreply@github.com>2022-08-11 18:23:25 -0300
commitad47bd2d4ef72e4489f037056ead0a5d021694cc (patch)
tree6548c08ee3be5e0f6784e0e408d3a7e903802251 /Ryujinx.Graphics.Gpu/Engine
parenta5ff0024fb33964c802e1712e5b11a52390603e7 (diff)
Fix blend with RGBX color formats (#3553)
Diffstat (limited to 'Ryujinx.Graphics.Gpu/Engine')
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs107
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Types/ColorFormat.cs33
2 files changed, 115 insertions, 25 deletions
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;
+
/// <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,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);
+ FilterBlendFactor(blend.AlphaSrcFactor, index),
+ FilterBlendFactor(blend.AlphaDstFactor, index));
+
+ _pipeline.BlendDescriptors[index] = descriptor;
+ _context.Renderer.Pipeline.SetBlendState(index, descriptor);
}
- else
+ }
+ 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++)
{
- bool enable = _state.State.BlendEnable[0];
- var blend = _state.State.BlendStateCommon;
-
- 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);
}
+ }
+ }
+
+ /// <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.
- _pipeline.BlendDescriptors[index] = descriptor;
- _context.Renderer.Pipeline.SetBlendState(index, descriptor);
+ 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>
@@ -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];
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
};
}
+
+ /// <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;
+ }
}
} \ No newline at end of file