Compare commits
24 commits
758cb975ef
...
2b067c2160
Author | SHA1 | Date | |
---|---|---|---|
2b067c2160 | |||
a2084c4b94 | |||
718891d11f | |||
bbcd8aded6 | |||
2bc792e211 | |||
e7560183fa | |||
84fadd1506 | |||
be7a3e1e86 | |||
6aa8be1da8 | |||
![]() |
e28b0d2590 | ||
![]() |
6fcfe7f4f3 | ||
e60fd4b68b | |||
10c76568b8 | |||
8dba6a2cb4 | |||
4b5a8e0621 | |||
39e27bc954 | |||
21c77bdcac | |||
1c3ca17cfb | |||
7ca197d900 | |||
3b4c1beb0c | |||
76de9d6c8c | |||
ab015bc730 | |||
f005f6a3ab | |||
47b703067e |
112 changed files with 1821 additions and 919 deletions
|
@ -1,6 +1,6 @@
|
|||
AppRun
|
||||
eden.desktop
|
||||
org.eden_emu.eden.desktop
|
||||
dev.eden_emu.eden.desktop
|
||||
shared/bin/eden
|
||||
shared/lib/lib.path
|
||||
shared/lib/ld-linux-x86-64.so.2
|
||||
|
|
|
@ -59,15 +59,15 @@ VERSION="$(echo "$EDEN_TAG")"
|
|||
mkdir -p ./AppDir
|
||||
cd ./AppDir
|
||||
|
||||
cp ../dist/org.eden_emu.eden.desktop .
|
||||
cp ../dist/org.eden_emu.eden.svg .
|
||||
cp ../dist/dev.eden_emu.eden.desktop .
|
||||
cp ../dist/dev.eden_emu.eden.svg .
|
||||
|
||||
ln -sf ./org.eden_emu.eden.svg ./.DirIcon
|
||||
ln -sf ./dev.eden_emu.eden.svg ./.DirIcon
|
||||
|
||||
UPINFO='gh-releases-zsync|eden-emulator|Releases|latest|*.AppImage.zsync'
|
||||
|
||||
if [ "$DEVEL" = 'true' ]; then
|
||||
sed -i 's|Name=Eden|Name=Eden Nightly|' ./org.eden_emu.eden.desktop
|
||||
sed -i 's|Name=Eden|Name=Eden Nightly|' ./dev.eden_emu.eden.desktop
|
||||
UPINFO="$(echo "$UPINFO" | sed 's|Releases|nightly|')"
|
||||
fi
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
which png2icns || [ which yay && yay libicns ] || exit
|
||||
which magick || exit
|
||||
|
||||
export EDEN_SVG_ICO="dist/org.eden_emu.eden.svg"
|
||||
export EDEN_SVG_ICO="dist/dev.eden_emu.eden.svg"
|
||||
svgo --multipass $EDEN_SVG_ICO
|
||||
|
||||
magick -density 256x256 -background transparent $EDEN_SVG_ICO \
|
||||
|
|
22
.patch/unordered-dense/0001-cmake.patch
Normal file
22
.patch/unordered-dense/0001-cmake.patch
Normal file
|
@ -0,0 +1,22 @@
|
|||
From e59d30b7b12e1d04cc2fc9c6219e35bda447c17e Mon Sep 17 00:00:00 2001
|
||||
From: Lizzie <159065448+Lizzie841@users.noreply.github.com>
|
||||
Date: Fri, 16 May 2025 04:12:13 +0100
|
||||
Subject: [PATCH] Update CMakeLists.txt
|
||||
|
||||
---
|
||||
CMakeLists.txt | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index b5f4c4f..c5c6f31 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -24,7 +24,7 @@ target_include_directories(
|
||||
|
||||
target_compile_features(unordered_dense INTERFACE cxx_std_17)
|
||||
|
||||
-if(_unordered_dense_is_toplevel_project)
|
||||
+if(_unordered_dense_is_toplevel_project OR UNORDERED_DENSE_INSTALL)
|
||||
# locations are provided by GNUInstallDirs
|
||||
install(
|
||||
TARGETS unordered_dense
|
|
@ -406,8 +406,10 @@ if (YUZU_USE_CPM)
|
|||
|
||||
if (NOT MSVC)
|
||||
# boost sucks
|
||||
if (NOT PLATFORM_LINUX AND NOT ANDROID)
|
||||
target_compile_definitions(boost_container INTERFACE BOOST_HAS_PTHREADS)
|
||||
# Solaris (and probably other NIXes) need explicit pthread definition
|
||||
if (PLATFORM_SUN)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthreads")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthreads")
|
||||
endif()
|
||||
|
||||
target_compile_options(boost_heap INTERFACE -Wno-shadow)
|
||||
|
@ -856,14 +858,14 @@ endif()
|
|||
# https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
|
||||
# https://www.freedesktop.org/software/appstream/docs/
|
||||
if(ENABLE_QT AND UNIX AND NOT APPLE)
|
||||
install(FILES "dist/org.eden_emu.eden.desktop"
|
||||
install(FILES "dist/dev.eden_emu.eden.desktop"
|
||||
DESTINATION "share/applications")
|
||||
install(FILES "dist/org.eden_emu.eden.svg"
|
||||
install(FILES "dist/dev.eden_emu.eden.svg"
|
||||
DESTINATION "share/icons/hicolor/scalable/apps")
|
||||
|
||||
# TODO: these files need to be updated.
|
||||
install(FILES "dist/org.eden_emu.eden.xml"
|
||||
install(FILES "dist/dev.eden_emu.eden.xml"
|
||||
DESTINATION "share/mime/packages")
|
||||
install(FILES "dist/org.eden_emu.eden.metainfo.xml"
|
||||
install(FILES "dist/dev.eden_emu.eden.metainfo.xml"
|
||||
DESTINATION "share/metainfo")
|
||||
endif()
|
||||
|
|
|
@ -184,8 +184,6 @@ function(AddJsonPackage)
|
|||
# system/bundled
|
||||
if (bundled STREQUAL "unset" AND DEFINED JSON_BUNDLED_PACKAGE)
|
||||
set(bundled ${JSON_BUNDLED_PACKAGE})
|
||||
else()
|
||||
set(bundled ON)
|
||||
endif()
|
||||
|
||||
AddPackage(
|
||||
|
@ -259,6 +257,7 @@ function(AddPackage)
|
|||
|
||||
KEY
|
||||
BUNDLED_PACKAGE
|
||||
FIND_PACKAGE_ARGUMENTS
|
||||
)
|
||||
|
||||
set(multiValueArgs OPTIONS PATCHES)
|
||||
|
@ -409,9 +408,9 @@ function(AddPackage)
|
|||
set_precedence(OFF OFF)
|
||||
elseif (CPMUTIL_FORCE_SYSTEM)
|
||||
set_precedence(ON ON)
|
||||
elseif(NOT CPMUTIL_FORCE_BUNDLED)
|
||||
elseif(CPMUTIL_FORCE_BUNDLED)
|
||||
set_precedence(OFF OFF)
|
||||
elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE)
|
||||
elseif (DEFINED PKG_ARGS_BUNDLED_PACKAGE AND NOT PKG_ARGS_BUNDLED_PACKAGE STREQUAL "unset")
|
||||
if (PKG_ARGS_BUNDLED_PACKAGE)
|
||||
set(local OFF)
|
||||
else()
|
||||
|
|
|
@ -10,7 +10,7 @@ Type=Application
|
|||
Name=Eden
|
||||
GenericName=Switch Emulator
|
||||
Comment=Nintendo Switch video game console emulator
|
||||
Icon=org.eden_emu.eden
|
||||
Icon=dev.eden_emu.eden
|
||||
TryExec=eden
|
||||
Exec=eden %f
|
||||
Categories=Game;Emulator;Qt;
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
14
externals/CMakeLists.txt
vendored
14
externals/CMakeLists.txt
vendored
|
@ -96,15 +96,7 @@ if (ENABLE_WEB_SERVICE)
|
|||
endif()
|
||||
|
||||
# unordered_dense
|
||||
AddPackage(
|
||||
NAME unordered_dense
|
||||
REPO "Lizzie841/unordered_dense"
|
||||
SHA e59d30b7b1
|
||||
HASH 71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0
|
||||
FIND_PACKAGE_ARGUMENTS "CONFIG"
|
||||
OPTIONS
|
||||
"UNORDERED_DENSE_INSTALL OFF"
|
||||
)
|
||||
AddJsonPackage(unordered-dense)
|
||||
|
||||
# FFMpeg
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
|
@ -147,6 +139,10 @@ add_subdirectory(nx_tzdb)
|
|||
# VMA
|
||||
AddJsonPackage(vulkan-memory-allocator)
|
||||
|
||||
if (VulkanMemoryAllocator_ADDED AND MSVC)
|
||||
target_compile_options(VulkanMemoryAllocator INTERFACE /wd4189)
|
||||
endif()
|
||||
|
||||
if (NOT TARGET LLVM::Demangle)
|
||||
add_library(demangle demangle/ItaniumDemangle.cpp)
|
||||
target_include_directories(demangle PUBLIC ./demangle)
|
||||
|
|
21
externals/cpmfile.json
vendored
21
externals/cpmfile.json
vendored
|
@ -74,14 +74,14 @@
|
|||
},
|
||||
"xbyak_sun": {
|
||||
"package": "xbyak",
|
||||
"repo": "Lizzie841/xbyak",
|
||||
"sha": "51f507b0b3",
|
||||
"hash": "4a29a3c2f97f7d5adf667a21a008be03c951fb6696b0d7ba27e7e4afa037bc76eb5e059bb84860e01baf741d4d3ac851b840cd54c99d038812fbe0f1fa6d38a4",
|
||||
"repo": "herumi/xbyak",
|
||||
"sha": "9bb219333a",
|
||||
"hash": "303165d45c8c19387ec49d9fda7d7a4e0d86d4c0153898c23f25ce2d58ece567f44c0bbbfe348239b933edb6e1a1e34f4bc1c0ab3a285bee5da0e548879387b0",
|
||||
"bundled": true
|
||||
},
|
||||
"xbyak": {
|
||||
"package": "xbyak",
|
||||
"repo": "Lizzie841/xbyak",
|
||||
"repo": "herumi/xbyak",
|
||||
"sha": "4e44f4614d",
|
||||
"hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70",
|
||||
"bundled": true
|
||||
|
@ -105,5 +105,18 @@
|
|||
"sha": "2bc873e53c",
|
||||
"hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768",
|
||||
"bundled": true
|
||||
},
|
||||
"unordered-dense": {
|
||||
"package": "unordered_dense",
|
||||
"repo": "martinus/unordered_dense",
|
||||
"sha": "73f3cbb237",
|
||||
"hash": "c08c03063938339d61392b687562909c1a92615b6ef39ec8df19ea472aa6b6478e70d7d5e33d4a27b5d23f7806daf57fe1bacb8124c8a945c918c7663a9e8532",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"UNORDERED_DENSE_INSTALL OFF"
|
||||
],
|
||||
"patches": [
|
||||
"0001-cmake.patch"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
28
externals/ffmpeg/CMakeLists.txt
vendored
28
externals/ffmpeg/CMakeLists.txt
vendored
|
@ -63,20 +63,22 @@ if (NOT WIN32 AND NOT ANDROID)
|
|||
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
|
||||
set(FFmpeg_HWACCEL_LDFLAGS)
|
||||
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(PLATFORM_SUN)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"/usr/lib/xorg/amd64/libdrm.so")
|
||||
else()
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS})
|
||||
if (NOT APPLE)
|
||||
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
|
||||
if(PLATFORM_SUN)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
X11
|
||||
"/usr/lib/xorg/amd64/libdrm.so")
|
||||
else()
|
||||
pkg_check_modules(LIBDRM libdrm REQUIRED)
|
||||
list(APPEND FFmpeg_HWACCEL_LIBRARIES
|
||||
${LIBDRM_LIBRARIES})
|
||||
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
|
||||
${LIBDRM_INCLUDE_DIRS})
|
||||
endif()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-libdrm)
|
||||
endif()
|
||||
list(APPEND FFmpeg_HWACCEL_FLAGS
|
||||
--enable-libdrm)
|
||||
|
||||
if(LIBVA_FOUND)
|
||||
find_package(X11 REQUIRED)
|
||||
|
|
|
@ -30,8 +30,8 @@ val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toIn
|
|||
android {
|
||||
namespace = "org.yuzu.yuzu_emu"
|
||||
|
||||
compileSdkVersion = "android-35"
|
||||
ndkVersion = "26.1.10909125"
|
||||
compileSdkVersion = "android-36"
|
||||
ndkVersion = "28.2.13676358"
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
|
@ -173,6 +173,7 @@ android {
|
|||
"-DENABLE_OPENSSL=ON",
|
||||
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
|
||||
"-DYUZU_USE_CPM=ON",
|
||||
"-DCPMUTIL_FORCE_BUNDLED=ON",
|
||||
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
|
||||
"-DYUZU_ENABLE_LTO=ON",
|
||||
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
|
||||
|
|
|
@ -36,6 +36,9 @@ import androidx.core.net.toUri
|
|||
import androidx.core.content.edit
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||
|
||||
class GameAdapter(private val activity: AppCompatActivity) :
|
||||
AbstractDiffAdapter<Game, GameAdapter.GameViewHolder>(exact = false) {
|
||||
|
@ -229,6 +232,8 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
|||
binding.root.findNavController().navigate(action)
|
||||
}
|
||||
|
||||
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||
|
||||
if (NativeLibrary.gameRequiresFirmware(game.programId) && !NativeLibrary.isFirmwareAvailable()) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.loader_requires_firmware)
|
||||
|
@ -243,6 +248,23 @@ class GameAdapter(private val activity: AppCompatActivity) :
|
|||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
} else if (BooleanSetting.DISABLE_NCA_VERIFICATION.getBoolean(false) && !preferences.getBoolean(
|
||||
Settings.PREF_HIDE_NCA_POPUP, false)) {
|
||||
MaterialAlertDialogBuilder(activity)
|
||||
.setTitle(R.string.nca_verification_disabled)
|
||||
.setMessage(activity.getString(R.string.nca_verification_disabled_description))
|
||||
.setPositiveButton(android.R.string.ok) { _, _ ->
|
||||
launch()
|
||||
}
|
||||
.setNeutralButton(R.string.dont_show_again) { _, _ ->
|
||||
preferences.edit {
|
||||
putBoolean(Settings.PREF_HIDE_NCA_POPUP, true)
|
||||
}
|
||||
|
||||
launch()
|
||||
}
|
||||
.setNegativeButton(android.R.string.cancel) { _, _ -> }
|
||||
.show()
|
||||
} else {
|
||||
launch()
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||
RENDERER_SAMPLE_SHADING("sample_shading"),
|
||||
PICTURE_IN_PICTURE("picture_in_picture"),
|
||||
USE_CUSTOM_RTC("custom_rtc_enabled"),
|
||||
DISABLE_NCA_VERIFICATION("disable_nca_verification"),
|
||||
BLACK_BACKGROUNDS("black_backgrounds"),
|
||||
JOYSTICK_REL_CENTER("joystick_rel_center"),
|
||||
DPAD_SLIDE("dpad_slide"),
|
||||
|
|
|
@ -37,6 +37,7 @@ object Settings {
|
|||
const val PREF_SHOULD_SHOW_PRE_ALPHA_WARNING = "ShouldShowPreAlphaWarning"
|
||||
const val PREF_SHOULD_SHOW_EDENS_VEIL_DIALOG = "ShouldShowEdensVeilDialog"
|
||||
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
||||
const val PREF_HIDE_NCA_POPUP = "HideNCAVerificationPopup"
|
||||
const val SECTION_STATS_OVERLAY = "Stats Overlay"
|
||||
|
||||
// Deprecated input overlay preference keys
|
||||
|
|
|
@ -297,7 +297,13 @@ abstract class SettingsItem(
|
|||
descriptionId = R.string.use_custom_rtc_description
|
||||
)
|
||||
)
|
||||
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.DISABLE_NCA_VERIFICATION,
|
||||
titleId = R.string.disable_nca_verification,
|
||||
descriptionId = R.string.disable_nca_verification_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
StringInputSetting(
|
||||
StringSetting.WEB_TOKEN,
|
||||
|
|
|
@ -210,6 +210,7 @@ class SettingsFragmentPresenter(
|
|||
add(IntSetting.LANGUAGE_INDEX.key)
|
||||
add(BooleanSetting.USE_CUSTOM_RTC.key)
|
||||
add(LongSetting.CUSTOM_RTC.key)
|
||||
add(BooleanSetting.DISABLE_NCA_VERIFICATION.key)
|
||||
|
||||
add(HeaderSetting(R.string.network))
|
||||
add(StringSetting.WEB_TOKEN.key)
|
||||
|
|
|
@ -79,7 +79,7 @@ class DriverFetcherFragment : Fragment() {
|
|||
IntRange(600, 639) to "Mr. Purple EOL-24.3.4",
|
||||
IntRange(640, 699) to "Mr. Purple T19",
|
||||
IntRange(700, 710) to "KIMCHI 25.2.0_r5",
|
||||
IntRange(711, 799) to "Mr. Purple T21",
|
||||
IntRange(711, 799) to "Mr. Purple T22",
|
||||
IntRange(800, 899) to "GameHub Adreno 8xx",
|
||||
IntRange(900, Int.MAX_VALUE) to "Unsupported"
|
||||
)
|
||||
|
|
|
@ -509,6 +509,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
gpuModel = GpuDriverHelper.getGpuModel().toString()
|
||||
fwVersion = NativeLibrary.firmwareVersion()
|
||||
|
||||
updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean())
|
||||
|
||||
binding.surfaceEmulation.holder.addCallback(this)
|
||||
binding.doneControlConfig.setOnClickListener { stopConfiguringControls() }
|
||||
|
||||
|
@ -530,6 +532,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
binding.drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
|
||||
binding.inGameMenu.requestFocus()
|
||||
emulationViewModel.setDrawerOpen(true)
|
||||
updateQuickOverlayMenuEntry(BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean())
|
||||
}
|
||||
|
||||
override fun onDrawerClosed(drawerView: View) {
|
||||
|
@ -571,25 +574,24 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
R.id.menu_pause_emulation -> {
|
||||
if (emulationState.isPaused) {
|
||||
emulationState.run(false)
|
||||
it.title = resources.getString(R.string.emulation_pause)
|
||||
it.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_pause,
|
||||
requireContext().theme
|
||||
)
|
||||
updatePauseMenuEntry(false)
|
||||
} else {
|
||||
emulationState.pause()
|
||||
it.title = resources.getString(R.string.emulation_unpause)
|
||||
it.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_play,
|
||||
requireContext().theme
|
||||
)
|
||||
updatePauseMenuEntry(true)
|
||||
}
|
||||
binding.inGameMenu.requestFocus()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_quick_overlay -> {
|
||||
val newState = !BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
|
||||
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(newState)
|
||||
updateQuickOverlayMenuEntry(newState)
|
||||
binding.surfaceInputOverlay.refreshControls()
|
||||
NativeConfig.saveGlobalConfig()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_settings -> {
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
null,
|
||||
|
@ -844,9 +846,50 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private fun updateQuickOverlayMenuEntry(isVisible: Boolean) {
|
||||
val menu = binding.inGameMenu.menu
|
||||
val item = menu.findItem(R.id.menu_quick_overlay)
|
||||
if (isVisible) {
|
||||
item.title = getString(R.string.emulation_hide_overlay)
|
||||
item.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_controller_disconnected,
|
||||
requireContext().theme
|
||||
)
|
||||
} else {
|
||||
item.title = getString(R.string.emulation_show_overlay)
|
||||
item.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_controller,
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun updatePauseMenuEntry(isPaused: Boolean) {
|
||||
val menu = binding.inGameMenu.menu
|
||||
val pauseItem = menu.findItem(R.id.menu_pause_emulation)
|
||||
if (isPaused) {
|
||||
pauseItem.title = getString(R.string.emulation_unpause)
|
||||
pauseItem.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_play,
|
||||
requireContext().theme
|
||||
)
|
||||
} else {
|
||||
pauseItem.title = getString(R.string.emulation_pause)
|
||||
pauseItem.icon = ResourcesCompat.getDrawable(
|
||||
resources,
|
||||
R.drawable.ic_pause,
|
||||
requireContext().theme
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
if (emulationState.isRunning && emulationActivity?.isInPictureInPictureMode != true) {
|
||||
emulationState.pause()
|
||||
updatePauseMenuEntry(true)
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
@ -869,6 +912,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
|
||||
val socPosition = IntSetting.SOC_OVERLAY_POSITION.getInt()
|
||||
updateSocPosition(socPosition)
|
||||
|
||||
binding.inGameMenu.post {
|
||||
emulationState?.isPaused?.let { updatePauseMenuEntry(it) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetInputOverlay() {
|
||||
|
@ -1391,6 +1438,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
R.id.menu_show_overlay -> {
|
||||
it.isChecked = !it.isChecked
|
||||
BooleanSetting.SHOW_INPUT_OVERLAY.setBoolean(it.isChecked)
|
||||
updateQuickOverlayMenuEntry(it.isChecked)
|
||||
binding.surfaceInputOverlay.refreshControls()
|
||||
true
|
||||
}
|
||||
|
|
|
@ -31,9 +31,6 @@ class HomeViewModel : ViewModel() {
|
|||
private val _checkKeys = MutableStateFlow(false)
|
||||
val checkKeys = _checkKeys.asStateFlow()
|
||||
|
||||
private val _checkFirmware = MutableStateFlow(false)
|
||||
val checkFirmware = _checkFirmware.asStateFlow()
|
||||
|
||||
var navigatedToSetup = false
|
||||
|
||||
fun setStatusBarShadeVisibility(visible: Boolean) {
|
||||
|
@ -66,8 +63,4 @@ class HomeViewModel : ViewModel() {
|
|||
fun setCheckKeys(value: Boolean) {
|
||||
_checkKeys.value = value
|
||||
}
|
||||
|
||||
fun setCheckFirmware(value: Boolean) {
|
||||
_checkFirmware.value = value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.yuzu.yuzu_emu.model.DriverViewModel
|
|||
import org.yuzu.yuzu_emu.model.GamesViewModel
|
||||
import org.yuzu.yuzu_emu.model.HomeViewModel
|
||||
import org.yuzu.yuzu_emu.model.InstallResult
|
||||
import android.os.Build
|
||||
import org.yuzu.yuzu_emu.model.TaskState
|
||||
import org.yuzu.yuzu_emu.model.TaskViewModel
|
||||
import org.yuzu.yuzu_emu.utils.*
|
||||
|
@ -47,6 +48,7 @@ import java.io.BufferedOutputStream
|
|||
import java.util.zip.ZipEntry
|
||||
import java.util.zip.ZipInputStream
|
||||
import androidx.core.content.edit
|
||||
import kotlin.text.compareTo
|
||||
|
||||
class MainActivity : AppCompatActivity(), ThemeProvider {
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
@ -110,6 +112,19 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
|
||||
// Since Android 15, google automatically forces "games" to be 60 hrz
|
||||
// This ensures the display's max refresh rate is actually used
|
||||
display?.let {
|
||||
val supportedModes = it.supportedModes
|
||||
val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate }
|
||||
|
||||
if (maxRefreshRate != null) {
|
||||
val layoutParams = window.attributes
|
||||
layoutParams.preferredDisplayModeId = maxRefreshRate.modeId
|
||||
window.attributes = layoutParams
|
||||
}
|
||||
}
|
||||
|
||||
setContentView(binding.root)
|
||||
|
||||
checkAndRequestBluetoothPermissions()
|
||||
|
@ -127,16 +142,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
checkedDecryption = true
|
||||
}
|
||||
|
||||
if (!checkedFirmware) {
|
||||
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
|
||||
if (!firstTimeSetup) {
|
||||
checkFirmware()
|
||||
showPreAlphaWarningDialog()
|
||||
}
|
||||
checkedFirmware = true
|
||||
}
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
|
||||
|
||||
|
@ -183,13 +188,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
if (it) checkKeys()
|
||||
}
|
||||
|
||||
homeViewModel.checkFirmware.collect(
|
||||
this,
|
||||
resetState = { homeViewModel.setCheckFirmware(false) }
|
||||
) {
|
||||
if (it) checkFirmware()
|
||||
}
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
|
@ -228,21 +226,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkFirmware() {
|
||||
val resultCode: Int = NativeLibrary.verifyFirmware()
|
||||
if (resultCode == 0) return
|
||||
|
||||
val resultString: String =
|
||||
resources.getStringArray(R.array.verifyFirmwareResults)[resultCode]
|
||||
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.firmware_invalid,
|
||||
descriptionString = resultString,
|
||||
helpLinkId = R.string.firmware_missing_help
|
||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
|
||||
|
@ -419,7 +402,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
cacheFirmwareDir.copyRecursively(firmwarePath, true)
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
homeViewModel.setCheckFirmware(true)
|
||||
getString(R.string.save_file_imported_success)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
@ -449,7 +431,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
// Optionally reinitialize the system or perform other necessary steps
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
homeViewModel.setCheckFirmware(true)
|
||||
messageToShow = getString(R.string.firmware_uninstalled_success)
|
||||
} else {
|
||||
messageToShow = getString(R.string.firmware_uninstalled_failure)
|
||||
|
|
|
@ -124,11 +124,16 @@ object CustomSettingsHandler {
|
|||
|
||||
// Check for driver requirements if activity and driverViewModel are provided
|
||||
if (activity != null && driverViewModel != null) {
|
||||
val driverPath = extractDriverPath(customSettings)
|
||||
if (driverPath != null) {
|
||||
Log.info("[CustomSettingsHandler] Custom settings specify driver: $driverPath")
|
||||
val rawDriverPath = extractDriverPath(customSettings)
|
||||
if (rawDriverPath != null) {
|
||||
// Normalize to local storage path (we only store drivers under driverStoragePath)
|
||||
val driverFilename = rawDriverPath.substringAfterLast('/')
|
||||
.substringAfterLast('\\')
|
||||
val localDriverPath = "${GpuDriverHelper.driverStoragePath}$driverFilename"
|
||||
Log.info("[CustomSettingsHandler] Custom settings specify driver: $rawDriverPath (normalized: $localDriverPath)")
|
||||
|
||||
// Check if driver exists in the driver storage
|
||||
val driverFile = File(driverPath)
|
||||
val driverFile = File(localDriverPath)
|
||||
if (!driverFile.exists()) {
|
||||
Log.info("[CustomSettingsHandler] Driver not found locally: ${driverFile.name}")
|
||||
|
||||
|
@ -182,7 +187,7 @@ object CustomSettingsHandler {
|
|||
}
|
||||
|
||||
// Attempt to download and install the driver
|
||||
val driverUri = DriverResolver.ensureDriverAvailable(driverPath, activity) { progress ->
|
||||
val driverUri = DriverResolver.ensureDriverAvailable(driverFilename, activity) { progress ->
|
||||
progressChannel.trySend(progress.toInt())
|
||||
}
|
||||
|
||||
|
@ -209,12 +214,12 @@ object CustomSettingsHandler {
|
|||
return null
|
||||
}
|
||||
|
||||
// Verify the downloaded driver
|
||||
val installedFile = File(driverPath)
|
||||
// Verify the downloaded driver (from normalized local path)
|
||||
val installedFile = File(localDriverPath)
|
||||
val metadata = GpuDriverHelper.getMetadataFromZip(installedFile)
|
||||
if (metadata.name == null) {
|
||||
Log.error(
|
||||
"[CustomSettingsHandler] Downloaded driver is invalid: $driverPath"
|
||||
"[CustomSettingsHandler] Downloaded driver is invalid: $localDriverPath"
|
||||
)
|
||||
Toast.makeText(
|
||||
activity,
|
||||
|
@ -232,7 +237,7 @@ object CustomSettingsHandler {
|
|||
}
|
||||
|
||||
// Add to driver list
|
||||
driverViewModel.onDriverAdded(Pair(driverPath, metadata))
|
||||
driverViewModel.onDriverAdded(Pair(localDriverPath, metadata))
|
||||
Log.info(
|
||||
"[CustomSettingsHandler] Successfully downloaded and installed driver: ${metadata.name}"
|
||||
)
|
||||
|
@ -268,7 +273,7 @@ object CustomSettingsHandler {
|
|||
// Driver exists, verify it's valid
|
||||
val metadata = GpuDriverHelper.getMetadataFromZip(driverFile)
|
||||
if (metadata.name == null) {
|
||||
Log.error("[CustomSettingsHandler] Invalid driver file: $driverPath")
|
||||
Log.error("[CustomSettingsHandler] Invalid driver file: $localDriverPath")
|
||||
Toast.makeText(
|
||||
activity,
|
||||
activity.getString(
|
||||
|
@ -459,6 +464,8 @@ object CustomSettingsHandler {
|
|||
|
||||
if (inGpuDriverSection && trimmed.startsWith("driver_path=")) {
|
||||
return trimmed.substringAfter("driver_path=")
|
||||
.trim()
|
||||
.removeSurrounding("\"", "\"")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,48 @@ object DriverResolver {
|
|||
val filename: String
|
||||
)
|
||||
|
||||
// Matching helpers
|
||||
private val KNOWN_SUFFIXES = listOf(
|
||||
".adpkg.zip",
|
||||
".zip",
|
||||
".7z",
|
||||
".tar.gz",
|
||||
".tar.xz",
|
||||
".rar"
|
||||
)
|
||||
|
||||
private fun stripKnownSuffixes(name: String): String {
|
||||
var result = name
|
||||
var changed: Boolean
|
||||
do {
|
||||
changed = false
|
||||
for (s in KNOWN_SUFFIXES) {
|
||||
if (result.endsWith(s, ignoreCase = true)) {
|
||||
result = result.dropLast(s.length)
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
} while (changed)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun normalizeName(name: String): String {
|
||||
val base = stripKnownSuffixes(name.lowercase())
|
||||
// Remove non-alphanumerics to make substring checks resilient
|
||||
return base.replace(Regex("[^a-z0-9]+"), " ").trim()
|
||||
}
|
||||
|
||||
private fun tokenize(name: String): Set<String> =
|
||||
normalizeName(name).split(Regex("\\s+")).filter { it.isNotBlank() }.toSet()
|
||||
|
||||
// Jaccard similarity between two sets
|
||||
private fun jaccard(a: Set<String>, b: Set<String>): Double {
|
||||
if (a.isEmpty() || b.isEmpty()) return 0.0
|
||||
val inter = a.intersect(b).size.toDouble()
|
||||
val uni = a.union(b).size.toDouble()
|
||||
return if (uni == 0.0) 0.0 else inter / uni
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a driver download URL from its filename
|
||||
* @param filename The driver filename (e.g., "turnip_mrpurple-T19-toasted.adpkg.zip")
|
||||
|
@ -98,7 +140,7 @@ object DriverResolver {
|
|||
async {
|
||||
searchRepository(repoPath, filename)
|
||||
}
|
||||
}.mapNotNull { it.await() }.firstOrNull().also { resolved ->
|
||||
}.firstNotNullOfOrNull { it.await() }.also { resolved ->
|
||||
// Cache the result if found
|
||||
resolved?.let {
|
||||
urlCache[filename] = it
|
||||
|
@ -119,22 +161,56 @@ object DriverResolver {
|
|||
releaseCache[repoPath] = it
|
||||
}
|
||||
|
||||
// Search through all releases and artifacts
|
||||
// First pass: exact name (case-insensitive) against asset filenames
|
||||
val target = filename.lowercase()
|
||||
for (release in releases) {
|
||||
for (artifact in release.artifacts) {
|
||||
if (artifact.name == filename) {
|
||||
Log.info(
|
||||
"[DriverResolver] Found $filename in $repoPath/${release.tagName}"
|
||||
)
|
||||
if (artifact.name.equals(filename, ignoreCase = true) || artifact.name.lowercase() == target) {
|
||||
Log.info("[DriverResolver] Found $filename in $repoPath/${release.tagName}")
|
||||
return@withContext ResolvedDriver(
|
||||
downloadUrl = artifact.url.toString(),
|
||||
repoPath = repoPath,
|
||||
releaseTag = release.tagName,
|
||||
filename = filename
|
||||
filename = artifact.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: fuzzy match by asset filenames only
|
||||
val reqNorm = normalizeName(filename)
|
||||
val reqTokens = tokenize(filename)
|
||||
var best: ResolvedDriver? = null
|
||||
var bestScore = 0.0
|
||||
|
||||
for (release in releases) {
|
||||
for (artifact in release.artifacts) {
|
||||
val artNorm = normalizeName(artifact.name)
|
||||
val artTokens = tokenize(artifact.name)
|
||||
|
||||
var score = jaccard(reqTokens, artTokens)
|
||||
// Boost if one normalized name contains the other
|
||||
if (artNorm.contains(reqNorm) || reqNorm.contains(artNorm)) {
|
||||
score = maxOf(score, 0.92)
|
||||
}
|
||||
|
||||
if (score > bestScore) {
|
||||
bestScore = score
|
||||
best = ResolvedDriver(
|
||||
downloadUrl = artifact.url.toString(),
|
||||
repoPath = repoPath,
|
||||
releaseTag = release.tagName,
|
||||
filename = artifact.name
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Threshold to avoid bad guesses, this worked fine in testing but might need tuning
|
||||
if (best != null && bestScore >= 0.6) {
|
||||
Log.info("[DriverResolver] Fuzzy matched $filename -> ${best.filename} in ${best.repoPath} (score=%.2f)".format(bestScore))
|
||||
return@withContext best
|
||||
}
|
||||
null
|
||||
} catch (e: Exception) {
|
||||
Log.error("[DriverResolver] Failed to search $repoPath: ${e.message}")
|
||||
|
@ -296,8 +372,8 @@ object DriverResolver {
|
|||
context: Context,
|
||||
onProgress: ((Float) -> Unit)? = null
|
||||
): Uri? {
|
||||
// Extract filename from path
|
||||
val filename = driverPath.substringAfterLast('/')
|
||||
// Extract filename from path (support both separators)
|
||||
val filename = driverPath.substringAfterLast('/').substringAfterLast('\\')
|
||||
|
||||
// Check if driver already exists locally
|
||||
val localPath = "${GpuDriverHelper.driverStoragePath}$filename"
|
||||
|
|
|
@ -17,7 +17,7 @@ add_library(yuzu-android SHARED
|
|||
|
||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||
|
||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common Vulkan::Headers)
|
||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common Vulkan::Headers GPUOpen::VulkanMemoryAllocator)
|
||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
|
||||
if (ARCHITECTURE_arm64)
|
||||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||
|
|
|
@ -596,6 +596,8 @@ jstring Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getGpuModel(JNIEnv *env, j
|
|||
|
||||
const std::string model_name{device.GetModelName()};
|
||||
|
||||
window.release();
|
||||
|
||||
return Common::Android::ToJString(env, model_name);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
android:icon="@drawable/ic_pause"
|
||||
android:title="@string/emulation_pause" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_quick_overlay"
|
||||
android:icon="@drawable/ic_controller"
|
||||
android:title="@string/emulation_show_overlay"/>
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
|
|
|
@ -498,6 +498,8 @@
|
|||
<string name="use_custom_rtc">ساعة مخصصة في الوقت الحقيقي</string>
|
||||
<string name="use_custom_rtc_description">يسمح لك بتعيين ساعة مخصصة في الوقت الفعلي منفصلة عن وقت النظام الحالي لديك</string>
|
||||
<string name="set_custom_rtc">تعيين ساعة مخصصة في الوقت الحقيقي</string>
|
||||
<string name="disable_nca_verification">تعطيل التحقق من NCA</string>
|
||||
<string name="disable_nca_verification_description">يعطل التحقق من سلامة أرشيفات محتوى NCA. قد يحسن هذا من سرعة التحميل لكنه يخاطر بتلف البيانات أو تمرير ملفات غير صالحة دون اكتشاف. ضروري لجعل الألعاب والتحديثات التي تتطلب نظامًا أساسيًا 20+ تعمل.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">توليد</string>
|
||||
|
@ -733,7 +735,8 @@
|
|||
<string name="emulation_rel_stick_center">مركز العصا النسبي</string>
|
||||
<string name="emulation_dpad_slide">مزلاق الأسهم</string>
|
||||
<string name="emulation_haptics">الاهتزازات الديناميكية</string>
|
||||
<string name="emulation_show_overlay">عرض التراكب</string>
|
||||
<string name="emulation_show_overlay">إظهار وحدة التحكم</string>
|
||||
<string name="emulation_hide_overlay">إخفاء وحدة التحكم</string>
|
||||
<string name="emulation_toggle_all">الكل</string>
|
||||
<string name="emulation_control_adjust">ضبط التراكب</string>
|
||||
<string name="emulation_control_scale">الحجم</string>
|
||||
|
|
|
@ -482,6 +482,8 @@
|
|||
<string name="use_custom_rtc">RTCی تایبەتمەند</string>
|
||||
<string name="use_custom_rtc_description">ڕێگەت پێدەدات کاتژمێرێکی کاتی ڕاستەقینەی تایبەتمەند دابنێیت کە جیاوازە لە کاتی ئێستای سیستەمەکەت.</string>
|
||||
<string name="set_custom_rtc">دانانی RTCی تایبەتمەند</string>
|
||||
<string name="disable_nca_verification">ناچالاککردنی پشکنینی NCA</string>
|
||||
<string name="disable_nca_verification_description">پشکنینی پێکهاتەی ئارشیڤەکانی ناوەڕۆکی NCA ناچالاک دەکات. ئەمە لەوانەیە خێرایی بارکردن بهرهوپێش ببات، بەڵام مەترسی لەناوچوونی داتا یان ئەوەی فایلە نادروستەکان بەبێ ئەوەی دۆزرایەوە تێپەڕبن زیاتر دەکات. بۆ ئەوەی یاری و نوێکردنەوەکان کار بکەن کە پێویستی بە فریموێری 20+ هەیە زۆر پێویستە.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">بەرهەم هێنان</string>
|
||||
|
@ -710,7 +712,8 @@
|
|||
<string name="emulation_rel_stick_center">ناوەندی گێڕ بەنزیکەیی</string>
|
||||
<string name="emulation_dpad_slide">خلیسکانی 4 دوگمەکە</string>
|
||||
<string name="emulation_haptics">لەرینەوەی پەنجەلێدان</string>
|
||||
<string name="emulation_show_overlay">نیشاندانی داپۆشەر</string>
|
||||
<string name="emulation_show_overlay">نیشاندانی کۆنتڕۆڵەر</string>
|
||||
<string name="emulation_hide_overlay">پیشاندانی کۆنتڕۆڵەر</string>
|
||||
<string name="emulation_toggle_all">گۆڕینی سەرجەم</string>
|
||||
<string name="emulation_control_adjust">ڕێکخستنی داپۆشەر</string>
|
||||
<string name="emulation_control_scale">پێوەر</string>
|
||||
|
|
|
@ -458,6 +458,8 @@
|
|||
<string name="use_custom_rtc">Vlastní RTC</string>
|
||||
<string name="use_custom_rtc_description">Vlastní nastavení času</string>
|
||||
<string name="set_custom_rtc">Nastavit vlastní RTC</string>
|
||||
<string name="disable_nca_verification">Zakázat ověřování NCA</string>
|
||||
<string name="disable_nca_verification_description">Zakáže ověřování integrity archivů obsahu NCA. To může zlepšit rychlost načítání, ale hrozí poškození dat nebo neodhalení neplatných souborů. Je nutné, aby fungovaly hry a aktualizace vyžadující firmware 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generovat</string>
|
||||
|
@ -691,7 +693,8 @@
|
|||
<string name="emulation_rel_stick_center">Relativní střed joysticku</string>
|
||||
<string name="emulation_dpad_slide">D-pad slide</string>
|
||||
<string name="emulation_haptics">Haptická odezva</string>
|
||||
<string name="emulation_show_overlay">Zobrazit překryv</string>
|
||||
<string name="emulation_show_overlay">Zobrazit ovladač</string>
|
||||
<string name="emulation_hide_overlay">Skrýt ovladač</string>
|
||||
<string name="emulation_toggle_all">Přepnout vše</string>
|
||||
<string name="emulation_control_adjust">Upravit překryv</string>
|
||||
<string name="emulation_control_scale">Měřítko</string>
|
||||
|
|
|
@ -486,6 +486,8 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
|
|||
<string name="select_rtc_date">RTC-Datum auswählen</string>
|
||||
<string name="select_rtc_time">RTC-Zeit auswählen</string>
|
||||
<string name="use_custom_rtc">Benutzerdefinierte Echtzeituhr</string>
|
||||
<string name="disable_nca_verification">NCA-Verifizierung deaktivieren</string>
|
||||
<string name="disable_nca_verification_description">Deaktiviert die Integritätsprüfung von NCA-Inhaltsarchiven. Dies kann die Ladegeschwindigkeit verbessern, riskiert jedoch Datenbeschädigung oder dass ungültige Dateien unentdeckt bleiben. Ist notwendig, um Spiele und Updates, die Firmware 20+ benötigen, zum Laufen zu bringen.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generieren</string>
|
||||
|
@ -762,6 +764,13 @@ Wirklich fortfahren?</string>
|
|||
<string name="emulation_exit">Emulation beenden</string>
|
||||
<string name="emulation_done">Fertig</string>
|
||||
<string name="emulation_fps_counter">FPS Zähler</string>
|
||||
<string name="emulation_thermal_indicator"></string>
|
||||
<string name="emulation_toggle_controls">Steuerung umschalten</string>
|
||||
<string name="emulation_rel_stick_center">Relativer Stick-Zentrum</string>
|
||||
<string name="emulation_dpad_slide">D-Pad-Scrollen</string>
|
||||
<string name="emulation_haptics">Haptisches Feedback</string>
|
||||
<string name="emulation_show_overlay">Controller anzeigen</string>
|
||||
<string name="emulation_hide_overlay">Controller ausblenden</string>
|
||||
<string name="emulation_toggle_all">Alle umschalten</string>
|
||||
<string name="emulation_control_adjust">Overlay anpassen</string>
|
||||
<string name="emulation_control_scale">Größe</string>
|
||||
|
|
|
@ -506,6 +506,8 @@
|
|||
<string name="use_custom_rtc">RTC personalizado</string>
|
||||
<string name="use_custom_rtc_description">Te permite tener un reloj personalizado en tiempo real diferente del tiempo del propio sistema.</string>
|
||||
<string name="set_custom_rtc">Configurar RTC personalizado</string>
|
||||
<string name="disable_nca_verification">Desactivar verificación NCA</string>
|
||||
<string name="disable_nca_verification_description">Desactiva la verificación de integridad de los archivos de contenido NCA. Esto puede mejorar la velocidad de carga, pero arriesga corrupción de datos o que archivos inválidos pasen desapercibidos. Es necesario para que funcionen juegos y actualizaciones que requieren firmware 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generar</string>
|
||||
|
@ -806,7 +808,8 @@
|
|||
<string name="emulation_rel_stick_center">Centro relativo del stick</string>
|
||||
<string name="emulation_dpad_slide">Deslizamiento de la cruceta</string>
|
||||
<string name="emulation_haptics">Toques hápticos</string>
|
||||
<string name="emulation_show_overlay">Mostrar overlay</string>
|
||||
<string name="emulation_show_overlay">Mostrar controlador</string>
|
||||
<string name="emulation_hide_overlay">Ocultar controlador</string>
|
||||
<string name="emulation_toggle_all">Alternar todo</string>
|
||||
<string name="emulation_control_adjust">Ajustar overlay</string>
|
||||
<string name="emulation_control_scale">Escala</string>
|
||||
|
|
|
@ -504,6 +504,8 @@
|
|||
<string name="use_custom_rtc">زمان سفارشی</string>
|
||||
<string name="use_custom_rtc_description">به شما امکان میدهد یک ساعت سفارشی جدا از زمان فعلی سیستم خود تنظیم کنید.</string>
|
||||
<string name="set_custom_rtc">تنظیم زمان سفارشی</string>
|
||||
<string name="disable_nca_verification">غیرفعال کردن تأیید اعتبار NCA</string>
|
||||
<string name="disable_nca_verification_description">بررسی صحت آرشیوهای محتوای NCA را غیرفعال میکند. این ممکن است سرعت بارگذاری را بهبود بخشد اما خطر خرابی داده یا تشخیص داده نشدن فایلهای نامعتبر را به همراه دارد. برای کار کردن بازیها و بهروزرسانیهایی که به فرمور ۲۰+ نیاز دارند، ضروری است.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">تولید</string>
|
||||
|
@ -805,7 +807,8 @@
|
|||
<string name="emulation_rel_stick_center">مرکز نسبی استیک</string>
|
||||
<string name="emulation_dpad_slide">لغزش دکمههای جهتی</string>
|
||||
<string name="emulation_haptics">لرزش لمسی</string>
|
||||
<string name="emulation_show_overlay">نشان دادن نمایش روی صفحه</string>
|
||||
<string name="emulation_show_overlay">نمایش کنترلر</string>
|
||||
<string name="emulation_hide_overlay">پنهان کردن کنترلر</string>
|
||||
<string name="emulation_toggle_all">تغییر همه</string>
|
||||
<string name="emulation_control_adjust">تنظیم نمایش روی صفحه</string>
|
||||
<string name="emulation_control_scale">مقیاس</string>
|
||||
|
|
|
@ -506,6 +506,8 @@
|
|||
<string name="use_custom_rtc">RTC personnalisé</string>
|
||||
<string name="use_custom_rtc_description">Vous permet de définir une horloge en temps réel personnalisée distincte de l\'heure actuelle de votre système.</string>
|
||||
<string name="set_custom_rtc">Définir l\'horloge RTC personnalisée</string>
|
||||
<string name="disable_nca_verification">Désactiver la vérification NCA</string>
|
||||
<string name="disable_nca_verification_description">Désactive la vérification d\'intégrité des archives de contenu NCA. Cela peut améliorer la vitesse de chargement mais risque une corruption des données ou que des fichiers invalides ne soient pas détectés. Est nécessaire pour faire fonctionner les jeux et mises à jour nécessitant un firmware 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Générer</string>
|
||||
|
@ -854,7 +856,8 @@
|
|||
<string name="emulation_rel_stick_center">Centre du stick relatif</string>
|
||||
<string name="emulation_dpad_slide">Glissement du D-pad</string>
|
||||
<string name="emulation_haptics">Toucher haptique</string>
|
||||
<string name="emulation_show_overlay">Afficher l\'overlay</string>
|
||||
<string name="emulation_show_overlay">Afficher la manette</string>
|
||||
<string name="emulation_hide_overlay">Masquer la manette</string>
|
||||
<string name="emulation_toggle_all">Tout basculer</string>
|
||||
<string name="emulation_control_adjust">Ajuster l\'overlay</string>
|
||||
<string name="emulation_control_scale">Échelle</string>
|
||||
|
|
|
@ -505,6 +505,8 @@
|
|||
<string name="use_custom_rtc">RTC מותאם אישית</string>
|
||||
<string name="use_custom_rtc_description">מאפשר לך לקבוע שעון זמן אמת נפרד משעון המערכת שלך.</string>
|
||||
<string name="set_custom_rtc">קבע RTC מותאם אישית</string>
|
||||
<string name="disable_nca_verification">השבת אימות NCA</string>
|
||||
<string name="disable_nca_verification_description">משבית את אימות השלמות של ארכיוני התוכן של NCA. זה עשוי לשפר את מהירות הטעינה אך מסתכן בשחיקת נתונים או שמא קבצים לא חוקיים יעברו ללא זיהוי. זה הכרחי כדי לגרום למשחקים ועדכונים הדורשים firmware 20+ לעבוד.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">יצירה</string>
|
||||
|
@ -739,7 +741,8 @@
|
|||
<string name="emulation_rel_stick_center">מרכז ג׳ויסטיק יחסי</string>
|
||||
<string name="emulation_dpad_slide">החלקת D-pad</string>
|
||||
<string name="emulation_haptics">רטט מגע</string>
|
||||
<string name="emulation_show_overlay">הצג את שכבת-העל</string>
|
||||
<string name="emulation_show_overlay">הצג בקר</string>
|
||||
<string name="emulation_hide_overlay">הסתר בקר</string>
|
||||
<string name="emulation_toggle_all">החלף הכל</string>
|
||||
<string name="emulation_control_adjust">התאם את שכבת-העל</string>
|
||||
<string name="emulation_control_scale">קנה מידה</string>
|
||||
|
|
|
@ -501,6 +501,8 @@
|
|||
<string name="use_custom_rtc">Egyéni RTC</string>
|
||||
<string name="use_custom_rtc_description">Megadhatsz egy valós idejű órát, amely eltér a rendszer által használt órától.</string>
|
||||
<string name="set_custom_rtc">Egyéni RTC beállítása</string>
|
||||
<string name="disable_nca_verification">NCA ellenőrzés letiltása</string>
|
||||
<string name="disable_nca_verification_description">Letiltja az NCA tartalomarchívumok integritás-ellenőrzését. Ez javíthatja a betöltési sebességet, de az adatsérülés vagy az érvénytelen fájlok észrevétlen maradásának kockázatával jár. Elengedhetetlen a 20+ firmware-et igénylő játékok és frissítések működtetéséhez.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generálás</string>
|
||||
|
@ -843,7 +845,8 @@
|
|||
<string name="emulation_toggle_controls">Irányítás átkapcsolása</string>
|
||||
<string name="emulation_dpad_slide">D-pad csúsztatása</string>
|
||||
<string name="emulation_haptics">Érintés haptikája</string>
|
||||
<string name="emulation_show_overlay">Átfedés mutatása</string>
|
||||
<string name="emulation_show_overlay">Vezérlő megjelenítése</string>
|
||||
<string name="emulation_hide_overlay">Vezérlő elrejtése</string>
|
||||
<string name="emulation_toggle_all">Összes átkapcsolása</string>
|
||||
<string name="emulation_control_adjust">Átfedés testreszabása</string>
|
||||
<string name="emulation_control_scale">Skálázás</string>
|
||||
|
|
|
@ -502,6 +502,8 @@
|
|||
<string name="use_custom_rtc">RTC Kustom</string>
|
||||
<string name="use_custom_rtc_description">Memungkinkan Anda untuk mengatur jam waktu nyata kustom yang terpisah dari waktu sistem saat ini Anda.</string>
|
||||
<string name="set_custom_rtc">Setel RTC Kustom</string>
|
||||
<string name="disable_nca_verification">Nonaktifkan Verifikasi NCA</string>
|
||||
<string name="disable_nca_verification_description">Menonaktifkan verifikasi integritas arsip konten NCA. Ini dapat meningkatkan kecepatan pemuatan tetapi berisiko kerusakan data atau file yang tidak valid tidak terdeteksi. Diperlukan untuk membuat game dan pembaruan yang membutuhkan firmware 20+ bekerja.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Hasilkan</string>
|
||||
|
@ -798,7 +800,8 @@
|
|||
<string name="emulation_rel_stick_center">Pusat stick relatif</string>
|
||||
<string name="emulation_dpad_slide">Geser Dpad</string>
|
||||
<string name="emulation_haptics">Haptik</string>
|
||||
<string name="emulation_show_overlay">Tampilkan Hamparan</string>
|
||||
<string name="emulation_show_overlay">Tampilkan Kontroler</string>
|
||||
<string name="emulation_hide_overlay">Sembunyikan Kontroler</string>
|
||||
<string name="emulation_toggle_all">Alihkan Semua</string>
|
||||
<string name="emulation_control_adjust">Menyesuaikan</string>
|
||||
<string name="emulation_control_scale">Skala</string>
|
||||
|
|
|
@ -505,6 +505,8 @@
|
|||
<string name="use_custom_rtc">RTC Personalizzato</string>
|
||||
<string name="use_custom_rtc_description">Ti permette di impostare un orologio in tempo reale personalizzato, completamente separato da quello di sistema.</string>
|
||||
<string name="set_custom_rtc">Imposta un orologio in tempo reale personalizzato</string>
|
||||
<string name="disable_nca_verification">Disabilita verifica NCA</string>
|
||||
<string name="disable_nca_verification_description">Disabilita la verifica dell\'integrità degli archivi di contenuto NCA. Può migliorare la velocità di caricamento ma rischia il danneggiamento dei dati o che file non validi passino inosservati. Necessario per far funzionare giochi e aggiornamenti che richiedono il firmware 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Genera</string>
|
||||
|
@ -770,7 +772,8 @@
|
|||
<string name="emulation_rel_stick_center">Centro relativo degli Stick</string>
|
||||
<string name="emulation_dpad_slide">DPad A Scorrimento</string>
|
||||
<string name="emulation_haptics">Feedback Aptico</string>
|
||||
<string name="emulation_show_overlay">Mostra l\'overlay</string>
|
||||
<string name="emulation_show_overlay">Mostra l\'controller</string>
|
||||
<string name="emulation_hide_overlay">Nascondi l\'controller</string>
|
||||
<string name="emulation_toggle_all">Attiva/Disattiva tutto</string>
|
||||
<string name="emulation_control_adjust">Regola l\'overlay</string>
|
||||
<string name="emulation_control_scale">Scala</string>
|
||||
|
|
|
@ -491,6 +491,8 @@
|
|||
<string name="use_custom_rtc">カスタム RTC</string>
|
||||
<string name="use_custom_rtc_description">現在のシステム時間とは別に、任意のリアルタイムクロックを設定できます。</string>
|
||||
<string name="set_custom_rtc">カスタムRTCを設定</string>
|
||||
<string name="disable_nca_verification">NCA検証を無効化</string>
|
||||
<string name="disable_nca_verification_description">NCAコンテンツアーカイブの整合性検証を無効にします。読み込み速度が向上する可能性がありますが、データ破損や不正なファイルが検出されないリスクがあります。ファームウェア20以上が必要なゲームや更新を動作させるために必要です。</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">生成</string>
|
||||
|
@ -729,7 +731,8 @@
|
|||
<string name="emulation_rel_stick_center">スティックを固定しない</string>
|
||||
<string name="emulation_dpad_slide">十字キーをスライド操作</string>
|
||||
<string name="emulation_haptics">タッチ振動</string>
|
||||
<string name="emulation_show_overlay">ボタンを表示</string>
|
||||
<string name="emulation_show_overlay">コントローラーを表示</string>
|
||||
<string name="emulation_hide_overlay">コントローラーを非表示</string>
|
||||
<string name="emulation_toggle_all">すべて切替</string>
|
||||
<string name="emulation_control_adjust">見た目を調整</string>
|
||||
<string name="emulation_control_scale">大きさ</string>
|
||||
|
|
|
@ -501,6 +501,8 @@
|
|||
<string name="use_custom_rtc">사용자 지정 RTC</string>
|
||||
<string name="use_custom_rtc_description">현재 시스템 시간과 별도로 사용자 지정 RTC를 설정할 수 있습니다.</string>
|
||||
<string name="set_custom_rtc">사용자 지정 RTC 설정</string>
|
||||
<string name="disable_nca_verification">NCA 검증 비활성화</string>
|
||||
<string name="disable_nca_verification_description">NCA 콘텐츠 아카이브의 무결성 검증을 비활성화합니다. 로딩 속도를 향상시킬 수 있지만 데이터 손상이나 유효하지 않은 파일이 미검증될 위험이 있습니다. 펌웨어 20+가 필요한 게임 및 업데이트를 실행하려면 필요합니다.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">생성</string>
|
||||
|
@ -798,6 +800,7 @@
|
|||
<string name="emulation_dpad_slide">십자키 슬라이드</string>
|
||||
<string name="emulation_haptics">터치 햅틱</string>
|
||||
<string name="emulation_show_overlay">컨트롤러 표시</string>
|
||||
<string name="emulation_hide_overlay">컨트롤러 숨기기</string>
|
||||
<string name="emulation_toggle_all">모두 선택</string>
|
||||
<string name="emulation_control_adjust">컨트롤러 조정</string>
|
||||
<string name="emulation_control_scale">크기</string>
|
||||
|
|
|
@ -482,6 +482,8 @@
|
|||
<string name="use_custom_rtc">Tilpasset Sannhetstidsklokke</string>
|
||||
<string name="use_custom_rtc_description">Gjør det mulig å stille inn en egendefinert sanntidsklokke separat fra den gjeldende systemtiden.</string>
|
||||
<string name="set_custom_rtc">Angi tilpasset RTC</string>
|
||||
<string name="disable_nca_verification">Deaktiver NCA-verifisering</string>
|
||||
<string name="disable_nca_verification_description">Deaktiverer integritetsverifisering av NCA-innholdsarkiv. Dette kan forbedre lastehastigheten, men medfører risiko for datakorrupsjon eller at ugyldige filer ikke oppdages. Er nødvendig for å få spill og oppdateringer som trenger firmware 20+ til å fungere.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generer</string>
|
||||
|
@ -720,7 +722,8 @@
|
|||
<string name="emulation_rel_stick_center">Relativt pinnesenter</string>
|
||||
<string name="emulation_dpad_slide">D-pad-skyving</string>
|
||||
<string name="emulation_haptics">Berøringshaptikk</string>
|
||||
<string name="emulation_show_overlay">Vis overlegg</string>
|
||||
<string name="emulation_show_overlay">Vis kontroller</string>
|
||||
<string name="emulation_hide_overlay">Skjul kontroller</string>
|
||||
<string name="emulation_toggle_all">Veksle mellom alle</string>
|
||||
<string name="emulation_control_adjust">Juster overlegg</string>
|
||||
<string name="emulation_control_scale">Skaler</string>
|
||||
|
|
|
@ -482,6 +482,8 @@
|
|||
<string name="use_custom_rtc">Niestandardowy RTC</string>
|
||||
<string name="use_custom_rtc_description">Ta opcja pozwala na wybranie własnych ustawień czasu używanych w czasie emulacji, innych niż czas systemu Android.</string>
|
||||
<string name="set_custom_rtc">Ustaw niestandardowy czas RTC</string>
|
||||
<string name="disable_nca_verification">Wyłącz weryfikację NCA</string>
|
||||
<string name="disable_nca_verification_description">Wyłącza weryfikację integralności archiwów zawartości NCA. Może to poprawić szybkość ładowania, ale niesie ryzyko uszkodzenia danych lub niezauważenia nieprawidłowych plików. Konieczne, aby działały gry i aktualizacje wymagające firmware\'u 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Generuj</string>
|
||||
|
@ -718,7 +720,8 @@
|
|||
<string name="emulation_rel_stick_center">Wycentruj gałki</string>
|
||||
<string name="emulation_dpad_slide">Ruchomy D-pad</string>
|
||||
<string name="emulation_haptics">Wibracje haptyczne</string>
|
||||
<string name="emulation_show_overlay">Pokaż przyciski</string>
|
||||
<string name="emulation_show_overlay">Pokaż kontroler</string>
|
||||
<string name="emulation_hide_overlay">Ukryj kontroler</string>
|
||||
<string name="emulation_toggle_all">Włącz wszystkie</string>
|
||||
<string name="emulation_control_adjust">Dostosuj nakładkę</string>
|
||||
<string name="emulation_control_scale">Skala</string>
|
||||
|
|
|
@ -506,6 +506,8 @@
|
|||
<string name="use_custom_rtc">Data e hora personalizadas</string>
|
||||
<string name="use_custom_rtc_description">Permite a você configurar um relógio em tempo real separado do relógio do seu dispositivo.</string>
|
||||
<string name="set_custom_rtc">Definir um relógio em tempo real personalizado</string>
|
||||
<string name="disable_nca_verification">Desativar verificação NCA</string>
|
||||
<string name="disable_nca_verification_description">Desativa a verificação de integridade de arquivos de conteúdo NCA. Pode melhorar a velocidade de carregamento, mas arrisica corromper dados ou que arquivos inválidos passem despercebidos. É necessário para fazer jogos e atualizações que exigem firmware 20+ funcionarem.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Gerar</string>
|
||||
|
@ -855,7 +857,8 @@ uma tentativa de mapeamento automático</string>
|
|||
<string name="emulation_rel_stick_center">Centro Relativo do Analógico</string>
|
||||
<string name="emulation_dpad_slide">Deslizamento dos Botões Direcionais</string>
|
||||
<string name="emulation_haptics">Vibração ao tocar</string>
|
||||
<string name="emulation_show_overlay">Mostrar overlay</string>
|
||||
<string name="emulation_show_overlay">Mostrar controle</string>
|
||||
<string name="emulation_hide_overlay">Ocultar controle</string>
|
||||
<string name="emulation_toggle_all">Marcar/Desmarcar tudo</string>
|
||||
<string name="emulation_control_adjust">Ajustar overlay</string>
|
||||
<string name="emulation_control_scale">Escala</string>
|
||||
|
|
|
@ -506,6 +506,8 @@
|
|||
<string name="use_custom_rtc">RTC personalizado</string>
|
||||
<string name="use_custom_rtc_description">Permite a você configurar um relógio em tempo real separado do relógio do seu dispositivo.</string>
|
||||
<string name="set_custom_rtc">Defina um relógio em tempo real personalizado</string>
|
||||
<string name="disable_nca_verification">Desativar verificação NCA</string>
|
||||
<string name="disable_nca_verification_description">Desativa a verificação de integridade dos arquivos de conteúdo NCA. Pode melhorar a velocidade de carregamento, mas arrisca a corrupção de dados ou que ficheiros inválidos passem despercebidos. É necessário para que jogos e atualizações que necessitam de firmware 20+ funcionem.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Gerar</string>
|
||||
|
@ -855,7 +857,8 @@ uma tentativa de mapeamento automático</string>
|
|||
<string name="emulation_rel_stick_center">Centro Relativo de Analógico</string>
|
||||
<string name="emulation_dpad_slide">Deslizamento dos Botões Direcionais</string>
|
||||
<string name="emulation_haptics">Vibração ao tocar</string>
|
||||
<string name="emulation_show_overlay">Mostrar overlay</string>
|
||||
<string name="emulation_show_overlay">Mostrar comando</string>
|
||||
<string name="emulation_hide_overlay">Ocultar comando</string>
|
||||
<string name="emulation_toggle_all">Marcar/Desmarcar tudo</string>
|
||||
<string name="emulation_control_adjust">Ajustar overlay</string>
|
||||
<string name="emulation_control_scale">Escala</string>
|
||||
|
|
|
@ -508,6 +508,8 @@
|
|||
<string name="use_custom_rtc">Пользовательский RTC</string>
|
||||
<string name="use_custom_rtc_description">Позволяет установить пользовательские часы реального времени отдельно от текущего системного времени.</string>
|
||||
<string name="set_custom_rtc">Установить пользовательский RTC</string>
|
||||
<string name="disable_nca_verification">Отключить проверку NCA</string>
|
||||
<string name="disable_nca_verification_description">Отключает проверку целостности архивов содержимого NCA. Может улучшить скорость загрузки, но есть риск повреждения данных или того, что недействительные файлы останутся незамеченными. Необходимо для работы игр и обновлений, требующих прошивку 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Создать</string>
|
||||
|
@ -856,7 +858,8 @@
|
|||
<string name="emulation_rel_stick_center">Относительный центр стика</string>
|
||||
<string name="emulation_dpad_slide">Слайд крестовиной</string>
|
||||
<string name="emulation_haptics">Обратная связь от нажатий</string>
|
||||
<string name="emulation_show_overlay">Показать оверлей</string>
|
||||
<string name="emulation_show_overlay">Показать контроллер</string>
|
||||
<string name="emulation_hide_overlay">Скрыть контроллер</string>
|
||||
<string name="emulation_toggle_all">Переключить всё</string>
|
||||
<string name="emulation_control_adjust">Регулировка оверлея</string>
|
||||
<string name="emulation_control_scale">Масштаб</string>
|
||||
|
|
|
@ -457,6 +457,8 @@
|
|||
<string name="use_custom_rtc">Цустом РТЦ</string>
|
||||
<string name="use_custom_rtc_description">Омогућава вам да поставите прилагођени сат у реалном времену одвојено од тренутног времена система.</string>
|
||||
<string name="set_custom_rtc">Подесите прилагођени РТЦ</string>
|
||||
<string name="disable_nca_verification">Искључи верификацију НЦА</string>
|
||||
<string name="disable_nca_verification_description">Искључује верификацију интегритета НЦА архива садржаја. Ово може побољшати брзину учитавања, али ризикује оштећење података или да неважећи фајлови прођу незапажено. Неопходно је да би игре и ажурирања која захтевају firmware 20+ радили.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Генериши</string>
|
||||
|
@ -812,7 +814,8 @@
|
|||
<string name="emulation_rel_stick_center">Релативни центар за штапић</string>
|
||||
<string name="emulation_dpad_slide">Д-Пад Слиде</string>
|
||||
<string name="emulation_haptics">Додирните ХАптицс</string>
|
||||
<string name="emulation_show_overlay">Приказати прекривање</string>
|
||||
<string name="emulation_show_overlay">Приказати контролер</string>
|
||||
<string name="emulation_hide_overlay">Сакрити контролер</string>
|
||||
<string name="emulation_toggle_all">Пребацивати све</string>
|
||||
<string name="emulation_control_adjust">Подесити прекривање</string>
|
||||
<string name="emulation_control_scale">Скала</string>
|
||||
|
|
|
@ -495,6 +495,8 @@
|
|||
<string name="use_custom_rtc">Свій RTC</string>
|
||||
<string name="use_custom_rtc_description">Дозволяє встановити власний час (Real-time clock, або RTC), відмінний від системного.</string>
|
||||
<string name="set_custom_rtc">Встановити RTC</string>
|
||||
<string name="disable_nca_verification">Вимкнути перевірку NCA</string>
|
||||
<string name="disable_nca_verification_description">Вимкає перевірку цілісності архівів вмісту NCA. Може покращити швидкість завантаження, але ризикує пошкодженням даних або тим, що недійсні файли залишаться непоміченими. Необхідно для роботи ігор та оновлень, які вимагають прошивки 20+.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Створити</string>
|
||||
|
@ -749,7 +751,8 @@
|
|||
<string name="emulation_rel_stick_center">Відносний центр джойстика</string>
|
||||
<string name="emulation_dpad_slide">Ковзання D-pad</string>
|
||||
<string name="emulation_haptics">Тактильний відгук</string>
|
||||
<string name="emulation_show_overlay">Показати накладання</string>
|
||||
<string name="emulation_show_overlay">Показати контролер</string>
|
||||
<string name="emulation_hide_overlay">Сховати контролер</string>
|
||||
<string name="emulation_toggle_all">Перемкнути все</string>
|
||||
<string name="emulation_control_adjust">Налаштувати накладання</string>
|
||||
<string name="emulation_control_scale">Масштаб</string>
|
||||
|
|
|
@ -482,6 +482,8 @@
|
|||
<string name="use_custom_rtc">RTC tuỳ chỉnh</string>
|
||||
<string name="use_custom_rtc_description">Cho phép bạn thiết lập một đồng hồ thời gian thực tùy chỉnh riêng biệt so với thời gian hệ thống hiện tại.</string>
|
||||
<string name="set_custom_rtc">Thiết lập RTC tùy chỉnh</string>
|
||||
<string name="disable_nca_verification">Tắt xác minh NCA</string>
|
||||
<string name="disable_nca_verification_description">Tắt xác minh tính toàn vẹn của kho lưu trữ nội dung NCA. Có thể cải thiện tốc độ tải nhưng có nguy cơ hỏng dữ liệu hoặc các tệp không hợp lệ không bị phát hiện. Cần thiết để các trò chơi và bản cập nhật yêu cầu firmware 20+ hoạt động.</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">Tạo</string>
|
||||
|
@ -723,7 +725,8 @@
|
|||
<string name="emulation_rel_stick_center">Trung tâm nút cần xoay tương đối</string>
|
||||
<string name="emulation_dpad_slide">Trượt D-pad</string>
|
||||
<string name="emulation_haptics">Chạm haptics</string>
|
||||
<string name="emulation_show_overlay">Hiện lớp phủ</string>
|
||||
<string name="emulation_show_overlay">Hiện bộ điều khiển</string>
|
||||
<string name="emulation_hide_overlay">Ẩn bộ điều khiển</string>
|
||||
<string name="emulation_toggle_all">Chuyển đổi tất cả</string>
|
||||
<string name="emulation_control_adjust">Điều chỉnh lớp phủ</string>
|
||||
<string name="emulation_control_scale">Tỉ lệ thu phóng</string>
|
||||
|
|
|
@ -500,6 +500,8 @@
|
|||
<string name="use_custom_rtc">自定义系统时间</string>
|
||||
<string name="use_custom_rtc_description">此选项允许您设置与目前系统时间相独立的自定义系统时钟。</string>
|
||||
<string name="set_custom_rtc">设置自定义系统时间</string>
|
||||
<string name="disable_nca_verification">禁用NCA验证</string>
|
||||
<string name="disable_nca_verification_description">禁用NCA内容存档的完整性验证。可能会提高加载速度,但存在数据损坏或无效文件未被检测到的风险。对于需要固件20+的游戏和更新是必需的。</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">生成</string>
|
||||
|
@ -848,7 +850,8 @@
|
|||
<string name="emulation_rel_stick_center">相对摇杆中心</string>
|
||||
<string name="emulation_dpad_slide">十字方向键滑动</string>
|
||||
<string name="emulation_haptics">触觉反馈</string>
|
||||
<string name="emulation_show_overlay">显示虚拟按键</string>
|
||||
<string name="emulation_show_overlay">显示控制器</string>
|
||||
<string name="emulation_hide_overlay">隐藏控制器</string>
|
||||
<string name="emulation_toggle_all">全部切换</string>
|
||||
<string name="emulation_control_adjust">调整虚拟按键</string>
|
||||
<string name="emulation_control_scale">缩放</string>
|
||||
|
|
|
@ -505,6 +505,8 @@
|
|||
<string name="use_custom_rtc">自訂 RTC</string>
|
||||
<string name="use_custom_rtc_description">允許您設定與您的目前系統時間相互獨立的自訂即時時鐘。</string>
|
||||
<string name="set_custom_rtc">設定自訂 RTC</string>
|
||||
<string name="disable_nca_verification">停用NCA驗證</string>
|
||||
<string name="disable_nca_verification_description">停用NCA內容存檔的完整性驗證。可能會提高載入速度,但存在資料損毀或無效檔案未被偵測到的風險。對於需要韌體20+的遊戲和更新是必需的。</string>
|
||||
|
||||
<!-- Network settings strings -->
|
||||
<string name="generate">生成</string>
|
||||
|
@ -853,7 +855,8 @@
|
|||
<string name="emulation_rel_stick_center">相對搖桿中心</string>
|
||||
<string name="emulation_dpad_slide">方向鍵滑動</string>
|
||||
<string name="emulation_haptics">觸覺回饋技術</string>
|
||||
<string name="emulation_show_overlay">顯示覆疊</string>
|
||||
<string name="emulation_show_overlay">顯示控制器</string>
|
||||
<string name="emulation_hide_overlay">隱藏控制器</string>
|
||||
<string name="emulation_toggle_all">全部切換</string>
|
||||
<string name="emulation_control_adjust">調整覆疊</string>
|
||||
<string name="emulation_control_scale">縮放</string>
|
||||
|
|
|
@ -474,6 +474,8 @@
|
|||
<string name="use_custom_rtc">Custom RTC</string>
|
||||
<string name="use_custom_rtc_description">Allows you to set a custom real-time clock separate from your current system time.</string>
|
||||
<string name="set_custom_rtc">Set custom RTC</string>
|
||||
<string name="disable_nca_verification">Disable NCA Verification</string>
|
||||
<string name="disable_nca_verification_description">Disables integrity verification of NCA content archives. This may improve loading speed but risks data corruption or invalid files going undetected. Some games that require firmware versions 20+ may need this as well.</string>
|
||||
|
||||
<string name="generate">Generate</string>
|
||||
|
||||
|
@ -782,6 +784,9 @@
|
|||
<string name="loader_requires_firmware">Game Requires Firmware</string>
|
||||
<string name="loader_requires_firmware_description"><![CDATA[The game you are trying to launch requires firmware to boot or to get past the opening menu. Please <a href="https://yuzu-mirror.github.io/help/quickstart"> dump and install firmware</a>, or press "OK" to launch anyways.]]></string>
|
||||
|
||||
<string name="nca_verification_disabled">NCA Verification Disabled</string>
|
||||
<string name="nca_verification_disabled_description">This is required to run new games and updates, but may cause instability or crashes if NCA files are corrupt, modified, or tampered with. If unsure, re-enable verification in Advanced Settings -> System, and use firmware versions of 19.0.1 or below.</string>
|
||||
|
||||
<!-- Intent Launch strings -->
|
||||
<string name="searching_for_game">Searching for game...</string>
|
||||
<string name="game_not_found_for_title_id">Game not found for Title ID: %1$s</string>
|
||||
|
@ -835,7 +840,8 @@
|
|||
<string name="emulation_rel_stick_center">Relative stick center</string>
|
||||
<string name="emulation_dpad_slide">D-pad slide</string>
|
||||
<string name="emulation_haptics">Touch haptics</string>
|
||||
<string name="emulation_show_overlay">Show overlay</string>
|
||||
<string name="emulation_show_overlay">Show controller</string>
|
||||
<string name="emulation_hide_overlay">Hide controller</string>
|
||||
<string name="emulation_toggle_all">Toggle all</string>
|
||||
<string name="emulation_control_adjust">Adjust overlay</string>
|
||||
<string name="emulation_control_scale">Scale</string>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "common/polyfill_ranges.h"
|
||||
|
||||
namespace AudioCore {
|
||||
constexpr u32 CurrentRevision = 13;
|
||||
constexpr u32 CurrentRevision = 15;
|
||||
|
||||
enum class SupportTags {
|
||||
CommandProcessingTimeEstimatorVersion4,
|
||||
|
|
|
@ -262,23 +262,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
|||
endif()
|
||||
|
||||
if (BOOST_NO_HEADERS)
|
||||
target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool)
|
||||
target_link_libraries(common PUBLIC Boost::algorithm Boost::icl Boost::pool)
|
||||
else()
|
||||
target_link_libraries(common PUBLIC Boost::headers)
|
||||
target_link_libraries(common PUBLIC Boost::headers)
|
||||
endif()
|
||||
|
||||
if (lz4_ADDED)
|
||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
|
||||
endif()
|
||||
|
||||
target_link_libraries(common PUBLIC fmt::fmt stb::headers Threads::Threads)
|
||||
target_link_libraries(common PRIVATE lz4::lz4 LLVM::Demangle zstd::zstd)
|
||||
|
||||
if (TARGET unordered_dense::unordered_dense)
|
||||
# weird quirk of system installs
|
||||
target_link_libraries(common PUBLIC unordered_dense::unordered_dense)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
# For ASharedMemory_create
|
||||
target_link_libraries(common PRIVATE android)
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -35,60 +33,68 @@ HeapTracker::~HeapTracker() = default;
|
|||
|
||||
void HeapTracker::Map(size_t virtual_offset, size_t host_offset, size_t length,
|
||||
MemoryPermission perm, bool is_separate_heap) {
|
||||
bool rebuild_required = false;
|
||||
// When mapping other memory, map pages immediately.
|
||||
if (!is_separate_heap) {
|
||||
m_buffer.Map(virtual_offset, host_offset, length, perm, false);
|
||||
return;
|
||||
}
|
||||
|
||||
{
|
||||
// We are mapping part of a separate heap and insert into mappings.
|
||||
// We are mapping part of a separate heap.
|
||||
std::scoped_lock lk{m_lock};
|
||||
m_map_count++;
|
||||
const auto it = m_mappings.insert_or_assign(virtual_offset, SeparateHeapMap{
|
||||
|
||||
auto* const map = new SeparateHeapMap{
|
||||
.vaddr = virtual_offset,
|
||||
.paddr = host_offset,
|
||||
.size = length,
|
||||
.tick = m_tick++,
|
||||
.perm = perm,
|
||||
.is_resident = false,
|
||||
});
|
||||
// Update tick before possible rebuild.
|
||||
it.first->second.tick = m_tick++;
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count >= m_max_resident_map_count)
|
||||
rebuild_required = true;
|
||||
// Map the area.
|
||||
m_buffer.Map(it.first->first, it.first->second.paddr, it.first->second.size, it.first->second.perm, false);
|
||||
// This map is now resident.
|
||||
it.first->second.is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it.first);
|
||||
};
|
||||
|
||||
// Insert into mappings.
|
||||
m_map_count++;
|
||||
m_mappings.insert(*map);
|
||||
}
|
||||
// A rebuild was required, so perform it now.
|
||||
if (rebuild_required)
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
|
||||
// Finally, map.
|
||||
this->DeferredMapSeparateHeap(virtual_offset);
|
||||
}
|
||||
|
||||
void HeapTracker::Unmap(size_t virtual_offset, size_t size, bool is_separate_heap) {
|
||||
// If this is a separate heap...
|
||||
if (is_separate_heap) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = virtual_offset,
|
||||
};
|
||||
|
||||
// Split at the boundaries of the region we are removing.
|
||||
this->SplitHeapMapLocked(virtual_offset);
|
||||
this->SplitHeapMapLocked(virtual_offset + size);
|
||||
|
||||
// Erase all mappings in range.
|
||||
auto it = m_mappings.find(virtual_offset);
|
||||
while (it != m_mappings.end() && it->first < virtual_offset + size) {
|
||||
auto it = m_mappings.find(key);
|
||||
while (it != m_mappings.end() && it->vaddr < virtual_offset + size) {
|
||||
// Get underlying item.
|
||||
auto* const item = std::addressof(*it);
|
||||
|
||||
// If resident, erase from resident map.
|
||||
if (it->second.is_resident) {
|
||||
if (item->is_resident) {
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
m_resident_mappings.erase(m_resident_mappings.find(it->first));
|
||||
m_resident_mappings.erase(m_resident_mappings.iterator_to(*item));
|
||||
}
|
||||
|
||||
// Erase from map.
|
||||
ASSERT(--m_map_count >= 0);
|
||||
it = m_mappings.erase(it);
|
||||
|
||||
// Free the item.
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
// Unmap pages.
|
||||
m_buffer.Unmap(virtual_offset, size, false);
|
||||
}
|
||||
|
@ -110,51 +116,110 @@ void HeapTracker::Protect(size_t virtual_offset, size_t size, MemoryPermission p
|
|||
|
||||
{
|
||||
std::scoped_lock lk2{m_lock};
|
||||
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = next,
|
||||
};
|
||||
|
||||
// Try to get the next mapping corresponding to this address.
|
||||
const auto it = m_mappings.find(next);
|
||||
const auto it = m_mappings.nfind(key);
|
||||
|
||||
if (it == m_mappings.end()) {
|
||||
// There are no separate heap mappings remaining.
|
||||
next = end;
|
||||
should_protect = true;
|
||||
} else if (it->first == cur) {
|
||||
} else if (it->vaddr == cur) {
|
||||
// We are in range.
|
||||
// Update permission bits.
|
||||
it->second.perm = perm;
|
||||
it->perm = perm;
|
||||
|
||||
// Determine next address and whether we should protect.
|
||||
next = cur + it->second.size;
|
||||
should_protect = it->second.is_resident;
|
||||
next = cur + it->size;
|
||||
should_protect = it->is_resident;
|
||||
} else /* if (it->vaddr > cur) */ {
|
||||
// We weren't in range, but there is a block coming up that will be.
|
||||
next = it->first;
|
||||
next = it->vaddr;
|
||||
should_protect = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp to end.
|
||||
next = std::min(next, end);
|
||||
|
||||
// Reprotect, if we need to.
|
||||
if (should_protect)
|
||||
if (should_protect) {
|
||||
m_buffer.Protect(cur, next - cur, perm);
|
||||
}
|
||||
|
||||
// Advance.
|
||||
cur = next;
|
||||
}
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(u8* fault_address) {
|
||||
if (m_buffer.IsInVirtualRange(fault_address)) {
|
||||
return this->DeferredMapSeparateHeap(fault_address - m_buffer.VirtualBasePointer());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HeapTracker::DeferredMapSeparateHeap(size_t virtual_offset) {
|
||||
bool rebuild_required = false;
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
// Check to ensure this was a non-resident separate heap mapping.
|
||||
const auto it = this->GetNearestHeapMapLocked(virtual_offset);
|
||||
if (it == m_mappings.end() || it->is_resident) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update tick before possible rebuild.
|
||||
it->tick = m_tick++;
|
||||
|
||||
// Check if we need to rebuild.
|
||||
if (m_resident_map_count > m_max_resident_map_count) {
|
||||
rebuild_required = true;
|
||||
}
|
||||
|
||||
// Map the area.
|
||||
m_buffer.Map(it->vaddr, it->paddr, it->size, it->perm, false);
|
||||
|
||||
// This map is now resident.
|
||||
it->is_resident = true;
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*it);
|
||||
}
|
||||
|
||||
if (rebuild_required) {
|
||||
// A rebuild was required, so perform it now.
|
||||
this->RebuildSeparateHeapAddressSpace();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
||||
std::scoped_lock lk{m_rebuild_lock, m_lock};
|
||||
|
||||
ASSERT(!m_resident_mappings.empty());
|
||||
|
||||
// Dump half of the mappings.
|
||||
//
|
||||
// Despite being worse in theory, this has proven to be better in practice than more
|
||||
// regularly dumping a smaller amount, because it significantly reduces average case
|
||||
// lock contention.
|
||||
std::size_t const desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
std::size_t const evict_count = m_resident_map_count - desired_count;
|
||||
const size_t desired_count = std::min(m_resident_map_count, m_max_resident_map_count) / 2;
|
||||
const size_t evict_count = m_resident_map_count - desired_count;
|
||||
auto it = m_resident_mappings.begin();
|
||||
for (std::size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
|
||||
for (size_t i = 0; i < evict_count && it != m_resident_mappings.end(); i++) {
|
||||
// Unmark and unmap.
|
||||
it->second.is_resident = false;
|
||||
m_buffer.Unmap(it->first, it->second.size, false);
|
||||
it->is_resident = false;
|
||||
m_buffer.Unmap(it->vaddr, it->size, false);
|
||||
|
||||
// Advance.
|
||||
ASSERT(--m_resident_map_count >= 0);
|
||||
it = m_resident_mappings.erase(it);
|
||||
|
@ -163,32 +228,53 @@ void HeapTracker::RebuildSeparateHeapAddressSpace() {
|
|||
|
||||
void HeapTracker::SplitHeapMap(VAddr offset, size_t size) {
|
||||
std::scoped_lock lk{m_lock};
|
||||
|
||||
this->SplitHeapMapLocked(offset);
|
||||
this->SplitHeapMapLocked(offset + size);
|
||||
}
|
||||
|
||||
void HeapTracker::SplitHeapMapLocked(VAddr offset) {
|
||||
auto it = this->GetNearestHeapMapLocked(offset);
|
||||
if (it != m_mappings.end() && it->first != offset) {
|
||||
// Adjust left iterator
|
||||
auto const orig_size = it->second.size;
|
||||
auto const left_size = offset - it->first;
|
||||
it->second.size = left_size;
|
||||
// Insert the new right map.
|
||||
auto const right = SeparateHeapMap{
|
||||
.paddr = it->second.paddr + left_size,
|
||||
.size = orig_size - left_size,
|
||||
.tick = it->second.tick,
|
||||
.perm = it->second.perm,
|
||||
.is_resident = it->second.is_resident,
|
||||
};
|
||||
m_map_count++;
|
||||
auto rit = m_mappings.insert_or_assign(it->first + left_size, right);
|
||||
if (rit.first->second.is_resident) {
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*rit.first);
|
||||
}
|
||||
const auto it = this->GetNearestHeapMapLocked(offset);
|
||||
if (it == m_mappings.end() || it->vaddr == offset) {
|
||||
// Not contained or no split required.
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache the original values.
|
||||
auto* const left = std::addressof(*it);
|
||||
const size_t orig_size = left->size;
|
||||
|
||||
// Adjust the left map.
|
||||
const size_t left_size = offset - left->vaddr;
|
||||
left->size = left_size;
|
||||
|
||||
// Create the new right map.
|
||||
auto* const right = new SeparateHeapMap{
|
||||
.vaddr = left->vaddr + left_size,
|
||||
.paddr = left->paddr + left_size,
|
||||
.size = orig_size - left_size,
|
||||
.tick = left->tick,
|
||||
.perm = left->perm,
|
||||
.is_resident = left->is_resident,
|
||||
};
|
||||
|
||||
// Insert the new right map.
|
||||
m_map_count++;
|
||||
m_mappings.insert(*right);
|
||||
|
||||
// If resident, also insert into resident map.
|
||||
if (right->is_resident) {
|
||||
m_resident_map_count++;
|
||||
m_resident_mappings.insert(*right);
|
||||
}
|
||||
}
|
||||
|
||||
HeapTracker::AddrTree::iterator HeapTracker::GetNearestHeapMapLocked(VAddr offset) {
|
||||
const SeparateHeapMap key{
|
||||
.vaddr = offset,
|
||||
};
|
||||
|
||||
return m_mappings.find(key);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -1,55 +1,93 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <shared_mutex>
|
||||
#include <ankerl/unordered_dense.h>
|
||||
|
||||
#include "common/host_memory.h"
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
struct SeparateHeapMap {
|
||||
PAddr paddr{}; //8
|
||||
std::size_t size{}; //8 (16)
|
||||
std::size_t tick{}; //8 (24)
|
||||
// 4 bits needed, sync with host_memory.h if needed
|
||||
MemoryPermission perm : 4 = MemoryPermission::Read;
|
||||
bool is_resident : 1 = false;
|
||||
Common::IntrusiveRedBlackTreeNode addr_node{};
|
||||
Common::IntrusiveRedBlackTreeNode tick_node{};
|
||||
VAddr vaddr{};
|
||||
PAddr paddr{};
|
||||
size_t size{};
|
||||
size_t tick{};
|
||||
MemoryPermission perm{};
|
||||
bool is_resident{};
|
||||
};
|
||||
|
||||
struct SeparateHeapMapAddrComparator {
|
||||
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
||||
if (lhs.vaddr < rhs.vaddr) {
|
||||
return -1;
|
||||
} else if (lhs.vaddr <= (rhs.vaddr + rhs.size - 1)) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct SeparateHeapMapTickComparator {
|
||||
static constexpr int Compare(const SeparateHeapMap& lhs, const SeparateHeapMap& rhs) {
|
||||
if (lhs.tick < rhs.tick) {
|
||||
return -1;
|
||||
} else if (lhs.tick > rhs.tick) {
|
||||
return 1;
|
||||
} else {
|
||||
return SeparateHeapMapAddrComparator::Compare(lhs, rhs);
|
||||
}
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(SeparateHeapMap) == 32); //half a cache line! good for coherency
|
||||
|
||||
class HeapTracker {
|
||||
public:
|
||||
explicit HeapTracker(Common::HostMemory& buffer);
|
||||
~HeapTracker();
|
||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm, bool is_separate_heap);
|
||||
|
||||
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perm,
|
||||
bool is_separate_heap);
|
||||
void Unmap(size_t virtual_offset, size_t size, bool is_separate_heap);
|
||||
void Protect(size_t virtual_offset, size_t length, MemoryPermission perm);
|
||||
inline u8* VirtualBasePointer() noexcept {
|
||||
u8* VirtualBasePointer() {
|
||||
return m_buffer.VirtualBasePointer();
|
||||
}
|
||||
|
||||
bool DeferredMapSeparateHeap(u8* fault_address);
|
||||
bool DeferredMapSeparateHeap(size_t virtual_offset);
|
||||
|
||||
private:
|
||||
// TODO: You may want to "fake-map" the first 2GB of 64-bit address space
|
||||
// and dedicate it entirely to a recursive PTE mapping :)
|
||||
// However Ankerl is way better than using an RB tree, in all senses
|
||||
using AddrTree = ankerl::unordered_dense::map<VAddr, SeparateHeapMap>;
|
||||
AddrTree m_mappings;
|
||||
using TicksTree = ankerl::unordered_dense::map<VAddr, SeparateHeapMap>;
|
||||
TicksTree m_resident_mappings;
|
||||
using AddrTreeTraits =
|
||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::addr_node>;
|
||||
using AddrTree = AddrTreeTraits::TreeType<SeparateHeapMapAddrComparator>;
|
||||
|
||||
using TickTreeTraits =
|
||||
Common::IntrusiveRedBlackTreeMemberTraitsDeferredAssert<&SeparateHeapMap::tick_node>;
|
||||
using TickTree = TickTreeTraits::TreeType<SeparateHeapMapTickComparator>;
|
||||
|
||||
AddrTree m_mappings{};
|
||||
TickTree m_resident_mappings{};
|
||||
|
||||
private:
|
||||
void SplitHeapMap(VAddr offset, size_t size);
|
||||
void SplitHeapMapLocked(VAddr offset);
|
||||
|
||||
AddrTree::iterator GetNearestHeapMapLocked(VAddr offset);
|
||||
|
||||
void RebuildSeparateHeapAddressSpace();
|
||||
inline HeapTracker::AddrTree::iterator GetNearestHeapMapLocked(VAddr offset) noexcept {
|
||||
return m_mappings.find(offset);
|
||||
}
|
||||
|
||||
private:
|
||||
Common::HostMemory& m_buffer;
|
||||
const s64 m_max_resident_map_count;
|
||||
|
||||
std::shared_mutex m_rebuild_lock{};
|
||||
std::mutex m_lock{};
|
||||
s64 m_map_count{};
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include <windows.h>
|
||||
#include "common/dynamic_library.h"
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) // ^^^ Windows ^^^ vvv Linux vvv
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv
|
||||
|
||||
#ifndef _GNU_SOURCE
|
||||
#define _GNU_SOURCE
|
||||
|
@ -20,10 +20,18 @@
|
|||
#include <boost/icl/interval_set.hpp>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/random.h>
|
||||
#include <unistd.h>
|
||||
#include "common/scope_exit.h"
|
||||
|
||||
#if defined(__linux__)
|
||||
#include <sys/random.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/random.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach.h>
|
||||
#endif
|
||||
|
||||
// FreeBSD
|
||||
#ifndef MAP_NORESERVE
|
||||
#define MAP_NORESERVE 0
|
||||
|
@ -32,8 +40,12 @@
|
|||
#ifndef MAP_ALIGNED_SUPER
|
||||
#define MAP_ALIGNED_SUPER 0
|
||||
#endif
|
||||
// macOS
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#endif // ^^^ Linux ^^^
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
|
@ -372,7 +384,7 @@ private:
|
|||
std::unordered_map<size_t, size_t> placeholder_host_pointers; ///< Placeholder backing offset
|
||||
};
|
||||
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) // ^^^ Windows ^^^ vvv Linux vvv
|
||||
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__) || defined(__APPLE__) // ^^^ Windows ^^^ vvv POSIX vvv
|
||||
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
|
||||
|
@ -417,14 +429,11 @@ static void* ChooseVirtualBase(size_t virtual_size) {
|
|||
#else
|
||||
|
||||
static void* ChooseVirtualBase(size_t virtual_size) {
|
||||
#if defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__)
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
|
||||
void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
|
||||
|
||||
if (virtual_base != MAP_FAILED) {
|
||||
if (virtual_base != MAP_FAILED)
|
||||
return virtual_base;
|
||||
}
|
||||
#endif
|
||||
|
||||
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
|
||||
|
@ -492,6 +501,13 @@ public:
|
|||
#elif defined(__FreeBSD__) && __FreeBSD__ < 13
|
||||
// XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30
|
||||
fd = shm_open(SHM_ANON, O_RDWR, 0600);
|
||||
#elif defined(__APPLE__)
|
||||
// macOS doesn't have memfd_create, use anonymous temporary file
|
||||
char template_path[] = "/tmp/eden_mem_XXXXXX";
|
||||
fd = mkstemp(template_path);
|
||||
if (fd >= 0) {
|
||||
unlink(template_path);
|
||||
}
|
||||
#else
|
||||
fd = memfd_create("HostMemory", 0);
|
||||
#endif
|
||||
|
@ -648,7 +664,7 @@ private:
|
|||
FreeRegionManager free_manager{};
|
||||
};
|
||||
|
||||
#else // ^^^ Linux ^^^ vvv Generic vvv
|
||||
#else // ^^^ POSIX ^^^ vvv Generic vvv
|
||||
|
||||
class HostMemory::Impl {
|
||||
public:
|
||||
|
|
|
@ -163,8 +163,9 @@ bool IsFastmemEnabled() {
|
|||
}
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__)
|
||||
return false;
|
||||
#endif
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool is_nce_enabled = false;
|
||||
|
|
|
@ -217,7 +217,8 @@ struct Values {
|
|||
true,
|
||||
true,
|
||||
&use_speed_limit};
|
||||
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core, Specialization::Default};
|
||||
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core,
|
||||
Specialization::Default};
|
||||
|
||||
// Memory
|
||||
#ifdef HAS_NCE
|
||||
|
@ -551,6 +552,8 @@ struct Values {
|
|||
3,
|
||||
#elif defined (ANDROID)
|
||||
0,
|
||||
#elif defined (__APPLE__)
|
||||
0,
|
||||
#else
|
||||
2,
|
||||
#endif
|
||||
|
@ -622,7 +625,11 @@ struct Values {
|
|||
linkage, 0, "rng_seed", Category::System, Specialization::Hex,
|
||||
true, true, &rng_seed_enabled};
|
||||
Setting<std::string> device_name{
|
||||
linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true};
|
||||
linkage, "Eden", "device_name", Category::System, Specialization::Default, true, true};
|
||||
SwitchableSetting<bool> disable_nca_verification{linkage, true, "disable_nca_verification",
|
||||
Category::System, Specialization::Default};
|
||||
Setting<bool> hide_nca_verification_popup{
|
||||
linkage, false, "hide_nca_verification_popup", Category::System, Specialization::Default};
|
||||
|
||||
Setting<s32> current_user{linkage, 0, "current_user", Category::System};
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <span>
|
||||
#include <string>
|
||||
|
|
|
@ -88,6 +88,8 @@ add_library(core STATIC
|
|||
file_sys/fssystem/fssystem_crypto_configuration.h
|
||||
file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.cpp
|
||||
file_sys/fssystem/fssystem_hierarchical_integrity_verification_storage.h
|
||||
file_sys/fssystem/fssystem_hierarchical_sha3_storage.cpp
|
||||
file_sys/fssystem/fssystem_hierarchical_sha3_storage.h
|
||||
file_sys/fssystem/fssystem_hierarchical_sha256_storage.cpp
|
||||
file_sys/fssystem/fssystem_hierarchical_sha256_storage.h
|
||||
file_sys/fssystem/fssystem_indirect_storage.cpp
|
||||
|
@ -102,6 +104,7 @@ add_library(core STATIC
|
|||
file_sys/fssystem/fssystem_nca_header.cpp
|
||||
file_sys/fssystem/fssystem_nca_header.h
|
||||
file_sys/fssystem/fssystem_nca_reader.cpp
|
||||
file_sys/fssystem/fssystem_passthrough_storage.h
|
||||
file_sys/fssystem/fssystem_pooled_buffer.cpp
|
||||
file_sys/fssystem/fssystem_pooled_buffer.h
|
||||
file_sys/fssystem/fssystem_sparse_storage.cpp
|
||||
|
|
|
@ -3,9 +3,47 @@
|
|||
|
||||
#ifdef __linux__
|
||||
|
||||
//#include "common/signal_chain.h"
|
||||
#include "common/signal_chain.h"
|
||||
|
||||
#include "core/arm/dynarmic/arm_dynarmic.h"
|
||||
//#include "core/hle/kernel/k_process.h"
|
||||
//#include "core/memory.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
thread_local Core::Memory::Memory* g_current_memory{};
|
||||
std::once_flag g_registered{};
|
||||
struct sigaction g_old_segv {};
|
||||
|
||||
void HandleSigSegv(int sig, siginfo_t* info, void* ctx) {
|
||||
if (g_current_memory && g_current_memory->InvalidateSeparateHeap(info->si_addr)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return g_old_segv.sa_sigaction(sig, info, ctx);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedJitExecution::ScopedJitExecution(Kernel::KProcess* process) {
|
||||
g_current_memory = std::addressof(process->GetMemory());
|
||||
}
|
||||
|
||||
ScopedJitExecution::~ScopedJitExecution() {
|
||||
g_current_memory = nullptr;
|
||||
}
|
||||
|
||||
void ScopedJitExecution::RegisterHandler() {
|
||||
std::call_once(g_registered, [] {
|
||||
struct sigaction sa {};
|
||||
sa.sa_sigaction = &HandleSigSegv;
|
||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
|
||||
Common::SigAction(SIGSEGV, std::addressof(sa), std::addressof(g_old_segv));
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
#endif
|
||||
|
|
|
@ -26,4 +26,24 @@ constexpr HaltReason TranslateHaltReason(Dynarmic::HaltReason hr) {
|
|||
return static_cast<HaltReason>(hr);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process);
|
||||
~ScopedJitExecution();
|
||||
static void RegisterHandler();
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class ScopedJitExecution {
|
||||
public:
|
||||
explicit ScopedJitExecution(Kernel::KProcess* process) {}
|
||||
~ScopedJitExecution() {}
|
||||
static void RegisterHandler() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -343,11 +343,15 @@ bool ArmDynarmic32::IsInThumbMode() const {
|
|||
}
|
||||
|
||||
HaltReason ArmDynarmic32::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic32::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
|
@ -389,6 +393,7 @@ ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProc
|
|||
m_cp15(std::make_shared<DynarmicCP15>(*this)), m_core_index{core_index} {
|
||||
auto& page_table_impl = process->GetPageTable().GetBasePageTable().GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl);
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic32::~ArmDynarmic32() = default;
|
||||
|
|
|
@ -374,11 +374,15 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
|||
}
|
||||
|
||||
HaltReason ArmDynarmic64::RunThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Run());
|
||||
}
|
||||
|
||||
HaltReason ArmDynarmic64::StepThread(Kernel::KThread* thread) {
|
||||
ScopedJitExecution sj(thread->GetOwnerProcess());
|
||||
|
||||
m_jit->ClearExclusiveState();
|
||||
return TranslateHaltReason(m_jit->Step());
|
||||
}
|
||||
|
@ -418,6 +422,7 @@ ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProc
|
|||
auto& page_table = process->GetPageTable().GetBasePageTable();
|
||||
auto& page_table_impl = page_table.GetImpl();
|
||||
m_jit = MakeJit(&page_table_impl, page_table.GetAddressSpaceWidth());
|
||||
ScopedJitExecution::RegisterHandler();
|
||||
}
|
||||
|
||||
ArmDynarmic64::~ArmDynarmic64() = default;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree.h"
|
||||
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"
|
||||
|
@ -233,7 +237,10 @@ Result BucketTree::Initialize(VirtualFile node_storage, VirtualFile entry_storag
|
|||
void BucketTree::Initialize(size_t node_size, s64 end_offset) {
|
||||
ASSERT(NodeSizeMin <= node_size && node_size <= NodeSizeMax);
|
||||
ASSERT(Common::IsPowerOfTwo(node_size));
|
||||
ASSERT(end_offset > 0);
|
||||
|
||||
if (!Settings::values.disable_nca_verification.GetValue()) {
|
||||
ASSERT(end_offset > 0);
|
||||
}
|
||||
ASSERT(!this->IsInitialized());
|
||||
|
||||
m_node_size = node_size;
|
||||
|
|
|
@ -5,23 +5,10 @@
|
|||
#include "common/scope_exit.h"
|
||||
#include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
namespace {
|
||||
|
||||
s32 Log2(s32 value) {
|
||||
ASSERT(value > 0);
|
||||
ASSERT(Common::IsPowerOfTwo(value));
|
||||
|
||||
s32 log = 0;
|
||||
while ((value >>= 1) > 0) {
|
||||
++log;
|
||||
}
|
||||
return log;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 layer_count,
|
||||
size_t htbs, void* hash_buf, size_t hash_buf_size) {
|
||||
// Validate preconditions.
|
||||
|
@ -31,7 +18,8 @@ Result HierarchicalSha256Storage::Initialize(VirtualFile* base_storages, s32 lay
|
|||
|
||||
// Set size tracking members.
|
||||
m_hash_target_block_size = static_cast<s32>(htbs);
|
||||
m_log_size_ratio = Log2(m_hash_target_block_size / HashSize);
|
||||
m_log_size_ratio =
|
||||
static_cast<s32>(std::log2(static_cast<double>(m_hash_target_block_size) / HashSize));
|
||||
|
||||
// Get the base storage size.
|
||||
m_base_storage_size = base_storages[2]->GetSize();
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
Result HierarchicalSha3Storage::Initialize(VirtualFile* base_storages, s32 layer_count, size_t htbs,
|
||||
void* hash_buf, size_t hash_buf_size) {
|
||||
ASSERT(layer_count == LayerCount);
|
||||
ASSERT(Common::IsPowerOfTwo(htbs));
|
||||
ASSERT(hash_buf != nullptr);
|
||||
|
||||
m_hash_target_block_size = static_cast<s32>(htbs);
|
||||
m_log_size_ratio =
|
||||
static_cast<s32>(std::log2(static_cast<double>(m_hash_target_block_size) / HashSize));
|
||||
|
||||
m_base_storage_size = base_storages[2]->GetSize();
|
||||
{
|
||||
auto size_guard = SCOPE_GUARD {
|
||||
m_base_storage_size = 0;
|
||||
};
|
||||
R_UNLESS(m_base_storage_size <= static_cast<s64>(HashSize)
|
||||
<< m_log_size_ratio << m_log_size_ratio,
|
||||
ResultHierarchicalSha256BaseStorageTooLarge);
|
||||
size_guard.Cancel();
|
||||
}
|
||||
|
||||
m_base_storage = base_storages[2];
|
||||
m_hash_buffer = static_cast<char*>(hash_buf);
|
||||
m_hash_buffer_size = hash_buf_size;
|
||||
|
||||
std::array<u8, HashSize> master_hash{};
|
||||
base_storages[0]->ReadObject(std::addressof(master_hash));
|
||||
|
||||
s64 hash_storage_size = base_storages[1]->GetSize();
|
||||
ASSERT(Common::IsAligned(hash_storage_size, HashSize));
|
||||
ASSERT(hash_storage_size <= m_hash_target_block_size);
|
||||
ASSERT(hash_storage_size <= static_cast<s64>(m_hash_buffer_size));
|
||||
|
||||
base_storages[1]->Read(reinterpret_cast<u8*>(m_hash_buffer),
|
||||
static_cast<size_t>(hash_storage_size), 0);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
size_t HierarchicalSha3Storage::Read(u8* buffer, size_t size, size_t offset) const {
|
||||
if (size == 0)
|
||||
return size;
|
||||
ASSERT(buffer != nullptr);
|
||||
return m_base_storage->Read(buffer, size, offset);
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
|
@ -0,0 +1,44 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class HierarchicalSha3Storage : public IReadOnlyStorage {
|
||||
YUZU_NON_COPYABLE(HierarchicalSha3Storage);
|
||||
YUZU_NON_MOVEABLE(HierarchicalSha3Storage);
|
||||
|
||||
public:
|
||||
static constexpr s32 LayerCount = 3;
|
||||
static constexpr size_t HashSize = 256 / 8; // SHA3-256
|
||||
|
||||
public:
|
||||
HierarchicalSha3Storage() : m_mutex() {}
|
||||
|
||||
Result Initialize(VirtualFile* base_storages, s32 layer_count, size_t htbs, void* hash_buf,
|
||||
size_t hash_buf_size);
|
||||
|
||||
virtual size_t GetSize() const override {
|
||||
return m_base_storage->GetSize();
|
||||
}
|
||||
|
||||
virtual size_t Read(u8* buffer, size_t length, size_t offset) const override;
|
||||
|
||||
private:
|
||||
VirtualFile m_base_storage;
|
||||
s64 m_base_storage_size{};
|
||||
char* m_hash_buffer{};
|
||||
size_t m_hash_buffer_size{};
|
||||
s32 m_hash_target_block_size{};
|
||||
s32 m_log_size_ratio{};
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
|
@ -1,6 +1,10 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_aes_xts_storage.h"
|
||||
|
@ -10,10 +14,12 @@
|
|||
#include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_indirect_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_integrity_romfs_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_passthrough_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_memory_resource_buffer_hold_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h"
|
||||
#include "core/file_sys/fssystem/fssystem_sparse_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_switch_storage.h"
|
||||
#include "core/file_sys/fssystem/fssystem_hierarchical_sha3_storage.h"
|
||||
#include "core/file_sys/vfs/vfs_offset.h"
|
||||
#include "core/file_sys/vfs/vfs_vector.h"
|
||||
|
||||
|
@ -299,18 +305,24 @@ Result NcaFileSystemDriver::CreateStorageByRawStorage(VirtualFile* out,
|
|||
// Process hash/integrity layer.
|
||||
switch (header_reader->GetHashType()) {
|
||||
case NcaFsHeader::HashType::HierarchicalSha256Hash:
|
||||
R_TRY(this->CreateSha256Storage(std::addressof(storage), std::move(storage),
|
||||
header_reader->GetHashData().hierarchical_sha256_data));
|
||||
R_TRY(CreateSha256Storage(&storage, std::move(storage),
|
||||
header_reader->GetHashData().hierarchical_sha256_data));
|
||||
break;
|
||||
case NcaFsHeader::HashType::HierarchicalIntegrityHash:
|
||||
R_TRY(this->CreateIntegrityVerificationStorage(
|
||||
std::addressof(storage), std::move(storage),
|
||||
header_reader->GetHashData().integrity_meta_info));
|
||||
R_TRY(CreateIntegrityVerificationStorage(&storage, std::move(storage),
|
||||
header_reader->GetHashData().integrity_meta_info));
|
||||
break;
|
||||
case NcaFsHeader::HashType::HierarchicalSha3256Hash:
|
||||
R_TRY(CreateSha3Storage(&storage, std::move(storage),
|
||||
header_reader->GetHashData().hierarchical_sha256_data));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Loader, "Unhandled Fs HashType enum={}",
|
||||
static_cast<int>(header_reader->GetHashType()));
|
||||
R_THROW(ResultInvalidNcaFsHeaderHashType);
|
||||
}
|
||||
|
||||
|
||||
// Process compression layer.
|
||||
if (header_reader->ExistsCompressionLayer()) {
|
||||
R_TRY(this->CreateCompressedStorage(
|
||||
|
@ -679,6 +691,7 @@ Result NcaFileSystemDriver::CreateSparseStorageMetaStorageWithVerification(
|
|||
|
||||
// Create the verification storage.
|
||||
VirtualFile integrity_storage;
|
||||
|
||||
Result rc = this->CreateIntegrityVerificationStorageForMeta(
|
||||
std::addressof(integrity_storage), out_layer_info_storage, std::move(decrypted_storage),
|
||||
meta_offset, meta_data_hash_data_info);
|
||||
|
@ -734,8 +747,26 @@ Result NcaFileSystemDriver::CreateSparseStorageWithVerification(
|
|||
NcaHeader::CtrBlockSize)));
|
||||
|
||||
// Check the meta data hash type.
|
||||
R_UNLESS(meta_data_hash_type == NcaFsHeader::MetaDataHashType::HierarchicalIntegrity,
|
||||
ResultRomNcaInvalidSparseMetaDataHashType);
|
||||
if (meta_data_hash_type != NcaFsHeader::MetaDataHashType::HierarchicalIntegrity) {
|
||||
LOG_ERROR(Loader, "Sparse meta hash type {} not supported for verification; mounting sparse data WITHOUT verification (temporary).", static_cast<int>(meta_data_hash_type));
|
||||
|
||||
R_TRY(this->CreateBodySubStorage(std::addressof(body_substorage),
|
||||
sparse_info.physical_offset,
|
||||
sparse_info.GetPhysicalSize()));
|
||||
|
||||
// Create sparse core directly (no meta verification)
|
||||
std::shared_ptr<SparseStorage> sparse_storage_fallback;
|
||||
R_TRY(this->CreateSparseStorageCore(std::addressof(sparse_storage_fallback),
|
||||
body_substorage, sparse_info.GetPhysicalSize(),
|
||||
/*meta_storage*/ body_substorage, // dummy; not used
|
||||
sparse_info, false));
|
||||
|
||||
if (out_sparse_storage)
|
||||
*out_sparse_storage = sparse_storage_fallback;
|
||||
*out_fs_data_offset = fs_offset;
|
||||
*out = std::move(sparse_storage_fallback);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Create the meta storage.
|
||||
VirtualFile meta_storage;
|
||||
|
@ -1093,6 +1124,56 @@ Result NcaFileSystemDriver::CreatePatchMetaStorage(
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result NcaFileSystemDriver::CreateSha3Storage(
|
||||
VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data) {
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
|
||||
using VerificationStorage = HierarchicalSha3Storage;
|
||||
|
||||
R_UNLESS(Common::IsPowerOfTwo(hash_data.hash_block_size),
|
||||
ResultInvalidHierarchicalSha256BlockSize);
|
||||
R_UNLESS(hash_data.hash_layer_count == VerificationStorage::LayerCount - 1,
|
||||
ResultInvalidHierarchicalSha256LayerCount);
|
||||
|
||||
const auto& hash_region = hash_data.hash_layer_region[0];
|
||||
const auto& data_region = hash_data.hash_layer_region[1];
|
||||
|
||||
constexpr s32 CacheBlockCount = 2;
|
||||
const auto hash_buffer_size = static_cast<size_t>(hash_region.size);
|
||||
const auto cache_buffer_size = CacheBlockCount * hash_data.hash_block_size;
|
||||
const auto total_buffer_size = hash_buffer_size + cache_buffer_size;
|
||||
|
||||
auto buffer_hold_storage = std::make_shared<MemoryResourceBufferHoldStorage>(
|
||||
std::move(base_storage), total_buffer_size);
|
||||
R_UNLESS(buffer_hold_storage != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
R_UNLESS(buffer_hold_storage->IsValid(), ResultAllocationMemoryFailedInNcaFileSystemDriverI);
|
||||
|
||||
s64 base_size = buffer_hold_storage->GetSize();
|
||||
R_UNLESS(hash_region.offset + hash_region.size <= base_size, ResultNcaBaseStorageOutOfRangeC);
|
||||
R_UNLESS(data_region.offset + data_region.size <= base_size, ResultNcaBaseStorageOutOfRangeC);
|
||||
|
||||
auto master_hash_storage =
|
||||
std::make_shared<ArrayVfsFile<sizeof(Hash)>>(hash_data.fs_data_master_hash.value);
|
||||
|
||||
auto verification_storage = std::make_shared<VerificationStorage>();
|
||||
R_UNLESS(verification_storage != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
std::array<VirtualFile, VerificationStorage::LayerCount> layer_storages{
|
||||
std::make_shared<OffsetVfsFile>(master_hash_storage, sizeof(Hash), 0),
|
||||
std::make_shared<OffsetVfsFile>(buffer_hold_storage, hash_region.size, hash_region.offset),
|
||||
std::make_shared<OffsetVfsFile>(buffer_hold_storage, data_region.size, data_region.offset),
|
||||
};
|
||||
|
||||
R_TRY(verification_storage->Initialize(layer_storages.data(), VerificationStorage::LayerCount,
|
||||
hash_data.hash_block_size,
|
||||
buffer_hold_storage->GetBuffer(), hash_buffer_size));
|
||||
|
||||
*out = std::move(verification_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result NcaFileSystemDriver::CreateSha256Storage(
|
||||
VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data) {
|
||||
|
@ -1160,6 +1241,7 @@ Result NcaFileSystemDriver::CreateSha256Storage(
|
|||
Result NcaFileSystemDriver::CreateIntegrityVerificationStorage(
|
||||
VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::IntegrityMetaInfo& meta_info) {
|
||||
|
||||
R_RETURN(this->CreateIntegrityVerificationStorageImpl(
|
||||
out, base_storage, meta_info, 0, IntegrityDataCacheCount, IntegrityHashCacheCount,
|
||||
HierarchicalIntegrityVerificationStorage::GetDefaultDataCacheBufferLevel(
|
||||
|
@ -1209,63 +1291,96 @@ Result NcaFileSystemDriver::CreateIntegrityVerificationStorageImpl(
|
|||
VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::IntegrityMetaInfo& meta_info, s64 layer_info_offset,
|
||||
int max_data_cache_entries, int max_hash_cache_entries, s8 buffer_level) {
|
||||
// Validate preconditions.
|
||||
// Preconditions
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
ASSERT(layer_info_offset >= 0);
|
||||
|
||||
// Define storage types.
|
||||
using VerificationStorage = HierarchicalIntegrityVerificationStorage;
|
||||
using StorageInfo = VerificationStorage::HierarchicalStorageInformation;
|
||||
if (!Settings::values.disable_nca_verification.GetValue()) {
|
||||
// Define storage types.
|
||||
using VerificationStorage = HierarchicalIntegrityVerificationStorage;
|
||||
using StorageInfo = VerificationStorage::HierarchicalStorageInformation;
|
||||
|
||||
// Validate the meta info.
|
||||
HierarchicalIntegrityVerificationInformation level_hash_info;
|
||||
std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info),
|
||||
sizeof(level_hash_info));
|
||||
// Validate the meta info.
|
||||
HierarchicalIntegrityVerificationInformation level_hash_info;
|
||||
std::memcpy(std::addressof(level_hash_info), std::addressof(meta_info.level_hash_info),
|
||||
sizeof(level_hash_info));
|
||||
|
||||
R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
R_UNLESS(IntegrityMinLayerCount <= level_hash_info.max_layers,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
R_UNLESS(level_hash_info.max_layers <= IntegrityMaxLayerCount,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
|
||||
// Get the base storage size.
|
||||
s64 base_storage_size = base_storage->GetSize();
|
||||
// Get the base storage size.
|
||||
s64 base_storage_size = base_storage->GetSize();
|
||||
|
||||
// Create storage info.
|
||||
StorageInfo storage_info;
|
||||
for (s32 i = 0; i < static_cast<s32>(level_hash_info.max_layers - 2); ++i) {
|
||||
const auto& layer_info = level_hash_info.info[i];
|
||||
R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size,
|
||||
// Create storage info.
|
||||
StorageInfo storage_info;
|
||||
for (s32 i = 0; i < static_cast<s32>(level_hash_info.max_layers - 2); ++i) {
|
||||
const auto& layer_info = level_hash_info.info[i];
|
||||
R_UNLESS(layer_info_offset + layer_info.offset + layer_info.size <= base_storage_size,
|
||||
ResultNcaBaseStorageOutOfRangeD);
|
||||
|
||||
storage_info[i + 1] = std::make_shared<OffsetVfsFile>(
|
||||
base_storage, layer_info.size, layer_info_offset + layer_info.offset);
|
||||
}
|
||||
|
||||
// Set the last layer info.
|
||||
const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2];
|
||||
const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get();
|
||||
R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size,
|
||||
ResultNcaBaseStorageOutOfRangeD);
|
||||
if (layer_info_offset > 0) {
|
||||
R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset,
|
||||
ResultRomNcaInvalidIntegrityLayerInfoOffset);
|
||||
}
|
||||
storage_info.SetDataStorage(std::make_shared<OffsetVfsFile>(
|
||||
std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
|
||||
storage_info[i + 1] = std::make_shared<OffsetVfsFile>(
|
||||
base_storage, layer_info.size, layer_info_offset + layer_info.offset);
|
||||
// Make the integrity romfs storage.
|
||||
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();
|
||||
R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
// Initialize the integrity storage.
|
||||
R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info,
|
||||
max_data_cache_entries, max_hash_cache_entries,
|
||||
buffer_level));
|
||||
|
||||
// Set the output.
|
||||
*out = std::move(integrity_storage);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
// Read IVFC layout
|
||||
HierarchicalIntegrityVerificationInformation lhi{};
|
||||
std::memcpy(std::addressof(lhi), std::addressof(meta_info.level_hash_info), sizeof(lhi));
|
||||
|
||||
R_UNLESS(IntegrityMinLayerCount <= lhi.max_layers,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
R_UNLESS(lhi.max_layers <= IntegrityMaxLayerCount,
|
||||
ResultInvalidNcaHierarchicalIntegrityVerificationLayerCount);
|
||||
|
||||
const auto& data_li = lhi.info[lhi.max_layers - 2];
|
||||
|
||||
const s64 base_size = base_storage->GetSize();
|
||||
|
||||
// Compute the data layer window
|
||||
const s64 data_off = (layer_info_offset > 0) ? 0LL : data_li.offset.Get();
|
||||
R_UNLESS(data_off + data_li.size <= base_size, ResultNcaBaseStorageOutOfRangeD);
|
||||
if (layer_info_offset > 0) {
|
||||
R_UNLESS(data_off + data_li.size <= layer_info_offset,
|
||||
ResultRomNcaInvalidIntegrityLayerInfoOffset);
|
||||
}
|
||||
|
||||
// TODO: Passthrough (temporary compatibility: integrity disabled)
|
||||
auto data_view = std::make_shared<OffsetVfsFile>(base_storage, data_li.size, data_off);
|
||||
R_UNLESS(data_view != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
auto passthrough = std::make_shared<PassthroughStorage>(std::move(data_view));
|
||||
R_UNLESS(passthrough != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
*out = std::move(passthrough);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Set the last layer info.
|
||||
const auto& layer_info = level_hash_info.info[level_hash_info.max_layers - 2];
|
||||
const s64 last_layer_info_offset = layer_info_offset > 0 ? 0LL : layer_info.offset.Get();
|
||||
R_UNLESS(last_layer_info_offset + layer_info.size <= base_storage_size,
|
||||
ResultNcaBaseStorageOutOfRangeD);
|
||||
if (layer_info_offset > 0) {
|
||||
R_UNLESS(last_layer_info_offset + layer_info.size <= layer_info_offset,
|
||||
ResultRomNcaInvalidIntegrityLayerInfoOffset);
|
||||
}
|
||||
storage_info.SetDataStorage(std::make_shared<OffsetVfsFile>(
|
||||
std::move(base_storage), layer_info.size, last_layer_info_offset));
|
||||
|
||||
// Make the integrity romfs storage.
|
||||
auto integrity_storage = std::make_shared<IntegrityRomFsStorage>();
|
||||
R_UNLESS(integrity_storage != nullptr, ResultAllocationMemoryFailedAllocateShared);
|
||||
|
||||
// Initialize the integrity storage.
|
||||
R_TRY(integrity_storage->Initialize(level_hash_info, meta_info.master_hash, storage_info,
|
||||
max_data_cache_entries, max_hash_cache_entries,
|
||||
buffer_level));
|
||||
|
||||
// Set the output.
|
||||
*out = std::move(integrity_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result NcaFileSystemDriver::CreateRegionSwitchStorage(VirtualFile* out,
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -329,6 +332,10 @@ private:
|
|||
const NcaPatchInfo& patch_info,
|
||||
const NcaMetaDataHashDataInfo& meta_data_hash_data_info);
|
||||
|
||||
|
||||
Result CreateSha3Storage(VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::HierarchicalSha256Data& hash_data);
|
||||
|
||||
Result CreateSha256Storage(VirtualFile* out, VirtualFile base_storage,
|
||||
const NcaFsHeader::HashData::HierarchicalSha256Data& sha256_data);
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -10,11 +13,13 @@ u8 NcaHeader::GetProperKeyGeneration() const {
|
|||
}
|
||||
|
||||
bool NcaPatchInfo::HasIndirectTable() const {
|
||||
return this->indirect_size != 0;
|
||||
static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'};
|
||||
return std::memcmp(indirect_header.data(), BKTR, sizeof(BKTR)) == 0;
|
||||
}
|
||||
|
||||
bool NcaPatchInfo::HasAesCtrExTable() const {
|
||||
return this->aes_ctr_ex_size != 0;
|
||||
static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'};
|
||||
return std::memcmp(aes_ctr_ex_header.data(), BKTR, sizeof(BKTR)) == 0;
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
32
src/core/file_sys/fssystem/fssystem_passthrough_storage.h
Normal file
32
src/core/file_sys/fssystem/fssystem_passthrough_storage.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "core/file_sys/fssystem/fs_i_storage.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
//TODO: No integrity verification.
|
||||
class PassthroughStorage final : public IReadOnlyStorage {
|
||||
YUZU_NON_COPYABLE(PassthroughStorage);
|
||||
YUZU_NON_MOVEABLE(PassthroughStorage);
|
||||
|
||||
public:
|
||||
explicit PassthroughStorage(VirtualFile base) : base_(std::move(base)) {}
|
||||
~PassthroughStorage() override = default;
|
||||
|
||||
size_t Read(u8* buffer, size_t size, size_t offset) const override {
|
||||
if (!base_ || size == 0)
|
||||
return 0;
|
||||
return base_->Read(buffer, size, offset);
|
||||
}
|
||||
size_t GetSize() const override {
|
||||
return base_ ? base_->GetSize() : 0;
|
||||
}
|
||||
|
||||
private:
|
||||
VirtualFile base_{};
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
|
@ -1266,6 +1266,10 @@ void KProcess::InitializeInterfaces() {
|
|||
|
||||
#ifdef HAS_NCE
|
||||
if (this->IsApplication() && Settings::IsNceEnabled()) {
|
||||
// Register the scoped JIT handler before creating any NCE instances
|
||||
// so that its signal handler will appear first in the signal chain.
|
||||
Core::ScopedJitExecution::RegisterHandler();
|
||||
|
||||
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
|
||||
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator
|
||||
// Project// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
|
@ -12,7 +15,7 @@ Applet::Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_
|
|||
process(std::move(process_)), hid_registration(system, *process),
|
||||
gpu_error_detected_event(context), friend_invitation_storage_channel_event(context),
|
||||
notification_storage_channel_event(context), health_warning_disappeared_system_event(context),
|
||||
acquired_sleep_lock_event(context), pop_from_general_channel_event(context),
|
||||
unknown_event(context), acquired_sleep_lock_event(context), pop_from_general_channel_event(context),
|
||||
library_applet_launchable_event(context), accumulated_suspended_tick_changed_event(context),
|
||||
sleep_lock_event(context), state_changed_event(context) {
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -120,6 +123,7 @@ struct Applet {
|
|||
Event friend_invitation_storage_channel_event;
|
||||
Event notification_storage_channel_event;
|
||||
Event health_warning_disappeared_system_event;
|
||||
Event unknown_event;
|
||||
Event acquired_sleep_lock_event;
|
||||
Event pop_from_general_channel_event;
|
||||
Event library_applet_launchable_event;
|
||||
|
|
|
@ -18,6 +18,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
|
|||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
|
||||
{110, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxyEx"},
|
||||
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
|
||||
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
|
||||
{300, nullptr, "OpenOverlayAppletProxy"},
|
||||
|
@ -25,6 +26,7 @@ IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& sys
|
|||
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
|
||||
{410, nullptr, "GetSystemAppletControllerForDebug"},
|
||||
{450, D<&IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions>, "GetSystemProcessCommonFunctions"}, // 19.0.0+
|
||||
{460, D<&IAllSystemAppletProxiesService::GetAppletAlternativeFunctions>, "GetAppletAlternativeFunctions"}, // 20.0.0+
|
||||
{1000, nullptr, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -99,6 +101,14 @@ Result IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions() {
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::GetAppletAlternativeFunctions() {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called.");
|
||||
|
||||
// TODO (maufeat)
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
|
||||
ProcessId process_id) {
|
||||
return m_window_system.GetByAppletResourceUserId(process_id.pid);
|
||||
|
|
|
@ -39,6 +39,7 @@ private:
|
|||
InCopyHandle<Kernel::KProcess> process_handle,
|
||||
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
|
||||
Result GetSystemProcessCommonFunctions();
|
||||
Result GetAppletAlternativeFunctions();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
|
||||
|
|
|
@ -35,6 +35,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
|
|||
{310, nullptr, "IsSystemAppletHomeMenu"}, //19.0.0+
|
||||
{320, nullptr, "SetGpuTimeSliceBoost"}, //19.0.0+
|
||||
{321, nullptr, "SetGpuTimeSliceBoostDueToApplication"}, //19.0.0+
|
||||
{350, D<&IAppletCommonFunctions::Unknown350>, "Unknown350"} //20.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
@ -70,4 +71,10 @@ Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Unknown350(Out<u16> out_unknown) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_unknown = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
|
|
@ -20,6 +20,7 @@ private:
|
|||
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
|
||||
Result SetCpuBoostRequestPriority(s32 priority);
|
||||
Result GetCurrentApplicationId(Out<u64> out_application_id);
|
||||
Result Unknown350(Out<u16> out_unknown);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -85,6 +88,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
|
|||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{210, D<&IApplicationFunctions::GetUnknownEvent210>, "Unknown210"},
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
|
||||
|
@ -487,6 +491,13 @@ Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::GetUnknownEvent210(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_event = m_applet->unknown_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationFunctions::PrepareForJit() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -76,6 +79,7 @@ private:
|
|||
Result TryPopFromFriendInvitationStorageChannel(Out<SharedPointer<IStorage>> out_storage);
|
||||
Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetUnknownEvent210(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result PrepareForJit();
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
|
|
|
@ -113,9 +113,11 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
|||
Firmware1700 = 17,
|
||||
Firmware1800 = 18,
|
||||
Firmware1900 = 19,
|
||||
Firmware2000 = 20,
|
||||
Firmware2100 = 21,
|
||||
};
|
||||
|
||||
auto process = CreateProcess(system, program_id, Firmware1400, Firmware1900);
|
||||
auto process = CreateProcess(system, program_id, Firmware1400, Firmware2100);
|
||||
if (!process) {
|
||||
// Couldn't initialize the guest process
|
||||
return {};
|
||||
|
|
|
@ -306,6 +306,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
|||
{3013, nullptr, "IsGameCardEnabled"},
|
||||
{3014, nullptr, "IsLocalContentShareEnabled"},
|
||||
{3050, nullptr, "ListAssignELicenseTaskResult"},
|
||||
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"},
|
||||
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"},
|
||||
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"},
|
||||
{9999, nullptr, "GetApplicationCertificate"},
|
||||
};
|
||||
// clang-format on
|
||||
|
@ -523,4 +526,17 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> o
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationManagerInterface::Unknown4022(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_NS, "(STUBBED) called");
|
||||
*out_event = gamecard_update_detection_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationManagerInterface::Unknown4023(Out<u64> out_result) {
|
||||
LOG_WARNING(Service_NS, "(STUBBED) called.");
|
||||
*out_result = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::NS
|
||||
|
|
|
@ -53,6 +53,8 @@ public:
|
|||
u64 application_id);
|
||||
Result CheckApplicationLaunchVersion(u64 application_id);
|
||||
Result GetApplicationTerminateResult(Out<Result> out_result, u64 application_id);
|
||||
Result Unknown4022(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result Unknown4023(Out<u64> out_result);
|
||||
|
||||
private:
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
|
|
@ -219,28 +219,55 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd) {
|
|||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, class_num={:X}, flags={:X}, obj_id={:X}", params.class_num,
|
||||
params.flags, params.obj_id);
|
||||
s32_le nvhost_gpu::GetObjectContextClassNumberIndex(CtxClasses class_number) {
|
||||
constexpr s32_le invalid_class_number_index = -1;
|
||||
switch (class_number) {
|
||||
case CtxClasses::Ctx2D: return 0;
|
||||
case CtxClasses::Ctx3D: return 1;
|
||||
case CtxClasses::CtxCompute: return 2;
|
||||
case CtxClasses::CtxKepler: return 3;
|
||||
case CtxClasses::CtxDMA: return 4;
|
||||
case CtxClasses::CtxChannelGPFIFO: return 5;
|
||||
default: return invalid_class_number_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (!channel_state->initialized) {
|
||||
NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
|
||||
LOG_DEBUG(Service_NVDRV, "called, class_num={:#X}, flags={:#X}, obj_id={:#X}", params.class_num,
|
||||
params.flags, params.obj_id);
|
||||
|
||||
if (!channel_state || !channel_state->initialized) {
|
||||
LOG_CRITICAL(Service_NVDRV, "No address space bound to allocate a object context!");
|
||||
return NvResult::NotInitialized;
|
||||
}
|
||||
|
||||
switch (static_cast<CtxClasses>(params.class_num)) {
|
||||
case CtxClasses::Ctx2D:
|
||||
case CtxClasses::Ctx3D:
|
||||
case CtxClasses::CtxCompute:
|
||||
case CtxClasses::CtxKepler:
|
||||
case CtxClasses::CtxDMA:
|
||||
case CtxClasses::CtxChannelGPFIFO:
|
||||
ctxObj_params.push_back(params);
|
||||
return NvResult::Success;
|
||||
default:
|
||||
LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:X}", params.class_num);
|
||||
std::scoped_lock lk(channel_mutex);
|
||||
|
||||
if (params.flags) {
|
||||
LOG_WARNING(Service_NVDRV, "non-zero flags={:#X} for class={:#X}", params.flags,
|
||||
params.class_num);
|
||||
|
||||
constexpr u32 allowed_mask{};
|
||||
params.flags = allowed_mask;
|
||||
}
|
||||
|
||||
s32_le ctx_class_number_index =
|
||||
GetObjectContextClassNumberIndex(static_cast<CtxClasses>(params.class_num));
|
||||
if (ctx_class_number_index < 0) {
|
||||
LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#X}",
|
||||
params.class_num);
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
if (ctxObjs[ctx_class_number_index].has_value()) {
|
||||
LOG_ERROR(Service_NVDRV, "Object context for class {:#X} already allocated on this channel",
|
||||
params.class_num);
|
||||
return NvResult::AlreadyAllocated;
|
||||
}
|
||||
|
||||
ctxObjs[ctx_class_number_index] = params;
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildWaitCommandList(
|
||||
|
|
|
@ -172,7 +172,7 @@ private:
|
|||
s32_le nvmap_fd{};
|
||||
u64_le user_data{};
|
||||
IoctlZCullBind zcull_params{};
|
||||
std::vector<IoctlAllocObjCtx> ctxObj_params{};
|
||||
std::array<std::optional<IoctlAllocObjCtx>, 6> ctxObjs{};
|
||||
u32_le channel_priority{};
|
||||
u32_le channel_timeslice{};
|
||||
|
||||
|
@ -184,9 +184,12 @@ private:
|
|||
NvResult SetChannelPriority(IoctlChannelSetPriority& params);
|
||||
NvResult AllocGPFIFOEx(IoctlAllocGpfifoEx& params, DeviceFD fd);
|
||||
NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd);
|
||||
|
||||
s32_le GetObjectContextClassNumberIndex(CtxClasses class_number);
|
||||
NvResult AllocateObjectContext(IoctlAllocObjCtx& params);
|
||||
|
||||
NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries);
|
||||
|
||||
NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
|
||||
std::span<Tegra::CommandListHeader> commands, bool kickoff = false);
|
||||
NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params,
|
||||
|
|
|
@ -80,11 +80,12 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
|||
{1451, D<&IParentalControlService::StartPlayTimer>, "StartPlayTimer"},
|
||||
{1452, D<&IParentalControlService::StopPlayTimer>, "StopPlayTimer"},
|
||||
{1453, D<&IParentalControlService::IsPlayTimerEnabled>, "IsPlayTimerEnabled"},
|
||||
{1454, nullptr, "GetPlayTimerRemainingTime"},
|
||||
{1454, D<&IParentalControlService::GetPlayTimerRemainingTime>, "GetPlayTimerRemainingTime"},
|
||||
{1455, D<&IParentalControlService::IsRestrictedByPlayTimer>, "IsRestrictedByPlayTimer"},
|
||||
{1456, D<&IParentalControlService::GetPlayTimerSettingsOld>, "GetPlayTimerSettingsOld"},
|
||||
{1457, D<&IParentalControlService::GetPlayTimerEventToRequestSuspension>, "GetPlayTimerEventToRequestSuspension"},
|
||||
{1458, D<&IParentalControlService::IsPlayTimerAlarmDisabled>, "IsPlayTimerAlarmDisabled"},
|
||||
{1459, D<&IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo>, "GetPlayTimerRemainingTimeDisplayInfo"},
|
||||
{1471, nullptr, "NotifyWrongPinCodeInputManyTimes"},
|
||||
{1472, nullptr, "CancelNetworkRequest"},
|
||||
{1473, D<&IParentalControlService::GetUnlinkedEvent>, "GetUnlinkedEvent"},
|
||||
|
@ -378,6 +379,12 @@ Result IParentalControlService::IsPlayTimerEnabled(Out<bool> out_is_play_timer_e
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerRemainingTime(Out<s32> out_remaining_time) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
*out_remaining_time = std::numeric_limits<s32>::max();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer) {
|
||||
*out_is_restricted_by_play_timer = false;
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, restricted={}", *out_is_restricted_by_play_timer);
|
||||
|
@ -412,6 +419,11 @@ Result IParentalControlService::IsPlayTimerAlarmDisabled(Out<bool> out_play_time
|
|||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerRemainingTimeDisplayInfo(/* Out 0x18 */) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(Service_PCTL, "called");
|
||||
*out_event = unlinked_event.GetHandle();
|
||||
|
|
|
@ -49,10 +49,12 @@ private:
|
|||
Result StartPlayTimer();
|
||||
Result StopPlayTimer();
|
||||
Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
|
||||
Result GetPlayTimerRemainingTime(Out<s32> out_remaining_time);
|
||||
Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
|
||||
Result GetPlayTimerSettingsOld(Out<PlayTimerSettings> out_play_timer_settings);
|
||||
Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
|
||||
Result GetPlayTimerRemainingTimeDisplayInfo();
|
||||
Result GetUnlinkedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetStereoVisionRestriction(Out<bool> out_stereo_vision_restriction);
|
||||
Result SetStereoVisionRestriction(bool stereo_vision_restriction);
|
||||
|
|
|
@ -61,7 +61,8 @@ struct Memory::Impl {
|
|||
}
|
||||
|
||||
#ifdef __linux__
|
||||
buffer.emplace(system.DeviceMemory().buffer);
|
||||
heap_tracker.emplace(system.DeviceMemory().buffer);
|
||||
buffer = std::addressof(*heap_tracker);
|
||||
#else
|
||||
buffer = std::addressof(system.DeviceMemory().buffer);
|
||||
#endif
|
||||
|
@ -1023,8 +1024,9 @@ struct Memory::Impl {
|
|||
std::span<Core::GPUDirtyMemoryManager> gpu_dirty_managers;
|
||||
std::mutex sys_core_guard;
|
||||
|
||||
std::optional<Common::HeapTracker> heap_tracker;
|
||||
#ifdef __linux__
|
||||
std::optional<Common::HeapTracker> buffer;
|
||||
Common::HeapTracker* buffer{};
|
||||
#else
|
||||
Common::HostMemory* buffer{};
|
||||
#endif
|
||||
|
@ -1228,7 +1230,22 @@ bool Memory::InvalidateNCE(Common::ProcessAddress vaddr, size_t size) {
|
|||
if (rasterizer) {
|
||||
impl->InvalidateGPUMemory(ptr, size);
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (!rasterizer && mapped) {
|
||||
impl->buffer->DeferredMapSeparateHeap(GetInteger(vaddr));
|
||||
}
|
||||
#endif
|
||||
|
||||
return mapped && ptr != nullptr;
|
||||
}
|
||||
|
||||
bool Memory::InvalidateSeparateHeap(void* fault_address) {
|
||||
#ifdef __linux__
|
||||
return impl->buffer->DeferredMapSeparateHeap(static_cast<u8*>(fault_address));
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core::Memory
|
||||
|
|
|
@ -487,8 +487,13 @@ public:
|
|||
* marked as debug or non-debug.
|
||||
*/
|
||||
void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug);
|
||||
|
||||
void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers);
|
||||
|
||||
bool InvalidateNCE(Common::ProcessAddress vaddr, size_t size);
|
||||
|
||||
bool InvalidateSeparateHeap(void* fault_address);
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
|
|
8
src/dynarmic/externals/CMakeLists.txt
vendored
8
src/dynarmic/externals/CMakeLists.txt
vendored
|
@ -62,10 +62,10 @@ AddJsonPackage(
|
|||
|
||||
# unordered_dense
|
||||
|
||||
AddJsonPackage(
|
||||
NAME unordered-dense
|
||||
BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
|
||||
)
|
||||
# AddJsonPackage(
|
||||
# NAME unordered-dense
|
||||
# BUNDLED_PACKAGE ${DYNARMIC_USE_BUNDLED_EXTERNALS}
|
||||
# )
|
||||
|
||||
# xbyak
|
||||
# uncomment if in an independent repo
|
||||
|
|
10
src/dynarmic/externals/cpmfile.json
vendored
10
src/dynarmic/externals/cpmfile.json
vendored
|
@ -14,16 +14,6 @@
|
|||
"MCL_INSTALL OFF"
|
||||
]
|
||||
},
|
||||
"unordered-dense": {
|
||||
"package": "unordered_dense",
|
||||
"repo": "Lizzie841/unordered_dense",
|
||||
"sha": "e59d30b7b1",
|
||||
"hash": "71eff7bd9ba4b9226967bacd56a8ff000946f8813167cb5664bb01e96fb79e4e220684d824fe9c59c4d1cc98c606f13aff05b7940a1ed8ab3c95d6974ee34fa0",
|
||||
"find_args": "CONFIG",
|
||||
"options": [
|
||||
"UNORDERED_DENSE_INSTALL OFF"
|
||||
]
|
||||
},
|
||||
"zycore": {
|
||||
"package": "Zycore",
|
||||
"repo": "zyantific/zycore-c",
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
/* This file is part of the dynarmic project.
|
||||
* Copyright (c) 2018 MerryMage
|
||||
* SPDX-License-Identifier: 0BSD
|
||||
|
@ -19,6 +22,16 @@
|
|||
|
||||
namespace Dynarmic::Common {
|
||||
|
||||
// prevents this function from printing 56,000 character warning messages
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wno-stack-usage"
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wno-stack-usage"
|
||||
#endif
|
||||
|
||||
template<typename Function, typename... Values>
|
||||
inline auto GenerateLookupTableFromList(Function f, mcl::mp::list<Values...>) {
|
||||
#ifdef _MSC_VER
|
||||
|
@ -34,4 +47,11 @@ inline auto GenerateLookupTableFromList(Function f, mcl::mp::list<Values...>) {
|
|||
return MapT(pair_array.begin(), pair_array.end());
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
} // namespace Dynarmic::Common
|
||||
|
|
|
@ -332,7 +332,8 @@ target_link_options(video_core PRIVATE ${FFmpeg_LDFLAGS})
|
|||
add_dependencies(video_core host_shaders)
|
||||
target_include_directories(video_core PRIVATE ${HOST_SHADERS_INCLUDE})
|
||||
|
||||
target_link_libraries(video_core PRIVATE sirit Vulkan::Headers Vulkan::UtilityHeaders GPUOpen::VulkanMemoryAllocator)
|
||||
target_link_libraries(video_core PRIVATE sirit Vulkan::Headers Vulkan::UtilityHeaders)
|
||||
target_link_libraries(video_core PUBLIC GPUOpen::VulkanMemoryAllocator)
|
||||
|
||||
if (ENABLE_NSIGHT_AFTERMATH)
|
||||
if (NOT DEFINED ENV{NSIGHT_AFTERMATH_SDK})
|
||||
|
|
|
@ -102,13 +102,16 @@ constexpr VkPipelineVertexInputStateCreateInfo PIPELINE_VERTEX_INPUT_STATE_CREAT
|
|||
.vertexAttributeDescriptionCount = 0,
|
||||
.pVertexAttributeDescriptions = nullptr,
|
||||
};
|
||||
constexpr VkPipelineInputAssemblyStateCreateInfo PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo GetPipelineInputAssemblyStateCreateInfo(const Device& device) {
|
||||
return VkPipelineInputAssemblyStateCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
}
|
||||
constexpr VkPipelineViewportStateCreateInfo PIPELINE_VIEWPORT_STATE_CREATE_INFO{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -802,6 +805,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||
.pAttachments = &blend_attachment,
|
||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
blit_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -809,7 +813,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceColorPipeline(const BlitImagePipelineKe
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -833,6 +837,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
|||
}
|
||||
blit_depth_stencil_keys.push_back(key);
|
||||
const std::array stages = MakeStages(*full_screen_vert, *blit_depth_stencil_frag);
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
blit_depth_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -840,7 +845,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceDepthStencilPipeline(const BlitImagePip
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -885,6 +890,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel
|
|||
.pAttachments = &color_blend_attachment_state,
|
||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
clear_color_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -892,7 +898,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearColorPipeline(const BlitImagePipel
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -940,6 +946,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||
.minDepthBounds = 0.0f,
|
||||
.maxDepthBounds = 0.0f,
|
||||
};
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -947,7 +954,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -970,6 +977,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
|
|||
}
|
||||
VkShaderModule frag_shader = *convert_float_to_depth_frag;
|
||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -977,7 +985,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -999,6 +1007,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
|
|||
}
|
||||
VkShaderModule frag_shader = *convert_depth_to_float_frag;
|
||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -1006,7 +1015,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -1029,6 +1038,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
|||
return;
|
||||
}
|
||||
const std::array stages = MakeStages(*full_screen_vert, *module);
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -1036,7 +1046,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
@ -1070,6 +1080,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende
|
|||
VkShaderModule frag_shader =
|
||||
is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag;
|
||||
const std::array stages = MakeStages(*full_screen_vert, frag_shader);
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
pipeline = device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@ -1077,7 +1088,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende
|
|||
.stageCount = static_cast<u32>(stages.size()),
|
||||
.pStages = stages.data(),
|
||||
.pVertexInputState = &PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pInputAssemblyState = &input_assembly_ci,
|
||||
.pTessellationState = nullptr,
|
||||
.pViewportState = &PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pRasterizationState = &PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
|
|
|
@ -400,12 +400,12 @@ static vk::Pipeline CreateWrappedPipelineImpl(
|
|||
.pVertexAttributeDescriptions = nullptr,
|
||||
};
|
||||
|
||||
constexpr VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP,
|
||||
.primitiveRestartEnable = VK_FALSE,
|
||||
.primitiveRestartEnable = device.IsMoltenVK() ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
|
||||
constexpr VkPipelineViewportStateCreateInfo viewport_state_ci{
|
||||
|
|
|
@ -635,14 +635,16 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||
.flags = 0,
|
||||
.topology = input_assembly_topology,
|
||||
.primitiveRestartEnable =
|
||||
dynamic.primitive_restart_enable != 0 &&
|
||||
// MoltenVK/Metal always has primitive restart enabled and cannot disable it
|
||||
device.IsMoltenVK() ? VK_TRUE :
|
||||
(dynamic.primitive_restart_enable != 0 &&
|
||||
((input_assembly_topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsTopologyListPrimitiveRestartSupported()) ||
|
||||
SupportsPrimitiveRestart(input_assembly_topology) ||
|
||||
(input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||
device.IsPatchListPrimitiveRestartSupported()))
|
||||
? VK_TRUE
|
||||
: VK_FALSE,
|
||||
: VK_FALSE),
|
||||
};
|
||||
const VkPipelineTessellationStateCreateInfo tessellation_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -8,4 +10,4 @@
|
|||
#define VMA_STATIC_VULKAN_FUNCTIONS 0
|
||||
#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
|
||||
|
||||
#include <vk_mem_alloc.h>
|
||||
#include "vk_mem_alloc.h"
|
||||
|
|
|
@ -725,6 +725,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||
dynamic_state3_enables = true;
|
||||
}
|
||||
|
||||
if (is_mvk && Settings::values.dyna_state.GetValue() != 0) {
|
||||
LOG_WARNING(Render_Vulkan, "MoltenVK detected: Forcing dynamic state to 0 to prevent black screen issues");
|
||||
Settings::values.dyna_state.SetValue(0);
|
||||
}
|
||||
|
||||
if (Settings::values.dyna_state.GetValue() == 0) {
|
||||
must_emulate_scaled_formats = true;
|
||||
LOG_INFO(Render_Vulkan, "Dynamic state is disabled (dyna_state = 0), forcing scaled format emulation ON");
|
||||
|
@ -753,18 +758,24 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||
functions.vkGetInstanceProcAddr = dld.vkGetInstanceProcAddr;
|
||||
functions.vkGetDeviceProcAddr = dld.vkGetDeviceProcAddr;
|
||||
|
||||
const VmaAllocatorCreateInfo allocator_info = {
|
||||
.flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT,
|
||||
.physicalDevice = physical,
|
||||
.device = *logical,
|
||||
.preferredLargeHeapBlockSize = 0,
|
||||
.pAllocationCallbacks = nullptr,
|
||||
.pDeviceMemoryCallbacks = nullptr,
|
||||
.pHeapSizeLimit = nullptr,
|
||||
.pVulkanFunctions = &functions,
|
||||
.instance = instance,
|
||||
.vulkanApiVersion = VK_API_VERSION_1_1,
|
||||
.pTypeExternalMemoryHandleTypes = nullptr,
|
||||
VmaAllocatorCreateFlags flags = VMA_ALLOCATOR_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
|
||||
if (extensions.memory_budget) {
|
||||
flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||
}
|
||||
const VmaAllocatorCreateInfo allocator_info{
|
||||
.flags = flags,
|
||||
.physicalDevice = physical,
|
||||
.device = *logical,
|
||||
.preferredLargeHeapBlockSize = is_integrated
|
||||
? (64u * 1024u * 1024u)
|
||||
: (256u * 1024u * 1024u),
|
||||
.pAllocationCallbacks = nullptr,
|
||||
.pDeviceMemoryCallbacks = nullptr,
|
||||
.pHeapSizeLimit = nullptr,
|
||||
.pVulkanFunctions = &functions,
|
||||
.instance = instance,
|
||||
.vulkanApiVersion = ApiVersion(),
|
||||
.pTypeExternalMemoryHandleTypes = nullptr,
|
||||
};
|
||||
|
||||
vk::Check(vmaCreateAllocator(&allocator_info, &allocator));
|
||||
|
@ -1090,8 +1101,15 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
|||
// Some features are mandatory. Check those.
|
||||
#define CHECK_FEATURE(feature, name) \
|
||||
if (!features.feature.name) { \
|
||||
LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name); \
|
||||
suitable = false; \
|
||||
if (IsMoltenVK() && (strcmp(#name, "geometryShader") == 0 || \
|
||||
strcmp(#name, "logicOp") == 0 || \
|
||||
strcmp(#name, "shaderCullDistance") == 0 || \
|
||||
strcmp(#name, "wideLines") == 0)) { \
|
||||
LOG_INFO(Render_Vulkan, "MoltenVK missing feature {} - using fallback", #name); \
|
||||
} else { \
|
||||
LOG_ERROR(Render_Vulkan, "Missing required feature {}", #name); \
|
||||
suitable = false; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define LOG_FEATURE(feature, name) \
|
||||
|
@ -1378,13 +1396,13 @@ void Device::CollectPhysicalMemoryInfo() {
|
|||
device_access_memory += mem_properties.memoryHeaps[element].size;
|
||||
}
|
||||
if (!is_integrated) {
|
||||
const u64 reserve_memory = std::min<u64>(device_access_memory / 4, 2_GiB);
|
||||
const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
|
||||
device_access_memory -= reserve_memory;
|
||||
|
||||
if (Settings::values.vram_usage_mode.GetValue() != Settings::VramUsageMode::Aggressive) {
|
||||
// Account for resolution scaling in memory limits
|
||||
const size_t normal_memory = 8_GiB;
|
||||
const size_t scaler_memory = 2_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||
const size_t normal_memory = 6_GiB;
|
||||
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
|
||||
device_access_memory =
|
||||
std::min<u64>(device_access_memory, normal_memory + scaler_memory);
|
||||
}
|
||||
|
@ -1393,7 +1411,7 @@ void Device::CollectPhysicalMemoryInfo() {
|
|||
}
|
||||
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);
|
||||
device_access_memory = static_cast<u64>(std::max<s64>(
|
||||
std::min<s64>(available_memory - 4_GiB, 6_GiB), std::min<s64>(local_memory, 6_GiB)));
|
||||
std::min<s64>(available_memory - 8_GiB, 6_GiB), std::min<s64>(local_memory, 6_GiB)));
|
||||
}
|
||||
|
||||
void Device::CollectToolingInfo() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue