Compare commits

..

4 Commits

Author SHA1 Message Date
lizzie cddadf3b6c simplify 2 2026-03-26 20:50:47 +01:00
lizzie ef42d03bec fix? 2026-03-26 20:50:47 +01:00
lizzie 14a3799a03 license 2026-03-26 20:50:47 +01:00
lizzie e780b8f8d3 [dynarmic] fix multicore macOS issue
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-03-26 20:50:47 +01:00
376 changed files with 16497 additions and 19922 deletions
-54
View File
@@ -1,54 +0,0 @@
name: update-deps
on:
# saturday at noon
schedule:
- cron: '0 12 * * 6'
workflow_dispatch:
jobs:
tx-update:
runs-on: source
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Update deps
run: |
git config --local user.name "Eden CI"
git config --local user.email "ci@eden-emu.dev"
git config --local user.signingkey "D57652791BB25D2A"
git config --local push.autoSetupRemote true
git remote set-url origin ci:eden-emu/eden.git
DATE=$(date +"%b %d")
echo "DATE=$DATE" >> "$GITHUB_ENV"
git switch -c update-deps-$DATE
tools/cpmutil.sh package update -ac
git push
- name: Create PR
run: |
TITLE="[externals] Dependency update for $DATE"
BODY="$(git show -s --format='%b')"
BASE=master
HEAD=update-deps-$DATE
cat << EOF > data.json
{
"base": "$BASE",
"body": "$BODY",
"head": "$HEAD",
"title": "$TITLE"
}
EOF
curl -X 'POST' \
'https://git.eden-emu.dev/api/v1/repos/eden-emu/eden/pulls' \
-H 'accept: application/json' \
-H 'Authorization: Bearer ${{ secrets.CI_FJ_TOKEN }}' \
-H 'Content-Type: application/json' \
-d "@data.json" --fail
@@ -1,9 +1,10 @@
name: tx-pull
on:
# tuesday, saturday at 2pm
# monday, wednesday, saturday at 2pm
schedule:
- cron: '0 14 * * 2,6'
cron:
- '0 14 * * 1,3,6'
workflow_dispatch:
jobs:
@@ -58,3 +59,4 @@ jobs:
-H 'Authorization: Bearer ${{ secrets.CI_FJ_TOKEN }}' \
-H 'Content-Type: application/json' \
-d "@data.json" --fail
+55
View File
@@ -0,0 +1,55 @@
diff --git a/include/mcl/assert.hpp b/include/mcl/assert.hpp
index f77dbe7..9ec0b9c 100644
--- a/include/mcl/assert.hpp
+++ b/include/mcl/assert.hpp
@@ -23,8 +23,11 @@ template<typename... Ts>
} // namespace mcl::detail
+#ifndef UNREACHABLE
#define UNREACHABLE() ASSERT_FALSE("Unreachable code!")
+#endif
+#ifndef ASSERT
#define ASSERT(expr) \
[&] { \
if (std::is_constant_evaluated()) { \
@@ -37,7 +40,9 @@ template<typename... Ts>
} \
} \
}()
+#endif
+#ifndef ASSERT_MSG
#define ASSERT_MSG(expr, ...) \
[&] { \
if (std::is_constant_evaluated()) { \
@@ -50,13 +55,24 @@ template<typename... Ts>
} \
} \
}()
+#endif
+#ifndef ASSERT_FALSE
#define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false", __VA_ARGS__)
+#endif
#if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS)
-# define DEBUG_ASSERT(expr) ASSUME(expr)
-# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
+# ifndef DEBUG_ASSERT
+# define DEBUG_ASSERT(expr) ASSUME(expr)
+# endif
+# ifndef DEBUG_ASSERT_MSG
+# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
+# endif
#else
-# define DEBUG_ASSERT(expr) ASSERT(expr)
-# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
+# ifndef DEBUG_ASSERT
+# define DEBUG_ASSERT(expr) ASSERT(expr)
+# endif
+# ifndef DEBUG_ASSERT_MSG
+# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
+# endif
#endif
+1
View File
@@ -526,6 +526,7 @@ if (NOT YUZU_STATIC_ROOM)
find_package(SPIRV-Tools)
find_package(sirit)
find_package(gamemode)
find_package(mcl)
find_package(frozen)
if (ARCHITECTURE_riscv64)
+4 -4
View File
@@ -37,10 +37,10 @@ set(GIT_DESC ${BUILD_VERSION})
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
if (NIGHTLY_BUILD)
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
set(BUILD_AUTO_UPDATE_API "git.eden-emu.dev")
set(BUILD_AUTO_UPDATE_API_PATH "/api/v1/repos/")
set(BUILD_AUTO_UPDATE_REPO "eden-ci/nightly")
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
set(BUILD_AUTO_UPDATE_API "api.github.com")
set(BUILD_AUTO_UPDATE_API_PATH "/repos/")
set(BUILD_AUTO_UPDATE_REPO "Eden-CI/Nightly")
set(REPO_NAME "Eden Nightly")
else()
set(BUILD_AUTO_UPDATE_WEBSITE "https://git.eden-emu.dev")
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 19 KiB

-1
View File
@@ -1 +0,0 @@
#43fcfcff
+413 -403
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+482 -472
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+556 -562
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+408 -398
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+408 -398
View File
File diff suppressed because it is too large Load Diff
+405 -395
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+407 -397
View File
File diff suppressed because it is too large Load Diff
+403 -393
View File
File diff suppressed because it is too large Load Diff
+2 -1
View File
@@ -76,6 +76,7 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
* This package is known to be broken on the AUR.
* [cpp-jwt](https://github.com/arun11299/cpp-jwt) 1.4+ - if `ENABLE_WEB_SERVICE` is on
* [unordered-dense](https://github.com/martinus/unordered_dense)
* [mcl](https://github.com/azahar-emu/mcl) - subject to removal
On amd64:
@@ -334,7 +335,7 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.89_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
```
[Caveats](./Caveats.md#haikuos).
-1
View File
@@ -16,7 +16,6 @@ This contains documentation created by developers. This contains build instructi
- **[Dynarmic](./dynarmic)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**
- **[Building Older Commits](./build/OlderCommits.md)**
## Policies
-40
View File
@@ -1,40 +0,0 @@
# Building Older Commits
Bisecting and debugging older versions of Eden can be difficult, as many of our submodules have been deleted or removed. However, work has been done to make this process as simple as possible for users.
## Script
Copy the following script and store it in `fix.sh`:
```sh
#!/bin/sh -e
git -C externals/discord-rpc checkout 0d8b2d6a37c6e47d62b37caa14708bf747c883bb
git add externals/discord-rpc
git -C externals/dynarmic checkout 05b7ba50588d1004e23ef91f1bda8be234be68f4
git add externals/dynarmic
git -C externals/mbedtls checkout ce4f81f4a926a0e0dcadd0128e016baba416e8ea
git add externals/mbedtls
git -C externals/oboe checkout e4f06f2143eb0173bf4a2bd15aae5e8cc3179405
git add externals/oboe
git -C externals/sirit checkout b870b062998244231a4f08004d3b25151732c5c5
git add externals/sirit
```
Then, run `chmod +x fix.sh`
## Submodules
To check out submodules successfully, use this order of operations:
```sh
git submodule update --init --recursive --depth 1 --jobs 8 --progress
./fix.sh
git submodule update --init --recursive --depth 1 --jobs 8 --progress
```
And you should be good to go! If you check out a different commit that changes submodule commits, run the above command list again.
+15 -35
View File
@@ -56,7 +56,7 @@ Use this when you need to connect to a multiplayer room for LDN functionality in
- Multiplayer Options Configured in Eden Settings
- Network Access
### Steps
## Steps
There are 2 primary methods that you can use to connect to an existing room, depending on how the room is hosted.
- Joining a Public Lobby
@@ -70,7 +70,7 @@ There are 2 primary methods that you can use to connect to an existing room, dep
</aside>
## Joining a Public Lobby
### Joining a Public Lobby
1. Open Eden and navigate to *Multiplayer → Browse Public Game Lobby*.
2. The **Public Room Browser** will now open and display a list of publicly accessible rooms. Find one you want to connect to and double click it.
@@ -90,7 +90,7 @@ If the hoster has not made the lobby public, or you don't want to find it in the
---
## Hosting a Multiplayer Room
# Hosting a Multiplayer Room
Use this guide for when you want to host a multiplayer lobby to play with others in Eden. In order to have someone access the room from outside your local network, see the *Access Your Multiplayer Room Externally* section for next steps.
**Click [Here](https://evilperson1337.notion.site/Hosting-a-Multiplayer-Room-2c357c2edaf6819481dbe8a99926cea2) for a version of this guide with images & visual elements.**
@@ -100,7 +100,7 @@ Use this guide for when you want to host a multiplayer lobby to play with others
- Network Access
- Ability to allow programs through the firewall on your device.
### Steps
## Steps
1. Open Eden and navigate to *Emulation → Multiplayer → Create Room.*
2. Fill out the following information in the popup dialog box.
@@ -120,7 +120,7 @@ Use this guide for when you want to host a multiplayer lobby to play with others
---
## Access Your Multiplayer Room Externally
# Access Your Multiplayer Room Externally
Quite often the person with whom you want to play is located off of your internal network (LAN). If you want to host a room and play with them you will need to get your devices to communicate with each other. This guide will go over your options on how to do this so that you can play together.
**Click [Here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for a version of this guide with images & visual elements.**
@@ -129,9 +129,9 @@ Quite often the person with whom you want to play is located off of your interna
- Eden set up and Functioning
- Network Access
### Options
## Options
#### Port Forwarding
### Port Forwarding
- **Difficulty Level**: High
@@ -148,9 +148,8 @@ The process works by creating a static mapping—often called a “port-forward
For our purposes we would pick the port we want to expose (*e.g. 24872*) and we would access our router's configuration and create a port-forward rule to send the traffic from an external connection to your local machine over our specified port (*24872)*. The exact way to do so, varies greatly by router manufacturer - and sometimes require contacting your ISP to do so depending on your agreement. You can look up your router on [*portforward.com*](https://portforward.com/router.htm) which may have instructions on how to do so for your specific equipment. If it is not there, you will have to use Google/ChatGPT to determine the steps for your equipment.
Remember you can't have one port open for multiple devices at the same time - you must only host from one device (or do more convoluted networking which we will not cover here).
#### Use a Tunnelling Service
### Use a Tunnelling Service
- **Difficulty Level**: Easy
<aside>
@@ -168,7 +167,7 @@ For our purposes we would spawn the listener for the port that way chose when ho
- [*Playit.GG*](https://playit.gg/)
#### Use a VPN Service
### Use a VPN Service
- **Difficulty**: Easy
@@ -190,7 +189,7 @@ The VPN solution is a good compromise between the tunnelling solution and port f
---
## Finding the Server Information for a Multiplayer Room
# Finding the Server Information for a Multiplayer Room
Use this guide when you need to determine the connection information for the Public Multiplayer Lobby you are connected to.
**Click [Here](https://evilperson1337.notion.site/Finding-the-Server-Information-for-a-Multiplayer-Room-2c557c2edaf6809e94e8ed3429b9eb26) for a version of this guide with images & visual elements.**
@@ -199,7 +198,7 @@ Use this guide when you need to determine the connection information for the Pub
- Eden set up and configured
- Internet Access
### Steps
## Steps
### Method 1: Grabbing the Address from the Log File
1. Open Eden and Connect to the room you want to identify.
@@ -223,7 +222,7 @@ Use this guide when you need to determine the connection information for the Pub
2. Open the terminal supported by your operating system.
3. Run one of the following commands, replacing *<Name>* with the name of the server from step 1.
#### PowerShell Command [Windows Users]
### PowerShell Command [Windows Users]
```powershell
# Calls the API to get the address and port information
@@ -236,7 +235,7 @@ Use this guide when you need to determine the connection information for the Pub
#}
```
#### CURL Command [MacOS/Linux Users] **Requires jq*
### CURL Command [MacOS/Linux Users] **Requires jq*
```bash
# Calls the API to get the address and port information
@@ -253,7 +252,7 @@ Use this guide when you need to determine the connection information for the Pub
---
## Multiplayer for Local Co-Op Games
# Multiplayer for Local Co-Op Games
Use this guide when you want to play with a friend on a different system for games that only support local co-op.
**Click [Here](https://evilperson1337.notion.site/Multiplayer-for-Local-Co-Op-Games-2c657c2edaf680c59975ec6b52022a2d) for a version of this guide with images & visual elements.**
@@ -272,7 +271,7 @@ In either situation at its core, we are emulating an input device on the host ma
- Parsec is free to use for personal, non-commercial use. For instructions on how to set up an account and install the client you should refer to the Parsec documentation on it's site.
- Parsec client installed on your machine and remote (friend's) machine
### Steps
## Steps
<aside>
@@ -295,22 +294,3 @@ This guide will assume you are the one hosting the game and go over things *Pars
10. Set up the remote player's controller.
11. Hit **OK** to apply the changes.
12. Launch the game you want to play and enter the co-op mode. How this works depends on the game, so you will have to look in the menus or online to find out.
## Metaserver troubleshooting
If you can't connect to the metaserver, it's likely your ISP is blocking the requests.
### Linux and Steamdeck
Most Linux systems and Steamdeck should allow to modify the base `/etc/hosts` file, this should fix the DNS lookup issue; hence add the following to said file:
```
28.165.181.135 api.ynet-fun.xyz api.ynet-fun.xyz
```
### Zapret
In `lists/list-general.txt` add the following:
```
api.ynet-fun.xyz
ynet-fun.xyz
```
+6 -6
View File
@@ -62,12 +62,6 @@ endif()
# unordered_dense
AddJsonPackage(unordered-dense)
# httplib
if (IOS)
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
endif()
AddJsonPackage(httplib)
if (YUZU_STATIC_ROOM)
return()
endif()
@@ -82,6 +76,9 @@ if (ARCHITECTURE_riscv64)
AddJsonPackage(biscuit)
endif()
# mcl
AddJsonPackage(mcl)
# Vulkan stuff
AddDependentPackages(vulkan-headers vulkan-utility-libraries)
@@ -233,6 +230,9 @@ if (VulkanMemoryAllocator_ADDED)
endif()
endif()
# httplib
AddJsonPackage(httplib)
# cpp-jwt
if (ENABLE_WEB_SERVICE OR ENABLE_UPDATE_CHECKER)
AddJsonPackage(cpp-jwt)
+13 -3
View File
@@ -30,15 +30,13 @@
"tag": "v%VERSION%",
"hash": "5efa8140aadffe105dcf39935b732476e95755f6c7473ada3d0b64df2bc02c557633ae3948a25b45e1cf67e89a3ff6329fb30362e4ac033b9a1d1e453aa2eded",
"git_version": "0.37.0",
"version": "0.18.7",
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch",
"0002-fix-zstd.patch"
],
"options": [
"HTTPLIB_REQUIRE_OPENSSL ON",
"HTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES ON"
"HTTPLIB_REQUIRE_OPENSSL ON"
]
},
"cpp-jwt": {
@@ -210,6 +208,18 @@
"version": "0.9.1",
"git_version": "0.19.0"
},
"mcl": {
"version": "0.1.12",
"repo": "azahar-emu/mcl",
"sha": "7b08d83418",
"hash": "9c6ba624cb22ef622f78046a82abb99bf5026284ba17dfacaf46ac842cbd3b0f515f5ba45a1598c7671318a78a2e648db72ce8d10e7537f34e39800bdcb57694",
"options": [
"MCL_INSTALL OFF"
],
"patches": [
"0001-assert-macro.patch"
]
},
"libusb": {
"repo": "libusb/libusb",
"tag": "v%VERSION%",
+1 -1
View File
@@ -8,7 +8,7 @@
include_directories(.)
# Dynarmic
if ((ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64) AND NOT YUZU_STATIC_ROOM)
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 AND NOT YUZU_STATIC_ROOM)
add_subdirectory(dynarmic)
add_library(dynarmic::dynarmic ALIAS dynarmic)
endif()
@@ -25,11 +25,6 @@ import android.hardware.SensorEventListener
import android.hardware.SensorManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import androidx.navigation.NavOptions
import org.yuzu.yuzu_emu.fragments.EmulationFragment
import org.yuzu.yuzu_emu.utils.CustomSettingsHandler
import android.util.Rational
import android.view.InputDevice
import android.view.KeyEvent
@@ -92,28 +87,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
private val emulationViewModel: EmulationViewModel by viewModels()
private var foregroundService: Intent? = null
private val mainHandler = Handler(Looper.getMainLooper())
private var pendingRomSwapIntent: Intent? = null
private var isWaitingForRomSwapStop = false
private var romSwapNativeStopped = false
private var romSwapThreadStopped = false
private var romSwapGeneration = 0
private var hasEmulationSession = processHasEmulationSession
private val romSwapStopTimeoutRunnable = Runnable { onRomSwapStopTimeout() }
private fun onRomSwapStopTimeout() {
if (!isWaitingForRomSwapStop) {
return
}
Log.warning("[EmulationActivity] ROM swap stop timed out; retrying native stop and continuing to wait")
NativeLibrary.stopEmulation()
scheduleRomSwapStopTimeout()
}
private fun scheduleRomSwapStopTimeout() {
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
mainHandler.postDelayed(romSwapStopTimeoutRunnable, ROM_SWAP_STOP_TIMEOUT_MS)
}
override fun attachBaseContext(base: Context) {
super.attachBaseContext(YuzuApplication.applyLanguage(base))
@@ -155,29 +128,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
binding = ActivityEmulationBinding.inflate(layoutInflater)
setContentView(binding.root)
val launchIntent = Intent(intent)
val shouldDeferLaunchForSwap = hasEmulationSession && isSwapIntent(launchIntent)
if (shouldDeferLaunchForSwap) {
Log.info("[EmulationActivity] onCreate detected existing session; deferring new game setup for swap")
emulationViewModel.setIsEmulationStopping(true)
emulationViewModel.setEmulationStopped(false)
}
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
val initialArgs = if (shouldDeferLaunchForSwap) {
Bundle(intent.extras ?: Bundle()).apply {
processSessionGame?.let { putParcelable("game", it) }
}
} else {
intent.extras
}
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, initialArgs)
if (shouldDeferLaunchForSwap) {
mainHandler.post {
handleSwapIntent(launchIntent)
}
}
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras)
isActivityRecreated = savedInstanceState != null
@@ -257,7 +210,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
}
override fun onDestroy() {
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
super.onDestroy()
inputManager.unregisterInputDeviceListener(this)
stopForegroundService(this)
@@ -276,121 +228,15 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleSwapIntent(intent)
nfcReader.onNewIntent(intent)
InputHandler.updateControllerData()
}
setIntent(intent)
private fun isSwapIntent(intent: Intent): Boolean {
return when {
intent.getBooleanExtra(EXTRA_OVERLAY_GAMELESS_EDIT_MODE, false) -> false
intent.action == CustomSettingsHandler.CUSTOM_CONFIG_ACTION -> true
intent.data != null -> true
else -> {
val extras = intent.extras
extras != null &&
BundleCompat.getParcelable(extras, EXTRA_SELECTED_GAME, Game::class.java) != null
}
}
}
private fun handleSwapIntent(intent: Intent) {
if (!isSwapIntent(intent)) {
return
}
pendingRomSwapIntent = Intent(intent)
if (!isWaitingForRomSwapStop) {
Log.info("[EmulationActivity] Begin ROM swap: data=${intent.data}")
isWaitingForRomSwapStop = true
romSwapNativeStopped = false
romSwapThreadStopped = false
romSwapGeneration += 1
val thisSwapGeneration = romSwapGeneration
emulationViewModel.setIsEmulationStopping(true)
emulationViewModel.setEmulationStopped(false)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
val childFragmentManager = navHostFragment?.childFragmentManager
val stoppingFragmentForSwap =
(childFragmentManager?.primaryNavigationFragment as? EmulationFragment) ?:
childFragmentManager
?.fragments
?.asReversed()
?.firstOrNull {
it is EmulationFragment &&
it.isAdded &&
it.view != null &&
!it.isRemoving
} as? EmulationFragment
val hasSessionForSwap = hasEmulationSession || stoppingFragmentForSwap != null
if (!hasSessionForSwap) {
romSwapNativeStopped = true
romSwapThreadStopped = true
} else {
if (stoppingFragmentForSwap != null) {
stoppingFragmentForSwap.stopForRomSwap()
stoppingFragmentForSwap.notifyWhenEmulationThreadStops {
if (!isWaitingForRomSwapStop || romSwapGeneration != thisSwapGeneration) {
return@notifyWhenEmulationThreadStops
}
romSwapThreadStopped = true
Log.info("[EmulationActivity] ROM swap thread stop acknowledged")
launchPendingRomSwap(force = false)
}
} else {
Log.warning("[EmulationActivity] ROM swap stop target fragment not found; requesting native stop")
romSwapThreadStopped = true
NativeLibrary.stopEmulation()
}
scheduleRomSwapStopTimeout()
}
}
launchPendingRomSwap(force = false)
}
private fun launchPendingRomSwap(force: Boolean) {
if (!isWaitingForRomSwapStop) {
return
}
if (!force && (!romSwapNativeStopped || !romSwapThreadStopped)) {
return
}
val swapIntent = pendingRomSwapIntent ?: return
Log.info("[EmulationActivity] Launching pending ROM swap: data=${swapIntent.data}")
pendingRomSwapIntent = null
isWaitingForRomSwapStop = false
romSwapNativeStopped = false
romSwapThreadStopped = false
mainHandler.removeCallbacks(romSwapStopTimeoutRunnable)
applyGameLaunchIntent(swapIntent)
}
private fun applyGameLaunchIntent(intent: Intent) {
hasEmulationSession = true
processHasEmulationSession = true
emulationViewModel.setIsEmulationStopping(false)
emulationViewModel.setEmulationStopped(false)
setIntent(Intent(intent))
// Reset navigation graph with new intent data to recreate EmulationFragment
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
val navController = navHostFragment.navController
val startArgs = intent.extras?.let { Bundle(it) } ?: Bundle()
val navOptions = NavOptions.Builder()
.setPopUpTo(R.id.emulationFragment, true)
.build()
navHostFragment.navController.setGraph(R.navigation.emulation_navigation, intent.extras)
runCatching {
navController.navigate(R.id.emulationFragment, startArgs, navOptions)
}.onFailure {
Log.warning("[EmulationActivity] ROM swap navigate fallback to setGraph: ${it.message}")
navController.setGraph(R.navigation.emulation_navigation, startArgs)
}
nfcReader.onNewIntent(intent)
InputHandler.updateControllerData()
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@@ -762,48 +608,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
}
fun onEmulationStarted() {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post { onEmulationStarted() }
return
}
hasEmulationSession = true
processHasEmulationSession = true
emulationViewModel.setEmulationStarted(true)
emulationViewModel.setIsEmulationStopping(false)
emulationViewModel.setEmulationStopped(false)
NativeLibrary.playTimeManagerStart()
}
fun onEmulationStopped(status: Int) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post { onEmulationStopped(status) }
return
}
hasEmulationSession = false
processHasEmulationSession = false
if (isWaitingForRomSwapStop) {
romSwapNativeStopped = true
Log.info("[EmulationActivity] ROM swap native stop acknowledged")
launchPendingRomSwap(force = false)
} else if (status == 0 && emulationViewModel.programChanged.value == -1) {
processSessionGame = null
if (status == 0 && emulationViewModel.programChanged.value == -1) {
finish()
} else if (!isWaitingForRomSwapStop) {
processSessionGame = null
}
emulationViewModel.setEmulationStopped(true)
}
fun updateSessionGame(game: Game?) {
processSessionGame = game
}
fun onProgramChanged(programIndex: Int) {
if (Looper.myLooper() != Looper.getMainLooper()) {
mainHandler.post { onProgramChanged(programIndex) }
return
}
emulationViewModel.setProgramChanged(programIndex)
}
@@ -827,11 +644,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
companion object {
const val EXTRA_SELECTED_GAME = "SelectedGame"
const val EXTRA_OVERLAY_GAMELESS_EDIT_MODE = "overlayGamelessEditMode"
private const val ROM_SWAP_STOP_TIMEOUT_MS = 5000L
@Volatile
private var processHasEmulationSession = false
@Volatile
private var processSessionGame: Game? = null
fun stopForegroundService(activity: Activity) {
val startIntent = Intent(activity, ForegroundService::class.java)
@@ -50,7 +50,6 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.fragment.navArgs
import androidx.window.layout.FoldingFeature
import androidx.window.layout.WindowInfoTracker
@@ -136,8 +135,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var intentGame: Game? = null
private var isCustomSettingsIntent = false
private var isStoppingForRomSwap = false
private var deferGameSetupUntilStopCompletes = false
private var perfStatsRunnable: Runnable? = null
private var socRunnable: Runnable? = null
@@ -241,14 +238,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
if (emulationViewModel.isEmulationStopping.value) {
deferGameSetupUntilStopCompletes = true
if (game == null) {
game = args.game ?: intentGame
}
return
}
finishGameSetup()
}
@@ -271,7 +260,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
game = gameToUse
emulationActivity?.updateSessionGame(gameToUse)
} catch (e: Exception) {
Log.error("[EmulationFragment] Error during game setup: ${e.message}")
Toast.makeText(
@@ -346,8 +334,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
emulationState = EmulationState(game!!.path) {
return@EmulationState driverViewModel.isInteractionAllowed.value &&
!isStoppingForRomSwap
return@EmulationState driverViewModel.isInteractionAllowed.value
}
}
@@ -903,12 +890,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
)
game?.let {
GameIconUtils.loadGameIcon(it, binding.loadingImage)
binding.loadingTitle.text = it.title
} ?: run {
binding.loadingTitle.text = ""
}
GameIconUtils.loadGameIcon(game!!, binding.loadingImage)
binding.loadingTitle.text = game!!.title
binding.loadingTitle.isSelected = true
binding.loadingText.isSelected = true
@@ -976,12 +959,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.showStatsOverlayText)
} else if (deferGameSetupUntilStopCompletes) {
if (!isAdded) {
return@collect
}
deferGameSetupUntilStopCompletes = false
finishGameSetup()
}
}
emulationViewModel.drawerOpen.collect(viewLifecycleOwner) {
@@ -1018,24 +995,26 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
driverViewModel.isInteractionAllowed.collect(viewLifecycleOwner) {
if (it &&
!isStoppingForRomSwap &&
!NativeLibrary.isRunning() &&
!NativeLibrary.isPaused()
) {
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start()
}
updateScreenLayout()
emulationState.run(emulationActivity!!.isActivityRecreated)
if (it && !NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
startEmulation()
}
}
driverViewModel.onLaunchGame()
}
private fun startEmulation(programIndex: Int = 0) {
if (!NativeLibrary.isRunning() && !NativeLibrary.isPaused()) {
if (!DirectoryInitialization.areDirectoriesReady) {
DirectoryInitialization.start()
}
updateScreenLayout()
emulationState.run(emulationActivity!!.isActivityRecreated, programIndex)
}
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
val b = _binding ?: return
@@ -1396,9 +1375,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
super.onDestroyView()
amiiboLoadJob?.cancel()
amiiboLoadJob = null
perfStatsRunnable?.let { perfStatsUpdateHandler.removeCallbacks(it) }
socRunnable?.let { socUpdateHandler.removeCallbacks(it) }
handler.removeCallbacksAndMessages(null)
clearPausedFrame()
_binding?.surfaceInputOverlay?.touchEventListener = null
_binding = null
@@ -1406,9 +1382,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
override fun onDetach() {
if (!hasNewerEmulationFragment()) {
NativeLibrary.clearEmulationActivity()
}
NativeLibrary.clearEmulationActivity()
super.onDetach()
}
@@ -1866,74 +1840,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
if (this::emulationState.isInitialized && !hasNewerEmulationFragment()) {
emulationState.clearSurface()
}
emulationState.clearSurface()
emulationStarted = false
}
private fun hasNewerEmulationFragment(): Boolean {
val activity = emulationActivity ?: return false
return try {
val navHostFragment =
activity.supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
?: return false
val currentFragment = navHostFragment.childFragmentManager.fragments
.filterIsInstance<EmulationFragment>()
.firstOrNull()
currentFragment != null && currentFragment !== this
} catch (_: Exception) {
false
}
}
// xbzk: called from EmulationActivity when a new game is loaded while this fragment is still active,
// to wait for the emulation thread to stop before allowing the ROM swap to proceed
fun notifyWhenEmulationThreadStops(onStopped: () -> Unit) {
if (!this::emulationState.isInitialized) {
onStopped()
return
}
val emuThread = runCatching { emulationState.emulationThread }.getOrNull()
if (emuThread == null || !emuThread.isAlive) {
onStopped()
return
}
Thread({
runCatching { emuThread.join() }
Handler(Looper.getMainLooper()).post {
onStopped()
}
}, "RomSwapWait").start()
}
// xbzk: called from EmulationActivity when a new game is loaded while this
// fragment is still active, to stop the current emulation before swapping the ROM
fun stopForRomSwap() {
if (isStoppingForRomSwap) {
return
}
isStoppingForRomSwap = true
clearPausedFrame()
emulationViewModel.setIsEmulationStopping(true)
_binding?.let {
binding.loadingText.setText(R.string.shutting_down)
ViewUtils.showView(binding.loadingIndicator)
ViewUtils.hideView(binding.inputContainer)
ViewUtils.hideView(binding.showStatsOverlayText)
}
if (this::emulationState.isInitialized) {
emulationState.stop()
if (NativeLibrary.isRunning() || NativeLibrary.isPaused()) {
Log.warning("[EmulationFragment] ROM swap stop fallback: forcing native stop request.")
NativeLibrary.stopEmulation()
}
} else {
NativeLibrary.stopEmulation()
}
NativeConfig.reloadGlobalConfig()
}
private fun showOverlayOptions() {
val anchor = binding.inGameMenu.findViewById<View>(R.id.menu_overlay_controls)
val popup = PopupMenu(requireContext(), anchor)
@@ -2224,7 +2134,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
state = State.STOPPED
} else {
Log.warning("[EmulationFragment] Stop called while already stopped.")
NativeLibrary.stopEmulation()
}
}
@@ -36,7 +36,6 @@ import org.yuzu.yuzu_emu.databinding.FragmentGamePropertiesBinding
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.features.settings.ui.SettingsSubscreen
import org.yuzu.yuzu_emu.model.AddonViewModel
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.GamesViewModel
@@ -47,7 +46,6 @@ import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GameHelper
import org.yuzu.yuzu_emu.utils.GameIconUtils
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.MemoryUtil
@@ -63,7 +61,6 @@ class GamePropertiesFragment : Fragment() {
private val homeViewModel: HomeViewModel by activityViewModels()
private val gamesViewModel: GamesViewModel by activityViewModels()
private val addonViewModel: AddonViewModel by activityViewModels()
private val driverViewModel: DriverViewModel by activityViewModels()
private val args by navArgs<GamePropertiesFragmentArgs>()
@@ -121,20 +118,6 @@ class GamePropertiesFragment : Fragment() {
.show(childFragmentManager, LaunchGameDialogFragment.TAG)
}
if (GameHelper.cachedGameList.isEmpty()) {
binding.buttonStart.isEnabled = false
viewLifecycleOwner.lifecycleScope.launch {
withContext(Dispatchers.IO) {
GameHelper.restoreContentForGame(args.game)
}
if (_binding == null) {
return@launch
}
addonViewModel.onAddonsViewStarted(args.game)
binding.buttonStart.isEnabled = true
}
}
reloadList()
homeViewModel.openImportSaves.collect(
@@ -150,11 +133,8 @@ class GamePropertiesFragment : Fragment() {
}
override fun onDestroy() {
val isChangingConfigurations = activity?.isChangingConfigurations == true
super.onDestroy()
if (!isChangingConfigurations) {
gamesViewModel.reloadGames(true)
}
gamesViewModel.reloadGames(true)
}
private fun getPlayTime() {
@@ -100,45 +100,42 @@ class GamesViewModel : ViewModel() {
viewModelScope.launch {
withContext(Dispatchers.IO) {
try {
if (firstStartup) {
// Retrieve list of cached games
val storedGames =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
.getStringSet(GameHelper.KEY_GAMES, emptySet())
if (storedGames!!.isNotEmpty()) {
val deserializedGames = mutableSetOf<Game>()
storedGames.forEach {
val game: Game
try {
game = Json.decodeFromString(it)
} catch (e: Exception) {
// We don't care about any errors related to parsing the game cache
return@forEach
}
val gameExists =
DocumentFile.fromSingleUri(
YuzuApplication.appContext,
Uri.parse(game.path)
)?.exists()
if (gameExists == true) {
deserializedGames.add(game)
}
if (firstStartup) {
// Retrieve list of cached games
val storedGames =
PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
.getStringSet(GameHelper.KEY_GAMES, emptySet())
if (storedGames!!.isNotEmpty()) {
val deserializedGames = mutableSetOf<Game>()
storedGames.forEach {
val game: Game
try {
game = Json.decodeFromString(it)
} catch (e: Exception) {
// We don't care about any errors related to parsing the game cache
return@forEach
}
val gameExists =
DocumentFile.fromSingleUri(
YuzuApplication.appContext,
Uri.parse(game.path)
)?.exists()
if (gameExists == true) {
deserializedGames.add(game)
}
setGames(deserializedGames.toList())
}
setGames(deserializedGames.toList())
}
}
setGames(GameHelper.getGames())
_shouldScrollAfterReload.value = true
setGames(GameHelper.getGames())
reloading.set(false)
_isReloading.value = false
_shouldScrollAfterReload.value = true
if (directoriesChanged) {
setShouldSwapData(true)
}
} finally {
reloading.set(false)
_isReloading.value = false
if (directoriesChanged) {
setShouldSwapData(true)
}
}
}
@@ -23,8 +23,8 @@ object DirectoryInitialization {
fun start() {
if (!areDirectoriesReady) {
initializeInternalStorage()
NativeConfig.initializeGlobalConfig()
NativeLibrary.initializeSystem(false)
NativeConfig.initializeGlobalConfig()
NativeLibrary.reloadProfiles()
migrateSettings()
areDirectoriesReady = true
@@ -8,11 +8,9 @@ package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences
import android.net.Uri
import android.provider.DocumentsContract
import androidx.preference.PreferenceManager
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import java.io.File
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game
@@ -51,8 +49,29 @@ object GameHelper {
// Remove previous filesystem provider information so we can get up to date version info
NativeLibrary.clearFilesystemProvider()
// Scan External Content directories and register all NSP/XCI files
val externalContentDirs = NativeConfig.getExternalContentDirs()
val uniqueExternalContentDirs = linkedSetOf<String>()
externalContentDirs.forEach { externalDir ->
if (externalDir.isNotEmpty()) {
uniqueExternalContentDirs.add(externalDir)
}
}
val mountedContainerUris = mutableSetOf<String>()
mountExternalContentDirectories(mountedContainerUris)
for (externalDir in uniqueExternalContentDirs) {
if (externalDir.isNotEmpty()) {
val externalDirUri = externalDir.toUri()
if (FileUtil.isTreeUriValid(externalDirUri)) {
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
val containerUri = it.uri.toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addFileToFilesystemProvider(containerUri)
}
}
}
}
}
val badDirs = mutableListOf<Int>()
gameDirs.forEachIndexed { index: Int, gameDir: GameDir ->
@@ -96,15 +115,6 @@ object GameHelper {
return games.toList()
}
fun restoreContentForGame(game: Game) {
NativeLibrary.reloadKeys()
val mountedContainerUris = mutableSetOf<String>()
mountExternalContentDirectories(mountedContainerUris)
mountGameFolderContent(Uri.parse(game.path), mountedContainerUris)
NativeLibrary.addFileToFilesystemProvider(game.path)
}
// File extensions considered as external content, buuut should
// be done better imo.
private val externalContentExtensions = setOf("nsp", "xci")
@@ -171,71 +181,6 @@ object GameHelper {
}
}
private fun mountExternalContentDirectories(mountedContainerUris: MutableSet<String>) {
val uniqueExternalContentDirs = linkedSetOf<String>()
NativeConfig.getExternalContentDirs().forEach { externalDir ->
if (externalDir.isNotEmpty()) {
uniqueExternalContentDirs.add(externalDir)
}
}
for (externalDir in uniqueExternalContentDirs) {
val externalDirUri = externalDir.toUri()
if (FileUtil.isTreeUriValid(externalDirUri)) {
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
val containerUri = it.uri.toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addFileToFilesystemProvider(containerUri)
}
}
}
}
}
private fun mountGameFolderContent(gameUri: Uri, mountedContainerUris: MutableSet<String>) {
if (gameUri.scheme == "content") {
val parentUri = getParentDocumentUri(gameUri) ?: return
scanContentContainersRecursive(FileUtil.listFiles(parentUri), 1) {
val containerUri = it.uri.toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(containerUri)
}
}
return
}
val gameFile = File(gameUri.path ?: gameUri.toString())
val parentDir = gameFile.parentFile ?: return
parentDir.listFiles()?.forEach { sibling ->
if (!sibling.isFile) {
return@forEach
}
val extension = sibling.extension.lowercase()
if (externalContentExtensions.contains(extension)) {
val containerUri = Uri.fromFile(sibling).toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(containerUri)
}
}
}
}
private fun getParentDocumentUri(uri: Uri): Uri? {
return try {
val documentId = DocumentsContract.getDocumentId(uri)
val separatorIndex = documentId.lastIndexOf('/')
if (separatorIndex == -1) {
null
} else {
val parentDocumentId = documentId.substring(0, separatorIndex)
DocumentsContract.buildDocumentUriUsingTree(uri, parentDocumentId)
}
} catch (_: Exception) {
null
}
}
fun getGame(
uri: Uri,
addedToLibrary: Boolean,
@@ -473,6 +473,8 @@
<string name="renderer_accuracy_description">يتحكم في وضع محاكاة وحدة معالجة الرسومات. تعمل معظم الألعاب بشكل جيد مع وضعي سريع أو متوازن، لكن الوضع الدقيق لا يزال مطلوبًا لبعض الألعاب. تميل الجسيمات إلى العرض بشكل صحيح فقط عند استخدام الوضع الدقيق.</string>
<string name="dma_accuracy">دقة DMA</string>
<string name="dma_accuracy_description">يتحكم في دقة DMA. يمكن أن تؤدي الدقة الآمنة إلى حل المشكلات في بعض الألعاب، ولكنها قد تؤثر أيضًا على الأداء في بعض الحالات. إذا لم تكن متأكدًا، فاترك هذا الخيار على الإعداد الافتراضي.</string>
<string name="frame_pacing_mode">وضع توقيت الإطارات</string>
<string name="frame_pacing_mode_description">يتحكم في كيفية إدارة المحاكي لسرعة الإطارات لتقليل التقطع وجعل معدل الإطارات أكثر سلاسة واتساقًا.</string>
<string name="anisotropic_filtering">تصفية متباينة الخواص</string>
<string name="anisotropic_filtering_description">يحسن جودة الأنسجة عند عرضها بزوايا مائلة</string>
<string name="vram_usage_mode">وضع استخدام ذاكرة VRAM</string>
@@ -997,6 +999,13 @@
<string name="dma_accuracy_unsafe">غير آمن</string>
<string name="dma_accuracy_safe">آمن</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">تلقائي</string>
<string name="frame_pacing_mode_target_30">30 إطارًا في الثانية</string>
<string name="frame_pacing_mode_target_60">60 إطارًا في الثانية</string>
<string name="frame_pacing_mode_target_90">90 إطارًا في الثانية</string>
<string name="frame_pacing_mode_target_120">120 إطارًا في الثانية</string>
<!-- ASTC Recompression Method Choices -->
<string name="astc_recompression_uncompressed">غير مضغوط</string>
<!-- ASTC Recompression Method Choices -->
@@ -1066,8 +1075,6 @@
<string name="theme_material_you">ألوان ديناميكية</string>
<string name="app_settings">إعدادات التطبيق</string>
<string name="theme_and_color">السمة واللون</string>
<string name="fullscreen_mode">وضع ملء الشاشة</string>
<string name="fullscreen_mode_description">إخفاء أشرطة نظام Android عبر شاشات التطبيق. اسحب من أحد الحواف لإظهارها مؤقتًا.</string>
<!-- Theme Modes -->
<string name="change_theme_mode">تغيير وضع السمة</string>
@@ -1098,7 +1105,7 @@
<string name="blue">أزرق</string>
<string name="cyan">سماوي</string>
<string name="red">أحمر</string>
<string name="green">أخضر</string>
<string name="green">أخضر (افتراضي)</string>
<string name="yellow">أصفر</string>
<string name="orange">برتقالي</string>
<string name="pink">وردي</string>
@@ -452,6 +452,8 @@
<string name="renderer_accuracy_description">Určuje režim emulovaného GPU. Většina her běží bez problémů v rychlém, nebo vyváženém režimu, ale některé stále vyžadují přesný režim. Částicové efekty se většinou zobrazují korektně pouze v přesném režimu. </string>
<string name="dma_accuracy">Přesnost DMA</string>
<string name="dma_accuracy_description">Ovládá přesnost DMA. Bezpečná přesnost může vyřešit problémy v některých hrách, ale v některých případech může také ovlivnit výkon. Pokud si nejste jisti, použijte výchozí nastavení.</string>
<string name="frame_pacing_mode">Režim Framepacingu</string>
<string name="frame_pacing_mode_description">Řídí způsob jakým emulátor spravuje časování snímku aby snížil trhání a zlepšení plynulost a stabilitu snímkové frekvence.</string>
<string name="anisotropic_filtering">Anizotropní filtrování</string>
<string name="anisotropic_filtering_description">Zlepšuje kvalitu textur při pohledu pod úhlem</string>
<string name="vram_usage_mode">Režim využití VRAM</string>
@@ -1004,6 +1004,7 @@ Wirklich fortfahren?</string>
<string name="theme_material_you">Material You</string>
<string name="app_settings">App-Einstellungen</string>
<string name="theme_and_color">Theme und Farben</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Design</string>
<string name="theme_mode_follow_system">System folgen</string>
@@ -302,7 +302,7 @@
<string name="manage_save_data">Administrar datos de guardado</string>
<string name="manage_save_data_description">Guardar los datos encontrados. Por favor, seleccione una opción de abajo.</string>
<string name="import_save_warning">Importar datos de guardado</string>
<string name="import_save_warning_description">Esto sobreescribirá todos los datos de guardado existentes con el archivo proporcionado. ¿Está seguro de querer continuar\?</string>
<string name="import_save_warning_description">Ésto sobreescribirá todos los datos de guardado existentes con el archivo proporcionado. ¿Está seguro de querer continuar?</string>
<string name="save_files_importing">Importando archivos de guardado...</string>
<string name="save_files_exporting">Exportando archivos de guardado...</string>
<string name="save_file_imported_success">Importado correctamente</string>
@@ -333,8 +333,8 @@
<string name="install_game_content_help_link">https://yuzu-mirror.github.io/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">Controladores personalizados no soportados</string>
<string name="custom_driver_not_supported_description">La carga de controladores personalizados no está disponible para este dispositivo.\n¡Compruebe más adelante si se añadió el soporte a esta opción!</string>
<string name="manage_yuzu_data">Gestionar datos de Eden</string>
<string name="manage_yuzu_data_description">Importar/exportar el firmware, las claves, los datos de usuario, ¡y más!</string>
<string name="manage_yuzu_data">Administrar datos de Eden</string>
<string name="manage_yuzu_data_description">Importa/exporta el firmware, las claves, los datos de usuario, ¡y más!</string>
<string name="game_folders">Carpetas de juegos</string>
<string name="deep_scan">Escaneo recursivo </string>
<string name="add_game_folder">Añadir carpeta con juegos</string>
@@ -350,8 +350,8 @@
<item quantity="many">%d archivos de guardado importados con éxito.</item>
<item quantity="other">%d archivos de guardado importados con éxito.</item>
</plurals>
<string name="no_save_data_found">No se encontraron datos de guardado</string>
<string name="verify_installed_content">Verificar contenido instalado</string>
<string name="no_save_data_found">No hay archivos de guardado</string>
<string name="verify_installed_content">Verificar contenidos instalados</string>
<string name="verify_installed_content_description">Comprueba todo el contenido instalado por si hubiese alguno corrupto</string>
<string name="keys_missing">Faltan las claves de encriptación</string>
@@ -467,6 +467,8 @@
<string name="renderer_accuracy_description">Controla el modo de la emulación de la GPU. La mayoría de los juegos se renderizan correctamente en los modos Rápido o Equilibrado, pero algunos requieren Preciso. Las partículas tienden a renderizarse correctamente solo con el modo Preciso.</string>
<string name="dma_accuracy">Precisión de DMA</string>
<string name="dma_accuracy_description">Controla la precisión de DMA. La precisión segura puede solucionar problemas en algunos juegos, pero también puede afectar al rendimiento en algunos casos. Si no está seguro, déjelo en Predeterminado.</string>
<string name="frame_pacing_mode">Modo de ritmo de fotogramas</string>
<string name="frame_pacing_mode_description">Controla cómo el emulador gestiona el ritmo de los fotogramas para reducir los tirones y hacer que la velocidad de los fotogramas sea más suave y consistente.</string>
<string name="anisotropic_filtering">Filtrado anisotrópico</string>
<string name="anisotropic_filtering_description">Mejora la calidad de las texturas al ser observadas desde ángulos oblicuos</string>
<string name="vram_usage_mode">Modo de uso de VRAM</string>
@@ -768,7 +770,7 @@
<string name="developer">Desarrollador</string>
<string name="version">Versión</string>
<string name="copy_details">Copiar detalles</string>
<string name="add_ons">Complementos</string>
<string name="add_ons">Extras/Add-ons</string>
<string name="add_ons_description">Activa/desactiva mods, actualizaciones y contenidos descargables</string>
<string name="playtime">Tiempo jugado:</string>
<string name="reset_playtime">Borrar tiempo de juego</string>
@@ -791,28 +793,28 @@
<string name="cleared_shaders_successfully">Sombreadores limpiados con éxito</string>
<string name="driver_shader_wipe_dialog_title">Sombreadores limpiados</string>
<string name="driver_shader_wipe_dialog_message">Eden ha limpiado automáticamente todos los sombreadores guardados para mantener la canalización de Vulkan válida. Esto es esencial al cambiar o actualizar los controladores de la GPU para prevenir errores y fallos gráficos. Es posible que experimente algunas interrupciones durante la reconstrucción de los sombreadores.</string>
<string name="addons_game">Complementos: %1$s</string>
<string name="addons_game">Addons: %1$s</string>
<string name="save_data">Datos de guardado</string>
<string name="save_data_description">Gestiona los datos de guardado de este juego</string>
<string name="save_data_description">Controla los datos de guardado de este juego</string>
<string name="delete_save_data">Borrar datos de guardado</string>
<string name="delete_save_data_description">Elimina todos los datos de guardado especificos de este juego</string>
<string name="delete_save_data_warning_description">Esto elimina de manera permanente todos los datos de guardado de este juego. ¿Está seguro de que quiere continuar\?</string>
<string name="delete_save_data_description">Elimina todos los datos de guardado de este juego</string>
<string name="delete_save_data_warning_description">Ésto elimina de manera permanente todos los datos de guardado de este juego. ¿Seguro que quieres continuar?</string>
<string name="save_data_deleted_successfully">Datos de guardado eliminados con éxito</string>
<string name="select_content_type">Tipo de contenido</string>
<string name="updates_and_dlc">Actualizaciones y contenido descargable</string>
<string name="mods_and_cheats">Mods y trucos</string>
<string name="addon_notice">Aviso importante de complementos</string>
<string name="addon_notice">Aviso importante de addons</string>
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
<string name="addon_notice_description">Para instalar mods y trucos, debe seleccionar una carpeta que contenga los directorios cheats/, romfs/, o exefs/ . ¡No podemos confirmar si éstos serán compatibles con su juego, así que tenga cuidado!</string>
<string name="invalid_directory">Directorio no válido</string>
<!-- \"cheats/" "romfs/" and \"exefs/ should not be translated -->
<string name="invalid_directory_description">Por favor, asegúrese de que el directorio que ha selecionado incluye las carpetas cheats/, romfs/, o exefs/ e inténtelo de nuevo.</string>
<string name="addon_installed_successfully">Complemento instalado con éxito</string>
<string name="addon_installed_successfully">Addon instalado con éxito</string>
<string name="verifying_content">Verificando contenido...</string>
<string name="content_install_notice">Aviso importante de contenido</string>
<string name="content_install_notice_description">El contenido seleccionado no es de este juego.\n¿Instalar aun que\?</string>
<string name="confirm_uninstall">Confirmar desinstalación</string>
<string name="confirm_uninstall_description">¿Está seguro de que quiere desinstalar este complemento\?</string>
<string name="confirm_uninstall_description">¿De verdad quieres desinstalar este addon?</string>
<string name="verify_integrity">Verificar integridad</string>
<string name="verifying">Verificando...</string>
<string name="verify_success">¡La verificación de integridad ha sido un éxito!</string>
@@ -828,14 +830,14 @@
<!-- ROM loading errors -->
<string name="loader_error_encrypted">Su ROM está encriptada</string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Siga las guías para volver a volcar sus <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-physical-titles-game-cards\">tarjetas de juego</a> o <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-digital-titles-eshop\">títulos instalados</a>.]]></string>
<string name="loader_error_encrypted_keys_description"><![CDATA[Por favor, compruebe que su archivo <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> está instalado, para que los juegos sean desencriptados.]]></string>
<string name="loader_error_encrypted_roms_description"><![CDATA[Siga las guías para volver a volcar sus <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-physical-titles-game-cards\">tarjetas de juego</a> o <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-digital-titles-eshop\">títulos digitales</a>.]]></string>
<string name="loader_error_encrypted_keys_description"><![CDATA[Por favor, compruebe que su archivo <a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> está instalado, para que los juegos sean descifrados.]]></string>
<string name="loader_error_video_core">Ocurrió un error al inicializar el núcleo de video, posiblemente debido a una incompatibilidad con el driver seleccionado</string>
<string name="loader_error_video_core_description">Esto suele deberse a un controlador de la GPU incompatible. La instalación de un controlador de la GPU personalizado puede resolver este problema.</string>
<string name="loader_error_file_not_found">Archivo ROM no existe</string>
<string name="loader_requires_firmware">El juego requiere firmware</string>
<string name="loader_requires_firmware_description"><![CDATA[El juego que intenta iniciar requiere el firmware para arrancar o pasar el menú de inicio. Por favor <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> vuelque e instale el firmware</a>, o pulse \"Aceptar\" para continuar de todos modos.]]></string>
<string name="loader_requires_firmware_description"><![CDATA[El juego que intentas iniciar requiere firmware para arrancar o pasar el menú de inicio. Por favor <a href=\"https://yuzu-mirror.github.io/help/quickstart\"> vuelca e instala el firmware</a>, o pulsa \"Aceptar\" para continuar de todos modos.]]></string>
<!-- Intent Launch strings -->
<string name="searching_for_game">Buscando juego...</string>
@@ -991,6 +993,13 @@
<string name="dma_accuracy_unsafe">Inseguro</string>
<string name="dma_accuracy_safe">Seguro</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">Automático</string>
<string name="frame_pacing_mode_target_30">30 FPS</string>
<string name="frame_pacing_mode_target_60">60 FPS</string>
<string name="frame_pacing_mode_target_90">90 FPS</string>
<string name="frame_pacing_mode_target_120">120 FPS</string>
<!-- ASTC Recompression Method Choices -->
<string name="astc_recompression_uncompressed">Sin compresión</string>
<!-- ASTC Recompression Method Choices -->
@@ -1060,8 +1069,6 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Configuración de la aplicación</string>
<string name="theme_and_color">Tema y color</string>
<string name="fullscreen_mode">Modo pantalla completa</string>
<string name="fullscreen_mode_description">Ocultar las barras del sistema de Android. Desliza la pantalla desde una esquina para mostrarlas temporalmente.</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Cambiar modo del tema</string>
@@ -1092,7 +1099,7 @@
<string name="blue">Azul</string>
<string name="cyan">Cian</string>
<string name="red">Rojo</string>
<string name="green">Verde</string>
<string name="green">Verde (Predeterminado)</string>
<string name="yellow">Amarillo</string>
<string name="orange">Naranja</string>
<string name="pink">Rosa</string>
@@ -1121,7 +1128,7 @@
<string name="airplane_mode">Modo avión</string>
<string name="airplane_mode_description">Pasa el modo avión al sistema operativo Switch</string>
<string name="enable_overlay">Habilitar el applet de superposición</string>
<string name="enable_overlay">Habilitar el Applet de superposición</string>
<string name="enable_overlay_description">Activa el applet integrado superpuesto de Horizon. Mantenga pulsado el botón de inicio durante 1 segundo para que aparezca.</string>
<!-- Profile Management -->
@@ -275,11 +275,8 @@
<string name="cpu_info">Informations sur le processeur central</string>
<string name="gpu_information">Informations sur le processeur graphique</string>
<string name="vulkan_driver_version">Version du pilote Vulkan</string>
<string name="error_getting_emulator_info">Impossible dobtenir les infos de l’émulateur</string>
<string name="memory_info">Informations sur la mémoire</string>
<string name="total_memory">Capacité totale de mémoire</string>
<string name="soc">SOC:</string>
<string name="warning_help">Aide</string>
<string name="warning">Avertissement</string>
<string name="warning_skip">Sauter</string>
@@ -317,9 +314,6 @@
<string name="share_log">Partager les logs de débogage</string>
<string name="share_log_description">Partagez le fichier de log de Eden pour déboguer les problèmes.</string>
<string name="share_log_missing">Aucun fichier de log trouvé</string>
<string name="share_gpu_log">Partager les logs du GPU</string>
<string name="share_gpu_log_description">Partage les logs du GPU générés par Eden afin de déboguer les problèmes graphiques.</string>
<string name="share_gpu_log_missing">Aucun fichier de log du GPU trouvé,</string>
<string name="install_game_content">Installer le contenu du jeu</string>
<string name="install_game_content_description">Installer une mise à jour ou un DLC</string>
<string name="installing_game_content">Installation du contenu en cours...</string>
@@ -375,9 +369,7 @@
<string name="qlaunch_description">Lancer des applications depuis l\'écran d\'accueil du système</string>
<string name="applets">Lanceur d\'applets</string>
<string name="applets_description">Lancer des applets système en utilisant le firmware installé</string>
<string name="applets_error_firmware">Aucun firmware installé</string>
<string name="applets_error_applet">Applet non disponible</string>
<string name="applets_error_description"><![CDATA[Veuillez vérifier que votre fichier<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a> et le<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware\">firmware</a>sont installés et réessayez.]]></string>
<string name="album_applet">Album</string>
<string name="album_applet_description">Afficher les images stockées dans le dossier de captures d\'écran de l\'utilisateur avec le visualiseur de photos système.</string>
<string name="mii_edit_applet">Éditeur Mii</string>
@@ -395,7 +387,6 @@
<string name="copied_to_clipboard">Copié dans le presse-papier</string>
<string name="about_app_description">Un émulateur Switch open source</string>
<string name="contributors">Contributeurs</string>
<string name="contributors_description">Les gens qui ont rendu possible Eden pour Android</string>
<string name="licenses_description">Des projets qui rendent possible Eden pour Android</string>
<string name="build">Build</string>
<string name="user_data">Données utilisateur</string>
@@ -412,8 +403,6 @@
<string name="frame_limit_enable_description">Limiter la vitesse d\'émulation à un pourcentage spécifié de la vitesse normale</string>
<string name="frame_limit_slider">Limiter le pourcentage de vitesse</string>
<string name="frame_limit_slider_description">Spécifier le pourcentage pour limiter la vitesse d\'émulation. 100% correspond à la vitesse normale. Des valeurs plus élevées ou plus basses augmenteront ou diminueront la limite de vitesse.</string>
<string name="turbo_speed_limit">Vitesse turbo</string>
<string name="slow_speed_limit">Vitesse lente</string>
<string name="cpu_backend">Backend du CPU</string>
<string name="cpu_accuracy">Précision du CPU</string>
<string name="value_with_units">%1$s%2$s</string>
@@ -430,9 +419,6 @@
<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>
<!-- CPU -->
<string name="fast_cpu_time">Overclock du CPU</string>
<string name="fast_cpu_time_description">Force le CPU émulé à fonctionner à une fréquence plus élevée, en contournant certaines limitations de FPS. Utilisez Boost (1700MHz) pour atteindre la fréquence native maximale de la Nintendo Switch, ou Fast (2000MHz) pour doubler la fréquence. Cest un “hack”. Certains chipsets moins puissants peuvent voir leurs performances réduites et les jeux peuvent se comporter différemment.</string>
<string name="custom_cpu_ticks">Ticks CPU personnalisés</string>
<string name="custom_cpu_ticks_description">Définissez une valeur personnalisée de ticks CPU. Des valeurs plus élevées peuvent améliorer les performances, mais peuvent aussi provoquer des gels du jeu. Une plage de 77 à 21000 est recommandée.</string>
<string name="cpu_ticks">Ticks</string>
@@ -911,6 +897,7 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Paramètres de lApp</string>
<string name="theme_and_color">Thème et Couleur</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Changer le mode de thème</string>
<string name="theme_mode_follow_system">Automatique</string>
@@ -844,6 +844,7 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Impostazioni app</string>
<string name="theme_and_color">Tema e colore</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Cambia la modalità del tema</string>
<string name="theme_mode_follow_system">Segue il Sistema</string>
@@ -960,6 +960,7 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Ustawienia aplikacji</string>
<string name="theme_and_color">Motyw i kolor</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Zmień tryb motywu</string>
<string name="theme_mode_follow_system">Podążaj za systemowym</string>
@@ -905,6 +905,7 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Configurações do App</string>
<string name="theme_and_color">Tema e Cores</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Alterar o tema</string>
<string name="theme_mode_follow_system">Igual ao Sistema</string>
@@ -352,7 +352,7 @@
<item quantity="many">Импортировано %d сохранений</item>
<item quantity="other">Импортировано %d сохранений</item>
</plurals>
<string name="no_save_data_found">Файлы сохранений не найдены</string>
<string name="no_save_data_found">Не найдены сохраненмия</string>
<string name="verify_installed_content">Подтвердить установленный контент</string>
<string name="verify_installed_content_description">Проверяет весь установленный контент на наличие повреждений</string>
@@ -361,7 +361,7 @@
<string name="keys_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys</string>
<string name="uninstall_firmware">Удалить прошивку</string>
<string name="uninstall_firmware_description">Удаление прошивки сотрёт её с устройства и может повлиять на совместимость игр.</string>
<string name="uninstall_firmware_description">Удаление прошивки сотрет ее с устройства и может повлиять на совместимость игр.</string>
<string name="firmware_uninstalling">Удаление прошивки...</string>
<string name="firmware_uninstalled_success">Прошивка успешно удалена</string>
@@ -397,7 +397,6 @@
<string name="copied_to_clipboard">Скопировано в буфер обмена</string>
<string name="about_app_description">Эмулятор Switch с открытым исходным кодом</string>
<string name="contributors">Контрибьюторы</string>
<string name="contributors_description">Люди, благодаря которым появился Eden для Android</string>
<string name="licenses_description">Проекты, которые сделали Eden для Android возможным</string>
<string name="build">Сборка</string>
<string name="user_data">Данные пользователя</string>
@@ -469,6 +468,8 @@
<string name="renderer_accuracy_description">Управляет режимом эмуляции графического процессора. Большинство игр нормально отображаются в режимах «Быстрый» или «Сбалансированный», но для некоторых требуется режим «Точный». Частицы обычно корректно отображаются только в режиме «Точный».</string>
<string name="dma_accuracy">Точность DMA</string>
<string name="dma_accuracy_description">Управляет точностью DMA. Безопасная точность может исправить проблемы в некоторых играх, но в некоторых случаях также может повлиять на производительность. Если не уверены, оставьте значение По умолчанию.</string>
<string name="frame_pacing_mode">Режим синхронизации кадров</string>
<string name="frame_pacing_mode_description">Управляет синхронизацией кадров в эмуляторе для уменьшения рывков и обеспечения более плавной и стабильной частоты кадров.</string>
<string name="anisotropic_filtering">Анизотропная фильтрация</string>
<string name="anisotropic_filtering_description">Улучшает качество текстур под углом</string>
<string name="vram_usage_mode">Режим VRAM</string>
@@ -482,7 +483,7 @@
<string name="sync_memory_operations_description">Обеспечивает согласованность данных между вычислительными операциями и операциями с памятью. Эта опция должна исправлять проблемы в некоторых играх, но может снижать производительность в некоторых случаях. Наиболее сильно это затрагивает игры на Unreal Engine 4.</string>
<string name="use_disk_shader_cache">Кэш шейдеров на диске</string>
<string name="use_disk_shader_cache_description">Уменьшение зависаний за счет хранения и загрузки сгенерированных шейдеров.</string>
<string name="renderer_force_max_clock">Принудительная максимальная тактовая частота (только для Adreno)</string>
<string name="renderer_force_max_clock">Принудительно заставить максимальную тактовую частоту (только для Adreno)</string>
<string name="renderer_force_max_clock_description">Заставляет ГПУ работать на максимально возможных тактовых частотах (тепловые ограничения все равно будут применяться).</string>
<string name="renderer_reactive_flushing">Реактивная очистка</string>
<string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string>
@@ -993,6 +994,13 @@
<string name="dma_accuracy_unsafe">Небезопасно</string>
<string name="dma_accuracy_safe">Безопасный</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">Авто</string>
<string name="frame_pacing_mode_target_30">30 FPS</string>
<string name="frame_pacing_mode_target_60">60 FPS</string>
<string name="frame_pacing_mode_target_90">90 FPS</string>
<string name="frame_pacing_mode_target_120">120 FPS</string>
<!-- ASTC Recompression Method Choices -->
<string name="astc_recompression_uncompressed">Без сжатия</string>
<!-- ASTC Recompression Method Choices -->
@@ -1062,8 +1070,6 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Настройки приложения</string>
<string name="theme_and_color">Тема и цвет</string>
<string name="fullscreen_mode">Полноэкранный режим</string>
<string name="fullscreen_mode_description">Скрывать системные панели Android на всех экранах приложения. Проведите от края экрана, чтобы временно отобразить их</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Сменить режим темы</string>
@@ -1093,7 +1099,7 @@
<string name="blue">Синий</string>
<string name="cyan">Циановый</string>
<string name="red">Красный</string>
<string name="green">Зелёный</string>
<string name="green">Зелёный (По умолчанию)</string>
<string name="yellow">Жёлтый</string>
<string name="orange">Оранжевый</string>
<string name="pink">Розовый</string>
@@ -1119,8 +1125,8 @@
<string name="swkbd_applet">Программная клавиатура</string>
<string name="airplane_mode">Режим полёта</string>
<string name="airplane_mode_description">Передаёт режим полёта в ОС Switch</string>
<string name="airplane_mode">Режим полета</string>
<string name="airplane_mode_description">Передает режим полета в ОС Switch</string>
<string name="enable_overlay">Включить апплет-оверлей</string>
<string name="enable_overlay_description">Активирует встроенный в Horizon оверлейный апплет. Для его отображения нажмите и удерживайте кнопку «HOME» в течение одной секунды.</string>
@@ -12,7 +12,7 @@
<!-- Spinbox strings -->
<string name="increment">Збільшення</string>
<string name="decrement">Зменшення</string>
<string name="value_too_low">Значення повинно бути не менше %1$d</string>
<string name="value_too_low">Значення повинно бути щонайменше %1$d</string>
<string name="value_too_high">Значення повинно бути не більше %1$d</string>
<string name="invalid_value">Неправильне значення</string>
@@ -469,6 +469,8 @@
<string name="renderer_accuracy_description">Керує режимом емуляції ГП. Більшість ігор добре візуалізуються з режимами «Швидко» або «Збалансовано», але деякі ігри можуть потребувати режиму «Точно». Частинки зазвичай правильно візуалізуються лише з режимом «Точно».</string>
<string name="dma_accuracy">Точність DMA</string>
<string name="dma_accuracy_description">Керує точністю DMA. Безпечна точність може виправити проблеми в деяких іграх, але в деяких випадках також може вплинути на продуктивність. Якщо не впевнені, залиште це значення за замовчуванням.</string>
<string name="frame_pacing_mode">Режим виведення кадрів</string>
<string name="frame_pacing_mode_description">Керує тим, як емулятор виконує виведення кадрів, щоб зменшити затримки й забезпечити плавнішу й стабільнішу частоту кадрів.</string>
<string name="anisotropic_filtering">Анізотропне фільтрування</string>
<string name="anisotropic_filtering_description">Покращує якість текстур під кутом.</string>
<string name="vram_usage_mode">Режим використання VRAM</string>
@@ -993,6 +995,13 @@
<string name="dma_accuracy_unsafe">Небезпечно</string>
<string name="dma_accuracy_safe">Безпечно</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">Автоматично</string>
<string name="frame_pacing_mode_target_30">30 к/с</string>
<string name="frame_pacing_mode_target_60">60 к/с</string>
<string name="frame_pacing_mode_target_90">90 к/с</string>
<string name="frame_pacing_mode_target_120">120 к/с</string>
<!-- ASTC Recompression Method Choices -->
<string name="astc_recompression_uncompressed">Без стиснення</string>
<!-- ASTC Recompression Method Choices -->
@@ -1062,8 +1071,6 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Налаштування застосунку</string>
<string name="theme_and_color">Тема і колір</string>
<string name="fullscreen_mode">Повноекранний режим</string>
<string name="fullscreen_mode_description">Приховати системні панелі Android у застосунку. Проведіть пальцем від краю екрана, щоб показати їх на короткий час.</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Змінити режим теми</string>
@@ -1094,7 +1101,7 @@
<string name="blue">Синій</string>
<string name="cyan">Блакитний</string>
<string name="red">Червоний</string>
<string name="green">Зелений</string>
<string name="green">Зелений (стандартний)</string>
<string name="yellow">Жовтий</string>
<string name="orange">Помаранчевий</string>
<string name="pink">Рожевий</string>
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">软件可以运行Nintendo Switch游戏机的游戏,但身并不包含任何游戏或密钥。<br /><br />请于开始之前选定位于你的设备存储空间中的<![CDATA[<b>prod.keys</b>]]><br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">了解更多</a>]]></string>
<string name="notice_notification_channel_name">错误与注意事项</string>
<string name="app_disclaimer">软件可以运行Nintendo Switch游戏机的游戏,但身并不自带任何游戏或密钥。<br /><br />开始之前,请先选择<![CDATA[<b>密钥文件(prod.keys</b>]]><br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">详情</a>]]></string>
<string name="notice_notification_channel_name">通知及错误提醒</string>
<string name="notice_notification_channel_description">当发生错误时显示通知。</string>
<string name="notification_permission_not_granted">未授予通知权限!</string>
<string name="app_notification_channel_description">Eden模拟器通知</string>
@@ -12,36 +12,36 @@
<!-- Spinbox strings -->
<string name="increment">增加</string>
<string name="decrement">减少</string>
<string name="value_too_low">此值至少应为 %1$d</string>
<string name="value_too_high">此值至多应为 %1$d</string>
<string name="value_too_low">值必须最小为 %1$d</string>
<string name="value_too_high">值最大必须为 %1$d</string>
<string name="invalid_value">无效的值</string>
<string name="using_per_game_config">使用各别游戏配置</string>
<string name="using_per_game_config">使用针对特定游戏配置</string>
<!-- Input Overlay -->
<string name="show_input_overlay">显示输入叠加层</string>
<string name="show_input_overlay_description">游戏模拟期间显示触控叠加层</string>
<string name="overlay_snap_to_grid">对齐到网格</string>
<string name="overlay_snap_to_grid_description">编辑时将叠加控件对齐到网格</string>
<string name="overlay_grid_size">网格尺寸</string>
<string name="overlay_grid_size_description">网格单元像素单位尺寸</string>
<string name="input_overlay_behavior">行为</string>
<string name="overlay_auto_hide">触控叠加层自动隐藏</string>
<string name="overlay_auto_hide_description">在指定时间内未进行任何操作后,自动隐藏触控叠加层。</string>
<string name="enable_input_overlay_auto_hide">启用触控叠加层自动隐藏</string>
<string name="hide_overlay_on_controller_input">使用控制器时隐藏触控叠加层</string>
<string name="hide_overlay_on_controller_input_description">在使用实体控制器自动隐藏触控叠加层,而当控制器断开时触控叠加层则会重新显现。</string>
<string name="invert_confirm_back_controller_buttons">切换“确认/返回”控制器按钮功能</string>
<string name="invert_confirm_back_controller_buttons_description">与本应用界面交互时,交换 Android 的“确认”与“返回按钮的处理方式,以匹配 Switch 和 Xbox 的风格</string>
<string name="show_input_overlay">虚拟按键输入</string>
<string name="show_input_overlay_description">模拟过程中显示触摸控制覆盖</string>
<string name="overlay_snap_to_grid">截图到网格</string>
<string name="overlay_snap_to_grid_description">编辑时将叠加控件吸附到网格</string>
<string name="overlay_grid_size">网格大小</string>
<string name="overlay_grid_size_description">网格单元的大小(以像素单位</string>
<string name="input_overlay_behavior">平衡</string>
<string name="overlay_auto_hide">自动隐藏虚拟按键</string>
<string name="overlay_auto_hide_description">在指定时间间隔后自动隐藏触摸控制覆盖层。</string>
<string name="enable_input_overlay_auto_hide">开启自动隐藏虚拟按键</string>
<string name="hide_overlay_on_controller_input">使用控制器时自动隐藏虚拟输入</string>
<string name="hide_overlay_on_controller_input_description">在使用控制器自动隐藏虚拟输入,当控制器断开会自动再现。</string>
<string name="invert_confirm_back_controller_buttons">反转 确认/返回 手柄按钮</string>
<string name="invert_confirm_back_controller_buttons_description">使用应用界面时,将安卓确认和返回按钮的作切换到 Switch 和 Xbox 的样式</string>
<string name="input_overlay_options">输入叠加层</string>
<string name="input_overlay_options_description">配置屏上控件</string>
<string name="edit_overlay_layout">编辑触控叠加层布局</string>
<string name="edit_overlay_layout_description">调整屏控件的的位置和大小</string>
<string name="input_overlay_options">虚拟按键输入</string>
<string name="input_overlay_options_description">配置虚拟按键</string>
<string name="edit_overlay_layout">编辑虚拟按键</string>
<string name="edit_overlay_layout_description">调整屏控件的的位置和大小</string>
<!-- Stats Overlay settings -->
<string name="process_ram">进程内存占用: %1$d MB</string>
<string name="process_ram">进程内存: %1$d MB</string>
<string name="shaders_prefix">正在编译</string>
<string name="shaders_suffix">着色器</string>
<string name="charging">(充电中)</string>
@@ -51,31 +51,31 @@
<string name="stats_overlay_customization">自定义</string>
<string name="stats_overlay_items">显示项</string>
<string name="stats_overlay_options">悬浮窗</string>
<string name="enable_stats_overlay_">启用性能统计叠加层</string>
<string name="stats_overlay_options_description">配置性能统计叠加层中显示的信息</string>
<string name="enable_stats_overlay_">启用性能统计悬浮窗</string>
<string name="stats_overlay_options_description">配置悬浮窗中显示的性能信息</string>
<string name="show_fps">显示帧率</string>
<string name="show_fps_description">显示当前帧率</string>
<string name="show_fps_description">显示当前帧率(FPS)</string>
<string name="show_frametime">显示帧时间</string>
<string name="show_app_ram_usage">显示应用内存使用情况</string>
<string name="show_app_ram_usage_description">显示模拟器内存</string>
<string name="show_system_ram_usage">显示系统内存使用情况</string>
<string name="show_system_ram_usage_description">显示系统内存</string>
<string name="show_app_ram_usage">显示应用内存占用</string>
<string name="show_app_ram_usage_description">显示模拟器正在使用的内存量</string>
<string name="show_system_ram_usage">显示系统内存占用</string>
<string name="show_system_ram_usage_description">显示系统使用的内存量</string>
<string name="show_bat_temperature">显示电池温度</string>
<string name="bat_temperature_unit">电池温度单位</string>
<string name="show_power_info">显示电池信息</string>
<string name="show_power_info_description">显示当前功耗和电池剩余容量</string>
<string name="show_shaders_building">显示着色器编译信息</string>
<string name="show_shaders_building_description">显示当前正在编译的着色器数量</string>
<string name="overlay_position">叠加层位置</string>
<string name="overlay_position_description">选择叠加层在屏幕上显示位置</string>
<string name="show_shaders_building">显示着色器构建</string>
<string name="show_shaders_building_description">显示当前正在构建的着色器数量</string>
<string name="overlay_position">悬浮窗位置</string>
<string name="overlay_position_description">选择悬浮窗在屏幕上显示位置</string>
<string name="overlay_position_top_left">左上</string>
<string name="overlay_position_top_right">右上</string>
<string name="overlay_position_bottom_left">左下</string>
<string name="overlay_position_bottom_right">右下</string>
<string name="overlay_position_center_top">顶部居中</string>
<string name="overlay_position_center_bottom">底部居中</string>
<string name="perf_overlay_background">叠加层背景</string>
<string name="perf_overlay_background_description">叠加层添加背景以提高可读性</string>
<string name="perf_overlay_background">悬浮窗背景</string>
<string name="perf_overlay_background_description">悬浮窗添加背景以提高可读性</string>
<!-- Device Overlay settings -->
<string name="show_soc_overlay">显示设备信息叠加层</string>
@@ -391,7 +391,6 @@
<string name="copied_to_clipboard">已复制到剪贴板</string>
<string name="about_app_description">一款开源的 Switch 模拟器</string>
<string name="contributors">贡献者</string>
<string name="contributors_description">Eden Android 版的诞生离不开这些人的支持</string>
<string name="licenses_description">Android 版 Eden 离不开这些项目的支持</string>
<string name="build">构建版本</string>
<string name="user_data">用户数据</string>
@@ -463,6 +462,8 @@
<string name="renderer_accuracy_description">控制 GPU 模拟的精确度。大部分游戏在性能或平衡模式下可以正常渲染,但部分游戏需要设置为精确。粒子效果通常只有在精确模式下才能正确显示。</string>
<string name="dma_accuracy">DMA 精度</string>
<string name="dma_accuracy_description">控制 DMA 精度。安全精度可以修复某些游戏中的问题,但在某些情况下也可能影响性能。如果不确定,请保留为“默认”。</string>
<string name="frame_pacing_mode">帧同步模式</string>
<string name="frame_pacing_mode_description">控制模拟器如何管理帧同步,以减少卡顿,使帧率表现更加平稳顺滑。</string>
<string name="anisotropic_filtering">各向异性过滤</string>
<string name="anisotropic_filtering_description">提高斜角的纹理质量</string>
<string name="vram_usage_mode">显存使用模式</string>
@@ -629,7 +630,7 @@
<string name="toggle_axis">切换轴</string>
<string name="connected">已连接</string>
<string name="use_system_vibrator">使用系统马达</string>
<string name="input_overlay">输入叠加层</string>
<string name="input_overlay">虚拟按键输入</string>
<string name="vibration">震动</string>
<string name="vibration_strength">震动强度</string>
<string name="profile">用户配置</string>
@@ -877,19 +878,19 @@
<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_adjust">调整虚拟按键</string>
<string name="emulation_control_scale">缩放</string>
<string name="emulation_control_opacity">不透明度</string>
<string name="emulation_touch_overlay_reset">重置触控叠加层</string>
<string name="emulation_touch_overlay_edit">编辑触控叠加层</string>
<string name="emulation_touch_overlay_reset">重置虚拟按键</string>
<string name="emulation_touch_overlay_edit">编辑虚拟按键</string>
<string name="emulation_snap_to_grid">截图到网格</string>
<string name="emulation_pause">暂停模拟</string>
<string name="emulation_unpause">继续模拟</string>
<string name="emulation_input_overlay">触控叠加层选项</string>
<string name="emulation_input_overlay">虚拟按键选项</string>
<string name="load_amiibo">加载 Amiibo</string>
<string name="touchscreen">触摸屏</string>
<string name="lock_drawer">锁定侧边</string>
<string name="unlock_drawer">解锁侧边</string>
<string name="lock_drawer">锁定侧边菜单</string>
<string name="unlock_drawer">解锁侧边菜单</string>
<string name="reset">重置</string>
<!-- Amiibo -->
@@ -903,7 +904,7 @@
<!-- Software keyboard -->
<string name="software_keyboard">软键盘</string>
<string name="software_keyboard">键盘</string>
<!-- Errors and warnings -->
<string name="abort_button">中止</string>
@@ -914,7 +915,7 @@
<string name="save_load_error">保存/载入发生错误</string>
<string name="fatal_error">致命错误</string>
<string name="fatal_error_message">发生致命错误。请查阅日志获取详细信息。\n继续模拟可能会导致崩溃。</string>
<string name="device_memory_inadequate">设备内存%1$s\n建议:%2$s</string>
<string name="device_memory_inadequate">设备RAM%1$s\n建议:%2$s</string>
<string name="memory_formatted">%1$s%2$s</string>
<string name="no_game_present">当前没有可启动的游戏!</string>
@@ -925,7 +926,7 @@
<string name="region_australia">澳大利亚</string>
<string name="region_china">中国</string>
<string name="region_korea">韩国</string>
<string name="region_taiwan">台湾</string>
<string name="region_taiwan">台湾地区</string>
<!-- Memory Layouts -->
<string name="memory_4gb">4GB (推荐)</string>
@@ -942,21 +943,21 @@
<string name="fast_gpu_high">高 (512)</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">小 (16 MB)</string>
<string name="gpu_texturesizeswizzle_verysmall">小 (16 MB)</string>
<string name="gpu_texturesizeswizzle_small">较小 (32 MB)</string>
<string name="gpu_texturesizeswizzle_normal">正常 (128 MB)</string>
<string name="gpu_texturesizeswizzle_large">较大 (256 MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">大 (512 MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">大 (512 MB)</string>
<!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">低 (4 MB)</string>
<string name="gpu_swizzle_verylow">低 (4 MB)</string>
<string name="gpu_swizzle_low">低 (8 MB)</string>
<string name="gpu_swizzle_normal">正常 (16 MB)</string>
<string name="gpu_swizzle_medium">中 (32 MB)</string>
<string name="gpu_swizzle_high">高 (64 MB)</string>
<!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">低 (32)</string>
<string name="gpu_swizzlechunk_verylow">低 (32)</string>
<string name="gpu_swizzlechunk_low">低 (64)</string>
<string name="gpu_swizzlechunk_normal">正常 (128)</string>
<string name="gpu_swizzlechunk_medium">中 (256)</string>
@@ -987,6 +988,13 @@
<string name="dma_accuracy_unsafe">不安全</string>
<string name="dma_accuracy_safe">安全</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">自动</string>
<string name="frame_pacing_mode_target_30">30 FPS</string>
<string name="frame_pacing_mode_target_60">60 FPS</string>
<string name="frame_pacing_mode_target_90">90 FPS</string>
<string name="frame_pacing_mode_target_120">120 FPS</string>
<!-- ASTC Recompression Method Choices -->
<string name="astc_recompression_uncompressed">不压缩</string>
<!-- ASTC Recompression Method Choices -->
@@ -1054,10 +1062,8 @@
<string name="change_app_theme">切换主题</string>
<string name="theme_default">系统默认</string>
<string name="theme_material_you">Material You</string>
<string name="app_settings">应用设置</string>
<string name="app_settings">App 设置</string>
<string name="theme_and_color">主题与颜色</string>
<string name="fullscreen_mode">全屏模式</string>
<string name="fullscreen_mode_description">于应用中隐藏 Android 系统栏,若要短暂显示只需从屏幕边缘向内滑动即可。</string>
<!-- Theme Modes -->
<string name="change_theme_mode">更改主题模式</string>
@@ -1078,17 +1084,16 @@
<string name="enable_qlaunch_button_description">显示启动 QLaunch 的按钮</string>
<!-- App Language -->
<string name="app_language">应用使用的语言</string>
<string name="app_language_description">更改应用界面语言</string>
<string name="app_language">App 语言</string>
<string name="app_language_description">更改 app 界面语言</string>
<string name="app_language_system">跟随系统</string>
<!-- Static Themes -->
<string name="static_theme_color">主题颜色</string>
<string name="eden_theme">Eden</string>
<string name="violet">紫色</string>
<string name="violet">紫色(默认)</string>
<string name="blue">蓝色</string>
<string name="cyan">青色</string>
<string name="red">红色</string>
<string name="green">绿色</string>
<string name="yellow">黄色</string>
<string name="orange">橙色</string>
<string name="pink">粉色</string>
@@ -1112,13 +1117,13 @@
<string name="applet_hle">自定义前端</string>
<string name="applet_lle">真实小程序</string>
<string name="swkbd_applet">软键盘</string>
<string name="swkbd_applet">键盘</string>
<string name="airplane_mode">飞行模式</string>
<string name="airplane_mode_description">将飞行模式传递给Switch操作系统</string>
<string name="enable_overlay">启用叠加层小程序</string>
<string name="enable_overlay_description">开启 Horizon 内建的叠加层小程序,要显示它请按 home 键 1 秒</string>
<string name="enable_overlay">开启覆盖层小程序</string>
<string name="enable_overlay_description">开启 Horizon 内置的覆盖层小程序。请按 home 键 1 秒来显示它。</string>
<!-- Profile Management -->
<string name="profile_manager">用户配置管理</string>
@@ -1151,7 +1156,7 @@
<!-- Licenses screen strings -->
<string name="licenses">许可证</string>
<string name="license_fidelityfx_fsr_description">AMD 的高品质画面增强技术</string>
<string name="license_fidelityfx_fsr_description">来自 AMD 的高品质画质升级技术</string>
<string name="external_content">外部内容</string>
<string name="add_folders">添加文件夹</string>
@@ -908,6 +908,7 @@
<string name="theme_material_you">質感設計3</string>
<string name="app_settings">Eden介面設定</string>
<string name="theme_and_color">主題和顏色</string>
<!-- Theme Modes -->
<string name="change_theme_mode">變更主題模式</string>
<string name="theme_mode_follow_system">跟隨系統</string>
@@ -533,6 +533,20 @@
<item>2</item>
</integer-array>
<string-array name="framePacingModeNames">
<item>@string/frame_pacing_mode_target_Auto</item>
<item>@string/frame_pacing_mode_target_30</item>
<item>@string/frame_pacing_mode_target_60</item>
<item>@string/frame_pacing_mode_target_90</item>
<item>@string/frame_pacing_mode_target_120</item>
</string-array>
<integer-array name="framePacingModeValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<string-array name="appletEntries">
<item>@string/applet_hle</item>
@@ -479,6 +479,8 @@
<string name="renderer_accuracy_description">Controls the GPU emulation mode. Most games render fine with Fast or Balanced modes, but Accurate is still required for some. Particles tend to only render correctly with Accurate mode.</string>
<string name="dma_accuracy">DMA Accuracy</string>
<string name="dma_accuracy_description">Controls the DMA precision accuracy. Safe precision can fix issues in some games, but it can also impact performance in some cases. If unsure, leave this on Default.</string>
<string name="frame_pacing_mode">Frame Pacing Mode</string>
<string name="frame_pacing_mode_description">Controls how the emulator manages frame pacing to reduce stuttering and make the frame rate smoother and more consistent.</string>
<string name="anisotropic_filtering">Anisotropic filtering</string>
<string name="anisotropic_filtering_description">Improves the quality of textures when viewed at oblique angles</string>
<string name="vram_usage_mode">VRAM Usage Mode</string>
@@ -1036,6 +1038,13 @@
<string name="dma_accuracy_unsafe">Unsafe</string>
<string name="dma_accuracy_safe">Safe</string>
<!-- Frame Pacing Mode -->
<string name="frame_pacing_mode_target_Auto">Auto</string>
<string name="frame_pacing_mode_target_30">30 FPS</string>
<string name="frame_pacing_mode_target_60">60 FPS</string>
<string name="frame_pacing_mode_target_90">90 FPS</string>
<string name="frame_pacing_mode_target_120">120 FPS</string>
<!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
<string name="accelerate_astc_gpu" translatable="false">GPU</string>
+2 -5
View File
@@ -134,8 +134,6 @@ add_library(
typed_address.h
uint128.h
unique_function.h
random.cpp
random.h
uuid.cpp
uuid.h
vector_math.h
@@ -146,8 +144,7 @@ add_library(
zstd_compression.cpp
zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
fs/symlink.h fs/symlink.cpp
httplib.h)
fs/symlink.h fs/symlink.cpp)
if(WIN32)
target_sources(common PRIVATE windows/timer_resolution.cpp
@@ -245,7 +242,7 @@ else()
target_link_libraries(common PUBLIC Boost::headers)
endif()
target_link_libraries(common PUBLIC Boost::filesystem Boost::context httplib::httplib)
target_link_libraries(common PUBLIC Boost::filesystem Boost::context)
if (lz4_ADDED)
target_include_directories(common PRIVATE ${lz4_SOURCE_DIR}/lib)
+7 -7
View File
@@ -30,8 +30,6 @@
#include <sys/random.h>
#include <mach/vm_map.h>
#include <mach/mach.h>
#elif defined(__FreeBSD__)
#include <sys/shm.h>
#endif
// FreeBSD
@@ -505,7 +503,8 @@ public:
fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
#elif defined(__OpenBSD__)
fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
#elif defined(__FreeBSD__)
#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
@@ -572,9 +571,9 @@ public:
if (True(perms & MemoryPermission::Execute))
prot_flags |= PROT_EXEC;
#endif
int flags = (fd >= 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED;
int flags = (fd > 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED;
void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset);
ASSERT_MSG(ret != MAP_FAILED, "mmap: {} {}", strerror(errno), fd);
ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno));
}
void Unmap(size_t virtual_offset, size_t length) {
@@ -588,8 +587,9 @@ public:
auto [merged_pointer, merged_size] =
free_manager.FreeBlock(virtual_base + virtual_offset, length);
void* ret = mmap(merged_pointer, merged_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno));
void* ret = mmap(merged_pointer, merged_size, PROT_NONE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
}
void Protect(size_t virtual_offset, size_t length, bool read, bool write, bool execute) {
-18
View File
@@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
#ifdef __GNUC__
#pragma GCC diagnostic push
#ifndef __clang__
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif
#endif
#include <httplib.h>
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
-22
View File
@@ -1,22 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <optional>
#include <random>
#include "common/random.h"
namespace Common::Random {
[[nodiscard]] static std::random_device& GetGlobalRandomDevice() noexcept {
static std::random_device g_random_device{};
return g_random_device;
}
[[nodiscard]] u32 Random32(u32 seed) noexcept {
return GetGlobalRandomDevice()();
}
[[nodiscard]] u64 Random64(u64 seed) noexcept {
return GetGlobalRandomDevice()();
}
[[nodiscard]] std::mt19937 GetMT19937() noexcept {
return std::mt19937(GetGlobalRandomDevice()());
}
}
-13
View File
@@ -1,13 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <random>
#include "common/common_types.h"
namespace Common::Random {
[[nodiscard]] u32 Random32(u32 seed) noexcept;
[[nodiscard]] u64 Random64(u64 seed) noexcept;
[[nodiscard]] std::mt19937 GetMT19937() noexcept;
}
+1 -1
View File
@@ -186,7 +186,7 @@ bool IsFastmemEnabled() {
// Only 4kb systems support host MMU right now
// TODO: Support this
return getpagesize() == 4096;
#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__)
#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__)
return false;
#else
return true;
+2
View File
@@ -287,6 +287,8 @@ struct Values {
true,
&use_custom_cpu_ticks};
SwitchableSetting<bool> vtable_bouncing{linkage, true, "vtable_bouncing", Category::Cpu};
Setting<bool> cpuopt_page_tables{linkage, true, "cpuopt_page_tables", Category::CpuDebug};
Setting<bool> cpuopt_block_linking{linkage, true, "cpuopt_block_linking", Category::CpuDebug};
Setting<bool> cpuopt_return_stack_buffer{linkage, true, "cpuopt_return_stack_buffer",
+7 -1
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -218,6 +218,12 @@ public:
return t0;
}
u64 GenerateRandomU64() {
const u32 lo = this->GenerateRandomU32();
const u32 hi = this->GenerateRandomU32();
return (u64{hi} << 32) | u64{lo};
}
float GenerateRandomF32() {
// Floats have 24 bits of mantissa.
constexpr u32 MantissaBits = 24;
+6 -5
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -13,7 +10,6 @@
#include "common/assert.h"
#include "common/tiny_mt.h"
#include "common/uuid.h"
#include "common/random.h"
namespace Common {
@@ -179,16 +175,21 @@ u128 UUID::AsU128() const {
}
UUID UUID::MakeRandom() {
return MakeRandomWithSeed(Common::Random::Random32(0));
std::random_device device;
return MakeRandomWithSeed(device());
}
UUID UUID::MakeRandomWithSeed(u32 seed) {
// Create and initialize our RNG.
TinyMT rng;
rng.Initialize(seed);
UUID uuid;
// Populate the UUID with random bytes.
rng.GenerateRandomBytes(uuid.uuid.data(), sizeof(UUID));
return uuid;
}
+2 -1
View File
@@ -1246,7 +1246,7 @@ if (HAS_NCE)
target_link_libraries(core PRIVATE merry::oaknut)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64 OR ARCHITECTURE_riscv64)
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic.h
arm/dynarmic/arm_dynarmic_64.cpp
@@ -1269,6 +1269,7 @@ endif()
target_sources(core PRIVATE hle/service/ssl/ssl_backend_openssl.cpp)
target_link_libraries(core PRIVATE OpenSSL::SSL OpenSSL::Crypto)
target_compile_definitions(core PRIVATE CPPHTTPLIB_OPENSSL_SUPPORT)
# TODO
+5 -5
View File
@@ -186,7 +186,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
config.fastmem_pointer = page_table->fastmem_arena ?
std::optional<uintptr_t>{uintptr_t(page_table->fastmem_arena)} :
std::optional<uintptr_t>{reinterpret_cast<uintptr_t>(page_table->fastmem_arena)} :
std::nullopt;
config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt;
@@ -286,6 +286,10 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
// Curated optimizations
case Settings::CpuAccuracy::Auto:
config.unsafe_optimizations = true;
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__)
config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false;
#endif
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreStandardFPCRValue;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN;
@@ -300,10 +304,6 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
default:
break;
}
if (!Settings::IsFastmemEnabled()) {
config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false;
}
m_jit.emplace(config);
}
+4 -4
View File
@@ -338,6 +338,10 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
// Safe optimisations
case Settings::CpuAccuracy::Auto:
config.unsafe_optimizations = true;
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__ANDROID__) && !defined(_WIN32)
config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false;
#endif
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
config.fastmem_address_space_bits = 64;
config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor;
@@ -351,10 +355,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
default:
break;
}
if (!Settings::IsFastmemEnabled()) {
config.fastmem_pointer = std::nullopt;
config.fastmem_exclusive_access = false;
}
m_jit.emplace(config);
}
+10 -2
View File
@@ -59,10 +59,14 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
#if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64)
_mm_mfence();
_mm_lfence();
#elif defined(ARCHITECTURE_x86_64)
asm volatile("mfence\n\tlfence\n\t" : : : "memory");
#elif defined(_MSC_VER) && defined(ARCHITECTURE_arm64)
_Memory_barrier();
#elif defined(ARCHITECTURE_arm64)
asm volatile("dsb sy\n\t" : : : "memory");
#else
__sync_synchronize();
#error Unsupported architecture
#endif
return 0;
},
@@ -74,10 +78,14 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
[](void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64)
_mm_mfence();
#elif defined(ARCHITECTURE_x86_64)
asm volatile("mfence\n\t" : : : "memory");
#elif defined(_MSC_VER) && defined(ARCHITECTURE_arm64)
_Memory_barrier();
#elif defined(ARCHITECTURE_arm64)
asm volatile("dmb sy\n\t" : : : "memory");
#else
__sync_synchronize();
#error Unsupported architecture
#endif
return 0;
},
+1 -5
View File
@@ -773,11 +773,7 @@ std::optional<u64> MatchAndExecuteOneInstruction(Core::Memory::Memory& memory, m
bool was_executed = false;
auto decoder = Dynarmic::A64::Decode<VisitorBase>(instruction);
if (decoder) {
was_executed = decoder->get().call(visitor, instruction);
} else {
was_executed = false;
}
was_executed = decoder.get().call(visitor, instruction);
return was_executed ? std::optional<u64>(pc + 4) : std::nullopt;
}
+36 -48
View File
@@ -26,15 +26,42 @@ CpuManager::~CpuManager() = default;
void CpuManager::Initialize() {
num_cores = is_multicore ? Core::Hardware::NUM_CPU_CORES : 1;
gpu_barrier = std::make_unique<Common::Barrier>(num_cores + 1);
for (std::size_t core = 0; core < num_cores; core++)
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) { RunThread(token, core); });
for (std::size_t core = 0; core < num_cores; core++) {
core_data[core].host_thread = std::jthread([this, core](std::stop_token token) {
// Initialization
system.RegisterCoreThread(core);
Common::SetCurrentThreadName(("CPUCore_" + std::to_string(core)).c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
#ifdef __ANDROID__
// Aimed specifically for Snapdragon 8 Elite devices
// This kills performance on desktop, but boosts perf for UMA devices
// like the S8E. Mediatek and Mali likely won't suffer.
Common::PinCurrentThreadToPerformanceCore(core);
#endif
auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber();
// Running
if (gpu_barrier->Sync(token)) {
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
}
auto& kernel = system.Kernel();
auto& scheduler = *kernel.CurrentScheduler();
auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
}
// Cleanup
data.host_context->Exit();
});
}
}
void CpuManager::Shutdown() {
for (std::size_t core = 0; core < num_cores; core++) {
if (core_data[core].host_thread.joinable()) {
core_data[core].host_thread.request_stop();
core_data[core].host_thread.join();
for (auto it = core_data.begin(); it != core_data.end(); ++it) {
if (it->host_thread.joinable()) {
it->host_thread.request_stop();
it->host_thread.join();
}
}
}
@@ -77,12 +104,10 @@ void CpuManager::MultiCoreRunGuestThread() {
kernel.CurrentScheduler()->OnThreadStart();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
while (!physical_core->IsInterrupted()) {
physical_core->RunThread(thread);
physical_core = &kernel.CurrentPhysicalCore();
auto& physical_core = kernel.CurrentPhysicalCore();
while (!physical_core.IsInterrupted()) {
physical_core.RunThread(thread);
}
HandleInterrupt();
}
}
@@ -183,41 +208,4 @@ void CpuManager::ShutdownThread() {
UNREACHABLE();
}
void CpuManager::RunThread(std::stop_token token, std::size_t core) {
/// Initialization
system.RegisterCoreThread(core);
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
Common::SetCurrentThreadName(name.c_str());
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
#ifdef __ANDROID__
// Aimed specifically for Snapdragon 8 Elite devices
// This kills performance on desktop, but boosts perf for UMA devices
// like the S8E. Mediatek and Mali likely won't suffer.
Common::PinCurrentThreadToPerformanceCore(core);
#endif
auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup
SCOPE_EXIT {
data.host_context->Exit();
};
// Running
if (!gpu_barrier->Sync(token)) {
return;
}
if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext();
}
auto& kernel = system.Kernel();
auto& scheduler = *kernel.CurrentScheduler();
auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
}
} // namespace Core
+3 -1
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -84,7 +87,6 @@ private:
void GuestActivate();
void HandleInterrupt();
void ShutdownThread();
void RunThread(std::stop_token stop_token, std::size_t core);
struct CoreData {
std::shared_ptr<Common::Fiber> host_context;
+5 -2
View File
@@ -12,7 +12,6 @@
#include "common/fs/path_util.h"
#include "common/hex_util.h"
#include "common/logging.h"
#include "common/random.h"
#include "common/string_util.h"
#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
@@ -491,13 +490,17 @@ std::vector<NcaID> PlaceholderCache::List() const {
}
NcaID PlaceholderCache::Generate() {
auto gen = Common::Random::GetMT19937();
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, (std::numeric_limits<u64>::max)());
NcaID out{};
const auto v1 = distribution(gen);
const auto v2 = distribution(gen);
std::memcpy(out.data(), &v1, sizeof(u64));
std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
return out;
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -7,7 +7,6 @@
#include <random>
#include "common/literals.h"
#include "common/random.h"
#include "common/settings.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
@@ -202,8 +201,15 @@ u64 GenerateUniformRange(u64 min, u64 max, F f) {
} // Anonymous namespace
u64 KSystemControl::GenerateRandomU64() {
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(1, (std::numeric_limits<u64>::max)());
return distribution(gen);
}
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
return GenerateUniformRange(min, max, Common::Random::GetMT19937());
return GenerateUniformRange(min, max, GenerateRandomU64);
}
size_t KSystemControl::CalculateRequiredSecureMemorySize(size_t size, u32 pool) {
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -36,6 +33,7 @@ public:
// Randomness.
static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64();
// Secure Memory.
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool);
+2 -3
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@@ -14,7 +14,6 @@
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/tiny_mt.h"
#include "common/random.h"
#include "core/hle/kernel/k_system_control.h"
namespace Kernel {
@@ -24,7 +23,7 @@ public:
class RandomBitGenerator {
public:
RandomBitGenerator() {
m_rng.Initialize(u32(Common::Random::Random64(0)));
m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
}
u64 SelectRandomBit(u64 bitmap) {
+5 -4
View File
@@ -20,7 +20,6 @@
#include "common/fiber.h"
#include "common/logging.h"
#include "common/settings.h"
#include "common/random.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/hardware_properties.h"
@@ -46,7 +45,8 @@ namespace {
constexpr inline s32 TerminatingThreadPriority = Kernel::Svc::SystemThreadPriorityHighest - 1;
static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, u64 arg) {
static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
u64 arg) {
ctx = {};
ctx.r[0] = arg;
ctx.r[15] = entry_point;
@@ -55,10 +55,11 @@ static void ResetThreadContext32(Kernel::Svc::ThreadContext& ctx, u64 stack_top,
ctx.fpsr = 0;
}
static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point, u64 arg) {
static void ResetThreadContext64(Kernel::Svc::ThreadContext& ctx, u64 stack_top, u64 entry_point,
u64 arg) {
ctx = {};
ctx.r[0] = arg;
ctx.r[18] = Common::Random::Random64(0) | 1;
ctx.r[18] = Kernel::KSystemControl::GenerateRandomU64() | 1;
ctx.pc = entry_point;
ctx.sp = stack_top;
ctx.fpcr = 0;
+8 -31
View File
@@ -170,9 +170,6 @@ struct KernelCore::Impl {
schedulers[core_id].reset();
}
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
next_host_thread_id = Core::Hardware::NUM_CPU_CORES;
// Close kernel objects that were not freed on shutdown
{
std::scoped_lock lk{registered_in_use_objects_lock};
@@ -355,22 +352,6 @@ struct KernelCore::Impl {
application_process->Open();
}
/// Sets the host thread ID for the caller.
u32 SetHostThreadId(std::size_t core_id) {
// This should only be called during core init.
ASSERT(tls_data.host_thread_id == UINT8_MAX);
// The first four slots are reserved for CPU core threads
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
tls_data.host_thread_id = u8(core_id);
return tls_data.host_thread_id;
}
/// Gets the host thread ID for the caller
u32 GetHostThreadId() const {
return tls_data.host_thread_id;
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread(KThread* existing_thread) {
if (tls_data.thread == nullptr) {
@@ -386,9 +367,12 @@ struct KernelCore::Impl {
}
/// Registers a CPU core thread by allocating a host thread ID for it
void RegisterCoreThread(std::size_t core_id) {
void RegisterCoreThread(std::size_t core_id) noexcept {
// This should only be called during core init.
ASSERT(tls_data.host_thread_id == UINT8_MAX);
// The first four slots are reserved for CPU core threads
ASSERT(core_id < Core::Hardware::NUM_CPU_CORES);
const auto this_id = SetHostThreadId(core_id);
const auto this_id = tls_data.host_thread_id = u8(core_id);
if (!is_multicore)
single_core_thread_id = this_id;
}
@@ -398,8 +382,8 @@ struct KernelCore::Impl {
(void)GetHostDummyThread(existing_thread);
}
[[nodiscard]] u32 GetCurrentHostThreadID() {
auto const this_id = GetHostThreadId();
[[nodiscard]] inline u32 GetCurrentHostThreadID() noexcept {
auto const this_id = tls_data.host_thread_id;
if (!is_multicore && single_core_thread_id == this_id)
return u32(system.GetCpuManager().CurrentCore());
return this_id;
@@ -794,9 +778,6 @@ struct KernelCore::Impl {
std::array<std::optional<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
// Kernel memory management
std::optional<KMemoryManager> memory_manager;
@@ -930,11 +911,7 @@ const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
}
size_t KernelCore::CurrentPhysicalCoreIndex() const {
const u32 core_id = impl->GetCurrentHostThreadID();
if (core_id >= Core::Hardware::NUM_CPU_CORES) {
return Core::Hardware::NUM_CPU_CORES - 1;
}
return core_id;
return impl->GetCurrentHostThreadID();
}
Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
+44 -46
View File
@@ -103,12 +103,25 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
const bool data_abort = True(hr & Core::HaltReason::DataAbort);
const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
bool may_abort = true; // Ignore aborting virtual functions (for debugging)
if (prefetch_abort && ::Settings::values.vtable_bouncing) {
auto& lock = m_kernel.GlobalSchedulerContext().SchedulerLock();
lock.Lock();
Kernel::Svc::ThreadContext ctx;
interface->GetContext(ctx);
LOG_WARNING(Core_ARM, "vtable bouncing {:016X}", ctx.lr);
ctx.pc = ctx.lr;
ctx.r[0] = 0;
interface->SetContext(ctx);
lock.Unlock();
may_abort = false;
}
// Since scheduling may occur here, we cannot use any cached
// state after returning from calls we make.
// Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason.
if (breakpoint || prefetch_abort) {
if (breakpoint || (prefetch_abort && may_abort)) {
// Notify the debugger and go to sleep if a breakpoint was hit,
// or if the thread is unable to continue for any reason.
if (breakpoint) {
interface->RewindBreakpointInstruction();
}
@@ -119,26 +132,19 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
}
thread->RequestSuspend(SuspendType::Debug);
return;
}
// Notify the debugger and go to sleep on data abort.
if (data_abort) {
} else if (data_abort) {
// Notify the debugger and go to sleep on data abort.
if (system.DebuggerEnabled()) {
system.GetDebugger().NotifyThreadWatchpoint(thread, *interface->HaltedWatchpoint());
}
thread->RequestSuspend(SuspendType::Debug);
return;
}
// Handle system calls.
if (supervisor_call) {
// Perform call.
} else if (supervisor_call) {
// Handle system calls: Perform call.
Svc::Call(system, interface->GetSvcNumber());
return;
}
// Handle external interrupt sources.
if (interrupt || m_is_single_core) {
} else if (interrupt || m_is_single_core) {
// Handle external interrupt sources.
return;
}
}
@@ -146,16 +152,14 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
void PhysicalCore::LoadContext(const KThread* thread) {
auto* const process = thread->GetOwnerProcess();
if (!process) {
if (process) {
// Kernel threads do not run on emulated CPU cores.
return;
}
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->SetContext(thread->GetContext());
interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
interface->SetWatchpointArray(&process->GetWatchpoints());
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->SetContext(thread->GetContext());
interface->SetTpidrroEl0(GetInteger(thread->GetTlsAddress()));
interface->SetWatchpointArray(&process->GetWatchpoints());
}
}
}
@@ -165,14 +169,12 @@ void PhysicalCore::LoadSvcArguments(const KProcess& process, std::span<const uin
void PhysicalCore::SaveContext(KThread* thread) const {
auto* const process = thread->GetOwnerProcess();
if (!process) {
if (process) {
// Kernel threads do not run on emulated CPU cores.
return;
}
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->GetContext(thread->GetContext());
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->GetContext(thread->GetContext());
}
}
}
@@ -192,13 +194,11 @@ void PhysicalCore::CloneFpuStatus(KThread* dst) const {
void PhysicalCore::LogBacktrace() {
auto* process = GetCurrentProcessPointer(m_kernel);
if (!process) {
return;
}
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->LogBacktrace(process);
if (process) {
auto* interface = process->GetArmInterface(m_core_index);
if (interface) {
interface->LogBacktrace(process);
}
}
}
@@ -207,7 +207,7 @@ void PhysicalCore::Idle() {
m_on_interrupt.wait(lk, [this] { return m_is_interrupted; });
}
bool PhysicalCore::IsInterrupted() const {
[[noinline]] bool PhysicalCore::IsInterrupted() const {
return m_is_interrupted;
}
@@ -226,12 +226,10 @@ void PhysicalCore::Interrupt() {
m_on_interrupt.notify_one();
// If there is no thread running, we are done.
if (arm_interface == nullptr) {
return;
if (arm_interface != nullptr) {
// Interrupt the CPU.
arm_interface->SignalInterrupt(thread);
}
// Interrupt the CPU.
arm_interface->SignalInterrupt(thread);
}
void PhysicalCore::ClearInterrupt() {
+3 -70
View File
@@ -1,13 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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 <condition_variable>
#include <mutex>
#include <thread>
#include "core/core.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
@@ -15,62 +8,14 @@
namespace Kernel::Svc {
constexpr auto MAX_MSG_TIME = std::chrono::milliseconds(250);
const auto MAX_MSG_SIZE = 0x1000;
static std::string msg_buffer;
static std::mutex msg_mutex;
static std::condition_variable msg_cv;
static std::chrono::steady_clock::time_point last_msg_time;
static bool worker_running = true;
static std::unique_ptr<std::thread> flush_thread;
static std::once_flag start_flag;
static void FlushDbgLoop() {
while (true) {
std::unique_lock lock(msg_mutex);
msg_cv.wait(lock, [] { return !msg_buffer.empty() || !worker_running; });
if (!worker_running && msg_buffer.empty()) break;
auto timeout = last_msg_time + MAX_MSG_TIME;
bool woke_early = msg_cv.wait_until(lock, timeout, [] {
return msg_buffer.size() >= MAX_MSG_SIZE || !worker_running;
});
if (!woke_early || msg_buffer.size() >= MAX_MSG_SIZE || !worker_running) {
if (!msg_buffer.empty()) {
// Remove trailing newline as LOG_INFO adds that anyways
if (msg_buffer.back() == '\n')
msg_buffer.pop_back();
LOG_INFO(Debug_Emulated, "\n{}", msg_buffer);
msg_buffer.clear();
}
if (!worker_running) break;
}
}
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
Result OutputDebugString(Core::System& system, u64 address, u64 len) {
R_SUCCEED_IF(len == 0);
// Only start the thread the very first time this function is called
std::call_once(start_flag, [] {
flush_thread = std::make_unique<std::thread>(FlushDbgLoop);
});
std::string str(len, '\0');
GetCurrentMemory(system.Kernel()).ReadBlock(address, str.data(), str.size());
LOG_INFO(Debug_Emulated, "{}", str);
{
std::lock_guard lock(msg_mutex);
const auto old_size = msg_buffer.size();
msg_buffer.resize(old_size + len);
GetCurrentMemory(system.Kernel()).ReadBlock(address, msg_buffer.data() + old_size, len);
last_msg_time = std::chrono::steady_clock::now();
}
msg_cv.notify_one();
R_SUCCEED();
}
@@ -82,16 +27,4 @@ Result OutputDebugString64From32(Core::System& system, uint32_t debug_str, uint3
R_RETURN(OutputDebugString(system, debug_str, len));
}
struct BufferAutoFlush {
~BufferAutoFlush() {
{
std::lock_guard lock(msg_mutex);
worker_running = false;
}
msg_cv.notify_all();
if (flush_thread && flush_thread->joinable()) flush_thread->join();
}
};
static BufferAutoFlush auto_flusher;
} // namespace Kernel::Svc
+27 -55
View File
@@ -15,7 +15,9 @@
#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include "common/httplib.h"
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
#include <httplib.h>
#endif
#include <chrono>
#include <cstring>
@@ -35,8 +37,7 @@
namespace Service::News {
namespace {
// TODO(crueter): COMPILE DEFINITION
constexpr const char* GitHubAPI_EdenReleases = "/api/v1/repos/eden-emu/eden/releases";
constexpr const char* GitHubAPI_EdenReleases = "/repos/eden-emulator/Releases/releases";
// Cached logo data
std::vector<u8> default_logo_small;
@@ -102,6 +103,8 @@ std::vector<u8> TryLoadFromDisk(const std::filesystem::path& path) {
std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem::path& cache_path) {
LOG_INFO(Service_BCAT, "Downloading image: https://eden-emu.dev{}", url_path);
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
try {
httplib::Client cli("https://eden-emu.dev");
cli.set_follow_location(true);
@@ -125,6 +128,8 @@ std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem
} catch (...) {
LOG_WARNING(Service_BCAT, "Failed to download: {}", url_path);
}
#endif
return {};
}
@@ -227,63 +232,30 @@ void WriteCachedJson(std::string_view json) {
}
std::optional<std::string> DownloadReleasesJson() {
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
try {
#ifdef YUZU_BUNDLED_OPENSSL
const auto url = "https://git.eden-emu.dev";
#else
const auto url = "git.eden-emu.dev";
#endif
httplib::SSLClient cli{"api.github.com", 443};
cli.set_connection_timeout(10);
cli.set_read_timeout(10);
// TODO(crueter): This is duplicated between frontend and here.
constexpr auto path = GitHubAPI_EdenReleases;
constexpr std::size_t timeout_seconds = 15;
std::unique_ptr<httplib::Client> client = std::make_unique<httplib::Client>(url);
client->set_connection_timeout(timeout_seconds);
client->set_read_timeout(timeout_seconds);
client->set_write_timeout(timeout_seconds);
#ifdef YUZU_BUNDLED_OPENSSL
client->load_ca_cert_store(kCert, sizeof(kCert));
#endif
if (client == nullptr) {
LOG_ERROR(Service_BCAT, "Invalid URL {}{}", url, path);
return {};
}
httplib::Request request{
.method = "GET",
.path = path,
httplib::Headers headers{
{"User-Agent", "Eden"},
{"Accept", "application/vnd.github+json"},
};
client->set_follow_location(true);
httplib::Result result = client->send(request);
// TODO(crueter): automate this in some way...
#ifdef YUZU_BUNDLED_OPENSSL
cli.load_ca_cert_store(kCert, sizeof(kCert));
#endif
if (!result) {
LOG_ERROR(Service_BCAT, "GET to {}{} returned null", url, path);
return {};
} else if (result->status < 400) {
return result->body;
}
if (result->status >= 400) {
LOG_ERROR(Service_BCAT,
"GET to {}{} returned error status code: {}",
url,
path,
result->status);
return {};
}
if (!result->headers.contains("content-type")) {
LOG_ERROR(Service_BCAT, "GET to {}{} returned no content", url, path);
return {};
if (auto res = cli.Get(GitHubAPI_EdenReleases, headers); res && res->status < 400) {
return res->body;
}
} catch (...) {
LOG_WARNING(Service_BCAT, " failed to download releases");
}
#endif
return std::nullopt;
}
@@ -369,7 +341,7 @@ std::string FormatBody(const nlohmann::json& release, std::string_view title) {
body.pop_back();
}
body += "\n\n... View more on Forgejo";
body += "\n\n... View more on GitHub";
}
return body;
@@ -526,7 +498,7 @@ std::vector<u8> BuildMsgpack(std::string_view title, std::string_view body,
w.WriteString("");
w.WriteKey("allow_domains");
w.WriteString("^https?://git.eden-emu.dev(/|$)");
w.WriteString("^https?://github.com(/|$)");
// More link
w.WriteKey("more");
@@ -536,7 +508,7 @@ std::vector<u8> BuildMsgpack(std::string_view title, std::string_view body,
w.WriteKey("url");
w.WriteString(html_url);
w.WriteKey("text");
w.WriteString("Open Forgejo");
w.WriteString("Open GitHub");
// Body
w.WriteKey("body");
@@ -573,7 +545,7 @@ void EnsureBuiltinNewsLoaded() {
if (const auto fresh = DownloadReleasesJson()) {
WriteCachedJson(*fresh);
ImportReleases(*fresh);
LOG_DEBUG(Service_BCAT, "news: {} entries updated from Forgejo", NewsStorage::Instance().ListAll().size());
LOG_DEBUG(Service_BCAT, "news: {} entries updated from GitHub", NewsStorage::Instance().ListAll().size());
}
}).detach();
});
+11 -11
View File
@@ -438,20 +438,20 @@ void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequ
template <bool Domain, typename T, typename... A>
void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) {
const auto mgr = ctx.GetManager().get();
// Verify domain state.
if constexpr (!Domain) {
const bool is_domain = mgr ? mgr->IsDomain() : false;
ASSERT_MSG(!is_domain,
"Non-domain reply used on domain session\n"
"Service={} (TIPC={} CmdType={} Cmd=0x{:08X}\n"
"HasDomainHeader={} DomainHandlers={}\nDesc={}",
t.GetServiceName(), ctx.IsTipc(),
u32(ctx.GetCommandType()), u32(ctx.GetCommand()),
ctx.HasDomainMessageHeader(), mgr ? u32(mgr->DomainHandlerCount()) : 0u,
ctx.Description());
const auto _mgr = ctx.GetManager();
const bool _is_domain = _mgr ? _mgr->IsDomain() : false;
ASSERT_MSG(!_is_domain,
"Non-domain reply used on domain session\n"
"Service={} (TIPC={} CmdType={} Cmd=0x{:08X}\n"
"HasDomainHeader={} DomainHandlers={}\nDesc={}",
t.GetServiceName(), ctx.IsTipc(),
static_cast<u32>(ctx.GetCommandType()), static_cast<u32>(ctx.GetCommand()),
ctx.HasDomainMessageHeader(), _mgr ? static_cast<u32>(_mgr->DomainHandlerCount()) : 0u,
ctx.Description());
}
const bool is_domain = Domain ? mgr->IsDomain() : false;
const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false;
static_assert(ConstIfReference<A...>(), "Arguments taken by reference must be const");
using MethodArguments = std::tuple<std::remove_cvref_t<A>...>;
+11 -11
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -81,29 +78,32 @@ public:
memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH);
IPC::CommandHeader header{};
auto const mgr = ctx.GetManager().get();
// The entire size of the raw data section in u32 units, including the 16 bytes of mandatory
// padding.
u32 raw_data_size = ctx.write_size = ctx.IsTipc() ? normal_params_size - 1 : normal_params_size;
u32 raw_data_size = ctx.write_size =
ctx.IsTipc() ? normal_params_size - 1 : normal_params_size;
u32 num_handles_to_move{};
u32 num_domain_objects{};
const bool always_move_handles = (u32(flags) & u32(Flags::AlwaysMoveHandles)) != 0;
if (!mgr->IsDomain() || always_move_handles) {
const bool always_move_handles{
(static_cast<u32>(flags) & static_cast<u32>(Flags::AlwaysMoveHandles)) != 0};
if (!ctx.GetManager()->IsDomain() || always_move_handles) {
num_handles_to_move = num_objects_to_move;
} else {
num_domain_objects = num_objects_to_move;
}
if (mgr->IsDomain()) {
raw_data_size += u32(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
if (ctx.GetManager()->IsDomain()) {
raw_data_size +=
static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects);
ctx.write_size += num_domain_objects;
}
if (ctx.IsTipc()) {
header.type.Assign(ctx.GetCommandType());
} else {
raw_data_size += u32(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + normal_params_size);
raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 +
normal_params_size);
}
header.data_size.Assign(raw_data_size);
@@ -126,7 +126,7 @@ public:
if (!ctx.IsTipc()) {
AlignWithPadding();
if (mgr->IsDomain() && ctx.HasDomainMessageHeader()) {
if (ctx.GetManager()->IsDomain() && ctx.HasDomainMessageHeader()) {
IPC::DomainMessageHeader domain_header{};
domain_header.num_objects = num_domain_objects;
PushRaw(domain_header);
+5 -7
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 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,7 +7,6 @@
#include <span>
#include "common/common_types.h"
#include "common/random.h"
#include "common/swap.h"
#include "common/uuid.h"
#include "core/hle/service/mii/mii_types.h"
@@ -69,9 +65,11 @@ public:
template <typename T>
static T GetRandomValue(T min, T max) {
std::uniform_int_distribution<u64> distribution{u64(min), u64(max)};
auto gen = Common::Random::GetMT19937();
return T(distribution(gen));
std::random_device device;
std::mt19937 gen(device());
std::uniform_int_distribution<u64> distribution(static_cast<u64>(min),
static_cast<u64>(max));
return static_cast<T>(distribution(gen));
}
template <typename T>
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -373,8 +373,6 @@ Result SharedBufferManager::PresentSharedFrameBuffer(android::Fence fence,
android::Status::NoError,
VI::ResultOperationFailed);
(void)m_container.SetLayerZIndex(layer_id, 100000);
// We succeeded.
R_SUCCEED();
}
@@ -6,7 +6,6 @@
#include <cstring>
#include "common/logging.h"
#include "common/random.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
@@ -230,7 +229,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// TODO: this is bad form of ASLR, it sucks
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
: std::rand()) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
+1 -2
View File
@@ -6,7 +6,6 @@
#include <cstring>
#include "common/settings.h"
#include "common/random.h"
#include "core/file_sys/kernel_executable.h"
#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/code_set.h"
@@ -91,7 +90,7 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
// TODO: this is bad form of ASLR, it sucks
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
: std::rand()) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), codeset.memory.size(), 0, aslr_offset, false).IsError()) {
+1 -2
View File
@@ -11,7 +11,6 @@
#include "common/common_types.h"
#include "common/logging.h"
#include "common/settings.h"
#include "common/random.h"
#include "common/swap.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
@@ -244,7 +243,7 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
// TODO: this is bad form of ASLR, it sucks
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
? ::Settings::values.rng_seed.GetValue()
: Common::Random::Random64(0)) * 0x734287f27) & 0xfff000;
: std::rand()) * 0x734287f27) & 0xfff000;
// Setup the process code layout
if (process

Some files were not shown because too many files have changed in this diff Show More