mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-06-27 19:06:23 +02:00
Merge branch 'XC-ios-ht' into motionDev
This commit is contained in:
commit
30b9d3cf1c
50 changed files with 6593 additions and 461 deletions
|
@ -3,11 +3,13 @@
|
||||||
# Define the destination directory (hardcoded)
|
# Define the destination directory (hardcoded)
|
||||||
DESTINATION_DIR="src/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib"
|
DESTINATION_DIR="src/MeloNX/Dependencies/Dynamic\ Libraries/Ryujinx.Headless.SDL2.dylib"
|
||||||
|
|
||||||
|
dotnet clean
|
||||||
|
|
||||||
# Restore the project
|
# Restore the project
|
||||||
dotnet restore
|
dotnet restore
|
||||||
|
|
||||||
# Build the project with the specified version
|
# Build the project with the specified version
|
||||||
dotnet build -c Release
|
# dotnet build -c Release
|
||||||
|
|
||||||
# Publish the project with the specified runtime and settings
|
# Publish the project with the specified runtime and settings
|
||||||
dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig"
|
# XCCONFIG_FILE="${SRCROOT}/MeloNX.xcconfig"
|
||||||
|
|
||||||
# Define the common paths to search for dotnet, including user-specific directories
|
|
||||||
SEARCH_PATHS=(
|
SEARCH_PATHS=(
|
||||||
"/usr/local/share/dotnet"
|
"/usr/local/share/dotnet"
|
||||||
"/usr/local/bin"
|
"/usr/local/bin"
|
||||||
|
@ -14,10 +13,10 @@ SEARCH_PATHS=(
|
||||||
"$HOME/Developer"
|
"$HOME/Developer"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Initialize DOTNET_PATH as empty
|
|
||||||
|
|
||||||
DOTNET_PATH=""
|
DOTNET_PATH=""
|
||||||
|
|
||||||
# Search in the defined paths
|
|
||||||
for path in "${SEARCH_PATHS[@]}"; do
|
for path in "${SEARCH_PATHS[@]}"; do
|
||||||
if [ -d "$path" ]; then
|
if [ -d "$path" ]; then
|
||||||
DOTNET_PATH=$(find "$path" -name dotnet -type f -print -quit 2>/dev/null)
|
DOTNET_PATH=$(find "$path" -name dotnet -type f -print -quit 2>/dev/null)
|
||||||
|
@ -27,20 +26,8 @@ for path in "${SEARCH_PATHS[@]}"; do
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Check if the path was found
|
|
||||||
if [ -z "$DOTNET_PATH" ]; then
|
if [ -z "$DOTNET_PATH" ]; then
|
||||||
echo "Error: dotnet path not found."
|
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "dotnet path: $DOTNET_PATH"
|
echo "$DOTNET_PATH"
|
||||||
|
|
||||||
# Escape the path for sed
|
|
||||||
ESCAPED_PATH=$(echo "$DOTNET_PATH" | sed 's/\//\\\//g')
|
|
||||||
|
|
||||||
# Update the xcconfig file
|
|
||||||
sed -i '' "s/^DOTNET = .*/DOTNET = $ESCAPED_PATH/g" "$XCCONFIG_FILE"
|
|
||||||
|
|
||||||
$DOTNET_PATH clean
|
|
||||||
|
|
||||||
echo "Updated MeloNX.xcconfig with DOTNET path: $DOTNET_PATH"
|
|
||||||
|
|
21
distribution/ios/xc-compile.sh
Executable file
21
distribution/ios/xc-compile.sh
Executable file
|
@ -0,0 +1,21 @@
|
||||||
|
dotnet_output=$(./distribution/ios/get_dotnet.sh)
|
||||||
|
exit_code=$?
|
||||||
|
|
||||||
|
if [ $exit_code -eq 0 ]; then
|
||||||
|
dotnet="$dotnet_output"
|
||||||
|
else
|
||||||
|
echo "error: .NET not found, Please follow the compilation instructions on the gitea." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
$dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "warning: Compiling MeloNX failed! Running dotnet clean + restore then Retrying..."
|
||||||
|
|
||||||
|
$dotnet clean
|
||||||
|
|
||||||
|
$dotnet restore
|
||||||
|
|
||||||
|
$dotnet publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true
|
||||||
|
fi
|
|
@ -75,7 +75,7 @@ namespace ARMeilleure.Translation
|
||||||
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
||||||
Stubs = new TranslatorStubs(FunctionTable);
|
Stubs = new TranslatorStubs(FunctionTable);
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.DispatchStub;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
public IPtcLoadState LoadDiskCache(string titleIdText, string displayVersion, bool enabled)
|
||||||
|
|
|
@ -9,5 +9,3 @@
|
||||||
// https://help.apple.com/xcode/#/dev745c5c974
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
VERSION = 1.7.0
|
VERSION = 1.7.0
|
||||||
|
|
||||||
DOTNET = /usr/local/share/dotnet/dotnet
|
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
4E2953AB2D803BC9000497CD /* PBXContainerItemProxy */ = {
|
4E59B0A32DEA5CA9004BFF2A /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 4E80A9852CD6F54500029585 /* Project object */;
|
containerPortal = 4E80A9852CD6F54500029585 /* Project object */;
|
||||||
proxyType = 1;
|
proxyType = 1;
|
||||||
|
@ -120,6 +120,10 @@
|
||||||
CodeSignOnCopy,
|
CodeSignOnCopy,
|
||||||
RemoveHeadersOnCopy,
|
RemoveHeadersOnCopy,
|
||||||
);
|
);
|
||||||
|
"Dependencies/Dynamic Libraries/StosJIT.framework" = (
|
||||||
|
CodeSignOnCopy,
|
||||||
|
RemoveHeadersOnCopy,
|
||||||
|
);
|
||||||
"Dependencies/Dynamic Libraries/libMoltenVK.dylib" = (
|
"Dependencies/Dynamic Libraries/libMoltenVK.dylib" = (
|
||||||
CodeSignOnCopy,
|
CodeSignOnCopy,
|
||||||
);
|
);
|
||||||
|
@ -174,6 +178,7 @@
|
||||||
"Dependencies/Dynamic Libraries/libMoltenVK.dylib",
|
"Dependencies/Dynamic Libraries/libMoltenVK.dylib",
|
||||||
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib",
|
"Dependencies/Dynamic Libraries/Ryujinx.Headless.SDL2.dylib",
|
||||||
"Dependencies/Dynamic Libraries/RyujinxHelper.framework",
|
"Dependencies/Dynamic Libraries/RyujinxHelper.framework",
|
||||||
|
"Dependencies/Dynamic Libraries/StosJIT.framework",
|
||||||
Dependencies/XCFrameworks/libavcodec.xcframework,
|
Dependencies/XCFrameworks/libavcodec.xcframework,
|
||||||
Dependencies/XCFrameworks/libavfilter.xcframework,
|
Dependencies/XCFrameworks/libavfilter.xcframework,
|
||||||
Dependencies/XCFrameworks/libavformat.xcframework,
|
Dependencies/XCFrameworks/libavformat.xcframework,
|
||||||
|
@ -259,12 +264,12 @@
|
||||||
/* Begin PBXLegacyTarget section */
|
/* Begin PBXLegacyTarget section */
|
||||||
BD43C61D2D1B23AB003BBC42 /* Ryujinx */ = {
|
BD43C61D2D1B23AB003BBC42 /* Ryujinx */ = {
|
||||||
isa = PBXLegacyTarget;
|
isa = PBXLegacyTarget;
|
||||||
buildArgumentsString = "publish -c Release -r ios-arm64 -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained true";
|
buildArgumentsString = "./distribution/ios/xc-compile.sh";
|
||||||
buildConfigurationList = BD43C61E2D1B23AB003BBC42 /* Build configuration list for PBXLegacyTarget "Ryujinx" */;
|
buildConfigurationList = BD43C61E2D1B23AB003BBC42 /* Build configuration list for PBXLegacyTarget "Ryujinx" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
);
|
);
|
||||||
buildToolPath = "$(DOTNET)";
|
buildToolPath = /bin/sh;
|
||||||
buildWorkingDirectory = "$(SRCROOT)/../..";
|
buildWorkingDirectory = "$(SRCROOT)/../../";
|
||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = Ryujinx;
|
name = Ryujinx;
|
||||||
|
@ -289,7 +294,7 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
4E2953AC2D803BC9000497CD /* PBXTargetDependency */,
|
4E59B0A42DEA5CA9004BFF2A /* PBXTargetDependency */,
|
||||||
);
|
);
|
||||||
fileSystemSynchronizedGroups = (
|
fileSystemSynchronizedGroups = (
|
||||||
4E80A98F2CD6F54500029585 /* MeloNX */,
|
4E80A98F2CD6F54500029585 /* MeloNX */,
|
||||||
|
@ -477,11 +482,10 @@
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
4E2953AC2D803BC9000497CD /* PBXTargetDependency */ = {
|
4E59B0A42DEA5CA9004BFF2A /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
platformFilter = ios;
|
|
||||||
target = BD43C6212D1B248D003BBC42 /* com.Stossy11.MeloNX.RyujinxAg */;
|
target = BD43C6212D1B248D003BBC42 /* com.Stossy11.MeloNX.RyujinxAg */;
|
||||||
targetProxy = 4E2953AB2D803BC9000497CD /* PBXContainerItemProxy */;
|
targetProxy = 4E59B0A32DEA5CA9004BFF2A /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
4E80A99F2CD6F54700029585 /* PBXTargetDependency */ = {
|
4E80A99F2CD6F54700029585 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
|
@ -566,6 +570,7 @@
|
||||||
ONLY_ACTIVE_ARCH = NO;
|
ONLY_ACTIVE_ARCH = NO;
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
|
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
};
|
};
|
||||||
|
@ -632,6 +637,7 @@
|
||||||
SDKROOT = iphoneos;
|
SDKROOT = iphoneos;
|
||||||
SWIFT_COMPILATION_MODE = wholemodule;
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
SWIFT_DISABLE_SAFETY_CHECKS = YES;
|
SWIFT_DISABLE_SAFETY_CHECKS = YES;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
|
SWIFT_ENFORCE_EXCLUSIVE_ACCESS = "debug-only";
|
||||||
VALIDATE_PRODUCT = YES;
|
VALIDATE_PRODUCT = YES;
|
||||||
};
|
};
|
||||||
|
@ -647,7 +653,7 @@
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
DEVELOPMENT_ASSET_PATHS = "";
|
DEVELOPMENT_ASSET_PATHS = "";
|
||||||
DEVELOPMENT_TEAM = "";
|
DEVELOPMENT_TEAM = 95J8WZ4TN8;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
ENABLE_TESTABILITY = NO;
|
ENABLE_TESTABILITY = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
|
@ -740,6 +746,30 @@
|
||||||
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = z;
|
GCC_OPTIMIZATION_LEVEL = z;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
@ -752,7 +782,7 @@
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||||
|
@ -938,6 +968,39 @@
|
||||||
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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 = "$(VERSION)";
|
MARKETING_VERSION = "$(VERSION)";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
@ -1054,6 +1117,30 @@
|
||||||
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
|
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||||
);
|
);
|
||||||
GCC_OPTIMIZATION_LEVEL = z;
|
GCC_OPTIMIZATION_LEVEL = z;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
@ -1066,7 +1153,7 @@
|
||||||
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
|
||||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||||
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
|
||||||
INFOPLIST_KEY_UIRequiresFullScreen = YES;
|
INFOPLIST_KEY_UIRequiresFullScreen = NO;
|
||||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||||
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
INFOPLIST_KEY_UISupportsDocumentBrowser = YES;
|
||||||
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
IPHONEOS_DEPLOYMENT_TARGET = 15.6;
|
||||||
|
@ -1252,6 +1339,39 @@
|
||||||
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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",
|
||||||
|
"$(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 = "$(VERSION)";
|
MARKETING_VERSION = "$(VERSION)";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||||
|
|
Binary file not shown.
|
@ -17,11 +17,20 @@ func SecTaskCopyValueForEntitlement(
|
||||||
_ error: NSErrorPointer
|
_ error: NSErrorPointer
|
||||||
) -> CFTypeRef?
|
) -> CFTypeRef?
|
||||||
|
|
||||||
|
@_silgen_name("SecTaskCopyTeamIdentifier")
|
||||||
|
func SecTaskCopyTeamIdentifier(
|
||||||
|
_ task: SecTaskRef,
|
||||||
|
_ error: NSErrorPointer
|
||||||
|
) -> NSString?
|
||||||
|
|
||||||
@_silgen_name("SecTaskCreateFromSelf")
|
@_silgen_name("SecTaskCreateFromSelf")
|
||||||
func SecTaskCreateFromSelf(
|
func SecTaskCreateFromSelf(
|
||||||
_ allocator: CFAllocator?
|
_ allocator: CFAllocator?
|
||||||
) -> SecTaskRef?
|
) -> SecTaskRef?
|
||||||
|
|
||||||
|
@_silgen_name("CFRelease")
|
||||||
|
func CFRelease(_ cf: CFTypeRef)
|
||||||
|
|
||||||
@_silgen_name("SecTaskCopyValuesForEntitlements")
|
@_silgen_name("SecTaskCopyValuesForEntitlements")
|
||||||
func SecTaskCopyValuesForEntitlements(
|
func SecTaskCopyValuesForEntitlements(
|
||||||
_ task: SecTaskRef,
|
_ task: SecTaskRef,
|
||||||
|
@ -29,30 +38,43 @@ func SecTaskCopyValuesForEntitlements(
|
||||||
_ error: UnsafeMutablePointer<Unmanaged<CFError>?>?
|
_ error: UnsafeMutablePointer<Unmanaged<CFError>?>?
|
||||||
) -> CFDictionary?
|
) -> CFDictionary?
|
||||||
|
|
||||||
|
func releaseSecTask(_ task: SecTaskRef) {
|
||||||
|
let cf = unsafeBitCast(task, to: CFTypeRef.self)
|
||||||
|
CFRelease(cf)
|
||||||
|
}
|
||||||
|
|
||||||
func checkAppEntitlements(_ ents: [String]) -> [String: Any] {
|
func checkAppEntitlements(_ ents: [String]) -> [String: Any] {
|
||||||
guard let task = SecTaskCreateFromSelf(nil) else {
|
guard let task = SecTaskCreateFromSelf(nil) else {
|
||||||
// print("Failed to create SecTask")
|
|
||||||
return [:]
|
return [:]
|
||||||
}
|
}
|
||||||
|
defer {
|
||||||
|
releaseSecTask(task)
|
||||||
|
}
|
||||||
|
|
||||||
guard let entitlements = SecTaskCopyValuesForEntitlements(task, ents as CFArray, nil) else {
|
guard let entitlements = SecTaskCopyValuesForEntitlements(task, ents as CFArray, nil) else {
|
||||||
// print("Failed to get entitlements")
|
|
||||||
return [:]
|
return [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return (entitlements as? [String: Any]) ?? [:]
|
return (entitlements as NSDictionary) as? [String: Any] ?? [:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkAppEntitlement(_ ent: String) -> Bool {
|
func checkAppEntitlement(_ ent: String) -> Bool {
|
||||||
guard let task = SecTaskCreateFromSelf(nil) else {
|
guard let task = SecTaskCreateFromSelf(nil) else {
|
||||||
// print("Failed to create SecTask")
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
defer {
|
||||||
guard let entitlements = SecTaskCopyValueForEntitlement(task, ent as NSString, nil) else {
|
releaseSecTask(task)
|
||||||
// print("Failed to get entitlements")
|
}
|
||||||
|
|
||||||
|
guard let entitlement = SecTaskCopyValueForEntitlement(task, ent as NSString, nil) else {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return entitlements.boolValue != nil && entitlements.boolValue
|
if let number = entitlement as? NSNumber {
|
||||||
|
return number.boolValue
|
||||||
|
} else if let bool = entitlement as? Bool {
|
||||||
|
return bool
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
#include <SDL2/SDL.h>
|
#include <SDL2/SDL.h>
|
||||||
#include <SDL2/SDL_syswm.h>
|
#include <SDL2/SDL_syswm.h>
|
||||||
|
#include <StosJIT/idevice.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -20,6 +20,14 @@ func isJITEnabled() -> Bool {
|
||||||
return csops(pid: getpid(), ops: 0, useraddr: &flags, usersize: Int32(MemoryLayout.size(ofValue: flags))) == 0 && (flags & Int(CS_DEBUGGED)) != 0 ? allocateTest() : false
|
return csops(pid: getpid(), ops: 0, useraddr: &flags, usersize: Int32(MemoryLayout.size(ofValue: flags))) == 0 && (flags & Int(CS_DEBUGGED)) != 0 ? allocateTest() : false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkDebugged() -> Bool {
|
||||||
|
var flags: Int = 0
|
||||||
|
if checkAppEntitlement("dynamic-codesigning") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return csops(pid: getpid(), ops: 0, useraddr: &flags, usersize: Int32(MemoryLayout.size(ofValue: flags))) == 0 && (flags & Int(CS_DEBUGGED)) != 0
|
||||||
|
}
|
||||||
|
|
||||||
func checkMemoryPermissions(at address: UnsafeRawPointer) -> Bool {
|
func checkMemoryPermissions(at address: UnsafeRawPointer) -> Bool {
|
||||||
var region: vm_address_t = vm_address_t(UInt(bitPattern: address))
|
var region: vm_address_t = vm_address_t(UInt(bitPattern: address))
|
||||||
var regionSize: vm_size_t = 0
|
var regionSize: vm_size_t = 0
|
||||||
|
@ -54,6 +62,7 @@ func allocateTest() -> Bool {
|
||||||
|
|
||||||
memcpy(jitMemory, code, code.count)
|
memcpy(jitMemory, code, code.count)
|
||||||
|
|
||||||
|
|
||||||
if mprotect(jitMemory, pageSize, PROT_READ | PROT_EXEC) != 0 {
|
if mprotect(jitMemory, pageSize, PROT_READ | PROT_EXEC) != 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
@ -118,6 +118,7 @@ func presentAlert(title: String, message: String, completion: (() -> Void)? = ni
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct LaunchApp: Codable {
|
struct LaunchApp: Codable {
|
||||||
let success: Bool
|
let success: Bool
|
||||||
let message: String
|
let message: String
|
||||||
|
|
|
@ -9,11 +9,55 @@ import Foundation
|
||||||
import Network
|
import Network
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
func enableJITStik() {
|
|
||||||
let bundleid = Bundle.main.bundleIdentifier ?? "Unknown"
|
|
||||||
|
func stikJITorStikDebug() -> Int {
|
||||||
|
let teamid = SecTaskCopyTeamIdentifier(SecTaskCreateFromSelf(nil)!, nil)
|
||||||
|
|
||||||
let address = URL(string: "stikjit://enable-jit?bundle-id=\(bundleid)")!
|
if checkifappinstalled("com.stik.sj") {
|
||||||
if UIApplication.shared.canOpenURL(address) {
|
return 1 // StikDebug
|
||||||
UIApplication.shared.open(address)
|
}
|
||||||
|
|
||||||
|
if checkifappinstalled("com.stik.sj.\(String(teamid ?? ""))") {
|
||||||
|
return 2 // StikJIT
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0 // Not Found
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func checkifappinstalled(_ id: String) -> Bool {
|
||||||
|
|
||||||
|
guard let handle = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY) else {
|
||||||
|
if let error = dlerror() {
|
||||||
|
print(String(cString: error))
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
// fatalError("Failed to open dylib")
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias SBSLaunchApplicationWithIdentifierFunc = @convention(c) (CFString, Bool) -> Int32
|
||||||
|
guard let sym = dlsym(handle, "SBSLaunchApplicationWithIdentifier") else {
|
||||||
|
if let error = dlerror() {
|
||||||
|
print(String(cString: error))
|
||||||
|
}
|
||||||
|
dlclose(handle)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let bundleID: CFString = id as CFString
|
||||||
|
let suspended: Bool = false
|
||||||
|
|
||||||
|
|
||||||
|
let SBSLaunchApplicationWithIdentifier = unsafeBitCast(sym, to: SBSLaunchApplicationWithIdentifierFunc.self)
|
||||||
|
let result = SBSLaunchApplicationWithIdentifier(bundleID, suspended)
|
||||||
|
|
||||||
|
return result == 9
|
||||||
|
}
|
||||||
|
|
||||||
|
func enableJITStik() {
|
||||||
|
let urlScheme = "stikjit://enable-jit?bundle-id=\(Bundle.main.bundleIdentifier ?? "wow")"
|
||||||
|
if let launchURL = URL(string: urlScheme), !isJITEnabled() {
|
||||||
|
UIApplication.shared.open(launchURL, options: [:], completionHandler: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MemoryUsageMonitor: ObservableObject {
|
||||||
private var timer: Timer?
|
private var timer: Timer?
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) { [weak self] _ in
|
timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: true) { [weak self] _ in
|
||||||
self?.updateMemoryUsage()
|
self?.updateMemoryUsage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ class MemoryUsageMonitor: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
if result == KERN_SUCCESS {
|
if result == KERN_SUCCESS {
|
||||||
|
memoryUsage = 0
|
||||||
memoryUsage = taskInfo.phys_footprint
|
memoryUsage = taskInfo.phys_footprint
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -46,7 +47,6 @@ class MemoryUsageMonitor: ObservableObject {
|
||||||
formatter.countStyle = .memory
|
formatter.countStyle = .memory
|
||||||
return formatter.string(fromByteCount: Int64(bytes))
|
return formatter.string(fromByteCount: Int64(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
//
|
|
||||||
// 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))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -6,34 +6,28 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
class MTLHud: ObservableObject {
|
||||||
class MTLHud {
|
|
||||||
|
|
||||||
@Published var canMetalHud: Bool = false
|
@Published var canMetalHud: Bool = false
|
||||||
|
|
||||||
var isEnabled: Bool {
|
@AppStorage("MTL_HUD_ENABLED") var metalHudEnabled: Bool = false {
|
||||||
if let getenv = getenv("MTL_HUD_ENABLED") {
|
didSet {
|
||||||
return String(cString: getenv).contains("1")
|
if metalHudEnabled {
|
||||||
|
enable()
|
||||||
|
} else {
|
||||||
|
disable()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static let shared = MTLHud()
|
static let shared = MTLHud()
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
let _ = openMetalDylib() // i'm fixing the warnings just because you said i suck at coding Autumn (propenchiefer,
|
canMetalHud = openMetalDylib() // i'm fixing the warnings just because you said i suck at coding Autumn (propenchiefer, https://youtu.be/tc65SNOTMz4 7:23)
|
||||||
https://youtu.be/tc65SNOTMz4 7:23)
|
|
||||||
if UserDefaults.standard.bool(forKey: "MTL_HUD_ENABLED") {
|
if metalHudEnabled {
|
||||||
enable()
|
|
||||||
} else {
|
|
||||||
disable()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func toggle() {
|
|
||||||
// print(UserDefaults.standard.bool(forKey: "MTL_HUD_ENABLED"))
|
|
||||||
if UserDefaults.standard.bool(forKey: "MTL_HUD_ENABLED") {
|
|
||||||
enable()
|
enable()
|
||||||
} else {
|
} else {
|
||||||
disable()
|
disable()
|
||||||
|
@ -44,14 +38,8 @@ class MTLHud {
|
||||||
let path = "/usr/lib/libMTLHud.dylib"
|
let path = "/usr/lib/libMTLHud.dylib"
|
||||||
|
|
||||||
if dlopen(path, RTLD_NOW) != nil {
|
if dlopen(path, RTLD_NOW) != nil {
|
||||||
// print("Library loaded from \(path)")
|
|
||||||
canMetalHud = true
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
if let error = String(validatingUTF8: dlerror()) {
|
|
||||||
// print("Error loading library: \(error)")
|
|
||||||
}
|
|
||||||
canMetalHud = false
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import SwiftUI
|
||||||
import GameController
|
import GameController
|
||||||
import MetalKit
|
import MetalKit
|
||||||
import Metal
|
import Metal
|
||||||
|
import Darwin
|
||||||
|
|
||||||
class LogCapture {
|
class LogCapture {
|
||||||
static let shared = LogCapture()
|
static let shared = LogCapture()
|
||||||
|
@ -117,6 +118,11 @@ struct iOSNav<Content: View>: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func threadEntry(_ arg: () -> Void) -> UnsafeMutableRawPointer? {
|
||||||
|
arg()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class Ryujinx : ObservableObject {
|
class Ryujinx : ObservableObject {
|
||||||
@Published var isRunning = false
|
@Published var isRunning = false
|
||||||
|
@ -128,12 +134,12 @@ class Ryujinx : ObservableObject {
|
||||||
@Published var isPortrait = false
|
@Published var isPortrait = false
|
||||||
@Published var firmwareversion = "0"
|
@Published var firmwareversion = "0"
|
||||||
@Published var emulationUIView: MeloMTKView? = nil
|
@Published var emulationUIView: MeloMTKView? = nil
|
||||||
@Published var config: Ryujinx.Configuration? = nil
|
@Published var config: Ryujinx.Arguments? = nil
|
||||||
@Published var games: [Game] = []
|
@Published var games: [Game] = []
|
||||||
|
|
||||||
@Published var defMLContentSize: CGFloat?
|
@Published var defMLContentSize: CGFloat?
|
||||||
|
|
||||||
var thread: Thread = Thread { }
|
var thread: pthread_t? = nil
|
||||||
|
|
||||||
@Published var jitenabled = false
|
@Published var jitenabled = false
|
||||||
|
|
||||||
|
@ -142,8 +148,8 @@ class Ryujinx : ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
static let shared = Ryujinx()
|
static let shared = Ryujinx()
|
||||||
|
|
||||||
private init() {
|
func addGames() {
|
||||||
self.games = loadGames()
|
self.games = loadGames()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,46 +159,64 @@ class Ryujinx : ObservableObject {
|
||||||
cool()
|
cool()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
thread = Thread {
|
// Box the closure
|
||||||
cool()
|
let boxed = Unmanaged.passRetained(ClosureBox(cool)).toOpaque()
|
||||||
|
|
||||||
|
var thread: pthread_t?
|
||||||
|
let result = pthread_create(&thread, nil, { arg in
|
||||||
|
let unmanaged = Unmanaged<ClosureBox>.fromOpaque(arg)
|
||||||
|
let box = unmanaged.takeRetainedValue()
|
||||||
|
box.closure()
|
||||||
|
return nil
|
||||||
|
}, boxed)
|
||||||
|
|
||||||
|
if result == 0 {
|
||||||
|
pthread_detach(thread!)
|
||||||
|
} else {
|
||||||
|
print("Failed to create thread: \(result)")
|
||||||
|
Unmanaged<ClosureBox>.fromOpaque(boxed).release()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
thread.qualityOfService = .userInteractive
|
}
|
||||||
thread.name = "MeloNX"
|
|
||||||
thread.start()
|
private class ClosureBox {
|
||||||
|
let closure: () -> Void
|
||||||
|
init(_ closure: @escaping () -> Void) {
|
||||||
|
self.closure = closure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct Configuration : Codable, Equatable {
|
public class Arguments : Observable, Codable, Equatable {
|
||||||
var gamepath: String
|
var gamepath: String
|
||||||
var inputids: [String]
|
var inputids: [String]
|
||||||
var inputDSUServers: [String]
|
var inputDSUServers: [String]
|
||||||
var resscale: Float
|
var resscale: Float = 1.0
|
||||||
var debuglogs: Bool
|
var debuglogs: Bool = false
|
||||||
var tracelogs: Bool
|
var tracelogs: Bool = false
|
||||||
var nintendoinput: Bool
|
var nintendoinput: Bool = true
|
||||||
var enableInternet: Bool
|
var enableInternet: Bool = false
|
||||||
var listinputids: Bool
|
var listinputids: Bool = false
|
||||||
var aspectRatio: AspectRatio
|
var aspectRatio: AspectRatio = .fixed16x9
|
||||||
var memoryManagerMode: String
|
var memoryManagerMode: String = "HostMappedUnsafe"
|
||||||
var disableShaderCache: Bool
|
var disableShaderCache: Bool = false
|
||||||
var hypervisor: Bool
|
var hypervisor: Bool = false
|
||||||
var disableDockedMode: Bool
|
var disableDockedMode: Bool = false
|
||||||
var enableTextureRecompression: Bool
|
var enableTextureRecompression: Bool = true
|
||||||
var additionalArgs: [String]
|
var additionalArgs: [String] = []
|
||||||
var maxAnisotropy: Float
|
var maxAnisotropy: Float = 1.0
|
||||||
var macroHLE: Bool
|
var macroHLE: Bool = true
|
||||||
var ignoreMissingServices: Bool
|
var ignoreMissingServices: Bool = false
|
||||||
var expandRam: Bool
|
var expandRam: Bool = false
|
||||||
var dfsIntegrityChecks: Bool
|
var dfsIntegrityChecks: Bool = false
|
||||||
var disablePTC: Bool
|
var disablePTC: Bool = false
|
||||||
var disablevsync: Bool
|
var disablevsync: Bool = false
|
||||||
var language: SystemLanguage
|
var language: SystemLanguage = .americanEnglish
|
||||||
var regioncode: SystemRegionCode
|
var regioncode: SystemRegionCode = .usa
|
||||||
var handHeldController: Bool
|
var handHeldController: Bool = true
|
||||||
|
var backendMultithreading: Bool = true
|
||||||
|
|
||||||
|
|
||||||
init(gamepath: String,
|
init(gamepath: String = "",
|
||||||
inputids: [String] = [],
|
inputids: [String] = [],
|
||||||
inputDSUServers: [String] = [],
|
inputDSUServers: [String] = [],
|
||||||
debuglogs: Bool = false,
|
debuglogs: Bool = false,
|
||||||
|
@ -217,7 +241,8 @@ class Ryujinx : ObservableObject {
|
||||||
disablevsync: Bool = false,
|
disablevsync: Bool = false,
|
||||||
language: SystemLanguage = .americanEnglish,
|
language: SystemLanguage = .americanEnglish,
|
||||||
regioncode: SystemRegionCode = .usa,
|
regioncode: SystemRegionCode = .usa,
|
||||||
handHeldController: Bool = false
|
handHeldController: Bool = false,
|
||||||
|
backendMultithreading: Bool = true
|
||||||
) {
|
) {
|
||||||
self.gamepath = gamepath
|
self.gamepath = gamepath
|
||||||
self.inputids = inputids
|
self.inputids = inputids
|
||||||
|
@ -245,11 +270,39 @@ class Ryujinx : ObservableObject {
|
||||||
self.language = language
|
self.language = language
|
||||||
self.regioncode = regioncode
|
self.regioncode = regioncode
|
||||||
self.handHeldController = handHeldController
|
self.handHeldController = handHeldController
|
||||||
|
self.backendMultithreading = backendMultithreading
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static func == (lhs: Arguments, rhs: Arguments) -> Bool {
|
||||||
|
return lhs.resscale == rhs.resscale &&
|
||||||
|
lhs.debuglogs == rhs.debuglogs &&
|
||||||
|
lhs.tracelogs == rhs.tracelogs &&
|
||||||
|
lhs.nintendoinput == rhs.nintendoinput &&
|
||||||
|
lhs.enableInternet == rhs.enableInternet &&
|
||||||
|
lhs.listinputids == rhs.listinputids &&
|
||||||
|
lhs.aspectRatio == rhs.aspectRatio &&
|
||||||
|
lhs.memoryManagerMode == rhs.memoryManagerMode &&
|
||||||
|
lhs.disableShaderCache == rhs.disableShaderCache &&
|
||||||
|
lhs.hypervisor == rhs.hypervisor &&
|
||||||
|
lhs.disableDockedMode == rhs.disableDockedMode &&
|
||||||
|
lhs.enableTextureRecompression == rhs.enableTextureRecompression &&
|
||||||
|
lhs.additionalArgs == rhs.additionalArgs &&
|
||||||
|
lhs.maxAnisotropy == rhs.maxAnisotropy &&
|
||||||
|
lhs.macroHLE == rhs.macroHLE &&
|
||||||
|
lhs.ignoreMissingServices == rhs.ignoreMissingServices &&
|
||||||
|
lhs.expandRam == rhs.expandRam &&
|
||||||
|
lhs.dfsIntegrityChecks == rhs.dfsIntegrityChecks &&
|
||||||
|
lhs.disablePTC == rhs.disablePTC &&
|
||||||
|
lhs.disablevsync == rhs.disablevsync &&
|
||||||
|
lhs.language == rhs.language &&
|
||||||
|
lhs.regioncode == rhs.regioncode &&
|
||||||
|
lhs.handHeldController == rhs.handHeldController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func start(with config: Configuration) throws {
|
func start(with config: Arguments) throws {
|
||||||
guard !isRunning else {
|
guard !isRunning else {
|
||||||
throw RyujinxError.alreadyRunning
|
throw RyujinxError.alreadyRunning
|
||||||
}
|
}
|
||||||
|
@ -257,6 +310,32 @@ class Ryujinx : ObservableObject {
|
||||||
self.config = config
|
self.config = config
|
||||||
|
|
||||||
|
|
||||||
|
if UserDefaults.standard.bool(forKey: "lockInApp") {
|
||||||
|
let cool = Thread {
|
||||||
|
while true {
|
||||||
|
if UserDefaults.standard.bool(forKey: "lockInApp") {
|
||||||
|
if let workspaceClass = NSClassFromString("LSApplicationWorkspace") as? NSObject.Type,
|
||||||
|
let workspace = workspaceClass.perform(NSSelectorFromString("defaultWorkspace"))?.takeUnretainedValue() {
|
||||||
|
|
||||||
|
let selector = NSSelectorFromString("openApplicationWithBundleID:")
|
||||||
|
|
||||||
|
if workspace.responds(to: selector) {
|
||||||
|
workspace.perform(selector, with: Bundle.main.bundleIdentifier ?? "")
|
||||||
|
} else {
|
||||||
|
print("Selector not found or not responding.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("Could not get LSApplicationWorkspace class.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cool.qualityOfService = .userInteractive
|
||||||
|
cool.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
runloop { [self] in
|
runloop { [self] in
|
||||||
|
|
||||||
isRunning = true
|
isRunning = true
|
||||||
|
@ -383,10 +462,12 @@ class Ryujinx : ObservableObject {
|
||||||
|
|
||||||
isRunning = false
|
isRunning = false
|
||||||
|
|
||||||
|
UserDefaults.standard.set(false, forKey: "lockInApp")
|
||||||
|
|
||||||
self.emulationUIView = nil
|
self.emulationUIView = nil
|
||||||
self.metalLayer = nil
|
self.metalLayer = nil
|
||||||
|
|
||||||
thread.cancel()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,10 +515,9 @@ class Ryujinx : ObservableObject {
|
||||||
// print("Error loading games from roms folder: \(error)")
|
// print("Error loading games from roms folder: \(error)")
|
||||||
return games
|
return games
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func buildCommandLineArgs(from config: Configuration) -> [String] {
|
private func buildCommandLineArgs(from config: Arguments) -> [String] {
|
||||||
var args: [String] = []
|
var args: [String] = []
|
||||||
|
|
||||||
// Add the game path
|
// Add the game path
|
||||||
|
@ -479,6 +559,14 @@ class Ryujinx : ObservableObject {
|
||||||
|
|
||||||
args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue])
|
args.append(contentsOf: ["--aspect-ratio", config.aspectRatio.rawValue])
|
||||||
|
|
||||||
|
// args.append(contentsOf: ["--system-timezone", TimeZone.current.identifier])
|
||||||
|
|
||||||
|
args.append(contentsOf: ["--system-time-offset", String(TimeZone.current.secondsFromGMT())])
|
||||||
|
|
||||||
|
if !config.backendMultithreading {
|
||||||
|
args.append(contentsOf: ["--backend-multithreading", "Off"])
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if config.nintendoinput {
|
if config.nintendoinput {
|
||||||
args.append("--correct-controller")
|
args.append("--correct-controller")
|
||||||
|
|
|
@ -45,23 +45,25 @@ struct ControllerView: View {
|
||||||
HStack(spacing: 30) {
|
HStack(spacing: 30) {
|
||||||
VStack(spacing: 15) {
|
VStack(spacing: 15) {
|
||||||
ShoulderButtonsViewLeft()
|
ShoulderButtonsViewLeft()
|
||||||
|
.padding(.vertical)
|
||||||
ZStack {
|
ZStack {
|
||||||
JoystickController(showBackground: $hideDpad)
|
JoystickController(showBackground: $hideDpad)
|
||||||
if !hideDpad {
|
DPadView()
|
||||||
DPadView()
|
.opacity(hideDpad ? 0 : 1)
|
||||||
.animation(.easeInOut(duration: 0.2), value: hideDpad)
|
.allowsHitTesting(!hideDpad)
|
||||||
}
|
.animation(.easeInOut(duration: 0.2), value: hideDpad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
VStack(spacing: 15) {
|
VStack(spacing: 15) {
|
||||||
ShoulderButtonsViewRight()
|
ShoulderButtonsViewRight()
|
||||||
|
.padding(.vertical)
|
||||||
ZStack {
|
ZStack {
|
||||||
JoystickController(iscool: true, showBackground: $hideABXY)
|
JoystickController(iscool: true, showBackground: $hideABXY)
|
||||||
if !hideABXY {
|
ABXYView()
|
||||||
ABXYView()
|
.opacity(hideABXY ? 0 : 1)
|
||||||
.animation(.easeInOut(duration: 0.2), value: hideABXY)
|
.allowsHitTesting(!hideABXY)
|
||||||
}
|
.animation(.easeInOut(duration: 0.2), value: hideABXY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -90,12 +92,13 @@ struct ControllerView: View {
|
||||||
HStack {
|
HStack {
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
ShoulderButtonsViewLeft()
|
ShoulderButtonsViewLeft()
|
||||||
|
.padding(.vertical)
|
||||||
ZStack {
|
ZStack {
|
||||||
JoystickController(showBackground: $hideDpad)
|
JoystickController(showBackground: $hideDpad)
|
||||||
if !hideDpad {
|
DPadView()
|
||||||
DPadView()
|
.opacity(hideDpad ? 0 : 1)
|
||||||
.animation(.easeInOut(duration: 0.2), value: hideDpad)
|
.allowsHitTesting(!hideDpad)
|
||||||
}
|
.animation(.easeInOut(duration: 0.2), value: hideDpad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,12 +110,13 @@ struct ControllerView: View {
|
||||||
|
|
||||||
VStack(spacing: 20) {
|
VStack(spacing: 20) {
|
||||||
ShoulderButtonsViewRight()
|
ShoulderButtonsViewRight()
|
||||||
|
.padding(.vertical)
|
||||||
ZStack {
|
ZStack {
|
||||||
JoystickController(iscool: true, showBackground: $hideABXY)
|
JoystickController(iscool: true, showBackground: $hideABXY)
|
||||||
if !hideABXY {
|
ABXYView()
|
||||||
ABXYView()
|
.opacity(hideABXY ? 0 : 1)
|
||||||
.animation(.easeInOut(duration: 0.2), value: hideABXY)
|
.allowsHitTesting(!hideABXY)
|
||||||
}
|
.animation(.easeInOut(duration: 0.2), value: hideABXY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,7 +286,7 @@ struct ButtonView: View {
|
||||||
.scaledToFit()
|
.scaledToFit()
|
||||||
.frame(width: size.width, height: size.height)
|
.frame(width: size.width, height: size.height)
|
||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
.opacity(isPressed ? 0.6 : 1.0)
|
.opacity(isPressed ? 0.6 : 0.8)
|
||||||
.allowsHitTesting(false)
|
.allowsHitTesting(false)
|
||||||
}
|
}
|
||||||
.frame(width: size.width, height: size.height)
|
.frame(width: size.width, height: size.height)
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct Joystick: View {
|
struct Joystick: View {
|
||||||
|
@AppStorage("On-ScreenControllerScale") var controllerScale: Double = 1.0
|
||||||
|
|
||||||
@Binding var position: CGPoint
|
@Binding var position: CGPoint
|
||||||
@State var joystickSize: CGFloat
|
@State var joystickSize: CGFloat
|
||||||
var boundarySize: CGFloat
|
var boundarySize: CGFloat
|
||||||
|
@ -17,6 +19,7 @@ struct Joystick: View {
|
||||||
@Binding var showBackground: Bool
|
@Binding var showBackground: Bool
|
||||||
|
|
||||||
let sensitivity: CGFloat = 1.5
|
let sensitivity: CGFloat = 1.5
|
||||||
|
|
||||||
|
|
||||||
var dragGesture: some Gesture {
|
var dragGesture: some Gesture {
|
||||||
DragGesture()
|
DragGesture()
|
||||||
|
@ -56,12 +59,14 @@ struct Joystick: View {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(Color.clear.opacity(0))
|
.fill(Color.clear.opacity(0))
|
||||||
.frame(width: boundarySize, height: boundarySize)
|
.frame(width: boundarySize, height: boundarySize)
|
||||||
|
.scaleEffect(controllerScale)
|
||||||
|
|
||||||
if showBackground {
|
if showBackground {
|
||||||
Circle()
|
Circle()
|
||||||
.fill(Color.gray.opacity(0.4))
|
.fill(Color.gray.opacity(0.4))
|
||||||
.frame(width: boundarySize, height: boundarySize)
|
.frame(width: boundarySize, height: boundarySize)
|
||||||
.animation(.easeInOut(duration: 0.1), value: showBackground)
|
.animation(.easeInOut(duration: 0.1), value: showBackground)
|
||||||
|
.scaleEffect(controllerScale)
|
||||||
}
|
}
|
||||||
|
|
||||||
Circle()
|
Circle()
|
||||||
|
@ -74,6 +79,7 @@ struct Joystick: View {
|
||||||
)
|
)
|
||||||
.offset(offset)
|
.offset(offset)
|
||||||
.gesture(dragGesture)
|
.gesture(dragGesture)
|
||||||
|
.scaleEffect(controllerScale)
|
||||||
}
|
}
|
||||||
.frame(width: boundarySize, height: boundarySize)
|
.frame(width: boundarySize, height: boundarySize)
|
||||||
.onChange(of: showBackground) { newValue in
|
.onChange(of: showBackground) { newValue in
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct JoystickController: View {
|
||||||
@State var position: CGPoint = CGPoint(x: 0, y: 0)
|
@State var position: CGPoint = CGPoint(x: 0, y: 0)
|
||||||
var dragDiameter: CGFloat {
|
var dragDiameter: CGFloat {
|
||||||
var selfs = CGFloat(160)
|
var selfs = CGFloat(160)
|
||||||
selfs *= controllerScale
|
// selfs *= controllerScale
|
||||||
if UIDevice.current.systemName.contains("iPadOS") {
|
if UIDevice.current.systemName.contains("iPadOS") {
|
||||||
return selfs * 1.2
|
return selfs * 1.2
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,6 @@ struct JoystickController: View {
|
||||||
VStack {
|
VStack {
|
||||||
Joystick(position: $position, joystickSize: dragDiameter * 0.2, boundarySize: dragDiameter, showBackground: $showBackground)
|
Joystick(position: $position, joystickSize: dragDiameter * 0.2, boundarySize: dragDiameter, showBackground: $showBackground)
|
||||||
.onChange(of: position) { newValue in
|
.onChange(of: position) { newValue in
|
||||||
let scaledX = Float(newValue.x)
|
|
||||||
let scaledY = Float(newValue.y) // my dumbass broke this by having -y instead of y :/
|
|
||||||
// print("Joystick Position: (\(scaledX), \(scaledY))")
|
|
||||||
|
|
||||||
if iscool != nil {
|
if iscool != nil {
|
||||||
Ryujinx.shared.virtualController.thumbstickMoved(.right, x: newValue.x, y: newValue.y)
|
Ryujinx.shared.virtualController.thumbstickMoved(.right, x: newValue.x, y: newValue.y)
|
||||||
|
|
|
@ -14,6 +14,10 @@ struct EmulationView: View {
|
||||||
@AppStorage("showScreenShotButton") var ssb: Bool = false
|
@AppStorage("showScreenShotButton") var ssb: Bool = false
|
||||||
@AppStorage("showlogsgame") var showlogsgame: Bool = false
|
@AppStorage("showlogsgame") var showlogsgame: Bool = false
|
||||||
|
|
||||||
|
@AppStorage("On-ScreenControllerOpacity") var controllerOpacity: Double = 1.0
|
||||||
|
|
||||||
|
@AppStorage("disableTouch") var blackScreen = false
|
||||||
|
|
||||||
@State var isPresentedThree: Bool = false
|
@State var isPresentedThree: Bool = false
|
||||||
@State var isAirplaying = Air.shared.connected
|
@State var isAirplaying = Air.shared.connected
|
||||||
@Binding var startgame: Game?
|
@Binding var startgame: Game?
|
||||||
|
@ -31,6 +35,11 @@ struct EmulationView: View {
|
||||||
.onAppear {
|
.onAppear {
|
||||||
Air.play(AnyView(MetalView().ignoresSafeArea().edgesIgnoringSafeArea(.all)))
|
Air.play(AnyView(MetalView().ignoresSafeArea().edgesIgnoringSafeArea(.all)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Color.black
|
||||||
|
.ignoresSafeArea()
|
||||||
|
.edgesIgnoringSafeArea(.all)
|
||||||
|
.allowsHitTesting(false)
|
||||||
} else {
|
} else {
|
||||||
MetalView() // The Emulation View
|
MetalView() // The Emulation View
|
||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
|
@ -41,6 +50,8 @@ struct EmulationView: View {
|
||||||
|
|
||||||
if isVCA {
|
if isVCA {
|
||||||
ControllerView() // Virtual Controller
|
ControllerView() // Virtual Controller
|
||||||
|
.opacity(controllerOpacity)
|
||||||
|
.allowsHitTesting(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
Group {
|
Group {
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
// 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())")
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.stroke(color: .black, width: 2)
|
||||||
|
Text(memorymonitor.formatMemorySize(memorymonitor.memoryUsage))
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
.stroke(color: .black, width: 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func stroke(color: Color, width: CGFloat = 1) -> some View {
|
||||||
|
modifier(StrokeModifier(strokeSize: width, strokeColor: color))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct StrokeModifier: ViewModifier {
|
||||||
|
private let id = UUID()
|
||||||
|
var strokeSize: CGFloat = 1
|
||||||
|
var strokeColor: Color = .blue
|
||||||
|
|
||||||
|
func body(content: Content) -> some View {
|
||||||
|
if strokeSize > 0 {
|
||||||
|
appliedStrokeBackground(content: content)
|
||||||
|
} else {
|
||||||
|
content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func appliedStrokeBackground(content: Content) -> some View {
|
||||||
|
content
|
||||||
|
.padding(strokeSize*2)
|
||||||
|
.background(
|
||||||
|
Rectangle()
|
||||||
|
.foregroundColor(strokeColor)
|
||||||
|
.mask(alignment: .center) {
|
||||||
|
mask(content: content)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func mask(content: Content) -> some View {
|
||||||
|
Canvas { context, size in
|
||||||
|
context.addFilter(.alphaThreshold(min: 0.01))
|
||||||
|
if let resolvedView = context.resolveSymbol(id: id) {
|
||||||
|
context.draw(resolvedView, at: .init(x: size.width/2, y: size.height/2))
|
||||||
|
}
|
||||||
|
} symbols: {
|
||||||
|
content
|
||||||
|
.tag(id)
|
||||||
|
.blur(radius: strokeSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import Darwin
|
||||||
import UIKit
|
import UIKit
|
||||||
import MetalKit
|
import MetalKit
|
||||||
import CoreLocation
|
import CoreLocation
|
||||||
|
import StosJIT
|
||||||
|
|
||||||
struct MoltenVKSettings: Codable, Hashable {
|
struct MoltenVKSettings: Codable, Hashable {
|
||||||
let string: String
|
let string: String
|
||||||
|
@ -32,11 +33,16 @@ struct ContentView: View {
|
||||||
@AppStorage("isVirtualController") var isVCA: Bool = true
|
@AppStorage("isVirtualController") var isVCA: Bool = true
|
||||||
|
|
||||||
// Settings and Configuration
|
// Settings and Configuration
|
||||||
@State private var config: Ryujinx.Configuration
|
private var config: Ryujinx.Arguments {
|
||||||
|
settingsManager.config
|
||||||
|
}
|
||||||
|
|
||||||
|
@StateObject private var settingsManager = SettingsManager.shared
|
||||||
|
|
||||||
@State var settings: [MoltenVKSettings]
|
@State var settings: [MoltenVKSettings]
|
||||||
@AppStorage("useTrollStore") var useTrollStore: Bool = false
|
|
||||||
|
|
||||||
// JIT
|
// JIT
|
||||||
|
@AppStorage("useTrollStore") var useTrollStore: Bool = false
|
||||||
@AppStorage("jitStreamerEB") var jitStreamerEB: Bool = false
|
@AppStorage("jitStreamerEB") var jitStreamerEB: Bool = false
|
||||||
@AppStorage("stikJIT") var stikJIT: Bool = false
|
@AppStorage("stikJIT") var stikJIT: Bool = false
|
||||||
|
|
||||||
|
@ -55,6 +61,9 @@ struct ContentView: View {
|
||||||
private let animationDuration: Double = 1.0
|
private let animationDuration: Double = 1.0
|
||||||
@State private var isAnimating = false
|
@State private var isAnimating = false
|
||||||
@State var isLoading = true
|
@State var isLoading = true
|
||||||
|
|
||||||
|
|
||||||
|
// MARK: - CORE
|
||||||
@StateObject var ryujinx = Ryujinx.shared
|
@StateObject var ryujinx = Ryujinx.shared
|
||||||
|
|
||||||
// MARK: - SDL
|
// MARK: - SDL
|
||||||
|
@ -62,14 +71,6 @@ struct ContentView: View {
|
||||||
|
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
init() {
|
init() {
|
||||||
var defaultConfig = loadSettings()
|
|
||||||
if defaultConfig == nil {
|
|
||||||
saveSettings(config: .init(gamepath: ""))
|
|
||||||
defaultConfig = loadSettings()
|
|
||||||
}
|
|
||||||
|
|
||||||
_config = State(initialValue: defaultConfig!)
|
|
||||||
|
|
||||||
let defaultSettings: [MoltenVKSettings] = [
|
let defaultSettings: [MoltenVKSettings] = [
|
||||||
MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"),
|
MoltenVKSettings(string: "MVK_USE_METAL_PRIVATE_API", value: "1"),
|
||||||
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"),
|
MoltenVKSettings(string: "MVK_CONFIG_USE_METAL_PRIVATE_API", value: "1"),
|
||||||
|
@ -139,7 +140,6 @@ struct ContentView: View {
|
||||||
private var mainMenuView: some View {
|
private var mainMenuView: some View {
|
||||||
MainTabView(
|
MainTabView(
|
||||||
startemu: $game,
|
startemu: $game,
|
||||||
config: $config,
|
|
||||||
MVKconfig: $settings,
|
MVKconfig: $settings,
|
||||||
controllersList: $controllersList,
|
controllersList: $controllersList,
|
||||||
currentControllers: $currentControllers,
|
currentControllers: $currentControllers,
|
||||||
|
@ -155,6 +155,8 @@ struct ContentView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UserDefaults.standard.set(false, forKey: "lockInApp")
|
||||||
|
|
||||||
// print(MTLHud.shared.isEnabled)
|
// print(MTLHud.shared.isEnabled)
|
||||||
|
|
||||||
initControllerObservers()
|
initControllerObservers()
|
||||||
|
@ -163,6 +165,11 @@ struct ContentView: View {
|
||||||
ControllerListView(game: $game)
|
ControllerListView(game: $game)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
refreshControllersList()
|
||||||
|
|
||||||
|
|
||||||
|
ryujinx.addGames()
|
||||||
|
|
||||||
checkJitStatus()
|
checkJitStatus()
|
||||||
}
|
}
|
||||||
.onOpenURL { url in
|
.onOpenURL { url in
|
||||||
|
@ -399,6 +406,8 @@ struct ContentView: View {
|
||||||
if jitStreamerEB {
|
if jitStreamerEB {
|
||||||
jitStreamerEB = false // byee jitstreamer eb
|
jitStreamerEB = false // byee jitstreamer eb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if !ryujinx.jitenabled {
|
if !ryujinx.jitenabled {
|
||||||
if useTrollStore {
|
if useTrollStore {
|
||||||
askForJIT()
|
askForJIT()
|
||||||
|
@ -407,7 +416,12 @@ struct ContentView: View {
|
||||||
} else if jitStreamerEB {
|
} else if jitStreamerEB {
|
||||||
enableJITEB()
|
enableJITEB()
|
||||||
} else {
|
} else {
|
||||||
// print("no JIT")
|
if !allocateTest(), checkDebugged() {
|
||||||
|
loop_heartbeat()
|
||||||
|
sleep(5)
|
||||||
|
let cool = String(cString: attach(getpid())!)
|
||||||
|
print(cool)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,13 +429,13 @@ struct ContentView: View {
|
||||||
private func handleDeepLink(_ url: URL) {
|
private func handleDeepLink(_ url: URL) {
|
||||||
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
|
||||||
components.host == "game" {
|
components.host == "game" {
|
||||||
DispatchQueue.main.async {
|
|
||||||
refreshControllersList()
|
refreshControllersList()
|
||||||
if let text = components.queryItems?.first(where: { $0.name == "id" })?.value {
|
|
||||||
game = ryujinx.games.first(where: { $0.titleId == text })
|
if let text = components.queryItems?.first(where: { $0.name == "id" })?.value {
|
||||||
} else if let text = components.queryItems?.first(where: { $0.name == "name" })?.value {
|
game = ryujinx.games.first(where: { $0.titleId == text })
|
||||||
game = ryujinx.games.first(where: { $0.titleName == text })
|
} else if let text = components.queryItems?.first(where: { $0.name == "name" })?.value {
|
||||||
}
|
game = ryujinx.games.first(where: { $0.titleName == text })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,7 +494,6 @@ class LocationManager: NSObject, CLLocationManagerDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct ControllerListView: View {
|
struct ControllerListView: View {
|
||||||
@State private var selectedIndex = 0
|
@State private var selectedIndex = 0
|
||||||
@Binding var game: Game?
|
@Binding var game: Game?
|
||||||
|
|
|
@ -273,7 +273,7 @@ struct GameLibraryView: View {
|
||||||
gameRequirements: $gameRequirements,
|
gameRequirements: $gameRequirements,
|
||||||
gameInfo: $gameInfo
|
gameInfo: $gameInfo
|
||||||
)
|
)
|
||||||
.padding(.horizontal, 3)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +290,7 @@ struct GameLibraryView: View {
|
||||||
gameRequirements: $gameRequirements,
|
gameRequirements: $gameRequirements,
|
||||||
gameInfo: $gameInfo
|
gameInfo: $gameInfo
|
||||||
)
|
)
|
||||||
.padding(.horizontal, 3)
|
.padding(.horizontal)
|
||||||
.padding(.vertical, 8)
|
.padding(.vertical, 8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -314,12 +314,19 @@ struct GameLibraryView: View {
|
||||||
} else {
|
} else {
|
||||||
Menu("Applets") {
|
Menu("Applets") {
|
||||||
Button {
|
Button {
|
||||||
let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "0x0100000000001009")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
||||||
self.startemu = game
|
self.startemu = game
|
||||||
} label: {
|
} label: {
|
||||||
Label("Launch Mii Maker", systemImage: "person.crop.circle")
|
Label("Launch Mii Maker", systemImage: "person.crop.circle")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "0x0100000000001000")!, titleName: "Home Menu (Broken)", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
||||||
|
self.startemu = game
|
||||||
|
} label: {
|
||||||
|
Label("Home Menu (Broken)", systemImage: "house.circle")
|
||||||
|
}
|
||||||
|
.foregroundStyle(.red)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -658,6 +665,7 @@ struct GameCardView: View {
|
||||||
@Binding var gameRequirements: [GameRequirements]
|
@Binding var gameRequirements: [GameRequirements]
|
||||||
@Binding var gameInfo: Game?
|
@Binding var gameInfo: Game?
|
||||||
@Environment(\.colorScheme) var colorScheme
|
@Environment(\.colorScheme) var colorScheme
|
||||||
|
let totalMemory = ProcessInfo.processInfo.physicalMemory
|
||||||
|
|
||||||
var gameRequirement: GameRequirements? {
|
var gameRequirement: GameRequirements? {
|
||||||
gameRequirements.first(where: { $0.game_id == game.titleId })
|
gameRequirements.first(where: { $0.game_id == game.titleId })
|
||||||
|
@ -729,7 +737,17 @@ struct GameCardView: View {
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.padding(.horizontal, 6)
|
.padding(.horizontal, 6)
|
||||||
.padding(.vertical, 2)
|
.padding(.vertical, 2)
|
||||||
.background(Color.blue)
|
.background(req.memoryInt <= Int(String(format: "%.0f", Double(totalMemory) / 1_000_000_000)) ?? 0 ? Color.blue : Color.red)
|
||||||
|
.cornerRadius(4)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Text("0GB")
|
||||||
|
.font(.system(size: 10, weight: .medium))
|
||||||
|
.foregroundColor(.clear)
|
||||||
|
.padding(.horizontal, 6)
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
.background(Color.clear)
|
||||||
.cornerRadius(4)
|
.cornerRadius(4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -796,16 +814,15 @@ struct GameListRow: View {
|
||||||
|
|
||||||
HStack {
|
HStack {
|
||||||
Text(game.developer)
|
Text(game.developer)
|
||||||
.font(.system(size: 14))
|
.font(.system(size: 12))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
.multilineTextAlignment(.leading)
|
.multilineTextAlignment(.leading)
|
||||||
|
|
||||||
if !game.version.isEmpty && game.version != "0" {
|
if !game.version.isEmpty && game.version != "0" {
|
||||||
Text("•")
|
Divider().frame(width: 1, height: 15)
|
||||||
.foregroundColor(.secondary)
|
|
||||||
|
|
||||||
Text("v\(game.version)")
|
Text("v\(game.version)")
|
||||||
.font(.system(size: 14))
|
.font(.system(size: 10))
|
||||||
.foregroundColor(.secondary)
|
.foregroundColor(.secondary)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -820,7 +837,6 @@ struct GameListRow: View {
|
||||||
let totalMemory = ProcessInfo.processInfo.physicalMemory
|
let totalMemory = ProcessInfo.processInfo.physicalMemory
|
||||||
|
|
||||||
HStack(spacing: 4) {
|
HStack(spacing: 4) {
|
||||||
// Memory requirement badge
|
|
||||||
Text(gameReq.device_memory)
|
Text(gameReq.device_memory)
|
||||||
.font(.system(size: 11, weight: .medium))
|
.font(.system(size: 11, weight: .medium))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
|
@ -830,8 +846,11 @@ struct GameListRow: View {
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(gameReq.memoryInt <= Int(String(format: "%.0f", Double(totalMemory) / 1_000_000_000)) ?? 0 ? Color.blue : Color.red)
|
.fill(gameReq.memoryInt <= Int(String(format: "%.0f", Double(totalMemory) / 1_000_000_000)) ?? 0 ? Color.blue : Color.red)
|
||||||
)
|
)
|
||||||
|
.lineLimit(1)
|
||||||
// Compatibility badge
|
.truncationMode(.tail)
|
||||||
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
.layoutPriority(1)
|
||||||
|
|
||||||
Text(gameReq.compatibility)
|
Text(gameReq.compatibility)
|
||||||
.font(.system(size: 11, weight: .medium))
|
.font(.system(size: 11, weight: .medium))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
|
@ -841,6 +860,10 @@ struct GameListRow: View {
|
||||||
Capsule()
|
Capsule()
|
||||||
.fill(gameReq.color)
|
.fill(gameReq.color)
|
||||||
)
|
)
|
||||||
|
.lineLimit(1)
|
||||||
|
.truncationMode(.tail)
|
||||||
|
.fixedSize(horizontal: true, vertical: false)
|
||||||
|
.layoutPriority(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -11,7 +11,6 @@ import UniformTypeIdentifiers
|
||||||
|
|
||||||
struct MainTabView: View {
|
struct MainTabView: View {
|
||||||
@Binding var startemu: Game?
|
@Binding var startemu: Game?
|
||||||
@Binding var config: Ryujinx.Configuration
|
|
||||||
@Binding var MVKconfig: [MoltenVKSettings]
|
@Binding var MVKconfig: [MoltenVKSettings]
|
||||||
@Binding var controllersList: [Controller]
|
@Binding var controllersList: [Controller]
|
||||||
@Binding var currentControllers: [Controller]
|
@Binding var currentControllers: [Controller]
|
||||||
|
@ -25,7 +24,8 @@ struct MainTabView: View {
|
||||||
Label("Games", systemImage: "gamecontroller.fill")
|
Label("Games", systemImage: "gamecontroller.fill")
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsView(config: $config, MoltenVKSettings: $MVKconfig, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller)
|
// SettingsView(config: $config, MoltenVKSettings: $MVKconfig, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller)
|
||||||
|
SettingsViewNew(MoltenVKSettings: $MVKconfig, controllersList: $controllersList, currentControllers: $currentControllers, onscreencontroller: $onscreencontroller)
|
||||||
.tabItem {
|
.tabItem {
|
||||||
Label("Settings", systemImage: "gear")
|
Label("Settings", systemImage: "gear")
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,11 +280,10 @@ struct UpdateManagerSheet: View {
|
||||||
print("toggle selection \(update.path)")
|
print("toggle selection \(update.path)")
|
||||||
|
|
||||||
updates = updates.map { item in
|
updates = updates.map { item in
|
||||||
var mutableItem = item
|
item.isSelected = item.path == update.path && !update.isSelected
|
||||||
mutableItem.isSelected = item.path == update.path && !update.isSelected
|
|
||||||
// print(mutableItem.isSelected)
|
// print(mutableItem.isSelected)
|
||||||
// print(update.isSelected)
|
// print(update.isSelected)
|
||||||
return mutableItem
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
// print(updates)
|
// print(updates)
|
||||||
|
|
|
@ -28,6 +28,8 @@ struct MeloNXApp: App {
|
||||||
@State var showOutOfDateSheet = false
|
@State var showOutOfDateSheet = false
|
||||||
@State var updateInfo: LatestVersionResponse? = nil
|
@State var updateInfo: LatestVersionResponse? = nil
|
||||||
|
|
||||||
|
@StateObject var metalHudEnabler = MTLHud.shared
|
||||||
|
|
||||||
@State var finished = false
|
@State var finished = false
|
||||||
@AppStorage("hasbeenfinished") var finishedStorage: Bool = false
|
@AppStorage("hasbeenfinished") var finishedStorage: Bool = false
|
||||||
|
|
||||||
|
@ -47,6 +49,10 @@ struct MeloNXApp: App {
|
||||||
if checkForUpdate {
|
if checkForUpdate {
|
||||||
checkLatestVersion()
|
checkLatestVersion()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print(metalHudEnabler.canMetalHud)
|
||||||
|
|
||||||
|
UserDefaults.standard.set(false, forKey: "lockInApp")
|
||||||
}
|
}
|
||||||
.sheet(isPresented: Binding(
|
.sheet(isPresented: Binding(
|
||||||
get: { showOutOfDateSheet && updateInfo != nil },
|
get: { showOutOfDateSheet && updateInfo != nil },
|
||||||
|
|
|
@ -0,0 +1,330 @@
|
||||||
|
#if 0
|
||||||
|
#elif defined(__arm64__) && __arm64__
|
||||||
|
// Generated by Apple Swift version 6.0.3 effective-5.10 (swiftlang-6.0.3.1.10 clang-1600.0.30.1)
|
||||||
|
#ifndef STOSJIT_SWIFT_H
|
||||||
|
#define STOSJIT_SWIFT_H
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||||
|
|
||||||
|
#if !defined(__has_include)
|
||||||
|
# define __has_include(x) 0
|
||||||
|
#endif
|
||||||
|
#if !defined(__has_attribute)
|
||||||
|
# define __has_attribute(x) 0
|
||||||
|
#endif
|
||||||
|
#if !defined(__has_feature)
|
||||||
|
# define __has_feature(x) 0
|
||||||
|
#endif
|
||||||
|
#if !defined(__has_warning)
|
||||||
|
# define __has_warning(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __has_include(<swift/objc-prologue.h>)
|
||||||
|
# include <swift/objc-prologue.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#pragma clang diagnostic ignored "-Wauto-import"
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
#endif
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdbool>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wnon-modular-include-in-framework-module"
|
||||||
|
#if defined(__arm64e__) && __has_include(<ptrauth.h>)
|
||||||
|
# include <ptrauth.h>
|
||||||
|
#else
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
|
||||||
|
# ifndef __ptrauth_swift_value_witness_function_pointer
|
||||||
|
# define __ptrauth_swift_value_witness_function_pointer(x)
|
||||||
|
# endif
|
||||||
|
# ifndef __ptrauth_swift_class_method_pointer
|
||||||
|
# define __ptrauth_swift_class_method_pointer(x)
|
||||||
|
# endif
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SWIFT_TYPEDEFS)
|
||||||
|
# define SWIFT_TYPEDEFS 1
|
||||||
|
# if __has_include(<uchar.h>)
|
||||||
|
# include <uchar.h>
|
||||||
|
# elif !defined(__cplusplus)
|
||||||
|
typedef uint_least16_t char16_t;
|
||||||
|
typedef uint_least32_t char32_t;
|
||||||
|
# endif
|
||||||
|
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||||
|
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||||
|
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||||
|
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||||
|
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||||
|
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||||
|
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||||
|
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||||
|
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||||
|
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||||
|
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||||
|
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(SWIFT_PASTE)
|
||||||
|
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||||
|
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_METATYPE)
|
||||||
|
# define SWIFT_METATYPE(X) Class
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||||
|
# if __has_feature(objc_class_property)
|
||||||
|
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||||
|
# else
|
||||||
|
# define SWIFT_CLASS_PROPERTY(...)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_RUNTIME_NAME)
|
||||||
|
# if __has_attribute(objc_runtime_name)
|
||||||
|
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||||
|
# else
|
||||||
|
# define SWIFT_RUNTIME_NAME(X)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_COMPILE_NAME)
|
||||||
|
# if __has_attribute(swift_name)
|
||||||
|
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||||
|
# else
|
||||||
|
# define SWIFT_COMPILE_NAME(X)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_METHOD_FAMILY)
|
||||||
|
# if __has_attribute(objc_method_family)
|
||||||
|
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||||
|
# else
|
||||||
|
# define SWIFT_METHOD_FAMILY(X)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_NOESCAPE)
|
||||||
|
# if __has_attribute(noescape)
|
||||||
|
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||||
|
# else
|
||||||
|
# define SWIFT_NOESCAPE
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_RELEASES_ARGUMENT)
|
||||||
|
# if __has_attribute(ns_consumed)
|
||||||
|
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
|
||||||
|
# else
|
||||||
|
# define SWIFT_RELEASES_ARGUMENT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_WARN_UNUSED_RESULT)
|
||||||
|
# if __has_attribute(warn_unused_result)
|
||||||
|
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||||
|
# else
|
||||||
|
# define SWIFT_WARN_UNUSED_RESULT
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_NORETURN)
|
||||||
|
# if __has_attribute(noreturn)
|
||||||
|
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||||
|
# else
|
||||||
|
# define SWIFT_NORETURN
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_CLASS_EXTRA)
|
||||||
|
# define SWIFT_CLASS_EXTRA
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||||
|
# define SWIFT_PROTOCOL_EXTRA
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_ENUM_EXTRA)
|
||||||
|
# define SWIFT_ENUM_EXTRA
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_CLASS)
|
||||||
|
# if __has_attribute(objc_subclassing_restricted)
|
||||||
|
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||||
|
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||||
|
# else
|
||||||
|
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||||
|
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_RESILIENT_CLASS)
|
||||||
|
# if __has_attribute(objc_class_stub)
|
||||||
|
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
|
||||||
|
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
|
||||||
|
# else
|
||||||
|
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
|
||||||
|
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_PROTOCOL)
|
||||||
|
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||||
|
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_EXTENSION)
|
||||||
|
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||||
|
#endif
|
||||||
|
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||||
|
# if __has_attribute(objc_designated_initializer)
|
||||||
|
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||||
|
# else
|
||||||
|
# define OBJC_DESIGNATED_INITIALIZER
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_ENUM_ATTR)
|
||||||
|
# if __has_attribute(enum_extensibility)
|
||||||
|
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
|
||||||
|
# else
|
||||||
|
# define SWIFT_ENUM_ATTR(_extensibility)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_ENUM)
|
||||||
|
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
|
||||||
|
# if __has_feature(generalized_swift_name)
|
||||||
|
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
|
||||||
|
# else
|
||||||
|
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_UNAVAILABLE)
|
||||||
|
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||||
|
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_AVAILABILITY)
|
||||||
|
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_WEAK_IMPORT)
|
||||||
|
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_DEPRECATED)
|
||||||
|
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||||
|
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_DEPRECATED_OBJC)
|
||||||
|
# if __has_feature(attribute_diagnose_if_objc)
|
||||||
|
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||||
|
# else
|
||||||
|
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
#if !defined(IBSegueAction)
|
||||||
|
# define IBSegueAction
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_EXTERN)
|
||||||
|
# if defined(__cplusplus)
|
||||||
|
# define SWIFT_EXTERN extern "C"
|
||||||
|
# else
|
||||||
|
# define SWIFT_EXTERN extern
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_CALL)
|
||||||
|
# define SWIFT_CALL __attribute__((swiftcall))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_INDIRECT_RESULT)
|
||||||
|
# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_CONTEXT)
|
||||||
|
# define SWIFT_CONTEXT __attribute__((swift_context))
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_ERROR_RESULT)
|
||||||
|
# define SWIFT_ERROR_RESULT __attribute__((swift_error_result))
|
||||||
|
#endif
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
# define SWIFT_NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
# define SWIFT_NOEXCEPT
|
||||||
|
#endif
|
||||||
|
#if !defined(SWIFT_C_INLINE_THUNK)
|
||||||
|
# if __has_attribute(always_inline)
|
||||||
|
# if __has_attribute(nodebug)
|
||||||
|
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug))
|
||||||
|
# else
|
||||||
|
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline))
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define SWIFT_C_INLINE_THUNK inline
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
|
||||||
|
# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
|
||||||
|
# define SWIFT_IMPORT_STDLIB_SYMBOL
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
#if __has_feature(objc_modules)
|
||||||
|
#if __has_warning("-Watimport-in-framework-header")
|
||||||
|
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||||
|
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||||
|
#if __has_warning("-Wpragma-clang-attribute")
|
||||||
|
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||||
|
#endif
|
||||||
|
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||||
|
#pragma clang diagnostic ignored "-Wnullability"
|
||||||
|
#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||||
|
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
|
||||||
|
|
||||||
|
#if __has_attribute(external_source_symbol)
|
||||||
|
# pragma push_macro("any")
|
||||||
|
# undef any
|
||||||
|
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="StosJIT",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
|
||||||
|
# pragma pop_macro("any")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__OBJC__)
|
||||||
|
|
||||||
|
SWIFT_EXTERN char * _Nullable attach(int32_t pid) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
||||||
|
SWIFT_EXTERN char * _Nullable debugattachanddetachApp(char * _Nonnull bundleId) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
|
||||||
|
SWIFT_EXTERN void detach(void) SWIFT_NOEXCEPT;
|
||||||
|
|
||||||
|
|
||||||
|
SWIFT_EXTERN void loop_heartbeat(void) SWIFT_NOEXCEPT;
|
||||||
|
|
||||||
|
|
||||||
|
SWIFT_EXTERN BOOL writeZeroToMemory(uint64_t addr, int32_t length) SWIFT_NOEXCEPT SWIFT_WARN_UNUSED_RESULT;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#if __has_attribute(external_source_symbol)
|
||||||
|
# pragma clang attribute pop
|
||||||
|
#endif
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#endif
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error unsupported Swift architecture
|
||||||
|
#endif
|
|
@ -0,0 +1,19 @@
|
||||||
|
//
|
||||||
|
// StosJIT.h
|
||||||
|
// StosJIT
|
||||||
|
//
|
||||||
|
// Created by Stossy11 on 10/05/2025.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <StosJIT/idevice.h>
|
||||||
|
|
||||||
|
//! Project version number for StosJIT.
|
||||||
|
FOUNDATION_EXPORT double StosJITVersionNumber;
|
||||||
|
|
||||||
|
//! Project version string for StosJIT.
|
||||||
|
FOUNDATION_EXPORT const unsigned char StosJITVersionString[];
|
||||||
|
|
||||||
|
// In this header, you should import all the public headers of your framework using statements like #import <StosJIT/PublicHeader.h>
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"ABIRoot": {
|
||||||
|
"kind": "Root",
|
||||||
|
"name": "NO_MODULE",
|
||||||
|
"printedName": "NO_MODULE",
|
||||||
|
"json_format_version": 8
|
||||||
|
},
|
||||||
|
"ConstValues": []
|
||||||
|
}
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,11 @@
|
||||||
|
framework module StosJIT {
|
||||||
|
umbrella header "StosJIT.h"
|
||||||
|
export *
|
||||||
|
|
||||||
|
module * { export * }
|
||||||
|
}
|
||||||
|
|
||||||
|
module StosJIT.Swift {
|
||||||
|
header "StosJIT-Swift.h"
|
||||||
|
requires objc
|
||||||
|
}
|
BIN
src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/StosJIT.framework/StosJIT
Executable file
BIN
src/MeloNX/MeloNX/Dependencies/Dynamic Libraries/StosJIT.framework/StosJIT
Executable file
Binary file not shown.
|
@ -0,0 +1,201 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>files</key>
|
||||||
|
<dict>
|
||||||
|
<key>Headers/StosJIT-Swift.h</key>
|
||||||
|
<data>
|
||||||
|
h9vaTwhC6FlnyKmIkaxLQGlFd1g=
|
||||||
|
</data>
|
||||||
|
<key>Headers/StosJIT.h</key>
|
||||||
|
<data>
|
||||||
|
ggHr5wlLNIIPydwUL9Vxm6abxjo=
|
||||||
|
</data>
|
||||||
|
<key>Headers/idevice.h</key>
|
||||||
|
<data>
|
||||||
|
mHDz7368FsBID56/epJ2NgIkha4=
|
||||||
|
</data>
|
||||||
|
<key>Headers/plist.h</key>
|
||||||
|
<data>
|
||||||
|
bL/f0MQDpLfvIcI1zxPwMuJ/PfI=
|
||||||
|
</data>
|
||||||
|
<key>Info.plist</key>
|
||||||
|
<data>
|
||||||
|
ZTTwPKlta/gjXAr1HIHmyAxeU4E=
|
||||||
|
</data>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
|
||||||
|
<data>
|
||||||
|
2mJoWBgg56N+3OxKfIDMLZFNHVk=
|
||||||
|
</data>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.abi.json</key>
|
||||||
|
<data>
|
||||||
|
gcwBsH4BgyFY4sVtNt+/xOKS3vY=
|
||||||
|
</data>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.swiftdoc</key>
|
||||||
|
<data>
|
||||||
|
YPtkDrAuBiPPEp4ZdRdBVlFXnRM=
|
||||||
|
</data>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.swiftmodule</key>
|
||||||
|
<data>
|
||||||
|
9cIInnjJzJFtY+CZm2iNo5qL3MQ=
|
||||||
|
</data>
|
||||||
|
<key>Modules/module.modulemap</key>
|
||||||
|
<data>
|
||||||
|
cnpvYzvLIwWcxkQodj5uLbHkyRk=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>files2</key>
|
||||||
|
<dict>
|
||||||
|
<key>Headers/StosJIT-Swift.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
1obIr4IjMvtcyNyYIV/Nh/5wahcA1cFjc4n4XVlNt2I=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/StosJIT.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
yY9KyrRdOYRdlb7G6wVMU2hogasXMjwV5r8jUIk44ok=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/idevice.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
zR9/TB9Dnv3uRC8qqGvaQ6c2yyOFUURmrHKLdEiUh/g=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Headers/plist.h</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
yFbGsiXBBp91tfsSFtS0Utt2Gpc3MEDFiMVXKG9q1rs=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
sZBe57nozztJzv83RPLjKIRYGSQmeE7XYCqr63xZONM=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.abi.json</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
Qnesa0n4URGWAopawg9bGx36dUwkYV00BoCJ8LFzlyg=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.swiftdoc</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
k7F2Xs2hh9iMbK8IE8TMtN6gjQ9kWs30NUKHeupq6VE=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/StosJIT.swiftmodule/arm64-apple-ios.swiftmodule</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
gMDYNHcBPCNwZw2A5mEUiCyYAS9VhtQG0z+/WqAUrOQ=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
<key>Modules/module.modulemap</key>
|
||||||
|
<dict>
|
||||||
|
<key>hash2</key>
|
||||||
|
<data>
|
||||||
|
FGwGKs5SNvpCyiIWiOP4eml9m2e3KISmtCJVtNnUnUc=
|
||||||
|
</data>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
<key>rules</key>
|
||||||
|
<dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version.plist$</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
<key>rules2</key>
|
||||||
|
<dict>
|
||||||
|
<key>.*\.dSYM($|/)</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>11</real>
|
||||||
|
</dict>
|
||||||
|
<key>^(.*/)?\.DS_Store$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>2000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*</key>
|
||||||
|
<true/>
|
||||||
|
<key>^.*\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>optional</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1000</real>
|
||||||
|
</dict>
|
||||||
|
<key>^.*\.lproj/locversion.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1100</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Base\.lproj/</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>1010</real>
|
||||||
|
</dict>
|
||||||
|
<key>^Info\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^PkgInfo$</key>
|
||||||
|
<dict>
|
||||||
|
<key>omit</key>
|
||||||
|
<true/>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^embedded\.provisionprofile$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
<key>^version\.plist$</key>
|
||||||
|
<dict>
|
||||||
|
<key>weight</key>
|
||||||
|
<real>20</real>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
622
src/Ryujinx.Cpu/LightningJit/Cache/WriteZeroCache.cs
Normal file
622
src/Ryujinx.Cpu/LightningJit/Cache/WriteZeroCache.cs
Normal file
|
@ -0,0 +1,622 @@
|
||||||
|
using ARMeilleure.Memory;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Memory;
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Ryujinx.Cpu.LightningJit.Cache
|
||||||
|
{
|
||||||
|
class WriteZeroCache : IDisposable
|
||||||
|
{
|
||||||
|
private const int CodeAlignment = 4;
|
||||||
|
private const int InitialCacheSize = 2 * 1024 * 1024;
|
||||||
|
private const int GrowthCacheSize = 2 * 1024 * 1024;
|
||||||
|
private const int MaxSharedCacheSize = 512 * 1024 * 1024;
|
||||||
|
private const int MaxLocalCacheSize = 128 * 1024 * 1024;
|
||||||
|
|
||||||
|
[DllImport("StosJIT.framework/StosJIT", EntryPoint = "writeZeroToMemory")]
|
||||||
|
public static extern bool WriteZeroToMemory(ulong addr, int length);
|
||||||
|
|
||||||
|
// How many calls to the same function we allow until we pad the shared cache to force the function to become available there
|
||||||
|
// and allow the guest to take the fast path.
|
||||||
|
private const int MinCallsForPad = 8;
|
||||||
|
|
||||||
|
private class MemoryCache : IDisposable
|
||||||
|
{
|
||||||
|
private readonly ReservedRegion _region;
|
||||||
|
private readonly CacheMemoryAllocator _cacheAllocator;
|
||||||
|
public readonly IJitMemoryAllocator Allocator;
|
||||||
|
private readonly ulong _maxSize;
|
||||||
|
private ulong _currentSize;
|
||||||
|
|
||||||
|
private readonly Dictionary<int, HashSet<int>> _reusePages;
|
||||||
|
private readonly object _reuselock = new object();
|
||||||
|
|
||||||
|
public CacheMemoryAllocator CacheAllocator => _cacheAllocator;
|
||||||
|
public IntPtr Pointer => _region.Block.Pointer;
|
||||||
|
public ulong CurrentSize => _currentSize;
|
||||||
|
public ulong MaxSize => _maxSize;
|
||||||
|
|
||||||
|
public MemoryCache(IJitMemoryAllocator allocator, ulong maxSize)
|
||||||
|
{
|
||||||
|
Allocator = allocator;
|
||||||
|
_maxSize = maxSize;
|
||||||
|
_currentSize = InitialCacheSize;
|
||||||
|
|
||||||
|
|
||||||
|
_region = new(allocator, maxSize);
|
||||||
|
_cacheAllocator = new((int)maxSize);
|
||||||
|
|
||||||
|
_reusePages = new Dictionary<int, HashSet<int>>();
|
||||||
|
|
||||||
|
_region.Block.MapAsRw(0, _currentSize);
|
||||||
|
_region.ExpandIfNeeded(_currentSize);
|
||||||
|
|
||||||
|
WriteZeroToMemory((ulong)_region.Block.Pointer.ToInt64(), (int)_currentSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetReusablePage(int size, out int offset)
|
||||||
|
{
|
||||||
|
lock (_reuselock)
|
||||||
|
{
|
||||||
|
if (_reusePages.TryGetValue(size, out var exactOffsets) && exactOffsets.Count > 0)
|
||||||
|
{
|
||||||
|
offset = exactOffsets.First();
|
||||||
|
exactOffsets.Remove(offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var largerSizes = _reusePages.Where(kvp => kvp.Key > size && kvp.Value.Count > 0)
|
||||||
|
.OrderBy(kvp => kvp.Key)
|
||||||
|
.FirstOrDefault();
|
||||||
|
|
||||||
|
if (largerSizes.Value != null && largerSizes.Value.Count > 0)
|
||||||
|
{
|
||||||
|
int largerSize = largerSizes.Key;
|
||||||
|
var largerOffsets = largerSizes.Value;
|
||||||
|
|
||||||
|
offset = largerOffsets.First();
|
||||||
|
largerOffsets.Remove(offset);
|
||||||
|
|
||||||
|
int remainingSize = largerSize - size;
|
||||||
|
if (remainingSize > 0)
|
||||||
|
{
|
||||||
|
AddReusablePage(offset + size, remainingSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddReusablePage(int offset, int size)
|
||||||
|
{
|
||||||
|
if (size < (int)MemoryBlock.GetPageSize())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_reuselock)
|
||||||
|
{
|
||||||
|
if (!_reusePages.TryGetValue(size, out var offsets))
|
||||||
|
{
|
||||||
|
offsets = new HashSet<int>();
|
||||||
|
_reusePages[size] = offsets;
|
||||||
|
}
|
||||||
|
offsets.Add(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Allocate(int codeSize)
|
||||||
|
{
|
||||||
|
codeSize = AlignCodeSize(codeSize);
|
||||||
|
|
||||||
|
if (codeSize >= (int)MemoryBlock.GetPageSize() &&
|
||||||
|
(codeSize % (int)MemoryBlock.GetPageSize() == 0) &&
|
||||||
|
TryGetReusablePage(codeSize, out int reuseOffset))
|
||||||
|
{
|
||||||
|
ReprotectAsRw(reuseOffset, codeSize);
|
||||||
|
return reuseOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
int allocOffset = _cacheAllocator.Allocate(codeSize);
|
||||||
|
|
||||||
|
if (allocOffset < 0)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException("JIT Cache exhausted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ulong requiredSize = (ulong)allocOffset + (ulong)codeSize;
|
||||||
|
if (requiredSize > _currentSize)
|
||||||
|
{
|
||||||
|
ulong neededGrowth = requiredSize - _currentSize;
|
||||||
|
ulong growthIncrements = (neededGrowth + GrowthCacheSize - 1) / GrowthCacheSize;
|
||||||
|
ulong newSize = _currentSize + (growthIncrements * GrowthCacheSize);
|
||||||
|
|
||||||
|
newSize = Math.Min(newSize, _maxSize);
|
||||||
|
|
||||||
|
if (newSize <= _currentSize || requiredSize > newSize)
|
||||||
|
{
|
||||||
|
throw new OutOfMemoryException("JIT Cache exhausted, cannot grow further.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_region.Block.MapAsRw(_currentSize, newSize - _currentSize);
|
||||||
|
_region.ExpandIfNeeded(newSize);
|
||||||
|
|
||||||
|
WriteZeroToMemory((ulong)(_region.Block.Pointer.ToInt64() + (long)_currentSize), (int)(newSize - _currentSize));
|
||||||
|
|
||||||
|
_currentSize = newSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return allocOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Free(int offset, int size)
|
||||||
|
{
|
||||||
|
if (size >= (int)MemoryBlock.GetPageSize() && (size % (int)MemoryBlock.GetPageSize() == 0) &&
|
||||||
|
(offset % (int)MemoryBlock.GetPageSize() == 0))
|
||||||
|
{
|
||||||
|
AddReusablePage(offset, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_cacheAllocator.Free(offset, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReprotectAsRw(int offset, int size)
|
||||||
|
{
|
||||||
|
Debug.Assert(offset >= 0 && (offset & (int)(MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
Debug.Assert(size > 0 && (size & (int)(MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
|
||||||
|
_region.Block.MapAsRw((ulong)offset, (ulong)size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ReprotectAsRx(int offset, int size)
|
||||||
|
{
|
||||||
|
Debug.Assert(offset >= 0 && (offset & (int)(MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
Debug.Assert(size > 0 && (size & (int)(MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
|
||||||
|
_region.Block.MapAsRx((ulong)offset, (ulong)size);
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS() || OperatingSystem.IsIOS())
|
||||||
|
{
|
||||||
|
JitSupportDarwin.SysIcacheInvalidate(_region.Block.Pointer + offset, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new PlatformNotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearReusePool()
|
||||||
|
{
|
||||||
|
lock (_reuselock)
|
||||||
|
{
|
||||||
|
_reusePages.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int AlignCodeSize(int codeSize)
|
||||||
|
{
|
||||||
|
return checked(codeSize + (CodeAlignment - 1)) & ~(CodeAlignment - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
ClearReusePool();
|
||||||
|
_region.Dispose();
|
||||||
|
_cacheAllocator.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly IStackWalker _stackWalker;
|
||||||
|
private readonly Translator _translator;
|
||||||
|
private readonly List<MemoryCache> _sharedCaches;
|
||||||
|
private readonly List<MemoryCache> _localCaches;
|
||||||
|
private readonly Dictionary<ulong, PageAlignedRangeList> _pendingMaps;
|
||||||
|
private readonly object _lock;
|
||||||
|
|
||||||
|
class ThreadLocalCacheEntry
|
||||||
|
{
|
||||||
|
public readonly int Offset;
|
||||||
|
public readonly int Size;
|
||||||
|
public readonly IntPtr FuncPtr;
|
||||||
|
public readonly int CacheIndex;
|
||||||
|
private int _useCount;
|
||||||
|
|
||||||
|
public ThreadLocalCacheEntry(int offset, int size, IntPtr funcPtr, int cacheIndex)
|
||||||
|
{
|
||||||
|
Offset = offset;
|
||||||
|
Size = size;
|
||||||
|
FuncPtr = funcPtr;
|
||||||
|
CacheIndex = cacheIndex;
|
||||||
|
_useCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int IncrementUseCount()
|
||||||
|
{
|
||||||
|
return ++_useCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static Dictionary<ulong, ThreadLocalCacheEntry> _threadLocalCache;
|
||||||
|
|
||||||
|
public WriteZeroCache(IJitMemoryAllocator allocator, IStackWalker stackWalker, Translator translator)
|
||||||
|
{
|
||||||
|
_stackWalker = stackWalker;
|
||||||
|
_translator = translator;
|
||||||
|
_sharedCaches = new List<MemoryCache> { new(allocator, MaxSharedCacheSize) };
|
||||||
|
_localCaches = new List<MemoryCache> { new(allocator, MaxLocalCacheSize) };
|
||||||
|
_pendingMaps = new Dictionary<ulong, PageAlignedRangeList>();
|
||||||
|
_lock = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
private PageAlignedRangeList GetPendingMapForCache(int cacheIndex)
|
||||||
|
{
|
||||||
|
ulong cacheKey = (ulong)cacheIndex;
|
||||||
|
if (!_pendingMaps.TryGetValue(cacheKey, out var pendingMap))
|
||||||
|
{
|
||||||
|
pendingMap = new PageAlignedRangeList(
|
||||||
|
(offset, size) => _sharedCaches[cacheIndex].ReprotectAsRx(offset, size),
|
||||||
|
(address, func) => RegisterFunction(address, func));
|
||||||
|
_pendingMaps[cacheKey] = pendingMap;
|
||||||
|
}
|
||||||
|
return pendingMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool HasInAnyPendingMap(ulong guestAddress)
|
||||||
|
{
|
||||||
|
foreach (var pendingMap in _pendingMaps.Values)
|
||||||
|
{
|
||||||
|
if (pendingMap.Has(guestAddress))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AllocateInSharedCache(int codeLength)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _sharedCaches.Count; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (i << 28) | _sharedCaches[i].Allocate(codeLength);
|
||||||
|
}
|
||||||
|
catch (OutOfMemoryException)
|
||||||
|
{
|
||||||
|
// Try next cache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// All existing caches are full, create a new one
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var allocator = _sharedCaches[0].Allocator;
|
||||||
|
_sharedCaches.Add(new(allocator, MaxSharedCacheSize));
|
||||||
|
return (_sharedCaches.Count - 1) << 28 | _sharedCaches[_sharedCaches.Count - 1].Allocate(codeLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int AllocateInLocalCache(int codeLength)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _localCaches.Count; i++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return (i << 28) | _localCaches[i].Allocate(codeLength);
|
||||||
|
}
|
||||||
|
catch (OutOfMemoryException)
|
||||||
|
{
|
||||||
|
// Try next cache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
var allocator = _localCaches[0].Allocator;
|
||||||
|
_localCaches.Add(new(allocator, MaxLocalCacheSize));
|
||||||
|
return (_localCaches.Count - 1) << 28 | _localCaches[_localCaches.Count - 1].Allocate(codeLength);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (int cacheIndex, int offset) SplitCacheOffset(int combinedOffset)
|
||||||
|
{
|
||||||
|
return (combinedOffset >> 28, combinedOffset & 0xFFFFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe IntPtr Map(IntPtr framePointer, ReadOnlySpan<byte> code, ulong guestAddress, ulong guestSize)
|
||||||
|
{
|
||||||
|
if (TryGetThreadLocalFunction(guestAddress, out IntPtr funcPtr))
|
||||||
|
{
|
||||||
|
return funcPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (!HasInAnyPendingMap(guestAddress) && !_translator.Functions.ContainsKey(guestAddress))
|
||||||
|
{
|
||||||
|
int combinedOffset = AllocateInSharedCache(code.Length);
|
||||||
|
var (cacheIndex, funcOffset) = SplitCacheOffset(combinedOffset);
|
||||||
|
|
||||||
|
MemoryCache cache = _sharedCaches[cacheIndex];
|
||||||
|
funcPtr = cache.Pointer + funcOffset;
|
||||||
|
|
||||||
|
code.CopyTo(new Span<byte>((void*)funcPtr, code.Length));
|
||||||
|
|
||||||
|
TranslatedFunction function = new(funcPtr, guestSize);
|
||||||
|
|
||||||
|
GetPendingMapForCache(cacheIndex).Add(funcOffset, code.Length, guestAddress, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearThreadLocalCache(framePointer);
|
||||||
|
|
||||||
|
return AddThreadLocalFunction(code, guestAddress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public unsafe IntPtr MapPageAligned(ReadOnlySpan<byte> code)
|
||||||
|
{
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
int cacheIndex;
|
||||||
|
int funcOffset;
|
||||||
|
IntPtr mappedFuncPtr = IntPtr.Zero;
|
||||||
|
|
||||||
|
for (cacheIndex = 0; cacheIndex < _sharedCaches.Count; cacheIndex++)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var pendingMap = GetPendingMapForCache(cacheIndex);
|
||||||
|
|
||||||
|
pendingMap.Pad(_sharedCaches[cacheIndex].CacheAllocator);
|
||||||
|
|
||||||
|
int sizeAligned = BitUtils.AlignUp(code.Length, (int)MemoryBlock.GetPageSize());
|
||||||
|
funcOffset = _sharedCaches[cacheIndex].Allocate(sizeAligned);
|
||||||
|
|
||||||
|
Debug.Assert((funcOffset & ((int)MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
|
||||||
|
IntPtr funcPtr1 = _sharedCaches[cacheIndex].Pointer + funcOffset;
|
||||||
|
|
||||||
|
code.CopyTo(new Span<byte>((void*)funcPtr1, code.Length));
|
||||||
|
|
||||||
|
_sharedCaches[cacheIndex].ReprotectAsRx(funcOffset, sizeAligned);
|
||||||
|
|
||||||
|
return funcPtr1;
|
||||||
|
}
|
||||||
|
catch (OutOfMemoryException)
|
||||||
|
{
|
||||||
|
// Try next cache
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var allocator = _sharedCaches[0].Allocator;
|
||||||
|
var newCache = new MemoryCache(allocator, MaxSharedCacheSize);
|
||||||
|
_sharedCaches.Add(newCache);
|
||||||
|
cacheIndex = _sharedCaches.Count - 1;
|
||||||
|
|
||||||
|
var newPendingMap = GetPendingMapForCache(cacheIndex);
|
||||||
|
|
||||||
|
newPendingMap.Pad(newCache.CacheAllocator);
|
||||||
|
|
||||||
|
int newSizeAligned = BitUtils.AlignUp(code.Length, (int)MemoryBlock.GetPageSize());
|
||||||
|
funcOffset = newCache.Allocate(newSizeAligned);
|
||||||
|
|
||||||
|
Debug.Assert((funcOffset & ((int)MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
|
||||||
|
IntPtr funcPtr = newCache.Pointer + funcOffset;
|
||||||
|
code.CopyTo(new Span<byte>((void*)funcPtr, code.Length));
|
||||||
|
|
||||||
|
newCache.ReprotectAsRx(funcOffset, newSizeAligned);
|
||||||
|
|
||||||
|
return funcPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryGetThreadLocalFunction(ulong guestAddress, out IntPtr funcPtr)
|
||||||
|
{
|
||||||
|
if ((_threadLocalCache ??= new()).TryGetValue(guestAddress, out var entry))
|
||||||
|
{
|
||||||
|
if (entry.IncrementUseCount() >= MinCallsForPad)
|
||||||
|
{
|
||||||
|
// Function is being called often, let's make it available in the shared cache so that the guest code
|
||||||
|
// can take the fast path and stop calling the emulator to get the function from the thread local cache.
|
||||||
|
// To do that we pad all "pending" function until they complete a page of memory, allowing us to reprotect them as RX.
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var pendingMap in _pendingMaps.Values)
|
||||||
|
{
|
||||||
|
// Get the cache index from the pendingMap key
|
||||||
|
if (_pendingMaps.FirstOrDefault(x => x.Value == pendingMap).Key is ulong cacheIndex)
|
||||||
|
{
|
||||||
|
// Use the correct shared cache for padding based on the cache index
|
||||||
|
pendingMap.Pad(_sharedCaches[(int)cacheIndex].CacheAllocator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
funcPtr = entry.FuncPtr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
funcPtr = IntPtr.Zero;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClearThreadLocalCache(IntPtr framePointer)
|
||||||
|
{
|
||||||
|
// Try to delete functions that are already on the shared cache
|
||||||
|
// and no longer being executed.
|
||||||
|
|
||||||
|
if (_threadLocalCache == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr[] cachePointers = new IntPtr[_localCaches.Count];
|
||||||
|
int[] cacheSizes = new int[_localCaches.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < _localCaches.Count; i++)
|
||||||
|
{
|
||||||
|
cachePointers[i] = _localCaches[i].Pointer;
|
||||||
|
cacheSizes[i] = (int)_localCaches[i].CurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntPtr[] sharedPointers = new IntPtr[_sharedCaches.Count];
|
||||||
|
int[] sharedSizes = new int[_sharedCaches.Count];
|
||||||
|
|
||||||
|
for (int i = 0; i < _sharedCaches.Count; i++)
|
||||||
|
{
|
||||||
|
sharedPointers[i] = _sharedCaches[i].Pointer;
|
||||||
|
sharedSizes[i] = (int)_sharedCaches[i].CurrentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerable<ulong> callStack = null;
|
||||||
|
for (int i = 0; i < _localCaches.Count; i++)
|
||||||
|
{
|
||||||
|
callStack = _stackWalker.GetCallStack(
|
||||||
|
framePointer,
|
||||||
|
cachePointers[i],
|
||||||
|
cacheSizes[i],
|
||||||
|
sharedPointers[i],
|
||||||
|
sharedSizes[i]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<(ulong, ThreadLocalCacheEntry)> toDelete = new();
|
||||||
|
|
||||||
|
foreach ((ulong address, ThreadLocalCacheEntry entry) in _threadLocalCache)
|
||||||
|
{
|
||||||
|
bool canDelete = !HasInAnyPendingMap(address);
|
||||||
|
if (!canDelete)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (ulong funcAddress in callStack)
|
||||||
|
{
|
||||||
|
if (funcAddress >= (ulong)entry.FuncPtr && funcAddress < (ulong)entry.FuncPtr + (ulong)entry.Size)
|
||||||
|
{
|
||||||
|
canDelete = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canDelete)
|
||||||
|
{
|
||||||
|
toDelete.Add((address, entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
|
|
||||||
|
foreach ((ulong address, ThreadLocalCacheEntry entry) in toDelete)
|
||||||
|
{
|
||||||
|
_threadLocalCache.Remove(address);
|
||||||
|
|
||||||
|
int sizeAligned = BitUtils.AlignUp(entry.Size, pageSize);
|
||||||
|
var (cacheIndex, offset) = SplitCacheOffset(entry.Offset);
|
||||||
|
|
||||||
|
_localCaches[cacheIndex].Free(offset, sizeAligned);
|
||||||
|
_localCaches[cacheIndex].ReprotectAsRw(offset, sizeAligned);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearEntireThreadLocalCache()
|
||||||
|
{
|
||||||
|
if (_threadLocalCache == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int pageSize = (int)MemoryBlock.GetPageSize();
|
||||||
|
|
||||||
|
foreach ((_, ThreadLocalCacheEntry entry) in _threadLocalCache)
|
||||||
|
{
|
||||||
|
int sizeAligned = BitUtils.AlignUp(entry.Size, pageSize);
|
||||||
|
var (cacheIndex, offset) = SplitCacheOffset(entry.Offset);
|
||||||
|
|
||||||
|
_localCaches[cacheIndex].Free(offset, sizeAligned);
|
||||||
|
_localCaches[cacheIndex].ReprotectAsRw(offset, sizeAligned);
|
||||||
|
}
|
||||||
|
|
||||||
|
_threadLocalCache.Clear();
|
||||||
|
_threadLocalCache = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe IntPtr AddThreadLocalFunction(ReadOnlySpan<byte> code, ulong guestAddress)
|
||||||
|
{
|
||||||
|
int alignedSize = BitUtils.AlignUp(code.Length, (int)MemoryBlock.GetPageSize());
|
||||||
|
int combinedOffset = AllocateInLocalCache(alignedSize);
|
||||||
|
var (cacheIndex, funcOffset) = SplitCacheOffset(combinedOffset);
|
||||||
|
|
||||||
|
Debug.Assert((funcOffset & (int)(MemoryBlock.GetPageSize() - 1)) == 0);
|
||||||
|
|
||||||
|
IntPtr funcPtr = _localCaches[cacheIndex].Pointer + funcOffset;
|
||||||
|
code.CopyTo(new Span<byte>((void*)funcPtr, code.Length));
|
||||||
|
|
||||||
|
(_threadLocalCache ??= new()).Add(guestAddress, new(funcOffset, code.Length, funcPtr, cacheIndex));
|
||||||
|
|
||||||
|
_localCaches[cacheIndex].ReprotectAsRx(funcOffset, alignedSize);
|
||||||
|
|
||||||
|
return funcPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RegisterFunction(ulong address, TranslatedFunction func)
|
||||||
|
{
|
||||||
|
TranslatedFunction oldFunc = _translator.Functions.GetOrAdd(address, func.GuestSize, func);
|
||||||
|
|
||||||
|
Debug.Assert(oldFunc == func);
|
||||||
|
|
||||||
|
_translator.RegisterFunction(address, func);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
foreach (var cache in _localCaches)
|
||||||
|
{
|
||||||
|
cache.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var cache in _sharedCaches)
|
||||||
|
{
|
||||||
|
cache.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_localCaches.Clear();
|
||||||
|
_sharedCaches.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(disposing: true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
namespace Ryujinx.Cpu.LightningJit
|
namespace Ryujinx.Cpu.LightningJit
|
||||||
{
|
{
|
||||||
|
@ -40,6 +41,7 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
|
|
||||||
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
private readonly ConcurrentQueue<KeyValuePair<ulong, TranslatedFunction>> _oldFuncs;
|
||||||
private readonly NoWxCache _noWxCache;
|
private readonly NoWxCache _noWxCache;
|
||||||
|
private readonly WriteZeroCache _writeZeroCache;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
internal TranslatorCache<TranslatedFunction> Functions { get; }
|
||||||
|
@ -55,17 +57,44 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
|
|
||||||
if (IsNoWxPlatform)
|
if (IsNoWxPlatform)
|
||||||
{
|
{
|
||||||
_noWxCache = new(new JitMemoryAllocator(), CreateStackWalker(), this);
|
if (File.Exists("/System/Library/CoreServices/SystemVersion.plist"))
|
||||||
|
{
|
||||||
|
string content = File.ReadAllText("/System/Library/CoreServices/SystemVersion.plist");
|
||||||
|
if (content.Contains("22E5200s") && content.Contains("18.4") && content.Contains("Beta"))
|
||||||
|
{
|
||||||
|
// iOS 18.4db1 (22E5200s) disables traditional JIT (R/X) and needs a debugger to fill to the page to make the executable region a debug map.
|
||||||
|
// Apple has confirmed that this change will be coming to later iOS releases.
|
||||||
|
// Credit to JJTech for figuring out a workaround: https://gist.github.com/JJTech0130/142aee0f7bda9c61a421140d17afbdeb
|
||||||
|
Console.WriteLine($"User is using iOS 18.4db1 (22E5200s), enabling Debugger Memory Writing");
|
||||||
|
_writeZeroCache = new(new JitMemoryAllocator(), CreateStackWalker(), this);
|
||||||
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
||||||
|
Stubs = new TranslatorStubs(FunctionTable, _writeZeroCache);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_noWxCache = new(new JitMemoryAllocator(), CreateStackWalker(), this);
|
||||||
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
||||||
|
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_noWxCache = new(new JitMemoryAllocator(), CreateStackWalker(), this);
|
||||||
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
||||||
|
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
JitCache.Initialize(new JitMemoryAllocator(forJit: true));
|
JitCache.Initialize(new JitMemoryAllocator(forJit: true));
|
||||||
|
Functions = new TranslatorCache<TranslatedFunction>();
|
||||||
|
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
||||||
|
Stubs = new TranslatorStubs(FunctionTable, (NoWxCache)null);
|
||||||
}
|
}
|
||||||
|
|
||||||
Functions = new TranslatorCache<TranslatedFunction>();
|
|
||||||
FunctionTable = new AddressTable<ulong>(for64Bits ? _levels64Bit : _levels32Bit);
|
|
||||||
Stubs = new TranslatorStubs(FunctionTable, _noWxCache);
|
|
||||||
|
|
||||||
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
FunctionTable.Fill = (ulong)Stubs.SlowDispatchStub;
|
||||||
|
|
||||||
if (memory.Type.IsHostMappedOrTracked())
|
if (memory.Type.IsHostMappedOrTracked())
|
||||||
|
@ -96,6 +125,7 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
|
|
||||||
NativeInterface.UnregisterThread();
|
NativeInterface.UnregisterThread();
|
||||||
_noWxCache?.ClearEntireThreadLocalCache();
|
_noWxCache?.ClearEntireThreadLocalCache();
|
||||||
|
_writeZeroCache?.ClearEntireThreadLocalCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IntPtr GetOrTranslatePointer(IntPtr framePointer, ulong address, ExecutionMode mode)
|
internal IntPtr GetOrTranslatePointer(IntPtr framePointer, ulong address, ExecutionMode mode)
|
||||||
|
@ -103,9 +133,13 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
if (_noWxCache != null)
|
if (_noWxCache != null)
|
||||||
{
|
{
|
||||||
CompiledFunction func = Compile(address, mode);
|
CompiledFunction func = Compile(address, mode);
|
||||||
|
|
||||||
return _noWxCache.Map(framePointer, func.Code, address, (ulong)func.GuestCodeLength);
|
return _noWxCache.Map(framePointer, func.Code, address, (ulong)func.GuestCodeLength);
|
||||||
}
|
}
|
||||||
|
else if (_writeZeroCache != null)
|
||||||
|
{
|
||||||
|
CompiledFunction func = Compile(address, mode);
|
||||||
|
return _writeZeroCache.Map(framePointer, func.Code, address, (ulong)func.GuestCodeLength);
|
||||||
|
}
|
||||||
|
|
||||||
return GetOrTranslate(address, mode).FuncPointer;
|
return GetOrTranslate(address, mode).FuncPointer;
|
||||||
}
|
}
|
||||||
|
@ -205,6 +239,10 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
{
|
{
|
||||||
_noWxCache.Dispose();
|
_noWxCache.Dispose();
|
||||||
}
|
}
|
||||||
|
else if (_writeZeroCache != null)
|
||||||
|
{
|
||||||
|
_writeZeroCache.Dispose();
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ClearJitCache();
|
ClearJitCache();
|
||||||
|
|
|
@ -25,6 +25,8 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
|
|
||||||
private readonly AddressTable<ulong> _functionTable;
|
private readonly AddressTable<ulong> _functionTable;
|
||||||
private readonly NoWxCache _noWxCache;
|
private readonly NoWxCache _noWxCache;
|
||||||
|
private readonly WriteZeroCache _writeZeroCache;
|
||||||
|
|
||||||
private readonly GetFunctionAddressDelegate _getFunctionAddressRef;
|
private readonly GetFunctionAddressDelegate _getFunctionAddressRef;
|
||||||
private readonly IntPtr _getFunctionAddress;
|
private readonly IntPtr _getFunctionAddress;
|
||||||
private readonly Lazy<IntPtr> _dispatchStub;
|
private readonly Lazy<IntPtr> _dispatchStub;
|
||||||
|
@ -92,6 +94,26 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
_dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
|
_dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TranslatorStubs"/> class with the specified
|
||||||
|
/// <see cref="Translator"/> instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="functionTable">Function table used to store pointers to the functions that the guest code will call</param>
|
||||||
|
/// <param name="writeZeroCache">Cache used on iOS versions that need a debugger to make a debug map</param>
|
||||||
|
/// <exception cref="ArgumentNullException"><paramref name="translator"/> is null</exception>
|
||||||
|
public TranslatorStubs(AddressTable<ulong> functionTable, WriteZeroCache writeZeroCache)
|
||||||
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(functionTable);
|
||||||
|
|
||||||
|
_functionTable = functionTable;
|
||||||
|
_writeZeroCache = writeZeroCache;
|
||||||
|
_getFunctionAddressRef = NativeInterface.GetFunctionAddress;
|
||||||
|
_getFunctionAddress = Marshal.GetFunctionPointerForDelegate(_getFunctionAddressRef);
|
||||||
|
_slowDispatchStub = new(GenerateSlowDispatchStub, isThreadSafe: true);
|
||||||
|
_dispatchStub = new(GenerateDispatchStub, isThreadSafe: true);
|
||||||
|
_dispatchLoop = new(GenerateDispatchLoop, isThreadSafe: true);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Releases all resources used by the <see cref="TranslatorStubs"/> instance.
|
/// Releases all resources used by the <see cref="TranslatorStubs"/> instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -361,6 +383,10 @@ namespace Ryujinx.Cpu.LightningJit
|
||||||
{
|
{
|
||||||
return _noWxCache.MapPageAligned(code);
|
return _noWxCache.MapPageAligned(code);
|
||||||
}
|
}
|
||||||
|
else if (_writeZeroCache != null)
|
||||||
|
{
|
||||||
|
return _writeZeroCache.MapPageAligned(code);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return JitCache.Map(code);
|
return JitCache.Map(code);
|
||||||
|
|
|
@ -106,6 +106,8 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
var externalMemoryBuffer = new ExternalMemoryBufferCreateInfo
|
var externalMemoryBuffer = new ExternalMemoryBufferCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.ExternalMemoryBufferCreateInfo,
|
SType = StructureType.ExternalMemoryBufferCreateInfo,
|
||||||
|
// For MoltenVK 1.3
|
||||||
|
// ExternalMemoryHandleTypeFlagsExt.MtlBufferBitExt
|
||||||
HandleTypes = ExternalMemoryHandleTypeFlags.HostAllocationBitExt,
|
HandleTypes = ExternalMemoryHandleTypeFlags.HostAllocationBitExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -676,4 +678,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ExternalMemoryHandleTypeFlagsExt
|
||||||
|
{
|
||||||
|
public const ExternalMemoryHandleTypeFlags MtlBufferBitExt = (ExternalMemoryHandleTypeFlags)0x00010000;
|
||||||
|
public const ExternalMemoryHandleTypeFlags MtlHeapBitExt = (ExternalMemoryHandleTypeFlags)0x00040000;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
public const int MaxShaderStages = 5;
|
public const int MaxShaderStages = 5;
|
||||||
public const int MaxUniformBuffersPerStage = 18;
|
public const int MaxUniformBuffersPerStage = 18;
|
||||||
public const int MaxStorageBuffersPerStage = 16;
|
public const int MaxStorageBuffersPerStage = 16;
|
||||||
public const int MaxTexturesPerStage = 64;
|
public const int MaxTexturesPerStage = 31;
|
||||||
public const int MaxImagesPerStage = 16;
|
public const int MaxImagesPerStage = 16;
|
||||||
public const int MaxUniformBufferBindings = MaxUniformBuffersPerStage * MaxShaderStages;
|
public const int MaxUniformBufferBindings = MaxUniformBuffersPerStage * MaxShaderStages;
|
||||||
public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages;
|
public const int MaxStorageBufferBindings = MaxStorageBuffersPerStage * MaxShaderStages;
|
||||||
|
|
|
@ -47,25 +47,25 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public unsafe void UpdateBuffers(int setIndex, int baseBinding, ReadOnlySpan<DescriptorBufferInfo> bufferInfo, DescriptorType type)
|
public unsafe void UpdateBuffers(int setIndex, int baseBinding, ReadOnlySpan<DescriptorBufferInfo> bufferInfo, DescriptorType type)
|
||||||
{
|
{
|
||||||
|
for (int i = 0; i < bufferInfo.Length; i++)
|
||||||
|
|
||||||
// Proceed if all checks pass
|
|
||||||
fixed (DescriptorBufferInfo* pBufferInfo = bufferInfo)
|
|
||||||
{
|
{
|
||||||
var writeDescriptorSet = new WriteDescriptorSet
|
fixed (DescriptorBufferInfo* pBufferInfo = &bufferInfo[i])
|
||||||
{
|
{
|
||||||
SType = StructureType.WriteDescriptorSet,
|
var writeDescriptorSet = new WriteDescriptorSet
|
||||||
DstSet = _descriptorSets[setIndex],
|
{
|
||||||
DstBinding = (uint)baseBinding,
|
SType = StructureType.WriteDescriptorSet,
|
||||||
DescriptorType = type,
|
DstSet = _descriptorSets[setIndex],
|
||||||
DescriptorCount = (uint)bufferInfo.Length,
|
DstBinding = (uint)(baseBinding + i),
|
||||||
PBufferInfo = pBufferInfo
|
DescriptorType = type,
|
||||||
};
|
DescriptorCount = 1,
|
||||||
|
PBufferInfo = pBufferInfo
|
||||||
|
};
|
||||||
|
|
||||||
// Update descriptor sets
|
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
||||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, writeDescriptorSet, 0, null);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
if (imageInfo.ImageView.Handle != 0UL)
|
if (imageInfo.ImageView.Handle != 0UL)
|
||||||
{
|
{
|
||||||
|
|
||||||
var writeDescriptorSet = new WriteDescriptorSet
|
var writeDescriptorSet = new WriteDescriptorSet
|
||||||
{
|
{
|
||||||
SType = StructureType.WriteDescriptorSet,
|
SType = StructureType.WriteDescriptorSet,
|
||||||
|
@ -90,19 +90,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
public unsafe void UpdateImages(int setIndex, int baseBinding, ReadOnlySpan<DescriptorImageInfo> imageInfo, DescriptorType type)
|
public unsafe void UpdateImages(int setIndex, int baseBinding, ReadOnlySpan<DescriptorImageInfo> imageInfo, DescriptorType type)
|
||||||
{
|
{
|
||||||
fixed (DescriptorImageInfo* pImageInfo = imageInfo)
|
for (int i = 0; i < imageInfo.Length; i++)
|
||||||
{
|
{
|
||||||
var writeDescriptorSet = new WriteDescriptorSet
|
fixed (DescriptorImageInfo* pImageInfo = &imageInfo[i])
|
||||||
{
|
{
|
||||||
SType = StructureType.WriteDescriptorSet,
|
var writeDescriptorSet = new WriteDescriptorSet
|
||||||
DstSet = _descriptorSets[setIndex],
|
{
|
||||||
DstBinding = (uint)baseBinding,
|
SType = StructureType.WriteDescriptorSet,
|
||||||
DescriptorType = type,
|
DstSet = _descriptorSets[setIndex],
|
||||||
DescriptorCount = (uint)imageInfo.Length,
|
DstBinding = (uint)(baseBinding + i),
|
||||||
PImageInfo = pImageInfo,
|
DescriptorType = type,
|
||||||
};
|
DescriptorCount = 1,
|
||||||
|
PImageInfo = pImageInfo,
|
||||||
|
};
|
||||||
|
|
||||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +115,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fixed (DescriptorImageInfo* pImageInfo = imageInfo)
|
fixed (DescriptorImageInfo* pImageInfo = imageInfo)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < imageInfo.Length; i++)
|
for (int i = 0; i < imageInfo.Length; i++)
|
||||||
|
@ -120,33 +123,24 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bool nonNull = imageInfo[i].ImageView.Handle != 0 && imageInfo[i].Sampler.Handle != 0;
|
bool nonNull = imageInfo[i].ImageView.Handle != 0 && imageInfo[i].Sampler.Handle != 0;
|
||||||
if (nonNull)
|
if (nonNull)
|
||||||
{
|
{
|
||||||
int count = 1;
|
|
||||||
|
|
||||||
while (i + count < imageInfo.Length &&
|
|
||||||
imageInfo[i + count].ImageView.Handle != 0 &&
|
|
||||||
imageInfo[i + count].Sampler.Handle != 0)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var writeDescriptorSet = new WriteDescriptorSet
|
var writeDescriptorSet = new WriteDescriptorSet
|
||||||
{
|
{
|
||||||
SType = StructureType.WriteDescriptorSet,
|
SType = StructureType.WriteDescriptorSet,
|
||||||
DstSet = _descriptorSets[setIndex],
|
DstSet = _descriptorSets[setIndex],
|
||||||
DstBinding = (uint)(baseBinding + i),
|
DstBinding = (uint)(baseBinding + i),
|
||||||
DescriptorType = DescriptorType.CombinedImageSampler,
|
DescriptorType = type,
|
||||||
DescriptorCount = 1,
|
DescriptorCount = 1,
|
||||||
PImageInfo = pImageInfo,
|
PImageInfo = pImageInfo + i,
|
||||||
};
|
};
|
||||||
|
|
||||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
|
||||||
|
|
||||||
i += count - 1;
|
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public unsafe void UpdateBufferImage(int setIndex, int bindingIndex, BufferView texelBufferView, DescriptorType type)
|
public unsafe void UpdateBufferImage(int setIndex, int bindingIndex, BufferView texelBufferView, DescriptorType type)
|
||||||
{
|
{
|
||||||
if (texelBufferView.Handle != 0UL)
|
if (texelBufferView.Handle != 0UL)
|
||||||
|
@ -174,31 +168,22 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
fixed (BufferView* pTexelBufferView = texelBufferView)
|
fixed (BufferView* pTexelBufferView = texelBufferView)
|
||||||
{
|
{
|
||||||
for (uint i = 0; i < texelBufferView.Length;)
|
for (int i = 0; i < texelBufferView.Length; i++)
|
||||||
{
|
{
|
||||||
uint count = 1;
|
if (texelBufferView[i].Handle != 0UL)
|
||||||
|
|
||||||
if (texelBufferView[(int)i].Handle != 0UL)
|
|
||||||
{
|
{
|
||||||
while (i + count < texelBufferView.Length && texelBufferView[(int)(i + count)].Handle != 0UL)
|
|
||||||
{
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
var writeDescriptorSet = new WriteDescriptorSet
|
var writeDescriptorSet = new WriteDescriptorSet
|
||||||
{
|
{
|
||||||
SType = StructureType.WriteDescriptorSet,
|
SType = StructureType.WriteDescriptorSet,
|
||||||
DstSet = _descriptorSets[setIndex],
|
DstSet = _descriptorSets[setIndex],
|
||||||
DstBinding = (uint)baseBinding + i,
|
DstBinding = (uint)baseBinding + (uint)i,
|
||||||
DescriptorType = type,
|
DescriptorType = type,
|
||||||
DescriptorCount = 1,
|
DescriptorCount = 1,
|
||||||
PTexelBufferView = pTexelBufferView + i,
|
PTexelBufferView = pTexelBufferView + i,
|
||||||
};
|
};
|
||||||
|
|
||||||
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
_holder.Api.UpdateDescriptorSets(_holder.Device, 1, in writeDescriptorSet, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
i += count;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -757,6 +757,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return mirrored;
|
return mirrored;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
|
private void UpdateAndBind(CommandBufferScoped cbs, ShaderCollection program, int setIndex, PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
|
@ -810,9 +811,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split buffer updates into individual slices for MoltenVK compatibility
|
||||||
ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
|
ReadOnlySpan<DescriptorBufferInfo> uniformBuffers = _uniformBuffers;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
tu.Push(uniformBuffers.Slice(binding, count));
|
{
|
||||||
|
tu.Push(uniformBuffers.Slice(binding + i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (setIndex == PipelineBase.StorageSetIndex)
|
else if (setIndex == PipelineBase.StorageSetIndex)
|
||||||
{
|
{
|
||||||
|
@ -836,9 +840,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Split buffer updates into individual slices for MoltenVK compatibility
|
||||||
ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
|
ReadOnlySpan<DescriptorBufferInfo> storageBuffers = _storageBuffers;
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
tu.Push(storageBuffers.Slice(binding, count));
|
{
|
||||||
|
tu.Push(storageBuffers.Slice(binding + i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (setIndex == PipelineBase.TextureSetIndex)
|
else if (setIndex == PipelineBase.TextureSetIndex)
|
||||||
{
|
{
|
||||||
|
@ -867,7 +874,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<DescriptorImageInfo>(textures[..count]);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tu.Push<DescriptorImageInfo>(textures.Slice(i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -878,7 +888,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
|
bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<BufferView>(bufferTextures[..count]);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tu.Push<BufferView>(bufferTextures.Slice(i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -906,7 +919,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
images[i].ImageView = _imageRefs[binding + i].ImageView?.Get(cbs).Value ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<DescriptorImageInfo>(images[..count]);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tu.Push<DescriptorImageInfo>(images.Slice(i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -917,7 +933,10 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
|
bufferImages[i] = _bufferImageRefs[binding + i]?.GetBufferView(cbs, true) ?? default;
|
||||||
}
|
}
|
||||||
|
|
||||||
tu.Push<BufferView>(bufferImages[..count]);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
tu.Push<BufferView>(bufferImages.Slice(i, 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -940,6 +959,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
|
private void UpdateAndBindTexturesWithoutTemplate(CommandBufferScoped cbs, ShaderCollection program, PipelineBindPoint pbp)
|
||||||
{
|
{
|
||||||
int setIndex = PipelineBase.TextureSetIndex;
|
int setIndex = PipelineBase.TextureSetIndex;
|
||||||
|
@ -950,11 +970,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_updateDescriptorCacheCbIndex)
|
var dummyImageInfo = new DescriptorImageInfo
|
||||||
{
|
{
|
||||||
_updateDescriptorCacheCbIndex = false;
|
ImageView = _dummyTexture.GetImageView().Get(cbs).Value,
|
||||||
program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
|
Sampler = _dummySampler.GetSampler().Get(cbs).Value,
|
||||||
}
|
ImageLayout = ImageLayout.General
|
||||||
|
};
|
||||||
|
|
||||||
var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
|
var dsc = program.GetNewDescriptorSetCollection(setIndex, out _).Get(cbs);
|
||||||
|
|
||||||
|
@ -967,71 +988,78 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
if (segment.Type != ResourceType.BufferTexture)
|
if (segment.Type != ResourceType.BufferTexture)
|
||||||
{
|
{
|
||||||
Span<DescriptorImageInfo> textures = _textures;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
ref var texture = ref textures[i];
|
int index = binding + i;
|
||||||
ref var refs = ref _textureRefs[binding + i];
|
ref var textureRef = ref _textureRefs[index];
|
||||||
|
|
||||||
texture.ImageView = refs.ImageView?.Get(cbs).Value ?? default;
|
var imageView = textureRef.ImageView?.Get(cbs).Value ?? dummyImageInfo.ImageView;
|
||||||
texture.Sampler = refs.Sampler?.Get(cbs).Value ?? default;
|
var sampler = textureRef.Sampler?.Get(cbs).Value ?? dummyImageInfo.Sampler;
|
||||||
|
|
||||||
if (texture.ImageView.Handle == 0)
|
var imageInfo = new DescriptorImageInfo
|
||||||
{
|
{
|
||||||
texture.ImageView = _dummyTexture.GetImageView().Get(cbs).Value;
|
ImageView = imageView.Handle != 0 ? imageView : dummyImageInfo.ImageView,
|
||||||
}
|
Sampler = sampler.Handle != 0 ? sampler : dummyImageInfo.Sampler,
|
||||||
|
ImageLayout = ImageLayout.General
|
||||||
|
};
|
||||||
|
|
||||||
if (texture.Sampler.Handle == 0)
|
dsc.UpdateImages(0, index, new[] { imageInfo }, DescriptorType.CombinedImageSampler);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!OperatingSystem.IsIOS()) {
|
|
||||||
dsc.UpdateImages(0, binding, textures[..count], DescriptorType.CombinedImageSampler);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Span<BufferView> bufferTextures = _bufferTextures;
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
bufferTextures[i] = _bufferTextureRefs[binding + i]?.GetBufferView(cbs, false) ?? default;
|
int index = binding + i;
|
||||||
|
var bufferView = _bufferTextureRefs[index]?.GetBufferView(cbs, false) ?? default;
|
||||||
|
dsc.UpdateBufferImages(0, index, new[] { bufferView }, DescriptorType.UniformTexelBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
dsc.UpdateBufferImages(0, binding, bufferTextures[..count], DescriptorType.UniformTexelBuffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
var arrayRef = _textureArrayRefs[binding];
|
||||||
|
|
||||||
if (segment.Type != ResourceType.BufferTexture)
|
if (segment.Type != ResourceType.BufferTexture)
|
||||||
{
|
{
|
||||||
// Span<DescriptorImageInfo> images = _imageRefs.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler);
|
var imageInfos = arrayRef.Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler);
|
||||||
|
if (imageInfos != null)
|
||||||
if (OperatingSystem.IsIOS())
|
|
||||||
{
|
{
|
||||||
dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler);
|
for (int i = 0; i < imageInfos.Length && i < count; i++)
|
||||||
|
{
|
||||||
|
dsc.UpdateImages(0, binding + i, new[] { imageInfos[i] }, DescriptorType.CombinedImageSampler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dsc.UpdateImages(0, binding, _textureArrayRefs[binding].Array.GetImageInfos(_gd, cbs, _dummyTexture, _dummySampler), DescriptorType.CombinedImageSampler);
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
dsc.UpdateImages(0, binding + i, new[] { dummyImageInfo }, DescriptorType.CombinedImageSampler);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
dsc.UpdateBufferImages(0, binding, _textureArrayRefs[binding].Array.GetBufferViews(cbs), DescriptorType.UniformTexelBuffer);
|
var bufferViews = arrayRef.Array.GetBufferViews(cbs);
|
||||||
|
if (bufferViews != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < bufferViews.Length && i < count; i++)
|
||||||
|
{
|
||||||
|
dsc.UpdateBufferImages(0, binding + i, new[] { bufferViews[i] }, DescriptorType.UniformTexelBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
dsc.UpdateBufferImages(0, binding + i, new[] { default(BufferView) }, DescriptorType.UniformTexelBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var sets = dsc.GetSets();
|
var sets = dsc.GetSets();
|
||||||
|
|
||||||
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
_gd.Api.CmdBindDescriptorSets(cbs.CommandBuffer, pbp, _program.PipelineLayout, (uint)setIndex, 1, sets, 0, ReadOnlySpan<uint>.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1241,7 +1241,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
int vbSize = vertexBuffer.Buffer.Size;
|
int vbSize = vertexBuffer.Buffer.Size;
|
||||||
|
|
||||||
if ((Gd.Vendor == Vendor.Amd || !OperatingSystem.IsIOSVersionAtLeast(17)) && !Gd.IsMoltenVk && vertexBuffer.Stride > 0)
|
if (Gd.Vendor == Vendor.Amd && !Gd.IsMoltenVk && vertexBuffer.Stride > 0)
|
||||||
{
|
{
|
||||||
// AMD has a bug where if offset + stride * count is greater than
|
// AMD has a bug where if offset + stride * count is greater than
|
||||||
// the size, then the last attribute will have the wrong value.
|
// the size, then the last attribute will have the wrong value.
|
||||||
|
|
|
@ -409,7 +409,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
SType = StructureType.PipelineVertexInputStateCreateInfo,
|
SType = StructureType.PipelineVertexInputStateCreateInfo,
|
||||||
VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
|
VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
|
||||||
PVertexAttributeDescriptions = isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
|
PVertexAttributeDescriptions = pVertexAttributeDescriptions2, // isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
|
||||||
VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
|
VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
|
||||||
PVertexBindingDescriptions = pVertexBindingDescriptions,
|
PVertexBindingDescriptions = pVertexBindingDescriptions,
|
||||||
};
|
};
|
||||||
|
@ -521,6 +521,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
|
|
||||||
uint blendEnables = 0;
|
uint blendEnables = 0;
|
||||||
|
|
||||||
|
|
||||||
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
|
if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
|
||||||
{
|
{
|
||||||
// Blend can't be enabled for integer formats, so let's make sure it is disabled.
|
// Blend can't be enabled for integer formats, so let's make sure it is disabled.
|
||||||
|
|
|
@ -422,7 +422,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
features2.Features.ShaderStorageImageMultisample,
|
features2.Features.ShaderStorageImageMultisample,
|
||||||
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
|
_physicalDevice.IsDeviceExtensionPresent(ExtConditionalRendering.ExtensionName),
|
||||||
isDynamicStateSupported,
|
isDynamicStateSupported,
|
||||||
features2.Features.MultiViewport && !(IsMoltenVk && Vendor == Vendor.Amd), // Workaround for AMD on MoltenVK issue
|
features2.Features.MultiViewport && !IsMoltenVk, // Workaround for AMD on MoltenVK issue
|
||||||
!IsMoltenVk ? featuresRobustness2.NullDescriptor : false,
|
!IsMoltenVk ? featuresRobustness2.NullDescriptor : false,
|
||||||
supportsPushDescriptors && !IsMoltenVk,
|
supportsPushDescriptors && !IsMoltenVk,
|
||||||
propertiesPushDescriptor.MaxPushDescriptors,
|
propertiesPushDescriptor.MaxPushDescriptors,
|
||||||
|
@ -785,7 +785,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||||
shaderSubgroupSize: (int)Capabilities.SubgroupSize,
|
shaderSubgroupSize: (int)Capabilities.SubgroupSize,
|
||||||
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment,
|
storageBufferOffsetAlignment: (int)limits.MinStorageBufferOffsetAlignment,
|
||||||
textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment,
|
textureBufferOffsetAlignment: (int)limits.MinTexelBufferOffsetAlignment,
|
||||||
gatherBiasPrecision: IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0,
|
gatherBiasPrecision: (int)Capabilities.SubTexelPrecisionBits, //IsIntelWindows || IsAmdWindows ? (int)Capabilities.SubTexelPrecisionBits : 0,
|
||||||
maximumGpuMemory: GetTotalGPUMemory());
|
maximumGpuMemory: GetTotalGPUMemory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ using Ryujinx.Input.HLE;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using SDL2;
|
using SDL2;
|
||||||
|
|
||||||
|
@ -1161,7 +1162,7 @@ namespace Ryujinx.Headless.SDL2
|
||||||
_libHacHorizonManager.InitializeBcatServer();
|
_libHacHorizonManager.InitializeBcatServer();
|
||||||
_libHacHorizonManager.InitializeSystemClients();
|
_libHacHorizonManager.InitializeSystemClients();
|
||||||
|
|
||||||
_contentManager = new ContentManager(_virtualFileSystem);
|
// _contentManager = new ContentManager(_virtualFileSystem);
|
||||||
|
|
||||||
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
|
_accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient, option.UserProfile);
|
||||||
|
|
||||||
|
@ -1223,9 +1224,14 @@ namespace Ryujinx.Headless.SDL2
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (option.InputPath == "MiiMaker") {
|
Match match = Regex.Match(option.InputPath, @"0x[0-9A-Fa-f]+");
|
||||||
string contentPath = _contentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
|
if (match.Success)
|
||||||
|
{
|
||||||
|
string hexStr = match.Value.Substring(2);
|
||||||
|
ulong id = Convert.ToUInt64(hexStr, 16);
|
||||||
|
string contentPath = _contentManager.GetInstalledContentPath(id, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||||
|
|
||||||
option.InputPath = contentPath;
|
option.InputPath = contentPath;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue