Move texture instructions into a separate file
This commit is contained in:
parent
ba15713cf4
commit
66bc1511db
2 changed files with 767 additions and 756 deletions
|
@ -1,8 +1,6 @@
|
||||||
using Ryujinx.Graphics.Shader.Decoders;
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
using Ryujinx.Graphics.Shader.Translation;
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
|
@ -136,759 +134,5 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
context.EndPrimitive();
|
context.EndPrimitive();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Tex(EmitterContext context)
|
|
||||||
{
|
|
||||||
Tex(context, TextureFlags.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Tex_B(EmitterContext context)
|
|
||||||
{
|
|
||||||
Tex(context, TextureFlags.Bindless);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Tld(EmitterContext context)
|
|
||||||
{
|
|
||||||
Tex(context, TextureFlags.IntCoords);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Tld_B(EmitterContext context)
|
|
||||||
{
|
|
||||||
Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Texs(EmitterContext context)
|
|
||||||
{
|
|
||||||
OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp;
|
|
||||||
|
|
||||||
if (op.Rd0.IsRZ && op.Rd1.IsRZ)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Operand> sourcesList = new List<Operand>();
|
|
||||||
|
|
||||||
int raIndex = op.Ra.Index;
|
|
||||||
int rbIndex = op.Rb.Index;
|
|
||||||
|
|
||||||
Operand Ra()
|
|
||||||
{
|
|
||||||
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand Rb()
|
|
||||||
{
|
|
||||||
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureType type;
|
|
||||||
TextureFlags flags;
|
|
||||||
|
|
||||||
if (op is OpCodeTexs texsOp)
|
|
||||||
{
|
|
||||||
type = GetTextureType (texsOp.Type);
|
|
||||||
flags = GetTextureFlags(texsOp.Type);
|
|
||||||
|
|
||||||
if ((type & TextureType.Array) != 0)
|
|
||||||
{
|
|
||||||
Operand arrayIndex = Ra();
|
|
||||||
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
|
|
||||||
sourcesList.Add(arrayIndex);
|
|
||||||
|
|
||||||
if ((type & TextureType.Shadow) != 0)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((flags & TextureFlags.LodLevel) != 0)
|
|
||||||
{
|
|
||||||
sourcesList.Add(ConstF(0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (texsOp.Type)
|
|
||||||
{
|
|
||||||
case TextureScalarType.Texture1DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2D:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(ConstF(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DLodLevel:
|
|
||||||
case TextureScalarType.Texture2DDepthCompare:
|
|
||||||
case TextureScalarType.Texture3D:
|
|
||||||
case TextureScalarType.TextureCube:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
|
||||||
case TextureScalarType.Texture3DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(ConstF(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
|
||||||
case TextureScalarType.TextureCubeLodLevel:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (op is OpCodeTlds tldsOp)
|
|
||||||
{
|
|
||||||
type = GetTextureType (tldsOp.Type);
|
|
||||||
flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords;
|
|
||||||
|
|
||||||
switch (tldsOp.Type)
|
|
||||||
{
|
|
||||||
case TexelLoadScalarType.Texture1DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Const(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture1DLodLevel:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Const(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Const(0));
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevel:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture3DLodZero:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Const(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DArrayLodZero:
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Const(0));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (op is OpCodeTld4s tld4sOp)
|
|
||||||
{
|
|
||||||
if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset))
|
|
||||||
{
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
}
|
|
||||||
|
|
||||||
type = TextureType.Texture2D;
|
|
||||||
flags = TextureFlags.Gather;
|
|
||||||
|
|
||||||
if (tld4sOp.HasDepthCompare)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
|
|
||||||
type |= TextureType.Shadow;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tld4sOp.HasOffset)
|
|
||||||
{
|
|
||||||
Operand packedOffs = Rb();
|
|
||||||
|
|
||||||
for (int index = 0; index < type.GetCoordsCount(); index++)
|
|
||||||
{
|
|
||||||
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6)));
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= TextureFlags.Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
sourcesList.Add(Const(tld4sOp.GatherCompIndex));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = sourcesList.ToArray();
|
|
||||||
|
|
||||||
Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) };
|
|
||||||
Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) };
|
|
||||||
|
|
||||||
int destIncrement = 0;
|
|
||||||
|
|
||||||
Operand GetDest()
|
|
||||||
{
|
|
||||||
int high = destIncrement >> 1;
|
|
||||||
int low = destIncrement & 1;
|
|
||||||
|
|
||||||
destIncrement++;
|
|
||||||
|
|
||||||
if (op.IsFp16)
|
|
||||||
{
|
|
||||||
return high != 0
|
|
||||||
? (rd1[low] = Local())
|
|
||||||
: (rd0[low] = Local());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index;
|
|
||||||
|
|
||||||
if (rdIndex < RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
rdIndex += low;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Register(rdIndex, RegisterType.Gpr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle = 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,
|
|
||||||
handle,
|
|
||||||
compIndex,
|
|
||||||
dest,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.IsFp16)
|
|
||||||
{
|
|
||||||
context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1]));
|
|
||||||
context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Tld4(EmitterContext context)
|
|
||||||
{
|
|
||||||
OpCodeTld4 op = (OpCodeTld4)context.CurrOp;
|
|
||||||
|
|
||||||
if (op.Rd.IsRZ)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int raIndex = op.Ra.Index;
|
|
||||||
int rbIndex = op.Rb.Index;
|
|
||||||
|
|
||||||
Operand Ra()
|
|
||||||
{
|
|
||||||
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand Rb()
|
|
||||||
{
|
|
||||||
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(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 coordsCount = type.GetCoordsCount();
|
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.IsArray)
|
|
||||||
{
|
|
||||||
sourcesList.Add(arrayIndex);
|
|
||||||
|
|
||||||
type |= TextureType.Array;
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] packedOffs = new Operand[2];
|
|
||||||
|
|
||||||
packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null;
|
|
||||||
packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null;
|
|
||||||
|
|
||||||
if (op.HasDepthCompare)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.Offset != TextureGatherOffset.None)
|
|
||||||
{
|
|
||||||
int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1;
|
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount * offsetTexelsCount; index++)
|
|
||||||
{
|
|
||||||
Operand packed = packedOffs[(index >> 2) & 1];
|
|
||||||
|
|
||||||
sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6)));
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= op.Offset == TextureGatherOffset.Offsets
|
|
||||||
? TextureFlags.Offsets
|
|
||||||
: TextureFlags.Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
sourcesList.Add(Const(op.GatherCompIndex));
|
|
||||||
|
|
||||||
Operand[] sources = sourcesList.ToArray();
|
|
||||||
|
|
||||||
int rdIndex = op.Rd.Index;
|
|
||||||
|
|
||||||
Operand GetDest()
|
|
||||||
{
|
|
||||||
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Register(rdIndex++, RegisterType.Gpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle = 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,
|
|
||||||
handle,
|
|
||||||
compIndex,
|
|
||||||
dest,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Txq(EmitterContext context)
|
|
||||||
{
|
|
||||||
Txq(context, bindless: false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Txq_B(EmitterContext context)
|
|
||||||
{
|
|
||||||
Txq(context, bindless: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Txq(EmitterContext context, bool bindless)
|
|
||||||
{
|
|
||||||
OpCodeTex op = (OpCodeTex)context.CurrOp;
|
|
||||||
|
|
||||||
if (op.Rd.IsRZ)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6);
|
|
||||||
|
|
||||||
//TODO: Validate and use property.
|
|
||||||
Instruction inst = Instruction.TextureSize;
|
|
||||||
|
|
||||||
TextureType type = TextureType.Texture2D;
|
|
||||||
|
|
||||||
TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
|
|
||||||
|
|
||||||
int raIndex = op.Ra.Index;
|
|
||||||
|
|
||||||
Operand Ra()
|
|
||||||
{
|
|
||||||
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Operand> sourcesList = new List<Operand>();
|
|
||||||
|
|
||||||
if (bindless)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
}
|
|
||||||
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
|
|
||||||
Operand[] sources = sourcesList.ToArray();
|
|
||||||
|
|
||||||
int rdIndex = op.Rd.Index;
|
|
||||||
|
|
||||||
Operand GetDest()
|
|
||||||
{
|
|
||||||
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Register(rdIndex++, RegisterType.Gpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle = !bindless ? op.Immediate : 0;
|
|
||||||
|
|
||||||
for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
|
||||||
{
|
|
||||||
if ((compMask & 1) != 0)
|
|
||||||
{
|
|
||||||
Operand dest = GetDest();
|
|
||||||
|
|
||||||
TextureOperation operation = new TextureOperation(
|
|
||||||
inst,
|
|
||||||
type,
|
|
||||||
flags,
|
|
||||||
handle,
|
|
||||||
compIndex,
|
|
||||||
dest,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void Tex(EmitterContext context, TextureFlags flags)
|
|
||||||
{
|
|
||||||
OpCodeTexture op = (OpCodeTexture)context.CurrOp;
|
|
||||||
|
|
||||||
bool isBindless = (flags & TextureFlags.Bindless) != 0;
|
|
||||||
bool intCoords = (flags & TextureFlags.IntCoords) != 0;
|
|
||||||
|
|
||||||
if (op.Rd.IsRZ)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int raIndex = op.Ra.Index;
|
|
||||||
int rbIndex = op.Rb.Index;
|
|
||||||
|
|
||||||
Operand Ra()
|
|
||||||
{
|
|
||||||
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand Rb()
|
|
||||||
{
|
|
||||||
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand arrayIndex = op.IsArray ? Ra() : null;
|
|
||||||
|
|
||||||
List<Operand> sourcesList = new List<Operand>();
|
|
||||||
|
|
||||||
if (isBindless)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
|
|
||||||
TextureType type = GetTextureType(op.Dimensions);
|
|
||||||
|
|
||||||
int coordsCount = type.GetCoordsCount();
|
|
||||||
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Ra());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.IsArray)
|
|
||||||
{
|
|
||||||
sourcesList.Add(arrayIndex);
|
|
||||||
|
|
||||||
type |= TextureType.Array;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasLod = op.LodMode > TextureLodMode.LodZero;
|
|
||||||
|
|
||||||
Operand lodValue = hasLod ? Rb() : ConstF(0);
|
|
||||||
|
|
||||||
Operand packedOffs = op.HasOffset ? Rb() : null;
|
|
||||||
|
|
||||||
if (op is OpCodeTex texOp && texOp.HasDepthCompare)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.LodMode == TextureLodMode.LodZero ||
|
|
||||||
op.LodMode == TextureLodMode.LodLevel ||
|
|
||||||
op.LodMode == TextureLodMode.LodLevelA)
|
|
||||||
{
|
|
||||||
sourcesList.Add(lodValue);
|
|
||||||
|
|
||||||
flags |= TextureFlags.LodLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.HasOffset)
|
|
||||||
{
|
|
||||||
for (int index = 0; index < coordsCount; index++)
|
|
||||||
{
|
|
||||||
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
|
|
||||||
}
|
|
||||||
|
|
||||||
flags |= TextureFlags.Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op.LodMode == TextureLodMode.LodBias ||
|
|
||||||
op.LodMode == TextureLodMode.LodBiasA)
|
|
||||||
{
|
|
||||||
sourcesList.Add(lodValue);
|
|
||||||
|
|
||||||
flags |= TextureFlags.LodBias;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (op is OpCodeTld tldOp && tldOp.IsMultisample)
|
|
||||||
{
|
|
||||||
sourcesList.Add(Rb());
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand[] sources = sourcesList.ToArray();
|
|
||||||
|
|
||||||
int rdIndex = op.Rd.Index;
|
|
||||||
|
|
||||||
Operand GetDest()
|
|
||||||
{
|
|
||||||
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
|
||||||
{
|
|
||||||
return Const(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Register(rdIndex++, RegisterType.Gpr);
|
|
||||||
}
|
|
||||||
|
|
||||||
int handle = !isBindless ? op.Immediate : 0;
|
|
||||||
|
|
||||||
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,
|
|
||||||
handle,
|
|
||||||
compIndex,
|
|
||||||
dest,
|
|
||||||
sources);
|
|
||||||
|
|
||||||
context.Add(operation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextureType GetTextureType(TextureDimensions dimensions)
|
|
||||||
{
|
|
||||||
switch (dimensions)
|
|
||||||
{
|
|
||||||
case TextureDimensions.Texture1D: return TextureType.Texture1D;
|
|
||||||
case TextureDimensions.Texture2D: return TextureType.Texture2D;
|
|
||||||
case TextureDimensions.Texture3D: return TextureType.Texture3D;
|
|
||||||
case TextureDimensions.TextureCube: return TextureType.TextureCube;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextureType GetTextureType(TextureScalarType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case TextureScalarType.Texture1DLodZero:
|
|
||||||
return TextureType.Texture1D;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2D:
|
|
||||||
case TextureScalarType.Texture2DLodZero:
|
|
||||||
case TextureScalarType.Texture2DLodLevel:
|
|
||||||
return TextureType.Texture2D;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DDepthCompare:
|
|
||||||
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
|
||||||
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
|
||||||
return TextureType.Texture2D | TextureType.Shadow;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DArray:
|
|
||||||
case TextureScalarType.Texture2DArrayLodZero:
|
|
||||||
return TextureType.Texture2D | TextureType.Array;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2DArrayLodZeroDepthCompare:
|
|
||||||
return TextureType.Texture2D | TextureType.Array | TextureType.Shadow;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture3D:
|
|
||||||
case TextureScalarType.Texture3DLodZero:
|
|
||||||
return TextureType.Texture3D;
|
|
||||||
|
|
||||||
case TextureScalarType.TextureCube:
|
|
||||||
case TextureScalarType.TextureCubeLodLevel:
|
|
||||||
return TextureType.TextureCube;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextureType GetTextureType(TexelLoadScalarType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case TexelLoadScalarType.Texture1DLodZero:
|
|
||||||
case TexelLoadScalarType.Texture1DLodLevel:
|
|
||||||
return TextureType.Texture1D;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodZero:
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevel:
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
|
||||||
return TextureType.Texture2D;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
|
||||||
return TextureType.Texture2D | TextureType.Multisample;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture3DLodZero:
|
|
||||||
return TextureType.Texture3D;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DArrayLodZero:
|
|
||||||
return TextureType.Texture2D | TextureType.Array;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextureFlags GetTextureFlags(TextureScalarType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case TextureScalarType.Texture1DLodZero:
|
|
||||||
case TextureScalarType.Texture2DLodZero:
|
|
||||||
case TextureScalarType.Texture2DLodLevel:
|
|
||||||
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
|
||||||
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
|
||||||
case TextureScalarType.Texture2DArrayLodZero:
|
|
||||||
case TextureScalarType.Texture2DArrayLodZeroDepthCompare:
|
|
||||||
case TextureScalarType.Texture3DLodZero:
|
|
||||||
case TextureScalarType.TextureCubeLodLevel:
|
|
||||||
return TextureFlags.LodLevel;
|
|
||||||
|
|
||||||
case TextureScalarType.Texture2D:
|
|
||||||
case TextureScalarType.Texture2DDepthCompare:
|
|
||||||
case TextureScalarType.Texture2DArray:
|
|
||||||
case TextureScalarType.Texture3D:
|
|
||||||
case TextureScalarType.TextureCube:
|
|
||||||
return TextureFlags.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TextureFlags GetTextureFlags(TexelLoadScalarType type)
|
|
||||||
{
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case TexelLoadScalarType.Texture1DLodZero:
|
|
||||||
case TexelLoadScalarType.Texture1DLodLevel:
|
|
||||||
case TexelLoadScalarType.Texture2DLodZero:
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevel:
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
|
||||||
case TexelLoadScalarType.Texture3DLodZero:
|
|
||||||
case TexelLoadScalarType.Texture2DArrayLodZero:
|
|
||||||
return TextureFlags.LodLevel;
|
|
||||||
|
|
||||||
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
|
||||||
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
|
||||||
return TextureFlags.LodLevel | TextureFlags.Offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
767
Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs
Normal file
767
Ryujinx.Graphics/Shader/Instructions/InstEmitTexture.cs
Normal file
|
@ -0,0 +1,767 @@
|
||||||
|
using Ryujinx.Graphics.Shader.Decoders;
|
||||||
|
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||||
|
using Ryujinx.Graphics.Shader.Translation;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||||
|
|
||||||
|
namespace Ryujinx.Graphics.Shader.Instructions
|
||||||
|
{
|
||||||
|
static partial class InstEmit
|
||||||
|
{
|
||||||
|
public static void Tex(EmitterContext context)
|
||||||
|
{
|
||||||
|
Tex(context, TextureFlags.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tex_B(EmitterContext context)
|
||||||
|
{
|
||||||
|
Tex(context, TextureFlags.Bindless);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tld(EmitterContext context)
|
||||||
|
{
|
||||||
|
Tex(context, TextureFlags.IntCoords);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tld_B(EmitterContext context)
|
||||||
|
{
|
||||||
|
Tex(context, TextureFlags.IntCoords | TextureFlags.Bindless);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Texs(EmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeTextureScalar op = (OpCodeTextureScalar)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Rd0.IsRZ && op.Rd1.IsRZ)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Operand> sourcesList = new List<Operand>();
|
||||||
|
|
||||||
|
int raIndex = op.Ra.Index;
|
||||||
|
int rbIndex = op.Rb.Index;
|
||||||
|
|
||||||
|
Operand Ra()
|
||||||
|
{
|
||||||
|
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand Rb()
|
||||||
|
{
|
||||||
|
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureType type;
|
||||||
|
TextureFlags flags;
|
||||||
|
|
||||||
|
if (op is OpCodeTexs texsOp)
|
||||||
|
{
|
||||||
|
type = GetTextureType (texsOp.Type);
|
||||||
|
flags = GetTextureFlags(texsOp.Type);
|
||||||
|
|
||||||
|
if ((type & TextureType.Array) != 0)
|
||||||
|
{
|
||||||
|
Operand arrayIndex = Ra();
|
||||||
|
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
|
||||||
|
sourcesList.Add(arrayIndex);
|
||||||
|
|
||||||
|
if ((type & TextureType.Shadow) != 0)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & TextureFlags.LodLevel) != 0)
|
||||||
|
{
|
||||||
|
sourcesList.Add(ConstF(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (texsOp.Type)
|
||||||
|
{
|
||||||
|
case TextureScalarType.Texture1DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2D:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(ConstF(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DLodLevel:
|
||||||
|
case TextureScalarType.Texture2DDepthCompare:
|
||||||
|
case TextureScalarType.Texture3D:
|
||||||
|
case TextureScalarType.TextureCube:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
||||||
|
case TextureScalarType.Texture3DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(ConstF(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
||||||
|
case TextureScalarType.TextureCubeLodLevel:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (op is OpCodeTlds tldsOp)
|
||||||
|
{
|
||||||
|
type = GetTextureType (tldsOp.Type);
|
||||||
|
flags = GetTextureFlags(tldsOp.Type) | TextureFlags.IntCoords;
|
||||||
|
|
||||||
|
switch (tldsOp.Type)
|
||||||
|
{
|
||||||
|
case TexelLoadScalarType.Texture1DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Const(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture1DLodLevel:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Const(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Const(0));
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevel:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture3DLodZero:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Const(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DArrayLodZero:
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Const(0));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (op is OpCodeTld4s tld4sOp)
|
||||||
|
{
|
||||||
|
if (!(tld4sOp.HasDepthCompare || tld4sOp.HasOffset))
|
||||||
|
{
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
}
|
||||||
|
|
||||||
|
type = TextureType.Texture2D;
|
||||||
|
flags = TextureFlags.Gather;
|
||||||
|
|
||||||
|
if (tld4sOp.HasDepthCompare)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
|
||||||
|
type |= TextureType.Shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tld4sOp.HasOffset)
|
||||||
|
{
|
||||||
|
Operand packedOffs = Rb();
|
||||||
|
|
||||||
|
for (int index = 0; index < type.GetCoordsCount(); index++)
|
||||||
|
{
|
||||||
|
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 8), Const(6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= TextureFlags.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesList.Add(Const(tld4sOp.GatherCompIndex));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException($"Invalid opcode type \"{op.GetType().Name}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] sources = sourcesList.ToArray();
|
||||||
|
|
||||||
|
Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||||
|
Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||||
|
|
||||||
|
int destIncrement = 0;
|
||||||
|
|
||||||
|
Operand GetDest()
|
||||||
|
{
|
||||||
|
int high = destIncrement >> 1;
|
||||||
|
int low = destIncrement & 1;
|
||||||
|
|
||||||
|
destIncrement++;
|
||||||
|
|
||||||
|
if (op.IsFp16)
|
||||||
|
{
|
||||||
|
return high != 0
|
||||||
|
? (rd1[low] = Local())
|
||||||
|
: (rd0[low] = Local());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index;
|
||||||
|
|
||||||
|
if (rdIndex < RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
rdIndex += low;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register(rdIndex, RegisterType.Gpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle = 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,
|
||||||
|
handle,
|
||||||
|
compIndex,
|
||||||
|
dest,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
context.Add(operation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.IsFp16)
|
||||||
|
{
|
||||||
|
context.Copy(Register(op.Rd0), context.PackHalf2x16(rd0[0], rd0[1]));
|
||||||
|
context.Copy(Register(op.Rd1), context.PackHalf2x16(rd1[0], rd1[1]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Tld4(EmitterContext context)
|
||||||
|
{
|
||||||
|
OpCodeTld4 op = (OpCodeTld4)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Rd.IsRZ)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int raIndex = op.Ra.Index;
|
||||||
|
int rbIndex = op.Rb.Index;
|
||||||
|
|
||||||
|
Operand Ra()
|
||||||
|
{
|
||||||
|
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand Rb()
|
||||||
|
{
|
||||||
|
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(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 coordsCount = type.GetCoordsCount();
|
||||||
|
|
||||||
|
for (int index = 0; index < coordsCount; index++)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.IsArray)
|
||||||
|
{
|
||||||
|
sourcesList.Add(arrayIndex);
|
||||||
|
|
||||||
|
type |= TextureType.Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] packedOffs = new Operand[2];
|
||||||
|
|
||||||
|
packedOffs[0] = op.Offset != TextureGatherOffset.None ? Rb() : null;
|
||||||
|
packedOffs[1] = op.Offset == TextureGatherOffset.Offsets ? Rb() : null;
|
||||||
|
|
||||||
|
if (op.HasDepthCompare)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.Offset != TextureGatherOffset.None)
|
||||||
|
{
|
||||||
|
int offsetTexelsCount = op.Offset == TextureGatherOffset.Offsets ? 4 : 1;
|
||||||
|
|
||||||
|
for (int index = 0; index < coordsCount * offsetTexelsCount; index++)
|
||||||
|
{
|
||||||
|
Operand packed = packedOffs[(index >> 2) & 1];
|
||||||
|
|
||||||
|
sourcesList.Add(context.BitfieldExtractS32(packed, Const((index & 3) * 8), Const(6)));
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= op.Offset == TextureGatherOffset.Offsets
|
||||||
|
? TextureFlags.Offsets
|
||||||
|
: TextureFlags.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesList.Add(Const(op.GatherCompIndex));
|
||||||
|
|
||||||
|
Operand[] sources = sourcesList.ToArray();
|
||||||
|
|
||||||
|
int rdIndex = op.Rd.Index;
|
||||||
|
|
||||||
|
Operand GetDest()
|
||||||
|
{
|
||||||
|
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register(rdIndex++, RegisterType.Gpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle = 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,
|
||||||
|
handle,
|
||||||
|
compIndex,
|
||||||
|
dest,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
context.Add(operation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Txq(EmitterContext context)
|
||||||
|
{
|
||||||
|
Txq(context, bindless: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Txq_B(EmitterContext context)
|
||||||
|
{
|
||||||
|
Txq(context, bindless: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Txq(EmitterContext context, bool bindless)
|
||||||
|
{
|
||||||
|
OpCodeTex op = (OpCodeTex)context.CurrOp;
|
||||||
|
|
||||||
|
if (op.Rd.IsRZ)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureProperty property = (TextureProperty)op.RawOpCode.Extract(22, 6);
|
||||||
|
|
||||||
|
//TODO: Validate and use property.
|
||||||
|
Instruction inst = Instruction.TextureSize;
|
||||||
|
|
||||||
|
TextureType type = TextureType.Texture2D;
|
||||||
|
|
||||||
|
TextureFlags flags = bindless ? TextureFlags.Bindless : TextureFlags.None;
|
||||||
|
|
||||||
|
int raIndex = op.Ra.Index;
|
||||||
|
|
||||||
|
Operand Ra()
|
||||||
|
{
|
||||||
|
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Operand> sourcesList = new List<Operand>();
|
||||||
|
|
||||||
|
if (bindless)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
}
|
||||||
|
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
|
||||||
|
Operand[] sources = sourcesList.ToArray();
|
||||||
|
|
||||||
|
int rdIndex = op.Rd.Index;
|
||||||
|
|
||||||
|
Operand GetDest()
|
||||||
|
{
|
||||||
|
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register(rdIndex++, RegisterType.Gpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle = !bindless ? op.Immediate : 0;
|
||||||
|
|
||||||
|
for (int compMask = op.ComponentMask, compIndex = 0; compMask != 0; compMask >>= 1, compIndex++)
|
||||||
|
{
|
||||||
|
if ((compMask & 1) != 0)
|
||||||
|
{
|
||||||
|
Operand dest = GetDest();
|
||||||
|
|
||||||
|
TextureOperation operation = new TextureOperation(
|
||||||
|
inst,
|
||||||
|
type,
|
||||||
|
flags,
|
||||||
|
handle,
|
||||||
|
compIndex,
|
||||||
|
dest,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
context.Add(operation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Tex(EmitterContext context, TextureFlags flags)
|
||||||
|
{
|
||||||
|
OpCodeTexture op = (OpCodeTexture)context.CurrOp;
|
||||||
|
|
||||||
|
bool isBindless = (flags & TextureFlags.Bindless) != 0;
|
||||||
|
bool intCoords = (flags & TextureFlags.IntCoords) != 0;
|
||||||
|
|
||||||
|
if (op.Rd.IsRZ)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int raIndex = op.Ra.Index;
|
||||||
|
int rbIndex = op.Rb.Index;
|
||||||
|
|
||||||
|
Operand Ra()
|
||||||
|
{
|
||||||
|
if (raIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand Rb()
|
||||||
|
{
|
||||||
|
if (rbIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand arrayIndex = op.IsArray ? Ra() : null;
|
||||||
|
|
||||||
|
List<Operand> sourcesList = new List<Operand>();
|
||||||
|
|
||||||
|
if (isBindless)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
|
||||||
|
TextureType type = GetTextureType(op.Dimensions);
|
||||||
|
|
||||||
|
int coordsCount = type.GetCoordsCount();
|
||||||
|
|
||||||
|
for (int index = 0; index < coordsCount; index++)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Ra());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.IsArray)
|
||||||
|
{
|
||||||
|
sourcesList.Add(arrayIndex);
|
||||||
|
|
||||||
|
type |= TextureType.Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hasLod = op.LodMode > TextureLodMode.LodZero;
|
||||||
|
|
||||||
|
Operand lodValue = hasLod ? Rb() : ConstF(0);
|
||||||
|
|
||||||
|
Operand packedOffs = op.HasOffset ? Rb() : null;
|
||||||
|
|
||||||
|
if (op is OpCodeTex texOp && texOp.HasDepthCompare)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.LodMode == TextureLodMode.LodZero ||
|
||||||
|
op.LodMode == TextureLodMode.LodLevel ||
|
||||||
|
op.LodMode == TextureLodMode.LodLevelA)
|
||||||
|
{
|
||||||
|
sourcesList.Add(lodValue);
|
||||||
|
|
||||||
|
flags |= TextureFlags.LodLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.HasOffset)
|
||||||
|
{
|
||||||
|
for (int index = 0; index < coordsCount; index++)
|
||||||
|
{
|
||||||
|
sourcesList.Add(context.BitfieldExtractS32(packedOffs, Const(index * 4), Const(4)));
|
||||||
|
}
|
||||||
|
|
||||||
|
flags |= TextureFlags.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op.LodMode == TextureLodMode.LodBias ||
|
||||||
|
op.LodMode == TextureLodMode.LodBiasA)
|
||||||
|
{
|
||||||
|
sourcesList.Add(lodValue);
|
||||||
|
|
||||||
|
flags |= TextureFlags.LodBias;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op is OpCodeTld tldOp && tldOp.IsMultisample)
|
||||||
|
{
|
||||||
|
sourcesList.Add(Rb());
|
||||||
|
}
|
||||||
|
|
||||||
|
Operand[] sources = sourcesList.ToArray();
|
||||||
|
|
||||||
|
int rdIndex = op.Rd.Index;
|
||||||
|
|
||||||
|
Operand GetDest()
|
||||||
|
{
|
||||||
|
if (rdIndex > RegisterConsts.RegisterZeroIndex)
|
||||||
|
{
|
||||||
|
return Const(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Register(rdIndex++, RegisterType.Gpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
int handle = !isBindless ? op.Immediate : 0;
|
||||||
|
|
||||||
|
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,
|
||||||
|
handle,
|
||||||
|
compIndex,
|
||||||
|
dest,
|
||||||
|
sources);
|
||||||
|
|
||||||
|
context.Add(operation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureType GetTextureType(TextureDimensions dimensions)
|
||||||
|
{
|
||||||
|
switch (dimensions)
|
||||||
|
{
|
||||||
|
case TextureDimensions.Texture1D: return TextureType.Texture1D;
|
||||||
|
case TextureDimensions.Texture2D: return TextureType.Texture2D;
|
||||||
|
case TextureDimensions.Texture3D: return TextureType.Texture3D;
|
||||||
|
case TextureDimensions.TextureCube: return TextureType.TextureCube;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid texture dimensions \"{dimensions}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureType GetTextureType(TextureScalarType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TextureScalarType.Texture1DLodZero:
|
||||||
|
return TextureType.Texture1D;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2D:
|
||||||
|
case TextureScalarType.Texture2DLodZero:
|
||||||
|
case TextureScalarType.Texture2DLodLevel:
|
||||||
|
return TextureType.Texture2D;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DDepthCompare:
|
||||||
|
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
||||||
|
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
||||||
|
return TextureType.Texture2D | TextureType.Shadow;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DArray:
|
||||||
|
case TextureScalarType.Texture2DArrayLodZero:
|
||||||
|
return TextureType.Texture2D | TextureType.Array;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2DArrayLodZeroDepthCompare:
|
||||||
|
return TextureType.Texture2D | TextureType.Array | TextureType.Shadow;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture3D:
|
||||||
|
case TextureScalarType.Texture3DLodZero:
|
||||||
|
return TextureType.Texture3D;
|
||||||
|
|
||||||
|
case TextureScalarType.TextureCube:
|
||||||
|
case TextureScalarType.TextureCubeLodLevel:
|
||||||
|
return TextureType.TextureCube;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureType GetTextureType(TexelLoadScalarType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TexelLoadScalarType.Texture1DLodZero:
|
||||||
|
case TexelLoadScalarType.Texture1DLodLevel:
|
||||||
|
return TextureType.Texture1D;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodZero:
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevel:
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
||||||
|
return TextureType.Texture2D;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
||||||
|
return TextureType.Texture2D | TextureType.Multisample;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture3DLodZero:
|
||||||
|
return TextureType.Texture3D;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DArrayLodZero:
|
||||||
|
return TextureType.Texture2D | TextureType.Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureFlags GetTextureFlags(TextureScalarType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TextureScalarType.Texture1DLodZero:
|
||||||
|
case TextureScalarType.Texture2DLodZero:
|
||||||
|
case TextureScalarType.Texture2DLodLevel:
|
||||||
|
case TextureScalarType.Texture2DLodLevelDepthCompare:
|
||||||
|
case TextureScalarType.Texture2DLodZeroDepthCompare:
|
||||||
|
case TextureScalarType.Texture2DArrayLodZero:
|
||||||
|
case TextureScalarType.Texture2DArrayLodZeroDepthCompare:
|
||||||
|
case TextureScalarType.Texture3DLodZero:
|
||||||
|
case TextureScalarType.TextureCubeLodLevel:
|
||||||
|
return TextureFlags.LodLevel;
|
||||||
|
|
||||||
|
case TextureScalarType.Texture2D:
|
||||||
|
case TextureScalarType.Texture2DDepthCompare:
|
||||||
|
case TextureScalarType.Texture2DArray:
|
||||||
|
case TextureScalarType.Texture3D:
|
||||||
|
case TextureScalarType.TextureCube:
|
||||||
|
return TextureFlags.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextureFlags GetTextureFlags(TexelLoadScalarType type)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
case TexelLoadScalarType.Texture1DLodZero:
|
||||||
|
case TexelLoadScalarType.Texture1DLodLevel:
|
||||||
|
case TexelLoadScalarType.Texture2DLodZero:
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevel:
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroMultisample:
|
||||||
|
case TexelLoadScalarType.Texture3DLodZero:
|
||||||
|
case TexelLoadScalarType.Texture2DArrayLodZero:
|
||||||
|
return TextureFlags.LodLevel;
|
||||||
|
|
||||||
|
case TexelLoadScalarType.Texture2DLodZeroOffset:
|
||||||
|
case TexelLoadScalarType.Texture2DLodLevelOffset:
|
||||||
|
return TextureFlags.LodLevel | TextureFlags.Offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ArgumentException($"Invalid texture type \"{type}\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue