diff --git a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj
index b699782b8..f95210535 100644
--- a/src/MeloNX/MeloNX.xcodeproj/project.pbxproj
+++ b/src/MeloNX/MeloNX.xcodeproj/project.pbxproj
@@ -632,6 +632,8 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
);
GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES;
@@ -671,6 +673,10 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
);
MARKETING_VERSION = 0.0.8;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
@@ -705,6 +711,8 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
);
GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES;
@@ -744,6 +752,10 @@
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
+ "$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
);
MARKETING_VERSION = 0.0.8;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
diff --git a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate
index d302e4ee7..506c634a1 100644
Binary files a/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist b/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist
index 62375ba69..8ff6cf524 100644
--- a/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/src/MeloNX/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,12 +12,12 @@
Ryujinx.xcscheme_^#shared#^_
orderHint
- 1
+ 2
com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_
orderHint
- 2
+ 1
SuppressBuildableAutocreation
diff --git a/src/MeloNX/MeloNX/App/Core/Headers/Ryujinx-Header.h b/src/MeloNX/MeloNX/App/Core/Headers/Ryujinx-Header.h
index 6e601c023..f106a9b5e 100644
--- a/src/MeloNX/MeloNX/App/Core/Headers/Ryujinx-Header.h
+++ b/src/MeloNX/MeloNX/App/Core/Headers/Ryujinx-Header.h
@@ -5,6 +5,8 @@
// Created by Stossy11 on 3/11/2024.
//
+#define DRM 1
+
#ifndef RyujinxHeader
#define RyujinxHeader
@@ -13,6 +15,7 @@
#include
#import "utils.h"
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/MeloNX/MeloNX/App/Core/Ryujinx/Controller/VirtualController.swift b/src/MeloNX/MeloNX/App/Core/Ryujinx/Controller/VirtualController.swift
index 11415e6d0..e35e6f603 100644
--- a/src/MeloNX/MeloNX/App/Core/Ryujinx/Controller/VirtualController.swift
+++ b/src/MeloNX/MeloNX/App/Core/Ryujinx/Controller/VirtualController.swift
@@ -20,12 +20,10 @@ class VirtualController {
}
private func setupVirtualController() {
- // Initialize SDL if not already initialized
if SDL_WasInit(Uint32(SDL_INIT_GAMECONTROLLER)) == 0 {
SDL_InitSubSystem(Uint32(SDL_INIT_GAMECONTROLLER))
}
- // Create virtual controller
var joystickDesc = SDL_VirtualJoystickDesc(
version: UInt16(SDL_VIRTUAL_JOYSTICK_DESC_VERSION),
type: Uint16(SDL_JOYSTICK_TYPE_GAMECONTROLLER.rawValue),
diff --git a/src/MeloNX/MeloNX/App/Core/Ryujinx/Display/UIView/Screenshot.swift b/src/MeloNX/MeloNX/App/Core/Ryujinx/Display/UIView/Screenshot.swift
new file mode 100644
index 000000000..a8387d67b
--- /dev/null
+++ b/src/MeloNX/MeloNX/App/Core/Ryujinx/Display/UIView/Screenshot.swift
@@ -0,0 +1,18 @@
+//
+// Screenshot.swift
+// MeloNX
+//
+// Created by Stossy11 on 09/02/2025.
+//
+
+import UIKit
+
+extension UIView {
+ func screenshot() -> UIImage? {
+ UIGraphicsBeginImageContextWithOptions(self.bounds.size, false, 0)
+ defer { UIGraphicsEndImageContext() }
+
+ self.drawHierarchy(in: self.bounds, afterScreenUpdates: true)
+ return UIGraphicsGetImageFromCurrentImageContext()
+ }
+}
diff --git a/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift b/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift
index 2c78f9708..a4911b829 100644
--- a/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift
+++ b/src/MeloNX/MeloNX/App/Core/Ryujinx/Ryujinx.swift
@@ -87,7 +87,7 @@ class Ryujinx {
var macroHLE: Bool
var ignoreMissingServices: Bool
var expandRam: Bool
-
+ var dfsIntegrityChecks: Bool
init(gamepath: String,
@@ -108,7 +108,8 @@ class Ryujinx {
macroHLE: Bool = false,
ignoreMissingServices: Bool = false,
hypervisor: Bool = false,
- expandRam: Bool = false
+ expandRam: Bool = false,
+ dfsIntegrityChecks: Bool = false
) {
self.gamepath = gamepath
self.inputids = inputids
@@ -129,6 +130,7 @@ class Ryujinx {
self.expandRam = expandRam
self.ignoreMissingServices = ignoreMissingServices
self.hypervisor = hypervisor
+ self.dfsIntegrityChecks = dfsIntegrityChecks
}
}
@@ -232,13 +234,17 @@ class Ryujinx {
args.append("--use-hypervisor")
}
+ if config.dfsIntegrityChecks {
+ args.append("--disable-fs-integrity-checks")
+ }
+
if config.resscale != 1.0 {
args.append(contentsOf: ["--resolution-scale", String(config.resscale)])
}
if config.expandRam {
- args.append(contentsOf: ["--expand-ram", String(config.maxAnisotropy)])
+ args.append(contentsOf: ["--expand-ram", String(config.expandRam)])
}
if config.ignoreMissingServices {
diff --git a/src/MeloNX/MeloNX/App/Views/ContentView.swift b/src/MeloNX/MeloNX/App/Views/ContentView.swift
index 31c8f3e6c..3e9ba4f5d 100644
--- a/src/MeloNX/MeloNX/App/Views/ContentView.swift
+++ b/src/MeloNX/MeloNX/App/Views/ContentView.swift
@@ -59,8 +59,12 @@ struct ContentView: View {
// MoltenVKSettings(string: "MVK_CONFIG_SYNCHRONOUS_QUEUE_SUBMITS", value: "1"),
// MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "2"),
// Metal Private API isn't needed and causes more stutters
- MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "0"),
- MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "0"),
+ MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"),
+ MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"),
+ MoltenVKSettings(string: "MVK_DEBUG", value: "1"),
+ MoltenVKSettings(string: "MVK_CONFIG_LOG_LEVEL", value: "2"),
+ // MVK_CONFIG_LOG_LEVEL
+ //MVK_DEBUG
// Uses more ram but makes performance higher, may add an option in settings to change or enable / disable this value (default 64 or 192 depending on what i decide)
MoltenVKSettings(string: "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE", value: "1024"),
]
@@ -76,21 +80,29 @@ struct ContentView: View {
var body: some View {
if game != nil, quits == false {
if isLoading {
- emulationView
- .onAppear() {
- // This is fro the old exiting game feature that didn't work properly. will look into it and figure out a better alternative
- /*
- Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
- timer.invalidate()
- quits = quit
-
- if quits {
- quit = false
- timer.invalidate()
- }
+ if Air.shared.connected {
+ Text("")
+ .onAppear() {
+ Air.play(AnyView(emulationView))
}
- */
- }
+ } else {
+
+ emulationView
+ .onAppear() {
+ // This is fro the old exiting game feature that didn't work properly. will look into it and figure out a better alternative
+ /*
+ Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
+ timer.invalidate()
+ quits = quit
+
+ if quits {
+ quit = false
+ timer.invalidate()
+ }
+ }
+ */
+ }
+ }
} else {
// This is when the game starts to stop the animation
EmulationView()
@@ -187,7 +199,7 @@ struct ContentView: View {
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
- if Ryujinx.shared.metalLayer != nil {
+ if get_current_fps() != 0 {
withAnimation {
isLoading = false
}
diff --git a/src/MeloNX/MeloNX/App/Views/Emulation/EmulationView/EmulationView.swift b/src/MeloNX/MeloNX/App/Views/Emulation/EmulationView/EmulationView.swift
index 108cf698e..f9f2a3d8a 100644
--- a/src/MeloNX/MeloNX/App/Views/Emulation/EmulationView/EmulationView.swift
+++ b/src/MeloNX/MeloNX/App/Views/Emulation/EmulationView/EmulationView.swift
@@ -10,6 +10,7 @@ import SwiftUI
// Emulation View
struct EmulationView: View {
@AppStorage("isVirtualController") var isVCA: Bool = true
+ @AppStorage("showScreenShotButton") var ssb: Bool = false
@State var isAirplaying = Air.shared.connected
var body: some View {
ZStack {
@@ -29,6 +30,30 @@ struct EmulationView: View {
if isVCA {
ControllerView() // Virtual Controller
}
+
+ if ssb {
+ Group {
+ VStack {
+ Spacer()
+
+ HStack {
+
+ Button {
+ if let screenshot = Ryujinx.shared.emulationUIView.screenshot() {
+ UIImageWriteToSavedPhotosAlbum(screenshot, nil, nil, nil)
+ }
+ } label: {
+ Image(systemName: "square.and.arrow.up")
+ }
+ .frame(width: UIDevice.current.systemName.contains("iPadOS") ? 60 * 1.2 : 45, height: UIDevice.current.systemName.contains("iPadOS") ? 60 * 1.2 : 45)
+ .padding()
+
+ Spacer()
+ }
+
+ }
+ }
+ }
}
.onAppear {
Air.shared.connectionCallbacks.append { cool in
diff --git a/src/MeloNX/MeloNX/App/Views/Logging/Logs.swift b/src/MeloNX/MeloNX/App/Views/Logging/Logs.swift
new file mode 100644
index 000000000..108e3b796
--- /dev/null
+++ b/src/MeloNX/MeloNX/App/Views/Logging/Logs.swift
@@ -0,0 +1,100 @@
+//
+// LogEntry.swift
+// MeloNX
+//
+// Created by Stossy11 on 09/02/2025.
+//
+
+
+import SwiftUI
+
+struct LogEntry: Identifiable, Equatable {
+ let id = UUID()
+ let text: String
+
+ static func == (lhs: LogEntry, rhs: LogEntry) -> Bool {
+ return lhs.id == rhs.id && lhs.text == rhs.text
+ }
+}
+
+struct LogViewer: View {
+ @State private var logs: [LogEntry] = []
+ @State private var latestLogFilePath: String?
+
+ var body: some View {
+ VStack {
+ Spacer()
+ VStack {
+ ForEach(logs) { log in
+ Text(log.text)
+ .padding(4)
+ .background(Color.black.opacity(0.7))
+ .foregroundColor(.white)
+ .cornerRadius(8)
+ .transition(.move(edge: .top).combined(with: .opacity))
+ .animation(.easeOut(duration: 2), value: logs)
+ }
+ }
+ .frame(maxWidth: .infinity)
+ .padding()
+ }
+ .edgesIgnoringSafeArea(.all)
+ .onAppear {
+ findNewestLogFile()
+ }
+ }
+
+ func findNewestLogFile() {
+ let logsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("logs")
+
+ guard let directory = logsDirectory else { return }
+
+ do {
+ let logFiles = try FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: [.contentModificationDateKey], options: .skipsHiddenFiles)
+
+ // Sort files by modification date (newest first)
+ let sortedFiles = logFiles.sorted {
+ (try? $0.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? Date.distantPast >
+ (try? $1.resourceValues(forKeys: [.contentModificationDateKey]).contentModificationDate) ?? Date.distantPast
+ }
+
+ if let newestLogFile = sortedFiles.first {
+ latestLogFilePath = newestLogFile.path
+ startReadingLogFile()
+ }
+ } catch {
+ print("Error reading log files: \(error)")
+ }
+ }
+
+ func startReadingLogFile() {
+ guard let path = latestLogFilePath else { return }
+ let fileHandle = try? FileHandle(forReadingAtPath: path)
+ fileHandle?.seekToEndOfFile()
+
+ NotificationCenter.default.addObserver(forName: .NSFileHandleDataAvailable, object: fileHandle, queue: .main) { _ in
+ if let data = fileHandle?.availableData, !data.isEmpty {
+ if let logLine = String(data: data, encoding: .utf8)?.trimmingCharacters(in: .whitespacesAndNewlines) {
+ DispatchQueue.main.async {
+ withAnimation {
+ logs.append(LogEntry(text: logLine))
+ }
+ // Remove old logs after a delay
+ DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
+ withAnimation {
+ removelogfirst()
+ }
+ }
+ }
+ }
+ }
+ fileHandle?.waitForDataInBackgroundAndNotify()
+ }
+
+ fileHandle?.waitForDataInBackgroundAndNotify()
+ }
+
+ func removelogfirst() {
+ logs.removeFirst()
+ }
+}
diff --git a/src/MeloNX/MeloNX/App/Views/SettingsView/SettingsView.swift b/src/MeloNX/MeloNX/App/Views/SettingsView/SettingsView.swift
index 153263bec..1e1985753 100644
--- a/src/MeloNX/MeloNX/App/Views/SettingsView/SettingsView.swift
+++ b/src/MeloNX/MeloNX/App/Views/SettingsView/SettingsView.swift
@@ -29,6 +29,8 @@ struct SettingsView: View {
@AppStorage("RyuDemoControls") var ryuDemo: Bool = false
@AppStorage("MTL_HUD_ENABLED") var metalHUDEnabled: Bool = false
+ @AppStorage("showScreenShotButton") var ssb: Bool = false
+
@AppStorage("MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS") var mVKPreFillBuffer: Bool = false
@AppStorage("performacehud") var performacehud: Bool = false
@@ -103,7 +105,7 @@ struct SettingsView: View {
}
}
- Slider(value: $config.resscale, in: 0.1...3.0, step: 0.1) {
+ Slider(value: $config.resscale, in: 0.1...3.0, step: 0.05) {
Text("Resolution Scale")
} minimumValueLabel: {
Text("0.1x")
@@ -347,6 +349,11 @@ struct SettingsView: View {
// Other Settings
Section {
+ Toggle(isOn: $ssb) {
+ labelWithIcon("Screenshot Button", iconName: "square.and.arrow.up")
+ }
+ .tint(.blue)
+
Toggle(isOn: $useTrollStore) {
labelWithIcon("TrollStore", iconName: "troll.svg")
}
@@ -361,13 +368,15 @@ struct SettingsView: View {
labelWithIcon("Trace Logs", iconName: "waveform.path")
}
.tint(.blue)
+
+
} header: {
Text("Miscellaneous Options")
.font(.title3.weight(.semibold))
.textCase(nil)
.headerProminence(.increased)
} footer: {
- Text("Enable logs for troubleshooting and Enable automatic TrollStore JIT.")
+ Text("Enable trace and debug logs for troubleshooting, enable Screenshotting without distractions and Enable automatic TrollStore JIT.")
}
// Advanced
diff --git a/src/MeloNX/MeloNX/Info.plist b/src/MeloNX/MeloNX/Info.plist
index 62088bbb0..d23c87fd9 100644
--- a/src/MeloNX/MeloNX/Info.plist
+++ b/src/MeloNX/MeloNX/Info.plist
@@ -3,7 +3,7 @@
MeloID
- 1d0e26921bac938456ee7210ff4f2fa701dc16c02de1760e0aa757db28818ec7
+ 83f67a0a96bd8628a150d7853e360db5bae64e7769524fae399c4b8e7e6aff17
UIFileSharingEnabled
UTExportedTypeDeclarations
diff --git a/src/MeloNX/MeloNX/MeloNXApp.swift b/src/MeloNX/MeloNX/MeloNXApp.swift
index ce720a05a..665bf9e4c 100644
--- a/src/MeloNX/MeloNX/MeloNXApp.swift
+++ b/src/MeloNX/MeloNX/MeloNXApp.swift
@@ -9,46 +9,81 @@ import SwiftUI
import UIKit
import CryptoKit
+
+
@main
struct MeloNXApp: App {
- @AppStorage("showeddrmcheck") var showed = true
+ @State var showed = false
- init() {
- DispatchQueue.main.async { [self] in
- // drmcheck()
- InitializeRyujinx() { bool in
- if bool {
- print("Ryujinx Files Initialized Successfully")
+
+ var body: some Scene {
+ WindowGroup {
+ ZStack {
+ if showed {
+ ContentView()
} else {
- // exit(0)
+ Group {
+ VStack {
+ Spacer()
+
+ HStack {
+ Text("Loading...")
+ ProgressView()
+ }
+ Spacer()
+
+ Text(UIDevice.current.identifierForVendor?.uuidString ?? "")
+ }
+ }
+ .onAppear {
+ initR()
+ }
+ .frame(maxWidth: .infinity, maxHeight: .infinity)
+ .background(Color.black.opacity(1))
+ .foregroundColor(.white)
+ }
+ }
+ }
+ }
+
+ func initR() {
+ if DRM == 1 {
+ DispatchQueue.main.async { [self] in
+ // drmcheck()
+ InitializeRyujinx() { bool in
+ if bool {
+ print("Ryujinx Files Initialized Successfully")
+ DispatchQueue.main.async { [self] in
+ withAnimation {
+ showed = true
+ }
+
+ Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
+ InitializeRyujinx() { bool in
+ if !bool {
+ withAnimation {
+ showed = false
+ }
+ showDMCAAlert()
+ }
+ }
+ }
+
+ }
+
+ } else {
+ showDMCAAlert()
+ }
+
}
}
- Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
- InitializeRyujinx() { bool in
- if !bool {
- // exit(0)
- }
-
- }
- }
- }
- }
-
- var body: some Scene {
- WindowGroup {
- if showed {
- ContentView()
- } else {
- HStack {
- Text("Loading...")
- ProgressView()
- }
- }
}
+
}
+
func showAlert() {
// Create the alert controller
@@ -87,8 +122,21 @@ struct MeloNXApp: App {
exit(0)
}
}
+
+
}
+func showDMCAAlert() {
+ DispatchQueue.main.async {
+ if let mainWindow = UIApplication.shared.windows.last {
+ let alertController = UIAlertController(title: "Unauthorized Copy Notice", message: "This app was illegally leaked. Please report the download on the MeloNX Discord. In the meantime, check out Pomelo! \n -Stossy11", preferredStyle: .alert)
+
+ mainWindow.rootViewController!.present(alertController, animated: true, completion: nil)
+ } else {
+ exit(0)
+ }
+ }
+}
/*
func drmcheck(completion: @escaping (Bool) -> Void) {
@@ -132,22 +180,47 @@ func drmcheck(completion: @escaping (Bool) -> Void) {
*/
func InitializeRyujinx(completion: @escaping (Bool) -> Void) {
- let path = "aHR0cHM6Ly9zdG9zc3kxMS5jb20vd293LnR4dA=="
+ let path = "aHR0cHM6Ly9teC5zdG9zc3kxMS5jb20v"
guard let value = Bundle.main.object(forInfoDictionaryKey: "MeloID") as? String, !value.isEmpty else {
- exit(0)
+ completion(false)
+ return
}
if (detectRoms(path: path) != value) {
- exit(0)
+ completion(false)
}
- let task = URLSession.shared.dataTask(with: URL(string: addFolders(path)!)!) { data, response, error in
- let text = String(data: data ?? Data(), encoding: .utf8) ?? ""
- print(text)
- completion(text.contains("true"))
+ let configuration = URLSessionConfiguration.default
+ configuration.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData
+ configuration.urlCache = nil
+
+ let session = URLSession(configuration: configuration)
+
+ guard let url = URL(string: addFolders(path)!) else {
+ completion(false)
+ return
+ }
+
+ let task = session.dataTask(with: url) { data, response, error in
+ if error != nil {
+ completion(false)
+ }
+
+
+ guard let httpResponse = response as? HTTPURLResponse else {
+ completion(false)
+ return
+ }
+
+ if httpResponse.statusCode == 200 {
+ completion(true)
+ } else {
+ completion(false)
+ }
+ return
}
task.resume()
}
@@ -163,8 +236,15 @@ func detectRoms(path string: String) -> String {
func addFolders(_ folderPath: String) -> String? {
let fileManager = FileManager.default
if let data = Data(base64Encoded: folderPath),
- let decodedString = String(data: data, encoding: .utf8) {
- return decodedString
+ let decodedString = String(data: data, encoding: .utf8), let fileURL = UIDevice.current.identifierForVendor?.uuidString {
+ return decodedString + "auth/" + fileURL + "/"
}
return nil
}
+
+extension String {
+
+ func print() {
+ Swift.print(self)
+ }
+}
diff --git a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs
index aab25899f..e9963d45a 100644
--- a/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs
+++ b/src/Ryujinx.Graphics.Vulkan/MoltenVK/MVKInitialization.cs
@@ -26,6 +26,8 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
if (OperatingSystem.IsIOSVersionAtLeast(17)) {
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE;
}
+
+ config.MaxActiveMetalCommandBuffersPerQueue = 1024;
config.SynchronousQueueSubmits = false;
diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs
index 2df4889c6..2a39ad810 100644
--- a/src/Ryujinx.Headless.SDL2/WindowBase.cs
+++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs
@@ -450,23 +450,12 @@ namespace Ryujinx.Headless.SDL2
};
renderLoopThread.Start();
- Thread nvidiaStutterWorkaround = null;
- if (Renderer is OpenGLRenderer)
- {
- nvidiaStutterWorkaround = new Thread(NvidiaStutterWorkaround)
- {
- Name = "GUI.NvidiaStutterWorkaround",
- };
- nvidiaStutterWorkaround.Start();
- }
-
MainLoop();
// NOTE: The render loop is allowed to stay alive until the renderer itself is disposed, as it may handle resource dispose.
// We only need to wait for all commands submitted during the main gpu loop to be processed.
_gpuDoneEvent.WaitOne();
_gpuDoneEvent.Dispose();
- nvidiaStutterWorkaround?.Join();
Exit();
}