diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 88d247e..fe093e7 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 46; + objectVersion = 52; objects = { /* Begin PBXAggregateTarget section */ @@ -165,6 +165,9 @@ BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03623E3BB2600931B96 /* libSnes9x.a */; }; BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03D23E3C0F000931B96 /* libGambatte.a */; }; BFFDF04623E3D3A600931B96 /* libMupen64Plus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */; }; + D524F4A1273DE9A100D500B2 /* AltKit in Frameworks */ = {isa = PBXBuildFile; productRef = D524F4A0273DE9A100D500B2 /* AltKit */; }; + D524F4A3273DE9C000D500B2 /* ProcessInfo+JIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */; }; + D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -358,6 +361,8 @@ BFFDF03D23E3C0F000931B96 /* libGambatte.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libGambatte.a; sourceTree = BUILT_PRODUCTS_DIR; }; BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libMupen64Plus.a; sourceTree = BUILT_PRODUCTS_DIR; }; C786AF1D2DDB6223BE2063CC /* Pods-Delta.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Delta.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig"; sourceTree = ""; }; + D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+JIT.swift"; sourceTree = ""; }; + D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ServerManager+Delta.swift"; sourceTree = ""; }; DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -373,6 +378,7 @@ BFDCA1E6244EBAA900B8FBDB /* liblibDeSmuME.a in Frameworks */, BFCADF1E25D22FE2008D78FB /* Systems.framework in Frameworks */, BF69FBC923E3A8380051BEEA /* libNestopia.a in Frameworks */, + D524F4A1273DE9A100D500B2 /* AltKit in Frameworks */, 1FA4ABA79AB72914FE414A61 /* libPods-Delta.a in Frameworks */, BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */, BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */, @@ -403,6 +409,8 @@ BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */, BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */, BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */, + D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */, + D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */, ); path = Extensions; sourceTree = ""; @@ -908,6 +916,7 @@ ); name = Delta; packageProductDependencies = ( + D524F4A0273DE9A100D500B2 /* AltKit */, ); productName = Delta; productReference = BFFA71D71AAC406100EE9DD1 /* Delta.app */; @@ -957,6 +966,9 @@ Base, ); mainGroup = BFFA71CE1AAC406100EE9DD1; + packageReferences = ( + D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */, + ); productRefGroup = BFFA71D81AAC406100EE9DD1 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -1148,6 +1160,7 @@ BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */, BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */, BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */, + D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */, BF1F45AD21AF57BA00EF9895 /* HarmonyMetadataKey+Keys.swift in Sources */, BFD1EF402336BD8800D197CF /* UIDevice+Processor.swift in Sources */, BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */, @@ -1179,6 +1192,7 @@ BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */, BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */, BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */, + D524F4A3273DE9C000D500B2 /* ProcessInfo+JIT.swift in Sources */, BFDCA1E9244F7E1000B8FBDB /* Delta5ToDelta6.xcmappingmodel in Sources */, BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */, BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */, @@ -1407,7 +1421,8 @@ PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta; PRODUCT_NAME = Delta; SDKROOT = iphoneos; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; @@ -1462,9 +1477,10 @@ PROVISIONING_PROFILE_SPECIFIER = ""; STRIP_INSTALLED_PRODUCT = YES; STRIP_STYLE = "non-global"; + SWIFT_COMPILATION_MODE = wholemodule; SWIFT_INCLUDE_PATHS = "$(inherited) \"$(SRCROOT)/Cores/GPGXDeltaCore/Sources/GPGXBridge\""; SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_OPTIMIZATION_LEVEL = "-O"; SWIFT_VERSION = 5.0; }; name = Release; @@ -1510,6 +1526,25 @@ }; /* End XCConfigurationList section */ +/* Begin XCRemoteSwiftPackageReference section */ + D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/rileytestut/AltKit.git"; + requirement = { + kind = revision; + revision = 2fd376df1c79ec06a5c80cc8933da027f65b3148; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + D524F4A0273DE9A100D500B2 /* AltKit */ = { + isa = XCSwiftPackageProductDependency; + package = D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */; + productName = AltKit; + }; +/* End XCSwiftPackageProductDependency section */ + /* Begin XCVersionGroup section */ BF4828811F9027B600028B97 /* Delta.xcdatamodeld */ = { isa = XCVersionGroup; diff --git a/Delta.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Delta.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0ac4043..0afb4a3 100644 --- a/Delta.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Delta.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,6 +1,15 @@ { "object": { "pins": [ + { + "package": "AltKit", + "repositoryURL": "https://github.com/rileytestut/AltKit.git", + "state": { + "branch": null, + "revision": "2fd376df1c79ec06a5c80cc8933da027f65b3148", + "version": null + } + }, { "package": "DeltaCore", "repositoryURL": "https://github.com/rileytestut/DeltaCore.git", diff --git a/Delta/AppDelegate.swift b/Delta/AppDelegate.swift index 780f386..aade6e3 100644 --- a/Delta/AppDelegate.swift +++ b/Delta/AppDelegate.swift @@ -10,6 +10,7 @@ import UIKit import DeltaCore import Harmony +import AltKit import Fabric import Crashlytics @@ -63,6 +64,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate // Controllers ExternalGameControllerManager.shared.startMonitoring() + // JIT + ServerManager.shared.prepare() + // Notifications let center = CFNotificationCenterGetDarwinNotifyCenter() CFNotificationCenterAddObserver(center, nil, ReceivedApplicationState, CFNotificationName.altstoreRequestAppState.rawValue, nil, .deliverImmediately) diff --git a/Delta/Base.lproj/Settings.storyboard b/Delta/Base.lproj/Settings.storyboard index b68c00e..2a2a5d6 100644 --- a/Delta/Base.lproj/Settings.storyboard +++ b/Delta/Base.lproj/Settings.storyboard @@ -1861,10 +1861,48 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + @@ -1887,7 +1925,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -1910,7 +1948,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -1937,7 +1975,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -1960,7 +1998,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -1983,7 +2021,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -2006,7 +2044,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + @@ -2033,7 +2071,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games. - + diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift index ad520de..a4d2fc9 100644 --- a/Delta/Emulation/GameViewController.swift +++ b/Delta/Emulation/GameViewController.swift @@ -10,11 +10,13 @@ import UIKit import DeltaCore import GBADeltaCore +import MelonDSDeltaCore import Systems import struct DSDeltaCore.DS import Roxas +import AltKit private var kvoContext = 0 @@ -167,6 +169,8 @@ class GameViewController: DeltaCore.GameViewController private var isGyroActive = false private var presentedGyroAlert = false + private var presentedJITAlert = false + override var shouldAutorotate: Bool { return !self.isGyroActive } @@ -205,6 +209,8 @@ class GameViewController: DeltaCore.GameViewController NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didDeactivateGyro(with:)), name: GBA.didDeactivateGyroNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.emulationDidQuit(with:)), name: EmulatorCore.emulationDidQuitNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnableJIT(with:)), name: ServerManager.didEnableJITNotification, object: nil) } deinit @@ -330,6 +336,10 @@ extension GameViewController UserDefaults.standard.desmumeDeprecatedAlertCount += 1 } + else if self.emulatorCore?.deltaCore == MelonDS.core, ProcessInfo.processInfo.isJITAvailable + { + self.showJITEnabledAlert() + } } override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) @@ -474,6 +484,13 @@ extension GameViewController } self._isLoadingSaveState = false + + if self.emulatorCore?.deltaCore == MelonDS.core, ProcessInfo.processInfo.isJITAvailable + { + self.transitionCoordinator?.animate(alongsideTransition: nil, completion: { (context) in + self.showJITEnabledAlert() + }) + } } case "unwindToGames": @@ -1085,6 +1102,48 @@ private extension GameViewController toastView.presentationEdge = .top toastView.show(in: self.view, duration: duration) } + + func showJITEnabledAlert() + { + guard !self.presentedJITAlert, self.presentedViewController == nil, self.game != nil else { return } + self.presentedJITAlert = true + + func presentToastView() + { + let detailText: String? + let duration: TimeInterval + + if UserDefaults.standard.jitEnabledAlertCount < 3 + { + detailText = NSLocalizedString("You can now Fast Forward DS games up to 3x speed.", comment: "") + duration = 5.0 + } + else + { + detailText = nil + duration = 2.0 + } + + let toastView = RSTToastView(text: NSLocalizedString("JIT Compilation Enabled", comment: ""), detailText: detailText) + toastView.edgeOffset.vertical = 8 + self.show(toastView, duration: duration) + + UserDefaults.standard.jitEnabledAlertCount += 1 + } + + DispatchQueue.main.async { + if let transitionCoordinator = self.transitionCoordinator + { + transitionCoordinator.animate(alongsideTransition: nil) { (context) in + presentToastView() + } + } + else + { + presentToastView() + } + } + } } //MARK: - Notifications - @@ -1129,7 +1188,7 @@ private extension GameViewController case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity - case .syncingService: break + case .syncingService, .isAltJITEnabled: break } } @@ -1207,6 +1266,60 @@ private extension GameViewController self.isGyroActive = false } + @objc func didEnableJIT(with notification: Notification) + { + DispatchQueue.main.async { + self.showJITEnabledAlert() + } + + DispatchQueue.global(qos: .utility).async { + guard let emulatorCore = self.emulatorCore, let emulatorBridge = emulatorCore.deltaCore.emulatorBridge as? MelonDSEmulatorBridge, !emulatorBridge.isJITEnabled + else { return } + + guard emulatorCore.state != .stopped else { + // Emulator core is not running, which means we can set + // isJITEnabled to true without resetting the core. + emulatorBridge.isJITEnabled = true + return + } + + let isVideoEnabled = emulatorCore.videoManager.isEnabled + emulatorCore.videoManager.isEnabled = false + + let isRunning = (emulatorCore.state == .running) + if isRunning + { + self.pauseEmulation() + } + + let temporaryFileURL = FileManager.default.uniqueTemporaryURL() + + let saveState = emulatorCore.saveSaveState(to: temporaryFileURL) + emulatorCore.stop() + + emulatorBridge.isJITEnabled = true + + emulatorCore.start() + emulatorCore.pause() + + do + { + try emulatorCore.load(saveState) + } + catch + { + print("Failed to load save state after enabling JIT.", error) + } + + if isRunning + { + self.resumeEmulation() + } + + emulatorCore.videoManager.isEnabled = isVideoEnabled + } + } + @objc func emulationDidQuit(with notification: Notification) { DispatchQueue.main.async { @@ -1231,4 +1344,6 @@ private extension GameViewController private extension UserDefaults { @NSManaged var desmumeDeprecatedAlertCount: Int + + @NSManaged var jitEnabledAlertCount: Int } diff --git a/Delta/Extensions/ProcessInfo+JIT.swift b/Delta/Extensions/ProcessInfo+JIT.swift new file mode 100644 index 0000000..c3e7eb9 --- /dev/null +++ b/Delta/Extensions/ProcessInfo+JIT.swift @@ -0,0 +1,41 @@ +// +// ProcessInfo+JIT.swift +// Delta +// +// Created by Riley Testut on 9/14/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import UIKit + +private let CS_OPS_STATUS: UInt32 = 0 /* OK */ +private let CS_DEBUGGED: UInt32 = 0x10000000 /* Process is or has been attached to debugger. */ + +@_silgen_name("csops") +func csops(_ pid: pid_t, _ ops: UInt32, _ useraddr: UnsafeMutableRawPointer?, _ usersize: Int) -> Int + +extension ProcessInfo +{ + static var isJITDisabled = false + + var isDebugging: Bool { + var flags: UInt32 = 0 + let result = csops(getpid(), CS_OPS_STATUS, &flags, MemoryLayout.size) + + let isDebugging = result == 0 && (flags & CS_DEBUGGED == CS_DEBUGGED) + return isDebugging + } + + var isJITAvailable: Bool { + guard UIDevice.current.supportsJIT && !ProcessInfo.isJITDisabled else { return false } + + let ios14_4 = OperatingSystemVersion(majorVersion: 14, minorVersion: 4, patchVersion: 0) + if #available(iOS 14.2, *), !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14_4) + { + // JIT is always available on supported devices running iOS 14.2 - 14.3. + return true + } + + return self.isDebugging + } +} diff --git a/Delta/Extensions/ServerManager+Delta.swift b/Delta/Extensions/ServerManager+Delta.swift new file mode 100644 index 0000000..ce69c80 --- /dev/null +++ b/Delta/Extensions/ServerManager+Delta.swift @@ -0,0 +1,104 @@ +// +// ServerManager+Delta.swift +// Delta +// +// Created by Riley Testut on 9/15/21. +// Copyright © 2021 Riley Testut. All rights reserved. +// + +import AltKit + +extension ServerManager +{ + static let didEnableJITNotification = Notification.Name("didEnableJITNotification") +} + +extension ServerManager +{ + func prepare() + { + NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.didChangeJITMode(_:)), name: .settingsDidChange, object: nil) + + #if DEBUG + if ProcessInfo.processInfo.isDebugging + { + // Debugger is attached at app launch, so we assume + // we're connected to Xcode for debugging purposes. + // In that case, we manually treat JIT as unavailable + // until AltServer is discovered to simulate real-world use. + ProcessInfo.isJITDisabled = true + } + #endif + + self.start() + } +} + +private extension ServerManager +{ + func start() + { + guard Settings.isAltJITEnabled && !ProcessInfo.processInfo.isJITAvailable else { return } + + self.startDiscovering() + self.autoconnect() + } + + func autoconnect() + { + self.autoconnect { result in + switch result + { + case .failure(let error): + print("Could not auto-connect to server.", error) + self.autoconnect() + + case .success(let connection): + func finish(result: Result) + { + switch result + { + case .failure(ALTServerError.unknownRequest), .failure(ALTServerError.deviceNotFound): + // Try connecting to a different server. + self.autoconnect() + + case .failure(let error): + print("Could not enable JIT compilation.", error) + + case .success: + print("Successfully enabled JIT compilation!") + + NotificationCenter.default.post(name: ServerManager.didEnableJITNotification, object: nil) + self.stopDiscovering() + } + + connection.disconnect() + } + + if ProcessInfo.isJITDisabled + { + ProcessInfo.isJITDisabled = false + finish(result: .success(())) + } + else + { + connection.enableUnsignedCodeExecution(completion: finish) + } + } + } + } + + @objc func didChangeJITMode(_ notification: Notification) + { + guard let name = notification.userInfo?[Settings.NotificationUserInfoKey.name] as? Settings.Name, name == Settings.Name.isAltJITEnabled else { return } + + if Settings.isAltJITEnabled + { + self.start() + } + else + { + self.stopDiscovering() + } + } +} diff --git a/Delta/Extensions/UIDevice+Processor.swift b/Delta/Extensions/UIDevice+Processor.swift index 2f84c4c..2a903fb 100644 --- a/Delta/Extensions/UIDevice+Processor.swift +++ b/Delta/Extensions/UIDevice+Processor.swift @@ -26,12 +26,9 @@ extension UIDevice } var supportsJIT: Bool { - // As of iOS 14.4 beta 2, JIT is no longer supported :( - // Hopefully this change is reversed before the public release... - let ios14_4 = OperatingSystemVersion(majorVersion: 14, minorVersion: 4, patchVersion: 0) - guard #available(iOS 14.2, *), !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14_4) else { return false } + guard #available(iOS 14.0, *) else { return false } - // JIT is supported on devices with an A12 processor or better running iOS 14.2 or later. + // JIT is supported on devices with an A12 processor or better running iOS 14.0 or later. // ARKit 3 is only supported by devices with an A12 processor or better, according to the documentation. return ARBodyTrackingConfiguration.isSupported } diff --git a/Delta/Game Selection/GameCollectionViewController.swift b/Delta/Game Selection/GameCollectionViewController.swift index ef16b87..51cfb10 100644 --- a/Delta/Game Selection/GameCollectionViewController.swift +++ b/Delta/Game Selection/GameCollectionViewController.swift @@ -180,7 +180,7 @@ extension GameCollectionViewController emulatorBridge.systemType = .ds } - emulatorBridge.isJITEnabled = UIDevice.current.supportsJIT + emulatorBridge.isJITEnabled = ProcessInfo.processInfo.isJITAvailable } if let saveState = self.activeSaveState @@ -843,7 +843,7 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate emulatorBridge.systemType = .ds } - emulatorBridge.isJITEnabled = UIDevice.current.supportsJIT + emulatorBridge.isJITEnabled = ProcessInfo.processInfo.isJITAvailable } let actions = self.actions(for: game).previewActions diff --git a/Delta/Settings/App Icon Shortcuts/AppIconShortcutsViewController.swift b/Delta/Settings/App Icon Shortcuts/AppIconShortcutsViewController.swift index c688f5a..f5c2b08 100644 --- a/Delta/Settings/App Icon Shortcuts/AppIconShortcutsViewController.swift +++ b/Delta/Settings/App Icon Shortcuts/AppIconShortcutsViewController.swift @@ -14,7 +14,7 @@ import DeltaCore import Roxas @objc(SwitchTableViewCell) -private class SwitchTableViewCell: UITableViewCell +class SwitchTableViewCell: UITableViewCell { @IBOutlet var switchView: UISwitch! } diff --git a/Delta/Settings/Cores/MelonDSCoreSettingsViewController.swift b/Delta/Settings/Cores/MelonDSCoreSettingsViewController.swift index 7bff331..b4334f3 100644 --- a/Delta/Settings/Cores/MelonDSCoreSettingsViewController.swift +++ b/Delta/Settings/Cores/MelonDSCoreSettingsViewController.swift @@ -23,6 +23,7 @@ private extension MelonDSCoreSettingsViewController enum Section: Int { case general + case performance case dsBIOS case dsiBIOS case changeCore @@ -149,6 +150,10 @@ private extension MelonDSCoreSettingsViewController switch section { + case .performance: + guard Settings.preferredCore(for: .ds) == MelonDS.core else { return true } + return !UIDevice.current.supportsJIT + case .dsBIOS where Settings.preferredCore(for: .ds) == DS.core: // Using DeSmuME core, which doesn't require BIOS. return true @@ -252,6 +257,11 @@ private extension MelonDSCoreSettingsViewController } } + @IBAction func toggleAltJITEnabled(_ sender: UISwitch) + { + Settings.isAltJITEnabled = sender.isOn + } + @objc func willEnterForeground(_ notification: Notification) { self.tableView.reloadData() @@ -300,6 +310,10 @@ extension MelonDSCoreSettingsViewController cell.contentView.isHidden = (item == nil) + case .performance: + let cell = cell as! SwitchTableViewCell + cell.switchView.isOn = Settings.isAltJITEnabled + case .dsBIOS: let bios = DSBIOS.allCases[indexPath.row] @@ -378,6 +392,8 @@ extension MelonDSCoreSettingsViewController case .changeCore: self.changeCore() + + case .performance: break } } diff --git a/Delta/Settings/Settings.swift b/Delta/Settings/Settings.swift index 38ff687..0a1559c 100644 --- a/Delta/Settings/Settings.swift +++ b/Delta/Settings/Settings.swift @@ -38,6 +38,7 @@ extension Settings case syncingService case isButtonHapticFeedbackEnabled case isThumbstickHapticFeedbackEnabled + case isAltJITEnabled } } @@ -60,6 +61,7 @@ struct Settings #keyPath(UserDefaults.isThumbstickHapticFeedbackEnabled): true, #keyPath(UserDefaults.sortSaveStatesByOldestFirst): true, #keyPath(UserDefaults.isPreviewsEnabled): true, + #keyPath(UserDefaults.isAltJITEnabled): true, Settings.preferredCoreSettingsKey(for: .ds): MelonDS.core.identifier] as [String : Any] UserDefaults.standard.register(defaults: defaults) @@ -195,6 +197,17 @@ extension Settings } } + static var isAltJITEnabled: Bool { + get { + let isAltJITEnabled = UserDefaults.standard.isAltJITEnabled + return isAltJITEnabled + } + set { + UserDefaults.standard.isAltJITEnabled = newValue + NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.isAltJITEnabled]) + } + } + static func preferredCore(for gameType: GameType) -> DeltaCoreProtocol? { let key = self.preferredCoreSettingsKey(for: gameType) @@ -390,4 +403,6 @@ private extension UserDefaults @NSManaged var sortSaveStatesByOldestFirst: Bool @NSManaged var isPreviewsEnabled: Bool + + @NSManaged var isAltJITEnabled: Bool } diff --git a/Delta/Settings/SettingsViewController.swift b/Delta/Settings/SettingsViewController.swift index 16fef76..282a0ee 100644 --- a/Delta/Settings/SettingsViewController.swift +++ b/Delta/Settings/SettingsViewController.swift @@ -290,7 +290,7 @@ private extension SettingsViewController self.tableView.selectRow(at: selectedIndexPath, animated: true, scrollPosition: .none) } - case .localControllerPlayerIndex, .preferredControllerSkin, .translucentControllerSkinOpacity, .isButtonHapticFeedbackEnabled, .isThumbstickHapticFeedbackEnabled: break + case .localControllerPlayerIndex, .preferredControllerSkin, .translucentControllerSkinOpacity, .isButtonHapticFeedbackEnabled, .isThumbstickHapticFeedbackEnabled, .isAltJITEnabled: break } } diff --git a/Delta/Supporting Files/Info.plist b/Delta/Supporting Files/Info.plist index 7839b8e..cc6ca54 100644 --- a/Delta/Supporting Files/Info.plist +++ b/Delta/Supporting Files/Info.plist @@ -400,5 +400,13 @@ + NSBonjourServices + + _altserver._tcp + + ALTDeviceID + 00008110-000A68390A82801E + NSLocalNetworkUsageDescription + Delta uses the local network to communicate with AltServer and enable JIT. diff --git a/Delta/Systems/DeltaCoreProtocol+Delta.swift b/Delta/Systems/DeltaCoreProtocol+Delta.swift index 899ee6a..0ac6cf4 100644 --- a/Delta/Systems/DeltaCoreProtocol+Delta.swift +++ b/Delta/Systems/DeltaCoreProtocol+Delta.swift @@ -72,7 +72,7 @@ extension DeltaCoreProtocol case GBA.core: return 3 case N64.core where UIDevice.current.hasA11ProcessorOrBetter: return 3 case N64.core where UIDevice.current.hasA9ProcessorOrBetter: return 1.5 - case MelonDS.core where UIDevice.current.supportsJIT: return 3 + case MelonDS.core where ProcessInfo.processInfo.isJITAvailable: return 3 case MelonDS.core where UIDevice.current.hasA11ProcessorOrBetter: return 1.5 case GPGX.core: return 4 default: return 1