Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
9bad71afbf | |||
923089a298 | |||
d9aa15eb24 | |||
12c89a61f9 | |||
f5235fff29 | |||
eba682b767 | |||
b994dafe7a | |||
54421760c3 |
@ -157,6 +157,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(X86Instruction.Paddd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffe, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Paddq, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fd4, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Paddw, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000ffd, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Palignr, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f3a0f, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pand, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdb, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pandn, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fdf, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
Add(X86Instruction.Pavgb, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fe0, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
@ -239,6 +240,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(X86Instruction.Rsqrtss, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f52, InstructionFlags.Vex | InstructionFlags.PrefixF3));
|
||||
Add(X86Instruction.Sar, new InstructionInfo(0x070000d3, 0x070000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Setcc, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000f90, InstructionFlags.Reg8Dest));
|
||||
Add(X86Instruction.Sha256Msg1, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cc, InstructionFlags.None));
|
||||
Add(X86Instruction.Sha256Msg2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cd, InstructionFlags.None));
|
||||
Add(X86Instruction.Sha256Rnds2, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x000f38cb, InstructionFlags.None));
|
||||
Add(X86Instruction.Shl, new InstructionInfo(0x040000d3, 0x040000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Shr, new InstructionInfo(0x050000d3, 0x050000c1, BadOp, BadOp, BadOp, InstructionFlags.None));
|
||||
Add(X86Instruction.Shufpd, new InstructionInfo(BadOp, BadOp, BadOp, BadOp, 0x00000fc6, InstructionFlags.Vex | InstructionFlags.Prefix66));
|
||||
|
@ -12,21 +12,28 @@ namespace ARMeilleure.CodeGen.X86
|
||||
return;
|
||||
}
|
||||
|
||||
(_, _, int ecx, int edx) = X86Base.CpuId(0x00000001, 0x00000000);
|
||||
(int maxNum, _, _, _) = X86Base.CpuId(0x00000000, 0x00000000);
|
||||
|
||||
FeatureInfoEdx = (FeatureFlagsEdx)edx;
|
||||
FeatureInfoEcx = (FeatureFlagsEcx)ecx;
|
||||
(_, _, int ecx1, int edx1) = X86Base.CpuId(0x00000001, 0x00000000);
|
||||
FeatureInfo1Edx = (FeatureFlags1Edx)edx1;
|
||||
FeatureInfo1Ecx = (FeatureFlags1Ecx)ecx1;
|
||||
|
||||
if (maxNum >= 7)
|
||||
{
|
||||
(_, int ebx7, _, _) = X86Base.CpuId(0x00000007, 0x00000000);
|
||||
FeatureInfo7Ebx = (FeatureFlags7Ebx)ebx7;
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlagsEdx
|
||||
public enum FeatureFlags1Edx
|
||||
{
|
||||
Sse = 1 << 25,
|
||||
Sse2 = 1 << 26
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlagsEcx
|
||||
public enum FeatureFlags1Ecx
|
||||
{
|
||||
Sse3 = 1 << 0,
|
||||
Pclmulqdq = 1 << 1,
|
||||
@ -40,21 +47,31 @@ namespace ARMeilleure.CodeGen.X86
|
||||
F16c = 1 << 29
|
||||
}
|
||||
|
||||
public static FeatureFlagsEdx FeatureInfoEdx { get; }
|
||||
public static FeatureFlagsEcx FeatureInfoEcx { get; }
|
||||
[Flags]
|
||||
public enum FeatureFlags7Ebx
|
||||
{
|
||||
Avx2 = 1 << 5,
|
||||
Sha = 1 << 29
|
||||
}
|
||||
|
||||
public static bool SupportsSse => FeatureInfoEdx.HasFlag(FeatureFlagsEdx.Sse);
|
||||
public static bool SupportsSse2 => FeatureInfoEdx.HasFlag(FeatureFlagsEdx.Sse2);
|
||||
public static bool SupportsSse3 => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Sse3);
|
||||
public static bool SupportsPclmulqdq => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Pclmulqdq);
|
||||
public static bool SupportsSsse3 => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Ssse3);
|
||||
public static bool SupportsFma => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Fma);
|
||||
public static bool SupportsSse41 => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Sse41);
|
||||
public static bool SupportsSse42 => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Sse42);
|
||||
public static bool SupportsPopcnt => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Popcnt);
|
||||
public static bool SupportsAesni => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Aes);
|
||||
public static bool SupportsAvx => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.Avx);
|
||||
public static bool SupportsF16c => FeatureInfoEcx.HasFlag(FeatureFlagsEcx.F16c);
|
||||
public static FeatureFlags1Edx FeatureInfo1Edx { get; }
|
||||
public static FeatureFlags1Ecx FeatureInfo1Ecx { get; }
|
||||
public static FeatureFlags7Ebx FeatureInfo7Ebx { get; } = 0;
|
||||
|
||||
public static bool SupportsSse => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse);
|
||||
public static bool SupportsSse2 => FeatureInfo1Edx.HasFlag(FeatureFlags1Edx.Sse2);
|
||||
public static bool SupportsSse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse3);
|
||||
public static bool SupportsPclmulqdq => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Pclmulqdq);
|
||||
public static bool SupportsSsse3 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Ssse3);
|
||||
public static bool SupportsFma => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Fma);
|
||||
public static bool SupportsSse41 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse41);
|
||||
public static bool SupportsSse42 => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Sse42);
|
||||
public static bool SupportsPopcnt => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Popcnt);
|
||||
public static bool SupportsAesni => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Aes);
|
||||
public static bool SupportsAvx => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.Avx);
|
||||
public static bool SupportsAvx2 => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Avx2) && SupportsAvx;
|
||||
public static bool SupportsF16c => FeatureInfo1Ecx.HasFlag(FeatureFlags1Ecx.F16c);
|
||||
public static bool SupportsSha => FeatureInfo7Ebx.HasFlag(FeatureFlags7Ebx.Sha);
|
||||
|
||||
public static bool ForceLegacySse { get; set; }
|
||||
|
||||
|
@ -82,6 +82,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(Intrinsic.X86Paddd, new IntrinsicInfo(X86Instruction.Paddd, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Paddq, new IntrinsicInfo(X86Instruction.Paddq, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Paddw, new IntrinsicInfo(X86Instruction.Paddw, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Palignr, new IntrinsicInfo(X86Instruction.Palignr, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Pand, new IntrinsicInfo(X86Instruction.Pand, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pandn, new IntrinsicInfo(X86Instruction.Pandn, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Pavgb, new IntrinsicInfo(X86Instruction.Pavgb, IntrinsicType.Binary));
|
||||
@ -151,6 +152,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Add(Intrinsic.X86Roundss, new IntrinsicInfo(X86Instruction.Roundss, IntrinsicType.BinaryImm));
|
||||
Add(Intrinsic.X86Rsqrtps, new IntrinsicInfo(X86Instruction.Rsqrtps, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Rsqrtss, new IntrinsicInfo(X86Instruction.Rsqrtss, IntrinsicType.Unary));
|
||||
Add(Intrinsic.X86Sha256Msg1, new IntrinsicInfo(X86Instruction.Sha256Msg1, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Sha256Msg2, new IntrinsicInfo(X86Instruction.Sha256Msg2, IntrinsicType.Binary));
|
||||
Add(Intrinsic.X86Sha256Rnds2, new IntrinsicInfo(X86Instruction.Sha256Rnds2, IntrinsicType.Ternary));
|
||||
Add(Intrinsic.X86Shufpd, new IntrinsicInfo(X86Instruction.Shufpd, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Shufps, new IntrinsicInfo(X86Instruction.Shufps, IntrinsicType.TernaryImm));
|
||||
Add(Intrinsic.X86Sqrtpd, new IntrinsicInfo(X86Instruction.Sqrtpd, IntrinsicType.Unary));
|
||||
|
@ -308,11 +308,13 @@ namespace ARMeilleure.CodeGen.X86
|
||||
|
||||
case Instruction.Extended:
|
||||
{
|
||||
bool isBlend = node.Intrinsic == Intrinsic.X86Blendvpd ||
|
||||
node.Intrinsic == Intrinsic.X86Blendvps ||
|
||||
node.Intrinsic == Intrinsic.X86Pblendvb;
|
||||
|
||||
// BLENDVPD, BLENDVPS, PBLENDVB last operand is always implied to be XMM0 when VEX is not supported.
|
||||
if ((node.Intrinsic == Intrinsic.X86Blendvpd ||
|
||||
node.Intrinsic == Intrinsic.X86Blendvps ||
|
||||
node.Intrinsic == Intrinsic.X86Pblendvb) &&
|
||||
!HardwareCapabilities.SupportsVexEncoding)
|
||||
// SHA256RNDS2 always has an implied XMM0 as a last operand.
|
||||
if ((isBlend && !HardwareCapabilities.SupportsVexEncoding) || node.Intrinsic == Intrinsic.X86Sha256Rnds2)
|
||||
{
|
||||
Operand xmm0 = Xmm(X86Register.Xmm0, OperandType.V128);
|
||||
|
||||
|
@ -98,6 +98,7 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Paddd,
|
||||
Paddq,
|
||||
Paddw,
|
||||
Palignr,
|
||||
Pand,
|
||||
Pandn,
|
||||
Pavgb,
|
||||
@ -180,6 +181,9 @@ namespace ARMeilleure.CodeGen.X86
|
||||
Rsqrtss,
|
||||
Sar,
|
||||
Setcc,
|
||||
Sha256Msg1,
|
||||
Sha256Msg2,
|
||||
Sha256Rnds2,
|
||||
Shl,
|
||||
Shr,
|
||||
Shufpd,
|
||||
|
8
ARMeilleure/Decoders/IOpCode32MemRsImm.cs
Normal file
8
ARMeilleure/Decoders/IOpCode32MemRsImm.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
interface IOpCode32MemRsImm : IOpCode32Mem
|
||||
{
|
||||
int Rm { get; }
|
||||
ShiftType ShiftType { get; }
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32MemMult : OpCode32, IOpCode32MemMult
|
||||
@ -23,14 +25,7 @@ namespace ARMeilleure.Decoders
|
||||
|
||||
RegisterMask = opCode & 0xffff;
|
||||
|
||||
int regsSize = 0;
|
||||
|
||||
for (int index = 0; index < 16; index++)
|
||||
{
|
||||
regsSize += (RegisterMask >> index) & 1;
|
||||
}
|
||||
|
||||
regsSize *= 4;
|
||||
int regsSize = BitOperations.PopCount((uint)RegisterMask) * 4;
|
||||
|
||||
if (!u)
|
||||
{
|
||||
|
@ -1,6 +1,6 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32MemRsImm : OpCode32Mem
|
||||
class OpCode32MemRsImm : OpCode32Mem, IOpCode32MemRsImm
|
||||
{
|
||||
public int Rm { get; }
|
||||
public ShiftType ShiftType { get; }
|
||||
|
@ -1,10 +1,10 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT16BImmCmp : OpCodeT16
|
||||
class OpCodeT16BImmCmp : OpCodeT16, IOpCode32BImm
|
||||
{
|
||||
public int Rn { get; }
|
||||
|
||||
public int Immediate { get; }
|
||||
public long Immediate { get; }
|
||||
|
||||
public static new OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT16BImmCmp(inst, address, opCode);
|
||||
|
||||
|
31
ARMeilleure/Decoders/OpCodeT32MemImm8D.cs
Normal file
31
ARMeilleure/Decoders/OpCodeT32MemImm8D.cs
Normal file
@ -0,0 +1,31 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT32MemImm8D : OpCodeT32, IOpCode32Mem
|
||||
{
|
||||
public int Rt { get; }
|
||||
public int Rt2 { get; }
|
||||
public int Rn { get; }
|
||||
public bool WBack { get; }
|
||||
public bool IsLoad { get; }
|
||||
public bool Index { get; }
|
||||
public bool Add { get; }
|
||||
public int Immediate { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemImm8D(inst, address, opCode);
|
||||
|
||||
public OpCodeT32MemImm8D(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rt2 = (opCode >> 8) & 0xf;
|
||||
Rt = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
|
||||
Index = ((opCode >> 24) & 1) != 0;
|
||||
Add = ((opCode >> 23) & 1) != 0;
|
||||
WBack = ((opCode >> 21) & 1) != 0;
|
||||
|
||||
Immediate = opCode & 0xff;
|
||||
|
||||
IsLoad = ((opCode >> 20) & 1) != 0;
|
||||
}
|
||||
}
|
||||
}
|
24
ARMeilleure/Decoders/OpCodeT32MemLdEx.cs
Normal file
24
ARMeilleure/Decoders/OpCodeT32MemLdEx.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT32MemLdEx : OpCodeT32, IOpCode32MemEx
|
||||
{
|
||||
public int Rd => 0;
|
||||
public int Rt { get; }
|
||||
public int Rn { get; }
|
||||
|
||||
public bool WBack => false;
|
||||
public bool IsLoad => true;
|
||||
public bool Index => false;
|
||||
public bool Add => false;
|
||||
|
||||
public int Immediate => 0;
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemLdEx(inst, address, opCode);
|
||||
|
||||
public OpCodeT32MemLdEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rt = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
52
ARMeilleure/Decoders/OpCodeT32MemMult.cs
Normal file
52
ARMeilleure/Decoders/OpCodeT32MemMult.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT32MemMult : OpCodeT32, IOpCode32MemMult
|
||||
{
|
||||
public int Rn { get; }
|
||||
|
||||
public int RegisterMask { get; }
|
||||
public int Offset { get; }
|
||||
public int PostOffset { get; }
|
||||
|
||||
public bool IsLoad { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemMult(inst, address, opCode);
|
||||
|
||||
public OpCodeT32MemMult(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
|
||||
bool isLoad = (opCode & (1 << 20)) != 0;
|
||||
bool w = (opCode & (1 << 21)) != 0;
|
||||
bool u = (opCode & (1 << 23)) != 0;
|
||||
bool p = (opCode & (1 << 24)) != 0;
|
||||
|
||||
RegisterMask = opCode & 0xffff;
|
||||
|
||||
int regsSize = BitOperations.PopCount((uint)RegisterMask) * 4;
|
||||
|
||||
if (!u)
|
||||
{
|
||||
Offset -= regsSize;
|
||||
}
|
||||
|
||||
if (u == p)
|
||||
{
|
||||
Offset += 4;
|
||||
}
|
||||
|
||||
if (w)
|
||||
{
|
||||
PostOffset = u ? regsSize : -regsSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
PostOffset = 0;
|
||||
}
|
||||
|
||||
IsLoad = isLoad;
|
||||
}
|
||||
}
|
||||
}
|
30
ARMeilleure/Decoders/OpCodeT32MemRsImm.cs
Normal file
30
ARMeilleure/Decoders/OpCodeT32MemRsImm.cs
Normal file
@ -0,0 +1,30 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT32MemRsImm : OpCodeT32, IOpCode32MemRsImm
|
||||
{
|
||||
public int Rt { get; }
|
||||
public int Rn { get; }
|
||||
public int Rm { get; }
|
||||
public ShiftType ShiftType => ShiftType.Lsl;
|
||||
|
||||
public bool WBack => false;
|
||||
public bool IsLoad { get; }
|
||||
public bool Index => true;
|
||||
public bool Add => true;
|
||||
|
||||
public int Immediate { get; }
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemRsImm(inst, address, opCode);
|
||||
|
||||
public OpCodeT32MemRsImm(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rm = (opCode >> 0) & 0xf;
|
||||
Rt = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
|
||||
IsLoad = (opCode & (1 << 20)) != 0;
|
||||
|
||||
Immediate = (opCode >> 4) & 3;
|
||||
}
|
||||
}
|
||||
}
|
25
ARMeilleure/Decoders/OpCodeT32MemStEx.cs
Normal file
25
ARMeilleure/Decoders/OpCodeT32MemStEx.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCodeT32MemStEx : OpCodeT32, IOpCode32MemEx
|
||||
{
|
||||
public int Rd { get; }
|
||||
public int Rt { get; }
|
||||
public int Rn { get; }
|
||||
|
||||
public bool WBack => false;
|
||||
public bool IsLoad => false;
|
||||
public bool Index => false;
|
||||
public bool Add => false;
|
||||
|
||||
public int Immediate => 0;
|
||||
|
||||
public new static OpCode Create(InstDescriptor inst, ulong address, int opCode) => new OpCodeT32MemStEx(inst, address, opCode);
|
||||
|
||||
public OpCodeT32MemStEx(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
Rd = (opCode >> 0) & 0xf;
|
||||
Rt = (opCode >> 12) & 0xf;
|
||||
Rn = (opCode >> 16) & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
@ -1070,14 +1070,19 @@ namespace ARMeilleure.Decoders
|
||||
SetT32("11110x011011xxxx0xxx1111xxxxxxxx", InstName.Cmp, InstEmit32.Cmp, OpCodeT32AluImm.Create);
|
||||
SetT32("11101010100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluRsImm.Create);
|
||||
SetT32("11110x00100<xxxx0xxx<<<<xxxxxxxx", InstName.Eor, InstEmit32.Eor, OpCodeT32AluImm.Create);
|
||||
SetT32("111010001101xxxxxxxx111111101111", InstName.Ldaex, InstEmit32.Ldaex, OpCodeT32MemLdEx.Create);
|
||||
SetT32("1110100010x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||
SetT32("1110100100x1xxxxxxxxxxxxxxxxxxxx", InstName.Ldm, InstEmit32.Ldm, OpCodeT32MemMult.Create);
|
||||
SetT32("111110000101xxxx<<<<10x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000101xxxx<<<<1100xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000101xxxx<<<<11x1xxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110001101xxxxxxxxxxxxxxxxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemImm12.Create);
|
||||
SetT32("111110000101<<<<xxxx000000xxxxxx", InstName.Ldr, InstEmit32.Ldr, OpCodeT32MemRsImm.Create);
|
||||
SetT32("111110000001xxxx<<<<10x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000001xxxx<<<<1100xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000001xxxx<<<<11x1xxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110001001xxxxxxxxxxxxxxxxxxxx", InstName.Ldrb, InstEmit32.Ldrb, OpCodeT32MemImm12.Create);
|
||||
SetT32("1110100>x1>1<<<<xxxxxxxxxxxxxxxx", InstName.Ldrd, InstEmit32.Ldrd, OpCodeT32MemImm8D.Create);
|
||||
SetT32("111110000011xxxx<<<<10x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000011xxxx<<<<1100xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110000011xxxx<<<<11x1xxxxxxxx", InstName.Ldrh, InstEmit32.Ldrh, OpCodeT32MemImm8.Create);
|
||||
@ -1102,10 +1107,15 @@ namespace ARMeilleure.Decoders
|
||||
SetT32("11110x01110xxxxx0xxxxxxxxxxxxxxx", InstName.Rsb, InstEmit32.Rsb, OpCodeT32AluImm.Create);
|
||||
SetT32("11101011011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluRsImm.Create);
|
||||
SetT32("11110x01011xxxxx0xxxxxxxxxxxxxxx", InstName.Sbc, InstEmit32.Sbc, OpCodeT32AluImm.Create);
|
||||
SetT32("111010001100xxxxxxxx11111110xxxx", InstName.Stlex, InstEmit32.Stlex, OpCodeT32MemStEx.Create);
|
||||
SetT32("1110100010x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
||||
SetT32("1110100100x0xxxx0xxxxxxxxxxxxxxx", InstName.Stm, InstEmit32.Stm, OpCodeT32MemMult.Create);
|
||||
SetT32("111110000100xxxxxxxx1<<>xxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110001100xxxxxxxxxxxxxxxxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemImm12.Create);
|
||||
SetT32("111110000100<<<<xxxx000000xxxxxx", InstName.Str, InstEmit32.Str, OpCodeT32MemRsImm.Create);
|
||||
SetT32("111110000000xxxxxxxx1<<>xxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110001000xxxxxxxxxxxxxxxxxxxx", InstName.Strb, InstEmit32.Strb, OpCodeT32MemImm12.Create);
|
||||
SetT32("1110100>x1>0<<<<xxxxxxxxxxxxxxxx", InstName.Strd, InstEmit32.Strd, OpCodeT32MemImm8D.Create);
|
||||
SetT32("111110000010xxxxxxxx1<<>xxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm8.Create);
|
||||
SetT32("111110001010xxxxxxxxxxxxxxxxxxxx", InstName.Strh, InstEmit32.Strh, OpCodeT32MemImm12.Create);
|
||||
SetT32("11101011101<xxxx0xxx<<<<xxxxxxxx", InstName.Sub, InstEmit32.Sub, OpCodeT32AluRsImm.Create);
|
||||
|
@ -88,7 +88,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
OpCodeT16BImmCmp op = (OpCodeT16BImmCmp)context.CurrOp;
|
||||
|
||||
Operand value = GetIntOrZR(context, op.Rn);
|
||||
Operand value = GetIntA32(context, op.Rn);
|
||||
Operand lblTarget = context.GetLabel((ulong)op.Immediate);
|
||||
|
||||
if (onNotZero)
|
||||
|
@ -547,7 +547,7 @@ namespace ARMeilleure.Instructions
|
||||
{
|
||||
switch (context.CurrOp)
|
||||
{
|
||||
case OpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
case IOpCode32MemRsImm op: return GetMShiftedByImmediate(context, op, setCarry);
|
||||
|
||||
case IOpCode32MemReg op: return GetIntA32(context, op.Rm);
|
||||
|
||||
@ -564,7 +564,7 @@ namespace ARMeilleure.Instructions
|
||||
return new InvalidOperationException($"Invalid OpCode type \"{opCode?.GetType().Name ?? "null"}\".");
|
||||
}
|
||||
|
||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, OpCode32MemRsImm op, bool setCarry)
|
||||
public static Operand GetMShiftedByImmediate(ArmEmitterContext context, IOpCode32MemRsImm op, bool setCarry)
|
||||
{
|
||||
Operand m = GetIntA32(context, op.Rm);
|
||||
|
||||
|
@ -100,7 +100,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256h(context, d, n, m, part2: false);
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
@ -113,7 +113,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256h(context, n, d, m, part2: true);
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
@ -125,7 +125,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand d = GetVec(op.Rd);
|
||||
Operand n = GetVec(op.Rn);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)), d, n);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256su0(context, d, n);
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
@ -138,7 +138,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVec(op.Rn);
|
||||
Operand m = GetVec(op.Rm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256su1(context, d, n, m);
|
||||
|
||||
context.Copy(GetVec(op.Rd), res);
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVecA32(op.Qn);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashLower)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256h(context, d, n, m, part2: false);
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
@ -30,7 +30,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVecA32(op.Qn);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.HashUpper)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256h(context, n, d, m, part2: true);
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
@ -42,7 +42,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand d = GetVecA32(op.Qd);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)), d, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256su0(context, d, m);
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
@ -55,7 +55,7 @@ namespace ARMeilleure.Instructions
|
||||
Operand n = GetVecA32(op.Qn);
|
||||
Operand m = GetVecA32(op.Qm);
|
||||
|
||||
Operand res = context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)), d, n, m);
|
||||
Operand res = InstEmitSimdHashHelper.EmitSha256su1(context, d, n, m);
|
||||
|
||||
context.Copy(GetVecA32(op.Qd), res);
|
||||
}
|
||||
|
56
ARMeilleure/Instructions/InstEmitSimdHashHelper.cs
Normal file
56
ARMeilleure/Instructions/InstEmitSimdHashHelper.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using ARMeilleure.IntermediateRepresentation;
|
||||
using ARMeilleure.Translation;
|
||||
using System;
|
||||
|
||||
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
static class InstEmitSimdHashHelper
|
||||
{
|
||||
public static Operand EmitSha256h(ArmEmitterContext context, Operand x, Operand y, Operand w, bool part2)
|
||||
{
|
||||
if (Optimizations.UseSha)
|
||||
{
|
||||
Operand src1 = context.AddIntrinsic(Intrinsic.X86Shufps, y, x, Const(0xbb));
|
||||
Operand src2 = context.AddIntrinsic(Intrinsic.X86Shufps, y, x, Const(0x11));
|
||||
Operand w2 = context.AddIntrinsic(Intrinsic.X86Punpckhqdq, w, w);
|
||||
|
||||
Operand round2 = context.AddIntrinsic(Intrinsic.X86Sha256Rnds2, src1, src2, w);
|
||||
Operand round4 = context.AddIntrinsic(Intrinsic.X86Sha256Rnds2, src2, round2, w2);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Shufps, round4, round2, Const(part2 ? 0x11 : 0xbb));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
String method = part2 ? nameof(SoftFallback.HashUpper) : nameof(SoftFallback.HashLower);
|
||||
return context.Call(typeof(SoftFallback).GetMethod(method), x, y, w);
|
||||
}
|
||||
|
||||
public static Operand EmitSha256su0(ArmEmitterContext context, Operand x, Operand y)
|
||||
{
|
||||
if (Optimizations.UseSha)
|
||||
{
|
||||
return context.AddIntrinsic(Intrinsic.X86Sha256Msg1, x, y);
|
||||
}
|
||||
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart1)), x, y);
|
||||
}
|
||||
|
||||
public static Operand EmitSha256su1(ArmEmitterContext context, Operand x, Operand y, Operand z)
|
||||
{
|
||||
if (Optimizations.UseSha && Optimizations.UseSsse3)
|
||||
{
|
||||
Operand extr = context.AddIntrinsic(Intrinsic.X86Palignr, z, y, Const(4));
|
||||
Operand tmp = context.AddIntrinsic(Intrinsic.X86Paddd, extr, x);
|
||||
|
||||
Operand res = context.AddIntrinsic(Intrinsic.X86Sha256Msg2, tmp, z);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
return context.Call(typeof(SoftFallback).GetMethod(nameof(SoftFallback.Sha256SchedulePart2)), x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
@ -1129,7 +1129,7 @@ namespace ARMeilleure.Instructions
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: true);
|
||||
}
|
||||
|
||||
public static V128 HashUpper(V128 hash_efgh, V128 hash_abcd, V128 wk)
|
||||
public static V128 HashUpper(V128 hash_abcd, V128 hash_efgh, V128 wk)
|
||||
{
|
||||
return Sha256Hash(hash_abcd, hash_efgh, wk, part1: false);
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
X86Paddd,
|
||||
X86Paddq,
|
||||
X86Paddw,
|
||||
X86Palignr,
|
||||
X86Pand,
|
||||
X86Pandn,
|
||||
X86Pavgb,
|
||||
@ -140,6 +141,9 @@ namespace ARMeilleure.IntermediateRepresentation
|
||||
X86Roundss,
|
||||
X86Rsqrtps,
|
||||
X86Rsqrtss,
|
||||
X86Sha256Msg1,
|
||||
X86Sha256Msg2,
|
||||
X86Sha256Rnds2,
|
||||
X86Shufpd,
|
||||
X86Shufps,
|
||||
X86Sqrtpd,
|
||||
|
@ -21,6 +21,7 @@ namespace ARMeilleure
|
||||
public static bool UseFmaIfAvailable { get; set; } = true;
|
||||
public static bool UseAesniIfAvailable { get; set; } = true;
|
||||
public static bool UsePclmulqdqIfAvailable { get; set; } = true;
|
||||
public static bool UseShaIfAvailable { get; set; } = true;
|
||||
|
||||
public static bool ForceLegacySse
|
||||
{
|
||||
@ -40,5 +41,6 @@ namespace ARMeilleure
|
||||
internal static bool UseFma => UseFmaIfAvailable && HardwareCapabilities.SupportsFma;
|
||||
internal static bool UseAesni => UseAesniIfAvailable && HardwareCapabilities.SupportsAesni;
|
||||
internal static bool UsePclmulqdq => UsePclmulqdqIfAvailable && HardwareCapabilities.SupportsPclmulqdq;
|
||||
internal static bool UseSha => UseShaIfAvailable && HardwareCapabilities.SupportsSha;
|
||||
}
|
||||
}
|
@ -14,7 +14,7 @@ namespace ARMeilleure.Translation
|
||||
public BasicBlock Entry { get; }
|
||||
public IntrusiveList<BasicBlock> Blocks { get; }
|
||||
public BasicBlock[] PostOrderBlocks => _postOrderBlocks;
|
||||
public int[] PostOrderMap => _postOrderMap;
|
||||
public int[] PostOrderMap => _postOrderMap;
|
||||
|
||||
public ControlFlowGraph(BasicBlock entry, IntrusiveList<BasicBlock> blocks, int localsCount)
|
||||
{
|
||||
|
@ -27,7 +27,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
private const string OuterHeaderMagicString = "PTCohd\0\0";
|
||||
private const string InnerHeaderMagicString = "PTCihd\0\0";
|
||||
|
||||
private const uint InternalVersion = 3439; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
private const uint InternalVersion = 3585; //! To be incremented manually for each change to the ARMeilleure project.
|
||||
|
||||
private const string ActualDir = "0";
|
||||
private const string BackupDir = "1";
|
||||
@ -946,9 +946,12 @@ namespace ARMeilleure.Translation.PTC
|
||||
return BitConverter.IsLittleEndian;
|
||||
}
|
||||
|
||||
private static ulong GetFeatureInfo()
|
||||
private static FeatureInfo GetFeatureInfo()
|
||||
{
|
||||
return (ulong)HardwareCapabilities.FeatureInfoEdx << 32 | (uint)HardwareCapabilities.FeatureInfoEcx;
|
||||
return new FeatureInfo(
|
||||
(uint)HardwareCapabilities.FeatureInfo1Ecx,
|
||||
(uint)HardwareCapabilities.FeatureInfo1Edx,
|
||||
(uint)HardwareCapabilities.FeatureInfo7Ebx);
|
||||
}
|
||||
|
||||
private static byte GetMemoryManagerMode()
|
||||
@ -968,7 +971,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
return osPlatform;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 50*/)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 54*/)]
|
||||
private struct OuterHeader
|
||||
{
|
||||
public ulong Magic;
|
||||
@ -976,7 +979,7 @@ namespace ARMeilleure.Translation.PTC
|
||||
public uint CacheFileVersion;
|
||||
|
||||
public bool Endianness;
|
||||
public ulong FeatureInfo;
|
||||
public FeatureInfo FeatureInfo;
|
||||
public byte MemoryManagerMode;
|
||||
public uint OSPlatform;
|
||||
|
||||
@ -999,6 +1002,9 @@ namespace ARMeilleure.Translation.PTC
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 12*/)]
|
||||
private record struct FeatureInfo(uint FeatureInfo0, uint FeatureInfo1, uint FeatureInfo2);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1/*, Size = 128*/)]
|
||||
private struct InnerHeader
|
||||
{
|
||||
|
@ -350,7 +350,7 @@
|
||||
"DialogProfileDeleteProfileTitle": "Deleting Profile",
|
||||
"DialogProfileDeleteProfileMessage": "This action is irreversible, are you sure you want to continue?",
|
||||
"DialogWarning": "Warning",
|
||||
"DialogPPTCDeletionMessage": "You are about to delete the PPTC cache for :\n\n{0}\n\nAre you sure you want to proceed?",
|
||||
"DialogPPTCDeletionMessage": "You are about to queue a PPTC rebuild on the next boot of:\n\n{0}\n\nAre you sure you want to proceed?",
|
||||
"DialogPPTCDeletionErrorMessage": "Error purging PPTC cache at {0}: {1}",
|
||||
"DialogShaderDeletionMessage": "You are about to delete the Shader cache for :\n\n{0}\n\nAre you sure you want to proceed?",
|
||||
"DialogShaderDeletionErrorMessage": "Error purging Shader cache at {0}: {1}",
|
||||
|
@ -49,6 +49,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
private float _previousVolumeLevel;
|
||||
private float _volume;
|
||||
private bool _isVulkanAvailable = true;
|
||||
private bool _directoryChanged = false;
|
||||
private List<string> _gpuIds = new List<string>();
|
||||
private KeyboardHotkeys _keyboardHotkeys;
|
||||
private int _graphicsBackendIndex;
|
||||
@ -112,6 +113,17 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool DirectoryChanged
|
||||
{
|
||||
get => _directoryChanged;
|
||||
set
|
||||
{
|
||||
_directoryChanged = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool EnableDiscordIntegration { get; set; }
|
||||
public bool CheckUpdatesOnStart { get; set; }
|
||||
public bool ShowConfirmExit { get; set; }
|
||||
@ -397,10 +409,14 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public async Task SaveSettings()
|
||||
{
|
||||
List<string> gameDirs = new List<string>(GameDirectories);
|
||||
|
||||
ConfigurationState config = ConfigurationState.Instance;
|
||||
|
||||
if (_directoryChanged)
|
||||
{
|
||||
List<string> gameDirs = new List<string>(GameDirectories);
|
||||
config.Ui.GameDirs.Value = gameDirs;
|
||||
}
|
||||
|
||||
if (_validTzRegions.Contains(TimeZone))
|
||||
{
|
||||
config.System.TimeZone.Value = TimeZone;
|
||||
@ -465,7 +481,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
config.System.SystemTimeOffset.Value = systemTimeOffset.Seconds;
|
||||
config.Graphics.ShadersDumpPath.Value = ShaderDumpPath;
|
||||
config.Ui.GameDirs.Value = gameDirs;
|
||||
config.System.FsGlobalAccessLogMode.Value = FsGlobalAccessLogMode;
|
||||
config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
|
||||
|
||||
|
@ -162,6 +162,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -170,6 +171,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
if (!string.IsNullOrWhiteSpace(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -181,6 +183,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
foreach (string path in selected)
|
||||
{
|
||||
ViewModel.GameDirectories.Remove(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,10 +235,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
ControllerSettings?.SaveCurrentProfile();
|
||||
|
||||
if (Owner is MainWindow window)
|
||||
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
||||
{
|
||||
window.ViewModel.LoadApplications();
|
||||
}
|
||||
|
||||
ViewModel.DirectoryChanged = false;
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs e)
|
||||
|
@ -19,6 +19,7 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void SetData(ReadOnlySpan<byte> data);
|
||||
void SetData(ReadOnlySpan<byte> data, int layer, int level);
|
||||
void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region);
|
||||
void SetStorage(BufferRange buffer);
|
||||
void Release();
|
||||
}
|
||||
|
@ -113,6 +113,8 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetDataSlice] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetDataSliceRegion] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
|
||||
_lookup[(int)CommandType.TextureSetStorage] = (Span<byte> memory, ThreadedRenderer threaded, IRenderer renderer) =>
|
||||
TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
|
||||
|
||||
|
@ -37,6 +37,7 @@
|
||||
TextureRelease,
|
||||
TextureSetData,
|
||||
TextureSetDataSlice,
|
||||
TextureSetDataSliceRegion,
|
||||
TextureSetStorage,
|
||||
|
||||
WindowPresent,
|
||||
|
@ -0,0 +1,31 @@
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Model;
|
||||
using Ryujinx.Graphics.GAL.Multithreading.Resources;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
|
||||
{
|
||||
struct TextureSetDataSliceRegionCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.TextureSetDataSliceRegion;
|
||||
private TableRef<ThreadedTexture> _texture;
|
||||
private TableRef<byte[]> _data;
|
||||
private int _layer;
|
||||
private int _level;
|
||||
private Rectangle<int> _region;
|
||||
|
||||
public void Set(TableRef<ThreadedTexture> texture, TableRef<byte[]> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
_texture = texture;
|
||||
_data = data;
|
||||
_layer = layer;
|
||||
_level = level;
|
||||
_region = region;
|
||||
}
|
||||
|
||||
public static void Run(ref TextureSetDataSliceRegionCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
ThreadedTexture texture = command._texture.Get(threaded);
|
||||
texture.Base.SetData(new ReadOnlySpan<byte>(command._data.Get(threaded)), command._layer, command._level, command._region);
|
||||
}
|
||||
}
|
||||
}
|
@ -119,6 +119,12 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Resources
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
_renderer.New<TextureSetDataSliceRegionCommand>().Set(Ref(this), Ref(data.ToArray()), layer, level, region);
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetStorage(BufferRange buffer)
|
||||
{
|
||||
_renderer.New<TextureSetStorageCommand>().Set(Ref(this), buffer);
|
||||
|
@ -224,7 +224,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Dma
|
||||
xCount,
|
||||
yCount,
|
||||
dstLinear,
|
||||
dst.MemoryLayout);
|
||||
dst.MemoryLayout.UnpackGobBlocksInY(),
|
||||
dst.MemoryLayout.UnpackGobBlocksInZ());
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
||||
private int _dstHeight;
|
||||
private int _dstStride;
|
||||
private int _dstGobBlocksInY;
|
||||
private int _dstGobBlocksInZ;
|
||||
private int _lineLengthIn;
|
||||
private int _lineCount;
|
||||
|
||||
@ -117,6 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
||||
_dstHeight = (int)state.SetDstHeight;
|
||||
_dstStride = (int)state.PitchOut;
|
||||
_dstGobBlocksInY = 1 << (int)state.SetDstBlockSizeHeight;
|
||||
_dstGobBlocksInZ = 1 << (int)state.SetDstBlockSizeDepth;
|
||||
_lineLengthIn = (int)state.LineLengthIn;
|
||||
_lineCount = (int)state.LineCount;
|
||||
|
||||
@ -176,6 +178,31 @@ namespace Ryujinx.Graphics.Gpu.Engine.InlineToMemory
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Verify if the destination X/Y and width/height are taken into account
|
||||
// for linear texture transfers. If not, we can use the fast path for that aswell.
|
||||
// Right now the copy code at the bottom assumes that it is used on both which might be incorrect.
|
||||
if (!_isLinear)
|
||||
{
|
||||
var target = memoryManager.Physical.TextureCache.FindTexture(
|
||||
memoryManager,
|
||||
_dstGpuVa,
|
||||
1,
|
||||
_dstStride,
|
||||
_dstHeight,
|
||||
_lineLengthIn,
|
||||
_lineCount,
|
||||
_isLinear,
|
||||
_dstGobBlocksInY,
|
||||
_dstGobBlocksInZ);
|
||||
|
||||
if (target != null)
|
||||
{
|
||||
target.SetData(data, 0, 0, new GAL.Rectangle<int>(_dstX, _dstY, _lineLengthIn / target.Info.FormatInfo.BytesPerPixel, _lineCount));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var dstCalculator = new OffsetCalculator(
|
||||
_dstWidth,
|
||||
_dstHeight,
|
||||
|
@ -761,6 +761,24 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
_hasData = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Uploads new texture data to the host GPU for a specific layer/level and 2D sub-region.
|
||||
/// </summary>
|
||||
/// <param name="data">New data</param>
|
||||
/// <param name="layer">Target layer</param>
|
||||
/// <param name="level">Target level</param>
|
||||
/// <param name="region">Target sub-region of the texture to update</param>
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
BlacklistScale();
|
||||
|
||||
HostTexture.SetData(data, layer, level, region);
|
||||
|
||||
_currentData = null;
|
||||
|
||||
_hasData = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts texture data to a format and layout that is supported by the host GPU.
|
||||
/// </summary>
|
||||
|
@ -905,7 +905,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
/// <param name="xCount">Number of pixels to be copied per line</param>
|
||||
/// <param name="yCount">Number of lines to be copied</param>
|
||||
/// <param name="linear">True if the texture has a linear layout, false otherwise</param>
|
||||
/// <param name="memoryLayout">If <paramref name="linear"/> is false, should have the memory layout, otherwise ignored</param>
|
||||
/// <param name="gobBlocksInY">If <paramref name="linear"/> is false, the amount of GOB blocks in the Y axis</param>
|
||||
/// <param name="gobBlocksInZ">If <paramref name="linear"/> is false, the amount of GOB blocks in the Z axis</param>
|
||||
/// <returns>A matching texture, or null if there is no match</returns>
|
||||
public Texture FindTexture(
|
||||
MemoryManager memoryManager,
|
||||
@ -916,7 +917,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
int xCount,
|
||||
int yCount,
|
||||
bool linear,
|
||||
MemoryLayout memoryLayout)
|
||||
int gobBlocksInY,
|
||||
int gobBlocksInZ)
|
||||
{
|
||||
ulong address = memoryManager.Translate(gpuVa);
|
||||
|
||||
@ -955,8 +957,8 @@ namespace Ryujinx.Graphics.Gpu.Image
|
||||
|
||||
bool sizeMatch = xCount * bpp == texture.Info.Width * format.BytesPerPixel && height == texture.Info.Height;
|
||||
bool formatMatch = !texture.Info.IsLinear &&
|
||||
texture.Info.GobBlocksInY == memoryLayout.UnpackGobBlocksInY() &&
|
||||
texture.Info.GobBlocksInZ == memoryLayout.UnpackGobBlocksInZ();
|
||||
texture.Info.GobBlocksInY == gobBlocksInY &&
|
||||
texture.Info.GobBlocksInZ == gobBlocksInZ;
|
||||
|
||||
match = sizeMatch && formatMatch;
|
||||
}
|
||||
|
@ -58,6 +58,11 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetStorage(BufferRange buffer)
|
||||
{
|
||||
if (_buffer != BufferHandle.Null &&
|
||||
|
@ -1,4 +1,5 @@
|
||||
using OpenTK.Graphics.OpenGL;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using System;
|
||||
|
||||
@ -385,7 +386,34 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
int width = Math.Max(Info.Width >> level, 1);
|
||||
int height = Math.Max(Info.Height >> level, 1);
|
||||
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, width, height);
|
||||
ReadFrom2D((IntPtr)ptr, layer, level, 0, 0, width, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
if (Format == Format.S8UintD24Unorm)
|
||||
{
|
||||
data = FormatConverter.ConvertS8D24ToD24S8(data);
|
||||
}
|
||||
|
||||
int wInBlocks = BitUtils.DivRoundUp(region.Width, Info.BlockWidth);
|
||||
int hInBlocks = BitUtils.DivRoundUp(region.Height, Info.BlockHeight);
|
||||
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
ReadFrom2D(
|
||||
(IntPtr)ptr,
|
||||
layer,
|
||||
level,
|
||||
region.X,
|
||||
region.Y,
|
||||
region.Width,
|
||||
region.Height,
|
||||
BitUtils.AlignUp(wInBlocks * Info.BytesPerPixel, 4) * hInBlocks);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -397,15 +425,20 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
|
||||
public void ReadFromPbo2D(int offset, int layer, int level, int width, int height)
|
||||
{
|
||||
ReadFrom2D(IntPtr.Zero + offset, layer, level, width, height);
|
||||
ReadFrom2D(IntPtr.Zero + offset, layer, level, 0, 0, width, height);
|
||||
}
|
||||
|
||||
private void ReadFrom2D(IntPtr data, int layer, int level, int width, int height)
|
||||
private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height)
|
||||
{
|
||||
int mipSize = Info.GetMipSize2D(level);
|
||||
|
||||
ReadFrom2D(data, layer, level, x, y, width, height, mipSize);
|
||||
}
|
||||
|
||||
private void ReadFrom2D(IntPtr data, int layer, int level, int x, int y, int width, int height, int mipSize)
|
||||
{
|
||||
TextureTarget target = Target.Convert();
|
||||
|
||||
int mipSize = Info.GetMipSize2D(level);
|
||||
|
||||
Bind(target, 0);
|
||||
|
||||
FormatInfo format = FormatTable.GetFormatInfo(Info.Format);
|
||||
@ -418,7 +451,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.CompressedTexSubImage1D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
x,
|
||||
width,
|
||||
format.PixelFormat,
|
||||
mipSize,
|
||||
@ -429,7 +462,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.TexSubImage1D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
x,
|
||||
width,
|
||||
format.PixelFormat,
|
||||
format.PixelType,
|
||||
@ -443,7 +476,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.CompressedTexSubImage2D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
x,
|
||||
layer,
|
||||
width,
|
||||
1,
|
||||
@ -456,7 +489,7 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.TexSubImage2D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
x,
|
||||
layer,
|
||||
width,
|
||||
1,
|
||||
@ -472,8 +505,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.CompressedTexSubImage2D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
format.PixelFormat,
|
||||
@ -485,8 +518,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.TexSubImage2D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
format.PixelFormat,
|
||||
@ -503,8 +536,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.CompressedTexSubImage3D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
layer,
|
||||
width,
|
||||
height,
|
||||
@ -518,8 +551,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.TexSubImage3D(
|
||||
target,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
layer,
|
||||
width,
|
||||
height,
|
||||
@ -536,8 +569,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.CompressedTexSubImage2D(
|
||||
TextureTarget.TextureCubeMapPositiveX + layer,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
format.PixelFormat,
|
||||
@ -549,8 +582,8 @@ namespace Ryujinx.Graphics.OpenGL.Image
|
||||
GL.TexSubImage2D(
|
||||
TextureTarget.TextureCubeMapPositiveX + layer,
|
||||
level,
|
||||
0,
|
||||
0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
format.PixelFormat,
|
||||
|
@ -98,6 +98,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void SetStorage(BufferRange buffer)
|
||||
{
|
||||
if (_bufferHandle == buffer.Handle &&
|
||||
|
@ -819,7 +819,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
|
||||
var image = GetImage().Get(cbs).Value;
|
||||
|
||||
CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, x, y, width, height);
|
||||
CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, size, true, 0, 0, x, y, width, height);
|
||||
}
|
||||
|
||||
bufferHolder.WaitForFences();
|
||||
@ -893,7 +893,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SetData(data, layer, level, 1, 1, singleSlice: true);
|
||||
}
|
||||
|
||||
private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice)
|
||||
public void SetData(ReadOnlySpan<byte> data, int layer, int level, Rectangle<int> region)
|
||||
{
|
||||
SetData(data, layer, level, 1, 1, singleSlice: true, region);
|
||||
}
|
||||
|
||||
private void SetData(ReadOnlySpan<byte> data, int layer, int level, int layers, int levels, bool singleSlice, Rectangle<int>? region = null)
|
||||
{
|
||||
int bufferDataLength = GetBufferDataLength(data.Length);
|
||||
|
||||
@ -917,7 +922,25 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
var buffer = bufferHolder.GetBuffer(cbs.CommandBuffer).Get(cbs).Value;
|
||||
var image = imageAuto.Get(cbs).Value;
|
||||
|
||||
CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
|
||||
if (region.HasValue)
|
||||
{
|
||||
CopyFromOrToBuffer(
|
||||
cbs.CommandBuffer,
|
||||
buffer,
|
||||
image,
|
||||
bufferDataLength,
|
||||
false,
|
||||
layer,
|
||||
level,
|
||||
region.Value.X,
|
||||
region.Value.Y,
|
||||
region.Value.Width,
|
||||
region.Value.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
CopyFromOrToBuffer(cbs.CommandBuffer, buffer, image, bufferDataLength, false, layer, level, layers, levels, singleSlice);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetBufferDataLength(int length)
|
||||
@ -1059,6 +1082,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Image image,
|
||||
int size,
|
||||
bool to,
|
||||
int dstLayer,
|
||||
int dstLevel,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
@ -1071,13 +1096,21 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
aspectFlags = ImageAspectFlags.ImageAspectDepthBit;
|
||||
}
|
||||
|
||||
var sl = new ImageSubresourceLayers(aspectFlags, (uint)FirstLevel, (uint)FirstLayer, 1);
|
||||
var sl = new ImageSubresourceLayers(aspectFlags, (uint)(FirstLevel + dstLevel), (uint)(FirstLayer + dstLayer), 1);
|
||||
|
||||
var extent = new Extent3D((uint)width, (uint)height, 1);
|
||||
|
||||
int rowLengthAlignment = Info.BlockWidth;
|
||||
|
||||
// We expect all data being written into the texture to have a stride aligned by 4.
|
||||
if (!to && Info.BytesPerPixel < 4)
|
||||
{
|
||||
rowLengthAlignment = 4 / Info.BytesPerPixel;
|
||||
}
|
||||
|
||||
var region = new BufferImageCopy(
|
||||
0,
|
||||
(uint)AlignUpNpot(width, Info.BlockWidth),
|
||||
(uint)AlignUpNpot(width, rowLengthAlignment),
|
||||
(uint)AlignUpNpot(height, Info.BlockHeight),
|
||||
sl,
|
||||
new Offset3D(x, y, 0),
|
||||
|
@ -14,11 +14,14 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
||||
private ParentalControlFlagValue _parentalControlFlag;
|
||||
private int[] _ratingAge;
|
||||
|
||||
#pragma warning disable CS0414
|
||||
// TODO: Find where they are set.
|
||||
private bool _restrictionEnabled = false;
|
||||
private bool _featuresRestriction = false;
|
||||
private bool _freeCommunicationEnabled = false;
|
||||
private bool _stereoVisionRestrictionConfigurable = true;
|
||||
private bool _stereoVisionRestriction = false;
|
||||
#pragma warning restore CS0414
|
||||
|
||||
public IParentalControlService(ServiceCtx context, ulong pid, bool withInitialize, int permissionFlag)
|
||||
{
|
||||
@ -88,13 +91,22 @@ namespace Ryujinx.HLE.HOS.Services.Pctl.ParentalControlServiceFactory
|
||||
return ResultCode.FreeCommunicationDisabled;
|
||||
}
|
||||
|
||||
// NOTE: This sets an internal field to true. Usage have to be determined.
|
||||
_freeCommunicationEnabled = true;
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServicePctl);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1017)] // 10.0.0+
|
||||
// EndFreeCommunication()
|
||||
public ResultCode EndFreeCommunication(ServiceCtx context)
|
||||
{
|
||||
_freeCommunicationEnabled = false;
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1013)] // 4.0.0+
|
||||
// ConfirmStereoVisionPermission()
|
||||
public ResultCode ConfirmStereoVisionPermission(ServiceCtx context)
|
||||
|
@ -219,9 +219,10 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
int fdsCount = context.RequestData.ReadInt32();
|
||||
int timeout = context.RequestData.ReadInt32();
|
||||
|
||||
(ulong bufferPosition, ulong bufferSize) = context.Request.GetBufferType0x21();
|
||||
(ulong inputBufferPosition, ulong inputBufferSize) = context.Request.GetBufferType0x21();
|
||||
(ulong outputBufferPosition, ulong outputBufferSize) = context.Request.GetBufferType0x22();
|
||||
|
||||
if (timeout < -1 || fdsCount < 0 || (ulong)(fdsCount * 8) > bufferSize)
|
||||
if (timeout < -1 || fdsCount < 0 || (ulong)(fdsCount * 8) > inputBufferSize)
|
||||
{
|
||||
return WriteBsdResult(context, -1, LinuxError.EINVAL);
|
||||
}
|
||||
@ -230,7 +231,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
|
||||
for (int i = 0; i < fdsCount; i++)
|
||||
{
|
||||
PollEventData pollEventData = context.Memory.Read<PollEventData>(bufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()));
|
||||
PollEventData pollEventData = context.Memory.Read<PollEventData>(inputBufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()));
|
||||
|
||||
IFileDescriptor fileDescriptor = _context.RetrieveFileDescriptor(pollEventData.SocketFd);
|
||||
|
||||
@ -277,7 +278,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
{
|
||||
bool IsUnexpectedLinuxError(LinuxError error)
|
||||
{
|
||||
return errno != LinuxError.SUCCESS && errno != LinuxError.ETIMEDOUT;
|
||||
return error != LinuxError.SUCCESS && error != LinuxError.ETIMEDOUT;
|
||||
}
|
||||
|
||||
// Hybrid approach
|
||||
@ -332,7 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd
|
||||
// TODO: Spanify
|
||||
for (int i = 0; i < fdsCount; i++)
|
||||
{
|
||||
context.Memory.Write(bufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()), events[i].Data);
|
||||
context.Memory.Write(outputBufferPosition + (ulong)(i * Unsafe.SizeOf<PollEventData>()), events[i].Data);
|
||||
}
|
||||
|
||||
return WriteBsdResult(context, updateCount, errno);
|
||||
|
@ -253,7 +253,7 @@ namespace Ryujinx.HLE.Loaders.Mods
|
||||
|
||||
if (tokens[1][0] == '"')
|
||||
{
|
||||
var patch = Encoding.ASCII.GetBytes(tokens[1].Trim('"'));
|
||||
var patch = Encoding.ASCII.GetBytes(tokens[1].Trim('"') + "\0");
|
||||
patches.Add((uint)offset, patch);
|
||||
}
|
||||
else
|
||||
|
@ -522,7 +522,7 @@ namespace Ryujinx.Ui.Widgets
|
||||
DirectoryInfo mainDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleIdText, "cache", "cpu", "1"));
|
||||
|
||||
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to delete the PPTC cache for :\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
||||
MessageDialog warningDialog = GtkDialog.CreateConfirmationDialog("Warning", $"You are about to queue a PPTC rebuild on the next boot of:\n\n<b>{_titleName}</b>\n\nAre you sure you want to proceed?");
|
||||
|
||||
List<FileInfo> cacheFiles = new List<FileInfo>();
|
||||
|
||||
|
@ -34,6 +34,7 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private long _systemTimeOffset;
|
||||
private float _previousVolumeLevel;
|
||||
private bool _directoryChanged = false;
|
||||
|
||||
#pragma warning disable CS0649, IDE0044
|
||||
[GUI] CheckButton _traceLogToggle;
|
||||
@ -501,14 +502,22 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
private void SaveSettings()
|
||||
{
|
||||
List<string> gameDirs = new List<string>();
|
||||
|
||||
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
|
||||
for (int i = 0; i < _gameDirsBoxStore.IterNChildren(); i++)
|
||||
if (_directoryChanged)
|
||||
{
|
||||
gameDirs.Add((string)_gameDirsBoxStore.GetValue(treeIter, 0));
|
||||
List<string> gameDirs = new List<string>();
|
||||
|
||||
_gameDirsBoxStore.IterNext(ref treeIter);
|
||||
_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter);
|
||||
|
||||
for (int i = 0; i < _gameDirsBoxStore.IterNChildren(); i++)
|
||||
{
|
||||
gameDirs.Add((string)_gameDirsBoxStore.GetValue(treeIter, 0));
|
||||
|
||||
_gameDirsBoxStore.IterNext(ref treeIter);
|
||||
}
|
||||
|
||||
ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs;
|
||||
|
||||
_directoryChanged = false;
|
||||
}
|
||||
|
||||
if (!float.TryParse(_resScaleText.Buffer.Text, out float resScaleCustom) || resScaleCustom <= 0.0f)
|
||||
@ -571,7 +580,6 @@ namespace Ryujinx.Ui.Windows
|
||||
ConfigurationState.Instance.System.SystemTimeOffset.Value = _systemTimeOffset;
|
||||
ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text;
|
||||
ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text;
|
||||
ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs;
|
||||
ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value;
|
||||
ConfigurationState.Instance.Graphics.MaxAnisotropy.Value = float.Parse(_anisotropy.ActiveId, CultureInfo.InvariantCulture);
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value = Enum.Parse<AspectRatio>(_aspectRatio.ActiveId);
|
||||
@ -655,27 +663,27 @@ namespace Ryujinx.Ui.Windows
|
||||
|
||||
if (fileChooser.Run() == (int)ResponseType.Accept)
|
||||
{
|
||||
_directoryChanged = false;
|
||||
foreach (string directory in fileChooser.Filenames)
|
||||
{
|
||||
bool directoryAdded = false;
|
||||
|
||||
if (_gameDirsBoxStore.GetIterFirst(out TreeIter treeIter))
|
||||
{
|
||||
do
|
||||
{
|
||||
if (directory.Equals((string)_gameDirsBoxStore.GetValue(treeIter, 0)))
|
||||
{
|
||||
directoryAdded = true;
|
||||
break;
|
||||
}
|
||||
} while(_gameDirsBoxStore.IterNext(ref treeIter));
|
||||
}
|
||||
|
||||
if (!directoryAdded)
|
||||
if (!_directoryChanged)
|
||||
{
|
||||
_gameDirsBoxStore.AppendValues(directory);
|
||||
}
|
||||
}
|
||||
|
||||
_directoryChanged = true;
|
||||
}
|
||||
|
||||
fileChooser.Dispose();
|
||||
@ -693,6 +701,8 @@ namespace Ryujinx.Ui.Windows
|
||||
if (selection.GetSelected(out TreeIter treeIter))
|
||||
{
|
||||
_gameDirsBoxStore.Remove(ref treeIter);
|
||||
|
||||
_directoryChanged = true;
|
||||
}
|
||||
|
||||
((ToggleButton)sender).SetStateFlags(StateFlags.Normal, true);
|
||||
|
Reference in New Issue
Block a user