Use index fragment shader output when dual source blend is enabled (#4404)

* Use index fragment shader output when dual source blend is enabled

* Shader cache version bump

* Actually set DualSourceBlendEnabled to true

* Fix XML doc

---------

Co-authored-by: Ac_K <Acoustik666@gmail.com>
This commit is contained in:
gdkchan 2023-04-05 00:25:19 -03:00 committed by GitHub
parent 52d6f2e656
commit c532118d94
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 141 additions and 25 deletions

View File

@ -38,4 +38,25 @@ namespace Ryujinx.Graphics.GAL
Src1AlphaGl = 0xc902,
OneMinusSrc1AlphaGl = 0xc903
}
public static class BlendFactorExtensions
{
public static bool IsDualSource(this BlendFactor factor)
{
switch (factor)
{
case BlendFactor.Src1Color:
case BlendFactor.Src1ColorGl:
case BlendFactor.Src1Alpha:
case BlendFactor.Src1AlphaGl:
case BlendFactor.OneMinusSrc1Color:
case BlendFactor.OneMinusSrc1ColorGl:
case BlendFactor.OneMinusSrc1Alpha:
case BlendFactor.OneMinusSrc1AlphaGl:
return true;
}
return false;
}
}
}

View File

@ -328,5 +328,19 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
Signal();
}
}
/// <summary>
/// Sets the dual-source blend enabled state.
/// </summary>
/// <param name="enabled">True if blending is enabled and using dual-source blend</param>
public void SetDualSourceBlendEnabled(bool enabled)
{
if (enabled != _graphics.DualSourceBlendEnable)
{
_graphics.DualSourceBlendEnable = enabled;
Signal();
}
}
}
}

View File

@ -1183,6 +1183,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
bool blendIndependent = _state.State.BlendIndependent;
ColorF blendConstant = _state.State.BlendConstant;
bool dualSourceBlendEnabled = false;
if (blendIndependent)
{
for (int index = 0; index < Constants.TotalRenderTargets; index++)
@ -1200,6 +1202,15 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaSrcFactor, index),
FilterBlendFactor(blend.AlphaDstFactor, index));
if (enable &&
(blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource()))
{
dualSourceBlendEnabled = true;
}
_pipeline.BlendDescriptors[index] = descriptor;
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
}
@ -1219,12 +1230,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
FilterBlendFactor(blend.AlphaSrcFactor, 0),
FilterBlendFactor(blend.AlphaDstFactor, 0));
if (enable &&
(blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource()))
{
dualSourceBlendEnabled = true;
}
for (int index = 0; index < Constants.TotalRenderTargets; index++)
{
_pipeline.BlendDescriptors[index] = descriptor;
_context.Renderer.Pipeline.SetBlendState(index, descriptor);
}
}
_currentSpecState.SetDualSourceBlendEnabled(dualSourceBlendEnabled);
}
/// <summary>

View File

@ -141,6 +141,12 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
return _oldSpecState.GraphicsState.HasConstantBufferDrawParameters;
}
/// <inheritdoc/>
public bool QueryDualSourceBlendEnable()
{
return _oldSpecState.GraphicsState.DualSourceBlendEnable;
}
/// <inheritdoc/>
public InputTopology QueryPrimitiveTopology()
{

View File

@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
private const ushort FileFormatVersionMajor = 1;
private const ushort FileFormatVersionMinor = 2;
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
private const uint CodeGenVersion = 4368;
private const uint CodeGenVersion = 4404;
private const string SharedTocFileName = "shared.toc";
private const string SharedDataFileName = "shared.data";

View File

@ -157,6 +157,12 @@ namespace Ryujinx.Graphics.Gpu.Shader
return _state.GraphicsState.HasUnalignedStorageBuffer || _state.ComputeState.HasUnalignedStorageBuffer;
}
/// <inheritdoc/>
public bool QueryDualSourceBlendEnable()
{
return _state.GraphicsState.DualSourceBlendEnable;
}
/// <inheritdoc/>
public InputTopology QueryPrimitiveTopology()
{

View File

@ -92,6 +92,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// </summary>
public Array8<AttributeType> FragmentOutputTypes;
/// <summary>
/// Indicates whether dual source blend is enabled.
/// </summary>
public bool DualSourceBlendEnable;
/// <summary>
/// Creates a new GPU graphics state.
/// </summary>
@ -111,6 +116,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <param name="hasConstantBufferDrawParameters">Indicates that the draw is writing the base vertex, base instance and draw index to Constant Buffer 0</param>
/// <param name="hasUnalignedStorageBuffer">Indicates that any storage buffer use is unaligned</param>
/// <param name="fragmentOutputTypes">Type of the fragment shader outputs</param>
/// <param name="dualSourceBlendEnable">Type of the vertex attributes consumed by the shader</param>
public GpuChannelGraphicsState(
bool earlyZForce,
PrimitiveTopology topology,
@ -127,7 +133,8 @@ namespace Ryujinx.Graphics.Gpu.Shader
ref Array32<AttributeType> attributeTypes,
bool hasConstantBufferDrawParameters,
bool hasUnalignedStorageBuffer,
ref Array8<AttributeType> fragmentOutputTypes)
ref Array8<AttributeType> fragmentOutputTypes,
bool dualSourceBlendEnable)
{
EarlyZForce = earlyZForce;
Topology = topology;
@ -145,6 +152,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
HasConstantBufferDrawParameters = hasConstantBufferDrawParameters;
HasUnalignedStorageBuffer = hasUnalignedStorageBuffer;
FragmentOutputTypes = fragmentOutputTypes;
DualSourceBlendEnable = dualSourceBlendEnable;
}
}
}

View File

@ -535,6 +535,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
return false;
}
if (graphicsState.DualSourceBlendEnable != GraphicsState.DualSourceBlendEnable)
{
return false;
}
return Matches(channel, ref poolState, checkTextures, isCompute: false);
}

View File

@ -833,31 +833,13 @@ namespace Ryujinx.Graphics.OpenGL
(BlendingFactorSrc)blend.AlphaSrcFactor.Convert(),
(BlendingFactorDest)blend.AlphaDstFactor.Convert());
static bool IsDualSource(BlendFactor factor)
{
switch (factor)
{
case BlendFactor.Src1Color:
case BlendFactor.Src1ColorGl:
case BlendFactor.Src1Alpha:
case BlendFactor.Src1AlphaGl:
case BlendFactor.OneMinusSrc1Color:
case BlendFactor.OneMinusSrc1ColorGl:
case BlendFactor.OneMinusSrc1Alpha:
case BlendFactor.OneMinusSrc1AlphaGl:
return true;
}
return false;
}
EnsureFramebuffer();
_framebuffer.SetDualSourceBlend(
IsDualSource(blend.ColorSrcFactor) ||
IsDualSource(blend.ColorDstFactor) ||
IsDualSource(blend.AlphaSrcFactor) ||
IsDualSource(blend.AlphaDstFactor));
blend.ColorSrcFactor.IsDualSource() ||
blend.ColorDstFactor.IsDualSource() ||
blend.AlphaSrcFactor.IsDualSource() ||
blend.AlphaDstFactor.IsDualSource());
if (_blendConstant != blend.BlendConstant)
{

View File

@ -612,6 +612,19 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
else
{
int usedAttributes = context.Config.UsedOutputAttributes;
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
{
int firstOutput = BitOperations.TrailingZeroCount(usedAttributes);
int mask = 3 << firstOutput;
if ((usedAttributes & mask) == mask)
{
usedAttributes &= ~mask;
DeclareOutputDualSourceBlendAttribute(context, firstOutput);
}
}
while (usedAttributes != 0)
{
int index = BitOperations.TrailingZeroCount(usedAttributes);
@ -690,6 +703,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
}
}
private static void DeclareOutputDualSourceBlendAttribute(CodeGenContext context, int attr)
{
string name = $"{DefaultNames.OAttributePrefix}{attr}";
string name2 = $"{DefaultNames.OAttributePrefix}{(attr + 1)}";
context.AppendLine($"layout (location = {attr}, index = 0) out vec4 {name};");
context.AppendLine($"layout (location = {attr}, index = 1) out vec4 {name2};");
}
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
{
foreach (int attr in attrs.Order())

View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
using static Spv.Specification;
namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
@ -622,8 +623,28 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
else if (attr >= AttributeConsts.FragmentOutputColorBase && attr < AttributeConsts.FragmentOutputColorEnd)
{
int location = (attr - AttributeConsts.FragmentOutputColorBase) / 16;
if (context.Config.Stage == ShaderStage.Fragment && context.Config.GpuAccessor.QueryDualSourceBlendEnable())
{
int firstLocation = BitOperations.TrailingZeroCount(context.Config.UsedOutputAttributes);
int index = location - firstLocation;
int mask = 3 << firstLocation;
if ((uint)index < 2 && (context.Config.UsedOutputAttributes & mask) == mask)
{
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)firstLocation);
context.Decorate(spvVar, Decoration.Index, (LiteralInteger)index);
}
else
{
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
}
}
else
{
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
}
}
if (!isOutAttr)
{

View File

@ -205,6 +205,15 @@ namespace Ryujinx.Graphics.Shader
return false;
}
/// <summary>
/// Queries dual source blend state.
/// </summary>
/// <returns>True if blending is enabled with a dual source blend equation, false otherwise</returns>
bool QueryDualSourceBlendEnable()
{
return false;
}
/// <summary>
/// Queries host about the presence of the FrontFacing built-in variable bug.
/// </summary>