diff --git a/MeloNX-XC/MeloNX.xcodeproj/project.pbxproj b/MeloNX-XC/MeloNX.xcodeproj/project.pbxproj index d7dd6b1d9..0c8f10931 100644 --- a/MeloNX-XC/MeloNX.xcodeproj/project.pbxproj +++ b/MeloNX-XC/MeloNX.xcodeproj/project.pbxproj @@ -389,11 +389,14 @@ "$(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 = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/Header/MeloNX-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; @@ -437,11 +440,14 @@ "$(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 = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OBJC_BRIDGING_HEADER = "MeloNX/Header/MeloNX-Bridging-Header.h"; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; diff --git a/MeloNX-XC/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate b/MeloNX-XC/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate index f55522fbb..f16549702 100644 Binary files a/MeloNX-XC/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate and b/MeloNX-XC/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/MeloNX-XC/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/MeloNX-XC/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index a2c154405..561e47f20 100644 --- a/MeloNX-XC/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/MeloNX-XC/MeloNX.xcodeproj/xcuserdata/stossy11.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -15,8 +15,8 @@ filePath = "MeloNX/Core/Ryujinx.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "117" - endingLineNumber = "117" + startingLineNumber = "111" + endingLineNumber = "111" landmarkName = "startWithRunLoop(config:)" landmarkType = "7"> @@ -40,8 +40,8 @@ filePath = "MeloNX/Core/Ryujinx.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "126" - endingLineNumber = "126" + startingLineNumber = "120" + endingLineNumber = "120" landmarkName = "startWithRunLoop(config:)" landmarkType = "7"> diff --git a/MeloNX-XC/MeloNX/ContentView.swift b/MeloNX-XC/MeloNX/ContentView.swift index 6186367f2..9c43d5d5c 100644 --- a/MeloNX-XC/MeloNX/ContentView.swift +++ b/MeloNX-XC/MeloNX/ContentView.swift @@ -22,7 +22,22 @@ struct ContentView: View { var body: some View { ZStack { - + if let gameUrl, emulationStarted { + VulkanSDLViewRepresentable { displayid in + gameUrl.startAccessingSecurityScopedResource() + + let config = RyujinxEmulator.Configuration( + inputPath: gameUrl.path, + mainThread: mainThread, + graphicsBackend: "Vulkan", + additionalArgs: ["--display-id", String(displayid)] + ) + + + + showVirtualController(url: gameUrl, ryuconfig: config) + } + } VStack { Text("NX iOS") @@ -50,15 +65,6 @@ struct ContentView: View { if let gameUrl { Button { emulationStarted = true - gameUrl.startAccessingSecurityScopedResource() - - let config = RyujinxEmulator.Configuration( - inputPath: gameUrl.path, - mainThread: mainThread, - graphicsBackend: "Vulkan" - ) - - showVirtualController(url: gameUrl, ryuconfig: config) } label: { Text("Go!") } @@ -86,9 +92,6 @@ func startEmulation(game: URL, config: RyujinxEmulator.Configuration) { let config = config // patchMakeKeyAndVisible() - SDL_SetMainReady() - SDL_iPhoneSetEventPump(SDL_TRUE) - print(SDL_Init(SDL_INIT_VIDEO)) let window = SDL_CreateWindow("Ryujinx", Int32(SDL_WINDOWPOS_CENTERED_MASK), Int32(SDL_WINDOWPOS_CENTERED_MASK), 640, 480, SDL_WINDOW_SHOWN.rawValue | SDL_WINDOW_ALLOW_HIGHDPI.rawValue) if window == nil { diff --git a/MeloNX-XC/MeloNX/Core/Ryujinx.h b/MeloNX-XC/MeloNX/Core/Ryujinx.h new file mode 100644 index 000000000..0e61470de --- /dev/null +++ b/MeloNX-XC/MeloNX/Core/Ryujinx.h @@ -0,0 +1,22 @@ +// +// Ryujinx.h +// MeloNX +// +// Created by Stossy11 on 1/11/2024. +// + +#ifndef RyujinxSDL_h +#define RyujinxSDL_h + +#ifdef __cplusplus +extern "C" { +#endif + +// Declare the main_ryujinx_sdl function, matching the signature +int main_ryujinx_sdl(int argc, char **argv); + +#ifdef __cplusplus +} +#endif + +#endif /* RyujinxSDL_h */ diff --git a/MeloNX-XC/MeloNX/Core/Ryujinx.swift b/MeloNX-XC/MeloNX/Core/Ryujinx.swift index 343dac026..0380bf2bd 100644 --- a/MeloNX-XC/MeloNX/Core/Ryujinx.swift +++ b/MeloNX-XC/MeloNX/Core/Ryujinx.swift @@ -8,12 +8,6 @@ import Foundation import SwiftUI -// Create a bridging header for the C function -private let ryujinxMain: @convention(c) (Int32, UnsafeMutablePointer?>) -> Int32 = { - let sym = dlsym(dlopen("Ryujinx.Headless.SDL2.dylib", RTLD_NOW), "main_ryujinx_sdl") - return unsafeBitCast(sym, to: (@convention(c) (Int32, UnsafeMutablePointer?>) -> Int32).self) -}() - enum RyujinxError: Error { case libraryLoadError case executionError(code: Int32) @@ -89,7 +83,7 @@ class RyujinxEmulator { var argvPtrs = cArgs - let result = ryujinxMain(Int32(args.count), &argvPtrs) + let result = main_ryujinx_sdl(Int32(args.count), &argvPtrs) if result != 0 { throw RyujinxError.executionError(code: result) diff --git a/MeloNX-XC/MeloNX/Header/MeloNX-Bridging-Header.h b/MeloNX-XC/MeloNX/Header/MeloNX-Bridging-Header.h new file mode 100644 index 000000000..b6dd78a41 --- /dev/null +++ b/MeloNX-XC/MeloNX/Header/MeloNX-Bridging-Header.h @@ -0,0 +1,8 @@ +// +// MeloNX-Bridging-Header.h +// MeloNX +// +// Created by Stossy11 on 1/11/2024. +// + +#import "../Core/Ryujinx.h" diff --git a/MeloNX-XC/MeloNX/MetalVIew.swift b/MeloNX-XC/MeloNX/MetalVIew.swift index 99603bf91..2402090f5 100644 --- a/MeloNX-XC/MeloNX/MetalVIew.swift +++ b/MeloNX-XC/MeloNX/MetalVIew.swift @@ -8,6 +8,90 @@ import SwiftUI import Metal import MetalKit +import UIKit +import SDL2 + + + +struct VulkanSDLViewRepresentable: UIViewRepresentable { + + let configure: (Uint32) -> Void + func makeUIView(context: Context) -> VulkanSDLView { + let view = VulkanSDLView(frame: .zero) + configure(SDL_GetWindowID(view.sdlWindow)) + return view + } + + func updateUIView(_ uiView: VulkanSDLView, context: Context) { + // Handle any updates if needed + } +} + +class VulkanSDLView: UIView { + var sdlWindow: OpaquePointer? + var metalView: UnsafeMutableRawPointer? + + override init(frame: CGRect) { + super.init(frame: frame) + initializeSDL() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + initializeSDL() + } + + private func initializeSDL() { + + SDL_SetMainReady() + SDL_iPhoneSetEventPump(SDL_TRUE) + // print(SDL_Init(SDL_INIT_VIDEO)) + // Initialize SDL with video support + if SDL_Init(SDL_INIT_VIDEO) < 0 { + print("Unable to initialize SDL: \(String(cString: SDL_GetError()))") + return + } + + // Create an SDL window with Metal support + sdlWindow = SDL_CreateWindow( + "Ryujinx", + Int32(SDL_WINDOWPOS_CENTERED_MASK), + Int32(SDL_WINDOWPOS_CENTERED_MASK), + Int32(frame.width), + Int32(frame.height), + SDL_WINDOW_SHOWN.rawValue | SDL_WINDOW_ALLOW_HIGHDPI.rawValue | SDL_WINDOW_METAL.rawValue + ) + + guard sdlWindow != nil else { + print("Error creating SDL window: \(String(cString: SDL_GetError()))") + return + } + + // Create SDL Metal view and attach to this UIView + metalView = SDL_Metal_CreateView(sdlWindow) + if metalView == nil { + print("Failed to create SDL Metal view.") + return + } + + if let metalLayerPointer = SDL_Metal_GetLayer(metalView) { + let metalLayer = Unmanaged.fromOpaque(metalLayerPointer).takeUnretainedValue() + metalLayer.device = MTLCreateSystemDefaultDevice() + metalLayer.pixelFormat = .bgra8Unorm + layer.addSublayer(metalLayer) + } + } + + deinit { + if let metalView = metalView { + SDL_Metal_DestroyView(metalView) + } + if let sdlWindow = sdlWindow { + SDL_DestroyWindow(sdlWindow) + } + SDL_Quit() + } +} struct MetalView: UIViewRepresentable { let device: MTLDevice? diff --git a/src/Ryujinx.Headless.SDL2/WindowBase.cs b/src/Ryujinx.Headless.SDL2/WindowBase.cs index 9facead38..4f0b76640 100644 --- a/src/Ryujinx.Headless.SDL2/WindowBase.cs +++ b/src/Ryujinx.Headless.SDL2/WindowBase.cs @@ -185,7 +185,8 @@ namespace Ryujinx.Headless.SDL2 FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP; } - WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags()); + WindowHandle = SDL_GetWindowFromID(1); + //SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags()); if (WindowHandle == IntPtr.Zero) {