Initial non 2D textures support (#525)
* Initial non 2D textures support - Shaders still need to be changed - Some types aren't yet implemented * 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 * Support depth in read/writeTexture Also support WrapR and detect mipmap * Proper cube map textures support + fix TEXS.LZ * Implement depth compare * some code clean up * Implement CubeMap textures in OGLTexture.Create * Implement TLD4 and TLD4S * Add Texture 1D support * updates comments * fix some code style issues * Fix some nits + rename some things to be less confusing * Remove GetSuffix local functions * AOFFI => AOffI * TextureType => GalTextureTarget * finish renaming TextureType to TextureTarget * Disable LL, LZ and LB support in the decompiler This needs more work at the GL level (GLSL implementation should be right) * Revert "Disable LL, LZ and LB support in the decompiler" This reverts commit 64536c3d9f673645faff3152838d1413c3203395. * Fix TEXS ARRAY_2D index * ImageFormat depth should be 1 for all image format * Fix shader build issues with sampler1DShadow and texture * Fix DC & AOFFI combinaison with TEX/TEXS * Support AOFFI with TLD4 and TLD4S * Fix shader compilation error for TLD4.AOFFI with no DC * Fix binding isuses on the 2d copy engine TODO: support 2d array copy * Support 2D array copy operation in the 2D engine This make every copy right in the GPU side. Thie CPU copy probably needs to be updated * Implement GetGpuSize + fix somes issues with 2d engine copies TODO: mipmap level in it * Don't throw an exception in the layer handling * Fix because of rebase * Reject 2d layers of non textures in 2d copy engine * Add 3D textures and mipmap support on BlockLinearSwizzle * Fix naming on new BitUtils methods * gpu cache: Make sure to invalidate textures that doesn't have the same target * Add the concept of layer count for array instead of using depth Also cleanup GetGpuSize as Swizzle can compute the size with mipmap * Support multi layer with mip map in ReadTexture * Add more check for cache invalidation & remove cubemap and cubemap array code for now Also fix compressed 2d array * Fix texelFetchOffset shader build error * Start looking into cube map again Also add some way to log write in register in engines * fix write register log levles * Remove debug logs in WriteRegister * Disable AOFFI support on non NVIDIA drivers * Fix code align
This commit is contained in:
parent
81aa50feb0
commit
884b4e5fd3
39 changed files with 2084 additions and 370 deletions
|
@ -1,3 +1,4 @@
|
|||
using Ryujinx.Graphics.Texture;
|
||||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Gal.Shader.ShaderDecodeHelper;
|
||||
|
@ -29,6 +30,75 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{ RGB_, RG_A, R_BA, _GBA, RGBA, ____, ____, ____ }
|
||||
};
|
||||
|
||||
private static GalTextureTarget TexToTextureTarget(int TexType, bool IsArray)
|
||||
{
|
||||
switch (TexType)
|
||||
{
|
||||
case 0:
|
||||
return IsArray ? GalTextureTarget.OneDArray : GalTextureTarget.OneD;
|
||||
case 2:
|
||||
return IsArray ? GalTextureTarget.TwoDArray : GalTextureTarget.TwoD;
|
||||
case 4:
|
||||
if (IsArray)
|
||||
throw new InvalidOperationException($"ARRAY bit set on a TEX with 3D texture!");
|
||||
return GalTextureTarget.ThreeD;
|
||||
case 6:
|
||||
return IsArray ? GalTextureTarget.CubeArray : GalTextureTarget.CubeMap;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
private static GalTextureTarget TexsToTextureTarget(int TexType)
|
||||
{
|
||||
switch (TexType)
|
||||
{
|
||||
case 0:
|
||||
return GalTextureTarget.OneD;
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
case 8:
|
||||
case 0xa:
|
||||
case 0xc:
|
||||
return GalTextureTarget.TwoD;
|
||||
case 0xe:
|
||||
case 0x10:
|
||||
case 0x12:
|
||||
return GalTextureTarget.TwoDArray;
|
||||
case 0x14:
|
||||
case 0x16:
|
||||
return GalTextureTarget.ThreeD;
|
||||
case 0x18:
|
||||
case 0x1a:
|
||||
return GalTextureTarget.CubeMap;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static GalTextureTarget TldsToTextureTarget(int TexType)
|
||||
{
|
||||
switch (TexType)
|
||||
{
|
||||
case 0:
|
||||
case 2:
|
||||
return GalTextureTarget.OneD;
|
||||
case 4:
|
||||
case 8:
|
||||
case 0xa:
|
||||
case 0xc:
|
||||
case 0x18:
|
||||
return GalTextureTarget.TwoD;
|
||||
case 0x10:
|
||||
return GalTextureTarget.TwoDArray;
|
||||
case 0xe:
|
||||
return GalTextureTarget.ThreeD;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ld_A(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
ShaderIrNode[] Opers = OpCode.Abuf20();
|
||||
|
@ -132,43 +202,166 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Tex(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: false);
|
||||
TextureInstructionSuffix Suffix;
|
||||
|
||||
int RawSuffix = OpCode.Read(0x34, 0x38);
|
||||
|
||||
switch (RawSuffix)
|
||||
{
|
||||
case 0:
|
||||
Suffix = TextureInstructionSuffix.None;
|
||||
break;
|
||||
case 0x8:
|
||||
Suffix = TextureInstructionSuffix.LZ;
|
||||
break;
|
||||
case 0x10:
|
||||
Suffix = TextureInstructionSuffix.LB;
|
||||
break;
|
||||
case 0x18:
|
||||
Suffix = TextureInstructionSuffix.LL;
|
||||
break;
|
||||
case 0x30:
|
||||
Suffix = TextureInstructionSuffix.LBA;
|
||||
break;
|
||||
case 0x38:
|
||||
Suffix = TextureInstructionSuffix.LLA;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEX instruction {RawSuffix}");
|
||||
}
|
||||
|
||||
bool IsOffset = OpCode.Read(0x36);
|
||||
|
||||
if (IsOffset)
|
||||
Suffix |= TextureInstructionSuffix.AOffI;
|
||||
|
||||
EmitTex(Block, OpCode, Suffix, GprHandle: false);
|
||||
}
|
||||
|
||||
public static void Tex_B(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTex(Block, OpCode, GprHandle: true);
|
||||
TextureInstructionSuffix Suffix;
|
||||
|
||||
int RawSuffix = OpCode.Read(0x24, 0xe);
|
||||
|
||||
switch (RawSuffix)
|
||||
{
|
||||
case 0:
|
||||
Suffix = TextureInstructionSuffix.None;
|
||||
break;
|
||||
case 0x2:
|
||||
Suffix = TextureInstructionSuffix.LZ;
|
||||
break;
|
||||
case 0x4:
|
||||
Suffix = TextureInstructionSuffix.LB;
|
||||
break;
|
||||
case 0x6:
|
||||
Suffix = TextureInstructionSuffix.LL;
|
||||
break;
|
||||
case 0xc:
|
||||
Suffix = TextureInstructionSuffix.LBA;
|
||||
break;
|
||||
case 0xe:
|
||||
Suffix = TextureInstructionSuffix.LLA;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEX.B instruction {RawSuffix}");
|
||||
}
|
||||
|
||||
bool IsOffset = OpCode.Read(0x23);
|
||||
|
||||
if (IsOffset)
|
||||
Suffix |= TextureInstructionSuffix.AOffI;
|
||||
|
||||
EmitTex(Block, OpCode, Suffix, 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 other formats.
|
||||
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[2];
|
||||
bool IsArray = OpCode.HasArray();
|
||||
|
||||
for (int Index = 0; Index < Coords.Length; Index++)
|
||||
GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
|
||||
|
||||
bool HasDepthCompare = OpCode.Read(0x32);
|
||||
|
||||
if (HasDepthCompare)
|
||||
{
|
||||
TextureInstructionSuffix |= TextureInstructionSuffix.DC;
|
||||
}
|
||||
|
||||
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
|
||||
|
||||
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;
|
||||
|
||||
CoordReg.Index += IndexExtraCoord;
|
||||
|
||||
if (!CoordReg.IsValidRegister)
|
||||
{
|
||||
CoordReg.Index = ShaderIrOperGpr.ZRIndex;
|
||||
}
|
||||
|
||||
Coords[Index] = ShaderIrOperGpr.MakeTemporary(Index);
|
||||
|
||||
Block.AddNode(new ShaderIrAsg(Coords[Index], CoordReg));
|
||||
Coords[Index] = CoordReg;
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
ShaderIrInst Inst = GprHandle ? ShaderIrInst.Texb : ShaderIrInst.Texs;
|
||||
|
||||
Coords = CoordsRegistersToTempRegisters(Block, Coords);
|
||||
|
||||
int RegInc = 0;
|
||||
|
||||
for (int Ch = 0; Ch < 4; Ch++)
|
||||
|
@ -187,9 +380,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
continue;
|
||||
}
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, 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)));
|
||||
}
|
||||
|
@ -197,17 +395,238 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
public static void Texs(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs);
|
||||
TextureInstructionSuffix Suffix;
|
||||
|
||||
int RawSuffix = OpCode.Read(0x34, 0x1e);
|
||||
|
||||
switch (RawSuffix)
|
||||
{
|
||||
case 0:
|
||||
case 0x4:
|
||||
case 0x10:
|
||||
case 0x16:
|
||||
Suffix = TextureInstructionSuffix.LZ;
|
||||
break;
|
||||
case 0x6:
|
||||
case 0x1a:
|
||||
Suffix = TextureInstructionSuffix.LL;
|
||||
break;
|
||||
case 0x8:
|
||||
Suffix = TextureInstructionSuffix.DC;
|
||||
break;
|
||||
case 0x2:
|
||||
case 0xe:
|
||||
case 0x14:
|
||||
case 0x18:
|
||||
Suffix = TextureInstructionSuffix.None;
|
||||
break;
|
||||
case 0xa:
|
||||
Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.DC;
|
||||
break;
|
||||
case 0xc:
|
||||
case 0x12:
|
||||
Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.DC;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TEXS instruction {RawSuffix}");
|
||||
}
|
||||
|
||||
GalTextureTarget TextureTarget = TexsToTextureTarget(OpCode.Read(52, 0x1e));
|
||||
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Texs, TextureTarget, Suffix);
|
||||
}
|
||||
|
||||
public static void Tlds(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf);
|
||||
TextureInstructionSuffix Suffix;
|
||||
|
||||
int RawSuffix = OpCode.Read(0x34, 0x1e);
|
||||
|
||||
switch (RawSuffix)
|
||||
{
|
||||
case 0:
|
||||
case 0x4:
|
||||
case 0x8:
|
||||
Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.AOffI;
|
||||
break;
|
||||
case 0xc:
|
||||
Suffix = TextureInstructionSuffix.LZ | TextureInstructionSuffix.MZ;
|
||||
break;
|
||||
case 0xe:
|
||||
case 0x10:
|
||||
Suffix = TextureInstructionSuffix.LZ;
|
||||
break;
|
||||
case 0x2:
|
||||
case 0xa:
|
||||
Suffix = TextureInstructionSuffix.LL;
|
||||
break;
|
||||
case 0x18:
|
||||
Suffix = TextureInstructionSuffix.LL | TextureInstructionSuffix.AOffI;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException($"Invalid Suffix for TLDS instruction {RawSuffix}");
|
||||
}
|
||||
|
||||
GalTextureTarget TextureTarget = TldsToTextureTarget(OpCode.Read(52, 0x1e));
|
||||
|
||||
EmitTexs(Block, OpCode, ShaderIrInst.Txlf, TextureTarget, Suffix);
|
||||
}
|
||||
|
||||
private static void EmitTexs(ShaderIrBlock Block, long OpCode, ShaderIrInst Inst)
|
||||
public static void Tld4(ShaderIrBlock Block, long OpCode, int Position)
|
||||
{
|
||||
//TODO: Support other formats.
|
||||
TextureInstructionSuffix Suffix;
|
||||
|
||||
int RawSuffix = OpCode.Read(0x34, 0xc);
|
||||
|
||||
switch (RawSuffix)
|
||||
{
|
||||
case 0:
|
||||
Suffix = TextureInstructionSuffix.None;
|
||||
break;
|
||||
case 0x4:
|
||||
Suffix = TextureInstructionSuffix.AOffI;
|
||||
break;
|
||||
case 0x8:
|
||||
Suffix = TextureInstructionSuffix.PTP;
|
||||
break;
|
||||
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);
|
||||
|
||||
GalTextureTarget TextureTarget = TexToTextureTarget(OpCode.Read(28, 6), IsArray);
|
||||
|
||||
if (IsShadow)
|
||||
{
|
||||
Suffix |= TextureInstructionSuffix.DC;
|
||||
}
|
||||
|
||||
EmitTld4(Block, OpCode, TextureTarget, 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, GalTextureTarget.TwoD, Suffix, RGBA, OpCode.Read(0x34, 0x3), true);
|
||||
}
|
||||
|
||||
private static void EmitTexs(ShaderIrBlock Block,
|
||||
long OpCode,
|
||||
ShaderIrInst Inst,
|
||||
GalTextureTarget TextureTarget,
|
||||
TextureInstructionSuffix TextureInstructionSuffix)
|
||||
{
|
||||
if (Inst == ShaderIrInst.Txlf && TextureTarget == GalTextureTarget.CubeArray)
|
||||
{
|
||||
throw new InvalidOperationException("TLDS instructions cannot use CUBE modifier!");
|
||||
}
|
||||
|
||||
bool IsArray = ImageUtils.IsArray(TextureTarget);
|
||||
|
||||
ShaderIrOperGpr[] Coords = new ShaderIrOperGpr[ImageUtils.GetCoordsCountTextureTarget(TextureTarget)];
|
||||
|
||||
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] = OpCode.Gpr8();
|
||||
}
|
||||
|
||||
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 && TextureInstructionSuffix != TextureInstructionSuffix.LZ && TextureTarget == GalTextureTarget.TwoD)
|
||||
{
|
||||
Coords[Coords.Length - CoordStartIndex - 1] = OpCode.Gpr8();
|
||||
Coords[Coords.Length - CoordStartIndex - 1].Index += Coords.Length - CoordStartIndex - 1;
|
||||
OperBIndex--;
|
||||
}
|
||||
|
||||
// TODO: Find what MZ does and what changes 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;
|
||||
|
||||
LutIndex = !OpCode.Gpr0().IsConst ? 1 : 0;
|
||||
|
@ -276,12 +695,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
|
||||
ShaderIrNode OperC = OpCode.Imm13_36();
|
||||
|
||||
ShaderIrOperGpr Coord0 = ShaderIrOperGpr.MakeTemporary(0);
|
||||
ShaderIrOperGpr Coord1 = ShaderIrOperGpr.MakeTemporary(1);
|
||||
|
||||
Block.AddNode(new ShaderIrAsg(Coord0, OpCode.Gpr8()));
|
||||
Block.AddNode(new ShaderIrAsg(Coord1, OpCode.Gpr20()));
|
||||
Coords = CoordsRegistersToTempRegisters(Block, Coords);
|
||||
|
||||
for (int Ch = 0; Ch < 4; Ch++)
|
||||
{
|
||||
|
@ -290,9 +704,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
continue;
|
||||
}
|
||||
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch);
|
||||
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, Coord0, Coord1, OperC, Meta);
|
||||
ShaderIrMetaTex Meta = new ShaderIrMetaTex(Ch, TextureTarget, TextureInstructionSuffix, Coords)
|
||||
{
|
||||
LevelOfDetail = LevelOfDetail,
|
||||
Offset = Offset,
|
||||
DepthCompare = DepthCompare
|
||||
};
|
||||
ShaderIrOp Op = new ShaderIrOp(Inst, OperA, OperB, OperC, Meta);
|
||||
|
||||
ShaderIrOperGpr Dst = GetDst();
|
||||
|
||||
|
@ -303,9 +721,156 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitTld4(ShaderIrBlock Block, long OpCode, GalTextureTarget 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.GetCoordsCountTextureTarget(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 == GalTextureTarget.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++;
|
||||
}
|
||||
|
||||
Coords = CoordsRegistersToTempRegisters(Block, Coords);
|
||||
|
||||
int RegInc = 0;
|
||||
|
||||
for (int Ch = 0; Ch < 4; Ch++)
|
||||
{
|
||||
if (!IsChannelUsed(ChMask, Ch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
ShaderIrOperGpr Dst = OpCode.Gpr0();
|
||||
|
||||
Dst.Index += RegInc++;
|
||||
|
||||
if (!Dst.IsValidRegister || Dst.IsConst)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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)));
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsChannelUsed(int ChMask, int Ch)
|
||||
{
|
||||
return (ChMask & (1 << Ch)) != 0;
|
||||
}
|
||||
|
||||
private static ShaderIrOperGpr[] CoordsRegistersToTempRegisters(ShaderIrBlock Block, params ShaderIrOperGpr[] Registers)
|
||||
{
|
||||
ShaderIrOperGpr[] Res = new ShaderIrOperGpr[Registers.Length];
|
||||
|
||||
for (int Index = 0; Index < Res.Length; Index++)
|
||||
{
|
||||
Res[Index] = ShaderIrOperGpr.MakeTemporary(Index);
|
||||
Block.AddNode(new ShaderIrAsg(Res[Index], Registers[Index]));
|
||||
}
|
||||
|
||||
return Res;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue