Implement TLD4

This commit is contained in:
gdkchan 2019-03-28 22:08:23 -03:00
parent 6f5367701f
commit f601f0d98f
12 changed files with 294 additions and 92 deletions

View file

@ -1460,7 +1460,7 @@ namespace Ryujinx.Graphics.Gal.Shader
// TODO: Support PTP
else if ((suffix & TextureInstructionSuffix.Ptp) != 0)
{
throw new NotImplementedException();
//throw new NotImplementedException();
}
return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString;

View file

@ -136,7 +136,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
typeName += "Array";
}
if ((type & TextureType.DepthCompare) != 0)
if ((type & TextureType.Shadow) != 0)
{
typeName += "Shadow";
}

View file

@ -251,21 +251,31 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
AstTextureOperation texOp = (AstTextureOperation)operation;
bool isShadow = (context.Info.Samplers[texOp.TextureHandle] & TextureType.DepthCompare) != 0;
bool isGather = (texOp.Flags & TextureFlags.Gather) != 0;
bool isShadow = (texOp.Type & TextureType.Shadow) != 0;
string samplerName = OperandManager.GetSamplerName(context.ShaderType, texOp.TextureHandle);
string texCall = "texture";
if ((texOp.Type & TextureType.LodLevel) != 0)
if (isGather)
{
texCall += "Gather";
}
if ((texOp.Flags & TextureFlags.LodLevel) != 0)
{
texCall += "Lod";
}
if ((texOp.Type & TextureType.Offset) != 0)
if ((texOp.Flags & TextureFlags.Offset) != 0)
{
texCall += "Offset";
}
else if ((texOp.Flags & TextureFlags.Offsets) != 0)
{
texCall += "Offsets";
}
texCall += "(" + samplerName;
@ -292,12 +302,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
arrayIndexElem = pCount++;
}
if ((texOp.Type & TextureType.DepthCompare) != 0)
if (isShadow && !isGather)
{
pCount++;
}
bool hasExtraCompareArg = false;
//On textureGather*, the comparison value is always specified as an extra argument.
bool hasExtraCompareArg = isShadow && isGather;
if (pCount == 5)
{
@ -348,24 +359,48 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
texCall += ", " + Src(VariableType.F32);
}
if ((texOp.Type & TextureType.LodLevel) != 0)
if ((texOp.Flags & TextureFlags.LodLevel) != 0)
{
texCall += ", " + Src(VariableType.F32);
}
if ((texOp.Type & TextureType.Offset) != 0)
if ((texOp.Flags & TextureFlags.Offset) != 0)
{
texCall += ", " + AssembleVector(elemsCount, VariableType.S32);
}
else if ((texOp.Flags & TextureFlags.Offsets) != 0)
{
const int gatherTexelsCount = 4;
if ((texOp.Type & TextureType.LodBias) != 0)
texCall += $", ivec{elemsCount}[{gatherTexelsCount}](";
for (int index = 0; index < gatherTexelsCount; index++)
{
texCall += AssembleVector(elemsCount, VariableType.S32);
if (index < gatherTexelsCount - 1)
{
texCall += ", ";
}
}
texCall += ")";
}
if ((texOp.Flags & TextureFlags.LodBias) != 0)
{
texCall += ", " + Src(VariableType.F32);
}
//textureGather* optional extra component index, not needed for shadow samplers.
if (isGather && !isShadow)
{
texCall += ", " + Src(VariableType.S32);
}
texCall += ")";
if (!isShadow)
if (isGather || !isShadow)
{
texCall += ".";

View file

@ -123,6 +123,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
Set("1111000011111x", InstEmit.Sync, typeof(OpCodeSync));
Set("110000xxxx111x", InstEmit.Tex, typeof(OpCodeTex));
Set("1101x00xxxxxxx", InstEmit.Texs, typeof(OpCodeTexs));
Set("110010xxxx111x", InstEmit.Tld4, typeof(OpCodeTex));
Set("0100111xxxxxxx", InstEmit.Xmad, typeof(OpCodeAluCbuf));
Set("0011011x00xxxx", InstEmit.Xmad, typeof(OpCodeAluImm));
Set("010100010xxxxx", InstEmit.Xmad, typeof(OpCodeAluRegCbuf));

View file

@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
return Const(0);
}
return Register(new Register(raIndex++, RegisterType.Gpr));
return context.Copy(Register(new Register(raIndex++, RegisterType.Gpr)));
}
Operand Rb()
@ -166,36 +166,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
return Const(0);
}
return Register(new Register(rbIndex++, RegisterType.Gpr));
return context.Copy(Register(new Register(rbIndex++, RegisterType.Gpr)));
}
Operand arrayIndex = op.IsArray ? Ra() : null;
List<Operand> sourcesList = new List<Operand>();
switch (op.Dimensions)
{
case TextureDimensions.Texture1D:
sourcesList.Add(Ra());
break;
case TextureDimensions.Texture2D:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
break;
case TextureDimensions.Texture3D:
case TextureDimensions.TextureCube:
sourcesList.Add(Ra());
sourcesList.Add(Ra());
sourcesList.Add(Ra());
break;
}
int elemsCount = sourcesList.Count;
TextureType type = GetTextureType(op.Dimensions);
TextureFlags flags = TextureFlags.None;
int elemsCount = GetTextureCoordsCount(type);
for (int index = 0; index < elemsCount; index++)
{
sourcesList.Add(Ra());
}
if (op.IsArray)
{
sourcesList.Add(arrayIndex);
@ -220,7 +208,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
sourcesList.Add(lodValue);
type |= TextureType.LodLevel;
flags |= TextureFlags.LodLevel;
}
if (op.HasOffset)
@ -230,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
}
type |= TextureType.Offset;
flags |= TextureFlags.Offset;
}
if (op.LodMode == TextureLodMode.LodBias ||
@ -238,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{
sourcesList.Add(lodValue);
type |= TextureType.LodBias;
flags |= TextureFlags.LodBias;
}
Operand[] sources = sourcesList.ToArray();
@ -266,6 +254,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureOperation operation = new TextureOperation(
Instruction.TextureSample,
type,
flags,
textureHandle,
compIndex,
dest,
@ -287,7 +276,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
List<Operand> sourcesList = new List<Operand>();
Operand GetSource(int index)
Operand Src(int index)
{
int regIndex = 0;
@ -308,17 +297,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (op.Type)
{
case TexsType.Texture1DLodZero:
sourcesList.Add(GetSource(0));
sourcesList.Add(Src(0));
break;
case TexsType.Texture2D:
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(2));
sourcesList.Add(Src(0));
sourcesList.Add(Src(2));
break;
case TexsType.Texture2DLodZero:
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(2));
sourcesList.Add(Src(0));
sourcesList.Add(Src(2));
sourcesList.Add(ConstF(0));
break;
@ -326,52 +315,53 @@ namespace Ryujinx.Graphics.Shader.Instructions
case TexsType.Texture2DDepthCompare:
case TexsType.Texture3D:
case TexsType.TextureCube:
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(Src(0));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
break;
case TexsType.Texture2DLodZeroDepthCompare:
case TexsType.Texture3DLodZero:
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(Src(0));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
sourcesList.Add(ConstF(0));
break;
case TexsType.Texture2DLodLevelDepthCompare:
case TexsType.TextureCubeLodLevel:
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(GetSource(3));
sourcesList.Add(Src(0));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
sourcesList.Add(Src(3));
break;
case TexsType.Texture2DArray:
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(GetSource(0));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
sourcesList.Add(Src(0));
break;
case TexsType.Texture2DArrayLodZero:
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(GetSource(0));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
sourcesList.Add(Src(0));
sourcesList.Add(ConstF(0));
break;
case TexsType.Texture2DArrayLodZeroDepthCompare:
sourcesList.Add(GetSource(1));
sourcesList.Add(GetSource(2));
sourcesList.Add(GetSource(0));
sourcesList.Add(GetSource(3));
sourcesList.Add(Src(1));
sourcesList.Add(Src(2));
sourcesList.Add(Src(0));
sourcesList.Add(Src(3));
sourcesList.Add(ConstF(0));
break;
}
Operand[] sources = sourcesList.ToArray();
TextureType type = GetTextureType(op.Type);
TextureType type = GetTextureType (op.Type);
TextureFlags flags = GetTextureFlags(op.Type);
int destIncrement = 0;
@ -408,6 +398,129 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureOperation operation = new TextureOperation(
Instruction.TextureSample,
type,
flags,
textureHandle,
compIndex,
dest,
sources);
context.Add(operation);
}
}
}
public static void Tld4(EmitterContext context)
{
OpCodeTex op = (OpCodeTex)context.CurrOp;
if (op.Rd.IsRZ)
{
return;
}
TextureGatherOffset offset = (TextureGatherOffset)op.RawOpCode.Extract(54, 2);
int gatherCompIndex = op.RawOpCode.Extract(56, 2);
int raIndex = op.Ra.Index;
int rbIndex = op.Rb.Index;
Operand Ra()
{
if (raIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return context.Copy(Register(new Register(raIndex++, RegisterType.Gpr)));
}
Operand Rb()
{
if (rbIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return context.Copy(Register(new Register(rbIndex++, RegisterType.Gpr)));
}
Operand arrayIndex = op.IsArray ? Ra() : null;
List<Operand> sourcesList = new List<Operand>();
TextureType type = GetTextureType(op.Dimensions);
TextureFlags flags = TextureFlags.Gather;
int elemsCount = GetTextureCoordsCount(type);
for (int index = 0; index < elemsCount; index++)
{
sourcesList.Add(Ra());
}
if (op.IsArray)
{
sourcesList.Add(arrayIndex);
type |= TextureType.Array;
}
Operand[] packedOffs = new Operand[2];
packedOffs[0] = offset != TextureGatherOffset.None ? Rb() : null;
packedOffs[1] = offset == TextureGatherOffset.Offsets ? Rb() : null;
if (op.HasDepthCompare)
{
sourcesList.Add(Rb());
}
if (offset != TextureGatherOffset.None)
{
int offsetTexelsCount = offset == TextureGatherOffset.Offsets ? 4 : 1;
for (int index = 0; index < elemsCount * offsetTexelsCount; index++)
{
Operand packed = packedOffs[(index >> 2) & 1];
sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6)));
}
flags |= offset == TextureGatherOffset.Offsets
? TextureFlags.Offsets
: TextureFlags.Offset;
}
sourcesList.Add(Const(gatherCompIndex));
Operand[] sources = sourcesList.ToArray();
int rdIndex = op.Rd.Index;
Operand GetDest()
{
if (rdIndex > RegisterConsts.RegisterZeroIndex)
{
return Const(0);
}
return Register(new Register(rdIndex++, RegisterType.Gpr));
}
int textureHandle = op.Immediate;
for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
{
if ((compMask & 1) != 0)
{
Operand dest = GetDest();
TextureOperation operation = new TextureOperation(
Instruction.TextureSample,
type,
flags,
textureHandle,
compIndex,
dest,
@ -431,47 +544,76 @@ namespace Ryujinx.Graphics.Shader.Instructions
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
}
private static int GetTextureCoordsCount(TextureType type)
{
switch (type & TextureType.Mask)
{
case TextureType.Texture1D: return 1;
case TextureType.Texture2D: return 2;
case TextureType.Texture3D: return 3;
case TextureType.TextureCube: return 3;
}
throw new ArgumentException($"Invalid texture type \"{type}\".");
}
private static TextureType GetTextureType(TexsType type)
{
switch (type)
{
case TexsType.Texture1DLodZero:
return TextureType.Texture1D | TextureType.LodLevel;
return TextureType.Texture1D;
case TexsType.Texture2D:
return TextureType.Texture2D;
case TexsType.Texture2DLodZero:
case TexsType.Texture2DLodLevel:
return TextureType.Texture2D | TextureType.LodLevel;
return TextureType.Texture2D;
case TexsType.Texture2DDepthCompare:
return TextureType.Texture2D | TextureType.DepthCompare;
case TexsType.Texture2DLodLevelDepthCompare:
case TexsType.Texture2DLodZeroDepthCompare:
return TextureType.Texture2D | TextureType.LodLevelDepthCompare;
return TextureType.Texture2D | TextureType.Shadow;
case TexsType.Texture2DArray:
case TexsType.Texture2DArrayLodZero:
return TextureType.Texture2D | TextureType.Array;
case TexsType.Texture2DArrayLodZero:
return TextureType.Texture2D | TextureType.Array | TextureType.LodLevel;
case TexsType.Texture2DArrayLodZeroDepthCompare:
return TextureType.Texture2D | TextureType.Array | TextureType.LodLevelDepthCompare;
return TextureType.Texture2D | TextureType.Array | TextureType.Shadow;
case TexsType.Texture3D:
case TexsType.Texture3DLodZero:
return TextureType.Texture3D;
case TexsType.Texture3DLodZero:
return TextureType.Texture3D | TextureType.LodLevel;
case TexsType.TextureCube:
return TextureType.TextureCube;
case TexsType.TextureCubeLodLevel:
return TextureType.TextureCube | TextureType.LodLevel;
return TextureType.TextureCube;
}
throw new ArgumentException($"Invalid texture type \"{type}\".");
}
private static TextureFlags GetTextureFlags(TexsType type)
{
switch (type)
{
case TexsType.Texture1DLodZero:
case TexsType.Texture2DLodZero:
case TexsType.Texture2DLodLevel:
case TexsType.Texture2DLodLevelDepthCompare:
case TexsType.Texture2DLodZeroDepthCompare:
case TexsType.Texture2DArrayLodZero:
case TexsType.Texture2DArrayLodZeroDepthCompare:
case TexsType.Texture3DLodZero:
case TexsType.TextureCubeLodLevel:
return TextureFlags.LodLevel;
case TexsType.Texture2D:
case TexsType.Texture2DDepthCompare:
case TexsType.Texture2DArray:
case TexsType.Texture3D:
case TexsType.TextureCube:
return TextureFlags.None;
}
throw new ArgumentException($"Invalid texture type \"{type}\".");

View file

@ -0,0 +1,9 @@
namespace Ryujinx.Graphics.Shader.Instructions
{
enum TextureGatherOffset
{
None = 0,
Offset = 1,
Offsets = 2
}
}

View file

@ -0,0 +1,15 @@
using System;
namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
[Flags]
enum TextureFlags
{
None = 0,
Gather = 1 << 0,
LodBias = 1 << 1,
LodLevel = 1 << 2,
Offset = 1 << 3,
Offsets = 1 << 4
}
}

View file

@ -2,7 +2,8 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
{
class TextureOperation : Operation
{
public TextureType Type { get; }
public TextureType Type { get; }
public TextureFlags Flags { get; }
public int TextureHandle { get; }
public int ComponentIndex { get; }
@ -10,12 +11,14 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public TextureOperation(
Instruction inst,
TextureType type,
TextureFlags flags,
int textureHandle,
int componentIndex,
Operand dest,
params Operand[] sources) : base(inst, dest, sources)
{
Type = type;
Flags = flags;
TextureHandle = textureHandle;
ComponentIndex = componentIndex;
}

View file

@ -12,12 +12,7 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
Mask = 0xff,
Array = 1 << 8,
DepthCompare = 1 << 9,
LodBias = 1 << 10,
LodLevel = 1 << 11,
Offset = 1 << 12,
LodLevelDepthCompare = LodLevel | DepthCompare
Array = 1 << 8,
Shadow = 1 << 9
}
}

View file

@ -4,7 +4,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
{
class AstTextureOperation : AstOperation
{
public TextureType Type { get; }
public TextureType Type { get; }
public TextureFlags Flags { get; }
public int TextureHandle { get; }
public int[] Components { get; }
@ -12,11 +13,13 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
public AstTextureOperation(
Instruction inst,
TextureType type,
TextureFlags flags,
int textureHandle,
int[] components,
params IAstNode[] sources) : base(inst, sources)
{
Type = type;
Flags = flags;
TextureHandle = textureHandle;
Components = components;
}

View file

@ -79,6 +79,7 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
astOperation = new AstTextureOperation(
inst,
texOp.Type,
texOp.Flags,
texOp.TextureHandle,
components,
sources);

View file

@ -103,8 +103,6 @@ namespace Ryujinx.Graphics.Shader.Translation
string glslProgram = generator.Generate(prgInfo, shaderType);
System.Console.WriteLine(glslProgram);
return glslProgram;
}
}