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:
parent
f2ea6448dc
commit
cb114fbb68
src
MeloNX
MeloNX.xcodeproj
MeloNX
App
Core
Models
Views
Dependencies
Dynamic Libraries
XCFrameworks/MoltenVK.xcframework/ios-arm64/MoltenVK.framework
Ryujinx.Graphics.Vulkan
Ryujinx.Headless.SDL2
@ -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)";
|
||||||
|
BIN
src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate
generated
BIN
src/MeloNX/MeloNX.xcodeproj/project.xcworkspace/xcuserdata/stossy11.xcuserdatad/UserInterfaceState.xcuserstate
generated
Binary file not shown.
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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] = []
|
||||||
|
@ -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
|
||||||
|
@ -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")
|
||||||
|
@ -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 {
|
||||||
|
@ -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")
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user