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

View File

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

View File

@ -33,7 +33,6 @@ func waitForController() {
let controllerView = ControllerView()
let newHostingController = UIHostingController(rootView: controllerView)
// Store reference globally to prevent deallocation
hostingController = newHostingController
let containerView = newHostingController.view!
@ -50,7 +49,7 @@ func waitForController() {
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
RunLoop.current.perform {
let url = URL(string: config.gamepath)!
MainThread {
let url = URL(string: config.gamepath)
do {
let args = self.buildCommandLineArgs(from: config)
let accessing = url.startAccessingSecurityScopedResource()
let accessing = url?.startAccessingSecurityScopedResource()
// Convert Arguments to ones that Ryujinx can Read
let cArgs = args.map { strdup($0) }
@ -151,8 +152,8 @@ class Ryujinx {
if result != 0 {
self.isRunning = false
if accessing {
url.stopAccessingSecurityScopedResource()
if let accessing, accessing {
url!.stopAccessingSecurityScopedResource()
}
throw RyujinxError.executionError(code: result)
@ -177,6 +178,19 @@ class Ryujinx {
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] {
var args: [String] = []

View File

@ -22,6 +22,51 @@ public struct Game: Identifiable, Equatable {
var version: String
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? {
// Access the struct
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_USE_METAL_PRIVATE_API", value: "0"),
// 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")
]
@ -285,12 +288,6 @@ struct ContentView: View {
config.gamepath = game.fileURL.path
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 {
config.inputids.append("0")

View File

@ -223,29 +223,7 @@ struct GameLibraryView: View {
var gameInfo = get_game_info(handle.fileDescriptor, extensionPtr)
var game = Game(containerFolder: url.deletingLastPathComponent(), fileType: .item, fileURL: url, titleName: "", titleId: "", developer: "", version: "")
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)
let game = Game.convertGameInfoToGame(gameInfo: gameInfo, url: url)
DispatchQueue.main.async {
startemu = game
@ -321,29 +299,10 @@ struct GameLibraryView: View {
let fileExtension = (fileURLCandidate.pathExtension as NSString).utf8String
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: "")
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)
game.version = String(gameInfo.Version)
game.icon = game.createImage(from: gameInfo)
let gameInfo = get_game_info(handle.fileDescriptor, extensionPtr)
let game = Game.convertGameInfoToGame(gameInfo: gameInfo, url: fileURLCandidate)
games.append(game)
} catch {

View File

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

View File

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

View File

@ -23,7 +23,10 @@ namespace Ryujinx.Graphics.Vulkan.MoltenVK
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.ResumeLostDevice = true;

View File

@ -322,7 +322,14 @@ namespace Ryujinx.Headless.SDL2
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)
@ -1482,42 +1489,41 @@ namespace Ryujinx.Headless.SDL2
{
public ulong FileSize;
public fixed byte TitleName[512];
public ulong TitleId;
public fixed byte TitleId[32];
public fixed byte Developer[256];
public uint Version;
public fixed byte Version[16];
public byte* ImageData;
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;
TitleId = titleId;
Version = version;
fixed (byte* developerPtr = Developer)
fixed (byte* titleNamePtr = TitleName)
fixed (byte* titleIdPtr = TitleId)
fixed (byte* developerPtr = Developer)
fixed (byte* versionPtr = Version)
{
CopyStringToFixedArray(titleName, titleNamePtr, 512);
CopyStringToFixedArray(titleId, titleIdPtr, 32);
CopyStringToFixedArray(developer, developerPtr, 256);
CopyStringToFixedArray(version, versionPtr, 16);
}
if (imageData == null || imageData.Length > 4096 * 4096)
{
// throw new ArgumentException("Image data must not exceed 4 MB.");
ImageSize = (uint)0;
ImageSize = 0;
ImageData = null;
}
else
{
ImageSize = (uint)imageData.Length;
ImageData = (byte*)Marshal.AllocHGlobal(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()
{
if (ImageData != null)
@ -1526,17 +1532,14 @@ namespace Ryujinx.Headless.SDL2
ImageData = null;
}
}
private static void CopyStringToFixedArray(string source, byte* destination, int length)
{
var span = new Span<byte>(destination, length);
span.Clear();
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);
}
}
}
}