Merge branch 'master' into pptc_and_pool_enhancements
This commit is contained in:
commit
defdda7f23
10 changed files with 148 additions and 126 deletions
|
@ -19,19 +19,8 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
if (size == 4)
|
if (size == 4)
|
||||||
{
|
{
|
||||||
Operand isUnalignedAddr = InstEmitMemoryHelper.EmitAddressCheck(context, address, size);
|
|
||||||
|
|
||||||
Operand lblFastPath = Label();
|
|
||||||
|
|
||||||
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
// The call is not expected to return (it should throw).
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
|
|
||||||
|
|
||||||
context.MarkLabel(lblFastPath);
|
|
||||||
|
|
||||||
// Only 128-bit CAS is guaranteed to have a atomic load.
|
// Only 128-bit CAS is guaranteed to have a atomic load.
|
||||||
Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: false);
|
Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: false, 4);
|
||||||
|
|
||||||
Operand zero = context.VectorZero();
|
Operand zero = context.VectorZero();
|
||||||
|
|
||||||
|
@ -119,20 +108,8 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
context.BranchIfTrue(lblExit, exFailed);
|
context.BranchIfTrue(lblExit, exFailed);
|
||||||
|
|
||||||
// STEP 2: We have exclusive access, make sure that the address is valid.
|
// STEP 2: We have exclusive access and the address is valid, attempt the store using CAS.
|
||||||
Operand isUnalignedAddr = InstEmitMemoryHelper.EmitAddressCheck(context, address, size);
|
Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true, size);
|
||||||
|
|
||||||
Operand lblFastPath = Label();
|
|
||||||
|
|
||||||
context.BranchIfFalse(lblFastPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
// The call is not expected to return (it should throw).
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
|
|
||||||
|
|
||||||
// STEP 3: We have exclusive access and the address is valid, attempt the store using CAS.
|
|
||||||
context.MarkLabel(lblFastPath);
|
|
||||||
|
|
||||||
Operand physAddr = InstEmitMemoryHelper.EmitPtPointerLoad(context, address, null, write: true);
|
|
||||||
|
|
||||||
Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset()));
|
Operand exValuePtr = context.Add(arg0, Const((long)NativeContext.GetExclusiveValueOffset()));
|
||||||
Operand exValue = size switch
|
Operand exValue = size switch
|
||||||
|
@ -151,7 +128,7 @@ namespace ARMeilleure.Instructions
|
||||||
_ => context.CompareAndSwap(physAddr, exValue, value)
|
_ => context.CompareAndSwap(physAddr, exValue, value)
|
||||||
};
|
};
|
||||||
|
|
||||||
// STEP 4: Check if we succeeded by comparing expected and in-memory values.
|
// STEP 3: Check if we succeeded by comparing expected and in-memory values.
|
||||||
Operand storeFailed;
|
Operand storeFailed;
|
||||||
|
|
||||||
if (size == 4)
|
if (size == 4)
|
||||||
|
|
|
@ -127,11 +127,7 @@ namespace ARMeilleure.Instructions
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
|
||||||
|
|
||||||
context.BranchIfTrue(lblSlowPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false);
|
|
||||||
|
|
||||||
Operand value = null;
|
Operand value = null;
|
||||||
|
|
||||||
|
@ -161,18 +157,7 @@ namespace ARMeilleure.Instructions
|
||||||
throw new ArgumentOutOfRangeException(nameof(size));
|
throw new ArgumentOutOfRangeException(nameof(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, null, write: false, size);
|
||||||
|
|
||||||
Operand lblFastPath = Label();
|
|
||||||
|
|
||||||
context.BranchIfFalse(lblFastPath, isUnalignedAddr, BasicBlockFrequency.Cold);
|
|
||||||
|
|
||||||
// The call is not expected to return (it should throw).
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
|
|
||||||
|
|
||||||
context.MarkLabel(lblFastPath);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, null, write: false);
|
|
||||||
|
|
||||||
return size switch
|
return size switch
|
||||||
{
|
{
|
||||||
|
@ -195,11 +180,7 @@ namespace ARMeilleure.Instructions
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false, size);
|
||||||
|
|
||||||
context.BranchIfTrue(lblSlowPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: false);
|
|
||||||
|
|
||||||
Operand value = null;
|
Operand value = null;
|
||||||
|
|
||||||
|
@ -233,11 +214,7 @@ namespace ARMeilleure.Instructions
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true, size);
|
||||||
|
|
||||||
context.BranchIfTrue(lblSlowPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true);
|
|
||||||
|
|
||||||
Operand value = GetInt(context, rt);
|
Operand value = GetInt(context, rt);
|
||||||
|
|
||||||
|
@ -270,18 +247,7 @@ namespace ARMeilleure.Instructions
|
||||||
throw new ArgumentOutOfRangeException(nameof(size));
|
throw new ArgumentOutOfRangeException(nameof(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, null, write: true, size);
|
||||||
|
|
||||||
Operand lblFastPath = Label();
|
|
||||||
|
|
||||||
context.BranchIfFalse(lblFastPath, isUnalignedAddr, BasicBlockFrequency.Cold);
|
|
||||||
|
|
||||||
// The call is not expected to return (it should throw).
|
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.ThrowInvalidMemoryAccess)), address);
|
|
||||||
|
|
||||||
context.MarkLabel(lblFastPath);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, null, write: true);
|
|
||||||
|
|
||||||
if (size < 3 && value.Type == OperandType.I64)
|
if (size < 3 && value.Type == OperandType.I64)
|
||||||
{
|
{
|
||||||
|
@ -312,11 +278,7 @@ namespace ARMeilleure.Instructions
|
||||||
Operand lblSlowPath = Label();
|
Operand lblSlowPath = Label();
|
||||||
Operand lblEnd = Label();
|
Operand lblEnd = Label();
|
||||||
|
|
||||||
Operand isUnalignedAddr = EmitAddressCheck(context, address, size);
|
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true, size);
|
||||||
|
|
||||||
context.BranchIfTrue(lblSlowPath, isUnalignedAddr);
|
|
||||||
|
|
||||||
Operand physAddr = EmitPtPointerLoad(context, address, lblSlowPath, write: true);
|
|
||||||
|
|
||||||
Operand value = GetVec(rt);
|
Operand value = GetVec(rt);
|
||||||
|
|
||||||
|
@ -338,61 +300,49 @@ namespace ARMeilleure.Instructions
|
||||||
context.MarkLabel(lblEnd);
|
context.MarkLabel(lblEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Operand EmitAddressCheck(ArmEmitterContext context, Operand address, int size)
|
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write, int size)
|
||||||
{
|
{
|
||||||
ulong addressCheckMask = ~((1UL << context.Memory.AddressSpaceBits) - 1);
|
int ptLevelBits = context.Memory.AddressSpaceBits - PageBits;
|
||||||
|
|
||||||
addressCheckMask |= (1u << size) - 1;
|
|
||||||
|
|
||||||
return context.BitwiseAnd(address, Const(address.Type, (long)addressCheckMask));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Operand EmitPtPointerLoad(ArmEmitterContext context, Operand address, Operand lblSlowPath, bool write)
|
|
||||||
{
|
|
||||||
int ptLevelBits = context.Memory.AddressSpaceBits - 12; // 12 = Number of page bits.
|
|
||||||
int ptLevelSize = 1 << ptLevelBits;
|
int ptLevelSize = 1 << ptLevelBits;
|
||||||
int ptLevelMask = ptLevelSize - 1;
|
int ptLevelMask = ptLevelSize - 1;
|
||||||
|
|
||||||
|
Operand addrRotated = size != 0 ? context.RotateRight(address, Const(size)) : address;
|
||||||
|
Operand addrShifted = context.ShiftRightUI(addrRotated, Const(PageBits - size));
|
||||||
|
|
||||||
Operand pte = Ptc.State == PtcState.Disabled
|
Operand pte = Ptc.State == PtcState.Disabled
|
||||||
? Const(context.Memory.PageTablePointer.ToInt64())
|
? Const(context.Memory.PageTablePointer.ToInt64())
|
||||||
: Const(context.Memory.PageTablePointer.ToInt64(), true, Ptc.PageTablePointerIndex);
|
: Const(context.Memory.PageTablePointer.ToInt64(), true, Ptc.PageTablePointerIndex);
|
||||||
|
|
||||||
int bit = PageBits;
|
Operand pteOffset = context.BitwiseAnd(addrShifted, Const(addrShifted.Type, ptLevelMask));
|
||||||
|
|
||||||
// Load page table entry from the page table.
|
|
||||||
// This was designed to support multi-level page tables of any size, however right
|
|
||||||
// now we only use flat page tables (so there's only one level).
|
|
||||||
// The page table entry contains the host address where the page is located.
|
|
||||||
// Additionally, the higher 16-bits of the host address may contain extra information
|
|
||||||
// used for write tracking, so this must be handled here aswell.
|
|
||||||
do
|
|
||||||
{
|
|
||||||
Operand addrPart = context.ShiftRightUI(address, Const(bit));
|
|
||||||
|
|
||||||
bit += ptLevelBits;
|
|
||||||
|
|
||||||
if (bit < context.Memory.AddressSpaceBits)
|
|
||||||
{
|
|
||||||
addrPart = context.BitwiseAnd(addrPart, Const(addrPart.Type, ptLevelMask));
|
|
||||||
}
|
|
||||||
|
|
||||||
Operand pteOffset = context.ShiftLeft(addrPart, Const(3));
|
|
||||||
|
|
||||||
if (pteOffset.Type == OperandType.I32)
|
if (pteOffset.Type == OperandType.I32)
|
||||||
{
|
{
|
||||||
pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset);
|
pteOffset = context.ZeroExtend32(OperandType.I64, pteOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
Operand pteAddress = context.Add(pte, pteOffset);
|
pte = context.Load(OperandType.I64, context.Add(pte, context.ShiftLeft(pteOffset, Const(3))));
|
||||||
|
|
||||||
pte = context.Load(OperandType.I64, pteAddress);
|
if (addrShifted.Type == OperandType.I32)
|
||||||
|
{
|
||||||
|
addrShifted = context.ZeroExtend32(OperandType.I64, addrShifted);
|
||||||
}
|
}
|
||||||
while (bit < context.Memory.AddressSpaceBits);
|
|
||||||
|
// If the VA is out of range, or not aligned to the access size, force PTE to 0 by masking it.
|
||||||
|
pte = context.BitwiseAnd(pte, context.ShiftRightSI(context.Add(addrShifted, Const(-(long)ptLevelSize)), Const(63)));
|
||||||
|
|
||||||
if (lblSlowPath != null)
|
if (lblSlowPath != null)
|
||||||
{
|
{
|
||||||
ulong protection = (write ? 3UL : 1UL) << 48;
|
if (write)
|
||||||
context.BranchIfTrue(lblSlowPath, context.BitwiseAnd(pte, Const(protection)));
|
{
|
||||||
|
pte = context.ShiftLeft(pte, Const(1));
|
||||||
|
context.BranchIf(lblSlowPath, pte, Const(0L), Comparison.LessOrEqual);
|
||||||
|
pte = context.ShiftRightUI(pte, Const(1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.BranchIf(lblSlowPath, pte, Const(0L), Comparison.LessOrEqual);
|
||||||
|
pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -401,13 +351,15 @@ namespace ARMeilleure.Instructions
|
||||||
|
|
||||||
Operand lblNotWatched = Label();
|
Operand lblNotWatched = Label();
|
||||||
|
|
||||||
// Is the page currently being tracked for read/write? If so we need to call MarkRegionAsModified.
|
// Is the page currently being tracked for read/write? If so we need to call SignalMemoryTracking.
|
||||||
context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual, BasicBlockFrequency.Cold);
|
context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual, BasicBlockFrequency.Cold);
|
||||||
|
|
||||||
// Mark the region as modified. Size here doesn't matter as address is assumed to be size aligned here.
|
// Signal memory tracking. Size here doesn't matter as address is assumed to be size aligned here.
|
||||||
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
|
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.SignalMemoryTracking)), address, Const(1UL), Const(write ? 1 : 0));
|
||||||
context.MarkLabel(lblNotWatched);
|
context.MarkLabel(lblNotWatched);
|
||||||
|
|
||||||
|
pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by C# memory access)
|
||||||
|
|
||||||
Operand lblNonNull = Label();
|
Operand lblNonNull = Label();
|
||||||
|
|
||||||
// Skip exception if the PTE address is non-null (not zero).
|
// Skip exception if the PTE address is non-null (not zero).
|
||||||
|
@ -418,8 +370,6 @@ namespace ARMeilleure.Instructions
|
||||||
context.MarkLabel(lblNonNull);
|
context.MarkLabel(lblNonNull);
|
||||||
}
|
}
|
||||||
|
|
||||||
pte = context.BitwiseAnd(pte, Const(0xffffffffffffUL)); // Ignore any software protection bits. (they are still used by c# memory access)
|
|
||||||
|
|
||||||
Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, PageMask));
|
Operand pageOffset = context.BitwiseAnd(address, Const(address.Type, PageMask));
|
||||||
|
|
||||||
if (pageOffset.Type == OperandType.I32)
|
if (pageOffset.Type == OperandType.I32)
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace Ryujinx.Configuration
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 20;
|
public const int CurrentVersion = 22;
|
||||||
|
|
||||||
public int Version { get; set; }
|
public int Version { get; set; }
|
||||||
|
|
||||||
|
@ -133,6 +133,11 @@ namespace Ryujinx.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool ShowConfirmExit { get; set; }
|
public bool ShowConfirmExit { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide Cursor on Idle
|
||||||
|
/// </summary>
|
||||||
|
public bool HideCursorOnIdle { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables Vertical Sync
|
/// Enables or disables Vertical Sync
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -365,6 +365,11 @@ namespace Ryujinx.Configuration
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide Cursor on Idle
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> HideCursorOnIdle { get; private set; }
|
||||||
|
|
||||||
private ConfigurationState()
|
private ConfigurationState()
|
||||||
{
|
{
|
||||||
Ui = new UiSection();
|
Ui = new UiSection();
|
||||||
|
@ -375,6 +380,7 @@ namespace Ryujinx.Configuration
|
||||||
EnableDiscordIntegration = new ReactiveObject<bool>();
|
EnableDiscordIntegration = new ReactiveObject<bool>();
|
||||||
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
||||||
ShowConfirmExit = new ReactiveObject<bool>();
|
ShowConfirmExit = new ReactiveObject<bool>();
|
||||||
|
HideCursorOnIdle = new ReactiveObject<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationFileFormat ToFileFormat()
|
public ConfigurationFileFormat ToFileFormat()
|
||||||
|
@ -420,6 +426,7 @@ namespace Ryujinx.Configuration
|
||||||
EnableDiscordIntegration = EnableDiscordIntegration,
|
EnableDiscordIntegration = EnableDiscordIntegration,
|
||||||
CheckUpdatesOnStart = CheckUpdatesOnStart,
|
CheckUpdatesOnStart = CheckUpdatesOnStart,
|
||||||
ShowConfirmExit = ShowConfirmExit,
|
ShowConfirmExit = ShowConfirmExit,
|
||||||
|
HideCursorOnIdle = HideCursorOnIdle,
|
||||||
EnableVsync = Graphics.EnableVsync,
|
EnableVsync = Graphics.EnableVsync,
|
||||||
EnableShaderCache = Graphics.EnableShaderCache,
|
EnableShaderCache = Graphics.EnableShaderCache,
|
||||||
EnablePtc = System.EnablePtc,
|
EnablePtc = System.EnablePtc,
|
||||||
|
@ -483,6 +490,7 @@ namespace Ryujinx.Configuration
|
||||||
EnableDiscordIntegration.Value = true;
|
EnableDiscordIntegration.Value = true;
|
||||||
CheckUpdatesOnStart.Value = true;
|
CheckUpdatesOnStart.Value = true;
|
||||||
ShowConfirmExit.Value = true;
|
ShowConfirmExit.Value = true;
|
||||||
|
HideCursorOnIdle.Value = false;
|
||||||
Graphics.EnableVsync.Value = true;
|
Graphics.EnableVsync.Value = true;
|
||||||
Graphics.EnableShaderCache.Value = true;
|
Graphics.EnableShaderCache.Value = true;
|
||||||
System.EnablePtc.Value = true;
|
System.EnablePtc.Value = true;
|
||||||
|
@ -787,6 +795,15 @@ namespace Ryujinx.Configuration
|
||||||
configurationFileUpdated = true;
|
configurationFileUpdated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 22)
|
||||||
|
{
|
||||||
|
Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");
|
||||||
|
|
||||||
|
configurationFileFormat.HideCursorOnIdle = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
List<InputConfig> inputConfig = new List<InputConfig>();
|
List<InputConfig> inputConfig = new List<InputConfig>();
|
||||||
inputConfig.AddRange(configurationFileFormat.ControllerConfig);
|
inputConfig.AddRange(configurationFileFormat.ControllerConfig);
|
||||||
inputConfig.AddRange(configurationFileFormat.KeyboardConfig);
|
inputConfig.AddRange(configurationFileFormat.KeyboardConfig);
|
||||||
|
@ -814,6 +831,7 @@ namespace Ryujinx.Configuration
|
||||||
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
||||||
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
|
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
|
||||||
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
|
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
|
||||||
|
HideCursorOnIdle.Value = configurationFileFormat.HideCursorOnIdle;
|
||||||
Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
|
Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
|
||||||
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
||||||
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
|
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Ryujinx.Cpu
|
||||||
|
|
||||||
private const int PteSize = 8;
|
private const int PteSize = 8;
|
||||||
|
|
||||||
|
private const int PointerTagBit = 62;
|
||||||
|
|
||||||
private readonly InvalidAccessHandler _invalidAccessHandler;
|
private readonly InvalidAccessHandler _invalidAccessHandler;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -556,11 +558,12 @@ namespace Ryujinx.Cpu
|
||||||
// Protection is inverted on software pages, since the default value is 0.
|
// Protection is inverted on software pages, since the default value is 0.
|
||||||
protection = (~protection) & MemoryPermission.ReadAndWrite;
|
protection = (~protection) & MemoryPermission.ReadAndWrite;
|
||||||
|
|
||||||
long tag = (long)protection << 48;
|
long tag = protection switch
|
||||||
if (tag > 0)
|
|
||||||
{
|
{
|
||||||
tag |= long.MinValue; // If any protection is present, the whole pte is negative.
|
MemoryPermission.None => 0L,
|
||||||
}
|
MemoryPermission.Read => 2L << PointerTagBit,
|
||||||
|
_ => 3L << PointerTagBit
|
||||||
|
};
|
||||||
|
|
||||||
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
||||||
long invTagMask = ~(0xffffL << 48);
|
long invTagMask = ~(0xffffL << 48);
|
||||||
|
@ -628,7 +631,7 @@ namespace Ryujinx.Cpu
|
||||||
// tracking using host guard pages in future, but also supporting platforms where this is not possible.
|
// tracking using host guard pages in future, but also supporting platforms where this is not possible.
|
||||||
|
|
||||||
// Write tag includes read protection, since we don't have any read actions that aren't performed before write too.
|
// Write tag includes read protection, since we don't have any read actions that aren't performed before write too.
|
||||||
long tag = (write ? 3L : 1L) << 48;
|
long tag = (write ? 3L : 2L) << PointerTagBit;
|
||||||
|
|
||||||
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
ulong endVa = (va + size + PageMask) & ~(ulong)PageMask;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"version": 20,
|
"version": 22,
|
||||||
"res_scale": 1,
|
"res_scale": 1,
|
||||||
"res_scale_custom": 1,
|
"res_scale_custom": 1,
|
||||||
"max_anisotropy": -1,
|
"max_anisotropy": -1,
|
||||||
|
@ -22,6 +22,7 @@
|
||||||
"enable_discord_integration": true,
|
"enable_discord_integration": true,
|
||||||
"check_updates_on_start": true,
|
"check_updates_on_start": true,
|
||||||
"show_confirm_exit": true,
|
"show_confirm_exit": true,
|
||||||
|
"hide_cursor_on_idle": false,
|
||||||
"enable_vsync": true,
|
"enable_vsync": true,
|
||||||
"enable_shader_cache": true,
|
"enable_shader_cache": true,
|
||||||
"enable_ptc": true,
|
"enable_ptc": true,
|
||||||
|
|
|
@ -42,6 +42,8 @@ namespace Ryujinx.Ui
|
||||||
private double _mouseY;
|
private double _mouseY;
|
||||||
private bool _mousePressed;
|
private bool _mousePressed;
|
||||||
|
|
||||||
|
private DateTime _lastCursorMoveTime = DateTime.Now;
|
||||||
|
|
||||||
private bool _toggleFullscreen;
|
private bool _toggleFullscreen;
|
||||||
private bool _toggleDockedMode;
|
private bool _toggleDockedMode;
|
||||||
|
|
||||||
|
@ -63,6 +65,8 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
private readonly ManualResetEvent _exitEvent;
|
private readonly ManualResetEvent _exitEvent;
|
||||||
|
|
||||||
|
private Gdk.Cursor _invisibleCursor = new Gdk.Cursor (Gdk.Display.Default, Gdk.CursorType.BlankCursor);
|
||||||
|
|
||||||
public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel)
|
public GlRenderer(Switch device, GraphicsDebugLevel glLogLevel)
|
||||||
: base (GetGraphicsMode(),
|
: base (GetGraphicsMode(),
|
||||||
3, 3,
|
3, 3,
|
||||||
|
@ -304,9 +308,37 @@ namespace Ryujinx.Ui
|
||||||
_mouseY = evnt.Y;
|
_mouseY = evnt.Y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResetCursorIdle();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ResetCursorIdle()
|
||||||
|
{
|
||||||
|
if (ConfigurationState.Instance.HideCursorOnIdle)
|
||||||
|
{
|
||||||
|
_lastCursorMoveTime = DateTime.Now;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Window.Cursor != null)
|
||||||
|
{
|
||||||
|
Window.Cursor = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HideCursorIdle()
|
||||||
|
{
|
||||||
|
if (ConfigurationState.Instance.HideCursorOnIdle)
|
||||||
|
{
|
||||||
|
TimeSpan elapsedTime = DateTime.Now.Subtract(_lastCursorMoveTime);
|
||||||
|
|
||||||
|
if (elapsedTime.TotalSeconds > 8)
|
||||||
|
{
|
||||||
|
Gtk.Application.Invoke(delegate { Window.Cursor = _invisibleCursor; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnGetPreferredHeight(out int minimumHeight, out int naturalHeight)
|
protected override void OnGetPreferredHeight(out int minimumHeight, out int naturalHeight)
|
||||||
{
|
{
|
||||||
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
|
Gdk.Monitor monitor = Display.GetMonitorAtWindow(Window);
|
||||||
|
@ -485,6 +517,8 @@ namespace Ryujinx.Ui
|
||||||
|
|
||||||
MotionDevice motionDevice = new MotionDevice(_dsuClient);
|
MotionDevice motionDevice = new MotionDevice(_dsuClient);
|
||||||
|
|
||||||
|
HideCursorIdle();
|
||||||
|
|
||||||
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
|
foreach (InputConfig inputConfig in ConfigurationState.Instance.Hid.InputConfig.Value)
|
||||||
{
|
{
|
||||||
ControllerKeys currentButton = 0;
|
ControllerKeys currentButton = 0;
|
||||||
|
|
|
@ -43,6 +43,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
[GUI] CheckButton _discordToggle;
|
[GUI] CheckButton _discordToggle;
|
||||||
[GUI] CheckButton _checkUpdatesToggle;
|
[GUI] CheckButton _checkUpdatesToggle;
|
||||||
[GUI] CheckButton _showConfirmExitToggle;
|
[GUI] CheckButton _showConfirmExitToggle;
|
||||||
|
[GUI] CheckButton _hideCursorOnIdleToggle;
|
||||||
[GUI] CheckButton _vSyncToggle;
|
[GUI] CheckButton _vSyncToggle;
|
||||||
[GUI] CheckButton _shaderCacheToggle;
|
[GUI] CheckButton _shaderCacheToggle;
|
||||||
[GUI] CheckButton _ptcToggle;
|
[GUI] CheckButton _ptcToggle;
|
||||||
|
@ -185,6 +186,11 @@ namespace Ryujinx.Ui.Windows
|
||||||
_showConfirmExitToggle.Click();
|
_showConfirmExitToggle.Click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ConfigurationState.Instance.HideCursorOnIdle)
|
||||||
|
{
|
||||||
|
_hideCursorOnIdleToggle.Click();
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.Graphics.EnableVsync)
|
if (ConfigurationState.Instance.Graphics.EnableVsync)
|
||||||
{
|
{
|
||||||
_vSyncToggle.Click();
|
_vSyncToggle.Click();
|
||||||
|
@ -403,6 +409,7 @@ namespace Ryujinx.Ui.Windows
|
||||||
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
|
ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active;
|
||||||
ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active;
|
ConfigurationState.Instance.CheckUpdatesOnStart.Value = _checkUpdatesToggle.Active;
|
||||||
ConfigurationState.Instance.ShowConfirmExit.Value = _showConfirmExitToggle.Active;
|
ConfigurationState.Instance.ShowConfirmExit.Value = _showConfirmExitToggle.Active;
|
||||||
|
ConfigurationState.Instance.HideCursorOnIdle.Value = _hideCursorOnIdleToggle.Active;
|
||||||
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active;
|
||||||
ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active;
|
ConfigurationState.Instance.Graphics.EnableShaderCache.Value = _shaderCacheToggle.Active;
|
||||||
ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
|
ConfigurationState.Instance.System.EnablePtc.Value = _ptcToggle.Active;
|
||||||
|
|
|
@ -150,7 +150,23 @@
|
||||||
<property name="expand">False</property>
|
<property name="expand">False</property>
|
||||||
<property name="fill">True</property>
|
<property name="fill">True</property>
|
||||||
<property name="padding">5</property>
|
<property name="padding">5</property>
|
||||||
<property name="position">1</property>
|
<property name="position">2</property>
|
||||||
|
</packing>
|
||||||
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkCheckButton" id="_hideCursorOnIdleToggle">
|
||||||
|
<property name="label" translatable="yes">Hide Cursor On Idle</property>
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">False</property>
|
||||||
|
<property name="halign">start</property>
|
||||||
|
<property name="draw-indicator">True</property>
|
||||||
|
</object>
|
||||||
|
<packing>
|
||||||
|
<property name="expand">False</property>
|
||||||
|
<property name="fill">True</property>
|
||||||
|
<property name="padding">5</property>
|
||||||
|
<property name="position">3</property>
|
||||||
</packing>
|
</packing>
|
||||||
</child>
|
</child>
|
||||||
</object>
|
</object>
|
||||||
|
|
|
@ -1209,6 +1209,17 @@
|
||||||
true,
|
true,
|
||||||
false
|
false
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"hide_cursor_on_idle": {
|
||||||
|
"$id": "#/properties/hide_cursor_on_idle",
|
||||||
|
"type": "boolean",
|
||||||
|
"title": "Hide Cursor On Idle",
|
||||||
|
"description": "Hides the cursor after being idle for 5 seconds",
|
||||||
|
"default": false,
|
||||||
|
"examples": [
|
||||||
|
true,
|
||||||
|
false
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"enable_vsync": {
|
"enable_vsync": {
|
||||||
"$id": "#/properties/enable_vsync",
|
"$id": "#/properties/enable_vsync",
|
||||||
|
|
Loading…
Reference in a new issue