Start implementing texture instructions suffixes
Fix wrong texture type with cube and TEXS Also support array textures in TEX and TEX.B Clean up TEX and TEXS coords managment Fix TEXS.LL with non-2d textures Implement TEX.AOFFI Get the right arguments for TEX, TEXS and TLDS Also, store suffix operands in appropriate values to support multiple suffix combinaisons
This commit is contained in:
parent
b9a8380ac5
commit
f426de7e15
6 changed files with 545 additions and 141 deletions
|
@ -1164,7 +1164,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
string Ch = "rgba".Substring(Meta.Elem, 1);
|
||||
|
||||
return "texture(" + DeclInfo.Name + ", " + Coords + ")." + Ch;
|
||||
return GetTextureOperation(Op, DeclInfo.Name, Coords, Ch);
|
||||
}
|
||||
|
||||
private string GetTexqExpr(ShaderIrOp Op)
|
||||
|
@ -1197,20 +1197,35 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
string Ch = "rgba".Substring(Meta.Elem, 1);
|
||||
|
||||
return "texture(" + Sampler + ", " + Coords + ")." + Ch;
|
||||
return GetTextureOperation(Op, Sampler, Coords, Ch);
|
||||
}
|
||||
|
||||
private string GetTxlfExpr(ShaderIrOp Op)
|
||||
{
|
||||
// TODO: DC AND MZ
|
||||
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||
|
||||
TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
|
||||
|
||||
string Sampler = GetTexSamplerName(Op);
|
||||
|
||||
string Coords = GetITexSamplerCoords(Op);
|
||||
|
||||
string Ch = "rgba".Substring(Meta.Elem, 1);
|
||||
|
||||
return "texelFetch(" + Sampler + ", " + Coords + ", 0)." + Ch;
|
||||
string Lod = "0";
|
||||
|
||||
if (Meta.LevelOfDetail != null)
|
||||
{
|
||||
Lod = GetOperExpr(Op, Meta.LevelOfDetail);
|
||||
}
|
||||
|
||||
if ((Suffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
return "texelFetchOffset(" + Sampler + ", " + Coords + ", " + Lod + ", " + GetOperExpr(Op, Meta.Offset) + ")." + Ch;
|
||||
}
|
||||
|
||||
return "texelFetch(" + Sampler + ", " + Coords + ", " + Lod + ")." + Ch;
|
||||
}
|
||||
|
||||
private string GetTruncExpr(ShaderIrOp Op) => GetUnaryCall(Op, "trunc");
|
||||
|
@ -1288,27 +1303,146 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||
|
||||
switch (Meta.TextureType)
|
||||
int Coords = ImageUtils.GetCoordsCountTextureType(Meta.TextureType);
|
||||
|
||||
bool IsArray = ImageUtils.IsArray(Meta.TextureType);
|
||||
|
||||
string GetLastArgument(ShaderIrNode Node)
|
||||
{
|
||||
case TextureType.OneD:
|
||||
return GetOperExpr(Op, Meta.Coordinates[0]);
|
||||
case TextureType.ThreeD:
|
||||
case TextureType.TwoDArray:
|
||||
case TextureType.CubeMap:
|
||||
return "vec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")";
|
||||
case TextureType.CubeArray:
|
||||
return "vec4(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ", " + GetOperExpr(Op, Meta.Coordinates[3]) + ")";
|
||||
case TextureType.TwoD:
|
||||
default:
|
||||
return "vec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")";
|
||||
string Result = GetOperExpr(Op, Node);
|
||||
|
||||
// array index is actually an integer so we need to pass it correctly
|
||||
if (IsArray)
|
||||
{
|
||||
Result = "float(floatBitsToInt(" + Result + "))";
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
string LastArgument;
|
||||
|
||||
switch (Coords)
|
||||
{
|
||||
case 1:
|
||||
return GetOperExpr(Op, Meta.Coordinates[0]);
|
||||
case 2:
|
||||
LastArgument = GetLastArgument(Meta.Coordinates[1]);
|
||||
|
||||
return "vec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + LastArgument + ")";
|
||||
case 3:
|
||||
LastArgument = GetLastArgument(Meta.Coordinates[2]);
|
||||
|
||||
return "vec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + LastArgument + ")";
|
||||
case 4:
|
||||
LastArgument = GetLastArgument(Meta.Coordinates[3]);
|
||||
|
||||
return "vec4(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ", " + LastArgument + ")";
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetTextureOffset(ShaderIrMetaTex Meta, string Oper)
|
||||
{
|
||||
string GetOffset(string Operation, int index)
|
||||
{
|
||||
return "(" + Operation + " >> " + index * 4 + ") & 0xF";
|
||||
}
|
||||
|
||||
int Coords = ImageUtils.GetCoordsCountTextureType(Meta.TextureType);
|
||||
|
||||
if (ImageUtils.IsArray(Meta.TextureType))
|
||||
Coords -= 1;
|
||||
|
||||
// FIXME: DC not supported
|
||||
switch (Coords)
|
||||
{
|
||||
case 1:
|
||||
return GetOffset(Oper, 0);
|
||||
case 2:
|
||||
return "ivec2(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ")";
|
||||
case 3:
|
||||
return "ivec3(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ")";
|
||||
case 4:
|
||||
return "ivec4(" + GetOffset(Oper, 0) + ", " + GetOffset(Oper, 1) + ", " + GetOffset(Oper, 2) + ", " + GetOffset(Oper, 3) + ")";
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetTextureOperation(ShaderIrOp Op, string Sampler, string Coords, string Ch)
|
||||
{
|
||||
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||
|
||||
TextureInstructionSuffix Suffix = Meta.TextureInstructionSuffix;
|
||||
|
||||
// TODO: support LBA and LLA and DC
|
||||
if ((Suffix & TextureInstructionSuffix.LZ) != 0)
|
||||
{
|
||||
if ((Suffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
|
||||
|
||||
return "textureLodOffset(" + Sampler + ", " + Coords + ", 0.0, " + Offset + ")." + Ch;
|
||||
}
|
||||
|
||||
return "textureLod(" + Sampler + ", " + Coords + ", 0.0)." + Ch;
|
||||
}
|
||||
else if ((Suffix & TextureInstructionSuffix.LB) != 0)
|
||||
{
|
||||
if ((Suffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
|
||||
|
||||
return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch;
|
||||
}
|
||||
|
||||
return "texture(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch;
|
||||
}
|
||||
else if ((Suffix & TextureInstructionSuffix.LL) != 0)
|
||||
{
|
||||
if ((Suffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
|
||||
|
||||
return "textureLodOffset(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ", " + Offset + ")." + Ch;
|
||||
}
|
||||
|
||||
return "textureLod(" + Sampler + ", " + Coords + ", " + GetOperExpr(Op, Meta.LevelOfDetail) + ")." + Ch;
|
||||
}
|
||||
else if (Suffix == TextureInstructionSuffix.AOFFI)
|
||||
{
|
||||
string Offset = GetTextureOffset(Meta, "floatBitsToInt((" + GetOperExpr(Op, Meta.Offset) + "))");
|
||||
|
||||
return "textureOffset(" + Sampler + ", " + Coords + ", " + Offset + ")." + Ch;
|
||||
}
|
||||
else if (Suffix == TextureInstructionSuffix.None || Suffix == TextureInstructionSuffix.DC)
|
||||
{
|
||||
// FIXME: implement DC
|
||||
// Load Standard
|
||||
return "texture(" + Sampler + ", " + Coords + ")." + Ch;
|
||||
}
|
||||
throw new NotImplementedException($"Texture Suffix {Meta.TextureInstructionSuffix} is not implemented");
|
||||
|
||||
}
|
||||
|
||||
private string GetITexSamplerCoords(ShaderIrOp Op)
|
||||
{
|
||||
return "ivec2(" + GetOperExpr(Op, Op.OperandA) + ", " +
|
||||
GetOperExpr(Op, Op.OperandB) + ")";
|
||||
ShaderIrMetaTex Meta = (ShaderIrMetaTex)Op.MetaData;
|
||||
|
||||
switch (ImageUtils.GetCoordsCountTextureType(Meta.TextureType))
|
||||
{
|
||||
case 1:
|
||||
return GetOperExpr(Op, Meta.Coordinates[0]);
|
||||
case 2:
|
||||
return "ivec2(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ")";
|
||||
case 3:
|
||||
return "ivec3(" + GetOperExpr(Op, Meta.Coordinates[0]) + ", " + GetOperExpr(Op, Meta.Coordinates[1]) + ", " + GetOperExpr(Op, Meta.Coordinates[2]) + ")";
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private string GetOperExpr(ShaderIrOp Op, ShaderIrNode Oper)
|
||||
|
@ -1347,22 +1481,6 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ShaderIrOperImm Imm:
|
||||
{
|
||||
//For integer immediates being used as float,
|
||||
//it's better (for readability) to just return the float value.
|
||||
if (DstType == OperType.F32)
|
||||
{
|
||||
float Value = BitConverter.Int32BitsToSingle(Imm.Value);
|
||||
|
||||
if (!float.IsNaN(Value) && !float.IsInfinity(Value))
|
||||
{
|
||||
return GetFloatConst(Value);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (DstType)
|
||||
|
|
|
@ -30,40 +30,25 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||
};
|
||||
|
||||
private static TextureType TexToTextureType(int TexType)
|
||||
private static TextureType TexToTextureType(int TexType, bool IsArray)
|
||||
{
|
||||
switch (TexType)
|
||||
{
|
||||
case 0:
|
||||
return IsArray ? TextureType.OneDArray : TextureType.OneD;
|
||||
case 2:
|
||||
return TextureType.TwoD;
|
||||
return IsArray ? TextureType.TwoDArray : TextureType.TwoD;
|
||||
case 4:
|
||||
if (IsArray)
|
||||
throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!");
|
||||
return TextureType.ThreeD;
|
||||
case 6:
|
||||
return TextureType.CubeMap;
|
||||
return IsArray ? TextureType.CubeArray : TextureType.CubeMap;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetCoordsCountTextureType(TextureType TextureType)
|
||||
{
|
||||
switch (TextureType)
|
||||
{
|
||||
case TextureType.OneD:
|
||||
return 1;
|
||||
case TextureType.OneDArray:
|
||||
case TextureType.TwoD:
|
||||
case TextureType.TwoDNoMipMap:
|
||||
return 2;
|
||||
case TextureType.ThreeD:
|
||||
case TextureType.TwoDArray:
|
||||
case TextureType.CubeMap:
|
||||
return 3;
|
||||
default:
|
||||
throw new NotImplementedException($"TEX of TextureTpe.{TextureType} not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
private static TextureType TexsToTextureType(int TexType)
|
||||
{
|
||||
switch (TexType)
|
||||
|
@ -86,7 +71,28 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return TextureType.ThreeD;
|
||||
case 0x18:
|
||||
case 0x1a:
|
||||
return TextureType.CubeArray;
|
||||
return TextureType.CubeMap;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static TextureType TldsToTextureType(int TexType)
|
||||
{
|
||||
switch (TexType)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
return TextureType.OneD;
|
||||
case 4:
|
||||
case 8:
|
||||
case 0xa:
|
||||
case 0xc:
|
||||
return TextureType.TwoD;
|
||||
case 0x10:
|
||||
return TextureType.TwoDArray;
|
||||
case 0xe:
|
||||
return TextureType.ThreeD;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
@ -195,29 +201,109 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: false);
|
||||
TextureInstructionSuffix GetSuffix()
|
||||
{
|
||||
int Suffix = OpCode.Read(0x34, 0x38);
|
||||
|
||||
switch (Suffix)
|
||||
{
|
||||
case 0:
|
||||
return TextureInstructionSuffix.None;
|
||||
case 0x8:
|
||||
return TextureInstructionSuffix.LZ;
|
||||
case 0x10:
|
||||
return TextureInstructionSuffix.LB;
|
||||
case 0x18:
|
||||
return TextureInstructionSuffix.LL;
|
||||
case 0x30:
|
||||
return TextureInstructionSuffix.LBA;
|
||||
case 0x38:
|
||||
return TextureInstructionSuffix.LLA;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEX instruction {Suffix}");
|
||||
}
|
||||
}
|
||||
|
||||
TextureInstructionSuffix InstructionSuffix = GetSuffix();
|
||||
bool IsOffset = OpCode.Read(0x36);
|
||||
|
||||
if (IsOffset)
|
||||
InstructionSuffix |= TextureInstructionSuffix.AOFFI;
|
||||
|
||||
EmitTex(Block, OpCode, InstructionSuffix, GprHandle: false);
|
||||
}
|
||||
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: true);
|
||||
TextureInstructionSuffix GetSuffix()
|
||||
{
|
||||
int Suffix = OpCode.Read(0x24, 0xe);
|
||||
switch (Suffix)
|
||||
{
|
||||
case 0:
|
||||
return TextureInstructionSuffix.None;
|
||||
case 0x2:
|
||||
return TextureInstructionSuffix.LZ;
|
||||
case 0x4:
|
||||
return TextureInstructionSuffix.LB;
|
||||
case 0x6:
|
||||
return TextureInstructionSuffix.LL;
|
||||
case 0xC:
|
||||
return TextureInstructionSuffix.LBA;
|
||||
case 0xE:
|
||||
return TextureInstructionSuffix.LLA;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {Suffix}");
|
||||
}
|
||||
}
|
||||
|
||||
TextureInstructionSuffix InstructionSuffix = GetSuffix();
|
||||
bool IsOffset = OpCode.Read(0x23);
|
||||
|
||||
if (IsOffset)
|
||||
InstructionSuffix |= TextureInstructionSuffix.AOFFI;
|
||||
|
||||
EmitTex(Block, OpCode, InstructionSuffix, GprHandle: true);
|
||||
}
|
||||
|
||||
private static void EmitTex(ShaderIrBlock Block, long OpCode, bool GprHandle)
|
||||
private static void EmitTex(ShaderIrBlock Block, long OpCode, TextureInstructionSuffix TextureInstructionSuffix, bool GprHandle)
|
||||
{
|
||||
// TODO: Support array textures
|
||||
TextureType TextureType = TexToTextureType(OpCode.Read(28, 6));
|
||||
bool IsArray = OpCode.HasArray();
|
||||
|
||||
TextureType TextureType = TexToTextureType(OpCode.Read(28, 6), IsArray);
|
||||
Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}"));
|
||||
Block.AddNode(new ShaderIrCmnt($"TextureInstructionSuffix: {TextureInstructionSuffix}"));
|
||||
Block.AddNode(new ShaderIrCmnt($"Array: {IsArray}"));
|
||||
|
||||
// FIXME: check if this is right
|
||||
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[GetCoordsCountTextureType(TextureType)];
|
||||
bool HasDepthCompare = OpCode.Read(0x32);
|
||||
|
||||
for (int Index = 0; Index < Coords.Length; Index++)
|
||||
if (HasDepthCompare)
|
||||
{
|
||||
TextureInstructionSuffix |= TextureInstructionSuffix.DC;
|
||||
}
|
||||
|
||||
ShaderIrOperGpr[] Coords = null;
|
||||
|
||||
Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
|
||||
|
||||
int IndexExtraCoord = 0;
|
||||
|
||||
if (IsArray)
|
||||
{
|
||||
IndexExtraCoord++;
|
||||
|
||||
Coords[Coords.Length - 1] = OpCode.Gpr8();
|
||||
}
|
||||
|
||||
|
||||
for (int Index = 0; Index < Coords.Length - IndexExtraCoord; Index++)
|
||||
{
|
||||
ShaderIrOperGpr CoordReg = OpCode.Gpr8();
|
||||
|
||||
CoordReg.Index += Index;
|
||||
|
||||
Coords[Index].Index += IndexExtraCoord;
|
||||
|
||||
if (!CoordReg.IsValidRegister)
|
||||
{
|
||||
CoordReg.Index = ShaderIrOperGpr.ZRIndex;
|
||||
|
@ -230,6 +316,41 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
int ChMask = OpCode.Read(31, 0xf);
|
||||
|
||||
ShaderIrOperGpr LevelOfDetail = null;
|
||||
ShaderIrOperGpr Offset = null;
|
||||
ShaderIrOperGpr DepthCompare = null;
|
||||
|
||||
// TODO: determine first argument when TEX.B is used
|
||||
int OperBIndex = GprHandle ? 1 : 0;
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0 ||
|
||||
(TextureInstructionSuffix & TextureInstructionSuffix.LB) != 0 ||
|
||||
(TextureInstructionSuffix & TextureInstructionSuffix.LBA) != 0 ||
|
||||
(TextureInstructionSuffix & TextureInstructionSuffix.LLA) != 0)
|
||||
{
|
||||
LevelOfDetail = OpCode.Gpr20();
|
||||
LevelOfDetail.Index += OperBIndex;
|
||||
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
Offset = OpCode.Gpr20();
|
||||
Offset.Index += OperBIndex;
|
||||
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
|
||||
{
|
||||
DepthCompare = OpCode.Gpr20();
|
||||
DepthCompare.Index += OperBIndex;
|
||||
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
// ???
|
||||
ShaderIrNode OperC = GprHandle
|
||||
? (ShaderIrNode)OpCode.Gpr20()
|
||||
: (ShaderIrNode)OpCode.Imm13_36();
|
||||
|
@ -254,9 +375,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
continue;
|
||||
}
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, Coords);
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords)
|
||||
{
|
||||
LevelOfDetail = LevelOfDetail,
|
||||
Offset = Offset,
|
||||
DepthCompare = DepthCompare
|
||||
};
|
||||
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords[1], OperC, Meta);
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, Coords[0], Coords.Length > 1 ? Coords[1] : null, OperC, Meta);
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(Dst, Op)));
|
||||
}
|
||||
|
@ -264,82 +390,176 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||
TextureInstructionSuffix GetSuffix()
|
||||
{
|
||||
int Suffix = OpCode.Read(0x34, 0x1e);
|
||||
switch (Suffix)
|
||||
{
|
||||
case 0:
|
||||
case 0x4:
|
||||
case 0x10:
|
||||
case 0x16:
|
||||
return TextureInstructionSuffix.LZ;
|
||||
case 0x6:
|
||||
case 0x1a:
|
||||
return TextureInstructionSuffix.LL;
|
||||
case 0x8:
|
||||
return TextureInstructionSuffix.DC;
|
||||
case 0x2:
|
||||
case 0xe:
|
||||
case 0x14:
|
||||
case 0x18:
|
||||
return TextureInstructionSuffix.None;
|
||||
case 0xa:
|
||||
return TextureInstructionSuffix.LL | TextureInstructionSuffix.DC;
|
||||
case 0xc:
|
||||
case 0x12:
|
||||
return TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {Suffix}");
|
||||
}
|
||||
}
|
||||
|
||||
TextureType TextureType = TexsToTextureType(OpCode.Read(52, 0x1e));
|
||||
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureType, GetSuffix());
|
||||
}
|
||||
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||
}
|
||||
|
||||
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
|
||||
{
|
||||
TextureType TextureType = TexsToTextureType(OpCode.Read(52, 0x1e));
|
||||
Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}"));
|
||||
|
||||
if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray)
|
||||
TextureInstructionSuffix GetSuffix()
|
||||
{
|
||||
throw new InvalidOperationException("TXLF instructions cannot use CUBE modifier!");
|
||||
}
|
||||
|
||||
//TODO: Support other formats.
|
||||
ShaderIrOperGpr OperA = OpCode.Gpr8();
|
||||
ShaderIrOperGpr OperB = OpCode.Gpr20();
|
||||
|
||||
ShaderIrOperGpr[] GetCoordinates()
|
||||
{
|
||||
ShaderIrOperGpr X;
|
||||
ShaderIrOperGpr Y;
|
||||
ShaderIrOperGpr Z;
|
||||
ShaderIrOperGpr Index;
|
||||
|
||||
switch (TextureType)
|
||||
int Suffix = OpCode.Read(0x34, 0x1e);
|
||||
switch (Suffix)
|
||||
{
|
||||
case TextureType.OneD:
|
||||
X = OperA;
|
||||
|
||||
return CoordsRegistersToTempRegisters(Block, X);
|
||||
case TextureType.TwoDArray:
|
||||
Index = OperA;
|
||||
|
||||
X = OpCode.Gpr8();
|
||||
X.Index++;
|
||||
|
||||
Y = OperB;
|
||||
|
||||
return CoordsRegistersToTempRegisters(Block, X, Y, Index);
|
||||
case TextureType.ThreeD:
|
||||
case TextureType.CubeMap:
|
||||
X = OperA;
|
||||
|
||||
Y = OpCode.Gpr8();
|
||||
Y.Index += 1;
|
||||
|
||||
Z = OperB;
|
||||
|
||||
return CoordsRegistersToTempRegisters(Block, X, Y, Z);
|
||||
case TextureType.CubeArray:
|
||||
Index = OperA;
|
||||
|
||||
X = OpCode.Gpr8();
|
||||
X.Index += 1;
|
||||
|
||||
Y = OpCode.Gpr8();
|
||||
Y.Index += 2;
|
||||
|
||||
Z = OperB;
|
||||
|
||||
return CoordsRegistersToTempRegisters(Block, X, Y, Z, Index);
|
||||
case TextureType.TwoD:
|
||||
X = OperA;
|
||||
Y = OperB;
|
||||
|
||||
return new ShaderIrOperGpr[] { X, Y };
|
||||
case 0:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
return TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOFFI;
|
||||
case 0xc:
|
||||
return TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ;
|
||||
case 0xe:
|
||||
case 0x10:
|
||||
return TextureInstructionSuffix.LZ;
|
||||
case 0x2:
|
||||
case 0xa:
|
||||
return TextureInstructionSuffix.LL;
|
||||
case 0x18:
|
||||
return TextureInstructionSuffix.LL | TextureInstructionSuffix.AOFFI;
|
||||
default:
|
||||
throw new NotImplementedException($"TEXS of TextureType.{TextureType} not supported!");
|
||||
throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {Suffix}");
|
||||
}
|
||||
}
|
||||
|
||||
TextureType TextureType = TldsToTextureType(OpCode.Read(52, 0x1e));
|
||||
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureType, GetSuffix());
|
||||
}
|
||||
|
||||
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix)
|
||||
{
|
||||
Block.AddNode(new ShaderIrCmnt($"TextureType: {TextureType}"));
|
||||
Block.AddNode(new ShaderIrCmnt($"TextureInstructionSuffix: {TextureInstructionSuffix}"));
|
||||
|
||||
if (Inst == ShaderIrInst.Txlf && TextureType == TextureType.CubeArray)
|
||||
{
|
||||
throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!");
|
||||
}
|
||||
|
||||
// This is the only array type that is known to be usable with TEXS
|
||||
bool IsArray = ImageUtils.IsArray(TextureType);
|
||||
|
||||
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureType(TextureType)];
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
|
||||
{
|
||||
// TODO
|
||||
//throw new NotImplementedException($"TEXS.DC isn't implemented yet");
|
||||
}
|
||||
|
||||
|
||||
ShaderIrOperGpr OperA = OpCode.Gpr8();
|
||||
ShaderIrOperGpr OperB = OpCode.Gpr20();
|
||||
|
||||
ShaderIrOperGpr SuffixExtra = OpCode.Gpr20();
|
||||
SuffixExtra.Index += 1;
|
||||
|
||||
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 TEXS");
|
||||
}
|
||||
|
||||
int OperBIndex = 0;
|
||||
|
||||
ShaderIrOperGpr LevelOfDetail = null;
|
||||
ShaderIrOperGpr Offset = null;
|
||||
ShaderIrOperGpr DepthCompare = null;
|
||||
|
||||
// OperB is always the last value
|
||||
// Not applicable to 1d textures
|
||||
if (Coords.Length - CoordStartIndex != 1)
|
||||
{
|
||||
Coords[Coords.Length - CoordStartIndex - 1] = OperB;
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
// Encoding of TEXS/TLDS is a bit special and change for 2d textures
|
||||
// NOTE: OperA seems to hold at best two args.
|
||||
// On 2D textures, if no suffix need an additional values, Y is stored in OperB, otherwise coords are in OperA and the additional values is in OperB.
|
||||
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--;
|
||||
}
|
||||
|
||||
// TODO: Find what MZ do and what change about the encoding (Maybe Multisample?)
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.LL) != 0)
|
||||
{
|
||||
LevelOfDetail = OpCode.Gpr20();
|
||||
LevelOfDetail.Index += OperBIndex;
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.AOFFI) != 0)
|
||||
{
|
||||
Offset = OpCode.Gpr20();
|
||||
Offset.Index += OperBIndex;
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
if ((TextureInstructionSuffix & TextureInstructionSuffix.DC) != 0)
|
||||
{
|
||||
DepthCompare = OpCode.Gpr20();
|
||||
DepthCompare.Index += OperBIndex;
|
||||
OperBIndex++;
|
||||
}
|
||||
|
||||
int LutIndex;
|
||||
|
||||
|
@ -417,8 +637,12 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
continue;
|
||||
}
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, GetCoordinates());
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureType, TextureInstructionSuffix, Coords)
|
||||
{
|
||||
LevelOfDetail = LevelOfDetail,
|
||||
Offset = Offset,
|
||||
DepthCompare = DepthCompare
|
||||
};
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
|
||||
|
||||
ShaderIrOperGpr Dst = GetDst();
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return ((int)(OpCode >> 20) << 8) >> 8;
|
||||
}
|
||||
|
||||
private static bool HasArray(this long OpCode)
|
||||
{
|
||||
return OpCode.Read(0x1c);
|
||||
}
|
||||
|
||||
private static ShaderIrOperAbuf[] Abuf20(this long OpCode)
|
||||
{
|
||||
int Abuf = OpCode.Read(20, 0x3ff);
|
||||
|
|
|
@ -4,15 +4,20 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
class ShaderIrMetaTex : ShaderIrMeta
|
||||
{
|
||||
public int Elem { get; private set; }
|
||||
public TextureType TextureType { get; private set; }
|
||||
public ShaderIrNode[] Coordinates { get; private set; }
|
||||
public int Elem { get; private set; }
|
||||
public TextureType TextureType { get; private set; }
|
||||
public ShaderIrNode[] Coordinates { get; private set; }
|
||||
public TextureInstructionSuffix TextureInstructionSuffix { get; private set; }
|
||||
public ShaderIrOperGpr LevelOfDetail;
|
||||
public ShaderIrOperGpr Offset;
|
||||
public ShaderIrOperGpr DepthCompare;
|
||||
|
||||
public ShaderIrMetaTex(int Elem, TextureType TextureType, params ShaderIrNode[] Coordinates)
|
||||
public ShaderIrMetaTex(int Elem, TextureType TextureType, TextureInstructionSuffix TextureInstructionSuffix, params ShaderIrNode[] Coordinates)
|
||||
{
|
||||
this.Elem = Elem;
|
||||
this.TextureType = TextureType;
|
||||
this.Coordinates = Coordinates;
|
||||
this.Elem = Elem;
|
||||
this.TextureType = TextureType;
|
||||
this.TextureInstructionSuffix = TextureInstructionSuffix;
|
||||
this.Coordinates = Coordinates;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -469,5 +469,39 @@ namespace Ryujinx.Graphics.Texture
|
|||
throw new NotSupportedException($"Texture type {TextureType} currently not supported!");
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsArray(TextureType TextureType)
|
||||
{
|
||||
switch (TextureType)
|
||||
{
|
||||
case TextureType.OneDArray:
|
||||
case TextureType.TwoDArray:
|
||||
case TextureType.CubeArray:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetCoordsCountTextureType(TextureType TextureType)
|
||||
{
|
||||
switch (TextureType)
|
||||
{
|
||||
case TextureType.OneD:
|
||||
return 1;
|
||||
case TextureType.OneDArray:
|
||||
case TextureType.TwoD:
|
||||
case TextureType.TwoDNoMipMap:
|
||||
return 2;
|
||||
case TextureType.ThreeD:
|
||||
case TextureType.TwoDArray:
|
||||
case TextureType.CubeMap:
|
||||
return 3;
|
||||
case TextureType.CubeArray:
|
||||
return 4;
|
||||
default:
|
||||
throw new NotImplementedException($"TextureTpe.{TextureType} not implemented yet");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs
Normal file
18
Ryujinx.Graphics/Texture/TextureInstructionSuffix.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
[Flags]
|
||||
enum TextureInstructionSuffix
|
||||
{
|
||||
None = 0x00, // No Modifier
|
||||
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?
|
||||
DC = 0x80, // Depth Compare
|
||||
AOFFI = 0x100, // Offset
|
||||
MZ = 0x200 // Multisample Zero?
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue