Compare commits

..

1 Commits

Author SHA1 Message Date
shinyoyo
2cd876b1cb Update Zh-CN Simplified Chinese (#642) 2025-02-08 21:33:20 -06:00
6 changed files with 92 additions and 165 deletions

View File

@@ -7,7 +7,6 @@ namespace ARMeilleure.Memory
public const int DefaultGranularity = 65536; // Mapping granularity in Windows.
public IJitMemoryBlock Block { get; }
public IJitMemoryAllocator Allocator { get; }
public nint Pointer => Block.Pointer;
@@ -22,7 +21,6 @@ namespace ARMeilleure.Memory
granularity = DefaultGranularity;
}
Allocator = allocator;
Block = allocator.Reserve(maxSize);
_maxSize = maxSize;
_sizeGranularity = granularity;

View File

@@ -2,8 +2,6 @@ using ARMeilleure.CodeGen;
using ARMeilleure.CodeGen.Unwinding;
using ARMeilleure.Memory;
using ARMeilleure.Native;
using Humanizer;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
@@ -20,8 +18,9 @@ namespace ARMeilleure.Translation.Cache
private static readonly int _pageMask = _pageSize - 1;
private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 256 * 1024 * 1024;
private const int CacheSize = 2047 * 1024 * 1024;
private static ReservedRegion _jitRegion;
private static JitCacheInvalidation _jitCacheInvalidator;
private static CacheMemoryAllocator _cacheAllocator;
@@ -31,9 +30,6 @@ namespace ARMeilleure.Translation.Cache
private static readonly Lock _lock = new();
private static bool _initialized;
private static readonly List<ReservedRegion> _jitRegions = new();
private static int _activeRegionIndex = 0;
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32.dll", SetLastError = true)]
public static partial nint FlushInstructionCache(nint hProcess, nint lpAddress, nuint dwSize);
@@ -52,9 +48,7 @@ namespace ARMeilleure.Translation.Cache
return;
}
var firstRegion = new ReservedRegion(allocator, CacheSize);
_jitRegions.Add(firstRegion);
_activeRegionIndex = 0;
_jitRegion = new ReservedRegion(allocator, CacheSize);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{
@@ -65,9 +59,7 @@ namespace ARMeilleure.Translation.Cache
if (OperatingSystem.IsWindows())
{
JitUnwindWindows.InstallFunctionTableHandler(
firstRegion.Pointer, CacheSize, firstRegion.Pointer + Allocate(_pageSize)
);
JitUnwindWindows.InstallFunctionTableHandler(_jitRegion.Pointer, CacheSize, _jitRegion.Pointer + Allocate(_pageSize));
}
_initialized = true;
@@ -83,8 +75,8 @@ namespace ARMeilleure.Translation.Cache
Debug.Assert(_initialized);
int funcOffset = Allocate(code.Length);
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
nint funcPtr = targetRegion.Pointer + funcOffset;
nint funcPtr = _jitRegion.Pointer + funcOffset;
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
@@ -98,9 +90,9 @@ namespace ARMeilleure.Translation.Cache
}
else
{
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
ReprotectAsWritable(funcOffset, code.Length);
Marshal.Copy(code, 0, funcPtr, code.Length);
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
ReprotectAsExecutable(funcOffset, code.Length);
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
@@ -124,83 +116,52 @@ namespace ARMeilleure.Translation.Cache
{
Debug.Assert(_initialized);
foreach (var region in _jitRegions)
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
if (pointer.ToInt64() < region.Pointer.ToInt64() ||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
{
continue;
}
int funcOffset = (int)(pointer.ToInt64() - region.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
return;
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
}
}
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
private static void ReprotectAsWritable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
private static void ReprotectAsExecutable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static int Allocate(int codeSize)
{
codeSize = AlignCodeSize(codeSize);
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset < 0)
{
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset >= 0)
{
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
_activeRegionIndex = i;
return allocOffset;
}
throw new OutOfMemoryException("JIT Cache exhausted.");
}
int exhaustedRegion = _activeRegionIndex;
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex;
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation).");
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
if (allocOffsetNew < 0)
{
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
}
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
return allocOffsetNew;
return allocOffset;
}
private static int AlignCodeSize(int codeSize)
{
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
@@ -224,21 +185,18 @@ namespace ARMeilleure.Translation.Cache
{
lock (_lock)
{
foreach (var region in _jitRegions)
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
if (index < 0)
{
int index = _cacheEntries.BinarySearch(new CacheEntry(offset, 0, default));
index = ~index - 1;
}
if (index < 0)
{
index = ~index - 1;
}
if (index >= 0)
{
entry = _cacheEntries[index];
entryIndex = index;
return true;
}
if (index >= 0)
{
entry = _cacheEntries[index];
entryIndex = index;
return true;
}
}

View File

@@ -1,6 +1,4 @@
using ARMeilleure.Memory;
using Humanizer;
using Ryujinx.Common.Logging;
using Ryujinx.Memory;
using System;
using System.Collections.Generic;
@@ -17,8 +15,9 @@ namespace Ryujinx.Cpu.LightningJit.Cache
private static readonly int _pageMask = _pageSize - 1;
private const int CodeAlignment = 4; // Bytes.
private const int CacheSize = 256 * 1024 * 1024;
private const int CacheSize = 2047 * 1024 * 1024;
private static ReservedRegion _jitRegion;
private static JitCacheInvalidation _jitCacheInvalidator;
private static CacheMemoryAllocator _cacheAllocator;
@@ -27,8 +26,6 @@ namespace Ryujinx.Cpu.LightningJit.Cache
private static readonly Lock _lock = new();
private static bool _initialized;
private static readonly List<ReservedRegion> _jitRegions = new();
private static int _activeRegionIndex = 0;
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32.dll", SetLastError = true)]
@@ -48,9 +45,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
return;
}
var firstRegion = new ReservedRegion(allocator, CacheSize);
_jitRegions.Add(firstRegion);
_activeRegionIndex = 0;
_jitRegion = new ReservedRegion(allocator, CacheSize);
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
{
@@ -70,8 +65,8 @@ namespace Ryujinx.Cpu.LightningJit.Cache
Debug.Assert(_initialized);
int funcOffset = Allocate(code.Length);
ReservedRegion targetRegion = _jitRegions[_activeRegionIndex];
nint funcPtr = targetRegion.Pointer + funcOffset;
nint funcPtr = _jitRegion.Pointer + funcOffset;
if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
@@ -85,11 +80,18 @@ namespace Ryujinx.Cpu.LightningJit.Cache
}
else
{
ReprotectAsWritable(targetRegion, funcOffset, code.Length);
Marshal.Copy(code.ToArray(), 0, funcPtr, code.Length);
ReprotectAsExecutable(targetRegion, funcOffset, code.Length);
ReprotectAsWritable(funcOffset, code.Length);
code.CopyTo(new Span<byte>((void*)funcPtr, code.Length));
ReprotectAsExecutable(funcOffset, code.Length);
_jitCacheInvalidator?.Invalidate(funcPtr, (ulong)code.Length);
if (OperatingSystem.IsWindows() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64)
{
FlushInstructionCache(Process.GetCurrentProcess().Handle, funcPtr, (nuint)code.Length);
}
else
{
_jitCacheInvalidator?.Invalidate(funcPtr, (ulong)code.Length);
}
}
Add(funcOffset, code.Length);
@@ -104,80 +106,50 @@ namespace Ryujinx.Cpu.LightningJit.Cache
{
Debug.Assert(_initialized);
foreach (var region in _jitRegions)
int funcOffset = (int)(pointer.ToInt64() - _jitRegion.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
if (pointer.ToInt64() < region.Pointer.ToInt64() ||
pointer.ToInt64() >= (region.Pointer + CacheSize).ToInt64())
{
continue;
}
int funcOffset = (int)(pointer.ToInt64() - region.Pointer.ToInt64());
if (TryFind(funcOffset, out CacheEntry entry, out int entryIndex) && entry.Offset == funcOffset)
{
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
return;
_cacheAllocator.Free(funcOffset, AlignCodeSize(entry.Size));
_cacheEntries.RemoveAt(entryIndex);
}
}
}
private static void ReprotectAsWritable(ReservedRegion region, int offset, int size)
private static void ReprotectAsWritable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRwx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static void ReprotectAsExecutable(ReservedRegion region, int offset, int size)
private static void ReprotectAsExecutable(int offset, int size)
{
int endOffs = offset + size;
int regionStart = offset & ~_pageMask;
int regionEnd = (endOffs + _pageMask) & ~_pageMask;
region.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
_jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart));
}
private static int Allocate(int codeSize)
{
codeSize = AlignCodeSize(codeSize);
for (int i = _activeRegionIndex; i < _jitRegions.Count; i++)
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset < 0)
{
int allocOffset = _cacheAllocator.Allocate(codeSize);
if (allocOffset >= 0)
{
_jitRegions[i].ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
_activeRegionIndex = i;
return allocOffset;
}
throw new OutOfMemoryException("JIT Cache exhausted.");
}
int exhaustedRegion = _activeRegionIndex;
var newRegion = new ReservedRegion(_jitRegions[0].Allocator, CacheSize);
_jitRegions.Add(newRegion);
_activeRegionIndex = _jitRegions.Count - 1;
int newRegionNumber = _activeRegionIndex;
_jitRegion.ExpandIfNeeded((ulong)allocOffset + (ulong)codeSize);
Logger.Warning?.Print(LogClass.Cpu, $"JIT Cache Region {exhaustedRegion} exhausted, creating new Cache Region {newRegionNumber} ({((newRegionNumber + 1) * CacheSize).Bytes()} Total Allocation).");
_cacheAllocator = new CacheMemoryAllocator(CacheSize);
int allocOffsetNew = _cacheAllocator.Allocate(codeSize);
if (allocOffsetNew < 0)
{
throw new OutOfMemoryException("Failed to allocate in new Cache Region!");
}
newRegion.ExpandIfNeeded((ulong)allocOffsetNew + (ulong)codeSize);
return allocOffsetNew;
return allocOffset;
}
private static int AlignCodeSize(int codeSize)

View File

@@ -12,7 +12,7 @@ namespace Ryujinx.Cpu.LightningJit.Cache
{
private const int CodeAlignment = 4; // Bytes.
private const int SharedCacheSize = 2047 * 1024 * 1024;
private const int LocalCacheSize = 256 * 1024 * 1024;
private const int LocalCacheSize = 128 * 1024 * 1024;
// How many calls to the same function we allow until we pad the shared cache to force the function to become available there
// and allow the guest to take the fast path.

View File

@@ -150,7 +150,6 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl
{ BsdSocketOption.SoLinger, SocketOptionName.Linger },
{ BsdSocketOption.SoOobInline, SocketOptionName.OutOfBandInline },
{ BsdSocketOption.SoReusePort, SocketOptionName.ReuseAddress },
{ BsdSocketOption.SoNoSigpipe, SocketOptionName.DontLinger },
{ BsdSocketOption.SoSndBuf, SocketOptionName.SendBuffer },
{ BsdSocketOption.SoRcvBuf, SocketOptionName.ReceiveBuffer },
{ BsdSocketOption.SoSndLoWat, SocketOptionName.SendLowWater },

View File

@@ -1543,7 +1543,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "由 {0} 开发",
"zh_TW": ""
}
},
@@ -1843,7 +1843,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "兼容性:",
"zh_TW": ""
}
},
@@ -1868,7 +1868,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "标题 ID:",
"zh_TW": ""
}
},
@@ -1893,7 +1893,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "服务的游戏: {0}",
"zh_TW": ""
}
},
@@ -1918,7 +1918,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "在线玩家: {0}",
"zh_TW": ""
}
},
@@ -2268,7 +2268,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "清理 PPTC 缓存",
"zh_TW": ""
}
},
@@ -2293,7 +2293,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "删除应用程序的所有 PPTC 缓存",
"zh_TW": ""
}
},
@@ -2768,7 +2768,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "显示兼容性项目",
"zh_TW": ""
}
},
@@ -2793,7 +2793,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "在兼容性列表中显示选定的游戏,您通常可以通过帮助菜单访问。",
"zh_TW": ""
}
},
@@ -2818,7 +2818,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "显示游戏信息",
"zh_TW": ""
}
},
@@ -2843,7 +2843,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "显示当前选定游戏的状态与详细信息。",
"zh_TW": ""
}
},
@@ -4493,7 +4493,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "与系统时间同步",
"zh_TW": ""
}
},
@@ -6143,7 +6143,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "重置设置",
"zh_TW": ""
}
},
@@ -6168,7 +6168,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "我要重置我的设置。",
"zh_TW": ""
}
},
@@ -8143,7 +8143,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "彩虹滚动速度",
"zh_TW": ""
}
},
@@ -13418,7 +13418,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "您正要清理 PPTC 数据:\n\n{0}\n\n您确实要继续吗?",
"zh_TW": ""
}
},
@@ -23568,7 +23568,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "启动和游戏时不会出现任何崩溃或任何类型的 GPU bug 且速度足够快可以在一般 PC 上尽情游玩。",
"zh_TW": ""
}
},
@@ -23593,7 +23593,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "可以成功启动并进入游戏但可能会遇到以下一种或多种问题: 崩溃、卡死、GPU bug、令人无法接受的音频,或者只是太慢。仍然可以继续进行游戏,但是可能无法达到预期。",
"zh_TW": ""
}
},
@@ -23618,7 +23618,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "可以启动并通过标题画面但是无法进入到主要的游戏流程。",
"zh_TW": ""
}
},
@@ -23643,7 +23643,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "可以启动但是无法通过标题画面。",
"zh_TW": ""
}
},
@@ -23668,7 +23668,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "无法启动或显示无任何动静。",
"zh_TW": ""
}
},
@@ -23718,7 +23718,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "Rich Presence 图像",
"zh_TW": ""
}
},
@@ -23743,7 +23743,7 @@
"th_TH": "",
"tr_TR": "",
"uk_UA": "",
"zh_CN": "",
"zh_CN": "动态 Rich Presence",
"zh_TW": ""
}
}