Fix blend with RGBX color formats (#3553)
This commit is contained in:
parent
a5ff0024fb
commit
ad47bd2d4e
5 changed files with 117 additions and 85 deletions
|
@ -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);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue