diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index 7b5f2ca81..e480985b1 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache private static JitCacheInvalidation _jitCacheInvalidator; - private static CacheMemoryAllocator _cacheAllocator; + private static List _cacheAllocators = []; private static readonly List _cacheEntries = []; @@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache public static void Initialize(IJitMemoryAllocator allocator) { - if (_initialized) - { - return; - } - lock (_lock) { if (_initialized) { - return; + if (OperatingSystem.IsWindows()) + { + JitUnwindWindows.RemoveFunctionTableHandler( + _jitRegions[0].Pointer); + } + + for (int i = 0; i < _jitRegions.Count; i++) + { + _jitRegions[i].Dispose(); + } + + _jitRegions.Clear(); + _cacheAllocators.Clear(); } + else + { + _initialized = true; + } + + _activeRegionIndex = 0; ReservedRegion firstRegion = new(allocator, CacheSize); _jitRegions.Add(firstRegion); - _activeRegionIndex = 0; + + CacheMemoryAllocator firstCacheAllocator = new(CacheSize); + _cacheAllocators.Add(firstCacheAllocator); if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS()) { _jitCacheInvalidator = new JitCacheInvalidation(allocator); } - _cacheAllocator = new CacheMemoryAllocator(CacheSize); - if (OperatingSystem.IsWindows()) { JitUnwindWindows.InstallFunctionTableHandler( firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize) ); } - - _initialized = true; } } @@ -136,7 +147,7 @@ namespace ARMeilleure.Translation.Cache if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset) { - _cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size)); + _cacheAllocators[_activeRegionIndex].Free(funcOffset, AlignCodeSize(entry.Size)); _cacheEntries.RemoveAt(entryIndex); } @@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache { codeSize = AlignCodeSize(codeSize); - for (int i = _activeRegionIndex; i < _jitRegions.Count; i++) + int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize); + + if (allocOffset >= 0) { - int allocOffset = _cacheAllocator.Allocate(codeSize); - - if (allocOffset >= 0) - { - _jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); - _activeRegionIndex = i; - return allocOffset; - } + _jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); + return allocOffset; } int exhaustedRegion = _activeRegionIndex; ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize); _jitRegions.Add(newRegion); _activeRegionIndex = _jitRegions.Count - 1; - - int newRegionNumber = _activeRegionIndex; - Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation)."); - - _cacheAllocator = new CacheMemoryAllocator(CacheSize); + Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation)."); - int allocOffsetNew = _cacheAllocator.Allocate(codeSize); + _cacheAllocators.Add(new CacheMemoryAllocator(CacheSize)); + + int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize); if (allocOffsetNew < 0) { throw new OutOfMemoryException("Failed to allocate in new Cache Region!"); diff --git a/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs b/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs index 01b2aa8ed..15a1051fa 100644 --- a/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs +++ b/src/ARMeilleure/Translation/Cache/JitUnwindWindows.cs @@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache nint context, [MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll); + [LibraryImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static unsafe partial bool RtlDeleteFunctionTable( + ulong tableIdentifier); + private static GetRuntimeFunctionCallback _getRuntimeFunctionCallback; private static int _sizeOfRuntimeFunction; @@ -91,6 +96,23 @@ namespace ARMeilleure.Translation.Cache } } + public static void RemoveFunctionTableHandler(nint codeCachePointer) + { + ulong codeCachePtr = (ulong)codeCachePointer.ToInt64(); + + bool result; + + unsafe + { + result = RtlDeleteFunctionTable(codeCachePtr | 3); + } + + if (!result) + { + throw new InvalidOperationException("Failure removing function table callback."); + } + } + private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context) { int offset = (int)((long)controlPc - context.ToInt64()); diff --git a/src/Ryujinx.Common/Helpers/RunningPlatform.cs b/src/Ryujinx.Common/Helpers/RunningPlatform.cs index 8d85c4a3c..7ec2f18df 100644 --- a/src/Ryujinx.Common/Helpers/RunningPlatform.cs +++ b/src/Ryujinx.Common/Helpers/RunningPlatform.cs @@ -5,15 +5,34 @@ using System.Runtime.InteropServices; namespace Ryujinx.Common.Helper { + public enum OperatingSystemType + { + MacOS, + Linux, + Windows + } + public static class RunningPlatform { + public static readonly OperatingSystemType CurrentOS + = IsMacOS + ? OperatingSystemType.MacOS + : IsWindows + ? OperatingSystemType.Windows + : IsLinux + ? OperatingSystemType.Linux + : throw new PlatformNotSupportedException(); + + public static Architecture Architecture => RuntimeInformation.OSArchitecture; + public static Architecture CurrentProcessArchitecture => RuntimeInformation.ProcessArchitecture; + public static bool IsMacOS => OperatingSystem.IsMacOS(); public static bool IsWindows => OperatingSystem.IsWindows(); public static bool IsLinux => OperatingSystem.IsLinux(); - public static bool IsArm => RuntimeInformation.OSArchitecture is Architecture.Arm64; + public static bool IsArm => Architecture is Architecture.Arm64; - public static bool IsX64 => RuntimeInformation.OSArchitecture is Architecture.X64; + public static bool IsX64 => Architecture is Architecture.X64; public static bool IsIntelMac => IsMacOS && IsX64; public static bool IsArmMac => IsMacOS && IsArm; diff --git a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs index 9f270420e..4929e1a19 100644 --- a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs @@ -200,7 +200,7 @@ namespace Ryujinx.Ava.UI.Controls if (backupDir.Exists) { cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache")); - cacheFiles.AddRange(mainDir.EnumerateFiles("*.info")); + cacheFiles.AddRange(backupDir.EnumerateFiles("*.info")); } if (cacheFiles.Count > 0) diff --git a/src/Ryujinx/Updater.cs b/src/Ryujinx/Updater.cs index 338e9de43..7ca5e885a 100644 --- a/src/Ryujinx/Updater.cs +++ b/src/Ryujinx/Updater.cs @@ -43,17 +43,9 @@ namespace Ryujinx.Ava private const int ConnectionCount = 4; private static string _buildVer; + - private static readonly string _platformExt = - RunningPlatform.IsMacOS - ? "macos_universal.app.tar.gz" - : RunningPlatform.IsWindows - ? "win_x64.zip" - : RunningPlatform.IsX64Linux - ? "linux_x64.tar.gz" - : RunningPlatform.IsArmLinux - ? "linux_arm64.tar.gz" - : throw new PlatformNotSupportedException(); + private static readonly string _platformExt = BuildPlatformExtension(); private static string _buildUrl; private static long _buildSize; @@ -780,5 +772,34 @@ namespace Ryujinx.Ava public static void CleanupUpdate() => Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories) .ForEach(File.Delete); + + private static string BuildPlatformExtension() + { + if (RunningPlatform.IsMacOS) + return "macos_universal.app.tar.gz"; + +#pragma warning disable CS8509 // It is exhaustive for any values this can contain. + string osPrefix = RunningPlatform.CurrentOS switch + { + OperatingSystemType.Linux => "linux", + OperatingSystemType.Windows => "win" + }; + + string archSuffix = RunningPlatform.Architecture switch + { + Architecture.Arm64 => "arm64", + Architecture.X64 => "x64", + _ => throw new PlatformNotSupportedException($"Unknown architecture {Enum.GetName(RunningPlatform.Architecture)}."), + }; + + string fileExtension = RunningPlatform.CurrentOS switch +#pragma warning restore CS8509 + { + OperatingSystemType.Linux => "tar.gz", + OperatingSystemType.Windows => "zip" + }; + + return $"{osPrefix}_{archSuffix}.{fileExtension}"; + } } } diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs index 43e830819..b5215c693 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs @@ -59,12 +59,13 @@ namespace Ryujinx.Ava.Utilities.PlayReport "Race" => "Racing", _ => FormattedValue.ForceReset }; - - private static FormattedValue PokemonSVUnionCircle(SingleValue value) - => value.Matched.BoxedValue is 0 ? "Playing Alone" : "Playing in a group"; - - private static FormattedValue PokemonSVArea(SingleValue value) - => value.Matched.StringValue switch + + private static FormattedValue PokemonSV(MultiValue values) + { + + string playStatus = values.Matched[0].BoxedValue is 0 ? "Playing Alone" : "Playing in a group"; + + FormattedValue locations = values.Matched[1].ToString() switch { // Base Game Locations "a_w01" => "South Area One", @@ -92,10 +93,13 @@ namespace Ryujinx.Ava.Utilities.PlayReport "a_w24" => "South Paldean Sea", "a_w25" => "West Paldean Sea", "a_w26" => "East Paldean Sea", - "a_w27" => "Nouth Paldean Sea", + "a_w27" => "North Paldean Sea", //TODO DLC Locations _ => FormattedValue.ForceReset }; + + return$"{playStatus} in {locations}"; + } private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values) { @@ -115,6 +119,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport return $"Achievement Unlocked - ID: {anniversary}"; } + if (values.Matched.ContainsKey("is_created")) + { + return "Edited a Custom Stage!"; + } + if (values.Matched.ContainsKey("adv_slot")) { return diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index 9feb888b3..c46ae2be5 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -59,9 +59,8 @@ namespace Ryujinx.Ava.Utilities.PlayReport .AddSpec( ["0100a3d008c5c000", "01008f6008c5e000"], spec => spec - .WithDescription("based on what area of Paldea you're exploring.") - .AddValueFormatter("area_no", PokemonSVArea) - .AddValueFormatter("team_circle", PokemonSVUnionCircle) + .WithDescription("based on if you're playing alone or in a group and what area of Paldea you're exploring.") + .AddMultiValueFormatter(["team_circle", "area_no"], PokemonSV) ) .AddSpec( "01006a800016e000", @@ -71,7 +70,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport [ // Metadata to figure out what PlayReport we have. "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", - "adv_slot", + "adv_slot", "is_created", // List of Fighters "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter",