Merge branch 'feature/dsb-ub' into 'master'

Workaround undefined behavior in bad dual source blend states

See merge request ryubing/ryujinx!14
This commit is contained in:
Keaton 2025-03-28 04:05:53 +00:00
commit 0e8db1f6cf
2 changed files with 21 additions and 9 deletions

View file

@ -512,13 +512,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (context.Definitions.Stage == ShaderStage.Fragment && context.Definitions.DualSourceBlend) if (context.Definitions.Stage == ShaderStage.Fragment && context.Definitions.DualSourceBlend)
{ {
IoDefinition firstOutput = outputs.ElementAtOrDefault(0); IoDefinition firstOutput = outputs.ElementAtOrDefault(0);
IoDefinition secondOutput = outputs.ElementAtOrDefault(1);
if (firstOutput.Location + 1 == secondOutput.Location) DeclareOutputDualSourceBlendAttribute(context, firstOutput.Location);
{ outputs = outputs.Skip(2);
DeclareOutputDualSourceBlendAttribute(context, firstOutput.Location);
outputs = outputs.Skip(2);
}
} }
foreach (IoDefinition ioDefinition in outputs) foreach (IoDefinition ioDefinition in outputs)

View file

@ -181,13 +181,29 @@ namespace Ryujinx.Graphics.Shader.Translation
private static void EmitOutputsInitialization(EmitterContext context, AttributeUsage attributeUsage, IGpuAccessor gpuAccessor, ShaderStage stage) private static void EmitOutputsInitialization(EmitterContext context, AttributeUsage attributeUsage, IGpuAccessor gpuAccessor, ShaderStage stage)
{ {
// Compute has no output attributes, and fragment is the last stage, so we // Compute has no output attributes, so we
// don't need to initialize outputs on those stages. // don't need to initialize outputs on that stage.
if (stage == ShaderStage.Compute || stage == ShaderStage.Fragment) if (stage == ShaderStage.Compute)
{ {
return; return;
} }
if (stage == ShaderStage.Fragment)
{
// Fragment is the last stage, so we don't need to
// initialize outputs unless we're using DSB, in which
// we need to make sure the ouput has a valid value.
if (gpuAccessor.QueryGraphicsState().DualSourceBlendEnable)
{
for (int i = 0; i < 4; i++)
{
context.Store(StorageKind.Output, IoVariable.FragmentOutputColor, null, Const(1), Const(i), ConstF(0));
}
}
return;
}
if (stage == ShaderStage.Vertex) if (stage == ShaderStage.Vertex)
{ {
InitializeVertexOutputs(context); InitializeVertexOutputs(context);