Implement TLD4 and TLD4S
This commit is contained in:
parent
82e10ad3ad
commit
a1df758958
7 changed files with 256 additions and 9 deletions
|
@ -226,6 +226,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
|
|
||||||
if (Op.Inst == ShaderIrInst.Texq ||
|
if (Op.Inst == ShaderIrInst.Texq ||
|
||||||
Op.Inst == ShaderIrInst.Texs ||
|
Op.Inst == ShaderIrInst.Texs ||
|
||||||
|
Op.Inst == ShaderIrInst.Tld4 ||
|
||||||
Op.Inst == ShaderIrInst.Txlf)
|
Op.Inst == ShaderIrInst.Txlf)
|
||||||
{
|
{
|
||||||
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
|
int Handle = ((ShaderIrOperImm)Op.OperandC).Value;
|
||||||
|
@ -241,14 +242,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
// TODO: non 2d texture type for TEXQ?
|
// TODO: non 2d texture type for TEXQ?
|
||||||
if (Op.Inst == ShaderIrInst.Texq)
|
if (Op.Inst == ShaderIrInst.Texq)
|
||||||
{
|
{
|
||||||
TextureType = TextureType.TwoD;
|
TextureType = TextureType.TwoD;
|
||||||
TextureInstructionSuffix = TextureInstructionSuffix.None;
|
TextureInstructionSuffix = TextureInstructionSuffix.None;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
|
ShaderIrMetaTex Meta = ((ShaderIrMetaTex)Op.MetaData);
|
||||||
|
|
||||||
TextureType = Meta.TextureType;
|
TextureType = Meta.TextureType;
|
||||||
TextureInstructionSuffix = Meta.TextureInstructionSuffix;
|
TextureInstructionSuffix = Meta.TextureInstructionSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
{ ShaderIrInst.Texb, GetTexbExpr },
|
{ ShaderIrInst.Texb, GetTexbExpr },
|
||||||
{ ShaderIrInst.Texq, GetTexqExpr },
|
{ ShaderIrInst.Texq, GetTexqExpr },
|
||||||
{ ShaderIrInst.Texs, GetTexsExpr },
|
{ ShaderIrInst.Texs, GetTexsExpr },
|
||||||
|
{ ShaderIrInst.Tld4, GetTld4Expr },
|
||||||
{ ShaderIrInst.Trunc, GetTruncExpr },
|
{ ShaderIrInst.Trunc, GetTruncExpr },
|
||||||
{ ShaderIrInst.Txlf, GetTxlfExpr },
|
{ ShaderIrInst.Txlf, GetTxlfExpr },
|
||||||
{ ShaderIrInst.Utof, GetUtofExpr },
|
{ ShaderIrInst.Utof, GetUtofExpr },
|
||||||
|
@ -837,6 +838,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
case ShaderIrInst.Ipa:
|
case ShaderIrInst.Ipa:
|
||||||
case ShaderIrInst.Texq:
|
case ShaderIrInst.Texq:
|
||||||
case ShaderIrInst.Texs:
|
case ShaderIrInst.Texs:
|
||||||
|
case ShaderIrInst.Tld4:
|
||||||
case ShaderIrInst.Txlf:
|
case ShaderIrInst.Txlf:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1219,6 +1221,19 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
return GetTextureOperation(Op, Sampler, Coords, Ch);
|
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)
|
private string GetTxlfExpr(ShaderIrOp Op)
|
||||||
{
|
{
|
||||||
// TODO: DC AND MZ
|
// TODO: DC AND MZ
|
||||||
|
@ -1346,7 +1361,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
string DepthArgument = "";
|
string DepthArgument = "";
|
||||||
|
|
||||||
int VecSize = Coords;
|
int VecSize = Coords;
|
||||||
if (HasDepth)
|
if (HasDepth && Op.Inst != ShaderIrInst.Tld4)
|
||||||
{
|
{
|
||||||
VecSize++;
|
VecSize++;
|
||||||
DepthArgument = $", {GetOperExpr(Op, Meta.DepthCompare)}";
|
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)
|
private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
|
||||||
{
|
{
|
||||||
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||||
|
|
|
@ -279,9 +279,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
TextureInstructionSuffix |= TextureInstructionSuffix.DC;
|
TextureInstructionSuffix |= TextureInstructionSuffix.DC;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderIrOperGpr[] Coords = null;
|
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
|
||||||
|
|
||||||
Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
|
|
||||||
|
|
||||||
int IndexExtraCoord = 0;
|
int IndexExtraCoord = 0;
|
||||||
|
|
||||||
|
@ -453,6 +451,63 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureType, GetSuffix());
|
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)
|
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix)
|
||||||
{
|
{
|
||||||
if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray)
|
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)
|
private static bool IsChannelUsed(int ChMask, int Ch)
|
||||||
{
|
{
|
||||||
return (ChMask & (1 << Ch)) != 0;
|
return (ChMask & (1 << Ch)) != 0;
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Ipa,
|
Ipa,
|
||||||
Texb,
|
Texb,
|
||||||
Texs,
|
Texs,
|
||||||
|
Tld4,
|
||||||
Trunc,
|
Trunc,
|
||||||
F_End,
|
F_End,
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
public ShaderIrOperGpr LevelOfDetail;
|
public ShaderIrOperGpr LevelOfDetail;
|
||||||
public ShaderIrOperGpr Offset;
|
public ShaderIrOperGpr Offset;
|
||||||
public ShaderIrOperGpr DepthCompare;
|
public ShaderIrOperGpr DepthCompare;
|
||||||
|
public int Component; // for TLD4(S)
|
||||||
|
|
||||||
public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
|
public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
|
||||||
{
|
{
|
||||||
|
|
|
@ -122,6 +122,8 @@ namespace Ryujinx.Graphics.Gal.Shader
|
||||||
Set("1101111101001x", ShaderDecode.Texq);
|
Set("1101111101001x", ShaderDecode.Texq);
|
||||||
Set("1101x00xxxxxxx", ShaderDecode.Texs);
|
Set("1101x00xxxxxxx", ShaderDecode.Texs);
|
||||||
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
Set("1101101xxxxxxx", ShaderDecode.Tlds);
|
||||||
|
Set("110010xxxx111x", ShaderDecode.Tld4);
|
||||||
|
Set("1101111100xxxx", ShaderDecode.Tld4s);
|
||||||
Set("01011111xxxxxx", ShaderDecode.Vmad);
|
Set("01011111xxxxxx", ShaderDecode.Vmad);
|
||||||
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
|
Set("0100111xxxxxxx", ShaderDecode.Xmad_CR);
|
||||||
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
|
Set("0011011x00xxxx", ShaderDecode.Xmad_I);
|
||||||
|
|
|
@ -9,10 +9,11 @@ namespace Ryujinx.Graphics.Texture
|
||||||
LZ = 0x02, // Load LOD Zero
|
LZ = 0x02, // Load LOD Zero
|
||||||
LB = 0x08, // Load Bias
|
LB = 0x08, // Load Bias
|
||||||
LL = 0x10, // Load LOD
|
LL = 0x10, // Load LOD
|
||||||
LBA = 0x20, // Load Bias with OperA?
|
LBA = 0x20, // Load Bias with OperA? Auto?
|
||||||
LLA = 0x40, // Load LOD with OperA?
|
LLA = 0x40, // Load LOD with OperA? Auto?
|
||||||
DC = 0x80, // Depth Compare
|
DC = 0x80, // Depth Compare
|
||||||
AOFFI = 0x100, // Offset
|
AOFFI = 0x100, // Offset
|
||||||
MZ = 0x200 // Multisample Zero?
|
MZ = 0x200, // Multisample Zero?
|
||||||
|
PTP = 0x400 // ???
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue