Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
12c89a61f9 | ||
![]() |
f5235fff29 | ||
![]() |
eba682b767 | ||
![]() |
b994dafe7a | ||
![]() |
54421760c3 | ||
![]() |
88a0e720cb | ||
![]() |
53cc9e0561 | ||
![]() |
7defc59b9d |
@@ -58,7 +58,6 @@ namespace ARMeilleure.CodeGen.Linking
|
||||
/// <param name="a">First instance</param>
|
||||
/// <param name="b">Second instance</param>
|
||||
/// <returns><see langword="true"/> if not equal; otherwise <see langword="false"/></returns>
|
||||
/// <inheritdoc/>
|
||||
public static bool operator !=(Symbol a, Symbol b)
|
||||
{
|
||||
return !(a == b);
|
||||
|
@@ -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,
|
||||
|
@@ -206,7 +206,7 @@ namespace ARMeilleure.Common
|
||||
/// <typeparam name="T">Type of elements</typeparam>
|
||||
/// <param name="length">Number of elements</param>
|
||||
/// <param name="fill">Fill value</param>
|
||||
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword=""="false"/></param>
|
||||
/// <param name="leaf"><see langword="true"/> if leaf; otherwise <see langword="false"/></param>
|
||||
/// <returns>Allocated block</returns>
|
||||
private IntPtr Allocate<T>(int length, T fill, bool leaf) where T : unmanaged
|
||||
{
|
||||
|
@@ -9,6 +9,9 @@ namespace ARMeilleure.Common
|
||||
class Counter<T> : IDisposable where T : unmanaged
|
||||
{
|
||||
private bool _disposed;
|
||||
/// <summary>
|
||||
/// Index in the <see cref="EntryTable{T}"/>
|
||||
/// </summary>
|
||||
private readonly int _index;
|
||||
private readonly EntryTable<T> _countTable;
|
||||
|
||||
@@ -17,7 +20,6 @@ namespace ARMeilleure.Common
|
||||
/// <see cref="EntryTable{T}"/> instance and index.
|
||||
/// </summary>
|
||||
/// <param name="countTable"><see cref="EntryTable{T}"/> instance</param>
|
||||
/// <param name="index">Index in the <see cref="EntryTable{T}"/></param>
|
||||
/// <exception cref="ArgumentNullException"><paramref name="countTable"/> is <see langword="null"/></exception>
|
||||
/// <exception cref="ArgumentException"><typeparamref name="T"/> is unsupported</exception>
|
||||
public Counter(EntryTable<T> countTable)
|
||||
@@ -68,7 +70,7 @@ namespace ARMeilleure.Common
|
||||
/// <summary>
|
||||
/// Releases all unmanaged and optionally managed resources used by the <see cref="Counter{T}"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resouces</param>
|
||||
/// <param name="disposing"><see langword="true"/> to dispose managed resources also; otherwise just unmanaged resources</param>
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!_disposed)
|
||||
|
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)
|
||||
{
|
||||
|
@@ -344,7 +344,7 @@ namespace ARMeilleure.Translation
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the value from the dictionary after searching for it with <paramref name="key">.
|
||||
/// Removes the value from the dictionary after searching for it with <paramref name="key"/>.
|
||||
/// </summary>
|
||||
/// <param name="key">Key to search for</param>
|
||||
/// <returns>Number of deleted values</returns>
|
||||
|
@@ -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
|
||||
{
|
||||
|
@@ -52,8 +52,8 @@
|
||||
"GameListContextMenuOpenModsDirectory": "Open Mods Directory",
|
||||
"GameListContextMenuOpenModsDirectoryToolTip": "Opens the directory which contains Application's Mods",
|
||||
"GameListContextMenuCacheManagement": "Cache Management",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Purge PPTC Cache",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Deletes Application's PPTC cache",
|
||||
"GameListContextMenuCacheManagementPurgePptc": "Queue PPTC Rebuild",
|
||||
"GameListContextMenuCacheManagementPurgePptcToolTip": "Trigger PPTC to rebuild at boot time on the next game launch",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCache": "Purge Shader Cache",
|
||||
"GameListContextMenuCacheManagementPurgeShaderCacheToolTip": "Deletes Application's shader cache",
|
||||
"GameListContextMenuCacheManagementOpenPptcDirectory": "Open PPTC Directory",
|
||||
@@ -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)
|
||||
|
@@ -1317,10 +1317,12 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
for (int location = 0; location < attributeTypes.Length; location++)
|
||||
{
|
||||
attributeTypes[location] = vertexAttribState[location].UnpackType() switch
|
||||
VertexAttribType type = vertexAttribState[location].UnpackType();
|
||||
|
||||
attributeTypes[location] = type switch
|
||||
{
|
||||
3 => AttributeType.Sint,
|
||||
4 => AttributeType.Uint,
|
||||
VertexAttribType.Sint => AttributeType.Sint,
|
||||
VertexAttribType.Uint => AttributeType.Uint,
|
||||
_ => AttributeType.Float
|
||||
};
|
||||
}
|
||||
|
@@ -267,6 +267,41 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
#pragma warning restore CS0649
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex attribute vector and component size.
|
||||
/// </summary>
|
||||
enum VertexAttribSize
|
||||
{
|
||||
Size32x4 = 1,
|
||||
Size32x3 = 2,
|
||||
Size16x4 = 3,
|
||||
Size32x2 = 4,
|
||||
Size16x3 = 5,
|
||||
Size8x4 = 0xa,
|
||||
Size16x2 = 0xf,
|
||||
Size32 = 0x12,
|
||||
Size8x3 = 0x13,
|
||||
Size8x2 = 0x18,
|
||||
Size16 = 0x1b,
|
||||
Size8 = 0x1d,
|
||||
Rgb10A2 = 0x30,
|
||||
Rg11B10 = 0x31
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex attribute component type.
|
||||
/// </summary>
|
||||
enum VertexAttribType
|
||||
{
|
||||
Snorm = 1,
|
||||
Unorm = 2,
|
||||
Sint = 3,
|
||||
Uint = 4,
|
||||
Uscaled = 5,
|
||||
Sscaled = 6,
|
||||
Float = 7
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vertex buffer attribute state.
|
||||
/// </summary>
|
||||
@@ -312,13 +347,22 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
return Attribute & 0x3fe00000;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Unpacks the Maxwell attribute size.
|
||||
/// </summary>
|
||||
/// <returns>Attribute size</returns>
|
||||
public VertexAttribSize UnpackSize()
|
||||
{
|
||||
return (VertexAttribSize)((Attribute >> 21) & 0x3f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unpacks the Maxwell attribute component type.
|
||||
/// </summary>
|
||||
/// <returns>Attribute component type</returns>
|
||||
public uint UnpackType()
|
||||
public VertexAttribType UnpackType()
|
||||
{
|
||||
return (Attribute >> 27) & 7;
|
||||
return (VertexAttribType)((Attribute >> 27) & 7);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -82,7 +82,7 @@ namespace Ryujinx.Graphics.Gpu
|
||||
/// <summary>
|
||||
/// Host hardware capabilities.
|
||||
/// </summary>
|
||||
internal Capabilities Capabilities { get; private set; }
|
||||
internal Capabilities Capabilities;
|
||||
|
||||
/// <summary>
|
||||
/// Event for signalling shader cache loading progress.
|
||||
|
@@ -573,9 +573,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
RecompileGraphicsFromGuestCode(guestShaders, specState, programIndex);
|
||||
}
|
||||
}
|
||||
catch (DiskCacheLoadException diskCacheLoadException)
|
||||
catch (Exception exception)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Error translating guest shader. {diskCacheLoadException.Message}");
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Error translating guest shader. {exception.Message}");
|
||||
|
||||
ErrorCount++;
|
||||
SignalCompiled();
|
||||
|
@@ -27,7 +27,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
_stageIndex = stageIndex;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int QueryBindingConstantBuffer(int index)
|
||||
{
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
@@ -41,7 +40,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int QueryBindingStorageBuffer(int index)
|
||||
{
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
@@ -54,7 +52,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int QueryBindingTexture(int index, bool isBuffer)
|
||||
{
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
@@ -72,7 +69,6 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int QueryBindingImage(int index, bool isBuffer)
|
||||
{
|
||||
if (_context.Capabilities.Api == TargetApi.Vulkan)
|
||||
@@ -116,37 +112,26 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostHasFrontFacingBug() => _context.Capabilities.HasFrontFacingBug;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostHasVectorIndexingBug() => _context.Capabilities.HasVectorIndexingBug;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public int QueryHostStorageBufferOffsetAlignment() => _context.Capabilities.StorageBufferOffsetAlignment;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsBgraFormat() => _context.Capabilities.SupportsBgraFormat;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsFragmentShaderInterlock() => _context.Capabilities.SupportsFragmentShaderInterlock;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsFragmentShaderOrderingIntel() => _context.Capabilities.SupportsFragmentShaderOrderingIntel;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsGeometryShaderPassthrough() => _context.Capabilities.SupportsGeometryShaderPassthrough;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsImageLoadFormatted() => _context.Capabilities.SupportsImageLoadFormatted;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsNonConstantTextureOffset() => _context.Capabilities.SupportsNonConstantTextureOffset;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsShaderBallot() => _context.Capabilities.SupportsShaderBallot;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool QueryHostSupportsTextureShadowLod() => _context.Capabilities.SupportsTextureShadowLod;
|
||||
|
||||
/// <summary>
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using Ryujinx.Graphics.Shader.StructuredIr;
|
||||
using Ryujinx.Graphics.Shader.Translation;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Graphics.Shader
|
||||
{
|
||||
public enum AttributeType : byte
|
||||
{
|
||||
// Generic types.
|
||||
Float,
|
||||
Sint,
|
||||
Uint
|
||||
@@ -11,18 +14,7 @@ namespace Ryujinx.Graphics.Shader
|
||||
|
||||
static class AttributeTypeExtensions
|
||||
{
|
||||
public static string GetScalarType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => "float",
|
||||
AttributeType.Sint => "int",
|
||||
AttributeType.Uint => "uint",
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static string GetVec4Type(this AttributeType type)
|
||||
public static string ToVec4Type(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
@@ -32,5 +24,27 @@ namespace Ryujinx.Graphics.Shader
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static VariableType ToVariableType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => VariableType.F32,
|
||||
AttributeType.Sint => VariableType.S32,
|
||||
AttributeType.Uint => VariableType.U32,
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
|
||||
public static AggregateType ToAggregateType(this AttributeType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Float => AggregateType.FP32,
|
||||
AttributeType.Sint => AggregateType.S32,
|
||||
AttributeType.Uint => AggregateType.U32,
|
||||
_ => throw new ArgumentException($"Invalid attribute type \"{type}\".")
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@@ -553,11 +553,11 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
if (context.Config.Stage == ShaderStage.Vertex)
|
||||
{
|
||||
type = context.Config.GpuAccessor.QueryAttributeType(attr).GetVec4Type();
|
||||
type = context.Config.GpuAccessor.QueryAttributeType(attr).ToVec4Type();
|
||||
}
|
||||
else
|
||||
{
|
||||
type = AttributeType.Float.GetVec4Type();
|
||||
type = AttributeType.Float.ToVec4Type();
|
||||
}
|
||||
|
||||
context.AppendLine($"layout ({pass}location = {attr}) {iq}in {type} {name}{suffix};");
|
||||
|
@@ -454,12 +454,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
|
||||
|
||||
AttributeType type = context.Config.GpuAccessor.QueryAttributeType(location);
|
||||
|
||||
return type switch
|
||||
{
|
||||
AttributeType.Sint => VariableType.S32,
|
||||
AttributeType.Uint => VariableType.U32,
|
||||
_ => VariableType.F32
|
||||
};
|
||||
return type.ToVariableType();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -93,12 +93,7 @@ namespace Ryujinx.Graphics.Shader.Translation
|
||||
|
||||
if (config.Stage == ShaderStage.Vertex && !isOutAttr)
|
||||
{
|
||||
elemType = config.GpuAccessor.QueryAttributeType(location) switch
|
||||
{
|
||||
AttributeType.Sint => AggregateType.S32,
|
||||
AttributeType.Uint => AggregateType.U32,
|
||||
_ => AggregateType.FP32
|
||||
};
|
||||
elemType = config.GpuAccessor.QueryAttributeType(location).ToAggregateType();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -8,7 +8,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
class FormatCapabilities
|
||||
{
|
||||
private readonly FormatFeatureFlags[] _table;
|
||||
private readonly FormatFeatureFlags[] _bufferTable;
|
||||
private readonly FormatFeatureFlags[] _optimalTable;
|
||||
|
||||
private readonly Vk _api;
|
||||
private readonly PhysicalDevice _physicalDevice;
|
||||
@@ -17,14 +18,18 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
{
|
||||
_api = api;
|
||||
_physicalDevice = physicalDevice;
|
||||
_table = new FormatFeatureFlags[Enum.GetNames(typeof(GAL.Format)).Length];
|
||||
|
||||
int totalFormats = Enum.GetNames(typeof(GAL.Format)).Length;
|
||||
|
||||
_bufferTable = new FormatFeatureFlags[totalFormats];
|
||||
_optimalTable = new FormatFeatureFlags[totalFormats];
|
||||
}
|
||||
|
||||
public bool FormatsSupports(FormatFeatureFlags flags, params GAL.Format[] formats)
|
||||
public bool BufferFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
|
||||
{
|
||||
foreach (GAL.Format format in formats)
|
||||
{
|
||||
if (!FormatSupports(flags, format))
|
||||
if (!BufferFormatSupports(flags, format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -33,15 +38,42 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool FormatSupports(FormatFeatureFlags flags, GAL.Format format)
|
||||
public bool OptimalFormatsSupport(FormatFeatureFlags flags, params GAL.Format[] formats)
|
||||
{
|
||||
var formatFeatureFlags = _table[(int)format];
|
||||
foreach (GAL.Format format in formats)
|
||||
{
|
||||
if (!OptimalFormatSupports(flags, format))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool BufferFormatSupports(FormatFeatureFlags flags, GAL.Format format)
|
||||
{
|
||||
var formatFeatureFlags = _bufferTable[(int)format];
|
||||
|
||||
if (formatFeatureFlags == 0)
|
||||
{
|
||||
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
|
||||
formatFeatureFlags = fp.BufferFeatures;
|
||||
_bufferTable[(int)format] = formatFeatureFlags;
|
||||
}
|
||||
|
||||
return (formatFeatureFlags & flags) == flags;
|
||||
}
|
||||
|
||||
public bool OptimalFormatSupports(FormatFeatureFlags flags, GAL.Format format)
|
||||
{
|
||||
var formatFeatureFlags = _optimalTable[(int)format];
|
||||
|
||||
if (formatFeatureFlags == 0)
|
||||
{
|
||||
_api.GetPhysicalDeviceFormatProperties(_physicalDevice, FormatTable.GetFormat(format), out var fp);
|
||||
formatFeatureFlags = fp.OptimalTilingFeatures;
|
||||
_table[(int)format] = formatFeatureFlags;
|
||||
_optimalTable[(int)format] = formatFeatureFlags;
|
||||
}
|
||||
|
||||
return (formatFeatureFlags & flags) == flags;
|
||||
@@ -69,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
requiredFeatures |= FormatFeatureFlags.FormatFeatureStorageImageBit;
|
||||
}
|
||||
|
||||
if (!FormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
|
||||
if (!OptimalFormatSupports(requiredFeatures, srcFormat) || (IsD24S8(srcFormat) && VulkanConfiguration.ForceD24S8Unsupported))
|
||||
{
|
||||
// The format is not supported. Can we convert it to a higher precision format?
|
||||
if (IsD24S8(srcFormat))
|
||||
@@ -85,9 +117,44 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return format;
|
||||
}
|
||||
|
||||
public VkFormat ConvertToVertexVkFormat(GAL.Format srcFormat)
|
||||
{
|
||||
var format = FormatTable.GetFormat(srcFormat);
|
||||
|
||||
if (!BufferFormatSupports(FormatFeatureFlags.FormatFeatureVertexBufferBit, srcFormat) ||
|
||||
(IsRGB16IntFloat(srcFormat) && VulkanConfiguration.ForceRGB16IntFloatUnsupported))
|
||||
{
|
||||
// The format is not supported. Can we convert it to an alternative format?
|
||||
switch (srcFormat)
|
||||
{
|
||||
case GAL.Format.R16G16B16Float:
|
||||
format = VkFormat.R16G16B16A16Sfloat;
|
||||
break;
|
||||
case GAL.Format.R16G16B16Sint:
|
||||
format = VkFormat.R16G16B16A16Sint;
|
||||
break;
|
||||
case GAL.Format.R16G16B16Uint:
|
||||
format = VkFormat.R16G16B16A16Uint;
|
||||
break;
|
||||
default:
|
||||
Logger.Error?.Print(LogClass.Gpu, $"Format {srcFormat} is not supported by the host.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
public static bool IsD24S8(GAL.Format format)
|
||||
{
|
||||
return format == GAL.Format.D24UnormS8Uint || format == GAL.Format.S8UintD24Unorm;
|
||||
}
|
||||
|
||||
private static bool IsRGB16IntFloat(GAL.Format format)
|
||||
{
|
||||
return format == GAL.Format.R16G16B16Float ||
|
||||
format == GAL.Format.R16G16B16Sint ||
|
||||
format == GAL.Format.R16G16B16Uint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -730,6 +730,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
|
||||
{
|
||||
var formatCapabilities = Gd.FormatCapabilities;
|
||||
|
||||
int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
@@ -740,7 +742,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
_newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
||||
(uint)i,
|
||||
(uint)bufferIndex,
|
||||
FormatTable.GetFormat(attribute.Format),
|
||||
formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
||||
(uint)attribute.Offset);
|
||||
}
|
||||
|
||||
|
@@ -211,7 +211,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
pipeline.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
|
||||
(uint)i,
|
||||
(uint)bufferIndex,
|
||||
FormatTable.GetFormat(attribute.Format),
|
||||
gd.FormatCapabilities.ConvertToVertexVkFormat(attribute.Format),
|
||||
(uint)attribute.Offset);
|
||||
}
|
||||
|
||||
|
@@ -451,8 +451,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
return;
|
||||
}
|
||||
else if (_gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
|
||||
_gd.FormatCapabilities.FormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
|
||||
else if (_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitSrcBit, srcFormat) &&
|
||||
_gd.FormatCapabilities.OptimalFormatSupports(FormatFeatureFlags.FormatFeatureBlitDstBit, dstFormat))
|
||||
{
|
||||
TextureCopy.Blit(
|
||||
_gd.Api,
|
||||
@@ -761,8 +761,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private bool SupportsBlitFromD32FS8ToD32FAndS8()
|
||||
{
|
||||
var formatFeatureFlags = FormatFeatureFlags.FormatFeatureBlitSrcBit | FormatFeatureFlags.FormatFeatureBlitDstBit;
|
||||
return _gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
|
||||
_gd.FormatCapabilities.FormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
|
||||
return _gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.D32Float) &&
|
||||
_gd.FormatCapabilities.OptimalFormatSupports(formatFeatureFlags, GAL.Format.S8Uint);
|
||||
}
|
||||
|
||||
public TextureView GetView(GAL.Format format)
|
||||
|
@@ -7,5 +7,6 @@
|
||||
public const bool UsePushDescriptors = false;
|
||||
|
||||
public const bool ForceD24S8Unsupported = false;
|
||||
public const bool ForceRGB16IntFloatUnsupported = false;
|
||||
}
|
||||
}
|
||||
|
@@ -377,7 +377,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
FormatFeatureFlags.FormatFeatureTransferSrcBit |
|
||||
FormatFeatureFlags.FormatFeatureTransferDstBit;
|
||||
|
||||
bool supportsBc123CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
bool supportsBc123CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc1RgbaSrgb,
|
||||
GAL.Format.Bc1RgbaUnorm,
|
||||
GAL.Format.Bc2Srgb,
|
||||
@@ -385,13 +385,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
GAL.Format.Bc3Srgb,
|
||||
GAL.Format.Bc3Unorm);
|
||||
|
||||
bool supportsBc45CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
bool supportsBc45CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc4Snorm,
|
||||
GAL.Format.Bc4Unorm,
|
||||
GAL.Format.Bc5Snorm,
|
||||
GAL.Format.Bc5Unorm);
|
||||
|
||||
bool supportsBc67CompressionFormat = FormatCapabilities.FormatsSupports(compressedFormatFeatureFlags,
|
||||
bool supportsBc67CompressionFormat = FormatCapabilities.OptimalFormatsSupport(compressedFormatFeatureFlags,
|
||||
GAL.Format.Bc6HSfloat,
|
||||
GAL.Format.Bc6HUfloat,
|
||||
GAL.Format.Bc7Srgb,
|
||||
|
@@ -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
|
||||
|
@@ -154,9 +154,9 @@ namespace Ryujinx.Ui.Widgets
|
||||
//
|
||||
// _purgePtcCacheMenuItem
|
||||
//
|
||||
_purgePtcCacheMenuItem = new MenuItem("Purge PPTC Cache")
|
||||
_purgePtcCacheMenuItem = new MenuItem("Queue PPTC Rebuild")
|
||||
{
|
||||
TooltipText = "Delete the Application's PPTC cache."
|
||||
TooltipText = "Trigger PPTC to rebuild at boot time on the next game launch."
|
||||
};
|
||||
_purgePtcCacheMenuItem.Activated += PurgePtcCache_Clicked;
|
||||
|
||||
|
@@ -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