1
0
forked from MeloNX/MeloNX

Put everything on the main thread for testing.

This commit is contained in:
stossy11 2024-11-02 12:37:08 +11:00
parent 60cfb86774
commit 02901a5a14
4 changed files with 93 additions and 52 deletions

View File

@ -41,6 +41,8 @@ struct ContentView: View {
ZStack { ZStack {
if let gameUrl, emulationStarted { if let gameUrl, emulationStarted {
VulkanSDLViewRepresentable { displayid in VulkanSDLViewRepresentable { displayid in
DispatchQueue.main.async {
gameUrl.startAccessingSecurityScopedResource() gameUrl.startAccessingSecurityScopedResource()
let config = RyujinxEmulator.Configuration( let config = RyujinxEmulator.Configuration(
@ -57,6 +59,7 @@ struct ContentView: View {
showVirtualController(url: gameUrl, ryuconfig: config) showVirtualController(url: gameUrl, ryuconfig: config)
} }
} }
}
VStack { VStack {
Text("NX iOS") Text("NX iOS")
@ -110,26 +113,31 @@ func startEmulation(game: URL, config: RyujinxEmulator.Configuration) {
let config = config let config = config
// patchMakeKeyAndVisible() patchMakeKeyAndVisible()
// SDL_Init(SDL_INIT_VIDEO) // SDL_Init(SDL_INIT_VIDEO)
DispatchQueue.main.async {
let emulator = RyujinxEmulator() let emulator = RyujinxEmulator()
do { do {
try emulator.startWithRunLoop(config: config) try emulator.startWithRunLoop(config: config)
} catch { } catch {
print(error) print(error)
} }
}
} }
func patchMakeKeyAndVisible() { func patchMakeKeyAndVisible() {
DispatchQueue.main.async {
let uiwindowClass = UIWindow.self let uiwindowClass = UIWindow.self
let m1 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.makeKeyAndVisible))! let m1 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.makeKeyAndVisible))!
let m2 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.wdb_makeKeyAndVisible))! let m2 = class_getInstanceMethod(uiwindowClass, #selector(UIWindow.wdb_makeKeyAndVisible))!
method_exchangeImplementations(m1, m2) method_exchangeImplementations(m1, m2)
}
} }
extension UIWindow { extension UIWindow {
@objc func wdb_makeKeyAndVisible() { @objc func wdb_makeKeyAndVisible() {
DispatchQueue.main.async {
print("Making window key and visible...") print("Making window key and visible...")
if #available(iOS 13.0, *) { if #available(iOS 13.0, *) {
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene) self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
@ -137,12 +145,15 @@ extension UIWindow {
self.wdb_makeKeyAndVisible() self.wdb_makeKeyAndVisible()
theWindow = self theWindow = self
} }
}
} }
@available(iOS 15.0, *) @available(iOS 15.0, *)
var g_gcVirtualController: GCVirtualController! var g_gcVirtualController: GCVirtualController!
@available(iOS 15.0, *) @available(iOS 15.0, *)
func showVirtualController(url: URL, ryuconfig: RyujinxEmulator.Configuration) { func showVirtualController(url: URL, ryuconfig: RyujinxEmulator.Configuration) {
DispatchQueue.main.async {
print("Showing virtual controller...") print("Showing virtual controller...")
let config = GCVirtualController.Configuration() let config = GCVirtualController.Configuration()
config.elements = [ config.elements = [
@ -151,8 +162,11 @@ func showVirtualController(url: URL, ryuconfig: RyujinxEmulator.Configuration) {
g_gcVirtualController = GCVirtualController(configuration: config) g_gcVirtualController = GCVirtualController(configuration: config)
g_gcVirtualController.connect { err in g_gcVirtualController.connect { err in
print("Controller connect: \(String(describing: err))") print("Controller connect: \(String(describing: err))")
DispatchQueue.main.async {
startEmulation(game: url, config: ryuconfig) startEmulation(game: url, config: ryuconfig)
} }
}
}
} }
@available(iOS 15.0, *) @available(iOS 15.0, *)

View File

@ -98,6 +98,16 @@ class RyujinxEmulator {
isRunning = true isRunning = true
DispatchQueue.main.async {
do {
try Self.start(with: config)
} catch {
Self.log("Emulation failed to start: \(error)")
self.isRunning = false
return
}
}
emulationThread = Thread { emulationThread = Thread {
let runLoop = RunLoop.current let runLoop = RunLoop.current
@ -105,6 +115,7 @@ class RyujinxEmulator {
runLoop.add(port, forMode: .default) runLoop.add(port, forMode: .default)
print(config.mainThread ? "Running on the main thread" : "Running on the background thread") print(config.mainThread ? "Running on the main thread" : "Running on the background thread")
/*
if config.mainThread { if config.mainThread {
DispatchQueue.main.async { DispatchQueue.main.async {
do { do {
@ -124,6 +135,8 @@ class RyujinxEmulator {
return return
} }
} }
*/
@ -138,7 +151,7 @@ class RyujinxEmulator {
emulationThread?.name = "RyujinxEmulationThread" emulationThread?.name = "RyujinxEmulationThread"
emulationThread?.qualityOfService = .userInteractive emulationThread?.qualityOfService = .userInteractive
emulationThread?.threadPriority = 0.9 emulationThread?.threadPriority = 0.9
emulationThread?.start() // emulationThread?.start()
} }
func quickStart(romPath: String) throws { func quickStart(romPath: String) throws {

View File

@ -18,8 +18,11 @@ struct VulkanSDLViewRepresentable: UIViewRepresentable {
let configure: (Uint32) -> Void let configure: (Uint32) -> Void
func makeUIView(context: Context) -> VulkanSDLView { func makeUIView(context: Context) -> VulkanSDLView {
let view = VulkanSDLView(frame: .zero) let view = VulkanSDLView(frame: .zero)
DispatchQueue.main.async { [self] in
configure(SDL_GetWindowID(view.sdlWindow)) configure(SDL_GetWindowID(view.sdlWindow))
}
return view return view
} }
func updateUIView(_ uiView: VulkanSDLView, context: Context) { func updateUIView(_ uiView: VulkanSDLView, context: Context) {
@ -33,14 +36,19 @@ class VulkanSDLView: UIView {
override init(frame: CGRect) { override init(frame: CGRect) {
super.init(frame: frame) super.init(frame: frame)
DispatchQueue.main.async { [self] in
initializeSDL() initializeSDL()
} }
}
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
DispatchQueue.main.async { [self] in
initializeSDL() initializeSDL()
} }
}
private func initializeSDL() { private func initializeSDL() {
// Initialize SDL with video support // Initialize SDL with video support
@ -58,26 +66,32 @@ class VulkanSDLView: UIView {
) )
} }
guard sdlWindow != nil else { guard sdlWindow != nil else {
print("Error creating SDL window: \(String(cString: SDL_GetError()))") print("Error creating SDL window: \(String(cString: SDL_GetError()))")
return return
} }
// Create SDL Metal view and attach to this UIView // Create SDL Metal view and attach to this UIView
DispatchQueue.main.async { [self] in
metalView = SDL_Metal_CreateView(sdlWindow) metalView = SDL_Metal_CreateView(sdlWindow)
if metalView == nil { if metalView == nil {
print("Failed to create SDL Metal view.") print("Failed to create SDL Metal view.")
return return
} }
}
if let metalLayerPointer = SDL_Metal_GetLayer(metalView) { if let metalLayerPointer = SDL_Metal_GetLayer(metalView) {
let metalLayer = Unmanaged<CAMetalLayer>.fromOpaque(metalLayerPointer).takeUnretainedValue() let metalLayer = Unmanaged<CAMetalLayer>.fromOpaque(metalLayerPointer).takeUnretainedValue()
metalLayer.device = MTLCreateSystemDefaultDevice() metalLayer.device = MTLCreateSystemDefaultDevice()
metalLayer.pixelFormat = .bgra8Unorm metalLayer.pixelFormat = .bgra8Unorm
DispatchQueue.main.async { [self] in
layer.addSublayer(metalLayer) layer.addSublayer(metalLayer)
} }
} }
}
deinit { deinit {
if let metalView = metalView { if let metalView = metalView {
SDL_Metal_DestroyView(metalView) SDL_Metal_DestroyView(metalView)