Compare commits
21 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
476b4683cf | ||
|
5fb5079730 | ||
|
3fbacd0f49 | ||
|
7aa6abc120 | ||
|
548bfd60a2 | ||
|
65778a6b78 | ||
|
f4e879a1e6 | ||
|
a1ddaa2736 | ||
|
008286b79f | ||
|
a0c77f8d11 | ||
|
ece36b274d | ||
|
f3cc2e5703 | ||
|
5a39d3c4a1 | ||
|
cc51a03af9 | ||
|
567c64e149 | ||
|
36f00985d3 | ||
|
748d87adcc | ||
|
0fd47ff490 | ||
|
f088c3d344 | ||
|
905a191e28 | ||
|
ab0491817e |
@@ -21,6 +21,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
Name = $"Ryujinx {Program.Version}";
|
||||
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
|
@@ -60,7 +60,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
private const float VolumeDelta = 0.05f;
|
||||
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
private static readonly Cursor InvisibleCursor = new Cursor(StandardCursorType.None);
|
||||
|
||||
private readonly long _ticksPerFrame;
|
||||
private readonly Stopwatch _chrono;
|
||||
@@ -349,7 +349,10 @@ namespace Ryujinx.Ava
|
||||
|
||||
_isActive = false;
|
||||
|
||||
_renderingThread.Join();
|
||||
if (_renderingThread.IsAlive)
|
||||
{
|
||||
_renderingThread.Join();
|
||||
}
|
||||
|
||||
DisplaySleep.Restore();
|
||||
|
||||
@@ -378,7 +381,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
_gpuCancellationTokenSource.Cancel();
|
||||
_gpuCancellationTokenSource.Dispose();
|
||||
|
||||
|
||||
_chrono.Stop();
|
||||
}
|
||||
|
||||
@@ -393,7 +396,7 @@ namespace Ryujinx.Ava
|
||||
Renderer?.MakeCurrent();
|
||||
|
||||
Device.DisposeGpu();
|
||||
|
||||
|
||||
Renderer?.MakeCurrent(null);
|
||||
}
|
||||
|
||||
@@ -417,7 +420,6 @@ namespace Ryujinx.Ava
|
||||
public async Task<bool> LoadGuestApplication()
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@@ -428,17 +430,16 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
if (userError == UserError.NoFirmware)
|
||||
{
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"],
|
||||
firmwareVersion.VersionString);
|
||||
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"], message,
|
||||
LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], "");
|
||||
LocaleManager.Instance["DialogFirmwareNoFirmwareInstalledMessage"],
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
"");
|
||||
|
||||
if (result != UserResult.Yes)
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -447,8 +448,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -461,11 +461,9 @@ namespace Ryujinx.Ava
|
||||
|
||||
_parent.RefreshFirmwareStatus();
|
||||
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstalledMessage"], firmwareVersion.VersionString),
|
||||
message,
|
||||
string.Format(LocaleManager.Instance["DialogFirmwareInstallEmbeddedSuccessMessage"], firmwareVersion.VersionString),
|
||||
LocaleManager.Instance["InputDialogOk"],
|
||||
"",
|
||||
LocaleManager.Instance["RyujinxInfo"]);
|
||||
@@ -473,9 +471,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(userError, _parent));
|
||||
|
||||
await UserErrorDialog.ShowUserErrorDialog(userError, _parent);
|
||||
Device.Dispose();
|
||||
|
||||
return false;
|
||||
@@ -514,7 +510,7 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
switch (System.IO.Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
{
|
||||
@@ -602,7 +598,7 @@ namespace Ryujinx.Ava
|
||||
if (Renderer.IsVulkan)
|
||||
{
|
||||
string preferredGpu = ConfigurationState.Instance.Graphics.PreferredGpu.Value;
|
||||
|
||||
|
||||
renderer = new VulkanRenderer(Renderer.CreateVulkanSurface, VulkanHelper.GetRequiredInstanceExtensions, preferredGpu);
|
||||
}
|
||||
else
|
||||
|
@@ -119,7 +119,7 @@
|
||||
"SettingsTabSystemAudioBackendSDL2": "SDL2",
|
||||
"SettingsTabSystemHacks": "Hacks",
|
||||
"SettingsTabSystemHacksNote": " (may cause instability)",
|
||||
"SettingsTabSystemExpandDramSize": "Expand DRAM Size to 6GiB",
|
||||
"SettingsTabSystemExpandDramSize": "Use alternative memory layout (Developers)",
|
||||
"SettingsTabSystemIgnoreMissingServices": "Ignore Missing Services",
|
||||
"SettingsTabGraphics": "Graphics",
|
||||
"SettingsTabGraphicsAPI": "Graphics API",
|
||||
@@ -410,6 +410,8 @@
|
||||
"DlcManagerTableHeadingContainerPathLabel": "Container Path",
|
||||
"DlcManagerTableHeadingFullPathLabel": "Full Path",
|
||||
"DlcManagerRemoveAllButton": "Remove All",
|
||||
"DlcManagerEnableAllButton": "Enable All",
|
||||
"DlcManagerDisableAllButton": "Disable All",
|
||||
"MenuBarOptionsChangeLanguage": "Change Language",
|
||||
"CommonSort": "Sort",
|
||||
"CommonShowNames": "Show Names",
|
||||
@@ -440,7 +442,7 @@
|
||||
"MemoryManagerSoftwareTooltip": "Use a software page table for address translation. Highest accuracy but slowest performance.",
|
||||
"MemoryManagerHostTooltip": "Directly map memory in the host address space. Much faster JIT compilation and execution.",
|
||||
"MemoryManagerUnsafeTooltip": "Directly map memory, but do not mask the address within the guest address space before access. Faster, but at the cost of safety. The guest application can access memory from anywhere in Ryujinx, so only run programs you trust with this mode.",
|
||||
"DRamTooltip": "Increases the amount of memory on the emulated system from 4GiB to 6GiB.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"DRamTooltip": "Utilizes an alternative MemoryMode layout to mimic a Switch development model.\n\nThis is only useful for higher-resolution texture packs or 4k resolution mods. Does NOT improve performance.\n\nLeave OFF if unsure.",
|
||||
"IgnoreMissingServicesTooltip": "Ignores unimplemented Horizon OS services. This may help in bypassing crashes when booting certain games.\n\nLeave OFF if unsure.",
|
||||
"GraphicsBackendThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
"GalThreadingTooltip": "Executes graphics backend commands on a second thread.\n\nSpeeds up shader compilation, reduces stuttering, and improves performance on GPU drivers without multithreading support of their own. Slightly better performance on drivers with multithreading.\n\nSet to AUTO if unsure.",
|
||||
@@ -567,7 +569,7 @@
|
||||
"DlcWindowTitle": "Manage Game DLC",
|
||||
"UpdateWindowTitle": "Manage Game Updates",
|
||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||
"DlcWindowHeading": "DLC Available for {0} [{1}]",
|
||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||
"UserProfilesEditProfile": "Edit Selected",
|
||||
"Cancel": "Cancel",
|
||||
"Save": "Save",
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.Ui.Common.Configuration;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
@@ -93,7 +94,7 @@ namespace Ryujinx.Ava.Common.Locale
|
||||
return;
|
||||
}
|
||||
|
||||
var strings = JsonSerializer.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
var strings = JsonHelper.Deserialize<Dictionary<string, string>>(languageJson);
|
||||
|
||||
foreach (var item in strings)
|
||||
{
|
||||
|
@@ -23,19 +23,18 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
internal class Program
|
||||
{
|
||||
public static double WindowScaleFactor { get; set; }
|
||||
public static double ActualScaleFactor { get; set; }
|
||||
public static string Version { get; private set; }
|
||||
public static string ConfigurationPath { get; private set; }
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
|
||||
public static RenderTimer RenderTimer { get; private set; }
|
||||
public static double WindowScaleFactor { get; set; }
|
||||
public static double ActualScaleFactor { get; set; }
|
||||
public static string Version { get; private set; }
|
||||
public static string ConfigurationPath { get; private set; }
|
||||
public static bool PreviewerDetached { get; private set; }
|
||||
public static RenderTimer RenderTimer { get; private set; }
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
public static extern int MessageBoxA(IntPtr hWnd, string text, string caption, uint type);
|
||||
|
||||
private const uint MB_ICONWARNING = 0x30;
|
||||
private const int BaseDpi = 96;
|
||||
private const int BaseDpi = 96;
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
@@ -43,7 +42,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||
{
|
||||
MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
||||
_ = MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING);
|
||||
}
|
||||
|
||||
PreviewerDetached = true;
|
||||
@@ -64,16 +63,16 @@ namespace Ryujinx.Ava
|
||||
.With(new X11PlatformOptions
|
||||
{
|
||||
EnableMultiTouch = true,
|
||||
EnableIme = true,
|
||||
UseEGL = false,
|
||||
UseGpu = false
|
||||
EnableIme = true,
|
||||
UseEGL = false,
|
||||
UseGpu = false
|
||||
})
|
||||
.With(new Win32PlatformOptions
|
||||
{
|
||||
EnableMultitouch = true,
|
||||
UseWgl = false,
|
||||
AllowEglInitialization = false,
|
||||
CompositionBackdropCornerRadius = 8f,
|
||||
EnableMultitouch = true,
|
||||
UseWgl = false,
|
||||
AllowEglInitialization = false,
|
||||
CompositionBackdropCornerRadius = 8.0f,
|
||||
})
|
||||
.UseSkia()
|
||||
.AfterSetup(_ =>
|
||||
@@ -122,12 +121,10 @@ namespace Ryujinx.Ava
|
||||
PrintSystemInfo();
|
||||
|
||||
// Enable OGL multithreading on the driver, when available.
|
||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||
DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off);
|
||||
DriverUtilities.ToggleOGLThreading(ConfigurationState.Instance.Graphics.BackendThreading == BackendThreading.Off);
|
||||
|
||||
// Check if keys exists.
|
||||
bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys"));
|
||||
if (!hasSystemProdKeys)
|
||||
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
|
||||
{
|
||||
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
|
||||
{
|
||||
@@ -143,7 +140,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
public static void ReloadConfig()
|
||||
{
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json");
|
||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json");
|
||||
|
||||
// Now load the configuration as the other subsystems are now registered
|
||||
@@ -197,8 +194,7 @@ namespace Ryujinx.Ava
|
||||
Logger.Notice.Print(LogClass.Application, $"Ryujinx Version: {Version}");
|
||||
SystemInfo.Gather().Print();
|
||||
|
||||
var enabledLogs = Logger.GetEnabledLevels();
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogs.Count == 0 ? "<None>" : string.Join(", ", enabledLogs))}");
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(Logger.GetEnabledLevels().Count == 0 ? "<None>" : string.Join(", ", Logger.GetEnabledLevels()))}");
|
||||
|
||||
if (AppDataManager.Mode == AppDataManager.LaunchMode.Custom)
|
||||
{
|
||||
|
@@ -18,17 +18,17 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.15" />
|
||||
<PackageReference Include="Avalonia.Svg" Version="0.10.14" />
|
||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.14" />
|
||||
<PackageReference Include="Avalonia" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Desktop" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Markup.Xaml.Loader" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Svg" Version="0.10.18" />
|
||||
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.18" />
|
||||
<PackageReference Include="jp2masa.Avalonia.Flexbox" Version="0.2.0" />
|
||||
<PackageReference Include="DynamicData" Version="7.9.4" />
|
||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" />
|
||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.3.4" />
|
||||
<PackageReference Include="DynamicData" Version="7.12.8" />
|
||||
<PackageReference Include="FluentAvaloniaUI" Version="1.4.4" />
|
||||
<PackageReference Include="XamlNameReferenceGenerator" Version="1.4.2" />
|
||||
|
||||
<PackageReference Include="OpenTK.Core" Version="4.7.2" />
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||
@@ -37,7 +37,7 @@
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.10.1" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.10.1" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -57,14 +57,14 @@ namespace Ryujinx.Ava.Ui.Applet
|
||||
|
||||
bool opened = false;
|
||||
|
||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||
title,
|
||||
message,
|
||||
"",
|
||||
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
|
||||
"",
|
||||
LocaleManager.Instance["SettingsButtonClose"],
|
||||
(int)Symbol.Important,
|
||||
UserResult response = await ContentDialogHelper.ShowDeferredContentDialog(_parent,
|
||||
title,
|
||||
message,
|
||||
"",
|
||||
LocaleManager.Instance["DialogOpenSettingsWindowLabel"],
|
||||
"",
|
||||
LocaleManager.Instance["SettingsButtonClose"],
|
||||
(int)Symbol.Important,
|
||||
deferEvent,
|
||||
async (window) =>
|
||||
{
|
||||
@@ -168,7 +168,7 @@ namespace Ryujinx.Ava.Ui.Applet
|
||||
|
||||
object response = await msgDialog.Run();
|
||||
|
||||
if (response != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
|
||||
if (response != null && buttons != null && buttons.Length > 1 && (int)response != buttons.Length - 1)
|
||||
{
|
||||
showDetails = true;
|
||||
}
|
||||
|
@@ -49,7 +49,7 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
{
|
||||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
|
||||
var flags = OpenGLContextFlags.Compat;
|
||||
if (_graphicsDebugLevel != GraphicsDebugLevel.None)
|
||||
{
|
||||
@@ -69,12 +69,12 @@ namespace Ryujinx.Ava.Ui.Controls
|
||||
|
||||
public void MakeCurrent()
|
||||
{
|
||||
Context.MakeCurrent(_window);
|
||||
Context?.MakeCurrent(_window);
|
||||
}
|
||||
|
||||
public void MakeCurrent(NativeWindowBase window)
|
||||
{
|
||||
Context.MakeCurrent(window);
|
||||
Context?.MakeCurrent(window);
|
||||
}
|
||||
|
||||
public void SwapBuffers()
|
||||
|
@@ -1,8 +1,22 @@
|
||||
namespace Ryujinx.Ava.Ui.Models
|
||||
using Ryujinx.Ava.Ui.ViewModels;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Models
|
||||
{
|
||||
public class DownloadableContentModel
|
||||
public class DownloadableContentModel : BaseModel
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
private bool _enabled;
|
||||
|
||||
public bool Enabled
|
||||
{
|
||||
get => _enabled;
|
||||
set
|
||||
{
|
||||
_enabled = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string TitleId { get; }
|
||||
public string ContainerPath { get; }
|
||||
public string FullPath { get; }
|
||||
|
@@ -8,6 +8,7 @@ using Ryujinx.Ava.Ui.Models;
|
||||
using Ryujinx.Ava.Ui.Windows;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
@@ -189,7 +190,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
amiiboJsonString = File.ReadAllText(_amiiboJsonPath);
|
||||
|
||||
if (await NeedsUpdate(JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||
if (await NeedsUpdate(JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).LastUpdated))
|
||||
{
|
||||
amiiboJsonString = await DownloadAmiiboJson();
|
||||
}
|
||||
@@ -206,7 +207,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
_amiiboList = JsonSerializer.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
|
||||
_amiiboList = JsonHelper.Deserialize<Amiibo.AmiiboJson>(amiiboJsonString).Amiibo;
|
||||
_amiiboList = _amiiboList.OrderBy(amiibo => amiibo.AmiiboSeries).ToList();
|
||||
|
||||
ParseAmiiboData();
|
||||
|
@@ -460,8 +460,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
using IGamepad gamepad = _mainWindow.InputManager.KeyboardDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
|
||||
|
||||
if (gamepad != null)
|
||||
{
|
||||
Devices.Add((DeviceType.Keyboard, id, $"{GetShortGamepadName(gamepad.Name)}"));
|
||||
@@ -472,8 +470,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
using IGamepad gamepad = _mainWindow.InputManager.GamepadDriver.GetGamepad(id);
|
||||
|
||||
Logger.Info?.Print(LogClass.Configuration, $"{GetShortGamepadName(gamepad.Name)} has been connected with ID: {gamepad.Id}");
|
||||
|
||||
if (gamepad != null)
|
||||
{
|
||||
if (Devices.Any(controller => GetShortGamepadId(controller.Id) == GetShortGamepadId(gamepad.Id)))
|
||||
|
@@ -19,6 +19,7 @@ using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.Modules;
|
||||
using Ryujinx.Ui.App.Common;
|
||||
using Ryujinx.Ui.Common;
|
||||
@@ -47,6 +48,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
private string _loadHeading;
|
||||
private string _cacheLoadStatus;
|
||||
private string _searchText;
|
||||
private Timer _searchTimer;
|
||||
private string _dockedStatusText;
|
||||
private string _fifoStatusText;
|
||||
private string _gameStatusText;
|
||||
@@ -115,10 +117,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
_searchText = value;
|
||||
|
||||
RefreshView();
|
||||
_searchTimer?.Dispose();
|
||||
|
||||
_searchTimer = new Timer(TimerCallback, null, 1000, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void TimerCallback(object obj)
|
||||
{
|
||||
RefreshView();
|
||||
|
||||
_searchTimer.Dispose();
|
||||
_searchTimer = null;
|
||||
}
|
||||
|
||||
public ReadOnlyObservableCollection<ApplicationData> AppsObservableList
|
||||
{
|
||||
get => _appsObservableList;
|
||||
@@ -200,22 +212,19 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
private string _showUikey = "F4";
|
||||
private string _pauseKey = "F5";
|
||||
private string _screenshotkey = "F8";
|
||||
private float _volume;
|
||||
private float _volume;
|
||||
private string _backendText;
|
||||
|
||||
public ApplicationData SelectedApplication
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (Glyph)
|
||||
return Glyph switch
|
||||
{
|
||||
case Glyph.List:
|
||||
return _owner.GameList.SelectedApplication;
|
||||
case Glyph.Grid:
|
||||
return _owner.GameGrid.SelectedApplication;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
Glyph.List => _owner.GameList.SelectedApplication,
|
||||
Glyph.Grid => _owner.GameGrid.SelectedApplication,
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,6 +417,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
_owner.AppHost.Device.SetVolume(_volume);
|
||||
}
|
||||
|
||||
OnPropertyChanged(nameof(VolumeStatusText));
|
||||
OnPropertyChanged(nameof(VolumeMuted));
|
||||
OnPropertyChanged();
|
||||
@@ -477,38 +487,36 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
internal void Sort(bool isAscending)
|
||||
{
|
||||
IsAscending = isAscending;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
internal void Sort(ApplicationSort sort)
|
||||
{
|
||||
SortMode = sort;
|
||||
|
||||
RefreshView();
|
||||
}
|
||||
|
||||
private IComparer<ApplicationData> GetComparer()
|
||||
{
|
||||
switch (SortMode)
|
||||
return SortMode switch
|
||||
{
|
||||
case ApplicationSort.LastPlayed:
|
||||
return new Models.Generic.LastPlayedSortComparer(IsAscending);
|
||||
case ApplicationSort.FileSize:
|
||||
return new Models.Generic.FileSizeSortComparer(IsAscending);
|
||||
case ApplicationSort.TotalTimePlayed:
|
||||
return new Models.Generic.TimePlayedSortComparer(IsAscending);
|
||||
case ApplicationSort.Title:
|
||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName) : SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName);
|
||||
case ApplicationSort.Favorite:
|
||||
return !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite) : SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite);
|
||||
case ApplicationSort.Developer:
|
||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer) : SortExpressionComparer<ApplicationData>.Descending(app => app.Developer);
|
||||
case ApplicationSort.FileType:
|
||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension) : SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension);
|
||||
case ApplicationSort.Path:
|
||||
return IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path) : SortExpressionComparer<ApplicationData>.Descending(app => app.Path);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
ApplicationSort.LastPlayed => new Models.Generic.LastPlayedSortComparer(IsAscending),
|
||||
ApplicationSort.FileSize => new Models.Generic.FileSizeSortComparer(IsAscending),
|
||||
ApplicationSort.TotalTimePlayed => new Models.Generic.TimePlayedSortComparer(IsAscending),
|
||||
ApplicationSort.Title => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.TitleName)
|
||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.TitleName),
|
||||
ApplicationSort.Favorite => !IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Favorite)
|
||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Favorite),
|
||||
ApplicationSort.Developer => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Developer)
|
||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Developer),
|
||||
ApplicationSort.FileType => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.FileExtension)
|
||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.FileExtension),
|
||||
ApplicationSort.Path => IsAscending ? SortExpressionComparer<ApplicationData>.Ascending(app => app.Path)
|
||||
: SortExpressionComparer<ApplicationData>.Descending(app => app.Path),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
private void RefreshView()
|
||||
@@ -611,40 +619,31 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
|
||||
public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
|
||||
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
|
||||
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
|
||||
public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
|
||||
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
|
||||
public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed;
|
||||
public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed;
|
||||
public bool IsSortedByType => SortMode == ApplicationSort.FileType;
|
||||
public bool IsSortedBySize => SortMode == ApplicationSort.FileSize;
|
||||
public bool IsSortedByPath => SortMode == ApplicationSort.Path;
|
||||
public bool IsSortedByType => SortMode == ApplicationSort.FileType;
|
||||
public bool IsSortedBySize => SortMode == ApplicationSort.FileSize;
|
||||
public bool IsSortedByPath => SortMode == ApplicationSort.Path;
|
||||
|
||||
public string SortName
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (SortMode)
|
||||
return SortMode switch
|
||||
{
|
||||
case ApplicationSort.Title:
|
||||
return LocaleManager.Instance["GameListHeaderApplication"];
|
||||
case ApplicationSort.Developer:
|
||||
return LocaleManager.Instance["GameListHeaderDeveloper"];
|
||||
case ApplicationSort.LastPlayed:
|
||||
return LocaleManager.Instance["GameListHeaderLastPlayed"];
|
||||
case ApplicationSort.TotalTimePlayed:
|
||||
return LocaleManager.Instance["GameListHeaderTimePlayed"];
|
||||
case ApplicationSort.FileType:
|
||||
return LocaleManager.Instance["GameListHeaderFileExtension"];
|
||||
case ApplicationSort.FileSize:
|
||||
return LocaleManager.Instance["GameListHeaderFileSize"];
|
||||
case ApplicationSort.Path:
|
||||
return LocaleManager.Instance["GameListHeaderPath"];
|
||||
case ApplicationSort.Favorite:
|
||||
return LocaleManager.Instance["CommonFavorite"];
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
ApplicationSort.Title => LocaleManager.Instance["GameListHeaderApplication"],
|
||||
ApplicationSort.Developer => LocaleManager.Instance["GameListHeaderDeveloper"],
|
||||
ApplicationSort.LastPlayed => LocaleManager.Instance["GameListHeaderLastPlayed"],
|
||||
ApplicationSort.TotalTimePlayed => LocaleManager.Instance["GameListHeaderTimePlayed"],
|
||||
ApplicationSort.FileType => LocaleManager.Instance["GameListHeaderFileExtension"],
|
||||
ApplicationSort.FileSize => LocaleManager.Instance["GameListHeaderFileSize"],
|
||||
ApplicationSort.Path => LocaleManager.Instance["GameListHeaderPath"],
|
||||
ApplicationSort.Favorite => LocaleManager.Instance["CommonFavorite"],
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -668,6 +667,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
get => KeyGesture.Parse(_showUikey); set
|
||||
{
|
||||
_showUikey = value.ToString();
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -677,6 +677,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
get => KeyGesture.Parse(_screenshotkey); set
|
||||
{
|
||||
_screenshotkey = value.ToString();
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
@@ -686,14 +687,15 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
get => KeyGesture.Parse(_pauseKey); set
|
||||
{
|
||||
_pauseKey = value.ToString();
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1;
|
||||
public bool IsGridSmall => ConfigurationState.Instance.Ui.GridSize == 1;
|
||||
public bool IsGridMedium => ConfigurationState.Instance.Ui.GridSize == 2;
|
||||
public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3;
|
||||
public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4;
|
||||
public bool IsGridLarge => ConfigurationState.Instance.Ui.GridSize == 3;
|
||||
public bool IsGridHuge => ConfigurationState.Instance.Ui.GridSize == 4;
|
||||
|
||||
public int GridSizeScale
|
||||
{
|
||||
@@ -728,14 +730,14 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
if (_owner.AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
{
|
||||
string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper();
|
||||
string titleId = _owner.AppHost.Device.Application.TitleIdText.ToUpper();
|
||||
AmiiboWindow window = new(_showAll, _lastScannedAmiiboId, titleId);
|
||||
|
||||
await window.ShowDialog(_owner);
|
||||
|
||||
if (window.IsScanned)
|
||||
{
|
||||
_showAll = window.ViewModel.ShowAllAmiibo;
|
||||
_showAll = window.ViewModel.ShowAllAmiibo;
|
||||
_lastScannedAmiiboId = window.ScannedAmiibo.GetId();
|
||||
|
||||
_owner.AppHost.Device.System.ScanAmiibo(deviceId, _lastScannedAmiiboId, window.ViewModel.UseRandomUuid);
|
||||
@@ -766,8 +768,9 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
private void ApplicationLibrary_ApplicationCountUpdated(object sender, ApplicationCountUpdatedEventArgs e)
|
||||
{
|
||||
StatusBarProgressValue = e.NumAppsLoaded;
|
||||
StatusBarProgressValue = e.NumAppsLoaded;
|
||||
StatusBarProgressMaximum = e.NumAppsFound;
|
||||
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", StatusBarProgressValue, StatusBarProgressMaximum);
|
||||
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
@@ -792,9 +795,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
Applications.Clear();
|
||||
|
||||
_owner.LoadProgressBar.IsVisible = true;
|
||||
StatusBarProgressMaximum = 0;
|
||||
StatusBarProgressValue = 0;
|
||||
StatusBarProgressMaximum = 0;
|
||||
StatusBarProgressValue = 0;
|
||||
|
||||
LocaleManager.Instance.UpdateDynamicValue("StatusBarGamesLoaded", 0, 0);
|
||||
});
|
||||
|
||||
@@ -842,12 +847,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
}
|
||||
});
|
||||
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSP", Extensions = { "nsp" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "PFS0", Extensions = { "pfs0" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NCA", Extensions = { "nca" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NRO", Extensions = { "nro" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "NSO", Extensions = { "nso" } });
|
||||
|
||||
string[] files = await dialog.ShowAsync(_owner);
|
||||
|
||||
@@ -878,10 +883,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
ShowUiKey = new KeyGesture(showUiKey, KeyModifiers.None);
|
||||
}
|
||||
|
||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Screenshot, out var screenshotKey))
|
||||
{
|
||||
ScreenshotKey = new KeyGesture(screenshotKey, KeyModifiers.None);
|
||||
}
|
||||
|
||||
if (AvaloniaMappingHelper.TryGetAvaKey((Ryujinx.Input.Key)ConfigurationState.Instance.Hid.Hotkeys.Value.Pause, out var pauseKey))
|
||||
{
|
||||
PauseKey = new KeyGesture(pauseKey, KeyModifiers.None);
|
||||
@@ -941,9 +948,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
_lastFullscreenToggle = Environment.TickCount64;
|
||||
|
||||
WindowState state = _owner.WindowState;
|
||||
|
||||
if (state == WindowState.FullScreen)
|
||||
if (_owner.WindowState == WindowState.FullScreen)
|
||||
{
|
||||
_owner.WindowState = WindowState.Normal;
|
||||
|
||||
@@ -971,8 +976,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
if (IsGameRunning)
|
||||
{
|
||||
ConfigurationState.Instance.System.EnableDockedMode.Value =
|
||||
!ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||
ConfigurationState.Instance.System.EnableDockedMode.Value = !ConfigurationState.Instance.System.EnableDockedMode.Value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -985,6 +989,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
else if (IsGameRunning)
|
||||
{
|
||||
await Task.Delay(100);
|
||||
|
||||
_owner.AppHost?.ShowExitPrompt();
|
||||
}
|
||||
}
|
||||
@@ -994,6 +999,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
_owner.SettingsWindow = new(_owner.VirtualFileSystem, _owner.ContentManager);
|
||||
|
||||
await _owner.SettingsWindow.ShowDialog(_owner);
|
||||
|
||||
LoadConfigurableHotKeys();
|
||||
}
|
||||
|
||||
@@ -1004,9 +1010,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public async void OpenAboutWindow()
|
||||
{
|
||||
AboutWindow window = new();
|
||||
|
||||
await window.ShowDialog(_owner);
|
||||
await new AboutWindow().ShowDialog(_owner);
|
||||
}
|
||||
|
||||
public void ChangeLanguage(object obj)
|
||||
@@ -1020,7 +1024,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
try
|
||||
{
|
||||
ProgressMaximum = total;
|
||||
ProgressValue = current;
|
||||
ProgressValue = current;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
@@ -1030,13 +1034,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
case PtcLoadingState.Start:
|
||||
case PtcLoadingState.Loading:
|
||||
LoadHeading = LocaleManager.Instance["CompilingPPTC"];
|
||||
LoadHeading = LocaleManager.Instance["CompilingPPTC"];
|
||||
IsLoadingIndeterminate = false;
|
||||
break;
|
||||
case PtcLoadingState.Loaded:
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
IsLoadingIndeterminate = true;
|
||||
CacheLoadStatus = "";
|
||||
CacheLoadStatus = "";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1046,13 +1050,13 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
case ShaderCacheLoadingState.Start:
|
||||
case ShaderCacheLoadingState.Loading:
|
||||
LoadHeading = LocaleManager.Instance["CompilingShaders"];
|
||||
LoadHeading = LocaleManager.Instance["CompilingShaders"];
|
||||
IsLoadingIndeterminate = false;
|
||||
break;
|
||||
case ShaderCacheLoadingState.Loaded:
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
LoadHeading = string.Format(LocaleManager.Instance["LoadingHeading"], TitleName);
|
||||
IsLoadingIndeterminate = true;
|
||||
CacheLoadStatus = "";
|
||||
CacheLoadStatus = "";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -1065,14 +1069,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenUserSaveDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out ulong titleIdNumber))
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
@@ -1082,8 +1084,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
var userId = new LibHac.Fs.UserId((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
|
||||
var saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
|
||||
UserId userId = new((ulong)_owner.AccountManager.LastOpenedUser.UserId.High, (ulong)_owner.AccountManager.LastOpenedUser.UserId.Low);
|
||||
SaveDataFilter saveDataFilter = SaveDataFilter.Make(titleIdNumber, saveType: default, userId, saveDataId: default, index: default);
|
||||
OpenSaveDirectory(in saveDataFilter, selection, titleIdNumber);
|
||||
});
|
||||
}
|
||||
@@ -1091,8 +1093,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void ToggleFavorite()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
selection.Favorite = !selection.Favorite;
|
||||
@@ -1108,11 +1109,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenModsDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
|
||||
string modsBasePath = _owner.VirtualFileSystem.ModLoader.GetModsBasePath();
|
||||
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(modsBasePath, selection.TitleId);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
@@ -1121,12 +1121,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenSdModsDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
ApplicationData selection = SelectedApplication;
|
||||
|
||||
if (selection != null)
|
||||
{
|
||||
string sdModsBasePath = _owner.VirtualFileSystem.ModLoader.GetSdModsBasePath();
|
||||
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId);
|
||||
string titleModsPath = _owner.VirtualFileSystem.ModLoader.GetTitleDir(sdModsBasePath, selection.TitleId);
|
||||
|
||||
OpenHelper.OpenFolder(titleModsPath);
|
||||
}
|
||||
@@ -1134,13 +1134,11 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenPtcDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
|
||||
|
||||
string mainPath = Path.Combine(ptcDir, "0");
|
||||
string ptcDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu");
|
||||
string mainPath = Path.Combine(ptcDir, "0");
|
||||
string backupPath = Path.Combine(ptcDir, "1");
|
||||
|
||||
if (!Directory.Exists(ptcDir))
|
||||
@@ -1156,16 +1154,18 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public async void PurgePtcCache()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
|
||||
DirectoryInfo mainDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "0"));
|
||||
DirectoryInfo backupDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "cpu", "1"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogPPTCDeletionMessage"], selection.TitleName),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
List<FileInfo> cacheFiles = new();
|
||||
|
||||
@@ -1198,8 +1198,7 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenShaderCacheDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader");
|
||||
@@ -1220,18 +1219,20 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public async void PurgeShaderCache()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
DirectoryInfo shaderCacheDir = new(Path.Combine(AppDataManager.GamesDirPath, selection.TitleId, "cache", "shader"));
|
||||
|
||||
// FIXME: Found a way to reproduce the bold effect on the title name (fork?).
|
||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(LocaleManager.Instance["DialogWarning"],
|
||||
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName), LocaleManager.Instance["InputDialogYes"], LocaleManager.Instance["InputDialogNo"], LocaleManager.Instance["RyujinxConfirm"]);
|
||||
string.Format(LocaleManager.Instance["DialogShaderDeletionMessage"], selection.TitleName),
|
||||
LocaleManager.Instance["InputDialogYes"],
|
||||
LocaleManager.Instance["InputDialogNo"],
|
||||
LocaleManager.Instance["RyujinxConfirm"]);
|
||||
|
||||
List<DirectoryInfo> oldCacheDirectories = new List<DirectoryInfo>();
|
||||
List<FileInfo> newCacheFiles = new List<FileInfo>();
|
||||
List<DirectoryInfo> oldCacheDirectories = new();
|
||||
List<FileInfo> newCacheFiles = new();
|
||||
|
||||
if (shaderCacheDir.Exists)
|
||||
{
|
||||
@@ -1279,38 +1280,28 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public async void OpenTitleUpdateManager()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
TitleUpdateWindow titleUpdateManager =
|
||||
new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
|
||||
|
||||
await titleUpdateManager.ShowDialog(_owner);
|
||||
await new TitleUpdateWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
|
||||
}
|
||||
}
|
||||
|
||||
public async void OpenDownloadableContentManager()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
DownloadableContentManagerWindow downloadableContentManager = new(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName);
|
||||
|
||||
await downloadableContentManager.ShowDialog(_owner);
|
||||
await new DownloadableContentManagerWindow(_owner.VirtualFileSystem, ulong.Parse(selection.TitleId, NumberStyles.HexNumber), selection.TitleName).ShowDialog(_owner);
|
||||
}
|
||||
}
|
||||
|
||||
public async void OpenCheatManager()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
CheatWindow cheatManager = new(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName);
|
||||
|
||||
await cheatManager.ShowDialog(_owner);
|
||||
await new CheatWindow(_owner.VirtualFileSystem, selection.TitleId, selection.TitleName).ShowDialog(_owner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1321,13 +1312,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
return;
|
||||
}
|
||||
|
||||
var application = _owner.AppHost.Device.Application;
|
||||
|
||||
ApplicationLoader application = _owner.AppHost.Device.Application;
|
||||
if (application != null)
|
||||
{
|
||||
CheatWindow cheatManager = new(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName);
|
||||
|
||||
await cheatManager.ShowDialog(_owner);
|
||||
await new CheatWindow(_owner.VirtualFileSystem, application.TitleIdText, application.TitleName).ShowDialog(_owner);
|
||||
|
||||
_owner.AppHost.Device.EnableCheats();
|
||||
}
|
||||
@@ -1335,14 +1323,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenDeviceSaveDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out ulong titleIdNumber))
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
@@ -1360,14 +1346,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
public void OpenBcatSaveDirectory()
|
||||
{
|
||||
var selection = SelectedApplication;
|
||||
|
||||
ApplicationData selection = SelectedApplication;
|
||||
if (selection != null)
|
||||
{
|
||||
Task.Run(() =>
|
||||
{
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture,
|
||||
out ulong titleIdNumber))
|
||||
if (!ulong.TryParse(selection.TitleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNumber))
|
||||
{
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
@@ -1420,12 +1404,10 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
_owner.Close();
|
||||
}
|
||||
|
||||
private async Task HandleFirmwareInstallation(string path)
|
||||
private async Task HandleFirmwareInstallation(string filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
string filename = path;
|
||||
|
||||
SystemVersion firmwareVersion = _owner.ContentManager.VerifyFirmwarePackage(filename);
|
||||
|
||||
if (firmwareVersion == null)
|
||||
@@ -1437,7 +1419,6 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
|
||||
string dialogTitle = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallTitle"], firmwareVersion.VersionString);
|
||||
|
||||
|
||||
SystemVersion currentVersion = _owner.ContentManager.GetCurrentFirmwareVersion();
|
||||
|
||||
string dialogMessage = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallMessage"], firmwareVersion.VersionString);
|
||||
@@ -1480,11 +1461,12 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
string message = string.Format(LocaleManager.Instance["DialogFirmwareInstallerFirmwareInstallSuccessMessage"], firmwareVersion.VersionString);
|
||||
|
||||
await ContentDialogHelper.CreateInfoDialog(dialogTitle, message, LocaleManager.Instance["InputDialogOk"], "", LocaleManager.Instance["RyujinxInfo"]);
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, message);
|
||||
|
||||
// Purge Applet Cache.
|
||||
|
||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(System.IO.Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||
DirectoryInfo miiEditorCacheFolder = new DirectoryInfo(Path.Combine(AppDataManager.GamesDirPath, "0100000000001009", "cache"));
|
||||
|
||||
if (miiEditorCacheFolder.Exists)
|
||||
{
|
||||
@@ -1514,8 +1496,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
catch (LibHac.Common.Keys.MissingKeyException ex)
|
||||
{
|
||||
Logger.Error?.Print(LogClass.Application, ex.ToString());
|
||||
Dispatcher.UIThread.Post(async () => await
|
||||
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
|
||||
|
||||
Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys, _owner));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -1527,8 +1509,8 @@ namespace Ryujinx.Ava.Ui.ViewModels
|
||||
{
|
||||
OpenFileDialog dialog = new() { AllowMultiple = false };
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = LocaleManager.Instance["FileDialogAllTypes"], Extensions = { "xci", "zip" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "XCI", Extensions = { "xci" } });
|
||||
dialog.Filters.Add(new FileDialogFilter { Name = "ZIP", Extensions = { "zip" } });
|
||||
|
||||
string[] file = await dialog.ShowAsync(_owner);
|
||||
|
||||
|
@@ -3,89 +3,126 @@
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:locale="clr-namespace:Ryujinx.Ava.Common.Locale"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:window="clr-namespace:Ryujinx.Ava.Ui.Windows"
|
||||
SizeToContent="Height"
|
||||
Width="600" MinHeight="500" Height="500"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
Width="800"
|
||||
Height="500"
|
||||
MinWidth="600"
|
||||
MinHeight="500"
|
||||
SizeToContent="Height"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
mc:Ignorable="d">
|
||||
<Grid Name="DownloadableContentGrid" Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock
|
||||
Name="Heading"
|
||||
Grid.Row="1"
|
||||
MaxWidth="500"
|
||||
Margin="20,15,20,20"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
MaxWidth="500"
|
||||
LineHeight="18"
|
||||
TextWrapping="Wrap"
|
||||
Text="{Binding Heading}"
|
||||
TextAlignment="Center" />
|
||||
<Border
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap" />
|
||||
<DockPanel
|
||||
Grid.Row="2"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Left">
|
||||
<Button
|
||||
Name="EnableAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding EnableAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerEnableAllButton}" />
|
||||
</Button>
|
||||
<Button
|
||||
Name="DisableAllButton"
|
||||
MinWidth="90"
|
||||
Margin="5"
|
||||
Command="{Binding DisableAll}">
|
||||
<TextBlock Text="{locale:Locale DlcManagerDisableAllButton}" />
|
||||
</Button>
|
||||
</DockPanel>
|
||||
<Border
|
||||
Grid.Row="3"
|
||||
Margin="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
BorderBrush="Gray"
|
||||
BorderThickness="1">
|
||||
<DataGrid
|
||||
MinHeight="200"
|
||||
HorizontalAlignment="Stretch"
|
||||
<ScrollViewer
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
Items="{Binding DownloadableContents}"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="90">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox
|
||||
Width="50"
|
||||
MinWidth="40"
|
||||
HorizontalAlignment="Right"
|
||||
IsChecked="{Binding Enabled}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn
|
||||
Width="190"
|
||||
Binding="{Binding TitleId}"
|
||||
CanUserResize="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn
|
||||
Width="*"
|
||||
Binding="{Binding ContainerPath}"
|
||||
CanUserResize="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn
|
||||
Width="*"
|
||||
Binding="{Binding FullPath}"
|
||||
CanUserResize="True">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
<DataGrid
|
||||
Name="DlcDataGrid"
|
||||
MinHeight="200"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="True"
|
||||
CanUserSortColumns="True"
|
||||
HorizontalScrollBarVisibility="Auto"
|
||||
Items="{Binding _downloadableContents}"
|
||||
SelectionMode="Extended"
|
||||
VerticalScrollBarVisibility="Auto">
|
||||
<DataGrid.Styles>
|
||||
<Styles>
|
||||
<Style Selector="DataGridCell:nth-child(3), DataGridCell:nth-child(4)">
|
||||
<Setter Property="HorizontalAlignment" Value="Left" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Left" />
|
||||
</Style>
|
||||
</Styles>
|
||||
<Styles>
|
||||
<Style Selector="DataGridCell:nth-child(1)">
|
||||
<Setter Property="HorizontalAlignment" Value="Right" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Right" />
|
||||
</Style>
|
||||
</Styles>
|
||||
</DataGrid.Styles>
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="90">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<CheckBox
|
||||
Width="50"
|
||||
MinWidth="40"
|
||||
HorizontalAlignment="Center"
|
||||
IsChecked="{Binding Enabled}" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
<DataGridTemplateColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingEnabledLabel}" />
|
||||
</DataGridTemplateColumn.Header>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTextColumn Width="140" Binding="{Binding TitleId}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingTitleIdLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Width="280" Binding="{Binding FullPath}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingFullPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
<DataGridTextColumn Binding="{Binding ContainerPath}">
|
||||
<DataGridTextColumn.Header>
|
||||
<TextBlock Text="{locale:Locale DlcManagerTableHeadingContainerPathLabel}" />
|
||||
</DataGridTextColumn.Header>
|
||||
</DataGridTextColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<DockPanel
|
||||
Grid.Row="3"
|
||||
Grid.Row="4"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch">
|
||||
<DockPanel Margin="0" HorizontalAlignment="Left">
|
||||
|
@@ -8,6 +8,7 @@ using LibHac.FsSystem;
|
||||
using LibHac.Tools.Fs;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using LibHac.Tools.FsSystem.Save;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Ui.Controls;
|
||||
using Ryujinx.Ava.Ui.Models;
|
||||
@@ -16,8 +17,11 @@ using Ryujinx.Common.Utilities;
|
||||
using Ryujinx.HLE.FileSystem;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Path = System.IO.Path;
|
||||
@@ -27,14 +31,13 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
public partial class DownloadableContentManagerWindow : StyleableWindow
|
||||
{
|
||||
private readonly List<DownloadableContentContainer> _downloadableContentContainerList;
|
||||
private readonly string _downloadableContentJsonPath;
|
||||
private readonly string _downloadableContentJsonPath;
|
||||
|
||||
public VirtualFileSystem VirtualFileSystem { get; }
|
||||
public AvaloniaList<DownloadableContentModel> DownloadableContents { get; set; } = new AvaloniaList<DownloadableContentModel>();
|
||||
public ulong TitleId { get; }
|
||||
public string TitleName { get; }
|
||||
private VirtualFileSystem _virtualFileSystem { get; }
|
||||
private AvaloniaList<DownloadableContentModel> _downloadableContents { get; set; }
|
||||
|
||||
public string Heading => string.Format(LocaleManager.Instance["DlcWindowHeading"], TitleName, TitleId.ToString("X16"));
|
||||
private ulong TitleId { get; }
|
||||
private string TitleName { get; }
|
||||
|
||||
public DownloadableContentManagerWindow()
|
||||
{
|
||||
@@ -42,14 +45,15 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
|
||||
}
|
||||
|
||||
public DownloadableContentManagerWindow(VirtualFileSystem virtualFileSystem, ulong titleId, string titleName)
|
||||
{
|
||||
VirtualFileSystem = virtualFileSystem;
|
||||
TitleId = titleId;
|
||||
TitleName = titleName;
|
||||
_virtualFileSystem = virtualFileSystem;
|
||||
_downloadableContents = new AvaloniaList<DownloadableContentModel>();
|
||||
TitleId = titleId;
|
||||
TitleName = titleName;
|
||||
|
||||
_downloadableContentJsonPath = Path.Combine(AppDataManager.GamesDirPath, titleId.ToString("x16"), "dlc.json");
|
||||
|
||||
@@ -66,9 +70,24 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
InitializeComponent();
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - " + LocaleManager.Instance["DlcWindowTitle"];
|
||||
RemoveButton.IsEnabled = false;
|
||||
|
||||
DlcDataGrid.SelectionChanged += DlcDataGrid_SelectionChanged;
|
||||
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["DlcWindowTitle"]} - {TitleName} ({TitleId:X16})";
|
||||
|
||||
LoadDownloadableContents();
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
private void DlcDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
RemoveButton.IsEnabled = (DlcDataGrid.SelectedItems.Count > 0);
|
||||
}
|
||||
|
||||
private void PrintHeading()
|
||||
{
|
||||
Heading.Text = string.Format(LocaleManager.Instance["DlcWindowHeading"], _downloadableContents.Count, TitleName, TitleId.ToString("X16"));
|
||||
}
|
||||
|
||||
private void LoadDownloadableContents()
|
||||
@@ -79,23 +98,23 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
using FileStream containerFile = File.OpenRead(downloadableContentContainer.ContainerPath);
|
||||
|
||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
||||
PartitionFileSystem pfs = new(containerFile.AsStorage());
|
||||
|
||||
VirtualFileSystem.ImportTickets(pfs);
|
||||
_virtualFileSystem.ImportTickets(pfs);
|
||||
|
||||
foreach (DownloadableContentNca downloadableContentNca in downloadableContentContainer.DownloadableContentNcaList)
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
using UniqueRef<IFile> ncaFile = new();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref(), downloadableContentNca.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
|
||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), downloadableContentContainer.ContainerPath);
|
||||
if (nca != null)
|
||||
{
|
||||
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
|
||||
downloadableContentContainer.ContainerPath,
|
||||
downloadableContentNca.FullPath,
|
||||
downloadableContentNca.Enabled));
|
||||
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"),
|
||||
downloadableContentContainer.ContainerPath,
|
||||
downloadableContentNca.FullPath,
|
||||
downloadableContentNca.Enabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -105,11 +124,11 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
Save();
|
||||
}
|
||||
|
||||
private Nca TryCreateNca(IStorage ncaStorage, string containerPath)
|
||||
private Nca TryOpenNca(IStorage ncaStorage, string containerPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new Nca(VirtualFileSystem.KeySet, ncaStorage);
|
||||
return new Nca(_virtualFileSystem.KeySet, ncaStorage);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -124,61 +143,73 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
private async Task AddDownloadableContent(string path)
|
||||
{
|
||||
if (!File.Exists(path) || DownloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
|
||||
if (!File.Exists(path) || _downloadableContents.FirstOrDefault(x => x.ContainerPath == path) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (FileStream containerFile = File.OpenRead(path))
|
||||
using FileStream containerFile = File.OpenRead(path);
|
||||
|
||||
PartitionFileSystem partitionFileSystem = new(containerFile.AsStorage());
|
||||
bool containsDownloadableContent = false;
|
||||
|
||||
_virtualFileSystem.ImportTickets(partitionFileSystem);
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in partitionFileSystem.EnumerateEntries("/", "*.nca"))
|
||||
{
|
||||
PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage());
|
||||
bool containsDownloadableContent = false;
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
VirtualFileSystem.ImportTickets(pfs);
|
||||
partitionFileSystem.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||
Nca nca = TryOpenNca(ncaFile.Get.AsStorage(), path);
|
||||
if (nca == null)
|
||||
{
|
||||
using var ncaFile = new UniqueRef<IFile>();
|
||||
|
||||
pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
|
||||
|
||||
Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path);
|
||||
|
||||
if (nca == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||
{
|
||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
DownloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
|
||||
|
||||
containsDownloadableContent = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!containsDownloadableContent)
|
||||
if (nca.Header.ContentType == NcaContentType.PublicData)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
|
||||
if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
_downloadableContents.Add(new DownloadableContentModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true));
|
||||
|
||||
containsDownloadableContent = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!containsDownloadableContent)
|
||||
{
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveDownloadableContents(bool removeSelectedOnly = false)
|
||||
{
|
||||
if (removeSelectedOnly)
|
||||
{
|
||||
DownloadableContents.RemoveAll(DownloadableContents.Where(x => x.Enabled).ToList());
|
||||
AvaloniaList<DownloadableContentModel> removedItems = new();
|
||||
|
||||
foreach (var item in DlcDataGrid.SelectedItems)
|
||||
{
|
||||
removedItems.Add(item as DownloadableContentModel);
|
||||
}
|
||||
|
||||
DlcDataGrid.SelectedItems.Clear();
|
||||
|
||||
foreach (var item in removedItems)
|
||||
{
|
||||
_downloadableContents.RemoveAll(_downloadableContents.Where(x => x.TitleId == item.TitleId).ToList());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadableContents.Clear();
|
||||
_downloadableContents.Clear();
|
||||
}
|
||||
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
public void RemoveSelected()
|
||||
@@ -191,6 +222,22 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
RemoveDownloadableContents();
|
||||
}
|
||||
|
||||
public void EnableAll()
|
||||
{
|
||||
foreach(var item in _downloadableContents)
|
||||
{
|
||||
item.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableAll()
|
||||
{
|
||||
foreach (var item in _downloadableContents)
|
||||
{
|
||||
item.Enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
public async void Add()
|
||||
{
|
||||
OpenFileDialog dialog = new OpenFileDialog()
|
||||
@@ -214,6 +261,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
await AddDownloadableContent(file);
|
||||
}
|
||||
}
|
||||
|
||||
PrintHeading();
|
||||
}
|
||||
|
||||
public void Save()
|
||||
@@ -222,7 +271,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
DownloadableContentContainer container = default;
|
||||
|
||||
foreach (DownloadableContentModel downloadableContent in DownloadableContents)
|
||||
foreach (DownloadableContentModel downloadableContent in _downloadableContents)
|
||||
{
|
||||
if (container.ContainerPath != downloadableContent.ContainerPath)
|
||||
{
|
||||
|
@@ -90,8 +90,8 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
Title = $"Ryujinx {Program.Version}";
|
||||
|
||||
Height = Height / Program.WindowScaleFactor;
|
||||
Width = Width / Program.WindowScaleFactor;
|
||||
Height /= Program.WindowScaleFactor;
|
||||
Width /= Program.WindowScaleFactor;
|
||||
|
||||
if (Program.PreviewerDetached)
|
||||
{
|
||||
@@ -251,24 +251,29 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
AppHost = new AppHost(RendererControl, InputManager, path, VirtualFileSystem, ContentManager, AccountManager, _userChannelPersistence, this);
|
||||
|
||||
if (!AppHost.LoadGuestApplication().Result)
|
||||
Dispatcher.UIThread.Post(async () =>
|
||||
{
|
||||
AppHost.DisposeContext();
|
||||
if (!await AppHost.LoadGuestApplication())
|
||||
{
|
||||
AppHost.DisposeContext();
|
||||
AppHost = null;
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
ViewModel.LoadHeading = string.IsNullOrWhiteSpace(titleName) ? string.Format(LocaleManager.Instance["LoadingHeading"], AppHost.Device.Application.TitleName) : titleName;
|
||||
ViewModel.TitleName = string.IsNullOrWhiteSpace(titleName) ? AppHost.Device.Application.TitleName : titleName;
|
||||
|
||||
SwitchToGameControl(startFullscreen);
|
||||
SwitchToGameControl(startFullscreen);
|
||||
|
||||
_currentEmulatedGamePath = path;
|
||||
Thread gameThread = new Thread(InitializeGame)
|
||||
{
|
||||
Name = "GUI.WindowThread"
|
||||
};
|
||||
gameThread.Start();
|
||||
_currentEmulatedGamePath = path;
|
||||
|
||||
Thread gameThread = new(InitializeGame)
|
||||
{
|
||||
Name = "GUI.WindowThread"
|
||||
};
|
||||
gameThread.Start();
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeGame()
|
||||
@@ -518,23 +523,20 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
public static void UpdateGraphicsConfig()
|
||||
{
|
||||
int resScale = ConfigurationState.Instance.Graphics.ResScale;
|
||||
float resScaleCustom = ConfigurationState.Instance.Graphics.ResScaleCustom;
|
||||
|
||||
GraphicsConfig.ResScale = resScale == -1 ? resScaleCustom : resScale;
|
||||
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||
GraphicsConfig.ResScale = ConfigurationState.Instance.Graphics.ResScale == -1 ? ConfigurationState.Instance.Graphics.ResScaleCustom : ConfigurationState.Instance.Graphics.ResScale;
|
||||
GraphicsConfig.MaxAnisotropy = ConfigurationState.Instance.Graphics.MaxAnisotropy;
|
||||
GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath;
|
||||
GraphicsConfig.EnableShaderCache = ConfigurationState.Instance.Graphics.EnableShaderCache;
|
||||
GraphicsConfig.EnableTextureRecompression = ConfigurationState.Instance.Graphics.EnableTextureRecompression;
|
||||
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||
GraphicsConfig.EnableMacroHLE = ConfigurationState.Instance.Graphics.EnableMacroHLE;
|
||||
}
|
||||
|
||||
public void LoadHotKeys()
|
||||
{
|
||||
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
|
||||
HotKeyManager.SetHotKey(FullscreenHotKey, new KeyGesture(Key.Enter, KeyModifiers.Alt));
|
||||
HotKeyManager.SetHotKey(FullscreenHotKey2, new KeyGesture(Key.F11));
|
||||
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
|
||||
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
||||
HotKeyManager.SetHotKey(DockToggleHotKey, new KeyGesture(Key.F9));
|
||||
HotKeyManager.SetHotKey(ExitHotKey, new KeyGesture(Key.Escape));
|
||||
}
|
||||
|
||||
public static void SaveConfig()
|
||||
@@ -546,10 +548,12 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
ApplicationLibrary.LoadAndSaveMetaData(titleId, appMetadata =>
|
||||
{
|
||||
DateTime lastPlayedDateTime = DateTime.Parse(appMetadata.LastPlayed);
|
||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
||||
if (DateTime.TryParse(appMetadata.LastPlayed, out DateTime lastPlayedDateTime))
|
||||
{
|
||||
double sessionTimePlayed = DateTime.UtcNow.Subtract(lastPlayedDateTime).TotalSeconds;
|
||||
|
||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
||||
appMetadata.TimePlayed += Math.Round(sessionTimePlayed, MidpointRounding.AwayFromZero);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@@ -75,7 +75,7 @@
|
||||
Spacing="10">
|
||||
<ListBox
|
||||
Name="GameList"
|
||||
MinHeight="150"
|
||||
MinHeight="250"
|
||||
Items="{Binding GameDirectories}" />
|
||||
<Grid HorizontalAlignment="Stretch">
|
||||
<Grid.ColumnDefinitions>
|
||||
|
@@ -16,7 +16,6 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using TimeZone = Ryujinx.Ava.Ui.Models.TimeZone;
|
||||
|
||||
namespace Ryujinx.Ava.Ui.Windows
|
||||
@@ -31,7 +30,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
Title = $"Ryujinx {Program.Version} - {LocaleManager.Instance["Settings"]}";
|
||||
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
||||
ViewModel = new SettingsViewModel(virtualFileSystem, contentManager, this);
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
@@ -48,7 +47,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
public SettingsWindow()
|
||||
{
|
||||
ViewModel = new SettingsViewModel();
|
||||
ViewModel = new SettingsViewModel();
|
||||
DataContext = ViewModel;
|
||||
|
||||
InitializeComponent();
|
||||
@@ -79,7 +78,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
PointerPressed += MouseClick;
|
||||
|
||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||
IKeyboard keyboard = (IKeyboard)ViewModel.AvaloniaKeyboardDriver.GetGamepad(ViewModel.AvaloniaKeyboardDriver.GamepadsIds[0]);
|
||||
IButtonAssigner assigner = new KeyboardKeyAssigner(keyboard);
|
||||
|
||||
_currentAssigner.GetInputAndAssign(assigner);
|
||||
@@ -92,6 +91,7 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
_currentAssigner.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
button.IsChecked = false;
|
||||
}
|
||||
}
|
||||
@@ -122,36 +122,19 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
{
|
||||
if (e.SelectedItem is NavigationViewItem navitem)
|
||||
{
|
||||
switch (navitem.Tag.ToString())
|
||||
NavPanel.Content = navitem.Tag.ToString() switch
|
||||
{
|
||||
case "UiPage":
|
||||
NavPanel.Content = UiPage;
|
||||
break;
|
||||
case "InputPage":
|
||||
NavPanel.Content = InputPage;
|
||||
break;
|
||||
case "HotkeysPage":
|
||||
NavPanel.Content = HotkeysPage;
|
||||
break;
|
||||
case "SystemPage":
|
||||
NavPanel.Content = SystemPage;
|
||||
break;
|
||||
case "CpuPage":
|
||||
NavPanel.Content = CpuPage;
|
||||
break;
|
||||
case "GraphicsPage":
|
||||
NavPanel.Content = GraphicsPage;
|
||||
break;
|
||||
case "AudioPage":
|
||||
NavPanel.Content = AudioPage;
|
||||
break;
|
||||
case "NetworkPage":
|
||||
NavPanel.Content = NetworkPage;
|
||||
break;
|
||||
case "LoggingPage":
|
||||
NavPanel.Content = LoggingPage;
|
||||
break;
|
||||
}
|
||||
"UiPage" => UiPage,
|
||||
"InputPage" => InputPage,
|
||||
"HotkeysPage" => HotkeysPage,
|
||||
"SystemPage" => SystemPage,
|
||||
"CpuPage" => CpuPage,
|
||||
"GraphicsPage" => GraphicsPage,
|
||||
"AudioPage" => AudioPage,
|
||||
"NetworkPage" => NetworkPage,
|
||||
"LoggingPage" => LoggingPage,
|
||||
_ => throw new NotImplementedException()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,13 +161,18 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
|
||||
private void RemoveButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
List<string> selected = new(GameList.SelectedItems.Cast<string>());
|
||||
int oldIndex = GameList.SelectedIndex;
|
||||
|
||||
foreach (string path in selected)
|
||||
foreach (string path in new List<string>(GameList.SelectedItems.Cast<string>()))
|
||||
{
|
||||
ViewModel.GameDirectories.Remove(path);
|
||||
ViewModel.DirectoryChanged = true;
|
||||
}
|
||||
|
||||
if (GameList.ItemCount > 0)
|
||||
{
|
||||
GameList.SelectedIndex = oldIndex < GameList.ItemCount ? oldIndex : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void TimeZoneBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
@@ -214,7 +202,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
private void SaveButton_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
SaveSettings();
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
@@ -232,7 +219,6 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
private void SaveSettings()
|
||||
{
|
||||
ViewModel.SaveSettings();
|
||||
|
||||
ControllerSettings?.SaveCurrentProfile();
|
||||
|
||||
if (Owner is MainWindow window && ViewModel.DirectoryChanged)
|
||||
@@ -246,8 +232,10 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
protected override void OnClosed(EventArgs e)
|
||||
{
|
||||
ControllerSettings.Dispose();
|
||||
|
||||
_currentAssigner?.Cancel();
|
||||
_currentAssigner = null;
|
||||
|
||||
base.OnClosed(e);
|
||||
}
|
||||
}
|
||||
|
@@ -131,6 +131,13 @@ namespace Ryujinx.Ava.Ui.Windows
|
||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure();
|
||||
|
||||
TitleUpdates.Add(new TitleUpdateModel(controlData, path));
|
||||
|
||||
foreach (var update in TitleUpdates)
|
||||
{
|
||||
update.IsEnabled = false;
|
||||
}
|
||||
|
||||
TitleUpdates.Last().IsEnabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
@@ -7,49 +8,15 @@ namespace Ryujinx.Common
|
||||
public static class BinaryReaderExtensions
|
||||
{
|
||||
public unsafe static T ReadStruct<T>(this BinaryReader reader)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T[] ReadStructArray<T>(this BinaryReader reader, int count)
|
||||
where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
T[] result = new T[count];
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
byte[] data = reader.ReadBytes(size);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
result[i] = Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return MemoryMarshal.Cast<byte, T>(reader.ReadBytes(Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static void WriteStruct<T>(this BinaryWriter writer, T value)
|
||||
where T : struct
|
||||
where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
writer.Write(data);
|
||||
}
|
||||
|
@@ -180,6 +180,37 @@ namespace Ryujinx.Cpu.Jit
|
||||
WriteImpl(va, data);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
if (data.Length == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
if (IsContiguousAndMapped(va, data.Length))
|
||||
{
|
||||
var target = _backingMemory.GetSpan(GetPhysicalAddressInternal(va), data.Length);
|
||||
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteImpl(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to CPU mapped memory.
|
||||
/// </summary>
|
||||
|
@@ -307,6 +307,34 @@ namespace Ryujinx.Cpu.Jit
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
try
|
||||
{
|
||||
SignalMemoryTracking(va, (ulong)data.Length, false);
|
||||
|
||||
Span<byte> target = _addressSpaceMirror.GetSpan(va, data.Length);
|
||||
bool changed = !data.SequenceEqual(target);
|
||||
|
||||
if (changed)
|
||||
{
|
||||
data.CopyTo(target);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
catch (InvalidMemoryRegionException)
|
||||
{
|
||||
if (_invalidAccessHandler == null || !_invalidAccessHandler(va))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -23,34 +24,18 @@ namespace Ryujinx.Cpu
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : struct
|
||||
public unsafe static T Read<T>(IVirtualMemoryManager memory, ulong position) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
memory.Read(position, data);
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
return Marshal.PtrToStructure<T>((IntPtr)ptr);
|
||||
}
|
||||
return MemoryMarshal.Cast<byte, T>(memory.GetSpan(position, Unsafe.SizeOf<T>()))[0];
|
||||
}
|
||||
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : struct
|
||||
public unsafe static ulong Write<T>(IVirtualMemoryManager memory, ulong position, T value) where T : unmanaged
|
||||
{
|
||||
long size = Marshal.SizeOf<T>();
|
||||
|
||||
byte[] data = new byte[size];
|
||||
|
||||
fixed (byte* ptr = data)
|
||||
{
|
||||
Marshal.StructureToPtr<T>(value, (IntPtr)ptr, false);
|
||||
}
|
||||
ReadOnlySpan<byte> data = MemoryMarshal.Cast<T, byte>(MemoryMarshal.CreateReadOnlySpan(ref value, 1));
|
||||
|
||||
memory.Write(position, data);
|
||||
|
||||
return (ulong)size;
|
||||
return (ulong)data.Length;
|
||||
}
|
||||
|
||||
public static string ReadAsciiString(IVirtualMemoryManager memory, ulong position, long maxSize = -1)
|
||||
|
14
Ryujinx.Graphics.GAL/BufferAssignment.cs
Normal file
14
Ryujinx.Graphics.GAL/BufferAssignment.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
namespace Ryujinx.Graphics.GAL
|
||||
{
|
||||
public struct BufferAssignment
|
||||
{
|
||||
public readonly int Binding;
|
||||
public readonly BufferRange Range;
|
||||
|
||||
public BufferAssignment(int binding, BufferRange range)
|
||||
{
|
||||
Binding = binding;
|
||||
Range = range;
|
||||
}
|
||||
}
|
||||
}
|
@@ -86,12 +86,12 @@ namespace Ryujinx.Graphics.GAL
|
||||
|
||||
void SetStencilTest(StencilTestDescriptor stencilTest);
|
||||
|
||||
void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers);
|
||||
void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||
|
||||
void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler);
|
||||
|
||||
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
|
||||
void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers);
|
||||
void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers);
|
||||
|
||||
void SetUserClipDistance(int index, bool enableClip);
|
||||
|
||||
|
@@ -142,6 +142,30 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
return ranges;
|
||||
}
|
||||
|
||||
internal Span<BufferAssignment> MapBufferRanges(Span<BufferAssignment> ranges)
|
||||
{
|
||||
// Rewrite the buffer ranges to point to the mapped handles.
|
||||
|
||||
lock (_bufferMap)
|
||||
{
|
||||
for (int i = 0; i < ranges.Length; i++)
|
||||
{
|
||||
ref BufferAssignment assignment = ref ranges[i];
|
||||
BufferRange range = assignment.Range;
|
||||
BufferHandle result;
|
||||
|
||||
if (!_bufferMap.TryGetValue(range.Handle, out result))
|
||||
{
|
||||
result = BufferHandle.Null;
|
||||
}
|
||||
|
||||
assignment = new BufferAssignment(ranges[i].Binding, new BufferRange(result, range.Offset, range.Size));
|
||||
}
|
||||
}
|
||||
|
||||
return ranges;
|
||||
}
|
||||
|
||||
internal Span<VertexBufferDescriptor> MapBufferRanges(Span<VertexBufferDescriptor> ranges)
|
||||
{
|
||||
// Rewrite the buffer ranges to point to the mapped handles.
|
||||
|
@@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
struct SetStorageBuffersCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.SetStorageBuffers;
|
||||
private int _first;
|
||||
private SpanRef<BufferRange> _buffers;
|
||||
private SpanRef<BufferAssignment> _buffers;
|
||||
|
||||
public void Set(int first, SpanRef<BufferRange> buffers)
|
||||
public void Set(SpanRef<BufferAssignment> buffers)
|
||||
{
|
||||
_first = first;
|
||||
_buffers = buffers;
|
||||
}
|
||||
|
||||
public static void Run(ref SetStorageBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
Span<BufferRange> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetStorageBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
|
||||
Span<BufferAssignment> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetStorageBuffers(threaded.Buffers.MapBufferRanges(buffers));
|
||||
command._buffers.Dispose(threaded);
|
||||
}
|
||||
}
|
||||
|
@@ -6,19 +6,17 @@ namespace Ryujinx.Graphics.GAL.Multithreading.Commands
|
||||
struct SetUniformBuffersCommand : IGALCommand
|
||||
{
|
||||
public CommandType CommandType => CommandType.SetUniformBuffers;
|
||||
private int _first;
|
||||
private SpanRef<BufferRange> _buffers;
|
||||
private SpanRef<BufferAssignment> _buffers;
|
||||
|
||||
public void Set(int first, SpanRef<BufferRange> buffers)
|
||||
public void Set(SpanRef<BufferAssignment> buffers)
|
||||
{
|
||||
_first = first;
|
||||
_buffers = buffers;
|
||||
}
|
||||
|
||||
public static void Run(ref SetUniformBuffersCommand command, ThreadedRenderer threaded, IRenderer renderer)
|
||||
{
|
||||
Span<BufferRange> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetUniformBuffers(command._first, threaded.Buffers.MapBufferRanges(buffers));
|
||||
Span<BufferAssignment> buffers = command._buffers.Get(threaded);
|
||||
renderer.Pipeline.SetUniformBuffers(threaded.Buffers.MapBufferRanges(buffers));
|
||||
command._buffers.Dispose(threaded);
|
||||
}
|
||||
}
|
||||
|
@@ -275,9 +275,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_renderer.New<SetStorageBuffersCommand>().Set(first, _renderer.CopySpan(buffers));
|
||||
_renderer.New<SetStorageBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
@@ -293,9 +293,9 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_renderer.New<SetUniformBuffersCommand>().Set(first, _renderer.CopySpan(buffers));
|
||||
_renderer.New<SetUniformBuffersCommand>().Set(_renderer.CopySpan(buffers));
|
||||
_renderer.QueueCommand();
|
||||
}
|
||||
|
||||
|
@@ -422,7 +422,11 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
|
||||
// Stop the GPU thread.
|
||||
_disposed = true;
|
||||
_gpuThread.Join();
|
||||
|
||||
if (_gpuThread != null && _gpuThread.IsAlive)
|
||||
{
|
||||
_gpuThread.Join();
|
||||
}
|
||||
|
||||
// Dispose the renderer.
|
||||
_baseRenderer.Dispose();
|
||||
@@ -435,4 +439,4 @@ namespace Ryujinx.Graphics.GAL.Multithreading
|
||||
Sync.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -51,16 +51,35 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
/// </summary>
|
||||
public uint EntryCount;
|
||||
|
||||
/// <summary>
|
||||
/// Get the entries for the command buffer from memory.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
|
||||
/// <returns>The fetched data</returns>
|
||||
private ReadOnlySpan<int> GetWords(MemoryManager memoryManager, bool flush)
|
||||
{
|
||||
return MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prefetch the command buffer.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
public void Prefetch(MemoryManager memoryManager)
|
||||
{
|
||||
Words = GetWords(memoryManager, true).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetch the command buffer.
|
||||
/// </summary>
|
||||
/// <param name="memoryManager">The memory manager used to fetch the data</param>
|
||||
/// <param name="flush">If true, flushes potential GPU written data before reading the command buffer</param>
|
||||
public void Fetch(MemoryManager memoryManager, bool flush = true)
|
||||
/// <returns>The command buffer words</returns>
|
||||
public ReadOnlySpan<int> Fetch(MemoryManager memoryManager, bool flush)
|
||||
{
|
||||
if (Words == null)
|
||||
{
|
||||
Words = MemoryMarshal.Cast<byte, int>(memoryManager.GetSpan(EntryAddress, (int)EntryCount * 4, flush)).ToArray();
|
||||
}
|
||||
return Words ?? GetWords(memoryManager, flush);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +177,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
|
||||
if (beforeBarrier && commandBuffer.Type == CommandBufferType.Prefetch)
|
||||
{
|
||||
commandBuffer.Fetch(processor.MemoryManager);
|
||||
commandBuffer.Prefetch(processor.MemoryManager);
|
||||
}
|
||||
|
||||
if (commandBuffer.Type == CommandBufferType.NoPrefetch)
|
||||
@@ -199,7 +218,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
}
|
||||
|
||||
_currentCommandBuffer = entry;
|
||||
_currentCommandBuffer.Fetch(entry.Processor.MemoryManager, flushCommandBuffer);
|
||||
ReadOnlySpan<int> words = entry.Fetch(entry.Processor.MemoryManager, flushCommandBuffer);
|
||||
|
||||
// If we are changing the current channel,
|
||||
// we need to force all the host state to be updated.
|
||||
@@ -209,7 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
|
||||
entry.Processor.ForceAllDirty();
|
||||
}
|
||||
|
||||
entry.Processor.Process(entry.EntryAddress, _currentCommandBuffer.Words);
|
||||
entry.Processor.Process(entry.EntryAddress, words);
|
||||
}
|
||||
|
||||
_interrupt = false;
|
||||
|
@@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
/// </summary>
|
||||
class ConstantBufferUpdater
|
||||
{
|
||||
private const int UniformDataCacheSize = 512;
|
||||
|
||||
private readonly GpuChannel _channel;
|
||||
private readonly DeviceStateWithShadow<ThreedClassState> _state;
|
||||
|
||||
@@ -16,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
private ulong _ubBeginCpuAddress = 0;
|
||||
private ulong _ubFollowUpAddress = 0;
|
||||
private ulong _ubByteCount = 0;
|
||||
private int _ubIndex = 0;
|
||||
private int[] _ubData = new int[UniformDataCacheSize];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the constant buffer updater.
|
||||
@@ -108,9 +112,16 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
if (_ubFollowUpAddress != 0)
|
||||
{
|
||||
var memoryManager = _channel.MemoryManager;
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
|
||||
Span<byte> data = MemoryMarshal.Cast<int, byte>(_ubData.AsSpan(0, (int)(_ubByteCount / 4)));
|
||||
|
||||
if (memoryManager.Physical.WriteWithRedundancyCheck(_ubBeginCpuAddress, data))
|
||||
{
|
||||
memoryManager.Physical.BufferCache.ForceDirty(memoryManager, _ubFollowUpAddress - _ubByteCount, _ubByteCount);
|
||||
}
|
||||
|
||||
_ubFollowUpAddress = 0;
|
||||
_ubIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +135,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong address = uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex == _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -132,8 +143,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(MemoryMarshal.CreateSpan(ref argument, 1));
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
_ubData[_ubIndex++] = argument;
|
||||
|
||||
_ubFollowUpAddress = address + 4;
|
||||
_ubByteCount += 4;
|
||||
@@ -153,7 +163,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
|
||||
ulong size = (ulong)data.Length * 4;
|
||||
|
||||
if (_ubFollowUpAddress != address)
|
||||
if (_ubFollowUpAddress != address || _ubIndex + data.Length > _ubData.Length)
|
||||
{
|
||||
FlushUboDirty();
|
||||
|
||||
@@ -161,8 +171,8 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
_ubBeginCpuAddress = _channel.MemoryManager.Translate(address);
|
||||
}
|
||||
|
||||
var byteData = MemoryMarshal.Cast<int, byte>(data);
|
||||
_channel.MemoryManager.Physical.WriteUntracked(_ubBeginCpuAddress + _ubByteCount, byteData);
|
||||
data.CopyTo(_ubData.AsSpan(_ubIndex));
|
||||
_ubIndex += data.Length;
|
||||
|
||||
_ubFollowUpAddress = address + size;
|
||||
_ubByteCount += size;
|
||||
|
@@ -372,7 +372,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
|
||||
float srcX1 = ((float)_state.State.DrawTextureDuDx / (1UL << 32)) * dstWidth + srcX0;
|
||||
float srcY1 = ((float)_state.State.DrawTextureDvDy / (1UL << 32)) * dstHeight + srcY0;
|
||||
|
||||
engine.UpdateState();
|
||||
engine.UpdateState(ulong.MaxValue & ~(1UL << StateUpdater.ShaderStateIndex));
|
||||
|
||||
_channel.TextureManager.UpdateRenderTargets();
|
||||
|
||||
int textureId = _state.State.DrawTextureTextureId;
|
||||
int samplerId = _state.State.DrawTextureSamplerId;
|
||||
|
@@ -22,6 +22,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private readonly GpuContext _context;
|
||||
private readonly PhysicalMemory _physicalMemory;
|
||||
|
||||
/// <remarks>
|
||||
/// Only modified from the GPU thread. Must lock for add/remove.
|
||||
/// Must lock for any access from other threads.
|
||||
/// </remarks>
|
||||
private readonly RangeList<Buffer> _buffers;
|
||||
|
||||
private Buffer[] _bufferOverlaps;
|
||||
@@ -200,12 +204,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="size">Size in bytes of the buffer</param>
|
||||
private void CreateBufferAligned(ulong address, ulong size)
|
||||
{
|
||||
int overlapsCount;
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
||||
}
|
||||
int overlapsCount = _buffers.FindOverlapsNonOverlapping(address, size, ref _bufferOverlaps);
|
||||
|
||||
if (overlapsCount != 0)
|
||||
{
|
||||
@@ -410,10 +409,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
}
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
|
||||
@@ -424,10 +420,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||
}
|
||||
buffer = _buffers.FindFirstOverlap(address, 1);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@@ -442,12 +435,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
{
|
||||
if (size != 0)
|
||||
{
|
||||
Buffer buffer;
|
||||
|
||||
lock (_buffers)
|
||||
{
|
||||
buffer = _buffers.FindFirstOverlap(address, size);
|
||||
}
|
||||
Buffer buffer = _buffers.FindFirstOverlap(address, size);
|
||||
|
||||
buffer.SynchronizeMemory(address, size);
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
private readonly VertexBuffer[] _vertexBuffers;
|
||||
private readonly BufferBounds[] _transformFeedbackBuffers;
|
||||
private readonly List<BufferTextureBinding> _bufferTextures;
|
||||
private readonly BufferRange[] _ranges;
|
||||
private readonly BufferAssignment[] _ranges;
|
||||
|
||||
/// <summary>
|
||||
/// Holds shader stage buffer state and binding information.
|
||||
@@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
|
||||
_bufferTextures = new List<BufferTextureBinding>();
|
||||
|
||||
_ranges = new BufferRange[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
||||
_ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
|
||||
}
|
||||
|
||||
|
||||
@@ -618,10 +618,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void BindBuffers(BufferCache bufferCache, BuffersPerStage[] bindings, bool isStorage)
|
||||
{
|
||||
int rangesFirst = 0;
|
||||
int rangesCount = 0;
|
||||
|
||||
Span<BufferRange> ranges = _ranges;
|
||||
Span<BufferAssignment> ranges = _ranges;
|
||||
|
||||
for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++)
|
||||
{
|
||||
@@ -640,25 +639,14 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
|
||||
if (rangesCount == 0)
|
||||
{
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
}
|
||||
else if (bindingInfo.Binding != rangesFirst + rangesCount)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
rangesCount = 0;
|
||||
}
|
||||
|
||||
ranges[rangesCount++] = range;
|
||||
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rangesCount != 0)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
SetHostBuffers(ranges, rangesCount, isStorage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -671,10 +659,9 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void BindBuffers(BufferCache bufferCache, BuffersPerStage buffers, bool isStorage)
|
||||
{
|
||||
int rangesFirst = 0;
|
||||
int rangesCount = 0;
|
||||
|
||||
Span<BufferRange> ranges = _ranges;
|
||||
Span<BufferAssignment> ranges = _ranges;
|
||||
|
||||
for (int index = 0; index < buffers.Count; index++)
|
||||
{
|
||||
@@ -689,24 +676,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
? bufferCache.GetBufferRangeTillEnd(bounds.Address, bounds.Size, isWrite)
|
||||
: bufferCache.GetBufferRange(bounds.Address, bounds.Size);
|
||||
|
||||
if (rangesCount == 0)
|
||||
{
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
}
|
||||
else if (bindingInfo.Binding != rangesFirst + rangesCount)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
rangesFirst = bindingInfo.Binding;
|
||||
rangesCount = 0;
|
||||
}
|
||||
|
||||
ranges[rangesCount++] = range;
|
||||
ranges[rangesCount++] = new BufferAssignment(bindingInfo.Binding, range);
|
||||
}
|
||||
}
|
||||
|
||||
if (rangesCount != 0)
|
||||
{
|
||||
SetHostBuffers(ranges, rangesFirst, rangesCount, isStorage);
|
||||
SetHostBuffers(ranges, rangesCount, isStorage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,15 +694,15 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
/// <param name="count">Number of bindings</param>
|
||||
/// <param name="isStorage">Indicates if the buffers are storage or uniform buffers</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void SetHostBuffers(ReadOnlySpan<BufferRange> ranges, int first, int count, bool isStorage)
|
||||
private void SetHostBuffers(ReadOnlySpan<BufferAssignment> ranges, int count, bool isStorage)
|
||||
{
|
||||
if (isStorage)
|
||||
{
|
||||
_context.Renderer.Pipeline.SetStorageBuffers(first, ranges.Slice(0, count));
|
||||
_context.Renderer.Pipeline.SetStorageBuffers(ranges.Slice(0, count));
|
||||
}
|
||||
else
|
||||
{
|
||||
_context.Renderer.Pipeline.SetUniformBuffers(first, ranges.Slice(0, count));
|
||||
_context.Renderer.Pipeline.SetUniformBuffers(ranges.Slice(0, count));
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -242,6 +242,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
||||
WriteImpl(range, data, _cpuMemory.WriteUntracked);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="address">Address to write into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
public bool WriteWithRedundancyCheck(ulong address, ReadOnlySpan<byte> data)
|
||||
{
|
||||
return _cpuMemory.WriteWithRedundancyCheck(address, data);
|
||||
}
|
||||
|
||||
private delegate void WriteCallback(ulong address, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
|
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
|
||||
private const ushort FileFormatVersionMajor = 1;
|
||||
private const ushort FileFormatVersionMinor = 2;
|
||||
private const uint FileFormatVersionPacked = ((uint)FileFormatVersionMajor << 16) | FileFormatVersionMinor;
|
||||
private const uint CodeGenVersion = 3868;
|
||||
private const uint CodeGenVersion = 3897;
|
||||
|
||||
private const string SharedTocFileName = "shared.toc";
|
||||
private const string SharedDataFileName = "shared.data";
|
||||
|
@@ -1296,9 +1296,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
_stencilFrontMask = stencilTest.FrontMask;
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
SetBuffers(first, buffers, isStorage: true);
|
||||
SetBuffers(buffers, isStorage: true);
|
||||
}
|
||||
|
||||
public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
|
||||
@@ -1366,9 +1366,9 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
SetBuffers(first, buffers, isStorage: false);
|
||||
SetBuffers(buffers, isStorage: false);
|
||||
}
|
||||
|
||||
public void SetUserClipDistance(int index, bool enableClip)
|
||||
@@ -1460,21 +1460,22 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
|
||||
}
|
||||
|
||||
private void SetBuffers(int first, ReadOnlySpan<BufferRange> buffers, bool isStorage)
|
||||
private void SetBuffers(ReadOnlySpan<BufferAssignment> buffers, bool isStorage)
|
||||
{
|
||||
BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
|
||||
|
||||
for (int index = 0; index < buffers.Length; index++)
|
||||
{
|
||||
BufferRange buffer = buffers[index];
|
||||
BufferAssignment assignment = buffers[index];
|
||||
BufferRange buffer = assignment.Range;
|
||||
|
||||
if (buffer.Handle == BufferHandle.Null)
|
||||
{
|
||||
GL.BindBufferRange(target, first + index, 0, IntPtr.Zero, 0);
|
||||
GL.BindBufferRange(target, assignment.Binding, 0, IntPtr.Zero, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
GL.BindBufferRange(target, first + index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
GL.BindBufferRange(target, assignment.Binding, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -54,4 +54,4 @@ namespace Ryujinx.Graphics.OpenGL.Queries
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -10,6 +10,8 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
private const int TextureCount = 3;
|
||||
private readonly OpenGLRenderer _renderer;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
private int _width;
|
||||
private int _height;
|
||||
private int _copyFramebufferHandle;
|
||||
@@ -179,6 +181,7 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
public void InitializeBackgroundContext(IOpenGLContext baseContext)
|
||||
{
|
||||
BackgroundContext = new BackgroundContextWorker(baseContext);
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public void CaptureFrame(int x, int y, int width, int height, bool isBgra, bool flipX, bool flipY)
|
||||
@@ -193,6 +196,11 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BackgroundContext.Dispose();
|
||||
|
||||
if (_copyFramebufferHandle != 0)
|
||||
@@ -203,4 +211,4 @@ namespace Ryujinx.Graphics.OpenGL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -128,6 +128,11 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
GetStorageOffset(block, Utils.FindLastOperation(addrLow, block), baseAddressCbOffset) :
|
||||
(null, 0);
|
||||
|
||||
if (byteOffset != null)
|
||||
{
|
||||
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
|
||||
}
|
||||
|
||||
if (byteOffset == null)
|
||||
{
|
||||
Operand baseAddrLow = Cbuf(0, baseAddressCbOffset);
|
||||
@@ -156,11 +161,6 @@ namespace Ryujinx.Graphics.Shader.Translation.Optimizations
|
||||
byteOffset = offset;
|
||||
}
|
||||
|
||||
if (byteOffset != null)
|
||||
{
|
||||
ReplaceAddressAlignment(node.List, addrLow, byteOffset, constantOffset);
|
||||
}
|
||||
|
||||
if (isStg16Or8)
|
||||
{
|
||||
return byteOffset;
|
||||
|
@@ -163,12 +163,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SignalDirty(DirtyFlags.Image);
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
for (int i = 0; i < buffers.Length; i++)
|
||||
{
|
||||
var buffer = buffers[i];
|
||||
int index = first + i;
|
||||
var assignment = buffers[i];
|
||||
var buffer = assignment.Range;
|
||||
int index = assignment.Binding;
|
||||
|
||||
Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
|
||||
ref Auto<DisposableBuffer> currentVkBuffer = ref _storageBufferRefs[index];
|
||||
@@ -243,12 +244,13 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SignalDirty(DirtyFlags.Texture);
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(CommandBuffer commandBuffer, int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(CommandBuffer commandBuffer, ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
for (int i = 0; i < buffers.Length; i++)
|
||||
{
|
||||
var buffer = buffers[i];
|
||||
int index = first + i;
|
||||
var assignment = buffers[i];
|
||||
var buffer = assignment.Range;
|
||||
int index = assignment.Binding;
|
||||
|
||||
Auto<DisposableBuffer> vkBuffer = _gd.BufferManager.GetBuffer(commandBuffer, buffer.Handle, false);
|
||||
ref Auto<DisposableBuffer> currentVkBuffer = ref _uniformBufferRefs[index];
|
||||
|
@@ -177,7 +177,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
||||
|
||||
_pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
||||
|
||||
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
|
||||
|
||||
@@ -240,7 +240,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, clearColor);
|
||||
|
||||
_pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, ClearColorBufferSize) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, ClearColorBufferSize)) });
|
||||
|
||||
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
|
||||
|
||||
@@ -302,7 +302,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
gd.BufferManager.SetData<float>(bufferHandle, 0, region);
|
||||
|
||||
pipeline.SetUniformBuffers(1, stackalloc[] { new BufferRange(bufferHandle, 0, RegionBufferSize) });
|
||||
pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(1, new BufferRange(bufferHandle, 0, RegionBufferSize)) });
|
||||
|
||||
Span<GAL.Viewport> viewports = stackalloc GAL.Viewport[1];
|
||||
|
||||
@@ -380,7 +380,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
_pipeline.SetCommandBuffer(cbs);
|
||||
|
||||
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
|
||||
Span<Auto<DisposableBuffer>> sbRanges = new Auto<DisposableBuffer>[2];
|
||||
|
||||
@@ -571,7 +571,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
int conversionType = srcIsMs ? src.Info.BytesPerPixel : -src.Info.BytesPerPixel;
|
||||
_pipeline.Specialize(conversionType);
|
||||
|
||||
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(bufferHandle, 0, ParamsBufferSize) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(bufferHandle, 0, ParamsBufferSize)) });
|
||||
|
||||
if (src.Info.Target == Target.Texture2DMultisampleArray ||
|
||||
dst.Info.Target == Target.Texture2DMultisampleArray)
|
||||
@@ -776,7 +776,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
srcIndirectBufferOffset,
|
||||
indirectDataSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(0, stackalloc[] { drawCountBufferAligned });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, drawCountBufferAligned) });
|
||||
_pipeline.SetStorageBuffers(1, new[] { srcIndirectBuffer.GetBuffer(), dstIndirectBuffer.GetBuffer(), patternBuffer.GetBuffer() });
|
||||
|
||||
_pipeline.SetProgram(_programConvertIndirectData);
|
||||
@@ -804,7 +804,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
0,
|
||||
convertedCount * outputIndexSize);
|
||||
|
||||
_pipeline.SetUniformBuffers(0, stackalloc[] { new BufferRange(patternBufferHandle, 0, ParamsBufferSize) });
|
||||
_pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, new BufferRange(patternBufferHandle, 0, ParamsBufferSize)) });
|
||||
_pipeline.SetStorageBuffers(1, new[] { srcIndexBuffer.GetBuffer(), dstIndexBuffer.GetBuffer() });
|
||||
|
||||
_pipeline.SetProgram(_programConvertIndexBuffer);
|
||||
|
@@ -973,9 +973,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
SignalStateChange();
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
|
||||
_descriptorSetUpdater.SetStorageBuffers(CommandBuffer, buffers);
|
||||
}
|
||||
|
||||
public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
|
||||
@@ -1013,9 +1013,9 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
}
|
||||
}
|
||||
|
||||
public void SetUniformBuffers(int first, ReadOnlySpan<BufferRange> buffers)
|
||||
public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
|
||||
{
|
||||
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, first, buffers);
|
||||
_descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
|
||||
}
|
||||
|
||||
public void SetUserClipDistance(int index, bool enableClip)
|
||||
|
@@ -22,6 +22,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
private Device _device;
|
||||
private WindowBase _window;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
internal FormatCapabilities FormatCapabilities { get; private set; }
|
||||
internal HardwareCapabilities Capabilities;
|
||||
|
||||
@@ -266,6 +268,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
LoadFeatures(supportedExtensions, maxQueueCount, queueFamilyIndex);
|
||||
|
||||
_window = new Window(this, _surface, _physicalDevice, _device);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
public BufferHandle CreateBuffer(int size)
|
||||
@@ -573,6 +577,11 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
public unsafe void Dispose()
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
CommandBufferPool.Dispose();
|
||||
BackgroundResources.Dispose();
|
||||
_counters.Dispose();
|
||||
@@ -613,4 +622,4 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
Api.DestroyInstance(_instance, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -172,9 +172,11 @@ namespace Ryujinx.HLE.FileSystem
|
||||
fsServerClient = horizon.CreatePrivilegedHorizonClient();
|
||||
var fsServer = new FileSystemServer(fsServerClient);
|
||||
|
||||
DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet, fsServer);
|
||||
RandomDataGenerator randomGenerator = buffer => Random.Shared.NextBytes(buffer);
|
||||
|
||||
// Use our own encrypted fs creator that always uses all-zero keys
|
||||
DefaultFsServerObjects fsServerObjects = DefaultFsServerObjects.GetDefaultEmulatedCreators(serverBaseFs, KeySet, fsServer, randomGenerator);
|
||||
|
||||
// Use our own encrypted fs creator that doesn't actually do any encryption
|
||||
fsServerObjects.FsCreators.EncryptedFileSystemCreator = new EncryptedFileSystemCreator();
|
||||
|
||||
GameCard = fsServerObjects.GameCard;
|
||||
@@ -186,7 +188,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
DeviceOperator = fsServerObjects.DeviceOperator,
|
||||
ExternalKeySet = KeySet.ExternalKeySet,
|
||||
FsCreators = fsServerObjects.FsCreators
|
||||
FsCreators = fsServerObjects.FsCreators,
|
||||
RandomGenerator = randomGenerator
|
||||
};
|
||||
|
||||
FileSystemServerInitializer.InitializeWithConfig(fsServerClient, fsServer, fsServerConfig);
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||
@@ -9,6 +10,7 @@ using Ryujinx.Memory;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -78,13 +80,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
var launchParams = _normalSession.Pop();
|
||||
var keyboardConfig = _normalSession.Pop();
|
||||
|
||||
_isBackground = keyboardConfig.Length == Marshal.SizeOf<SoftwareKeyboardInitialize>();
|
||||
_isBackground = keyboardConfig.Length == Unsafe.SizeOf<SoftwareKeyboardInitialize>();
|
||||
|
||||
if (_isBackground)
|
||||
{
|
||||
// Initialize the keyboard applet in background mode.
|
||||
|
||||
_keyboardBackgroundInitialize = ReadStruct<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_keyboardBackgroundInitialize = MemoryMarshal.Read<SoftwareKeyboardInitialize>(keyboardConfig);
|
||||
_backgroundState = InlineKeyboardState.Uninitialized;
|
||||
|
||||
if (_device.UiHandler == null)
|
||||
@@ -342,7 +344,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
else
|
||||
{
|
||||
int wordsCount = reader.ReadInt32();
|
||||
int wordSize = Marshal.SizeOf<SoftwareKeyboardUserWord>();
|
||||
int wordSize = Unsafe.SizeOf<SoftwareKeyboardUserWord>();
|
||||
remaining = stream.Length - stream.Position;
|
||||
|
||||
if (wordsCount > MaxUserWords)
|
||||
@@ -359,8 +361,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
|
||||
for (int word = 0; word < wordsCount; word++)
|
||||
{
|
||||
byte[] wordData = reader.ReadBytes(wordSize);
|
||||
_keyboardBackgroundUserWords[word] = ReadStruct<SoftwareKeyboardUserWord>(wordData);
|
||||
_keyboardBackgroundUserWords[word] = reader.ReadStruct<SoftwareKeyboardUserWord>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -369,27 +370,25 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
case InlineKeyboardRequest.SetCustomizeDic:
|
||||
// Read the custom dic data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardCustomizeDic>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard Customize Dic of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDicData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDic = ReadStruct<SoftwareKeyboardCustomizeDic>(keyboardDicData);
|
||||
_keyboardBackgroundDic = reader.ReadStruct<SoftwareKeyboardCustomizeDic>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.SetCustomizedDictionaries:
|
||||
// Read the custom dictionaries data.
|
||||
remaining = stream.Length - stream.Position;
|
||||
if (remaining != Marshal.SizeOf<SoftwareKeyboardDictSet>())
|
||||
if (remaining != Unsafe.SizeOf<SoftwareKeyboardDictSet>())
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.ServiceAm, $"Received invalid Software Keyboard DictSet of {remaining} bytes");
|
||||
}
|
||||
else
|
||||
{
|
||||
var keyboardDictData = reader.ReadBytes((int)remaining);
|
||||
_keyboardBackgroundDictSet = ReadStruct<SoftwareKeyboardDictSet>(keyboardDictData);
|
||||
_keyboardBackgroundDictSet = reader.ReadStruct<SoftwareKeyboardDictSet>();
|
||||
}
|
||||
break;
|
||||
case InlineKeyboardRequest.Calc:
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetCustomizeDic request to software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x70)]
|
||||
struct SoftwareKeyboardCustomizeDic
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 112)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
{
|
||||
@@ -21,8 +22,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// Array of word entries in the buffer.
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 24)]
|
||||
public ulong[] Entries;
|
||||
public Array24<ulong> Entries;
|
||||
|
||||
/// <summary>
|
||||
/// Number of used entries in the Entries field.
|
||||
|
@@ -5,10 +5,9 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
||||
/// <summary>
|
||||
/// A structure used by SetUserWordInfo request to the software keyboard.
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x64)]
|
||||
struct SoftwareKeyboardUserWord
|
||||
{
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
|
||||
public byte[] Unknown;
|
||||
// Unknown
|
||||
}
|
||||
}
|
||||
|
@@ -850,7 +850,7 @@ namespace Ryujinx.HLE.HOS
|
||||
for (int i = 0; i < programCount; i++)
|
||||
{
|
||||
mapInfo[i].ProgramId = new ProgramId(applicationId + (uint)i);
|
||||
mapInfo[i].MainProgramId = new ProgramId(applicationId);
|
||||
mapInfo[i].MainProgramId = new ApplicationId(applicationId);
|
||||
mapInfo[i].ProgramIndex = (byte)i;
|
||||
}
|
||||
|
||||
|
@@ -479,7 +479,10 @@ namespace Ryujinx.HLE.HOS
|
||||
|
||||
AudioRendererManager.Dispose();
|
||||
|
||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||
if (LibHacHorizonManager.ApplicationClient != null)
|
||||
{
|
||||
LibHacHorizonManager.PmClient.Fs.UnregisterProgram(LibHacHorizonManager.ApplicationClient.Os.GetCurrentProcessId().Value).ThrowIfFailure();
|
||||
}
|
||||
|
||||
KernelContext.Dispose();
|
||||
}
|
||||
|
@@ -60,8 +60,6 @@ namespace Ryujinx.HLE.HOS
|
||||
virtualFileSystem.InitializeFsServer(Server, out var fsClient);
|
||||
|
||||
FsClient = fsClient;
|
||||
|
||||
CleanSdCardDirectory();
|
||||
}
|
||||
|
||||
public void InitializeSystemClients()
|
||||
@@ -78,27 +76,6 @@ namespace Ryujinx.HLE.HOS
|
||||
ApplicationClient = Server.CreateHorizonClient(new ProgramLocation(programId, StorageId.BuiltInUser), npdm.FsAccessControlData, npdm.FsAccessControlDescriptor);
|
||||
}
|
||||
|
||||
// This function was added to avoid errors that come from a user's keys or SD encryption seed changing.
|
||||
// Catching these errors and recreating the file ended up not working because of the different ways
|
||||
// applications respond to a file suddenly containing all zeros or having a length of zero.
|
||||
// Clearing the SD card save directory was determined to be the best option for the moment since
|
||||
// the saves on the SD card are meant as caches that can be deleted at any time.
|
||||
private void CleanSdCardDirectory()
|
||||
{
|
||||
Result rc = RyujinxClient.Fs.MountSdCard("sdcard".ToU8Span());
|
||||
if (rc.IsFailure()) return;
|
||||
|
||||
try
|
||||
{
|
||||
RyujinxClient.Fs.CleanDirectoryRecursively("sdcard:/Nintendo/save".ToU8Span()).IgnoreResult();
|
||||
RyujinxClient.Fs.DeleteDirectoryRecursively("sdcard:/save".ToU8Span()).IgnoreResult();
|
||||
}
|
||||
finally
|
||||
{
|
||||
RyujinxClient.Fs.Unmount("sdcard".ToU8Span());
|
||||
}
|
||||
}
|
||||
|
||||
private static AccessControlBits.Bits AccountFsPermissions => AccessControlBits.Bits.SystemSaveData |
|
||||
AccessControlBits.Bits.GameCard |
|
||||
AccessControlBits.Bits.SaveDataMeta |
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.Common.Memory;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, CharSet = CharSet.Ansi)]
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8)]
|
||||
struct UserPresence
|
||||
{
|
||||
public UserId UserId;
|
||||
@@ -13,15 +16,20 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.FriendService
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool SamePresenceGroupApplication;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
|
||||
public char[] Unknown;
|
||||
public Array3<byte> Unknown;
|
||||
private AppKeyValueStorageHolder _appKeyValueStorage;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0xC0)]
|
||||
public char[] AppKeyValueStorage;
|
||||
public Span<byte> AppKeyValueStorage => MemoryMarshal.Cast<AppKeyValueStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _appKeyValueStorage, AppKeyValueStorageHolder.Size));
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x1, Size = Size)]
|
||||
private struct AppKeyValueStorageHolder
|
||||
{
|
||||
public const int Size = 0xC0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {AppKeyValueStorage} }}";
|
||||
return $"UserPresence {{ UserId: {UserId}, LastTimeOnlineTimestamp: {LastTimeOnlineTimestamp}, Status: {Status}, AppKeyValueStorage: {Encoding.ASCII.GetString(AppKeyValueStorage)} }}";
|
||||
}
|
||||
}
|
||||
}
|
@@ -43,6 +43,16 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(1)]
|
||||
// nn::friends::Cancel()
|
||||
public ResultCode Cancel(ServiceCtx context)
|
||||
{
|
||||
// TODO: Original service sets an internal field to 1 here. Determine usage.
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend);
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandHipc(10100)]
|
||||
// nn::friends::GetFriendListIds(int offset, nn::account::Uid userId, nn::friends::detail::ipc::SizedFriendFilter friendFilter, ulong pidPlaceHolder, pid)
|
||||
// -> int outCount, array<nn::account::NetworkServiceAccountId, 0xa>
|
||||
@@ -226,23 +236,14 @@ namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator
|
||||
ulong position = context.Request.PtrBuff[0].Position;
|
||||
ulong size = context.Request.PtrBuff[0].Size;
|
||||
|
||||
byte[] bufferContent = new byte[size];
|
||||
|
||||
context.Memory.Read(position, bufferContent);
|
||||
ReadOnlySpan<UserPresence> userPresenceInputArray = MemoryMarshal.Cast<byte, UserPresence>(context.Memory.GetSpan(position, (int)size));
|
||||
|
||||
if (uuid.IsNull)
|
||||
{
|
||||
return ResultCode.InvalidArgument;
|
||||
}
|
||||
|
||||
int elementCount = bufferContent.Length / Marshal.SizeOf<UserPresence>();
|
||||
|
||||
using (BinaryReader bufferReader = new BinaryReader(new MemoryStream(bufferContent)))
|
||||
{
|
||||
UserPresence[] userPresenceInputArray = bufferReader.ReadStructArray<UserPresence>(elementCount);
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray });
|
||||
}
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceFriend, new { UserId = uuid.ToString(), userPresenceInputArray = userPresenceInputArray.ToArray() });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
@@ -1,15 +1,13 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Friend.ServiceCreator.NotificationService
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 0x8, Size = 0x10)]
|
||||
[StructLayout(LayoutKind.Sequential, Size = 0x10)]
|
||||
struct NotificationInfo
|
||||
{
|
||||
public NotificationEventType Type;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x4)]
|
||||
public char[] Padding;
|
||||
|
||||
private Array4<byte> _padding;
|
||||
public long NetworkUserIdPlaceholder;
|
||||
}
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
using LibHac;
|
||||
using LibHac.Common;
|
||||
using LibHac.Fs;
|
||||
|
||||
using GameCardHandle = System.UInt32;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
{
|
||||
@@ -41,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
{
|
||||
Result result = _baseOperator.Get.GetGameCardHandle(out GameCardHandle handle);
|
||||
|
||||
context.ResponseData.Write(handle.Value);
|
||||
context.ResponseData.Write(handle);
|
||||
|
||||
return (ResultCode)result.Value;
|
||||
}
|
||||
|
@@ -19,6 +19,7 @@ using static Ryujinx.HLE.Utilities.StringUtils;
|
||||
using IFileSystem = LibHac.FsSrv.Sf.IFileSystem;
|
||||
using IStorage = LibHac.FsSrv.Sf.IStorage;
|
||||
using RightsId = LibHac.Fs.RightsId;
|
||||
using GameCardHandle = System.UInt32;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
{
|
||||
@@ -239,7 +240,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
// OpenGameCardStorage(u32 handle, u32 partitionId) -> object<nn::fssrv::sf::IStorage>
|
||||
public ResultCode OpenGameCardStorage(ServiceCtx context)
|
||||
{
|
||||
GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32());
|
||||
GameCardHandle handle = context.RequestData.ReadUInt32();
|
||||
GameCardPartitionRaw partitionId = (GameCardPartitionRaw)context.RequestData.ReadInt32();
|
||||
using var storage = new SharedRef<IStorage>();
|
||||
|
||||
@@ -255,7 +256,7 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
// OpenGameCardFileSystem(u32 handle, u32 partitionId) -> object<nn::fssrv::sf::IFileSystem>
|
||||
public ResultCode OpenGameCardFileSystem(ServiceCtx context)
|
||||
{
|
||||
GameCardHandle handle = new GameCardHandle(context.RequestData.ReadInt32());
|
||||
GameCardHandle handle = context.RequestData.ReadUInt32();
|
||||
GameCardPartition partitionId = (GameCardPartition)context.RequestData.ReadInt32();
|
||||
using var fileSystem = new SharedRef<IFileSystem>();
|
||||
|
||||
@@ -315,6 +316,17 @@ namespace Ryujinx.HLE.HOS.Services.Fs
|
||||
return (ResultCode)_baseFileSystemProxy.Get.CreateSaveDataFileSystemWithHashSalt(in attribute, in creationInfo, in metaCreateInfo, in hashSalt).Value;
|
||||
}
|
||||
|
||||
[CommandHipc(37)] // 14.0.0+
|
||||
// CreateSaveDataFileSystemWithCreationInfo2(buffer<nn::fs::SaveDataCreationInfo2, 25> creationInfo) -> ()
|
||||
public ResultCode CreateSaveDataFileSystemWithCreationInfo2(ServiceCtx context)
|
||||
{
|
||||
byte[] creationInfoBuffer = new byte[context.Request.SendBuff[0].Size];
|
||||
context.Memory.Read(context.Request.SendBuff[0].Position, creationInfoBuffer);
|
||||
ref readonly SaveDataCreationInfo2 creationInfo = ref SpanHelpers.AsReadOnlyStruct<SaveDataCreationInfo2>(creationInfoBuffer);
|
||||
|
||||
return (ResultCode)_baseFileSystemProxy.Get.CreateSaveDataFileSystemWithCreationInfo2(in creationInfo).Value;
|
||||
}
|
||||
|
||||
[CommandHipc(51)]
|
||||
// OpenSaveDataFileSystem(u8 spaceId, nn::fs::SaveDataAttribute attribute) -> object<nn::fssrv::sf::IFileSystem> saveDataFs
|
||||
public ResultCode OpenSaveDataFileSystem(ServiceCtx context)
|
||||
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService.Types;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
@@ -75,7 +76,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pdm.QueryService
|
||||
|
||||
for (int i = 0; i < filteredApplicationPlayStatistics.Count(); i++)
|
||||
{
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Marshal.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
MemoryHelper.Write(context.Memory, outputPosition + (ulong)(i * Unsafe.SizeOf<ApplicationPlayStatistics>()), filteredApplicationPlayStatistics.ElementAt(i).Value);
|
||||
}
|
||||
|
||||
context.ResponseData.Write(filteredApplicationPlayStatistics.Count());
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
@@ -16,14 +17,22 @@ namespace Ryujinx.HLE.HOS.Services.Time.Clock
|
||||
public CalendarAdditionalInfo NetworkCalendarAdditionalTime;
|
||||
public SteadyClockTimePoint SteadyClockTimePoint;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x24)]
|
||||
public char[] LocationName;
|
||||
private LocationNameStorageHolder _locationName;
|
||||
|
||||
public Span<byte> LocationName => MemoryMarshal.Cast<LocationNameStorageHolder, byte>(MemoryMarshal.CreateSpan(ref _locationName, LocationNameStorageHolder.Size));
|
||||
|
||||
[MarshalAs(UnmanagedType.I1)]
|
||||
public bool IsAutomaticCorrectionEnabled;
|
||||
public byte Type;
|
||||
public ushort Unknown;
|
||||
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1, Size = Size)]
|
||||
private struct LocationNameStorageHolder
|
||||
{
|
||||
public const int Size = 0x24;
|
||||
}
|
||||
|
||||
public static ResultCode GetCurrentTime(out long currentTime, SteadyClockTimePoint steadyClockTimePoint, SystemClockContext context)
|
||||
{
|
||||
currentTime = 0;
|
||||
|
@@ -8,7 +8,9 @@ using Ryujinx.HLE.HOS.Services.Time.TimeZone;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
@@ -281,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
{
|
||||
byte type = context.RequestData.ReadByte();
|
||||
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Marshal.SizeOf<ClockSnapshot>());
|
||||
context.Response.PtrBuff[0] = context.Response.PtrBuff[0].WithSize((uint)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
context.RequestData.BaseStream.Position += 7;
|
||||
|
||||
@@ -372,12 +374,9 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
return result;
|
||||
}
|
||||
|
||||
char[] tzName = deviceLocationName.ToCharArray();
|
||||
char[] locationName = new char[0x24];
|
||||
ReadOnlySpan<byte> tzName = Encoding.ASCII.GetBytes(deviceLocationName);
|
||||
|
||||
Array.Copy(tzName, locationName, tzName.Length);
|
||||
|
||||
clockSnapshot.LocationName = locationName;
|
||||
tzName.CopyTo(clockSnapshot.LocationName);
|
||||
|
||||
result = ClockSnapshot.GetCurrentTime(out clockSnapshot.UserTime, currentTimePoint, clockSnapshot.UserContext);
|
||||
|
||||
@@ -414,7 +413,7 @@ namespace Ryujinx.HLE.HOS.Services.Time
|
||||
|
||||
private ClockSnapshot ReadClockSnapshotFromBuffer(ServiceCtx context, IpcPtrBuffDesc ipcDesc)
|
||||
{
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Marshal.SizeOf<ClockSnapshot>());
|
||||
Debug.Assert(ipcDesc.Size == (ulong)Unsafe.SizeOf<ClockSnapshot>());
|
||||
|
||||
byte[] temp = new byte[ipcDesc.Size];
|
||||
|
||||
|
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Utilities;
|
||||
using System;
|
||||
using System.Buffers.Binary;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
@@ -890,14 +891,14 @@ namespace Ryujinx.HLE.HOS.Services.Time.TimeZone
|
||||
|
||||
long streamLength = reader.BaseStream.Length;
|
||||
|
||||
if (streamLength < Marshal.SizeOf<TzifHeader>())
|
||||
if (streamLength < Unsafe.SizeOf<TzifHeader>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TzifHeader header = reader.ReadStruct<TzifHeader>();
|
||||
|
||||
streamLength -= Marshal.SizeOf<TzifHeader>();
|
||||
streamLength -= Unsafe.SizeOf<TzifHeader>();
|
||||
|
||||
int ttisGMTCount = Detzcode32(header.TtisGMTCount);
|
||||
int ttisSTDCount = Detzcode32(header.TtisSTDCount);
|
||||
|
@@ -22,7 +22,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Concentus" Version="1.1.7" />
|
||||
<PackageReference Include="LibHac" Version="0.16.1" />
|
||||
<PackageReference Include="LibHac" Version="0.17.0" />
|
||||
<PackageReference Include="MsgPack.Cli" Version="1.0.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
<PackageReference Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||
|
@@ -40,20 +40,16 @@ namespace Ryujinx.Headless.SDL2.Vulkan
|
||||
return (IntPtr)surfaceHandle;
|
||||
}
|
||||
|
||||
// TODO: Fix this in SDL2-CS.
|
||||
[DllImport("SDL2", EntryPoint = "SDL_Vulkan_GetInstanceExtensions", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern SDL_bool SDL_Vulkan_GetInstanceExtensions_Workaround(IntPtr window, out uint count, IntPtr names);
|
||||
|
||||
public unsafe string[] GetRequiredInstanceExtensions()
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out uint extensionsCount, IntPtr.Zero) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
IntPtr[] rawExtensions = new IntPtr[(int)extensionsCount];
|
||||
string[] extensions = new string[(int)extensionsCount];
|
||||
|
||||
fixed (IntPtr* rawExtensionsPtr = rawExtensions)
|
||||
{
|
||||
if (SDL_Vulkan_GetInstanceExtensions_Workaround(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
if (SDL_Vulkan_GetInstanceExtensions(WindowHandle, out extensionsCount, (IntPtr)rawExtensionsPtr) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
for (int i = 0; i < extensions.Length; i++)
|
||||
{
|
||||
|
@@ -1,16 +1,15 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct ControllerDataRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public MessageType Type;
|
||||
public SubscriberType SubscriberType;
|
||||
public byte Slot;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public byte Slot;
|
||||
public Array6<byte> MacAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
@@ -27,11 +26,8 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public uint DPadAnalog;
|
||||
public ulong MainButtonsAnalog;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch1;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] Touch2;
|
||||
public Array6<byte> Touch1;
|
||||
public Array6<byte> Touch2;
|
||||
|
||||
public ulong MotionTimestamp;
|
||||
public float AccelerometerX;
|
||||
|
@@ -1,21 +1,20 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoResponse
|
||||
{
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
public SharedResponse Shared;
|
||||
private byte _zero;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
public struct ControllerInfoRequest
|
||||
{
|
||||
public MessageType Type;
|
||||
public int PortsCount;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
|
||||
public byte[] PortIndices;
|
||||
public int PortsCount;
|
||||
public Array4<byte> PortIndices;
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using Ryujinx.Common.Memory;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
{
|
||||
@@ -11,8 +12,7 @@ namespace Ryujinx.Input.Motion.CemuHook.Protocol
|
||||
public DeviceModelType ModelType;
|
||||
public ConnectionType ConnectionType;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]
|
||||
public byte[] MacAddress;
|
||||
public Array6<byte> MacAddress;
|
||||
public BatteryStatus BatteryStatus;
|
||||
}
|
||||
|
||||
|
@@ -44,6 +44,11 @@ namespace Ryujinx.Memory.Tests
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
@@ -136,6 +136,14 @@ namespace Ryujinx.Memory
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data)
|
||||
{
|
||||
Write(va, data);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public ReadOnlySpan<byte> GetSpan(ulong va, int size, bool tracked = false)
|
||||
{
|
||||
|
@@ -58,6 +58,17 @@ namespace Ryujinx.Memory
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
void Write(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
/// <summary>
|
||||
/// Writes data to the application process, returning false if the data was not changed.
|
||||
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
|
||||
/// </summary>
|
||||
/// <remarks>The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.</remarks>
|
||||
/// <param name="va">Virtual address to write the data into</param>
|
||||
/// <param name="data">Data to be written</param>
|
||||
/// <exception cref="InvalidMemoryRegionException">Throw for unhandled invalid or unmapped memory accesses</exception>
|
||||
/// <returns>True if the data was changed, false otherwise</returns>
|
||||
bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan<byte> data);
|
||||
|
||||
void Fill(ulong va, ulong size, byte value)
|
||||
{
|
||||
const int MaxChunkSize = 1 << 24;
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.0.22-build20" />
|
||||
<PackageReference Include="Ryujinx.SDL2-CS" Version="2.24.2-build21" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@@ -43,6 +43,8 @@ namespace Ryujinx.SDL2.Common
|
||||
|
||||
private SDL2Driver() {}
|
||||
|
||||
private const string SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS = "SDL_JOYSTICK_HIDAPI_COMBINE_JOY_CONS";
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
lock (_lock)
|
||||
@@ -60,6 +62,11 @@ namespace Ryujinx.SDL2.Common
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0");
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1");
|
||||
|
||||
|
||||
// NOTE: As of SDL2 2.24.0, joycons are combined by default but the motion source only come from one of them.
|
||||
// We disable this behavior for now.
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_COMBINE_JOY_CONS, "0");
|
||||
|
||||
if (SDL_Init(SdlInitFlags) != 0)
|
||||
{
|
||||
string errorMessage = $"SDL2 initlaization failed with error \"{SDL_GetError()}\"";
|
||||
|
@@ -1,135 +0,0 @@
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public enum Arm32Register
|
||||
{
|
||||
INVALID = 0,
|
||||
|
||||
APSR,
|
||||
APSR_NZCV,
|
||||
CPSR,
|
||||
FPEXC,
|
||||
FPINST,
|
||||
FPSCR,
|
||||
FPSCR_NZCV,
|
||||
FPSID,
|
||||
ITSTATE,
|
||||
LR,
|
||||
PC,
|
||||
SP,
|
||||
SPSR,
|
||||
D0,
|
||||
D1,
|
||||
D2,
|
||||
D3,
|
||||
D4,
|
||||
D5,
|
||||
D6,
|
||||
D7,
|
||||
D8,
|
||||
D9,
|
||||
D10,
|
||||
D11,
|
||||
D12,
|
||||
D13,
|
||||
D14,
|
||||
D15,
|
||||
D16,
|
||||
D17,
|
||||
D18,
|
||||
D19,
|
||||
D20,
|
||||
D21,
|
||||
D22,
|
||||
D23,
|
||||
D24,
|
||||
D25,
|
||||
D26,
|
||||
D27,
|
||||
D28,
|
||||
D29,
|
||||
D30,
|
||||
D31,
|
||||
FPINST2,
|
||||
MVFR0,
|
||||
MVFR1,
|
||||
MVFR2,
|
||||
Q0,
|
||||
Q1,
|
||||
Q2,
|
||||
Q3,
|
||||
Q4,
|
||||
Q5,
|
||||
Q6,
|
||||
Q7,
|
||||
Q8,
|
||||
Q9,
|
||||
Q10,
|
||||
Q11,
|
||||
Q12,
|
||||
Q13,
|
||||
Q14,
|
||||
Q15,
|
||||
R0,
|
||||
R1,
|
||||
R2,
|
||||
R3,
|
||||
R4,
|
||||
R5,
|
||||
R6,
|
||||
R7,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
S0,
|
||||
S1,
|
||||
S2,
|
||||
S3,
|
||||
S4,
|
||||
S5,
|
||||
S6,
|
||||
S7,
|
||||
S8,
|
||||
S9,
|
||||
S10,
|
||||
S11,
|
||||
S12,
|
||||
S13,
|
||||
S14,
|
||||
S15,
|
||||
S16,
|
||||
S17,
|
||||
S18,
|
||||
S19,
|
||||
S20,
|
||||
S21,
|
||||
S22,
|
||||
S23,
|
||||
S24,
|
||||
S25,
|
||||
S26,
|
||||
S27,
|
||||
S28,
|
||||
S29,
|
||||
S30,
|
||||
S31,
|
||||
C1_C0_2,
|
||||
C13_C0_2,
|
||||
C13_C0_3,
|
||||
IPSR,
|
||||
MSP,
|
||||
PSP,
|
||||
CONTROL,
|
||||
ENDING,
|
||||
|
||||
// Alias registers.
|
||||
R13 = SP,
|
||||
R14 = LR,
|
||||
R15 = PC,
|
||||
SB = R9,
|
||||
SL = R10,
|
||||
FP = R11,
|
||||
IP = R12,
|
||||
}
|
||||
}
|
@@ -1,295 +0,0 @@
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public enum ArmRegister
|
||||
{
|
||||
INVALID = 0,
|
||||
|
||||
X29,
|
||||
X30,
|
||||
NZCV,
|
||||
SP,
|
||||
WSP,
|
||||
WZR,
|
||||
XZR,
|
||||
B0,
|
||||
B1,
|
||||
B2,
|
||||
B3,
|
||||
B4,
|
||||
B5,
|
||||
B6,
|
||||
B7,
|
||||
B8,
|
||||
B9,
|
||||
B10,
|
||||
B11,
|
||||
B12,
|
||||
B13,
|
||||
B14,
|
||||
B15,
|
||||
B16,
|
||||
B17,
|
||||
B18,
|
||||
B19,
|
||||
B20,
|
||||
B21,
|
||||
B22,
|
||||
B23,
|
||||
B24,
|
||||
B25,
|
||||
B26,
|
||||
B27,
|
||||
B28,
|
||||
B29,
|
||||
B30,
|
||||
B31,
|
||||
D0,
|
||||
D1,
|
||||
D2,
|
||||
D3,
|
||||
D4,
|
||||
D5,
|
||||
D6,
|
||||
D7,
|
||||
D8,
|
||||
D9,
|
||||
D10,
|
||||
D11,
|
||||
D12,
|
||||
D13,
|
||||
D14,
|
||||
D15,
|
||||
D16,
|
||||
D17,
|
||||
D18,
|
||||
D19,
|
||||
D20,
|
||||
D21,
|
||||
D22,
|
||||
D23,
|
||||
D24,
|
||||
D25,
|
||||
D26,
|
||||
D27,
|
||||
D28,
|
||||
D29,
|
||||
D30,
|
||||
D31,
|
||||
H0,
|
||||
H1,
|
||||
H2,
|
||||
H3,
|
||||
H4,
|
||||
H5,
|
||||
H6,
|
||||
H7,
|
||||
H8,
|
||||
H9,
|
||||
H10,
|
||||
H11,
|
||||
H12,
|
||||
H13,
|
||||
H14,
|
||||
H15,
|
||||
H16,
|
||||
H17,
|
||||
H18,
|
||||
H19,
|
||||
H20,
|
||||
H21,
|
||||
H22,
|
||||
H23,
|
||||
H24,
|
||||
H25,
|
||||
H26,
|
||||
H27,
|
||||
H28,
|
||||
H29,
|
||||
H30,
|
||||
H31,
|
||||
Q0,
|
||||
Q1,
|
||||
Q2,
|
||||
Q3,
|
||||
Q4,
|
||||
Q5,
|
||||
Q6,
|
||||
Q7,
|
||||
Q8,
|
||||
Q9,
|
||||
Q10,
|
||||
Q11,
|
||||
Q12,
|
||||
Q13,
|
||||
Q14,
|
||||
Q15,
|
||||
Q16,
|
||||
Q17,
|
||||
Q18,
|
||||
Q19,
|
||||
Q20,
|
||||
Q21,
|
||||
Q22,
|
||||
Q23,
|
||||
Q24,
|
||||
Q25,
|
||||
Q26,
|
||||
Q27,
|
||||
Q28,
|
||||
Q29,
|
||||
Q30,
|
||||
Q31,
|
||||
S0,
|
||||
S1,
|
||||
S2,
|
||||
S3,
|
||||
S4,
|
||||
S5,
|
||||
S6,
|
||||
S7,
|
||||
S8,
|
||||
S9,
|
||||
S10,
|
||||
S11,
|
||||
S12,
|
||||
S13,
|
||||
S14,
|
||||
S15,
|
||||
S16,
|
||||
S17,
|
||||
S18,
|
||||
S19,
|
||||
S20,
|
||||
S21,
|
||||
S22,
|
||||
S23,
|
||||
S24,
|
||||
S25,
|
||||
S26,
|
||||
S27,
|
||||
S28,
|
||||
S29,
|
||||
S30,
|
||||
S31,
|
||||
W0,
|
||||
W1,
|
||||
W2,
|
||||
W3,
|
||||
W4,
|
||||
W5,
|
||||
W6,
|
||||
W7,
|
||||
W8,
|
||||
W9,
|
||||
W10,
|
||||
W11,
|
||||
W12,
|
||||
W13,
|
||||
W14,
|
||||
W15,
|
||||
W16,
|
||||
W17,
|
||||
W18,
|
||||
W19,
|
||||
W20,
|
||||
W21,
|
||||
W22,
|
||||
W23,
|
||||
W24,
|
||||
W25,
|
||||
W26,
|
||||
W27,
|
||||
W28,
|
||||
W29,
|
||||
W30,
|
||||
X0,
|
||||
X1,
|
||||
X2,
|
||||
X3,
|
||||
X4,
|
||||
X5,
|
||||
X6,
|
||||
X7,
|
||||
X8,
|
||||
X9,
|
||||
X10,
|
||||
X11,
|
||||
X12,
|
||||
X13,
|
||||
X14,
|
||||
X15,
|
||||
X16,
|
||||
X17,
|
||||
X18,
|
||||
X19,
|
||||
X20,
|
||||
X21,
|
||||
X22,
|
||||
X23,
|
||||
X24,
|
||||
X25,
|
||||
X26,
|
||||
X27,
|
||||
X28,
|
||||
|
||||
V0,
|
||||
V1,
|
||||
V2,
|
||||
V3,
|
||||
V4,
|
||||
V5,
|
||||
V6,
|
||||
V7,
|
||||
V8,
|
||||
V9,
|
||||
V10,
|
||||
V11,
|
||||
V12,
|
||||
V13,
|
||||
V14,
|
||||
V15,
|
||||
V16,
|
||||
V17,
|
||||
V18,
|
||||
V19,
|
||||
V20,
|
||||
V21,
|
||||
V22,
|
||||
V23,
|
||||
V24,
|
||||
V25,
|
||||
V26,
|
||||
V27,
|
||||
V28,
|
||||
V29,
|
||||
V30,
|
||||
V31,
|
||||
|
||||
// > pseudo registers
|
||||
PC, // program counter register
|
||||
|
||||
CPACR_EL1,
|
||||
ESR,
|
||||
|
||||
// > thread registers
|
||||
TPIDR_EL0,
|
||||
TPIDRRO_EL0,
|
||||
TPIDR_EL1,
|
||||
|
||||
PSTATE, // PSTATE pseudoregister
|
||||
|
||||
// > floating point control and status registers
|
||||
FPCR,
|
||||
FPSR,
|
||||
|
||||
ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
// > alias registers
|
||||
|
||||
IP0 = X16,
|
||||
IP1 = X17,
|
||||
FP = X29,
|
||||
LR = X30,
|
||||
}
|
||||
}
|
20
Ryujinx.Tests.Unicorn/Native/Const/Arch.cs
Normal file
20
Ryujinx.Tests.Unicorn/Native/Const/Arch.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arch
|
||||
{
|
||||
ARM = 1,
|
||||
ARM64 = 2,
|
||||
MIPS = 3,
|
||||
X86 = 4,
|
||||
PPC = 5,
|
||||
SPARC = 6,
|
||||
M68K = 7,
|
||||
RISCV = 8,
|
||||
S390X = 9,
|
||||
TRICORE = 10,
|
||||
MAX = 11,
|
||||
}
|
||||
}
|
200
Ryujinx.Tests.Unicorn/Native/Const/Arm.cs
Normal file
200
Ryujinx.Tests.Unicorn/Native/Const/Arm.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arm
|
||||
{
|
||||
|
||||
// ARM CPU
|
||||
|
||||
CPU_ARM_926 = 0,
|
||||
CPU_ARM_946 = 1,
|
||||
CPU_ARM_1026 = 2,
|
||||
CPU_ARM_1136_R2 = 3,
|
||||
CPU_ARM_1136 = 4,
|
||||
CPU_ARM_1176 = 5,
|
||||
CPU_ARM_11MPCORE = 6,
|
||||
CPU_ARM_CORTEX_M0 = 7,
|
||||
CPU_ARM_CORTEX_M3 = 8,
|
||||
CPU_ARM_CORTEX_M4 = 9,
|
||||
CPU_ARM_CORTEX_M7 = 10,
|
||||
CPU_ARM_CORTEX_M33 = 11,
|
||||
CPU_ARM_CORTEX_R5 = 12,
|
||||
CPU_ARM_CORTEX_R5F = 13,
|
||||
CPU_ARM_CORTEX_A7 = 14,
|
||||
CPU_ARM_CORTEX_A8 = 15,
|
||||
CPU_ARM_CORTEX_A9 = 16,
|
||||
CPU_ARM_CORTEX_A15 = 17,
|
||||
CPU_ARM_TI925T = 18,
|
||||
CPU_ARM_SA1100 = 19,
|
||||
CPU_ARM_SA1110 = 20,
|
||||
CPU_ARM_PXA250 = 21,
|
||||
CPU_ARM_PXA255 = 22,
|
||||
CPU_ARM_PXA260 = 23,
|
||||
CPU_ARM_PXA261 = 24,
|
||||
CPU_ARM_PXA262 = 25,
|
||||
CPU_ARM_PXA270 = 26,
|
||||
CPU_ARM_PXA270A0 = 27,
|
||||
CPU_ARM_PXA270A1 = 28,
|
||||
CPU_ARM_PXA270B0 = 29,
|
||||
CPU_ARM_PXA270B1 = 30,
|
||||
CPU_ARM_PXA270C0 = 31,
|
||||
CPU_ARM_PXA270C5 = 32,
|
||||
CPU_ARM_MAX = 33,
|
||||
CPU_ARM_ENDING = 34,
|
||||
|
||||
// ARM registers
|
||||
|
||||
REG_INVALID = 0,
|
||||
REG_APSR = 1,
|
||||
REG_APSR_NZCV = 2,
|
||||
REG_CPSR = 3,
|
||||
REG_FPEXC = 4,
|
||||
REG_FPINST = 5,
|
||||
REG_FPSCR = 6,
|
||||
REG_FPSCR_NZCV = 7,
|
||||
REG_FPSID = 8,
|
||||
REG_ITSTATE = 9,
|
||||
REG_LR = 10,
|
||||
REG_PC = 11,
|
||||
REG_SP = 12,
|
||||
REG_SPSR = 13,
|
||||
REG_D0 = 14,
|
||||
REG_D1 = 15,
|
||||
REG_D2 = 16,
|
||||
REG_D3 = 17,
|
||||
REG_D4 = 18,
|
||||
REG_D5 = 19,
|
||||
REG_D6 = 20,
|
||||
REG_D7 = 21,
|
||||
REG_D8 = 22,
|
||||
REG_D9 = 23,
|
||||
REG_D10 = 24,
|
||||
REG_D11 = 25,
|
||||
REG_D12 = 26,
|
||||
REG_D13 = 27,
|
||||
REG_D14 = 28,
|
||||
REG_D15 = 29,
|
||||
REG_D16 = 30,
|
||||
REG_D17 = 31,
|
||||
REG_D18 = 32,
|
||||
REG_D19 = 33,
|
||||
REG_D20 = 34,
|
||||
REG_D21 = 35,
|
||||
REG_D22 = 36,
|
||||
REG_D23 = 37,
|
||||
REG_D24 = 38,
|
||||
REG_D25 = 39,
|
||||
REG_D26 = 40,
|
||||
REG_D27 = 41,
|
||||
REG_D28 = 42,
|
||||
REG_D29 = 43,
|
||||
REG_D30 = 44,
|
||||
REG_D31 = 45,
|
||||
REG_FPINST2 = 46,
|
||||
REG_MVFR0 = 47,
|
||||
REG_MVFR1 = 48,
|
||||
REG_MVFR2 = 49,
|
||||
REG_Q0 = 50,
|
||||
REG_Q1 = 51,
|
||||
REG_Q2 = 52,
|
||||
REG_Q3 = 53,
|
||||
REG_Q4 = 54,
|
||||
REG_Q5 = 55,
|
||||
REG_Q6 = 56,
|
||||
REG_Q7 = 57,
|
||||
REG_Q8 = 58,
|
||||
REG_Q9 = 59,
|
||||
REG_Q10 = 60,
|
||||
REG_Q11 = 61,
|
||||
REG_Q12 = 62,
|
||||
REG_Q13 = 63,
|
||||
REG_Q14 = 64,
|
||||
REG_Q15 = 65,
|
||||
REG_R0 = 66,
|
||||
REG_R1 = 67,
|
||||
REG_R2 = 68,
|
||||
REG_R3 = 69,
|
||||
REG_R4 = 70,
|
||||
REG_R5 = 71,
|
||||
REG_R6 = 72,
|
||||
REG_R7 = 73,
|
||||
REG_R8 = 74,
|
||||
REG_R9 = 75,
|
||||
REG_R10 = 76,
|
||||
REG_R11 = 77,
|
||||
REG_R12 = 78,
|
||||
REG_S0 = 79,
|
||||
REG_S1 = 80,
|
||||
REG_S2 = 81,
|
||||
REG_S3 = 82,
|
||||
REG_S4 = 83,
|
||||
REG_S5 = 84,
|
||||
REG_S6 = 85,
|
||||
REG_S7 = 86,
|
||||
REG_S8 = 87,
|
||||
REG_S9 = 88,
|
||||
REG_S10 = 89,
|
||||
REG_S11 = 90,
|
||||
REG_S12 = 91,
|
||||
REG_S13 = 92,
|
||||
REG_S14 = 93,
|
||||
REG_S15 = 94,
|
||||
REG_S16 = 95,
|
||||
REG_S17 = 96,
|
||||
REG_S18 = 97,
|
||||
REG_S19 = 98,
|
||||
REG_S20 = 99,
|
||||
REG_S21 = 100,
|
||||
REG_S22 = 101,
|
||||
REG_S23 = 102,
|
||||
REG_S24 = 103,
|
||||
REG_S25 = 104,
|
||||
REG_S26 = 105,
|
||||
REG_S27 = 106,
|
||||
REG_S28 = 107,
|
||||
REG_S29 = 108,
|
||||
REG_S30 = 109,
|
||||
REG_S31 = 110,
|
||||
REG_C1_C0_2 = 111,
|
||||
REG_C13_C0_2 = 112,
|
||||
REG_C13_C0_3 = 113,
|
||||
REG_IPSR = 114,
|
||||
REG_MSP = 115,
|
||||
REG_PSP = 116,
|
||||
REG_CONTROL = 117,
|
||||
REG_IAPSR = 118,
|
||||
REG_EAPSR = 119,
|
||||
REG_XPSR = 120,
|
||||
REG_EPSR = 121,
|
||||
REG_IEPSR = 122,
|
||||
REG_PRIMASK = 123,
|
||||
REG_BASEPRI = 124,
|
||||
REG_BASEPRI_MAX = 125,
|
||||
REG_FAULTMASK = 126,
|
||||
REG_APSR_NZCVQ = 127,
|
||||
REG_APSR_G = 128,
|
||||
REG_APSR_NZCVQG = 129,
|
||||
REG_IAPSR_NZCVQ = 130,
|
||||
REG_IAPSR_G = 131,
|
||||
REG_IAPSR_NZCVQG = 132,
|
||||
REG_EAPSR_NZCVQ = 133,
|
||||
REG_EAPSR_G = 134,
|
||||
REG_EAPSR_NZCVQG = 135,
|
||||
REG_XPSR_NZCVQ = 136,
|
||||
REG_XPSR_G = 137,
|
||||
REG_XPSR_NZCVQG = 138,
|
||||
REG_CP_REG = 139,
|
||||
REG_ENDING = 140,
|
||||
|
||||
// alias registers
|
||||
REG_R13 = 12,
|
||||
REG_R14 = 10,
|
||||
REG_R15 = 11,
|
||||
REG_SB = 75,
|
||||
REG_SL = 76,
|
||||
REG_FP = 77,
|
||||
REG_IP = 78,
|
||||
}
|
||||
}
|
341
Ryujinx.Tests.Unicorn/Native/Const/Arm64.cs
Normal file
341
Ryujinx.Tests.Unicorn/Native/Const/Arm64.cs
Normal file
@@ -0,0 +1,341 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Arm64
|
||||
{
|
||||
|
||||
// ARM64 CPU
|
||||
|
||||
CPU_ARM64_A57 = 0,
|
||||
CPU_ARM64_A53 = 1,
|
||||
CPU_ARM64_A72 = 2,
|
||||
CPU_ARM64_MAX = 3,
|
||||
CPU_ARM64_ENDING = 4,
|
||||
|
||||
// ARM64 registers
|
||||
|
||||
REG_INVALID = 0,
|
||||
REG_X29 = 1,
|
||||
REG_X30 = 2,
|
||||
REG_NZCV = 3,
|
||||
REG_SP = 4,
|
||||
REG_WSP = 5,
|
||||
REG_WZR = 6,
|
||||
REG_XZR = 7,
|
||||
REG_B0 = 8,
|
||||
REG_B1 = 9,
|
||||
REG_B2 = 10,
|
||||
REG_B3 = 11,
|
||||
REG_B4 = 12,
|
||||
REG_B5 = 13,
|
||||
REG_B6 = 14,
|
||||
REG_B7 = 15,
|
||||
REG_B8 = 16,
|
||||
REG_B9 = 17,
|
||||
REG_B10 = 18,
|
||||
REG_B11 = 19,
|
||||
REG_B12 = 20,
|
||||
REG_B13 = 21,
|
||||
REG_B14 = 22,
|
||||
REG_B15 = 23,
|
||||
REG_B16 = 24,
|
||||
REG_B17 = 25,
|
||||
REG_B18 = 26,
|
||||
REG_B19 = 27,
|
||||
REG_B20 = 28,
|
||||
REG_B21 = 29,
|
||||
REG_B22 = 30,
|
||||
REG_B23 = 31,
|
||||
REG_B24 = 32,
|
||||
REG_B25 = 33,
|
||||
REG_B26 = 34,
|
||||
REG_B27 = 35,
|
||||
REG_B28 = 36,
|
||||
REG_B29 = 37,
|
||||
REG_B30 = 38,
|
||||
REG_B31 = 39,
|
||||
REG_D0 = 40,
|
||||
REG_D1 = 41,
|
||||
REG_D2 = 42,
|
||||
REG_D3 = 43,
|
||||
REG_D4 = 44,
|
||||
REG_D5 = 45,
|
||||
REG_D6 = 46,
|
||||
REG_D7 = 47,
|
||||
REG_D8 = 48,
|
||||
REG_D9 = 49,
|
||||
REG_D10 = 50,
|
||||
REG_D11 = 51,
|
||||
REG_D12 = 52,
|
||||
REG_D13 = 53,
|
||||
REG_D14 = 54,
|
||||
REG_D15 = 55,
|
||||
REG_D16 = 56,
|
||||
REG_D17 = 57,
|
||||
REG_D18 = 58,
|
||||
REG_D19 = 59,
|
||||
REG_D20 = 60,
|
||||
REG_D21 = 61,
|
||||
REG_D22 = 62,
|
||||
REG_D23 = 63,
|
||||
REG_D24 = 64,
|
||||
REG_D25 = 65,
|
||||
REG_D26 = 66,
|
||||
REG_D27 = 67,
|
||||
REG_D28 = 68,
|
||||
REG_D29 = 69,
|
||||
REG_D30 = 70,
|
||||
REG_D31 = 71,
|
||||
REG_H0 = 72,
|
||||
REG_H1 = 73,
|
||||
REG_H2 = 74,
|
||||
REG_H3 = 75,
|
||||
REG_H4 = 76,
|
||||
REG_H5 = 77,
|
||||
REG_H6 = 78,
|
||||
REG_H7 = 79,
|
||||
REG_H8 = 80,
|
||||
REG_H9 = 81,
|
||||
REG_H10 = 82,
|
||||
REG_H11 = 83,
|
||||
REG_H12 = 84,
|
||||
REG_H13 = 85,
|
||||
REG_H14 = 86,
|
||||
REG_H15 = 87,
|
||||
REG_H16 = 88,
|
||||
REG_H17 = 89,
|
||||
REG_H18 = 90,
|
||||
REG_H19 = 91,
|
||||
REG_H20 = 92,
|
||||
REG_H21 = 93,
|
||||
REG_H22 = 94,
|
||||
REG_H23 = 95,
|
||||
REG_H24 = 96,
|
||||
REG_H25 = 97,
|
||||
REG_H26 = 98,
|
||||
REG_H27 = 99,
|
||||
REG_H28 = 100,
|
||||
REG_H29 = 101,
|
||||
REG_H30 = 102,
|
||||
REG_H31 = 103,
|
||||
REG_Q0 = 104,
|
||||
REG_Q1 = 105,
|
||||
REG_Q2 = 106,
|
||||
REG_Q3 = 107,
|
||||
REG_Q4 = 108,
|
||||
REG_Q5 = 109,
|
||||
REG_Q6 = 110,
|
||||
REG_Q7 = 111,
|
||||
REG_Q8 = 112,
|
||||
REG_Q9 = 113,
|
||||
REG_Q10 = 114,
|
||||
REG_Q11 = 115,
|
||||
REG_Q12 = 116,
|
||||
REG_Q13 = 117,
|
||||
REG_Q14 = 118,
|
||||
REG_Q15 = 119,
|
||||
REG_Q16 = 120,
|
||||
REG_Q17 = 121,
|
||||
REG_Q18 = 122,
|
||||
REG_Q19 = 123,
|
||||
REG_Q20 = 124,
|
||||
REG_Q21 = 125,
|
||||
REG_Q22 = 126,
|
||||
REG_Q23 = 127,
|
||||
REG_Q24 = 128,
|
||||
REG_Q25 = 129,
|
||||
REG_Q26 = 130,
|
||||
REG_Q27 = 131,
|
||||
REG_Q28 = 132,
|
||||
REG_Q29 = 133,
|
||||
REG_Q30 = 134,
|
||||
REG_Q31 = 135,
|
||||
REG_S0 = 136,
|
||||
REG_S1 = 137,
|
||||
REG_S2 = 138,
|
||||
REG_S3 = 139,
|
||||
REG_S4 = 140,
|
||||
REG_S5 = 141,
|
||||
REG_S6 = 142,
|
||||
REG_S7 = 143,
|
||||
REG_S8 = 144,
|
||||
REG_S9 = 145,
|
||||
REG_S10 = 146,
|
||||
REG_S11 = 147,
|
||||
REG_S12 = 148,
|
||||
REG_S13 = 149,
|
||||
REG_S14 = 150,
|
||||
REG_S15 = 151,
|
||||
REG_S16 = 152,
|
||||
REG_S17 = 153,
|
||||
REG_S18 = 154,
|
||||
REG_S19 = 155,
|
||||
REG_S20 = 156,
|
||||
REG_S21 = 157,
|
||||
REG_S22 = 158,
|
||||
REG_S23 = 159,
|
||||
REG_S24 = 160,
|
||||
REG_S25 = 161,
|
||||
REG_S26 = 162,
|
||||
REG_S27 = 163,
|
||||
REG_S28 = 164,
|
||||
REG_S29 = 165,
|
||||
REG_S30 = 166,
|
||||
REG_S31 = 167,
|
||||
REG_W0 = 168,
|
||||
REG_W1 = 169,
|
||||
REG_W2 = 170,
|
||||
REG_W3 = 171,
|
||||
REG_W4 = 172,
|
||||
REG_W5 = 173,
|
||||
REG_W6 = 174,
|
||||
REG_W7 = 175,
|
||||
REG_W8 = 176,
|
||||
REG_W9 = 177,
|
||||
REG_W10 = 178,
|
||||
REG_W11 = 179,
|
||||
REG_W12 = 180,
|
||||
REG_W13 = 181,
|
||||
REG_W14 = 182,
|
||||
REG_W15 = 183,
|
||||
REG_W16 = 184,
|
||||
REG_W17 = 185,
|
||||
REG_W18 = 186,
|
||||
REG_W19 = 187,
|
||||
REG_W20 = 188,
|
||||
REG_W21 = 189,
|
||||
REG_W22 = 190,
|
||||
REG_W23 = 191,
|
||||
REG_W24 = 192,
|
||||
REG_W25 = 193,
|
||||
REG_W26 = 194,
|
||||
REG_W27 = 195,
|
||||
REG_W28 = 196,
|
||||
REG_W29 = 197,
|
||||
REG_W30 = 198,
|
||||
REG_X0 = 199,
|
||||
REG_X1 = 200,
|
||||
REG_X2 = 201,
|
||||
REG_X3 = 202,
|
||||
REG_X4 = 203,
|
||||
REG_X5 = 204,
|
||||
REG_X6 = 205,
|
||||
REG_X7 = 206,
|
||||
REG_X8 = 207,
|
||||
REG_X9 = 208,
|
||||
REG_X10 = 209,
|
||||
REG_X11 = 210,
|
||||
REG_X12 = 211,
|
||||
REG_X13 = 212,
|
||||
REG_X14 = 213,
|
||||
REG_X15 = 214,
|
||||
REG_X16 = 215,
|
||||
REG_X17 = 216,
|
||||
REG_X18 = 217,
|
||||
REG_X19 = 218,
|
||||
REG_X20 = 219,
|
||||
REG_X21 = 220,
|
||||
REG_X22 = 221,
|
||||
REG_X23 = 222,
|
||||
REG_X24 = 223,
|
||||
REG_X25 = 224,
|
||||
REG_X26 = 225,
|
||||
REG_X27 = 226,
|
||||
REG_X28 = 227,
|
||||
REG_V0 = 228,
|
||||
REG_V1 = 229,
|
||||
REG_V2 = 230,
|
||||
REG_V3 = 231,
|
||||
REG_V4 = 232,
|
||||
REG_V5 = 233,
|
||||
REG_V6 = 234,
|
||||
REG_V7 = 235,
|
||||
REG_V8 = 236,
|
||||
REG_V9 = 237,
|
||||
REG_V10 = 238,
|
||||
REG_V11 = 239,
|
||||
REG_V12 = 240,
|
||||
REG_V13 = 241,
|
||||
REG_V14 = 242,
|
||||
REG_V15 = 243,
|
||||
REG_V16 = 244,
|
||||
REG_V17 = 245,
|
||||
REG_V18 = 246,
|
||||
REG_V19 = 247,
|
||||
REG_V20 = 248,
|
||||
REG_V21 = 249,
|
||||
REG_V22 = 250,
|
||||
REG_V23 = 251,
|
||||
REG_V24 = 252,
|
||||
REG_V25 = 253,
|
||||
REG_V26 = 254,
|
||||
REG_V27 = 255,
|
||||
REG_V28 = 256,
|
||||
REG_V29 = 257,
|
||||
REG_V30 = 258,
|
||||
REG_V31 = 259,
|
||||
|
||||
// pseudo registers
|
||||
REG_PC = 260,
|
||||
REG_CPACR_EL1 = 261,
|
||||
|
||||
// thread registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_TPIDR_EL0 = 262,
|
||||
REG_TPIDRRO_EL0 = 263,
|
||||
REG_TPIDR_EL1 = 264,
|
||||
REG_PSTATE = 265,
|
||||
|
||||
// exception link registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_ELR_EL0 = 266,
|
||||
REG_ELR_EL1 = 267,
|
||||
REG_ELR_EL2 = 268,
|
||||
REG_ELR_EL3 = 269,
|
||||
|
||||
// stack pointers registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_SP_EL0 = 270,
|
||||
REG_SP_EL1 = 271,
|
||||
REG_SP_EL2 = 272,
|
||||
REG_SP_EL3 = 273,
|
||||
|
||||
// other CP15 registers, depreciated, use UC_ARM64_REG_CP_REG instead
|
||||
REG_TTBR0_EL1 = 274,
|
||||
REG_TTBR1_EL1 = 275,
|
||||
REG_ESR_EL0 = 276,
|
||||
REG_ESR_EL1 = 277,
|
||||
REG_ESR_EL2 = 278,
|
||||
REG_ESR_EL3 = 279,
|
||||
REG_FAR_EL0 = 280,
|
||||
REG_FAR_EL1 = 281,
|
||||
REG_FAR_EL2 = 282,
|
||||
REG_FAR_EL3 = 283,
|
||||
REG_PAR_EL1 = 284,
|
||||
REG_MAIR_EL1 = 285,
|
||||
REG_VBAR_EL0 = 286,
|
||||
REG_VBAR_EL1 = 287,
|
||||
REG_VBAR_EL2 = 288,
|
||||
REG_VBAR_EL3 = 289,
|
||||
REG_CP_REG = 290,
|
||||
|
||||
// floating point control and status registers
|
||||
REG_FPCR = 291,
|
||||
REG_FPSR = 292,
|
||||
REG_ENDING = 293,
|
||||
|
||||
// alias registers
|
||||
REG_IP0 = 215,
|
||||
REG_IP1 = 216,
|
||||
REG_FP = 1,
|
||||
REG_LR = 2,
|
||||
|
||||
// ARM64 instructions
|
||||
|
||||
INS_INVALID = 0,
|
||||
INS_MRS = 1,
|
||||
INS_MSR = 2,
|
||||
INS_SYS = 3,
|
||||
INS_SYSL = 4,
|
||||
INS_ENDING = 5,
|
||||
}
|
||||
}
|
44
Ryujinx.Tests.Unicorn/Native/Const/Common.cs
Normal file
44
Ryujinx.Tests.Unicorn/Native/Const/Common.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Common
|
||||
{
|
||||
API_MAJOR = 2,
|
||||
|
||||
API_MINOR = 0,
|
||||
|
||||
API_PATCH = 0,
|
||||
API_EXTRA = 255,
|
||||
VERSION_MAJOR = 2,
|
||||
|
||||
VERSION_MINOR = 0,
|
||||
|
||||
VERSION_PATCH = 0,
|
||||
VERSION_EXTRA = 255,
|
||||
SECOND_SCALE = 1000000,
|
||||
MILISECOND_SCALE = 1000,
|
||||
QUERY_MODE = 1,
|
||||
QUERY_PAGE_SIZE = 2,
|
||||
QUERY_ARCH = 3,
|
||||
QUERY_TIMEOUT = 4,
|
||||
|
||||
CTL_IO_NONE = 0,
|
||||
CTL_IO_WRITE = 1,
|
||||
CTL_IO_READ = 2,
|
||||
CTL_IO_READ_WRITE = 3,
|
||||
|
||||
CTL_UC_MODE = 0,
|
||||
CTL_UC_PAGE_SIZE = 1,
|
||||
CTL_UC_ARCH = 2,
|
||||
CTL_UC_TIMEOUT = 3,
|
||||
CTL_UC_USE_EXITS = 4,
|
||||
CTL_UC_EXITS_CNT = 5,
|
||||
CTL_UC_EXITS = 6,
|
||||
CTL_CPU_MODEL = 7,
|
||||
CTL_TB_REQUEST_CACHE = 8,
|
||||
CTL_TB_REMOVE_CACHE = 9,
|
||||
CTL_TB_FLUSH = 10,
|
||||
}
|
||||
}
|
31
Ryujinx.Tests.Unicorn/Native/Const/Error.cs
Normal file
31
Ryujinx.Tests.Unicorn/Native/Const/Error.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Error
|
||||
{
|
||||
OK = 0,
|
||||
NOMEM = 1,
|
||||
ARCH = 2,
|
||||
HANDLE = 3,
|
||||
MODE = 4,
|
||||
VERSION = 5,
|
||||
READ_UNMAPPED = 6,
|
||||
WRITE_UNMAPPED = 7,
|
||||
FETCH_UNMAPPED = 8,
|
||||
HOOK = 9,
|
||||
INSN_INVALID = 10,
|
||||
MAP = 11,
|
||||
WRITE_PROT = 12,
|
||||
READ_PROT = 13,
|
||||
FETCH_PROT = 14,
|
||||
ARG = 15,
|
||||
READ_UNALIGNED = 16,
|
||||
WRITE_UNALIGNED = 17,
|
||||
FETCH_UNALIGNED = 18,
|
||||
HOOK_EXIST = 19,
|
||||
RESOURCE = 20,
|
||||
EXCEPTION = 21,
|
||||
}
|
||||
}
|
33
Ryujinx.Tests.Unicorn/Native/Const/Hook.cs
Normal file
33
Ryujinx.Tests.Unicorn/Native/Const/Hook.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Hook
|
||||
{
|
||||
INTR = 1,
|
||||
INSN = 2,
|
||||
CODE = 4,
|
||||
BLOCK = 8,
|
||||
MEM_READ_UNMAPPED = 16,
|
||||
MEM_WRITE_UNMAPPED = 32,
|
||||
MEM_FETCH_UNMAPPED = 64,
|
||||
MEM_READ_PROT = 128,
|
||||
MEM_WRITE_PROT = 256,
|
||||
MEM_FETCH_PROT = 512,
|
||||
MEM_READ = 1024,
|
||||
MEM_WRITE = 2048,
|
||||
MEM_FETCH = 4096,
|
||||
MEM_READ_AFTER = 8192,
|
||||
INSN_INVALID = 16384,
|
||||
EDGE_GENERATED = 32768,
|
||||
TCG_OPCODE = 65536,
|
||||
MEM_UNMAPPED = 112,
|
||||
MEM_PROT = 896,
|
||||
MEM_READ_INVALID = 144,
|
||||
MEM_WRITE_INVALID = 288,
|
||||
MEM_FETCH_INVALID = 576,
|
||||
MEM_INVALID = 1008,
|
||||
MEM_VALID = 7168,
|
||||
}
|
||||
}
|
19
Ryujinx.Tests.Unicorn/Native/Const/Memory.cs
Normal file
19
Ryujinx.Tests.Unicorn/Native/Const/Memory.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Memory
|
||||
{
|
||||
READ = 16,
|
||||
WRITE = 17,
|
||||
FETCH = 18,
|
||||
READ_UNMAPPED = 19,
|
||||
WRITE_UNMAPPED = 20,
|
||||
FETCH_UNMAPPED = 21,
|
||||
WRITE_PROT = 22,
|
||||
READ_PROT = 23,
|
||||
FETCH_PROT = 24,
|
||||
READ_AFTER = 25,
|
||||
}
|
||||
}
|
35
Ryujinx.Tests.Unicorn/Native/Const/Mode.cs
Normal file
35
Ryujinx.Tests.Unicorn/Native/Const/Mode.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Mode
|
||||
{
|
||||
LITTLE_ENDIAN = 0,
|
||||
BIG_ENDIAN = 1073741824,
|
||||
ARM = 0,
|
||||
THUMB = 16,
|
||||
MCLASS = 32,
|
||||
V8 = 64,
|
||||
ARMBE8 = 1024,
|
||||
ARM926 = 128,
|
||||
ARM946 = 256,
|
||||
ARM1176 = 512,
|
||||
MICRO = 16,
|
||||
MIPS3 = 32,
|
||||
MIPS32R6 = 64,
|
||||
MIPS32 = 4,
|
||||
MIPS64 = 8,
|
||||
MODE_16 = 2,
|
||||
MODE_32 = 4,
|
||||
MODE_64 = 8,
|
||||
PPC32 = 4,
|
||||
PPC64 = 8,
|
||||
QPX = 16,
|
||||
SPARC32 = 4,
|
||||
SPARC64 = 8,
|
||||
V9 = 16,
|
||||
RISCV32 = 4,
|
||||
RISCV64 = 8,
|
||||
}
|
||||
}
|
14
Ryujinx.Tests.Unicorn/Native/Const/Permission.cs
Normal file
14
Ryujinx.Tests.Unicorn/Native/Const/Permission.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum Permission
|
||||
{
|
||||
NONE = 0,
|
||||
READ = 1,
|
||||
WRITE = 2,
|
||||
EXEC = 4,
|
||||
ALL = 7,
|
||||
}
|
||||
}
|
12
Ryujinx.Tests.Unicorn/Native/Const/TCG.cs
Normal file
12
Ryujinx.Tests.Unicorn/Native/Const/TCG.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native.Const
|
||||
{
|
||||
public enum TCG
|
||||
{
|
||||
OP_SUB = 0,
|
||||
OP_FLAG_CMP = 1,
|
||||
OP_FLAG_DIRECT = 2,
|
||||
}
|
||||
}
|
@@ -1,13 +1,43 @@
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public class Interface
|
||||
public static class Interface
|
||||
{
|
||||
public static void Checked(UnicornError error)
|
||||
public static bool IsUnicornAvailable { get; private set; } = true;
|
||||
|
||||
private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
|
||||
{
|
||||
if (error != UnicornError.UC_ERR_OK)
|
||||
if (libraryName == "unicorn")
|
||||
{
|
||||
string loadPath = $"{Path.GetDirectoryName(assembly.Location)}/";
|
||||
loadPath += OperatingSystem.IsWindows() ? $"{libraryName}.dll" : $"lib{libraryName}.so";
|
||||
|
||||
if (!NativeLibrary.TryLoad(loadPath, out IntPtr libraryPtr))
|
||||
{
|
||||
IsUnicornAvailable = false;
|
||||
Console.Error.WriteLine($"ERROR: Could not find unicorn at: {loadPath}");
|
||||
}
|
||||
|
||||
return libraryPtr;
|
||||
}
|
||||
|
||||
// Otherwise, fallback to default import resolver.
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
static Interface()
|
||||
{
|
||||
NativeLibrary.SetDllImportResolver(Assembly.GetExecutingAssembly(), ImportResolver);
|
||||
}
|
||||
|
||||
public static void Checked(Error error)
|
||||
{
|
||||
if (error != Error.OK)
|
||||
{
|
||||
throw new UnicornException(error);
|
||||
}
|
||||
@@ -31,39 +61,39 @@ namespace Ryujinx.Tests.Unicorn.Native
|
||||
public static extern uint uc_version(out uint major, out uint minor);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_open(UnicornArch arch, UnicornMode mode, out IntPtr uc);
|
||||
public static extern Error uc_open(Arch arch, Mode mode, out IntPtr uc);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_close(IntPtr uc);
|
||||
public static extern Error uc_close(IntPtr uc);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern IntPtr uc_strerror(UnicornError err);
|
||||
public static extern IntPtr uc_strerror(Error err);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_reg_write(IntPtr uc, int regid, byte[] value);
|
||||
public static extern Error uc_reg_write(IntPtr uc, int regid, byte[] value);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_reg_read(IntPtr uc, int regid, byte[] value);
|
||||
public static extern Error uc_reg_read(IntPtr uc, int regid, byte[] value);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_write(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
public static extern Error uc_mem_write(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_read(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
public static extern Error uc_mem_read(IntPtr uc, ulong address, byte[] bytes, ulong size);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_emu_start(IntPtr uc, ulong begin, ulong until, ulong timeout, ulong count);
|
||||
public static extern Error uc_emu_start(IntPtr uc, ulong begin, ulong until, ulong timeout, ulong count);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_map(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
public static extern Error uc_mem_map(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_unmap(IntPtr uc, ulong address, ulong size);
|
||||
public static extern Error uc_mem_unmap(IntPtr uc, ulong address, ulong size);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_protect(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
public static extern Error uc_mem_protect(IntPtr uc, ulong address, ulong size, uint perms);
|
||||
|
||||
[DllImport("unicorn", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern UnicornError uc_mem_regions(IntPtr uc, out IntPtr regions, out uint count);
|
||||
public static extern Error uc_mem_regions(IntPtr uc, out IntPtr regions, out uint count);
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,14 +0,0 @@
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public enum UnicornArch : uint
|
||||
{
|
||||
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
|
||||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||
UC_ARCH_MIPS, // Mips architecture
|
||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_MAX,
|
||||
}
|
||||
}
|
@@ -1,33 +0,0 @@
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn.Native
|
||||
{
|
||||
public enum UnicornMode : uint
|
||||
{
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
// arm / arm64
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||
// mips
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||
// x86 / x64
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||
// ppc
|
||||
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
|
||||
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||
// sparc
|
||||
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||
// m68k
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Tests.Unicorn.Native;
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
@@ -30,32 +31,32 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
public uint LR
|
||||
{
|
||||
get => GetRegister(Arm32Register.LR);
|
||||
set => SetRegister(Arm32Register.LR, value);
|
||||
get => GetRegister(Arm.REG_LR);
|
||||
set => SetRegister(Arm.REG_LR, value);
|
||||
}
|
||||
|
||||
public uint SP
|
||||
{
|
||||
get => GetRegister(Arm32Register.SP);
|
||||
set => SetRegister(Arm32Register.SP, value);
|
||||
get => GetRegister(Arm.REG_SP);
|
||||
set => SetRegister(Arm.REG_SP, value);
|
||||
}
|
||||
|
||||
public uint PC
|
||||
{
|
||||
get => GetRegister(Arm32Register.PC) & 0xfffffffeu;
|
||||
set => SetRegister(Arm32Register.PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
|
||||
get => GetRegister(Arm.REG_PC) & 0xfffffffeu;
|
||||
set => SetRegister(Arm.REG_PC, (value & 0xfffffffeu) | (ThumbFlag ? 1u : 0u));
|
||||
}
|
||||
|
||||
public uint CPSR
|
||||
{
|
||||
get => (uint)GetRegister(Arm32Register.CPSR);
|
||||
set => SetRegister(Arm32Register.CPSR, (uint)value);
|
||||
get => GetRegister(Arm.REG_CPSR);
|
||||
set => SetRegister(Arm.REG_CPSR, value);
|
||||
}
|
||||
|
||||
public int Fpscr
|
||||
{
|
||||
get => (int)GetRegister(Arm32Register.FPSCR) | ((int)GetRegister(Arm32Register.FPSCR_NZCV));
|
||||
set => SetRegister(Arm32Register.FPSCR, (uint)value);
|
||||
get => (int)GetRegister(Arm.REG_FPSCR) | ((int)GetRegister(Arm.REG_FPSCR_NZCV));
|
||||
set => SetRegister(Arm.REG_FPSCR, (uint)value);
|
||||
}
|
||||
|
||||
public bool QFlag
|
||||
@@ -94,16 +95,16 @@ namespace Ryujinx.Tests.Unicorn
|
||||
set
|
||||
{
|
||||
CPSR = (CPSR & ~0x00000020u) | (value ? 0x00000020u : 0u);
|
||||
SetRegister(Arm32Register.PC, (GetRegister(Arm32Register.PC) & 0xfffffffeu) | (value ? 1u : 0u));
|
||||
SetRegister(Arm.REG_PC, (GetRegister(Arm.REG_PC) & 0xfffffffeu) | (value ? 1u : 0u));
|
||||
}
|
||||
}
|
||||
|
||||
public UnicornAArch32()
|
||||
{
|
||||
Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
|
||||
Interface.Checked(Interface.uc_open(Arch.ARM, Mode.LITTLE_ENDIAN, out uc));
|
||||
|
||||
SetRegister(Arm32Register.C1_C0_2, GetRegister(Arm32Register.C1_C0_2) | 0xf00000);
|
||||
SetRegister(Arm32Register.FPEXC, 0x40000000);
|
||||
SetRegister(Arm.REG_C1_C0_2, GetRegister(Arm.REG_C1_C0_2) | 0xf00000);
|
||||
SetRegister(Arm.REG_FPEXC, 0x40000000);
|
||||
}
|
||||
|
||||
~UnicornAArch32()
|
||||
@@ -136,44 +137,44 @@ namespace Ryujinx.Tests.Unicorn
|
||||
RunForCount(1);
|
||||
}
|
||||
|
||||
private static Arm32Register[] XRegisters = new Arm32Register[16]
|
||||
private static Arm[] XRegisters = new Arm[16]
|
||||
{
|
||||
Arm32Register.R0,
|
||||
Arm32Register.R1,
|
||||
Arm32Register.R2,
|
||||
Arm32Register.R3,
|
||||
Arm32Register.R4,
|
||||
Arm32Register.R5,
|
||||
Arm32Register.R6,
|
||||
Arm32Register.R7,
|
||||
Arm32Register.R8,
|
||||
Arm32Register.R9,
|
||||
Arm32Register.R10,
|
||||
Arm32Register.R11,
|
||||
Arm32Register.R12,
|
||||
Arm32Register.R13,
|
||||
Arm32Register.R14,
|
||||
Arm32Register.R15,
|
||||
Arm.REG_R0,
|
||||
Arm.REG_R1,
|
||||
Arm.REG_R2,
|
||||
Arm.REG_R3,
|
||||
Arm.REG_R4,
|
||||
Arm.REG_R5,
|
||||
Arm.REG_R6,
|
||||
Arm.REG_R7,
|
||||
Arm.REG_R8,
|
||||
Arm.REG_R9,
|
||||
Arm.REG_R10,
|
||||
Arm.REG_R11,
|
||||
Arm.REG_R12,
|
||||
Arm.REG_R13,
|
||||
Arm.REG_R14,
|
||||
Arm.REG_R15,
|
||||
};
|
||||
|
||||
private static Arm32Register[] QRegisters = new Arm32Register[16]
|
||||
private static Arm[] QRegisters = new Arm[16]
|
||||
{
|
||||
Arm32Register.Q0,
|
||||
Arm32Register.Q1,
|
||||
Arm32Register.Q2,
|
||||
Arm32Register.Q3,
|
||||
Arm32Register.Q4,
|
||||
Arm32Register.Q5,
|
||||
Arm32Register.Q6,
|
||||
Arm32Register.Q7,
|
||||
Arm32Register.Q8,
|
||||
Arm32Register.Q9,
|
||||
Arm32Register.Q10,
|
||||
Arm32Register.Q11,
|
||||
Arm32Register.Q12,
|
||||
Arm32Register.Q13,
|
||||
Arm32Register.Q14,
|
||||
Arm32Register.Q15
|
||||
Arm.REG_Q0,
|
||||
Arm.REG_Q1,
|
||||
Arm.REG_Q2,
|
||||
Arm.REG_Q3,
|
||||
Arm.REG_Q4,
|
||||
Arm.REG_Q5,
|
||||
Arm.REG_Q6,
|
||||
Arm.REG_Q7,
|
||||
Arm.REG_Q8,
|
||||
Arm.REG_Q9,
|
||||
Arm.REG_Q10,
|
||||
Arm.REG_Q11,
|
||||
Arm.REG_Q12,
|
||||
Arm.REG_Q13,
|
||||
Arm.REG_Q14,
|
||||
Arm.REG_Q15
|
||||
};
|
||||
|
||||
public uint GetX(int index)
|
||||
@@ -204,7 +205,7 @@ namespace Ryujinx.Tests.Unicorn
|
||||
}
|
||||
|
||||
// Getting quadword registers from Unicorn A32 seems to be broken, so we combine its 2 doubleword registers instead.
|
||||
return GetVector((Arm32Register)((int)Arm32Register.D0 + index * 2));
|
||||
return GetVector((Arm)((int)Arm.REG_D0 + index * 2));
|
||||
}
|
||||
|
||||
public void SetQ(int index, SimdValue value)
|
||||
@@ -214,10 +215,10 @@ namespace Ryujinx.Tests.Unicorn
|
||||
throw new ArgumentOutOfRangeException(nameof(index));
|
||||
}
|
||||
|
||||
SetVector((Arm32Register)((int)Arm32Register.D0 + index * 2), value);
|
||||
SetVector((Arm)((int)Arm.REG_D0 + index * 2), value);
|
||||
}
|
||||
|
||||
public uint GetRegister(Arm32Register register)
|
||||
public uint GetRegister(Arm register)
|
||||
{
|
||||
byte[] data = new byte[4];
|
||||
|
||||
@@ -226,14 +227,14 @@ namespace Ryujinx.Tests.Unicorn
|
||||
return (uint)BitConverter.ToInt32(data, 0);
|
||||
}
|
||||
|
||||
public void SetRegister(Arm32Register register, uint value)
|
||||
public void SetRegister(Arm register, uint value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value);
|
||||
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
}
|
||||
|
||||
public SimdValue GetVector(Arm32Register register)
|
||||
public SimdValue GetVector(Arm register)
|
||||
{
|
||||
byte[] data = new byte[8];
|
||||
|
||||
@@ -245,7 +246,7 @@ namespace Ryujinx.Tests.Unicorn
|
||||
return new SimdValue(lo, hi);
|
||||
}
|
||||
|
||||
private void SetVector(Arm32Register register, SimdValue value)
|
||||
private void SetVector(Arm register, SimdValue value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value.GetUInt64(0));
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
@@ -300,13 +301,10 @@ namespace Ryujinx.Tests.Unicorn
|
||||
try
|
||||
{
|
||||
Interface.uc_version(out _, out _);
|
||||
}
|
||||
catch (DllNotFoundException) { }
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Interface.IsUnicornAvailable;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
using Ryujinx.Tests.Unicorn.Native;
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
@@ -30,38 +31,38 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
public ulong LR
|
||||
{
|
||||
get => GetRegister(ArmRegister.LR);
|
||||
set => SetRegister(ArmRegister.LR, value);
|
||||
get => GetRegister(Arm64.REG_LR);
|
||||
set => SetRegister(Arm64.REG_LR, value);
|
||||
}
|
||||
|
||||
public ulong SP
|
||||
{
|
||||
get => GetRegister(ArmRegister.SP);
|
||||
set => SetRegister(ArmRegister.SP, value);
|
||||
get => GetRegister(Arm64.REG_SP);
|
||||
set => SetRegister(Arm64.REG_SP, value);
|
||||
}
|
||||
|
||||
public ulong PC
|
||||
{
|
||||
get => GetRegister(ArmRegister.PC);
|
||||
set => SetRegister(ArmRegister.PC, value);
|
||||
get => GetRegister(Arm64.REG_PC);
|
||||
set => SetRegister(Arm64.REG_PC, value);
|
||||
}
|
||||
|
||||
public uint Pstate
|
||||
{
|
||||
get => (uint)GetRegister(ArmRegister.PSTATE);
|
||||
set => SetRegister(ArmRegister.PSTATE, (uint)value);
|
||||
get => (uint)GetRegister(Arm64.REG_PSTATE);
|
||||
set => SetRegister(Arm64.REG_PSTATE, (uint)value);
|
||||
}
|
||||
|
||||
public int Fpcr
|
||||
{
|
||||
get => (int)GetRegister(ArmRegister.FPCR);
|
||||
set => SetRegister(ArmRegister.FPCR, (uint)value);
|
||||
get => (int)GetRegister(Arm64.REG_FPCR);
|
||||
set => SetRegister(Arm64.REG_FPCR, (uint)value);
|
||||
}
|
||||
|
||||
public int Fpsr
|
||||
{
|
||||
get => (int)GetRegister(ArmRegister.FPSR);
|
||||
set => SetRegister(ArmRegister.FPSR, (uint)value);
|
||||
get => (int)GetRegister(Arm64.REG_FPSR);
|
||||
set => SetRegister(Arm64.REG_FPSR, (uint)value);
|
||||
}
|
||||
|
||||
public bool OverflowFlag
|
||||
@@ -90,9 +91,9 @@ namespace Ryujinx.Tests.Unicorn
|
||||
|
||||
public UnicornAArch64()
|
||||
{
|
||||
Interface.Checked(Interface.uc_open(UnicornArch.UC_ARCH_ARM64, UnicornMode.UC_MODE_LITTLE_ENDIAN, out uc));
|
||||
Interface.Checked(Interface.uc_open(Arch.ARM64, Mode.LITTLE_ENDIAN, out uc));
|
||||
|
||||
SetRegister(ArmRegister.CPACR_EL1, 0x00300000);
|
||||
SetRegister(Arm64.REG_CPACR_EL1, 0x00300000);
|
||||
}
|
||||
|
||||
~UnicornAArch64()
|
||||
@@ -125,75 +126,75 @@ namespace Ryujinx.Tests.Unicorn
|
||||
RunForCount(1);
|
||||
}
|
||||
|
||||
private static ArmRegister[] XRegisters = new ArmRegister[31]
|
||||
private static Arm64[] XRegisters = new Arm64[31]
|
||||
{
|
||||
ArmRegister.X0,
|
||||
ArmRegister.X1,
|
||||
ArmRegister.X2,
|
||||
ArmRegister.X3,
|
||||
ArmRegister.X4,
|
||||
ArmRegister.X5,
|
||||
ArmRegister.X6,
|
||||
ArmRegister.X7,
|
||||
ArmRegister.X8,
|
||||
ArmRegister.X9,
|
||||
ArmRegister.X10,
|
||||
ArmRegister.X11,
|
||||
ArmRegister.X12,
|
||||
ArmRegister.X13,
|
||||
ArmRegister.X14,
|
||||
ArmRegister.X15,
|
||||
ArmRegister.X16,
|
||||
ArmRegister.X17,
|
||||
ArmRegister.X18,
|
||||
ArmRegister.X19,
|
||||
ArmRegister.X20,
|
||||
ArmRegister.X21,
|
||||
ArmRegister.X22,
|
||||
ArmRegister.X23,
|
||||
ArmRegister.X24,
|
||||
ArmRegister.X25,
|
||||
ArmRegister.X26,
|
||||
ArmRegister.X27,
|
||||
ArmRegister.X28,
|
||||
ArmRegister.X29,
|
||||
ArmRegister.X30,
|
||||
Arm64.REG_X0,
|
||||
Arm64.REG_X1,
|
||||
Arm64.REG_X2,
|
||||
Arm64.REG_X3,
|
||||
Arm64.REG_X4,
|
||||
Arm64.REG_X5,
|
||||
Arm64.REG_X6,
|
||||
Arm64.REG_X7,
|
||||
Arm64.REG_X8,
|
||||
Arm64.REG_X9,
|
||||
Arm64.REG_X10,
|
||||
Arm64.REG_X11,
|
||||
Arm64.REG_X12,
|
||||
Arm64.REG_X13,
|
||||
Arm64.REG_X14,
|
||||
Arm64.REG_X15,
|
||||
Arm64.REG_X16,
|
||||
Arm64.REG_X17,
|
||||
Arm64.REG_X18,
|
||||
Arm64.REG_X19,
|
||||
Arm64.REG_X20,
|
||||
Arm64.REG_X21,
|
||||
Arm64.REG_X22,
|
||||
Arm64.REG_X23,
|
||||
Arm64.REG_X24,
|
||||
Arm64.REG_X25,
|
||||
Arm64.REG_X26,
|
||||
Arm64.REG_X27,
|
||||
Arm64.REG_X28,
|
||||
Arm64.REG_X29,
|
||||
Arm64.REG_X30,
|
||||
};
|
||||
|
||||
private static ArmRegister[] QRegisters = new ArmRegister[32]
|
||||
private static Arm64[] QRegisters = new Arm64[32]
|
||||
{
|
||||
ArmRegister.Q0,
|
||||
ArmRegister.Q1,
|
||||
ArmRegister.Q2,
|
||||
ArmRegister.Q3,
|
||||
ArmRegister.Q4,
|
||||
ArmRegister.Q5,
|
||||
ArmRegister.Q6,
|
||||
ArmRegister.Q7,
|
||||
ArmRegister.Q8,
|
||||
ArmRegister.Q9,
|
||||
ArmRegister.Q10,
|
||||
ArmRegister.Q11,
|
||||
ArmRegister.Q12,
|
||||
ArmRegister.Q13,
|
||||
ArmRegister.Q14,
|
||||
ArmRegister.Q15,
|
||||
ArmRegister.Q16,
|
||||
ArmRegister.Q17,
|
||||
ArmRegister.Q18,
|
||||
ArmRegister.Q19,
|
||||
ArmRegister.Q20,
|
||||
ArmRegister.Q21,
|
||||
ArmRegister.Q22,
|
||||
ArmRegister.Q23,
|
||||
ArmRegister.Q24,
|
||||
ArmRegister.Q25,
|
||||
ArmRegister.Q26,
|
||||
ArmRegister.Q27,
|
||||
ArmRegister.Q28,
|
||||
ArmRegister.Q29,
|
||||
ArmRegister.Q30,
|
||||
ArmRegister.Q31,
|
||||
Arm64.REG_Q0,
|
||||
Arm64.REG_Q1,
|
||||
Arm64.REG_Q2,
|
||||
Arm64.REG_Q3,
|
||||
Arm64.REG_Q4,
|
||||
Arm64.REG_Q5,
|
||||
Arm64.REG_Q6,
|
||||
Arm64.REG_Q7,
|
||||
Arm64.REG_Q8,
|
||||
Arm64.REG_Q9,
|
||||
Arm64.REG_Q10,
|
||||
Arm64.REG_Q11,
|
||||
Arm64.REG_Q12,
|
||||
Arm64.REG_Q13,
|
||||
Arm64.REG_Q14,
|
||||
Arm64.REG_Q15,
|
||||
Arm64.REG_Q16,
|
||||
Arm64.REG_Q17,
|
||||
Arm64.REG_Q18,
|
||||
Arm64.REG_Q19,
|
||||
Arm64.REG_Q20,
|
||||
Arm64.REG_Q21,
|
||||
Arm64.REG_Q22,
|
||||
Arm64.REG_Q23,
|
||||
Arm64.REG_Q24,
|
||||
Arm64.REG_Q25,
|
||||
Arm64.REG_Q26,
|
||||
Arm64.REG_Q27,
|
||||
Arm64.REG_Q28,
|
||||
Arm64.REG_Q29,
|
||||
Arm64.REG_Q30,
|
||||
Arm64.REG_Q31,
|
||||
};
|
||||
|
||||
public ulong GetX(int index)
|
||||
@@ -236,7 +237,7 @@ namespace Ryujinx.Tests.Unicorn
|
||||
SetVector(QRegisters[index], value);
|
||||
}
|
||||
|
||||
private ulong GetRegister(ArmRegister register)
|
||||
private ulong GetRegister(Arm64 register)
|
||||
{
|
||||
byte[] data = new byte[8];
|
||||
|
||||
@@ -245,14 +246,14 @@ namespace Ryujinx.Tests.Unicorn
|
||||
return (ulong)BitConverter.ToInt64(data, 0);
|
||||
}
|
||||
|
||||
private void SetRegister(ArmRegister register, ulong value)
|
||||
private void SetRegister(Arm64 register, ulong value)
|
||||
{
|
||||
byte[] data = BitConverter.GetBytes(value);
|
||||
|
||||
Interface.Checked(Interface.uc_reg_write(uc, (int)register, data));
|
||||
}
|
||||
|
||||
private SimdValue GetVector(ArmRegister register)
|
||||
private SimdValue GetVector(Arm64 register)
|
||||
{
|
||||
byte[] data = new byte[16];
|
||||
|
||||
@@ -261,7 +262,7 @@ namespace Ryujinx.Tests.Unicorn
|
||||
return new SimdValue(data);
|
||||
}
|
||||
|
||||
private void SetVector(ArmRegister register, SimdValue value)
|
||||
private void SetVector(Arm64 register, SimdValue value)
|
||||
{
|
||||
byte[] data = value.ToArray();
|
||||
|
||||
@@ -315,13 +316,10 @@ namespace Ryujinx.Tests.Unicorn
|
||||
try
|
||||
{
|
||||
Interface.uc_version(out _, out _);
|
||||
}
|
||||
catch (DllNotFoundException) { }
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Interface.IsUnicornAvailable;
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,29 +0,0 @@
|
||||
// ReSharper disable InconsistentNaming
|
||||
namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public enum UnicornError
|
||||
{
|
||||
UC_ERR_OK = 0, // No error: everything was fine
|
||||
UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
UC_ERR_ARCH, // Unsupported architecture: uc_open()
|
||||
UC_ERR_HANDLE, // Invalid handle
|
||||
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start()
|
||||
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start()
|
||||
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start()
|
||||
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
|
||||
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
|
||||
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
|
||||
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
|
||||
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
|
||||
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
|
||||
UC_ERR_ARG, // Invalid argument provided to uc_xxx function (See specific function API)
|
||||
UC_ERR_READ_UNALIGNED, // Unaligned read
|
||||
UC_ERR_WRITE_UNALIGNED, // Unaligned write
|
||||
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
||||
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||
UC_ERR_EXCEPTION // Unhandled CPU exception
|
||||
}
|
||||
}
|
@@ -1,3 +1,4 @@
|
||||
using Ryujinx.Tests.Unicorn.Native.Const;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
@@ -5,9 +6,9 @@ namespace Ryujinx.Tests.Unicorn
|
||||
{
|
||||
public class UnicornException : Exception
|
||||
{
|
||||
public readonly UnicornError Error;
|
||||
public readonly Error Error;
|
||||
|
||||
internal UnicornException(UnicornError error)
|
||||
internal UnicornException(Error error)
|
||||
{
|
||||
Error = error;
|
||||
}
|
||||
@@ -20,4 +21,4 @@ namespace Ryujinx.Tests.Unicorn
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -9,14 +9,12 @@ CPU simulator, Armeilleure.
|
||||
|
||||
On Windows, Unicorn is shipped as a pre-compiled dynamic library (`.dll`), licenced under the GPLv2.
|
||||
|
||||
The source code for `windows/unicorn.dll` is available at: https://github.com/MerryMage/UnicornDotNet/tree/299451c02d9c810d2feca51f5e9cb6d8b2f38960
|
||||
The source code for `windows/unicorn.dll` is available at: https://github.com/unicorn-engine/unicorn/tree/df3aa0fccbce9e1420e82110cbae5951755a0698
|
||||
|
||||
## Linux
|
||||
|
||||
On Linux, you will first need to download Unicorn from https://github.com/unicorn-engine/unicorn.
|
||||
On Windows, Unicorn is shipped as a pre-compiled shared object (`.so`), licenced under the GPLv2.
|
||||
|
||||
Then you need to patch it to expose the FSPCR register by applying `linux/unicorn_fspcr.patch`
|
||||
|
||||
Then, compile Unicorn from source with its `make.sh` script.
|
||||
The source code for `linux/unicorn.so` is available at: https://github.com/unicorn-engine/unicorn/tree/df3aa0fccbce9e1420e82110cbae5951755a0698
|
||||
|
||||
See https://github.com/Ryujinx/Ryujinx/pull/1433 for details.
|
||||
|
BIN
Ryujinx.Tests.Unicorn/libs/linux/libunicorn.so
Normal file
BIN
Ryujinx.Tests.Unicorn/libs/linux/libunicorn.so
Normal file
Binary file not shown.
@@ -1,24 +0,0 @@
|
||||
diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c
|
||||
index 5ff9ebb..d4953f4 100644
|
||||
--- a/qemu/target-arm/unicorn_arm.c
|
||||
+++ b/qemu/target-arm/unicorn_arm.c
|
||||
@@ -101,6 +101,9 @@ int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun
|
||||
case UC_ARM_REG_FPEXC:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.vfp.xregs[ARM_VFP_FPEXC];
|
||||
break;
|
||||
+ case UC_ARM_REG_FPSCR:
|
||||
+ *(int32_t *)value = vfp_get_fpscr(&ARM_CPU(uc, mycpu)->env);
|
||||
+ break;
|
||||
case UC_ARM_REG_IPSR:
|
||||
*(uint32_t *)value = xpsr_read(&ARM_CPU(uc, mycpu)->env) & 0x1ff;
|
||||
break;
|
||||
@@ -175,6 +178,9 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, i
|
||||
case UC_ARM_REG_FPEXC:
|
||||
ARM_CPU(uc, mycpu)->env.vfp.xregs[ARM_VFP_FPEXC] = *(int32_t *)value;
|
||||
break;
|
||||
+ case UC_ARM_REG_FPSCR:
|
||||
+ vfp_set_fpscr(&ARM_CPU(uc, mycpu)->env, *(uint32_t *)value);
|
||||
+ break;
|
||||
case UC_ARM_REG_IPSR:
|
||||
xpsr_write(&ARM_CPU(uc, mycpu)->env, *(uint32_t *)value, 0x1ff);
|
||||
break;
|
Binary file not shown.
199
Ryujinx.Tests.Unicorn/unicorn_const_generator.py
Normal file
199
Ryujinx.Tests.Unicorn/unicorn_const_generator.py
Normal file
@@ -0,0 +1,199 @@
|
||||
#!/usr/bin/env python3
|
||||
# Unicorn Engine
|
||||
# By Dang Hoang Vu, 2013
|
||||
# Modified for Ryujinx from: https://github.com/unicorn-engine/unicorn/blob/6c1cbef6ac505d355033aef1176b684d02e1eb3a/bindings/const_generator.py
|
||||
from __future__ import print_function
|
||||
import sys, re, os
|
||||
|
||||
include = [ 'arm.h', 'arm64.h', 'unicorn.h' ]
|
||||
split_common = [ 'ARCH', 'MODE', 'ERR', 'MEM', 'TCG', 'HOOK', 'PROT' ]
|
||||
|
||||
template = {
|
||||
'dotnet': {
|
||||
'header': "// Constants for Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\n// ReSharper disable InconsistentNaming\nnamespace Ryujinx.Tests.Unicorn.Native.Const\n{\n public enum %s\n {\n",
|
||||
'footer': " }\n}\n",
|
||||
'line_format': ' %s = %s,\n',
|
||||
'out_file': os.path.join(os.path.dirname(__file__), 'Native', 'Const', '%s.cs'),
|
||||
# prefixes for constant filenames of all archs - case sensitive
|
||||
'arm.h': 'Arm',
|
||||
'arm64.h': 'Arm64',
|
||||
'unicorn.h': 'Common',
|
||||
# prefixes for filenames of split_common values - case sensitive
|
||||
'ARCH': 'Arch',
|
||||
'MODE': 'Mode',
|
||||
'ERR': 'Error',
|
||||
'MEM': 'Memory',
|
||||
'TCG': 'TCG',
|
||||
'HOOK': 'Hook',
|
||||
'PROT': 'Permission',
|
||||
'comment_open': ' //',
|
||||
'comment_close': '',
|
||||
}
|
||||
}
|
||||
|
||||
# markup for comments to be added to autogen files
|
||||
MARKUP = '//>'
|
||||
|
||||
def gen(unicorn_repo_path):
|
||||
global include
|
||||
include_dir = os.path.join(unicorn_repo_path, 'include', 'unicorn')
|
||||
templ = template["dotnet"]
|
||||
for target in include:
|
||||
prefix = templ[target]
|
||||
outfile = open(templ['out_file'] %(prefix), 'wb') # open as binary prevents windows newlines
|
||||
outfile.write((templ['header'] % (prefix)).encode("utf-8"))
|
||||
if target == 'unicorn.h':
|
||||
prefix = ''
|
||||
for cat in split_common:
|
||||
with open(templ['out_file'] %(templ[cat]), 'wb') as file:
|
||||
file.write((templ['header'] %(templ[cat])).encode("utf-8"))
|
||||
with open(os.path.join(include_dir, target)) as f:
|
||||
lines = f.readlines()
|
||||
|
||||
previous = {}
|
||||
count = 0
|
||||
skip = 0
|
||||
in_comment = False
|
||||
|
||||
for lno, line in enumerate(lines):
|
||||
if "/*" in line:
|
||||
in_comment = True
|
||||
if "*/" in line:
|
||||
in_comment = False
|
||||
if in_comment:
|
||||
continue
|
||||
if skip > 0:
|
||||
# Due to clang-format, values may come up in the next line
|
||||
skip -= 1
|
||||
continue
|
||||
line = line.strip()
|
||||
|
||||
if line.startswith(MARKUP): # markup for comments
|
||||
outfile.write(("\n%s%s%s\n" %(templ['comment_open'], \
|
||||
line.replace(MARKUP, ''), templ['comment_close'])).encode("utf-8"))
|
||||
continue
|
||||
|
||||
if line == '' or line.startswith('//'):
|
||||
continue
|
||||
|
||||
tmp = line.strip().split(',')
|
||||
if len(tmp) >= 2 and tmp[0] != "#define" and not tmp[0].startswith("UC_"):
|
||||
continue
|
||||
for t in tmp:
|
||||
t = t.strip()
|
||||
if not t or t.startswith('//'): continue
|
||||
f = re.split('\s+', t)
|
||||
|
||||
# parse #define UC_TARGET (num)
|
||||
define = False
|
||||
if f[0] == '#define' and len(f) >= 3:
|
||||
define = True
|
||||
f.pop(0)
|
||||
f.insert(1, '=')
|
||||
if f[0].startswith("UC_" + prefix.upper()) or f[0].startswith("UC_CPU"):
|
||||
if len(f) > 1 and f[1] not in ('//', '='):
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
elif len(f) > 1 and f[1] == '=':
|
||||
# Like:
|
||||
# UC_A =
|
||||
# (1 << 2)
|
||||
# #define UC_B \
|
||||
# (UC_A | UC_C)
|
||||
# Let's search the next line
|
||||
if len(f) == 2:
|
||||
if lno == len(lines) - 1:
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
skip += 1
|
||||
next_line = lines[lno + 1]
|
||||
next_line_tmp = next_line.strip().split(",")
|
||||
rhs = next_line_tmp[0]
|
||||
elif f[-1] == "\\":
|
||||
idx = 0
|
||||
rhs = ""
|
||||
while True:
|
||||
idx += 1
|
||||
if lno + idx == len(lines):
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
skip += 1
|
||||
next_line = lines[lno + idx]
|
||||
next_line_f = re.split('\s+', next_line.strip())
|
||||
if next_line_f[-1] == "\\":
|
||||
rhs += "".join(next_line_f[:-1])
|
||||
else:
|
||||
rhs += next_line.strip()
|
||||
break
|
||||
else:
|
||||
rhs = ''.join(f[2:])
|
||||
else:
|
||||
rhs = str(count)
|
||||
|
||||
|
||||
lhs = f[0].strip()
|
||||
#print(f'lhs: {lhs} rhs: {rhs} f:{f}')
|
||||
# evaluate bitshifts in constants e.g. "UC_X86 = 1 << 1"
|
||||
match = re.match(r'(?P<rhs>\s*\d+\s*<<\s*\d+\s*)', rhs)
|
||||
if match:
|
||||
rhs = str(eval(match.group(1)))
|
||||
else:
|
||||
# evaluate references to other constants e.g. "UC_ARM_REG_X = UC_ARM_REG_SP"
|
||||
match = re.match(r'^([^\d]\w+)$', rhs)
|
||||
if match:
|
||||
rhs = previous[match.group(1)]
|
||||
|
||||
if not rhs.isdigit():
|
||||
for k, v in previous.items():
|
||||
rhs = re.sub(r'\b%s\b' % k, v, rhs)
|
||||
rhs = str(eval(rhs))
|
||||
|
||||
lhs_strip = re.sub(r'^UC_', '', lhs)
|
||||
count = int(rhs) + 1
|
||||
|
||||
if target == "unicorn.h":
|
||||
matched_cat = False
|
||||
for cat in split_common:
|
||||
if lhs_strip.startswith(f"{cat}_"):
|
||||
with open(templ['out_file'] %(templ[cat]), 'ab') as cat_file:
|
||||
cat_lhs_strip = lhs_strip
|
||||
if not lhs_strip.lstrip(f"{cat}_").isnumeric():
|
||||
cat_lhs_strip = lhs_strip.replace(f"{cat}_", "", 1)
|
||||
cat_file.write(
|
||||
(templ['line_format'] % (cat_lhs_strip, rhs)).encode("utf-8"))
|
||||
matched_cat = True
|
||||
break
|
||||
if matched_cat:
|
||||
previous[lhs] = str(rhs)
|
||||
continue
|
||||
|
||||
if (count == 1):
|
||||
outfile.write(("\n").encode("utf-8"))
|
||||
|
||||
if lhs_strip.startswith(f"{prefix.upper()}_") and not lhs_strip.replace(f"{prefix.upper()}_", "", 1).isnumeric():
|
||||
lhs_strip = lhs_strip.replace(f"{prefix.upper()}_", "", 1)
|
||||
|
||||
outfile.write((templ['line_format'] % (lhs_strip, rhs)).encode("utf-8"))
|
||||
previous[lhs] = str(rhs)
|
||||
|
||||
outfile.write((templ['footer']).encode("utf-8"))
|
||||
outfile.close()
|
||||
|
||||
if target == "unicorn.h":
|
||||
for cat in split_common:
|
||||
with open(templ['out_file'] %(templ[cat]), 'ab') as cat_file:
|
||||
cat_file.write(templ['footer'].encode('utf-8'))
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage:", sys.argv[0], " <path to unicorn repo>")
|
||||
sys.exit(1)
|
||||
unicorn_repo_path = sys.argv[1]
|
||||
if os.path.isdir(unicorn_repo_path):
|
||||
print("Generating constants for dotnet")
|
||||
gen(unicorn_repo_path)
|
||||
else:
|
||||
print("Couldn't find unicorn repo at:", unicorn_repo_path)
|
@@ -38,14 +38,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
static CpuTest()
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
_unicornAvailable = UnicornAArch64.IsAvailable();
|
||||
|
||||
if (!_unicornAvailable)
|
||||
{
|
||||
Console.WriteLine("WARNING: Could not find Unicorn.");
|
||||
}
|
||||
Assume.That(_unicornAvailable, "Unicorn is not available");
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
@@ -610,4 +607,4 @@ namespace Ryujinx.Tests.Cpu
|
||||
return rnd & 0x800FFFFFFFFFFFFFul;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -33,14 +33,11 @@ namespace Ryujinx.Tests.Cpu
|
||||
|
||||
private bool _usingMemory;
|
||||
|
||||
static CpuTest32()
|
||||
[OneTimeSetUp]
|
||||
public void OneTimeSetup()
|
||||
{
|
||||
_unicornAvailable = UnicornAArch32.IsAvailable();
|
||||
|
||||
if (!_unicornAvailable)
|
||||
{
|
||||
Console.WriteLine("WARNING: Could not find Unicorn.");
|
||||
}
|
||||
Assume.That(_unicornAvailable, "Unicorn is not available");
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
|
@@ -34,7 +34,17 @@
|
||||
</ItemGroup>
|
||||
|
||||
<Target Name="CopyUnicorn" AfterTargets="Build">
|
||||
<Copy SourceFiles="..\Ryujinx.Tests.Unicorn\libs\$(TargetOS)\unicorn.dll" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
|
||||
<ItemGroup>
|
||||
<UnicornLib Include="..\Ryujinx.Tests.Unicorn\libs\$(TargetOS)\*unicorn.*"/>
|
||||
</ItemGroup>
|
||||
<Copy SourceFiles="@(UnicornLib)" DestinationFolder="$(OutputPath)" ContinueOnError="true" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanUnicorn" BeforeTargets="Clean">
|
||||
<ItemGroup>
|
||||
<UnicornLib Include="$(OutputPath)/unicorn.*"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(UnicornLib)" />
|
||||
</Target>
|
||||
|
||||
</Project>
|
||||
|
@@ -26,7 +26,7 @@
|
||||
<PackageReference Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'osx-x64'" />
|
||||
<PackageReference Include="OpenTK.Graphics" Version="4.7.2" />
|
||||
<PackageReference Include="SPB" Version="0.0.4-build28" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.1" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@@ -735,7 +735,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -747,7 +746,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -770,7 +768,6 @@ namespace Ryujinx.Ui
|
||||
|
||||
_emulationContext.Dispose();
|
||||
SwitchToGameTable();
|
||||
RendererWidget.Dispose();
|
||||
|
||||
return;
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user