Merge branch 'master' of https://github.com/Ryujinx/Ryujinx
This commit is contained in:
commit
2c37642143
169 changed files with 9393 additions and 3184 deletions
|
@ -278,15 +278,18 @@ namespace ChocolArm64
|
|||
SetA64("0>0011100<1xxxxx111101xxxxxxxxxx", AInstEmit.Fmax_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("000111100x1xxxxx011010xxxxxxxxxx", AInstEmit.Fmaxnm_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011100<1xxxxx110001xxxxxxxxxx", AInstEmit.Fmaxnm_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>1011100<1xxxxx111101xxxxxxxxxx", AInstEmit.Fmaxp_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("000111100x1xxxxx010110xxxxxxxxxx", AInstEmit.Fmin_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011101<1xxxxx111101xxxxxxxxxx", AInstEmit.Fmin_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("000111100x1xxxxx011110xxxxxxxxxx", AInstEmit.Fminnm_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011101<1xxxxx110001xxxxxxxxxx", AInstEmit.Fminnm_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("010111111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>1011101<1xxxxx111101xxxxxxxxxx", AInstEmit.Fminp_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("010111111xxxxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011100<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmla_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x0011111<<xxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011111<xxxxxx0001x0xxxxxxxxxx", AInstEmit.Fmla_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("010111111xxxxxxx0101x0xxxxxxxxxx", AInstEmit.Fmls_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011101<1xxxxx110011xxxxxxxxxx", AInstEmit.Fmls_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x0011111<<xxxxx0101x0xxxxxxxxxx", AInstEmit.Fmls_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011111<xxxxxx0101x0xxxxxxxxxx", AInstEmit.Fmls_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("000111100x100000010000xxxxxxxxxx", AInstEmit.Fmov_S, typeof(AOpCodeSimd));
|
||||
SetA64("00011110xx1xxxxxxxx100xxxxxxxxxx", AInstEmit.Fmov_Si, typeof(AOpCodeSimdFmov));
|
||||
SetA64("0xx0111100000xxx111101xxxxxxxxxx", AInstEmit.Fmov_V, typeof(AOpCodeSimdImm));
|
||||
|
@ -296,9 +299,13 @@ namespace ChocolArm64
|
|||
SetA64("1001111010101111000000xxxxxxxxxx", AInstEmit.Fmov_Itof1, typeof(AOpCodeSimdCvt));
|
||||
SetA64("000111110x0xxxxx1xxxxxxxxxxxxxxx", AInstEmit.Fmsub_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("000111100x1xxxxx000010xxxxxxxxxx", AInstEmit.Fmul_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("010111111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("010111111xxxxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>1011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmul_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x0011111<<xxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011111<xxxxxx1001x0xxxxxxxxxx", AInstEmit.Fmul_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("010111100x1xxxxx110111xxxxxxxxxx", AInstEmit.Fmulx_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("011111111xxxxxxx1001x0xxxxxxxxxx", AInstEmit.Fmulx_Se, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("0>0011100<1xxxxx110111xxxxxxxxxx", AInstEmit.Fmulx_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>1011111<xxxxxx1001x0xxxxxxxxxx", AInstEmit.Fmulx_Ve, typeof(AOpCodeSimdRegElemF));
|
||||
SetA64("000111100x100001010000xxxxxxxxxx", AInstEmit.Fneg_S, typeof(AOpCodeSimd));
|
||||
SetA64("0>1011101<100000111110xxxxxxxxxx", AInstEmit.Fneg_V, typeof(AOpCodeSimd));
|
||||
SetA64("000111110x1xxxxx0xxxxxxxxxxxxxxx", AInstEmit.Fnmadd_S, typeof(AOpCodeSimdReg));
|
||||
|
@ -308,6 +315,7 @@ namespace ChocolArm64
|
|||
SetA64("0>0011101<100001110110xxxxxxxxxx", AInstEmit.Frecpe_V, typeof(AOpCodeSimd));
|
||||
SetA64("010111100x1xxxxx111111xxxxxxxxxx", AInstEmit.Frecps_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011100<1xxxxx111111xxxxxxxxxx", AInstEmit.Frecps_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("010111101x100001111110xxxxxxxxxx", AInstEmit.Frecpx_S, typeof(AOpCodeSimd));
|
||||
SetA64("000111100x100110010000xxxxxxxxxx", AInstEmit.Frinta_S, typeof(AOpCodeSimd));
|
||||
SetA64("0>1011100<100001100010xxxxxxxxxx", AInstEmit.Frinta_V, typeof(AOpCodeSimd));
|
||||
SetA64("000111100x100111110000xxxxxxxxxx", AInstEmit.Frinti_S, typeof(AOpCodeSimd));
|
||||
|
@ -325,6 +333,7 @@ namespace ChocolArm64
|
|||
SetA64("010111101x1xxxxx111111xxxxxxxxxx", AInstEmit.Frsqrts_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011101<1xxxxx111111xxxxxxxxxx", AInstEmit.Frsqrts_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("000111100x100001110000xxxxxxxxxx", AInstEmit.Fsqrt_S, typeof(AOpCodeSimd));
|
||||
SetA64("0>1011101<100001111110xxxxxxxxxx", AInstEmit.Fsqrt_V, typeof(AOpCodeSimd));
|
||||
SetA64("000111100x1xxxxx001110xxxxxxxxxx", AInstEmit.Fsub_S, typeof(AOpCodeSimdReg));
|
||||
SetA64("0>0011101<1xxxxx110101xxxxxxxxxx", AInstEmit.Fsub_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("01001110000xxxxx000111xxxxxxxxxx", AInstEmit.Ins_Gp, typeof(AOpCodeSimdIns));
|
||||
|
@ -395,6 +404,7 @@ namespace ChocolArm64
|
|||
SetA64("0x001110<<1xxxxx101011xxxxxxxxxx", AInstEmit.Sminp_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x001110<<1xxxxx101000xxxxxxxxxx", AInstEmit.Smlsl_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("0x001110000xxxxx001011xxxxxxxxxx", AInstEmit.Smov_S, typeof(AOpCodeSimdIns));
|
||||
SetA64("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg));
|
||||
SetA64("01011110xx100000011110xxxxxxxxxx", AInstEmit.Sqabs_S, typeof(AOpCodeSimd));
|
||||
SetA64("0>001110<<100000011110xxxxxxxxxx", AInstEmit.Sqabs_V, typeof(AOpCodeSimd));
|
||||
|
|
|
@ -2,6 +2,8 @@ using System.Runtime.Intrinsics.X86;
|
|||
|
||||
public static class AOptimizations
|
||||
{
|
||||
internal static bool FastFP = true;
|
||||
|
||||
private static bool UseAllSseIfAvailable = true;
|
||||
|
||||
private static bool UseSseIfAvailable = true;
|
||||
|
@ -13,4 +15,4 @@ public static class AOptimizations
|
|||
internal static bool UseSse2 = (UseAllSseIfAvailable && UseSse2IfAvailable) && Sse2.IsSupported;
|
||||
internal static bool UseSse41 = (UseAllSseIfAvailable && UseSse41IfAvailable) && Sse41.IsSupported;
|
||||
internal static bool UseSse42 = (UseAllSseIfAvailable && UseSse42IfAvailable) && Sse42.IsSupported;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,14 @@ namespace ChocolArm64
|
|||
{
|
||||
class ATranslatorCache
|
||||
{
|
||||
private const int MaxTotalSize = 2 * 1024 * 256;
|
||||
private const int MaxTimeDelta = 30000;
|
||||
private const int MinCallCountForUpdate = 1000;
|
||||
//Maximum size of the cache, in bytes, measured in ARM code size.
|
||||
private const int MaxTotalSize = 4 * 1024 * 256;
|
||||
|
||||
//Minimum time required in milliseconds for a method to be eligible for deletion.
|
||||
private const int MinTimeDelta = 2 * 60000;
|
||||
|
||||
//Minimum number of calls required to update the timestamp.
|
||||
private const int MinCallCountForUpdate = 250;
|
||||
|
||||
private class CacheBucket
|
||||
{
|
||||
|
@ -134,7 +139,7 @@ namespace ChocolArm64
|
|||
|
||||
int TimeDelta = RingDelta(Bucket.Timestamp, Timestamp);
|
||||
|
||||
if ((uint)TimeDelta <= (uint)MaxTimeDelta)
|
||||
if ((uint)TimeDelta <= (uint)MinTimeDelta)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -8,15 +8,26 @@ namespace ChocolArm64.Decoder
|
|||
|
||||
public AOpCodeSimdRegElemF(AInst Inst, long Position, int OpCode) : base(Inst, Position, OpCode)
|
||||
{
|
||||
if ((Size & 1) != 0)
|
||||
switch ((OpCode >> 21) & 3) // sz:L
|
||||
{
|
||||
Index = (OpCode >> 11) & 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index = (OpCode >> 21) & 1 |
|
||||
(OpCode >> 10) & 2;
|
||||
case 0: // H:0
|
||||
Index = (OpCode >> 10) & 2; // 0, 2
|
||||
|
||||
break;
|
||||
|
||||
case 1: // H:1
|
||||
Index = (OpCode >> 10) & 2;
|
||||
Index++; // 1, 3
|
||||
|
||||
break;
|
||||
|
||||
case 2: // H
|
||||
Index = (OpCode >> 11) & 1; // 0, 1
|
||||
|
||||
break;
|
||||
|
||||
default: Emitter = AInstEmit.Und; return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using ChocolArm64.Translation;
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
using static ChocolArm64.Instruction.AInstEmitAluHelper;
|
||||
|
||||
|
@ -117,9 +118,18 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
Context.EmitLdc_I4(Op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
if (Lzcnt.IsSupported)
|
||||
{
|
||||
Type TValue = Op.RegisterSize == ARegisterSize.Int32 ? typeof(uint) : typeof(ulong);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros));
|
||||
Context.EmitCall(typeof(Lzcnt).GetMethod(nameof(Lzcnt.LeadingZeroCount), new Type[] { TValue }));
|
||||
}
|
||||
else
|
||||
{
|
||||
Context.EmitLdc_I4(Op.RegisterSize == ARegisterSize.Int32 ? 32 : 64);
|
||||
|
||||
ASoftFallback.EmitCall(Context, nameof(ASoftFallback.CountLeadingZeros));
|
||||
}
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -23,11 +23,11 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Call(Context, nameof(Sse2.CompareEqual));
|
||||
EmitSse2Op(Context, nameof(Sse2.CompareEqual));
|
||||
}
|
||||
else if (Op.Size == 3 && AOptimizations.UseSse41)
|
||||
{
|
||||
EmitSse41Call(Context, nameof(Sse41.CompareEqual));
|
||||
EmitSse41Op(Context, nameof(Sse41.CompareEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -61,11 +61,11 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Op.Size < 3 && AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Call(Context, nameof(Sse2.CompareGreaterThan));
|
||||
EmitSse2Op(Context, nameof(Sse2.CompareGreaterThan));
|
||||
}
|
||||
else if (Op.Size == 3 && AOptimizations.UseSse42)
|
||||
{
|
||||
EmitSse42Call(Context, nameof(Sse42.CompareGreaterThan));
|
||||
EmitSse42Op(Context, nameof(Sse42.CompareGreaterThan));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -158,7 +158,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2CallF(Context, nameof(Sse.CompareEqualScalar));
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareEqualScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -171,7 +171,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2CallF(Context, nameof(Sse.CompareEqual));
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -184,7 +184,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2CallF(Context, nameof(Sse.CompareGreaterThanOrEqualScalar));
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanOrEqualScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -197,7 +197,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2CallF(Context, nameof(Sse.CompareGreaterThanOrEqual));
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanOrEqual));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -210,7 +210,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitScalarSseOrSse2CallF(Context, nameof(Sse.CompareGreaterThanScalar));
|
||||
EmitScalarSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThanScalar));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -223,7 +223,7 @@ namespace ChocolArm64.Instruction
|
|||
if (Context.CurrOp is AOpCodeSimdReg && AOptimizations.UseSse
|
||||
&& AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorSseOrSse2CallF(Context, nameof(Sse.CompareGreaterThan));
|
||||
EmitVectorSseOrSse2OpF(Context, nameof(Sse.CompareGreaterThan));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3,6 +3,8 @@ using ChocolArm64.State;
|
|||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
||||
|
||||
|
@ -14,11 +16,48 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
if (Op.Size == 1 && Op.Opc == 0)
|
||||
{
|
||||
//Double -> Single.
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleZero));
|
||||
|
||||
EmitFloatCast(Context, Op.Opc);
|
||||
EmitLdvecWithCastToDouble(Context, Op.Rn);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Opc);
|
||||
Type[] Types = new Type[] { typeof(Vector128<float>), typeof(Vector128<double>) };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Single), Types));
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
}
|
||||
else if (Op.Size == 0 && Op.Opc == 1)
|
||||
{
|
||||
//Single -> Double.
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleZero));
|
||||
|
||||
Context.EmitLdvec(Op.Rn);
|
||||
|
||||
Type[] Types = new Type[] { typeof(Vector128<double>), typeof(Vector128<float>) };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ConvertScalarToVector128Double), Types));
|
||||
|
||||
EmitStvecWithCastFromDouble(Context, Op.Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Invalid encoding.
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rn, 0, Op.Size);
|
||||
|
||||
EmitFloatCast(Context, Op.Opc);
|
||||
|
||||
EmitScalarSetF(Context, Op.Rd, Op.Opc);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Fcvtas_Gp(AILEmitterCtx Context)
|
||||
|
|
|
@ -4,7 +4,6 @@ using ChocolArm64.Translation;
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.Intrinsics;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
|
@ -12,6 +11,38 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
static class AInstEmitSimdHelper
|
||||
{
|
||||
public static readonly Type[] IntTypesPerSizeLog2 = new Type[]
|
||||
{
|
||||
typeof(sbyte),
|
||||
typeof(short),
|
||||
typeof(int),
|
||||
typeof(long)
|
||||
};
|
||||
|
||||
public static readonly Type[] UIntTypesPerSizeLog2 = new Type[]
|
||||
{
|
||||
typeof(byte),
|
||||
typeof(ushort),
|
||||
typeof(uint),
|
||||
typeof(ulong)
|
||||
};
|
||||
|
||||
public static readonly Type[] VectorIntTypesPerSizeLog2 = new Type[]
|
||||
{
|
||||
typeof(Vector128<sbyte>),
|
||||
typeof(Vector128<short>),
|
||||
typeof(Vector128<int>),
|
||||
typeof(Vector128<long>)
|
||||
};
|
||||
|
||||
public static readonly Type[] VectorUIntTypesPerSizeLog2 = new Type[]
|
||||
{
|
||||
typeof(Vector128<byte>),
|
||||
typeof(Vector128<ushort>),
|
||||
typeof(Vector128<uint>),
|
||||
typeof(Vector128<ulong>)
|
||||
};
|
||||
|
||||
[Flags]
|
||||
public enum OperFlags
|
||||
{
|
||||
|
@ -36,56 +67,32 @@ namespace ChocolArm64.Instruction
|
|||
return (8 << (Op.Size + 1)) - Op.Imm;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void EmitSse2Call(AILEmitterCtx Context, string Name)
|
||||
public static void EmitSse2Op(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
EmitSseCall(Context, Name, typeof(Sse2));
|
||||
EmitSseOp(Context, Name, typeof(Sse2));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void EmitSse41Call(AILEmitterCtx Context, string Name)
|
||||
public static void EmitSse41Op(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
EmitSseCall(Context, Name, typeof(Sse41));
|
||||
EmitSseOp(Context, Name, typeof(Sse41));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void EmitSse42Call(AILEmitterCtx Context, string Name)
|
||||
public static void EmitSse42Op(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
EmitSseCall(Context, Name, typeof(Sse42));
|
||||
EmitSseOp(Context, Name, typeof(Sse42));
|
||||
}
|
||||
|
||||
private static void EmitSseCall(AILEmitterCtx Context, string Name, Type Type)
|
||||
private static void EmitSseOp(AILEmitterCtx Context, string Name, Type Type)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
void Ldvec(int Reg)
|
||||
{
|
||||
Context.EmitLdvec(Reg);
|
||||
EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToSByte)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt16)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt32)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt64)); break;
|
||||
}
|
||||
}
|
||||
|
||||
Ldvec(Op.Rn);
|
||||
|
||||
Type BaseType = null;
|
||||
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: BaseType = typeof(Vector128<sbyte>); break;
|
||||
case 1: BaseType = typeof(Vector128<short>); break;
|
||||
case 2: BaseType = typeof(Vector128<int>); break;
|
||||
case 3: BaseType = typeof(Vector128<long>); break;
|
||||
}
|
||||
Type BaseType = VectorIntTypesPerSizeLog2[Op.Size];
|
||||
|
||||
if (Op is AOpCodeSimdReg BinOp)
|
||||
{
|
||||
Ldvec(BinOp.Rm);
|
||||
EmitLdvecWithSignedCast(Context, BinOp.Rm, Op.Size);
|
||||
|
||||
Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType, BaseType }));
|
||||
}
|
||||
|
@ -94,15 +101,7 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCall(Type.GetMethod(Name, new Type[] { BaseType }));
|
||||
}
|
||||
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSByteToSingle)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16ToSingle)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32ToSingle)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt64ToSingle)); break;
|
||||
}
|
||||
|
||||
Context.EmitStvec(Op.Rd);
|
||||
EmitStvecWithSignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
|
@ -110,17 +109,91 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void EmitScalarSseOrSse2CallF(AILEmitterCtx Context, string Name)
|
||||
public static void EmitLdvecWithSignedCast(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
EmitSseOrSse2CallF(Context, Name, true);
|
||||
Context.EmitLdvec(Reg);
|
||||
|
||||
switch (Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToSByte)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt16)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt32)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToInt64)); break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorSseOrSse2CallF(AILEmitterCtx Context, string Name)
|
||||
public static void EmitLdvecWithCastToDouble(AILEmitterCtx Context, int Reg)
|
||||
{
|
||||
EmitSseOrSse2CallF(Context, Name, false);
|
||||
Context.EmitLdvec(Reg);
|
||||
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToDouble));
|
||||
}
|
||||
|
||||
public static void EmitSseOrSse2CallF(AILEmitterCtx Context, string Name, bool Scalar)
|
||||
public static void EmitStvecWithCastFromDouble(AILEmitterCtx Context, int Reg)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorDoubleToSingle));
|
||||
|
||||
Context.EmitStvec(Reg);
|
||||
}
|
||||
|
||||
public static void EmitLdvecWithUnsignedCast(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
Context.EmitLdvec(Reg);
|
||||
|
||||
switch (Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToByte)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToUInt16)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToUInt32)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleToUInt64)); break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitStvecWithSignedCast(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSByteToSingle)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16ToSingle)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32ToSingle)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt64ToSingle)); break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
Context.EmitStvec(Reg);
|
||||
}
|
||||
|
||||
public static void EmitStvecWithUnsignedCast(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
switch (Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorByteToSingle)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorUInt16ToSingle)); break;
|
||||
case 2: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorUInt32ToSingle)); break;
|
||||
case 3: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorUInt64ToSingle)); break;
|
||||
|
||||
default: throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
Context.EmitStvec(Reg);
|
||||
}
|
||||
|
||||
public static void EmitScalarSseOrSse2OpF(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
EmitSseOrSse2OpF(Context, Name, true);
|
||||
}
|
||||
|
||||
public static void EmitVectorSseOrSse2OpF(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
EmitSseOrSse2OpF(Context, Name, false);
|
||||
}
|
||||
|
||||
public static void EmitSseOrSse2OpF(AILEmitterCtx Context, string Name, bool Scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
|
@ -233,25 +306,19 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
Context.EmitLdc_I4((int)RoundMode);
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
|
||||
Type[] Types = new Type[] { null, typeof(MidpointRounding) };
|
||||
|
||||
Types[0] = SizeF == 0
|
||||
? typeof(float)
|
||||
: typeof(double);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), Types);
|
||||
MthdInfo = typeof(MathF).GetMethod(nameof(MathF.Round), new Type[] { typeof(float), typeof(MidpointRounding) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), Types);
|
||||
MthdInfo = typeof(Math).GetMethod(nameof(Math.Round), new Type[] { typeof(double), typeof(MidpointRounding) });
|
||||
}
|
||||
|
||||
Context.EmitLdc_I4((int)RoundMode);
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
||||
|
@ -275,24 +342,17 @@ namespace ChocolArm64.Instruction
|
|||
Context.EmitCall(MthdInfo);
|
||||
}
|
||||
|
||||
public static void EmitBinarySoftFloatCall(AILEmitterCtx Context, string Name)
|
||||
public static void EmitSoftFloatCall(AILEmitterCtx Context, string Name)
|
||||
{
|
||||
IAOpCodeSimd Op = (IAOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
Type Type = (Op.Size & 1) == 0
|
||||
? typeof(ASoftFloat_32)
|
||||
: typeof(ASoftFloat_64);
|
||||
|
||||
MethodInfo MthdInfo;
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
MthdInfo = typeof(ASoftFloat).GetMethod(Name, new Type[] { typeof(float), typeof(float) });
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
MthdInfo = typeof(ASoftFloat).GetMethod(Name, new Type[] { typeof(double), typeof(double) });
|
||||
}
|
||||
|
||||
Context.EmitCall(MthdInfo);
|
||||
Context.EmitCall(Type, Name);
|
||||
}
|
||||
|
||||
public static void EmitScalarBinaryOpByElemF(AILEmitterCtx Context, Action Emit)
|
||||
|
@ -813,6 +873,42 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorPairwiseOpF(AILEmitterCtx Context, Action Emit)
|
||||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int SizeF = Op.Size & 1;
|
||||
|
||||
int Words = Op.GetBitsCount() >> 4;
|
||||
int Pairs = Words >> SizeF + 2;
|
||||
|
||||
for (int Index = 0; Index < Pairs; Index++)
|
||||
{
|
||||
int Idx = Index << 1;
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rn, Idx, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rn, Idx + 1, SizeF);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorExtractF(Context, Op.Rm, Idx, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rm, Idx + 1, SizeF);
|
||||
|
||||
Emit();
|
||||
|
||||
EmitVectorInsertTmpF(Context, Pairs + Index, SizeF);
|
||||
EmitVectorInsertTmpF(Context, Index, SizeF);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum SaturatingFlags
|
||||
{
|
||||
|
@ -1147,8 +1243,21 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitScalarSetF(AILEmitterCtx Context, int Reg, int Size)
|
||||
{
|
||||
EmitVectorZeroAll(Context, Reg);
|
||||
EmitVectorInsertF(Context, Reg, 0, Size);
|
||||
if (AOptimizations.UseSse41 && Size == 0)
|
||||
{
|
||||
//If the type is float, we can perform insertion and
|
||||
//zero the upper bits with a single instruction (INSERTPS);
|
||||
Context.EmitLdvec(Reg);
|
||||
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.Sse41VectorInsertScalarSingle));
|
||||
|
||||
Context.EmitStvec(Reg);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorZeroAll(Context, Reg);
|
||||
EmitVectorInsertF(Context, Reg, 0, Size);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorExtractSx(AILEmitterCtx Context, int Reg, int Index, int Size)
|
||||
|
@ -1199,8 +1308,17 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void EmitVectorZeroAll(AILEmitterCtx Context, int Rd)
|
||||
{
|
||||
EmitVectorZeroLower(Context, Rd);
|
||||
EmitVectorZeroUpper(Context, Rd);
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorSingleZero));
|
||||
|
||||
Context.EmitStvec(Rd);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorZeroLower(Context, Rd);
|
||||
EmitVectorZeroUpper(Context, Rd);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorZeroLower(AILEmitterCtx Context, int Rd)
|
||||
|
@ -1213,9 +1331,32 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorInsertTmp(Context, 0, 3, 0);
|
||||
}
|
||||
|
||||
public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Rd)
|
||||
public static void EmitVectorZeroUpper(AILEmitterCtx Context, int Reg)
|
||||
{
|
||||
EmitVectorInsert(Context, Rd, 1, 3, 0);
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
//TODO: Use MoveScalar once it is fixed, as of the
|
||||
//time of writing it just crashes the JIT.
|
||||
EmitLdvecWithUnsignedCast(Context, Reg, 3);
|
||||
|
||||
Type[] Types = new Type[] { typeof(Vector128<ulong>), typeof(byte) };
|
||||
|
||||
//Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.MoveScalar), Types));
|
||||
|
||||
Context.EmitLdc_I4(8);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical128BitLane), Types));
|
||||
|
||||
Context.EmitLdc_I4(8);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Reg, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorInsert(Context, Reg, 1, 3, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitVectorZero32_128(AILEmitterCtx Context, int Reg)
|
||||
|
|
|
@ -15,7 +15,7 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Call(Context, nameof(Sse2.And));
|
||||
EmitSse2Op(Context, nameof(Sse2.And));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -25,11 +25,36 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Bic_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () =>
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
});
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Type[] Types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
};
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.AndNot), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpZx(Context, () =>
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
Context.Emit(OpCodes.And);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bic_Vi(AILEmitterCtx Context)
|
||||
|
@ -55,59 +80,124 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
|
||||
if (NotRm)
|
||||
Type[] Types = new Type[]
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
};
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
|
||||
string Name = NotRm ? nameof(Sse2.AndNot) : nameof(Sse2.And);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(Name, Types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rm, Index, Op.Size);
|
||||
|
||||
if (NotRm)
|
||||
{
|
||||
Context.Emit(OpCodes.Not);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rd, Index, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Bsl_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorTernaryOpZx(Context, () =>
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
Context.EmitSttmp();
|
||||
Context.EmitLdtmp();
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.And);
|
||||
Type[] Types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
};
|
||||
|
||||
Context.EmitLdtmp();
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
});
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), Types));
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Xor), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorTernaryOpZx(Context, () =>
|
||||
{
|
||||
Context.EmitSttmp();
|
||||
Context.EmitLdtmp();
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
Context.Emit(OpCodes.And);
|
||||
|
||||
Context.EmitLdtmp();
|
||||
|
||||
Context.Emit(OpCodes.Xor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Eor_V(AILEmitterCtx Context)
|
||||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Call(Context, nameof(Sse2.Xor));
|
||||
EmitSse2Op(Context, nameof(Sse2.Xor));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -133,7 +223,7 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
EmitSse2Call(Context, nameof(Sse2.Or));
|
||||
EmitSse2Op(Context, nameof(Sse2.Or));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -3,6 +3,7 @@ using ChocolArm64.State;
|
|||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
||||
|
||||
|
@ -14,19 +15,44 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
|
||||
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: Context.Emit(OpCodes.Conv_U1); break;
|
||||
case 1: Context.Emit(OpCodes.Conv_U2); break;
|
||||
case 2: Context.Emit(OpCodes.Conv_U4); break;
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
Type[] Types = new Type[] { UIntTypesPerSizeLog2[Op.Size] };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
int Bytes = Op.GetBitsCount() >> 3;
|
||||
int Elems = Bytes >> Op.Size;
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
Context.EmitLdintzr(Op.Rn);
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +249,17 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorImmUnaryOp(Context, () => Context.Emit(OpCodes.Not));
|
||||
}
|
||||
|
||||
public static void Smov_S(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdIns Op = (AOpCodeSimdIns)Context.CurrOp;
|
||||
|
||||
EmitVectorExtractSx(Context, Op.Rn, Op.DstIndex, Op.Size);
|
||||
|
||||
EmitIntZeroUpperIfNeeded(Context);
|
||||
|
||||
Context.EmitStintzr(Op.Rd);
|
||||
}
|
||||
|
||||
public static void Tbl_V(AILEmitterCtx Context)
|
||||
{
|
||||
AOpCodeSimdTbl Op = (AOpCodeSimdTbl)Context.CurrOp;
|
||||
|
@ -295,25 +332,91 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
int Part = Op.RegisterSize == ARegisterSize.SIMD128 ? Elems : 0;
|
||||
|
||||
if (Part != 0)
|
||||
if (AOptimizations.UseSse41 && Op.Size < 2)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
void EmitZeroVector()
|
||||
{
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt16Zero)); break;
|
||||
case 1: AVectorHelper.EmitCall(Context, nameof(AVectorHelper.VectorInt32Zero)); break;
|
||||
}
|
||||
}
|
||||
|
||||
//For XTN, first operand is source, second operand is 0.
|
||||
//For XTN2, first operand is 0, second operand is source.
|
||||
if (Part != 0)
|
||||
{
|
||||
EmitZeroVector();
|
||||
}
|
||||
|
||||
EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size + 1);
|
||||
|
||||
//Set mask to discard the upper half of the wide elements.
|
||||
switch (Op.Size)
|
||||
{
|
||||
case 0: Context.EmitLdc_I4(0x00ff); break;
|
||||
case 1: Context.EmitLdc_I4(0x0000ffff); break;
|
||||
}
|
||||
|
||||
Type WideType = IntTypesPerSizeLog2[Op.Size + 1];
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.SetAllVector128), new Type[] { WideType }));
|
||||
|
||||
WideType = VectorIntTypesPerSizeLog2[Op.Size + 1];
|
||||
|
||||
Type[] WideTypes = new Type[] { WideType, WideType };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.And), WideTypes));
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitZeroVector();
|
||||
}
|
||||
|
||||
//Pack values with signed saturation, the signed saturation shouldn't
|
||||
//saturate anything since the upper bits were masked off.
|
||||
Type SseType = Op.Size == 0 ? typeof(Sse2) : typeof(Sse41);
|
||||
|
||||
Context.EmitCall(SseType.GetMethod(nameof(Sse2.PackUnsignedSaturate), WideTypes));
|
||||
|
||||
if (Part != 0)
|
||||
{
|
||||
//For XTN2, we additionally need to discard the upper bits
|
||||
//of the target register and OR the result with it.
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
Type NarrowType = VectorUIntTypesPerSizeLog2[Op.Size];
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Or), new Type[] { NarrowType, NarrowType }));
|
||||
}
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
else
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
|
||||
if (Part != 0)
|
||||
{
|
||||
Context.EmitLdvec(Op.Rd);
|
||||
Context.EmitStvectmp();
|
||||
}
|
||||
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
}
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractZx(Context, Op.Rn, Index, Op.Size + 1);
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
EmitVectorInsertTmp(Context, Part + Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,7 +432,8 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static void EmitIntZeroUpperIfNeeded(AILEmitterCtx Context)
|
||||
{
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32)
|
||||
if (Context.CurrOp.RegisterSize == ARegisterSize.Int32 ||
|
||||
Context.CurrOp.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
Context.Emit(OpCodes.Conv_U4);
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
|
@ -394,28 +498,64 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdReg Op = (AOpCodeSimdReg)Context.CurrOp;
|
||||
|
||||
int Words = Op.GetBitsCount() >> 4;
|
||||
int Pairs = Words >> Op.Size;
|
||||
|
||||
int Base = Part != 0 ? Pairs : 0;
|
||||
|
||||
for (int Index = 0; Index < Pairs; Index++)
|
||||
if (AOptimizations.UseSse2)
|
||||
{
|
||||
int Idx = Index << 1;
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rm, Op.Size);
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Base + Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Base + Index, Op.Size);
|
||||
Type[] Types = new Type[]
|
||||
{
|
||||
VectorUIntTypesPerSizeLog2[Op.Size],
|
||||
VectorUIntTypesPerSizeLog2[Op.Size]
|
||||
};
|
||||
|
||||
EmitVectorInsertTmp(Context, Idx + 1, Op.Size);
|
||||
EmitVectorInsertTmp(Context, Idx, Op.Size);
|
||||
string Name = Part == 0 || (Part != 0 && Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
? nameof(Sse2.UnpackLow)
|
||||
: nameof(Sse2.UnpackHigh);
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(Name, Types));
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64 && Part != 0)
|
||||
{
|
||||
Context.EmitLdc_I4(8);
|
||||
|
||||
Type[] ShTypes = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical128BitLane), ShTypes));
|
||||
}
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64 && Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
else
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
int Words = Op.GetBitsCount() >> 4;
|
||||
int Pairs = Words >> Op.Size;
|
||||
|
||||
int Base = Part != 0 ? Pairs : 0;
|
||||
|
||||
for (int Index = 0; Index < Pairs; Index++)
|
||||
{
|
||||
int Idx = Index << 1;
|
||||
|
||||
EmitVectorExtractZx(Context, Op.Rn, Base + Index, Op.Size);
|
||||
EmitVectorExtractZx(Context, Op.Rm, Base + Index, Op.Size);
|
||||
|
||||
EmitVectorInsertTmp(Context, Idx + 1, Op.Size);
|
||||
EmitVectorInsertTmp(Context, Idx, Op.Size);
|
||||
}
|
||||
|
||||
Context.EmitLdvectmp();
|
||||
Context.EmitStvec(Op.Rd);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ using ChocolArm64.State;
|
|||
using ChocolArm64.Translation;
|
||||
using System;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
|
||||
using static ChocolArm64.Instruction.AInstEmitSimdHelper;
|
||||
|
||||
|
@ -31,12 +32,32 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
EmitVectorUnaryOpZx(Context, () =>
|
||||
if (AOptimizations.UseSse2 && Op.Size > 0)
|
||||
{
|
||||
Type[] Types = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitLdc_I4(GetImmShl(Op));
|
||||
|
||||
Context.Emit(OpCodes.Shl);
|
||||
});
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftLeftLogical), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorUnaryOpZx(Context, () =>
|
||||
{
|
||||
Context.EmitLdc_I4(GetImmShl(Op));
|
||||
|
||||
Context.Emit(OpCodes.Shl);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static void Shll_V(AILEmitterCtx Context)
|
||||
|
@ -167,7 +188,30 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Sshr_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmOp(Context, ShrImmFlags.VectorSx);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2 && Op.Size > 0
|
||||
&& Op.Size < 3)
|
||||
{
|
||||
Type[] Types = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
|
||||
EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), Types));
|
||||
|
||||
EmitStvecWithSignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmOp(Context, ShrImmFlags.VectorSx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Ssra_S(AILEmitterCtx Context)
|
||||
|
@ -177,7 +221,33 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Ssra_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorShrImmOpSx(Context, ShrImmFlags.Accumulate);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2 && Op.Size > 0
|
||||
&& Op.Size < 3)
|
||||
{
|
||||
Type[] TypesSra = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
Type[] TypesAdd = new Type[] { VectorIntTypesPerSizeLog2[Op.Size], VectorIntTypesPerSizeLog2[Op.Size] };
|
||||
|
||||
EmitLdvecWithSignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithSignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightArithmetic), TypesSra));
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd));
|
||||
|
||||
EmitStvecWithSignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorShrImmOpSx(Context, ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Uqrshrn_S(AILEmitterCtx Context)
|
||||
|
@ -239,7 +309,29 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Ushr_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitShrImmOp(Context, ShrImmFlags.VectorZx);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2 && Op.Size > 0)
|
||||
{
|
||||
Type[] Types = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), Types));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitShrImmOp(Context, ShrImmFlags.VectorZx);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Usra_S(AILEmitterCtx Context)
|
||||
|
@ -249,7 +341,32 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
public static void Usra_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitVectorShrImmOpZx(Context, ShrImmFlags.Accumulate);
|
||||
AOpCodeSimdShImm Op = (AOpCodeSimdShImm)Context.CurrOp;
|
||||
|
||||
if (AOptimizations.UseSse2 && Op.Size > 0)
|
||||
{
|
||||
Type[] TypesSrl = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], typeof(byte) };
|
||||
Type[] TypesAdd = new Type[] { VectorUIntTypesPerSizeLog2[Op.Size], VectorUIntTypesPerSizeLog2[Op.Size] };
|
||||
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
EmitLdvecWithUnsignedCast(Context, Op.Rn, Op.Size);
|
||||
|
||||
Context.EmitLdc_I4(GetImmShr(Op));
|
||||
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.ShiftRightLogical), TypesSrl));
|
||||
Context.EmitCall(typeof(Sse2).GetMethod(nameof(Sse2.Add), TypesAdd));
|
||||
|
||||
EmitStvecWithUnsignedCast(Context, Op.Rd, Op.Size);
|
||||
|
||||
if (Op.RegisterSize == ARegisterSize.SIMD64)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorShrImmOpZx(Context, ShrImmFlags.Accumulate);
|
||||
}
|
||||
}
|
||||
|
||||
private static void EmitVectorShl(AILEmitterCtx Context, bool Signed)
|
||||
|
|
|
@ -386,7 +386,7 @@ namespace ChocolArm64.Instruction
|
|||
#endregion
|
||||
|
||||
#region "Count"
|
||||
public static ulong CountLeadingSigns(ulong Value, int Size)
|
||||
public static ulong CountLeadingSigns(ulong Value, int Size) // Size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
Value ^= Value >> 1;
|
||||
|
||||
|
@ -405,9 +405,9 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
private static readonly byte[] ClzNibbleTbl = { 4, 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
public static ulong CountLeadingZeros(ulong Value, int Size)
|
||||
public static ulong CountLeadingZeros(ulong Value, int Size) // Size is 8, 16, 32 or 64 (SIMD&FP or Base Inst.).
|
||||
{
|
||||
if (Value == 0)
|
||||
if (Value == 0ul)
|
||||
{
|
||||
return (ulong)Size;
|
||||
}
|
||||
|
@ -426,12 +426,17 @@ namespace ChocolArm64.Instruction
|
|||
return (ulong)Count;
|
||||
}
|
||||
|
||||
public static uint CountSetBits8(uint Value)
|
||||
public static ulong CountSetBits8(ulong Value) // "Size" is 8 (SIMD&FP Inst.).
|
||||
{
|
||||
Value = ((Value >> 1) & 0x55) + (Value & 0x55);
|
||||
Value = ((Value >> 2) & 0x33) + (Value & 0x33);
|
||||
if (Value == 0xfful)
|
||||
{
|
||||
return 8ul;
|
||||
}
|
||||
|
||||
return (Value >> 4) + (Value & 0x0f);
|
||||
Value = ((Value >> 1) & 0x55ul) + (Value & 0x55ul);
|
||||
Value = ((Value >> 2) & 0x33ul) + (Value & 0x33ul);
|
||||
|
||||
return (Value >> 4) + (Value & 0x0ful);
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -227,7 +227,16 @@ namespace ChocolArm64.Instruction
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static double VectorExtractDouble(Vector128<float> Vector, byte Index)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(VectorExtractIntSx(Vector, Index, 3));
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble(Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
return BitConverter.Int64BitsToDouble((long)VectorExtractIntZx(Vector, Index, 3));
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
|
@ -235,41 +244,49 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
|
||||
|
||||
case 1:
|
||||
return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
|
||||
|
||||
case 2:
|
||||
return Sse41.Extract(Sse.StaticCast<float, int>(Vector), Index);
|
||||
|
||||
case 3:
|
||||
return Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index);
|
||||
return (sbyte)Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return (short)Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
|
||||
}
|
||||
else if (Size == 2)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, int>(Vector), Index);
|
||||
}
|
||||
else if (Size == 3)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, long>(Vector), Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
return (sbyte)VectorExtractIntZx(Vector, Index, Size);
|
||||
|
||||
case 1:
|
||||
return (short)VectorExtractIntZx(Vector, Index, Size);
|
||||
|
||||
case 2:
|
||||
return (int)VectorExtractIntZx(Vector, Index, Size);
|
||||
|
||||
case 3:
|
||||
return (long)VectorExtractIntZx(Vector, Index, Size);
|
||||
return (sbyte)VectorExtractIntZx(Vector, Index, Size);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return (short)VectorExtractIntZx(Vector, Index, Size);
|
||||
}
|
||||
else if (Size == 2)
|
||||
{
|
||||
return (int)VectorExtractIntZx(Vector, Index, Size);
|
||||
}
|
||||
else if (Size == 3)
|
||||
{
|
||||
return (long)VectorExtractIntZx(Vector, Index, Size);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
|
@ -280,22 +297,26 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
return Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
|
||||
|
||||
case 1:
|
||||
return Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
|
||||
|
||||
case 2:
|
||||
return Sse41.Extract(Sse.StaticCast<float, uint>(Vector), Index);
|
||||
|
||||
case 3:
|
||||
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), Index);
|
||||
return Sse41.Extract(Sse.StaticCast<float, byte>(Vector), Index);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), Index);
|
||||
}
|
||||
else if (Size == 2)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, uint>(Vector), Index);
|
||||
}
|
||||
else if (Size == 3)
|
||||
{
|
||||
return Sse41.Extract(Sse.StaticCast<float, ulong>(Vector), Index);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -305,35 +326,35 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
ushort Value = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)ShortIdx);
|
||||
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
return (byte)(Value >> (Index & 1) * 8);
|
||||
|
||||
case 1:
|
||||
return Value;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
ushort Value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 1));
|
||||
|
||||
if (Size == 2)
|
||||
{
|
||||
return (uint)(Value | (Value1 << 16));
|
||||
}
|
||||
|
||||
ushort Value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 2));
|
||||
ushort Value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 3));
|
||||
|
||||
return ((ulong)Value << 0) |
|
||||
((ulong)Value1 << 16) |
|
||||
((ulong)Value2 << 32) |
|
||||
((ulong)Value3 << 48);
|
||||
}
|
||||
return (byte)(Value >> (Index & 1) * 8);
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
else if (Size == 2 || Size == 3)
|
||||
{
|
||||
ushort Value1 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 1));
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
if (Size == 2)
|
||||
{
|
||||
return (uint)(Value | (Value1 << 16));
|
||||
}
|
||||
|
||||
ushort Value2 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 2));
|
||||
ushort Value3 = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)(ShortIdx + 3));
|
||||
|
||||
return ((ulong)Value << 0) |
|
||||
((ulong)Value1 << 16) |
|
||||
((ulong)Value2 << 32) |
|
||||
((ulong)Value3 << 48);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
|
@ -370,22 +391,26 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(Vector), (byte)Value, Index));
|
||||
|
||||
case 1:
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
|
||||
|
||||
case 2:
|
||||
return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(Vector), (uint)Value, Index));
|
||||
|
||||
case 3:
|
||||
return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(Vector), Value, Index));
|
||||
return Sse.StaticCast<byte, float>(Sse41.Insert(Sse.StaticCast<float, byte>(Vector), (byte)Value, Index));
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
|
||||
}
|
||||
else if (Size == 2)
|
||||
{
|
||||
return Sse.StaticCast<uint, float>(Sse41.Insert(Sse.StaticCast<float, uint>(Vector), (uint)Value, Index));
|
||||
}
|
||||
else if (Size == 3)
|
||||
{
|
||||
return Sse.StaticCast<ulong, float>(Sse41.Insert(Sse.StaticCast<float, ulong>(Vector), Value, Index));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -395,41 +420,39 @@ namespace ChocolArm64.Instruction
|
|||
? Index >> 1
|
||||
: Index << (Size - 1);
|
||||
|
||||
switch (Size)
|
||||
if (Size == 0)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ushort ShortVal = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)ShortIdx);
|
||||
ushort ShortVal = Sse2.Extract(Sse.StaticCast<float, ushort>(Vector), (byte)ShortIdx);
|
||||
|
||||
int Shift = (Index & 1) * 8;
|
||||
int Shift = (Index & 1) * 8;
|
||||
|
||||
ShortVal &= (ushort)(0xff00 >> Shift);
|
||||
ShortVal &= (ushort)(0xff00 >> Shift);
|
||||
|
||||
ShortVal |= (ushort)((byte)Value << Shift);
|
||||
ShortVal |= (ushort)((byte)Value << Shift);
|
||||
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(ShortVector, ShortVal, (byte)ShortIdx));
|
||||
}
|
||||
|
||||
case 1:
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
{
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 0), (byte)(ShortIdx + 0));
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 16), (byte)(ShortIdx + 1));
|
||||
|
||||
if (Size == 3)
|
||||
{
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 32), (byte)(ShortIdx + 2));
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 48), (byte)(ShortIdx + 3));
|
||||
}
|
||||
|
||||
return Sse.StaticCast<ushort, float>(ShortVector);
|
||||
}
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(ShortVector, ShortVal, (byte)ShortIdx));
|
||||
}
|
||||
else if (Size == 1)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(Sse2.Insert(Sse.StaticCast<float, ushort>(Vector), (ushort)Value, Index));
|
||||
}
|
||||
else if (Size == 2 || Size == 3)
|
||||
{
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 0), (byte)(ShortIdx + 0));
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 16), (byte)(ShortIdx + 1));
|
||||
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
if (Size == 3)
|
||||
{
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 32), (byte)(ShortIdx + 2));
|
||||
ShortVector = Sse2.Insert(ShortVector, (ushort)(Value >> 48), (byte)(ShortIdx + 3));
|
||||
}
|
||||
|
||||
return Sse.StaticCast<ushort, float>(ShortVector);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Size));
|
||||
}
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
|
@ -440,7 +463,29 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
if (Sse41.IsSupported)
|
||||
{
|
||||
return Sse41.Insert(Vector, Value, (byte)(Index << 4));
|
||||
//Note: The if/else if is necessary to enable the JIT to
|
||||
//produce a single INSERTPS instruction instead of the
|
||||
//jump table fallback.
|
||||
if (Index == 0)
|
||||
{
|
||||
return Sse41.Insert(Vector, Value, 0x00);
|
||||
}
|
||||
else if (Index == 1)
|
||||
{
|
||||
return Sse41.Insert(Vector, Value, 0x10);
|
||||
}
|
||||
else if (Index == 2)
|
||||
{
|
||||
return Sse41.Insert(Vector, Value, 0x20);
|
||||
}
|
||||
else if (Index == 3)
|
||||
{
|
||||
return Sse41.Insert(Vector, Value, 0x30);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(Index));
|
||||
}
|
||||
}
|
||||
else if (Sse2.IsSupported)
|
||||
{
|
||||
|
@ -460,6 +505,79 @@ namespace ChocolArm64.Instruction
|
|||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> Sse41VectorInsertScalarSingle(float Value, Vector128<float> Vector)
|
||||
{
|
||||
//Note: 0b1110 is the mask to zero the upper bits.
|
||||
return Sse41.Insert(Vector, Value, 0b1110);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<sbyte> VectorSByteZero()
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<sbyte>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<short> VectorInt16Zero()
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<short>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<int> VectorInt32Zero()
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<int>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<long> VectorInt64Zero()
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<long>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorSingleZero()
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.SetZeroVector128();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<double> VectorDoubleZero()
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
{
|
||||
return Sse2.SetZeroVector128<double>();
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorZero32_128(Vector128<float> Vector)
|
||||
{
|
||||
|
@ -515,6 +633,50 @@ namespace ChocolArm64.Instruction
|
|||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<byte> VectorSingleToByte(Vector128<float> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, byte>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<ushort> VectorSingleToUInt16(Vector128<float> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, ushort>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<uint> VectorSingleToUInt32(Vector128<float> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, uint>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<ulong> VectorSingleToUInt64(Vector128<float> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<float, ulong>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<double> VectorSingleToDouble(Vector128<float> Vector)
|
||||
{
|
||||
|
@ -570,6 +732,50 @@ namespace ChocolArm64.Instruction
|
|||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorByteToSingle(Vector128<byte> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<byte, float>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt16ToSingle(Vector128<ushort> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<ushort, float>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt32ToSingle(Vector128<uint> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<uint, float>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorUInt64ToSingle(Vector128<ulong> Vector)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
{
|
||||
return Sse.StaticCast<ulong, float>(Vector);
|
||||
}
|
||||
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Vector128<float> VectorDoubleToSingle(Vector128<double> Vector)
|
||||
{
|
||||
|
|
|
@ -232,7 +232,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector32(long Position)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
|
@ -245,7 +245,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public Vector128<float> ReadVector64(long Position)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
|
@ -365,7 +365,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector32(long Position, Vector128<float> Value)
|
||||
{
|
||||
if (Sse.IsSupported)
|
||||
|
@ -378,7 +378,7 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void WriteVector64(long Position, Vector128<float> Value)
|
||||
{
|
||||
if (Sse2.IsSupported)
|
||||
|
|
|
@ -182,7 +182,10 @@ namespace Ryujinx.Audio.OpenAL
|
|||
{
|
||||
foreach (Track Td in Tracks.Values)
|
||||
{
|
||||
Td.CallReleaseCallbackIfNeeded();
|
||||
lock (Td)
|
||||
{
|
||||
Td.CallReleaseCallbackIfNeeded();
|
||||
}
|
||||
}
|
||||
|
||||
//If it's not slept it will waste cycles.
|
||||
|
|
|
@ -9,4 +9,8 @@
|
|||
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.HLE.Logging
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public enum LogClass
|
||||
{
|
||||
|
@ -22,6 +22,8 @@ namespace Ryujinx.HLE.Logging
|
|||
ServiceFriend,
|
||||
ServiceFs,
|
||||
ServiceHid,
|
||||
ServiceIrs,
|
||||
ServiceLdr,
|
||||
ServiceLm,
|
||||
ServiceMm,
|
||||
ServiceNfp,
|
|
@ -1,6 +1,6 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.Logging
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class LogEventArgs : EventArgs
|
||||
{
|
|
@ -1,4 +1,4 @@
|
|||
namespace Ryujinx.HLE.Logging
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public enum LogLevel
|
||||
{
|
|
@ -2,18 +2,18 @@ using System;
|
|||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Ryujinx.HLE.Logging
|
||||
namespace Ryujinx.Common.Logging
|
||||
{
|
||||
public class Logger
|
||||
public static class Logger
|
||||
{
|
||||
private bool[] EnabledLevels;
|
||||
private bool[] EnabledClasses;
|
||||
private static bool[] EnabledLevels;
|
||||
private static bool[] EnabledClasses;
|
||||
|
||||
public event EventHandler<LogEventArgs> Updated;
|
||||
public static event EventHandler<LogEventArgs> Updated;
|
||||
|
||||
private Stopwatch Time;
|
||||
private static Stopwatch Time;
|
||||
|
||||
public Logger()
|
||||
static Logger()
|
||||
{
|
||||
EnabledLevels = new bool[Enum.GetNames(typeof(LogLevel)).Length];
|
||||
EnabledClasses = new bool[Enum.GetNames(typeof(LogClass)).Length];
|
||||
|
@ -33,50 +33,50 @@ namespace Ryujinx.HLE.Logging
|
|||
Time.Start();
|
||||
}
|
||||
|
||||
public void SetEnable(LogLevel Level, bool Enabled)
|
||||
public static void SetEnable(LogLevel Level, bool Enabled)
|
||||
{
|
||||
EnabledLevels[(int)Level] = Enabled;
|
||||
}
|
||||
|
||||
public void SetEnable(LogClass Class, bool Enabled)
|
||||
public static void SetEnable(LogClass Class, bool Enabled)
|
||||
{
|
||||
EnabledClasses[(int)Class] = Enabled;
|
||||
}
|
||||
|
||||
internal void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
public static void PrintDebug(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Debug, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
}
|
||||
|
||||
internal void PrintStub(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
public static void PrintStub(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Stub, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
}
|
||||
|
||||
internal void PrintInfo(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
public static void PrintInfo(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Info, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
}
|
||||
|
||||
internal void PrintWarning(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
public static void PrintWarning(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Warning, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
}
|
||||
|
||||
internal void PrintError(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
public static void PrintError(LogClass Class, string Message, [CallerMemberName] string Caller = "")
|
||||
{
|
||||
Print(LogLevel.Error, Class, GetFormattedMessage(Class, Message, Caller));
|
||||
}
|
||||
|
||||
private void Print(LogLevel Level, LogClass Class, string Message)
|
||||
private static void Print(LogLevel Level, LogClass Class, string Message)
|
||||
{
|
||||
if (EnabledLevels[(int)Level] && EnabledClasses[(int)Class])
|
||||
{
|
||||
Updated?.Invoke(this, new LogEventArgs(Level, Time.Elapsed, Message));
|
||||
Updated?.Invoke(null, new LogEventArgs(Level, Time.Elapsed, Message));
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFormattedMessage(LogClass Class, string Message, string Caller)
|
||||
private static string GetFormattedMessage(LogClass Class, string Message, string Caller)
|
||||
{
|
||||
return $"{Class} {Caller}: {Message}";
|
||||
}
|
16
Ryujinx.Common/Ryujinx.Common.csproj
Normal file
16
Ryujinx.Common/Ryujinx.Common.csproj
Normal file
|
@ -0,0 +1,16 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
<RuntimeIdentifiers>win10-x64;osx-x64;linux-x64</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -5,89 +5,61 @@ namespace Ryujinx.Graphics.Gal
|
|||
[Flags]
|
||||
public enum GalImageFormat
|
||||
{
|
||||
Snorm = 1 << 27,
|
||||
Unorm = 1 << 28,
|
||||
Sint = 1 << 29,
|
||||
Uint = 1 << 30,
|
||||
Sfloat = 1 << 31,
|
||||
Astc2DStart,
|
||||
Astc2D4x4,
|
||||
Astc2D5x4,
|
||||
Astc2D5x5,
|
||||
Astc2D6x5,
|
||||
Astc2D6x6,
|
||||
Astc2D8x5,
|
||||
Astc2D8x6,
|
||||
Astc2D8x8,
|
||||
Astc2D10x5,
|
||||
Astc2D10x6,
|
||||
Astc2D10x8,
|
||||
Astc2D10x10,
|
||||
Astc2D12x10,
|
||||
Astc2D12x12,
|
||||
Astc2DEnd,
|
||||
|
||||
TypeMask = Snorm | Unorm | Sint | Uint | Sfloat,
|
||||
|
||||
FormatMask = ~TypeMask,
|
||||
|
||||
ASTC_BEGIN = ASTC_4x4,
|
||||
|
||||
ASTC_4x4 = 1,
|
||||
ASTC_5x4,
|
||||
ASTC_5x5,
|
||||
ASTC_6x5,
|
||||
ASTC_6x6,
|
||||
ASTC_8x5,
|
||||
ASTC_8x6,
|
||||
ASTC_8x8,
|
||||
ASTC_10x5,
|
||||
ASTC_10x6,
|
||||
ASTC_10x8,
|
||||
ASTC_10x10,
|
||||
ASTC_12x10,
|
||||
ASTC_12x12,
|
||||
|
||||
ASTC_END = ASTC_12x12,
|
||||
|
||||
R4G4,
|
||||
R4G4B4A4,
|
||||
B4G4R4A4,
|
||||
A4B4G4R4,
|
||||
R5G6B5,
|
||||
B5G6R5,
|
||||
R5G5B5A1,
|
||||
B5G5R5A1,
|
||||
A1R5G5B5,
|
||||
RGBA4,
|
||||
RGB565,
|
||||
BGR5A1,
|
||||
RGB5A1,
|
||||
R8,
|
||||
R8G8,
|
||||
G8R8,
|
||||
R8G8B8,
|
||||
B8G8R8,
|
||||
R8G8B8A8,
|
||||
B8G8R8A8,
|
||||
A8B8G8R8,
|
||||
A8B8G8R8_SRGB,
|
||||
A2R10G10B10,
|
||||
A2B10G10R10,
|
||||
RG8,
|
||||
RGBA8,
|
||||
BGRA8,
|
||||
RGB10A2,
|
||||
R16,
|
||||
R16G16,
|
||||
R16G16B16,
|
||||
R16G16B16A16,
|
||||
RG16,
|
||||
RGBA16,
|
||||
R32,
|
||||
R32G32,
|
||||
R32G32B32,
|
||||
R32G32B32A32,
|
||||
R64,
|
||||
R64G64,
|
||||
R64G64B64,
|
||||
R64G64B64A64,
|
||||
B10G11R11,
|
||||
E5B9G9R9,
|
||||
RG32,
|
||||
RGBA32,
|
||||
R11G11B10,
|
||||
D16,
|
||||
X8_D24,
|
||||
D32,
|
||||
S8,
|
||||
D16_S8,
|
||||
D24_S8,
|
||||
D32_S8,
|
||||
BC1_RGB,
|
||||
BC1_RGBA,
|
||||
D24S8,
|
||||
D32S8,
|
||||
BC1,
|
||||
BC2,
|
||||
BC3,
|
||||
BC4,
|
||||
BC5,
|
||||
BC6H_SF16,
|
||||
BC6H_UF16,
|
||||
BC7,
|
||||
ETC2_R8G8B8,
|
||||
ETC2_R8G8B8A1,
|
||||
ETC2_R8G8B8A8,
|
||||
EAC_R11,
|
||||
EAC_R11G11,
|
||||
BptcSfloat,
|
||||
BptcUfloat,
|
||||
BptcUnorm,
|
||||
|
||||
Snorm = 1 << 26,
|
||||
Unorm = 1 << 27,
|
||||
Sint = 1 << 28,
|
||||
Uint = 1 << 39,
|
||||
Float = 1 << 30,
|
||||
Srgb = 1 << 31,
|
||||
|
||||
TypeMask = Snorm | Unorm | Sint | Uint | Float | Srgb,
|
||||
|
||||
FormatMask = ~TypeMask
|
||||
}
|
||||
}
|
|
@ -1,21 +1,28 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalVertexBinding
|
||||
public struct ColorMaskRgba
|
||||
{
|
||||
//VboKey shouldn't be here, but ARB_vertex_attrib_binding is core since 4.3
|
||||
private static readonly ColorMaskRgba _Default = new ColorMaskRgba()
|
||||
{
|
||||
Red = true,
|
||||
Green = true,
|
||||
Blue = true,
|
||||
Alpha = true
|
||||
};
|
||||
|
||||
public bool Enabled;
|
||||
public int Stride;
|
||||
public long VboKey;
|
||||
public bool Instanced;
|
||||
public int Divisor;
|
||||
public GalVertexAttrib[] Attribs;
|
||||
public static ColorMaskRgba Default => _Default;
|
||||
|
||||
public bool Red;
|
||||
public bool Green;
|
||||
public bool Blue;
|
||||
public bool Alpha;
|
||||
}
|
||||
|
||||
public class GalPipelineState
|
||||
{
|
||||
public const int Stages = 5;
|
||||
public const int Stages = 5;
|
||||
public const int ConstBuffersPerStage = 18;
|
||||
public const int RenderTargetsCount = 8;
|
||||
|
||||
public long[][] ConstBufferKeys;
|
||||
|
||||
|
@ -38,6 +45,7 @@
|
|||
public GalComparisonOp DepthFunc;
|
||||
|
||||
public bool StencilTestEnabled;
|
||||
public bool StencilTwoSideEnabled;
|
||||
|
||||
public GalComparisonOp StencilBackFuncFunc;
|
||||
public int StencilBackFuncRef;
|
||||
|
@ -64,6 +72,9 @@
|
|||
public GalBlendFactor BlendFuncSrcAlpha;
|
||||
public GalBlendFactor BlendFuncDstAlpha;
|
||||
|
||||
public ColorMaskRgba ColorMask;
|
||||
public ColorMaskRgba[] ColorMasks;
|
||||
|
||||
public bool PrimitiveRestartEnabled;
|
||||
public uint PrimitiveRestartIndex;
|
||||
|
||||
|
@ -75,6 +86,8 @@
|
|||
{
|
||||
ConstBufferKeys[Stage] = new long[ConstBuffersPerStage];
|
||||
}
|
||||
|
||||
ColorMasks = new ColorMaskRgba[RenderTargetsCount];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,45 +2,45 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
public enum GalTextureFormat
|
||||
{
|
||||
R32G32B32A32 = 0x1,
|
||||
R16G16B16A16 = 0x3,
|
||||
R32G32 = 0x4,
|
||||
A8B8G8R8 = 0x8,
|
||||
A2B10G10R10 = 0x9,
|
||||
R16G16 = 0xc,
|
||||
R32 = 0xf,
|
||||
BC6H_SF16 = 0x10,
|
||||
BC6H_UF16 = 0x11,
|
||||
A4B4G4R4 = 0x12,
|
||||
A1B5G5R5 = 0x14,
|
||||
B5G6R5 = 0x15,
|
||||
BC7U = 0x17,
|
||||
G8R8 = 0x18,
|
||||
R16 = 0x1b,
|
||||
R8 = 0x1d,
|
||||
BF10GF11RF11 = 0x21,
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26,
|
||||
BC4 = 0x27,
|
||||
BC5 = 0x28,
|
||||
Z24S8 = 0x29,
|
||||
ZF32 = 0x2f,
|
||||
ZF32_X24S8 = 0x30,
|
||||
Z16 = 0x3a,
|
||||
Astc2D4x4 = 0x40,
|
||||
Astc2D5x5 = 0x41,
|
||||
Astc2D6x6 = 0x42,
|
||||
Astc2D8x8 = 0x44,
|
||||
Astc2D10x10 = 0x45,
|
||||
Astc2D12x12 = 0x46,
|
||||
Astc2D5x4 = 0x50,
|
||||
Astc2D6x5 = 0x51,
|
||||
Astc2D8x6 = 0x52,
|
||||
Astc2D10x8 = 0x53,
|
||||
Astc2D12x10 = 0x54,
|
||||
Astc2D8x5 = 0x55,
|
||||
Astc2D10x5 = 0x56,
|
||||
Astc2D10x6 = 0x57
|
||||
RGBA32 = 0x1,
|
||||
RGBA16 = 0x3,
|
||||
RG32 = 0x4,
|
||||
RGBA8 = 0x8,
|
||||
RGB10A2 = 0x9,
|
||||
RG16 = 0xc,
|
||||
R32 = 0xf,
|
||||
BptcSfloat = 0x10,
|
||||
BptcUfloat = 0x11,
|
||||
RGBA4 = 0x12,
|
||||
RGB5A1 = 0x14,
|
||||
RGB565 = 0x15,
|
||||
BptcUnorm = 0x17,
|
||||
RG8 = 0x18,
|
||||
R16 = 0x1b,
|
||||
R8 = 0x1d,
|
||||
R11G11B10F = 0x21,
|
||||
BC1 = 0x24,
|
||||
BC2 = 0x25,
|
||||
BC3 = 0x26,
|
||||
BC4 = 0x27,
|
||||
BC5 = 0x28,
|
||||
D24S8 = 0x29,
|
||||
D32F = 0x2f,
|
||||
D32FX24S8 = 0x30,
|
||||
D16 = 0x3a,
|
||||
Astc2D4x4 = 0x40,
|
||||
Astc2D5x5 = 0x41,
|
||||
Astc2D6x6 = 0x42,
|
||||
Astc2D8x8 = 0x44,
|
||||
Astc2D10x10 = 0x45,
|
||||
Astc2D12x12 = 0x46,
|
||||
Astc2D5x4 = 0x50,
|
||||
Astc2D6x5 = 0x51,
|
||||
Astc2D8x6 = 0x52,
|
||||
Astc2D10x8 = 0x53,
|
||||
Astc2D12x10 = 0x54,
|
||||
Astc2D8x5 = 0x55,
|
||||
Astc2D10x5 = 0x56,
|
||||
Astc2D10x6 = 0x57
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalVertexAttrib
|
||||
{
|
||||
public int Index { get; private set; }
|
||||
public bool IsConst { get; private set; }
|
||||
public int Offset { get; private set; }
|
||||
public int Index { get; private set; }
|
||||
public bool IsConst { get; private set; }
|
||||
public int Offset { get; private set; }
|
||||
public IntPtr Pointer { get; private set; }
|
||||
|
||||
public GalVertexAttribSize Size { get; private set; }
|
||||
public GalVertexAttribType Type { get; private set; }
|
||||
|
@ -15,12 +18,14 @@ namespace Ryujinx.Graphics.Gal
|
|||
int Index,
|
||||
bool IsConst,
|
||||
int Offset,
|
||||
IntPtr Pointer,
|
||||
GalVertexAttribSize Size,
|
||||
GalVertexAttribType Type,
|
||||
bool IsBgra)
|
||||
{
|
||||
this.Index = Index;
|
||||
this.IsConst = IsConst;
|
||||
this.Pointer = Pointer;
|
||||
this.Offset = Offset;
|
||||
this.Size = Size;
|
||||
this.Type = Type;
|
||||
|
|
14
Ryujinx.Graphics/Gal/GalVertexBinding.cs
Normal file
14
Ryujinx.Graphics/Gal/GalVertexBinding.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
namespace Ryujinx.Graphics.Gal
|
||||
{
|
||||
public struct GalVertexBinding
|
||||
{
|
||||
//VboKey shouldn't be here, but ARB_vertex_attrib_binding is core since 4.3
|
||||
|
||||
public bool Enabled;
|
||||
public int Stride;
|
||||
public long VboKey;
|
||||
public bool Instanced;
|
||||
public int Divisor;
|
||||
public GalVertexAttrib[] Attribs;
|
||||
}
|
||||
}
|
|
@ -2,15 +2,15 @@
|
|||
{
|
||||
public enum GalZetaFormat
|
||||
{
|
||||
Z32Float = 0x0a,
|
||||
Z16Unorm = 0x13,
|
||||
S8Z24Unorm = 0x14,
|
||||
Z24X8Unorm = 0x15,
|
||||
Z24S8Unorm = 0x16,
|
||||
Z24C8Unorm = 0x18,
|
||||
Z32S8X24Float = 0x19,
|
||||
Z24X8S8C8X16Unorm = 0x1d,
|
||||
Z32X8C8X16Float = 0x1e,
|
||||
Z32S8C8X16Float = 0x1f
|
||||
D32Float = 0x0a,
|
||||
D16Unorm = 0x13,
|
||||
S8D24Unorm = 0x14,
|
||||
D24X8Unorm = 0x15,
|
||||
D24S8Unorm = 0x16,
|
||||
D24C8Unorm = 0x18,
|
||||
D32S8X24Float = 0x19,
|
||||
D24X8S8C8X16Unorm = 0x1d,
|
||||
D32X8C8X16Float = 0x1e,
|
||||
D32S8C8X16Float = 0x1f
|
||||
}
|
||||
}
|
|
@ -3,5 +3,8 @@
|
|||
public interface IGalPipeline
|
||||
{
|
||||
void Bind(GalPipelineState State);
|
||||
|
||||
void ResetDepthMask();
|
||||
void ResetColorMask(int Index);
|
||||
}
|
||||
}
|
|
@ -10,7 +10,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
void ClearBuffers(
|
||||
GalClearBufferFlags Flags,
|
||||
int Attachment,
|
||||
float Red, float Green, float Blue, float Alpha,
|
||||
float Red,
|
||||
float Green,
|
||||
float Blue,
|
||||
float Alpha,
|
||||
float Depth,
|
||||
int Stencil);
|
||||
|
||||
|
@ -21,6 +24,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
void CreateVbo(long Key, int DataSize, IntPtr HostAddress);
|
||||
|
||||
void CreateIbo(long Key, int DataSize, IntPtr HostAddress);
|
||||
void CreateIbo(long Key, int DataSize, byte[] Buffer);
|
||||
|
||||
void SetIndexArray(int Size, GalIndexFormat Format);
|
||||
|
||||
|
|
|
@ -2,15 +2,17 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
public interface IGalRenderTarget
|
||||
{
|
||||
void BindColor(long Key, int Attachment, GalImage Image);
|
||||
void Bind();
|
||||
|
||||
void BindColor(long Key, int Attachment);
|
||||
|
||||
void UnbindColor(int Attachment);
|
||||
|
||||
void BindZeta(long Key, GalImage Image);
|
||||
void BindZeta(long Key);
|
||||
|
||||
void UnbindZeta();
|
||||
|
||||
void Set(long Key);
|
||||
void Present(long Key);
|
||||
|
||||
void SetMap(int[] Map);
|
||||
|
||||
|
@ -18,7 +20,7 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
void SetWindowSize(int Width, int Height);
|
||||
|
||||
void SetViewport(int X, int Y, int Width, int Height);
|
||||
void SetViewport(int Attachment, int X, int Y, int Width, int Height);
|
||||
|
||||
void Render();
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalFrontFace.CCW: return FrontFaceDirection.Ccw;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(FrontFace));
|
||||
throw new ArgumentException(nameof(FrontFace) + " \"" + FrontFace + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static CullFaceMode GetCullFace(GalCullFace CullFace)
|
||||
|
@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalCullFace.FrontAndBack: return CullFaceMode.FrontAndBack;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(CullFace));
|
||||
throw new ArgumentException(nameof(CullFace) + " \"" + CullFace + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static StencilOp GetStencilOp(GalStencilOp Op)
|
||||
|
@ -42,7 +42,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalStencilOp.DecrWrap: return StencilOp.DecrWrap;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Op));
|
||||
throw new ArgumentException(nameof(Op) + " \"" + Op + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static DepthFunction GetDepthFunc(GalComparisonOp Func)
|
||||
|
@ -66,7 +66,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalComparisonOp.Always: return DepthFunction.Always;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Func));
|
||||
throw new ArgumentException(nameof(Func) + " \"" + Func + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static StencilFunction GetStencilFunc(GalComparisonOp Func)
|
||||
|
@ -84,7 +84,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalIndexFormat.Int32: return DrawElementsType.UnsignedInt;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Format));
|
||||
throw new ArgumentException(nameof(Format) + " \"" + Format + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static PrimitiveType GetPrimitiveType(GalPrimitiveType Type)
|
||||
|
@ -98,8 +98,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
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;
|
||||
|
@ -108,7 +106,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalPrimitiveType.Patches: return PrimitiveType.Patches;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static ShaderType GetShaderType(GalShaderType Type)
|
||||
|
@ -122,58 +120,61 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalShaderType.Fragment: return ShaderType.FragmentShader;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Type));
|
||||
throw new ArgumentException(nameof(Type) + " \"" + Type + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static (PixelInternalFormat, PixelFormat, PixelType) GetImageFormat(GalImageFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.R32G32B32A32 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
|
||||
case GalImageFormat.R32G32B32A32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
|
||||
case GalImageFormat.R32G32B32A32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
|
||||
case GalImageFormat.R16G16B16A16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16G16B16A16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
|
||||
case GalImageFormat.R16G16B16A16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R32G32 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
|
||||
case GalImageFormat.R32G32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
|
||||
case GalImageFormat.R32G32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
|
||||
case GalImageFormat.A8B8G8R8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
|
||||
case GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalImageFormat.A8B8G8R8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
|
||||
case GalImageFormat.A8B8G8R8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.A8B8G8R8_SRGB: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalImageFormat.A4B4G4R4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
|
||||
case GalImageFormat.A2B10G10R10 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalImageFormat.A2B10G10R10 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalImageFormat.R32 | GalImageFormat.Sfloat: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||
case GalImageFormat.A1R5G5B5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||
case GalImageFormat.B5G6R5 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sfloat: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||
case GalImageFormat.R16G16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R8G8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
|
||||
case GalImageFormat.R8G8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||
case GalImageFormat.R8G8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R8G8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R16 | GalImageFormat.Sfloat: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
|
||||
case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Byte);
|
||||
case GalImageFormat.R16 | GalImageFormat.Uint: return (PixelInternalFormat.R16ui, PixelFormat.RedInteger, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R16 | GalImageFormat.Unorm: return (PixelInternalFormat.R16, PixelFormat.Red, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R8 | GalImageFormat.Sint: return (PixelInternalFormat.R8i, PixelFormat.RedInteger, PixelType.Byte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Snorm: return (PixelInternalFormat.R8Snorm, PixelFormat.Red, PixelType.Byte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Uint: return (PixelInternalFormat.R8ui, PixelFormat.RedInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Unorm: return (PixelInternalFormat.R8, PixelFormat.Red, PixelType.UnsignedByte);
|
||||
case GalImageFormat.B10G11R11 | GalImageFormat.Sfloat: return (PixelInternalFormat.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev);
|
||||
case GalImageFormat.RGBA32 | GalImageFormat.Float: return (PixelInternalFormat.Rgba32f, PixelFormat.Rgba, PixelType.Float);
|
||||
case GalImageFormat.RGBA32 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba32i, PixelFormat.RgbaInteger, PixelType.Int);
|
||||
case GalImageFormat.RGBA32 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba32ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt);
|
||||
case GalImageFormat.RGBA16 | GalImageFormat.Float: return (PixelInternalFormat.Rgba16f, PixelFormat.Rgba, PixelType.HalfFloat);
|
||||
case GalImageFormat.RGBA16 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba16i, PixelFormat.RgbaInteger, PixelType.Short);
|
||||
case GalImageFormat.RGBA16 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba16ui, PixelFormat.RgbaInteger, PixelType.UnsignedShort);
|
||||
case GalImageFormat.RG32 | GalImageFormat.Float: return (PixelInternalFormat.Rg32f, PixelFormat.Rg, PixelType.Float);
|
||||
case GalImageFormat.RG32 | GalImageFormat.Sint: return (PixelInternalFormat.Rg32i, PixelFormat.RgInteger, PixelType.Int);
|
||||
case GalImageFormat.RG32 | GalImageFormat.Uint: return (PixelInternalFormat.Rg32ui, PixelFormat.RgInteger, PixelType.UnsignedInt);
|
||||
case GalImageFormat.RGBA8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rgba8Snorm, PixelFormat.Rgba, PixelType.Byte);
|
||||
case GalImageFormat.RGBA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalImageFormat.RGBA8 | GalImageFormat.Sint: return (PixelInternalFormat.Rgba8i, PixelFormat.RgbaInteger, PixelType.Byte);
|
||||
case GalImageFormat.RGBA8 | GalImageFormat.Uint: return (PixelInternalFormat.Rgba8ui, PixelFormat.RgbaInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.RGBA8 | GalImageFormat.Srgb: return (PixelInternalFormat.Srgb8Alpha8, PixelFormat.Rgba, PixelType.UnsignedByte);
|
||||
case GalImageFormat.BGRA8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba8, PixelFormat.Bgra, PixelType.UnsignedByte);
|
||||
case GalImageFormat.RGBA4 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba4, PixelFormat.Rgba, PixelType.UnsignedShort4444Reversed);
|
||||
case GalImageFormat.RGB10A2 | GalImageFormat.Uint: return (PixelInternalFormat.Rgb10A2ui, PixelFormat.RgbaInteger, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalImageFormat.RGB10A2 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb10A2, PixelFormat.Rgba, PixelType.UnsignedInt2101010Reversed);
|
||||
case GalImageFormat.R32 | GalImageFormat.Float: return (PixelInternalFormat.R32f, PixelFormat.Red, PixelType.Float);
|
||||
case GalImageFormat.R32 | GalImageFormat.Sint: return (PixelInternalFormat.R32i, PixelFormat.Red, PixelType.Int);
|
||||
case GalImageFormat.R32 | GalImageFormat.Uint: return (PixelInternalFormat.R32ui, PixelFormat.Red, PixelType.UnsignedInt);
|
||||
case GalImageFormat.RGB5A1 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgb5A1, PixelFormat.Rgba, PixelType.UnsignedShort1555Reversed);
|
||||
case GalImageFormat.RGB565 | GalImageFormat.Unorm: return (PixelInternalFormat.Rgba, PixelFormat.Rgb, PixelType.UnsignedShort565Reversed);
|
||||
case GalImageFormat.RG16 | GalImageFormat.Float: return (PixelInternalFormat.Rg16f, PixelFormat.Rg, PixelType.HalfFloat);
|
||||
case GalImageFormat.RG16 | GalImageFormat.Sint: return (PixelInternalFormat.Rg16i, PixelFormat.RgInteger, PixelType.Short);
|
||||
case GalImageFormat.RG16 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg16Snorm, PixelFormat.Rg, PixelType.Short);
|
||||
case GalImageFormat.RG16 | GalImageFormat.Uint: return (PixelInternalFormat.Rg16ui, PixelFormat.RgInteger, PixelType.UnsignedShort);
|
||||
case GalImageFormat.RG16 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg16, PixelFormat.Rg, PixelType.UnsignedShort);
|
||||
case GalImageFormat.RG8 | GalImageFormat.Sint: return (PixelInternalFormat.Rg8i, PixelFormat.RgInteger, PixelType.Byte);
|
||||
case GalImageFormat.RG8 | GalImageFormat.Snorm: return (PixelInternalFormat.Rg8Snorm, PixelFormat.Rg, PixelType.Byte);
|
||||
case GalImageFormat.RG8 | GalImageFormat.Uint: return (PixelInternalFormat.Rg8ui, PixelFormat.RgInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.RG8 | GalImageFormat.Unorm: return (PixelInternalFormat.Rg8, PixelFormat.Rg, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R16 | GalImageFormat.Float: return (PixelInternalFormat.R16f, PixelFormat.Red, PixelType.HalfFloat);
|
||||
case GalImageFormat.R16 | GalImageFormat.Sint: return (PixelInternalFormat.R16i, PixelFormat.RedInteger, PixelType.Short);
|
||||
case GalImageFormat.R16 | GalImageFormat.Snorm: return (PixelInternalFormat.R16Snorm, PixelFormat.Red, PixelType.Short);
|
||||
case GalImageFormat.R16 | GalImageFormat.Uint: return (PixelInternalFormat.R16ui, PixelFormat.RedInteger, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R16 | GalImageFormat.Unorm: return (PixelInternalFormat.R16, PixelFormat.Red, PixelType.UnsignedShort);
|
||||
case GalImageFormat.R8 | GalImageFormat.Sint: return (PixelInternalFormat.R8i, PixelFormat.RedInteger, PixelType.Byte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Snorm: return (PixelInternalFormat.R8Snorm, PixelFormat.Red, PixelType.Byte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Uint: return (PixelInternalFormat.R8ui, PixelFormat.RedInteger, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R8 | GalImageFormat.Unorm: return (PixelInternalFormat.R8, PixelFormat.Red, PixelType.UnsignedByte);
|
||||
case GalImageFormat.R11G11B10 | GalImageFormat.Float: return (PixelInternalFormat.R11fG11fB10f, PixelFormat.Rgb, PixelType.UnsignedInt10F11F11FRev);
|
||||
|
||||
case GalImageFormat.D24_S8 | GalImageFormat.Unorm: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
||||
case GalImageFormat.D32 | GalImageFormat.Sfloat: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float);
|
||||
case GalImageFormat.D16 | GalImageFormat.Unorm: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort);
|
||||
case GalImageFormat.D32_S8 | GalImageFormat.Sfloat: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||
case GalImageFormat.D24S8 | GalImageFormat.Uint: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
||||
case GalImageFormat.D24S8 | GalImageFormat.Unorm: return (PixelInternalFormat.Depth24Stencil8, PixelFormat.DepthStencil, PixelType.UnsignedInt248);
|
||||
case GalImageFormat.D32 | GalImageFormat.Float: return (PixelInternalFormat.DepthComponent32f, PixelFormat.DepthComponent, PixelType.Float);
|
||||
case GalImageFormat.D16 | GalImageFormat.Unorm: return (PixelInternalFormat.DepthComponent16, PixelFormat.DepthComponent, PixelType.UnsignedShort);
|
||||
case GalImageFormat.D32S8 | GalImageFormat.Float: return (PixelInternalFormat.Depth32fStencil8, PixelFormat.DepthStencil, PixelType.Float32UnsignedInt248Rev);
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
||||
|
@ -183,16 +184,20 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalImageFormat.BC6H_UF16 | GalImageFormat.Sfloat: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||
case GalImageFormat.BC6H_SF16 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||
case GalImageFormat.BC7 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaBptcUnorm;
|
||||
case GalImageFormat.BC1_RGBA | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalImageFormat.BC2 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalImageFormat.BC3 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRedRgtc1;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Unorm: return InternalFormat.CompressedRedRgtc1;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRgRgtc2;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
||||
case GalImageFormat.BptcSfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcSignedFloat;
|
||||
case GalImageFormat.BptcUfloat | GalImageFormat.Float: return InternalFormat.CompressedRgbBptcUnsignedFloat;
|
||||
case GalImageFormat.BptcUnorm | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaBptcUnorm;
|
||||
case GalImageFormat.BptcUnorm | GalImageFormat.Srgb: return InternalFormat.CompressedSrgbAlphaBptcUnorm;
|
||||
case GalImageFormat.BC1 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt1Ext;
|
||||
case GalImageFormat.BC1 | GalImageFormat.Srgb: return InternalFormat.CompressedSrgbAlphaS3tcDxt1Ext;
|
||||
case GalImageFormat.BC2 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt3Ext;
|
||||
case GalImageFormat.BC2 | GalImageFormat.Srgb: return InternalFormat.CompressedSrgbAlphaS3tcDxt3Ext;
|
||||
case GalImageFormat.BC3 | GalImageFormat.Unorm: return InternalFormat.CompressedRgbaS3tcDxt5Ext;
|
||||
case GalImageFormat.BC3 | GalImageFormat.Srgb: return InternalFormat.CompressedSrgbAlphaS3tcDxt5Ext;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRedRgtc1;
|
||||
case GalImageFormat.BC4 | GalImageFormat.Unorm: return InternalFormat.CompressedRedRgtc1;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Snorm: return InternalFormat.CompressedSignedRgRgtc2;
|
||||
case GalImageFormat.BC5 | GalImageFormat.Unorm: return InternalFormat.CompressedRgRgtc2;
|
||||
}
|
||||
|
||||
throw new NotImplementedException($"{Format & GalImageFormat.FormatMask} {Format & GalImageFormat.TypeMask}");
|
||||
|
@ -211,7 +216,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalTextureSource.OneFloat: return All.One;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Source));
|
||||
throw new ArgumentException(nameof(Source) + " \"" + Source + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static TextureWrapMode GetTextureWrapMode(GalTextureWrap Wrap)
|
||||
|
@ -225,7 +230,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalTextureWrap.Clamp: return TextureWrapMode.Clamp;
|
||||
}
|
||||
|
||||
if (OGLExtension.HasTextureMirrorClamp())
|
||||
if (OGLExtension.TextureMirrorClamp)
|
||||
{
|
||||
switch (Wrap)
|
||||
{
|
||||
|
@ -245,7 +250,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Wrap));
|
||||
throw new ArgumentException(nameof(Wrap) + " \"" + Wrap + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static TextureMinFilter GetTextureMinFilter(
|
||||
|
@ -259,7 +264,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalTextureFilter.Linear: return TextureMinFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(MinFilter));
|
||||
throw new ArgumentException(nameof(MinFilter) + " \"" + MinFilter + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static TextureMagFilter GetTextureMagFilter(GalTextureFilter Filter)
|
||||
|
@ -270,7 +275,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalTextureFilter.Linear: return TextureMagFilter.Linear;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(Filter));
|
||||
throw new ArgumentException(nameof(Filter) + " \"" + Filter + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static BlendEquationMode GetBlendEquation(GalBlendEquation BlendEquation)
|
||||
|
@ -284,7 +289,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
case GalBlendEquation.Max: return BlendEquationMode.Max;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(BlendEquation));
|
||||
throw new ArgumentException(nameof(BlendEquation) + " \"" + BlendEquation + "\" is not valid!");
|
||||
}
|
||||
|
||||
public static BlendingFactor GetBlendFactor(GalBlendFactor BlendFactor)
|
||||
|
@ -315,7 +320,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return BlendingFactor.ConstantColor;
|
||||
}
|
||||
|
||||
throw new ArgumentException(nameof(BlendFactor));
|
||||
throw new ArgumentException(nameof(BlendFactor) + " \"" + BlendFactor + "\" is not valid!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,40 +1,17 @@
|
|||
using OpenTK.Graphics.OpenGL;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Gal.OpenGL
|
||||
{
|
||||
static class OGLExtension
|
||||
{
|
||||
private static bool Initialized = false;
|
||||
private static Lazy<bool> s_EnhancedLayouts = new Lazy<bool>(() => HasExtension("GL_ARB_enhanced_layouts"));
|
||||
private static Lazy<bool> s_TextureMirrorClamp = new Lazy<bool>(() => HasExtension("GL_EXT_texture_mirror_clamp"));
|
||||
private static Lazy<bool> s_ViewportArray = new Lazy<bool>(() => HasExtension("GL_ARB_viewport_array"));
|
||||
|
||||
private static bool EnhancedLayouts;
|
||||
|
||||
private static bool TextureMirrorClamp;
|
||||
|
||||
public static bool HasEnhancedLayouts()
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
return EnhancedLayouts;
|
||||
}
|
||||
|
||||
public static bool HasTextureMirrorClamp()
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
||||
return TextureMirrorClamp;
|
||||
}
|
||||
|
||||
private static void EnsureInitialized()
|
||||
{
|
||||
if (Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EnhancedLayouts = HasExtension("GL_ARB_enhanced_layouts");
|
||||
|
||||
TextureMirrorClamp = HasExtension("GL_EXT_texture_mirror_clamp");
|
||||
}
|
||||
public static bool EnhancedLayouts => s_EnhancedLayouts.Value;
|
||||
public static bool TextureMirrorClamp => s_TextureMirrorClamp.Value;
|
||||
public static bool ViewportArray => s_ViewportArray.Value;
|
||||
|
||||
private static bool HasExtension(string Name)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{ GalVertexAttribSize._11_11_10, 3 }
|
||||
};
|
||||
|
||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> FloatAttribTypes =
|
||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||
{
|
||||
{ GalVertexAttribSize._32_32_32_32, VertexAttribPointerType.Float },
|
||||
{ GalVertexAttribSize._32_32_32, VertexAttribPointerType.Float },
|
||||
{ GalVertexAttribSize._16_16_16_16, VertexAttribPointerType.HalfFloat },
|
||||
{ GalVertexAttribSize._32_32, VertexAttribPointerType.Float },
|
||||
{ GalVertexAttribSize._16_16_16, VertexAttribPointerType.HalfFloat },
|
||||
{ GalVertexAttribSize._16_16, VertexAttribPointerType.HalfFloat },
|
||||
{ GalVertexAttribSize._32, VertexAttribPointerType.Float },
|
||||
{ GalVertexAttribSize._16, VertexAttribPointerType.HalfFloat }
|
||||
};
|
||||
|
||||
private static Dictionary<GalVertexAttribSize, VertexAttribPointerType> SignedAttribTypes =
|
||||
new Dictionary<GalVertexAttribSize, VertexAttribPointerType>()
|
||||
{
|
||||
|
@ -116,9 +129,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
BlendFuncSrcAlpha = GalBlendFactor.One,
|
||||
BlendFuncDstAlpha = GalBlendFactor.Zero,
|
||||
|
||||
ColorMask = ColorMaskRgba.Default,
|
||||
|
||||
PrimitiveRestartEnabled = false,
|
||||
PrimitiveRestartIndex = 0
|
||||
};
|
||||
|
||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
||||
{
|
||||
Old.ColorMasks[Index] = ColorMaskRgba.Default;
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind(GalPipelineState New)
|
||||
|
@ -164,8 +184,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
if (New.DepthWriteEnabled != Old.DepthWriteEnabled)
|
||||
{
|
||||
Rasterizer.DepthWriteEnabled = New.DepthWriteEnabled;
|
||||
|
||||
GL.DepthMask(New.DepthWriteEnabled);
|
||||
}
|
||||
|
||||
|
@ -182,6 +200,11 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Enable(EnableCap.StencilTest, New.StencilTestEnabled);
|
||||
}
|
||||
|
||||
if (New.StencilTwoSideEnabled != Old.StencilTwoSideEnabled)
|
||||
{
|
||||
Enable((EnableCap)All.StencilTestTwoSideExt, New.StencilTwoSideEnabled);
|
||||
}
|
||||
|
||||
if (New.StencilTestEnabled)
|
||||
{
|
||||
if (New.StencilBackFuncFunc != Old.StencilBackFuncFunc ||
|
||||
|
@ -285,6 +308,19 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
||||
{
|
||||
if (!New.ColorMasks[Index].Equals(Old.ColorMasks[Index]))
|
||||
{
|
||||
GL.ColorMask(
|
||||
Index,
|
||||
New.ColorMasks[Index].Red,
|
||||
New.ColorMasks[Index].Green,
|
||||
New.ColorMasks[Index].Blue,
|
||||
New.ColorMasks[Index].Alpha);
|
||||
}
|
||||
}
|
||||
|
||||
if (New.PrimitiveRestartEnabled != Old.PrimitiveRestartEnabled)
|
||||
{
|
||||
Enable(EnableCap.PrimitiveRestart, New.PrimitiveRestartEnabled);
|
||||
|
@ -356,8 +392,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
continue;
|
||||
}
|
||||
|
||||
GL.EnableVertexAttribArray(Attrib.Index);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ArrayBuffer, VboHandle);
|
||||
|
||||
bool Unsigned =
|
||||
|
@ -373,35 +407,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
if (Attrib.Type == GalVertexAttribType.Float)
|
||||
{
|
||||
Type = VertexAttribPointerType.Float;
|
||||
Type = GetType(FloatAttribTypes, Attrib);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Unsigned)
|
||||
{
|
||||
Type = UnsignedAttribTypes[Attrib.Size];
|
||||
Type = GetType(UnsignedAttribTypes, Attrib);
|
||||
}
|
||||
else
|
||||
{
|
||||
Type = SignedAttribTypes[Attrib.Size];
|
||||
Type = GetType(SignedAttribTypes, Attrib);
|
||||
}
|
||||
}
|
||||
|
||||
int Size = AttribElements[Attrib.Size];
|
||||
if (!AttribElements.TryGetValue(Attrib.Size, out int Size))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid attribute size \"" + Attrib.Size + "\"!");
|
||||
}
|
||||
|
||||
int Offset = Attrib.Offset;
|
||||
|
||||
if (Attrib.Type == GalVertexAttribType.Sint ||
|
||||
Attrib.Type == GalVertexAttribType.Uint)
|
||||
if (Binding.Stride != 0)
|
||||
{
|
||||
IntPtr Pointer = new IntPtr(Offset);
|
||||
GL.EnableVertexAttribArray(Attrib.Index);
|
||||
|
||||
VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
|
||||
if (Attrib.Type == GalVertexAttribType.Sint ||
|
||||
Attrib.Type == GalVertexAttribType.Uint)
|
||||
{
|
||||
IntPtr Pointer = new IntPtr(Offset);
|
||||
|
||||
GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
|
||||
VertexAttribIntegerType IType = (VertexAttribIntegerType)Type;
|
||||
|
||||
GL.VertexAttribIPointer(Attrib.Index, Size, IType, Binding.Stride, Pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.VertexAttribPointer(Attrib.Index, Size, Type, Normalize, Binding.Stride, Offset);
|
||||
GL.DisableVertexAttribArray(Attrib.Index);
|
||||
|
||||
SetConstAttrib(Attrib);
|
||||
}
|
||||
|
||||
if (Binding.Instanced && Binding.Divisor != 0)
|
||||
|
@ -416,6 +465,149 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private static VertexAttribPointerType GetType(Dictionary<GalVertexAttribSize, VertexAttribPointerType> Dict, GalVertexAttrib Attrib)
|
||||
{
|
||||
if (!Dict.TryGetValue(Attrib.Size, out VertexAttribPointerType Type))
|
||||
{
|
||||
throw new NotImplementedException("Unsupported size \"" + Attrib.Size + "\" on type \"" + Attrib.Type + "\"!");
|
||||
}
|
||||
|
||||
return Type;
|
||||
}
|
||||
|
||||
private unsafe static void SetConstAttrib(GalVertexAttrib Attrib)
|
||||
{
|
||||
void Unsupported()
|
||||
{
|
||||
throw new NotImplementedException("Constant attribute " + Attrib.Size + " not implemented!");
|
||||
}
|
||||
|
||||
if (Attrib.Size == GalVertexAttribSize._10_10_10_2 ||
|
||||
Attrib.Size == GalVertexAttribSize._11_11_10)
|
||||
{
|
||||
Unsupported();
|
||||
}
|
||||
|
||||
if (Attrib.Type == GalVertexAttribType.Unorm)
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (byte*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (ushort*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (uint*)Attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Attrib.Type == GalVertexAttribType.Snorm)
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (sbyte*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (short*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
GL.VertexAttrib4N((uint)Attrib.Index, (int*)Attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Attrib.Type == GalVertexAttribType.Uint)
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (byte*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (ushort*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (uint*)Attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Attrib.Type == GalVertexAttribType.Sint)
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._8:
|
||||
case GalVertexAttribSize._8_8:
|
||||
case GalVertexAttribSize._8_8_8:
|
||||
case GalVertexAttribSize._8_8_8_8:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (sbyte*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._16:
|
||||
case GalVertexAttribSize._16_16:
|
||||
case GalVertexAttribSize._16_16_16:
|
||||
case GalVertexAttribSize._16_16_16_16:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (short*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
GL.VertexAttribI4((uint)Attrib.Index, (int*)Attrib.Pointer);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (Attrib.Type == GalVertexAttribType.Float)
|
||||
{
|
||||
switch (Attrib.Size)
|
||||
{
|
||||
case GalVertexAttribSize._32:
|
||||
case GalVertexAttribSize._32_32:
|
||||
case GalVertexAttribSize._32_32_32:
|
||||
case GalVertexAttribSize._32_32_32_32:
|
||||
GL.VertexAttrib4(Attrib.Index, (float*)Attrib.Pointer);
|
||||
break;
|
||||
|
||||
default: Unsupported(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Enable(EnableCap Cap, bool Enabled)
|
||||
{
|
||||
if (Enabled)
|
||||
|
@ -427,5 +619,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.Disable(Cap);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetDepthMask()
|
||||
{
|
||||
Old.DepthWriteEnabled = true;
|
||||
}
|
||||
|
||||
public void ResetColorMask(int Index)
|
||||
{
|
||||
Old.ColorMasks[Index] = ColorMaskRgba.Default;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
class OGLRasterizer : IGalRasterizer
|
||||
{
|
||||
public bool DepthWriteEnabled { set; private get; }
|
||||
|
||||
private int[] VertexBuffers;
|
||||
|
||||
private OGLCachedResource<int> VboCache;
|
||||
|
@ -30,8 +28,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
IboCache = new OGLCachedResource<int>(GL.DeleteBuffer);
|
||||
|
||||
IndexBuffer = new IbInfo();
|
||||
|
||||
DepthWriteEnabled = true;
|
||||
}
|
||||
|
||||
public void LockCaches()
|
||||
|
@ -49,17 +45,15 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
public void ClearBuffers(
|
||||
GalClearBufferFlags Flags,
|
||||
int Attachment,
|
||||
float Red, float Green, float Blue, float Alpha,
|
||||
float Red,
|
||||
float Green,
|
||||
float Blue,
|
||||
float Alpha,
|
||||
float Depth,
|
||||
int Stencil)
|
||||
{
|
||||
//OpenGL needs glDepthMask to be enabled to clear it
|
||||
if (!DepthWriteEnabled)
|
||||
{
|
||||
GL.DepthMask(true);
|
||||
}
|
||||
|
||||
GL.ColorMask(
|
||||
Attachment,
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorRed),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorGreen),
|
||||
Flags.HasFlag(GalClearBufferFlags.ColorBlue),
|
||||
|
@ -67,6 +61,9 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GL.ClearBuffer(ClearBuffer.Color, Attachment, new float[] { Red, Green, Blue, Alpha });
|
||||
|
||||
GL.ColorMask(Attachment, true, true, true, true);
|
||||
GL.DepthMask(true);
|
||||
|
||||
if (Flags.HasFlag(GalClearBufferFlags.Depth))
|
||||
{
|
||||
GL.ClearBuffer(ClearBuffer.Depth, 0, ref Depth);
|
||||
|
@ -76,13 +73,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
GL.ClearBuffer(ClearBuffer.Stencil, 0, ref Stencil);
|
||||
}
|
||||
|
||||
GL.ColorMask(true, true, true, true);
|
||||
|
||||
if (!DepthWriteEnabled)
|
||||
{
|
||||
GL.DepthMask(false);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsVboCached(long Key, long DataSize)
|
||||
|
@ -119,6 +109,18 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, HostAddress, BufferUsageHint.StreamDraw);
|
||||
}
|
||||
|
||||
public void CreateIbo(long Key, int DataSize, byte[] Buffer)
|
||||
{
|
||||
int Handle = GL.GenBuffer();
|
||||
|
||||
IboCache.AddOrUpdate(Key, Handle, (uint)DataSize);
|
||||
|
||||
IntPtr Length = new IntPtr(Buffer.Length);
|
||||
|
||||
GL.BindBuffer(BufferTarget.ElementArrayBuffer, Handle);
|
||||
GL.BufferData(BufferTarget.ElementArrayBuffer, Length, Buffer, BufferUsageHint.StreamDraw);
|
||||
}
|
||||
|
||||
public void SetIndexArray(int Size, GalIndexFormat Format)
|
||||
{
|
||||
IndexBuffer.Type = OGLEnumConverter.GetDrawElementsType(Format);
|
||||
|
@ -135,7 +137,26 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
return;
|
||||
}
|
||||
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||
if (PrimType == GalPrimitiveType.Quads)
|
||||
{
|
||||
for (int Offset = 0; Offset < Count; Offset += 4)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
||||
}
|
||||
}
|
||||
else if (PrimType == GalPrimitiveType.QuadStrip)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, First, 4);
|
||||
|
||||
for (int Offset = 2; Offset < Count; Offset += 2)
|
||||
{
|
||||
GL.DrawArrays(PrimitiveType.TriangleFan, First + Offset, 4);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.DrawArrays(OGLEnumConverter.GetPrimitiveType(PrimType), First, Count);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawElements(long IboKey, int First, int VertexBase, GalPrimitiveType PrimType)
|
||||
|
|
|
@ -22,16 +22,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private class FrameBufferAttachments
|
||||
{
|
||||
public long[] Colors;
|
||||
public long Zeta;
|
||||
|
||||
public int MapCount;
|
||||
public DrawBuffersEnum[] Map;
|
||||
|
||||
public FrameBufferAttachments()
|
||||
{
|
||||
Colors = new long[RenderTargetsCount];
|
||||
|
||||
Map = new DrawBuffersEnum[RenderTargetsCount];
|
||||
}
|
||||
|
||||
public void SetAndClear(FrameBufferAttachments Source)
|
||||
{
|
||||
Zeta = Source.Zeta;
|
||||
MapCount = Source.MapCount;
|
||||
|
||||
Source.Zeta = 0;
|
||||
Source.MapCount = 0;
|
||||
|
||||
for (int i = 0; i < RenderTargetsCount; i++)
|
||||
{
|
||||
Colors[i] = Source.Colors[i];
|
||||
Map[i] = Source.Map[i];
|
||||
|
||||
Source.Colors[i] = 0;
|
||||
Source.Map[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private const int NativeWidth = 1280;
|
||||
private const int NativeHeight = 720;
|
||||
|
||||
private const GalImageFormat RawFormat = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
|
||||
private const int RenderTargetsCount = GalPipelineState.RenderTargetsCount;
|
||||
|
||||
private OGLTexture Texture;
|
||||
|
||||
private ImageHandler ReadTex;
|
||||
|
||||
private Rect Viewport;
|
||||
private float[] Viewports;
|
||||
private Rect Window;
|
||||
|
||||
private bool FlipX;
|
||||
|
@ -50,138 +84,165 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
private int SrcFb;
|
||||
private int DstFb;
|
||||
|
||||
//Holds current attachments, used to avoid unnecesary calls to OpenGL
|
||||
private int[] ColorAttachments;
|
||||
|
||||
private int DepthAttachment;
|
||||
private int StencilAttachment;
|
||||
private FrameBufferAttachments Attachments;
|
||||
private FrameBufferAttachments OldAttachments;
|
||||
|
||||
private int CopyPBO;
|
||||
|
||||
public OGLRenderTarget(OGLTexture Texture)
|
||||
{
|
||||
ColorAttachments = new int[8];
|
||||
Attachments = new FrameBufferAttachments();
|
||||
|
||||
OldAttachments = new FrameBufferAttachments();
|
||||
|
||||
Viewports = new float[RenderTargetsCount * 4];
|
||||
|
||||
this.Texture = Texture;
|
||||
}
|
||||
|
||||
public void BindColor(long Key, int Attachment, GalImage Image)
|
||||
public void Bind()
|
||||
{
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
if (DummyFrameBuffer == 0)
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
Attach(ref ColorAttachments[Attachment], CachedImage.Handle, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
DummyFrameBuffer = GL.GenFramebuffer();
|
||||
}
|
||||
else
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||
|
||||
ImageHandler CachedImage;
|
||||
|
||||
for (int Attachment = 0; Attachment < RenderTargetsCount; Attachment++)
|
||||
{
|
||||
UnbindColor(Attachment);
|
||||
}
|
||||
}
|
||||
long Key = Attachments.Colors[Attachment];
|
||||
|
||||
public void UnbindColor(int Attachment)
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
Attach(ref ColorAttachments[Attachment], 0, FramebufferAttachment.ColorAttachment0 + Attachment);
|
||||
}
|
||||
|
||||
public void BindZeta(long Key, GalImage Image)
|
||||
{
|
||||
if (Texture.TryGetImageHandler(Key, out ImageHandler CachedImage))
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||
if (Key == OldAttachments.Colors[Attachment])
|
||||
{
|
||||
if (DepthAttachment != CachedImage.Handle ||
|
||||
StencilAttachment != CachedImage.Handle)
|
||||
continue;
|
||||
}
|
||||
|
||||
int Handle = 0;
|
||||
|
||||
if (Key != 0 && Texture.TryGetImageHandler(Key, out CachedImage))
|
||||
{
|
||||
Handle = CachedImage.Handle;
|
||||
}
|
||||
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.ColorAttachment0 + Attachment,
|
||||
Handle,
|
||||
0);
|
||||
}
|
||||
|
||||
if (Attachments.Zeta != OldAttachments.Zeta)
|
||||
{
|
||||
if (Attachments.Zeta != 0 && Texture.TryGetImageHandler(Attachments.Zeta, out CachedImage))
|
||||
{
|
||||
if (CachedImage.HasDepth && CachedImage.HasStencil)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
CachedImage.Handle,
|
||||
0);
|
||||
|
||||
DepthAttachment = CachedImage.Handle;
|
||||
StencilAttachment = CachedImage.Handle;
|
||||
}
|
||||
}
|
||||
else if (CachedImage.HasDepth)
|
||||
{
|
||||
Attach(ref DepthAttachment, CachedImage.Handle, FramebufferAttachment.DepthAttachment);
|
||||
else if (CachedImage.HasDepth)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthAttachment,
|
||||
CachedImage.Handle,
|
||||
0);
|
||||
|
||||
Attach(ref StencilAttachment, 0, FramebufferAttachment.StencilAttachment);
|
||||
}
|
||||
else if (CachedImage.HasStencil)
|
||||
{
|
||||
Attach(ref DepthAttachment, 0, FramebufferAttachment.DepthAttachment);
|
||||
|
||||
Attach(ref StencilAttachment, CachedImage.Handle, FramebufferAttachment.StencilAttachment);
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.StencilAttachment,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
0,
|
||||
0);
|
||||
}
|
||||
}
|
||||
|
||||
if (OGLExtension.ViewportArray)
|
||||
{
|
||||
GL.ViewportArray(0, RenderTargetsCount, Viewports);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnbindZeta();
|
||||
GL.Viewport(
|
||||
(int)Viewports[0],
|
||||
(int)Viewports[1],
|
||||
(int)Viewports[2],
|
||||
(int)Viewports[3]);
|
||||
}
|
||||
|
||||
if (Attachments.MapCount > 1)
|
||||
{
|
||||
GL.DrawBuffers(Attachments.MapCount, Attachments.Map);
|
||||
}
|
||||
else if (Attachments.MapCount == 1)
|
||||
{
|
||||
GL.DrawBuffer((DrawBufferMode)Attachments.Map[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.None);
|
||||
}
|
||||
|
||||
OldAttachments.SetAndClear(Attachments);
|
||||
}
|
||||
|
||||
private void Attach(ref int OldHandle, int NewHandle, FramebufferAttachment FbAttachment)
|
||||
public void BindColor(long Key, int Attachment)
|
||||
{
|
||||
if (OldHandle != NewHandle)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FbAttachment,
|
||||
NewHandle,
|
||||
0);
|
||||
Attachments.Colors[Attachment] = Key;
|
||||
}
|
||||
|
||||
OldHandle = NewHandle;
|
||||
}
|
||||
public void UnbindColor(int Attachment)
|
||||
{
|
||||
Attachments.Colors[Attachment] = 0;
|
||||
}
|
||||
|
||||
public void BindZeta(long Key)
|
||||
{
|
||||
Attachments.Zeta = Key;
|
||||
}
|
||||
|
||||
public void UnbindZeta()
|
||||
{
|
||||
EnsureFrameBuffer();
|
||||
|
||||
if (DepthAttachment != 0 || StencilAttachment != 0)
|
||||
{
|
||||
GL.FramebufferTexture(
|
||||
FramebufferTarget.DrawFramebuffer,
|
||||
FramebufferAttachment.DepthStencilAttachment,
|
||||
0,
|
||||
0);
|
||||
|
||||
DepthAttachment = 0;
|
||||
StencilAttachment = 0;
|
||||
}
|
||||
Attachments.Zeta = 0;
|
||||
}
|
||||
|
||||
public void Set(long Key)
|
||||
public void Present(long Key)
|
||||
{
|
||||
Texture.TryGetImageHandler(Key, out ReadTex);
|
||||
}
|
||||
|
||||
public void SetMap(int[] Map)
|
||||
{
|
||||
if (Map != null && Map.Length > 0)
|
||||
if (Map != null)
|
||||
{
|
||||
DrawBuffersEnum[] Mode = new DrawBuffersEnum[Map.Length];
|
||||
Attachments.MapCount = Map.Length;
|
||||
|
||||
for (int i = 0; i < Map.Length; i++)
|
||||
for (int Attachment = 0; Attachment < Attachments.MapCount; Attachment++)
|
||||
{
|
||||
Mode[i] = DrawBuffersEnum.ColorAttachment0 + Map[i];
|
||||
Attachments.Map[Attachment] = DrawBuffersEnum.ColorAttachment0 + Map[Attachment];
|
||||
}
|
||||
|
||||
GL.DrawBuffers(Mode.Length, Mode);
|
||||
}
|
||||
else
|
||||
{
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
Attachments.MapCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,20 +262,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Window = new Rect(0, 0, Width, Height);
|
||||
}
|
||||
|
||||
public void SetViewport(int X, int Y, int Width, int Height)
|
||||
public void SetViewport(int Attachment, int X, int Y, int Width, int Height)
|
||||
{
|
||||
Viewport = new Rect(X, Y, Width, Height);
|
||||
int Offset = Attachment * 4;
|
||||
|
||||
SetViewport(Viewport);
|
||||
}
|
||||
|
||||
private void SetViewport(Rect Viewport)
|
||||
{
|
||||
GL.Viewport(
|
||||
Viewport.X,
|
||||
Viewport.Y,
|
||||
Viewport.Width,
|
||||
Viewport.Height);
|
||||
Viewports[Offset + 0] = X;
|
||||
Viewports[Offset + 1] = Y;
|
||||
Viewports[Offset + 2] = Width;
|
||||
Viewports[Offset + 3] = Height;
|
||||
}
|
||||
|
||||
public void Render()
|
||||
|
@ -276,7 +331,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.FramebufferTexture(FramebufferTarget.ReadFramebuffer, FramebufferAttachment.ColorAttachment0, ReadTex.Handle, 0);
|
||||
|
||||
GL.ReadBuffer(ReadBufferMode.ColorAttachment0);
|
||||
GL.DrawBuffer(DrawBufferMode.ColorAttachment0);
|
||||
|
||||
GL.Clear(ClearBufferMask.ColorBufferBit);
|
||||
|
||||
|
@ -285,8 +339,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
DstX0, DstY0, DstX1, DstY1,
|
||||
ClearBufferMask.ColorBufferBit,
|
||||
BlitFramebufferFilter.Linear);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
|
||||
public void Copy(
|
||||
|
@ -343,8 +395,6 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
GL.Clear(Mask);
|
||||
|
||||
GL.BlitFramebuffer(SrcX0, SrcY0, SrcX1, SrcY1, DstX0, DstY0, DstX1, DstY1, Mask, Filter);
|
||||
|
||||
EnsureFrameBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,15 +469,5 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
(CachedImage.HasDepth ? ClearBufferMask.DepthBufferBit : 0) |
|
||||
(CachedImage.HasStencil ? ClearBufferMask.StencilBufferBit : 0);
|
||||
}
|
||||
|
||||
private void EnsureFrameBuffer()
|
||||
{
|
||||
if (DummyFrameBuffer == 0)
|
||||
{
|
||||
DummyFrameBuffer = GL.GenFramebuffer();
|
||||
}
|
||||
|
||||
GL.BindFramebuffer(FramebufferTarget.DrawFramebuffer, DummyFrameBuffer);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,16 +55,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
GlslDecompiler Decompiler = new GlslDecompiler();
|
||||
|
||||
int ShaderDumpIndex = ShaderDumper.DumpIndex;
|
||||
|
||||
if (IsDualVp)
|
||||
{
|
||||
ShaderDumper.Dump(Memory, Position, Type, "a");
|
||||
ShaderDumper.Dump(Memory, PositionB, Type, "b");
|
||||
|
||||
Program = Decompiler.Decompile(
|
||||
Memory,
|
||||
Position,
|
||||
PositionB,
|
||||
Type);
|
||||
Program = Decompiler.Decompile(Memory, Position, PositionB, Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -73,11 +71,14 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Program = Decompiler.Decompile(Memory, Position, Type);
|
||||
}
|
||||
|
||||
return new OGLShaderStage(
|
||||
Type,
|
||||
Program.Code,
|
||||
Program.Uniforms,
|
||||
Program.Textures);
|
||||
string Code = Program.Code;
|
||||
|
||||
if (ShaderDumper.IsDumpEnabled())
|
||||
{
|
||||
Code = "//Shader " + ShaderDumpIndex + Environment.NewLine + Code;
|
||||
}
|
||||
|
||||
return new OGLShaderStage(Type, Code, Program.Uniforms, Program.Textures);
|
||||
}
|
||||
|
||||
public IEnumerable<ShaderDeclInfo> GetConstBufferUsage(long Key)
|
||||
|
@ -133,7 +134,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
{
|
||||
//Enhanced layouts are required for Geometry shaders
|
||||
//skip this stage if current driver has no ARB_enhanced_layouts
|
||||
if (!OGLExtension.HasEnhancedLayouts())
|
||||
if (!OGLExtension.EnhancedLayouts)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -39,41 +39,25 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
|
||||
if (ImageUtils.IsCompressed(Image.Format))
|
||||
{
|
||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||
|
||||
GL.CompressedTexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Size,
|
||||
IntPtr.Zero);
|
||||
throw new InvalidOperationException("Surfaces with compressed formats are not supported!");
|
||||
}
|
||||
else
|
||||
{
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
(PixelInternalFormat InternalFmt,
|
||||
PixelFormat Format,
|
||||
PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format);
|
||||
|
||||
GL.TexImage2D(
|
||||
TextureTarget.Texture2D,
|
||||
Level,
|
||||
InternalFmt,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
Border,
|
||||
Format,
|
||||
Type,
|
||||
IntPtr.Zero);
|
||||
}
|
||||
|
||||
public void Create(long Key, byte[] Data, GalImage Image)
|
||||
|
@ -87,11 +71,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
|
||||
TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length);
|
||||
|
||||
GalImageFormat TypeLess = Image.Format & GalImageFormat.FormatMask;
|
||||
|
||||
bool IsASTC = TypeLess >= GalImageFormat.ASTC_BEGIN && TypeLess <= GalImageFormat.ASTC_END;
|
||||
|
||||
if (ImageUtils.IsCompressed(Image.Format) && !IsASTC)
|
||||
if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format))
|
||||
{
|
||||
InternalFormat InternalFmt = OGLEnumConverter.GetCompressedImageFormat(Image.Format);
|
||||
|
||||
|
@ -108,7 +88,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
else
|
||||
{
|
||||
//TODO: Use KHR_texture_compression_astc_hdr when available
|
||||
if (IsASTC)
|
||||
if (IsAstc(Image.Format))
|
||||
{
|
||||
int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format);
|
||||
int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format);
|
||||
|
@ -120,17 +100,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
Image.Width,
|
||||
Image.Height, 1);
|
||||
|
||||
Image.Format = GalImageFormat.A8B8G8R8 | GalImageFormat.Unorm;
|
||||
}
|
||||
else if (TypeLess == GalImageFormat.G8R8)
|
||||
{
|
||||
Data = ImageConverter.G8R8ToR8G8(
|
||||
Data,
|
||||
Image.Width,
|
||||
Image.Height,
|
||||
1);
|
||||
|
||||
Image.Format = GalImageFormat.R8G8 | (Image.Format & GalImageFormat.TypeMask);
|
||||
Image.Format = GalImageFormat.RGBA8 | GalImageFormat.Unorm;
|
||||
}
|
||||
|
||||
(PixelInternalFormat InternalFmt,
|
||||
|
@ -150,6 +120,13 @@ namespace Ryujinx.Graphics.Gal.OpenGL
|
|||
}
|
||||
}
|
||||
|
||||
private static bool IsAstc(GalImageFormat Format)
|
||||
{
|
||||
Format &= GalImageFormat.FormatMask;
|
||||
|
||||
return Format > GalImageFormat.Astc2DStart && Format < GalImageFormat.Astc2DEnd;
|
||||
}
|
||||
|
||||
public bool TryGetImage(long Key, out GalImage Image)
|
||||
{
|
||||
if (TextureCache.TryGetValue(Key, out ImageHandler CachedImage))
|
||||
|
|
|
@ -360,7 +360,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
private void PrintDeclSsy()
|
||||
{
|
||||
SB.AppendLine("uint " + GlslDecl.SsyCursorName + "= 0;");
|
||||
SB.AppendLine("uint " + GlslDecl.SsyCursorName + " = 0;");
|
||||
|
||||
SB.AppendLine("uint " + GlslDecl.SsyStackName + "[" + GlslDecl.SsyStackSize + "];" + Environment.NewLine);
|
||||
}
|
||||
|
|
|
@ -585,6 +585,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
bool AbsA = OpCode.Read(46);
|
||||
bool NegA = OpCode.Read(48);
|
||||
bool AbsB = OpCode.Read(49);
|
||||
bool Sat = OpCode.Read(50);
|
||||
|
||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
||||
|
||||
|
@ -603,12 +604,13 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fadd, OperA, OperB);
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||
}
|
||||
|
||||
private static void EmitFmul(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||
{
|
||||
bool NegB = OpCode.Read(48);
|
||||
bool Sat = OpCode.Read(50);
|
||||
|
||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB;
|
||||
|
||||
|
@ -625,13 +627,14 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrNode Op = new ShaderIrOp(ShaderIrInst.Fmul, OperA, OperB);
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||
}
|
||||
|
||||
private static void EmitFfma(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||
{
|
||||
bool NegB = OpCode.Read(48);
|
||||
bool NegC = OpCode.Read(49);
|
||||
bool Sat = OpCode.Read(50);
|
||||
|
||||
ShaderIrNode OperA = OpCode.Gpr8(), OperB, OperC;
|
||||
|
||||
|
@ -658,7 +661,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
ShaderIrOp Op = new ShaderIrOp(ShaderIrInst.Ffma, OperA, OperB, OperC);
|
||||
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), Op)));
|
||||
Block.AddNode(OpCode.PredNode(new ShaderIrAsg(OpCode.Gpr0(), GetAluFsat(Op, Sat))));
|
||||
}
|
||||
|
||||
private static void EmitIadd(ShaderIrBlock Block, long OpCode, ShaderOper Oper)
|
||||
|
|
|
@ -2,6 +2,9 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
static class ShaderDecodeHelper
|
||||
{
|
||||
private static readonly ShaderIrOperImmf ImmfZero = new ShaderIrOperImmf(0);
|
||||
private static readonly ShaderIrOperImmf ImmfOne = new ShaderIrOperImmf(1);
|
||||
|
||||
public static ShaderIrNode GetAluFabsFneg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||
{
|
||||
return GetAluFneg(GetAluFabs(Node, Abs), Neg);
|
||||
|
@ -17,6 +20,11 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
return Neg ? new ShaderIrOp(ShaderIrInst.Fneg, Node) : Node;
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluFsat(ShaderIrNode Node, bool Sat)
|
||||
{
|
||||
return Sat ? new ShaderIrOp(ShaderIrInst.Fclamp, Node, ImmfZero, ImmfOne) : Node;
|
||||
}
|
||||
|
||||
public static ShaderIrNode GetAluIabsIneg(ShaderIrNode Node, bool Abs, bool Neg)
|
||||
{
|
||||
return GetAluIneg(GetAluIabs(Node, Abs), Neg);
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
{
|
||||
int Target = ((ShaderIrOperImm)CurrOp.OperandA).Value;
|
||||
|
||||
Current.Branch = Enqueue(Target, Current);
|
||||
Enqueue(Target, Current);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -165,7 +165,7 @@ namespace Ryujinx.Graphics.Gal.Shader
|
|||
|
||||
DbgOpCode += (Decode?.Method.Name ?? "???");
|
||||
|
||||
if (Decode == ShaderDecode.Bra)
|
||||
if (Decode == ShaderDecode.Bra || Decode == ShaderDecode.Ssy)
|
||||
{
|
||||
int Offset = ((int)(OpCode >> 20) << 8) >> 8;
|
||||
|
||||
|
|
|
@ -7,11 +7,11 @@ namespace Ryujinx.Graphics.Gal
|
|||
{
|
||||
private static string RuntimeDir;
|
||||
|
||||
private static int DumpIndex = 1;
|
||||
public static int DumpIndex { get; private set; } = 1;
|
||||
|
||||
public static void Dump(IGalMemory Memory, long Position, GalShaderType Type, string ExtSuffix = "")
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(GraphicsConfig.ShadersDumpPath))
|
||||
if (!IsDumpEnabled())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -25,9 +25,10 @@ namespace Ryujinx.Graphics.Gal
|
|||
|
||||
using (FileStream FullFile = File.Create(FullPath))
|
||||
using (FileStream CodeFile = File.Create(CodePath))
|
||||
using (BinaryWriter FullWriter = new BinaryWriter(FullFile))
|
||||
using (BinaryWriter CodeWriter = new BinaryWriter(CodeFile))
|
||||
{
|
||||
BinaryWriter FullWriter = new BinaryWriter(FullFile);
|
||||
BinaryWriter CodeWriter = new BinaryWriter(CodeFile);
|
||||
|
||||
for (long i = 0; i < 0x50; i += 4)
|
||||
{
|
||||
FullWriter.Write(Memory.ReadInt32(Position + i));
|
||||
|
@ -69,6 +70,11 @@ namespace Ryujinx.Graphics.Gal
|
|||
}
|
||||
}
|
||||
|
||||
public static bool IsDumpEnabled()
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(GraphicsConfig.ShadersDumpPath);
|
||||
}
|
||||
|
||||
private static string FullDir()
|
||||
{
|
||||
return CreateAndReturn(Path.Combine(DumpDir(), "Full"));
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace Ryujinx.Graphics
|
|||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||
}
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment, NewImage);
|
||||
Gpu.Renderer.RenderTarget.BindColor(Position, Attachment);
|
||||
}
|
||||
|
||||
public void SendZetaBuffer(NvGpuVmm Vmm, long Position, GalImage NewImage)
|
||||
|
@ -60,7 +60,7 @@ namespace Ryujinx.Graphics
|
|||
Gpu.Renderer.Texture.Create(Position, (int)Size, NewImage);
|
||||
}
|
||||
|
||||
Gpu.Renderer.RenderTarget.BindZeta(Position, NewImage);
|
||||
Gpu.Renderer.RenderTarget.BindZeta(Position);
|
||||
}
|
||||
|
||||
public void SendTexture(NvGpuVmm Vmm, long Position, GalImage NewImage, int TexIndex = -1)
|
||||
|
|
|
@ -97,10 +97,14 @@ namespace Ryujinx.Graphics
|
|||
SetCullFace(State);
|
||||
SetDepth(State);
|
||||
SetStencil(State);
|
||||
SetAlphaBlending(State);
|
||||
SetBlending(State);
|
||||
SetColorMask(State);
|
||||
SetPrimitiveRestart(State);
|
||||
|
||||
SetFrameBuffer(Vmm, 0);
|
||||
for (int FbIndex = 0; FbIndex < 8; FbIndex++)
|
||||
{
|
||||
SetFrameBuffer(Vmm, FbIndex);
|
||||
}
|
||||
|
||||
SetZeta(Vmm);
|
||||
|
||||
|
@ -137,7 +141,7 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
int Arg0 = PBEntry.Arguments[0];
|
||||
|
||||
int FbIndex = (Arg0 >> 6) & 0xf;
|
||||
int Attachment = (Arg0 >> 6) & 0xf;
|
||||
|
||||
GalClearBufferFlags Flags = (GalClearBufferFlags)(Arg0 & 0x3f);
|
||||
|
||||
|
@ -150,16 +154,18 @@ namespace Ryujinx.Graphics
|
|||
|
||||
int Stencil = ReadRegister(NvGpuEngine3dReg.ClearStencil);
|
||||
|
||||
SetFrameBuffer(Vmm, FbIndex);
|
||||
SetFrameBuffer(Vmm, Attachment);
|
||||
|
||||
SetZeta(Vmm);
|
||||
|
||||
Gpu.Renderer.Rasterizer.ClearBuffers(
|
||||
Flags,
|
||||
FbIndex,
|
||||
Red, Green, Blue, Alpha,
|
||||
Depth,
|
||||
Stencil);
|
||||
SetRenderTargets();
|
||||
|
||||
Gpu.Renderer.RenderTarget.Bind();
|
||||
|
||||
Gpu.Renderer.Rasterizer.ClearBuffers(Flags, Attachment, Red, Green, Blue, Alpha, Depth, Stencil);
|
||||
|
||||
Gpu.Renderer.Pipeline.ResetDepthMask();
|
||||
Gpu.Renderer.Pipeline.ResetColorMask(Attachment);
|
||||
}
|
||||
|
||||
private void SetFrameBuffer(NvGpuVmm Vmm, int FbIndex)
|
||||
|
@ -204,7 +210,7 @@ namespace Ryujinx.Graphics
|
|||
|
||||
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
|
||||
|
||||
Gpu.Renderer.RenderTarget.SetViewport(VpX, VpY, VpW, VpH);
|
||||
Gpu.Renderer.RenderTarget.SetViewport(FbIndex, VpX, VpY, VpW, VpH);
|
||||
}
|
||||
|
||||
private void SetFrameBuffer(GalPipelineState State)
|
||||
|
@ -337,13 +343,8 @@ namespace Ryujinx.Graphics
|
|||
{
|
||||
switch (FrontFace)
|
||||
{
|
||||
case GalFrontFace.CW:
|
||||
FrontFace = GalFrontFace.CCW;
|
||||
break;
|
||||
|
||||
case GalFrontFace.CCW:
|
||||
FrontFace = GalFrontFace.CW;
|
||||
break;
|
||||
case GalFrontFace.CW: FrontFace = GalFrontFace.CCW; break;
|
||||
case GalFrontFace.CCW: FrontFace = GalFrontFace.CW; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -396,7 +397,7 @@ namespace Ryujinx.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
private void SetAlphaBlending(GalPipelineState State)
|
||||
private void SetBlending(GalPipelineState State)
|
||||
{
|
||||
//TODO: Support independent blend properly.
|
||||
State.BlendEnabled = ReadRegisterBool(NvGpuEngine3dReg.IBlendNEnable);
|
||||
|
@ -414,6 +415,26 @@ namespace Ryujinx.Graphics
|
|||
}
|
||||
}
|
||||
|
||||
private void SetColorMask(GalPipelineState State)
|
||||
{
|
||||
int ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMask);
|
||||
|
||||
State.ColorMask.Red = ((ColorMask >> 0) & 0xf) != 0;
|
||||
State.ColorMask.Green = ((ColorMask >> 4) & 0xf) != 0;
|
||||
State.ColorMask.Blue = ((ColorMask >> 8) & 0xf) != 0;
|
||||
State.ColorMask.Alpha = ((ColorMask >> 12) & 0xf) != 0;
|
||||
|
||||
for (int Index = 0; Index < GalPipelineState.RenderTargetsCount; Index++)
|
||||
{
|
||||
ColorMask = ReadRegister(NvGpuEngine3dReg.ColorMaskN + Index);
|
||||
|
||||
State.ColorMasks[Index].Red = ((ColorMask >> 0) & 0xf) != 0;
|
||||
State.ColorMasks[Index].Green = ((ColorMask >> 4) & 0xf) != 0;
|
||||
State.ColorMasks[Index].Blue = ((ColorMask >> 8) & 0xf) != 0;
|
||||
State.ColorMasks[Index].Alpha = ((ColorMask >> 12) & 0xf) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void SetPrimitiveRestart(GalPipelineState State)
|
||||
{
|
||||
State.PrimitiveRestartEnabled = ReadRegisterBool(NvGpuEngine3dReg.PrimRestartEnable);
|
||||
|
@ -426,21 +447,22 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void SetRenderTargets()
|
||||
{
|
||||
bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData);
|
||||
//Commercial games do not seem to
|
||||
//bool SeparateFragData = ReadRegisterBool(NvGpuEngine3dReg.RTSeparateFragData);
|
||||
|
||||
if (SeparateFragData)
|
||||
uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
|
||||
|
||||
uint Count = Control & 0xf;
|
||||
|
||||
if (Count > 0)
|
||||
{
|
||||
uint Control = (uint)(ReadRegister(NvGpuEngine3dReg.RTControl));
|
||||
|
||||
uint Count = Control & 0xf;
|
||||
|
||||
int[] Map = new int[Count];
|
||||
|
||||
for (int i = 0; i < Count; i++)
|
||||
for (int Index = 0; Index < Count; Index++)
|
||||
{
|
||||
int Shift = 4 + i * 3;
|
||||
int Shift = 4 + Index * 3;
|
||||
|
||||
Map[i] = (int)((Control >> Shift) & 7);
|
||||
Map[Index] = (int)((Control >> Shift) & 7);
|
||||
}
|
||||
|
||||
Gpu.Renderer.RenderTarget.SetMap(Map);
|
||||
|
@ -560,12 +582,15 @@ namespace Ryujinx.Graphics
|
|||
|
||||
private void UploadVertexArrays(NvGpuVmm Vmm, GalPipelineState State)
|
||||
{
|
||||
long IndexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||
long IbPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.IndexArrayAddress);
|
||||
|
||||
long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
|
||||
long IboKey = Vmm.GetPhysicalAddress(IbPosition);
|
||||
|
||||
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
||||
int IndexCount = ReadRegister(NvGpuEngine3dReg.IndexBatchCount);
|
||||
int PrimCtrl = ReadRegister(NvGpuEngine3dReg.VertexBeginGl);
|
||||
|
||||
GalPrimitiveType PrimType = (GalPrimitiveType)(PrimCtrl & 0xffff);
|
||||
|
||||
GalIndexFormat IndexFormat = (GalIndexFormat)IndexEntryFmt;
|
||||
|
||||
|
@ -582,14 +607,50 @@ namespace Ryujinx.Graphics
|
|||
|
||||
bool IboCached = Gpu.Renderer.Rasterizer.IsIboCached(IboKey, (uint)IbSize);
|
||||
|
||||
bool UsesLegacyQuads =
|
||||
PrimType == GalPrimitiveType.Quads ||
|
||||
PrimType == GalPrimitiveType.QuadStrip;
|
||||
|
||||
if (!IboCached || QueryKeyUpload(Vmm, IboKey, (uint)IbSize, NvGpuBufferType.Index))
|
||||
{
|
||||
IntPtr DataAddress = Vmm.GetHostAddress(IndexPosition, IbSize);
|
||||
if (!UsesLegacyQuads)
|
||||
{
|
||||
IntPtr DataAddress = Vmm.GetHostAddress(IbPosition, IbSize);
|
||||
|
||||
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
|
||||
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, DataAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] Buffer = Vmm.ReadBytes(IbPosition, IbSize);
|
||||
|
||||
if (PrimType == GalPrimitiveType.Quads)
|
||||
{
|
||||
Buffer = QuadHelper.ConvertIbQuadsToTris(Buffer, IndexEntrySize, IndexCount);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
Buffer = QuadHelper.ConvertIbQuadStripToTris(Buffer, IndexEntrySize, IndexCount);
|
||||
}
|
||||
|
||||
Gpu.Renderer.Rasterizer.CreateIbo(IboKey, IbSize, Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
|
||||
if (!UsesLegacyQuads)
|
||||
{
|
||||
Gpu.Renderer.Rasterizer.SetIndexArray(IbSize, IndexFormat);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PrimType == GalPrimitiveType.Quads)
|
||||
{
|
||||
Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadsToTris(IbSize), IndexFormat);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
Gpu.Renderer.Rasterizer.SetIndexArray(QuadHelper.ConvertIbSizeQuadStripToTris(IbSize), IndexFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<GalVertexAttrib>[] Attribs = new List<GalVertexAttrib>[32];
|
||||
|
@ -605,10 +666,19 @@ namespace Ryujinx.Graphics
|
|||
Attribs[ArrayIndex] = new List<GalVertexAttrib>();
|
||||
}
|
||||
|
||||
long VertexPosition = MakeInt64From2xInt32(NvGpuEngine3dReg.VertexArrayNAddress + ArrayIndex * 4);
|
||||
|
||||
int Offset = (Packed >> 7) & 0x3fff;
|
||||
|
||||
//Note: 16 is the maximum size of an attribute,
|
||||
//having a component size of 32-bits with 4 elements (a vec4).
|
||||
IntPtr Pointer = Vmm.GetHostAddress(VertexPosition + Offset, 16);
|
||||
|
||||
Attribs[ArrayIndex].Add(new GalVertexAttrib(
|
||||
Attr,
|
||||
((Packed >> 6) & 0x1) != 0,
|
||||
(Packed >> 7) & 0x3fff,
|
||||
Offset,
|
||||
Pointer,
|
||||
(GalVertexAttribSize)((Packed >> 21) & 0x3f),
|
||||
(GalVertexAttribType)((Packed >> 27) & 0x7),
|
||||
((Packed >> 31) & 0x1) != 0));
|
||||
|
@ -702,6 +772,8 @@ namespace Ryujinx.Graphics
|
|||
|
||||
Gpu.Renderer.Pipeline.Bind(State);
|
||||
|
||||
Gpu.Renderer.RenderTarget.Bind();
|
||||
|
||||
if (IndexCount != 0)
|
||||
{
|
||||
int IndexEntryFmt = ReadRegister(NvGpuEngine3dReg.IndexArrayFormat);
|
||||
|
@ -712,6 +784,27 @@ namespace Ryujinx.Graphics
|
|||
|
||||
long IboKey = Vmm.GetPhysicalAddress(IndexPosition);
|
||||
|
||||
//Quad primitive types were deprecated on OpenGL 3.x,
|
||||
//they are converted to a triangles index buffer on IB creation,
|
||||
//so we should use the triangles type here too.
|
||||
if (PrimType == GalPrimitiveType.Quads ||
|
||||
PrimType == GalPrimitiveType.QuadStrip)
|
||||
{
|
||||
PrimType = GalPrimitiveType.Triangles;
|
||||
|
||||
//Note: We assume that index first points to the first
|
||||
//vertex of a quad, if it points to the middle of a
|
||||
//quad (First % 4 != 0 for Quads) then it will not work properly.
|
||||
if (PrimType == GalPrimitiveType.Quads)
|
||||
{
|
||||
IndexFirst = QuadHelper.ConvertIbSizeQuadsToTris(IndexFirst);
|
||||
}
|
||||
else /* if (PrimType == GalPrimitiveType.QuadStrip) */
|
||||
{
|
||||
IndexFirst = QuadHelper.ConvertIbSizeQuadStripToTris(IndexFirst);
|
||||
}
|
||||
}
|
||||
|
||||
Gpu.Renderer.Rasterizer.DrawElements(IboKey, IndexFirst, VertexBase, PrimType);
|
||||
}
|
||||
else
|
||||
|
|
|
@ -23,6 +23,7 @@ namespace Ryujinx.Graphics
|
|||
StencilBackFuncRef = 0x3d5,
|
||||
StencilBackMask = 0x3d6,
|
||||
StencilBackFuncMask = 0x3d7,
|
||||
ColorMask = 0x3e4,
|
||||
RTSeparateFragData = 0x3eb,
|
||||
ZetaAddress = 0x3f8,
|
||||
ZetaFormat = 0x3fa,
|
||||
|
@ -78,6 +79,7 @@ namespace Ryujinx.Graphics
|
|||
CullFaceEnable = 0x646,
|
||||
FrontFace = 0x647,
|
||||
CullFace = 0x648,
|
||||
ColorMaskN = 0x680,
|
||||
QueryAddress = 0x6c0,
|
||||
QuerySequence = 0x6c2,
|
||||
QueryControl = 0x6c3,
|
||||
|
|
81
Ryujinx.Graphics/QuadHelper.cs
Normal file
81
Ryujinx.Graphics/QuadHelper.cs
Normal file
|
@ -0,0 +1,81 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics
|
||||
{
|
||||
static class QuadHelper
|
||||
{
|
||||
public static int ConvertIbSizeQuadsToTris(int Size)
|
||||
{
|
||||
return Size <= 0 ? 0 : (Size / 4) * 6;
|
||||
}
|
||||
|
||||
public static int ConvertIbSizeQuadStripToTris(int Size)
|
||||
{
|
||||
return Size <= 1 ? 0 : ((Size - 2) / 2) * 6;
|
||||
}
|
||||
|
||||
public static byte[] ConvertIbQuadsToTris(byte[] Data, int EntrySize, int Count)
|
||||
{
|
||||
int PrimitivesCount = Count / 4;
|
||||
|
||||
int QuadPrimSize = 4 * EntrySize;
|
||||
int TrisPrimSize = 6 * EntrySize;
|
||||
|
||||
byte[] Output = new byte[PrimitivesCount * 6 * EntrySize];
|
||||
|
||||
for (int Prim = 0; Prim < PrimitivesCount; Prim++)
|
||||
{
|
||||
void AssignIndex(int Src, int Dst, int CopyCount = 1)
|
||||
{
|
||||
Src = Prim * QuadPrimSize + Src * EntrySize;
|
||||
Dst = Prim * TrisPrimSize + Dst * EntrySize;
|
||||
|
||||
Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize);
|
||||
}
|
||||
|
||||
//0 1 2 -> 0 1 2.
|
||||
AssignIndex(0, 0, 3);
|
||||
|
||||
//2 3 -> 3 4.
|
||||
AssignIndex(2, 3, 2);
|
||||
|
||||
//0 -> 5.
|
||||
AssignIndex(0, 5);
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
|
||||
public static byte[] ConvertIbQuadStripToTris(byte[] Data, int EntrySize, int Count)
|
||||
{
|
||||
int PrimitivesCount = (Count - 2) / 2;
|
||||
|
||||
int QuadPrimSize = 2 * EntrySize;
|
||||
int TrisPrimSize = 6 * EntrySize;
|
||||
|
||||
byte[] Output = new byte[PrimitivesCount * 6 * EntrySize];
|
||||
|
||||
for (int Prim = 0; Prim < PrimitivesCount; Prim++)
|
||||
{
|
||||
void AssignIndex(int Src, int Dst, int CopyCount = 1)
|
||||
{
|
||||
Src = Prim * QuadPrimSize + Src * EntrySize + 2 * EntrySize;
|
||||
Dst = Prim * TrisPrimSize + Dst * EntrySize;
|
||||
|
||||
Buffer.BlockCopy(Data, Src, Output, Dst, CopyCount * EntrySize);
|
||||
}
|
||||
|
||||
//-2 -1 0 -> 0 1 2.
|
||||
AssignIndex(-2, 0, 3);
|
||||
|
||||
//0 1 -> 3 4.
|
||||
AssignIndex(0, 3, 2);
|
||||
|
||||
//-2 -> 5.
|
||||
AssignIndex(-2, 5);
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
namespace Ryujinx.Graphics.Texture
|
||||
{
|
||||
static class ImageConverter
|
||||
{
|
||||
public static byte[] G8R8ToR8G8(
|
||||
byte[] Data,
|
||||
int Width,
|
||||
int Height,
|
||||
int Depth)
|
||||
{
|
||||
int Texels = Width * Height * Depth;
|
||||
|
||||
byte[] Output = new byte[Texels * 2];
|
||||
|
||||
for (int Texel = 0; Texel < Texels; Texel++)
|
||||
{
|
||||
Output[Texel * 2 + 0] = Data[Texel * 2 + 1];
|
||||
Output[Texel * 2 + 1] = Data[Texel * 2 + 0];
|
||||
}
|
||||
|
||||
return Output;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,105 +35,105 @@ namespace Ryujinx.Graphics.Texture
|
|||
}
|
||||
}
|
||||
|
||||
private const GalImageFormat Snorm = GalImageFormat.Snorm;
|
||||
private const GalImageFormat Unorm = GalImageFormat.Unorm;
|
||||
private const GalImageFormat Sint = GalImageFormat.Sint;
|
||||
private const GalImageFormat Uint = GalImageFormat.Uint;
|
||||
private const GalImageFormat Sfloat = GalImageFormat.Sfloat;
|
||||
private const GalImageFormat Snorm = GalImageFormat.Snorm;
|
||||
private const GalImageFormat Unorm = GalImageFormat.Unorm;
|
||||
private const GalImageFormat Sint = GalImageFormat.Sint;
|
||||
private const GalImageFormat Uint = GalImageFormat.Uint;
|
||||
private const GalImageFormat Float = GalImageFormat.Float;
|
||||
private const GalImageFormat Srgb = GalImageFormat.Srgb;
|
||||
|
||||
private static readonly Dictionary<GalTextureFormat, GalImageFormat> s_TextureTable =
|
||||
new Dictionary<GalTextureFormat, GalImageFormat>()
|
||||
{
|
||||
{ GalTextureFormat.R32G32B32A32, GalImageFormat.R32G32B32A32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R16G16B16A16, GalImageFormat.R16G16B16A16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R32G32, GalImageFormat.R32G32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.A8B8G8R8, GalImageFormat.A8B8G8R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.A2B10G10R10, GalImageFormat.A2B10G10R10 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.G8R8, GalImageFormat.G8R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16G16, GalImageFormat.R16G16 | Snorm | Sfloat },
|
||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Sfloat },
|
||||
{ GalTextureFormat.A4B4G4R4, GalImageFormat.A4B4G4R4 | Unorm },
|
||||
{ GalTextureFormat.A1B5G5R5, GalImageFormat.A1R5G5B5 | Unorm },
|
||||
{ GalTextureFormat.B5G6R5, GalImageFormat.B5G6R5 | Unorm },
|
||||
{ GalTextureFormat.BF10GF11RF11, GalImageFormat.B10G11R11 | Sfloat },
|
||||
{ GalTextureFormat.Z24S8, GalImageFormat.D24_S8 | Unorm },
|
||||
{ GalTextureFormat.ZF32, GalImageFormat.D32 | Sfloat },
|
||||
{ GalTextureFormat.ZF32_X24S8, GalImageFormat.D32_S8 | Unorm },
|
||||
{ GalTextureFormat.Z16, GalImageFormat.D16 | Unorm },
|
||||
{
|
||||
{ GalTextureFormat.RGBA32, GalImageFormat.RGBA32 | Sint | Uint | Float },
|
||||
{ GalTextureFormat.RGBA16, GalImageFormat.RGBA16 | Snorm | Unorm | Sint | Uint | Float },
|
||||
{ GalTextureFormat.RG32, GalImageFormat.RG32 | Sint | Uint | Float },
|
||||
{ GalTextureFormat.RGBA8, GalImageFormat.RGBA8 | Snorm | Unorm | Sint | Uint | Srgb },
|
||||
{ GalTextureFormat.RGB10A2, GalImageFormat.RGB10A2 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.RG8, GalImageFormat.RG8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.R16, GalImageFormat.R16 | Snorm | Unorm | Sint | Uint | Float },
|
||||
{ GalTextureFormat.R8, GalImageFormat.R8 | Snorm | Unorm | Sint | Uint },
|
||||
{ GalTextureFormat.RG16, GalImageFormat.RG16 | Snorm | Unorm | Float },
|
||||
{ GalTextureFormat.R32, GalImageFormat.R32 | Sint | Uint | Float },
|
||||
{ GalTextureFormat.RGBA4, GalImageFormat.RGBA4 | Unorm },
|
||||
{ GalTextureFormat.RGB5A1, GalImageFormat.RGB5A1 | Unorm },
|
||||
{ GalTextureFormat.RGB565, GalImageFormat.RGB565 | Unorm },
|
||||
{ GalTextureFormat.R11G11B10F, GalImageFormat.R11G11B10 | Float },
|
||||
{ GalTextureFormat.D24S8, GalImageFormat.D24S8 | Unorm | Uint },
|
||||
{ GalTextureFormat.D32F, GalImageFormat.D32 | Float },
|
||||
{ GalTextureFormat.D32FX24S8, GalImageFormat.D32S8 | Unorm },
|
||||
{ GalTextureFormat.D16, GalImageFormat.D16 | Unorm },
|
||||
|
||||
//Compressed formats
|
||||
{ GalTextureFormat.BC6H_SF16, GalImageFormat.BC6H_SF16 | Unorm },
|
||||
{ GalTextureFormat.BC6H_UF16, GalImageFormat.BC6H_UF16 | Sfloat },
|
||||
{ GalTextureFormat.BC7U, GalImageFormat.BC7 | Unorm },
|
||||
{ GalTextureFormat.BC1, GalImageFormat.BC1_RGBA | Unorm },
|
||||
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm },
|
||||
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm },
|
||||
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
||||
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
||||
{ GalTextureFormat.Astc2D4x4, GalImageFormat.ASTC_4x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x5, GalImageFormat.ASTC_5x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x6, GalImageFormat.ASTC_6x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x8, GalImageFormat.ASTC_8x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x10, GalImageFormat.ASTC_10x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x12, GalImageFormat.ASTC_12x12 | Unorm },
|
||||
{ GalTextureFormat.Astc2D5x4, GalImageFormat.ASTC_5x4 | Unorm },
|
||||
{ GalTextureFormat.Astc2D6x5, GalImageFormat.ASTC_6x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x6, GalImageFormat.ASTC_8x6 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x8, GalImageFormat.ASTC_10x8 | Unorm },
|
||||
{ GalTextureFormat.Astc2D12x10, GalImageFormat.ASTC_12x10 | Unorm },
|
||||
{ GalTextureFormat.Astc2D8x5, GalImageFormat.ASTC_8x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x5, GalImageFormat.ASTC_10x5 | Unorm },
|
||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.ASTC_10x6 | Unorm }
|
||||
};
|
||||
//Compressed formats
|
||||
{ GalTextureFormat.BptcSfloat, GalImageFormat.BptcSfloat | Float },
|
||||
{ GalTextureFormat.BptcUfloat, GalImageFormat.BptcUfloat | Float },
|
||||
{ GalTextureFormat.BptcUnorm, GalImageFormat.BptcUnorm | Unorm | Srgb },
|
||||
{ GalTextureFormat.BC1, GalImageFormat.BC1 | Unorm | Srgb },
|
||||
{ GalTextureFormat.BC2, GalImageFormat.BC2 | Unorm | Srgb },
|
||||
{ GalTextureFormat.BC3, GalImageFormat.BC3 | Unorm | Srgb },
|
||||
{ GalTextureFormat.BC4, GalImageFormat.BC4 | Unorm | Snorm },
|
||||
{ GalTextureFormat.BC5, GalImageFormat.BC5 | Unorm | Snorm },
|
||||
{ GalTextureFormat.Astc2D4x4, GalImageFormat.Astc2D4x4 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D5x5, GalImageFormat.Astc2D5x5 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D6x6, GalImageFormat.Astc2D6x6 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D8x8, GalImageFormat.Astc2D8x8 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D10x10, GalImageFormat.Astc2D10x10 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D12x12, GalImageFormat.Astc2D12x12 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D5x4, GalImageFormat.Astc2D5x4 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D6x5, GalImageFormat.Astc2D6x5 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D8x6, GalImageFormat.Astc2D8x6 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D10x8, GalImageFormat.Astc2D10x8 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D12x10, GalImageFormat.Astc2D12x10 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D8x5, GalImageFormat.Astc2D8x5 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D10x5, GalImageFormat.Astc2D10x5 | Unorm | Srgb },
|
||||
{ GalTextureFormat.Astc2D10x6, GalImageFormat.Astc2D10x6 | Unorm | Srgb }
|
||||
};
|
||||
|
||||
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
|
||||
new Dictionary<GalImageFormat, ImageDescriptor>()
|
||||
{
|
||||
{ GalImageFormat.R32G32B32A32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16G16B16A16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R32G32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A8B8G8R8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A2B10G10R10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A4B4G4R4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC6H_SF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC6H_UF16, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A1R5G5B5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.B5G6R5, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC7, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16G16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R8G8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.G8R8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.B10G11R11, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.A8B8G8R8_SRGB, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC1_RGBA, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.ASTC_10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
|
||||
{ GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
|
||||
|
||||
{ GalImageFormat.D24_S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
|
||||
{ GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D32_S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) },
|
||||
{ GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
|
||||
{ GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
|
||||
{ GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) }
|
||||
};
|
||||
|
||||
public static GalImageFormat ConvertTexture(
|
||||
|
@ -141,60 +141,62 @@ namespace Ryujinx.Graphics.Texture
|
|||
GalTextureType RType,
|
||||
GalTextureType GType,
|
||||
GalTextureType BType,
|
||||
GalTextureType AType)
|
||||
GalTextureType AType,
|
||||
bool ConvSrgb)
|
||||
{
|
||||
if (RType != GType || RType != BType || RType != AType)
|
||||
{
|
||||
throw new NotImplementedException("Per component types are not implemented");
|
||||
throw new NotImplementedException("Per component types are not implemented!");
|
||||
}
|
||||
|
||||
if (!s_TextureTable.TryGetValue(Format, out GalImageFormat ImageFormat))
|
||||
{
|
||||
throw new NotImplementedException("Texture with format " + ((int)Format).ToString("x2") + " not implemented");
|
||||
throw new NotImplementedException($"Format 0x{((int)Format):x} not implemented!");
|
||||
}
|
||||
|
||||
GalTextureType Type = RType;
|
||||
GalImageFormat FormatType = ConvSrgb ? Srgb : GetFormatType(RType);
|
||||
|
||||
GalImageFormat FormatType = GetFormatType(RType);
|
||||
GalImageFormat CombinedFormat = (ImageFormat & GalImageFormat.FormatMask) | FormatType;
|
||||
|
||||
if (ImageFormat.HasFlag(FormatType))
|
||||
if (!ImageFormat.HasFlag(FormatType))
|
||||
{
|
||||
return (ImageFormat & GalImageFormat.FormatMask) | FormatType;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Texture with format " + Format +
|
||||
" and component type " + Type + " is not implemented");
|
||||
throw new NotImplementedException($"Format \"{CombinedFormat}\" not implemented!");
|
||||
}
|
||||
|
||||
return CombinedFormat;
|
||||
}
|
||||
|
||||
public static GalImageFormat ConvertSurface(GalSurfaceFormat Format)
|
||||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.R32G32B32A32 | Sfloat;
|
||||
case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.R32G32B32A32 | Uint;
|
||||
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.R16G16B16A16 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Float: return GalImageFormat.R32G32 | Sfloat;
|
||||
case GalSurfaceFormat.RG32Sint: return GalImageFormat.R32G32 | Sint;
|
||||
case GalSurfaceFormat.RG32Uint: return GalImageFormat.R32G32 | Uint;
|
||||
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.R8G8B8A8 | Unorm; //Is this right?
|
||||
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.A8B8G8R8_SRGB; //This one might be wrong
|
||||
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.A2B10G10R10 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.A8B8G8R8 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.A8B8G8R8_SRGB;
|
||||
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.A8B8G8R8 | Snorm;
|
||||
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.R16G16 | Snorm;
|
||||
case GalSurfaceFormat.RG16Float: return GalImageFormat.R16G16 | Sfloat;
|
||||
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.B10G11R11 | Sfloat;
|
||||
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Sfloat;
|
||||
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.R8G8 | Unorm;
|
||||
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.R8 | Snorm;
|
||||
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Sfloat;
|
||||
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
||||
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
||||
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.B5G6R5 | Unorm;
|
||||
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.A1R5G5B5 | Unorm;
|
||||
case GalSurfaceFormat.RGBA32Float: return GalImageFormat.RGBA32 | Float;
|
||||
case GalSurfaceFormat.RGBA32Uint: return GalImageFormat.RGBA32 | Uint;
|
||||
case GalSurfaceFormat.RGBA16Float: return GalImageFormat.RGBA16 | Float;
|
||||
case GalSurfaceFormat.RG32Float: return GalImageFormat.RG32 | Float;
|
||||
case GalSurfaceFormat.RG32Sint: return GalImageFormat.RG32 | Sint;
|
||||
case GalSurfaceFormat.RG32Uint: return GalImageFormat.RG32 | Uint;
|
||||
case GalSurfaceFormat.BGRA8Unorm: return GalImageFormat.BGRA8 | Unorm;
|
||||
case GalSurfaceFormat.BGRA8Srgb: return GalImageFormat.BGRA8 | Srgb;
|
||||
case GalSurfaceFormat.RGB10A2Unorm: return GalImageFormat.RGB10A2 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Unorm: return GalImageFormat.RGBA8 | Unorm;
|
||||
case GalSurfaceFormat.RGBA8Srgb: return GalImageFormat.RGBA8 | Srgb;
|
||||
case GalSurfaceFormat.RGBA8Snorm: return GalImageFormat.RGBA8 | Snorm;
|
||||
case GalSurfaceFormat.RG16Snorm: return GalImageFormat.RG16 | Snorm;
|
||||
case GalSurfaceFormat.RG16Unorm: return GalImageFormat.RG16 | Unorm;
|
||||
case GalSurfaceFormat.RG16Float: return GalImageFormat.RG16 | Float;
|
||||
case GalSurfaceFormat.R11G11B10Float: return GalImageFormat.R11G11B10 | Float;
|
||||
case GalSurfaceFormat.R32Float: return GalImageFormat.R32 | Float;
|
||||
case GalSurfaceFormat.R32Uint: return GalImageFormat.R32 | Uint;
|
||||
case GalSurfaceFormat.RG8Unorm: return GalImageFormat.RG8 | Unorm;
|
||||
case GalSurfaceFormat.RG8Snorm: return GalImageFormat.RG8 | Snorm;
|
||||
case GalSurfaceFormat.R16Float: return GalImageFormat.R16 | Float;
|
||||
case GalSurfaceFormat.R16Unorm: return GalImageFormat.R16 | Unorm;
|
||||
case GalSurfaceFormat.R16Uint: return GalImageFormat.R16 | Uint;
|
||||
case GalSurfaceFormat.R8Unorm: return GalImageFormat.R8 | Unorm;
|
||||
case GalSurfaceFormat.R8Uint: return GalImageFormat.R8 | Uint;
|
||||
case GalSurfaceFormat.B5G6R5Unorm: return GalImageFormat.RGB565 | Unorm;
|
||||
case GalSurfaceFormat.BGR5A1Unorm: return GalImageFormat.BGR5A1 | Unorm;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
|
@ -204,11 +206,11 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
switch (Format)
|
||||
{
|
||||
case GalZetaFormat.Z32Float: return GalImageFormat.D32 | Sfloat;
|
||||
case GalZetaFormat.S8Z24Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||
case GalZetaFormat.Z16Unorm: return GalImageFormat.D16 | Unorm;
|
||||
case GalZetaFormat.Z24S8Unorm: return GalImageFormat.D24_S8 | Unorm;
|
||||
case GalZetaFormat.Z32S8X24Float: return GalImageFormat.D32_S8 | Sfloat;
|
||||
case GalZetaFormat.D32Float: return GalImageFormat.D32 | Float;
|
||||
case GalZetaFormat.S8D24Unorm: return GalImageFormat.D24S8 | Unorm;
|
||||
case GalZetaFormat.D16Unorm: return GalImageFormat.D16 | Unorm;
|
||||
case GalZetaFormat.D24S8Unorm: return GalImageFormat.D24S8 | Unorm;
|
||||
case GalZetaFormat.D32S8X24Float: return GalImageFormat.D32S8 | Float;
|
||||
}
|
||||
|
||||
throw new NotImplementedException(Format.ToString());
|
||||
|
@ -235,18 +237,23 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
int BytesPerPixel = Desc.BytesPerPixel;
|
||||
|
||||
int OutOffs = 0;
|
||||
//Note: Each row of the texture needs to be aligned to 4 bytes.
|
||||
int Pitch = (Width * BytesPerPixel + 3) & ~3;
|
||||
|
||||
byte[] Data = new byte[Width * Height * BytesPerPixel];
|
||||
byte[] Data = new byte[Height * Pitch];
|
||||
|
||||
for (int Y = 0; Y < Height; Y++)
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
int OutOffs = Y * Pitch;
|
||||
|
||||
CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
|
||||
for (int X = 0; X < Width; X++)
|
||||
{
|
||||
long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
|
||||
|
||||
OutOffs += BytesPerPixel;
|
||||
CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
|
||||
|
||||
OutOffs += BytesPerPixel;
|
||||
}
|
||||
}
|
||||
|
||||
return Data;
|
||||
|
@ -289,7 +296,11 @@ namespace Ryujinx.Graphics.Texture
|
|||
{
|
||||
ImageDescriptor Desc = GetImageDescriptor(Format);
|
||||
|
||||
return Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
||||
int Pitch = Desc.BytesPerPixel * DivRoundUp(Width, Desc.BlockWidth);
|
||||
|
||||
Pitch = (Pitch + 0x1f) & ~0x1f;
|
||||
|
||||
return Pitch;
|
||||
}
|
||||
|
||||
public static int GetBlockWidth(GalImageFormat Format)
|
||||
|
@ -362,14 +373,14 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
private static ImageDescriptor GetImageDescriptor(GalImageFormat Format)
|
||||
{
|
||||
GalImageFormat TypeLess = (Format & GalImageFormat.FormatMask);
|
||||
GalImageFormat PixelFormat = Format & GalImageFormat.FormatMask;
|
||||
|
||||
if (s_ImageTable.TryGetValue(TypeLess, out ImageDescriptor Descriptor))
|
||||
if (s_ImageTable.TryGetValue(PixelFormat, out ImageDescriptor Descriptor))
|
||||
{
|
||||
return Descriptor;
|
||||
}
|
||||
|
||||
throw new NotImplementedException("Image with format " + TypeLess.ToString() + " not implemented");
|
||||
throw new NotImplementedException($"Format \"{PixelFormat}\" not implemented!");
|
||||
}
|
||||
|
||||
private static GalImageFormat GetFormatType(GalTextureType Type)
|
||||
|
@ -380,7 +391,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
case GalTextureType.Unorm: return Unorm;
|
||||
case GalTextureType.Sint: return Sint;
|
||||
case GalTextureType.Uint: return Uint;
|
||||
case GalTextureType.Float: return Sfloat;
|
||||
case GalTextureType.Float: return Float;
|
||||
|
||||
default: throw new NotImplementedException(((int)Type).ToString());
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Texture
|
|||
int Width = (Tic[4] & 0xffff) + 1;
|
||||
int Height = (Tic[5] & 0xffff) + 1;
|
||||
|
||||
return new GalImage(
|
||||
GalImage Image = new GalImage(
|
||||
Width,
|
||||
Height,
|
||||
TileWidth,
|
||||
|
@ -51,6 +51,13 @@ namespace Ryujinx.Graphics.Texture
|
|||
YSource,
|
||||
ZSource,
|
||||
WSource);
|
||||
|
||||
if (Layout == GalMemoryLayout.Pitch)
|
||||
{
|
||||
Image.Pitch = (Tic[3] & 0xffff) << 5;
|
||||
}
|
||||
|
||||
return Image;
|
||||
}
|
||||
|
||||
public static GalTextureSampler MakeSampler(NvGpu Gpu, NvGpuVmm Vmm, long TscPosition)
|
||||
|
@ -90,7 +97,9 @@ namespace Ryujinx.Graphics.Texture
|
|||
|
||||
GalTextureFormat Format = (GalTextureFormat)(Tic[0] & 0x7f);
|
||||
|
||||
return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType);
|
||||
bool ConvSrgb = ((Tic[4] >> 22) & 1) != 0;
|
||||
|
||||
return ImageUtils.ConvertTexture(Format, RType, GType, BType, AType, ConvSrgb);
|
||||
}
|
||||
|
||||
private static int[] ReadWords(NvGpuVmm Vmm, long Position, int Count)
|
||||
|
|
|
@ -35,9 +35,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||
}
|
||||
}
|
||||
|
||||
string SaveAccount = SaveMetaData.UserId.IsZero() ? "savecommon" : SaveMetaData.UserId.ToString();
|
||||
|
||||
string SavePath = Path.Combine(BaseSavePath,
|
||||
SaveMetaData.SaveId.ToString("x16"),
|
||||
SaveMetaData.UserId.ToString(),
|
||||
SaveAccount,
|
||||
SaveMetaData.SaveDataType == SaveDataType.SaveData ? CurrentTitleId.ToString("x16") : string.Empty);
|
||||
|
||||
return SavePath;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
|
||||
namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
|
@ -6,7 +6,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
public long TitleId { get; private set; }
|
||||
public long SaveId { get; private set; }
|
||||
public UserId UserId { get; private set; }
|
||||
public UInt128 UserId { get; private set; }
|
||||
|
||||
public SaveDataType SaveDataType { get; private set; }
|
||||
public SaveSpaceId SaveSpaceId { get; private set; }
|
||||
|
@ -15,7 +15,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||
long TitleId,
|
||||
long SaveId,
|
||||
SaveDataType SaveDataType,
|
||||
UserId UserId,
|
||||
UInt128 UserId,
|
||||
SaveSpaceId SaveSpaceId)
|
||||
{
|
||||
this.TitleId = TitleId;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
||||
{
|
||||
public class CastExpression : BaseNode
|
||||
|
@ -24,7 +22,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler.Ast
|
|||
To.PrintLeft(Writer);
|
||||
Writer.Write(">(");
|
||||
From.PrintLeft(Writer);
|
||||
Writer.Write(")");
|
||||
Writer.Write(")");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using LibHac;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Font;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Loaders.Npdm;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
|
@ -51,6 +51,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public string CurrentTitle { get; private set; }
|
||||
|
||||
public bool EnableFsIntegrityChecks { get; set; }
|
||||
|
||||
public Horizon(Switch Device)
|
||||
{
|
||||
this.Device = Device;
|
||||
|
@ -71,6 +73,8 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Withholders = new LinkedList<KThread>();
|
||||
|
||||
Scheduler.StartAutoPreemptionThread();
|
||||
|
||||
if (!Device.Memory.Allocator.TryAllocate(HidSize, out long HidPA) ||
|
||||
!Device.Memory.Allocator.TryAllocate(FontSize, out long FontPA))
|
||||
{
|
||||
|
@ -100,7 +104,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (File.Exists(NpdmFileName))
|
||||
{
|
||||
Device.Log.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
|
||||
|
||||
using (FileStream Input = new FileStream(NpdmFileName, FileMode.Open))
|
||||
{
|
||||
|
@ -109,7 +113,7 @@ namespace Ryujinx.HLE.HOS
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
}
|
||||
|
||||
Process MainProcess = MakeProcess(MetaData);
|
||||
|
@ -123,7 +127,7 @@ namespace Ryujinx.HLE.HOS
|
|||
continue;
|
||||
}
|
||||
|
||||
Device.Log.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(File)}...");
|
||||
|
||||
using (FileStream Input = new FileStream(File, FileMode.Open))
|
||||
{
|
||||
|
@ -164,7 +168,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (MainNca == null)
|
||||
{
|
||||
Device.Log.PrintError(LogClass.Loader, "Unable to load XCI");
|
||||
Logger.PrintError(LogClass.Loader, "Unable to load XCI");
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -208,22 +212,29 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (MainNca == null)
|
||||
{
|
||||
Device.Log.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
|
||||
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
|
||||
}
|
||||
|
||||
MainNca.SetBaseNca(PatchNca);
|
||||
|
||||
|
||||
if (ControlNca != null)
|
||||
{
|
||||
ReadControlData(ControlNca);
|
||||
}
|
||||
|
||||
if (PatchNca != null)
|
||||
{
|
||||
PatchNca.SetBaseNca(MainNca);
|
||||
|
||||
return (PatchNca, ControlNca);
|
||||
}
|
||||
|
||||
return (MainNca, ControlNca);
|
||||
}
|
||||
|
||||
public void ReadControlData(Nca ControlNca)
|
||||
{
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false));
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, EnableFsIntegrityChecks));
|
||||
|
||||
byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
|
||||
|
||||
|
@ -252,8 +263,7 @@ namespace Ryujinx.HLE.HOS
|
|||
// Load title key from the NSP's ticket in case the user doesn't have a title key file
|
||||
if (TicketFile != null)
|
||||
{
|
||||
// todo Change when Ticket(Stream) overload is added
|
||||
Ticket Ticket = new Ticket(new BinaryReader(Nsp.OpenFile(TicketFile)));
|
||||
Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile));
|
||||
|
||||
KeySet.TitleKeys[Ticket.RightsId] = Ticket.GetTitleKey(KeySet);
|
||||
}
|
||||
|
@ -282,33 +292,33 @@ namespace Ryujinx.HLE.HOS
|
|||
return;
|
||||
}
|
||||
|
||||
Device.Log.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
|
||||
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
|
||||
}
|
||||
|
||||
public void LoadNca(Nca MainNca, Nca ControlNca)
|
||||
{
|
||||
NcaSection RomfsSection = MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
NcaSection RomfsSection = MainNca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs || x?.Type == SectionType.Bktr);
|
||||
NcaSection ExefsSection = MainNca.Sections.FirstOrDefault(x => x?.IsExefs == true);
|
||||
|
||||
if (ExefsSection == null)
|
||||
{
|
||||
Device.Log.PrintError(LogClass.Loader, "No ExeFS found in NCA");
|
||||
Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (RomfsSection == null)
|
||||
{
|
||||
Device.Log.PrintError(LogClass.Loader, "No RomFS found in NCA");
|
||||
Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
|
||||
}
|
||||
else
|
||||
{
|
||||
Stream RomfsStream = MainNca.OpenSection(RomfsSection.SectionNum, false, EnableFsIntegrityChecks);
|
||||
|
||||
return;
|
||||
Device.FileSystem.SetRomFs(RomfsStream);
|
||||
}
|
||||
|
||||
Stream RomfsStream = MainNca.OpenSection(RomfsSection.SectionNum, false);
|
||||
|
||||
Device.FileSystem.SetRomFs(RomfsStream);
|
||||
|
||||
Stream ExefsStream = MainNca.OpenSection(ExefsSection.SectionNum, false);
|
||||
Stream ExefsStream = MainNca.OpenSection(ExefsSection.SectionNum, false, EnableFsIntegrityChecks);
|
||||
|
||||
Pfs Exefs = new Pfs(ExefsStream);
|
||||
|
||||
|
@ -316,13 +326,13 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
if (Exefs.FileExists("main.npdm"))
|
||||
{
|
||||
Device.Log.PrintInfo(LogClass.Loader, "Loading main.npdm...");
|
||||
Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
|
||||
|
||||
MetaData = new Npdm(Exefs.OpenFile("main.npdm"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
|
||||
}
|
||||
|
||||
Process MainProcess = MakeProcess(MetaData);
|
||||
|
@ -336,7 +346,7 @@ namespace Ryujinx.HLE.HOS
|
|||
continue;
|
||||
}
|
||||
|
||||
Device.Log.PrintInfo(LogClass.Loader, $"Loading {Filename}...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Loading {Filename}...");
|
||||
|
||||
string Name = Path.GetFileNameWithoutExtension(File.Name);
|
||||
|
||||
|
@ -348,7 +358,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Nacp ReadControlData()
|
||||
{
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false));
|
||||
Romfs ControlRomfs = new Romfs(ControlNca.OpenSection(0, false, EnableFsIntegrityChecks));
|
||||
|
||||
byte[] ControlFile = ControlRomfs.GetFile("/control.nacp");
|
||||
|
||||
|
@ -466,7 +476,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
public void SignalVsync()
|
||||
{
|
||||
VsyncEvent.Signal();
|
||||
VsyncEvent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
private Process MakeProcess(Npdm MetaData = null)
|
||||
|
|
|
@ -73,7 +73,10 @@ namespace Ryujinx.HLE.HOS.Ipc
|
|||
{
|
||||
int Unknown = ReqReader.ReadInt32();
|
||||
|
||||
int Handle = Process.HandleTable.OpenHandle(Session);
|
||||
if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Response.HandleDesc = IpcHandleDesc.MakeMove(Handle);
|
||||
|
||||
|
|
|
@ -15,6 +15,15 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
private bool KeepPreempting;
|
||||
|
||||
public void StartAutoPreemptionThread()
|
||||
{
|
||||
Thread PreemptionThread = new Thread(PreemptCurrentThread);
|
||||
|
||||
KeepPreempting = true;
|
||||
|
||||
PreemptionThread.Start();
|
||||
}
|
||||
|
||||
public void ContextSwitch()
|
||||
{
|
||||
lock (CoreContexts)
|
||||
|
|
|
@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
KThread MutexOwner = Process.HandleTable.GetData<KThread>(OwnerHandle);
|
||||
KThread MutexOwner = Process.HandleTable.GetObject<KThread>(OwnerHandle);
|
||||
|
||||
if (MutexOwner == null)
|
||||
{
|
||||
|
@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
MutexValue &= ~HasListenersMask;
|
||||
|
||||
KThread MutexOwner = Process.HandleTable.GetData<KThread>(MutexValue);
|
||||
KThread MutexOwner = Process.HandleTable.GetObject<KThread>(MutexValue);
|
||||
|
||||
if (MutexOwner != null)
|
||||
{
|
||||
|
|
|
@ -1,38 +1,14 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KEvent : KSynchronizationObject
|
||||
class KEvent
|
||||
{
|
||||
private bool Signaled;
|
||||
public KReadableEvent ReadableEvent { get; private set; }
|
||||
public KWritableEvent WritableEvent { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public KEvent(Horizon System, string Name = "") : base(System)
|
||||
public KEvent(Horizon System)
|
||||
{
|
||||
this.Name = Name;
|
||||
}
|
||||
|
||||
public override void Signal()
|
||||
{
|
||||
System.CriticalSectionLock.Lock();
|
||||
|
||||
if (!Signaled)
|
||||
{
|
||||
Signaled = true;
|
||||
|
||||
base.Signal();
|
||||
}
|
||||
|
||||
System.CriticalSectionLock.Unlock();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Signaled = false;
|
||||
}
|
||||
|
||||
public override bool IsSignaled()
|
||||
{
|
||||
return Signaled;
|
||||
ReadableEvent = new KReadableEvent(System, this);
|
||||
WritableEvent = new KWritableEvent(this);
|
||||
}
|
||||
}
|
||||
}
|
17
Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs
Normal file
17
Ryujinx.HLE/HOS/Kernel/KHandleEntry.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KHandleEntry
|
||||
{
|
||||
public KHandleEntry Next { get; set; }
|
||||
|
||||
public int Index { get; private set; }
|
||||
|
||||
public ushort HandleId { get; set; }
|
||||
public object Obj { get; set; }
|
||||
|
||||
public KHandleEntry(int Index)
|
||||
{
|
||||
this.Index = Index;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -148,6 +148,92 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
public long MapProcessCodeMemory(long Dst, long Src, long Size)
|
||||
{
|
||||
lock (Blocks)
|
||||
{
|
||||
long PagesCount = Size / PageSize;
|
||||
|
||||
bool Success = IsUnmapped(Dst, Size);
|
||||
|
||||
Success &= CheckRange(
|
||||
Src,
|
||||
Size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.ReadAndWrite,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out _,
|
||||
out _,
|
||||
out _);
|
||||
|
||||
if (Success)
|
||||
{
|
||||
long PA = CpuMemory.GetPhysicalAddress(Src);
|
||||
|
||||
InsertBlock(Dst, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute);
|
||||
InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.None);
|
||||
|
||||
CpuMemory.Map(Dst, PA, Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
public long UnmapProcessCodeMemory(long Dst, long Src, long Size)
|
||||
{
|
||||
lock (Blocks)
|
||||
{
|
||||
long PagesCount = Size / PageSize;
|
||||
|
||||
bool Success = CheckRange(
|
||||
Dst,
|
||||
Size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.CodeStatic,
|
||||
MemoryPermission.None,
|
||||
MemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out _,
|
||||
out _,
|
||||
out _);
|
||||
|
||||
Success &= CheckRange(
|
||||
Src,
|
||||
Size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Heap,
|
||||
MemoryPermission.Mask,
|
||||
MemoryPermission.None,
|
||||
MemoryAttribute.Mask,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out _,
|
||||
out _,
|
||||
out _);
|
||||
|
||||
if (Success)
|
||||
{
|
||||
InsertBlock(Dst, PagesCount, MemoryState.Unmapped);
|
||||
InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
|
||||
|
||||
CpuMemory.Unmap(Dst, Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
}
|
||||
|
||||
public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission)
|
||||
{
|
||||
long PagesCount = Size / PageSize;
|
||||
|
@ -755,6 +841,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
public bool HleIsUnmapped(long Position, long Size)
|
||||
{
|
||||
bool Result = false;
|
||||
|
||||
lock (Blocks)
|
||||
{
|
||||
Result = IsUnmapped(Position, Size);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private bool IsUnmapped(long Position, long Size)
|
||||
{
|
||||
return CheckRange(
|
||||
|
|
|
@ -1,34 +1,183 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KProcessHandleTable
|
||||
{
|
||||
private IdDictionary Handles;
|
||||
private const int SelfThreadHandle = (0x1ffff << 15) | 0;
|
||||
private const int SelfProcessHandle = (0x1ffff << 15) | 1;
|
||||
|
||||
public KProcessHandleTable()
|
||||
private Horizon System;
|
||||
|
||||
private KHandleEntry[] Table;
|
||||
|
||||
private KHandleEntry TableHead;
|
||||
private KHandleEntry NextFreeEntry;
|
||||
|
||||
private int ActiveSlotsCount;
|
||||
|
||||
private int Size;
|
||||
|
||||
private ushort IdCounter;
|
||||
|
||||
private object LockObj;
|
||||
|
||||
public KProcessHandleTable(Horizon System, int Size = 1024)
|
||||
{
|
||||
Handles = new IdDictionary();
|
||||
this.System = System;
|
||||
this.Size = Size;
|
||||
|
||||
IdCounter = 1;
|
||||
|
||||
Table = new KHandleEntry[Size];
|
||||
|
||||
TableHead = new KHandleEntry(0);
|
||||
|
||||
KHandleEntry Entry = TableHead;
|
||||
|
||||
for (int Index = 0; Index < Size; Index++)
|
||||
{
|
||||
Table[Index] = Entry;
|
||||
|
||||
Entry.Next = new KHandleEntry(Index + 1);
|
||||
|
||||
Entry = Entry.Next;
|
||||
}
|
||||
|
||||
Table[Size - 1].Next = null;
|
||||
|
||||
NextFreeEntry = TableHead;
|
||||
|
||||
LockObj = new object();
|
||||
}
|
||||
|
||||
public int OpenHandle(object Obj)
|
||||
public KernelResult GenerateHandle(object Obj, out int Handle)
|
||||
{
|
||||
return Handles.Add(Obj);
|
||||
Handle = 0;
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
if (ActiveSlotsCount >= Size)
|
||||
{
|
||||
return KernelResult.HandleTableFull;
|
||||
}
|
||||
|
||||
KHandleEntry Entry = NextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry.Next;
|
||||
|
||||
Entry.Obj = Obj;
|
||||
Entry.HandleId = IdCounter;
|
||||
|
||||
ActiveSlotsCount++;
|
||||
|
||||
Handle = (int)((IdCounter << 15) & (uint)0xffff8000) | Entry.Index;
|
||||
|
||||
if ((short)(IdCounter + 1) >= 0)
|
||||
{
|
||||
IdCounter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
IdCounter = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public T GetData<T>(int Handle)
|
||||
public bool CloseHandle(int Handle)
|
||||
{
|
||||
return Handles.GetData<T>(Handle);
|
||||
if ((Handle >> 30) != 0 ||
|
||||
Handle == SelfThreadHandle ||
|
||||
Handle == SelfProcessHandle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int Index = (Handle >> 0) & 0x7fff;
|
||||
int HandleId = (Handle >> 15);
|
||||
|
||||
bool Result = false;
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
if (HandleId != 0 && Index < Size)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
|
||||
if (Entry.Obj != null && Entry.HandleId == HandleId)
|
||||
{
|
||||
Entry.Obj = null;
|
||||
Entry.Next = NextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry;
|
||||
|
||||
ActiveSlotsCount--;
|
||||
|
||||
Result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public object CloseHandle(int Handle)
|
||||
public T GetObject<T>(int Handle)
|
||||
{
|
||||
return Handles.Delete(Handle);
|
||||
int Index = (Handle >> 0) & 0x7fff;
|
||||
int HandleId = (Handle >> 15);
|
||||
|
||||
lock (LockObj)
|
||||
{
|
||||
if ((Handle >> 30) == 0 && HandleId != 0)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
|
||||
if (Entry.HandleId == HandleId && Entry.Obj is T Obj)
|
||||
{
|
||||
return Obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public ICollection<object> Clear()
|
||||
public KThread GetKThread(int Handle)
|
||||
{
|
||||
return Handles.Clear();
|
||||
if (Handle == SelfThreadHandle)
|
||||
{
|
||||
return System.Scheduler.GetCurrentThread();
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetObject<KThread>(Handle);
|
||||
}
|
||||
}
|
||||
|
||||
public void Destroy()
|
||||
{
|
||||
lock (LockObj)
|
||||
{
|
||||
for (int Index = 0; Index < Size; Index++)
|
||||
{
|
||||
KHandleEntry Entry = Table[Index];
|
||||
|
||||
if (Entry.Obj != null)
|
||||
{
|
||||
if (Entry.Obj is IDisposable DisposableObj)
|
||||
{
|
||||
DisposableObj.Dispose();
|
||||
}
|
||||
|
||||
Entry.Obj = null;
|
||||
Entry.Next = NextFreeEntry;
|
||||
|
||||
NextFreeEntry = Entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs
Normal file
62
Ryujinx.HLE/HOS/Kernel/KReadableEvent.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KReadableEvent : KSynchronizationObject
|
||||
{
|
||||
private KEvent Parent;
|
||||
|
||||
private bool Signaled;
|
||||
|
||||
public KReadableEvent(Horizon System, KEvent Parent) : base(System)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
}
|
||||
|
||||
public override void Signal()
|
||||
{
|
||||
System.CriticalSectionLock.Lock();
|
||||
|
||||
if (!Signaled)
|
||||
{
|
||||
Signaled = true;
|
||||
|
||||
base.Signal();
|
||||
}
|
||||
|
||||
System.CriticalSectionLock.Unlock();
|
||||
}
|
||||
|
||||
public KernelResult Clear()
|
||||
{
|
||||
Signaled = false;
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult ClearIfSignaled()
|
||||
{
|
||||
KernelResult Result;
|
||||
|
||||
System.CriticalSectionLock.Lock();
|
||||
|
||||
if (Signaled)
|
||||
{
|
||||
Signaled = false;
|
||||
|
||||
Result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = KernelResult.InvalidState;
|
||||
}
|
||||
|
||||
System.CriticalSectionLock.Unlock();
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
public override bool IsSignaled()
|
||||
{
|
||||
return Signaled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
|
@ -35,12 +34,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
CoreContexts[Core] = new KCoreContext(this, CoreManager);
|
||||
}
|
||||
|
||||
Thread PreemptionThread = new Thread(PreemptCurrentThread);
|
||||
|
||||
KeepPreempting = true;
|
||||
|
||||
PreemptionThread.Start();
|
||||
}
|
||||
|
||||
private void PreemptThreads()
|
||||
|
|
22
Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs
Normal file
22
Ryujinx.HLE/HOS/Kernel/KWritableEvent.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
class KWritableEvent
|
||||
{
|
||||
private KEvent Parent;
|
||||
|
||||
public KWritableEvent(KEvent Parent)
|
||||
{
|
||||
this.Parent = Parent;
|
||||
}
|
||||
|
||||
public void Signal()
|
||||
{
|
||||
Parent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
public KernelResult Clear()
|
||||
{
|
||||
return Parent.ReadableEvent.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
public const int InvalidSize = 101;
|
||||
public const int InvalidAddress = 102;
|
||||
public const int OutOfMemory = 104;
|
||||
public const int HandleTableFull = 105;
|
||||
public const int NoAccessPerm = 106;
|
||||
public const int InvalidPermission = 108;
|
||||
public const int InvalidMemRange = 110;
|
||||
|
|
10
Ryujinx.HLE/HOS/Kernel/KernelResult.cs
Normal file
10
Ryujinx.HLE/HOS/Kernel/KernelResult.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ryujinx.HLE.HOS.Kernel
|
||||
{
|
||||
enum KernelResult
|
||||
{
|
||||
Success = 0,
|
||||
HandleTableFull = 0xd201,
|
||||
InvalidHandle = 0xe401,
|
||||
InvalidState = 0xfa01
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
using ChocolArm64.Events;
|
||||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -39,9 +39,6 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
private const uint SelfThreadHandle = 0xffff8000;
|
||||
private const uint SelfProcessHandle = 0xffff8001;
|
||||
|
||||
private static Random Rng;
|
||||
|
||||
public SvcHandler(Switch Device, Process Process)
|
||||
|
@ -63,12 +60,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{ 0x0e, SvcGetThreadCoreMask },
|
||||
{ 0x0f, SvcSetThreadCoreMask },
|
||||
{ 0x10, SvcGetCurrentProcessorNumber },
|
||||
{ 0x12, SvcClearEvent },
|
||||
{ 0x11, SignalEvent64 },
|
||||
{ 0x12, ClearEvent64 },
|
||||
{ 0x13, SvcMapSharedMemory },
|
||||
{ 0x14, SvcUnmapSharedMemory },
|
||||
{ 0x15, SvcCreateTransferMemory },
|
||||
{ 0x16, SvcCloseHandle },
|
||||
{ 0x17, SvcResetSignal },
|
||||
{ 0x17, ResetSignal64 },
|
||||
{ 0x18, SvcWaitSynchronization },
|
||||
{ 0x19, SvcCancelSynchronization },
|
||||
{ 0x1a, SvcArbitrateLock },
|
||||
|
@ -88,7 +86,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{ 0x32, SvcSetThreadActivity },
|
||||
{ 0x33, SvcGetThreadContext3 },
|
||||
{ 0x34, SvcWaitForAddress },
|
||||
{ 0x35, SvcSignalToAddress }
|
||||
{ 0x35, SvcSignalToAddress },
|
||||
{ 0x45, CreateEvent64 }
|
||||
};
|
||||
|
||||
this.Device = Device;
|
||||
|
@ -110,11 +109,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (SvcFuncs.TryGetValue(e.Id, out SvcFunc Func))
|
||||
{
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} called.");
|
||||
|
||||
Func(ThreadState);
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended.");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"{Func.Method.Name} ended.");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -123,17 +122,5 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
throw new NotImplementedException($"0x{e.Id:x4}");
|
||||
}
|
||||
}
|
||||
|
||||
private KThread GetThread(long Tpidr, int Handle)
|
||||
{
|
||||
if ((uint)Handle == SelfThreadHandle)
|
||||
{
|
||||
return Process.GetThread(Tpidr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Process.HandleTable.GetData<KThread>(Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
using ChocolArm64.State;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
||||
|
@ -13,7 +13,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((Size & 0xFFFFFFFE001FFFFF) != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Heap size 0x{Size:x16} is not aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -50,7 +50,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -65,7 +65,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
if (Attributes != AttributeMask ||
|
||||
(Attributes | MemoryAttribute.Uncached) != MemoryAttribute.Uncached)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Invalid memory attributes!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Src | Dst))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -116,7 +116,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -125,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Src, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideNewMapRegion(Dst, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -145,7 +145,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -159,7 +159,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Src | Dst))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses are not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -168,7 +168,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -177,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Src + Size) <= (ulong)Src || (ulong)(Dst + Size) <= (ulong)Dst)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Addresses outside of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -186,7 +186,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Src, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Src address 0x{Src:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -195,7 +195,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideNewMapRegion(Dst, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Dst address 0x{Dst:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMemRange);
|
||||
|
||||
|
@ -206,7 +206,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -240,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -249,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -258,7 +258,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -269,18 +269,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((Permission | MemoryPermission.Write) != MemoryPermission.ReadAndWrite)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle);
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -289,7 +289,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -298,7 +298,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (SharedMemory.Size != Size)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} does not match shared memory size 0x{SharedMemory.Size:16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -309,7 +309,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -323,7 +323,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -332,7 +332,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -341,18 +341,18 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetData<KSharedMemory>(Handle);
|
||||
KSharedMemory SharedMemory = Process.HandleTable.GetObject<KSharedMemory>(Handle);
|
||||
|
||||
if (SharedMemory == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid shared memory handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -361,7 +361,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Position, Size) || InsideMapRegion(Position, Size) || InsideHeapRegion(Position, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} out of range!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -372,7 +372,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -385,7 +385,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -394,7 +394,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -403,7 +403,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -414,7 +414,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Permission > MemoryPermission.ReadAndWrite || Permission == MemoryPermission.Write)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid permission {Permission}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPermission);
|
||||
|
||||
|
@ -425,9 +425,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
KTransferMemory TransferMemory = new KTransferMemory(Position, Size);
|
||||
|
||||
int Handle = Process.HandleTable.OpenHandle(TransferMemory);
|
||||
KernelResult Result = Process.HandleTable.GenerateHandle(TransferMemory, out int Handle);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X0 = (uint)Result;
|
||||
ThreadState.X1 = (ulong)Handle;
|
||||
}
|
||||
|
||||
|
@ -438,7 +438,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -447,7 +447,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -456,7 +456,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -465,7 +465,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Position, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -476,7 +476,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -489,7 +489,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Position))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Address 0x{Position:x16} is not page aligned!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -498,7 +498,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!PageAligned(Size) || Size == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Size 0x{Size:x16} is not page aligned or is zero!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidSize);
|
||||
|
||||
|
@ -507,7 +507,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((ulong)(Position + Size) <= (ulong)Position)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid region address 0x{Position:x16} / size 0x{Size:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -516,7 +516,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (!InsideAddrSpace(Position, Size))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address {Position:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -527,7 +527,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Services;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
|
@ -22,24 +22,77 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
Device.System.ExitProcess(Process.ProcessId);
|
||||
}
|
||||
|
||||
private void SvcClearEvent(AThreadState ThreadState)
|
||||
private void SignalEvent64(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
ThreadState.X0 = (ulong)SignalEvent((int)ThreadState.X0);
|
||||
}
|
||||
|
||||
//TODO: Implement events.
|
||||
private KernelResult SignalEvent(int Handle)
|
||||
{
|
||||
KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
KernelResult Result;
|
||||
|
||||
if (WritableEvent != null)
|
||||
{
|
||||
WritableEvent.Signal();
|
||||
|
||||
Result = KernelResult.Success;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void ClearEvent64(AThreadState ThreadState)
|
||||
{
|
||||
ThreadState.X0 = (ulong)ClearEvent((int)ThreadState.X0);
|
||||
}
|
||||
|
||||
private KernelResult ClearEvent(int Handle)
|
||||
{
|
||||
KernelResult Result;
|
||||
|
||||
KWritableEvent WritableEvent = Process.HandleTable.GetObject<KWritableEvent>(Handle);
|
||||
|
||||
if (WritableEvent == null)
|
||||
{
|
||||
KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
|
||||
|
||||
Result = ReadableEvent?.Clear() ?? KernelResult.InvalidHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = WritableEvent.Clear();
|
||||
}
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void SvcCloseHandle(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
|
||||
object Obj = Process.HandleTable.CloseHandle(Handle);
|
||||
object Obj = Process.HandleTable.GetObject<object>(Handle);
|
||||
|
||||
Process.HandleTable.CloseHandle(Handle);
|
||||
|
||||
if (Obj == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -60,24 +113,37 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void SvcResetSignal(AThreadState ThreadState)
|
||||
private void ResetSignal64(AThreadState ThreadState)
|
||||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
ThreadState.X0 = (ulong)ResetSignal((int)ThreadState.X0);
|
||||
}
|
||||
|
||||
KEvent Event = Process.HandleTable.GetData<KEvent>(Handle);
|
||||
private KernelResult ResetSignal(int Handle)
|
||||
{
|
||||
KReadableEvent ReadableEvent = Process.HandleTable.GetObject<KReadableEvent>(Handle);
|
||||
|
||||
if (Event != null)
|
||||
KernelResult Result;
|
||||
|
||||
//TODO: KProcess support.
|
||||
if (ReadableEvent != null)
|
||||
{
|
||||
Event.Reset();
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
Result = ReadableEvent.ClearIfSignaled();
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid event handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
Result = KernelResult.InvalidHandle;
|
||||
}
|
||||
|
||||
if (Result == KernelResult.InvalidState)
|
||||
{
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
|
||||
}
|
||||
else if (Result != KernelResult.Success)
|
||||
{
|
||||
Logger.PrintWarning(LogClass.KernelSvc, "Operation failed with error: " + Result + "!");
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
private void SvcGetSystemTick(AThreadState ThreadState)
|
||||
|
@ -96,10 +162,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
//actually exists, return error codes otherwise.
|
||||
KSession Session = new KSession(ServiceFactory.MakeService(System, Name), Name);
|
||||
|
||||
ulong Handle = (ulong)Process.HandleTable.OpenHandle(Session);
|
||||
if (Process.HandleTable.GenerateHandle(Session, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
ThreadState.X1 = Handle;
|
||||
ThreadState.X1 = (uint)Handle;
|
||||
}
|
||||
|
||||
private void SvcSendSyncRequest(AThreadState ThreadState)
|
||||
|
@ -122,7 +191,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
byte[] MessageData = Memory.ReadBytes(MessagePtr, Size);
|
||||
|
||||
KSession Session = Process.HandleTable.GetData<KSession>(Handle);
|
||||
KSession Session = Process.HandleTable.GetObject<KSession>(Handle);
|
||||
|
||||
if (Session != null)
|
||||
{
|
||||
|
@ -151,7 +220,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid session handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -178,9 +247,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long Unknown = (long)ThreadState.X1;
|
||||
long Info = (long)ThreadState.X2;
|
||||
|
||||
Process.PrintStackTrace(ThreadState);
|
||||
if ((Reason & (1 << 31)) == 0)
|
||||
{
|
||||
Process.PrintStackTrace(ThreadState);
|
||||
|
||||
throw new GuestBrokeExecutionException();
|
||||
throw new GuestBrokeExecutionException();
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.PrintInfo(LogClass.KernelSvc, "Debugger triggered");
|
||||
Process.PrintStackTrace(ThreadState);
|
||||
}
|
||||
}
|
||||
|
||||
private void SvcOutputDebugString(AThreadState ThreadState)
|
||||
|
@ -190,7 +267,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
string Str = AMemoryHelper.ReadAsciiString(Memory, Position, Size);
|
||||
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, Str);
|
||||
Logger.PrintWarning(LogClass.KernelSvc, Str);
|
||||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
@ -206,7 +283,8 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
if (InfoType == 18 ||
|
||||
InfoType == 19 ||
|
||||
InfoType == 20 ||
|
||||
InfoType == 21)
|
||||
InfoType == 21 ||
|
||||
InfoType == 22)
|
||||
{
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidEnumValue);
|
||||
|
||||
|
@ -287,5 +365,37 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
ThreadState.X0 = 0;
|
||||
}
|
||||
|
||||
private void CreateEvent64(AThreadState State)
|
||||
{
|
||||
KernelResult Result = CreateEvent(out int WEventHandle, out int REventHandle);
|
||||
|
||||
State.X0 = (ulong)Result;
|
||||
State.X1 = (ulong)WEventHandle;
|
||||
State.X2 = (ulong)REventHandle;
|
||||
}
|
||||
|
||||
private KernelResult CreateEvent(out int WEventHandle, out int REventHandle)
|
||||
{
|
||||
KEvent Event = new KEvent(System);
|
||||
|
||||
KernelResult Result = Process.HandleTable.GenerateHandle(Event.WritableEvent, out WEventHandle);
|
||||
|
||||
if (Result == KernelResult.Success)
|
||||
{
|
||||
Result = Process.HandleTable.GenerateHandle(Event.ReadableEvent, out REventHandle);
|
||||
|
||||
if (Result != KernelResult.Success)
|
||||
{
|
||||
Process.HandleTable.CloseHandle(WEventHandle);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
REventHandle = 0;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using ChocolArm64.State;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.Common.Logging;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if ((uint)Priority > 0x3f)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid priority 0x{Priority:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidPriority);
|
||||
|
||||
|
@ -31,7 +31,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else if ((uint)ProcessorId > 3)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{ProcessorId:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
|
||||
|
||||
|
@ -53,7 +53,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
int Handle = (int)ThreadState.X0;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
|
@ -61,14 +61,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
long Timeout = (long)ThreadState.X0;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + Timeout.ToString("x16"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Timeout = 0x" + Timeout.ToString("x16"));
|
||||
|
||||
KThread CurrentThread = System.Scheduler.GetCurrentThread();
|
||||
|
||||
|
@ -112,7 +112,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
int Handle = (int)ThreadState.X1;
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, Handle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
|
@ -121,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -132,17 +132,17 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int Handle = (int)ThreadState.X0;
|
||||
int Priority = (int)ThreadState.X1;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Handle = 0x" + Handle .ToString("x8") + ", " +
|
||||
"Priority = 0x" + Priority.ToString("x8"));
|
||||
|
||||
//TODO: NPDM check.
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, Handle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -158,9 +158,9 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
int Handle = (int)ThreadState.X2;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "Handle = 0x" + Handle.ToString("x8"));
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, Handle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
|
@ -170,7 +170,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -178,12 +178,12 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
private void SvcSetThreadCoreMask(AThreadState ThreadState)
|
||||
{
|
||||
int ThreadHandle = (int)ThreadState.X0;
|
||||
int Handle = (int)ThreadState.X0;
|
||||
int PrefferedCore = (int)ThreadState.X1;
|
||||
long AffinityMask = (long)ThreadState.X2;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
"ThreadHandle = 0x" + ThreadHandle .ToString("x8") + ", " +
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Handle = 0x" + Handle .ToString("x8") + ", " +
|
||||
"PrefferedCore = 0x" + PrefferedCore.ToString("x8") + ", " +
|
||||
"AffinityMask = 0x" + AffinityMask .ToString("x16"));
|
||||
|
||||
|
@ -202,7 +202,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
if ((PrefferedCore | 2) != -1)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{PrefferedCore:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core id 0x{PrefferedCore:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidCoreId);
|
||||
|
||||
|
@ -211,7 +211,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else if ((AffinityMask & (1 << PrefferedCore)) == 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{AffinityMask:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid core mask 0x{AffinityMask:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidMaskValue);
|
||||
|
||||
|
@ -219,11 +219,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
}
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, ThreadHandle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -234,7 +234,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -249,7 +249,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
int Handle = (int)ThreadState.X1;
|
||||
|
||||
KThread Thread = GetThread(ThreadState.Tpidr, Handle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(Handle);
|
||||
|
||||
if (Thread != null)
|
||||
{
|
||||
|
@ -258,7 +258,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
}
|
||||
|
@ -269,11 +269,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int Handle = (int)ThreadState.X0;
|
||||
bool Pause = (int)ThreadState.X1 == 1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -282,7 +282,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Thread.Owner != Process)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread owner process!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread owner process!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -293,7 +293,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -304,11 +304,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long Position = (long)ThreadState.X0;
|
||||
int Handle = (int)ThreadState.X1;
|
||||
|
||||
KThread Thread = Process.HandleTable.GetData<KThread>(Handle);
|
||||
KThread Thread = Process.HandleTable.GetObject<KThread>(Handle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{Handle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -317,7 +317,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Process.GetThread(ThreadState.Tpidr) == Thread)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Thread handle 0x{Handle:x8} is current thread!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Thread handle 0x{Handle:x8} is current thread!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidThread);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ChocolArm64.State;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
||||
|
@ -13,7 +14,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int HandlesCount = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"HandlesPtr = 0x" + HandlesPtr .ToString("x16") + ", " +
|
||||
"HandlesCount = 0x" + HandlesCount.ToString("x8") + ", " +
|
||||
"Timeout = 0x" + Timeout .ToString("x16"));
|
||||
|
@ -25,33 +26,38 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
return;
|
||||
}
|
||||
|
||||
KSynchronizationObject[] SyncObjs = new KSynchronizationObject[HandlesCount];
|
||||
List<KSynchronizationObject> SyncObjs = new List<KSynchronizationObject>();
|
||||
|
||||
for (int Index = 0; Index < HandlesCount; Index++)
|
||||
{
|
||||
int Handle = Memory.ReadInt32(HandlesPtr + Index * 4);
|
||||
|
||||
KSynchronizationObject SyncObj = Process.HandleTable.GetData<KSynchronizationObject>(Handle);
|
||||
KSynchronizationObject SyncObj = Process.HandleTable.GetObject<KSynchronizationObject>(Handle);
|
||||
|
||||
SyncObjs[Index] = SyncObj;
|
||||
if (SyncObj == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
SyncObjs.Add(SyncObj);
|
||||
}
|
||||
|
||||
int HndIndex = (int)ThreadState.X1;
|
||||
|
||||
ulong High = ThreadState.X1 & (0xffffffffUL << 32);
|
||||
|
||||
long Result = System.Synchronization.WaitFor(SyncObjs, Timeout, ref HndIndex);
|
||||
long Result = System.Synchronization.WaitFor(SyncObjs.ToArray(), Timeout, ref HndIndex);
|
||||
|
||||
if (Result != 0)
|
||||
{
|
||||
if (Result == MakeError(ErrorModule.Kernel, KernelErr.Timeout) ||
|
||||
Result == MakeError(ErrorModule.Kernel, KernelErr.Cancelled))
|
||||
{
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,13 +69,13 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
int ThreadHandle = (int)ThreadState.X0;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + ThreadHandle.ToString("x8"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "ThreadHandle = 0x" + ThreadHandle.ToString("x8"));
|
||||
|
||||
KThread Thread = Process.HandleTable.GetData<KThread>(ThreadHandle);
|
||||
KThread Thread = Process.HandleTable.GetKThread(ThreadHandle);
|
||||
|
||||
if (Thread == null)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid thread handle 0x{ThreadHandle:x8}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidHandle);
|
||||
|
||||
|
@ -87,14 +93,14 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long MutexAddress = (long)ThreadState.X1;
|
||||
int RequesterHandle = (int)ThreadState.X2;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"OwnerHandle = 0x" + OwnerHandle .ToString("x8") + ", " +
|
||||
"MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " +
|
||||
"RequesterHandle = 0x" + RequesterHandle.ToString("x8"));
|
||||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -103,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -119,7 +125,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -129,11 +135,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
long MutexAddress = (long)ThreadState.X0;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + MutexAddress.ToString("x16"));
|
||||
Logger.PrintDebug(LogClass.KernelSvc, "MutexAddress = 0x" + MutexAddress.ToString("x16"));
|
||||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -142,7 +148,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -153,7 +159,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -166,7 +172,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int ThreadHandle = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"MutexAddress = 0x" + MutexAddress .ToString("x16") + ", " +
|
||||
"CondVarAddress = 0x" + CondVarAddress.ToString("x16") + ", " +
|
||||
"ThreadHandle = 0x" + ThreadHandle .ToString("x8") + ", " +
|
||||
|
@ -174,7 +180,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsPointingInsideKernel(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -183,7 +189,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsAddressNotWordAligned(MutexAddress))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned mutex address 0x{MutexAddress:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -201,11 +207,11 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
{
|
||||
if (Result == MakeError(ErrorModule.Kernel, KernelErr.Timeout))
|
||||
{
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintDebug(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -217,7 +223,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
long Address = (long)ThreadState.X0;
|
||||
int Count = (int)ThreadState.X1;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Count = 0x" + Count .ToString("x8"));
|
||||
|
||||
|
@ -233,7 +239,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int Value = (int)ThreadState.X2;
|
||||
long Timeout = (long)ThreadState.X3;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Type = " + Type .ToString() + ", " +
|
||||
"Value = 0x" + Value .ToString("x8") + ", " +
|
||||
|
@ -241,7 +247,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsPointingInsideKernel(Address))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -250,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsAddressNotWordAligned(Address))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -280,7 +286,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
@ -293,7 +299,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
int Value = (int)ThreadState.X2;
|
||||
int Count = (int)ThreadState.X3;
|
||||
|
||||
Device.Log.PrintDebug(LogClass.KernelSvc,
|
||||
Logger.PrintDebug(LogClass.KernelSvc,
|
||||
"Address = 0x" + Address.ToString("x16") + ", " +
|
||||
"Type = " + Type .ToString() + ", " +
|
||||
"Value = 0x" + Value .ToString("x8") + ", " +
|
||||
|
@ -301,7 +307,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsPointingInsideKernel(Address))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Invalid address 0x{Address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
|
||||
|
||||
|
@ -310,7 +316,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (IsAddressNotWordAligned(Address))
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Unaligned address 0x{Address:x16}!");
|
||||
|
||||
ThreadState.X0 = MakeError(ErrorModule.Kernel, KernelErr.InvalidAddress);
|
||||
|
||||
|
@ -340,7 +346,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
|||
|
||||
if (Result != 0)
|
||||
{
|
||||
Device.Log.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
Logger.PrintWarning(LogClass.KernelSvc, $"Operation failed with error 0x{Result:x}!");
|
||||
}
|
||||
|
||||
ThreadState.X0 = (ulong)Result;
|
||||
|
|
|
@ -3,6 +3,7 @@ using ChocolArm64.Events;
|
|||
using ChocolArm64.Memory;
|
||||
using ChocolArm64.State;
|
||||
using LibHac;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Diagnostics.Demangler;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
|
@ -11,7 +12,6 @@ using Ryujinx.HLE.HOS.SystemState;
|
|||
using Ryujinx.HLE.Loaders;
|
||||
using Ryujinx.HLE.Loaders.Executables;
|
||||
using Ryujinx.HLE.Loaders.Npdm;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
|
@ -71,7 +71,22 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
TlsPages = new List<KTlsPageManager>();
|
||||
|
||||
HandleTable = new KProcessHandleTable();
|
||||
int HandleTableSize = 1024;
|
||||
|
||||
if (MetaData != null)
|
||||
{
|
||||
foreach (KernelAccessControlItem Item in MetaData.ACI0.KernelAccessControl.Items)
|
||||
{
|
||||
if (Item.HasHandleTableSize)
|
||||
{
|
||||
HandleTableSize = Item.HandleTableSize;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HandleTable = new KProcessHandleTable(Device.System, HandleTableSize);
|
||||
|
||||
AppletState = new AppletStateMgr(Device.System);
|
||||
|
||||
|
@ -91,13 +106,37 @@ namespace Ryujinx.HLE.HOS
|
|||
throw new ObjectDisposedException(nameof(Process));
|
||||
}
|
||||
|
||||
Device.Log.PrintInfo(LogClass.Loader, $"Image base at 0x{ImageBase:x16}.");
|
||||
long ImageEnd = LoadProgram(Program, ImageBase);
|
||||
|
||||
Executable Executable = new Executable(Program, MemoryManager, Memory, ImageBase);
|
||||
ImageBase = IntUtils.AlignUp(ImageEnd, KMemoryManager.PageSize);
|
||||
}
|
||||
|
||||
public long LoadProgram(IExecutable Program, long ExecutableBase)
|
||||
{
|
||||
if (Disposed)
|
||||
{
|
||||
throw new ObjectDisposedException(nameof(Process));
|
||||
}
|
||||
|
||||
Logger.PrintInfo(LogClass.Loader, $"Image base at 0x{ExecutableBase:x16}.");
|
||||
|
||||
Executable Executable = new Executable(Program, MemoryManager, Memory, ExecutableBase);
|
||||
|
||||
Executables.Add(Executable);
|
||||
|
||||
ImageBase = IntUtils.AlignUp(Executable.ImageEnd, KMemoryManager.PageSize);
|
||||
return Executable.ImageEnd;
|
||||
}
|
||||
|
||||
public void RemoveProgram(long ExecutableBase)
|
||||
{
|
||||
foreach (Executable Executable in Executables)
|
||||
{
|
||||
if (Executable.ImageBase == ExecutableBase)
|
||||
{
|
||||
Executables.Remove(Executable);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetEmptyArgs()
|
||||
|
@ -139,7 +178,7 @@ namespace Ryujinx.HLE.HOS
|
|||
return false;
|
||||
}
|
||||
|
||||
KThread MainThread = HandleTable.GetData<KThread>(Handle);
|
||||
KThread MainThread = HandleTable.GetKThread(Handle);
|
||||
|
||||
if (NeedsHbAbi)
|
||||
{
|
||||
|
@ -190,7 +229,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Thread.LastPc = EntryPoint;
|
||||
|
||||
int Handle = HandleTable.OpenHandle(Thread);
|
||||
HandleTable.GenerateHandle(Thread, out int Handle);
|
||||
|
||||
CpuThread.ThreadState.CntfrqEl0 = TickFreq;
|
||||
CpuThread.ThreadState.Tpidr = Tpidr;
|
||||
|
@ -280,7 +319,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
string ExeNameWithAddr = $"{Exe.Name}:0x{Offset:x8}";
|
||||
|
||||
Device.Log.PrintDebug(LogClass.Cpu, ExeNameWithAddr + " " + SubName);
|
||||
Logger.PrintDebug(LogClass.Cpu, ExeNameWithAddr + " " + SubName);
|
||||
}
|
||||
|
||||
private ATranslator GetTranslator()
|
||||
|
@ -335,7 +374,7 @@ namespace Ryujinx.HLE.HOS
|
|||
FramePointer = Memory.ReadInt64(FramePointer);
|
||||
}
|
||||
|
||||
Device.Log.PrintInfo(LogClass.Cpu, Trace.ToString());
|
||||
Logger.PrintInfo(LogClass.Cpu, Trace.ToString());
|
||||
}
|
||||
|
||||
private bool TryGetSubName(Executable Exe, long Position, out string Name)
|
||||
|
@ -427,13 +466,7 @@ namespace Ryujinx.HLE.HOS
|
|||
|
||||
Disposed = true;
|
||||
|
||||
foreach (object Obj in HandleTable.Clear())
|
||||
{
|
||||
if (Obj is KSession Session)
|
||||
{
|
||||
Session.Dispose();
|
||||
}
|
||||
}
|
||||
HandleTable.Destroy();
|
||||
|
||||
INvDrvServices.UnloadProcess(this);
|
||||
|
||||
|
@ -442,7 +475,7 @@ namespace Ryujinx.HLE.HOS
|
|||
File.Delete(Executables[0].FilePath);
|
||||
}
|
||||
|
||||
Device.Log.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
|
||||
Logger.PrintInfo(LogClass.Loader, $"Process {ProcessId} exiting...");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
@ -23,11 +24,14 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
{ 3, ListOpenUsers },
|
||||
{ 4, GetLastOpenedUser },
|
||||
{ 5, GetProfile },
|
||||
{ 50, IsUserRegistrationRequestPermitted },
|
||||
{ 51, TrySelectUserWithoutInteraction },
|
||||
{ 100, InitializeApplicationInfo },
|
||||
{ 101, GetBaasAccountManagerForApplication }
|
||||
};
|
||||
}
|
||||
|
||||
// GetUserCount() -> i32
|
||||
public long GetUserCount(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(Context.Device.System.State.GetUserCount());
|
||||
|
@ -35,22 +39,25 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
return 0;
|
||||
}
|
||||
|
||||
// GetUserExistence(nn::account::Uid) -> bool
|
||||
public long GetUserExistence(ServiceCtx Context)
|
||||
{
|
||||
UserId Uuid = new UserId(
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
Context.ResponseData.Write(Context.Device.System.State.TryGetUser(Uuid, out _) ? 1 : 0);
|
||||
Context.ResponseData.Write(Context.Device.System.State.TryGetUser(Uuid, out _));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ListAllUsers() -> array<nn::account::Uid, 0xa>
|
||||
public long ListAllUsers(ServiceCtx Context)
|
||||
{
|
||||
return WriteUserList(Context, Context.Device.System.State.GetAllUsers());
|
||||
}
|
||||
|
||||
// ListOpenUsers() -> array<nn::account::Uid, 0xa>
|
||||
public long ListOpenUsers(ServiceCtx Context)
|
||||
{
|
||||
return WriteUserList(Context, Context.Device.System.State.GetOpenUsers());
|
||||
|
@ -70,17 +77,14 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
break;
|
||||
}
|
||||
|
||||
byte[] Uuid = Profile.Uuid.Bytes;
|
||||
|
||||
for (int Index = Uuid.Length - 1; Index >= 0; Index--)
|
||||
{
|
||||
Context.Memory.WriteByte(OutputPosition + Offset++, Uuid[Index]);
|
||||
}
|
||||
Context.Memory.WriteInt64(OutputPosition, Profile.Uuid.Low);
|
||||
Context.Memory.WriteInt64(OutputPosition + 8, Profile.Uuid.High);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetLastOpenedUser() -> nn::account::Uid
|
||||
public long GetLastOpenedUser(ServiceCtx Context)
|
||||
{
|
||||
UserProfile LastOpened = Context.Device.System.State.LastOpenUser;
|
||||
|
@ -90,15 +94,16 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
return 0;
|
||||
}
|
||||
|
||||
// GetProfile(nn::account::Uid) -> object<nn::account::profile::IProfile>
|
||||
public long GetProfile(ServiceCtx Context)
|
||||
{
|
||||
UserId Uuid = new UserId(
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
if (!Context.Device.System.State.TryGetUser(Uuid, out UserProfile Profile))
|
||||
{
|
||||
Context.Device.Log.PrintWarning(LogClass.ServiceAcc, $"User 0x{Uuid} not found!");
|
||||
Logger.PrintWarning(LogClass.ServiceAcc, $"User 0x{Uuid} not found!");
|
||||
|
||||
return MakeError(ErrorModule.Account, AccErr.UserNotFound);
|
||||
}
|
||||
|
@ -108,16 +113,50 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
return 0;
|
||||
}
|
||||
|
||||
public long InitializeApplicationInfo(ServiceCtx Context)
|
||||
// IsUserRegistrationRequestPermitted(u64, pid) -> bool
|
||||
public long IsUserRegistrationRequestPermitted(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
Context.ResponseData.Write(false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// TrySelectUserWithoutInteraction(bool) -> nn::account::Uid
|
||||
public long TrySelectUserWithoutInteraction(ServiceCtx Context)
|
||||
{
|
||||
bool Unknown = Context.RequestData.ReadBoolean();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
UserProfile Profile = Context.Device.System.State.LastOpenUser;
|
||||
|
||||
Profile.Uuid.Write(Context.ResponseData);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// InitializeApplicationInfo(u64, pid)
|
||||
public long InitializeApplicationInfo(ServiceCtx Context)
|
||||
{
|
||||
long Unknown = Context.RequestData.ReadInt64();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. Unknown: {Unknown}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetBaasAccountManagerForApplication(nn::account::Uid) -> object<nn::account::baas::IManagerForApplication>
|
||||
public long GetBaasAccountManagerForApplication(ServiceCtx Context)
|
||||
{
|
||||
MakeObject(Context, new IManagerForApplication());
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
MakeObject(Context, new IManagerForApplication(Uuid));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,36 +1,45 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Acc
|
||||
{
|
||||
class IManagerForApplication : IpcService
|
||||
{
|
||||
private UInt128 Uuid;
|
||||
|
||||
private Dictionary<int, ServiceProcessRequest> m_Commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
public IManagerForApplication()
|
||||
public IManagerForApplication(UInt128 Uuid)
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, CheckAvailability },
|
||||
{ 1, GetAccountId }
|
||||
};
|
||||
|
||||
this.Uuid = Uuid;
|
||||
}
|
||||
|
||||
// CheckAvailability()
|
||||
public long CheckAvailability(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetAccountId() -> nn::account::NetworkServiceAccountId
|
||||
public long GetAccountId(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
long NetworkServiceAccountId = 0xcafe;
|
||||
|
||||
Context.ResponseData.Write(0xcafeL);
|
||||
Logger.PrintStub(LogClass.ServiceAcc, $"Stubbed. NetworkServiceAccountId: {NetworkServiceAccountId}");
|
||||
|
||||
Context.ResponseData.Write(NetworkServiceAccountId);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Services.Acc
|
|||
|
||||
public long Get(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAcc, "Stubbed.");
|
||||
|
||||
long Position = Context.Request.ReceiveBuff[0].Position;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -39,7 +39,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
long UIdLow = Context.RequestData.ReadInt64();
|
||||
long UIdHigh = Context.RequestData.ReadInt64();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
|
@ -59,7 +59,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
string Result = GetFormattedErrorCode(ErrorCode);
|
||||
|
||||
Context.Device.Log.PrintInfo(LogClass.ServiceAm, $"Result = 0x{ErrorCode:x8} ({Result}).");
|
||||
Logger.PrintInfo(LogClass.ServiceAm, $"Result = 0x{ErrorCode:x8} ({Result}).");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long GetPseudoDeviceId(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
Context.ResponseData.Write(0L);
|
||||
|
@ -100,7 +100,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long InitializeGamePlayRecording(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -109,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
int State = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -27,7 +27,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
float AppletVolume = Context.RequestData.ReadSingle();
|
||||
float LibraryAppletVolume = Context.RequestData.ReadSingle();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
float Unknown0 = Context.RequestData.ReadSingle();
|
||||
long Unknown1 = Context.RequestData.ReadInt64();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
float Unknown0 = Context.RequestData.ReadSingle();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
@ -36,7 +37,10 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
KEvent Event = Context.Process.AppletState.MessageEvent;
|
||||
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(Event);
|
||||
if (Context.Process.HandleTable.GenerateHandle(Event.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
|
@ -81,7 +85,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
Context.ResponseData.Write((byte)0); //Unknown value.
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -103,11 +107,14 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long GetDefaultDisplayResolutionChangeEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(DisplayResolutionChangeEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(DisplayResolutionChangeEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -27,18 +28,21 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long RequestToGetForeground(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetPopFromGeneralChannelEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(ChannelEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(ChannelEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -29,34 +30,37 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long GetAppletStateChangedEvent(ServiceCtx Context)
|
||||
{
|
||||
StateChangedEvent.Signal();
|
||||
StateChangedEvent.ReadableEvent.Signal();
|
||||
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(StateChangedEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(StateChangedEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long Start(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetResult(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long PushInData(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -13,6 +14,8 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
private KEvent LaunchableEvent;
|
||||
|
||||
private int IdleTimeDetectionExtension;
|
||||
|
||||
public ISelfController(Horizon System)
|
||||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
|
@ -28,7 +31,9 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{ 14, SetRestartMessageEnabled },
|
||||
{ 16, SetOutOfFocusSuspendingEnabled },
|
||||
{ 19, SetScreenShotImageOrientation },
|
||||
{ 50, SetHandlesRequestToDisplay }
|
||||
{ 50, SetHandlesRequestToDisplay },
|
||||
{ 62, SetIdleTimeDetectionExtension },
|
||||
{ 63, GetIdleTimeDetectionExtension }
|
||||
};
|
||||
|
||||
LaunchableEvent = new KEvent(System);
|
||||
|
@ -36,34 +41,37 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long Exit(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long LockExit(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long UnlockExit(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long GetLibraryAppletLaunchableEvent(ServiceCtx Context)
|
||||
{
|
||||
LaunchableEvent.Signal();
|
||||
LaunchableEvent.ReadableEvent.Signal();
|
||||
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(LaunchableEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(LaunchableEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -72,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -81,7 +89,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -90,7 +98,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -101,7 +109,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
bool Flag2 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
bool Flag3 = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,7 +118,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -119,7 +127,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -128,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
int Orientation = Context.RequestData.ReadInt32();
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -137,7 +145,27 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
{
|
||||
bool Enable = Context.RequestData.ReadByte() != 0 ? true : false;
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// SetIdleTimeDetectionExtension(u32)
|
||||
public long SetIdleTimeDetectionExtension(ServiceCtx Context)
|
||||
{
|
||||
IdleTimeDetectionExtension = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {IdleTimeDetectionExtension}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetIdleTimeDetectionExtension() -> u32
|
||||
public long GetIdleTimeDetectionExtension(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(IdleTimeDetectionExtension);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAm, $"Stubbed. IdleTimeDetectionExtension: {IdleTimeDetectionExtension}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Am
|
||||
|
@ -21,7 +21,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long GetAppletResourceUserId(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
|
@ -30,7 +30,7 @@ namespace Ryujinx.HLE.HOS.Services.Am
|
|||
|
||||
public long AcquireForegroundRights(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Apm
|
||||
|
@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Apm
|
|||
|
||||
Context.ResponseData.Write((uint)PerformanceConfiguration.PerformanceConfiguration1);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceApm, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceApm, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -67,7 +67,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioOut
|
|||
|
||||
public long RegisterBufferEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(ReleaseEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(ReleaseEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Audio.Adpcm;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
@ -38,6 +38,8 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
|
||||
private int Track;
|
||||
|
||||
private PlayState PlayState;
|
||||
|
||||
public IAudioRenderer(
|
||||
Horizon System,
|
||||
AMemory Memory,
|
||||
|
@ -46,6 +48,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, GetSampleRate },
|
||||
{ 1, GetSampleCount },
|
||||
{ 2, GetMixBufferCount },
|
||||
{ 3, GetState },
|
||||
{ 4, RequestUpdateAudioRenderer },
|
||||
{ 5, StartAudioRenderer },
|
||||
{ 6, StopAudioRenderer },
|
||||
|
@ -68,11 +74,47 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
Voices = CreateArray<VoiceContext>(Params.VoiceCount);
|
||||
|
||||
InitializeAudioOut();
|
||||
|
||||
PlayState = PlayState.Stopped;
|
||||
}
|
||||
|
||||
// GetSampleRate() -> u32
|
||||
public long GetSampleRate(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(Params.SampleRate);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetSampleCount() -> u32
|
||||
public long GetSampleCount(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(Params.SampleCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetMixBufferCount() -> u32
|
||||
public long GetMixBufferCount(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write(Params.MixCount);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetState() -> u32
|
||||
private long GetState(ServiceCtx Context)
|
||||
{
|
||||
Context.ResponseData.Write((int)PlayState);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. Renderer State: {Enum.GetName(typeof(PlayState), PlayState)}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private void AudioCallback()
|
||||
{
|
||||
UpdateEvent.Signal();
|
||||
UpdateEvent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
private static T[] CreateArray<T>(int Size) where T : new()
|
||||
|
@ -204,21 +246,28 @@ namespace Ryujinx.HLE.HOS.Services.Aud.AudioRenderer
|
|||
|
||||
public long StartAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
PlayState = PlayState.Playing;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long StopAudioRenderer(ServiceCtx Context)
|
||||
{
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
PlayState = PlayState.Stopped;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QuerySystemEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(UpdateEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(UpdateEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
@ -35,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
SystemEvent = new KEvent(System);
|
||||
|
||||
//TODO: We shouldn't be signaling this here.
|
||||
SystemEvent.Signal();
|
||||
SystemEvent.ReadableEvent.Signal();
|
||||
}
|
||||
|
||||
public long ListAudioDeviceName(ServiceCtx Context)
|
||||
|
@ -55,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
if ((Position - BasePosition) + Buffer.Length > Size)
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -79,7 +80,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
string DeviceName = Encoding.ASCII.GetString(DeviceNameBuffer);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -99,7 +100,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
}
|
||||
else
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -107,11 +108,14 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
public long QueryAudioDeviceSystemEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -120,7 +124,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
Context.ResponseData.Write(2);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -141,7 +145,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
if ((Position - BasePosition) + Buffer.Length > Size)
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -164,7 +168,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
string DeviceName = Encoding.UTF8.GetString(DeviceNameBuffer);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -173,7 +177,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
Context.ResponseData.Write(1f);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -192,7 +196,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
}
|
||||
else
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -200,22 +204,28 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
public long QueryAudioDeviceInputEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long QueryAudioDeviceOutputEvent(ServiceCtx Context)
|
||||
{
|
||||
int Handle = Context.Process.HandleTable.OpenHandle(SystemEvent);
|
||||
if (Context.Process.HandleTable.GenerateHandle(SystemEvent.ReadableEvent, out int Handle) != KernelResult.Success)
|
||||
{
|
||||
throw new InvalidOperationException("Out of handles!");
|
||||
}
|
||||
|
||||
Context.Response.HandleDesc = IpcHandleDesc.MakeCopy(Handle);
|
||||
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
Logger.PrintStub(LogClass.ServiceAudio, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
using ChocolArm64.Memory;
|
||||
using Ryujinx.Audio;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel;
|
||||
using Ryujinx.HLE.HOS.Services.Aud.AudioOut;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
|
@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
}
|
||||
else
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {Size} too small!");
|
||||
}
|
||||
|
||||
Context.ResponseData.Write(NameCount);
|
||||
|
@ -108,7 +108,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
if (DeviceName != DefaultAudioOutput)
|
||||
{
|
||||
Context.Device.Log.PrintWarning(LogClass.Audio, "Invalid device name!");
|
||||
Logger.PrintWarning(LogClass.Audio, "Invalid device name!");
|
||||
|
||||
return MakeError(ErrorModule.Audio, AudErr.DeviceNotFound);
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
}
|
||||
else
|
||||
{
|
||||
Context.Device.Log.PrintError(LogClass.ServiceAudio, $"Output buffer size {ReceiveSize} too small!");
|
||||
Logger.PrintError(LogClass.ServiceAudio, $"Output buffer size {ReceiveSize} too small!");
|
||||
}
|
||||
|
||||
int SampleRate = Context.RequestData.ReadInt32();
|
||||
|
@ -134,7 +134,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
if (SampleRate != DefaultSampleRate)
|
||||
{
|
||||
Context.Device.Log.PrintWarning(LogClass.Audio, "Invalid sample rate!");
|
||||
Logger.PrintWarning(LogClass.Audio, "Invalid sample rate!");
|
||||
|
||||
return MakeError(ErrorModule.Audio, AudErr.UnsupportedSampleRate);
|
||||
}
|
||||
|
@ -150,7 +150,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
ReleaseCallback Callback = () =>
|
||||
{
|
||||
ReleaseEvent.Signal();
|
||||
ReleaseEvent.ReadableEvent.Signal();
|
||||
};
|
||||
|
||||
IAalOutput AudioOut = Context.Device.AudioOut;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using Ryujinx.Audio;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.Services.Aud.AudioRenderer;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
@ -28,9 +28,10 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 0, OpenAudioRenderer },
|
||||
{ 1, GetAudioRendererWorkBufferSize },
|
||||
{ 2, GetAudioDevice }
|
||||
{ 0, OpenAudioRenderer },
|
||||
{ 1, GetAudioRendererWorkBufferSize },
|
||||
{ 2, GetAudioDeviceService },
|
||||
{ 4, GetAudioDeviceServiceWithRevisionInfo }
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -102,7 +103,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
|
||||
Context.ResponseData.Write(Size);
|
||||
|
||||
Context.Device.Log.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{Size:x16}.");
|
||||
Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{Size:x16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -110,7 +111,7 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
{
|
||||
Context.ResponseData.Write(0L);
|
||||
|
||||
Context.Device.Log.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!");
|
||||
Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision 0x{Params.Revision:x8} is not supported!");
|
||||
|
||||
return MakeError(ErrorModule.Audio, AudErr.UnsupportedRevision);
|
||||
}
|
||||
|
@ -161,13 +162,26 @@ namespace Ryujinx.HLE.HOS.Services.Aud
|
|||
return Result / 8;
|
||||
}
|
||||
|
||||
public long GetAudioDevice(ServiceCtx Context)
|
||||
// GetAudioDeviceService(nn::applet::AppletResourceUserId) -> object<nn::audio::detail::IAudioDevice>
|
||||
public long GetAudioDeviceService(ServiceCtx Context)
|
||||
{
|
||||
long UserId = Context.RequestData.ReadInt64();
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
|
||||
MakeObject(Context, new IAudioDevice(Context.Device.System));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// GetAudioDeviceServiceWithRevisionInfo(nn::applet::AppletResourceUserId, u32) -> object<nn::audio::detail::IAudioDevice>
|
||||
private long GetAudioDeviceServiceWithRevisionInfo(ServiceCtx Context)
|
||||
{
|
||||
long AppletResourceUserId = Context.RequestData.ReadInt64();
|
||||
int RevisionInfo = Context.RequestData.ReadInt32();
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceAudio, $"Stubbed. AppletResourceUserId: {AppletResourceUserId} - " +
|
||||
$"RevisionInfo: {RevisionInfo}");
|
||||
|
||||
return GetAudioDeviceService(Context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Logging;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend
|
||||
|
@ -15,14 +16,53 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
|||
{
|
||||
m_Commands = new Dictionary<int, ServiceProcessRequest>()
|
||||
{
|
||||
{ 10101, GetFriendList },
|
||||
{ 10601, DeclareCloseOnlinePlaySession },
|
||||
{ 10610, UpdateUserPresence }
|
||||
};
|
||||
}
|
||||
|
||||
// nn::friends::GetFriendListGetFriendListIds(nn::account::Uid, int Unknown0, nn::friends::detail::ipc::SizedFriendFilter, ulong Unknown1) -> int CounterIds, array<nn::account::NetworkServiceAccountId>
|
||||
public long GetFriendList(ServiceCtx Context)
|
||||
{
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
int Unknown0 = Context.RequestData.ReadInt32();
|
||||
|
||||
FriendFilter Filter = new FriendFilter()
|
||||
{
|
||||
PresenceStatus = (PresenceStatusFilter)Context.RequestData.ReadInt32(),
|
||||
IsFavoriteOnly = Context.RequestData.ReadBoolean(),
|
||||
IsSameAppPresenceOnly = Context.RequestData.ReadBoolean(),
|
||||
IsSameAppPlayedOnly = Context.RequestData.ReadBoolean(),
|
||||
IsArbitraryAppPlayedOnly = Context.RequestData.ReadBoolean(),
|
||||
PresenceGroupId = Context.RequestData.ReadInt64()
|
||||
};
|
||||
|
||||
long Unknown1 = Context.RequestData.ReadInt64();
|
||||
|
||||
// There are no friends online, so we return 0 because the nn::account::NetworkServiceAccountId array is empty.
|
||||
Context.ResponseData.Write(0);
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. UserId: {Uuid.ToString()} - " +
|
||||
$"Unknown0: {Unknown0} - " +
|
||||
$"PresenceStatus: {Filter.PresenceStatus} - " +
|
||||
$"IsFavoriteOnly: {Filter.IsFavoriteOnly} - " +
|
||||
$"IsSameAppPresenceOnly: {Filter.IsSameAppPresenceOnly} - " +
|
||||
$"IsSameAppPlayedOnly: {Filter.IsSameAppPlayedOnly} - " +
|
||||
$"IsArbitraryAppPlayedOnly: {Filter.IsArbitraryAppPlayedOnly} - " +
|
||||
$"PresenceGroupId: {Filter.PresenceGroupId} - " +
|
||||
$"Unknown1: {Unknown1}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// DeclareCloseOnlinePlaySession(nn::account::Uid)
|
||||
public long DeclareCloseOnlinePlaySession(ServiceCtx Context)
|
||||
{
|
||||
UserId Uuid = new UserId(
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
|
@ -31,19 +71,30 @@ namespace Ryujinx.HLE.HOS.Services.Friend
|
|||
Profile.OnlinePlayState = OpenCloseState.Closed;
|
||||
}
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " +
|
||||
$"OnlinePlayState: {Profile.OnlinePlayState}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// UpdateUserPresence(nn::account::Uid, ulong Unknown0) -> buffer<Unknown1, type: 0x19, size: 0xe0>
|
||||
public long UpdateUserPresence(ServiceCtx Context)
|
||||
{
|
||||
UserId Uuid = new UserId(
|
||||
UInt128 Uuid = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
//TODO.
|
||||
Context.Device.Log.PrintStub(LogClass.ServiceFriend, "Stubbed.");
|
||||
long Unknown0 = Context.RequestData.ReadInt64();
|
||||
|
||||
long Position = Context.Request.PtrBuff[0].Position;
|
||||
long Size = Context.Request.PtrBuff[0].Size;
|
||||
|
||||
//Todo: Write the buffer content.
|
||||
|
||||
Logger.PrintStub(LogClass.ServiceFriend, $"Stubbed. Uuid: {Uuid.ToString()} - " +
|
||||
$"Unknown0: {Unknown0}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
20
Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs
Normal file
20
Ryujinx.HLE/HOS/Services/Friend/IFriendServiceTypes.cs
Normal file
|
@ -0,0 +1,20 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Friend
|
||||
{
|
||||
enum PresenceStatusFilter
|
||||
{
|
||||
None,
|
||||
Online,
|
||||
OnlinePlay,
|
||||
OnlineOrOnlinePlay
|
||||
}
|
||||
|
||||
struct FriendFilter
|
||||
{
|
||||
public PresenceStatusFilter PresenceStatus;
|
||||
public bool IsFavoriteOnly;
|
||||
public bool IsSameAppPresenceOnly;
|
||||
public bool IsSameAppPlayedOnly;
|
||||
public bool IsArbitraryAppPlayedOnly;
|
||||
public long PresenceGroupId;
|
||||
}
|
||||
}
|
|
@ -281,11 +281,6 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
if (IsPathAlreadyInUse(DirName))
|
||||
{
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
IDirectory DirInterface = new IDirectory(DirName, FilterFlags);
|
||||
|
||||
DirInterface.Disposed += RemoveDirectoryInUse;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using Ryujinx.HLE.HOS.SystemState;
|
||||
using Ryujinx.HLE.Utilities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
|
@ -78,7 +78,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
UserId UserId = new UserId(
|
||||
UInt128 UserId = new UInt128(
|
||||
Context.RequestData.ReadInt64(),
|
||||
Context.RequestData.ReadInt64());
|
||||
|
||||
|
|
41
Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs
Normal file
41
Ryujinx.HLE/HOS/Services/Hid/HidNpad.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public enum HidNpadJoyAssignmentMode
|
||||
{
|
||||
Dual,
|
||||
Single,
|
||||
}
|
||||
|
||||
public enum HidNpadHandheldActivationMode
|
||||
{
|
||||
Dual,
|
||||
Single,
|
||||
None,
|
||||
}
|
||||
|
||||
public enum HidNpadJoyDeviceType
|
||||
{
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
public enum HidNpadJoyHoldType
|
||||
{
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum HidNpadStyle
|
||||
{
|
||||
None,
|
||||
FullKey = 1 << 0,
|
||||
Handheld = 1 << 1,
|
||||
Dual = 1 << 2,
|
||||
Left = 1 << 3,
|
||||
Right = 1 << 4,
|
||||
Invalid = 1 << 5,
|
||||
}
|
||||
}
|
21
Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs
Normal file
21
Ryujinx.HLE/HOS/Services/Hid/HidSixAxis.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
{
|
||||
public struct HidSensorFusionParameters
|
||||
{
|
||||
public float RevisePower;
|
||||
public float ReviseRange;
|
||||
}
|
||||
|
||||
public struct HidAccelerometerParameters
|
||||
{
|
||||
public float X;
|
||||
public float Y;
|
||||
}
|
||||
|
||||
public enum HidGyroscopeZeroDriftMode
|
||||
{
|
||||
Loose,
|
||||
Standard,
|
||||
Tight
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue