Merge branch 'master' into master

This commit is contained in:
Evan Husted 2025-02-25 20:39:31 -06:00 committed by GitHub
commit b784323007
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 127 additions and 52 deletions

View File

@ -24,7 +24,7 @@ namespace ARMeilleure.Translation.Cache
private static JitCacheInvalidation _jitCacheInvalidator; private static JitCacheInvalidation _jitCacheInvalidator;
private static CacheMemoryAllocator _cacheAllocator; private static List<CacheMemoryAllocator> _cacheAllocators = [];
private static readonly List<CacheEntry> _cacheEntries = []; private static readonly List<CacheEntry> _cacheEntries = [];
@ -40,37 +40,48 @@ namespace ARMeilleure.Translation.Cache
public static void Initialize(IJitMemoryAllocator allocator) public static void Initialize(IJitMemoryAllocator allocator)
{ {
if (_initialized)
{
return;
}
lock (_lock) lock (_lock)
{ {
if (_initialized) 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); ReservedRegion firstRegion = new(allocator, CacheSize);
_jitRegions.Add(firstRegion); _jitRegions.Add(firstRegion);
_activeRegionIndex = 0;
CacheMemoryAllocator firstCacheAllocator = new(CacheSize);
_cacheAllocators.Add(firstCacheAllocator);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS()) if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{ {
_jitCacheInvalidator = new JitCacheInvalidation(allocator); _jitCacheInvalidator = new JitCacheInvalidation(allocator);
} }
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())
{ {
JitUnwindWindows.InstallFunctionTableHandler( JitUnwindWindows.InstallFunctionTableHandler(
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize) 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) 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); _cacheEntries.RemoveAt(entryIndex);
} }
@ -167,30 +178,24 @@ namespace ARMeilleure.Translation.Cache
{ {
codeSize = AlignCodeSize(codeSize); codeSize = AlignCodeSize(codeSize);
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++) int allocOffset = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
{
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset >= 0) if (allocOffset >= 0)
{ {
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize); _jitRegions[_activeRegionIndex].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
_activeRegionIndex = i;
return allocOffset; return allocOffset;
} }
}
int exhaustedRegion = _activeRegionIndex; int exhaustedRegion = _activeRegionIndex;
ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize); ReservedRegion newRegion = new(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion); _jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1; _activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex; Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {_activeRegionIndex} ({((long)(_activeRegionIndex + 1) * CacheSize).Bytes()} Total Allocation).");
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((long)(newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation)."); _cacheAllocators.Add(new CacheMemoryAllocator(CacheSize));
_cacheAllocator = new CacheMemoryAllocator(CacheSize); int allocOffsetNew = _cacheAllocators[_activeRegionIndex].Allocate(codeSize);
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
if (allocOffsetNew < 0) if (allocOffsetNew < 0)
{ {
throw new OutOfMemoryException("Failed to allocate in new Cache Region!"); throw new OutOfMemoryException("Failed to allocate in new Cache Region!");

View File

@ -52,6 +52,11 @@ namespace ARMeilleure.Translation.Cache
nint context, nint context,
[MarshalAs(UnmanagedType.LPWStr)] string outOfProcessCallbackDll); [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 GetRuntimeFunctionCallback _getRuntimeFunctionCallback;
private static int _sizeOfRuntimeFunction; 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) private static unsafe RuntimeFunction* FunctionTableHandler(ulong controlPc, nint context)
{ {
int offset = (int)((long)controlPc - context.ToInt64()); int offset = (int)((long)controlPc - context.ToInt64());

View File

@ -5,15 +5,34 @@ using System.Runtime.InteropServices;
namespace Ryujinx.Common.Helper namespace Ryujinx.Common.Helper
{ {
public enum OperatingSystemType
{
MacOS,
Linux,
Windows
}
public static class RunningPlatform 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 IsMacOS => OperatingSystem.IsMacOS();
public static bool IsWindows => OperatingSystem.IsWindows(); public static bool IsWindows => OperatingSystem.IsWindows();
public static bool IsLinux => OperatingSystem.IsLinux(); 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 IsIntelMac => IsMacOS && IsX64;
public static bool IsArmMac => IsMacOS && IsArm; public static bool IsArmMac => IsMacOS && IsArm;

View File

@ -200,7 +200,7 @@ namespace Ryujinx.Ava.UI.Controls
if (backupDir.Exists) if (backupDir.Exists)
{ {
cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache")); cacheFiles.AddRange(backupDir.EnumerateFiles("*.cache"));
cacheFiles.AddRange(mainDir.EnumerateFiles("*.info")); cacheFiles.AddRange(backupDir.EnumerateFiles("*.info"));
} }
if (cacheFiles.Count > 0) if (cacheFiles.Count > 0)

View File

@ -44,16 +44,8 @@ namespace Ryujinx.Ava
private static string _buildVer; private static string _buildVer;
private static readonly string _platformExt =
RunningPlatform.IsMacOS private static readonly string _platformExt = BuildPlatformExtension();
? "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 string _buildUrl; private static string _buildUrl;
private static long _buildSize; private static long _buildSize;
@ -780,5 +772,34 @@ namespace Ryujinx.Ava
public static void CleanupUpdate() => public static void CleanupUpdate() =>
Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories) Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)
.ForEach(File.Delete); .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}";
}
} }
} }

View File

@ -60,11 +60,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport
_ => FormattedValue.ForceReset _ => FormattedValue.ForceReset
}; };
private static FormattedValue PokemonSVUnionCircle(SingleValue value) private static FormattedValue PokemonSV(MultiValue values)
=> value.Matched.BoxedValue is 0 ? "Playing Alone" : "Playing in a group"; {
private static FormattedValue PokemonSVArea(SingleValue value) string playStatus = values.Matched[0].BoxedValue is 0 ? "Playing Alone" : "Playing in a group";
=> value.Matched.StringValue switch
FormattedValue locations = values.Matched[1].ToString() switch
{ {
// Base Game Locations // Base Game Locations
"a_w01" => "South Area One", "a_w01" => "South Area One",
@ -92,11 +93,14 @@ namespace Ryujinx.Ava.Utilities.PlayReport
"a_w24" => "South Paldean Sea", "a_w24" => "South Paldean Sea",
"a_w25" => "West Paldean Sea", "a_w25" => "West Paldean Sea",
"a_w26" => "East Paldean Sea", "a_w26" => "East Paldean Sea",
"a_w27" => "Nouth Paldean Sea", "a_w27" => "North Paldean Sea",
//TODO DLC Locations //TODO DLC Locations
_ => FormattedValue.ForceReset _ => FormattedValue.ForceReset
}; };
return$"{playStatus} in {locations}";
}
private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values) private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values)
{ {
// Check if the PlayReport is for a challenger approach or an achievement. // Check if the PlayReport is for a challenger approach or an achievement.
@ -115,6 +119,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport
return $"Achievement Unlocked - ID: {anniversary}"; return $"Achievement Unlocked - ID: {anniversary}";
} }
if (values.Matched.ContainsKey("is_created"))
{
return "Edited a Custom Stage!";
}
if (values.Matched.ContainsKey("adv_slot")) if (values.Matched.ContainsKey("adv_slot"))
{ {
return return

View File

@ -59,9 +59,8 @@ namespace Ryujinx.Ava.Utilities.PlayReport
.AddSpec( .AddSpec(
["0100a3d008c5c000", "01008f6008c5e000"], ["0100a3d008c5c000", "01008f6008c5e000"],
spec => spec spec => spec
.WithDescription("based on what area of Paldea you're exploring.") .WithDescription("based on if you're playing alone or in a group and what area of Paldea you're exploring.")
.AddValueFormatter("area_no", PokemonSVArea) .AddMultiValueFormatter(["team_circle", "area_no"], PokemonSV)
.AddValueFormatter("team_circle", PokemonSVUnionCircle)
) )
.AddSpec( .AddSpec(
"01006a800016e000", "01006a800016e000",
@ -71,7 +70,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
[ [
// Metadata to figure out what PlayReport we have. // Metadata to figure out what PlayReport we have.
"match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count",
"adv_slot", "adv_slot", "is_created",
// List of Fighters // List of Fighters
"player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter",
"player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter", "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter",