1
0
forked from MeloNX/MeloNX

Edit MoltenVK and remove "MVK: Pre-Fill Metal Command Buffers" due to not being needed anymore

This commit is contained in:
Stossy11 2025-02-02 00:36:33 +11:00
parent f2ea6448dc
commit cb114fbb68
15 changed files with 121 additions and 86 deletions

View File

@ -26,7 +26,6 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */ = {isa = PBXBuildFile; productRef = 4E0DED332D05695D00FEF007 /* SwiftUIJoystick */; }; 4E0DED342D05695D00FEF007 /* SwiftUIJoystick in Frameworks */ = {isa = PBXBuildFile; productRef = 4E0DED332D05695D00FEF007 /* SwiftUIJoystick */; };
4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */ = {isa = PBXBuildFile; productRef = 4EA5AE812D16807500AD0B9F /* SwiftSVG */; }; 4EA5AE822D16807500AD0B9F /* SwiftSVG in Frameworks */ = {isa = PBXBuildFile; productRef = 4EA5AE812D16807500AD0B9F /* SwiftSVG */; };
5650564B2D2A758600C8BB1E /* dotnet.xcconfig.example in Resources */ = {isa = PBXBuildFile; fileRef = 5650564A2D2A758600C8BB1E /* dotnet.xcconfig.example */; };
CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; }; CA8F9C322D3F5AB200D7E586 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E80AA622CD7122800029585 /* GameController.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -392,7 +391,6 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
5650564B2D2A758600C8BB1E /* dotnet.xcconfig.example in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -626,6 +624,8 @@
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/MeloNX/Dependencies/XCFrameworks", "$(PROJECT_DIR)/MeloNX/Dependencies/XCFrameworks",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
GCC_OPTIMIZATION_LEVEL = fast; GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -644,7 +644,13 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
LIBRARY_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(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;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
@ -670,6 +676,8 @@
FRAMEWORK_SEARCH_PATHS = ( FRAMEWORK_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"$(PROJECT_DIR)/MeloNX/Dependencies/XCFrameworks", "$(PROJECT_DIR)/MeloNX/Dependencies/XCFrameworks",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
); );
GCC_OPTIMIZATION_LEVEL = fast; GCC_OPTIMIZATION_LEVEL = fast;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
@ -688,7 +696,13 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
LIBRARY_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"$(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;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";

View File

@ -19,10 +19,10 @@ extern "C" {
struct GameInfo { struct GameInfo {
long FileSize; long FileSize;
char TitleName[512]; char TitleName[512];
long TitleId; char TitleId[32];
char Developer[256]; char Developer[256];
int Version; char Version[16];
unsigned char* ImageData; unsigned char* ImageData;
unsigned int ImageSize; unsigned int ImageSize;
}; };

View File

@ -33,7 +33,6 @@ func waitForController() {
let controllerView = ControllerView() let controllerView = ControllerView()
let newHostingController = UIHostingController(rootView: controllerView) let newHostingController = UIHostingController(rootView: controllerView)
// Store reference globally to prevent deallocation
hostingController = newHostingController hostingController = newHostingController
let containerView = newHostingController.view! let containerView = newHostingController.view!
@ -50,7 +49,7 @@ func waitForController() {
SDL_SetWindowPosition(sdlWindow, 0, 0) SDL_SetWindowPosition(sdlWindow, 0, 0)
} }
timer.invalidate() // Stop the timer after adding the view timer.invalidate()
} }
} }
} }

View File

@ -134,12 +134,13 @@ class Ryujinx {
isRunning = true isRunning = true
RunLoop.current.perform { MainThread {
let url = URL(string: config.gamepath)!
let url = URL(string: config.gamepath)
do { do {
let args = self.buildCommandLineArgs(from: config) let args = self.buildCommandLineArgs(from: config)
let accessing = url.startAccessingSecurityScopedResource() let accessing = url?.startAccessingSecurityScopedResource()
// Convert Arguments to ones that Ryujinx can Read // Convert Arguments to ones that Ryujinx can Read
let cArgs = args.map { strdup($0) } let cArgs = args.map { strdup($0) }
@ -151,8 +152,8 @@ class Ryujinx {
if result != 0 { if result != 0 {
self.isRunning = false self.isRunning = false
if accessing { if let accessing, accessing {
url.stopAccessingSecurityScopedResource() url!.stopAccessingSecurityScopedResource()
} }
throw RyujinxError.executionError(code: result) throw RyujinxError.executionError(code: result)
@ -176,6 +177,19 @@ class Ryujinx {
var running: Bool { var running: Bool {
return isRunning return isRunning
} }
func MainThread(_ block: @escaping @Sendable () -> Void) {
if #available(iOS 17.0, *) {
RunLoop.current.perform {
block()
}
} else {
DispatchQueue.main.async {
block()
}
}
}
private func buildCommandLineArgs(from config: Configuration) -> [String] { private func buildCommandLineArgs(from config: Configuration) -> [String] {
var args: [String] = [] var args: [String] = []

View File

@ -22,6 +22,51 @@ public struct Game: Identifiable, Equatable {
var version: String var version: String
var icon: UIImage? var icon: UIImage?
static func convertGameInfoToGame(gameInfo: GameInfo, url: URL) -> Game {
var gameInfo = gameInfo
var gameTemp = Game(containerFolder: url.deletingLastPathComponent(), fileType: .item, fileURL: url, titleName: "", titleId: "", developer: "", version: "")
gameTemp.titleName = withUnsafePointer(to: &gameInfo.TitleName) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
gameTemp.developer = withUnsafePointer(to: &gameInfo.Developer) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
gameTemp.titleId = withUnsafePointer(to: &gameInfo.TitleId) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
gameTemp.version = withUnsafePointer(to: &gameInfo.Version) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
let imageSize = Int(gameInfo.ImageSize)
if imageSize > 0, imageSize <= 1024 * 1024 {
let imageData = Data(bytes: gameInfo.ImageData, count: imageSize)
gameTemp.icon = UIImage(data: imageData)
} else {
print("Invalid image size.")
}
return gameTemp
}
func createImage(from gameInfo: GameInfo) -> UIImage? { func createImage(from gameInfo: GameInfo) -> UIImage? {
// Access the struct // Access the struct
let gameInfoValue = gameInfo let gameInfoValue = gameInfo

View File

@ -52,6 +52,9 @@ struct ContentView: View {
// MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "2"), // MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "2"),
MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "0"), MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "0"),
// MoltenVKSettings(string: "MVK_CONFIG_RESUME_LOST_DEVICE", value: "1"), // MoltenVKSettings(string: "MVK_CONFIG_RESUME_LOST_DEVICE", value: "1"),
MoltenVKSettings(string: "MVK_CONFIG_MAX_ACTIVE_METAL_COMMAND_BUFFERS_PER_QUEUE", value: "192"),
MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "2"),
//MVK_CONFIG_LOG_LEVEL
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "0") MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "0")
] ]
@ -285,12 +288,6 @@ struct ContentView: View {
config.gamepath = game.fileURL.path config.gamepath = game.fileURL.path
config.inputids = Array(Set(currentControllers.map(\.id))) config.inputids = Array(Set(currentControllers.map(\.id)))
if mVKPreFillBuffer {
let setting = MoltenVKSettings(string: "MVK_CONFIG_PREFILL_METAL_COMMAND_BUFFERS", value: "1")
setenv(setting.string, setting.value, 1)
print("Prefill Metal Command Buffer Enabled")
}
if config.inputids.isEmpty { if config.inputids.isEmpty {
config.inputids.append("0") config.inputids.append("0")

View File

@ -223,30 +223,8 @@ struct GameLibraryView: View {
var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr) var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr)
var game = Game(containerFolder: url.deletingLastPathComponent(), fileType: .item, fileURL: url, titleName: "", titleId: "", developer: "", version: "") let game = Game.convertGameInfoToGame(gameInfo: gameInfo, url: url)
game.titleName = withUnsafePointer(to: &gameInfo.TitleName) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
game.developer = withUnsafePointer(to: &gameInfo.Developer) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
game.titleId = String(gameInfo.TitleId)
print(String(gameInfo.TitleId))
game.version = String(gameInfo.Version)
game.icon = game.createImage(from: gameInfo)
DispatchQueue.main.async { DispatchQueue.main.async {
startemu = game startemu = game
} }
@ -321,29 +299,10 @@ struct GameLibraryView: View {
let fileExtension = (fileURLCandidate.pathExtension as NSString).utf8String let fileExtension = (fileURLCandidate.pathExtension as NSString).utf8String
let extensionPtr = UnsafeMutablePointer<CChar>(mutating: fileExtension) let extensionPtr = UnsafeMutablePointer<CChar>(mutating: fileExtension)
var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr)
var game = Game(containerFolder: romsDirectory, fileType: .item, fileURL: fileURLCandidate, titleName: "", titleId: "", developer: "", version: "") let gameInfo = get_game_info(handle.fileDescriptor, extensionPtr)
game.titleName = withUnsafePointer(to: &gameInfo.TitleName) { let game = Game.convertGameInfoToGame(gameInfo: gameInfo, url: fileURLCandidate)
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
game.developer = withUnsafePointer(to: &gameInfo.Developer) {
$0.withMemoryRebound(to: UInt8.self, capacity: MemoryLayout.size(ofValue: $0)) {
String(cString: $0)
}
}
game.titleId = String(gameInfo.TitleId)
game.version = String(gameInfo.Version)
game.icon = game.createImage(from: gameInfo)
games.append(game) games.append(game)
} catch { } catch {

View File

@ -374,9 +374,9 @@ struct SettingsView: View {
Section { Section {
DisclosureGroup { DisclosureGroup {
Toggle(isOn: $mVKPreFillBuffer) { // Toggle(isOn: $mVKPreFillBuffer) {
labelWithIcon("MVK: Pre-Fill Metal Command Buffers", iconName: "gearshape") // labelWithIcon("MVK: Pre-Fill Metal Command Buffers", iconName: "gearshape")
}.tint(.blue) // }.tint(.blue)
HStack { HStack {
labelWithIcon("Page Size", iconName: "textformat.size") labelWithIcon("Page Size", iconName: "textformat.size")

View File

@ -580,6 +580,7 @@ namespace Ryujinx.Graphics.Vulkan
{ {
texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value; texture.Sampler = _dummySampler.GetSampler().Get(cbs).Value;
} }
if (OperatingSystem.IsIOS()) { if (OperatingSystem.IsIOS()) {
Span<DescriptorImageInfo> singleTexture = textures.Slice(i, 1); Span<DescriptorImageInfo> singleTexture = textures.Slice(i, 1);
dsc.UpdateImages(0, binding + i, singleTexture, DescriptorType.CombinedImageSampler); dsc.UpdateImages(0, binding + i, singleTexture, DescriptorType.CombinedImageSampler);

View File

@ -23,7 +23,10 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
config.UseMetalArgumentBuffers = true; config.UseMetalArgumentBuffers = true;
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE; if (OperatingSystem.IsIOSVersionAtLeast(17)) {
config.SemaphoreSupportStyle = MVKVkSemaphoreSupportStyle.MVK_CONFIG_VK_SEMAPHORE_SUPPORT_STYLE_SINGLE_QUEUE;
}
config.SynchronousQueueSubmits = false; config.SynchronousQueueSubmits = false;
config.ResumeLostDevice = true; config.ResumeLostDevice = true;

View File

@ -322,7 +322,14 @@ namespace Ryujinx.Headless.SDL2
var gameInfo = GetGameInfo(stream, extension); var gameInfo = GetGameInfo(stream, extension);
return new GameInfoNative(gameInfo.FileSize, gameInfo.TitleName, gameInfo.TitleId, gameInfo.Developer, gameInfo.Version, gameInfo.Icon); return new GameInfoNative(
(ulong)gameInfo.FileSize,
gameInfo.TitleName,
gameInfo.TitleId,
gameInfo.Developer,
gameInfo.Version,
gameInfo.Icon
);
} }
public static GameInfo? GetGameInfo(Stream gameStream, string extension) public static GameInfo? GetGameInfo(Stream gameStream, string extension)
@ -1482,42 +1489,41 @@ namespace Ryujinx.Headless.SDL2
{ {
public ulong FileSize; public ulong FileSize;
public fixed byte TitleName[512]; public fixed byte TitleName[512];
public ulong TitleId; public fixed byte TitleId[32];
public fixed byte Developer[256]; public fixed byte Developer[256];
public uint Version; public fixed byte Version[16];
public byte* ImageData; public byte* ImageData;
public uint ImageSize; public uint ImageSize;
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData) public GameInfoNative(ulong fileSize, string titleName, string titleId, string developer, string version, byte[] imageData)
{ {
FileSize = fileSize; FileSize = fileSize;
TitleId = titleId;
Version = version;
fixed (byte* developerPtr = Developer)
fixed (byte* titleNamePtr = TitleName) fixed (byte* titleNamePtr = TitleName)
fixed (byte* titleIdPtr = TitleId)
fixed (byte* developerPtr = Developer)
fixed (byte* versionPtr = Version)
{ {
CopyStringToFixedArray(titleName, titleNamePtr, 512); CopyStringToFixedArray(titleName, titleNamePtr, 512);
CopyStringToFixedArray(titleId, titleIdPtr, 32);
CopyStringToFixedArray(developer, developerPtr, 256); CopyStringToFixedArray(developer, developerPtr, 256);
CopyStringToFixedArray(version, versionPtr, 16);
} }
if (imageData == null || imageData.Length > 4096 * 4096) if (imageData == null || imageData.Length > 4096 * 4096)
{ {
// throw new ArgumentException("Image data must not exceed 4 MB."); ImageSize = 0;
ImageSize = (uint)0;
ImageData = null; ImageData = null;
} }
else else
{ {
ImageSize = (uint)imageData.Length; ImageSize = (uint)imageData.Length;
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length); ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length); Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length);
} }
} }
// Don't forget to free the allocated memory // Free allocated memory for ImageData
public void Dispose() public void Dispose()
{ {
if (ImageData != null) if (ImageData != null)
@ -1526,17 +1532,14 @@ namespace Ryujinx.Headless.SDL2
ImageData = null; ImageData = null;
} }
} }
private static void CopyStringToFixedArray(string source, byte* destination, int length) private static void CopyStringToFixedArray(string source, byte* destination, int length)
{ {
var span = new Span<byte>(destination, length); var span = new Span<byte>(destination, length);
span.Clear();
Encoding.UTF8.GetBytes(source, span); Encoding.UTF8.GetBytes(source, span);
} }
private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength)
{
var span = new Span<byte>(destination, maxLength);
source.AsSpan().CopyTo(span);
}
} }
} }
} }