merge + add fmax/min vector and fix + add fmin/max test
This commit is contained in:
parent
b78c62e80d
commit
da03846628
166 changed files with 8515 additions and 1923 deletions
|
@ -8,7 +8,7 @@ namespace ChocolArm64
|
|||
{
|
||||
static AOpCodeTable()
|
||||
{
|
||||
#region "OpCode Table"
|
||||
#region "OpCode Table"
|
||||
//Integer
|
||||
Set("x0011010000xxxxx000000xxxxxxxxxx", AInstEmit.Adc, typeof(AOpCodeAluRs));
|
||||
Set("x0111010000xxxxx000000xxxxxxxxxx", AInstEmit.Adcs, typeof(AOpCodeAluRs));
|
||||
|
@ -41,6 +41,7 @@ namespace ChocolArm64
|
|||
Set("x1111010010xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpImm));
|
||||
Set("x1111010010xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ccmp, typeof(AOpCodeCcmpReg));
|
||||
Set("11010101000000110011xxxx01011111", AInstEmit.Clrex, typeof(AOpCodeSystem));
|
||||
Set("x101101011000000000101xxxxxxxxxx", AInstEmit.Cls, typeof(AOpCodeAlu));
|
||||
Set("x101101011000000000100xxxxxxxxxx", AInstEmit.Clz, typeof(AOpCodeAlu));
|
||||
Set("x0011010110xxxxx010000xxxxxxxxxx", AInstEmit.Crc32b, typeof(AOpCodeAluRs));
|
||||
Set("x0011010110xxxxx010001xxxxxxxxxx", AInstEmit.Crc32h, typeof(AOpCodeAluRs));
|
||||
|
@ -68,7 +69,7 @@ namespace ChocolArm64
|
|||
Set("xx111000010xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm));
|
||||
Set("xx11100101xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemImm));
|
||||
Set("xx111000011xxxxxxxxx10xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeMemReg));
|
||||
Set("xx011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeMemLit));
|
||||
Set("xx011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.LdrLit, typeof(AOpCodeMemLit));
|
||||
Set("0x1110001x0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm));
|
||||
Set("0x1110011xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm));
|
||||
Set("10111000100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldrs, typeof(AOpCodeMemImm));
|
||||
|
@ -91,6 +92,7 @@ namespace ChocolArm64
|
|||
Set("x01100100xxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluImm));
|
||||
Set("x0101010xx0xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Orr, typeof(AOpCodeAluRs));
|
||||
Set("1111100110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemImm));
|
||||
Set("11111000100xxxxxxxxx00xxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemImm));
|
||||
Set("11011000xxxxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Pfrm, typeof(AOpCodeMemLit));
|
||||
Set("x101101011000000000000xxxxxxxxxx", AInstEmit.Rbit, typeof(AOpCodeAlu));
|
||||
Set("11010110010xxxxx000000xxxxxxxxxx", AInstEmit.Ret, typeof(AOpCodeBReg));
|
||||
|
@ -140,6 +142,7 @@ namespace ChocolArm64
|
|||
Set("0x001110011xxxxx000111xxxxxxxxxx", AInstEmit.Bic_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x10111100000xxx<<x101xxxxxxxxxx", AInstEmit.Bic_Vi, typeof(AOpCodeSimdImm));
|
||||
Set("0x101110111xxxxx000111xxxxxxxxxx", AInstEmit.Bif_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110101xxxxx000111xxxxxxxxxx", AInstEmit.Bit_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110011xxxxx000111xxxxxxxxxx", AInstEmit.Bsl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<1xxxxx100011xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<100000100110xxxxxxxxxx", AInstEmit.Cmeq_V, typeof(AOpCodeSimd));
|
||||
|
@ -162,8 +165,25 @@ namespace ChocolArm64
|
|||
Set("000111100x100000110000xxxxxxxxxx", AInstEmit.Fabs_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx001010xxxxxxxxxx", AInstEmit.Fadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Fadd_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011100<1xxxxx110101xxxxxxxxxx", AInstEmit.Faddp_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxxxxxx01xxxxx0xxxx", AInstEmit.Fccmp_S, typeof(AOpCodeSimdFcond));
|
||||
Set("000111100x1xxxxxxxxx01xxxxx1xxxx", AInstEmit.Fccmpe_S, typeof(AOpCodeSimdFcond));
|
||||
Set("010111100x1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmeq_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmeq_V, typeof(AOpCodeSimdReg));
|
||||
Set("010111101x100000110110xxxxxxxxxx", AInstEmit.Fcmeq_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011101<100000110110xxxxxxxxxx", AInstEmit.Fcmeq_V, typeof(AOpCodeSimd));
|
||||
Set("011111100x1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmge_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011100<1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmge_V, typeof(AOpCodeSimdReg));
|
||||
Set("011111101x100000110010xxxxxxxxxx", AInstEmit.Fcmge_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011101<100000110010xxxxxxxxxx", AInstEmit.Fcmge_V, typeof(AOpCodeSimd));
|
||||
Set("011111101x1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmgt_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011101<1xxxxx111001xxxxxxxxxx", AInstEmit.Fcmgt_V, typeof(AOpCodeSimdReg));
|
||||
Set("010111101x100000110010xxxxxxxxxx", AInstEmit.Fcmgt_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011101<100000110010xxxxxxxxxx", AInstEmit.Fcmgt_V, typeof(AOpCodeSimd));
|
||||
Set("011111101x100000110110xxxxxxxxxx", AInstEmit.Fcmle_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011101<100000110110xxxxxxxxxx", AInstEmit.Fcmle_V, typeof(AOpCodeSimd));
|
||||
Set("010111101x100000111010xxxxxxxxxx", AInstEmit.Fcmlt_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011101<100000111010xxxxxxxxxx", AInstEmit.Fcmlt_V, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx001000xxxxx0x000", AInstEmit.Fcmp_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx001000xxxxx1x000", AInstEmit.Fcmpe_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxxxxxx11xxxxxxxxxx", AInstEmit.Fcsel_S, typeof(AOpCodeSimdFcond));
|
||||
|
@ -183,16 +203,20 @@ namespace ChocolArm64
|
|||
Set("x00111100x111001000000xxxxxxxxxx", AInstEmit.Fcvtzu_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("x00111100x011001xxxxxxxxxxxxxxxx", AInstEmit.Fcvtzu_Gp_Fix, typeof(AOpCodeSimdCvt));
|
||||
Set("0>1011101<100001101110xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimd));
|
||||
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x1011110>>xxxxx111111xxxxxxxxxx", AInstEmit.Fcvtzu_V, typeof(AOpCodeSimdShImm));
|
||||
Set("000111100x1xxxxx000110xxxxxxxxxx", AInstEmit.Fdiv_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>1011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Fdiv_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111110x0xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fmadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx010010xxxxxxxxxx", AInstEmit.Fmax_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011100x1xxxxx111101xxxxxxxxxx", AInstEmit.Fmax_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011101x1xxxxx111101xxxxxxxxxx", AInstEmit.Fmin_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
Set("0>0011101<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmls_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx0101x0xxxxxxxxxx", AInstEmit.Fmls_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
Set("000111100x100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||
Set("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
||||
Set("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
||||
|
@ -202,11 +226,18 @@ namespace ChocolArm64
|
|||
Set("1001111010101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
||||
Set("000111110x0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("010111111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Se, typeof(AOpCodeSimdRegElemF));
|
||||
Set("0>1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
Set("000111100x100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011101<100000111110xxxxxxxxxx", AInstEmit.Fneg_V, typeof(AOpCodeSimd));
|
||||
Set("000111110x1xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fnmadd_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111110x1xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fnmsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x1xxxxx100010xxxxxxxxxx", AInstEmit.Fnmul_S, typeof(AOpCodeSimdReg));
|
||||
Set("010111101x100001110110xxxxxxxxxx", AInstEmit.Frecpe_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011101<100001110110xxxxxxxxxx", AInstEmit.Frecpe_V, typeof(AOpCodeSimd));
|
||||
Set("010111100x1xxxxx111111xxxxxxxxxx", AInstEmit.Frecps_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Frecps_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011100<100001100010xxxxxxxxxx", AInstEmit.Frinta_V, typeof(AOpCodeSimd));
|
||||
Set("000111100x100111110000xxxxxxxxxx", AInstEmit.Frinti_S, typeof(AOpCodeSimd));
|
||||
|
@ -218,7 +249,11 @@ namespace ChocolArm64
|
|||
Set("000111100x100100110000xxxxxxxxxx", AInstEmit.Frintp_S, typeof(AOpCodeSimd));
|
||||
Set("0>0011101<100001100010xxxxxxxxxx", AInstEmit.Frintp_V, typeof(AOpCodeSimd));
|
||||
Set("000111100x100111010000xxxxxxxxxx", AInstEmit.Frintx_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011100<100001100110xxxxxxxxxx", AInstEmit.Frintx_V, typeof(AOpCodeSimd));
|
||||
Set("0>1011100<100001100110xxxxxxxxxx", AInstEmit.Frintx_V, typeof(AOpCodeSimd));
|
||||
Set("011111101x100001110110xxxxxxxxxx", AInstEmit.Frsqrte_S, typeof(AOpCodeSimd));
|
||||
Set("0>1011101<100001110110xxxxxxxxxx", AInstEmit.Frsqrte_V, typeof(AOpCodeSimd));
|
||||
Set("010111101x1xxxxx111111xxxxxxxxxx", AInstEmit.Frsqrts_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011101<1xxxxx111111xxxxxxxxxx", AInstEmit.Frsqrts_V, typeof(AOpCodeSimdReg));
|
||||
Set("000111100x100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd));
|
||||
Set("000111100x1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg));
|
||||
|
@ -226,8 +261,8 @@ namespace ChocolArm64
|
|||
Set("01101110000xxxxx0xxxx1xxxxxxxxxx", AInstEmit.Ins_V, typeof(AOpCodeSimdIns));
|
||||
Set("0x00110001000000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x001100110xxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x00110101000000xx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x001101110xxxxxxx0xxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x00110101x00000xxxxxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x00110111xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ld__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("xx10110xx1xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Ldp, typeof(AOpCodeSimdMemPair));
|
||||
Set("xx111100x10xxxxxxxxx00xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm));
|
||||
Set("xx111100x10xxxxxxxxx01xxxxxxxxxx", AInstEmit.Ldr, typeof(AOpCodeSimdMemImm));
|
||||
|
@ -272,8 +307,8 @@ namespace ChocolArm64
|
|||
Set("0x0011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Ssra_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x00110000000000xxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x001100100xxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vms, typeof(AOpCodeSimdMemMs));
|
||||
Set("0x00110100000000xx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x001101100xxxxxxx0xxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x00110100x00000xxxxxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("0x00110110xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.St__Vss, typeof(AOpCodeSimdMemSs));
|
||||
Set("xx10110xx0xxxxxxxxxxxxxxxxxxxxxx", AInstEmit.Stp, typeof(AOpCodeSimdMemPair));
|
||||
Set("xx111100x00xxxxxxxxx00xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm));
|
||||
Set("xx111100x00xxxxxxxxx01xxxxxxxxxx", AInstEmit.Str, typeof(AOpCodeSimdMemImm));
|
||||
|
@ -283,12 +318,18 @@ namespace ChocolArm64
|
|||
Set("01111110xx1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_S, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<1xxxxx100001xxxxxxxxxx", AInstEmit.Sub_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110000xxxxx0xx000xxxxxxxxxx", AInstEmit.Tbl_V, typeof(AOpCodeSimdTbl));
|
||||
Set("0>001110<<0xxxxx001010xxxxxxxxxx", AInstEmit.Trn1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<0xxxxx011010xxxxxxxxxx", AInstEmit.Trn2_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110<<1xxxxx011101xxxxxxxxxx", AInstEmit.Uabd_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110<<1xxxxx011100xxxxxxxxxx", AInstEmit.Uabdl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x101110<<1xxxxx000000xxxxxxxxxx", AInstEmit.Uaddl_V, typeof(AOpCodeSimdReg));
|
||||
Set("001011100x110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd));
|
||||
Set("01101110<<110000001110xxxxxxxxxx", AInstEmit.Uaddlv_V, typeof(AOpCodeSimd));
|
||||
Set("0x101110<<1xxxxx000100xxxxxxxxxx", AInstEmit.Uaddw_V, typeof(AOpCodeSimdReg));
|
||||
Set("x0011110xx100011000000xxxxxxxxxx", AInstEmit.Ucvtf_Gp, typeof(AOpCodeSimdCvt));
|
||||
Set("011111100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_S, typeof(AOpCodeSimd));
|
||||
Set("0x1011100x100001110110xxxxxxxxxx", AInstEmit.Ucvtf_V, typeof(AOpCodeSimd));
|
||||
Set("0x101110<<1xxxxx000001xxxxxxxxxx", AInstEmit.Uhadd_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||
Set("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||
|
@ -296,11 +337,11 @@ namespace ChocolArm64
|
|||
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
||||
Set("0x1011110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x1011110>>>>xxx000101xxxxxxxxxx", AInstEmit.Usra_V, typeof(AOpCodeSimdShImm));
|
||||
Set("0x001110xx0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110xx0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<0xxxxx000110xxxxxxxxxx", AInstEmit.Uzp1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<0xxxxx010110xxxxxxxxxx", AInstEmit.Uzp2_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<100001001010xxxxxxxxxx", AInstEmit.Xtn_V, typeof(AOpCodeSimd));
|
||||
Set("0x001110xx0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110xx0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<0xxxxx001110xxxxxxxxxx", AInstEmit.Zip1_V, typeof(AOpCodeSimdReg));
|
||||
Set("0>001110<<0xxxxx011110xxxxxxxxxx", AInstEmit.Zip2_V, typeof(AOpCodeSimdReg));
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
@ -442,4 +483,4 @@ namespace ChocolArm64
|
|||
return AInst.Undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using ChocolArm64.State;
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
|
@ -23,7 +24,7 @@ namespace ChocolArm64
|
|||
|
||||
public ReadOnlyCollection<ARegister> Params { get; private set; }
|
||||
|
||||
private HashSet<long> Callees;
|
||||
private HashSet<long> Callers;
|
||||
|
||||
private ATranslatedSubType Type;
|
||||
|
||||
|
@ -33,7 +34,7 @@ namespace ChocolArm64
|
|||
|
||||
private int MinCallCountForReJit = 250;
|
||||
|
||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params, HashSet<long> Callees)
|
||||
public ATranslatedSub(DynamicMethod Method, List<ARegister> Params)
|
||||
{
|
||||
if (Method == null)
|
||||
{
|
||||
|
@ -45,14 +46,10 @@ namespace ChocolArm64
|
|||
throw new ArgumentNullException(nameof(Params));
|
||||
}
|
||||
|
||||
if (Callees == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Callees));
|
||||
}
|
||||
|
||||
this.Method = Method;
|
||||
this.Params = Params.AsReadOnly();
|
||||
this.Callees = Callees;
|
||||
|
||||
Callers = new HashSet<long>();
|
||||
|
||||
PrepareDelegate();
|
||||
}
|
||||
|
@ -107,17 +104,14 @@ namespace ChocolArm64
|
|||
|
||||
public bool ShouldReJit()
|
||||
{
|
||||
if (Type == ATranslatedSubType.SubTier0)
|
||||
if (NeedsReJit && CallCount < MinCallCountForReJit)
|
||||
{
|
||||
if (CallCount < MinCallCountForReJit)
|
||||
{
|
||||
CallCount++;
|
||||
}
|
||||
CallCount++;
|
||||
|
||||
return CallCount == MinCallCountForReJit;
|
||||
return false;
|
||||
}
|
||||
|
||||
return Type == ATranslatedSubType.SubTier1 && NeedsReJit;
|
||||
return NeedsReJit;
|
||||
}
|
||||
|
||||
public long Execute(AThreadState ThreadState, AMemory Memory)
|
||||
|
@ -125,10 +119,32 @@ namespace ChocolArm64
|
|||
return ExecDelegate(ThreadState, Memory);
|
||||
}
|
||||
|
||||
public void SetType(ATranslatedSubType Type) => this.Type = Type;
|
||||
public void AddCaller(long Position)
|
||||
{
|
||||
lock (Callers)
|
||||
{
|
||||
Callers.Add(Position);
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasCallee(long Position) => Callees.Contains(Position);
|
||||
public long[] GetCallerPositions()
|
||||
{
|
||||
lock (Callers)
|
||||
{
|
||||
return Callers.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkForReJit() => NeedsReJit = true;
|
||||
public void SetType(ATranslatedSubType Type)
|
||||
{
|
||||
this.Type = Type;
|
||||
|
||||
if (Type == ATranslatedSubType.SubTier0)
|
||||
{
|
||||
NeedsReJit = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void MarkForReJit() => NeedsReJit = true;
|
||||
}
|
||||
}
|
|
@ -107,25 +107,31 @@ namespace ChocolArm64
|
|||
|
||||
ATranslatedSub Subroutine = Context.GetSubroutine();
|
||||
|
||||
if (SubBlocks.Contains(Position))
|
||||
lock (SubBlocks)
|
||||
{
|
||||
SubBlocks.Remove(Position);
|
||||
if (SubBlocks.Contains(Position))
|
||||
{
|
||||
SubBlocks.Remove(Position);
|
||||
|
||||
Subroutine.SetType(ATranslatedSubType.SubBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
Subroutine.SetType(ATranslatedSubType.SubBlock);
|
||||
}
|
||||
else
|
||||
{
|
||||
Subroutine.SetType(ATranslatedSubType.SubTier0);
|
||||
}
|
||||
}
|
||||
|
||||
CachedSubs.AddOrUpdate(Position, Subroutine, (Key, OldVal) => Subroutine);
|
||||
|
||||
AOpCode LastOp = Block.GetLastOp();
|
||||
|
||||
if (LastOp.Emitter != AInstEmit.Ret &&
|
||||
LastOp.Emitter != AInstEmit.Br)
|
||||
lock (SubBlocks)
|
||||
{
|
||||
SubBlocks.Add(LastOp.Position + 4);
|
||||
if (LastOp.Emitter != AInstEmit.Ret &&
|
||||
LastOp.Emitter != AInstEmit.Br)
|
||||
{
|
||||
SubBlocks.Add(LastOp.Position + 4);
|
||||
}
|
||||
}
|
||||
|
||||
return Subroutine;
|
||||
|
@ -154,11 +160,14 @@ namespace ChocolArm64
|
|||
|
||||
//Mark all methods that calls this method for ReJiting,
|
||||
//since we can now call it directly which is faster.
|
||||
foreach (ATranslatedSub TS in CachedSubs.Values)
|
||||
if (CachedSubs.TryGetValue(Position, out ATranslatedSub OldSub))
|
||||
{
|
||||
if (TS.HasCallee(Position))
|
||||
foreach (long CallerPos in OldSub.GetCallerPositions())
|
||||
{
|
||||
TS.MarkForReJit();
|
||||
if (CachedSubs.TryGetValue(Position, out ATranslatedSub CallerSub))
|
||||
{
|
||||
CallerSub.MarkForReJit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using ChocolArm64.Instruction;
|
||||
using ChocolArm64.State;
|
||||
|
||||
namespace ChocolArm64.Decoder
|
||||
{
|
||||
|
@ -11,6 +12,10 @@ namespace ChocolArm64.Decoder
|
|||
Rt = OpCode & 0x1f;
|
||||
|
||||
Imm = Position + ADecoderHelper.DecodeImmS19_2(OpCode);
|
||||
|
||||
RegisterSize = (OpCode >> 31) != 0
|
||||
? ARegisterSize.Int64
|
||||
: ARegisterSize.Int32;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,8 +25,8 @@ namespace ChocolArm64.Decoder
|
|||
default: Inst = AInst.Undefined; return;
|
||||
}
|
||||
|
||||
Size = (OpCode >> 10) & 0x3;
|
||||
WBack = ((OpCode >> 23) & 0x1) != 0;
|
||||
Size = (OpCode >> 10) & 3;
|
||||
WBack = ((OpCode >> 23) & 1) != 0;
|
||||
|
||||
bool Q = ((OpCode >> 30) & 1) != 0;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ namespace ChocolArm64.Decoder
|
|||
int Scale = (OpCode >> 14) & 3;
|
||||
int L = (OpCode >> 22) & 1;
|
||||
int Q = (OpCode >> 30) & 1;
|
||||
|
||||
|
||||
SElems |= (OpCode >> 21) & 1;
|
||||
|
||||
SElems++;
|
||||
|
@ -88,7 +88,7 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
Extend64 = false;
|
||||
|
||||
WBack = ((OpCode >> 23) & 0x1) != 0;
|
||||
WBack = ((OpCode >> 23) & 1) != 0;
|
||||
|
||||
RegisterSize = Q != 0
|
||||
? ARegisterSize.SIMD128
|
||||
|
|
|
@ -100,6 +100,24 @@ namespace ChocolArm64.Instruction
|
|||
EmitDataStore(Context, SetFlags);
|
||||
}
|
||||
|
||||
public static void Cls(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingSigns32));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingSigns64));
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
public static void Clz(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeAlu Op = (AOpCodeAlu)Context.CurrOp;
|
||||
|
@ -383,4 +401,4 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStflg((int)APState.CBit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,38 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Add));
|
||||
}
|
||||
|
||||
public static void Faddp_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Elems = Bytes >> SizeF + 2;
|
||||
int Half = Elems >> 1;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
int Elem = (Index & (Half - 1)) << 1;
|
||||
|
||||
EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 0, SizeF);
|
||||
EmitVectorExtractF(Context, Index < Half ? Op.Rn : Op.Rm, Elem + 1, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
EmitVectorInsertTmpF(Context, Index, SizeF);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fdiv_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Div));
|
||||
|
@ -150,17 +182,84 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Fmax_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
{
|
||||
EmitBinaryMathCall(Context, nameof(Math.Max));
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMaxF));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMax));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fmax_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorBinaryOpF(Context, () =>
|
||||
{
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMaxF));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMax));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fmin_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
{
|
||||
EmitBinaryMathCall(Context, nameof(Math.Min));
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMinF));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMin));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fmin_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorBinaryOpF(Context, () =>
|
||||
{
|
||||
if (Op.Size == 2)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMinF));
|
||||
}
|
||||
else if (Op.Size == 3)
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CustomMin));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -192,6 +291,24 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Fmls_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpF(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Sub);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fmls_Ve(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpByElemF(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Sub);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Fmsub_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarTernaryRaOpF(Context, () =>
|
||||
|
@ -206,6 +323,11 @@ namespace ChocolArm64.Instruction
|
|||
EmitScalarBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Fmul_Se(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpByElemF(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Fmul_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpF(Context, () => Context.Emit(OpCodes.Mul));
|
||||
|
@ -221,13 +343,30 @@ namespace ChocolArm64.Instruction
|
|||
EmitScalarUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
|
||||
}
|
||||
|
||||
public static void Fnmul_S(AILEmitterCtx Context)
|
||||
public static void Fneg_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Neg);
|
||||
});
|
||||
EmitVectorUnaryOpF(Context, () => Context.Emit(OpCodes.Neg));
|
||||
}
|
||||
|
||||
public static void Fnmadd_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Neg);
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
|
||||
EmitVectorExtractF(Context, Op.Ra, 0, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
||||
}
|
||||
|
||||
public static void Fnmsub_S(AILEmitterCtx Context)
|
||||
|
@ -235,7 +374,7 @@ namespace ChocolArm64.Instruction
|
|||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, 0, SizeF);
|
||||
|
||||
|
@ -248,6 +387,138 @@ namespace ChocolArm64.Instruction
|
|||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
||||
}
|
||||
|
||||
public static void Fnmul_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Neg);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frecpe_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFrecpe(Context, 0, Scalar: true);
|
||||
}
|
||||
|
||||
public static void Frecpe_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
|
||||
{
|
||||
EmitFrecpe(Context, Index, Scalar: false);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFrecpe(AILEmitterCtx Context, int Index, bool Scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(1);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(1);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Div);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
|
||||
}
|
||||
|
||||
public static void Frecps_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFrecps(Context, 0, Scalar: true);
|
||||
}
|
||||
|
||||
public static void Frecps_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
|
||||
{
|
||||
EmitFrecps(Context, Index, Scalar: false);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFrecps(AILEmitterCtx Context, int Index, bool Scalar)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(2);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(2);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
|
||||
}
|
||||
|
||||
public static void Frinta_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
}
|
||||
|
||||
public static void Frinta_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frinti_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
@ -276,7 +547,7 @@ namespace ChocolArm64.Instruction
|
|||
public static void Frinti_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
|
||||
EmitVectorUnaryOpF(Context, () =>
|
||||
{
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
@ -284,11 +555,11 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
|
||||
|
||||
if (Op.Size == 2)
|
||||
{
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
|
||||
}
|
||||
else if (Op.Size == 3)
|
||||
{
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
|
||||
}
|
||||
else
|
||||
|
@ -298,25 +569,6 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Frinta_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Size);
|
||||
}
|
||||
|
||||
public static void Frinta_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitRoundMathCall(Context, MidpointRounding.AwayFromZero);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frintm_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
|
@ -404,11 +656,11 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpcr));
|
||||
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.RoundF));
|
||||
}
|
||||
else if (Op.Size == 1)
|
||||
{
|
||||
{
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.Round));
|
||||
}
|
||||
else
|
||||
|
@ -418,6 +670,86 @@ namespace ChocolArm64.Instruction
|
|||
});
|
||||
}
|
||||
|
||||
public static void Frsqrte_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frsqrte_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorUnaryOpF(Context, () =>
|
||||
{
|
||||
EmitUnarySoftFloatCall(Context, nameof(ASoftFloat.InvSqrtEstimate));
|
||||
});
|
||||
}
|
||||
|
||||
public static void Frsqrts_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitFrsqrts(Context, 0, Scalar: true);
|
||||
}
|
||||
|
||||
public static void Frsqrts_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
|
||||
{
|
||||
EmitFrsqrts(Context, Index, Scalar: false);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFrsqrts(AILEmitterCtx Context, int Index, bool Scalar)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(3);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(3);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, Index, SizeF);
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(0.5f);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(0.5);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Mul);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitVectorInsertF(Context, Op.Rd, Index, SizeF);
|
||||
}
|
||||
|
||||
public static void Fsqrt_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarUnaryOpF(Context, () =>
|
||||
|
@ -525,6 +857,30 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||
}
|
||||
|
||||
public static void Uabd_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () => EmitAbd(Context));
|
||||
}
|
||||
|
||||
public static void Uabdl_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmBinaryOpZx(Context, () => EmitAbd(Context));
|
||||
}
|
||||
|
||||
private static void EmitAbd(AILEmitterCtx Context)
|
||||
{
|
||||
Context.Emit(OpCodes.Sub);
|
||||
|
||||
Type[] Types = new Type[] { typeof(long) };
|
||||
|
||||
Context.EmitCall(typeof(Math).GetMethod(nameof(Math.Abs), Types));
|
||||
}
|
||||
|
||||
public static void Uaddl_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
||||
}
|
||||
|
||||
public static void Uaddlv_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
@ -548,9 +904,21 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorWidenRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Add));
|
||||
}
|
||||
|
||||
public static void Uhadd_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Add);
|
||||
|
||||
Context.EmitLdc_I4(1);
|
||||
|
||||
Context.Emit(OpCodes.Shr_Un);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Umull_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,13 +110,64 @@ namespace ChocolArm64.Instruction
|
|||
Fccmp_S(Context);
|
||||
}
|
||||
|
||||
public static void Fcmeq_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Beq_S);
|
||||
}
|
||||
|
||||
public static void Fcmeq_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Beq_S);
|
||||
}
|
||||
|
||||
public static void Fcmge_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Bge_S);
|
||||
}
|
||||
|
||||
public static void Fcmge_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Bge_S);
|
||||
}
|
||||
|
||||
public static void Fcmgt_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Bgt_S);
|
||||
}
|
||||
|
||||
public static void Fcmgt_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Bgt_S);
|
||||
}
|
||||
|
||||
public static void Fcmle_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Ble_S);
|
||||
}
|
||||
|
||||
public static void Fcmle_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Ble_S);
|
||||
}
|
||||
|
||||
public static void Fcmlt_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarFcmp(Context, OpCodes.Blt_S);
|
||||
}
|
||||
|
||||
public static void Fcmlt_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorFcmp(Context, OpCodes.Blt_S);
|
||||
}
|
||||
|
||||
public static void Fcmp_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
bool CmpWithZero = !(Op is AOpCodeSimdFcond) ? Op.Bit3 : false;
|
||||
|
||||
//Handle NaN case. If any number is NaN, then NZCV = 0011.
|
||||
//Handle NaN case.
|
||||
//If any number is NaN, then NZCV = 0011.
|
||||
if (CmpWithZero)
|
||||
{
|
||||
EmitNaNCheck(Context, Op.Rn);
|
||||
|
@ -140,7 +191,14 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
if (CmpWithZero)
|
||||
{
|
||||
EmitLdcImmF(Context, 0, Op.Size);
|
||||
if (Op.Size == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(0);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -190,22 +248,6 @@ namespace ChocolArm64.Instruction
|
|||
Fcmp_S(Context);
|
||||
}
|
||||
|
||||
private static void EmitLdcImmF(AILEmitterCtx Context, double ImmF, int Size)
|
||||
{
|
||||
if (Size == 0)
|
||||
{
|
||||
Context.EmitLdc_R4((float)ImmF);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
Context.EmitLdc_R8(ImmF);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitNaNCheck(AILEmitterCtx Context, int Reg)
|
||||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
@ -268,5 +310,84 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitScalarFcmp(AILEmitterCtx Context, OpCode ILOp)
|
||||
{
|
||||
EmitFcmp(Context, ILOp, 0, Scalar: true);
|
||||
}
|
||||
|
||||
private static void EmitVectorFcmp(AILEmitterCtx Context, OpCode ILOp)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
for (int Index = 0; Index < Bytes >> SizeF + 2; Index++)
|
||||
{
|
||||
EmitFcmp(Context, ILOp, Index, Scalar: false);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitFcmp(AILEmitterCtx Context, OpCode ILOp, int Index, bool Scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
ulong SzMask = ulong.MaxValue >> (64 - (32 << SizeF));
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
|
||||
if (Op is AOpCodeSimdReg BinOp)
|
||||
{
|
||||
EmitVectorExtractF(Context, BinOp.Rm, Index, SizeF);
|
||||
}
|
||||
else if (SizeF == 0)
|
||||
{
|
||||
Context.EmitLdc_R4(0);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
Context.EmitLdc_R8(0);
|
||||
}
|
||||
|
||||
AILLabel LblTrue = new AILLabel();
|
||||
AILLabel LblEnd = new AILLabel();
|
||||
|
||||
Context.Emit(ILOp, LblTrue);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, 0);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblEnd);
|
||||
|
||||
Context.MarkLabel(LblTrue);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, 3, (long)SzMask);
|
||||
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(Context, Op.Rd, Index, SizeF + 2, (long)SzMask);
|
||||
}
|
||||
|
||||
Context.MarkLabel(LblEnd);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -100,6 +100,52 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
||||
public static void EmitUnarySoftFloatCall(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(ASoftFloat).GetMethod(Name, new Type[] { typeof(float) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(ASoftFloat).GetMethod(Name, new Type[] { typeof(double) });
|
||||
}
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdRegElemF Op = (AOpCodeSimdRegElemF)Context.CurrOp;
|
||||
|
||||
EmitScalarOpByElemF(Context, Emit, Op.Index, Ternary: false);
|
||||
}
|
||||
|
||||
public static void EmitScalarOpByElemF(AILEmitterCtx Context, Action Emit, int Elem, bool Ternary)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
if (Ternary)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rd, 0, SizeF);
|
||||
}
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, Elem, SizeF);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, SizeF);
|
||||
}
|
||||
|
||||
public static void EmitScalarUnaryOpSx(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
EmitScalarOp(Context, Emit, OperFlags.Rn, true);
|
||||
|
@ -447,6 +493,9 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
@ -489,6 +538,9 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
|
||||
int Elems = 8 >> Op.Size;
|
||||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
@ -536,10 +588,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorExtract(AILEmitterCtx Context, int Reg, int Index, int Size, bool Signed)
|
||||
{
|
||||
if (Size < 0 || Size > 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
ThrowIfInvalid(Index, Size);
|
||||
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
|
@ -554,6 +603,8 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorExtractF(AILEmitterCtx Context, int Reg, int Index, int Size)
|
||||
{
|
||||
ThrowIfInvalidF(Index, Size);
|
||||
|
||||
Context.EmitLdvec(Reg);
|
||||
Context.EmitLdc_I4(Index);
|
||||
|
||||
|
@ -589,10 +640,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size)
|
||||
{
|
||||
if (Size < 0 || Size > 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
ThrowIfInvalid(Index, Size);
|
||||
|
||||
Context.EmitLdvec(Reg);
|
||||
Context.EmitLdc_I4(Index);
|
||||
|
@ -605,10 +653,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorInsertTmp(AILEmitterCtx Context, int Index, int Size)
|
||||
{
|
||||
if (Size < 0 || Size > 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
ThrowIfInvalid(Index, Size);
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitLdc_I4(Index);
|
||||
|
@ -621,10 +666,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorInsert(AILEmitterCtx Context, int Reg, int Index, int Size, long Value)
|
||||
{
|
||||
if (Size < 0 || Size > 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
ThrowIfInvalid(Index, Size);
|
||||
|
||||
Context.EmitLdc_I8(Value);
|
||||
Context.EmitLdvec(Reg);
|
||||
|
@ -638,6 +680,8 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorInsertF(AILEmitterCtx Context, int Reg, int Index, int Size)
|
||||
{
|
||||
ThrowIfInvalidF(Index, Size);
|
||||
|
||||
Context.EmitLdvec(Reg);
|
||||
Context.EmitLdc_I4(Index);
|
||||
|
||||
|
@ -659,6 +703,8 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorInsertTmpF(AILEmitterCtx Context, int Index, int Size)
|
||||
{
|
||||
ThrowIfInvalidF(Index, Size);
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitLdc_I4(Index);
|
||||
|
||||
|
@ -677,5 +723,31 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitStvectmp();
|
||||
}
|
||||
|
||||
private static void ThrowIfInvalid(int Index, int Size)
|
||||
{
|
||||
if ((uint)Size > 3)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
if ((uint)Index >= 16 >> Size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowIfInvalidF(int Index, int Size)
|
||||
{
|
||||
if ((uint)Size > 1)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
if ((uint)Index >= 4 >> Size)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,16 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
|
||||
public static void Bif_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitBitBif(Context, true);
|
||||
}
|
||||
|
||||
public static void Bit_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitBitBif(Context, false);
|
||||
}
|
||||
|
||||
public static void EmitBitBif(AILEmitterCtx Context, bool NotRm)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
|
@ -47,6 +57,11 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
|
||||
if (NotRm)
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
|
|
|
@ -61,6 +61,9 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdExt Op = (AOpCodeSimdExt)Context.CurrOp;
|
||||
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Position = Op.Imm4;
|
||||
|
@ -75,10 +78,12 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
|
||||
EmitVectorExtractZx(Context, Reg, Position++, 0);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, 0);
|
||||
EmitVectorInsertTmp(Context, Index, 0);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
|
@ -113,7 +118,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorExtractZx(Context, Op.Rn, 0, 3);
|
||||
|
||||
EmitIntZeroHigherIfNeeded(Context);
|
||||
EmitIntZeroUpperIfNeeded(Context);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
@ -124,7 +129,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
EmitVectorExtractZx(Context, Op.Rn, 1, 3);
|
||||
|
||||
EmitIntZeroHigherIfNeeded(Context);
|
||||
EmitIntZeroUpperIfNeeded(Context);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
@ -135,7 +140,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
EmitIntZeroHigherIfNeeded(Context);
|
||||
EmitIntZeroUpperIfNeeded(Context);
|
||||
|
||||
EmitScalarSet(Context, Op.Rd, 3);
|
||||
}
|
||||
|
@ -146,7 +151,7 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
EmitIntZeroHigherIfNeeded(Context);
|
||||
EmitIntZeroUpperIfNeeded(Context);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, 1, 3);
|
||||
}
|
||||
|
@ -251,6 +256,16 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitStvec(Op.Rd);
|
||||
}
|
||||
|
||||
public static void Trn1_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTranspose(Context, Part: 0);
|
||||
}
|
||||
|
||||
public static void Trn2_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTranspose(Context, Part: 1);
|
||||
}
|
||||
|
||||
public static void Umov_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
|
||||
|
@ -301,7 +316,7 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorZip(Context, Part: 1);
|
||||
}
|
||||
|
||||
private static void EmitIntZeroHigherIfNeeded(AILEmitterCtx Context)
|
||||
private static void EmitIntZeroUpperIfNeeded(AILEmitterCtx Context)
|
||||
{
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
{
|
||||
|
@ -310,6 +325,29 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorTranspose(AILEmitterCtx Context, int Part)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Context.CurrOp.GetBitsCount() >> 3;
|
||||
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
int Elem = (Index & ~1) + Part;
|
||||
|
||||
EmitVectorExtractZx(Context, (Index & 1) == 0 ? Op.Rn : Op.Rm, Elem, Op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorUnzip(AILEmitterCtx Context, int Part)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
@ -322,7 +360,7 @@ namespace ChocolArm64.Instruction
|
|||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
int Elem = Part + ((Index & (Half - 1)) << 1);
|
||||
|
||||
|
||||
EmitVectorExtractZx(Context, Index < Half ? Op.Rn : Op.Rm, Elem, Op.Size);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
|
@ -358,4 +396,4 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,14 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCall(typeof(ASoftFallback), MthdName);
|
||||
}
|
||||
|
||||
public static uint CountLeadingSigns32(uint Value) => (uint)CountLeadingSigns(Value, 32);
|
||||
public static ulong CountLeadingSigns64(ulong Value) => (ulong)CountLeadingSigns(Value, 64);
|
||||
|
||||
private static ulong CountLeadingSigns(ulong Value, int Size)
|
||||
{
|
||||
return CountLeadingZeros((Value >> 1) ^ Value, Size - 1);
|
||||
}
|
||||
|
||||
public static uint CountLeadingZeros32(uint Value) => (uint)CountLeadingZeros(Value, 32);
|
||||
public static ulong CountLeadingZeros64(ulong Value) => (ulong)CountLeadingZeros(Value, 64);
|
||||
|
||||
|
@ -113,7 +121,7 @@ namespace ChocolArm64.Instruction
|
|||
Value = ((Value & 0xcccccccccccccccc) >> 2) | ((Value & 0x3333333333333333) << 2);
|
||||
Value = ((Value & 0xf0f0f0f0f0f0f0f0) >> 4) | ((Value & 0x0f0f0f0f0f0f0f0f) << 4);
|
||||
Value = ((Value & 0xff00ff00ff00ff00) >> 8) | ((Value & 0x00ff00ff00ff00ff) << 8);
|
||||
Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16);
|
||||
Value = ((Value & 0xffff0000ffff0000) >> 16) | ((Value & 0x0000ffff0000ffff) << 16);
|
||||
|
||||
return (Value >> 32) | (Value << 32);
|
||||
}
|
||||
|
@ -242,10 +250,113 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static int CountSetBits8(byte Value)
|
||||
{
|
||||
return (Value >> 0) & 1 + (Value >> 1) & 1 +
|
||||
(Value >> 2) & 1 + (Value >> 3) & 1 +
|
||||
(Value >> 4) & 1 + (Value >> 5) & 1 +
|
||||
(Value >> 6) & 1 + (Value >> 7);
|
||||
return ((Value >> 0) & 1) + ((Value >> 1) & 1) +
|
||||
((Value >> 2) & 1) + ((Value >> 3) & 1) +
|
||||
((Value >> 4) & 1) + ((Value >> 5) & 1) +
|
||||
((Value >> 6) & 1) + (Value >> 7);
|
||||
}
|
||||
|
||||
public static float CustomMaxF(float val1, float val2) {
|
||||
|
||||
if(val1 == 0.0 && val2 == 0.0)
|
||||
{
|
||||
|
||||
if(BitConverter.GetBytes(val1)[3] == 0x80 && BitConverter.GetBytes(val2)[3] == 0x80)
|
||||
return (float)-0.0;
|
||||
|
||||
if(BitConverter.GetBytes(val1)[3] == 0x80 || BitConverter.GetBytes(val2)[3] == 0x80)
|
||||
return (float)0.0;
|
||||
|
||||
return (float)0.0;
|
||||
}
|
||||
|
||||
if(val1 > val2)
|
||||
return val1;
|
||||
|
||||
if(Single.IsNaN(val1))
|
||||
return val1;
|
||||
|
||||
return val2;
|
||||
}
|
||||
|
||||
public static double CustomMax(double val1, double val2) {
|
||||
|
||||
if(val1 == 0.0 && val2 == 0.0)
|
||||
{
|
||||
if(BitConverter.GetBytes(val1)[7] == 0x80 && BitConverter.GetBytes(val2)[7] == 0x80)
|
||||
return -0.0;
|
||||
|
||||
if(BitConverter.GetBytes(val1)[7] == 0x80 || BitConverter.GetBytes(val2)[7] == 0x80)
|
||||
return 0.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if(val1 > val2)
|
||||
return val1;
|
||||
|
||||
if(Double.IsNaN(val1))
|
||||
return val1;
|
||||
|
||||
return val2;
|
||||
}
|
||||
|
||||
public static float CustomMinF(float val1, float val2) {
|
||||
|
||||
if((val1 == 0.0 && val2 >= 0.0) || (val1 >= 0.0 && val2 == 0.0))
|
||||
{
|
||||
if(BitConverter.GetBytes(val1)[3] == 0x80 || BitConverter.GetBytes(val2)[3] == 0x80)
|
||||
return (float)-0.0;
|
||||
}
|
||||
|
||||
if(val1 == 0.0 && val2 == 0.0)
|
||||
{
|
||||
|
||||
if(BitConverter.GetBytes(val1)[3] == 0x80 && BitConverter.GetBytes(val2)[3] == 0x80)
|
||||
return (float)-0.0;
|
||||
|
||||
if(BitConverter.GetBytes(val1)[3] == 0x80 || BitConverter.GetBytes(val2)[3] == 0x80)
|
||||
return (float)-0.0;
|
||||
|
||||
return (float)0.0;
|
||||
}
|
||||
|
||||
if(val1 < val2)
|
||||
return val1;
|
||||
|
||||
if(Single.IsNaN(val1))
|
||||
return val1;
|
||||
|
||||
return val2;
|
||||
}
|
||||
|
||||
public static double CustomMin(double val1, double val2) {
|
||||
|
||||
if((val1 == 0.0 && val2 >= 0.0) || (val1 >= 0.0 && val2 == 0.0))
|
||||
{
|
||||
if(BitConverter.GetBytes(val1)[7] == 0x80 || BitConverter.GetBytes(val2)[7] == 0x80)
|
||||
return -0.0;
|
||||
}
|
||||
|
||||
if(val1 == 0.0 && val2 == 0.0)
|
||||
{
|
||||
|
||||
if(BitConverter.GetBytes(val1)[7] == 0x80 && BitConverter.GetBytes(val2)[7] == 0x80)
|
||||
return -0.0;
|
||||
|
||||
if(BitConverter.GetBytes(val1)[7] == 0x80 || BitConverter.GetBytes(val2)[7] == 0x80)
|
||||
return -0.0;
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
if(val1 < val2)
|
||||
return val1;
|
||||
|
||||
if(Double.IsNaN(val1))
|
||||
return val1;
|
||||
|
||||
return val2;
|
||||
}
|
||||
|
||||
public static float RoundF(float Value, int Fpcr)
|
||||
|
@ -398,4 +509,4 @@ namespace ChocolArm64.Instruction
|
|||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
103
ChocolArm64/Instruction/ASoftFloat.cs
Normal file
103
ChocolArm64/Instruction/ASoftFloat.cs
Normal file
|
@ -0,0 +1,103 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.Instruction
|
||||
{
|
||||
static class ASoftFloat
|
||||
{
|
||||
static ASoftFloat()
|
||||
{
|
||||
InvSqrtEstimateTable = BuildInvSqrtEstimateTable();
|
||||
}
|
||||
|
||||
private static readonly byte[] InvSqrtEstimateTable;
|
||||
|
||||
private static byte[] BuildInvSqrtEstimateTable()
|
||||
{
|
||||
byte[] Table = new byte[512];
|
||||
for (ulong index = 128; index < 512; index++)
|
||||
{
|
||||
ulong a = index;
|
||||
if (a < 256)
|
||||
{
|
||||
a = (a << 1) + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = (a | 1) << 1;
|
||||
}
|
||||
|
||||
ulong b = 256;
|
||||
while (a * (b + 1) * (b + 1) < (1ul << 28))
|
||||
{
|
||||
b++;
|
||||
}
|
||||
b = (b + 1) >> 1;
|
||||
|
||||
Table[index] = (byte)(b & 0xFF);
|
||||
}
|
||||
return Table;
|
||||
}
|
||||
|
||||
public static float InvSqrtEstimate(float x)
|
||||
{
|
||||
return (float)InvSqrtEstimate((double)x);
|
||||
}
|
||||
|
||||
public static double InvSqrtEstimate(double x)
|
||||
{
|
||||
ulong x_bits = (ulong)BitConverter.DoubleToInt64Bits(x);
|
||||
ulong x_sign = x_bits & 0x8000000000000000;
|
||||
long x_exp = (long)((x_bits >> 52) & 0x7FF);
|
||||
ulong scaled = x_bits & ((1ul << 52) - 1);
|
||||
|
||||
if (x_exp == 0x7ff)
|
||||
{
|
||||
if (scaled == 0)
|
||||
{
|
||||
// Infinity -> Zero
|
||||
return BitConverter.Int64BitsToDouble((long)x_sign);
|
||||
}
|
||||
|
||||
// NaN
|
||||
return BitConverter.Int64BitsToDouble((long)(x_bits | 0x0008000000000000));
|
||||
}
|
||||
|
||||
if (x_exp == 0)
|
||||
{
|
||||
if (scaled == 0)
|
||||
{
|
||||
// Zero -> Infinity
|
||||
return BitConverter.Int64BitsToDouble((long)(x_sign | 0x7ff0000000000000));
|
||||
}
|
||||
|
||||
// Denormal
|
||||
while ((scaled & (1 << 51)) == 0)
|
||||
{
|
||||
scaled <<= 1;
|
||||
x_exp--;
|
||||
}
|
||||
scaled <<= 1;
|
||||
}
|
||||
|
||||
if (((ulong)x_exp & 1) == 1)
|
||||
{
|
||||
scaled >>= 45;
|
||||
scaled &= 0xFF;
|
||||
scaled |= 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
scaled >>= 44;
|
||||
scaled &= 0xFF;
|
||||
scaled |= 0x100;
|
||||
}
|
||||
|
||||
ulong result_exp = ((ulong)(3068 - x_exp) / 2) & 0x7FF;
|
||||
ulong estimate = (ulong)InvSqrtEstimateTable[scaled];
|
||||
ulong fraction = estimate << 44;
|
||||
|
||||
ulong result = x_sign | (result_exp << 52) | fraction;
|
||||
return BitConverter.Int64BitsToDouble((long)result);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -60,11 +60,11 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public AILBlock GetILBlock(int Index) => ILBlocks[Index];
|
||||
|
||||
public ATranslatedSub GetSubroutine(HashSet<long> Callees)
|
||||
public ATranslatedSub GetSubroutine()
|
||||
{
|
||||
LocalAlloc = new ALocalAlloc(ILBlocks, Root);
|
||||
|
||||
InitSubroutine(Callees);
|
||||
InitSubroutine();
|
||||
InitLocals();
|
||||
|
||||
foreach (AILBlock ILBlock in ILBlocks)
|
||||
|
@ -75,7 +75,7 @@ namespace ChocolArm64.Translation
|
|||
return Subroutine;
|
||||
}
|
||||
|
||||
private void InitSubroutine(HashSet<long> Callees)
|
||||
private void InitSubroutine()
|
||||
{
|
||||
List<ARegister> Params = new List<ARegister>();
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace ChocolArm64.Translation
|
|||
|
||||
Generator = Mthd.GetILGenerator();
|
||||
|
||||
Subroutine = new ATranslatedSub(Mthd, Params, Callees);
|
||||
Subroutine = new ATranslatedSub(Mthd, Params);
|
||||
}
|
||||
|
||||
private void InitLocals()
|
||||
|
@ -115,7 +115,7 @@ namespace ChocolArm64.Translation
|
|||
Generator.EmitLdarg(Index + ParamsStart);
|
||||
Generator.EmitStloc(GetLocalIndex(Reg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] GetParamTypes(IList<ARegister> Params)
|
||||
{
|
||||
|
|
|
@ -12,8 +12,6 @@ namespace ChocolArm64.Translation
|
|||
{
|
||||
private ATranslator Translator;
|
||||
|
||||
private HashSet<long> Callees;
|
||||
|
||||
private Dictionary<long, AILLabel> Labels;
|
||||
|
||||
private int BlkIndex;
|
||||
|
@ -66,13 +64,11 @@ namespace ChocolArm64.Translation
|
|||
this.Graph = Graph;
|
||||
this.Root = Root;
|
||||
|
||||
Callees = new HashSet<long>();
|
||||
|
||||
Labels = new Dictionary<long, AILLabel>();
|
||||
|
||||
Emitter = new AILEmitter(Graph, Root, SubName);
|
||||
|
||||
ILBlock = Emitter.GetILBlock(0);
|
||||
ILBlock = Emitter.GetILBlock(0);
|
||||
|
||||
OpcIndex = -1;
|
||||
|
||||
|
@ -84,7 +80,7 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public ATranslatedSub GetSubroutine()
|
||||
{
|
||||
return Emitter.GetSubroutine(Callees);
|
||||
return Emitter.GetSubroutine();
|
||||
}
|
||||
|
||||
public bool AdvanceOpCode()
|
||||
|
@ -123,8 +119,6 @@ namespace ChocolArm64.Translation
|
|||
|
||||
public bool TryOptEmitSubroutineCall()
|
||||
{
|
||||
Callees.Add(((AOpCodeBImm)CurrOp).Imm);
|
||||
|
||||
if (CurrBlock.Next == null)
|
||||
{
|
||||
return false;
|
||||
|
@ -152,6 +146,8 @@ namespace ChocolArm64.Translation
|
|||
|
||||
EmitCall(Sub.Method);
|
||||
|
||||
Sub.AddCaller(Root.Position);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -260,18 +256,24 @@ namespace ChocolArm64.Translation
|
|||
case AIntType.Int64: Emit(OpCodes.Conv_I8); break;
|
||||
}
|
||||
|
||||
if (IntType == AIntType.UInt64 ||
|
||||
IntType == AIntType.Int64)
|
||||
bool Sz64 = CurrOp.RegisterSize != ARegisterSize.Int32;
|
||||
|
||||
if (Sz64 == (IntType == AIntType.UInt64 ||
|
||||
IntType == AIntType.Int64))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (CurrOp.RegisterSize != ARegisterSize.Int32)
|
||||
if (Sz64)
|
||||
{
|
||||
Emit(IntType >= AIntType.Int8
|
||||
? OpCodes.Conv_I8
|
||||
: OpCodes.Conv_U8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Emit(OpCodes.Conv_U4);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitLsl(int Amount) => EmitILShift(Amount, OpCodes.Shl);
|
||||
|
@ -298,7 +300,7 @@ namespace ChocolArm64.Translation
|
|||
EmitLdc_I4(Amount);
|
||||
|
||||
Emit(OpCodes.Shr_Un);
|
||||
|
||||
|
||||
Ldloc(Tmp2Index, AIoType.Int);
|
||||
|
||||
EmitLdc_I4(CurrOp.GetBitsCount() - Amount);
|
||||
|
|
|
@ -48,6 +48,9 @@ https://openal.org/downloads/OpenAL11CoreSDK.zip
|
|||
|
||||
- Config File: `Ryujinx.conf` should be present in executable folder.
|
||||
For more informations [you can go here](CONFIG.md).
|
||||
|
||||
- If you are a Windows user, you can configure your keys, the logs, install OpenAL, etc... with Ryujinx-Setting.
|
||||
[Download it, right here](https://github.com/AcK77/Ryujinx-Settings)
|
||||
|
||||
**Help**
|
||||
|
||||
|
|
|
@ -9,15 +9,18 @@ namespace Ryujinx.Core
|
|||
{
|
||||
public static class Config
|
||||
{
|
||||
public static bool EnableMemoryChecks { get; private set; }
|
||||
public static bool LoggingEnableInfo { get; private set; }
|
||||
public static bool LoggingEnableTrace { get; private set; }
|
||||
public static bool LoggingEnableDebug { get; private set; }
|
||||
public static bool LoggingEnableWarn { get; private set; }
|
||||
public static bool LoggingEnableError { get; private set; }
|
||||
public static bool LoggingEnableFatal { get; private set; }
|
||||
public static bool LoggingEnableIpc { get; private set; }
|
||||
public static bool LoggingEnableLogFile { get; private set; }
|
||||
public static bool EnableMemoryChecks { get; private set; }
|
||||
public static bool LoggingEnableInfo { get; private set; }
|
||||
public static bool LoggingEnableTrace { get; private set; }
|
||||
public static bool LoggingEnableDebug { get; private set; }
|
||||
public static bool LoggingEnableWarn { get; private set; }
|
||||
public static bool LoggingEnableError { get; private set; }
|
||||
public static bool LoggingEnableFatal { get; private set; }
|
||||
public static bool LoggingEnableIpc { get; private set; }
|
||||
public static bool LoggingEnableStub { get; private set; }
|
||||
public static bool LoggingEnableLogFile { get; private set; }
|
||||
public static bool LoggingEnableFilter { get; private set; }
|
||||
public static bool[] LoggingFilteredClasses { get; private set; }
|
||||
|
||||
public static JoyCon FakeJoyCon { get; private set; }
|
||||
|
||||
|
@ -27,15 +30,33 @@ namespace Ryujinx.Core
|
|||
var iniPath = Path.Combine(iniFolder, "Ryujinx.conf");
|
||||
IniParser Parser = new IniParser(iniPath);
|
||||
|
||||
EnableMemoryChecks = Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
|
||||
LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info"));
|
||||
LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace"));
|
||||
LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug"));
|
||||
LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn"));
|
||||
LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error"));
|
||||
LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal"));
|
||||
LoggingEnableIpc = Convert.ToBoolean(Parser.Value("Logging_Enable_Ipc"));
|
||||
LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile"));
|
||||
EnableMemoryChecks = Convert.ToBoolean(Parser.Value("Enable_Memory_Checks"));
|
||||
LoggingEnableInfo = Convert.ToBoolean(Parser.Value("Logging_Enable_Info"));
|
||||
LoggingEnableTrace = Convert.ToBoolean(Parser.Value("Logging_Enable_Trace"));
|
||||
LoggingEnableDebug = Convert.ToBoolean(Parser.Value("Logging_Enable_Debug"));
|
||||
LoggingEnableWarn = Convert.ToBoolean(Parser.Value("Logging_Enable_Warn"));
|
||||
LoggingEnableError = Convert.ToBoolean(Parser.Value("Logging_Enable_Error"));
|
||||
LoggingEnableFatal = Convert.ToBoolean(Parser.Value("Logging_Enable_Fatal"));
|
||||
LoggingEnableIpc = Convert.ToBoolean(Parser.Value("Logging_Enable_Ipc"));
|
||||
LoggingEnableStub = Convert.ToBoolean(Parser.Value("Logging_Enable_Stub"));
|
||||
LoggingEnableLogFile = Convert.ToBoolean(Parser.Value("Logging_Enable_LogFile"));
|
||||
LoggingEnableFilter = Convert.ToBoolean(Parser.Value("Logging_Enable_Filter"));
|
||||
LoggingFilteredClasses = new bool[(int)LogClass.Count];
|
||||
|
||||
string[] FilteredLogClasses = Parser.Value("Logging_Filtered_Classes", string.Empty).Split(',');
|
||||
foreach (string LogClass in FilteredLogClasses)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(LogClass.Trim()))
|
||||
{
|
||||
foreach (LogClass EnumItemName in Enum.GetValues(typeof(LogClass)))
|
||||
{
|
||||
if (EnumItemName.ToString().ToLower().Contains(LogClass.Trim().ToLower()))
|
||||
{
|
||||
LoggingFilteredClasses[(int)EnumItemName] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FakeJoyCon = new JoyCon
|
||||
{
|
||||
|
|
|
@ -82,7 +82,7 @@ namespace Ryujinx.Core.Input
|
|||
|
||||
(AMemory Memory, long Position) ShMem = ShMemPositions[ShMemPositions.Length - 1];
|
||||
|
||||
Logging.Info($"HID shared memory successfully mapped to 0x{ShMem.Position:x16}!");
|
||||
Logging.Info(LogClass.ServiceHid, $"HID shared memory successfully mapped to 0x{ShMem.Position:x16}!");
|
||||
|
||||
Init(ShMem.Memory, ShMem.Position);
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ namespace Ryujinx.Core.Input
|
|||
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x8, HidEntryCount);
|
||||
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x10, CurrEntry);
|
||||
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x18, HidEntryCount - 1);
|
||||
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x20, Timestamp);
|
||||
Memory.WriteInt64Unchecked(TouchScreenOffset + 0x20, Timestamp);
|
||||
|
||||
long TouchEntryOffset = TouchScreenOffset + HidTouchHeaderSize;
|
||||
|
||||
|
|
36
Ryujinx.Core/LogClass.cs
Normal file
36
Ryujinx.Core/LogClass.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
namespace Ryujinx.Core
|
||||
{
|
||||
public enum LogClass
|
||||
{
|
||||
Audio,
|
||||
CPU,
|
||||
GPU,
|
||||
Kernel,
|
||||
KernelIpc,
|
||||
KernelScheduler,
|
||||
KernelSvc,
|
||||
Loader,
|
||||
Service,
|
||||
ServiceAcc,
|
||||
ServiceAm,
|
||||
ServiceApm,
|
||||
ServiceAudio,
|
||||
ServiceBsd,
|
||||
ServiceFriend,
|
||||
ServiceFs,
|
||||
ServiceHid,
|
||||
ServiceLm,
|
||||
ServiceNifm,
|
||||
ServiceNs,
|
||||
ServiceNv,
|
||||
ServicePctl,
|
||||
ServicePl,
|
||||
ServiceSet,
|
||||
ServiceSfdnsres,
|
||||
ServiceSm,
|
||||
ServiceSss,
|
||||
ServiceTime,
|
||||
ServiceVi,
|
||||
Count,
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Core
|
||||
{
|
||||
|
@ -12,14 +14,28 @@ namespace Ryujinx.Core
|
|||
|
||||
private const string LogFileName = "Ryujinx.log";
|
||||
|
||||
private static bool EnableInfo = Config.LoggingEnableInfo;
|
||||
private static bool EnableTrace = Config.LoggingEnableTrace;
|
||||
private static bool EnableDebug = Config.LoggingEnableDebug;
|
||||
private static bool EnableWarn = Config.LoggingEnableWarn;
|
||||
private static bool EnableError = Config.LoggingEnableError;
|
||||
private static bool EnableFatal = Config.LoggingEnableFatal;
|
||||
private static bool EnableIpc = Config.LoggingEnableIpc;
|
||||
private static bool EnableLogFile = Config.LoggingEnableLogFile;
|
||||
private static bool EnableInfo = Config.LoggingEnableInfo;
|
||||
private static bool EnableTrace = Config.LoggingEnableTrace;
|
||||
private static bool EnableDebug = Config.LoggingEnableDebug;
|
||||
private static bool EnableWarn = Config.LoggingEnableWarn;
|
||||
private static bool EnableError = Config.LoggingEnableError;
|
||||
private static bool EnableFatal = Config.LoggingEnableFatal;
|
||||
private static bool EnableStub = Config.LoggingEnableIpc;
|
||||
private static bool EnableIpc = Config.LoggingEnableIpc;
|
||||
private static bool EnableFilter = Config.LoggingEnableFilter;
|
||||
private static bool EnableLogFile = Config.LoggingEnableLogFile;
|
||||
private static bool[] FilteredLogClasses = Config.LoggingFilteredClasses;
|
||||
|
||||
private enum LogLevel
|
||||
{
|
||||
Debug,
|
||||
Error,
|
||||
Fatal,
|
||||
Info,
|
||||
Stub,
|
||||
Trace,
|
||||
Warn
|
||||
}
|
||||
|
||||
static Logging()
|
||||
{
|
||||
|
@ -30,14 +46,51 @@ namespace Ryujinx.Core
|
|||
ExecutionTime.Start();
|
||||
}
|
||||
|
||||
public static string GetExecutionTime()
|
||||
{
|
||||
return ExecutionTime.ElapsedMilliseconds.ToString().PadLeft(8, '0') + "ms";
|
||||
}
|
||||
public static string GetExecutionTime() => ExecutionTime.ElapsedMilliseconds.ToString().PadLeft(8, '0') + "ms";
|
||||
|
||||
private static string WhoCalledMe()
|
||||
private static void LogMessage(LogEntry LogEntry)
|
||||
{
|
||||
return new StackTrace().GetFrame(2).GetMethod().Name;
|
||||
if (EnableFilter)
|
||||
if (!FilteredLogClasses[(int)LogEntry.LogClass])
|
||||
return;
|
||||
|
||||
ConsoleColor consoleColor = ConsoleColor.White;
|
||||
|
||||
switch (LogEntry.LogLevel)
|
||||
{
|
||||
case LogLevel.Debug:
|
||||
consoleColor = ConsoleColor.Gray;
|
||||
break;
|
||||
case LogLevel.Error:
|
||||
consoleColor = ConsoleColor.Red;
|
||||
break;
|
||||
case LogLevel.Fatal:
|
||||
consoleColor = ConsoleColor.Magenta;
|
||||
break;
|
||||
case LogLevel.Info:
|
||||
consoleColor = ConsoleColor.White;
|
||||
break;
|
||||
case LogLevel.Stub:
|
||||
consoleColor = ConsoleColor.DarkYellow;
|
||||
break;
|
||||
case LogLevel.Trace:
|
||||
consoleColor = ConsoleColor.DarkGray;
|
||||
break;
|
||||
case LogLevel.Warn:
|
||||
consoleColor = ConsoleColor.Yellow;
|
||||
break;
|
||||
}
|
||||
|
||||
LogEntry.ManagedThreadId = Thread.CurrentThread.ManagedThreadId;
|
||||
|
||||
string Text = $"{LogEntry.ExecutionTime} | {LogEntry.ManagedThreadId} > {LogEntry.LogClass} > " +
|
||||
$"{LogEntry.LogLevel.ToString()} > {LogEntry.CallingMember} > {LogEntry.Message}";
|
||||
|
||||
Console.ForegroundColor = consoleColor;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
}
|
||||
|
||||
private static void LogFile(string Message)
|
||||
|
@ -51,87 +104,108 @@ namespace Ryujinx.Core
|
|||
}
|
||||
}
|
||||
|
||||
public static void Info(string Message)
|
||||
public static void Info(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableInfo)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | INFO > {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Info,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Trace(string Message)
|
||||
public static void Trace(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableTrace)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | TRACE > {WhoCalledMe()} - {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Trace,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Debug(string Message)
|
||||
public static void Stub(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableStub)
|
||||
{
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Stub,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Debug(LogClass LogClass,string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableDebug)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | DEBUG > {WhoCalledMe()} - {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Debug,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Warn(string Message)
|
||||
public static void Warn(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableWarn)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | WARN > {WhoCalledMe()} - {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Yellow;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Warn,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Error(string Message)
|
||||
public static void Error(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableError)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | ERROR > {WhoCalledMe()} - {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Error,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fatal(string Message)
|
||||
public static void Fatal(LogClass LogClass, string Message, [CallerMemberName] string CallingMember = "")
|
||||
{
|
||||
if (EnableFatal)
|
||||
{
|
||||
string Text = $"{GetExecutionTime()} | FATAL > {WhoCalledMe()} - {Message}";
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.Magenta;
|
||||
Console.WriteLine(Text.PadLeft(Text.Length + 1, ' '));
|
||||
Console.ResetColor();
|
||||
|
||||
LogFile(Text);
|
||||
LogMessage(new LogEntry
|
||||
{
|
||||
CallingMember = CallingMember,
|
||||
LogLevel = LogLevel.Fatal,
|
||||
LogClass = LogClass,
|
||||
Message = Message,
|
||||
ExecutionTime = GetExecutionTime()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,7 +234,7 @@ namespace Ryujinx.Core
|
|||
int firstCharColumn = firstHexColumn
|
||||
+ bytesPerLine * 3 // - 2 digit for the hexadecimal value and 1 space
|
||||
+ (bytesPerLine - 1) / 8 // - 1 extra space every 8 characters from the 9th
|
||||
+ 2; // 2 spaces
|
||||
+ 2; // 2 spaces
|
||||
|
||||
int lineLength = firstCharColumn
|
||||
+ bytesPerLine // - characters to show the ascii value
|
||||
|
@ -208,5 +282,15 @@ namespace Ryujinx.Core
|
|||
}
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
private struct LogEntry
|
||||
{
|
||||
public string CallingMember;
|
||||
public string ExecutionTime;
|
||||
public string Message;
|
||||
public int ManagedThreadId;
|
||||
public LogClass LogClass;
|
||||
public LogLevel LogLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,13 +136,13 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
Thread.Thread.Execute();
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} running.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} running.");
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitingToRun[Thread.ProcessorId].Push(SchedThread);
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(SchedThread.Thread)} waiting to run.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,13 +168,13 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(CurrThread)} entering ipc delay wait state.");
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
if (!AllThreads.TryGetValue(CurrThread, out SchedThread))
|
||||
{
|
||||
Logging.Error($"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!");
|
||||
Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(CurrThread)} was not found on the scheduler queue!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} entering signal wait state.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} entering signal wait state.");
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
|
@ -204,7 +204,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
if (!AllThreads.TryGetValue(Thread, out SchedThread))
|
||||
{
|
||||
Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
||||
Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
if (Timeout >= 0)
|
||||
{
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} has wait timeout of {Timeout}ms.");
|
||||
|
||||
Result = SchedThread.WaitEvent.WaitOne(Timeout);
|
||||
}
|
||||
|
@ -236,7 +236,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
if (ActiveProcessors.Add(Thread.ProcessorId))
|
||||
{
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -246,14 +246,14 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
SchedThread.WaitEvent.WaitOne();
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
}
|
||||
|
||||
public void Yield(KThread Thread)
|
||||
{
|
||||
SchedulerThread SchedThread;
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} yielded execution.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} yielded execution.");
|
||||
|
||||
lock (SchedLock)
|
||||
{
|
||||
|
@ -261,7 +261,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
if (SchedThread == null)
|
||||
{
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resumed because theres nothing better to run.");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -270,7 +270,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
if (!AllThreads.TryGetValue(Thread, out SchedThread))
|
||||
{
|
||||
Logging.Error($"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
||||
Logging.Error(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} was not found on the scheduler queue!");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
|
||||
SchedThread.WaitEvent.WaitOne();
|
||||
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} resuming execution...");
|
||||
}
|
||||
|
||||
private void RunThread(SchedulerThread SchedThread)
|
||||
|
@ -291,7 +291,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
}
|
||||
else
|
||||
{
|
||||
Logging.Debug($"{GetDbgThreadInfo(SchedThread.Thread)} running.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(SchedThread.Thread)} running.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,7 +305,7 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
if (!WaitingToRun[Thread.ProcessorId].HasThread(SchedThread))
|
||||
{
|
||||
Logging.Debug($"{GetDbgThreadInfo(Thread)} signaled.");
|
||||
Logging.Debug(LogClass.KernelScheduler, $"{GetDbgThreadInfo(Thread)} signaled.");
|
||||
|
||||
SchedThread.WaitEvent.Set();
|
||||
}
|
||||
|
|
|
@ -7,9 +7,12 @@ namespace Ryujinx.Core.OsHle.Handles
|
|||
{
|
||||
public IpcService Service { get; private set; }
|
||||
|
||||
public KSession(IpcService Service)
|
||||
public string ServiceName { get; private set; }
|
||||
|
||||
public KSession(IpcService Service, string ServiceName)
|
||||
{
|
||||
this.Service = Service;
|
||||
this.Service = Service;
|
||||
this.ServiceName = ServiceName;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle
|
|||
continue;
|
||||
}
|
||||
|
||||
Logging.Info($"Loading {Path.GetFileNameWithoutExtension(File)}...");
|
||||
Logging.Info(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
|
||||
|
||||
using (FileStream Input = new FileStream(File, FileMode.Open))
|
||||
{
|
||||
|
@ -131,7 +131,7 @@ namespace Ryujinx.Core.OsHle
|
|||
{
|
||||
string NextNro = Homebrew.ReadHbAbiNextLoadPath(Process.Memory, Process.HbAbiDataPosition);
|
||||
|
||||
Logging.Info($"HbAbi NextLoadPath {NextNro}");
|
||||
Logging.Info(LogClass.Loader, $"HbAbi NextLoadPath {NextNro}");
|
||||
|
||||
if (NextNro == string.Empty)
|
||||
{
|
||||
|
|
|
@ -61,12 +61,12 @@ namespace Ryujinx.Core.OsHle.Ipc
|
|||
case 3:
|
||||
{
|
||||
Request = FillResponse(Response, 0, 0x500);
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//TODO: Whats the difference between IpcDuplicateSession/Ex?
|
||||
case 2:
|
||||
//TODO: Whats the difference between IpcDuplicateSession/Ex?
|
||||
case 2:
|
||||
case 4:
|
||||
{
|
||||
int Unknown = ReqReader.ReadInt32();
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
public const long MainStackAddress = AMemoryMgr.AddrSize - MainStackSize;
|
||||
|
||||
public const long TlsPagesSize = 0x4000;
|
||||
public const long TlsPagesSize = 0x20000;
|
||||
|
||||
public const long TlsPagesAddress = MainStackAddress - TlsPagesSize;
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ namespace Ryujinx.Core.OsHle
|
|||
{
|
||||
class Process : IDisposable
|
||||
{
|
||||
private const int TlsSize = 0x200;
|
||||
private const int TotalTlsSlots = 32;
|
||||
private const int TlsSize = 0x200;
|
||||
|
||||
private const int TotalTlsSlots = (int)MemoryRegions.TlsPagesSize / TlsSize;
|
||||
|
||||
private const int TickFreq = 19_200_000;
|
||||
|
||||
|
@ -90,7 +91,7 @@ namespace Ryujinx.Core.OsHle
|
|||
throw new ObjectDisposedException(nameof(Process));
|
||||
}
|
||||
|
||||
Logging.Info($"Image base at 0x{ImageBase:x16}.");
|
||||
Logging.Info(LogClass.Loader, $"Image base at 0x{ImageBase:x16}.");
|
||||
|
||||
Executable Executable = new Executable(Program, Memory, ImageBase);
|
||||
|
||||
|
@ -123,7 +124,7 @@ namespace Ryujinx.Core.OsHle
|
|||
MemoryRegions.MainStackAddress,
|
||||
MemoryRegions.MainStackSize,
|
||||
MemoryType.Normal);
|
||||
|
||||
|
||||
long StackTop = MemoryRegions.MainStackAddress + MemoryRegions.MainStackSize;
|
||||
|
||||
int Handle = MakeThread(Executables[0].ImageBase, StackTop, 0, 0, 0);
|
||||
|
@ -254,12 +255,12 @@ namespace Ryujinx.Core.OsHle
|
|||
if (e.Position >= Executables[Index].ImageBase)
|
||||
{
|
||||
NsoName = $"{(e.Position - Executables[Index].ImageBase):x16}";
|
||||
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Logging.Trace($"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
|
||||
Logging.Trace(LogClass.Loader, $"Executing at 0x{e.Position:x16} {e.SubName} {NsoName}");
|
||||
}
|
||||
|
||||
public void EnableCpuTracing()
|
||||
|
@ -289,7 +290,7 @@ namespace Ryujinx.Core.OsHle
|
|||
{
|
||||
if (sender is AThread Thread)
|
||||
{
|
||||
Logging.Info($"Thread {Thread.ThreadId} exiting...");
|
||||
Logging.Info(LogClass.KernelScheduler, $"Thread {Thread.ThreadId} exiting...");
|
||||
|
||||
TlsSlots.TryRemove(GetTlsSlot(Thread.ThreadState.Tpidr), out _);
|
||||
}
|
||||
|
@ -301,7 +302,7 @@ namespace Ryujinx.Core.OsHle
|
|||
Dispose();
|
||||
}
|
||||
|
||||
Logging.Info($"No threads running, now exiting Process {ProcessId}...");
|
||||
Logging.Info(LogClass.KernelScheduler, $"No threads running, now exiting Process {ProcessId}...");
|
||||
|
||||
Ns.Os.ExitProcess(ProcessId);
|
||||
}
|
||||
|
@ -316,7 +317,7 @@ namespace Ryujinx.Core.OsHle
|
|||
{
|
||||
if (!ThreadsByTpidr.TryGetValue(Tpidr, out KThread Thread))
|
||||
{
|
||||
Logging.Error($"Thread with TPIDR 0x{Tpidr:x16} not found!");
|
||||
Logging.Error(LogClass.KernelScheduler, $"Thread with TPIDR 0x{Tpidr:x16} not found!");
|
||||
}
|
||||
|
||||
return Thread;
|
||||
|
@ -339,7 +340,7 @@ namespace Ryujinx.Core.OsHle
|
|||
{
|
||||
ShouldDispose = true;
|
||||
|
||||
Logging.Info($"Process {ProcessId} waiting all threads terminate...");
|
||||
Logging.Info(LogClass.KernelScheduler, $"Process {ProcessId} waiting all threads terminate...");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -354,11 +355,11 @@ namespace Ryujinx.Core.OsHle
|
|||
}
|
||||
}
|
||||
|
||||
ServiceNvDrv.Fds.DeleteProcess(this);
|
||||
INvDrvServices.Fds.DeleteProcess(this);
|
||||
|
||||
ServiceNvDrv.NvMaps .DeleteProcess(this);
|
||||
ServiceNvDrv.NvMapsById.DeleteProcess(this);
|
||||
ServiceNvDrv.NvMapsFb .DeleteProcess(this);
|
||||
INvDrvServices.NvMaps .DeleteProcess(this);
|
||||
INvDrvServices.NvMapsById.DeleteProcess(this);
|
||||
INvDrvServices.NvMapsFb .DeleteProcess(this);
|
||||
|
||||
Scheduler.Dispose();
|
||||
|
||||
|
@ -368,7 +369,7 @@ namespace Ryujinx.Core.OsHle
|
|||
|
||||
Memory.Dispose();
|
||||
|
||||
Logging.Info($"Process {ProcessId} exiting...");
|
||||
Logging.Info(LogClass.KernelScheduler, $"Process {ProcessId} exiting...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,16 +3,17 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Acc
|
||||
{
|
||||
class ServiceAcc : IpcService
|
||||
class IAccountServiceForApplication : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAcc()
|
||||
public IAccountServiceForApplication()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetUserCount },
|
||||
{ 3, ListOpenUsers },
|
||||
{ 5, GetProfile },
|
||||
{ 100, InitializeApplicationInfo },
|
||||
|
@ -20,8 +21,19 @@ namespace Ryujinx.Core.OsHle.Services.Acc
|
|||
};
|
||||
}
|
||||
|
||||
public long GetUserCount(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logging.Stub(LogClass.ServiceAcc, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ListOpenUsers(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAcc, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -34,6 +46,8 @@ namespace Ryujinx.Core.OsHle.Services.Acc
|
|||
|
||||
public long InitializeApplicationInfo(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAcc, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -44,4 +58,4 @@ namespace Ryujinx.Core.OsHle.Services.Acc
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,12 +19,16 @@ namespace Ryujinx.Core.OsHle.Services.Acc
|
|||
}
|
||||
|
||||
public long CheckAvailability(ServiceCtx Context)
|
||||
{
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAcc, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetAccountId(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAcc, "AccountId = 0xcafeL");
|
||||
|
||||
Context.ResponseData.Write(0xcafeL);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -19,6 +19,8 @@ namespace Ryujinx.Core.OsHle.Services.Acc
|
|||
|
||||
public long GetBase(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAcc, "Stubbed");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
|
|
@ -37,6 +37,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
long UIdLow = Context.RequestData.ReadInt64();
|
||||
long UIdHigh = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"UidLow = {UIdLow}, UidHigh = {UIdHigh}");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
|
@ -44,6 +46,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
|
||||
public long GetDesiredLanguage(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAm, "LanguageId = 1");
|
||||
|
||||
//This is an enumerator where each number is a differnet language.
|
||||
//0 is Japanese and 1 is English, need to figure out the other codes.
|
||||
Context.ResponseData.Write(1L);
|
||||
|
@ -58,7 +62,7 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
int Module = ErrorCode & 0xFF;
|
||||
int Description = (ErrorCode >> 9) & 0xFFF;
|
||||
|
||||
Logging.Info($"({(ErrorModule)Module}){2000 + Module}-{Description}");
|
||||
Logging.Info(LogClass.ServiceAm, $"({(ErrorModule)Module}){2000 + Module}-{Description}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Am
|
||||
{
|
||||
class ServiceAppletOE : IpcService
|
||||
class IApplicationProxyService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAppletOE()
|
||||
public IApplicationProxyService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -56,7 +56,7 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
|
||||
public long GetPerformanceMode(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((byte)0);
|
||||
Context.ResponseData.Write((byte)Apm.PerformanceMode.Handheld);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, Exit },
|
||||
{ 1, LockExit },
|
||||
{ 10, SetScreenShotPermission },
|
||||
{ 11, SetOperationModeChangedNotification },
|
||||
{ 12, SetPerformanceModeChangedNotification },
|
||||
|
@ -23,7 +23,7 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
};
|
||||
}
|
||||
|
||||
public long Exit(ServiceCtx Context)
|
||||
public long LockExit(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"ScreenShot Allowed = {Enable}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -39,6 +41,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"OperationMode Changed = {Enable}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -46,6 +50,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"PerformanceMode Changed = {Enable}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -55,6 +61,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"Focus Handling Mode Flags = {{{Flag1}|{Flag2}|{Flag3}}}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -62,6 +70,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"Restart Message Enabled = {Enable}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -69,6 +79,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Logging.Stub(LogClass.ServiceAm, $"Out Of Focus Suspending Enabled = {Enable}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
|
||||
public long GetAppletResourceUserId(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAm, $"Applet Resource Id = 0");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
return 0;
|
||||
|
@ -27,6 +29,8 @@ namespace Ryujinx.Core.OsHle.Services.Am
|
|||
|
||||
public long AcquireForegroundRights(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Apm
|
||||
{
|
||||
class ServiceApm : IpcService
|
||||
class IManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceApm()
|
||||
public IManager()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -13,14 +13,27 @@ namespace Ryujinx.Core.OsHle.Services.Apm
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, SetPerformanceConfiguration }
|
||||
{ 0, SetPerformanceConfiguration },
|
||||
{ 1, GetPerformanceConfiguration }
|
||||
};
|
||||
}
|
||||
|
||||
public long SetPerformanceConfiguration(ServiceCtx Context)
|
||||
{
|
||||
int PerfMode = Context.RequestData.ReadInt32();
|
||||
int PerfConfig = Context.RequestData.ReadInt32();
|
||||
PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32();
|
||||
PerformanceConfiguration PerfConfig = (PerformanceConfiguration)Context.RequestData.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPerformanceConfiguration(ServiceCtx Context)
|
||||
{
|
||||
PerformanceMode PerfMode = (PerformanceMode)Context.RequestData.ReadInt32();
|
||||
|
||||
Context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1);
|
||||
|
||||
Logging.Stub(LogClass.ServiceApm, $"PerformanceMode = {PerfMode}, PerformanceConfiguration =" +
|
||||
$" {PerformanceConfiguration.PerformanceConfiguration1}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
18
Ryujinx.Core/OsHle/Services/Apm/PerformanceConfiguration.cs
Normal file
18
Ryujinx.Core/OsHle/Services/Apm/PerformanceConfiguration.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Apm
|
||||
{
|
||||
enum PerformanceConfiguration : uint
|
||||
{
|
||||
PerformanceConfiguration1 = 0x00010000,
|
||||
PerformanceConfiguration2 = 0x00010001,
|
||||
PerformanceConfiguration3 = 0x00010002,
|
||||
PerformanceConfiguration4 = 0x00020000,
|
||||
PerformanceConfiguration5 = 0x00020001,
|
||||
PerformanceConfiguration6 = 0x00020002,
|
||||
PerformanceConfiguration7 = 0x00020003,
|
||||
PerformanceConfiguration8 = 0x00020004,
|
||||
PerformanceConfiguration9 = 0x00020005,
|
||||
PerformanceConfiguration10 = 0x00020006,
|
||||
PerformanceConfiguration11 = 0x92220007,
|
||||
PerformanceConfiguration12 = 0x92220008
|
||||
}
|
||||
}
|
8
Ryujinx.Core/OsHle/Services/Apm/PerformanceMode.cs
Normal file
8
Ryujinx.Core/OsHle/Services/Apm/PerformanceMode.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Apm
|
||||
{
|
||||
enum PerformanceMode
|
||||
{
|
||||
Handheld = 0,
|
||||
Docked = 1
|
||||
}
|
||||
}
|
|
@ -5,13 +5,13 @@ using System.Text;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class IAudioDevice : IpcService
|
||||
class IAudioDeviceService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAudioDevice()
|
||||
public IAudioDeviceService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -57,6 +57,8 @@ namespace Ryujinx.Core.OsHle.Services.Aud
|
|||
|
||||
string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position, Size);
|
||||
|
||||
Logging.Stub(LogClass.ServiceAudio, $"Volume = {Volume}, Position = {Position}, Size = {Size}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -124,14 +124,14 @@ namespace Ryujinx.Core.OsHle.Services.Aud
|
|||
|
||||
public long AppendAudioOutBufferEx(ServiceCtx Context)
|
||||
{
|
||||
Logging.Warn("Not implemented!");
|
||||
Logging.Stub(LogClass.ServiceAudio, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetReleasedAudioOutBufferEx(ServiceCtx Context)
|
||||
{
|
||||
Logging.Warn("Not implemented!");
|
||||
Logging.Stub(LogClass.ServiceAudio, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@ using System.Text;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class ServiceAudOut : IpcService
|
||||
class IAudioOutManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAudOut()
|
||||
public IAudioOutManager()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -54,11 +54,15 @@ namespace Ryujinx.Core.OsHle.Services.Aud
|
|||
|
||||
public long StartAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAudio, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StopAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceAudio, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Aud
|
||||
{
|
||||
class ServiceAudRen : IpcService
|
||||
class IAudioRendererManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceAudRen()
|
||||
public IAudioRendererManager()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -42,6 +42,8 @@ namespace Ryujinx.Core.OsHle.Services.Aud
|
|||
int Unknown2c = Context.RequestData.ReadInt32();
|
||||
int Rev1Magic = Context.RequestData.ReadInt32();
|
||||
|
||||
Logging.Stub(LogClass.ServiceAudio, "BufferSize = 0x400L");
|
||||
|
||||
Context.ResponseData.Write(0x400L);
|
||||
|
||||
return 0;
|
||||
|
@ -51,7 +53,7 @@ namespace Ryujinx.Core.OsHle.Services.Aud
|
|||
{
|
||||
long UserId = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(Context, new IAudioDevice());
|
||||
MakeObject(Context, new IAudioDeviceService());
|
||||
|
||||
return 0;
|
||||
}
|
8
Ryujinx.Core/OsHle/Services/Bsd/BsdError.cs
Normal file
8
Ryujinx.Core/OsHle/Services/Bsd/BsdError.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Core.OsHle.Services.Bsd
|
||||
{
|
||||
//bsd_errno == (SocketException.ErrorCode - 10000)
|
||||
public enum BsdError
|
||||
{
|
||||
Timeout = 60
|
||||
}
|
||||
}
|
18
Ryujinx.Core/OsHle/Services/Bsd/BsdSocket.cs
Normal file
18
Ryujinx.Core/OsHle/Services/Bsd/BsdSocket.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Bsd
|
||||
{
|
||||
class BsdSocket
|
||||
{
|
||||
public int Family;
|
||||
public int Type;
|
||||
public int Protocol;
|
||||
|
||||
public IPAddress IpAddress;
|
||||
|
||||
public IPEndPoint RemoteEP;
|
||||
|
||||
public Socket Handle;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using Ryujinx.Core.OsHle.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
@ -10,56 +9,15 @@ using System.Threading.Tasks;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Bsd
|
||||
{
|
||||
|
||||
//bsd_errno == (SocketException.ErrorCode - 10000)
|
||||
//https://github.com/freebsd/freebsd/blob/master/sys/sys/errno.h
|
||||
public enum BsdError
|
||||
{
|
||||
ENOTSOCK = 38, /* Socket operation on non-socket */
|
||||
EDESTADDRREQ = 39, /* Destination address required */
|
||||
EMSGSIZE = 40, /* Message too long */
|
||||
EPROTOTYPE = 41, /* Protocol wrong type for socket */
|
||||
ENOPROTOOPT = 42, /* Protocol not available */
|
||||
EPROTONOSUPPORT = 43, /* Protocol not supported */
|
||||
ESOCKTNOSUPPORT = 44, /* Socket type not supported */
|
||||
EOPNOTSUPP = 45, /* Operation not supported */
|
||||
EPFNOSUPPORT = 46, /* Protocol family not supported */
|
||||
EAFNOSUPPORT = 47, /* Address family not supported by protocol family */
|
||||
EADDRINUSE = 48, /* Address already in use */
|
||||
EADDRNOTAVAIL = 49, /* Can't assign requested address */
|
||||
ENETDOWN = 50, /* Network is down */
|
||||
ENETUNREACH = 51, /* Network is unreachable */
|
||||
ENETRESET = 52, /* Network dropped connection on reset */
|
||||
ECONNABORTED = 53, /* Software caused connection abort */
|
||||
ECONNRESET = 54, /* Connection reset by peer */
|
||||
ENOBUFS = 55, /* No buffer space available */
|
||||
EISCONN = 56, /* Socket is already connected */
|
||||
ENOTCONN = 57, /* Socket is not connected */
|
||||
ESHUTDOWN = 58, /* Can't send after socket shutdown */
|
||||
ETOOMANYREFS = 59, /* Too many references: can't splice */
|
||||
ETIMEDOUT = 60, /* Operation timed out */
|
||||
ECONNREFUSED = 61 /* Connection refused */
|
||||
}
|
||||
|
||||
class SocketBsd
|
||||
{
|
||||
public int Family;
|
||||
public int Type;
|
||||
public int Protocol;
|
||||
public IPAddress IpAddress;
|
||||
public IPEndPoint RemoteEP;
|
||||
public Socket Handle;
|
||||
}
|
||||
|
||||
class ServiceBsd : IpcService
|
||||
class IClient : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private List<SocketBsd> Sockets = new List<SocketBsd>();
|
||||
private List<BsdSocket> Sockets = new List<BsdSocket>();
|
||||
|
||||
public ServiceBsd()
|
||||
public IClient()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -95,11 +53,6 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
} BsdBufferConfig;
|
||||
*/
|
||||
|
||||
long Pid = Context.RequestData.ReadInt64();
|
||||
long TransferMemorySize = Context.RequestData.ReadInt64();
|
||||
|
||||
// Two other args are unknown!
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
//Todo: Stub
|
||||
|
@ -118,18 +71,18 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 domain, u32 type, u32 protocol) -> (i32 ret, u32 bsd_errno)
|
||||
public long Socket(ServiceCtx Context)
|
||||
{
|
||||
SocketBsd NewBSDSocket = new SocketBsd
|
||||
BsdSocket NewBsdSocket = new BsdSocket
|
||||
{
|
||||
Family = Context.RequestData.ReadInt32(),
|
||||
Type = Context.RequestData.ReadInt32(),
|
||||
Protocol = Context.RequestData.ReadInt32()
|
||||
};
|
||||
|
||||
Sockets.Add(NewBSDSocket);
|
||||
Sockets.Add(NewBsdSocket);
|
||||
|
||||
Sockets[Sockets.Count - 1].Handle = new Socket((AddressFamily)Sockets[Sockets.Count - 1].Family,
|
||||
(SocketType)Sockets[Sockets.Count - 1].Type,
|
||||
(ProtocolType)Sockets[Sockets.Count - 1].Protocol);
|
||||
NewBsdSocket.Handle = new Socket((AddressFamily)NewBsdSocket.Family,
|
||||
(SocketType)NewBsdSocket.Type,
|
||||
(ProtocolType)NewBsdSocket.Protocol);
|
||||
|
||||
Context.ResponseData.Write(Sockets.Count - 1);
|
||||
Context.ResponseData.Write(0);
|
||||
|
@ -149,12 +102,13 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//https://github.com/TuxSH/ftpd/blob/switch_pr/source/ftp.c#L1634
|
||||
//https://linux.die.net/man/2/poll
|
||||
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
int SocketId = Get32(SentBuffer, 0);
|
||||
short RequestedEvents = (short)Get16(SentBuffer, 4);
|
||||
short ReturnedEvents = (short)Get16(SentBuffer, 6);
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
int SocketId = Get32(SentBuffer, 0);
|
||||
int RequestedEvents = Get16(SentBuffer, 4);
|
||||
int ReturnedEvents = Get16(SentBuffer, 6);
|
||||
|
||||
//Todo: Stub - Need to implemented the Type-22 buffer.
|
||||
|
||||
|
@ -167,18 +121,20 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 socket, u32 flags) -> (i32 ret, u32 bsd_errno, buffer<i8, 0x22, 0> message)
|
||||
public long Recv(ServiceCtx Context)
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size];
|
||||
|
||||
try
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
byte[] ReceivedBuffer = new byte[Context.Request.ReceiveBuff[0].Size];
|
||||
int ReadedBytes = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
|
||||
int BytesRead = Sockets[SocketId].Handle.Receive(ReceivedBuffer);
|
||||
|
||||
//Logging.Debug("Received Buffer:" + Environment.NewLine + Logging.HexDump(ReceivedBuffer));
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Context.Request.ReceiveBuff[0].Position, ReceivedBuffer);
|
||||
|
||||
Context.ResponseData.Write(ReadedBytes);
|
||||
Context.ResponseData.Write(BytesRead);
|
||||
Context.ResponseData.Write(0);
|
||||
}
|
||||
catch (SocketException Ex)
|
||||
|
@ -193,15 +149,16 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 socket, u32 flags, buffer<i8, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
|
||||
public long Send(ServiceCtx Context)
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
{
|
||||
//Logging.Debug("Sended Buffer:" + Environment.NewLine + Logging.HexDump(SendedBuffer));
|
||||
//Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer));
|
||||
|
||||
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
||||
|
||||
|
@ -220,13 +177,15 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 socket, u32 flags, buffer<i8, 0x21, 0>, buffer<sockaddr, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
|
||||
public long SendTo(ServiceCtx Context)
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[1].Position,
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketFlags = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] SentBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[1].Position,
|
||||
Context.Request.SendBuff[1].Size);
|
||||
|
||||
if (!Sockets[SocketId].Handle.Connected)
|
||||
|
@ -246,7 +205,7 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
|
||||
try
|
||||
{
|
||||
//Logging.Debug("Sended Buffer:" + Environment.NewLine + Logging.HexDump(SendedBuffer));
|
||||
//Logging.Debug("Sent Buffer:" + Environment.NewLine + Logging.HexDump(SentBuffer));
|
||||
|
||||
int BytesSent = Sockets[SocketId].Handle.Send(SentBuffer);
|
||||
|
||||
|
@ -265,12 +224,13 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 socket) -> (i32 ret, u32 bsd_errno, u32 addrlen, buffer<sockaddr, 0x22, 0> addr)
|
||||
public long Accept(ServiceCtx Context)
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
|
||||
long AddrBufferPtr = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
Socket HandleAccept = null;
|
||||
|
||||
var TimeOut = Task.Factory.StartNew(() =>
|
||||
Task TimeOut = Task.Factory.StartNew(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -287,28 +247,28 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
|
||||
if (HandleAccept != null)
|
||||
{
|
||||
SocketBsd NewBSDSocket = new SocketBsd
|
||||
BsdSocket NewBsdSocket = new BsdSocket
|
||||
{
|
||||
IpAddress = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint).Address,
|
||||
RemoteEP = ((IPEndPoint)Sockets[SocketId].Handle.LocalEndPoint),
|
||||
Handle = HandleAccept
|
||||
};
|
||||
|
||||
Sockets.Add(NewBSDSocket);
|
||||
Sockets.Add(NewBsdSocket);
|
||||
|
||||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
Writer.Write((byte)0);
|
||||
Writer.Write((byte)Sockets[Sockets.Count - 1].Handle.AddressFamily);
|
||||
Writer.Write((Int16)((IPEndPoint)Sockets[Sockets.Count - 1].Handle.LocalEndPoint).Port);
|
||||
|
||||
string[] IpAdress = Sockets[Sockets.Count - 1].IpAddress.ToString().Split('.');
|
||||
Writer.Write(byte.Parse(IpAdress[0]));
|
||||
Writer.Write(byte.Parse(IpAdress[1]));
|
||||
Writer.Write(byte.Parse(IpAdress[2]));
|
||||
Writer.Write(byte.Parse(IpAdress[3]));
|
||||
Writer.Write((byte)NewBsdSocket.Handle.AddressFamily);
|
||||
|
||||
Writer.Write((short)((IPEndPoint)NewBsdSocket.Handle.LocalEndPoint).Port);
|
||||
|
||||
byte[] IpAddress = NewBsdSocket.IpAddress.GetAddressBytes();
|
||||
|
||||
Writer.Write(IpAddress);
|
||||
|
||||
AMemoryHelper.WriteBytes(Context.Memory, AddrBufferPtr, MS.ToArray());
|
||||
|
||||
|
@ -320,7 +280,7 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
else
|
||||
{
|
||||
Context.ResponseData.Write(-1);
|
||||
Context.ResponseData.Write((int)BsdError.ETIMEDOUT);
|
||||
Context.ResponseData.Write((int)BsdError.Timeout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -331,8 +291,8 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
|
@ -356,8 +316,8 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
byte[] AddressBuffer = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.SendBuff[0].Position,
|
||||
Context.Request.SendBuff[0].Size);
|
||||
|
||||
try
|
||||
|
@ -404,19 +364,20 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
//(u32 socket, u32 level, u32 option_name, buffer<unknown, 0x21, 0>) -> (i32 ret, u32 bsd_errno)
|
||||
public long SetSockOpt(ServiceCtx Context)
|
||||
{
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
int SocketLevel = Context.RequestData.ReadInt32();
|
||||
int SocketOptionName = Context.RequestData.ReadInt32();
|
||||
int SocketId = Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] SocketOptionValue = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.PtrBuff[0].Position,
|
||||
SocketOptionLevel SocketLevel = (SocketOptionLevel)Context.RequestData.ReadInt32();
|
||||
SocketOptionName SocketOptionName = (SocketOptionName)Context.RequestData.ReadInt32();
|
||||
|
||||
byte[] SocketOptionValue = AMemoryHelper.ReadBytes(Context.Memory,
|
||||
Context.Request.PtrBuff[0].Position,
|
||||
Context.Request.PtrBuff[0].Size);
|
||||
|
||||
int OptionValue = Get32(SocketOptionValue, 0);
|
||||
|
||||
try
|
||||
{
|
||||
Sockets[SocketId].Handle.SetSocketOption((SocketOptionLevel)SocketLevel,
|
||||
(SocketOptionName)SocketOptionName,
|
||||
Get32(SocketOptionValue, 0));
|
||||
Sockets[SocketId].Handle.SetSocketOption(SocketLevel, SocketOptionName, OptionValue);
|
||||
|
||||
Context.ResponseData.Write(0);
|
||||
Context.ResponseData.Write(0);
|
||||
|
@ -461,12 +422,13 @@ namespace Ryujinx.Core.OsHle.Services.Bsd
|
|||
int Size = Reader.ReadByte();
|
||||
int Family = Reader.ReadByte();
|
||||
int Port = EndianSwap.Swap16(Reader.ReadInt16());
|
||||
string IpAddress = Reader.ReadByte().ToString() +
|
||||
"." + Reader.ReadByte().ToString() +
|
||||
"." + Reader.ReadByte().ToString() +
|
||||
"." + Reader.ReadByte().ToString();
|
||||
|
||||
Logging.Debug($"Try to connect to {IpAddress}:{Port}");
|
||||
string IpAddress = Reader.ReadByte().ToString() + "." +
|
||||
Reader.ReadByte().ToString() + "." +
|
||||
Reader.ReadByte().ToString() + "." +
|
||||
Reader.ReadByte().ToString();
|
||||
|
||||
Logging.Debug(LogClass.ServiceBsd, $"Try to connect to {IpAddress}:{Port}");
|
||||
|
||||
Sockets[SocketId].IpAddress = IPAddress.Parse(IpAddress);
|
||||
Sockets[SocketId].RemoteEP = new IPEndPoint(Sockets[SocketId].IpAddress, Port);
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Friend
|
||||
{
|
||||
class ServiceFriend : IpcService
|
||||
class IServiceCreator : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceFriend()
|
||||
public IServiceCreator()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -3,38 +3,38 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.FspSrv
|
||||
{
|
||||
class ServiceFspSrv : IpcService
|
||||
class IFileSystemProxy : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceFspSrv()
|
||||
public IFileSystemProxy()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, Initialize },
|
||||
{ 18, MountSdCard },
|
||||
{ 51, MountSaveData },
|
||||
{ 200, OpenDataStorageByCurrentProcess },
|
||||
{ 203, OpenRomStorage },
|
||||
{ 1005, GetGlobalAccessLogMode }
|
||||
{ 1, SetCurrentProcess },
|
||||
{ 18, OpenSdCardFileSystem },
|
||||
{ 51, OpenSaveDataFileSystem },
|
||||
{ 200, OpenDataStorageByCurrentProcess },
|
||||
{ 203, OpenPatchDataStorageByCurrentProcess },
|
||||
{ 1005, GetGlobalAccessLogMode }
|
||||
};
|
||||
}
|
||||
|
||||
public long Initialize(ServiceCtx Context)
|
||||
public long SetCurrentProcess(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long MountSdCard(ServiceCtx Context)
|
||||
public long OpenSdCardFileSystem(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetSdCardPath()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long MountSaveData(ServiceCtx Context)
|
||||
public long OpenSaveDataFileSystem(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IFileSystem(Context.Ns.VFs.GetGameSavesPath()));
|
||||
|
||||
|
@ -48,7 +48,7 @@ namespace Ryujinx.Core.OsHle.Services.FspSrv
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long OpenRomStorage(ServiceCtx Context)
|
||||
public long OpenPatchDataStorageByCurrentProcess(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IStorage(Context.Ns.VFs.RomFs));
|
||||
|
||||
|
@ -60,6 +60,6 @@ namespace Ryujinx.Core.OsHle.Services.FspSrv
|
|||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,29 +4,37 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Hid
|
||||
{
|
||||
class ServiceHid : IpcService
|
||||
class IHidServer : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceHid()
|
||||
public IHidServer()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CreateAppletResource },
|
||||
{ 1, ActivateDebugPad },
|
||||
{ 11, ActivateTouchScreen },
|
||||
{ 21, ActivateMouse },
|
||||
{ 31, ActivateKeyboard },
|
||||
{ 66, StartSixAxisSensor },
|
||||
{ 79, SetGyroscopeZeroDriftMode },
|
||||
{ 100, SetSupportedNpadStyleSet },
|
||||
{ 101, GetSupportedNpadStyleSet },
|
||||
{ 102, SetSupportedNpadIdType },
|
||||
{ 103, ActivateNpad },
|
||||
{ 108, GetPlayerLedPattern },
|
||||
{ 120, SetNpadJoyHoldType },
|
||||
{ 121, GetNpadJoyHoldType },
|
||||
{ 122, SetNpadJoyAssignmentModeSingleByDefault },
|
||||
{ 123, SetNpadJoyAssignmentModeSingle },
|
||||
{ 124, SetNpadJoyAssignmentModeDual },
|
||||
{ 125, MergeSingleJoyAsDualJoy },
|
||||
{ 128, SetNpadHandheldActivationMode },
|
||||
{ 200, GetVibrationDeviceInfo },
|
||||
{ 201, SendVibrationValue },
|
||||
{ 203, CreateActiveVibrationDeviceList },
|
||||
{ 206, SendVibrationValues }
|
||||
};
|
||||
|
@ -39,9 +47,36 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long ActivateDebugPad(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ActivateTouchScreen(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ActivateMouse(ServiceCtx Context)
|
||||
{
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long ActivateKeyboard(ServiceCtx Context)
|
||||
{
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -52,6 +87,19 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetGyroscopeZeroDriftMode(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.RequestData.ReadInt32();
|
||||
int Unknown = Context.RequestData.ReadInt32();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -59,6 +107,8 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -67,6 +117,8 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
long Unknown8 = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -74,6 +126,8 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -81,6 +135,19 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPlayerLedPattern(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -89,6 +156,8 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
long Unknown8 = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -96,13 +165,17 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetNpadJoyAssignmentModeSingleByDefault(ServiceCtx Context)
|
||||
{
|
||||
HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32();
|
||||
long AppletUserResourseId = Context.RequestData.ReadInt64();
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,16 +183,20 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
public long SetNpadJoyAssignmentModeSingle(ServiceCtx Context)
|
||||
{
|
||||
HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32();
|
||||
long AppletUserResourseId = Context.RequestData.ReadInt64();
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
long NpadJoyDeviceType = Context.RequestData.ReadInt64();
|
||||
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetNpadJoyAssignmentModeDual(ServiceCtx Context)
|
||||
{
|
||||
HidControllerId HidControllerId = (HidControllerId)Context.RequestData.ReadInt32();
|
||||
long AppletUserResourseId = Context.RequestData.ReadInt64();
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -128,7 +205,19 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
long Unknown0 = Context.RequestData.ReadInt32();
|
||||
long Unknown8 = Context.RequestData.ReadInt32();
|
||||
long AppletUserResourseId = Context.RequestData.ReadInt64();
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SetNpadHandheldActivationMode(ServiceCtx Context)
|
||||
{
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -137,11 +226,29 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
{
|
||||
int VibrationDeviceHandle = Context.RequestData.ReadInt32();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, $"VibrationDeviceHandle = {VibrationDeviceHandle}, VibrationDeviceInfo = 0");
|
||||
|
||||
Context.ResponseData.Write(0L); //VibrationDeviceInfoForIpc
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long SendVibrationValue(ServiceCtx Context)
|
||||
{
|
||||
int VibrationDeviceHandle = Context.RequestData.ReadInt32();
|
||||
|
||||
int VibrationValue1 = Context.RequestData.ReadInt32();
|
||||
int VibrationValue2 = Context.RequestData.ReadInt32();
|
||||
int VibrationValue3 = Context.RequestData.ReadInt32();
|
||||
int VibrationValue4 = Context.RequestData.ReadInt32();
|
||||
|
||||
long AppletUserResourceId = Context.RequestData.ReadInt64();
|
||||
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long CreateActiveVibrationDeviceList(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IActiveApplicationDeviceList());
|
||||
|
@ -151,7 +258,9 @@ namespace Ryujinx.Core.OsHle.Services.Hid
|
|||
|
||||
public long SendVibrationValues(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceHid, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.Core.OsHle.Services
|
|||
|
||||
private int SelfId;
|
||||
|
||||
private bool IsDomain;
|
||||
private bool IsDomain;
|
||||
|
||||
public IpcService()
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace Ryujinx.Core.OsHle.Services
|
|||
{
|
||||
Context.ResponseData.BaseStream.Seek(IsDomain ? 0x20 : 0x10, SeekOrigin.Begin);
|
||||
|
||||
Logging.Trace($"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
|
||||
Logging.Trace(LogClass.KernelIpc, $"{Service.GetType().Name}: {ProcessRequest.Method.Name}");
|
||||
|
||||
long Result = ProcessRequest(Context);
|
||||
|
||||
|
@ -104,7 +104,9 @@ namespace Ryujinx.Core.OsHle.Services
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"{Service.GetType().Name}: {CommandId}");
|
||||
string DbgMessage = $"{Context.Session.ServiceName} {Service.GetType().Name}: {CommandId}";
|
||||
|
||||
throw new NotImplementedException(DbgMessage);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,7 +120,7 @@ namespace Ryujinx.Core.OsHle.Services
|
|||
}
|
||||
else
|
||||
{
|
||||
KSession Session = new KSession(Obj);
|
||||
KSession Session = new KSession(Obj, Context.Session.ServiceName);
|
||||
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(Session);
|
||||
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Lm
|
||||
{
|
||||
class ServiceLm : IpcService
|
||||
class ILogService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceLm()
|
||||
public ILogService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -129,11 +129,11 @@ namespace Ryujinx.Core.OsHle.Services.Lm
|
|||
|
||||
switch((Severity)iSeverity)
|
||||
{
|
||||
case Severity.Trace: Logging.Trace(LogString); break;
|
||||
case Severity.Info: Logging.Info(LogString); break;
|
||||
case Severity.Warning: Logging.Warn(LogString); break;
|
||||
case Severity.Error: Logging.Error(LogString); break;
|
||||
case Severity.Critical: Logging.Fatal(LogString); break;
|
||||
case Severity.Trace: Logging.Trace(LogClass.ServiceLm, LogString); break;
|
||||
case Severity.Info: Logging.Info(LogClass.ServiceLm, LogString); break;
|
||||
case Severity.Warning: Logging.Warn(LogClass.ServiceLm, LogString); break;
|
||||
case Severity.Error: Logging.Error(LogClass.ServiceLm, LogString); break;
|
||||
case Severity.Critical: Logging.Fatal(LogClass.ServiceLm, LogString); break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
|||
|
||||
MakeObject(Context, new IRequest());
|
||||
|
||||
//Todo: Stub
|
||||
Logging.Stub(LogClass.ServiceNifm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,9 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
|||
{
|
||||
{ 0, GetRequestState },
|
||||
{ 1, GetResult },
|
||||
{ 2, GetSystemEventReadableHandles }
|
||||
{ 2, GetSystemEventReadableHandles },
|
||||
{ 3, Cancel },
|
||||
{ 4, Submit },
|
||||
};
|
||||
|
||||
Event = new KEvent();
|
||||
|
@ -29,14 +31,14 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
|||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
//Todo: Stub
|
||||
Logging.Stub(LogClass.ServiceNifm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetResult(ServiceCtx Context)
|
||||
{
|
||||
//Todo: Stub
|
||||
Logging.Stub(LogClass.ServiceNifm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -52,6 +54,20 @@ namespace Ryujinx.Core.OsHle.Services.Nifm
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long Cancel(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceNifm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Submit(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceNifm, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
|
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Nifm
|
||||
{
|
||||
class ServiceNifm : IpcService
|
||||
class IStaticService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceNifm()
|
||||
public IStaticService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
41
Ryujinx.Core/OsHle/Services/Ns/IAddOnContentManager.cs
Normal file
41
Ryujinx.Core/OsHle/Services/Ns/IAddOnContentManager.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Ns
|
||||
{
|
||||
class IAddOnContentManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IAddOnContentManager()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 2, CountAddOnContent },
|
||||
{ 3, ListAddOnContent }
|
||||
};
|
||||
}
|
||||
|
||||
public static long CountAddOnContent(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logging.Stub(LogClass.ServiceNs, "Stubbed");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long ListAddOnContent(ServiceCtx Context)
|
||||
{
|
||||
Logging.Stub(LogClass.ServiceNs, "Stubbed");
|
||||
|
||||
//TODO: This is supposed to write a u32 array aswell.
|
||||
//It's unknown what it contains.
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Ns
|
||||
{
|
||||
class ServiceNs : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceNs()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//{ 1, Function }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,10 +5,11 @@ using Ryujinx.Core.OsHle.Utilities;
|
|||
using Ryujinx.Graphics.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Nv
|
||||
{
|
||||
class ServiceNvDrv : IpcService, IDisposable
|
||||
class INvDrvServices : IpcService, IDisposable
|
||||
{
|
||||
private delegate long ServiceProcessIoctl(ServiceCtx Context);
|
||||
|
||||
|
@ -26,7 +27,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
private KEvent Event;
|
||||
|
||||
public ServiceNvDrv()
|
||||
public INvDrvServices()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -45,10 +46,12 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
{ ("/dev/nvhost-as-gpu", 0x4106), NvGpuAsIoctlMapBufferEx },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4108), NvGpuAsIoctlGetVaRegions },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4109), NvGpuAsIoctlInitializeEx },
|
||||
{ ("/dev/nvhost-as-gpu", 0x4114), NvGpuAsIoctlRemap },
|
||||
{ ("/dev/nvhost-ctrl", 0x001b), NvHostIoctlCtrlGetConfig },
|
||||
{ ("/dev/nvhost-ctrl", 0x001d), NvHostIoctlCtrlEventWait },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4701), NvGpuIoctlZcullGetCtxSize },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4702), NvGpuIoctlZcullGetInfo },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4703), NvGpuIoctlZbcSetTable },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4705), NvGpuIoctlGetCharacteristics },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4706), NvGpuIoctlGetTpcMasks },
|
||||
{ ("/dev/nvhost-ctrl-gpu", 0x4714), NvGpuIoctlZbcGetActiveSlotMask },
|
||||
|
@ -71,7 +74,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
Event = new KEvent();
|
||||
}
|
||||
|
||||
static ServiceNvDrv()
|
||||
static INvDrvServices()
|
||||
{
|
||||
Fds = new GlobalStateTable();
|
||||
|
||||
|
@ -98,7 +101,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
{
|
||||
int Fd = Context.RequestData.ReadInt32();
|
||||
int Cmd = Context.RequestData.ReadInt32() & 0xffff;
|
||||
|
||||
|
||||
NvFd FdData = Fds.GetData<NvFd>(Context.Process, Fd);
|
||||
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
@ -206,7 +209,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
int Flags = Reader.ReadInt32();
|
||||
int Kind = Reader.ReadInt32();
|
||||
int Handle = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
int PageSize = Reader.ReadInt32();
|
||||
long BuffAddr = Reader.ReadInt64();
|
||||
long MapSize = Reader.ReadInt64();
|
||||
long Offset = Reader.ReadInt64();
|
||||
|
@ -225,8 +228,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -241,6 +244,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
Context.Memory.WriteInt64(Position + 0x20, Offset);
|
||||
|
||||
Map.GpuAddress = Offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -291,6 +296,35 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
return 0;
|
||||
}
|
||||
|
||||
private long NvGpuAsIoctlRemap(ServiceCtx Context)
|
||||
{
|
||||
Context.RequestData.BaseStream.Seek(-4, SeekOrigin.Current);
|
||||
|
||||
int Cmd = Context.RequestData.ReadInt32();
|
||||
|
||||
int Size = (Cmd >> 16) & 0xff;
|
||||
|
||||
int Count = Size / 0x18;
|
||||
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
int Flags = Reader.ReadInt32();
|
||||
int Kind = Reader.ReadInt32();
|
||||
int Handle = Reader.ReadInt32();
|
||||
int Padding = Reader.ReadInt32();
|
||||
int Offset = Reader.ReadInt32();
|
||||
int Pages = Reader.ReadInt32();
|
||||
}
|
||||
|
||||
//TODO
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long NvHostIoctlCtrlGetConfig(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
@ -351,6 +385,32 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
return 0;
|
||||
}
|
||||
|
||||
private long NvGpuIoctlZbcSetTable(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
||||
MemReader Reader = new MemReader(Context.Memory, Position);
|
||||
|
||||
int[] ColorDs = new int[4];
|
||||
int[] ColorL2 = new int[4];
|
||||
|
||||
ColorDs[0] = Reader.ReadInt32();
|
||||
ColorDs[1] = Reader.ReadInt32();
|
||||
ColorDs[2] = Reader.ReadInt32();
|
||||
ColorDs[3] = Reader.ReadInt32();
|
||||
|
||||
ColorL2[0] = Reader.ReadInt32();
|
||||
ColorL2[1] = Reader.ReadInt32();
|
||||
ColorL2[2] = Reader.ReadInt32();
|
||||
ColorL2[3] = Reader.ReadInt32();
|
||||
|
||||
int Depth = Reader.ReadInt32();
|
||||
int Format = Reader.ReadInt32();
|
||||
int Type = Reader.ReadInt32();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long NvGpuIoctlGetCharacteristics(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.GetSendBuffPtr();
|
||||
|
@ -480,9 +540,9 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
{
|
||||
byte[] Data = AMemoryHelper.ReadBytes(Context.Memory, CpuAddr, Size);
|
||||
|
||||
NsGpuPBEntry[] PushBuffer = NsGpuPBEntry.DecodePushBuffer(Data);
|
||||
NsGpuPBEntry[] PushBuffer = NvGpuPushBuffer.Decode(Data);
|
||||
|
||||
Context.Ns.Gpu.ProcessPushBuffer(PushBuffer, Context.Memory);
|
||||
Context.Ns.Gpu.Fifo.PushBuffer(Context.Memory, PushBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,7 +634,7 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
Context.Memory.WriteInt32(Position + 4, Map.Handle);
|
||||
|
||||
Logging.Info($"NvMap {Map.Id} created with size {Size:x8}!");
|
||||
Logging.Info(LogClass.ServiceNv, $"NvMap {Map.Id} created with size {Size:x8}!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -589,8 +649,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Id {Id}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Id {Id}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -616,14 +676,14 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
Map.CpuAddress = Addr;
|
||||
Map.Align = Align;
|
||||
Map.Kind = Kind;
|
||||
Map.Align = Align;
|
||||
Map.Kind = Kind;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -642,8 +702,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -667,8 +727,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
||||
|
@ -697,8 +757,8 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
|
||||
if (Map == null)
|
||||
{
|
||||
Logging.Warn($"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
Logging.Warn(LogClass.ServiceNv, $"Trying to use invalid NvMap Handle {Handle}!");
|
||||
|
||||
return -1; //TODO: Corrent error code.
|
||||
}
|
||||
|
|
@ -8,5 +8,6 @@ namespace Ryujinx.Core.OsHle.Services.Nv
|
|||
public int Align;
|
||||
public int Kind;
|
||||
public long CpuAddress;
|
||||
public long GpuAddress;
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Pctl
|
||||
{
|
||||
class ServicePctl : IpcService
|
||||
class IParentalControlServiceFactory : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServicePctl()
|
||||
public IParentalControlServiceFactory()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Pl
|
||||
{
|
||||
class ServicePl : IpcService
|
||||
class ISharedFontManager : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServicePl()
|
||||
public ISharedFontManager()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -7,7 +7,6 @@ using Ryujinx.Core.OsHle.Services.Friend;
|
|||
using Ryujinx.Core.OsHle.Services.FspSrv;
|
||||
using Ryujinx.Core.OsHle.Services.Hid;
|
||||
using Ryujinx.Core.OsHle.Services.Lm;
|
||||
using Ryujinx.Core.OsHle.Services.Nifm;
|
||||
using Ryujinx.Core.OsHle.Services.Ns;
|
||||
using Ryujinx.Core.OsHle.Services.Nv;
|
||||
using Ryujinx.Core.OsHle.Services.Pctl;
|
||||
|
@ -16,7 +15,6 @@ using Ryujinx.Core.OsHle.Services.Set;
|
|||
using Ryujinx.Core.OsHle.Services.Sfdnsres;
|
||||
using Ryujinx.Core.OsHle.Services.Sm;
|
||||
using Ryujinx.Core.OsHle.Services.Ssl;
|
||||
using Ryujinx.Core.OsHle.Services.Time;
|
||||
using Ryujinx.Core.OsHle.Services.Vi;
|
||||
using System;
|
||||
|
||||
|
@ -29,88 +27,88 @@ namespace Ryujinx.Core.OsHle.Services
|
|||
switch (Name)
|
||||
{
|
||||
case "acc:u0":
|
||||
return new ServiceAcc();
|
||||
return new IAccountServiceForApplication();
|
||||
|
||||
case "aoc:u":
|
||||
return new ServiceNs();
|
||||
return new IAddOnContentManager();
|
||||
|
||||
case "apm":
|
||||
return new ServiceApm();
|
||||
return new IManager();
|
||||
|
||||
case "apm:p":
|
||||
return new ServiceApm();
|
||||
return new IManager();
|
||||
|
||||
case "appletOE":
|
||||
return new ServiceAppletOE();
|
||||
return new IApplicationProxyService();
|
||||
|
||||
case "audout:u":
|
||||
return new ServiceAudOut();
|
||||
return new IAudioOutManager();
|
||||
|
||||
case "audren:u":
|
||||
return new ServiceAudRen();
|
||||
return new IAudioRendererManager();
|
||||
|
||||
case "bsd:s":
|
||||
return new ServiceBsd();
|
||||
return new IClient();
|
||||
|
||||
case "bsd:u":
|
||||
return new ServiceBsd();
|
||||
return new IClient();
|
||||
|
||||
case "friend:a":
|
||||
return new ServiceFriend();
|
||||
return new IServiceCreator();
|
||||
|
||||
case "fsp-srv":
|
||||
return new ServiceFspSrv();
|
||||
return new IFileSystemProxy();
|
||||
|
||||
case "hid":
|
||||
return new ServiceHid();
|
||||
return new IHidServer();
|
||||
|
||||
case "lm":
|
||||
return new ServiceLm();
|
||||
return new ILogService();
|
||||
|
||||
case "nifm:u":
|
||||
return new ServiceNifm();
|
||||
return new Nifm.IStaticService();
|
||||
|
||||
case "nvdrv":
|
||||
return new ServiceNvDrv();
|
||||
return new INvDrvServices();
|
||||
|
||||
case "nvdrv:a":
|
||||
return new ServiceNvDrv();
|
||||
return new INvDrvServices();
|
||||
|
||||
case "pctl:a":
|
||||
return new ServicePctl();
|
||||
return new IParentalControlServiceFactory();
|
||||
|
||||
case "pl:u":
|
||||
return new ServicePl();
|
||||
return new ISharedFontManager();
|
||||
|
||||
case "set":
|
||||
return new ServiceSet();
|
||||
return new ISettingsServer();
|
||||
|
||||
case "set:sys":
|
||||
return new ServiceSetSys();
|
||||
return new ISystemSettingsServer();
|
||||
|
||||
case "sfdnsres":
|
||||
return new ServiceSfdnsres();
|
||||
return new IResolver();
|
||||
|
||||
case "sm:":
|
||||
return new ServiceSm();
|
||||
return new IUserInterface();
|
||||
|
||||
case "ssl":
|
||||
return new ServiceSsl();
|
||||
return new ISslService();
|
||||
|
||||
case "time:s":
|
||||
return new ServiceTime();
|
||||
return new Time.IStaticService();
|
||||
|
||||
case "time:u":
|
||||
return new ServiceTime();
|
||||
return new Time.IStaticService();
|
||||
|
||||
case "vi:m":
|
||||
return new ServiceVi();
|
||||
return new IManagerRootService();
|
||||
|
||||
case "vi:s":
|
||||
return new ServiceVi();
|
||||
return new ISystemRootService();
|
||||
|
||||
case "vi:u":
|
||||
return new ServiceVi();
|
||||
return new IApplicationRootService();
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Name);
|
||||
|
|
81
Ryujinx.Core/OsHle/Services/Set/ISettingsServer.cs
Normal file
81
Ryujinx.Core/OsHle/Services/Set/ISettingsServer.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Set
|
||||
{
|
||||
class ISettingsServer : IpcService
|
||||
{
|
||||
private static string[] LanguageCodes = new string[]
|
||||
{
|
||||
"ja",
|
||||
"en-US",
|
||||
"fr",
|
||||
"de",
|
||||
"it",
|
||||
"es",
|
||||
"zh-CN",
|
||||
"ko",
|
||||
"nl",
|
||||
"pt",
|
||||
"ru",
|
||||
"zh-TW",
|
||||
"en-GB",
|
||||
"fr-CA",
|
||||
"es-419",
|
||||
"zh-Hans",
|
||||
"zh-Hant"
|
||||
};
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISettingsServer()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, GetAvailableLanguageCodes },
|
||||
{ 3, GetAvailableLanguageCodeCount }
|
||||
};
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguageCodes(ServiceCtx Context)
|
||||
{
|
||||
long Position = Context.Request.RecvListBuff[0].Position;
|
||||
short Size = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
int Count = (int)((uint)Size / 8);
|
||||
|
||||
if (Count > LanguageCodes.Length)
|
||||
{
|
||||
Count = LanguageCodes.Length;
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
string LanguageCode = LanguageCodes[Index];
|
||||
|
||||
foreach (char Chr in LanguageCode)
|
||||
{
|
||||
Context.Memory.WriteByte(Position++, (byte)Chr);
|
||||
}
|
||||
|
||||
for (int Offs = 0; Offs < (8 - LanguageCode.Length); Offs++)
|
||||
{
|
||||
Context.Memory.WriteByte(Position++, 0);
|
||||
}
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(Count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long GetAvailableLanguageCodeCount(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(LanguageCodes.Length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,16 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using Ryujinx.Core.Settings;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Set
|
||||
{
|
||||
class ServiceSetSys : IpcService
|
||||
class ISystemSettingsServer : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceSetSys()
|
||||
public ISystemSettingsServer()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -26,7 +27,10 @@ namespace Ryujinx.Core.OsHle.Services.Set
|
|||
}
|
||||
|
||||
public static long SetColorSetId(ServiceCtx Context)
|
||||
{
|
||||
{
|
||||
int ColorSetId = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.Ns.Settings.ThemeColor = (ColorSet)ColorSetId;
|
||||
return 0;
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Set
|
||||
{
|
||||
class ServiceSet : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceSet()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, GetAvailableLanguageCodes }
|
||||
};
|
||||
}
|
||||
|
||||
private const int LangCodesCount = 13;
|
||||
|
||||
public static long GetAvailableLanguageCodes(ServiceCtx Context)
|
||||
{
|
||||
int PtrBuffSize = Context.RequestData.ReadInt32();
|
||||
|
||||
if (Context.Request.RecvListBuff.Count > 0)
|
||||
{
|
||||
long Position = Context.Request.RecvListBuff[0].Position;
|
||||
short Size = Context.Request.RecvListBuff[0].Size;
|
||||
|
||||
//This should return an array of ints with values matching the LanguageCode enum.
|
||||
foreach (long value in new long[] { 0L, 1L, 2L, 3L, 4L, 5L, 6L, 7L })
|
||||
{
|
||||
AMemoryHelper.WriteBytes(Context.Memory, Position += 8, BitConverter.GetBytes(value));
|
||||
}
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(LangCodesCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,17 +3,17 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Sfdnsres
|
||||
{
|
||||
class ServiceSfdnsres : IpcService
|
||||
class IResolver : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceSfdnsres()
|
||||
public IResolver()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//{ 0, Function }
|
||||
//...
|
||||
};
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Sm
|
||||
{
|
||||
class ServiceSm : IpcService
|
||||
class IUserInterface : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace Ryujinx.Core.OsHle.Services.Sm
|
|||
|
||||
private bool IsInitialized;
|
||||
|
||||
public ServiceSm()
|
||||
public IUserInterface()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -57,7 +57,7 @@ namespace Ryujinx.Core.OsHle.Services.Sm
|
|||
return 0;
|
||||
}
|
||||
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(Name));
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(Name), Name);
|
||||
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(Session);
|
||||
|
|
@ -3,17 +3,17 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Ssl
|
||||
{
|
||||
class ServiceSsl : IpcService
|
||||
class ISslService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceSsl()
|
||||
public ISslService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
//{ 0, Function }
|
||||
//...
|
||||
};
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Time
|
||||
{
|
||||
class ServiceTime : IpcService
|
||||
class IStaticService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceTime()
|
||||
public IStaticService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle.Services.Time
|
|||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
private SystemClockType ClockType;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Core.OsHle.Services.Time
|
|||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private static DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Local);
|
||||
private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
|
||||
public ITimeZoneService()
|
||||
{
|
||||
|
@ -20,30 +20,18 @@ namespace Ryujinx.Core.OsHle.Services.Time
|
|||
};
|
||||
}
|
||||
|
||||
//(nn::time::PosixTime)-> (nn::time::CalendarTime, nn::time::sf::CalendarAdditionalInfo)
|
||||
public long ToCalendarTimeWithMyRule(ServiceCtx Context)
|
||||
{
|
||||
long PosixTime = Context.RequestData.ReadInt64();
|
||||
|
||||
Epoch = Epoch.AddSeconds(PosixTime).ToLocalTime();
|
||||
DateTime CurrentTime = Epoch.AddSeconds(PosixTime).ToLocalTime();
|
||||
|
||||
/*
|
||||
struct CalendarTime {
|
||||
u16_le year;
|
||||
u8 month; // Starts at 1
|
||||
u8 day; // Starts at 1
|
||||
u8 hour;
|
||||
u8 minute;
|
||||
u8 second;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
};
|
||||
*/
|
||||
Context.ResponseData.Write((short)Epoch.Year);
|
||||
Context.ResponseData.Write((byte)Epoch.Month);
|
||||
Context.ResponseData.Write((byte)Epoch.Day);
|
||||
Context.ResponseData.Write((byte)Epoch.Hour);
|
||||
Context.ResponseData.Write((byte)Epoch.Minute);
|
||||
Context.ResponseData.Write((byte)Epoch.Second);
|
||||
Context.ResponseData.Write((ushort)CurrentTime.Year);
|
||||
Context.ResponseData.Write((byte)CurrentTime.Month);
|
||||
Context.ResponseData.Write((byte)CurrentTime.Day);
|
||||
Context.ResponseData.Write((byte)CurrentTime.Hour);
|
||||
Context.ResponseData.Write((byte)CurrentTime.Minute);
|
||||
Context.ResponseData.Write((byte)CurrentTime.Second);
|
||||
Context.ResponseData.Write((byte)0);
|
||||
|
||||
/* Thanks to TuxSH
|
||||
|
@ -57,11 +45,16 @@ namespace Ryujinx.Core.OsHle.Services.Time
|
|||
};
|
||||
};
|
||||
*/
|
||||
Context.ResponseData.Write((int)Epoch.DayOfWeek);
|
||||
Context.ResponseData.Write(Epoch.DayOfYear);
|
||||
Context.ResponseData.Write((int)CurrentTime.DayOfWeek);
|
||||
|
||||
Context.ResponseData.Write(CurrentTime.DayOfYear);
|
||||
|
||||
//TODO: Find out the names used.
|
||||
Context.ResponseData.Write(new byte[8]);
|
||||
Context.ResponseData.Write(Convert.ToByte(Epoch.IsDaylightSavingTime()));
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Context.ResponseData.Write((byte)(CurrentTime.IsDaylightSavingTime() ? 1 : 0));
|
||||
|
||||
Context.ResponseData.Write((int)TimeZoneInfo.Local.GetUtcOffset(CurrentTime).TotalSeconds);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ namespace Ryujinx.Core.OsHle.Services.Vi
|
|||
{ 103, GetIndirectDisplayTransactionService },
|
||||
{ 1010, OpenDisplay },
|
||||
{ 1020, CloseDisplay },
|
||||
{ 1102, GetDisplayResolution },
|
||||
{ 2020, OpenLayer },
|
||||
{ 2021, CloseLayer },
|
||||
{ 2030, CreateStrayLayer },
|
||||
|
@ -84,6 +85,16 @@ namespace Ryujinx.Core.OsHle.Services.Vi
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long GetDisplayResolution(ServiceCtx Context)
|
||||
{
|
||||
long DisplayId = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.ResponseData.Write(1280);
|
||||
Context.ResponseData.Write(720);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long OpenLayer(ServiceCtx Context)
|
||||
{
|
||||
long LayerId = Context.RequestData.ReadInt64();
|
||||
|
|
29
Ryujinx.Core/OsHle/Services/Vi/IApplicationRootService.cs
Normal file
29
Ryujinx.Core/OsHle/Services/Vi/IApplicationRootService.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Vi
|
||||
{
|
||||
class IApplicationRootService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IApplicationRootService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetDisplayService }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetDisplayService(ServiceCtx Context)
|
||||
{
|
||||
int ServiceType = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(Context, new IApplicationDisplayService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Ryujinx.Core.OsHle.Services.Vi
|
||||
{
|
||||
class ServiceVi : IpcService
|
||||
class IManagerRootService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ServiceVi()
|
||||
public IManagerRootService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
|
@ -19,7 +19,7 @@ namespace Ryujinx.Core.OsHle.Services.Vi
|
|||
|
||||
public long GetDisplayService(ServiceCtx Context)
|
||||
{
|
||||
int Unknown = Context.RequestData.ReadInt32();
|
||||
int ServiceType = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(Context, new IApplicationDisplayService());
|
||||
|
|
@ -13,7 +13,8 @@ namespace Ryujinx.Core.OsHle.Services.Vi
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 2205, SetLayerZ }
|
||||
{ 2205, SetLayerZ },
|
||||
{ 2207, SetLayerVisibility }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -21,5 +22,10 @@ namespace Ryujinx.Core.OsHle.Services.Vi
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static long SetLayerVisibility(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
29
Ryujinx.Core/OsHle/Services/Vi/ISystemRootService.cs
Normal file
29
Ryujinx.Core/OsHle/Services/Vi/ISystemRootService.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
using Ryujinx.Core.OsHle.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Services.Vi
|
||||
{
|
||||
class ISystemRootService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public ISystemRootService()
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 1, GetDisplayService }
|
||||
};
|
||||
}
|
||||
|
||||
public long GetDisplayService(ServiceCtx Context)
|
||||
{
|
||||
int ServiceType = Context.RequestData.ReadInt32();
|
||||
|
||||
MakeObject(Context, new IApplicationDisplayService());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ using ChocolArm64.Memory;
|
|||
using Ryujinx.Core.OsHle.Handles;
|
||||
using Ryujinx.Core.OsHle.Services.Nv;
|
||||
using Ryujinx.Graphics.Gal;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -62,14 +63,8 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
private BufferEntry[] BufferQueue;
|
||||
|
||||
private ManualResetEvent WaitBufferFree;
|
||||
|
||||
private object RenderQueueLock;
|
||||
|
||||
private int RenderQueueCount;
|
||||
|
||||
private bool NvFlingerDisposed;
|
||||
|
||||
private bool KeepRunning;
|
||||
private bool Disposed;
|
||||
|
||||
public NvFlinger(IGalRenderer Renderer, KEvent ReleaseEvent)
|
||||
{
|
||||
|
@ -85,17 +80,13 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
{ ("android.gui.IGraphicBufferProducer", 0xb), GbpDisconnect },
|
||||
{ ("android.gui.IGraphicBufferProducer", 0xe), GbpPreallocBuffer }
|
||||
};
|
||||
|
||||
|
||||
this.Renderer = Renderer;
|
||||
this.ReleaseEvent = ReleaseEvent;
|
||||
|
||||
BufferQueue = new BufferEntry[0x40];
|
||||
|
||||
WaitBufferFree = new ManualResetEvent(false);
|
||||
|
||||
RenderQueueLock = new object();
|
||||
|
||||
KeepRunning = true;
|
||||
}
|
||||
|
||||
public long ProcessParcelRequest(ServiceCtx Context, byte[] ParcelData, int Code)
|
||||
|
@ -121,7 +112,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
if (Commands.TryGetValue((InterfaceName, Code), out ServiceProcessParcel ProcReq))
|
||||
{
|
||||
Logging.Debug($"{InterfaceName} {ProcReq.Method.Name}");
|
||||
Logging.Debug(LogClass.ServiceNv, $"{InterfaceName} {ProcReq.Method.Name}");
|
||||
|
||||
return ProcReq(Context, Reader);
|
||||
}
|
||||
|
@ -139,7 +130,7 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
using (MemoryStream MS = new MemoryStream())
|
||||
{
|
||||
BinaryWriter Writer = new BinaryWriter(MS);
|
||||
|
||||
|
||||
BufferEntry Entry = BufferQueue[Slot];
|
||||
|
||||
int BufferCount = 1; //?
|
||||
|
@ -243,13 +234,17 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
private long GbpPreallocBuffer(ServiceCtx Context, BinaryReader ParcelReader)
|
||||
{
|
||||
int Slot = ParcelReader.ReadInt32();
|
||||
|
||||
int BufferCount = ParcelReader.ReadInt32();
|
||||
long BufferSize = ParcelReader.ReadInt64();
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
int BufferCount = ParcelReader.ReadInt32();
|
||||
|
||||
BufferQueue[Slot].Data = new GbpBuffer(ParcelReader);
|
||||
if (BufferCount > 0)
|
||||
{
|
||||
long BufferSize = ParcelReader.ReadInt64();
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
BufferQueue[Slot].Data = new GbpBuffer(ParcelReader);
|
||||
}
|
||||
|
||||
return MakeReplyParcel(Context, 0);
|
||||
}
|
||||
|
@ -281,35 +276,24 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
return 0;
|
||||
}
|
||||
|
||||
private unsafe void SendFrameBuffer(ServiceCtx Context, int Slot)
|
||||
private void SendFrameBuffer(ServiceCtx Context, int Slot)
|
||||
{
|
||||
int FbWidth = BufferQueue[Slot].Data.Width;
|
||||
int FbHeight = BufferQueue[Slot].Data.Height;
|
||||
|
||||
long FbSize = (uint)FbWidth * FbHeight * 4;
|
||||
int FbWidth = 1280;
|
||||
int FbHeight = 720;
|
||||
|
||||
NvMap Map = GetNvMap(Context, Slot);
|
||||
|
||||
NvMapFb MapFb = (NvMapFb)ServiceNvDrv.NvMapsFb.GetData(Context.Process, 0);
|
||||
NvMapFb MapFb = (NvMapFb)INvDrvServices.NvMapsFb.GetData(Context.Process, 0);
|
||||
|
||||
long CpuAddr = Map.CpuAddress;
|
||||
long GpuAddr = Map.GpuAddress;
|
||||
|
||||
long Address = Map.CpuAddress;
|
||||
|
||||
if (MapFb.HasBufferOffset(Slot))
|
||||
{
|
||||
Address += MapFb.GetBufferOffset(Slot);
|
||||
}
|
||||
CpuAddr += MapFb.GetBufferOffset(Slot);
|
||||
|
||||
if ((ulong)(Address + FbSize) > AMemoryMgr.AddrSize)
|
||||
{
|
||||
Logging.Error($"Frame buffer address {Address:x16} is invalid!");
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
ReleaseEvent.Handle.Set();
|
||||
|
||||
WaitBufferFree.Set();
|
||||
|
||||
return;
|
||||
//TODO: Enable once the frame buffers problems are fixed.
|
||||
//GpuAddr += MapFb.GetBufferOffset(Slot);
|
||||
}
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Acquired;
|
||||
|
@ -363,41 +347,28 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
Rotate = -MathF.PI * 0.5f;
|
||||
}
|
||||
|
||||
lock (RenderQueueLock)
|
||||
{
|
||||
if (NvFlingerDisposed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Renderer.SetFrameBufferTransform(ScaleX, ScaleY, Rotate, OffsX, OffsY);
|
||||
|
||||
Interlocked.Increment(ref RenderQueueCount);
|
||||
//TODO: Support double buffering here aswell, it is broken for GPU
|
||||
//frame buffers because it seems to be completely out of sync.
|
||||
if (Context.Ns.Gpu.Engine3d.IsFrameBufferPosition(GpuAddr))
|
||||
{
|
||||
//Frame buffer is rendered to by the GPU, we can just
|
||||
//bind the frame buffer texture, it's not necessary to read anything.
|
||||
Renderer.SetFrameBuffer(GpuAddr);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Frame buffer is not set on the GPU registers, in this case
|
||||
//assume that the app is manually writing to it.
|
||||
Texture Texture = new Texture(CpuAddr, FbWidth, FbHeight);
|
||||
|
||||
byte[] Data = TextureReader.Read(Context.Memory, Texture);
|
||||
|
||||
Renderer.SetFrameBuffer(Data, FbWidth, FbHeight);
|
||||
}
|
||||
|
||||
byte* Fb = (byte*)Context.Memory.Ram + Address;
|
||||
|
||||
Context.Ns.Gpu.Renderer.QueueAction(delegate()
|
||||
{
|
||||
Context.Ns.Gpu.Renderer.SetFrameBuffer(
|
||||
Fb,
|
||||
FbWidth,
|
||||
FbHeight,
|
||||
ScaleX,
|
||||
ScaleY,
|
||||
OffsX,
|
||||
OffsY,
|
||||
Rotate);
|
||||
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
Interlocked.Decrement(ref RenderQueueCount);
|
||||
|
||||
ReleaseEvent.Handle.Set();
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
});
|
||||
Context.Ns.Gpu.Renderer.QueueAction(() => ReleaseBuffer(Slot));
|
||||
}
|
||||
|
||||
private NvMap GetNvMap(ServiceCtx Context, int Slot)
|
||||
|
@ -413,7 +384,19 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
NvMapHandle = BitConverter.ToInt32(RawValue, 0);
|
||||
}
|
||||
|
||||
return ServiceNvDrv.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
|
||||
return INvDrvServices.NvMaps.GetData<NvMap>(Context.Process, NvMapHandle);
|
||||
}
|
||||
|
||||
private void ReleaseBuffer(int Slot)
|
||||
{
|
||||
BufferQueue[Slot].State = BufferState.Free;
|
||||
|
||||
ReleaseEvent.Handle.Set();
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetFreeSlotBlocking(int Width, int Height)
|
||||
|
@ -429,9 +412,9 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
break;
|
||||
}
|
||||
|
||||
Logging.Debug("Waiting for a free BufferQueue slot...");
|
||||
Logging.Debug(LogClass.ServiceNv, "Waiting for a free BufferQueue slot...");
|
||||
|
||||
if (!KeepRunning)
|
||||
if (Disposed)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -441,9 +424,9 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
WaitBufferFree.WaitOne();
|
||||
}
|
||||
while (KeepRunning);
|
||||
while (!Disposed);
|
||||
|
||||
Logging.Debug($"Found free BufferQueue slot {Slot}!");
|
||||
Logging.Debug(LogClass.ServiceNv, $"Found free BufferQueue slot {Slot}!");
|
||||
|
||||
return Slot;
|
||||
}
|
||||
|
@ -481,26 +464,12 @@ namespace Ryujinx.Core.OsHle.Services.Android
|
|||
|
||||
protected virtual void Dispose(bool Disposing)
|
||||
{
|
||||
if (Disposing && !NvFlingerDisposed)
|
||||
if (Disposing && !Disposed)
|
||||
{
|
||||
lock (RenderQueueLock)
|
||||
{
|
||||
NvFlingerDisposed = true;
|
||||
}
|
||||
|
||||
//Ensure that all pending actions was sent before
|
||||
//we can safely assume that the class was disposed.
|
||||
while (RenderQueueCount > 0)
|
||||
{
|
||||
Thread.Yield();
|
||||
}
|
||||
|
||||
Renderer.ResetFrameBuffer();
|
||||
Disposed = true;
|
||||
|
||||
lock (WaitBufferFree)
|
||||
{
|
||||
KeepRunning = false;
|
||||
|
||||
WaitBufferFree.Set();
|
||||
}
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
{ 0x0c, SvcGetThreadPriority },
|
||||
{ 0x0d, SvcSetThreadPriority },
|
||||
{ 0x0f, SvcSetThreadCoreMask },
|
||||
{ 0x10, SvcGetCurrentProcessorNumber },
|
||||
{ 0x12, SvcClearEvent },
|
||||
{ 0x13, SvcMapSharedMemory },
|
||||
{ 0x14, SvcUnmapSharedMemory },
|
||||
|
@ -79,11 +80,11 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||
{
|
||||
Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} called.");
|
||||
Logging.Trace(LogClass.KernelSvc, $"(Thread {ThreadState.ThreadId}) {Func.Method.Name} called.");
|
||||
|
||||
Func(ThreadState);
|
||||
|
||||
Logging.Trace($"(Thread {ThreadState.ThreadId}) {Func.Method.Name} ended.");
|
||||
Logging.Trace(LogClass.KernelSvc, $"(Thread {ThreadState.ThreadId}) {Func.Method.Name} ended.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidPosition(Src))
|
||||
{
|
||||
Logging.Warn($"Tried to map Memory at invalid src address {Src:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to map Memory at invalid src address {Src:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidMapPosition(Dst))
|
||||
{
|
||||
Logging.Warn($"Tried to map Memory at invalid dst address {Dst:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to map Memory at invalid dst address {Dst:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -92,7 +92,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidPosition(Src))
|
||||
{
|
||||
Logging.Warn($"Tried to unmap Memory at invalid src address {Src:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to unmap Memory at invalid src address {Src:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -101,7 +101,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidMapPosition(Dst))
|
||||
{
|
||||
Logging.Warn($"Tried to unmap Memory at invalid dst address {Dst:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to unmap Memory at invalid dst address {Dst:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -158,7 +158,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidPosition(Src))
|
||||
{
|
||||
Logging.Warn($"Tried to map SharedMemory at invalid address {Src:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to map SharedMemory at invalid address {Src:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -196,7 +196,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidPosition(Src))
|
||||
{
|
||||
Logging.Warn($"Tried to unmap SharedMemory at invalid address {Src:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to unmap SharedMemory at invalid address {Src:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -230,7 +230,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (!IsValidPosition(Src))
|
||||
{
|
||||
Logging.Warn($"Tried to create TransferMemory at invalid address {Src:x16}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to create TransferMemory at invalid address {Src:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (Obj == null)
|
||||
{
|
||||
Logging.Warn($"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to CloseHandle on invalid handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -75,7 +75,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
}
|
||||
else
|
||||
{
|
||||
Logging.Warn($"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to ResetSignal on invalid event handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
if (SyncObj == null)
|
||||
{
|
||||
Logging.Warn($"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to WaitSynchronization on invalid handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -153,10 +153,10 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
//TODO: Validate that app has perms to access the service, and that the service
|
||||
//actually exists, return error codes otherwise.
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(Name));
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(Name), Name);
|
||||
|
||||
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
|
||||
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = Handle;
|
||||
}
|
||||
|
@ -199,7 +199,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
}
|
||||
else
|
||||
{
|
||||
Logging.Warn($"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to SendSyncRequest on invalid session handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -221,7 +221,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size);
|
||||
|
||||
Logging.Info($"SvcOutputDebugString: {Str}");
|
||||
Logging.Info(LogClass.KernelSvc, Str);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
@ -235,7 +235,8 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
|
||||
//Fail for info not available on older Kernel versions.
|
||||
if (InfoType == 18 ||
|
||||
InfoType == 19)
|
||||
InfoType == 19 ||
|
||||
InfoType == 20)
|
||||
{
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidInfo);
|
||||
|
||||
|
@ -267,7 +268,7 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
case 6:
|
||||
ThreadState.X1 = MemoryRegions.TotalMemoryAvailable;
|
||||
break;
|
||||
|
||||
|
||||
case 7:
|
||||
ThreadState.X1 = MemoryRegions.TotalMemoryUsed + CurrentHeapSize;
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
using ChocolArm64.State;
|
||||
using Ryujinx.Core.OsHle.Handles;
|
||||
|
||||
using static Ryujinx.Core.OsHle.ErrorCode;
|
||||
|
||||
namespace Ryujinx.Core.OsHle.Svc
|
||||
{
|
||||
partial class SvcHandler
|
||||
|
@ -61,11 +63,11 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
}
|
||||
|
||||
private void SvcSleepThread(AThreadState ThreadState)
|
||||
{
|
||||
{
|
||||
ulong NanoSecs = ThreadState.X0;
|
||||
|
||||
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||
|
||||
|
||||
if (NanoSecs == 0)
|
||||
{
|
||||
Process.Scheduler.Yield(CurrThread);
|
||||
|
@ -115,9 +117,16 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
//TODO: Error codes.
|
||||
}
|
||||
|
||||
private void SvcGetCurrentProcessorNumber(AThreadState ThreadState)
|
||||
{
|
||||
KThread CurrThread = Process.GetThread(ThreadState.Tpidr);
|
||||
|
||||
ThreadState.X0 = (ulong)CurrThread.ProcessorId;
|
||||
}
|
||||
|
||||
private void SvcGetThreadId(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
int Handle = (int)ThreadState.X1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
|
||||
|
||||
|
@ -126,8 +135,12 @@ namespace Ryujinx.Core.OsHle.Svc
|
|||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = (ulong)Thread.ThreadId;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warn(LogClass.KernelSvc, $"Tried to GetThreadId on invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
//TODO: Error codes.
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Ryujinx.Graphics/Gal/GalBlendEquation.cs
Normal file
11
Ryujinx.Graphics/Gal/GalBlendEquation.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalBlendEquation
|
||||
{
|
||||
FuncAdd = 1,
|
||||
FuncSubtract = 2,
|
||||
FuncReverseSubtract = 3,
|
||||
Min = 4,
|
||||
Max = 5
|
||||
}
|
||||
}
|
25
Ryujinx.Graphics/Gal/GalBlendFactor.cs
Normal file
25
Ryujinx.Graphics/Gal/GalBlendFactor.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalBlendFactor
|
||||
{
|
||||
Zero = 0x1,
|
||||
One = 0x2,
|
||||
SrcColor = 0x3,
|
||||
OneMinusSrcColor = 0x4,
|
||||
SrcAlpha = 0x5,
|
||||
OneMinusSrcAlpha = 0x6,
|
||||
DstAlpha = 0x7,
|
||||
OneMinusDstAlpha = 0x8,
|
||||
DstColor = 0x9,
|
||||
OneMinusDstColor = 0xa,
|
||||
SrcAlphaSaturate = 0xb,
|
||||
Src1Color = 0x10,
|
||||
OneMinusSrc1Color = 0x11,
|
||||
Src1Alpha = 0x12,
|
||||
OneMinusSrc1Alpha = 0x13,
|
||||
ConstantColor = 0x61,
|
||||
OneMinusConstantColor = 0x62,
|
||||
ConstantAlpha = 0x63,
|
||||
OneMinusConstantAlpha = 0x64
|
||||
}
|
||||
}
|
15
Ryujinx.Graphics/Gal/GalClearBufferFlags.cs
Normal file
15
Ryujinx.Graphics/Gal/GalClearBufferFlags.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
[Flags]
|
||||
public enum GalClearBufferFlags
|
||||
{
|
||||
Depth = 1 << 0,
|
||||
Stencil = 1 << 1,
|
||||
ColorRed = 1 << 2,
|
||||
ColorGreen = 1 << 3,
|
||||
ColorBlue = 1 << 4,
|
||||
ColorAlpha = 1 << 5
|
||||
}
|
||||
}
|
22
Ryujinx.Graphics/Gal/GalColorF.cs
Normal file
22
Ryujinx.Graphics/Gal/GalColorF.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalColorF
|
||||
{
|
||||
public float Red { get; private set; }
|
||||
public float Green { get; private set; }
|
||||
public float Blue { get; private set; }
|
||||
public float Alpha { get; private set; }
|
||||
|
||||
public GalColorF(
|
||||
float Red,
|
||||
float Green,
|
||||
float Blue,
|
||||
float Alpha)
|
||||
{
|
||||
this.Red = Red;
|
||||
this.Green = Green;
|
||||
this.Blue = Blue;
|
||||
this.Alpha = Alpha;
|
||||
}
|
||||
}
|
||||
}
|
7
Ryujinx.Graphics/Gal/GalConsts.cs
Normal file
7
Ryujinx.Graphics/Gal/GalConsts.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public static class GalConsts
|
||||
{
|
||||
public const string FlipUniformName = "flip";
|
||||
}
|
||||
}
|
9
Ryujinx.Graphics/Gal/GalIndexFormat.cs
Normal file
9
Ryujinx.Graphics/Gal/GalIndexFormat.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalIndexFormat
|
||||
{
|
||||
Byte = 0,
|
||||
Int16 = 1,
|
||||
Int32 = 2
|
||||
}
|
||||
}
|
11
Ryujinx.Graphics/Gal/GalShaderType.cs
Normal file
11
Ryujinx.Graphics/Gal/GalShaderType.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalShaderType
|
||||
{
|
||||
Vertex = 0,
|
||||
TessControl = 1,
|
||||
TessEvaluation = 2,
|
||||
Geometry = 3,
|
||||
Fragment = 4
|
||||
}
|
||||
}
|
20
Ryujinx.Graphics/Gal/GalTexture.cs
Normal file
20
Ryujinx.Graphics/Gal/GalTexture.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalTexture
|
||||
{
|
||||
public byte[] Data;
|
||||
|
||||
public int Width;
|
||||
public int Height;
|
||||
|
||||
public GalTextureFormat Format;
|
||||
|
||||
public GalTexture(byte[] Data, int Width, int Height, GalTextureFormat Format)
|
||||
{
|
||||
this.Data = Data;
|
||||
this.Width = Width;
|
||||
this.Height = Height;
|
||||
this.Format = Format;
|
||||
}
|
||||
}
|
||||
}
|
8
Ryujinx.Graphics/Gal/GalTextureFilter.cs
Normal file
8
Ryujinx.Graphics/Gal/GalTextureFilter.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalTextureFilter
|
||||
{
|
||||
Nearest = 1,
|
||||
Linear = 2
|
||||
}
|
||||
}
|
14
Ryujinx.Graphics/Gal/GalTextureFormat.cs
Normal file
14
Ryujinx.Graphics/Gal/GalTextureFormat.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalTextureFormat
|
||||
{
|
||||
A8B8G8R8 = 0x8,
|
||||
A1B5G5R5 = 0x14,
|
||||
B5G6R5 = 0x15,
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26,
|
||||
BC4 = 0x27,
|
||||
BC5 = 0x28
|
||||
}
|
||||
}
|
9
Ryujinx.Graphics/Gal/GalTextureMipFilter.cs
Normal file
9
Ryujinx.Graphics/Gal/GalTextureMipFilter.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalTextureMipFilter
|
||||
{
|
||||
None = 1,
|
||||
Nearest = 2,
|
||||
Linear = 3
|
||||
}
|
||||
}
|
33
Ryujinx.Graphics/Gal/GalTextureSampler.cs
Normal file
33
Ryujinx.Graphics/Gal/GalTextureSampler.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalTextureSampler
|
||||
{
|
||||
public GalTextureWrap AddressU { get; private set; }
|
||||
public GalTextureWrap AddressV { get; private set; }
|
||||
public GalTextureWrap AddressP { get; private set; }
|
||||
|
||||
public GalTextureFilter MinFilter { get; private set; }
|
||||
public GalTextureFilter MagFilter { get; private set; }
|
||||
public GalTextureMipFilter MipFilter { get; private set; }
|
||||
|
||||
public GalColorF BorderColor { get; private set; }
|
||||
|
||||
public GalTextureSampler(
|
||||
GalTextureWrap AddressU,
|
||||
GalTextureWrap AddressV,
|
||||
GalTextureWrap AddressP,
|
||||
GalTextureFilter MinFilter,
|
||||
GalTextureFilter MagFilter,
|
||||
GalTextureMipFilter MipFilter,
|
||||
GalColorF BorderColor)
|
||||
{
|
||||
this.AddressU = AddressU;
|
||||
this.AddressV = AddressV;
|
||||
this.AddressP = AddressP;
|
||||
this.MinFilter = MinFilter;
|
||||
this.MagFilter = MagFilter;
|
||||
this.MipFilter = MipFilter;
|
||||
this.BorderColor = BorderColor;
|
||||
}
|
||||
}
|
||||
}
|
14
Ryujinx.Graphics/Gal/GalTextureWrap.cs
Normal file
14
Ryujinx.Graphics/Gal/GalTextureWrap.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public enum GalTextureWrap
|
||||
{
|
||||
Repeat = 0,
|
||||
MirroredRepeat = 1,
|
||||
ClampToEdge = 2,
|
||||
ClampToBorder = 3,
|
||||
Clamp = 4,
|
||||
MirrorClampToEdge = 5,
|
||||
MirrorClampToBorder = 6,
|
||||
MirrorClamp = 7
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
public struct GalVertexAttrib
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
public int Buffer { get; private set; }
|
||||
public bool IsConst { get; private set; }
|
||||
public int Offset { get; private set; }
|
||||
|
||||
|
@ -13,16 +11,12 @@ namespace Ryujinx.Graphics.Gal
|
|||
public bool IsBgra { get; private set; }
|
||||
|
||||
public GalVertexAttrib(
|
||||
int Index,
|
||||
int Buffer,
|
||||
bool IsConst,
|
||||
int Offset,
|
||||
GalVertexAttribSize Size,
|
||||
GalVertexAttribType Type,
|
||||
bool IsBgra)
|
||||
{
|
||||
this.Index = Index;
|
||||
this.Buffer = Buffer;
|
||||
this.IsConst = IsConst;
|
||||
this.Offset = Offset;
|
||||
this.Size = Size;
|
||||
|
|
|
@ -1,29 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public unsafe interface IGalRenderer
|
||||
{
|
||||
void QueueAction(Action ActionMthd);
|
||||
|
||||
void RunActions();
|
||||
|
||||
void InitializeFrameBuffer();
|
||||
void ResetFrameBuffer();
|
||||
void Render();
|
||||
|
||||
void SetWindowSize(int Width, int Height);
|
||||
void SetFrameBuffer(
|
||||
byte* Fb,
|
||||
int Width,
|
||||
int Height,
|
||||
float ScaleX,
|
||||
float ScaleY,
|
||||
float OffsX,
|
||||
float OffsY,
|
||||
float Rotate);
|
||||
|
||||
void SendVertexBuffer(int Index, byte[] Buffer, int Stride, GalVertexAttrib[] Attribs);
|
||||
//Blend
|
||||
void SetBlendEnable(bool Enable);
|
||||
|
||||
void SendR8G8B8A8Texture(int Index, byte[] Buffer, int Width, int Height);
|
||||
void SetBlend(
|
||||
GalBlendEquation Equation,
|
||||
GalBlendFactor FuncSrc,
|
||||
GalBlendFactor FuncDst);
|
||||
|
||||
void SetBlendSeparate(
|
||||
GalBlendEquation EquationRgb,
|
||||
GalBlendEquation EquationAlpha,
|
||||
GalBlendFactor FuncSrcRgb,
|
||||
GalBlendFactor FuncDstRgb,
|
||||
GalBlendFactor FuncSrcAlpha,
|
||||
GalBlendFactor FuncDstAlpha);
|
||||
|
||||
//Frame Buffer
|
||||
void CreateFrameBuffer(long Tag, int Width, int Height);
|
||||
|
||||
void BindFrameBuffer(long Tag);
|
||||
|
||||
void BindFrameBufferTexture(long Tag, int Index, GalTextureSampler Sampler);
|
||||
|
||||
void SetFrameBuffer(long Tag);
|
||||
|
||||
void SetFrameBuffer(byte[] Data, int Width, int Height);
|
||||
|
||||
void SetFrameBufferTransform(float SX, float SY, float Rotate, float TX, float TY);
|
||||
|
||||
void SetViewport(int X, int Y, int Width, int Height);
|
||||
|
||||
//Rasterizer
|
||||
void ClearBuffers(int RtIndex, GalClearBufferFlags Flags);
|
||||
|
||||
void SetVertexArray(int VbIndex, int Stride, byte[] Buffer, GalVertexAttrib[] Attribs);
|
||||
|
||||
void SetIndexArray(byte[] Buffer, GalIndexFormat Format);
|
||||
|
||||
void DrawArrays(int VbIndex, GalPrimitiveType PrimType);
|
||||
|
||||
void DrawElements(int VbIndex, int First, GalPrimitiveType PrimType);
|
||||
|
||||
//Shader
|
||||
void CreateShader(long Tag, GalShaderType Type, byte[] Data);
|
||||
|
||||
IEnumerable<ShaderDeclInfo> GetTextureUsage(long Tag);
|
||||
|
||||
void SetConstBuffer(long Tag, int Cbuf, byte[] Data);
|
||||
|
||||
void SetUniform1(string UniformName, int Value);
|
||||
|
||||
void SetUniform2F(string UniformName, float X, float Y);
|
||||
|
||||
void BindShader(long Tag);
|
||||
|
||||
void BindProgram();
|
||||
|
||||
//Texture
|
||||
void SetTextureAndSampler(int Index, GalTexture Texture, GalTextureSampler Sampler);
|
||||
|
||||
void BindTexture(int Index);
|
||||
}
|
||||
|
|
|
@ -1,250 +0,0 @@
|
|||
using OpenTK;
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
unsafe class FrameBuffer
|
||||
{
|
||||
public int WindowWidth { get; set; }
|
||||
public int WindowHeight { get; set; }
|
||||
|
||||
private int VtxShaderHandle;
|
||||
private int FragShaderHandle;
|
||||
private int PrgShaderHandle;
|
||||
|
||||
private int TexHandle;
|
||||
private int TexWidth;
|
||||
private int TexHeight;
|
||||
|
||||
private int VaoHandle;
|
||||
private int VboHandle;
|
||||
|
||||
private int[] Pixels;
|
||||
|
||||
private byte* FbPtr;
|
||||
|
||||
private object FbPtrLock;
|
||||
|
||||
public FrameBuffer(int Width, int Height)
|
||||
{
|
||||
if (Width < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Width));
|
||||
}
|
||||
|
||||
if (Height < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||
}
|
||||
|
||||
FbPtrLock = new object();
|
||||
|
||||
TexWidth = Width;
|
||||
TexHeight = Height;
|
||||
|
||||
WindowWidth = Width;
|
||||
WindowHeight = Height;
|
||||
|
||||
SetupShaders();
|
||||
SetupTexture();
|
||||
SetupVertex();
|
||||
}
|
||||
|
||||
private void SetupShaders()
|
||||
{
|
||||
VtxShaderHandle = GL.CreateShader(ShaderType.VertexShader);
|
||||
FragShaderHandle = GL.CreateShader(ShaderType.FragmentShader);
|
||||
|
||||
string VtxShaderSource = EmbeddedResource.GetString("GlFbVtxShader");
|
||||
string FragShaderSource = EmbeddedResource.GetString("GlFbFragShader");
|
||||
|
||||
GL.ShaderSource(VtxShaderHandle, VtxShaderSource);
|
||||
GL.ShaderSource(FragShaderHandle, FragShaderSource);
|
||||
GL.CompileShader(VtxShaderHandle);
|
||||
GL.CompileShader(FragShaderHandle);
|
||||
|
||||
PrgShaderHandle = GL.CreateProgram();
|
||||
|
||||
GL.AttachShader(PrgShaderHandle, VtxShaderHandle);
|
||||
GL.AttachShader(PrgShaderHandle, FragShaderHandle);
|
||||
GL.LinkProgram(PrgShaderHandle);
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
int TexUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "tex");
|
||||
|
||||
GL.Uniform1(TexUniformLocation, 0);
|
||||
|
||||
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
||||
|
||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(1280.0f, 720.0f));
|
||||
}
|
||||
|
||||
private void SetupTexture()
|
||||
{
|
||||
Pixels = new int[TexWidth * TexHeight];
|
||||
|
||||
if (TexHandle == 0)
|
||||
{
|
||||
TexHandle = GL.GenTexture();
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
|
||||
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
|
||||
GL.TexImage2D(TextureTarget.Texture2D,
|
||||
0,
|
||||
PixelInternalFormat.Rgba,
|
||||
TexWidth,
|
||||
TexHeight,
|
||||
0,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
private void SetupVertex()
|
||||
{
|
||||
VaoHandle = GL.GenVertexArray();
|
||||
VboHandle = GL.GenBuffer();
|
||||
|
||||
float[] Buffer = new float[]
|
||||
{
|
||||
-1, 1, 0, 0,
|
||||
1, 1, 1, 0,
|
||||
-1, -1, 0, 1,
|
||||
1, -1, 1, 1
|
||||
};
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length * 4);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
GL.BufferData(BufferTarget.ArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, 0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.EnableVertexAttribArray(0);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
||||
GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 16, 0);
|
||||
|
||||
GL.EnableVertexAttribArray(1);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
||||
GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 16, 8);
|
||||
|
||||
GL.BindVertexArray(0);
|
||||
}
|
||||
|
||||
public unsafe void Set(byte* Fb, int Width, int Height, Matrix2 Transform, Vector2 Offs)
|
||||
{
|
||||
if (Fb == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(Fb));
|
||||
}
|
||||
|
||||
if (Width < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Width));
|
||||
}
|
||||
|
||||
if (Height < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Height));
|
||||
}
|
||||
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
FbPtr = Fb;
|
||||
}
|
||||
|
||||
if (Width != TexWidth ||
|
||||
Height != TexHeight)
|
||||
{
|
||||
TexWidth = Width;
|
||||
TexHeight = Height;
|
||||
|
||||
SetupTexture();
|
||||
}
|
||||
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
int TransformUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "transform");
|
||||
|
||||
GL.UniformMatrix2(TransformUniformLocation, false, ref Transform);
|
||||
|
||||
int WindowSizeUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "window_size");
|
||||
|
||||
GL.Uniform2(WindowSizeUniformLocation, new Vector2(WindowWidth, WindowHeight));
|
||||
|
||||
int OffsetUniformLocation = GL.GetUniformLocation(PrgShaderHandle, "offset");
|
||||
|
||||
GL.Uniform2(OffsetUniformLocation, Offs);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
FbPtr = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
lock (FbPtrLock)
|
||||
{
|
||||
if (FbPtr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int Y = 0; Y < TexHeight; Y++)
|
||||
for (int X = 0; X < TexWidth; X++)
|
||||
{
|
||||
Pixels[X + Y * TexWidth] = *((int*)(FbPtr + GetSwizzleOffset(X, Y)));
|
||||
}
|
||||
}
|
||||
|
||||
GL.BindTexture(TextureTarget.Texture2D, TexHandle);
|
||||
GL.TexSubImage2D(TextureTarget.Texture2D,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
TexWidth,
|
||||
TexHeight,
|
||||
PixelFormat.Rgba,
|
||||
PixelType.UnsignedByte,
|
||||
Pixels);
|
||||
|
||||
GL.ActiveTexture(TextureUnit.Texture0);
|
||||
|
||||
GL.BindVertexArray(VaoHandle);
|
||||
|
||||
GL.UseProgram(PrgShaderHandle);
|
||||
|
||||
GL.DrawArrays(PrimitiveType.TriangleStrip, 0, 4);
|
||||
}
|
||||
|
||||
private int GetSwizzleOffset(int X, int Y)
|
||||
{
|
||||
int Pos;
|
||||
|
||||
Pos = (Y & 0x7f) >> 4;
|
||||
Pos += (X >> 4) << 3;
|
||||
Pos += (Y >> 7) * ((TexWidth >> 4) << 3);
|
||||
Pos *= 1024;
|
||||
Pos += ((Y & 0xf) >> 3) << 9;
|
||||
Pos += ((X & 0xf) >> 3) << 8;
|
||||
Pos += ((Y & 0x7) >> 1) << 6;
|
||||
Pos += ((X & 0x7) >> 2) << 5;
|
||||
Pos += ((Y & 0x1) >> 0) << 4;
|
||||
Pos += ((X & 0x3) >> 0) << 2;
|
||||
|
||||
return Pos;
|
||||
}
|
||||
}
|
||||
}
|
49
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
49
Ryujinx.Graphics/Gal/OpenGL/OGLBlend.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
class OGLBlend
|
||||
{
|
||||
public void Enable()
|
||||
{
|
||||
GL.Enable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
GL.Disable(EnableCap.Blend);
|
||||
}
|
||||
|
||||
public void Set(
|
||||
GalBlendEquation Equation,
|
||||
GalBlendFactor FuncSrc,
|
||||
GalBlendFactor FuncDst)
|
||||
{
|
||||
GL.BlendEquation(
|
||||
OGLEnumConverter.GetBlendEquation(Equation));
|
||||
|
||||
GL.BlendFunc(
|
||||
OGLEnumConverter.GetBlendFactorSrc(FuncSrc),
|
||||
OGLEnumConverter.GetBlendFactorDst(FuncDst));
|
||||
}
|
||||
|
||||
public void SetSeparate(
|
||||
GalBlendEquation EquationRgb,
|
||||
GalBlendEquation EquationAlpha,
|
||||
GalBlendFactor FuncSrcRgb,
|
||||
GalBlendFactor FuncDstRgb,
|
||||
GalBlendFactor FuncSrcAlpha,
|
||||
GalBlendFactor FuncDstAlpha)
|
||||
{
|
||||
GL.BlendEquationSeparate(
|
||||
OGLEnumConverter.GetBlendEquation(EquationRgb),
|
||||
OGLEnumConverter.GetBlendEquation(EquationAlpha));
|
||||
|
||||
GL.BlendFuncSeparate(
|
||||
OGLEnumConverter.GetBlendFactorSrc(FuncSrcRgb),
|
||||
OGLEnumConverter.GetBlendFactorDst(FuncDstRgb),
|
||||
OGLEnumConverter.GetBlendFactorSrc(FuncSrcAlpha),
|
||||
OGLEnumConverter.GetBlendFactorDst(FuncDstAlpha));
|
||||
}
|
||||
}
|
||||
}
|
198
Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
Normal file
198
Ryujinx.Graphics/Gal/OpenGL/OGLEnumConverter.cs
Normal file
|
@ -0,0 +1,198 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
static class OGLEnumConverter
|
||||
{
|
||||
public static DrawElementsType GetDrawElementsType(GalIndexFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalIndexFormat.Byte: return DrawElementsType.UnsignedByte;
|
||||
case GalIndexFormat.Int16: return DrawElementsType.UnsignedShort;
|
||||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
}
|
||||
|
||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalPrimitiveType.Points: return PrimitiveType.Points;
|
||||
case GalPrimitiveType.Lines: return PrimitiveType.Lines;
|
||||
case GalPrimitiveType.LineLoop: return PrimitiveType.LineLoop;
|
||||
case GalPrimitiveType.LineStrip: return PrimitiveType.LineStrip;
|
||||
case GalPrimitiveType.Triangles: return PrimitiveType.Triangles;
|
||||
case GalPrimitiveType.TriangleStrip: return PrimitiveType.TriangleStrip;
|
||||
case GalPrimitiveType.TriangleFan: return PrimitiveType.TriangleFan;
|
||||
case GalPrimitiveType.Quads: return PrimitiveType.Quads;
|
||||
case GalPrimitiveType.QuadStrip: return PrimitiveType.QuadStrip;
|
||||
case GalPrimitiveType.Polygon: return PrimitiveType.Polygon;
|
||||
case GalPrimitiveType.LinesAdjacency: return PrimitiveType.LinesAdjacency;
|
||||
case GalPrimitiveType.LineStripAdjacency: return PrimitiveType.LineStripAdjacency;
|
||||
case GalPrimitiveType.TrianglesAdjacency: return PrimitiveType.TrianglesAdjacency;
|
||||
case GalPrimitiveType.TriangleStripAdjacency: return PrimitiveType.TriangleStripAdjacency;
|
||||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static ShaderType GetShaderType(GalShaderType Type)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case GalShaderType.Vertex: return ShaderType.VertexShader;
|
||||
case GalShaderType.TessControl: return ShaderType.TessControlShader;
|
||||
case GalShaderType.TessEvaluation: return ShaderType.TessEvaluationShader;
|
||||
case GalShaderType.Geometry: return ShaderType.GeometryShader;
|
||||
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
}
|
||||
|
||||
public static (PixelFormat, PixelType) GetTextureFormat(GalTextureFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalTextureFormat.A8B8G8R8: return (PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalTextureFormat.A1B5G5R5: return (PixelFormat.Rgba, PixelType.UnsignedShort5551);
|
||||
case GalTextureFormat.B5G6R5: return (PixelFormat.Rgb, PixelType.UnsignedShort565);
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static PixelInternalFormat GetCompressedTextureFormat(GalTextureFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalTextureFormat.BC1: return PixelInternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalTextureFormat.BC2: return PixelInternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalTextureFormat.BC3: return PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
case GalTextureFormat.BC4: return PixelInternalFormat.CompressedRedRgtc1;
|
||||
case GalTextureFormat.BC5: return PixelInternalFormat.CompressedRgRgtc2;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
}
|
||||
|
||||
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
||||
{
|
||||
switch (Wrap)
|
||||
{
|
||||
case GalTextureWrap.Repeat: return TextureWrapMode.Repeat;
|
||||
case GalTextureWrap.MirroredRepeat: return TextureWrapMode.MirroredRepeat;
|
||||
case GalTextureWrap.ClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||
case GalTextureWrap.ClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
||||
|
||||
//TODO: Those needs extensions (and are currently wrong).
|
||||
case GalTextureWrap.MirrorClampToEdge: return TextureWrapMode.ClampToEdge;
|
||||
case GalTextureWrap.MirrorClampToBorder: return TextureWrapMode.ClampToBorder;
|
||||
case GalTextureWrap.MirrorClamp: return TextureWrapMode.Clamp;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Wrap));
|
||||
}
|
||||
|
||||
public static TextureMinFilter GetTextureMinFilter(
|
||||
GalTextureFilter MinFilter,
|
||||
GalTextureMipFilter MipFilter)
|
||||
{
|
||||
//TODO: Mip (needs mipmap support first).
|
||||
switch (MinFilter)
|
||||
{
|
||||
case GalTextureFilter.Nearest: return TextureMinFilter.Nearest;
|
||||
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(MinFilter));
|
||||
}
|
||||
|
||||
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
||||
{
|
||||
switch (Filter)
|
||||
{
|
||||
case GalTextureFilter.Nearest: return TextureMagFilter.Nearest;
|
||||
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Filter));
|
||||
}
|
||||
|
||||
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
||||
{
|
||||
switch (BlendEquation)
|
||||
{
|
||||
case GalBlendEquation.FuncAdd: return BlendEquationMode.FuncAdd;
|
||||
case GalBlendEquation.FuncSubtract: return BlendEquationMode.FuncSubtract;
|
||||
case GalBlendEquation.FuncReverseSubtract: return BlendEquationMode.FuncReverseSubtract;
|
||||
case GalBlendEquation.Min: return BlendEquationMode.Min;
|
||||
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(BlendEquation));
|
||||
}
|
||||
|
||||
public static BlendingFactorSrc GetBlendFactorSrc(GalBlendFactor BlendFactor)
|
||||
{
|
||||
switch (BlendFactor)
|
||||
{
|
||||
case GalBlendFactor.Zero: return BlendingFactorSrc.Zero;
|
||||
case GalBlendFactor.One: return BlendingFactorSrc.One;
|
||||
case GalBlendFactor.SrcColor: return BlendingFactorSrc.SrcColor;
|
||||
case GalBlendFactor.OneMinusSrcColor: return BlendingFactorSrc.OneMinusSrcColor;
|
||||
case GalBlendFactor.DstColor: return BlendingFactorSrc.DstColor;
|
||||
case GalBlendFactor.OneMinusDstColor: return BlendingFactorSrc.OneMinusDstColor;
|
||||
case GalBlendFactor.SrcAlpha: return BlendingFactorSrc.SrcAlpha;
|
||||
case GalBlendFactor.OneMinusSrcAlpha: return BlendingFactorSrc.OneMinusSrcAlpha;
|
||||
case GalBlendFactor.DstAlpha: return BlendingFactorSrc.DstAlpha;
|
||||
case GalBlendFactor.OneMinusDstAlpha: return BlendingFactorSrc.OneMinusDstAlpha;
|
||||
case GalBlendFactor.ConstantColor: return BlendingFactorSrc.ConstantColor;
|
||||
case GalBlendFactor.OneMinusConstantColor: return BlendingFactorSrc.OneMinusConstantColor;
|
||||
case GalBlendFactor.ConstantAlpha: return BlendingFactorSrc.ConstantAlpha;
|
||||
case GalBlendFactor.OneMinusConstantAlpha: return BlendingFactorSrc.OneMinusConstantAlpha;
|
||||
case GalBlendFactor.SrcAlphaSaturate: return BlendingFactorSrc.SrcAlphaSaturate;
|
||||
case GalBlendFactor.Src1Color: return BlendingFactorSrc.Src1Color;
|
||||
case GalBlendFactor.OneMinusSrc1Color: return BlendingFactorSrc.OneMinusSrc1Color;
|
||||
case GalBlendFactor.Src1Alpha: return BlendingFactorSrc.Src1Alpha;
|
||||
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorSrc.OneMinusSrc1Alpha;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(BlendFactor));
|
||||
}
|
||||
|
||||
public static BlendingFactorDest GetBlendFactorDst(GalBlendFactor BlendFactor)
|
||||
{
|
||||
switch (BlendFactor)
|
||||
{
|
||||
case GalBlendFactor.Zero: return BlendingFactorDest.Zero;
|
||||
case GalBlendFactor.One: return BlendingFactorDest.One;
|
||||
case GalBlendFactor.SrcColor: return BlendingFactorDest.SrcColor;
|
||||
case GalBlendFactor.OneMinusSrcColor: return BlendingFactorDest.OneMinusSrcColor;
|
||||
case GalBlendFactor.DstColor: return BlendingFactorDest.DstColor;
|
||||
case GalBlendFactor.OneMinusDstColor: return BlendingFactorDest.OneMinusDstColor;
|
||||
case GalBlendFactor.SrcAlpha: return BlendingFactorDest.SrcAlpha;
|
||||
case GalBlendFactor.OneMinusSrcAlpha: return BlendingFactorDest.OneMinusSrcAlpha;
|
||||
case GalBlendFactor.DstAlpha: return BlendingFactorDest.DstAlpha;
|
||||
case GalBlendFactor.OneMinusDstAlpha: return BlendingFactorDest.OneMinusDstAlpha;
|
||||
case GalBlendFactor.ConstantColor: return BlendingFactorDest.ConstantColor;
|
||||
case GalBlendFactor.OneMinusConstantColor: return BlendingFactorDest.OneMinusConstantColor;
|
||||
case GalBlendFactor.ConstantAlpha: return BlendingFactorDest.ConstantAlpha;
|
||||
case GalBlendFactor.OneMinusConstantAlpha: return BlendingFactorDest.OneMinusConstantAlpha;
|
||||
case GalBlendFactor.SrcAlphaSaturate: return BlendingFactorDest.SrcAlphaSaturate;
|
||||
case GalBlendFactor.Src1Color: return BlendingFactorDest.Src1Color;
|
||||
case GalBlendFactor.OneMinusSrc1Color: return BlendingFactorDest.OneMinusSrc1Color;
|
||||
case GalBlendFactor.Src1Alpha: return BlendingFactorDest.Src1Alpha;
|
||||
case GalBlendFactor.OneMinusSrc1Alpha: return BlendingFactorDest.OneMinusSrc1Alpha;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(BlendFactor));
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue