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)) 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};"); 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.PositionX: return "gl_FragCoord.x";
case AttributeConsts.PositionY: return "gl_FragCoord.y"; case AttributeConsts.PositionY: return "gl_FragCoord.y";
case AttributeConsts.PositionZ: return "gl_FragCoord.z"; 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; 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; int index = (op.AttributeOffset - AttributeConsts.UserAttributeBase) >> 4;
case InterpolationMode.Pass: iq = InterpolationQualifier.NoPerspective; break;
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); res = context.FPSaturate(res, op.Saturate);
Operand res = context.FPSaturate(srcA, op.Saturate);
context.Copy(GetDest(context), res); context.Copy(GetDest(context), res);
} }

View File

@ -14,8 +14,6 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public int Value { get; } public int Value { get; }
public InterpolationQualifier Interpolation { get; }
public INode AsgOp { get; set; } public INode AsgOp { get; set; }
public HashSet<INode> UseOps { get; } public HashSet<INode> UseOps { get; }
@ -30,11 +28,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Type = type; Type = type;
} }
public Operand(OperandType type, int value, InterpolationQualifier iq = InterpolationQualifier.None) : this() public Operand(OperandType type, int value) : this()
{ {
Type = type; Type = type;
Value = value; Value = value;
Interpolation = iq;
} }
public Operand(Register reg) : this() public Operand(Register reg) : this()

View File

@ -5,9 +5,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{ {
static class OperandHelper 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) 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; 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 VariableType VarType { get; set; }
public InterpolationQualifier Interpolation { get; }
public int Value { get; } public int Value { get; }
public int CbufSlot { get; } public int CbufSlot { get; }
@ -29,8 +27,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public AstOperand(Operand operand) : this() public AstOperand(Operand operand) : this()
{ {
Type = operand.Type; Type = operand.Type;
Interpolation = operand.Interpolation;
if (Type == OperandType.ConstantBuffer) if (Type == OperandType.ConstantBuffer)
{ {

View File

@ -273,8 +273,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
if (TryGetUserAttributeIndex(operand, out int attrIndex)) if (TryGetUserAttributeIndex(operand, out int attrIndex))
{ {
Info.IAttributes.Add(attrIndex); Info.IAttributes.Add(attrIndex);
Info.InterpolationQualifiers[attrIndex] = operand.Interpolation;
} }
else if (operand.Type == OperandType.Attribute && operand.Value == AttributeConsts.InstanceId) 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> IAttributes { get; }
public HashSet<int> OAttributes { get; } public HashSet<int> OAttributes { get; }
public InterpolationQualifier[] InterpolationQualifiers { get; }
public bool UsesInstanceId { get; set; } public bool UsesInstanceId { get; set; }
public HelperFunctionsMask HelperFunctionsMask { get; set; } public HelperFunctionsMask HelperFunctionsMask { get; set; }
@ -35,8 +33,6 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
IAttributes = new HashSet<int>(); IAttributes = new HashSet<int>();
OAttributes = new HashSet<int>(); OAttributes = new HashSet<int>();
InterpolationQualifiers = new InterpolationQualifier[32];
Samplers = new HashSet<AstTextureOperation>(); Samplers = new HashSet<AstTextureOperation>();
Images = 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++) for (int attachment = 0; attachment < 8; attachment++)
{ {
OutputMapTarget target = _config.OmapTargets[attachment]; OmapTarget target = _config.OmapTargets[attachment];
for (int component = 0; component < 4; component++) for (int component = 0; component < 4; component++)
{ {

View File

@ -12,9 +12,11 @@ namespace Ryujinx.Graphics.Shader.Translation
public int LocalMemorySize { get; } public int LocalMemorySize { get; }
public OutputMapTarget[] OmapTargets { get; } public ImapPixelType[] ImapTypes { get; }
public bool OmapSampleMask { get; }
public bool OmapDepth { get; } public OmapTarget[] OmapTargets { get; }
public bool OmapSampleMask { get; }
public bool OmapDepth { get; }
public TranslationFlags Flags { get; } public TranslationFlags Flags { get; }
@ -26,6 +28,7 @@ namespace Ryujinx.Graphics.Shader.Translation
OutputTopology = OutputTopology.PointList; OutputTopology = OutputTopology.PointList;
MaxOutputVertices = 0; MaxOutputVertices = 0;
LocalMemorySize = 0; LocalMemorySize = 0;
ImapTypes = null;
OmapTargets = null; OmapTargets = null;
OmapSampleMask = false; OmapSampleMask = false;
OmapDepth = false; OmapDepth = false;
@ -39,6 +42,7 @@ namespace Ryujinx.Graphics.Shader.Translation
OutputTopology = header.OutputTopology; OutputTopology = header.OutputTopology;
MaxOutputVertices = header.MaxOutputVertexCount; MaxOutputVertices = header.MaxOutputVertexCount;
LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize; LocalMemorySize = header.ShaderLocalMemoryLowSize + header.ShaderLocalMemoryHighSize;
ImapTypes = header.ImapTypes;
OmapTargets = header.OmapTargets; OmapTargets = header.OmapTargets;
OmapSampleMask = header.OmapSampleMask; OmapSampleMask = header.OmapSampleMask;
OmapDepth = header.OmapDepth; OmapDepth = header.OmapDepth;

View File

@ -4,7 +4,39 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Shader.Translation 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 Red { get; }
public bool Green { get; } public bool Green { get; }
@ -13,7 +45,7 @@ namespace Ryujinx.Graphics.Shader.Translation
public bool Enabled => Red || Green || Blue || Alpha; 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; Red = red;
Green = green; Green = green;
@ -72,9 +104,11 @@ namespace Ryujinx.Graphics.Shader.Translation
public int StoreReqStart { get; } public int StoreReqStart { get; }
public int StoreReqEnd { get; } public int StoreReqEnd { get; }
public OutputMapTarget[] OmapTargets { get; } public ImapPixelType[] ImapTypes { get; }
public bool OmapSampleMask { get; }
public bool OmapDepth { get; } public OmapTarget[] OmapTargets { get; }
public bool OmapSampleMask { get; }
public bool OmapDepth { get; }
public ShaderHeader(ReadOnlySpan<byte> code) public ShaderHeader(ReadOnlySpan<byte> code)
{ {
@ -127,14 +161,30 @@ namespace Ryujinx.Graphics.Shader.Translation
StoreReqStart = commonWord4.Extract(12, 8); StoreReqStart = commonWord4.Extract(12, 8);
StoreReqEnd = commonWord4.Extract(24, 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 type2OmapTarget = header[18];
int type2Omap = header[19]; int type2Omap = header[19];
OmapTargets = new OutputMapTarget[8]; OmapTargets = new OmapTarget[8];
for (int offset = 0; offset < OmapTargets.Length * 4; offset += 4) 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 + 0),
type2OmapTarget.Extract(offset + 1), type2OmapTarget.Extract(offset + 1),
type2OmapTarget.Extract(offset + 2), type2OmapTarget.Extract(offset + 2),