Implement TLD4 and TLD4S

This commit is contained in:
Thog 2018-12-03 19:31:57 +01:00
parent 82e10ad3ad
commit a1df758958
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
7 changed files with 256 additions and 9 deletions

View file

@ -226,6 +226,7 @@ namespace Ryujinx.Graphics.Gal.Shader
if (Op.Inst == ShaderIrInst.Texq ||
Op.Inst == ShaderIrInst.Texs ||
Op.Inst == ShaderIrInst.Tld4 ||
Op.Inst == ShaderIrInst.Txlf)
{
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
@ -241,14 +242,14 @@ namespace Ryujinx.Graphics.Gal.Shader
// TODO: non 2d texture type for TEXQ?
if (Op.Inst == ShaderIrInst.Texq)
{
TextureType = TextureType.TwoD;
TextureType = TextureType.TwoD;
TextureInstructionSuffix = TextureInstructionSuffix.None;
}
else
{
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
TextureType = Meta.TextureType;
TextureType = Meta.TextureType;
TextureInstructionSuffix = Meta.TextureInstructionSuffix;
}

View file

@ -105,6 +105,7 @@ namespace Ryujinx.Graphics.Gal.Shader
{ ShaderIrInst.Texb, GetTexbExpr },
{ ShaderIrInst.Texq, GetTexqExpr },
{ ShaderIrInst.Texs, GetTexsExpr },
{ ShaderIrInst.Tld4, GetTld4Expr },
{ ShaderIrInst.Trunc, GetTruncExpr },
{ ShaderIrInst.Txlf, GetTxlfExpr },
{ ShaderIrInst.Utof, GetUtofExpr },
@ -837,6 +838,7 @@ namespace Ryujinx.Graphics.Gal.Shader
case ShaderIrInst.Ipa:
case ShaderIrInst.Texq:
case ShaderIrInst.Texs:
case ShaderIrInst.Tld4:
case ShaderIrInst.Txlf:
return false;
}
@ -1219,6 +1221,19 @@ namespace Ryujinx.Graphics.Gal.Shader
return GetTextureOperation(Op, Sampler, Coords, Ch);
}
private string GetTld4Expr(ShaderIrOp Op)
{
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
string Sampler = GetTexSamplerName(Op);
string Coords = GetTexSamplerCoords(Op);
string Ch = "rgba".Substring(Meta.Elem, 1);
return GetTextureGatherOperation(Op, Sampler, Coords, Ch);
}
private string GetTxlfExpr(ShaderIrOp Op)
{
// TODO: DC AND MZ
@ -1346,7 +1361,7 @@ namespace Ryujinx.Graphics.Gal.Shader
string DepthArgument = "";
int VecSize = Coords;
if (HasDepth)
if (HasDepth && Op.Inst != ShaderIrInst.Tld4)
{
VecSize++;
DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}";
@ -1406,6 +1421,29 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
private string GetTextureGatherOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
{
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
string ChString = "." + Ch;
string Comp = Meta.Component.ToString();
if ((Suffix & TextureInstructionSuffix.DC) != 0)
{
Comp = GetOperExpr(Op, Meta.DepthCompare);
}
// TODO
if ((Suffix & TextureInstructionSuffix.AOFFI) != 0)
{
throw new NotSupportedException();
}
return "textureGather(" + Sampler + ", " + Coords + ", " + Comp + ")" + ChString;
}
private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
{
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;

View file

@ -279,9 +279,7 @@ namespace Ryujinx.Graphics.Gal.Shader
TextureInstructionSuffix |= TextureInstructionSuffix.DC;
}
ShaderIrOperGpr[] Coords = null;
Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
int IndexExtraCoord = 0;
@ -453,6 +451,63 @@ namespace Ryujinx.Graphics.Gal.Shader
EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureType, GetSuffix());
}
public static void Tld4(ShaderIrBlock Block, long OpCode, int Position)
{
TextureInstructionSuffix GetSuffix()
{
int RawSuffix = OpCode.Read(0x34, 0x38);
switch (RawSuffix)
{
case 0:
return TextureInstructionSuffix.None;
case 0x4:
return TextureInstructionSuffix.AOFFI;
case 0x8:
return TextureInstructionSuffix.PTP;
default:
throw new InvalidOperationException($"Invalid Suffix for TLD4 instruction {RawSuffix}");
}
}
bool IsShadow = OpCode.Read(0x32);
bool IsArray = OpCode.HasArray();
int ChMask = OpCode.Read(31, 0xf);
TextureType TextureType = TexToTextureType(OpCode.Read(28, 6), IsArray);
TextureInstructionSuffix Suffix = GetSuffix();
if (IsShadow)
{
Suffix |= TextureInstructionSuffix.DC;
}
EmitTld4(Block, OpCode, TextureType, Suffix, ChMask, OpCode.Read(0x38, 0x3), false);
}
public static void Tld4s(ShaderIrBlock Block, long OpCode, int Position)
{
TextureInstructionSuffix Suffix = TextureInstructionSuffix.None;
bool IsOffset = OpCode.Read(0x33);
bool IsShadow = OpCode.Read(0x32);
if (IsOffset)
{
Suffix |= TextureInstructionSuffix.AOFFI;
}
if (IsShadow)
{
Suffix |= TextureInstructionSuffix.DC;
}
// TLD4S seems to only support 2D textures with RGBA mask?
EmitTld4(Block, OpCode, TextureType.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true);
}
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix)
{
if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray)
@ -640,6 +695,154 @@ namespace Ryujinx.Graphics.Gal.Shader
}
}
private static void EmitTld4(ShaderIrBlock Block, long OpCode, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, int ChMask, int Component, bool Scalar)
{
ShaderIrOperGpr OperA = OpCode.Gpr8();
ShaderIrOperGpr OperB = OpCode.Gpr20();
ShaderIrOperImm OperC = OpCode.Imm13_36();
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
ShaderIrOperGpr Offset = null;
ShaderIrOperGpr DepthCompare = null;
bool IsArray = ImageUtils.IsArray(TextureType);
int OperBIndex = 0;
if (Scalar)
{
int CoordStartIndex = 0;
if (IsArray)
{
CoordStartIndex++;
Coords[Coords.Length - 1] = OperB;
}
switch (Coords.Length - CoordStartIndex)
{
case 1:
Coords[0] = OpCode.Gpr8();
break;
case 2:
Coords[0] = OpCode.Gpr8();
Coords[0].Index += CoordStartIndex;
break;
case 3:
Coords[0] = OpCode.Gpr8();
Coords[0].Index += CoordStartIndex;
Coords[1] = OpCode.Gpr8();
Coords[1].Index += 1 + CoordStartIndex;
break;
default:
throw new NotSupportedException($"{Coords.Length - CoordStartIndex} coords textures aren't supported in TLD4S");
}
if (Coords.Length - CoordStartIndex != 1)
{
Coords[Coords.Length - CoordStartIndex - 1] = OperB;
OperBIndex++;
}
if (TextureInstructionSuffix != TextureInstructionSuffix.None && TextureType == TextureType.TwoD)
{
Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
OperBIndex--;
}
}
else
{
int IndexExtraCoord = 0;
if (IsArray)
{
IndexExtraCoord++;
Coords[Coords.Length - 1] = OpCode.Gpr8();
}
for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
{
Coords[Index] = OpCode.Gpr8();
Coords[Index].Index += Index;
Coords[Index].Index += IndexExtraCoord;
if (Coords[Index].Index > ShaderIrOperGpr.ZRIndex)
{
Coords[Index].Index = ShaderIrOperGpr.ZRIndex;
}
}
}
if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0)
{
Offset = OpCode.Gpr20();
Offset.Index += OperBIndex;
OperBIndex++;
}
if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
{
DepthCompare = OpCode.Gpr20();
DepthCompare.Index += OperBIndex;
OperBIndex++;
}
for (int Ch = 0; Ch < 4; Ch++)
{
// Avoid usuless variable creation
if (!IsChannelUsed(ChMask, Ch))
{
continue;
}
ShaderIrOperGpr Dst = new ShaderIrOperGpr(TempRegStart + Ch);
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords)
{
Component = Component,
Offset = Offset,
DepthCompare = DepthCompare
};
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Tld4, OperA, OperB, OperC, Meta);
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
}
int RegInc = 0;
for (int Ch = 0; Ch < 4; Ch++)
{
if (!IsChannelUsed(ChMask, Ch))
{
continue;
}
ShaderIrOperGpr Src = new ShaderIrOperGpr(TempRegStart + Ch);
ShaderIrOperGpr Dst = OpCode.Gpr0();
Dst.Index += RegInc++;
if (Dst.Index >= ShaderIrOperGpr.ZRIndex)
{
continue;
}
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Src)));
}
}
private static bool IsChannelUsed(int ChMask, int Ch)
{
return (ChMask & (1 << Ch)) != 0;

View file

@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Gal.Shader
Ipa,
Texb,
Texs,
Tld4,
Trunc,
F_End,

View file

@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Gal.Shader
public ShaderIrOperGpr LevelOfDetail;
public ShaderIrOperGpr Offset;
public ShaderIrOperGpr DepthCompare;
public int Component; // for TLD4(S)
public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
{

View file

@ -122,6 +122,8 @@ namespace Ryujinx.Graphics.Gal.Shader
Set("1101111101001x", ShaderDecode.Texq);
Set("1101x00xxxxxxx", ShaderDecode.Texs);
Set("1101101xxxxxxx", ShaderDecode.Tlds);
Set("110010xxxx111x", ShaderDecode.Tld4);
Set("1101111100xxxx", ShaderDecode.Tld4s);
Set("01011111xxxxxx", ShaderDecode.Vmad);
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
Set("0011011x00xxxx", ShaderDecode.Xmad_I);

View file

@ -9,10 +9,11 @@ namespace Ryujinx.Graphics.Texture
LZ = 0x02, // Load LOD Zero
LB = 0x08, // Load Bias
LL = 0x10, // Load LOD
LBA = 0x20, // Load Bias with OperA?
LLA = 0x40, // Load LOD with OperA?
LBA = 0x20, // Load Bias with OperA? Auto?
LLA = 0x40, // Load LOD with OperA? Auto?
DC = 0x80, // Depth Compare
AOFFI = 0x100, // Offset
MZ = 0x200 // Multisample Zero?
MZ = 0x200, // Multisample Zero?
PTP = 0x400 // ???
}
}