forked from MeloNX/MeloNX
Add JIT detection and Lower memory plus other changes
This commit is contained in:
parent
bb4e7314a5
commit
300efe5f55
Binary file not shown.
27
src/MeloNX/MeloNX/Core/DetectJIT/utils.h
Normal file
27
src/MeloNX/MeloNX/Core/DetectJIT/utils.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#if __has_feature(modules)
|
||||||
|
@import UIKit;
|
||||||
|
@import Foundation;
|
||||||
|
#else
|
||||||
|
#import "UIKit/UIKit.h"
|
||||||
|
#import "Foundation/Foundation.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DISPATCH_ASYNC_START dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
#define DISPATCH_ASYNC_CLOSE });
|
||||||
|
|
||||||
|
#define PT_TRACE_ME 0
|
||||||
|
extern int ptrace(int, pid_t, caddr_t, int);
|
||||||
|
|
||||||
|
#define CS_DEBUGGED 0x10000000
|
||||||
|
extern int csops(
|
||||||
|
pid_t pid,
|
||||||
|
unsigned int ops,
|
||||||
|
void *useraddr,
|
||||||
|
size_t usersize
|
||||||
|
);
|
||||||
|
|
||||||
|
extern BOOL getEntitlementValue(NSString *key);
|
||||||
|
extern BOOL isJITEnabled(void);
|
||||||
|
|
||||||
|
#define DLOG(format, ...) ShowAlert(@"DEBUG", [NSString stringWithFormat:@"\n %s [Line %d] \n %@", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:format, ##__VA_ARGS__]])
|
||||||
|
void ShowAlert(NSString* title, NSString* message, _Bool* showok);
|
91
src/MeloNX/MeloNX/Core/DetectJIT/utils.m
Normal file
91
src/MeloNX/MeloNX/Core/DetectJIT/utils.m
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#import "utils.h"
|
||||||
|
|
||||||
|
typedef struct __SecTask * SecTaskRef;
|
||||||
|
extern CFTypeRef SecTaskCopyValueForEntitlement(
|
||||||
|
SecTaskRef task,
|
||||||
|
NSString* entitlement,
|
||||||
|
CFErrorRef _Nullable *error
|
||||||
|
)
|
||||||
|
__attribute__((weak_import));
|
||||||
|
|
||||||
|
extern SecTaskRef SecTaskCreateFromSelf(CFAllocatorRef allocator)
|
||||||
|
__attribute__((weak_import));
|
||||||
|
|
||||||
|
BOOL getEntitlementValue(NSString *key)
|
||||||
|
{
|
||||||
|
if (SecTaskCreateFromSelf == NULL || SecTaskCopyValueForEntitlement == NULL)
|
||||||
|
return NO;
|
||||||
|
SecTaskRef sec_task = SecTaskCreateFromSelf(NULL);
|
||||||
|
if(!sec_task) return NO;
|
||||||
|
CFTypeRef value = SecTaskCopyValueForEntitlement(sec_task, key, nil);
|
||||||
|
if (value != nil)
|
||||||
|
{
|
||||||
|
CFRelease(value);
|
||||||
|
}
|
||||||
|
CFRelease(sec_task);
|
||||||
|
return value != nil && [(__bridge id)value boolValue];
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL isJITEnabled(void)
|
||||||
|
{
|
||||||
|
if (getEntitlementValue(@"dynamic-codesigning"))
|
||||||
|
{
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags;
|
||||||
|
csops(getpid(), 0, &flags, sizeof(flags));
|
||||||
|
return (flags & CS_DEBUGGED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowAlert(NSString* title, NSString* message, _Bool* showok)
|
||||||
|
{
|
||||||
|
DISPATCH_ASYNC_START
|
||||||
|
UIWindow* mainWindow = [[UIApplication sharedApplication] windows].lastObject;
|
||||||
|
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title
|
||||||
|
message:message
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
if (showok) {
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"ok!"
|
||||||
|
style:UIAlertActionStyleDefault
|
||||||
|
handler:nil]];
|
||||||
|
}
|
||||||
|
[mainWindow.rootViewController presentViewController:alert
|
||||||
|
animated:true
|
||||||
|
completion:nil];
|
||||||
|
DISPATCH_ASYNC_CLOSE
|
||||||
|
}
|
||||||
|
|
||||||
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
|
__attribute__((constructor)) static void entry(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (isJITEnabled()) {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setBool:YES forKey:@"JIT"];
|
||||||
|
[defaults synchronize]; // Ensure the value is saved immediately
|
||||||
|
} else {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setBool:NO forKey:@"JIT"];
|
||||||
|
[defaults synchronize]; // Ensure the value is saved immediately
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getEntitlementValue(@"com.apple.developer.kernel.increased-memory-limit")) {
|
||||||
|
NSLog(@"Entitlement Does Exist");
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setBool:YES forKey:@"increased-memory-limit"];
|
||||||
|
[defaults synchronize]; // Ensure the value is saved immediately
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getEntitlementValue(@"com.apple.developer.kernel.increased-debugging-memory-limit")) {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setBool:YES forKey:@"increased-debugging-memory-limit"];
|
||||||
|
[defaults synchronize]; // Ensure the value is saved immediately
|
||||||
|
}
|
||||||
|
if (getEntitlementValue(@"com.apple.developer.kernel.extended-virtual-addressing")) {
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
||||||
|
[defaults setBool:YES forKey:@"extended-virtual-addressing"];
|
||||||
|
[defaults synchronize]; // Ensure the value is saved immediately
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
|
||||||
class MTLHud {
|
class MTLHud {
|
||||||
|
|
||||||
var canMetalHud: Bool {
|
var canMetalHud: Bool {
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
import SDL2
|
import SDL2
|
||||||
import GameController
|
import GameController
|
||||||
|
import Darwin
|
||||||
|
import UIKit
|
||||||
|
|
||||||
struct MoltenVKSettings: Codable, Hashable {
|
struct MoltenVKSettings: Codable, Hashable {
|
||||||
let string: String
|
let string: String
|
||||||
@ -26,19 +28,24 @@ struct ContentView: View {
|
|||||||
@State private var settings: [MoltenVKSettings]
|
@State private var settings: [MoltenVKSettings]
|
||||||
@State private var isVirtualControllerActive: Bool = false
|
@State private var isVirtualControllerActive: Bool = false
|
||||||
@State var onscreencontroller: Controller = Controller(id: "", name: "")
|
@State var onscreencontroller: Controller = Controller(id: "", name: "")
|
||||||
|
@AppStorage("JIT") var isJITEnabled: Bool = false
|
||||||
|
@AppStorage("ignoreJIT") var ignoreJIT: Bool = false
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
init() {
|
init() {
|
||||||
let defaultConfig = Ryujinx.Configuration(gamepath: "")
|
let defaultConfig = loadSettings() ?? Ryujinx.Configuration(gamepath: "")
|
||||||
_config = State(initialValue: defaultConfig)
|
_config = State(initialValue: defaultConfig)
|
||||||
|
|
||||||
let defaultSettings: [MoltenVKSettings] = [
|
let defaultSettings: [MoltenVKSettings] = [
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE", value: "1024"),
|
MoltenVKSettings(string: "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE", value: "2048"),
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", value: "1"),
|
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_ARGUMENT_BUFFERS", value: "1"),
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_RESUME_LOST_DEVICE", value: "1")
|
MoltenVKSettings(string: "MVK_CONFIG_RESUME_LOST_DEVICE", value: "1")
|
||||||
]
|
]
|
||||||
|
|
||||||
_settings = State(initialValue: defaultSettings)
|
_settings = State(initialValue: defaultSettings)
|
||||||
|
|
||||||
|
print("JIT Enabled: \(isJITEnabled)")
|
||||||
|
|
||||||
initializeSDL()
|
initializeSDL()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,12 +98,18 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Controller") {
|
|
||||||
|
Section {
|
||||||
Button("Refresh", action: refreshControllersList)
|
Button("Refresh", action: refreshControllersList)
|
||||||
Divider()
|
|
||||||
ForEach(controllersList, id: \.self) { controller in
|
ForEach(controllersList, id: \.self) { controller in
|
||||||
controllerRow(for: controller)
|
controllerRow(for: controller)
|
||||||
}
|
}
|
||||||
|
} header: {
|
||||||
|
Text("Controllers")
|
||||||
|
} footer: {
|
||||||
|
Text("If no controllers are selected, the keyboard will be used.")
|
||||||
|
.font(.footnote)
|
||||||
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -148,40 +161,57 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func setupEmulation() {
|
private func setupEmulation() {
|
||||||
virtualController?.disconnect()
|
if !isJITEnabled {
|
||||||
|
virtualController?.disconnect()
|
||||||
|
|
||||||
guard let game = game else { return }
|
|
||||||
|
|
||||||
if controllersList.first(where: { $0 == onscreencontroller}) != nil {
|
|
||||||
controllerCallback = {
|
controllerCallback = {
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
controllersList = Ryujinx.shared.getConnectedControllers()
|
controllersList = Ryujinx.shared.getConnectedControllers()
|
||||||
|
|
||||||
print(currentControllers)
|
print(currentControllers)
|
||||||
start(displayid: 1)
|
start(displayid: 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
showVirtualController()
|
showVirtualController()
|
||||||
} else {
|
} else {
|
||||||
DispatchQueue.main.async {
|
showAlert(title: "JIT Not Enabled", message: "JIT is Required for Emulation. Please use a JIT enabler to Enable JIT", showOk: true) { pressedok in
|
||||||
print(currentControllers)
|
if pressedok, !ignoreJIT {
|
||||||
start(displayid: 1)
|
game = nil
|
||||||
|
} else if pressedok, ignoreJIT {
|
||||||
|
virtualController?.disconnect()
|
||||||
|
controllerCallback = {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
controllersList = Ryujinx.shared.getConnectedControllers()
|
||||||
|
|
||||||
|
print(currentControllers)
|
||||||
|
start(displayid: 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
showVirtualController()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func refreshControllersList() {
|
private func refreshControllersList() {
|
||||||
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { _ in
|
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { _ in
|
||||||
DispatchQueue.main.async {
|
controllersList = Ryujinx.shared.getConnectedControllers()
|
||||||
controllersList = Ryujinx.shared.getConnectedControllers()
|
|
||||||
var controller = controllersList.first(where: { $0.name.hasPrefix("Apple")})
|
if let onscreen = controllersList.first(where: { $0.name.hasPrefix("Apple")}) {
|
||||||
self.onscreencontroller = (controller ?? Controller(id: "", name: ""))
|
self.onscreencontroller = onscreen
|
||||||
if controllersList.count > 2 {
|
}
|
||||||
let controller = controllersList[2]
|
|
||||||
currentControllers.append(controller)
|
controllersList.removeAll(where: { $0.id == "0"})
|
||||||
} else if let controller = controllersList.first(where: { $0.id == onscreencontroller.id }), !controllersList.isEmpty {
|
|
||||||
currentControllers.append(controller)
|
if controllersList.count > 2 {
|
||||||
}
|
let controller = controllersList[2]
|
||||||
|
currentControllers.append(controller)
|
||||||
|
} else if let controller = controllersList.first(where: { $0.id == onscreencontroller.id }), !controllersList.isEmpty {
|
||||||
|
currentControllers.append(controller)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -194,12 +224,37 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func showAlert(title: String, message: String, showOk: Bool, completion: @escaping (Bool) -> Void) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if let mainWindow = UIApplication.shared.windows.last {
|
||||||
|
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||||
|
|
||||||
|
if showOk {
|
||||||
|
let okAction = UIAlertAction(title: "OK", style: .default) { _ in
|
||||||
|
completion(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
alert.addAction(okAction)
|
||||||
|
} else {
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.rootViewController?.present(alert, animated: true, completion: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private func start(displayid: UInt32) {
|
private func start(displayid: UInt32) {
|
||||||
guard let game else { return }
|
guard let game else { return }
|
||||||
|
|
||||||
config.gamepath = game.path
|
config.gamepath = game.path
|
||||||
config.inputids = currentControllers.map(\.id)
|
config.inputids = Array(Set(currentControllers.map(\.id)))
|
||||||
|
|
||||||
|
if config.inputids.isEmpty {
|
||||||
|
config.inputids.append("0")
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
try Ryujinx.shared.start(with: config)
|
try Ryujinx.shared.start(with: config)
|
||||||
@ -207,12 +262,9 @@ struct ContentView: View {
|
|||||||
print("Error: \(error.localizedDescription)")
|
print("Error: \(error.localizedDescription)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private func setMoltenVKSettings() {
|
private func setMoltenVKSettings() {
|
||||||
if let configs = loadSettings() {
|
|
||||||
self.config = configs
|
|
||||||
}
|
|
||||||
|
|
||||||
settings.forEach { setting in
|
settings.forEach { setting in
|
||||||
setenv(setting.string, setting.value, 1)
|
setenv(setting.string, setting.value, 1)
|
||||||
@ -234,3 +286,4 @@ func loadSettings() -> Ryujinx.Configuration? {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ import SwiftUI
|
|||||||
struct SettingsView: View {
|
struct SettingsView: View {
|
||||||
@Binding var config: Ryujinx.Configuration
|
@Binding var config: Ryujinx.Configuration
|
||||||
@Binding var MoltenVKSettings: [MoltenVKSettings]
|
@Binding var MoltenVKSettings: [MoltenVKSettings]
|
||||||
|
@AppStorage("ignoreJIT") var ignoreJIT: Bool = false
|
||||||
|
|
||||||
var memoryManagerModes = [
|
var memoryManagerModes = [
|
||||||
("HostMapped", "Host (fast)"),
|
("HostMapped", "Host (fast)"),
|
||||||
@ -31,6 +32,7 @@ struct SettingsView: View {
|
|||||||
Toggle("Enable Texture Recompression", isOn: $config.enableTextureRecompression)
|
Toggle("Enable Texture Recompression", isOn: $config.enableTextureRecompression)
|
||||||
Toggle("Disable Docked Mode", isOn: $config.disableDockedMode)
|
Toggle("Disable Docked Mode", isOn: $config.disableDockedMode)
|
||||||
Resolution(value: $config.resscale)
|
Resolution(value: $config.resscale)
|
||||||
|
|
||||||
Toggle("Enable Metal HUD", isOn: $metalHUDEnabled)
|
Toggle("Enable Metal HUD", isOn: $metalHUDEnabled)
|
||||||
.onChange(of: metalHUDEnabled) { newValue in
|
.onChange(of: metalHUDEnabled) { newValue in
|
||||||
if newValue {
|
if newValue {
|
||||||
@ -70,7 +72,7 @@ struct SettingsView: View {
|
|||||||
//TextField("Game Path", text: $config.gamepath)
|
//TextField("Game Path", text: $config.gamepath)
|
||||||
|
|
||||||
Text("PageSize \(String(Int(getpagesize())))")
|
Text("PageSize \(String(Int(getpagesize())))")
|
||||||
|
Toggle("Ignore JIT Enabeld Popup", isOn: $ignoreJIT)
|
||||||
TextField("Additional Arguments", text: Binding(
|
TextField("Additional Arguments", text: Binding(
|
||||||
get: {
|
get: {
|
||||||
config.additionalArgs.joined(separator: ", ")
|
config.additionalArgs.joined(separator: ", ")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user