diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs index fb58f84a6c..b1291906cd 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs @@ -365,11 +365,16 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl foreach (int attr in info.IAttributes.OrderBy(x => x)) { - string iq = info.InterpolationQualifiers[attr].ToGlslQualifier(); + string iq = string.Empty; - if (iq != string.Empty) + if (context.Config.Stage == ShaderStage.Fragment) { - iq += " "; + iq = context.Config.ImapTypes[attr].GetFirstUsedType() switch + { + PixelImap.Constant => "flat ", + PixelImap.ScreenLinear => "noperspective ", + _ => string.Empty + }; } context.AppendLine($"layout (location = {attr}) {iq}in vec4 {DefaultNames.IAttributePrefix}{attr}{suffix};"); diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs index 2de55b2ddd..8d092d4e7c 100644 --- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs +++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/OperandManager.cs @@ -188,7 +188,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl case AttributeConsts.PositionX: return "gl_FragCoord.x"; case AttributeConsts.PositionY: return "gl_FragCoord.y"; case AttributeConsts.PositionZ: return "gl_FragCoord.z"; - case AttributeConsts.PositionW: return "1.0"; + case AttributeConsts.PositionW: return "gl_FragCoord.w"; } } diff --git a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs index 1fddcc8cac..7eb8888316 100644 --- a/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs +++ b/Ryujinx.Graphics.Shader/Instructions/InstEmitMemory.cs @@ -96,17 +96,27 @@ namespace Ryujinx.Graphics.Shader.Instructions { OpCodeIpa op = (OpCodeIpa)context.CurrOp; - InterpolationQualifier iq = InterpolationQualifier.None; + Operand res = Attribute(op.AttributeOffset); - switch (op.Mode) + if (op.AttributeOffset >= AttributeConsts.UserAttributeBase && + op.AttributeOffset < AttributeConsts.UserAttributeEnd) { - case InterpolationMode.Constant: iq = InterpolationQualifier.Flat; break; - case InterpolationMode.Pass: iq = InterpolationQualifier.NoPerspective; break; + int index = (op.AttributeOffset - AttributeConsts.UserAttributeBase) >> 4; + + if (context.Config.ImapTypes[index].GetFirstUsedType() == PixelImap.Perspective) + { + res = context.FPMultiply(res, Attribute(AttributeConsts.PositionW)); + } + } + + if (op.Mode == InterpolationMode.Default) + { + Operand srcB = GetSrcB(context); + + res = context.FPMultiply(res, srcB); } - Operand srcA = Attribute(op.AttributeOffset, iq); - - Operand res = context.FPSaturate(srcA, op.Saturate); + res = context.FPSaturate(res, op.Saturate); context.Copy(GetDest(context), res); } diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs index 567277a75b..1df88a3d9b 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/Operand.cs @@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation public int Value { get; } - public InterpolationQualifier Interpolation { get; } - public INode AsgOp { get; set; } public HashSet UseOps { get; } @@ -30,11 +28,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation Type = type; } - public Operand(OperandType type, int value, InterpolationQualifier iq = InterpolationQualifier.None) : this() + public Operand(OperandType type, int value) : this() { - Type = type; - Value = value; - Interpolation = iq; + Type = type; + Value = value; } public Operand(Register reg) : this() diff --git a/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs b/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs index 45c9ba1e55..6765f8a44f 100644 --- a/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs +++ b/Ryujinx.Graphics.Shader/IntermediateRepresentation/OperandHelper.cs @@ -5,9 +5,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation { static class OperandHelper { - public static Operand Attribute(int value, InterpolationQualifier iq = InterpolationQualifier.None) + public static Operand Attribute(int value) { - return new Operand(OperandType.Attribute, value, iq); + return new Operand(OperandType.Attribute, value); } public static Operand Cbuf(int slot, int offset) diff --git a/Ryujinx.Graphics.Shader/InterpolationQualifier.cs b/Ryujinx.Graphics.Shader/InterpolationQualifier.cs deleted file mode 100644 index b7a0c1c9a8..0000000000 --- a/Ryujinx.Graphics.Shader/InterpolationQualifier.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; - -namespace Ryujinx.Graphics.Shader -{ - [Flags] - enum InterpolationQualifier - { - None = 0, - - Flat = 1, - NoPerspective = 2, - Smooth = 3, - - Centroid = 1 << 16, - Sample = 1 << 17, - - FlagsMask = Centroid | Sample - } - - static class InterpolationQualifierExtensions - { - public static string ToGlslQualifier(this InterpolationQualifier iq) - { - string output = (iq & ~InterpolationQualifier.FlagsMask) switch - { - InterpolationQualifier.Flat => "flat", - InterpolationQualifier.NoPerspective => "noperspective", - InterpolationQualifier.Smooth => "smooth", - _ => string.Empty - }; - - if ((iq & InterpolationQualifier.Centroid) != 0) - { - output = "centroid " + output; - } - else if ((iq & InterpolationQualifier.Sample) != 0) - { - output = "sample " + output; - } - - return output; - } - } -} \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/ShaderProgram.cs b/Ryujinx.Graphics.Shader/ShaderProgram.cs index 4d0c6e5bd6..7a800d8c73 100644 --- a/Ryujinx.Graphics.Shader/ShaderProgram.cs +++ b/Ryujinx.Graphics.Shader/ShaderProgram.cs @@ -24,10 +24,5 @@ namespace Ryujinx.Graphics.Shader { Code = line + Environment.NewLine + Code; } - - public void Replace(string name, string value) - { - Code = Code.Replace(name, value); - } } } \ No newline at end of file diff --git a/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs b/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs index 25b09636fe..97ff3ca97c 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/AstOperand.cs @@ -12,8 +12,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public VariableType VarType { get; set; } - public InterpolationQualifier Interpolation { get; } - public int Value { get; } public int CbufSlot { get; } @@ -29,8 +27,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public AstOperand(Operand operand) : this() { - Type = operand.Type; - Interpolation = operand.Interpolation; + Type = operand.Type; if (Type == OperandType.ConstantBuffer) { diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs index f2af84f3b5..b7d5efbe54 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramContext.cs @@ -273,8 +273,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr if (TryGetUserAttributeIndex(operand, out int attrIndex)) { Info.IAttributes.Add(attrIndex); - - Info.InterpolationQualifiers[attrIndex] = operand.Interpolation; } else if (operand.Type == OperandType.Attribute && operand.Value == AttributeConsts.InstanceId) { diff --git a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs index 0ef4bde340..be79f00e2a 100644 --- a/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs +++ b/Ryujinx.Graphics.Shader/StructuredIr/StructuredProgramInfo.cs @@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr public HashSet IAttributes { get; } public HashSet OAttributes { get; } - public InterpolationQualifier[] InterpolationQualifiers { get; } - public bool UsesInstanceId { get; set; } public HelperFunctionsMask HelperFunctionsMask { get; set; } @@ -35,8 +33,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr IAttributes = new HashSet(); OAttributes = new HashSet(); - InterpolationQualifiers = new InterpolationQualifier[32]; - Samplers = new HashSet(); Images = new HashSet(); } diff --git a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs index 7111196b79..8044f074a7 100644 --- a/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs +++ b/Ryujinx.Graphics.Shader/Translation/EmitterContext.cs @@ -76,7 +76,7 @@ namespace Ryujinx.Graphics.Shader.Translation for (int attachment = 0; attachment < 8; attachment++) { - OutputMapTarget target = _config.OmapTargets[attachment]; + OmapTarget target = _config.OmapTargets[attachment]; for (int component = 0; component < 4; component++) { diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs index e3708b41d6..60660847b1 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs @@ -12,9 +12,11 @@ namespace Ryujinx.Graphics.Shader.Translation public int LocalMemorySize { get; } - public OutputMapTarget[] OmapTargets { get; } - public bool OmapSampleMask { get; } - public bool OmapDepth { get; } + public ImapPixelType[] ImapTypes { get; } + + public OmapTarget[] OmapTargets { get; } + public bool OmapSampleMask { get; } + public bool OmapDepth { get; } public TranslationFlags Flags { get; } @@ -26,6 +28,7 @@ namespace Ryujinx.Graphics.Shader.Translation OutputTopology = OutputTopology.PointList; MaxOutputVertices = 0; LocalMemorySize = 0; + ImapTypes = null; OmapTargets = null; OmapSampleMask = false; OmapDepth = false; @@ -39,6 +42,7 @@ namespace Ryujinx.Graphics.Shader.Translation OutputTopology = header.OutputTopology; MaxOutputVertices = header.MaxOutputVertexCount; LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize; + ImapTypes = header.ImapTypes; OmapTargets = header.OmapTargets; OmapSampleMask = header.OmapSampleMask; OmapDepth = header.OmapDepth; diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs index 42701fbdca..a3b861c979 100644 --- a/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs +++ b/Ryujinx.Graphics.Shader/Translation/ShaderHeader.cs @@ -4,7 +4,39 @@ using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Shader.Translation { - struct OutputMapTarget + enum PixelImap + { + Unused = 0, + Constant = 1, + Perspective = 2, + ScreenLinear = 3 + } + + struct ImapPixelType + { + public PixelImap X { get; } + public PixelImap Y { get; } + public PixelImap Z { get; } + public PixelImap W { get; } + + public ImapPixelType(PixelImap x, PixelImap y, PixelImap z, PixelImap w) + { + X = x; + Y = y; + Z = z; + W = w; + } + + public PixelImap GetFirstUsedType() + { + if (X != PixelImap.Unused) return X; + if (Y != PixelImap.Unused) return Y; + if (Z != PixelImap.Unused) return Z; + return W; + } + } + + struct OmapTarget { public bool Red { get; } public bool Green { get; } @@ -13,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation public bool Enabled => Red || Green || Blue || Alpha; - public OutputMapTarget(bool red, bool green, bool blue, bool alpha) + public OmapTarget(bool red, bool green, bool blue, bool alpha) { Red = red; Green = green; @@ -72,9 +104,11 @@ namespace Ryujinx.Graphics.Shader.Translation public int StoreReqStart { get; } public int StoreReqEnd { get; } - public OutputMapTarget[] OmapTargets { get; } - public bool OmapSampleMask { get; } - public bool OmapDepth { get; } + public ImapPixelType[] ImapTypes { get; } + + public OmapTarget[] OmapTargets { get; } + public bool OmapSampleMask { get; } + public bool OmapDepth { get; } public ShaderHeader(ReadOnlySpan code) { @@ -127,14 +161,30 @@ namespace Ryujinx.Graphics.Shader.Translation StoreReqStart = commonWord4.Extract(12, 8); StoreReqEnd = commonWord4.Extract(24, 8); + ImapTypes = new ImapPixelType[32]; + + for (int i = 0; i < 8; i++) + { + for (int j = 0; j < 4; j++) + { + byte imap = (byte)(header[6 + i] >> (j * 8)); + + ImapTypes[i * 4 + j] = new ImapPixelType( + (PixelImap)((imap >> 0) & 3), + (PixelImap)((imap >> 2) & 3), + (PixelImap)((imap >> 4) & 3), + (PixelImap)((imap >> 6) & 3)); + } + } + int type2OmapTarget = header[18]; int type2Omap = header[19]; - OmapTargets = new OutputMapTarget[8]; + OmapTargets = new OmapTarget[8]; for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4) { - OmapTargets[offset >> 2] = new OutputMapTarget( + OmapTargets[offset >> 2] = new OmapTarget( type2OmapTarget.Extract(offset + 0), type2OmapTarget.Extract(offset + 1), type2OmapTarget.Extract(offset + 2),