forked from MeloNX/MeloNX
Add a bunch of features
This commit is contained in:
parent
81941f9e9f
commit
0968360e08
@ -15,11 +15,11 @@ namespace ARMeilleure.Translation.Cache
|
|||||||
static partial class JitCache
|
static partial class JitCache
|
||||||
{
|
{
|
||||||
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
private static readonly int _pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
private static readonly int _pageMask = _pageSize - 2;
|
private static readonly int _pageMask = _pageSize - 1;
|
||||||
|
|
||||||
private const int CodeAlignment = 4; // Bytes.
|
private const int CodeAlignment = 4; // Bytes.
|
||||||
private const int CacheSize = 2047 * 1024 * 1024;
|
private const int CacheSize = 2047 * 1024 * 1024;
|
||||||
private const int CacheSizeIOS = 64 * 1024 * 1024;
|
private const int CacheSizeIOS = 128 * 1024 * 1024;
|
||||||
|
|
||||||
private static ReservedRegion _jitRegion;
|
private static ReservedRegion _jitRegion;
|
||||||
private static JitCacheInvalidation _jitCacheInvalidator;
|
private static JitCacheInvalidation _jitCacheInvalidator;
|
||||||
|
@ -528,6 +528,7 @@
|
|||||||
"$(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",
|
||||||
);
|
);
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = MeloNX/Info.plist;
|
INFOPLIST_FILE = MeloNX/Info.plist;
|
||||||
@ -668,6 +669,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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
@ -698,6 +703,7 @@
|
|||||||
"$(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",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = 3;
|
GCC_OPTIMIZATION_LEVEL = 3;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
@ -839,6 +845,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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 0.0.8;
|
MARKETING_VERSION = 0.0.8;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
Binary file not shown.
@ -35,6 +35,8 @@ void stop_emulation();
|
|||||||
|
|
||||||
int main_ryujinx_sdl(int argc, char **argv);
|
int main_ryujinx_sdl(int argc, char **argv);
|
||||||
|
|
||||||
|
int get_current_fps();
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
||||||
const char* get_game_controllers();
|
const char* get_game_controllers();
|
||||||
|
@ -44,7 +44,8 @@ func waitforcontroller() {
|
|||||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||||
if findGCControllerView(in: window) == nil {
|
if findGCControllerView(in: window) == nil {
|
||||||
window.addSubview(containerView)
|
window.addSubview(containerView)
|
||||||
|
} else {
|
||||||
|
timer.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
window.bringSubviewToFront(containerView)
|
window.bringSubviewToFront(containerView)
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
//
|
||||||
|
// FPSMonitor.swift
|
||||||
|
// MeloNX
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 21/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class FPSMonitor: ObservableObject {
|
||||||
|
@Published private(set) var currentFPS: UInt64 = 0
|
||||||
|
private var timer: Timer?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
|
||||||
|
self?.updateFPS()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
timer?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateFPS() {
|
||||||
|
let currentfps = UInt64(get_current_fps())
|
||||||
|
|
||||||
|
self.currentFPS = currentfps
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func formatFPS() -> String {
|
||||||
|
let fps = Double(currentFPS)
|
||||||
|
let fpsString = String(format: "FPS: %.2f", fps)
|
||||||
|
|
||||||
|
return fpsString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
|||||||
|
//
|
||||||
|
// MemoryUsageMonitor.swift
|
||||||
|
// MeloNX
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 21/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class MemoryUsageMonitor: ObservableObject {
|
||||||
|
@Published private(set) var memoryUsage: UInt64 = 0
|
||||||
|
private var timer: Timer?
|
||||||
|
|
||||||
|
init() {
|
||||||
|
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
||||||
|
self?.updateMemoryUsage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
timer?.invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateMemoryUsage() {
|
||||||
|
var taskInfo = task_vm_info_data_t()
|
||||||
|
var count = mach_msg_type_number_t(MemoryLayout<task_vm_info>.size) / 4
|
||||||
|
let result: kern_return_t = withUnsafeMutablePointer(to: &taskInfo) {
|
||||||
|
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
|
||||||
|
task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if result == KERN_SUCCESS {
|
||||||
|
memoryUsage = taskInfo.phys_footprint
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
print("Error with task_info(): " +
|
||||||
|
(String(cString: mach_error_string(result), encoding: String.Encoding.ascii) ?? "unknown error"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatMemorySize(_ bytes: UInt64) -> String {
|
||||||
|
let formatter = ByteCountFormatter()
|
||||||
|
formatter.allowedUnits = [.useMB, .useGB]
|
||||||
|
formatter.countStyle = .memory
|
||||||
|
return formatter.string(fromByteCount: Int64(bytes))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// Untitled.swift
|
||||||
|
// MeloNX
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 21/12/2024.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct PerformanceOverlayView: View {
|
||||||
|
@StateObject private var memorymonitor = MemoryUsageMonitor()
|
||||||
|
|
||||||
|
@StateObject private var fpsmonitor = FPSMonitor()
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text("\(fpsmonitor.formatFPS())")
|
||||||
|
Text(memorymonitor.formatMemorySize(memorymonitor.memoryUsage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,10 +2,6 @@
|
|||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
<key>com.apple.developer.kernel.increased-memory-limit</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
@ -62,8 +62,7 @@ struct ContentView: View {
|
|||||||
emulationView
|
emulationView
|
||||||
.onAppear() {
|
.onAppear() {
|
||||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||||
print(quit)
|
timer.invalidate()
|
||||||
|
|
||||||
quits = quit
|
quits = quit
|
||||||
|
|
||||||
if quits {
|
if quits {
|
||||||
|
@ -11,23 +11,29 @@ import SwiftUIJoystick
|
|||||||
import CoreMotion
|
import CoreMotion
|
||||||
|
|
||||||
struct ControllerView: View {
|
struct ControllerView: View {
|
||||||
|
|
||||||
|
@AppStorage("performacehud") var performacehud: Bool = false
|
||||||
@AppStorage("quit") var quit: Bool = false
|
@AppStorage("quit") var quit: Bool = false
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geometry in
|
GeometryReader { geometry in
|
||||||
if geometry.size.height > geometry.size.width && UIDevice.current.userInterfaceIdiom != .pad {
|
if geometry.size.height > geometry.size.width && UIDevice.current.userInterfaceIdiom != .pad {
|
||||||
VStack {
|
VStack {
|
||||||
/*
|
if performacehud {
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
|
||||||
|
PerformanceOverlayView()
|
||||||
Button("Stop emulation") {
|
|
||||||
DispatchQueue.main.async {
|
Spacer()
|
||||||
stop_emulation()
|
|
||||||
quit = true
|
// Button("Stop emulation") {
|
||||||
}
|
// DispatchQueue.main.async {
|
||||||
|
// stop_emulation()
|
||||||
|
// quit = true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
VStack {
|
VStack {
|
||||||
@ -62,18 +68,21 @@ struct ControllerView: View {
|
|||||||
} else {
|
} else {
|
||||||
// could be landscape
|
// could be landscape
|
||||||
VStack {
|
VStack {
|
||||||
/*
|
if performacehud {
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
PerformanceOverlayView()
|
||||||
|
|
||||||
Button("Stop emulation") {
|
Spacer()
|
||||||
DispatchQueue.main.async {
|
|
||||||
stop_emulation()
|
// Button("Stop emulation") {
|
||||||
quit = true
|
// DispatchQueue.main.async {
|
||||||
}
|
// stop_emulation()
|
||||||
|
// quit = true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
VStack {
|
VStack {
|
||||||
|
@ -29,6 +29,8 @@ struct SettingsView: View {
|
|||||||
@AppStorage("RyuDemoControls") var ryuDemo: Bool = false
|
@AppStorage("RyuDemoControls") var ryuDemo: Bool = false
|
||||||
@AppStorage("MTL_HUD_ENABLED") var metalHUDEnabled: Bool = false
|
@AppStorage("MTL_HUD_ENABLED") var metalHUDEnabled: Bool = false
|
||||||
|
|
||||||
|
@AppStorage("performacehud") var performacehud: Bool = false
|
||||||
|
|
||||||
@State private var showResolutionInfo = false
|
@State private var showResolutionInfo = false
|
||||||
@State private var searchText = ""
|
@State private var searchText = ""
|
||||||
|
|
||||||
@ -102,18 +104,10 @@ struct SettingsView: View {
|
|||||||
}
|
}
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
|
|
||||||
Toggle(isOn: $metalHUDEnabled) {
|
Toggle(isOn: $performacehud) {
|
||||||
labelWithIcon("Metal HUD", iconName: "speedometer")
|
labelWithIcon("Performance Overlay", iconName: "speedometer")
|
||||||
}
|
}
|
||||||
.tint(.blue)
|
.tint(.blue)
|
||||||
.onChange(of: metalHUDEnabled) { newValue in
|
|
||||||
// Preserves original functionality
|
|
||||||
if newValue {
|
|
||||||
MTLHud.shared.enable()
|
|
||||||
} else {
|
|
||||||
MTLHud.shared.disable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} header: {
|
} header: {
|
||||||
Text("Graphics & Performance")
|
Text("Graphics & Performance")
|
||||||
.font(.title3.weight(.semibold))
|
.font(.title3.weight(.semibold))
|
||||||
@ -215,27 +209,7 @@ struct SettingsView: View {
|
|||||||
} footer: {
|
} footer: {
|
||||||
Text("Configure input devices and on-screen controls for easier navigation and play.")
|
Text("Configure input devices and on-screen controls for easier navigation and play.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logging
|
|
||||||
Section {
|
|
||||||
Toggle(isOn: $config.debuglogs) {
|
|
||||||
labelWithIcon("Debug Logs", iconName: "exclamationmark.bubble")
|
|
||||||
}
|
|
||||||
.tint(.blue)
|
|
||||||
|
|
||||||
Toggle(isOn: $config.tracelogs) {
|
|
||||||
labelWithIcon("Trace Logs", iconName: "waveform.path")
|
|
||||||
}
|
|
||||||
.tint(.blue)
|
|
||||||
} header: {
|
|
||||||
Text("Logging")
|
|
||||||
.font(.title3.weight(.semibold))
|
|
||||||
.textCase(nil)
|
|
||||||
.headerProminence(.increased)
|
|
||||||
} footer: {
|
|
||||||
Text("Enable logs for troubleshooting or keep them off for a cleaner experience.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// CPU Mode
|
// CPU Mode
|
||||||
Section {
|
Section {
|
||||||
if filteredMemoryModes.isEmpty {
|
if filteredMemoryModes.isEmpty {
|
||||||
@ -259,13 +233,36 @@ struct SettingsView: View {
|
|||||||
Text("Select how memory is managed. 'Host (fast)' is best for most users.")
|
Text("Select how memory is managed. 'Host (fast)' is best for most users.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Other Settings
|
||||||
|
Section {
|
||||||
|
|
||||||
|
Toggle(isOn: $useTrollStore) {
|
||||||
|
labelWithIcon("TrollStore", iconName: "troll.svg")
|
||||||
|
}
|
||||||
|
.tint(.blue)
|
||||||
|
|
||||||
|
Toggle(isOn: $config.debuglogs) {
|
||||||
|
labelWithIcon("Debug Logs", iconName: "exclamationmark.bubble")
|
||||||
|
}
|
||||||
|
.tint(.blue)
|
||||||
|
|
||||||
|
Toggle(isOn: $config.tracelogs) {
|
||||||
|
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.")
|
||||||
|
}
|
||||||
|
|
||||||
// Advanced
|
// Advanced
|
||||||
Section {
|
Section {
|
||||||
DisclosureGroup {
|
DisclosureGroup {
|
||||||
Toggle(isOn: $useTrollStore) {
|
|
||||||
labelWithIcon("TrollStore", iconName: "troll.svg")
|
|
||||||
}
|
|
||||||
.tint(.blue)
|
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
labelWithIcon("Page Size", iconName: "textformat.size")
|
labelWithIcon("Page Size", iconName: "textformat.size")
|
||||||
@ -277,7 +274,7 @@ struct SettingsView: View {
|
|||||||
|
|
||||||
TextField("Additional Arguments", text: Binding(
|
TextField("Additional Arguments", text: Binding(
|
||||||
get: {
|
get: {
|
||||||
config.additionalArgs.joined(separator: ", ")
|
config.additionalArgs.joined(separator: " ")
|
||||||
},
|
},
|
||||||
set: { newValue in
|
set: { newValue in
|
||||||
config.additionalArgs = newValue
|
config.additionalArgs = newValue
|
||||||
|
@ -51,6 +51,59 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ARMeilleure.Translation;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using LibHac.Tools.FsSystem;
|
||||||
|
using Ryujinx.Audio.Backends.Dummy;
|
||||||
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
|
using Ryujinx.Audio.Backends.SDL2;
|
||||||
|
using Ryujinx.Audio.Backends.SoundIo;
|
||||||
|
using Ryujinx.Audio.Integration;
|
||||||
|
using Ryujinx.Ava.Common;
|
||||||
|
using Ryujinx.Ava.Common.Locale;
|
||||||
|
using Ryujinx.Ava.Input;
|
||||||
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
|
using Ryujinx.Ava.UI.Models;
|
||||||
|
using Ryujinx.Ava.UI.Renderer;
|
||||||
|
using Ryujinx.Ava.UI.ViewModels;
|
||||||
|
using Ryujinx.Ava.UI.Windows;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.SystemInterop;
|
||||||
|
using Ryujinx.Graphics.GAL;
|
||||||
|
using Ryujinx.Graphics.GAL.Multithreading;
|
||||||
|
using Ryujinx.Graphics.Gpu;
|
||||||
|
using Ryujinx.Graphics.OpenGL;
|
||||||
|
using Ryujinx.Graphics.Vulkan;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.HLE.FileSystem;
|
||||||
|
using Ryujinx.HLE.HOS;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||||
|
using Ryujinx.HLE.HOS.SystemState;
|
||||||
|
using Ryujinx.Input;
|
||||||
|
using Ryujinx.Input.HLE;
|
||||||
|
using Ryujinx.Ui.App.Common;
|
||||||
|
using Ryujinx.Ui.Common;
|
||||||
|
using Ryujinx.Ui.Common.Configuration;
|
||||||
|
using Ryujinx.Ui.Common.Helper;
|
||||||
|
using Silk.NET.Vulkan;
|
||||||
|
using SixLabors.ImageSharp;
|
||||||
|
using SixLabors.ImageSharp.Formats.Png;
|
||||||
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
|
using SixLabors.ImageSharp.Processing;
|
||||||
|
using SPB.Graphics.Vulkan;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
using static Ryujinx.Ava.UI.Helpers.Win32NativeInterop;
|
||||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||||
using Image = SixLabors.ImageSharp.Image;
|
using Image = SixLabors.ImageSharp.Image;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
@ -147,6 +147,21 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[UnmanagedCallersOnly(EntryPoint = "get_current_fps")]
|
||||||
|
public static unsafe int GetFPS()
|
||||||
|
{
|
||||||
|
if (_window != null) {
|
||||||
|
Switch Device = _window.Device;
|
||||||
|
|
||||||
|
int intValue = (int)Device.Statistics.GetGameFrameRate();
|
||||||
|
|
||||||
|
return intValue;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly(EntryPoint = "initialize")]
|
[UnmanagedCallersOnly(EntryPoint = "initialize")]
|
||||||
public static unsafe void Initialize()
|
public static unsafe void Initialize()
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
|
||||||
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
|
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
|
||||||
<TieredPGO>true</TieredPGO>
|
<TieredPGO>true</TieredPGO>
|
||||||
|
|
||||||
<PublishAot>true</PublishAot>
|
<PublishAot>true</PublishAot>
|
||||||
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
|
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
|
||||||
<UseNativeAOTRuntime>true</UseNativeAOTRuntime>
|
<UseNativeAOTRuntime>true</UseNativeAOTRuntime>
|
||||||
|
@ -7,6 +7,7 @@ namespace Ryujinx.Memory
|
|||||||
[SupportedOSPlatform("ios")]
|
[SupportedOSPlatform("ios")]
|
||||||
static unsafe partial class MachJitWorkaround
|
static unsafe partial class MachJitWorkaround
|
||||||
{
|
{
|
||||||
|
// Previous imports remain the same
|
||||||
[LibraryImport("libc")]
|
[LibraryImport("libc")]
|
||||||
public static partial int mach_task_self();
|
public static partial int mach_task_self();
|
||||||
|
|
||||||
@ -28,141 +29,206 @@ namespace Ryujinx.Memory
|
|||||||
[LibraryImport("libc")]
|
[LibraryImport("libc")]
|
||||||
public static partial int vm_remap(IntPtr target_task, IntPtr* target_address, IntPtr size, IntPtr mask, int flags, IntPtr src_task, IntPtr src_address, int copy, int* cur_protection, int* max_protection, int inheritance);
|
public static partial int vm_remap(IntPtr target_task, IntPtr* target_address, IntPtr size, IntPtr mask, int flags, IntPtr src_task, IntPtr src_address, int copy, int* cur_protection, int* max_protection, int inheritance);
|
||||||
|
|
||||||
const int MAP_MEM_LEDGER_TAGGED = 0x002000;
|
private static class Flags
|
||||||
const int MAP_MEM_NAMED_CREATE = 0x020000;
|
|
||||||
|
|
||||||
const int VM_PROT_READ = 0x01;
|
|
||||||
const int VM_PROT_WRITE = 0x02;
|
|
||||||
const int VM_PROT_EXECUTE = 0x04;
|
|
||||||
|
|
||||||
const int VM_LEDGER_TAG_DEFAULT = 0x00000001;
|
|
||||||
const int VM_LEDGER_FLAG_NO_FOOTPRINT = 0x00000001;
|
|
||||||
|
|
||||||
const int VM_INHERIT_COPY = 1;
|
|
||||||
const int VM_INHERIT_DEFAULT = VM_INHERIT_COPY;
|
|
||||||
|
|
||||||
const int VM_FLAGS_FIXED = 0x0000;
|
|
||||||
const int VM_FLAGS_ANYWHERE = 0x0001;
|
|
||||||
const int VM_FLAGS_OVERWRITE = 0x4000;
|
|
||||||
|
|
||||||
const IntPtr TASK_NULL = 0;
|
|
||||||
|
|
||||||
public static void ReallocateBlock(IntPtr address, int size)
|
|
||||||
{
|
{
|
||||||
IntPtr selfTask = mach_task_self();
|
public const int MAP_MEM_LEDGER_TAGGED = 0x002000;
|
||||||
IntPtr memorySize = (IntPtr)size;
|
public const int MAP_MEM_NAMED_CREATE = 0x020000;
|
||||||
IntPtr memoryObjectPort = IntPtr.Zero;
|
public const int VM_PROT_READ = 0x01;
|
||||||
|
public const int VM_PROT_WRITE = 0x02;
|
||||||
|
public const int VM_PROT_EXECUTE = 0x04;
|
||||||
|
public const int VM_LEDGER_TAG_DEFAULT = 0x00000001;
|
||||||
|
public const int VM_LEDGER_FLAG_NO_FOOTPRINT = 0x00000001;
|
||||||
|
public const int VM_INHERIT_COPY = 1;
|
||||||
|
public const int VM_INHERIT_DEFAULT = VM_INHERIT_COPY;
|
||||||
|
public const int VM_FLAGS_FIXED = 0x0000;
|
||||||
|
public const int VM_FLAGS_ANYWHERE = 0x0001;
|
||||||
|
public const int VM_FLAGS_OVERWRITE = 0x4000;
|
||||||
|
}
|
||||||
|
|
||||||
int err = mach_make_memory_entry_64(selfTask, &memorySize, 0, MAP_MEM_NAMED_CREATE | MAP_MEM_LEDGER_TAGGED | VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE, &memoryObjectPort, 0);
|
private const IntPtr TASK_NULL = 0;
|
||||||
|
private static readonly IntPtr _selfTask;
|
||||||
|
|
||||||
|
// Updated to iOS 16KB page size
|
||||||
|
private const int PAGE_SIZE = 16 * 1024;
|
||||||
|
private const ulong PAGE_MASK = ~((ulong)PAGE_SIZE - 1);
|
||||||
|
|
||||||
if (err != 0)
|
static MachJitWorkaround()
|
||||||
|
{
|
||||||
|
_selfTask = mach_task_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleMachError(int error, string operation)
|
||||||
|
{
|
||||||
|
if (error != 0)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Make memory entry failed: {err}");
|
throw new InvalidOperationException($"Mach operation '{operation}' failed with error: {error}");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IntPtr ReallocateBlock(IntPtr address, int size)
|
||||||
|
{
|
||||||
|
// Ensure size is page-aligned
|
||||||
|
int alignedSize = (int)((((ulong)size + PAGE_SIZE - 1) & PAGE_MASK));
|
||||||
|
|
||||||
|
// Deallocate existing mapping
|
||||||
|
vm_deallocate(_selfTask, address, (IntPtr)alignedSize);
|
||||||
|
|
||||||
|
IntPtr memorySize = (IntPtr)alignedSize;
|
||||||
|
IntPtr memoryObjectPort = IntPtr.Zero;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (memorySize != (IntPtr)size)
|
// Create minimal permission memory entry initially
|
||||||
{
|
HandleMachError(
|
||||||
throw new InvalidOperationException($"Created with size {memorySize} instead of {size}.");
|
mach_make_memory_entry_64(
|
||||||
}
|
_selfTask,
|
||||||
|
&memorySize,
|
||||||
|
IntPtr.Zero,
|
||||||
|
Flags.MAP_MEM_NAMED_CREATE | Flags.MAP_MEM_LEDGER_TAGGED |
|
||||||
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE, // Don't request execute initially
|
||||||
|
&memoryObjectPort,
|
||||||
|
IntPtr.Zero),
|
||||||
|
"make_memory_entry_64");
|
||||||
|
|
||||||
err = mach_memory_entry_ownership(memoryObjectPort, TASK_NULL, VM_LEDGER_TAG_DEFAULT, VM_LEDGER_FLAG_NO_FOOTPRINT);
|
// Set no-footprint flag to minimize memory usage
|
||||||
|
HandleMachError(
|
||||||
if (err != 0)
|
mach_memory_entry_ownership(
|
||||||
{
|
memoryObjectPort,
|
||||||
throw new InvalidOperationException($"Failed to set ownership: {err}");
|
TASK_NULL,
|
||||||
}
|
Flags.VM_LEDGER_TAG_DEFAULT,
|
||||||
|
Flags.VM_LEDGER_FLAG_NO_FOOTPRINT),
|
||||||
|
"memory_entry_ownership");
|
||||||
|
|
||||||
IntPtr mapAddress = address;
|
IntPtr mapAddress = address;
|
||||||
|
|
||||||
err = vm_map(
|
// Map with minimal initial permissions
|
||||||
selfTask,
|
int result = vm_map(
|
||||||
|
_selfTask,
|
||||||
&mapAddress,
|
&mapAddress,
|
||||||
memorySize,
|
memorySize,
|
||||||
/*mask=*/ 0,
|
IntPtr.Zero,
|
||||||
/*flags=*/ VM_FLAGS_OVERWRITE,
|
Flags.VM_FLAGS_OVERWRITE,
|
||||||
memoryObjectPort,
|
memoryObjectPort,
|
||||||
/*offset=*/ 0,
|
IntPtr.Zero,
|
||||||
/*copy=*/ 0,
|
0,
|
||||||
VM_PROT_READ | VM_PROT_WRITE,
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE,
|
||||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
|
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE | Flags.VM_PROT_EXECUTE, // Allow execute as max protection
|
||||||
VM_INHERIT_COPY);
|
Flags.VM_INHERIT_COPY);
|
||||||
|
|
||||||
if (err != 0)
|
HandleMachError(result, "vm_map");
|
||||||
{
|
|
||||||
throw new InvalidOperationException($"Failed to map: {err}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address != mapAddress)
|
if (address != mapAddress)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Remap changed address");
|
throw new InvalidOperationException("Memory mapping address mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return mapAddress;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
//mach_port_deallocate(selfTask, memoryObjectPort);
|
if (memoryObjectPort != IntPtr.Zero)
|
||||||
|
{
|
||||||
|
// Implement proper cleanup if needed
|
||||||
|
// mach_port_deallocate(_selfTask, memoryObjectPort);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Console.WriteLine($"Reallocated an area... {address:x16}");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ReallocateAreaWithOwnership(IntPtr address, int size)
|
public static void ReallocateAreaWithOwnership(IntPtr address, int size)
|
||||||
{
|
{
|
||||||
int mapChunkSize = 128 * 1024 * 1024;
|
if (size <= 0)
|
||||||
IntPtr endAddress = address + size;
|
|
||||||
IntPtr blockAddress = address;
|
|
||||||
while (blockAddress < endAddress)
|
|
||||||
{
|
{
|
||||||
int blockSize = Math.Min(mapChunkSize, (int)(endAddress - blockAddress));
|
throw new ArgumentException("Size must be positive", nameof(size));
|
||||||
|
}
|
||||||
|
|
||||||
ReallocateBlock(blockAddress, blockSize);
|
// Align size to 16KB page boundary
|
||||||
|
int alignedSize = (int)((((ulong)size + PAGE_SIZE - 1) & PAGE_MASK));
|
||||||
blockAddress += blockSize;
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ReallocateBlock(address, alignedSize);
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException)
|
||||||
|
{
|
||||||
|
// If first attempt fails, try with explicit deallocation and retry
|
||||||
|
vm_deallocate(_selfTask, address, (IntPtr)alignedSize);
|
||||||
|
ReallocateBlock(address, alignedSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr AllocateSharedMemory(ulong size, bool reserve)
|
public static IntPtr AllocateSharedMemory(ulong size, bool reserve)
|
||||||
{
|
{
|
||||||
IntPtr address = 0;
|
if (size == 0)
|
||||||
|
|
||||||
int err = vm_allocate(mach_task_self(), &address, (IntPtr)size, VM_FLAGS_ANYWHERE);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Failed to allocate shared memory: {err}");
|
throw new ArgumentException("Size must be positive", nameof(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
||||||
|
|
||||||
|
IntPtr address = IntPtr.Zero;
|
||||||
|
HandleMachError(
|
||||||
|
vm_allocate(
|
||||||
|
_selfTask,
|
||||||
|
&address,
|
||||||
|
(IntPtr)alignedSize,
|
||||||
|
Flags.VM_FLAGS_ANYWHERE),
|
||||||
|
"vm_allocate");
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void DestroySharedMemory(IntPtr handle, ulong size)
|
public static void DestroySharedMemory(IntPtr handle, ulong size)
|
||||||
{
|
{
|
||||||
vm_deallocate(mach_task_self(), handle, (IntPtr)size);
|
if (handle != IntPtr.Zero && size > 0)
|
||||||
|
{
|
||||||
|
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
||||||
|
vm_deallocate(_selfTask, handle, (IntPtr)alignedSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IntPtr MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size)
|
public static IntPtr MapView(IntPtr sharedMemory, ulong srcOffset, IntPtr location, ulong size)
|
||||||
{
|
{
|
||||||
IntPtr taskSelf = mach_task_self();
|
if (size == 0 || sharedMemory == IntPtr.Zero)
|
||||||
IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + srcOffset);
|
|
||||||
IntPtr dstAddress = location;
|
|
||||||
|
|
||||||
int cur_protection = 0;
|
|
||||||
int max_protection = 0;
|
|
||||||
|
|
||||||
int err = vm_remap(taskSelf, &dstAddress, (IntPtr)size, 0, VM_FLAGS_OVERWRITE, taskSelf, srcAddress, 0, &cur_protection, &max_protection, VM_INHERIT_DEFAULT);
|
|
||||||
|
|
||||||
if (err != 0)
|
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException($"Failed to allocate remap memory: {err}");
|
throw new ArgumentException("Invalid mapping parameters");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ulong alignedOffset = srcOffset & PAGE_MASK;
|
||||||
|
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
||||||
|
|
||||||
|
IntPtr srcAddress = (IntPtr)((ulong)sharedMemory + alignedOffset);
|
||||||
|
IntPtr dstAddress = location;
|
||||||
|
int curProtection = 0;
|
||||||
|
int maxProtection = 0;
|
||||||
|
|
||||||
|
// Deallocate existing mapping
|
||||||
|
vm_deallocate(_selfTask, location, (IntPtr)alignedSize);
|
||||||
|
|
||||||
|
HandleMachError(
|
||||||
|
vm_remap(
|
||||||
|
_selfTask,
|
||||||
|
&dstAddress,
|
||||||
|
(IntPtr)alignedSize,
|
||||||
|
IntPtr.Zero,
|
||||||
|
Flags.VM_FLAGS_FIXED,
|
||||||
|
_selfTask,
|
||||||
|
srcAddress,
|
||||||
|
0,
|
||||||
|
&curProtection,
|
||||||
|
&maxProtection,
|
||||||
|
Flags.VM_INHERIT_DEFAULT),
|
||||||
|
"vm_remap");
|
||||||
|
|
||||||
return dstAddress;
|
return dstAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void UnmapView(IntPtr location, ulong size)
|
public static void UnmapView(IntPtr location, ulong size)
|
||||||
{
|
{
|
||||||
vm_deallocate(mach_task_self(), location, (IntPtr)size);
|
if (location != IntPtr.Zero && size > 0)
|
||||||
|
{
|
||||||
|
ulong alignedSize = (size + (ulong)PAGE_SIZE - 1) & PAGE_MASK;
|
||||||
|
vm_deallocate(_selfTask, location, (IntPtr)alignedSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user