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(); }