Implement SHF (funnel shift) shader instruction (#2702)

* Implement SHF shader instruction

* Shader cache version bump

* Better name
This commit is contained in:
gdkchan 2021-10-17 17:02:20 -03:00 committed by GitHub
parent 1b81653478
commit d05573bfd1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 118 additions and 29 deletions

View file

@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
/// <summary> /// <summary>
/// Version of the codegen (to be changed when codegen or guest format change). /// Version of the codegen (to be changed when codegen or guest format change).
/// </summary> /// </summary>
private const ulong ShaderCodeGenVersion = 2697; private const ulong ShaderCodeGenVersion = 2702;
// Progress reporting helpers // Progress reporting helpers
private volatile int _shaderCount; private volatile int _shaderCount;

View file

@ -418,34 +418,6 @@ namespace Ryujinx.Graphics.Shader.Instructions
context.Config.GpuAccessor.Log("Shader instruction Setlmembase is not implemented."); context.Config.GpuAccessor.Log("Shader instruction Setlmembase is not implemented.");
} }
public static void ShfLR(EmitterContext context)
{
InstShfLR op = context.GetOp<InstShfLR>();
context.Config.GpuAccessor.Log("Shader instruction ShfLR is not implemented.");
}
public static void ShfRR(EmitterContext context)
{
InstShfRR op = context.GetOp<InstShfRR>();
context.Config.GpuAccessor.Log("Shader instruction ShfRR is not implemented.");
}
public static void ShfLI(EmitterContext context)
{
InstShfLI op = context.GetOp<InstShfLI>();
context.Config.GpuAccessor.Log("Shader instruction ShfLI is not implemented.");
}
public static void ShfRI(EmitterContext context)
{
InstShfRI op = context.GetOp<InstShfRI>();
context.Config.GpuAccessor.Log("Shader instruction ShfRI is not implemented.");
}
public static void St(EmitterContext context) public static void St(EmitterContext context)
{ {
InstSt op = context.GetOp<InstSt>(); InstSt op = context.GetOp<InstSt>();

View file

@ -9,6 +9,50 @@ namespace Ryujinx.Graphics.Shader.Instructions
{ {
static partial class InstEmit static partial class InstEmit
{ {
public static void ShfLR(EmitterContext context)
{
InstShfLR op = context.GetOp<InstShfLR>();
var srcA = GetSrcReg(context, op.SrcA);
var srcB = GetSrcReg(context, op.SrcB);
var srcC = GetSrcReg(context, op.SrcC);
EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
}
public static void ShfRR(EmitterContext context)
{
InstShfRR op = context.GetOp<InstShfRR>();
var srcA = GetSrcReg(context, op.SrcA);
var srcB = GetSrcReg(context, op.SrcB);
var srcC = GetSrcReg(context, op.SrcC);
EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
}
public static void ShfLI(EmitterContext context)
{
InstShfLI op = context.GetOp<InstShfLI>();
var srcA = GetSrcReg(context, op.SrcA);
var srcB = Const(op.Imm6);
var srcC = GetSrcReg(context, op.SrcC);
EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: true, op.WriteCC);
}
public static void ShfRI(EmitterContext context)
{
InstShfRI op = context.GetOp<InstShfRI>();
var srcA = GetSrcReg(context, op.SrcA);
var srcB = Const(op.Imm6);
var srcC = GetSrcReg(context, op.SrcC);
EmitShf(context, op.MaxShift, srcA, srcB, srcC, op.Dest, op.M, left: false, op.WriteCC);
}
public static void ShlR(EmitterContext context) public static void ShlR(EmitterContext context)
{ {
InstShlR op = context.GetOp<InstShlR>(); InstShlR op = context.GetOp<InstShlR>();
@ -60,6 +104,79 @@ namespace Ryujinx.Graphics.Shader.Instructions
EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed); EmitShr(context, srcA, srcB, op.Dest, op.M, op.Brev, op.Signed);
} }
private static void EmitShf(
EmitterContext context,
MaxShift maxShift,
Operand srcA,
Operand srcB,
Operand srcC,
int rd,
bool mask,
bool left,
bool writeCC)
{
bool isLongShift = maxShift == MaxShift.U64 || maxShift == MaxShift.S64;
bool signedShift = maxShift == MaxShift.S64;
int maxShiftConst = isLongShift ? 64 : 32;
if (mask)
{
srcB = context.BitwiseAnd(srcB, Const(maxShiftConst - 1));
}
Operand res;
if (left)
{
// res = (C << B) | (A >> (32 - B))
res = context.ShiftLeft(srcC, srcB);
res = context.BitwiseOr(res, context.ShiftRightU32(srcA, context.ISubtract(Const(32), srcB)));
if (isLongShift)
{
// res = B >= 32 ? A << (B - 32) : res
Operand lowerShift = context.ShiftLeft(srcA, context.ISubtract(srcB, Const(32)));
Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
res = context.ConditionalSelect(shiftGreaterThan31, lowerShift, res);
}
}
else
{
// res = (A >> B) | (C << (32 - B))
res = context.ShiftRightU32(srcA, srcB);
res = context.BitwiseOr(res, context.ShiftLeft(srcC, context.ISubtract(Const(32), srcB)));
if (isLongShift)
{
// res = B >= 32 ? C >> (B - 32) : res
Operand upperShift = signedShift
? context.ShiftRightS32(srcC, context.ISubtract(srcB, Const(32)))
: context.ShiftRightU32(srcC, context.ISubtract(srcB, Const(32)));
Operand shiftGreaterThan31 = context.ICompareGreaterOrEqualUnsigned(srcB, Const(32));
res = context.ConditionalSelect(shiftGreaterThan31, upperShift, res);
}
}
if (!mask)
{
// Clamped shift value.
Operand isLessThanMax = context.ICompareLessUnsigned(srcB, Const(maxShiftConst));
res = context.ConditionalSelect(isLessThanMax, res, Const(0));
}
context.Copy(GetDest(rd), res);
if (writeCC)
{
InstEmitAluHelper.SetZnFlags(context, res, writeCC);
}
// TODO: X.
}
private static void EmitShl(EmitterContext context, Operand srcA, Operand srcB, int rd, bool mask) private static void EmitShl(EmitterContext context, Operand srcA, Operand srcB, int rd, bool mask)
{ {
if (mask) if (mask)