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
|
||||
{
|
||||
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 CacheSize = 2047 * 1024 * 1024;
|
||||
private const int CacheSizeIOS = 64 * 1024 * 1024;
|
||||
private const int CacheSizeIOS = 128 * 1024 * 1024;
|
||||
|
||||
private static ReservedRegion _jitRegion;
|
||||
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",
|
||||
);
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
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",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
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",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = 3;
|
||||
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",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
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 get_current_fps();
|
||||
|
||||
void initialize();
|
||||
|
||||
const char* get_game_controllers();
|
||||
|
@ -44,7 +44,8 @@ func waitforcontroller() {
|
||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||
if findGCControllerView(in: window) == nil {
|
||||
window.addSubview(containerView)
|
||||
|
||||
} else {
|
||||
timer.invalidate()
|
||||
}
|
||||
|
||||
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">
|
||||
<plist version="1.0">
|
||||
<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>
|
||||
<true/>
|
||||
</dict>
|
||||
|
@ -62,8 +62,7 @@ struct ContentView: View {
|
||||
emulationView
|
||||
.onAppear() {
|
||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||
print(quit)
|
||||
|
||||
timer.invalidate()
|
||||
quits = quit
|
||||
|
||||
if quits {
|
||||
|
@ -11,23 +11,29 @@ import SwiftUIJoystick
|
||||
import CoreMotion
|
||||
|
||||
struct ControllerView: View {
|
||||
|
||||
@AppStorage("performacehud") var performacehud: Bool = false
|
||||
@AppStorage("quit") var quit: Bool = false
|
||||
var body: some View {
|
||||
GeometryReader { geometry in
|
||||
if geometry.size.height > geometry.size.width && UIDevice.current.userInterfaceIdiom != .pad {
|
||||
VStack {
|
||||
/*
|
||||
if performacehud {
|
||||
HStack {
|
||||
|
||||
PerformanceOverlayView()
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Stop emulation") {
|
||||
DispatchQueue.main.async {
|
||||
stop_emulation()
|
||||
quit = true
|
||||
// Button("Stop emulation") {
|
||||
// DispatchQueue.main.async {
|
||||
// stop_emulation()
|
||||
// quit = true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Spacer()
|
||||
VStack {
|
||||
@ -62,18 +68,21 @@ struct ControllerView: View {
|
||||
} else {
|
||||
// could be landscape
|
||||
VStack {
|
||||
/*
|
||||
if performacehud {
|
||||
HStack {
|
||||
PerformanceOverlayView()
|
||||
|
||||
Spacer()
|
||||
|
||||
Button("Stop emulation") {
|
||||
DispatchQueue.main.async {
|
||||
stop_emulation()
|
||||
quit = true
|
||||
// Button("Stop emulation") {
|
||||
// DispatchQueue.main.async {
|
||||
// stop_emulation()
|
||||
// quit = true
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
Spacer()
|
||||
VStack {
|
||||
|
@ -29,6 +29,8 @@ struct SettingsView: View {
|
||||
@AppStorage("RyuDemoControls") var ryuDemo: Bool = false
|
||||
@AppStorage("MTL_HUD_ENABLED") var metalHUDEnabled: Bool = false
|
||||
|
||||
@AppStorage("performacehud") var performacehud: Bool = false
|
||||
|
||||
@State private var showResolutionInfo = false
|
||||
@State private var searchText = ""
|
||||
|
||||
@ -102,18 +104,10 @@ struct SettingsView: View {
|
||||
}
|
||||
.padding(.vertical, 8)
|
||||
|
||||
Toggle(isOn: $metalHUDEnabled) {
|
||||
labelWithIcon("Metal HUD", iconName: "speedometer")
|
||||
Toggle(isOn: $performacehud) {
|
||||
labelWithIcon("Performance Overlay", iconName: "speedometer")
|
||||
}
|
||||
.tint(.blue)
|
||||
.onChange(of: metalHUDEnabled) { newValue in
|
||||
// Preserves original functionality
|
||||
if newValue {
|
||||
MTLHud.shared.enable()
|
||||
} else {
|
||||
MTLHud.shared.disable()
|
||||
}
|
||||
}
|
||||
} header: {
|
||||
Text("Graphics & Performance")
|
||||
.font(.title3.weight(.semibold))
|
||||
@ -216,26 +210,6 @@ struct SettingsView: View {
|
||||
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
|
||||
Section {
|
||||
if filteredMemoryModes.isEmpty {
|
||||
@ -259,14 +233,37 @@ struct SettingsView: View {
|
||||
Text("Select how memory is managed. 'Host (fast)' is best for most users.")
|
||||
}
|
||||
|
||||
// Advanced
|
||||
|
||||
// Other Settings
|
||||
Section {
|
||||
DisclosureGroup {
|
||||
|
||||
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
|
||||
Section {
|
||||
DisclosureGroup {
|
||||
|
||||
HStack {
|
||||
labelWithIcon("Page Size", iconName: "textformat.size")
|
||||
Spacer()
|
||||
@ -277,7 +274,7 @@ struct SettingsView: View {
|
||||
|
||||
TextField("Additional Arguments", text: Binding(
|
||||
get: {
|
||||
config.additionalArgs.joined(separator: ", ")
|
||||
config.additionalArgs.joined(separator: " ")
|
||||
},
|
||||
set: { newValue in
|
||||
config.additionalArgs = newValue
|
||||
|
@ -51,6 +51,59 @@ using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
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 AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||
using Image = SixLabors.ImageSharp.Image;
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
|
@ -147,6 +147,21 @@ namespace Ryujinx.Headless.SDL2
|
||||
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")]
|
||||
public static unsafe void Initialize()
|
||||
{
|
||||
|
@ -7,6 +7,7 @@ namespace Ryujinx.Memory
|
||||
[SupportedOSPlatform("ios")]
|
||||
static unsafe partial class MachJitWorkaround
|
||||
{
|
||||
// Previous imports remain the same
|
||||
[LibraryImport("libc")]
|
||||
public static partial int mach_task_self();
|
||||
|
||||
@ -28,141 +29,206 @@ namespace Ryujinx.Memory
|
||||
[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);
|
||||
|
||||
const int MAP_MEM_LEDGER_TAGGED = 0x002000;
|
||||
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)
|
||||
private static class Flags
|
||||
{
|
||||
IntPtr selfTask = mach_task_self();
|
||||
IntPtr memorySize = (IntPtr)size;
|
||||
IntPtr memoryObjectPort = IntPtr.Zero;
|
||||
|
||||
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);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Make memory entry failed: {err}");
|
||||
public const int MAP_MEM_LEDGER_TAGGED = 0x002000;
|
||||
public const int MAP_MEM_NAMED_CREATE = 0x020000;
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
static MachJitWorkaround()
|
||||
{
|
||||
_selfTask = mach_task_self();
|
||||
}
|
||||
|
||||
private static void HandleMachError(int error, string operation)
|
||||
{
|
||||
if (error != 0)
|
||||
{
|
||||
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
|
||||
{
|
||||
if (memorySize != (IntPtr)size)
|
||||
{
|
||||
throw new InvalidOperationException($"Created with size {memorySize} instead of {size}.");
|
||||
}
|
||||
// Create minimal permission memory entry initially
|
||||
HandleMachError(
|
||||
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);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to set ownership: {err}");
|
||||
}
|
||||
// Set no-footprint flag to minimize memory usage
|
||||
HandleMachError(
|
||||
mach_memory_entry_ownership(
|
||||
memoryObjectPort,
|
||||
TASK_NULL,
|
||||
Flags.VM_LEDGER_TAG_DEFAULT,
|
||||
Flags.VM_LEDGER_FLAG_NO_FOOTPRINT),
|
||||
"memory_entry_ownership");
|
||||
|
||||
IntPtr mapAddress = address;
|
||||
|
||||
err = vm_map(
|
||||
selfTask,
|
||||
// Map with minimal initial permissions
|
||||
int result = vm_map(
|
||||
_selfTask,
|
||||
&mapAddress,
|
||||
memorySize,
|
||||
/*mask=*/ 0,
|
||||
/*flags=*/ VM_FLAGS_OVERWRITE,
|
||||
IntPtr.Zero,
|
||||
Flags.VM_FLAGS_OVERWRITE,
|
||||
memoryObjectPort,
|
||||
/*offset=*/ 0,
|
||||
/*copy=*/ 0,
|
||||
VM_PROT_READ | VM_PROT_WRITE,
|
||||
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE,
|
||||
VM_INHERIT_COPY);
|
||||
IntPtr.Zero,
|
||||
0,
|
||||
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE,
|
||||
Flags.VM_PROT_READ | Flags.VM_PROT_WRITE | Flags.VM_PROT_EXECUTE, // Allow execute as max protection
|
||||
Flags.VM_INHERIT_COPY);
|
||||
|
||||
if (err != 0)
|
||||
{
|
||||
throw new InvalidOperationException($"Failed to map: {err}");
|
||||
}
|
||||
HandleMachError(result, "vm_map");
|
||||
|
||||
if (address != mapAddress)
|
||||
{
|
||||
throw new InvalidOperationException($"Remap changed address");
|
||||
throw new InvalidOperationException("Memory mapping address mismatch");
|
||||
}
|
||||
|
||||
return mapAddress;
|
||||
}
|
||||
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)
|
||||
{
|
||||
int mapChunkSize = 128 * 1024 * 1024;
|
||||
IntPtr endAddress = address + size;
|
||||
IntPtr blockAddress = address;
|
||||
while (blockAddress < endAddress)
|
||||
if (size <= 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
IntPtr address = 0;
|
||||
|
||||
int err = vm_allocate(mach_task_self(), &address, (IntPtr)size, VM_FLAGS_ANYWHERE);
|
||||
|
||||
if (err != 0)
|
||||
if (size == 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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
IntPtr taskSelf = mach_task_self();
|
||||
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)
|
||||
if (size == 0 || sharedMemory == IntPtr.Zero)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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