Better IPA shader instruction implementation (#1082)
* Fix varying interpolation on fragment shader * Some nits * Alignment
This commit is contained in:
parent
2365ddfc36
commit
e93ca84b14
13 changed files with 97 additions and 89 deletions
|
@ -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};");
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
Operand srcA = Attribute(op.AttributeOffset, iq);
|
||||
if (op.Mode == InterpolationMode.Default)
|
||||
{
|
||||
Operand srcB = GetSrcB(context);
|
||||
|
||||
Operand res = context.FPSaturate(srcA, op.Saturate);
|
||||
res = context.FPMultiply(res, srcB);
|
||||
}
|
||||
|
||||
res = context.FPSaturate(res, op.Saturate);
|
||||
|
||||
context.Copy(GetDest(context), res);
|
||||
}
|
||||
|
|
|
@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
|||
|
||||
public int Value { get; }
|
||||
|
||||
public InterpolationQualifier Interpolation { get; }
|
||||
|
||||
public INode AsgOp { get; set; }
|
||||
|
||||
public HashSet<INode> 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;
|
||||
}
|
||||
|
||||
public Operand(Register reg) : this()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
@ -30,7 +28,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||
public AstOperand(Operand operand) : this()
|
||||
{
|
||||
Type = operand.Type;
|
||||
Interpolation = operand.Interpolation;
|
||||
|
||||
if (Type == OperandType.ConstantBuffer)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||
public HashSet<int> IAttributes { get; }
|
||||
public HashSet<int> 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<int>();
|
||||
OAttributes = new HashSet<int>();
|
||||
|
||||
InterpolationQualifiers = new InterpolationQualifier[32];
|
||||
|
||||
Samplers = new HashSet<AstTextureOperation>();
|
||||
Images = new HashSet<AstTextureOperation>();
|
||||
}
|
||||
|
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
@ -12,7 +12,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
public int LocalMemorySize { get; }
|
||||
|
||||
public OutputMapTarget[] OmapTargets { get; }
|
||||
public ImapPixelType[] ImapTypes { get; }
|
||||
|
||||
public OmapTarget[] OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { 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;
|
||||
|
|
|
@ -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,7 +104,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
public int StoreReqStart { get; }
|
||||
public int StoreReqEnd { get; }
|
||||
|
||||
public OutputMapTarget[] OmapTargets { get; }
|
||||
public ImapPixelType[] ImapTypes { get; }
|
||||
|
||||
public OmapTarget[] OmapTargets { get; }
|
||||
public bool OmapSampleMask { get; }
|
||||
public bool OmapDepth { get; }
|
||||
|
||||
|
@ -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),
|
||||
|
|
Reference in a new issue