This commit is contained in:
stossy11 2024-10-28 10:22:25 +11:00
parent ac3958a363
commit b41251e360
9 changed files with 289 additions and 50 deletions

View File

@ -347,6 +347,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -356,6 +357,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",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
@ -385,6 +388,7 @@
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -394,6 +398,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",
);
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "64A8AF27-6696-4D7A-8C62-06216A95ECF0"
type = "1"
version = "2.0">
</Bucket>

View File

@ -12,10 +12,16 @@ import GameController
var theWindow: UIWindow? = nil
struct ContentView: View {
@State var device: MTLDevice? = MTLCreateSystemDefaultDevice()
@State var gameUrl: URL?
@State var showFileImporter: Bool = false
@State var emulationStarted: Bool = false
var body: some View {
ZStack {
VStack {
Text("NX iOS")
Button {
showFileImporter.toggle()
} label: {
@ -23,15 +29,16 @@ struct ContentView: View {
}
if let gameUrl {
Button {
DispatchQueue.main.async {
emulationStarted = true
gameUrl.startAccessingSecurityScopedResource()
showVirtualController(url: gameUrl)
}
} label: {
Text("Go!")
}
.padding(8)
}
}
}
.padding()
.fileImporter(isPresented: $showFileImporter, allowedContentTypes: [.item]) { result in
switch result {
@ -55,11 +62,9 @@ func startEmulation(game: URL) {
enableKeyboard: false,
graphicsBackend: "Vulkan"
)
DispatchQueue.main.async {
patchMakeKeyAndVisible()
SDL_SetMainReady()
SDL_iPhoneSetEventPump(SDL_TRUE)
patchMakeKeyAndVisible()
}
let emulator = RyujinxEmulator()
do {
try emulator.startWithRunLoop(config: config)
@ -78,16 +83,12 @@ func patchMakeKeyAndVisible() {
extension UIWindow {
@objc func wdb_makeKeyAndVisible() {
print("Making window key and visible...")
if #available(iOS 13.0, *) {
self.windowScene = (UIApplication.shared.connectedScenes.first! as! UIWindowScene)
}
self.wdb_makeKeyAndVisible()
theWindow = self
if #available(iOS 15.0, *) {
reconnectVirtualController()
}
}
}
@available(iOS 15.0, *)
var g_gcVirtualController: GCVirtualController!

View File

@ -61,13 +61,14 @@ class RyujinxEmulator {
]
*/
args.append("ryujinx")
args.append(config.inputPath)
args.append("--graphics-backend")
args.append(config.graphicsBackend)
args.append(contentsOf: ["--memory-manager-mode", "SoftwarePageTable"])
// args.append(contentsOf: ["--fullscreen", "true"])
args.append(contentsOf: ["--enable-debug-logs", "true"])
args.append(contentsOf: ["--enable-trace-logs", "true"])
// args.append("--input-path")
args.append(config.inputPath)
args.append(contentsOf: config.additionalArgs)
@ -82,6 +83,7 @@ class RyujinxEmulator {
var argvPtrs = cArgs
let result = ryujinxMain(Int32(args.count), &argvPtrs)
if result != 0 {
@ -103,6 +105,7 @@ class RyujinxEmulator {
let port = Port()
runLoop.add(port, forMode: .default)
DispatchQueue.main.async {
do {
try Self.start(with: config)
} catch {
@ -110,6 +113,8 @@ class RyujinxEmulator {
self.isRunning = false
return
}
}
while self.isRunning && runLoop.run(mode: .default, before: .distantFuture) {
@ -122,6 +127,8 @@ class RyujinxEmulator {
}
emulationThread?.name = "RyujinxEmulationThread"
emulationThread?.qualityOfService = .userInteractive
emulationThread?.threadPriority = 0.9
emulationThread?.start()
}

View File

@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>UIFileSharingEnabled</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,210 @@
//
// MetalVIew.swift
// MeloNX
//
// Created by Stossy11 on 27/10/2024.
//
import SwiftUI
import Metal
import MetalKit
struct MetalView: UIViewRepresentable {
let device: MTLDevice?
let configure: (UIView) -> Void
func makeUIView(context: Context) -> SudachiScreenView {
let view = SudachiScreenView()
configure(view.primaryScreen)
return view
}
func updateUIView(_ uiView: SudachiScreenView, context: Context) {
//
}
}
class SudachiScreenView: UIView {
var primaryScreen: UIView!
var portraitconstraints = [NSLayoutConstraint]()
var landscapeconstraints = [NSLayoutConstraint]()
var fullscreenconstraints = [NSLayoutConstraint]()
let userDefaults = UserDefaults.standard
override init(frame: CGRect) {
super.init(frame: frame)
if userDefaults.bool(forKey: "isfullscreen") {
// setupSudachiScreenforcools()
setupSudachiScreen2()
} else if userDefaults.bool(forKey: "isairplay") {
setupSudachiScreen2()
} else if userDefaults.bool(forKey: "169fullscreen") { // this is for the 16/9 aspect ratio full screen
setupSudachiScreenforcools()
} else if UIDevice.current.userInterfaceIdiom == .pad {
setupSudachiScreenforiPad()
} else {
setupSudachiScreen()
}
}
required init?(coder: NSCoder) {
super.init(coder: coder)
if userDefaults.bool(forKey: "isfullscreen") {
setupSudachiScreen2()
} else if userDefaults.bool(forKey: "isairplay") {
setupSudachiScreen2()
} else if UIDevice.current.userInterfaceIdiom == .pad {
setupSudachiScreenforiPad()
} else {
setupSudachiScreen()
}
}
func setupSudachiScreen2() {
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
primaryScreen.clipsToBounds = true
addSubview(primaryScreen)
fullscreenconstraints = [
primaryScreen.topAnchor.constraint(equalTo: topAnchor),
primaryScreen.leadingAnchor.constraint(equalTo: leadingAnchor),
primaryScreen.trailingAnchor.constraint(equalTo: trailingAnchor),
primaryScreen.bottomAnchor.constraint(equalTo: bottomAnchor)
]
addConstraints(fullscreenconstraints)
}
func setupSudachiScreenforcools() { // oh god this took a long time, im going insane
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
primaryScreen.clipsToBounds = true
addSubview(primaryScreen)
primaryScreen.layer.cornerRadius = 5
primaryScreen.layer.masksToBounds = true
NSLayoutConstraint.activate([
primaryScreen.centerXAnchor.constraint(equalTo: centerXAnchor),
primaryScreen.centerYAnchor.constraint(equalTo: centerYAnchor),
primaryScreen.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor),
primaryScreen.heightAnchor.constraint(lessThanOrEqualTo: heightAnchor)
])
let aspectRatio: CGFloat = 16.0/9.0
let aspectRatioConstraint = NSLayoutConstraint(
item: primaryScreen ?? UIView(),
attribute: .width,
relatedBy: .equal,
toItem: primaryScreen,
attribute: .height,
multiplier: aspectRatio,
constant: 0
)
aspectRatioConstraint.priority = .required - 1
primaryScreen.addConstraint(aspectRatioConstraint)
let heightConstraint = primaryScreen.heightAnchor.constraint(equalTo: heightAnchor)
heightConstraint.priority = .defaultHigh
let widthConstraint = primaryScreen.widthAnchor.constraint(equalTo: widthAnchor)
widthConstraint.priority = .defaultHigh
NSLayoutConstraint.activate([heightConstraint, widthConstraint])
// Make primaryScreen fill container
fullscreenconstraints = [
primaryScreen.topAnchor.constraint(equalTo: primaryScreen.topAnchor),
primaryScreen.bottomAnchor.constraint(equalTo: primaryScreen.bottomAnchor),
primaryScreen.leadingAnchor.constraint(equalTo: primaryScreen.leadingAnchor),
primaryScreen.trailingAnchor.constraint(equalTo: primaryScreen.trailingAnchor)
]
NSLayoutConstraint.activate(fullscreenconstraints)
}
func setupSudachiScreenforiPad() {
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
primaryScreen.clipsToBounds = true
primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor
primaryScreen.layer.borderWidth = 3
primaryScreen.layer.cornerCurve = .continuous
primaryScreen.layer.cornerRadius = 10
addSubview(primaryScreen)
portraitconstraints = [
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10),
primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10),
primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16),
]
landscapeconstraints = [
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 50),
primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -100),
primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9),
primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
]
updateConstraintsForOrientation()
}
func setupSudachiScreen() {
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
primaryScreen.clipsToBounds = true
primaryScreen.layer.borderColor = UIColor.secondarySystemBackground.cgColor
primaryScreen.layer.borderWidth = 3
primaryScreen.layer.cornerCurve = .continuous
primaryScreen.layer.cornerRadius = 10
addSubview(primaryScreen)
portraitconstraints = [
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
primaryScreen.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor, constant: 10),
primaryScreen.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor, constant: -10),
primaryScreen.heightAnchor.constraint(equalTo: primaryScreen.widthAnchor, multiplier: 9 / 16),
]
landscapeconstraints = [
primaryScreen.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor, constant: 10),
primaryScreen.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -10),
primaryScreen.widthAnchor.constraint(equalTo: primaryScreen.heightAnchor, multiplier: 16 / 9),
primaryScreen.centerXAnchor.constraint(equalTo: safeAreaLayoutGuide.centerXAnchor),
]
updateConstraintsForOrientation()
}
override func layoutSubviews() {
super.layoutSubviews()
updateConstraintsForOrientation()
}
private func updateConstraintsForOrientation() {
if userDefaults.bool(forKey: "isfullscreen") {
removeConstraints(portraitconstraints)
removeConstraints(landscapeconstraints)
removeConstraints(fullscreenconstraints)
addConstraints(fullscreenconstraints)
} else {
removeConstraints(portraitconstraints)
removeConstraints(landscapeconstraints)
let isPortrait = UIApplication.shared.statusBarOrientation.isPortrait
addConstraints(isPortrait ? portraitconstraints : landscapeconstraints)
}
}
}

View File

@ -5,56 +5,63 @@ using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Npad;
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.TouchScreen;
using System;
using System.Runtime.InteropServices;
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
{
/// <summary>
/// Represent the shared memory shared between applications for input.
/// Represents the shared memory used for input, shared between applications.
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 0x40000)]
struct SharedMemory
{
// Ensure each struct has a defined size and is properly aligned in memory.
/// <summary>
/// Debug controller.
/// Debug controller state (size: approximately 0x400).
/// </summary>
[FieldOffset(0)]
public RingLifo<DebugPadState> DebugPad;
/// <summary>
/// Touchscreen.
/// Touchscreen state (size: approximately 0x3000).
/// </summary>
[FieldOffset(0x400)]
public RingLifo<TouchScreenState> TouchScreen;
/// <summary>
/// Mouse.
/// Mouse state (size: approximately 0x400).
/// </summary>
[FieldOffset(0x3400)]
public RingLifo<MouseState> Mouse;
/// <summary>
/// Keyboard.
/// Keyboard state (size: approximately 0x400).
/// </summary>
[FieldOffset(0x3800)]
public RingLifo<KeyboardState> Keyboard;
/// <summary>
/// Nintendo Pads.
/// Nintendo Pads (size: approximately 0x800).
/// </summary>
[FieldOffset(0x9A00)]
[FieldOffset(0x3C00)]
public Array10<NpadState> Npads;
/// <summary>
/// Creates a SharedMemory instance with each component initialized.
/// </summary>
public static SharedMemory Create()
{
SharedMemory result = new()
{
DebugPad = RingLifo<DebugPadState>.Create(),
TouchScreen = RingLifo<TouchScreenState>.Create(),
Mouse = RingLifo<MouseState>.Create(),
Keyboard = RingLifo<KeyboardState>.Create(),
};
// Initialize each component separately to avoid potential layout issues.
SharedMemory result = new SharedMemory();
result.DebugPad = RingLifo<DebugPadState>.Create();
result.TouchScreen = RingLifo<TouchScreenState>.Create();
result.Mouse = RingLifo<MouseState>.Create();
result.Keyboard = RingLifo<KeyboardState>.Create();
// Initialize each Npad state in a loop
for (int i = 0; i < result.Npads.Length; i++)
{
result.Npads[i] = NpadState.Create();

View File

@ -52,7 +52,6 @@ namespace Ryujinx.HLE
Gpu = new GpuContext(Configuration.GpuRenderer);
System = new HOS.Horizon(this);
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
Processes = new ProcessLoader(this);
TamperMachine = new TamperMachine();