Add a bunch of features

This commit is contained in:
Stossy11 2024-12-23 16:34:14 +11:00
parent 81941f9e9f
commit 0968360e08
17 changed files with 410 additions and 147 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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)

View File

@ -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
}
}

View File

@ -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))
}
}

View File

@ -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))
}
}
}

View File

@ -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>

View File

@ -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 {

View File

@ -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 {
/*
HStack {
Spacer()
Button("Stop emulation") {
DispatchQueue.main.async {
stop_emulation()
quit = true
}
if performacehud {
HStack {
PerformanceOverlayView()
Spacer()
// Button("Stop emulation") {
// DispatchQueue.main.async {
// stop_emulation()
// quit = true
// }
// }
}
}
*/
Spacer()
VStack {
@ -62,18 +68,21 @@ struct ControllerView: View {
} else {
// could be landscape
VStack {
/*
HStack {
Spacer()
Button("Stop emulation") {
DispatchQueue.main.async {
stop_emulation()
quit = true
}
if performacehud {
HStack {
PerformanceOverlayView()
Spacer()
// Button("Stop emulation") {
// DispatchQueue.main.async {
// stop_emulation()
// quit = true
// }
// }
}
}
*/
Spacer()
VStack {

View File

@ -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))
@ -215,27 +209,7 @@ struct SettingsView: View {
} footer: {
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,13 +233,36 @@ struct SettingsView: View {
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
Section {
DisclosureGroup {
Toggle(isOn: $useTrollStore) {
labelWithIcon("TrollStore", iconName: "troll.svg")
}
.tint(.blue)
HStack {
labelWithIcon("Page Size", iconName: "textformat.size")
@ -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

View File

@ -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;

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>

View File

@ -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()
{

View File

@ -8,7 +8,7 @@
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
<TieredPGO>true</TieredPGO>
<PublishAot>true</PublishAot>
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
<UseNativeAOTRuntime>true</UseNativeAOTRuntime>

View File

@ -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;
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;
}
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
{
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);
blockAddress += blockSize;
// Align size to 16KB page boundary
int alignedSize = (int)((((ulong)size + PAGE_SIZE - 1) & PAGE_MASK));
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);
}
}
}
}