Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
96bf7f8522 | ||
|
33e673ceb8 | ||
|
9c2500de5f | ||
|
dbe43c1719 | ||
|
f502cfaf62 | ||
|
1fd5cf2b4a | ||
|
814f75142e |
@@ -726,7 +726,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMaxNum)), op1, op2);
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMaxNum), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -774,7 +774,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMax)), op1, op2);
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMax), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -900,7 +900,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMinNum)), op1, op2);
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMinNum), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -948,7 +948,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
EmitVectorAcrossVectorOpF(context, (op1, op2) =>
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPMin)), op1, op2);
|
||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMin), op1, op2);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1633,37 +1633,17 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Frinti_S(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
if (op.Size == 0)
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
||||
}
|
||||
else /* if (op.Size == 1) */
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
||||
}
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frinti_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
if (sizeF == 0)
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
||||
}
|
||||
else /* if (sizeF == 1) */
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
||||
}
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1759,37 +1739,17 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void Frintx_S(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
EmitScalarUnaryOpF(context, (op1) =>
|
||||
{
|
||||
if (op.Size == 0)
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
||||
}
|
||||
else /* if (op.Size == 1) */
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
||||
}
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frintx_V(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSimd op = (OpCodeSimd)context.CurrOp;
|
||||
|
||||
int sizeF = op.Size & 1;
|
||||
|
||||
EmitVectorUnaryOpF(context, (op1) =>
|
||||
{
|
||||
if (sizeF == 0)
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)), op1);
|
||||
}
|
||||
else /* if (sizeF == 1) */
|
||||
{
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)), op1);
|
||||
}
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -3,7 +3,6 @@ using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using static ARMeilleure.Instructions.InstEmitHelper;
|
||||
using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
||||
@@ -178,37 +177,20 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
private static void EmitCmpOpF32(ArmEmitterContext context, string name, bool zero)
|
||||
{
|
||||
Operand one = Const(1);
|
||||
if (zero)
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (m) =>
|
||||
{
|
||||
OperandType type = m.Type;
|
||||
Operand zeroOp = m.Type == OperandType.FP64 ? ConstF(0.0d) : ConstF(0.0f);
|
||||
|
||||
if (type == OperandType.FP64)
|
||||
{
|
||||
return context.Call(typeof(SoftFloat64).GetMethod(name), m, ConstF(0.0d), one);
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(name), m, ConstF(0.0f), one);
|
||||
}
|
||||
return EmitSoftFloatCallDefaultFpscr(context, name, m, zeroOp);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpF32(context, (n, m) =>
|
||||
{
|
||||
OperandType type = n.Type;
|
||||
|
||||
if (type == OperandType.FP64)
|
||||
{
|
||||
return context.Call(typeof(SoftFloat64).GetMethod(name), n, m, one);
|
||||
}
|
||||
else
|
||||
{
|
||||
return context.Call(typeof(SoftFloat32).GetMethod(name), n, m, one);
|
||||
}
|
||||
return EmitSoftFloatCallDefaultFpscr(context, name, n, m);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -357,11 +339,7 @@ namespace ARMeilleure.Instructions
|
||||
me = ExtractScalar(context, type, op.Vm);
|
||||
}
|
||||
|
||||
MethodInfo info = sizeF != 0
|
||||
? typeof(SoftFloat64).GetMethod(nameof(SoftFloat64.FPCompare))
|
||||
: typeof(SoftFloat32).GetMethod(nameof(SoftFloat32.FPCompare));
|
||||
|
||||
Operand nzcv = context.Call(info, ne, me, Const(signalNaNs));
|
||||
Operand nzcv = EmitSoftFloatCall(context, nameof(SoftFloat32.FPCompare), ne, me, Const(signalNaNs));
|
||||
|
||||
EmitSetFpscrNzcv(context, nzcv);
|
||||
}
|
||||
|
@@ -76,7 +76,9 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand ne = context.VectorExtract(OperandType.FP32, GetVec(op.Rn), 0);
|
||||
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
res = context.ZeroExtend16(OperandType.I64, res);
|
||||
|
||||
@@ -98,7 +100,9 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
||||
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
@@ -120,7 +124,9 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand ne = context.VectorExtract(OperandType.FP64, GetVec(op.Rn), 0);
|
||||
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(typeof(SoftFloat64_16).GetMethod(nameof(SoftFloat64_16.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
res = context.ZeroExtend16(OperandType.I64, res);
|
||||
|
||||
@@ -143,7 +149,9 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand ne = EmitVectorExtractZx(context, op.Rn, 0, 1);
|
||||
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(typeof(SoftFloat16_64).GetMethod(nameof(SoftFloat16_64.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
context.Copy(GetVec(op.Rd), context.VectorInsert(context.VectorZero(), res, 0));
|
||||
}
|
||||
@@ -224,7 +232,9 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand ne = EmitVectorExtractZx(context, op.Rn, part + index, 1);
|
||||
|
||||
context.StoreToContext();
|
||||
Operand e = context.Call(typeof(SoftFloat16_32).GetMethod(nameof(SoftFloat16_32.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
res = context.VectorInsert(res, e, index);
|
||||
}
|
||||
@@ -333,7 +343,9 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
if (sizeF == 0)
|
||||
{
|
||||
context.StoreToContext();
|
||||
Operand e = context.Call(typeof(SoftFloat32_16).GetMethod(nameof(SoftFloat32_16.FPConvert)), ne);
|
||||
context.LoadFromContext();
|
||||
|
||||
e = context.ZeroExtend16(OperandType.I64, e);
|
||||
|
||||
|
@@ -161,34 +161,15 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
Operand toConvert = ExtractScalar(context, floatSize, op.Vm);
|
||||
|
||||
Operand asInteger;
|
||||
|
||||
// TODO: Fast Path.
|
||||
if (roundWithFpscr)
|
||||
{
|
||||
MethodInfo info;
|
||||
|
||||
if (floatSize == OperandType.FP64)
|
||||
{
|
||||
info = unsigned
|
||||
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))
|
||||
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32));
|
||||
}
|
||||
else
|
||||
{
|
||||
info = unsigned
|
||||
? typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))
|
||||
: typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32));
|
||||
}
|
||||
|
||||
asInteger = context.Call(info, toConvert);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Round towards zero.
|
||||
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||
toConvert = EmitRoundByRMode(context, toConvert);
|
||||
}
|
||||
|
||||
// Round towards zero.
|
||||
Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||
|
||||
InsertScalar(context, op.Vd, asInteger);
|
||||
}
|
||||
}
|
||||
@@ -271,9 +252,7 @@ namespace ARMeilleure.Instructions
|
||||
break;
|
||||
}
|
||||
|
||||
Operand asInteger;
|
||||
|
||||
asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||
Operand asInteger = EmitSaturateFloatToInt(context, toConvert, unsigned);
|
||||
|
||||
InsertScalar(context, op.Vd, asInteger);
|
||||
}
|
||||
@@ -399,15 +378,9 @@ namespace ARMeilleure.Instructions
|
||||
// VRINTX (floating-point).
|
||||
public static void Vrintx_S(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||
|
||||
bool doubleSize = (op.Size & 1) == 1;
|
||||
string methodName = doubleSize ? nameof(SoftFallback.Round) : nameof(SoftFallback.RoundF);
|
||||
|
||||
EmitScalarUnaryOpF32(context, (op1) =>
|
||||
{
|
||||
MethodInfo info = typeof(SoftFallback).GetMethod(methodName);
|
||||
return context.Call(info, op1);
|
||||
return EmitRoundByRMode(context, op1);
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -361,6 +361,54 @@ namespace ARMeilleure.Instructions
|
||||
return context.Call(info, n, Const((int)roundMode));
|
||||
}
|
||||
|
||||
public static Operand EmitGetRoundingMode(ArmEmitterContext context)
|
||||
{
|
||||
Operand rMode = context.ShiftLeft(GetFpFlag(FPState.RMode1Flag), Const(1));
|
||||
rMode = context.BitwiseOr(rMode, GetFpFlag(FPState.RMode0Flag));
|
||||
|
||||
return rMode;
|
||||
}
|
||||
|
||||
public static Operand EmitRoundByRMode(ArmEmitterContext context, Operand op)
|
||||
{
|
||||
Debug.Assert(op.Type == OperandType.FP32 || op.Type == OperandType.FP64);
|
||||
|
||||
Operand lbl1 = Label();
|
||||
Operand lbl2 = Label();
|
||||
Operand lbl3 = Label();
|
||||
Operand lblEnd = Label();
|
||||
|
||||
Operand rN = Const((int)FPRoundingMode.ToNearest);
|
||||
Operand rP = Const((int)FPRoundingMode.TowardsPlusInfinity);
|
||||
Operand rM = Const((int)FPRoundingMode.TowardsMinusInfinity);
|
||||
|
||||
Operand res = context.AllocateLocal(op.Type);
|
||||
|
||||
Operand rMode = EmitGetRoundingMode(context);
|
||||
|
||||
context.BranchIf(lbl1, rMode, rN, Comparison.NotEqual);
|
||||
context.Copy(res, EmitRoundMathCall(context, MidpointRounding.ToEven, op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lbl2, rMode, rP, Comparison.NotEqual);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Ceiling), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl2);
|
||||
context.BranchIf(lbl3, rMode, rM, Comparison.NotEqual);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Floor), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl3);
|
||||
context.Copy(res, EmitUnaryMathCall(context, nameof(Math.Truncate), op));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Operand EmitSoftFloatCall(ArmEmitterContext context, string name, params Operand[] callArgs)
|
||||
{
|
||||
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
||||
@@ -369,7 +417,11 @@ namespace ARMeilleure.Instructions
|
||||
? typeof(SoftFloat32).GetMethod(name)
|
||||
: typeof(SoftFloat64).GetMethod(name);
|
||||
|
||||
return context.Call(info, callArgs);
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(info, callArgs);
|
||||
context.LoadFromContext();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpByElemF(ArmEmitterContext context, Func2I emit)
|
||||
@@ -1269,7 +1321,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitSseOrAvxEnterFtzAndDazModesOpF(ArmEmitterContext context, out Operand isTrue)
|
||||
{
|
||||
isTrue = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
|
||||
isTrue = GetFpFlag(FPState.FzFlag);
|
||||
|
||||
Operand lblTrue = Label();
|
||||
context.BranchIfFalse(lblTrue, isTrue);
|
||||
@@ -1281,9 +1333,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
public static void EmitSseOrAvxExitFtzAndDazModesOpF(ArmEmitterContext context, Operand isTrue = default)
|
||||
{
|
||||
isTrue = isTrue == default
|
||||
? context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)))
|
||||
: isTrue;
|
||||
isTrue = isTrue == default ? GetFpFlag(FPState.FzFlag) : isTrue;
|
||||
|
||||
Operand lblTrue = Label();
|
||||
context.BranchIfFalse(lblTrue, isTrue);
|
||||
@@ -1552,13 +1602,13 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lbl1, op, zeroL, Comparison.LessOrEqual);
|
||||
context.Copy(res, maxT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lblEnd, op, zeroL, Comparison.GreaterOrEqual);
|
||||
context.Copy(res, minT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1583,7 +1633,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lblEnd, op, zeroUL, Comparison.LessOrEqualUI);
|
||||
context.Copy(res, maxT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1610,13 +1660,13 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lbl1, op, maxT, Comparison.LessOrEqual);
|
||||
context.Copy(res, maxT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lblEnd, op, minT, Comparison.GreaterOrEqual);
|
||||
context.Copy(res, minT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1641,7 +1691,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lblEnd, op, maxT, Comparison.LessOrEqualUI);
|
||||
context.Copy(res, maxT);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1663,7 +1713,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lblEnd, op, minL, Comparison.NotEqual);
|
||||
context.Copy(res, maxL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1691,7 +1741,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1713,7 +1763,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||
context.Copy(res, maxUL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1741,7 +1791,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
Operand isPositive = context.ICompareGreaterOrEqual(op1, zeroL);
|
||||
context.Copy(res, context.ConditionalSelect(isPositive, maxL, minL));
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1763,7 +1813,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIf(lblEnd, op1, op2, Comparison.GreaterOrEqualUI);
|
||||
context.Copy(res, zeroL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1790,19 +1840,19 @@ namespace ARMeilleure.Instructions
|
||||
Operand notOp2AndRes = context.BitwiseAnd(context.BitwiseNot(op2), add);
|
||||
context.BranchIf(lblEnd, notOp2AndRes, zeroL, Comparison.GreaterOrEqual);
|
||||
context.Copy(res, maxL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lbl2, op2, zeroL, Comparison.Less);
|
||||
context.Copy(res, maxL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl2);
|
||||
context.BranchIf(lblEnd, add, maxL, Comparison.LessOrEqualUI);
|
||||
context.Copy(res, maxL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
@@ -1828,14 +1878,14 @@ namespace ARMeilleure.Instructions
|
||||
context.BranchIf(lbl1, op1, zeroL, Comparison.Less);
|
||||
context.BranchIf(lblEnd, add, op1, Comparison.GreaterOrEqualUI);
|
||||
context.Copy(res, maxUL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lbl1);
|
||||
context.BranchIf(lblEnd, op2, maxL, Comparison.GreaterUI);
|
||||
context.BranchIf(lblEnd, add, zeroL, Comparison.GreaterOrEqual);
|
||||
context.Copy(res, zeroL);
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
context.Branch(lblEnd);
|
||||
|
||||
context.MarkLabel(lblEnd);
|
||||
|
@@ -1181,7 +1181,11 @@ namespace ARMeilleure.Instructions
|
||||
Array.Resize(ref callArgs, callArgs.Length + 1);
|
||||
callArgs[callArgs.Length - 1] = Const(1);
|
||||
|
||||
return context.Call(info, callArgs);
|
||||
context.StoreToContext();
|
||||
Operand res = context.Call(info, callArgs);
|
||||
context.LoadFromContext();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Operand EmitVectorExtractSx32(ArmEmitterContext context, int reg, int index, int size)
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using ARMeilleure.Decoders;
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.State;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
@@ -378,7 +379,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
context.BranchIfFalse(lblNoSat, context.BitwiseOr(gt, lt));
|
||||
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetFpFlag(context, FPState.QcFlag, Const(1));
|
||||
|
||||
context.MarkLabel(lblNoSat);
|
||||
|
||||
|
@@ -31,8 +31,8 @@ namespace ARMeilleure.Instructions
|
||||
case 0b11_011_0000_0000_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)); break;
|
||||
case 0b11_011_0000_0000_111: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)); break;
|
||||
case 0b11_011_0100_0010_000: EmitGetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)); break;
|
||||
case 0b11_011_0100_0100_000: EmitGetFpcr(context); return;
|
||||
case 0b11_011_0100_0100_001: EmitGetFpsr(context); return;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrEl0)); break;
|
||||
case 0b11_011_1101_0000_011: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)); break;
|
||||
case 0b11_011_1110_0000_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntfrqEl0)); break;
|
||||
@@ -53,9 +53,9 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
switch (GetPackedId(op))
|
||||
{
|
||||
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)); break;
|
||||
case 0b11_011_0100_0100_001: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)); break;
|
||||
case 0b11_011_0100_0010_000: EmitSetNzcv(context); return;
|
||||
case 0b11_011_0100_0100_000: EmitSetFpcr(context); return;
|
||||
case 0b11_011_0100_0100_001: EmitSetFpsr(context); return;
|
||||
case 0b11_011_1101_0000_010: info = typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)); break;
|
||||
|
||||
default: throw new NotImplementedException($"Unknown MSR 0x{op.RawOpCode:X8} at 0x{op.Address:X16}.");
|
||||
@@ -121,39 +121,91 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
||||
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
||||
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
||||
Operand nzcv = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
|
||||
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
|
||||
nzcv = context.BitwiseOr(nzcv, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
|
||||
|
||||
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
||||
SetIntOrZR(context, op.Rt, nzcv);
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rt, nzcvSh);
|
||||
private static void EmitGetFpcr(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand fpcr = Const(0);
|
||||
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
|
||||
{
|
||||
fpcr = context.BitwiseOr(fpcr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||
}
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rt, fpcr);
|
||||
}
|
||||
|
||||
private static void EmitGetFpsr(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand fpsr = Const(0);
|
||||
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
|
||||
{
|
||||
fpsr = context.BitwiseOr(fpsr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||
}
|
||||
}
|
||||
|
||||
SetIntOrZR(context, op.Rt, fpsr);
|
||||
}
|
||||
|
||||
private static void EmitSetNzcv(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand t = GetIntOrZR(context, op.Rt);
|
||||
t = context.ConvertI64ToI32(t);
|
||||
Operand nzcv = GetIntOrZR(context, op.Rt);
|
||||
nzcv = context.ConvertI64ToI32(nzcv);
|
||||
|
||||
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
||||
v = context.BitwiseAnd (v, Const(1));
|
||||
SetFlag(context, PState.VFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.VFlag)), Const(1)));
|
||||
SetFlag(context, PState.CFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.CFlag)), Const(1)));
|
||||
SetFlag(context, PState.ZFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.ZFlag)), Const(1)));
|
||||
SetFlag(context, PState.NFlag, context.BitwiseAnd(context.ShiftRightUI(nzcv, Const((int)PState.NFlag)), Const(1)));
|
||||
}
|
||||
|
||||
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
||||
c = context.BitwiseAnd (c, Const(1));
|
||||
private static void EmitSetFpcr(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
||||
z = context.BitwiseAnd (z, Const(1));
|
||||
Operand fpcr = GetIntOrZR(context, op.Rt);
|
||||
fpcr = context.ConvertI64ToI32(fpcr);
|
||||
|
||||
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
||||
n = context.BitwiseAnd (n, Const(1));
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPCR.Mask.HasFlag((FPCR)(1u << flag)))
|
||||
{
|
||||
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpcr, Const(flag)), Const(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetFlag(context, PState.VFlag, v);
|
||||
SetFlag(context, PState.CFlag, c);
|
||||
SetFlag(context, PState.ZFlag, z);
|
||||
SetFlag(context, PState.NFlag, n);
|
||||
private static void EmitSetFpsr(ArmEmitterContext context)
|
||||
{
|
||||
OpCodeSystem op = (OpCodeSystem)context.CurrOp;
|
||||
|
||||
Operand fpsr = GetIntOrZR(context, op.Rt);
|
||||
fpsr = context.ConvertI64ToI32(fpsr);
|
||||
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPSR.Mask.HasFlag((FPSR)(1u << flag)))
|
||||
{
|
||||
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpsr, Const(flag)), Const(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -169,14 +169,11 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand vSh = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||
Operand cSh = context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag));
|
||||
Operand zSh = context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag));
|
||||
Operand nSh = context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag));
|
||||
Operand qSh = context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag));
|
||||
|
||||
Operand spsr = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
||||
spsr = context.BitwiseOr(spsr, qSh);
|
||||
Operand spsr = context.ShiftLeft(GetFlag(PState.VFlag), Const((int)PState.VFlag));
|
||||
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.CFlag), Const((int)PState.CFlag)));
|
||||
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.ZFlag), Const((int)PState.ZFlag)));
|
||||
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.NFlag), Const((int)PState.NFlag)));
|
||||
spsr = context.BitwiseOr(spsr, context.ShiftLeft(GetFlag(PState.QFlag), Const((int)PState.QFlag)));
|
||||
|
||||
// TODO: Remaining flags.
|
||||
|
||||
@@ -200,8 +197,7 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
EmitSetNzcv(context, value);
|
||||
|
||||
Operand q = context.ShiftRightUI(value, Const((int)PState.QFlag));
|
||||
q = context.BitwiseAnd(q, Const(1));
|
||||
Operand q = context.BitwiseAnd(context.ShiftRightUI(value, Const((int)PState.QFlag)), Const(1));
|
||||
|
||||
SetFlag(context, PState.QFlag, q);
|
||||
}
|
||||
@@ -284,17 +280,10 @@ namespace ARMeilleure.Instructions
|
||||
|
||||
private static void EmitSetNzcv(ArmEmitterContext context, Operand t)
|
||||
{
|
||||
Operand v = context.ShiftRightUI(t, Const((int)PState.VFlag));
|
||||
v = context.BitwiseAnd(v, Const(1));
|
||||
|
||||
Operand c = context.ShiftRightUI(t, Const((int)PState.CFlag));
|
||||
c = context.BitwiseAnd(c, Const(1));
|
||||
|
||||
Operand z = context.ShiftRightUI(t, Const((int)PState.ZFlag));
|
||||
z = context.BitwiseAnd(z, Const(1));
|
||||
|
||||
Operand n = context.ShiftRightUI(t, Const((int)PState.NFlag));
|
||||
n = context.BitwiseAnd(n, Const(1));
|
||||
Operand v = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.VFlag)), Const(1));
|
||||
Operand c = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.CFlag)), Const(1));
|
||||
Operand z = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.ZFlag)), Const(1));
|
||||
Operand n = context.BitwiseAnd(context.ShiftRightUI(t, Const((int)PState.NFlag)), Const(1));
|
||||
|
||||
SetFlag(context, PState.VFlag, v);
|
||||
SetFlag(context, PState.CFlag, c);
|
||||
@@ -306,42 +295,32 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
||||
|
||||
Operand vSh = context.ShiftLeft(GetFpFlag(FPState.VFlag), Const((int)FPState.VFlag));
|
||||
Operand cSh = context.ShiftLeft(GetFpFlag(FPState.CFlag), Const((int)FPState.CFlag));
|
||||
Operand zSh = context.ShiftLeft(GetFpFlag(FPState.ZFlag), Const((int)FPState.ZFlag));
|
||||
Operand nSh = context.ShiftLeft(GetFpFlag(FPState.NFlag), Const((int)FPState.NFlag));
|
||||
Operand fpscr = Const(0);
|
||||
|
||||
Operand nzcvSh = context.BitwiseOr(context.BitwiseOr(nSh, zSh), context.BitwiseOr(cSh, vSh));
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
|
||||
{
|
||||
fpscr = context.BitwiseOr(fpscr, context.ShiftLeft(GetFpFlag((FPState)flag), Const(flag)));
|
||||
}
|
||||
}
|
||||
|
||||
Operand fpscr = context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr)));
|
||||
|
||||
SetIntA32(context, op.Rt, context.BitwiseOr(nzcvSh, fpscr));
|
||||
SetIntA32(context, op.Rt, fpscr);
|
||||
}
|
||||
|
||||
private static void EmitSetFpscr(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdSpecial op = (OpCode32SimdSpecial)context.CurrOp;
|
||||
|
||||
Operand t = GetIntA32(context, op.Rt);
|
||||
Operand fpscr = GetIntA32(context, op.Rt);
|
||||
|
||||
Operand v = context.ShiftRightUI(t, Const((int)FPState.VFlag));
|
||||
v = context.BitwiseAnd(v, Const(1));
|
||||
|
||||
Operand c = context.ShiftRightUI(t, Const((int)FPState.CFlag));
|
||||
c = context.BitwiseAnd(c, Const(1));
|
||||
|
||||
Operand z = context.ShiftRightUI(t, Const((int)FPState.ZFlag));
|
||||
z = context.BitwiseAnd(z, Const(1));
|
||||
|
||||
Operand n = context.ShiftRightUI(t, Const((int)FPState.NFlag));
|
||||
n = context.BitwiseAnd(n, Const(1));
|
||||
|
||||
SetFpFlag(context, FPState.VFlag, v);
|
||||
SetFpFlag(context, FPState.CFlag, c);
|
||||
SetFpFlag(context, FPState.ZFlag, z);
|
||||
SetFpFlag(context, FPState.NFlag, n);
|
||||
|
||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr)), t);
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
if (FPSCR.Mask.HasFlag((FPSCR)(1u << flag)))
|
||||
{
|
||||
SetFpFlag(context, (FPState)flag, context.BitwiseAnd(context.ShiftRightUI(fpscr, Const(flag)), Const(1)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -72,29 +72,6 @@ namespace ARMeilleure.Instructions
|
||||
return (ulong)GetContext().DczidEl0;
|
||||
}
|
||||
|
||||
public static ulong GetFpcr()
|
||||
{
|
||||
return (ulong)GetContext().Fpcr;
|
||||
}
|
||||
|
||||
public static bool GetFpcrFz()
|
||||
{
|
||||
return (GetContext().Fpcr & FPCR.Fz) != 0;
|
||||
}
|
||||
|
||||
public static ulong GetFpsr()
|
||||
{
|
||||
return (ulong)GetContext().Fpsr;
|
||||
}
|
||||
|
||||
public static uint GetFpscr()
|
||||
{
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
return (uint)(context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) |
|
||||
(uint)(context.Fpcr & FPCR.A32Mask);
|
||||
}
|
||||
|
||||
public static ulong GetTpidrEl0()
|
||||
{
|
||||
return (ulong)GetContext().TpidrEl0;
|
||||
@@ -130,29 +107,6 @@ namespace ARMeilleure.Instructions
|
||||
return GetContext().CntvctEl0;
|
||||
}
|
||||
|
||||
public static void SetFpcr(ulong value)
|
||||
{
|
||||
GetContext().Fpcr = (FPCR)value;
|
||||
}
|
||||
|
||||
public static void SetFpsr(ulong value)
|
||||
{
|
||||
GetContext().Fpsr = (FPSR)value;
|
||||
}
|
||||
|
||||
public static void SetFpsrQc()
|
||||
{
|
||||
GetContext().Fpsr |= FPSR.Qc;
|
||||
}
|
||||
|
||||
public static void SetFpscr(uint fpscr)
|
||||
{
|
||||
ExecutionContext context = GetContext();
|
||||
|
||||
context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
|
||||
context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
|
||||
}
|
||||
|
||||
public static void SetTpidrEl0(ulong value)
|
||||
{
|
||||
GetContext().TpidrEl0 = (long)value;
|
||||
|
@@ -91,76 +91,6 @@ namespace ARMeilleure.Instructions
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "Rounding"
|
||||
public static double Round(double value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
|
||||
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
|
||||
|
||||
if (roundMode == FPRoundingMode.ToNearest)
|
||||
{
|
||||
return Math.Round(value); // even
|
||||
}
|
||||
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
|
||||
{
|
||||
return Math.Ceiling(value);
|
||||
}
|
||||
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
|
||||
{
|
||||
return Math.Floor(value);
|
||||
}
|
||||
else /* if (roundMode == FPRoundingMode.TowardsZero) */
|
||||
{
|
||||
return Math.Truncate(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static float RoundF(float value)
|
||||
{
|
||||
ExecutionContext context = NativeInterface.GetContext();
|
||||
|
||||
FPRoundingMode roundMode = context.Fpcr.GetRoundingMode();
|
||||
|
||||
if (roundMode == FPRoundingMode.ToNearest)
|
||||
{
|
||||
return MathF.Round(value); // even
|
||||
}
|
||||
else if (roundMode == FPRoundingMode.TowardsPlusInfinity)
|
||||
{
|
||||
return MathF.Ceiling(value);
|
||||
}
|
||||
else if (roundMode == FPRoundingMode.TowardsMinusInfinity)
|
||||
{
|
||||
return MathF.Floor(value);
|
||||
}
|
||||
else /* if (roundMode == FPRoundingMode.TowardsZero) */
|
||||
{
|
||||
return MathF.Truncate(value);
|
||||
}
|
||||
}
|
||||
|
||||
public static int FloatToInt32(float value)
|
||||
{
|
||||
return SatF32ToS32(RoundF(value));
|
||||
}
|
||||
|
||||
public static int DoubleToInt32(double value)
|
||||
{
|
||||
return SatF64ToS32(Round(value));
|
||||
}
|
||||
|
||||
public static uint FloatToUInt32(float value)
|
||||
{
|
||||
return SatF32ToU32(RoundF(value));
|
||||
}
|
||||
|
||||
public static uint DoubleToUInt32(double value)
|
||||
{
|
||||
return SatF64ToU32(Round(value));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "Saturation"
|
||||
public static int SatF32ToS32(float value)
|
||||
{
|
||||
|
@@ -12,8 +12,8 @@ namespace ARMeilleure.Instructions
|
||||
RecipSqrtEstimateTable = BuildRecipSqrtEstimateTable();
|
||||
}
|
||||
|
||||
internal static readonly byte[] RecipEstimateTable;
|
||||
internal static readonly byte[] RecipSqrtEstimateTable;
|
||||
public static readonly byte[] RecipEstimateTable;
|
||||
public static readonly byte[] RecipSqrtEstimateTable;
|
||||
|
||||
private static byte[] BuildRecipEstimateTable()
|
||||
{
|
||||
@@ -94,6 +94,13 @@ namespace ARMeilleure.Instructions
|
||||
context.Fpsr |= (FPSR)(1 << (int)exc);
|
||||
}
|
||||
}
|
||||
|
||||
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
|
||||
{
|
||||
const int RModeShift = 22;
|
||||
|
||||
return (FPRoundingMode)(((uint)fpcr >> RModeShift) & 3u);
|
||||
}
|
||||
}
|
||||
|
||||
static class SoftFloat16
|
||||
|
@@ -36,10 +36,25 @@ namespace ARMeilleure.State
|
||||
set => _nativeContext.SetPstate(value);
|
||||
}
|
||||
|
||||
public FPCR Fpcr { get; set; }
|
||||
public FPSR Fpsr { get; set; }
|
||||
public FPSR Fpsr
|
||||
{
|
||||
get => (FPSR)_nativeContext.GetFPState((uint)FPSR.Mask);
|
||||
set => _nativeContext.SetFPState((uint)value, (uint)FPSR.Mask);
|
||||
}
|
||||
|
||||
public FPCR Fpcr
|
||||
{
|
||||
get => (FPCR)_nativeContext.GetFPState((uint)FPCR.Mask);
|
||||
set => _nativeContext.SetFPState((uint)value, (uint)FPCR.Mask);
|
||||
}
|
||||
public FPCR StandardFpcrValue => (Fpcr & (FPCR.Ahp)) | FPCR.Dn | FPCR.Fz;
|
||||
|
||||
public FPSCR Fpscr
|
||||
{
|
||||
get => (FPSCR)_nativeContext.GetFPState((uint)FPSCR.Mask);
|
||||
set => _nativeContext.SetFPState((uint)value, (uint)FPSCR.Mask);
|
||||
}
|
||||
|
||||
public bool IsAarch32 { get; set; }
|
||||
|
||||
internal ExecutionMode ExecutionMode
|
||||
|
@@ -5,21 +5,18 @@ namespace ARMeilleure.State
|
||||
[Flags]
|
||||
public enum FPCR : uint
|
||||
{
|
||||
Ioe = 1u << 8,
|
||||
Dze = 1u << 9,
|
||||
Ofe = 1u << 10,
|
||||
Ufe = 1u << 11,
|
||||
Ixe = 1u << 12,
|
||||
Ide = 1u << 15,
|
||||
RMode0 = 1u << 22,
|
||||
RMode1 = 1u << 23,
|
||||
Fz = 1u << 24,
|
||||
Dn = 1u << 25,
|
||||
Ahp = 1u << 26,
|
||||
|
||||
A32Mask = 0x07FF9F00u
|
||||
}
|
||||
|
||||
public static class FPCRExtensions
|
||||
{
|
||||
private const int RModeShift = 22;
|
||||
|
||||
public static FPRoundingMode GetRoundingMode(this FPCR fpcr)
|
||||
{
|
||||
return (FPRoundingMode)(((int)fpcr >> RModeShift) & 3);
|
||||
}
|
||||
Mask = Ahp | Dn | Fz | RMode1 | RMode0 | Ide | Ixe | Ufe | Ofe | Dze | Ioe // 0x07C09F00u
|
||||
}
|
||||
}
|
||||
|
15
ARMeilleure/State/FPSCR.cs
Normal file
15
ARMeilleure/State/FPSCR.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace ARMeilleure.State
|
||||
{
|
||||
[Flags]
|
||||
public enum FPSCR : uint
|
||||
{
|
||||
V = 1u << 28,
|
||||
C = 1u << 29,
|
||||
Z = 1u << 30,
|
||||
N = 1u << 31,
|
||||
|
||||
Mask = N | Z | C | V | FPSR.Mask | FPCR.Mask // 0xFFC09F9Fu
|
||||
}
|
||||
}
|
@@ -5,11 +5,14 @@ namespace ARMeilleure.State
|
||||
[Flags]
|
||||
public enum FPSR : uint
|
||||
{
|
||||
Ioc = 1u << 0,
|
||||
Dzc = 1u << 1,
|
||||
Ofc = 1u << 2,
|
||||
Ufc = 1u << 3,
|
||||
Qc = 1u << 27,
|
||||
Ixc = 1u << 4,
|
||||
Idc = 1u << 7,
|
||||
Qc = 1u << 27,
|
||||
|
||||
Nzcv = (1u << 31) | (1u << 30) | (1u << 29) | (1u << 28),
|
||||
|
||||
A32Mask = 0xF800009Fu
|
||||
Mask = Qc | Idc | Ixc | Ufc | Ofc | Dzc | Ioc // 0x0800009Fu
|
||||
}
|
||||
}
|
||||
|
@@ -2,9 +2,30 @@
|
||||
{
|
||||
public enum FPState
|
||||
{
|
||||
// FPSR Flags.
|
||||
IocFlag = 0,
|
||||
DzcFlag = 1,
|
||||
OfcFlag = 2,
|
||||
UfcFlag = 3,
|
||||
IxcFlag = 4,
|
||||
IdcFlag = 7,
|
||||
QcFlag = 27,
|
||||
VFlag = 28,
|
||||
CFlag = 29,
|
||||
ZFlag = 30,
|
||||
NFlag = 31
|
||||
NFlag = 31,
|
||||
|
||||
// FPCR Flags.
|
||||
IoeFlag = 8,
|
||||
DzeFlag = 9,
|
||||
OfeFlag = 10,
|
||||
UfeFlag = 11,
|
||||
IxeFlag = 12,
|
||||
IdeFlag = 15,
|
||||
RMode0Flag = 22,
|
||||
RMode1Flag = 23,
|
||||
FzFlag = 24,
|
||||
DnFlag = 25,
|
||||
AhpFlag = 26
|
||||
}
|
||||
}
|
||||
|
@@ -140,6 +140,34 @@ namespace ARMeilleure.State
|
||||
GetStorage().FpFlags[(int)flag] = value ? 1u : 0u;
|
||||
}
|
||||
|
||||
public unsafe uint GetFPState(uint mask = uint.MaxValue)
|
||||
{
|
||||
uint value = 0;
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
uint bit = 1u << flag;
|
||||
|
||||
if ((mask & bit) == bit)
|
||||
{
|
||||
value |= GetStorage().FpFlags[flag] != 0 ? bit : 0u;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public unsafe void SetFPState(uint value, uint mask = uint.MaxValue)
|
||||
{
|
||||
for (int flag = 0; flag < RegisterConsts.FpFlagsCount; flag++)
|
||||
{
|
||||
uint bit = 1u << flag;
|
||||
|
||||
if ((mask & bit) == bit)
|
||||
{
|
||||
GetStorage().FpFlags[flag] = (value & bit) == bit ? 1u : 0u;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int GetCounter() => GetStorage().Counter;
|
||||
public void SetCounter(int value) => GetStorage().Counter = value;
|
||||
|
||||
|
@@ -109,10 +109,6 @@ namespace ARMeilleure.Translation
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCntvctEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetCtrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetDczidEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpcrFz)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFpsr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetFunctionAddress)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.InvalidateCacheLine)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.GetTpidrroEl0)));
|
||||
@@ -124,10 +120,6 @@ namespace ARMeilleure.Translation
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt32)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadUInt64)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ReadVector128)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpcr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpscr))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsr)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetFpsrQc)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl0)));
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SetTpidrEl032))); // A32 only.
|
||||
SetDelegateInfo(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)));
|
||||
@@ -151,12 +143,8 @@ namespace ARMeilleure.Translation
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32w)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Crc32x)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Decrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.DoubleToUInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Encrypt)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FixedRotate)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.FloatToUInt32))); // A32 only.
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashChoose)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashMajority)));
|
||||
@@ -165,8 +153,6 @@ namespace ARMeilleure.Translation
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.InverseMixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.MixColumns)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.PolynomialMult64_128)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Round)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.RoundF)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS32)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToS64)));
|
||||
SetDelegateInfo(typeof(SoftFallback).GetMethod(nameof(SoftFallback.SatF32ToU32)));
|
||||
|
@@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3700; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 3703; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
|
@@ -30,6 +30,7 @@ namespace Ryujinx.Common.Logging
|
||||
ServiceBsd,
|
||||
ServiceBtm,
|
||||
ServiceCaps,
|
||||
ServiceFatal,
|
||||
ServiceFriend,
|
||||
ServiceFs,
|
||||
ServiceHid,
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 3697;
|
||||
private const uint CodeGenVersion = 3728;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -2,6 +2,7 @@ using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
@@ -163,9 +164,17 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
else if (context.Config.Stage == ShaderStage.TessellationEvaluation)
|
||||
{
|
||||
bool tessCw = context.Config.GpuAccessor.QueryTessCw();
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
// We invert the front face on Vulkan backend, so we need to do that here aswell.
|
||||
tessCw = !tessCw;
|
||||
}
|
||||
|
||||
string patchType = context.Config.GpuAccessor.QueryTessPatchType().ToGlsl();
|
||||
string spacing = context.Config.GpuAccessor.QueryTessSpacing().ToGlsl();
|
||||
string windingOrder = context.Config.GpuAccessor.QueryTessCw() ? "cw" : "ccw";
|
||||
string windingOrder = tessCw ? "cw" : "ccw";
|
||||
|
||||
context.AppendLine($"layout ({patchType}, {spacing}, {windingOrder}) in;");
|
||||
context.AppendLine();
|
||||
@@ -185,14 +194,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedInputAttributesPerPatch != 0)
|
||||
if (context.Config.UsedInputAttributesPerPatch.Count != 0)
|
||||
{
|
||||
DeclareInputAttributesPerPatch(context, context.Config.UsedInputAttributesPerPatch);
|
||||
|
||||
context.AppendLine();
|
||||
}
|
||||
|
||||
if (context.Config.UsedOutputAttributesPerPatch != 0)
|
||||
if (context.Config.UsedOutputAttributesPerPatch.Count != 0)
|
||||
{
|
||||
DeclareUsedOutputAttributesPerPatch(context, context.Config.UsedOutputAttributesPerPatch);
|
||||
|
||||
@@ -509,13 +518,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, int usedAttributes)
|
||||
private static void DeclareInputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
while (usedAttributes != 0)
|
||||
foreach (int attr in attrs.OrderBy(x => x))
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
DeclareInputAttributePerPatch(context, index);
|
||||
usedAttributes &= ~(1 << index);
|
||||
DeclareInputAttributePerPatch(context, attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,16 +573,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static void DeclareInputAttributePerPatch(CodeGenContext context, int attr)
|
||||
{
|
||||
string layout = string.Empty;
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
layout = $"layout (location = {32 + attr}) ";
|
||||
}
|
||||
|
||||
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||
|
||||
context.AppendLine($"{layout}patch in vec4 {name};");
|
||||
context.AppendLine($"layout (location = {location}) patch in vec4 {name};");
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributes(CodeGenContext context, StructuredProgramInfo info)
|
||||
@@ -624,28 +625,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, int usedAttributes)
|
||||
private static void DeclareUsedOutputAttributesPerPatch(CodeGenContext context, HashSet<int> attrs)
|
||||
{
|
||||
while (usedAttributes != 0)
|
||||
foreach (int attr in attrs.OrderBy(x => x))
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(usedAttributes);
|
||||
DeclareOutputAttributePerPatch(context, index);
|
||||
usedAttributes &= ~(1 << index);
|
||||
DeclareOutputAttributePerPatch(context, attr);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeclareOutputAttributePerPatch(CodeGenContext context, int attr)
|
||||
{
|
||||
string layout = string.Empty;
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
layout = $"layout (location = {32 + attr}) ";
|
||||
}
|
||||
|
||||
int location = context.Config.GetPerPatchAttributeLocation(attr);
|
||||
string name = $"{DefaultNames.PerPatchAttributePrefix}{attr}";
|
||||
|
||||
context.AppendLine($"{layout}patch out vec4 {name};");
|
||||
context.AppendLine($"layout (location = {location}) patch out vec4 {name};");
|
||||
}
|
||||
|
||||
private static void DeclareSupportUniformBlock(CodeGenContext context, ShaderStage stage, int scaleElements)
|
||||
|
@@ -28,33 +28,27 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
private static Dictionary<int, BuiltInAttribute> _builtInAttributes = new Dictionary<int, BuiltInAttribute>()
|
||||
{
|
||||
{ AttributeConsts.TessLevelOuter0, new BuiltInAttribute("gl_TessLevelOuter[0]", VariableType.F32) },
|
||||
{ AttributeConsts.TessLevelOuter1, new BuiltInAttribute("gl_TessLevelOuter[1]", VariableType.F32) },
|
||||
{ AttributeConsts.TessLevelOuter2, new BuiltInAttribute("gl_TessLevelOuter[2]", VariableType.F32) },
|
||||
{ AttributeConsts.TessLevelOuter3, new BuiltInAttribute("gl_TessLevelOuter[3]", VariableType.F32) },
|
||||
{ AttributeConsts.TessLevelInner0, new BuiltInAttribute("gl_TessLevelInner[0]", VariableType.F32) },
|
||||
{ AttributeConsts.TessLevelInner1, new BuiltInAttribute("gl_TessLevelInner[1]", VariableType.F32) },
|
||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) },
|
||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) },
|
||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) },
|
||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) },
|
||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) },
|
||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||
{ AttributeConsts.Layer, new BuiltInAttribute("gl_Layer", VariableType.S32) },
|
||||
{ AttributeConsts.PointSize, new BuiltInAttribute("gl_PointSize", VariableType.F32) },
|
||||
{ AttributeConsts.PositionX, new BuiltInAttribute("gl_Position.x", VariableType.F32) },
|
||||
{ AttributeConsts.PositionY, new BuiltInAttribute("gl_Position.y", VariableType.F32) },
|
||||
{ AttributeConsts.PositionZ, new BuiltInAttribute("gl_Position.z", VariableType.F32) },
|
||||
{ AttributeConsts.PositionW, new BuiltInAttribute("gl_Position.w", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance0, new BuiltInAttribute("gl_ClipDistance[0]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance1, new BuiltInAttribute("gl_ClipDistance[1]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance2, new BuiltInAttribute("gl_ClipDistance[2]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance3, new BuiltInAttribute("gl_ClipDistance[3]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance4, new BuiltInAttribute("gl_ClipDistance[4]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance5, new BuiltInAttribute("gl_ClipDistance[5]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance6, new BuiltInAttribute("gl_ClipDistance[6]", VariableType.F32) },
|
||||
{ AttributeConsts.ClipDistance7, new BuiltInAttribute("gl_ClipDistance[7]", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordX, new BuiltInAttribute("gl_PointCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.PointCoordY, new BuiltInAttribute("gl_PointCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordX, new BuiltInAttribute("gl_TessCoord.x", VariableType.F32) },
|
||||
{ AttributeConsts.TessCoordY, new BuiltInAttribute("gl_TessCoord.y", VariableType.F32) },
|
||||
{ AttributeConsts.InstanceId, new BuiltInAttribute("gl_InstanceID", VariableType.S32) },
|
||||
{ AttributeConsts.VertexId, new BuiltInAttribute("gl_VertexID", VariableType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new BuiltInAttribute("gl_FrontFacing", VariableType.Bool) },
|
||||
|
||||
// Special.
|
||||
{ AttributeConsts.FragmentOutputDepth, new BuiltInAttribute("gl_FragDepth", VariableType.F32) },
|
||||
@@ -170,7 +164,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
value &= AttributeConsts.Mask & ~3;
|
||||
char swzMask = GetSwizzleMask((value >> 2) & 3);
|
||||
|
||||
if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||
if (perPatch)
|
||||
{
|
||||
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||
{
|
||||
value -= AttributeConsts.UserAttributePerPatchBase;
|
||||
|
||||
return $"{DefaultNames.PerPatchAttributePrefix}{(value >> 4)}.{swzMask}";
|
||||
}
|
||||
else if (value < AttributeConsts.UserAttributePerPatchBase)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
AttributeConsts.TessLevelOuter0 => "gl_TessLevelOuter[0]",
|
||||
AttributeConsts.TessLevelOuter1 => "gl_TessLevelOuter[1]",
|
||||
AttributeConsts.TessLevelOuter2 => "gl_TessLevelOuter[2]",
|
||||
AttributeConsts.TessLevelOuter3 => "gl_TessLevelOuter[3]",
|
||||
AttributeConsts.TessLevelInner0 => "gl_TessLevelInner[0]",
|
||||
AttributeConsts.TessLevelInner1 => "gl_TessLevelInner[1]",
|
||||
_ => null
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (value >= AttributeConsts.UserAttributeBase && value < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
value -= AttributeConsts.UserAttributeBase;
|
||||
|
||||
@@ -180,11 +196,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
bool indexable = config.UsedFeatures.HasFlag(isOutAttr ? FeatureFlags.OaIndexing : FeatureFlags.IaIndexing);
|
||||
|
||||
if (!indexable && perPatch)
|
||||
{
|
||||
prefix = DefaultNames.PerPatchAttributePrefix;
|
||||
}
|
||||
|
||||
if (indexable)
|
||||
{
|
||||
string name = prefix;
|
||||
@@ -202,7 +213,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
string name = $"{prefix}{(value >> 4)}_{swzMask}";
|
||||
|
||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
{
|
||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||
}
|
||||
@@ -213,7 +224,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
{
|
||||
string name = $"{prefix}{(value >> 4)}";
|
||||
|
||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr))
|
||||
{
|
||||
name += isOutAttr ? "[gl_InvocationID]" : $"[{indexExpr}]";
|
||||
}
|
||||
@@ -277,7 +288,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
string name = builtInAttr.Name;
|
||||
|
||||
if (!perPatch && AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
||||
if (AttributeInfo.IsArrayAttributeGlsl(config.Stage, isOutAttr) && AttributeInfo.IsArrayBuiltIn(value))
|
||||
{
|
||||
name = isOutAttr ? $"gl_out[gl_InvocationID].{name}" : $"gl_in[{indexExpr}].{name}";
|
||||
}
|
||||
|
@@ -382,17 +382,13 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
public Instruction GetAttributePerPatchElemPointer(int attr, bool isOutAttr, out AggregateType elemType)
|
||||
{
|
||||
var storageClass = isOutAttr ? StorageClass.Output : StorageClass.Input;
|
||||
var attrInfo = AttributeInfo.From(Config, attr, isOutAttr);
|
||||
var attrInfo = AttributeInfo.FromPatch(Config, attr, isOutAttr);
|
||||
|
||||
int attrOffset = attrInfo.BaseValue;
|
||||
Instruction ioVariable;
|
||||
|
||||
bool isUserAttr = attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd;
|
||||
Instruction ioVariable = isOutAttr ? OutputsPerPatch[attrOffset] : InputsPerPatch[attrOffset];
|
||||
|
||||
elemType = attrInfo.Type & AggregateType.ElementTypeMask;
|
||||
|
||||
ioVariable = isOutAttr ? OutputsPerPatch[attrOffset] : InputsPerPatch[attrOffset];
|
||||
|
||||
if ((attrInfo.Type & (AggregateType.Array | AggregateType.Vector)) == 0)
|
||||
{
|
||||
return ioVariable;
|
||||
@@ -404,7 +400,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
public Instruction GetAttributePerPatch(AggregateType type, int attr, bool isOutAttr)
|
||||
{
|
||||
if (!AttributeInfo.Validate(Config, attr, isOutAttr: false))
|
||||
if (!AttributeInfo.ValidatePerPatch(Config, attr, isOutAttr: false))
|
||||
{
|
||||
return GetConstant(type, new AstOperand(IrOperandType.Constant, 0));
|
||||
}
|
||||
|
@@ -403,7 +403,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
foreach (int attr in inputs)
|
||||
{
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false))
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: false, perPatch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -459,7 +459,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
foreach (int attr in outputs)
|
||||
{
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true))
|
||||
if (!AttributeInfo.Validate(context.Config, attr, isOutAttr: true, perPatch))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -519,7 +519,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
? (isOutAttr ? context.OutputsPerPatch : context.InputsPerPatch)
|
||||
: (isOutAttr ? context.Outputs : context.Inputs);
|
||||
|
||||
var attrInfo = AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||
var attrInfo = perPatch
|
||||
? AttributeInfo.FromPatch(context.Config, attr, isOutAttr)
|
||||
: AttributeInfo.From(context.Config, attr, isOutAttr);
|
||||
|
||||
if (dict.ContainsKey(attrInfo.BaseValue))
|
||||
{
|
||||
@@ -544,11 +546,6 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
var spvType = context.TypePointer(storageClass, attrType);
|
||||
var spvVar = context.Variable(spvType, storageClass);
|
||||
|
||||
if (perPatch)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Patch);
|
||||
}
|
||||
|
||||
if (builtInPassthrough)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.PassthroughNV);
|
||||
@@ -556,6 +553,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
|
||||
if (attrInfo.IsBuiltin)
|
||||
{
|
||||
if (perPatch)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Patch);
|
||||
}
|
||||
|
||||
context.Decorate(spvVar, Decoration.BuiltIn, (LiteralInteger)GetBuiltIn(context, attrInfo.BaseValue));
|
||||
|
||||
if (context.Config.TransformFeedbackEnabled && context.Config.LastInVertexPipeline && isOutAttr)
|
||||
@@ -569,6 +571,14 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (perPatch)
|
||||
{
|
||||
context.Decorate(spvVar, Decoration.Patch);
|
||||
|
||||
int location = context.Config.GetPerPatchAttributeLocation((attr - AttributeConsts.UserAttributePerPatchBase) / 16);
|
||||
|
||||
context.Decorate(spvVar, Decoration.Location, (LiteralInteger)location);
|
||||
}
|
||||
else if (isUserAttr)
|
||||
{
|
||||
int location = (attr - AttributeConsts.UserAttributeBase) / 16;
|
||||
|
@@ -882,7 +882,8 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
if (src2 is AstOperand operand && operand.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = (baseAttr.Value & AttributeConsts.Mask) + (operand.Value << 2);
|
||||
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, isOutAttr: false, index));
|
||||
bool isOutAttr = (baseAttr.Value & AttributeConsts.LoadOutputMask) != 0;
|
||||
return new OperationResult(resultType, context.GetAttribute(resultType, attrOffset, isOutAttr, index));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -191,7 +191,15 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
break;
|
||||
}
|
||||
|
||||
if (context.Config.GpuAccessor.QueryTessCw())
|
||||
bool tessCw = context.Config.GpuAccessor.QueryTessCw();
|
||||
|
||||
if (context.Config.Options.TargetApi == TargetApi.Vulkan)
|
||||
{
|
||||
// We invert the front face on Vulkan backend, so we need to do that here aswell.
|
||||
tessCw = !tessCw;
|
||||
}
|
||||
|
||||
if (tessCw)
|
||||
{
|
||||
context.AddExecutionMode(spvFunc, ExecutionMode.VertexOrderCw);
|
||||
}
|
||||
@@ -375,9 +383,10 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Spirv
|
||||
}
|
||||
else if (dest.Type == OperandType.Attribute || dest.Type == OperandType.AttributePerPatch)
|
||||
{
|
||||
if (AttributeInfo.Validate(context.Config, dest.Value, isOutAttr: true))
|
||||
bool perPatch = dest.Type == OperandType.AttributePerPatch;
|
||||
|
||||
if (AttributeInfo.Validate(context.Config, dest.Value, isOutAttr: true, perPatch))
|
||||
{
|
||||
bool perPatch = dest.Type == OperandType.AttributePerPatch;
|
||||
AggregateType elemType;
|
||||
|
||||
var elemPointer = perPatch
|
||||
|
@@ -306,18 +306,36 @@ namespace Ryujinx.Graphics.Shader.Decoders
|
||||
for (int elemIndex = 0; elemIndex < count; elemIndex++)
|
||||
{
|
||||
int attr = offset + elemIndex * 4;
|
||||
if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
|
||||
if (perPatch)
|
||||
{
|
||||
if (attr >= AttributeConsts.UserAttributePerPatchBase && attr < AttributeConsts.UserAttributePerPatchEnd)
|
||||
{
|
||||
int userAttr = attr - AttributeConsts.UserAttributePerPatchBase;
|
||||
int index = userAttr / 16;
|
||||
|
||||
if (isStore)
|
||||
{
|
||||
config.SetOutputUserAttributePerPatch(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetInputUserAttributePerPatch(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (attr >= AttributeConsts.UserAttributeBase && attr < AttributeConsts.UserAttributeEnd)
|
||||
{
|
||||
int userAttr = attr - AttributeConsts.UserAttributeBase;
|
||||
int index = userAttr / 16;
|
||||
|
||||
if (isStore)
|
||||
{
|
||||
config.SetOutputUserAttribute(index, perPatch);
|
||||
config.SetOutputUserAttribute(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
config.SetInputUserAttribute(index, (userAttr >> 2) & 3, perPatch);
|
||||
config.SetInputUserAttribute(index, (userAttr >> 2) & 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
context.FlagAttributeRead(offset);
|
||||
|
||||
if (op.O)
|
||||
if (op.O && CanLoadOutput(offset))
|
||||
{
|
||||
offset |= AttributeConsts.LoadOutputMask;
|
||||
}
|
||||
@@ -61,7 +61,7 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
|
||||
context.FlagAttributeRead(offset);
|
||||
|
||||
if (op.O)
|
||||
if (op.O && CanLoadOutput(offset))
|
||||
{
|
||||
offset |= AttributeConsts.LoadOutputMask;
|
||||
}
|
||||
@@ -241,6 +241,11 @@ namespace Ryujinx.Graphics.Shader.Instructions
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CanLoadOutput(int attr)
|
||||
{
|
||||
return attr != AttributeConsts.TessCoordX && attr != AttributeConsts.TessCoordY;
|
||||
}
|
||||
|
||||
private static bool TryFixedFuncToUserAttributeIpa(EmitterContext context, int attr, out Operand selectedAttr)
|
||||
{
|
||||
if (attr >= AttributeConsts.FrontColorDiffuseR && attr < AttributeConsts.BackColorDiffuseR)
|
||||
|
@@ -97,7 +97,15 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
|
||||
if (src1.Type == OperandType.Constant && src2.Type == OperandType.Constant)
|
||||
{
|
||||
int attrOffset = (src1.Value & AttributeConsts.Mask) + (src2.Value << 2);
|
||||
context.Info.Inputs.Add(attrOffset);
|
||||
|
||||
if ((src1.Value & AttributeConsts.LoadOutputMask) != 0)
|
||||
{
|
||||
context.Info.Outputs.Add(attrOffset);
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Info.Inputs.Add(attrOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -54,6 +54,9 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public const int UserAttributeBase = 0x80;
|
||||
public const int UserAttributeEnd = UserAttributeBase + UserAttributesCount * 16;
|
||||
|
||||
public const int UserAttributePerPatchBase = 0x18;
|
||||
public const int UserAttributePerPatchEnd = 0x200;
|
||||
|
||||
public const int LoadOutputMask = 1 << 30;
|
||||
public const int Mask = 0x3fffffff;
|
||||
|
||||
|
@@ -4,36 +4,30 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
struct AttributeInfo
|
||||
{
|
||||
private static readonly Dictionary<int, AttributeInfo> BuiltInAttributes = new Dictionary<int, AttributeInfo>()
|
||||
private static readonly Dictionary<int, AttributeInfo> _builtInAttributes = new Dictionary<int, AttributeInfo>()
|
||||
{
|
||||
{ AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) },
|
||||
{ AttributeConsts.Layer, new AttributeInfo(AttributeConsts.Layer, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.ViewportIndex, new AttributeInfo(AttributeConsts.ViewportIndex, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.PointSize, new AttributeInfo(AttributeConsts.PointSize, 0, 1, AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionX, new AttributeInfo(AttributeConsts.PositionX, 0, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionY, new AttributeInfo(AttributeConsts.PositionX, 1, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionZ, new AttributeInfo(AttributeConsts.PositionX, 2, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PositionW, new AttributeInfo(AttributeConsts.PositionX, 3, 4, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance0, new AttributeInfo(AttributeConsts.ClipDistance0, 0, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance1, new AttributeInfo(AttributeConsts.ClipDistance0, 1, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance2, new AttributeInfo(AttributeConsts.ClipDistance0, 2, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance3, new AttributeInfo(AttributeConsts.ClipDistance0, 3, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance4, new AttributeInfo(AttributeConsts.ClipDistance0, 4, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance5, new AttributeInfo(AttributeConsts.ClipDistance0, 5, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance6, new AttributeInfo(AttributeConsts.ClipDistance0, 6, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.ClipDistance7, new AttributeInfo(AttributeConsts.ClipDistance0, 7, 8, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordX, new AttributeInfo(AttributeConsts.PointCoordX, 0, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.PointCoordY, new AttributeInfo(AttributeConsts.PointCoordX, 1, 2, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordX, new AttributeInfo(AttributeConsts.TessCoordX, 0, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessCoordY, new AttributeInfo(AttributeConsts.TessCoordX, 1, 3, AggregateType.Vector | AggregateType.FP32) },
|
||||
{ AttributeConsts.InstanceId, new AttributeInfo(AttributeConsts.InstanceId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.VertexId, new AttributeInfo(AttributeConsts.VertexId, 0, 1, AggregateType.S32) },
|
||||
{ AttributeConsts.FrontFacing, new AttributeInfo(AttributeConsts.FrontFacing, 0, 1, AggregateType.Bool) },
|
||||
|
||||
// Special.
|
||||
{ AttributeConsts.FragmentOutputDepth, new AttributeInfo(AttributeConsts.FragmentOutputDepth, 0, 1, AggregateType.FP32) },
|
||||
@@ -55,6 +49,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{ AttributeConsts.LtMask, new AttributeInfo(AttributeConsts.LtMask, 0, 4, AggregateType.Vector | AggregateType.U32) },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<int, AttributeInfo> _builtInAttributesPerPatch = new Dictionary<int, AttributeInfo>()
|
||||
{
|
||||
{ AttributeConsts.TessLevelOuter0, new AttributeInfo(AttributeConsts.TessLevelOuter0, 0, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter1, new AttributeInfo(AttributeConsts.TessLevelOuter0, 1, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter2, new AttributeInfo(AttributeConsts.TessLevelOuter0, 2, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelOuter3, new AttributeInfo(AttributeConsts.TessLevelOuter0, 3, 4, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelInner0, new AttributeInfo(AttributeConsts.TessLevelInner0, 0, 2, AggregateType.Array | AggregateType.FP32) },
|
||||
{ AttributeConsts.TessLevelInner1, new AttributeInfo(AttributeConsts.TessLevelInner0, 1, 2, AggregateType.Array | AggregateType.FP32) },
|
||||
};
|
||||
|
||||
public int BaseValue { get; }
|
||||
public int Value { get; }
|
||||
public int Length { get; }
|
||||
@@ -76,6 +80,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return (Value - BaseValue) / 4;
|
||||
}
|
||||
|
||||
public static bool Validate(ShaderConfig config, int value, bool isOutAttr, bool perPatch)
|
||||
{
|
||||
return perPatch ? ValidatePerPatch(config, value, isOutAttr) : Validate(config, value, isOutAttr);
|
||||
}
|
||||
|
||||
public static bool Validate(ShaderConfig config, int value, bool isOutAttr)
|
||||
{
|
||||
if (value == AttributeConsts.ViewportIndex && !config.GpuAccessor.QueryHostSupportsViewportIndex())
|
||||
@@ -86,6 +95,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
return From(config, value, isOutAttr).IsValid;
|
||||
}
|
||||
|
||||
public static bool ValidatePerPatch(ShaderConfig config, int value, bool isOutAttr)
|
||||
{
|
||||
return FromPatch(config, value, isOutAttr).IsValid;
|
||||
}
|
||||
|
||||
public static AttributeInfo From(ShaderConfig config, int value, bool isOutAttr)
|
||||
{
|
||||
value &= ~3;
|
||||
@@ -115,7 +129,24 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
return new AttributeInfo(value, 0, 1, AggregateType.FP32);
|
||||
}
|
||||
else if (BuiltInAttributes.TryGetValue(value, out AttributeInfo info))
|
||||
else if (_builtInAttributes.TryGetValue(value, out AttributeInfo info))
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
||||
return new AttributeInfo(value, 0, 0, AggregateType.Invalid);
|
||||
}
|
||||
|
||||
public static AttributeInfo FromPatch(ShaderConfig config, int value, bool isOutAttr)
|
||||
{
|
||||
value &= ~3;
|
||||
|
||||
if (value >= AttributeConsts.UserAttributePerPatchBase && value < AttributeConsts.UserAttributePerPatchEnd)
|
||||
{
|
||||
int offset = (value - AttributeConsts.UserAttributePerPatchBase) & 0xf;
|
||||
return new AttributeInfo(value - offset, offset >> 2, 4, AggregateType.Vector | AggregateType.FP32, false);
|
||||
}
|
||||
else if (_builtInAttributesPerPatch.TryGetValue(value, out AttributeInfo info))
|
||||
{
|
||||
return info;
|
||||
}
|
||||
|
@@ -261,7 +261,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
{
|
||||
int index = BitOperations.TrailingZeroCount(passthroughAttributes);
|
||||
WriteOutput(AttributeConsts.UserAttributeBase + index * 16, primIndex);
|
||||
Config.SetOutputUserAttribute(index, perPatch: false);
|
||||
Config.SetOutputUserAttribute(index);
|
||||
passthroughAttributes &= ~(1 << index);
|
||||
}
|
||||
|
||||
@@ -364,7 +364,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
bool targetEnabled = (Config.OmapTargets & (0xf << (rtIndex * 4))) != 0;
|
||||
if (targetEnabled)
|
||||
{
|
||||
Config.SetOutputUserAttribute(rtIndex, perPatch: false);
|
||||
Config.SetOutputUserAttribute(rtIndex);
|
||||
regIndexBase += 4;
|
||||
}
|
||||
}
|
||||
|
@@ -50,16 +50,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
public bool NextUsesFixedFuncAttributes { get; private set; }
|
||||
public int UsedInputAttributes { get; private set; }
|
||||
public int UsedOutputAttributes { get; private set; }
|
||||
public int UsedInputAttributesPerPatch { get; private set; }
|
||||
public int UsedOutputAttributesPerPatch { get; private set; }
|
||||
public HashSet<int> UsedInputAttributesPerPatch { get; }
|
||||
public HashSet<int> UsedOutputAttributesPerPatch { get; }
|
||||
public HashSet<int> NextUsedInputAttributesPerPatch { get; private set; }
|
||||
public int PassthroughAttributes { get; private set; }
|
||||
private int _nextUsedInputAttributes;
|
||||
private int _thisUsedInputAttributes;
|
||||
private Dictionary<int, int> _perPatchAttributeLocations;
|
||||
|
||||
public UInt128 NextInputAttributesComponents { get; private set; }
|
||||
public UInt128 ThisInputAttributesComponents { get; private set; }
|
||||
public UInt128 NextInputAttributesPerPatchComponents { get; private set; }
|
||||
public UInt128 ThisInputAttributesPerPatchComponents { get; private set; }
|
||||
|
||||
private int _usedConstantBuffers;
|
||||
private int _usedStorageBuffers;
|
||||
@@ -119,9 +119,13 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
public ShaderConfig(IGpuAccessor gpuAccessor, TranslationOptions options)
|
||||
{
|
||||
Stage = ShaderStage.Compute;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Options = options;
|
||||
Stage = ShaderStage.Compute;
|
||||
GpuAccessor = gpuAccessor;
|
||||
Options = options;
|
||||
|
||||
UsedInputAttributesPerPatch = new HashSet<int>();
|
||||
UsedOutputAttributesPerPatch = new HashSet<int>();
|
||||
|
||||
_usedTextures = new Dictionary<TextureInfo, TextureMeta>();
|
||||
_usedImages = new Dictionary<TextureInfo, TextureMeta>();
|
||||
}
|
||||
@@ -244,49 +248,71 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
UsedOutputAttributes |= 1 << index;
|
||||
}
|
||||
|
||||
public void SetInputUserAttribute(int index, int component, bool perPatch)
|
||||
public void SetInputUserAttribute(int index, int component)
|
||||
{
|
||||
if (perPatch)
|
||||
{
|
||||
UsedInputAttributesPerPatch |= 1 << index;
|
||||
ThisInputAttributesPerPatchComponents |= UInt128.Pow2(index * 4 + component);
|
||||
}
|
||||
else
|
||||
{
|
||||
int mask = 1 << index;
|
||||
int mask = 1 << index;
|
||||
|
||||
UsedInputAttributes |= mask;
|
||||
_thisUsedInputAttributes |= mask;
|
||||
ThisInputAttributesComponents |= UInt128.Pow2(index * 4 + component);
|
||||
}
|
||||
UsedInputAttributes |= mask;
|
||||
_thisUsedInputAttributes |= mask;
|
||||
ThisInputAttributesComponents |= UInt128.Pow2(index * 4 + component);
|
||||
}
|
||||
|
||||
public void SetOutputUserAttribute(int index, bool perPatch)
|
||||
public void SetInputUserAttributePerPatch(int index)
|
||||
{
|
||||
if (perPatch)
|
||||
{
|
||||
UsedOutputAttributesPerPatch |= 1 << index;
|
||||
}
|
||||
else
|
||||
{
|
||||
UsedOutputAttributes |= 1 << index;
|
||||
}
|
||||
UsedInputAttributesPerPatch.Add(index);
|
||||
}
|
||||
|
||||
public void SetOutputUserAttribute(int index)
|
||||
{
|
||||
UsedOutputAttributes |= 1 << index;
|
||||
}
|
||||
|
||||
public void SetOutputUserAttributePerPatch(int index)
|
||||
{
|
||||
UsedOutputAttributesPerPatch.Add(index);
|
||||
}
|
||||
|
||||
public void MergeFromtNextStage(ShaderConfig config)
|
||||
{
|
||||
NextInputAttributesComponents = config.ThisInputAttributesComponents;
|
||||
NextInputAttributesPerPatchComponents = config.ThisInputAttributesPerPatchComponents;
|
||||
NextUsedInputAttributesPerPatch = config.UsedInputAttributesPerPatch;
|
||||
NextUsesFixedFuncAttributes = config.UsedFeatures.HasFlag(FeatureFlags.FixedFuncAttr);
|
||||
MergeOutputUserAttributes(config.UsedInputAttributes, config.UsedInputAttributesPerPatch);
|
||||
|
||||
if (UsedOutputAttributesPerPatch.Count != 0)
|
||||
{
|
||||
// Regular and per-patch input/output locations can't overlap,
|
||||
// so we must assign on our location using unused regular input/output locations.
|
||||
|
||||
Dictionary<int, int> locationsMap = new Dictionary<int, int>();
|
||||
|
||||
int freeMask = ~UsedOutputAttributes;
|
||||
|
||||
foreach (int attr in UsedOutputAttributesPerPatch)
|
||||
{
|
||||
int location = BitOperations.TrailingZeroCount(freeMask);
|
||||
if (location == 32)
|
||||
{
|
||||
config.GpuAccessor.Log($"No enough free locations for patch input/output 0x{attr:X}.");
|
||||
break;
|
||||
}
|
||||
|
||||
locationsMap.Add(attr, location);
|
||||
freeMask &= ~(1 << location);
|
||||
}
|
||||
|
||||
// Both stages must agree on the locations, so use the same "map" for both.
|
||||
_perPatchAttributeLocations = locationsMap;
|
||||
config._perPatchAttributeLocations = locationsMap;
|
||||
}
|
||||
|
||||
if (config.Stage != ShaderStage.Fragment)
|
||||
{
|
||||
LastInVertexPipeline = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void MergeOutputUserAttributes(int mask, int maskPerPatch)
|
||||
public void MergeOutputUserAttributes(int mask, IEnumerable<int> perPatch)
|
||||
{
|
||||
_nextUsedInputAttributes = mask;
|
||||
|
||||
@@ -297,10 +323,20 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
else
|
||||
{
|
||||
UsedOutputAttributes |= mask;
|
||||
UsedOutputAttributesPerPatch |= maskPerPatch;
|
||||
UsedOutputAttributesPerPatch.UnionWith(perPatch);
|
||||
}
|
||||
}
|
||||
|
||||
public int GetPerPatchAttributeLocation(int index)
|
||||
{
|
||||
if (_perPatchAttributeLocations == null || !_perPatchAttributeLocations.TryGetValue(index, out int location))
|
||||
{
|
||||
return index;
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
public bool IsUsedOutputAttribute(int attr)
|
||||
{
|
||||
// The check for fixed function attributes on the next stage is conservative,
|
||||
|
@@ -204,14 +204,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: false);
|
||||
}
|
||||
|
||||
UInt128 usedAttributesPerPatch = context.Config.NextInputAttributesPerPatchComponents;
|
||||
while (usedAttributesPerPatch != UInt128.Zero)
|
||||
if (context.Config.NextUsedInputAttributesPerPatch != null)
|
||||
{
|
||||
int index = usedAttributesPerPatch.TrailingZeroCount();
|
||||
|
||||
InitializeOutputComponent(context, AttributeConsts.UserAttributeBase + index * 4, perPatch: true);
|
||||
|
||||
usedAttributesPerPatch &= ~UInt128.Pow2(index);
|
||||
foreach (int vecIndex in context.Config.NextUsedInputAttributesPerPatch.OrderBy(x => x))
|
||||
{
|
||||
InitializeOutput(context, AttributeConsts.UserAttributePerPatchBase + vecIndex * 16, perPatch: true);
|
||||
}
|
||||
}
|
||||
|
||||
if (config.NextUsesFixedFuncAttributes)
|
||||
@@ -236,7 +234,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
for (int c = 0; c < 4; c++)
|
||||
{
|
||||
int attrOffset = baseAttr + c * 4;
|
||||
context.Copy(perPatch ? AttributePerPatch(attrOffset) : Attribute(attrOffset), ConstF(c == 3 ? 1f : 0f));
|
||||
InitializeOutputComponent(context, attrOffset, perPatch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Graphics.Shader.Decoders;
|
||||
using Ryujinx.Graphics.Shader.IntermediateRepresentation;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using static Ryujinx.Graphics.Shader.IntermediateRepresentation.OperandHelper;
|
||||
using static Ryujinx.Graphics.Shader.Translation.Translator;
|
||||
@@ -137,7 +138,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
if (other != null)
|
||||
{
|
||||
other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, 0);
|
||||
other._config.MergeOutputUserAttributes(_config.UsedOutputAttributes, Enumerable.Empty<int>());
|
||||
|
||||
FunctionCode[] otherCode = EmitShader(other._program, other._config, initializeOutputs: true, out int aStart);
|
||||
|
||||
|
@@ -68,6 +68,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private bool _tfEnabled;
|
||||
private bool _tfActive;
|
||||
|
||||
private PipelineColorBlendAttachmentState[] _storedBlend;
|
||||
|
||||
public ulong DrawCount { get; private set; }
|
||||
|
||||
public unsafe PipelineBase(VulkanRenderer gd, Device device)
|
||||
@@ -104,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.Initialize();
|
||||
_newState.LineWidth = 1f;
|
||||
_newState.SamplesCount = 1;
|
||||
|
||||
_storedBlend = new PipelineColorBlendAttachmentState[8];
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -498,13 +502,28 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
|
||||
|
||||
vkBlend.BlendEnable = blend.Enable;
|
||||
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
||||
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
||||
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
|
||||
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
||||
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
||||
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
||||
if (blend.Enable)
|
||||
{
|
||||
vkBlend.BlendEnable = blend.Enable;
|
||||
vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
|
||||
vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
|
||||
vkBlend.ColorBlendOp = blend.ColorOp.Convert();
|
||||
vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
|
||||
vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
|
||||
vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
|
||||
}
|
||||
else
|
||||
{
|
||||
vkBlend = new PipelineColorBlendAttachmentState(
|
||||
colorWriteMask: vkBlend.ColorWriteMask);
|
||||
}
|
||||
|
||||
if (vkBlend.ColorWriteMask == 0)
|
||||
{
|
||||
_storedBlend[index] = vkBlend;
|
||||
|
||||
vkBlend = new PipelineColorBlendAttachmentState();
|
||||
}
|
||||
|
||||
_newState.BlendConstantR = blend.BlendConstant.Red;
|
||||
_newState.BlendConstantG = blend.BlendConstant.Green;
|
||||
@@ -669,8 +688,25 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
ref var vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
|
||||
var newMask = (ColorComponentFlags)componentMask[i];
|
||||
|
||||
vkBlend.ColorWriteMask = (ColorComponentFlags)componentMask[i];
|
||||
// When color write mask is 0, remove all blend state to help the pipeline cache.
|
||||
// Restore it when the mask becomes non-zero.
|
||||
if (vkBlend.ColorWriteMask != newMask)
|
||||
{
|
||||
if (newMask == 0)
|
||||
{
|
||||
_storedBlend[i] = vkBlend;
|
||||
|
||||
vkBlend = new PipelineColorBlendAttachmentState();
|
||||
}
|
||||
else if (vkBlend.ColorWriteMask == 0)
|
||||
{
|
||||
vkBlend = _storedBlend[i];
|
||||
}
|
||||
}
|
||||
|
||||
vkBlend.ColorWriteMask = newMask;
|
||||
|
||||
if (componentMask[i] != 0)
|
||||
{
|
||||
|
@@ -257,15 +257,23 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
var blend = state.BlendDescriptors[i];
|
||||
|
||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||
blend.Enable,
|
||||
blend.ColorSrcFactor.Convert(),
|
||||
blend.ColorDstFactor.Convert(),
|
||||
blend.ColorOp.Convert(),
|
||||
blend.AlphaSrcFactor.Convert(),
|
||||
blend.AlphaDstFactor.Convert(),
|
||||
blend.AlphaOp.Convert(),
|
||||
(ColorComponentFlags)state.ColorWriteMask[i]);
|
||||
if (blend.Enable && state.ColorWriteMask[i] != 0)
|
||||
{
|
||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||
blend.Enable,
|
||||
blend.ColorSrcFactor.Convert(),
|
||||
blend.ColorDstFactor.Convert(),
|
||||
blend.ColorOp.Convert(),
|
||||
blend.AlphaSrcFactor.Convert(),
|
||||
blend.AlphaDstFactor.Convert(),
|
||||
blend.AlphaOp.Convert(),
|
||||
(ColorComponentFlags)state.ColorWriteMask[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
pipeline.Internal.ColorBlendAttachmentState[i] = new PipelineColorBlendAttachmentState(
|
||||
colorWriteMask: (ColorComponentFlags)state.ColorWriteMask[i]);
|
||||
}
|
||||
}
|
||||
|
||||
int maxAttachmentIndex = 0;
|
||||
|
@@ -9,17 +9,19 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class Shader
|
||||
class Shader : IDisposable
|
||||
{
|
||||
// The shaderc.net dependency's Options constructor and dispose are not thread safe.
|
||||
// Take this lock when using them.
|
||||
private static object _shaderOptionsLock = new object();
|
||||
|
||||
private static readonly IntPtr _ptrMainEntryPointName = Marshal.StringToHGlobalAnsi("main");
|
||||
|
||||
private readonly Vk _api;
|
||||
private readonly Device _device;
|
||||
private readonly ShaderStageFlags _stage;
|
||||
|
||||
private IntPtr _entryPointName;
|
||||
private bool _disposed;
|
||||
private ShaderModule _module;
|
||||
|
||||
public ShaderStageFlags StageFlags => _stage;
|
||||
@@ -39,7 +41,6 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
CompileStatus = ProgramLinkStatus.Incomplete;
|
||||
|
||||
_stage = shaderSource.Stage.Convert();
|
||||
_entryPointName = Marshal.StringToHGlobalAnsi("main");
|
||||
|
||||
CompileTask = Task.Run(() =>
|
||||
{
|
||||
@@ -145,7 +146,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SType = StructureType.PipelineShaderStageCreateInfo,
|
||||
Stage = _stage,
|
||||
Module = _module,
|
||||
PName = (byte*)_entryPointName
|
||||
PName = (byte*)_ptrMainEntryPointName
|
||||
};
|
||||
}
|
||||
|
||||
@@ -156,11 +157,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (_entryPointName != IntPtr.Zero)
|
||||
if (!_disposed)
|
||||
{
|
||||
_api.DestroyShaderModule(_device, _module, null);
|
||||
Marshal.FreeHGlobal(_entryPointName);
|
||||
_entryPointName = IntPtr.Zero;
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,8 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
// outside of the AccountManager.
|
||||
private readonly HorizonClient _horizonClient;
|
||||
|
||||
private ConcurrentDictionary<string, UserProfile> _profiles;
|
||||
private readonly ConcurrentDictionary<string, UserProfile> _profiles;
|
||||
private UserProfile[] _storedOpenedUsers;
|
||||
|
||||
public UserProfile LastOpenedUser { get; private set; }
|
||||
|
||||
@@ -31,6 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
_horizonClient = horizonClient;
|
||||
|
||||
_profiles = new ConcurrentDictionary<string, UserProfile>();
|
||||
_storedOpenedUsers = Array.Empty<UserProfile>();
|
||||
|
||||
_accountSaveDataManager = new AccountSaveDataManager(_profiles);
|
||||
|
||||
@@ -44,9 +46,9 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
}
|
||||
else
|
||||
{
|
||||
UserId commandLineUserProfileOverride = default;
|
||||
UserId commandLineUserProfileOverride = default;
|
||||
if (!string.IsNullOrEmpty(initialProfileName))
|
||||
{
|
||||
{
|
||||
commandLineUserProfileOverride = _profiles.Values.FirstOrDefault(x => x.Name == initialProfileName)?.UserId ?? default;
|
||||
if (commandLineUserProfileOverride.IsNull)
|
||||
Logger.Warning?.Print(LogClass.Application, $"The command line specified profile named '{initialProfileName}' was not found");
|
||||
@@ -221,6 +223,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
return _profiles.Values.Where(x => x.AccountState == AccountState.Open);
|
||||
}
|
||||
|
||||
internal IEnumerable<UserProfile> GetStoredOpenedUsers()
|
||||
{
|
||||
return _storedOpenedUsers;
|
||||
}
|
||||
|
||||
internal void StoreOpenedUsers()
|
||||
{
|
||||
_storedOpenedUsers = _profiles.Values.Where(x => x.AccountState == AccountState.Open).ToArray();
|
||||
}
|
||||
|
||||
internal UserProfile GetFirst()
|
||||
{
|
||||
return _profiles.First().Value;
|
||||
|
@@ -162,7 +162,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc.AccountService
|
||||
|
||||
public ResultCode StoreOpenContext(ServiceCtx context)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||
context.Device.System.AccountManager.StoreOpenedUsers();
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@@ -201,6 +201,11 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
|
||||
{
|
||||
return WriteUserList(context, context.Device.System.AccountManager.GetStoredOpenedUsers());
|
||||
}
|
||||
|
||||
public ResultCode ListQualifiedUsers(ServiceCtx context)
|
||||
{
|
||||
// TODO: Determine how users are "qualified". We assume all users are "qualified" for now.
|
||||
|
@@ -1,5 +1,4 @@
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Cpu;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc.AccountService;
|
||||
using Ryujinx.HLE.HOS.Services.Arp;
|
||||
|
||||
@@ -139,20 +138,21 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
return _applicationServiceServer.ClearSaveDataThumbnail(context);
|
||||
}
|
||||
|
||||
[CommandHipc(130)] // 5.0.0+
|
||||
// LoadOpenContext(nn::account::Uid)
|
||||
public ResultCode LoadOpenContext(ServiceCtx context)
|
||||
{
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(60)] // 5.0.0-5.1.0
|
||||
[CommandHipc(131)] // 6.0.0+
|
||||
// ListOpenContextStoredUsers() -> array<nn::account::Uid, 0xa>
|
||||
public ResultCode ListOpenContextStoredUsers(ServiceCtx context)
|
||||
{
|
||||
ulong outputPosition = context.Request.RecvListBuff[0].Position;
|
||||
ulong outputSize = context.Request.RecvListBuff[0].Size;
|
||||
|
||||
MemoryHelper.FillWithZeros(context.Memory, outputPosition, (int)outputSize);
|
||||
|
||||
// TODO: This seems to write stored userids of the OpenContext in the buffer. We needs to determine them.
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceAcc);
|
||||
|
||||
return ResultCode.Success;
|
||||
return _applicationServiceServer.ListOpenContextStoredUsers(context);
|
||||
}
|
||||
|
||||
[CommandHipc(141)] // 6.0.0+
|
||||
|
@@ -1,8 +1,147 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Fatal.Types;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal
|
||||
{
|
||||
[Service("fatal:u")]
|
||||
class IService : IpcService
|
||||
{
|
||||
public IService(ServiceCtx context) { }
|
||||
|
||||
[CommandHipc(0)]
|
||||
// ThrowFatal(u64 result_code, u64 pid)
|
||||
public ResultCode ThrowFatal(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, FatalPolicy.ErrorReportAndErrorScreen, null);
|
||||
}
|
||||
|
||||
[CommandHipc(1)]
|
||||
// ThrowFatalWithPolicy(u64 result_code, u32 fatal_policy, u64 pid)
|
||||
public ResultCode ThrowFatalWithPolicy(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, null);
|
||||
}
|
||||
|
||||
[CommandHipc(2)]
|
||||
// ThrowFatalWithCpuContext(u64 result_code, u32 fatal_policy, u64 pid, buffer<bytes, 0x15> cpu_context)
|
||||
public ResultCode ThrowFatalWithCpuContext(ServiceCtx context)
|
||||
{
|
||||
ResultCode resultCode = (ResultCode)context.RequestData.ReadUInt64();
|
||||
FatalPolicy fatalPolicy = (FatalPolicy)context.RequestData.ReadUInt32();
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
|
||||
ulong cpuContextPosition = context.Request.SendBuff[0].Position;
|
||||
ulong cpuContextSize = context.Request.SendBuff[0].Size;
|
||||
|
||||
ReadOnlySpan<byte> cpuContextData = context.Memory.GetSpan(cpuContextPosition, (int)cpuContextSize);
|
||||
|
||||
return ThrowFatalWithCpuContextImpl(context, resultCode, pid, fatalPolicy, cpuContextData);
|
||||
}
|
||||
|
||||
private ResultCode ThrowFatalWithCpuContextImpl(ServiceCtx context, ResultCode resultCode, ulong pid, FatalPolicy fatalPolicy, ReadOnlySpan<byte> cpuContext)
|
||||
{
|
||||
StringBuilder errorReport = new StringBuilder();
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine("ErrorReport log:");
|
||||
|
||||
errorReport.AppendLine($"\tTitleId: {context.Device.Application.TitleId:x16}");
|
||||
errorReport.AppendLine($"\tPid: {pid}");
|
||||
errorReport.AppendLine($"\tResultCode: {((int)resultCode & 0x1FF) + 2000}-{((int)resultCode >> 9) & 0x3FFF:d4}");
|
||||
errorReport.AppendLine($"\tFatalPolicy: {fatalPolicy}");
|
||||
|
||||
if (cpuContext != null)
|
||||
{
|
||||
errorReport.AppendLine("CPU Context:");
|
||||
|
||||
if (context.Device.Application.TitleIs64Bit)
|
||||
{
|
||||
CpuContext64 cpuContext64 = MemoryMarshal.Cast<byte, CpuContext64>(cpuContext)[0];
|
||||
|
||||
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext64.StartAddress:x16}");
|
||||
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext64.RegisterSetFlags}");
|
||||
|
||||
if (cpuContext64.StackTraceSize > 0)
|
||||
{
|
||||
errorReport.AppendLine("\tStackTrace:");
|
||||
|
||||
for (int i = 0; i < cpuContext64.StackTraceSize; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\t0x{cpuContext64.StackTrace[i]:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
errorReport.AppendLine("\tRegisters:");
|
||||
|
||||
for (int i = 0; i < cpuContext64.X.Length; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext64.X[i]:x16}");
|
||||
}
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext64.FP:x16}");
|
||||
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext64.LR:x16}");
|
||||
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext64.SP:x16}");
|
||||
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext64.PC:x16}");
|
||||
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext64.PState:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext64.Afsr0:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext64.Afsr1:x16}");
|
||||
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext64.Esr:x16}");
|
||||
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext64.Far:x16}");
|
||||
}
|
||||
else
|
||||
{
|
||||
CpuContext32 cpuContext32 = MemoryMarshal.Cast<byte, CpuContext32>(cpuContext)[0];
|
||||
|
||||
errorReport.AppendLine($"\tStartAddress: 0x{cpuContext32.StartAddress:16}");
|
||||
errorReport.AppendLine($"\tRegisterSetFlags: {cpuContext32.RegisterSetFlags}");
|
||||
|
||||
if (cpuContext32.StackTraceSize > 0)
|
||||
{
|
||||
errorReport.AppendLine("\tStackTrace:");
|
||||
|
||||
for (int i = 0; i < cpuContext32.StackTraceSize; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\t0x{cpuContext32.StackTrace[i]:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
errorReport.AppendLine("\tRegisters:");
|
||||
|
||||
for (int i = 0; i < cpuContext32.X.Length; i++)
|
||||
{
|
||||
errorReport.AppendLine($"\t\tX[{i:d2}]:\t0x{cpuContext32.X[i]:x16}");
|
||||
}
|
||||
|
||||
errorReport.AppendLine();
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.FP:x16}");
|
||||
errorReport.AppendLine($"\t\tFP:\t0x{cpuContext32.IP:x16}");
|
||||
errorReport.AppendLine($"\t\tSP:\t0x{cpuContext32.SP:x16}");
|
||||
errorReport.AppendLine($"\t\tLR:\t0x{cpuContext32.LR:x16}");
|
||||
errorReport.AppendLine($"\t\tPC:\t0x{cpuContext32.PC:x16}");
|
||||
errorReport.AppendLine($"\t\tPState:\t0x{cpuContext32.PState:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr0:\t0x{cpuContext32.Afsr0:x16}");
|
||||
errorReport.AppendLine($"\t\tAfsr1:\t0x{cpuContext32.Afsr1:x16}");
|
||||
errorReport.AppendLine($"\t\tEsr:\t0x{cpuContext32.Esr:x16}");
|
||||
errorReport.AppendLine($"\t\tFar:\t0x{cpuContext32.Far:x16}");
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.ServiceFatal, errorReport.ToString());
|
||||
|
||||
context.Device.System.KernelContext.Syscall.Break((ulong)resultCode);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
}
|
||||
}
|
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
25
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext32.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
public struct CpuContext32
|
||||
{
|
||||
public Array11<uint> X;
|
||||
public uint FP;
|
||||
public uint IP;
|
||||
public uint SP;
|
||||
public uint LR;
|
||||
public uint PC;
|
||||
|
||||
public uint PState;
|
||||
public uint Afsr0;
|
||||
public uint Afsr1;
|
||||
public uint Esr;
|
||||
public uint Far;
|
||||
|
||||
public Array32<uint> StackTrace;
|
||||
public uint StackTraceSize;
|
||||
public uint StartAddress;
|
||||
public uint RegisterSetFlags;
|
||||
}
|
||||
}
|
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
24
Ryujinx.HLE/HOS/Services/Fatal/Types/CpuContext64.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Ryujinx.Common.Memory;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
public struct CpuContext64
|
||||
{
|
||||
public Array29<ulong> X;
|
||||
public ulong FP;
|
||||
public ulong LR;
|
||||
public ulong SP;
|
||||
public ulong PC;
|
||||
|
||||
public ulong PState;
|
||||
public ulong Afsr0;
|
||||
public ulong Afsr1;
|
||||
public ulong Esr;
|
||||
public ulong Far;
|
||||
|
||||
public Array32<ulong> StackTrace;
|
||||
public ulong StartAddress;
|
||||
public ulong RegisterSetFlags;
|
||||
public uint StackTraceSize;
|
||||
}
|
||||
}
|
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
9
Ryujinx.HLE/HOS/Services/Fatal/Types/FatalPolicy.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Ryujinx.HLE.HOS.Services.Fatal.Types
|
||||
{
|
||||
enum FatalPolicy
|
||||
{
|
||||
ErrorReportAndErrorScreen,
|
||||
ErrorReport,
|
||||
ErrorScreen
|
||||
}
|
||||
}
|
@@ -181,7 +181,11 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetCertificates(ReadOnlySpan<CaCertificateId> ids, out CertStoreEntry[] entries)
|
||||
public bool TryGetCertificates(
|
||||
ReadOnlySpan<CaCertificateId> ids,
|
||||
out CertStoreEntry[] entries,
|
||||
out bool hasAllCertificates,
|
||||
out int requiredSize)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
@@ -190,7 +194,8 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
throw new InvalidSystemResourceException(CertStoreTitleMissingErrorMessage);
|
||||
}
|
||||
|
||||
bool hasAllCertificates = false;
|
||||
requiredSize = 0;
|
||||
hasAllCertificates = false;
|
||||
|
||||
foreach (CaCertificateId id in ids)
|
||||
{
|
||||
@@ -205,12 +210,14 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
if (hasAllCertificates)
|
||||
{
|
||||
entries = new CertStoreEntry[_certificates.Count];
|
||||
requiredSize = (_certificates.Count + 1) * Unsafe.SizeOf<BuiltInCertificateInfo>();
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (CertStoreEntry entry in _certificates.Values)
|
||||
{
|
||||
entries[i++] = entry;
|
||||
requiredSize += (entry.Data.Length + 3) & ~3;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -218,6 +225,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
else
|
||||
{
|
||||
entries = new CertStoreEntry[ids.Length];
|
||||
requiredSize = ids.Length * Unsafe.SizeOf<BuiltInCertificateInfo>();
|
||||
|
||||
for (int i = 0; i < ids.Length; i++)
|
||||
{
|
||||
@@ -227,6 +235,7 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
}
|
||||
|
||||
entries[i] = entry;
|
||||
requiredSize += (entry.Data.Length + 3) & ~3;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@@ -29,42 +29,40 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private uint ComputeCertificateBufferSizeRequired(ReadOnlySpan<BuiltInCertificateManager.CertStoreEntry> entries)
|
||||
{
|
||||
uint totalSize = 0;
|
||||
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
totalSize += (uint)Unsafe.SizeOf<BuiltInCertificateInfo>();
|
||||
totalSize += (uint)entries[i].Data.Length;
|
||||
}
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
[CommandHipc(2)]
|
||||
// GetCertificates(buffer<CaCertificateId, 5> ids) -> (u32 certificates_count, buffer<bytes, 6> certificates)
|
||||
public ResultCode GetCertificates(ServiceCtx context)
|
||||
{
|
||||
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
|
||||
|
||||
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries))
|
||||
if (!BuiltInCertificateManager.Instance.TryGetCertificates(
|
||||
ids,
|
||||
out BuiltInCertificateManager.CertStoreEntry[] entries,
|
||||
out bool hasAllCertificates,
|
||||
out int requiredSize))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
if (ComputeCertificateBufferSizeRequired(entries) > context.Request.ReceiveBuff[0].Size)
|
||||
if ((uint)requiredSize > (uint)context.Request.ReceiveBuff[0].Size)
|
||||
{
|
||||
return ResultCode.InvalidCertBufSize;
|
||||
}
|
||||
|
||||
int infosCount = entries.Length;
|
||||
|
||||
if (hasAllCertificates)
|
||||
{
|
||||
infosCount++;
|
||||
}
|
||||
|
||||
using (WritableRegion region = context.Memory.GetWritableRegion(context.Request.ReceiveBuff[0].Position, (int)context.Request.ReceiveBuff[0].Size))
|
||||
{
|
||||
Span<byte> rawData = region.Memory.Span;
|
||||
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..entries.Length];
|
||||
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * entries.Length)..];
|
||||
Span<BuiltInCertificateInfo> infos = MemoryMarshal.Cast<byte, BuiltInCertificateInfo>(rawData)[..infosCount];
|
||||
Span<byte> certificatesData = rawData[(Unsafe.SizeOf<BuiltInCertificateInfo>() * infosCount)..];
|
||||
|
||||
for (int i = 0; i < infos.Length; i++)
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
entries[i].Data.CopyTo(certificatesData);
|
||||
|
||||
@@ -78,6 +76,17 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
|
||||
certificatesData = certificatesData[entries[i].Data.Length..];
|
||||
}
|
||||
|
||||
if (hasAllCertificates)
|
||||
{
|
||||
infos[entries.Length] = new BuiltInCertificateInfo
|
||||
{
|
||||
Id = CaCertificateId.All,
|
||||
Status = TrustedCertStatus.Invalid,
|
||||
CertificateDataSize = 0,
|
||||
CertificateDataOffset = 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
context.ResponseData.Write(entries.Length);
|
||||
@@ -91,12 +100,12 @@ namespace Ryujinx.HLE.HOS.Services.Ssl
|
||||
{
|
||||
ReadOnlySpan<CaCertificateId> ids = MemoryMarshal.Cast<byte, CaCertificateId>(context.Memory.GetSpan(context.Request.SendBuff[0].Position, (int)context.Request.SendBuff[0].Size));
|
||||
|
||||
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out BuiltInCertificateManager.CertStoreEntry[] entries))
|
||||
if (!BuiltInCertificateManager.Instance.TryGetCertificates(ids, out _, out _, out int requiredSize))
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
context.ResponseData.Write(ComputeCertificateBufferSizeRequired(entries));
|
||||
context.ResponseData.Write(requiredSize);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@@ -162,7 +162,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
_context.SetPstateFlag(PState.ZFlag, zero);
|
||||
_context.SetPstateFlag(PState.NFlag, negative);
|
||||
|
||||
SetFpscr((uint)fpscr);
|
||||
_context.Fpscr = (FPSCR)fpscr;
|
||||
|
||||
_context.SetPstateFlag(PState.TFlag, thumb);
|
||||
|
||||
@@ -467,7 +467,7 @@ namespace Ryujinx.Tests.Cpu
|
||||
Assert.That(_context.GetPstateFlag(PState.NFlag), Is.EqualTo(_unicornEmu.NegativeFlag), "NFlag");
|
||||
});
|
||||
|
||||
Assert.That((int)GetFpscr() & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr");
|
||||
Assert.That((int)_context.Fpscr & (int)fpsrMask, Is.EqualTo(_unicornEmu.Fpscr & (int)fpsrMask), "Fpscr");
|
||||
|
||||
if (_usingMemory)
|
||||
{
|
||||
@@ -650,28 +650,5 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
return rnd & 0x800FFFFFFFFFFFFFul;
|
||||
}
|
||||
|
||||
private uint GetFpscr()
|
||||
{
|
||||
uint fpscr = (uint)(_context.Fpsr & FPSR.A32Mask & ~FPSR.Nzcv) | (uint)(_context.Fpcr & FPCR.A32Mask);
|
||||
|
||||
fpscr |= _context.GetFPstateFlag(FPState.NFlag) ? (1u << (int)FPState.NFlag) : 0;
|
||||
fpscr |= _context.GetFPstateFlag(FPState.ZFlag) ? (1u << (int)FPState.ZFlag) : 0;
|
||||
fpscr |= _context.GetFPstateFlag(FPState.CFlag) ? (1u << (int)FPState.CFlag) : 0;
|
||||
fpscr |= _context.GetFPstateFlag(FPState.VFlag) ? (1u << (int)FPState.VFlag) : 0;
|
||||
|
||||
return fpscr;
|
||||
}
|
||||
|
||||
private void SetFpscr(uint fpscr)
|
||||
{
|
||||
_context.Fpsr = FPSR.A32Mask & (FPSR)fpscr;
|
||||
_context.Fpcr = FPCR.A32Mask & (FPCR)fpscr;
|
||||
|
||||
_context.SetFPstateFlag(FPState.NFlag, (fpscr & (1u << (int)FPState.NFlag)) != 0);
|
||||
_context.SetFPstateFlag(FPState.ZFlag, (fpscr & (1u << (int)FPState.ZFlag)) != 0);
|
||||
_context.SetFPstateFlag(FPState.CFlag, (fpscr & (1u << (int)FPState.CFlag)) != 0);
|
||||
_context.SetFPstateFlag(FPState.VFlag, (fpscr & (1u << (int)FPState.VFlag)) != 0);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user