Add HADD2 and HMUL2 half float shader instructions
This commit is contained in:
parent
67868899e4
commit
3980043cf2
12 changed files with 304 additions and 30 deletions
|
@ -103,6 +103,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
Add(Instruction.MinimumU32, InstFlags.CallBinary, "min");
|
||||
Add(Instruction.Multiply, InstFlags.OpBinary, "*", 1);
|
||||
Add(Instruction.Negate, InstFlags.OpUnary, "-", 0);
|
||||
Add(Instruction.PackHalf2x16, InstFlags.Call);
|
||||
Add(Instruction.ReciprocalSquareRoot, InstFlags.CallUnary, "inversesqrt");
|
||||
Add(Instruction.Return, InstFlags.OpNullary, "return");
|
||||
Add(Instruction.Sine, InstFlags.CallUnary, "sin");
|
||||
|
@ -110,6 +111,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
Add(Instruction.Subtract, InstFlags.OpBinary, "-", 2);
|
||||
Add(Instruction.TextureSample, InstFlags.Call);
|
||||
Add(Instruction.Truncate, InstFlags.CallUnary, "trunc");
|
||||
Add(Instruction.UnpackHalf2x16High, InstFlags.Call);
|
||||
Add(Instruction.UnpackHalf2x16Low, InstFlags.Call);
|
||||
}
|
||||
|
||||
private static void Add(Instruction inst, InstFlags flags, string opName = null, int precedence = 0)
|
||||
|
@ -158,12 +161,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
case Instruction.LoadConstant:
|
||||
return GetLoadConstantExpr(context, operation);
|
||||
|
||||
case Instruction.PackHalf2x16:
|
||||
return GetPackHalf2x16Expr(context, operation);
|
||||
|
||||
case Instruction.TextureSample:
|
||||
return GetTextureSampleExpr(context, operation);
|
||||
|
||||
case Instruction.UnpackHalf2x16High:
|
||||
return GetUnpackHalf2x16Expr(context, operation, 1);
|
||||
|
||||
case Instruction.UnpackHalf2x16Low:
|
||||
return GetUnpackHalf2x16Expr(context, operation, 0);
|
||||
}
|
||||
|
||||
InstInfo info = _infoTbl[(int)inst];
|
||||
|
||||
if (info.OpName == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Unknown instruction \"{inst}\".");
|
||||
}
|
||||
|
||||
if ((info.Flags & InstFlags.Call) != 0)
|
||||
{
|
||||
int arity = (int)(info.Flags & InstFlags.ArityMask);
|
||||
|
@ -248,6 +265,26 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
|||
return OperandManager.GetConstantBufferName(context, operation.GetSource(0), offsetExpr);
|
||||
}
|
||||
|
||||
private static string GetPackHalf2x16Expr(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
IAstNode src0 = operation.GetSource(0);
|
||||
IAstNode src1 = operation.GetSource(1);
|
||||
|
||||
string src0Expr = GetSoureExpr(context, src0, GetSrcVarType(operation.Inst, 0));
|
||||
string src1Expr = GetSoureExpr(context, src1, GetSrcVarType(operation.Inst, 1));
|
||||
|
||||
return $"packHalf2x16(vec2({src0Expr}, {src1Expr}))";
|
||||
}
|
||||
|
||||
private static string GetUnpackHalf2x16Expr(CodeGenContext context, AstOperation operation, int elem)
|
||||
{
|
||||
IAstNode src = operation.GetSource(0);
|
||||
|
||||
string srcExpr = GetSoureExpr(context, src, GetSrcVarType(operation.Inst, 0));
|
||||
|
||||
return $"unpackHalf2x16({srcExpr}).{"xy".Substring(elem, 1)}";
|
||||
}
|
||||
|
||||
private static string GetTextureSampleExpr(CodeGenContext context, AstOperation operation)
|
||||
{
|
||||
AstTextureOperation texOp = (AstTextureOperation)operation;
|
||||
|
|
10
Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs
Normal file
10
Ryujinx.Graphics/Shader/Decoders/FPHalfSwizzle.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
enum FPHalfSwizzle
|
||||
{
|
||||
FP16 = 0,
|
||||
FP32 = 1,
|
||||
DupH0 = 2,
|
||||
DupH1 = 3
|
||||
}
|
||||
}
|
30
Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs
Normal file
30
Ryujinx.Graphics/Shader/Decoders/OpCodeAluImm2x10.cs
Normal file
|
@ -0,0 +1,30 @@
|
|||
using Ryujinx.Graphics.Shader.Instructions;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Decoders
|
||||
{
|
||||
class OpCodeAluImm2x10 : OpCode, IOpCodeImm
|
||||
{
|
||||
public int Immediate { get; }
|
||||
|
||||
public OpCodeAluImm2x10(InstEmitter emitter, ulong address, long opCode) : base(emitter, address, opCode)
|
||||
{
|
||||
int immH0 = opCode.Extract(20, 9);
|
||||
int immH1 = opCode.Extract(30, 9);
|
||||
|
||||
bool negateH0 = opCode.Extract(29);
|
||||
bool negateH1 = opCode.Extract(56);
|
||||
|
||||
if (negateH0)
|
||||
{
|
||||
immH0 |= 1 << 10;
|
||||
}
|
||||
|
||||
if (negateH1)
|
||||
{
|
||||
immH1 |= 1 << 10;
|
||||
}
|
||||
|
||||
Immediate = immH1 << 16 | immH0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -64,6 +64,14 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
|||
Set("010010111011xx", InstEmit.Fsetp, typeof(OpCodeSetCbuf));
|
||||
Set("0011011x1011xx", InstEmit.Fsetp, typeof(OpCodeFsetImm));
|
||||
Set("010110111011xx", InstEmit.Fsetp, typeof(OpCodeSetReg));
|
||||
Set("0111101x1xxxxx", InstEmit.Hadd2, typeof(OpCodeAluCbuf));
|
||||
Set("0111101x0xxxxx", InstEmit.Hadd2, typeof(OpCodeAluImm2x10));
|
||||
Set("0010110xxxxxxx", InstEmit.Hadd2, typeof(OpCodeAluImm32));
|
||||
Set("0101110100010x", InstEmit.Hadd2, typeof(OpCodeAluReg));
|
||||
Set("0111100x1xxxxx", InstEmit.Hmul2, typeof(OpCodeAluCbuf));
|
||||
Set("0111100x0xxxxx", InstEmit.Hmul2, typeof(OpCodeAluImm2x10));
|
||||
Set("0010101xxxxxxx", InstEmit.Hmul2, typeof(OpCodeAluImm32));
|
||||
Set("0101110100001x", InstEmit.Hmul2, typeof(OpCodeAluReg));
|
||||
Set("0100110010111x", InstEmit.I2F, typeof(OpCodeAluCbuf));
|
||||
Set("0011100x10111x", InstEmit.I2F, typeof(OpCodeAluImm));
|
||||
Set("0101110010111x", InstEmit.I2F, typeof(OpCodeAluReg));
|
||||
|
|
|
@ -3,8 +3,8 @@ using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
|||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitAluHelper;
|
||||
using static Ryujinx.Graphics.Shader.Instructions.InstEmitHelper;
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
@ -175,6 +175,44 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
context.Copy(Register(op.Predicate0), p1Res);
|
||||
}
|
||||
|
||||
public static void Hadd2(EmitterContext context)
|
||||
{
|
||||
Hadd2Hmul2Impl(context, isAdd: true);
|
||||
}
|
||||
|
||||
public static void Hmul2(EmitterContext context)
|
||||
{
|
||||
Hadd2Hmul2Impl(context, isAdd: false);
|
||||
}
|
||||
|
||||
private static void Hadd2Hmul2Impl(EmitterContext context, bool isAdd)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
bool saturate = op.RawOpCode.Extract(op is OpCodeAluImm32 ? 52 : 32);
|
||||
|
||||
Operand[] srcA = GetHalfSrcA(context);
|
||||
Operand[] srcB = GetHalfSrcB(context);
|
||||
|
||||
Operand[] res = new Operand[2];
|
||||
|
||||
for (int index = 0; index < res.Length; index++)
|
||||
{
|
||||
if (isAdd)
|
||||
{
|
||||
res[index] = context.FPAdd(srcA[index], srcB[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
res[index] = context.FPMultiply(srcA[index], srcB[index]);
|
||||
}
|
||||
|
||||
res[index] = context.FPSaturate(res[index], saturate);
|
||||
}
|
||||
|
||||
context.Copy(GetDest(context), GetHalfPacked(context, res));
|
||||
}
|
||||
|
||||
public static void Mufu(EmitterContext context)
|
||||
{
|
||||
IOpCodeFArith op = (IOpCodeFArith)context.CurrOp;
|
||||
|
@ -221,6 +259,124 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
context.Copy(GetDest(context), context.FPSaturate(res, op.Saturate));
|
||||
}
|
||||
|
||||
private static Operand[] GetHalfSrcA(EmitterContext context)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
bool absoluteA = false, negateA = false;
|
||||
|
||||
if (op is IOpCodeCbuf || op is IOpCodeImm)
|
||||
{
|
||||
negateA = op.RawOpCode.Extract(43);
|
||||
absoluteA = op.RawOpCode.Extract(44);
|
||||
}
|
||||
else if (op is IOpCodeReg)
|
||||
{
|
||||
absoluteA = op.RawOpCode.Extract(44);
|
||||
}
|
||||
else if (op is OpCodeAluImm32 && op.Emitter == Hadd2)
|
||||
{
|
||||
negateA = op.RawOpCode.Extract(56);
|
||||
}
|
||||
|
||||
FPHalfSwizzle swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(47, 2);
|
||||
|
||||
Operand[] operands = GetHalfSources(context, GetSrcA(context), swizzle);
|
||||
|
||||
return FPAbsNeg(context, operands, absoluteA, negateA);
|
||||
}
|
||||
|
||||
private static Operand[] GetHalfSrcB(EmitterContext context)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
|
||||
|
||||
if (!(op is OpCodeAluImm32))
|
||||
{
|
||||
swizzle = (FPHalfSwizzle)op.RawOpCode.Extract(28, 2);
|
||||
}
|
||||
|
||||
bool absoluteB = false, negateB = false;
|
||||
|
||||
if (op is IOpCodeReg)
|
||||
{
|
||||
absoluteB = op.RawOpCode.Extract(30);
|
||||
negateB = op.RawOpCode.Extract(31);
|
||||
}
|
||||
else if (op is IOpCodeCbuf)
|
||||
{
|
||||
absoluteB = op.RawOpCode.Extract(54);
|
||||
}
|
||||
|
||||
Operand[] operands = GetHalfSources(context, GetSrcB(context), swizzle);
|
||||
|
||||
return FPAbsNeg(context, operands, absoluteB, negateB);
|
||||
}
|
||||
|
||||
private static Operand[] FPAbsNeg(EmitterContext context, Operand[] operands, bool abs, bool neg)
|
||||
{
|
||||
for (int index = 0; index < operands.Length; index++)
|
||||
{
|
||||
operands[index] = context.FPAbsNeg(operands[index], abs, neg);
|
||||
}
|
||||
|
||||
return operands;
|
||||
}
|
||||
|
||||
private static Operand[] GetHalfSources(EmitterContext context, Operand src, FPHalfSwizzle swizzle)
|
||||
{
|
||||
switch (swizzle)
|
||||
{
|
||||
case FPHalfSwizzle.FP16:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16Low (src),
|
||||
context.UnpackHalf2x16High(src)
|
||||
};
|
||||
|
||||
case FPHalfSwizzle.FP32: return new Operand[] { src, src };
|
||||
|
||||
case FPHalfSwizzle.DupH0:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16Low(src),
|
||||
context.UnpackHalf2x16Low(src)
|
||||
};
|
||||
|
||||
case FPHalfSwizzle.DupH1:
|
||||
return new Operand[]
|
||||
{
|
||||
context.UnpackHalf2x16High(src),
|
||||
context.UnpackHalf2x16High(src)
|
||||
};
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
|
||||
}
|
||||
|
||||
private static Operand GetHalfPacked(EmitterContext context, Operand[] results)
|
||||
{
|
||||
OpCode op = context.CurrOp;
|
||||
|
||||
FPHalfSwizzle swizzle = FPHalfSwizzle.FP16;
|
||||
|
||||
if (!(op is OpCodeAluImm32))
|
||||
{
|
||||
swizzle = (FPHalfSwizzle)context.CurrOp.RawOpCode.Extract(49, 2);
|
||||
}
|
||||
|
||||
switch (swizzle)
|
||||
{
|
||||
case FPHalfSwizzle.FP16: return context.PackHalf2x16(results[0], results[1]);
|
||||
case FPHalfSwizzle.FP32: return results[0];
|
||||
case FPHalfSwizzle.DupH0: return context.PackHalf2x16(results[0], results[0]);
|
||||
case FPHalfSwizzle.DupH1: return context.PackHalf2x16(results[1], results[1]);
|
||||
}
|
||||
|
||||
throw new ArgumentException($"Invalid swizzle \"{swizzle}\".");
|
||||
}
|
||||
|
||||
private static Operand GetFPComparison(
|
||||
EmitterContext context,
|
||||
Condition cond,
|
||||
|
|
|
@ -11,22 +11,22 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
{
|
||||
public static Operand GetZF(EmitterContext context)
|
||||
{
|
||||
return Register(new Register(0, RegisterType.Flag));
|
||||
return Register(0, RegisterType.Flag);
|
||||
}
|
||||
|
||||
public static Operand GetNF(EmitterContext context)
|
||||
{
|
||||
return Register(new Register(1, RegisterType.Flag));
|
||||
return Register(1, RegisterType.Flag);
|
||||
}
|
||||
|
||||
public static Operand GetCF(EmitterContext context)
|
||||
{
|
||||
return Register(new Register(2, RegisterType.Flag));
|
||||
return Register(2, RegisterType.Flag);
|
||||
}
|
||||
|
||||
public static Operand GetVF(EmitterContext context)
|
||||
{
|
||||
return Register(new Register(3, RegisterType.Flag));
|
||||
return Register(3, RegisterType.Flag);
|
||||
}
|
||||
|
||||
public static Operand GetDest(EmitterContext context)
|
||||
|
|
|
@ -156,7 +156,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return context.Copy(Register(new Register(raIndex++, RegisterType.Gpr)));
|
||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand Rb()
|
||||
|
@ -166,7 +166,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return context.Copy(Register(new Register(rbIndex++, RegisterType.Gpr)));
|
||||
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand arrayIndex = op.IsArray ? Ra() : null;
|
||||
|
@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return Register(new Register(rdIndex++, RegisterType.Gpr));
|
||||
return Register(rdIndex++, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
int textureHandle = op.Immediate;
|
||||
|
@ -291,7 +291,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
regIndex += index & 1;
|
||||
}
|
||||
|
||||
return context.Copy(Register(new Register(regIndex, RegisterType.Gpr)));
|
||||
return context.Copy(Register(regIndex, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
switch (op.Type)
|
||||
|
@ -363,28 +363,35 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
TextureType type = GetTextureType (op.Type);
|
||||
TextureFlags flags = GetTextureFlags(op.Type);
|
||||
|
||||
Operand[] rd0 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||
Operand[] rd1 = new Operand[2] { ConstF(0), ConstF(0) };
|
||||
|
||||
int destIncrement = 0;
|
||||
|
||||
Operand GetDest()
|
||||
{
|
||||
int rdIndex;
|
||||
int high = destIncrement >> 1;
|
||||
int low = destIncrement & 1;
|
||||
|
||||
if (op.Rd1.IsRZ)
|
||||
destIncrement++;
|
||||
|
||||
if (op.IsFp16)
|
||||
{
|
||||
rdIndex = op.Rd0.Index;
|
||||
}
|
||||
else if (op.Rd0.IsRZ)
|
||||
{
|
||||
rdIndex = op.Rd1.Index;
|
||||
return high != 0
|
||||
? (rd1[low] = Local())
|
||||
: (rd0[low] = Local());
|
||||
}
|
||||
else
|
||||
{
|
||||
rdIndex = (destIncrement >> 1) != 0 ? op.Rd1.Index : op.Rd0.Index;
|
||||
int rdIndex = high != 0 ? op.Rd1.Index : op.Rd0.Index;
|
||||
|
||||
if (rdIndex < RegisterConsts.RegisterZeroIndex)
|
||||
{
|
||||
rdIndex += low;
|
||||
}
|
||||
|
||||
return Register(rdIndex, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
rdIndex += destIncrement++ & 1;
|
||||
|
||||
return Register(new Register(rdIndex, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
int textureHandle = op.Immediate;
|
||||
|
@ -407,6 +414,12 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
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)
|
||||
|
@ -432,7 +445,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return context.Copy(Register(new Register(raIndex++, RegisterType.Gpr)));
|
||||
return context.Copy(Register(raIndex++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand Rb()
|
||||
|
@ -442,7 +455,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return context.Copy(Register(new Register(rbIndex++, RegisterType.Gpr)));
|
||||
return context.Copy(Register(rbIndex++, RegisterType.Gpr));
|
||||
}
|
||||
|
||||
Operand arrayIndex = op.IsArray ? Ra() : null;
|
||||
|
@ -506,7 +519,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
|||
return Const(0);
|
||||
}
|
||||
|
||||
return Register(new Register(rdIndex++, RegisterType.Gpr));
|
||||
return Register(rdIndex++, RegisterType.Gpr);
|
||||
}
|
||||
|
||||
int textureHandle = op.Immediate;
|
||||
|
|
|
@ -76,8 +76,10 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
|||
Subtract,
|
||||
TextureSample,
|
||||
Truncate,
|
||||
UnpackDouble2x32,
|
||||
UnpackHalf2x16,
|
||||
UnpackDouble2x32High,
|
||||
UnpackDouble2x32Low,
|
||||
UnpackHalf2x16High,
|
||||
UnpackHalf2x16Low,
|
||||
|
||||
Count,
|
||||
FP = 1 << 16,
|
||||
|
|
|
@ -35,9 +35,9 @@ namespace Ryujinx.Graphics.Shader.IntermediateRepresentation
|
|||
return new Operand(OperandType.LocalVariable);
|
||||
}
|
||||
|
||||
public static Operand Register(Register reg, int increment)
|
||||
public static Operand Register(int index, RegisterType type)
|
||||
{
|
||||
return new Operand(new Register(reg.Index + increment, reg.Type));
|
||||
return Register(new Register(index, type));
|
||||
}
|
||||
|
||||
public static Operand Register(Register reg)
|
||||
|
|
|
@ -74,11 +74,14 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
|||
Add(Instruction.MinimumU32, VariableType.U32, VariableType.U32, VariableType.U32);
|
||||
Add(Instruction.Multiply, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Negate, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.PackHalf2x16, VariableType.U32, VariableType.F32, VariableType.F32);
|
||||
Add(Instruction.ReciprocalSquareRoot, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Sine, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.SquareRoot, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Subtract, VariableType.Scalar, VariableType.Scalar, VariableType.Scalar);
|
||||
Add(Instruction.Truncate, VariableType.F32, VariableType.F32);
|
||||
Add(Instruction.UnpackHalf2x16High, VariableType.F32, VariableType.U32);
|
||||
Add(Instruction.UnpackHalf2x16Low, VariableType.F32, VariableType.U32);
|
||||
}
|
||||
|
||||
private static void Add(Instruction inst, VariableType destType, params VariableType[] srcTypes)
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);
|
||||
|
||||
Operand src = Register(new Register(_header.DepthRegister, RegisterType.Gpr));
|
||||
Operand src = Register(_header.DepthRegister, RegisterType.Gpr);
|
||||
|
||||
this.Copy(dest, src);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
Operand dest = Attribute(AttributeConsts.FragmentOutputColorBase + regIndex * 4);
|
||||
|
||||
Operand src = Register(new Register(regIndex, RegisterType.Gpr));
|
||||
Operand src = Register(regIndex, RegisterType.Gpr);
|
||||
|
||||
this.Copy(dest, src);
|
||||
|
||||
|
|
|
@ -371,6 +371,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return context.Add(Instruction.LoadConstant, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand PackHalf2x16(this EmitterContext context, Operand a, Operand b)
|
||||
{
|
||||
return context.Add(Instruction.PackHalf2x16, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand Return(this EmitterContext context)
|
||||
{
|
||||
context.PrepareForReturn();
|
||||
|
@ -392,5 +397,15 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
{
|
||||
return context.Add(Instruction.ShiftRightU32, Local(), a, b);
|
||||
}
|
||||
|
||||
public static Operand UnpackHalf2x16High(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.UnpackHalf2x16High, Local(), a);
|
||||
}
|
||||
|
||||
public static Operand UnpackHalf2x16Low(this EmitterContext context, Operand a)
|
||||
{
|
||||
return context.Add(Instruction.UnpackHalf2x16Low, Local(), a);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue