Implement TLD4

This commit is contained in:
gdkchan 2019-03-28 22:08:23 -03:00
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 // TODO: Support PTP
else if ((suffix & TextureInstructionSuffix.Ptp) != 0) else if ((suffix & TextureInstructionSuffix.Ptp) != 0)
{ {
throw new NotImplementedException(); //throw new NotImplementedException();
} }
return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString; return "textureGather(" + sampler + ", " + coords + ", " + comp + ")" + chString;

View file

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

View file

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

View file

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

View file

@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
return Const(0); return Const(0);
} }
return Register(new Register(raIndex++, RegisterType.Gpr)); return context.Copy(Register(new Register(raIndex++, RegisterType.Gpr)));
} }
Operand Rb() Operand Rb()
@ -166,36 +166,24 @@ namespace Ryujinx.Graphics.Shader.Instructions
return Const(0); 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; Operand arrayIndex = op.IsArray ? Ra() : null;
List<Operand> sourcesList = new List<Operand>(); 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); 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) if (op.IsArray)
{ {
sourcesList.Add(arrayIndex); sourcesList.Add(arrayIndex);
@ -220,7 +208,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
sourcesList.Add(lodValue); sourcesList.Add(lodValue);
type |= TextureType.LodLevel; flags |= TextureFlags.LodLevel;
} }
if (op.HasOffset) if (op.HasOffset)
@ -230,7 +218,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4))); sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
} }
type |= TextureType.Offset; flags |= TextureFlags.Offset;
} }
if (op.LodMode == TextureLodMode.LodBias || if (op.LodMode == TextureLodMode.LodBias ||
@ -238,7 +226,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
sourcesList.Add(lodValue); sourcesList.Add(lodValue);
type |= TextureType.LodBias; flags |= TextureFlags.LodBias;
} }
Operand[] sources = sourcesList.ToArray(); Operand[] sources = sourcesList.ToArray();
@ -266,6 +254,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureOperation operation = new TextureOperation( TextureOperation operation = new TextureOperation(
Instruction.TextureSample, Instruction.TextureSample,
type, type,
flags,
textureHandle, textureHandle,
compIndex, compIndex,
dest, dest,
@ -287,7 +276,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
List<Operand> sourcesList = new List<Operand>(); List<Operand> sourcesList = new List<Operand>();
Operand GetSource(int index) Operand Src(int index)
{ {
int regIndex = 0; int regIndex = 0;
@ -308,17 +297,17 @@ namespace Ryujinx.Graphics.Shader.Instructions
switch (op.Type) switch (op.Type)
{ {
case TexsType.Texture1DLodZero: case TexsType.Texture1DLodZero:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
break; break;
case TexsType.Texture2D: case TexsType.Texture2D:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
break; break;
case TexsType.Texture2DLodZero: case TexsType.Texture2DLodZero:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(ConstF(0)); sourcesList.Add(ConstF(0));
break; break;
@ -326,52 +315,53 @@ namespace Ryujinx.Graphics.Shader.Instructions
case TexsType.Texture2DDepthCompare: case TexsType.Texture2DDepthCompare:
case TexsType.Texture3D: case TexsType.Texture3D:
case TexsType.TextureCube: case TexsType.TextureCube:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
break; break;
case TexsType.Texture2DLodZeroDepthCompare: case TexsType.Texture2DLodZeroDepthCompare:
case TexsType.Texture3DLodZero: case TexsType.Texture3DLodZero:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(ConstF(0)); sourcesList.Add(ConstF(0));
break; break;
case TexsType.Texture2DLodLevelDepthCompare: case TexsType.Texture2DLodLevelDepthCompare:
case TexsType.TextureCubeLodLevel: case TexsType.TextureCubeLodLevel:
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(GetSource(3)); sourcesList.Add(Src(3));
break; break;
case TexsType.Texture2DArray: case TexsType.Texture2DArray:
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
break; break;
case TexsType.Texture2DArrayLodZero: case TexsType.Texture2DArrayLodZero:
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(ConstF(0)); sourcesList.Add(ConstF(0));
break; break;
case TexsType.Texture2DArrayLodZeroDepthCompare: case TexsType.Texture2DArrayLodZeroDepthCompare:
sourcesList.Add(GetSource(1)); sourcesList.Add(Src(1));
sourcesList.Add(GetSource(2)); sourcesList.Add(Src(2));
sourcesList.Add(GetSource(0)); sourcesList.Add(Src(0));
sourcesList.Add(GetSource(3)); sourcesList.Add(Src(3));
sourcesList.Add(ConstF(0)); sourcesList.Add(ConstF(0));
break; break;
} }
Operand[] sources = sourcesList.ToArray(); Operand[] sources = sourcesList.ToArray();
TextureType type = GetTextureType(op.Type); TextureType type = GetTextureType (op.Type);
TextureFlags flags = GetTextureFlags(op.Type);
int destIncrement = 0; int destIncrement = 0;
@ -408,6 +398,129 @@ namespace Ryujinx.Graphics.Shader.Instructions
TextureOperation operation = new TextureOperation( TextureOperation operation = new TextureOperation(
Instruction.TextureSample, Instruction.TextureSample,
type, 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, textureHandle,
compIndex, compIndex,
dest, dest,
@ -431,47 +544,76 @@ namespace Ryujinx.Graphics.Shader.Instructions
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\"."); 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) private static TextureType GetTextureType(TexsType type)
{ {
switch (type) switch (type)
{ {
case TexsType.Texture1DLodZero: case TexsType.Texture1DLodZero:
return TextureType.Texture1D | TextureType.LodLevel; return TextureType.Texture1D;
case TexsType.Texture2D: case TexsType.Texture2D:
return TextureType.Texture2D;
case TexsType.Texture2DLodZero: case TexsType.Texture2DLodZero:
case TexsType.Texture2DLodLevel: case TexsType.Texture2DLodLevel:
return TextureType.Texture2D | TextureType.LodLevel; return TextureType.Texture2D;
case TexsType.Texture2DDepthCompare: case TexsType.Texture2DDepthCompare:
return TextureType.Texture2D | TextureType.DepthCompare;
case TexsType.Texture2DLodLevelDepthCompare: case TexsType.Texture2DLodLevelDepthCompare:
case TexsType.Texture2DLodZeroDepthCompare: case TexsType.Texture2DLodZeroDepthCompare:
return TextureType.Texture2D | TextureType.LodLevelDepthCompare; return TextureType.Texture2D | TextureType.Shadow;
case TexsType.Texture2DArray: case TexsType.Texture2DArray:
case TexsType.Texture2DArrayLodZero:
return TextureType.Texture2D | TextureType.Array; return TextureType.Texture2D | TextureType.Array;
case TexsType.Texture2DArrayLodZero:
return TextureType.Texture2D | TextureType.Array | TextureType.LodLevel;
case TexsType.Texture2DArrayLodZeroDepthCompare: case TexsType.Texture2DArrayLodZeroDepthCompare:
return TextureType.Texture2D | TextureType.Array | TextureType.LodLevelDepthCompare; return TextureType.Texture2D | TextureType.Array | TextureType.Shadow;
case TexsType.Texture3D: case TexsType.Texture3D:
case TexsType.Texture3DLodZero:
return TextureType.Texture3D; return TextureType.Texture3D;
case TexsType.Texture3DLodZero:
return TextureType.Texture3D | TextureType.LodLevel;
case TexsType.TextureCube: case TexsType.TextureCube:
return TextureType.TextureCube;
case TexsType.TextureCubeLodLevel: 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}\"."); 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 class TextureOperation : Operation
{ {
public TextureType Type { get; } public TextureType Type { get; }
public TextureFlags Flags { get; }
public int TextureHandle { get; } public int TextureHandle { get; }
public int ComponentIndex { get; } public int ComponentIndex { get; }
@ -10,12 +11,14 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
public TextureOperation( public TextureOperation(
Instruction inst, Instruction inst,
TextureType type, TextureType type,
TextureFlags flags,
int textureHandle, int textureHandle,
int componentIndex, int componentIndex,
Operand dest, Operand dest,
params Operand[] sources) : base(inst, dest, sources) params Operand[] sources) : base(inst, dest, sources)
{ {
Type = type; Type = type;
Flags = flags;
TextureHandle = textureHandle; TextureHandle = textureHandle;
ComponentIndex = componentIndex; ComponentIndex = componentIndex;
} }

View file

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

View file

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

View file

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

View file

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