diff --git a/src/ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs b/src/ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs index 86afc2b4d..374f4746b 100644 --- a/src/ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs +++ b/src/ARMeilleure/CodeGen/Arm64/HardwareCapabilities.cs @@ -20,7 +20,7 @@ namespace ARMeilleure.CodeGen.Arm64 LinuxFeatureInfoHwCap2 = (LinuxFeatureFlagsHwCap2)getauxval(AT_HWCAP2); } - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { for (int i = 0; i < _sysctlNames.Length; i++) { @@ -130,6 +130,7 @@ namespace ARMeilleure.CodeGen.Arm64 private static unsafe partial int sysctlbyname([MarshalAs(UnmanagedType.LPStr)] string name, out int oldValue, ref ulong oldSize, IntPtr newValue, ulong newValueSize); [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] private static bool CheckSysctlName(string name) { ulong size = sizeof(int); diff --git a/src/ARMeilleure/CodeGen/CompiledFunction.cs b/src/ARMeilleure/CodeGen/CompiledFunction.cs index 3844cbfc9..485c85d16 100644 --- a/src/ARMeilleure/CodeGen/CompiledFunction.cs +++ b/src/ARMeilleure/CodeGen/CompiledFunction.cs @@ -58,9 +58,9 @@ namespace ARMeilleure.CodeGen /// Type of delegate /// Pointer to the function code in memory /// A delegate of type pointing to the mapped function - public T MapWithPointer(out IntPtr codePointer) + public T MapWithPointer(out IntPtr codePointer, bool deferProtect = false) { - codePointer = JitCache.Map(this); + codePointer = JitCache.Map(this, deferProtect); return Marshal.GetDelegateForFunctionPointer(codePointer); } diff --git a/src/ARMeilleure/Native/JitSupportDarwin.cs b/src/ARMeilleure/Native/JitSupportDarwin.cs index ed347b9cf..bf94514ed 100644 --- a/src/ARMeilleure/Native/JitSupportDarwin.cs +++ b/src/ARMeilleure/Native/JitSupportDarwin.cs @@ -5,9 +5,41 @@ using System.Runtime.Versioning; namespace ARMeilleure.Native { [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] internal static partial class JitSupportDarwin { [LibraryImport("libarmeilleure-jitsupport", EntryPoint = "armeilleure_jit_memcpy")] public static partial void Copy(IntPtr dst, IntPtr src, ulong n); } + + [SupportedOSPlatform("ios")] + internal static partial class JitSupportDarwinAot + { + [LibraryImport("pthread", EntryPoint = "pthread_jit_write_protect_np")] + private static partial void pthread_jit_write_protect_np(int enabled); + + [LibraryImport("libc", EntryPoint = "sys_icache_invalidate")] + private static partial void sys_icache_invalidate(IntPtr start, IntPtr length); + + public static unsafe void Copy(IntPtr dst, IntPtr src, ulong n) { + // When NativeAOT is in use, we can toggle per-thread write protection without worrying about breaking .NET code. + + //pthread_jit_write_protect_np(0); + + var srcSpan = new Span(src.ToPointer(), (int)n); + var dstSpan = new Span(dst.ToPointer(), (int)n); + srcSpan.CopyTo(dstSpan); + + //pthread_jit_write_protect_np(1); + + // Ensure that the instruction cache for this range is invalidated. + sys_icache_invalidate(dst, (IntPtr)n); + } + + public static unsafe void Invalidate(IntPtr dst, ulong n) + { + // Ensure that the instruction cache for this range is invalidated. + sys_icache_invalidate(dst, (IntPtr)n); + } + } } diff --git a/src/ARMeilleure/Signal/NativeSignalHandler.cs b/src/ARMeilleure/Signal/NativeSignalHandler.cs index 31ec16cb1..d0d1aab7c 100644 --- a/src/ARMeilleure/Signal/NativeSignalHandler.cs +++ b/src/ARMeilleure/Signal/NativeSignalHandler.cs @@ -112,7 +112,7 @@ namespace ARMeilleure.Signal ref SignalHandlerConfig config = ref GetConfigRef(); - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { _signalHandlerPtr = Marshal.GetFunctionPointerForDelegate(GenerateUnixSignalHandler(_handlerConfig)); @@ -252,13 +252,13 @@ namespace ARMeilleure.Signal private static Operand GenerateUnixFaultAddress(EmitterContext context, Operand sigInfoPtr) { - ulong structAddressOffset = OperatingSystem.IsMacOS() ? 24ul : 16ul; // si_addr + ulong structAddressOffset = (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) ? 24ul : 16ul; // si_addr return context.Load(OperandType.I64, context.Add(sigInfoPtr, Const(structAddressOffset))); } private static Operand GenerateUnixWriteFlag(EmitterContext context, Operand ucontextPtr) { - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { const ulong McontextOffset = 48; // uc_mcontext Operand ctxPtr = context.Load(OperandType.I64, context.Add(ucontextPtr, Const(McontextOffset))); diff --git a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs b/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs index 70e9f2204..433aab636 100644 --- a/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs +++ b/src/ARMeilleure/Signal/UnixSignalHandlerRegistration.cs @@ -62,7 +62,7 @@ namespace ARMeilleure.Signal throw new InvalidOperationException($"Could not register SIGSEGV sigaction. Error: {result}"); } - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { result = sigaction(SIGBUS, ref sig, out _); @@ -77,7 +77,7 @@ namespace ARMeilleure.Signal public static bool RestoreExceptionHandler(SigAction oldAction) { - return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); + return sigaction(SIGSEGV, ref oldAction, out SigAction _) == 0 && (!OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || sigaction(SIGBUS, ref oldAction, out SigAction _) == 0); } } } diff --git a/src/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs b/src/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs index f36bf7a3d..a1bd3933a 100644 --- a/src/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs +++ b/src/ARMeilleure/Translation/Cache/CacheMemoryAllocator.cs @@ -30,21 +30,26 @@ namespace ARMeilleure.Translation.Cache _blocks.Add(new MemoryBlock(0, capacity)); } - public int Allocate(int size) + public int Allocate(ref int size, int alignment) { + int alignM1 = alignment - 1; for (int i = 0; i < _blocks.Count; i++) { MemoryBlock block = _blocks[i]; + int misAlignment = ((block.Offset + alignM1) & (~alignM1)) - block.Offset; + int alignedSize = size + misAlignment; - if (block.Size > size) + if (block.Size > alignedSize) { - _blocks[i] = new MemoryBlock(block.Offset + size, block.Size - size); - return block.Offset; + size = alignedSize; + _blocks[i] = new MemoryBlock(block.Offset + alignedSize, block.Size - alignedSize); + return block.Offset + misAlignment; } - else if (block.Size == size) + else if (block.Size == alignedSize) { + size = alignedSize; _blocks.RemoveAt(i); - return block.Offset; + return block.Offset + misAlignment; } } diff --git a/src/ARMeilleure/Translation/Cache/JitCache.cs b/src/ARMeilleure/Translation/Cache/JitCache.cs index e2b5e2d10..db4be66e5 100644 --- a/src/ARMeilleure/Translation/Cache/JitCache.cs +++ b/src/ARMeilleure/Translation/Cache/JitCache.cs @@ -4,6 +4,7 @@ using ARMeilleure.Memory; using ARMeilleure.Native; using Ryujinx.Memory; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; @@ -18,6 +19,7 @@ namespace ARMeilleure.Translation.Cache private const int CodeAlignment = 4; // Bytes. private const int CacheSize = 2047 * 1024 * 1024; + private const int CacheSizeIOS = 512 * 1024 * 1024; private static ReservedRegion _jitRegion; private static JitCacheInvalidation _jitCacheInvalidator; @@ -47,9 +49,9 @@ namespace ARMeilleure.Translation.Cache return; } - _jitRegion = new ReservedRegion(allocator, CacheSize); + _jitRegion = new ReservedRegion(allocator, (ulong)(OperatingSystem.IsIOS() ? CacheSizeIOS : CacheSize)); - if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS()) + if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS() && !OperatingSystem.IsIOS()) { _jitCacheInvalidator = new JitCacheInvalidation(allocator); } @@ -65,7 +67,17 @@ namespace ARMeilleure.Translation.Cache } } - public static IntPtr Map(CompiledFunction func) + static ConcurrentQueue<(int funcOffset, int length)> _deferredRxProtect = new(); + + public static void RunDeferredRxProtects() + { + while (_deferredRxProtect.TryDequeue(out var result)) + { + ReprotectAsExecutable(result.funcOffset, result.length); + } + } + + public static IntPtr Map(CompiledFunction func, bool deferProtect) { byte[] code = func.Code; @@ -73,11 +85,25 @@ namespace ARMeilleure.Translation.Cache { Debug.Assert(_initialized); - int funcOffset = Allocate(code.Length); + int funcOffset = Allocate(code.Length, deferProtect); IntPtr funcPtr = _jitRegion.Pointer + funcOffset; - if (OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64) + if (OperatingSystem.IsIOS()) + { + Marshal.Copy(code, 0, funcPtr, code.Length); + if (deferProtect) + { + _deferredRxProtect.Enqueue((funcOffset, code.Length)); + } + else + { + ReprotectAsExecutable(funcOffset, code.Length); + + JitSupportDarwinAot.Invalidate(funcPtr, (ulong)code.Length); + } + } + else if (OperatingSystem.IsMacOS()&& RuntimeInformation.ProcessArchitecture == Architecture.Arm64) { unsafe { @@ -111,6 +137,11 @@ namespace ARMeilleure.Translation.Cache public static void Unmap(IntPtr pointer) { + if (OperatingSystem.IsIOS()) + { + return; + } + lock (_lock) { Debug.Assert(_initialized); @@ -145,11 +176,20 @@ namespace ARMeilleure.Translation.Cache _jitRegion.Block.MapAsRx((ulong)regionStart, (ulong)(regionEnd - regionStart)); } - private static int Allocate(int codeSize) + private static int Allocate(int codeSize, bool deferProtect = false) { - codeSize = AlignCodeSize(codeSize); + codeSize = AlignCodeSize(codeSize, deferProtect); - int allocOffset = _cacheAllocator.Allocate(codeSize); + int alignment = CodeAlignment; + + if (OperatingSystem.IsIOS() && !deferProtect) + { + alignment = 0x4000; + } + + int allocOffset = _cacheAllocator.Allocate(ref codeSize, alignment); + + Console.WriteLine($"{allocOffset:x8}: {codeSize:x8} {alignment:x8}"); if (allocOffset < 0) { @@ -161,9 +201,16 @@ namespace ARMeilleure.Translation.Cache return allocOffset; } - private static int AlignCodeSize(int codeSize) + private static int AlignCodeSize(int codeSize, bool deferProtect = false) { - return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1); + int alignment = CodeAlignment; + + if (OperatingSystem.IsIOS() && !deferProtect) + { + alignment = 0x4000; + } + + return checked(codeSize + (alignment - 1)) & ~(alignment - 1); } private static void Add(int offset, int size, UnwindInfo unwindInfo) diff --git a/src/ARMeilleure/Translation/PTC/Ptc.cs b/src/ARMeilleure/Translation/PTC/Ptc.cs index 6f6dfcadf..5ed27927a 100644 --- a/src/ARMeilleure/Translation/PTC/Ptc.cs +++ b/src/ARMeilleure/Translation/PTC/Ptc.cs @@ -3,6 +3,7 @@ using ARMeilleure.CodeGen.Linking; using ARMeilleure.CodeGen.Unwinding; using ARMeilleure.Common; using ARMeilleure.Memory; +using ARMeilleure.Translation.Cache; using Ryujinx.Common; using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; @@ -744,7 +745,7 @@ namespace ARMeilleure.Translation.PTC bool highCq) { var cFunc = new CompiledFunction(code, unwindInfo, RelocInfo.Empty); - var gFunc = cFunc.MapWithPointer(out IntPtr gFuncPointer); + var gFunc = cFunc.MapWithPointer(out IntPtr gFuncPointer, true); return new TranslatedFunction(gFunc, gFuncPointer, callCounter, guestSize, highCq); } @@ -826,7 +827,7 @@ namespace ARMeilleure.Translation.PTC Debug.Assert(Profiler.IsAddressInStaticCodeRange(address)); - TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq); + TranslatedFunction func = translator.Translate(address, item.funcProfile.Mode, item.funcProfile.HighCq, deferProtect: true); bool isAddressUnique = translator.Functions.TryAdd(address, func.GuestSize, func); @@ -1004,6 +1005,7 @@ namespace ARMeilleure.Translation.PTC osPlatform |= (OperatingSystem.IsLinux() ? 1u : 0u) << 1; osPlatform |= (OperatingSystem.IsMacOS() ? 1u : 0u) << 2; osPlatform |= (OperatingSystem.IsWindows() ? 1u : 0u) << 3; + osPlatform |= (OperatingSystem.IsIOS() ? 1u : 0u) << 4; #pragma warning restore IDE0055 return osPlatform; diff --git a/src/ARMeilleure/Translation/Translator.cs b/src/ARMeilleure/Translation/Translator.cs index dc18038ba..88656b68f 100644 --- a/src/ARMeilleure/Translation/Translator.cs +++ b/src/ARMeilleure/Translation/Translator.cs @@ -112,6 +112,8 @@ namespace ARMeilleure.Translation Debug.Assert(Functions.Count == 0); _ptc.LoadTranslations(this); _ptc.MakeAndSaveTranslations(this); + + JitCache.RunDeferredRxProtects(); } _ptc.Profiler.Start(); @@ -250,7 +252,7 @@ namespace ARMeilleure.Translation } } - internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false) + internal TranslatedFunction Translate(ulong address, ExecutionMode mode, bool highCq, bool singleStep = false, bool deferProtect = false) { var context = new ArmEmitterContext( Memory, @@ -308,7 +310,7 @@ namespace ARMeilleure.Translation _ptc.WriteCompiledFunction(address, funcSize, hash, highCq, compiledFunc); } - GuestFunction func = compiledFunc.MapWithPointer(out IntPtr funcPointer); + GuestFunction func = compiledFunc.MapWithPointer(out IntPtr funcPointer, deferProtect); Allocators.ResetAll(); diff --git a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs index b83e63dbc..58137bb38 100644 --- a/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs +++ b/src/Ryujinx.Audio.Backends.SDL2/SDL2HardwareDeviceDriver.cs @@ -23,7 +23,7 @@ namespace Ryujinx.Audio.Backends.SDL2 // TODO: Add this to SDL2-CS // NOTE: We use a DllImport here because of marshaling issue for spec. #pragma warning disable SYSLIB1054 - [DllImport("SDL2")] + [DllImport("SDL2.framework/SDL2")] private static extern int SDL_GetDefaultAudioInfo(IntPtr name, out SDL_AudioSpec spec, int isCapture); #pragma warning restore SYSLIB1054 diff --git a/src/Ryujinx.Common/Configuration/AppDataManager.cs b/src/Ryujinx.Common/Configuration/AppDataManager.cs index 2b4a594d3..010b39dbf 100644 --- a/src/Ryujinx.Common/Configuration/AppDataManager.cs +++ b/src/Ryujinx.Common/Configuration/AppDataManager.cs @@ -50,6 +50,10 @@ namespace Ryujinx.Common.Configuration { appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Library", "Application Support"); } + else if (OperatingSystem.IsIOS()) + { + appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments); + } else { appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); diff --git a/src/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs b/src/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs index 42ba00cd5..effc8f507 100644 --- a/src/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs +++ b/src/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs @@ -30,15 +30,26 @@ namespace Ryujinx.Common.Logging.Targets public void Log(object sender, LogEventArgs args) { - Console.ForegroundColor = GetLogColor(args.Level); - Console.WriteLine(_formatter.Format(args)); - Console.ResetColor(); + if (OperatingSystem.IsIOS()) + { + Console.WriteLine(_formatter.Format(args)); + } + else + { + Console.ForegroundColor = GetLogColor(args.Level); + Console.WriteLine(_formatter.Format(args)); + Console.ResetColor(); + } } public void Dispose() { GC.SuppressFinalize(this); - Console.ResetColor(); + + if (!OperatingSystem.IsIOS()) + { + Console.ResetColor(); + } } } } diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index ab65a98f3..bf68cbbc8 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -30,6 +30,11 @@ namespace Ryujinx.Common public static string GetVersion() { + if (OperatingSystem.IsIOS()) + { + return "ios"; + } + if (IsValid()) { return BuildVersion; @@ -46,7 +51,7 @@ namespace Ryujinx.Common #else public static string GetBaseApplicationDirectory() { - if (IsFlatHubBuild() || OperatingSystem.IsMacOS()) + if (IsFlatHubBuild() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return AppDataManager.BaseDirPath; } diff --git a/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs b/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs index a04c404d8..1cf7a1928 100644 --- a/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs +++ b/src/Ryujinx.Common/SystemInterop/StdErrAdapter.cs @@ -19,7 +19,7 @@ namespace Ryujinx.Common.SystemInterop public StdErrAdapter() { - if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) // TODO: iOS? { RegisterPosix(); } @@ -27,6 +27,7 @@ namespace Ryujinx.Common.SystemInterop [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] private void RegisterPosix() { const int StdErrFileno = 2; @@ -44,6 +45,7 @@ namespace Ryujinx.Common.SystemInterop [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] private async Task EventWorkerAsync(CancellationToken cancellationToken) { using TextReader reader = new StreamReader(_pipeReader, leaveOpen: true); @@ -92,6 +94,7 @@ namespace Ryujinx.Common.SystemInterop [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] private static Stream CreateFileDescriptorStream(int fd) { return new FileStream( diff --git a/src/Ryujinx.Graphics.Gpu/GraphicsConfig.cs b/src/Ryujinx.Graphics.Gpu/GraphicsConfig.cs index fbb7399ca..9707d4fac 100644 --- a/src/Ryujinx.Graphics.Gpu/GraphicsConfig.cs +++ b/src/Ryujinx.Graphics.Gpu/GraphicsConfig.cs @@ -40,7 +40,7 @@ namespace Ryujinx.Graphics.Gpu /// /// Enables or disables the Just-in-Time compiler for GPU Macro code. /// - public static bool EnableMacroJit = true; + public static bool EnableMacroJit = false; /// /// Enables or disables high-level emulation of common GPU Macro code. diff --git a/src/Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs b/src/Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs index 5167ff9fe..c0a49b5f7 100644 --- a/src/Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs +++ b/src/Ryujinx.Graphics.Nvdec.FFmpeg/Native/FFmpegApi.cs @@ -26,7 +26,7 @@ namespace Ryujinx.Graphics.Nvdec.FFmpeg.Native { return $"lib{libraryName}.so.{version}"; } - else if (OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) // TODO: ffmpeg on ios { return $"lib{libraryName}.{version}.dylib"; } diff --git a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs index 457240aa0..fadfc66dd 100644 --- a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs +++ b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs @@ -6,6 +6,7 @@ using System.Runtime.Versioning; namespace Ryujinx.Graphics.Vulkan.MoltenVK { [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] public static partial class MVKInitialization { [LibraryImport("libMoltenVK.dylib")] diff --git a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs index 893ecf1a9..d379b9c18 100644 --- a/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs +++ b/src/Ryujinx.Graphics.Vulkan/VulkanRenderer.cs @@ -101,7 +101,7 @@ namespace Ryujinx.Graphics.Vulkan Textures = new HashSet(); Samplers = new HashSet(); - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MVKInitialization.Initialize(); diff --git a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs index 4fa674de9..359c9b75e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nifm/StaticService/Types/IpAddressSetting.cs @@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.Nifm.StaticService.Types public IpAddressSetting(IPInterfaceProperties interfaceProperties, UnicastIPAddressInformation unicastIPAddressInformation) { - IsDhcpEnabled = OperatingSystem.IsMacOS() || interfaceProperties.DhcpServerAddresses.Count != 0; + IsDhcpEnabled = OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || interfaceProperties.DhcpServerAddresses.Count != 0; Address = new IpV4Address(unicastIPAddressInformation.Address); IPv4Mask = new IpV4Address(unicastIPAddressInformation.IPv4Mask); GatewayAddress = (interfaceProperties.GatewayAddresses.Count == 0) ? new IpV4Address() : new IpV4Address(interfaceProperties.GatewayAddresses[0].Address); diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs index e2ef75f80..b6d8be135 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/WinSockHelper.cs @@ -283,7 +283,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl public static LinuxError ConvertError(WsaError errorCode) { - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { if (_errorMapMacOs.TryGetValue((int)errorCode, out LinuxError errno)) { diff --git a/src/Ryujinx.Headless.SDL2/Program.cs b/src/Ryujinx.Headless.SDL2/Program.cs index 7e3c79f54..bd077bc7e 100644 --- a/src/Ryujinx.Headless.SDL2/Program.cs +++ b/src/Ryujinx.Headless.SDL2/Program.cs @@ -33,6 +33,7 @@ using Silk.NET.Vulkan; using System; using System.Collections.Generic; using System.IO; +using System.Runtime.InteropServices; using System.Text.Json; using System.Threading; using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId; @@ -60,16 +61,46 @@ namespace Ryujinx.Headless.SDL2 private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); + [UnmanagedCallersOnly(EntryPoint = "main_ryujinx_sdl")] + public static unsafe int MainExternal(int argCount, IntPtr* pArgs) + { + string[] args = new string[argCount]; + + try + { + for (int i = 0; i < argCount; i++) + { + args[i] = Marshal.PtrToStringAnsi(pArgs[i]); + + Console.WriteLine(args[i]); + } + + Main(args); + } + catch (Exception e) + { + Console.WriteLine(e.ToString()); + return -1; + } + + return 0; + } + static void Main(string[] args) { - Version = ReleaseInformation.GetVersion(); - // Make process DPI aware for proper window sizing on high-res screens. ForceDpiAware.Windows(); - Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; + Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.MacOS; - if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()) + Version = ReleaseInformation.GetVersion(); + + if (!OperatingSystem.IsIOS()) + { + Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; + } + + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || OperatingSystem.IsLinux()) { AutoResetEvent invoked = new(false); @@ -344,12 +375,12 @@ namespace Ryujinx.Headless.SDL2 GraphicsConfig.EnableShaderCache = true; - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { if (option.GraphicsBackend == GraphicsBackend.OpenGl) { option.GraphicsBackend = GraphicsBackend.Vulkan; - Logger.Warning?.Print(LogClass.Application, "OpenGL is not supported on macOS, switching to Vulkan!"); + Logger.Warning?.Print(LogClass.Application, "OpenGL is not supported on Apple platforms, switching to Vulkan!"); } } diff --git a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj index 7b13df736..bb43ced2e 100644 --- a/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj +++ b/src/Ryujinx.Headless.SDL2/Ryujinx.Headless.SDL2.csproj @@ -2,21 +2,88 @@ net8.0 - win-x64;osx-x64;linux-x64 - Exe + ios-arm64 true 1.0.0-dirty $(DefineConstants);$(ExtraDefineConstants) - true + + true + true + true + false + + + + true + true + true + /Applications/Xcode.app/Contents/Developer + $([MSBuild]::EnsureTrailingSlash('$(XCodePath)')) + + + + + + + + + + + + + + $(XcodeSelect) + $([MSBuild]::EnsureTrailingSlash('$(XCodePath)')) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -65,7 +132,7 @@ - true + false true partial diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index adab07641..9603a86be 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -36,7 +36,7 @@ namespace Ryujinx.Headless.SDL2 private static readonly ConcurrentQueue _mainThreadActions = new(); - [LibraryImport("SDL2")] + [LibraryImport("SDL2.framework/SDL2")] // TODO: Remove this as soon as SDL2-CS was updated to expose this method publicly private static partial IntPtr SDL_LoadBMP_RW(IntPtr src, int freesrc); diff --git a/src/Ryujinx.Memory/MachJitWorkaround.cs b/src/Ryujinx.Memory/MachJitWorkaround.cs new file mode 100644 index 000000000..cfb1e419c --- /dev/null +++ b/src/Ryujinx.Memory/MachJitWorkaround.cs @@ -0,0 +1,168 @@ +using System; +using System.Runtime.InteropServices; +using System.Runtime.Versioning; + +namespace Ryujinx.Memory +{ + [SupportedOSPlatform("ios")] + static unsafe partial class MachJitWorkaround + { + [LibraryImport("libc")] + public static partial int mach_task_self(); + + [LibraryImport("libc")] + public static partial int mach_make_memory_entry_64(IntPtr target_task, IntPtr* size, IntPtr offset, int permission, IntPtr* object_handle, IntPtr parent_entry); + + [LibraryImport("libc")] + public static partial int mach_memory_entry_ownership(IntPtr mem_entry, IntPtr owner, int ledger_tag, int ledger_flags); + + [LibraryImport("libc")] + public static partial int vm_map(IntPtr target_task, IntPtr* address, IntPtr size, IntPtr mask, int flags, IntPtr obj, IntPtr offset, int copy, int cur_protection, int max_protection, int inheritance); + + [LibraryImport("libc")] + public static partial int vm_allocate(IntPtr target_task, IntPtr* address, IntPtr size, int flags); + + [LibraryImport("libc")] + public static partial int vm_deallocate(IntPtr target_task, IntPtr address, IntPtr size); + + [LibraryImport("libc")] + public static partial int vm_remap(IntPtr target_task, IntPtr* target_address, IntPtr size, IntPtr mask, int flags, IntPtr src_task, IntPtr src_address, int copy, int* cur_protection, int* max_protection, int inheritance); + + const int MAP_MEM_LEDGER_TAGGED = 0x002000; + const int MAP_MEM_NAMED_CREATE = 0x020000; + + const int VM_PROT_READ = 0x01; + const int VM_PROT_WRITE = 0x02; + const int VM_PROT_EXECUTE = 0x04; + + const int VM_LEDGER_TAG_DEFAULT = 0x00000001; + const int VM_LEDGER_FLAG_NO_FOOTPRINT = 0x00000001; + + const int VM_INHERIT_COPY = 1; + const int VM_INHERIT_DEFAULT = VM_INHERIT_COPY; + + const int VM_FLAGS_FIXED = 0x0000; + const int VM_FLAGS_ANYWHERE = 0x0001; + const int VM_FLAGS_OVERWRITE = 0x4000; + + const IntPtr TASK_NULL = 0; + + public static void ReallocateBlock(IntPtr address, int size) + { + IntPtr selfTask = mach_task_self(); + IntPtr memorySize = (IntPtr)size; + IntPtr memoryObjectPort = IntPtr.Zero; + + int err = mach_make_memory_entry_64(selfTask, &memorySize, 0, MAP_MEM_NAMED_CREATE | MAP_MEM_LEDGER_TAGGED | VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, &memoryObjectPort, 0); + + if (err != 0) + { + throw new InvalidOperationException($"Make memory entry failed: {err}"); + } + + try + { + if (memorySize != (IntPtr)size) + { + throw new InvalidOperationException($"Created with size {memorySize} instead of {size}."); + } + + err = mach_memory_entry_ownership(memoryObjectPort, TASK_NULL, VM_LEDGER_TAG_DEFAULT, VM_LEDGER_FLAG_NO_FOOTPRINT); + + if (err != 0) + { + throw new InvalidOperationException($"Failed to set ownership: {err}"); + } + + IntPtr mapAddress = address; + + err = vm_map( + selfTask, + &mapAddress, + memorySize, + /*mask=*/ 0, + /*flags=*/ VM_FLAGS_OVERWRITE, + memoryObjectPort, + /*offset=*/ 0, + /*copy=*/ 0, + VM_PROT_READ | VM_PROT_WRITE, + VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, + VM_INHERIT_COPY); + + if (err != 0) + { + throw new InvalidOperationException($"Failed to map: {err}"); + } + + if (address != mapAddress) + { + throw new InvalidOperationException($"Remap changed address"); + } + } + finally + { + //mach_port_deallocate(selfTask, memoryObjectPort); + } + + Console.WriteLine($"Reallocated an area... {address:x16}"); + } + + public static void ReallocateAreaWithOwnership(IntPtr address, int size) + { + int mapChunkSize = 128 * 1024 * 1024; + IntPtr endAddress = address + size; + IntPtr blockAddress = address; + while (blockAddress < endAddress) + { + int blockSize = Math.Min(mapChunkSize, (int)(endAddress - blockAddress)); + + ReallocateBlock(blockAddress, blockSize); + + blockAddress += blockSize; + } + } + + public static IntPtr AllocateSharedMemory(ulong size, bool reserve) + { + IntPtr address = 0; + + int err = vm_allocate(mach_task_self(), &address, (IntPtr)size, VM_FLAGS_ANYWHERE); + + if (err != 0) + { + throw new InvalidOperationException($"Failed to allocate shared memory: {err}"); + } + + return address; + } + + public static void DestroySharedMemory(IntPtr handle, ulong size) + { + vm_deallocate(mach_task_self(), handle, (IntPtr)size); + } + + public static IntPtr MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size) + { + IntPtr taskSelf = mach_task_self(); + IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + srcOffset); + IntPtr dstAddress = location; + + int cur_protection = 0; + int max_protection = 0; + + int err = vm_remap(taskSelf, &dstAddress, (IntPtr)size, 0, VM_FLAGS_OVERWRITE, taskSelf, srcAddress, 0, &cur_protection, &max_protection, VM_INHERIT_DEFAULT); + + if (err != 0) + { + throw new InvalidOperationException($"Failed to allocate remap memory: {err}"); + } + + return dstAddress; + } + + public static void UnmapView(IntPtr location, ulong size) + { + vm_deallocate(mach_task_self(), location, (IntPtr)size); + } + } +} \ No newline at end of file diff --git a/src/Ryujinx.Memory/MemoryBlock.cs b/src/Ryujinx.Memory/MemoryBlock.cs index 7fe7862a9..477be893a 100644 --- a/src/Ryujinx.Memory/MemoryBlock.cs +++ b/src/Ryujinx.Memory/MemoryBlock.cs @@ -426,7 +426,7 @@ namespace Ryujinx.Memory return OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134); } - return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS(); + return OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS(); } return true; diff --git a/src/Ryujinx.Memory/MemoryManagement.cs b/src/Ryujinx.Memory/MemoryManagement.cs index 860d3f368..a23fafb57 100644 --- a/src/Ryujinx.Memory/MemoryManagement.cs +++ b/src/Ryujinx.Memory/MemoryManagement.cs @@ -10,7 +10,7 @@ namespace Ryujinx.Memory { return MemoryManagementWindows.Allocate((IntPtr)size); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return MemoryManagementUnix.Allocate(size, forJit); } @@ -26,7 +26,7 @@ namespace Ryujinx.Memory { return MemoryManagementWindows.Reserve((IntPtr)size, viewCompatible); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return MemoryManagementUnix.Reserve(size, forJit); } @@ -42,7 +42,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.Commit(address, (IntPtr)size); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.Commit(address, size, forJit); } @@ -58,7 +58,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.Decommit(address, (IntPtr)size); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.Decommit(address, size); } @@ -74,7 +74,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.MapView(sharedMemory, srcOffset, address, (IntPtr)size, owner); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.MapView(sharedMemory, srcOffset, address, size); } @@ -90,7 +90,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.UnmapView(sharedMemory, address, (IntPtr)size, owner); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.UnmapView(address, size); } @@ -108,7 +108,7 @@ namespace Ryujinx.Memory { result = MemoryManagementWindows.Reprotect(address, (IntPtr)size, permission, forView); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { result = MemoryManagementUnix.Reprotect(address, size, permission); } @@ -129,7 +129,7 @@ namespace Ryujinx.Memory { return MemoryManagementWindows.Free(address, (IntPtr)size); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return MemoryManagementUnix.Free(address); } @@ -145,7 +145,7 @@ namespace Ryujinx.Memory { return MemoryManagementWindows.CreateSharedMemory((IntPtr)size, reserve); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return MemoryManagementUnix.CreateSharedMemory(size, reserve); } @@ -161,7 +161,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.DestroySharedMemory(handle); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.DestroySharedMemory(handle); } @@ -177,7 +177,7 @@ namespace Ryujinx.Memory { return MemoryManagementWindows.MapSharedMemory(handle); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { return MemoryManagementUnix.MapSharedMemory(handle, size); } @@ -193,7 +193,7 @@ namespace Ryujinx.Memory { MemoryManagementWindows.UnmapSharedMemory(address); } - else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsLinux() || OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { MemoryManagementUnix.UnmapSharedMemory(address, size); } diff --git a/src/Ryujinx.Memory/MemoryManagementUnix.cs b/src/Ryujinx.Memory/MemoryManagementUnix.cs index e132dbbb8..78966777e 100644 --- a/src/Ryujinx.Memory/MemoryManagementUnix.cs +++ b/src/Ryujinx.Memory/MemoryManagementUnix.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.Versioning; using static Ryujinx.Memory.MemoryManagerUnixHelper; @@ -8,6 +9,7 @@ namespace Ryujinx.Memory { [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] static class MemoryManagementUnix { private static readonly ConcurrentDictionary _allocations = new(); @@ -40,7 +42,7 @@ namespace Ryujinx.Memory flags |= MmapFlags.MAP_NORESERVE; } - if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit) + if (OperatingSystem.IsMacOS() && OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit) { flags |= MmapFlags.MAP_JIT_DARWIN; @@ -57,6 +59,11 @@ namespace Ryujinx.Memory throw new SystemException(Marshal.GetLastPInvokeErrorMessage()); } + if (OperatingSystem.IsIOS() && forJit) + { + MachJitWorkaround.ReallocateAreaWithOwnership(ptr, (int)size); + } + if (!_allocations.TryAdd(ptr, size)) { // This should be impossible, kernel shouldn't return an already mapped address. @@ -70,7 +77,7 @@ namespace Ryujinx.Memory { MmapProts prot = MmapProts.PROT_READ | MmapProts.PROT_WRITE; - if (OperatingSystem.IsMacOSVersionAtLeast(10, 14) && forJit) + if ((OperatingSystem.IsIOS() || OperatingSystem.IsMacOSVersionAtLeast(10, 14)) && forJit) { prot |= MmapProts.PROT_EXEC; } @@ -134,11 +141,21 @@ namespace Ryujinx.Memory return munmap(address, size) == 0; } + private static Dictionary _sharedMemorySizes = new Dictionary(); + public unsafe static IntPtr CreateSharedMemory(ulong size, bool reserve) { int fd; - if (OperatingSystem.IsMacOS()) + if (OperatingSystem.IsIOS()) + { + IntPtr baseAddress = MachJitWorkaround.AllocateSharedMemory(size, reserve); + + _sharedMemorySizes.Add(baseAddress, size); + + return baseAddress; + } + else if (OperatingSystem.IsMacOS()) { byte[] memName = "Ryujinx-XXXXXX"u8.ToArray(); @@ -185,27 +202,64 @@ namespace Ryujinx.Memory public static void DestroySharedMemory(IntPtr handle) { - close(handle.ToInt32()); + if (OperatingSystem.IsIOS()) + { + if (_sharedMemorySizes.TryGetValue(handle, out ulong size)) + { + MachJitWorkaround.DestroySharedMemory(handle, size); + } + } + else + { + close(handle.ToInt32()); + } } public static IntPtr MapSharedMemory(IntPtr handle, ulong size) { - return Mmap(IntPtr.Zero, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_SHARED, handle.ToInt32(), 0); + if (OperatingSystem.IsIOS()) + { + // The base of the shared memory is already mapped - it's the handle. + // Views are remapped from it. + + return handle; + } + else + { + return Mmap(IntPtr.Zero, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_SHARED, handle.ToInt32(), 0); + } } public static void UnmapSharedMemory(IntPtr address, ulong size) { - munmap(address, size); + if (!OperatingSystem.IsIOS()) + { + munmap(address, size); + } } public static void MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size) { - Mmap(location, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_FIXED | MmapFlags.MAP_SHARED, sharedMemory.ToInt32(), (long)srcOffset); + if (OperatingSystem.IsIOS()) + { + MachJitWorkaround.MapView(sharedMemory, srcOffset, location, size); + } + else + { + Mmap(location, size, MmapProts.PROT_READ | MmapProts.PROT_WRITE, MmapFlags.MAP_FIXED | MmapFlags.MAP_SHARED, sharedMemory.ToInt32(), (long)srcOffset); + } } public static void UnmapView(IntPtr location, ulong size) { - Mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED | MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_NORESERVE, -1, 0); + if (OperatingSystem.IsIOS()) + { + MachJitWorkaround.UnmapView(location, size); + } + else + { + Mmap(location, size, MmapProts.PROT_NONE, MmapFlags.MAP_FIXED | MmapFlags.MAP_PRIVATE | MmapFlags.MAP_ANONYMOUS | MmapFlags.MAP_NORESERVE, -1, 0); + } } } } diff --git a/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs b/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs index 43888c85b..6ed4d2387 100644 --- a/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs +++ b/src/Ryujinx.Memory/MemoryManagerUnixHelper.cs @@ -6,6 +6,7 @@ namespace Ryujinx.Memory { [SupportedOSPlatform("linux")] [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] public static partial class MemoryManagerUnixHelper { [Flags] @@ -114,7 +115,7 @@ namespace Ryujinx.Memory { result |= MAP_ANONYMOUS_LINUX_GENERIC; } - else if (OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { result |= MAP_ANONYMOUS_DARWIN; } @@ -130,7 +131,7 @@ namespace Ryujinx.Memory { result |= MAP_NORESERVE_LINUX_GENERIC; } - else if (OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { result |= MAP_NORESERVE_DARWIN; } @@ -146,7 +147,7 @@ namespace Ryujinx.Memory { result |= MAP_UNLOCKED_LINUX_GENERIC; } - else if (OperatingSystem.IsMacOS()) + else if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS()) { // FIXME: Doesn't exist on Darwin } @@ -156,7 +157,7 @@ namespace Ryujinx.Memory } } - if (flags.HasFlag(MmapFlags.MAP_JIT_DARWIN) && OperatingSystem.IsMacOSVersionAtLeast(10, 14)) + if (flags.HasFlag(MmapFlags.MAP_JIT_DARWIN) && (OperatingSystem.IsIOS() || OperatingSystem.IsMacOSVersionAtLeast(10, 14))) { result |= (int)MmapFlags.MAP_JIT_DARWIN; } diff --git a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs index b017d384c..52575a7e3 100644 --- a/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.Ui.Common/Configuration/ConfigurationState.cs @@ -1536,7 +1536,7 @@ namespace Ryujinx.Ui.Common.Configuration { // Any system running macOS or returning any amount of valid Vulkan devices should default to Vulkan. // Checks for if the Vulkan version and featureset is compatible should be performed within VulkanRenderer. - if (OperatingSystem.IsMacOS() || VulkanRenderer.GetPhysicalDevices().Length > 0) + if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() || VulkanRenderer.GetPhysicalDevices().Length > 0) { return GraphicsBackend.Vulkan; } diff --git a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs b/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs index af8723e2f..16a67ecb2 100644 --- a/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs +++ b/src/Ryujinx.Ui.Common/Helper/ObjectiveC.cs @@ -5,6 +5,7 @@ using System.Runtime.Versioning; namespace Ryujinx.Ui.Common.Helper { [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] public static partial class ObjectiveC { private const string ObjCRuntime = "/usr/lib/libobjc.A.dylib"; diff --git a/src/Ryujinx/Ui/Helper/MetalHelper.cs b/src/Ryujinx/Ui/Helper/MetalHelper.cs index a7af2aed2..f46a5e36e 100644 --- a/src/Ryujinx/Ui/Helper/MetalHelper.cs +++ b/src/Ryujinx/Ui/Helper/MetalHelper.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Ui.Helper public delegate void UpdateBoundsCallbackDelegate(Window window); [SupportedOSPlatform("macos")] + [SupportedOSPlatform("ios")] static partial class MetalHelper { private const string LibObjCImport = "/usr/lib/libobjc.A.dylib";