Better IPA shader instruction implementation (#1082)

* Fix varying interpolation on fragment shader

* Some nits

* Alignment
This commit is contained in:
gdkchan 2020-04-02 21:20:47 -03:00 committed by GitHub
parent 2365ddfc36
commit e93ca84b14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 97 additions and 89 deletions

View file

@ -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};");

View file

@ -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";
}
}

View file

@ -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);
}

View file

@ -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;
Type = type;
Value = value;
}
public Operand(Register reg) : this()

View file

@ -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)

View file

@ -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;
}
}
}

View file

@ -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);
}
}
}

View file

@ -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)
{

View file

@ -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)
{

View file

@ -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>();
}

View file

@ -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++)
{

View file

@ -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;

View file

@ -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<byte> 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),