mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-05-23 05:35:47 +00:00
Compare commits
5 Commits
Canary-1.3
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4631e0a9e1 | ||
|
|
e477ec7149 | ||
|
|
81468c1d25 | ||
|
|
004a12005e | ||
|
|
a3eda287b5 |
@@ -28,7 +28,7 @@ jobs:
|
|||||||
configuration: [Release]
|
configuration: [Release]
|
||||||
platform:
|
platform:
|
||||||
- { name: win-x64, zip_os_name: win_x64 }
|
- { name: win-x64, zip_os_name: win_x64 }
|
||||||
#- { name: win-arm64, zip_os_name: win_arm64 }
|
- { name: win-arm64, zip_os_name: win_arm64 }
|
||||||
- { name: linux-x64, zip_os_name: linux_x64 }
|
- { name: linux-x64, zip_os_name: linux_x64 }
|
||||||
- { name: linux-arm64, zip_os_name: linux_arm64 }
|
- { name: linux-arm64, zip_os_name: linux_arm64 }
|
||||||
#- { name: osx-x64, zip_os_name: osx_x64 }
|
#- { name: osx-x64, zip_os_name: osx_x64 }
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
||||||
#- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
||||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
platform:
|
platform:
|
||||||
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
- { name: win-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_x64 }
|
||||||
#- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
- { name: win-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: win_arm64 }
|
||||||
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
- { name: linux-x64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_x64 }
|
||||||
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
- { name: linux-arm64, os: ghcr.io/catthehacker/ubuntu:act-latest, zip_os_name: linux_arm64 }
|
||||||
steps:
|
steps:
|
||||||
|
|||||||
@@ -200,6 +200,31 @@
|
|||||||
"zh_TW": "使用 Hypervisor"
|
"zh_TW": "使用 Hypervisor"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "SettingsTabSystemGCLowLatency",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Use Low-latency Garbage Collector",
|
||||||
|
"es_ES": "Usa recolección de basura de baja latencia",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "MenuBarFile",
|
"ID": "MenuBarFile",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
@@ -16550,6 +16575,31 @@
|
|||||||
"zh_TW": "變更客體記憶體的映射和存取方式。這會極大地影響模擬 CPU 效能。\n\n如果不確定,請設定為主體略過檢查模式。"
|
"zh_TW": "變更客體記憶體的映射和存取方式。這會極大地影響模擬 CPU 效能。\n\n如果不確定,請設定為主體略過檢查模式。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"ID": "GCLowLatencyTooltip",
|
||||||
|
"Translations": {
|
||||||
|
"ar_SA": "",
|
||||||
|
"de_DE": "",
|
||||||
|
"el_GR": "",
|
||||||
|
"en_US": "Sets the garbage collector for the CLR to low-latency mode.\n\nThis may decrease stuttering at the cost of performance.\n\nLeave OFF if unsure.",
|
||||||
|
"es_ES": "",
|
||||||
|
"fr_FR": "",
|
||||||
|
"he_IL": "",
|
||||||
|
"it_IT": "",
|
||||||
|
"ja_JP": "",
|
||||||
|
"ko_KR": "",
|
||||||
|
"no_NO": "",
|
||||||
|
"pl_PL": "",
|
||||||
|
"pt_BR": "",
|
||||||
|
"ru_RU": "",
|
||||||
|
"sv_SE": "",
|
||||||
|
"th_TH": "",
|
||||||
|
"tr_TR": "",
|
||||||
|
"uk_UA": "",
|
||||||
|
"zh_CN": "",
|
||||||
|
"zh_TW": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"ID": "MemoryManagerSoftwareTooltip",
|
"ID": "MemoryManagerSoftwareTooltip",
|
||||||
"Translations": {
|
"Translations": {
|
||||||
|
|||||||
@@ -133,9 +133,9 @@ namespace Ryujinx.HLE.HOS.Services.Caps
|
|||||||
|
|
||||||
using SKBitmap bitmap = new(new SKImageInfo(ScreenshotWidth, ScreenshotHeight, SKColorType.Rgba8888));
|
using SKBitmap bitmap = new(new SKImageInfo(ScreenshotWidth, ScreenshotHeight, SKColorType.Rgba8888));
|
||||||
|
|
||||||
IntPtr pixels = bitmap.GetPixels();
|
nint pixels = bitmap.GetPixels();
|
||||||
|
|
||||||
if (pixels == IntPtr.Zero)
|
if (pixels == 0)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidArgument;
|
return ResultCode.InvalidArgument;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
private const uint MbIconwarning = 0x30;
|
private const uint MbIconwarning = 0x30;
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
public static int Main(string[] args)
|
public static int Main(string[] args)
|
||||||
{
|
{
|
||||||
Version = ReleaseInformation.Version;
|
Version = ReleaseInformation.Version;
|
||||||
@@ -54,17 +55,39 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
|
if (!OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
|
||||||
{
|
{
|
||||||
_ = Win32NativeInterop.MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 20H1 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run on an outdated version of Windows. Exiting...");
|
||||||
|
_ = Win32NativeInterop.MessageBoxA(nint.Zero,
|
||||||
|
"You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 20H1 and newer.\n",
|
||||||
|
$"Ryujinx {Version}", MbIconwarning);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
string onedriveFiles = Environment.GetEnvironmentVariable("Onedrive");
|
||||||
var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
|
string onedriveConsumerFiles = Environment.GetEnvironmentVariable("OnedriveConsumer");
|
||||||
|
string onedriveCommercialFiles = Environment.GetEnvironmentVariable("OnedriveCommercial");
|
||||||
|
|
||||||
|
// Apparently not everyone has OneDrive shoved onto their system.
|
||||||
|
if ((onedriveFiles is not null && Environment.CurrentDirectory.StartsWithIgnoreCase(onedriveFiles))
|
||||||
|
|| (onedriveConsumerFiles is not null && Environment.CurrentDirectory.StartsWithIgnoreCase(onedriveConsumerFiles))
|
||||||
|
|| (onedriveCommercialFiles is not null && Environment.CurrentDirectory.StartsWithIgnoreCase(onedriveCommercialFiles)))
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run from a OneDrive folder. Exiting...");
|
||||||
|
_ = Win32NativeInterop.MessageBoxA(nint.Zero,
|
||||||
|
"Ryujinx is not intended to be run from a OneDrive folder. Please move it out and relaunch.",
|
||||||
|
$"Ryujinx {Version}", MbIconwarning);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
|
||||||
|
string programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
|
||||||
|
|
||||||
if (Environment.CurrentDirectory.StartsWithIgnoreCase(programFiles) ||
|
if (Environment.CurrentDirectory.StartsWithIgnoreCase(programFiles) ||
|
||||||
Environment.CurrentDirectory.StartsWithIgnoreCase(programFilesX86))
|
Environment.CurrentDirectory.StartsWithIgnoreCase(programFilesX86))
|
||||||
{
|
{
|
||||||
_ = Win32NativeInterop.MessageBoxA(nint.Zero, "Ryujinx is not intended to be run from the Program Files folder. Please move it out and relaunch.", $"Ryujinx {Version}", MbIconwarning);
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run from the Program Files folder. Exiting...");
|
||||||
|
_ = Win32NativeInterop.MessageBoxA(nint.Zero,
|
||||||
|
"Ryujinx is not intended to be run from the Program Files folder. Please move it out and relaunch.",
|
||||||
|
$"Ryujinx {Version}", MbIconwarning);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,10 +97,70 @@ namespace Ryujinx.Ava
|
|||||||
// ...but this reads like it checks if the current is in/has the Windows admin role? lol
|
// ...but this reads like it checks if the current is in/has the Windows admin role? lol
|
||||||
if (new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
|
if (new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator))
|
||||||
{
|
{
|
||||||
_ = Win32NativeInterop.MessageBoxA(nint.Zero, "Ryujinx is not intended to be run as administrator.", $"Ryujinx {Version}", MbIconwarning);
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run as administrator. Exiting...");
|
||||||
|
_ = Win32NativeInterop.MessageBoxA(nint.Zero, "Ryujinx is not intended to be run as administrator.",
|
||||||
|
$"Ryujinx {Version}", MbIconwarning);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else // Unix
|
||||||
|
{
|
||||||
|
// sudo check
|
||||||
|
[DllImport("libc")]
|
||||||
|
static extern uint geteuid();
|
||||||
|
bool root = geteuid().Equals(0);
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
if (root)
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run as administrator. Exiting...");
|
||||||
|
macOSNativeInterop.SimpleMessageBox($"Ryujinx {Version}",
|
||||||
|
"Ryujinx is not intended to be run as administrator.", "Ok");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string downloadFiles = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
|
||||||
|
|
||||||
|
if (Environment.CurrentDirectory.StartsWithIgnoreCase(downloadFiles))
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run from the Downloads folder. Exiting...");
|
||||||
|
macOSNativeInterop.SimpleMessageBox($"Ryujinx {Version}",
|
||||||
|
"Ryujinx is not intended to be run from the Downloads folder.", "Ok");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string icloudFiles = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library/Mobile Documents/com~apple~CloudDocs");
|
||||||
|
|
||||||
|
if (Environment.CurrentDirectory.StartsWithIgnoreCase(icloudFiles))
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run from the iCloud folder. Exiting...");
|
||||||
|
macOSNativeInterop.SimpleMessageBox($"Ryujinx {Version}",
|
||||||
|
"Ryujinx is not intended to be run from the iCloud folder.", "Ok");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
if (root)
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Ryujinx is not intended to be run as administrator. Exiting...");
|
||||||
|
LinuxSDLInterop.SimpleMessageBox($"Ryujinx {Version}", "Ryujinx is not intended to be run as administrator.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
string container = Environment.GetEnvironmentVariable("container");
|
||||||
|
|
||||||
|
if (container is not null && container.EqualsIgnoreCase("flatpak"))
|
||||||
|
{
|
||||||
|
Logger.Info?.PrintMsg(LogClass.Application, "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||||
|
Logger.Warning?.PrintMsg(LogClass.Application, "This is very likely an unofficial build, Ryujinx does NOT have a flatpak!");
|
||||||
|
Logger.Info?.PrintMsg(LogClass.Application, "Please visit https://ryujinx.app/ for our official builds.");
|
||||||
|
Logger.Info?.PrintMsg(LogClass.Application, "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui");
|
bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui");
|
||||||
bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps");
|
bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps");
|
||||||
@@ -115,6 +198,12 @@ namespace Ryujinx.Ava
|
|||||||
public static AppBuilder BuildAvaloniaApp() =>
|
public static AppBuilder BuildAvaloniaApp() =>
|
||||||
AppBuilder.Configure<RyujinxApp>()
|
AppBuilder.Configure<RyujinxApp>()
|
||||||
.UsePlatformDetect()
|
.UsePlatformDetect()
|
||||||
|
|
||||||
|
// Vulkan UI rendering performs better, but its unpolished, and as such it lacks effective transparency.
|
||||||
|
// https://github.com/AvaloniaUI/Avalonia/issues/19378
|
||||||
|
// https://github.com/AvaloniaUI/Avalonia/issues/9610
|
||||||
|
// X11RenderingMode.Glx && X11RenderingMode.Egl, Win32RenderingMode.Vulkan have these issues.
|
||||||
|
|
||||||
.With(new X11PlatformOptions
|
.With(new X11PlatformOptions
|
||||||
{
|
{
|
||||||
EnableMultiTouch = true,
|
EnableMultiTouch = true,
|
||||||
@@ -310,7 +399,7 @@ namespace Ryujinx.Ava
|
|||||||
"never" => HideCursorMode.Never,
|
"never" => HideCursorMode.Never,
|
||||||
"onidle" => HideCursorMode.OnIdle,
|
"onidle" => HideCursorMode.OnIdle,
|
||||||
"always" => HideCursorMode.Always,
|
"always" => HideCursorMode.Always,
|
||||||
_ => ConfigurationState.Instance.HideCursor,
|
_ => ConfigurationState.Instance.HideCursor
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if memoryManagerMode was overridden.
|
// Check if memoryManagerMode was overridden.
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Runtime;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -579,6 +580,12 @@ namespace Ryujinx.Ava.Systems
|
|||||||
{
|
{
|
||||||
_isActive = false;
|
_isActive = false;
|
||||||
_playTimer.Stop();
|
_playTimer.Stop();
|
||||||
|
|
||||||
|
GCSettings.LatencyMode = GCLatencyMode.Interactive;
|
||||||
|
if (ConfigurationState.Instance.System.GCLowLatency)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Exit()
|
private void Exit()
|
||||||
@@ -662,6 +669,12 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
_chrono.Stop();
|
_chrono.Stop();
|
||||||
_playTimer.Stop();
|
_playTimer.Stop();
|
||||||
|
|
||||||
|
GCSettings.LatencyMode = GCLatencyMode.Interactive;
|
||||||
|
if (ConfigurationState.Instance.System.GCLowLatency)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DisposeGpu()
|
public void DisposeGpu()
|
||||||
@@ -915,7 +928,14 @@ namespace Ryujinx.Ava.Systems
|
|||||||
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
|
||||||
appMetadata => appMetadata.UpdatePreGame()
|
appMetadata => appMetadata.UpdatePreGame()
|
||||||
);
|
);
|
||||||
|
|
||||||
_playTimer.Start();
|
_playTimer.Start();
|
||||||
|
|
||||||
|
if (ConfigurationState.Instance.System.GCLowLatency)
|
||||||
|
{
|
||||||
|
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Garbage collector set to low latency mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Resume()
|
internal void Resume()
|
||||||
@@ -926,6 +946,12 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_playTimer.Start();
|
_playTimer.Start();
|
||||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
|
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI);
|
||||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed.");
|
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed.");
|
||||||
|
|
||||||
|
if (ConfigurationState.Instance.System.GCLowLatency)
|
||||||
|
{
|
||||||
|
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Garbage collector set to low latency mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Pause()
|
internal void Pause()
|
||||||
@@ -936,6 +962,12 @@ namespace Ryujinx.Ava.Systems
|
|||||||
_playTimer.Stop();
|
_playTimer.Stop();
|
||||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
|
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowOldUI, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused.");
|
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused.");
|
||||||
|
|
||||||
|
GCSettings.LatencyMode = GCLatencyMode.Interactive;
|
||||||
|
if (ConfigurationState.Instance.System.GCLowLatency)
|
||||||
|
{
|
||||||
|
Logger.Info?.Print(LogClass.Application, "Garbage collector set to interactive mode.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitEmulatedSwitch()
|
private void InitEmulatedSwitch()
|
||||||
|
|||||||
@@ -471,6 +471,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseHypervisor { get; set; }
|
public bool UseHypervisor { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable low-latency mode for garbage collection
|
||||||
|
/// </summary>
|
||||||
|
public bool GCLowLatency { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables or disables the GDB stub
|
/// Enables or disables the GDB stub
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
|
System.IgnoreControllerApplet.Value = cff.IgnoreApplet;
|
||||||
System.SkipUserProfilesManager.Value = cff.SkipUserProfiles;
|
System.SkipUserProfilesManager.Value = cff.SkipUserProfiles;
|
||||||
System.UseHypervisor.Value = cff.UseHypervisor;
|
System.UseHypervisor.Value = cff.UseHypervisor;
|
||||||
|
System.GCLowLatency.Value = cff.GCLowLatency;
|
||||||
|
|
||||||
UI.GuiColumns.FavColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FavColumn : UI.GuiColumns.FavColumn.Value;
|
UI.GuiColumns.FavColumn.Value = shouldLoadFromFile ? cff.GuiColumns.FavColumn : UI.GuiColumns.FavColumn.Value;
|
||||||
UI.GuiColumns.IconColumn.Value = shouldLoadFromFile ? cff.GuiColumns.IconColumn : UI.GuiColumns.IconColumn.Value;
|
UI.GuiColumns.IconColumn.Value = shouldLoadFromFile ? cff.GuiColumns.IconColumn : UI.GuiColumns.IconColumn.Value;
|
||||||
@@ -535,7 +536,8 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
{
|
{
|
||||||
if (cff.AudioBackend is AudioBackend.SDL2)
|
if (cff.AudioBackend is AudioBackend.SDL2)
|
||||||
cff.AudioBackend = AudioBackend.SDL3;
|
cff.AudioBackend = AudioBackend.SDL3;
|
||||||
})
|
}),
|
||||||
|
(72, static cff => cff.GCLowLatency = false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -418,6 +418,11 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public ReactiveObject<bool> UseHypervisor { get; private set; }
|
public ReactiveObject<bool> UseHypervisor { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable low-latency garbage collection
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> GCLowLatency { get; private set; }
|
||||||
|
|
||||||
public SystemSection()
|
public SystemSection()
|
||||||
{
|
{
|
||||||
Language = new ReactiveObject<Language>();
|
Language = new ReactiveObject<Language>();
|
||||||
@@ -471,6 +476,8 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
AudioVolume.LogChangesToValue(nameof(AudioVolume));
|
AudioVolume.LogChangesToValue(nameof(AudioVolume));
|
||||||
UseHypervisor = new ReactiveObject<bool>();
|
UseHypervisor = new ReactiveObject<bool>();
|
||||||
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
|
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
|
||||||
|
GCLowLatency = new ReactiveObject<bool>();
|
||||||
|
GCLowLatency.LogChangesToValue(nameof(GCLowLatency));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ namespace Ryujinx.Ava.Systems.Configuration
|
|||||||
IgnoreApplet = System.IgnoreControllerApplet,
|
IgnoreApplet = System.IgnoreControllerApplet,
|
||||||
SkipUserProfiles = System.SkipUserProfilesManager,
|
SkipUserProfiles = System.SkipUserProfilesManager,
|
||||||
UseHypervisor = System.UseHypervisor,
|
UseHypervisor = System.UseHypervisor,
|
||||||
|
GCLowLatency = System.GCLowLatency,
|
||||||
GuiColumns = new GuiColumns
|
GuiColumns = new GuiColumns
|
||||||
{
|
{
|
||||||
FavColumn = UI.GuiColumns.FavColumn,
|
FavColumn = UI.GuiColumns.FavColumn,
|
||||||
|
|||||||
@@ -1070,6 +1070,23 @@ namespace Ryujinx.Ava.Systems.PlayReport
|
|||||||
_ => FormattedValue.ForceReset
|
_ => FormattedValue.ForceReset
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static FormattedValue TomodachiLifeLTD_Status(SingleValue value)
|
||||||
|
{
|
||||||
|
MessagePackObject messagePackObject = value.Matched.PackedValue;
|
||||||
|
MessagePackObjectDictionary messagePackObjectDictionary = messagePackObject.AsDictionary();
|
||||||
|
|
||||||
|
int miiCount = messagePackObjectDictionary["MiiNum"].AsInt32();
|
||||||
|
int fountainLevel = messagePackObjectDictionary["FountainLevel"].AsInt32();
|
||||||
|
|
||||||
|
return $"Looking after {"Mii".ToQuantity(miiCount)}, with an island level of {fountainLevel}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FormattedValue AnimalCrossingNewHorizons_AppCommon(SingleValue value)
|
||||||
|
{
|
||||||
|
MessagePackObject messagePackObject = value.Matched.PackedValue;
|
||||||
|
MessagePackObjectDictionary messagePackObjectDictionary = messagePackObject.AsDictionary();
|
||||||
|
|
||||||
|
return $"Living on {messagePackObjectDictionary["LandName"].AsString()} Island";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,6 +119,19 @@ namespace Ryujinx.Ava.Systems.PlayReport
|
|||||||
"based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.")
|
"based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.")
|
||||||
.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame)
|
.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame)
|
||||||
)
|
)
|
||||||
|
.AddSpec(
|
||||||
|
[ "010051f0207b2000", "0100ca502552a000" ], // Tomodachi Life: Living the Dream + Demo
|
||||||
|
spec => spec
|
||||||
|
.WithDescription(
|
||||||
|
"based on your total Mii count and island level.")
|
||||||
|
.AddValueFormatter("Common", TomodachiLifeLTD_Status)
|
||||||
|
)
|
||||||
|
.AddSpec(
|
||||||
|
"01006f8002326000", // Animal Crossing New Horizons
|
||||||
|
spec => spec
|
||||||
|
.WithDescription("based on your island name.")
|
||||||
|
.AddValueFormatter("AppCmn", AnimalCrossingNewHorizons_AppCommon)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
private static string Playing(string game) => $"Playing {game}";
|
private static string Playing(string game) => $"Playing {game}";
|
||||||
|
|||||||
30
src/Ryujinx/UI/Helpers/LinuxSDLInterop.cs
Normal file
30
src/Ryujinx/UI/Helpers/LinuxSDLInterop.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
public class LinuxSDLInterop
|
||||||
|
{
|
||||||
|
// TODO: add a parameter for prompt style
|
||||||
|
// TODO: look into adding text for the button
|
||||||
|
// TODO: check success of prompt box
|
||||||
|
public static int SimpleMessageBox(string caption, string text)
|
||||||
|
{
|
||||||
|
const string sdl = "SDL2";
|
||||||
|
|
||||||
|
[DllImport(sdl)]
|
||||||
|
static extern int SDL_Init(uint flags);
|
||||||
|
|
||||||
|
[DllImport(sdl, CallingConvention = CallingConvention.Cdecl)]
|
||||||
|
static extern int SDL_ShowSimpleMessageBox(uint flags, string title, string message, IntPtr window);
|
||||||
|
|
||||||
|
[DllImport(sdl)]
|
||||||
|
static extern void SDL_Quit();
|
||||||
|
|
||||||
|
SDL_Init(0);
|
||||||
|
SDL_ShowSimpleMessageBox(32 /* 32 = warning style */, caption, text, IntPtr.Zero);
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/Ryujinx/UI/Helpers/macOSNativeInterop.cs
Normal file
62
src/Ryujinx/UI/Helpers/macOSNativeInterop.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.Ava.UI.Helpers
|
||||||
|
{
|
||||||
|
public class macOSNativeInterop
|
||||||
|
{
|
||||||
|
// TODO: add a parameter for prompt style
|
||||||
|
// TODO: check success of prompt box
|
||||||
|
public static int SimpleMessageBox(string caption, string text, string button)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Grab what we need to make the message box.
|
||||||
|
const string ObjCRuntime = "/usr/lib/libobjc.A.dylib";
|
||||||
|
const string FoundationFramework = "/System/Library/Frameworks/Foundation.framework/Foundation";
|
||||||
|
const string AppKitFramework = "/System/Library/Frameworks/AppKit.framework/AppKit";
|
||||||
|
|
||||||
|
[DllImport(ObjCRuntime, EntryPoint = "sel_registerName")]
|
||||||
|
static extern IntPtr GetSelector(string name);
|
||||||
|
|
||||||
|
[DllImport(ObjCRuntime, EntryPoint = "objc_getClass")]
|
||||||
|
static extern IntPtr GetClass(string name);
|
||||||
|
|
||||||
|
[DllImport(FoundationFramework, EntryPoint = "objc_msgSend")]
|
||||||
|
static extern IntPtr SendMessage(IntPtr target, IntPtr selector);
|
||||||
|
|
||||||
|
[DllImport(FoundationFramework, EntryPoint = "objc_msgSend")]
|
||||||
|
static extern IntPtr SendMessageWithParameter(IntPtr target, IntPtr selector, IntPtr param);
|
||||||
|
|
||||||
|
[DllImport(ObjCRuntime)]
|
||||||
|
static extern IntPtr dlopen(string path, int mode);
|
||||||
|
|
||||||
|
dlopen(AppKitFramework, 0x1); // have to invoke AppKit so that NSAlert doesn't return a null pointer
|
||||||
|
|
||||||
|
IntPtr NSStringClass = GetClass("NSString");
|
||||||
|
IntPtr Selector = GetSelector("stringWithUTF8String:");
|
||||||
|
IntPtr SharedApp = SendMessage(GetClass("NSApplication"), GetSelector("sharedApplication"));
|
||||||
|
IntPtr NSAlert = SendMessage(GetClass("NSAlert"), GetSelector("alloc"));
|
||||||
|
IntPtr AlertInstance = SendMessage(NSAlert, GetSelector("init"));
|
||||||
|
|
||||||
|
// Create caption, text, and button text.
|
||||||
|
IntPtr boxCaption = SendMessageWithParameter(NSStringClass, Selector, Marshal.StringToHGlobalAnsi(caption));
|
||||||
|
IntPtr boxText = SendMessageWithParameter(NSStringClass, Selector, Marshal.StringToHGlobalAnsi(text));
|
||||||
|
IntPtr boxButton = SendMessageWithParameter(NSStringClass, Selector, Marshal.StringToHGlobalAnsi(button));
|
||||||
|
|
||||||
|
// Set up the window.
|
||||||
|
SendMessageWithParameter(SharedApp, GetSelector("setActivationPolicy:"), IntPtr.Zero); // Give it a window.
|
||||||
|
SendMessageWithParameter(SharedApp, GetSelector("activateIgnoringOtherApps:"), (IntPtr) 1); // Force it to the front.
|
||||||
|
|
||||||
|
// Set up the message box.
|
||||||
|
SendMessageWithParameter(AlertInstance, GetSelector("setAlertStyle:"), IntPtr.Zero); // Set style to warning.
|
||||||
|
SendMessageWithParameter(AlertInstance, GetSelector("setMessageText:"), boxCaption);
|
||||||
|
SendMessageWithParameter(AlertInstance, GetSelector("setInformativeText:"), boxText);
|
||||||
|
SendMessageWithParameter(AlertInstance, GetSelector("addButtonWithTitle:"), boxButton);
|
||||||
|
|
||||||
|
// Send prompt to user, then clean up.
|
||||||
|
SendMessage(AlertInstance, GetSelector("runModal"));
|
||||||
|
SendMessage(AlertInstance, GetSelector("release"));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2067,6 +2067,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE,
|
Win32NativeInterop.SetWindowLongPtrW(hwnd, Win32NativeInterop.GWL_STYLE,
|
||||||
unchecked((nint)(Win32NativeInterop.WS_POPUP | Win32NativeInterop.WS_VISIBLE)));
|
unchecked((nint)(Win32NativeInterop.WS_POPUP | Win32NativeInterop.WS_VISIBLE)));
|
||||||
|
|
||||||
|
// TODO: why is this nullable
|
||||||
Avalonia.Platform.Screen? screen = Window.Screens.ScreenFromVisual(Window);
|
Avalonia.Platform.Screen? screen = Window.Screens.ScreenFromVisual(Window);
|
||||||
int w = screen?.Bounds.Width ?? 0;
|
int w = screen?.Bounds.Width ?? 0;
|
||||||
int h = screen?.Bounds.Height ?? 0;
|
int h = screen?.Bounds.Height ?? 0;
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
public bool IsVulkanSelected =>
|
public bool IsVulkanSelected =>
|
||||||
GraphicsBackendIndex == 1 || (GraphicsBackendIndex == 0 && !OperatingSystem.IsMacOS());
|
GraphicsBackendIndex == 1 || (GraphicsBackendIndex == 0 && !OperatingSystem.IsMacOS());
|
||||||
public bool UseHypervisor { get; set; }
|
public bool UseHypervisor { get; set; }
|
||||||
|
public bool GCLowLatency { get; set; }
|
||||||
public bool DisableP2P { get; set; }
|
public bool DisableP2P { get; set; }
|
||||||
|
|
||||||
public bool ShowDirtyHacks => ConfigurationState.Instance.Hacks.ShowDirtyHacks;
|
public bool ShowDirtyHacks => ConfigurationState.Instance.Hacks.ShowDirtyHacks;
|
||||||
@@ -689,6 +690,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
EnableLowPowerPptc = config.System.EnableLowPowerPtc;
|
EnableLowPowerPptc = config.System.EnableLowPowerPtc;
|
||||||
MemoryMode = (int)config.System.MemoryManagerMode.Value;
|
MemoryMode = (int)config.System.MemoryManagerMode.Value;
|
||||||
UseHypervisor = config.System.UseHypervisor;
|
UseHypervisor = config.System.UseHypervisor;
|
||||||
|
GCLowLatency = config.System.GCLowLatency;
|
||||||
TurboMultiplier = config.System.TickScalar;
|
TurboMultiplier = config.System.TickScalar;
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
@@ -800,6 +802,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
config.System.EnableLowPowerPtc.Value = EnableLowPowerPptc;
|
config.System.EnableLowPowerPtc.Value = EnableLowPowerPptc;
|
||||||
config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
|
config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
|
||||||
config.System.UseHypervisor.Value = UseHypervisor;
|
config.System.UseHypervisor.Value = UseHypervisor;
|
||||||
|
config.System.GCLowLatency.Value = GCLowLatency;
|
||||||
config.System.TickScalar.Value = TurboMultiplier;
|
config.System.TickScalar.Value = TurboMultiplier;
|
||||||
|
|
||||||
// Graphics
|
// Graphics
|
||||||
|
|||||||
@@ -71,6 +71,11 @@
|
|||||||
<TextBlock Text="{ext:Locale SettingsTabSystemUseHypervisor}"
|
<TextBlock Text="{ext:Locale SettingsTabSystemUseHypervisor}"
|
||||||
ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" />
|
ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" />
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
|
<CheckBox
|
||||||
|
IsChecked="{Binding GCLowLatency}"
|
||||||
|
ToolTip.Tip="{ext:Locale GCLowLatencyTooltip}">
|
||||||
|
<TextBlock Text="{ext:Locale SettingsTabSystemGCLowLatency}" />
|
||||||
|
</CheckBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Separator Height="1" />
|
<Separator Height="1" />
|
||||||
<StackPanel
|
<StackPanel
|
||||||
|
|||||||
11
src/Ryujinx/runtimeconfig.template.json
Normal file
11
src/Ryujinx/runtimeconfig.template.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"configProperties": {
|
||||||
|
"System.GC.Concurrent": true,
|
||||||
|
"System.GC.Server": false,
|
||||||
|
"System.GC.RetainVM": true,
|
||||||
|
"System.Runtime.TieredCompilation.QuickJit": false,
|
||||||
|
"System.Runtime.TieredCompilation.QuickJitForLoops": false,
|
||||||
|
"DOTNET_ReadyToRun": false,
|
||||||
|
"DOTNET_TieredPGO": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user