Compare commits

..

120 Commits

Author SHA1 Message Date
CamilleLaVey 9c18bd44e7 Fix licenses 2026-10-05 18:44:01 -04:00
CamilleLaVey 013deb4f3f Revert "Address turnip bug with depths" 2026-10-02 03:59:24 -04:00
CamilleLaVey 0b7d216a09 Address some regressions with unswizzle changes + barriers reductions 2026-10-02 01:41:19 -04:00
CamilleLaVey b8478a570b Experiments with TS on turnip 2026-10-02 00:47:24 -04:00
CamilleLaVey 9d620bba88 Address son sync issues 2026-10-01 23:56:07 -04:00
CamilleLaVey 165a1d1da1 Experiments with gpu stalls per fence wait 2026-10-01 22:52:42 -04:00
CamilleLaVey 5c7520f572 Address some regressions with UMA 2026-10-01 20:56:23 -04:00
CamilleLaVey 7db354a25a Framerate display corrections 2026-10-01 20:27:22 -04:00
CamilleLaVey f759409cc2 Address turnip bug with depths 2026-10-01 19:30:50 -04:00
CamilleLaVey e11ea7f008 Port UMA part 5.3 (NCE EXT) 2026-10-01 16:52:15 -04:00
CamilleLaVey 73cac64037 Port UMA part 5.2 2026-10-01 16:26:33 -04:00
CamilleLaVey fb174abf04 Port UMA part 5.1 2026-10-01 14:07:31 -04:00
CamilleLaVey 1b764efad9 Port UMA part 4.1 2026-10-01 12:23:20 -04:00
CamilleLaVey 488dcefec5 Port UMA part 4 2026-10-01 02:49:53 -04:00
CamilleLaVey df36685c9b Port UMA part 3 2026-10-01 02:01:24 -04:00
CamilleLaVey 9cc9a1fc35 Port UMA part 2 2026-10-01 01:09:01 -04:00
CamilleLaVey 0a88e761eb Port UMA part 1 2026-10-01 00:19:46 -04:00
CamilleLaVey 451b8eb80c Some adjustments to EDS 2026-09-30 23:09:44 -04:00
CamilleLaVey e4f74863d2 Overlap barriers on window adapt filter + lsfg dedup 2026-09-30 20:58:40 -04:00
CamilleLaVey 51584f5a63 1st phase of framepacer rework 2026-09-30 17:54:48 -04:00
CamilleLaVey 148a7b24cd Another intent to fix build 2026-09-30 17:27:43 -04:00
CamilleLaVey 940568bb33 fix lsfg build desktop + adjustments 2026-09-30 15:06:43 -04:00
CamilleLaVey 5714c3e477 Experiments with polishing LSFG impl 2026-09-30 14:14:57 -04:00
CamilleLaVey bad10039ae Address some corrections towards MSAA discard/enable removal 2026-09-30 13:03:09 -04:00
CamilleLaVey dd1c024efc Some corrections towards HCR + Discard MSAA 2026-09-30 12:05:15 -04:00
CamilleLaVey 4f5fc58b6e Use copy commands 2 2026-09-30 03:00:07 -04:00
CamilleLaVey efba499fd3 Remove some dependencies to framebuffer and renderpass 2026-09-30 02:47:44 -04:00
CamilleLaVey 41d8da1612 Remove deferred clears 2026-09-30 00:47:14 -04:00
CamilleLaVey 63fc150635 Addresing some problems with TFB and DR 2026-09-30 00:22:27 -04:00
CamilleLaVey 92cbcb8fe5 Revert "God has forsaken me to BDA" 2026-09-29 23:54:39 -04:00
CamilleLaVey 8040f06c87 Revert "quick test to add pointer range management on buffer binding from indirect draws" 2026-09-29 23:54:21 -04:00
CamilleLaVey bdc890f647 quick test to add pointer range management on buffer binding from indirect draws 2026-09-29 23:17:06 -04:00
CamilleLaVey 08917afe0e God has forsaken me to BDA 2026-09-29 21:57:46 -04:00
CamilleLaVey 213d9fb4a7 Just force reads on 8/16bits 2026-09-29 17:46:53 -04:00
CamilleLaVey 2d6f28c50e Some work around CAS 2026-09-29 16:13:50 -04:00
CamilleLaVey ef7cde0c2b Barrier feedback loops toggle android 2026-09-27 02:48:26 -04:00
CamilleLaVey 2d5c79c9f3 Address some bugs with load none vs lrz 2026-09-27 02:44:37 -04:00
CamilleLaVey 14b6160fcd first try on dynamic rendering unused attachments 2026-09-27 01:15:26 -04:00
CamilleLaVey dfe0b7e7c7 A quick test on global memory cbuf tracker 2026-09-26 23:23:38 -04:00
CamilleLaVey b8d9f44421 Another change on GS 2026-09-26 21:38:39 -04:00
CamilleLaVey 7d61946b7c Tfb fix x62132321 2026-09-26 21:33:17 -04:00
CamilleLaVey d8fc94093d More work on GS 2026-09-26 21:14:21 -04:00
CamilleLaVey 4ce91d18b8 Avoid constant calls to fixed pipelines 2026-09-26 18:50:48 -04:00
CamilleLaVey f6cd6128ff Experiment on tfb draws again 2026-09-26 18:28:32 -04:00
CamilleLaVey f3ce6acf53 Another intent on load store op none impl 2026-09-26 17:21:32 -04:00
CamilleLaVey 656370e70a Upload only images needed 2026-09-26 16:43:23 -04:00
CamilleLaVey 16483a27ed Remove PostCopyBarrier on buffers 2026-09-26 15:43:34 -04:00
CamilleLaVey d6f69e14dc experiment with depth ranges 2026-09-26 14:59:01 -04:00
CamilleLaVey 1a65725a35 Fix licenses 2026-09-26 13:37:49 -04:00
CamilleLaVey 381d97639f Rework dynamic rendering impl 2026-09-26 13:30:28 -04:00
CamilleLaVey be4bcbee85 Merge pull request '[arm, vulkan] 5th Vulkan Global Maintenance + NCE maintenance' (#1) from cleanup-vk into master
Reviewed-on: https://git.eden-emu.dev/CamilleLaVey/Eden/pulls/1
2026-09-26 18:57:15 +02:00
CamilleLaVey 49c3a79fa8 Keep adjusting memory barriers to be more explicit 2026-09-26 12:45:27 -04:00
CamilleLaVey 9d4355064b Another try to make barriers more explicit 2026-09-26 12:45:27 -04:00
CamilleLaVey d832f5e156 Re-do geometry compaction pass 2026-09-26 12:45:27 -04:00
CamilleLaVey 5dc91d7e25 Another take on the qcom/turnip missing handling for geometry stages 2026-09-26 12:45:27 -04:00
CamilleLaVey ccbaa75e5e Adjust cuts on depth draws 2026-09-26 12:45:27 -04:00
CamilleLaVey 63ce0a0527 Fix build 2026-09-26 12:45:26 -04:00
CamilleLaVey d2d2220b24 Address some regressions with TFB + SSBO's due to WFI removal 2026-09-26 12:45:26 -04:00
CamilleLaVey bc121efc19 Corrections on the barriers for compute dispatch 2026-09-26 12:45:26 -04:00
CamilleLaVey bcb3fbcf12 Remove the binding/rt image cache 2026-09-26 12:45:26 -04:00
CamilleLaVey ab11282def Keep adjusting the barriers until qcom is finally fixed 2026-09-26 12:45:26 -04:00
CamilleLaVey a5c5966cd8 Keep adjusting barriers 2026-09-26 12:45:26 -04:00
CamilleLaVey 7a007fbf48 Another intent to fix qcom driver bugs with render 2026-09-26 12:45:26 -04:00
CamilleLaVey 3f3240caed Fix android build 2026-09-26 12:45:26 -04:00
CamilleLaVey 19298b713b Removal of WFI + address device creation crash on A6xx 2026-09-26 12:45:26 -04:00
CamilleLaVey 10a21bf246 Another try on sparse binding 2026-09-26 12:45:26 -04:00
CamilleLaVey 108c991431 Experiment on descriptors payloads 2026-09-26 12:45:26 -04:00
CamilleLaVey 98ad2d5e4c Quick tests on payloads 2026-09-26 12:45:26 -04:00
CamilleLaVey 3ff00afd59 Some other dead code removal 2026-09-26 12:45:26 -04:00
CamilleLaVey fd8da678df Re-adjust dispatch draw + masks 2026-09-26 12:45:26 -04:00
CamilleLaVey f71a80671c Remove final references to sync1 2026-09-26 12:45:26 -04:00
CamilleLaVey 6ffd65adaf another intent to remove sync1 and replace it with sync2 completely 2026-09-26 12:45:26 -04:00
CamilleLaVey e6fe763afa Correction on the descriptor pool 2026-09-26 12:45:26 -04:00
CamilleLaVey fa9e069907 Adjust buffer stream size + reduce descriptor loads 2026-09-26 12:45:26 -04:00
CamilleLaVey 3ab215fd30 experiment to address some TPIDR_EL0 stalls 2026-09-26 12:45:26 -04:00
CamilleLaVey 8d8e67cd7f Just an small experiment to simply interpreter 2026-09-26 12:45:26 -04:00
CamilleLaVey 36b06254b4 Fix licenses 2026-09-26 12:45:26 -04:00
CamilleLaVey ffb75c2b68 Revert "[common/core/dynarmic] Optimize page table allocations (#4219)" 2026-09-26 12:43:32 -04:00
CamilleLaVey d82a9c3ba5 Adjust stagging buffer ring 2026-09-26 12:43:32 -04:00
CamilleLaVey b7b90c183f Add checks on texel buffer alignments 2026-09-26 12:43:32 -04:00
CamilleLaVey 1fbb1a0499 Revert QCOM spoof 2026-09-26 12:43:32 -04:00
CamilleLaVey 09371eab60 Remove dead code om VMA 2026-09-26 12:43:32 -04:00
CamilleLaVey 8a8c7f4c06 addresing MHR regression 2026-09-26 12:43:31 -04:00
CamilleLaVey 3a22f908a3 Re-add pitch 2D pass 2026-09-26 12:43:31 -04:00
CamilleLaVey 0dd78bbd07 Re-add unswizzle 3D pass 2026-09-26 12:43:31 -04:00
CamilleLaVey 20d3a4370a Remove the dependency test + remove color texture filter per shasder storage view 2026-09-26 12:43:31 -04:00
CamilleLaVey 1529e30435 quick tests with dependency flags per attachment stage 2026-09-26 12:43:31 -04:00
CamilleLaVey 51d64c298d Some reviews on storage views 2026-09-26 12:43:31 -04:00
CamilleLaVey 3cabafc06a Re-add unswizzle linear 2D to the pass 2026-09-26 12:43:31 -04:00
CamilleLaVey e9436f8094 A test to remove uneeded Finish() 2026-09-26 12:43:31 -04:00
CamilleLaVey 228a400752 Quick change to previous GC adjustment 2026-09-26 12:43:31 -04:00
CamilleLaVey 08741c919a Some changes to GC 2026-09-26 12:43:31 -04:00
CamilleLaVey 17adc28b2c Remove some dead accesors 2026-09-26 12:43:31 -04:00
CamilleLaVey 10528f1ceb Revert some previous changes partially + maintenance5 changes 2026-09-26 12:43:31 -04:00
CamilleLaVey 377478cd46 A quick topology test 2026-09-26 12:43:31 -04:00
CamilleLaVey f92e326e17 Adjustments from the previous change for pipelines 2026-09-26 12:43:30 -04:00
CamilleLaVey b10212fe94 Let's try to change a bit the redundancy 2026-09-26 12:43:30 -04:00
CamilleLaVey 521d3922f5 Fix build 2026-09-26 12:43:30 -04:00
CamilleLaVey 8cdf552c28 Some adjustments to vertex attributes 2026-09-26 12:43:30 -04:00
CamilleLaVey d633c43aae Remove static pipelines 2026-09-26 12:43:30 -04:00
CamilleLaVey 27bcaba75c first intent to pinpoint performance decrease on virtual buffer table + multi-range 2026-09-26 12:43:30 -04:00
CamilleLaVey 64a307c6dc Port some changes from Lizzie's optimization with some exceptions 2026-09-26 12:43:30 -04:00
CamilleLaVey 691b63e79b Quick adjustments on overlapped buffers 2026-09-26 12:43:30 -04:00
CamilleLaVey f955dfedcb remove async vulkan presentation toggle android 2026-09-26 12:43:30 -04:00
CamilleLaVey 86f826c313 Remove astc recompression method 2026-09-26 12:43:30 -04:00
CamilleLaVey 052a04e610 Correcting some bugs on the vulkan async presentation thread 2026-09-26 12:43:30 -04:00
CamilleLaVey bd82351d73 First try to align GOB's 2026-09-26 12:43:30 -04:00
CamilleLaVey a152596f29 Chinga su madre que perramente molesto es este puto juego 2026-09-26 12:43:30 -04:00
CamilleLaVey 40036eb0f8 Remove the thread opt for unswizzle images 2026-09-26 12:43:30 -04:00
CamilleLaVey 0cc76f1f22 First intent to relax the pressure on the gpu thread for unswizzling images 2026-09-26 12:43:30 -04:00
CamilleLaVey b016c88768 Remove the unswizzle path on the extra shaders 2026-09-26 12:43:30 -04:00
CamilleLaVey 6221bd2c43 Reduce accelerated unswizzle path 2026-09-26 12:43:30 -04:00
CamilleLaVey facee08b5e More tests to find out the texture corruption on previous unswizzle changes 2026-09-26 12:43:30 -04:00
CamilleLaVey 43622f463d A test for a corrupted unswizzled textures 2026-09-26 12:43:30 -04:00
CamilleLaVey 9bedcf6202 Keep working on ASTC 2026-09-26 12:43:29 -04:00
CamilleLaVey 66a25a3d79 Some unvalid checks on astc decoder 2026-09-26 12:43:29 -04:00
CamilleLaVey b24c3d7226 Keep refining astc decoding math 2026-09-26 12:43:29 -04:00
CamilleLaVey 26031c0940 Fixes on the astc decoder 2026-09-26 12:43:29 -04:00
CamilleLaVey 930b64858e Fix build 2026-09-26 12:43:29 -04:00
CamilleLaVey b1e512c152 Some cleanups 2026-09-15 21:10:36 -04:00
363 changed files with 23643 additions and 29604 deletions
+2 -2
View File
@@ -82,8 +82,8 @@ cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSV
option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF) option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF)
option(ENABLE_WERROR "Enable -Werror diagnostics" ON) option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
# Lossless Scaling frame generation. Only Android. # Lossless Scaling frame generation.
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF) option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON)
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON) option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
-5
View File
@@ -333,11 +333,6 @@
"repo": "herumi/xbyak", "repo": "herumi/xbyak",
"version": "v7.40.1" "version": "v7.40.1"
}, },
"zbic": {
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
"repo": "kinnay/zbic",
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
},
"zlib": { "zlib": {
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4", "hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
"min_version": "1.2", "min_version": "1.2",
+579 -624
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+503 -548
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+508 -550
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+527 -573
View File
File diff suppressed because it is too large Load Diff
+502 -547
View File
File diff suppressed because it is too large Load Diff
+21 -33
View File
@@ -1,44 +1,32 @@
# User Handbook - Command Line # User Handbook - Command Line
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept the same command line arguments. There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
## eden
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application. - `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application.
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234` - `-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
- `--config/-c`: Specify alternate configuration file. - `-f`: Use fullscreen.
- `--fullscreen/-f`: Use fullscreen. - `-u <number>`: Select the index of the user to load as.
- `--help/-h`: Display help. - `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
- `--game/-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
- `--multiplayer/-m`: Specify multiplayer options.
- `--program/-p`: Specify the program arguments to pass (optional).
- `--user/-u <number>`: Specify the user index.
- `--version/-v`: Display version and quit.
- `--input-profile/-i <name>`: Specifies input profile name to use (for player #0 only).
- `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
- `--filter/-x`: Sets the debug log filter irrespective of settings.
- `--singlecore/-s`: Forces single-core regardless of settings.
Only the Qt frontend supports the following arguments:
- `-qlaunch`: Launch QLaunch. - `-qlaunch`: Launch QLaunch.
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`. - `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
- Requires a copy of Atmosphere to be extracted onto `sdmc`. - Requires a copy of Atmosphere to be extracted onto `sdmc`.
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`. - This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
- `-setup`: Launch setup applet. - `-setup`: Launch setup applet.
`eden` (provided with `--room`), and `eden-room` supports the following options as well: ## eden-cli
- `-n/--room-name`: The name of the room. - `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
- `-d/--room-description`: The room description. - `--config/-c`: Specify alternate configuration file.
- `-s/--bind-address`: The bind address for the room. - `--fullscreen/-f`: Set fullscreen.
- `-p/--port`: The port used for the room. - `--help/-h`: Display help.
- `-m/--max-members`: The maximum number of players for this room. - `--game/-g`: Specify the game to run.
- `-w/--password`: The password for the room. - `--multiplayer/-m`: Specify multiplayer options.
- `-g/--preferred-game`: The preferred game for this room. - `--program/-p`: Specify the program arguments to pass (optional).
- `-i/--preferred-game-id`: The preferred game-id for this room. - `--user/-u`: Specify the user index.
- `-u/--username`: The username used for announce. - `--version/-v`: Display version and quit.
- `-t/--token`: The token used for announce. - `--input-profile/-i`: Specifies input profile name to use (for player #0 only).
- `-a/--web-api-url`: yuzu Web API url. - `--null-render/-n`: Forces the usage of the "Null" render backend irrespective of settings.
- `-b/--ban-list-file`: The file for storing the room ban list. - `--filter/-x`: Sets the debug log filter irrespective of settings.
- `-l/--log-file`: The file for storing the room log. - `--singlecore/-s`: Forces single-core regardless of settings.
- `-h/--help`: Display this help and exit.
- `-v/--version`: Output version information and exit.
-5
View File
@@ -48,11 +48,6 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb) add_library(stb::headers ALIAS stb)
endif() endif()
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
set(ZBIC_INCLUDE_DIR
"${zbic_SOURCE_DIR}/src"
PARENT_SCOPE)
# ItaniumDemangle (Windows only) # ItaniumDemangle (Windows only)
if (WIN32 AND NOT TARGET LLVM::Demangle) if (WIN32 AND NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp) add_library(demangle demangle/ItaniumDemangle.cpp)
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.adapters package org.yuzu.yuzu_emu.adapters
@@ -20,17 +20,21 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
EMULATE_BGR565("emulate_bgr565"), EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"), RESCALE_HACK("rescale_hack"),
CPUOPT_UNSAFE_HOST_MMU("cpuopt_unsafe_host_mmu"), CPUOPT_UNSAFE_HOST_MMU("cpuopt_unsafe_host_mmu"),
RELOCATE_36BIT_ADDRESS_SPACE("relocate_36bit_address_space"),
USE_DOCKED_MODE("use_docked_mode"), USE_DOCKED_MODE("use_docked_mode"),
USE_AUTO_STUB("use_auto_stub"), USE_AUTO_STUB("use_auto_stub"),
RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"), RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
RENDERER_FORCE_MAX_CLOCK("force_max_clock"), RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"), RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"),
RENDERER_ASYNC_PRESENTATION("async_presentation"),
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"), RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"), RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
RENDERER_BARRIER_FEEDBACK_LOOPS("barrier_feedback_loops"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"), ENABLE_BUFFER_HISTORY("enable_buffer_history"),
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"), USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
USE_UNIFIED_MEMORY("use_unified_memory"),
SYNC_MEMORY_OPERATIONS("sync_memory_operations"), SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
STALL_ON_GPU_FENCE_WAIT("stall_on_gpu_fence_wait"),
BUFFER_REORDER_DISABLE("disable_buffer_reorder"), BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
RENDERER_DEBUG("debug"), RENDERER_DEBUG("debug"),
RENDERER_PATCH_OLD_QCOM_DRIVERS("patch_old_qcom_drivers"), RENDERER_PATCH_OLD_QCOM_DRIVERS("patch_old_qcom_drivers"),
@@ -38,7 +42,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_SAMPLE_SHADING("sample_shading"), RENDERER_SAMPLE_SHADING("sample_shading"),
RENDERER_FRAME_GEN("frame_gen"), RENDERER_FRAME_GEN("frame_gen"),
RENDERER_FRAME_GEN_FLOW_SCALE_AUTO("frame_gen_flow_scale_auto"), RENDERER_FRAME_GEN_FLOW_SCALE_AUTO("frame_gen_flow_scale_auto"),
GPU_UNSWIZZLE_ENABLED("gpu_unswizzle_enabled"),
PICTURE_IN_PICTURE("picture_in_picture"), PICTURE_IN_PICTURE("picture_in_picture"),
USE_CUSTOM_RTC("custom_rtc_enabled"), USE_CUSTOM_RTC("custom_rtc_enabled"),
BLACK_BACKGROUNDS("black_backgrounds"), BLACK_BACKGROUNDS("black_backgrounds"),
@@ -32,7 +32,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
RENDERER_DYNA_STATE("dyna_state"), RENDERER_DYNA_STATE("dyna_state"),
DMA_ACCURACY("dma_accuracy"), DMA_ACCURACY("dma_accuracy"),
GPU_FENCE_BEHAVIOR("gpu_fence_behavior"), GPU_FENCE_BEHAVIOR("gpu_fence_behavior"),
FRAME_PACING_MODE("frame_pacing_mode"),
AUDIO_OUTPUT_ENGINE("output_engine"), AUDIO_OUTPUT_ENGINE("output_engine"),
MAX_ANISOTROPY("max_anisotropy"), MAX_ANISOTROPY("max_anisotropy"),
THEME("theme"), THEME("theme"),
@@ -51,9 +50,6 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
FAST_CPU_TIME("fast_cpu_time"), FAST_CPU_TIME("fast_cpu_time"),
CPU_TICKS("cpu_ticks"), CPU_TICKS("cpu_ticks"),
FAST_GPU_TIME("fast_gpu_time"), FAST_GPU_TIME("fast_gpu_time"),
GPU_UNSWIZZLE_TEXTURE_SIZE("gpu_unswizzle_texture_size"),
GPU_UNSWIZZLE_STREAM_SIZE("gpu_unswizzle_stream_size"),
GPU_UNSWIZZLE_CHUNK_SIZE("gpu_unswizzle_chunk_size"),
BAT_TEMPERATURE_UNIT("bat_temperature_unit"), BAT_TEMPERATURE_UNIT("bat_temperature_unit"),
CABINET_APPLET("cabinet_applet_mode"), CABINET_APPLET("cabinet_applet_mode"),
CONTROLLER_APPLET("controller_applet_mode"), CONTROLLER_APPLET("controller_applet_mode"),
@@ -1,89 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.ArrayRes
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
class GpuUnswizzleSetting(
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = "",
@ArrayRes val textureSizeChoicesId: Int,
@ArrayRes val textureSizeValuesId: Int,
@ArrayRes val streamSizeChoicesId: Int,
@ArrayRes val streamSizeValuesId: Int,
@ArrayRes val chunkSizeChoicesId: Int,
@ArrayRes val chunkSizeValuesId: Int
) : SettingsItem(
object : AbstractSetting {
override val key: String = SettingsItem.GPU_UNSWIZZLE_COMBINED
override val defaultValue: Any = false
override val isSaveable = true
override val isRuntimeModifiable = true
override val isSwitchable = true
override val pairedSettingKey: String = ""
override var global: Boolean
get() {
return BooleanSetting.GPU_UNSWIZZLE_ENABLED.global &&
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.global &&
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.global &&
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.global
}
set(value) {
BooleanSetting.GPU_UNSWIZZLE_ENABLED.global = value
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.global = value
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.global = value
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.global = value
}
override fun getValueAsString(needsGlobal: Boolean): String = "combined"
override fun reset() {
BooleanSetting.GPU_UNSWIZZLE_ENABLED.reset()
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.reset()
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.reset()
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.reset()
}
},
titleId,
titleString,
descriptionId,
descriptionString
) {
override val type = SettingsItem.TYPE_GPU_UNSWIZZLE
// Check if GPU unswizzle is enabled via the dedicated boolean setting
fun isEnabled(needsGlobal: Boolean = false): Boolean =
BooleanSetting.GPU_UNSWIZZLE_ENABLED.getBoolean(needsGlobal)
fun setEnabled(value: Boolean) =
BooleanSetting.GPU_UNSWIZZLE_ENABLED.setBoolean(value)
fun enable() = setEnabled(true)
fun disable() = setEnabled(false)
fun getTextureSize(needsGlobal: Boolean = false): Int =
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.getInt(needsGlobal)
fun setTextureSize(value: Int) =
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE.setInt(value)
fun getStreamSize(needsGlobal: Boolean = false): Int =
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.getInt(needsGlobal)
fun setStreamSize(value: Int) =
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE.setInt(value)
fun getChunkSize(needsGlobal: Boolean = false): Int =
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.getInt(needsGlobal)
fun setChunkSize(value: Int) =
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE.setInt(value)
fun reset() = setting.reset()
}
@@ -141,14 +141,12 @@ abstract class SettingsItem(
const val TYPE_SPINBOX = 12 const val TYPE_SPINBOX = 12
const val TYPE_LAUNCHABLE = 13 const val TYPE_LAUNCHABLE = 13
const val TYPE_PATH = 14 const val TYPE_PATH = 14
const val TYPE_GPU_UNSWIZZLE = 15
const val TYPE_FX_TOOLBAR = 16 const val TYPE_FX_TOOLBAR = 16
const val TYPE_FX_PRESET = 17 const val TYPE_FX_PRESET = 17
const val TYPE_FX_SHADER = 18 const val TYPE_FX_SHADER = 18
const val TYPE_FX_BUTTON = 19 const val TYPE_FX_BUTTON = 19
const val FASTMEM_COMBINED = "fastmem_combined" const val FASTMEM_COMBINED = "fastmem_combined"
const val GPU_UNSWIZZLE_COMBINED = "gpu_unswizzle_combined"
val emptySetting = object : AbstractSetting { val emptySetting = object : AbstractSetting {
override val key: String = "" override val key: String = ""
@@ -753,13 +751,6 @@ abstract class SettingsItem(
descriptionId = R.string.renderer_asynchronous_gpu_emulation_description descriptionId = R.string.renderer_asynchronous_gpu_emulation_description
) )
) )
put(
SwitchSetting(
BooleanSetting.RENDERER_ASYNC_PRESENTATION,
titleId = R.string.renderer_async_presentation,
descriptionId = R.string.renderer_async_presentation_description
)
)
put( put(
SingleChoiceSetting( SingleChoiceSetting(
IntSetting.DMA_ACCURACY, IntSetting.DMA_ACCURACY,
@@ -794,45 +785,6 @@ abstract class SettingsItem(
valuesId = R.array.gpuValues valuesId = R.array.gpuValues
) )
) )
put(
SingleChoiceSetting(
IntSetting.GPU_UNSWIZZLE_TEXTURE_SIZE,
titleId = R.string.gpu_unswizzle_texture_size,
descriptionId = R.string.gpu_unswizzle_texture_size_description,
choicesId = R.array.gpuTextureSizeSwizzleEntries,
valuesId = R.array.gpuTextureSizeSwizzleValues
)
)
put(
SingleChoiceSetting(
IntSetting.GPU_UNSWIZZLE_STREAM_SIZE,
titleId = R.string.gpu_unswizzle_stream_size,
descriptionId = R.string.gpu_unswizzle_stream_size_description,
choicesId = R.array.gpuSwizzleEntries,
valuesId = R.array.gpuSwizzleValues
)
)
put(
SingleChoiceSetting(
IntSetting.GPU_UNSWIZZLE_CHUNK_SIZE,
titleId = R.string.gpu_unswizzle_chunk_size,
descriptionId = R.string.gpu_unswizzle_chunk_size_description,
choicesId = R.array.gpuSwizzleChunkEntries,
valuesId = R.array.gpuSwizzleChunkValues
)
)
put(
GpuUnswizzleSetting(
titleId = R.string.gpu_unswizzle_settings,
descriptionId = R.string.gpu_unswizzle_settings_description,
textureSizeChoicesId = R.array.gpuTextureSizeSwizzleEntries,
textureSizeValuesId = R.array.gpuTextureSizeSwizzleValues,
streamSizeChoicesId = R.array.gpuSwizzleEntries,
streamSizeValuesId = R.array.gpuSwizzleValues,
chunkSizeChoicesId = R.array.gpuSwizzleChunkEntries,
chunkSizeValuesId = R.array.gpuSwizzleChunkValues
)
)
put( put(
SingleChoiceSetting( SingleChoiceSetting(
IntSetting.FAST_CPU_TIME, IntSetting.FAST_CPU_TIME,
@@ -894,6 +846,13 @@ abstract class SettingsItem(
descriptionId = R.string.cpuopt_unsafe_host_mmu_description descriptionId = R.string.cpuopt_unsafe_host_mmu_description
) )
) )
put(
SwitchSetting(
BooleanSetting.RELOCATE_36BIT_ADDRESS_SPACE,
titleId = R.string.relocate_36bit_address_space,
descriptionId = R.string.relocate_36bit_address_space_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.RENDERER_REACTIVE_FLUSHING, BooleanSetting.RENDERER_REACTIVE_FLUSHING,
@@ -901,6 +860,13 @@ abstract class SettingsItem(
descriptionId = R.string.renderer_reactive_flushing_description descriptionId = R.string.renderer_reactive_flushing_description
) )
) )
put(
SwitchSetting(
BooleanSetting.RENDERER_BARRIER_FEEDBACK_LOOPS,
titleId = R.string.renderer_barrier_feedback_loops,
descriptionId = R.string.renderer_barrier_feedback_loops_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.ENABLE_BUFFER_HISTORY, BooleanSetting.ENABLE_BUFFER_HISTORY,
@@ -908,6 +874,20 @@ abstract class SettingsItem(
descriptionId = R.string.enable_buffer_history_description descriptionId = R.string.enable_buffer_history_description
) )
) )
put(
SwitchSetting(
BooleanSetting.ENABLE_GPU_BUFFER_READBACK,
titleId = R.string.enable_gpu_buffer_readback,
descriptionId = R.string.enable_gpu_buffer_readback_description
)
)
put(
SwitchSetting(
BooleanSetting.USE_UNIFIED_MEMORY,
titleId = R.string.use_unified_memory,
descriptionId = R.string.use_unified_memory_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS, BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS,
@@ -922,6 +902,13 @@ abstract class SettingsItem(
descriptionId = R.string.sync_memory_operations_description descriptionId = R.string.sync_memory_operations_description
) )
) )
put(
SwitchSetting(
BooleanSetting.STALL_ON_GPU_FENCE_WAIT,
titleId = R.string.stall_on_gpu_fence_wait,
descriptionId = R.string.stall_on_gpu_fence_wait_description
)
)
put( put(
SwitchSetting( SwitchSetting(
BooleanSetting.BUFFER_REORDER_DISABLE, BooleanSetting.BUFFER_REORDER_DISABLE,
@@ -1,206 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.widget.ArrayAdapter
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogGpuUnswizzleBinding
import org.yuzu.yuzu_emu.features.settings.model.view.GpuUnswizzleSetting
class GpuUnswizzleDialogFragment : DialogFragment() {
private var position = 0
private val settingsViewModel: SettingsViewModel by activityViewModels()
private lateinit var binding: DialogGpuUnswizzleBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
position = requireArguments().getInt(POSITION)
if (settingsViewModel.clickedItem == null) dismiss()
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
binding = DialogGpuUnswizzleBinding.inflate(LayoutInflater.from(requireContext()))
val item = settingsViewModel.clickedItem as GpuUnswizzleSetting
// Setup texture size dropdown
val textureSizeEntries = resources.getStringArray(item.textureSizeChoicesId)
val textureSizeValues = resources.getIntArray(item.textureSizeValuesId)
val textureSizeAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
textureSizeEntries.toMutableList()
)
binding.dropdownTextureSize.setAdapter(textureSizeAdapter)
// Setup stream size dropdown
val streamSizeEntries = resources.getStringArray(item.streamSizeChoicesId)
val streamSizeValues = resources.getIntArray(item.streamSizeValuesId)
val streamSizeAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
streamSizeEntries.toMutableList()
)
binding.dropdownStreamSize.setAdapter(streamSizeAdapter)
// Setup chunk size dropdown
val chunkSizeEntries = resources.getStringArray(item.chunkSizeChoicesId)
val chunkSizeValues = resources.getIntArray(item.chunkSizeValuesId)
val chunkSizeAdapter = ArrayAdapter(
requireContext(),
android.R.layout.simple_dropdown_item_1line,
chunkSizeEntries.toMutableList()
)
binding.dropdownChunkSize.setAdapter(chunkSizeAdapter)
// Load current values
val isEnabled = item.isEnabled()
binding.switchEnable.isChecked = isEnabled
if (isEnabled) {
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
if (textureSizeIndex >= 0) {
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
}
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
if (streamSizeIndex >= 0) {
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
}
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
if (chunkSizeIndex >= 0) {
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
}
} else {
// Set default/recommended values when disabling
binding.dropdownTextureSize.setText(textureSizeEntries[3], false)
binding.dropdownStreamSize.setText(streamSizeEntries[3], false)
binding.dropdownChunkSize.setText(chunkSizeEntries[3], false)
}
// Clear adapter filters after setText to fix rotation bug
textureSizeAdapter.filter.filter(null)
streamSizeAdapter.filter.filter(null)
chunkSizeAdapter.filter.filter(null)
// Enable/disable dropdowns based on switch state
updateDropdownsState(isEnabled)
binding.switchEnable.setOnCheckedChangeListener { _, checked ->
updateDropdownsState(checked)
}
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(item.title)
.setView(binding.root)
.create()
// Setup button listeners
binding.btnDefault.setOnClickListener {
// Reset to defaults
item.reset()
// Refresh values with adapters reset
val textureSizeIndex = textureSizeValues.indexOf(item.getTextureSize())
if (textureSizeIndex >= 0) {
binding.dropdownTextureSize.setText(textureSizeEntries[textureSizeIndex], false)
}
val streamSizeIndex = streamSizeValues.indexOf(item.getStreamSize())
if (streamSizeIndex >= 0) {
binding.dropdownStreamSize.setText(streamSizeEntries[streamSizeIndex], false)
}
val chunkSizeIndex = chunkSizeValues.indexOf(item.getChunkSize())
if (chunkSizeIndex >= 0) {
binding.dropdownChunkSize.setText(chunkSizeEntries[chunkSizeIndex], false)
}
// Clear filters
textureSizeAdapter.filter.filter(null)
streamSizeAdapter.filter.filter(null)
chunkSizeAdapter.filter.filter(null)
settingsViewModel.setAdapterItemChanged(position)
settingsViewModel.setShouldReloadSettingsList(true)
}
binding.btnCancel.setOnClickListener {
dialog.dismiss()
}
binding.btnOk.setOnClickListener {
if (binding.switchEnable.isChecked) {
item.enable()
// Save the selected values
val selectedTextureIndex = textureSizeEntries.indexOf(
binding.dropdownTextureSize.text.toString()
)
if (selectedTextureIndex >= 0) {
item.setTextureSize(textureSizeValues[selectedTextureIndex])
}
val selectedStreamIndex = streamSizeEntries.indexOf(
binding.dropdownStreamSize.text.toString()
)
if (selectedStreamIndex >= 0) {
item.setStreamSize(streamSizeValues[selectedStreamIndex])
}
val selectedChunkIndex = chunkSizeEntries.indexOf(
binding.dropdownChunkSize.text.toString()
)
if (selectedChunkIndex >= 0) {
item.setChunkSize(chunkSizeValues[selectedChunkIndex])
}
} else {
// Disable GPU unswizzle
item.disable()
}
settingsViewModel.setAdapterItemChanged(position)
settingsViewModel.setShouldReloadSettingsList(true)
dialog.dismiss()
}
// Ensure filters are cleared after dialog is shown
binding.root.post {
textureSizeAdapter.filter.filter(null)
streamSizeAdapter.filter.filter(null)
chunkSizeAdapter.filter.filter(null)
}
return dialog
}
private fun updateDropdownsState(enabled: Boolean) {
binding.layoutTextureSize.isEnabled = enabled
binding.dropdownTextureSize.isEnabled = enabled
binding.layoutStreamSize.isEnabled = enabled
binding.dropdownStreamSize.isEnabled = enabled
binding.layoutChunkSize.isEnabled = enabled
binding.dropdownChunkSize.isEnabled = enabled
}
companion object {
const val TAG = "GpuUnswizzleDialogFragment"
const val POSITION = "Position"
fun newInstance(
settingsViewModel: SettingsViewModel,
item: GpuUnswizzleSetting,
position: Int
): GpuUnswizzleDialogFragment {
val dialog = GpuUnswizzleDialogFragment()
val args = Bundle()
args.putInt(POSITION, position)
dialog.arguments = args
settingsViewModel.clickedItem = item
return dialog
}
}
}
@@ -106,10 +106,6 @@ class SettingsAdapter(
PathViewHolder(ListItemSettingBinding.inflate(inflater), this) PathViewHolder(ListItemSettingBinding.inflate(inflater), this)
} }
SettingsItem.TYPE_GPU_UNSWIZZLE -> {
GpuUnswizzleViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_FX_TOOLBAR -> { SettingsItem.TYPE_FX_TOOLBAR -> {
FxToolbarViewHolder( FxToolbarViewHolder(
ListItemSettingFxToolbarBinding.inflate(inflater, parent, false), ListItemSettingFxToolbarBinding.inflate(inflater, parent, false),
@@ -511,14 +507,6 @@ class SettingsAdapter(
settingsViewModel.setShouldShowPathResetDialog(true) settingsViewModel.setShouldShowPathResetDialog(true)
} }
fun onGpuUnswizzleClick(item: GpuUnswizzleSetting, position: Int) {
GpuUnswizzleDialogFragment.newInstance(
settingsViewModel,
item,
position
).show(fragment.childFragmentManager, GpuUnswizzleDialogFragment.TAG)
}
private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() { private class DiffCallback : DiffUtil.ItemCallback<SettingsItem>() {
override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean { override fun areItemsTheSame(oldItem: SettingsItem, newItem: SettingsItem): Boolean {
return oldItem.setting.key == newItem.setting.key return oldItem.setting.key == newItem.setting.key
@@ -545,10 +545,14 @@ class SettingsFragmentPresenter(
add(IntSetting.RENDERER_NVDEC_EMULATION.key) add(IntSetting.RENDERER_NVDEC_EMULATION.key)
add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key) add(BooleanSetting.SYNC_MEMORY_OPERATIONS.key)
add(BooleanSetting.STALL_ON_GPU_FENCE_WAIT.key)
add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key) add(BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key)
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key) add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key) add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
add(BooleanSetting.RENDERER_BARRIER_FEEDBACK_LOOPS.key)
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key) add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
add(BooleanSetting.USE_UNIFIED_MEMORY.key)
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key) add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
add(HeaderSetting(R.string.hacks)) add(HeaderSetting(R.string.hacks))
@@ -559,8 +563,6 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
add(IntSetting.ANDROID_PIPELINE_WORKERS.key) add(IntSetting.ANDROID_PIPELINE_WORKERS.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key) add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
add(HeaderSetting(R.string.extensions)) add(HeaderSetting(R.string.extensions))
@@ -1526,6 +1528,7 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.cpu)) add(HeaderSetting(R.string.cpu))
add(IntSetting.CPU_BACKEND.key) add(IntSetting.CPU_BACKEND.key)
add(BooleanSetting.RELOCATE_36BIT_ADDRESS_SPACE.key)
add(IntSetting.CPU_ACCURACY.key) add(IntSetting.CPU_ACCURACY.key)
add(BooleanSetting.USE_AUTO_STUB.key) add(BooleanSetting.USE_AUTO_STUB.key)
add(SettingsItem.FASTMEM_COMBINED) add(SettingsItem.FASTMEM_COMBINED)
@@ -1,71 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.GpuUnswizzleSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class GpuUnswizzleViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: GpuUnswizzleSetting
override fun bind(item: SettingsItem) {
setting = item as GpuUnswizzleSetting
binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = item.description
binding.textSettingValue.setVisible(true)
val resMgr = binding.root.context.resources
if (setting.isEnabled()) {
// Show a summary of current settings
val textureSizeEntries = resMgr.getStringArray(setting.textureSizeChoicesId)
val textureSizeValues = resMgr.getIntArray(setting.textureSizeValuesId)
val textureSizeIndex = textureSizeValues.indexOf(setting.getTextureSize())
val textureSizeLabel = if (textureSizeIndex >= 0) textureSizeEntries[textureSizeIndex] else "?"
val streamSizeEntries = resMgr.getStringArray(setting.streamSizeChoicesId)
val streamSizeValues = resMgr.getIntArray(setting.streamSizeValuesId)
val streamSizeIndex = streamSizeValues.indexOf(setting.getStreamSize())
val streamSizeLabel = if (streamSizeIndex >= 0) streamSizeEntries[streamSizeIndex] else "?"
val chunkSizeEntries = resMgr.getStringArray(setting.chunkSizeChoicesId)
val chunkSizeValues = resMgr.getIntArray(setting.chunkSizeValuesId)
val chunkSizeIndex = chunkSizeValues.indexOf(setting.getChunkSize())
val chunkSizeLabel = if (chunkSizeIndex >= 0) chunkSizeEntries[chunkSizeIndex] else "?"
binding.textSettingValue.text = "$textureSizeLabel ⋅ $streamSizeLabel ⋅ $chunkSizeLabel"
} else {
binding.textSettingValue.text = resMgr.getString(R.string.gpu_unswizzle_disabled)
}
binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
if (!setting.isEditable) {
return
}
adapter.onGpuUnswizzleClick(setting, bindingAdapterPosition)
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting, bindingAdapterPosition)
}
return false
}
}
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@@ -64,8 +64,8 @@ void EmuWindow_Android::OnTouchReleased(int id) {
EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id); EmulationSession::GetInstance().GetInputSubsystem().GetTouchScreen()->TouchReleased(id);
} }
void EmuWindow_Android::OnFrameDisplayed() { void EmuWindow_Android::OnFrameDisplayed(u32 presented_frames) {
UpdateObservedFrameRate(); UpdateObservedFrameRate(presented_frames);
UpdateFrameRateHint(); UpdateFrameRateHint();
if (!m_first_frame) { if (!m_first_frame) {
@@ -75,15 +75,16 @@ void EmuWindow_Android::OnFrameDisplayed() {
} }
} }
void EmuWindow_Android::UpdateObservedFrameRate() { void EmuWindow_Android::UpdateObservedFrameRate(u32 presented_frames) {
m_presented_frames = static_cast<float>((std::max)(presented_frames, 1u));
const auto now = Clock::now(); const auto now = Clock::now();
if (m_last_frame_display_time.time_since_epoch().count() != 0) { if (m_last_frame_display_time.time_since_epoch().count() != 0) {
const auto frame_time = std::chrono::duration<float>(now - m_last_frame_display_time); const auto frame_time = std::chrono::duration<float>(now - m_last_frame_display_time);
const float seconds = frame_time.count(); const float seconds = frame_time.count();
if (seconds > 0.0f) { if (seconds > 0.0f) {
const float instantaneous_rate = 1.0f / seconds; const float instantaneous_rate = m_presented_frames / seconds;
if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 1.0f && if (std::isfinite(instantaneous_rate) && instantaneous_rate >= 1.0f &&
instantaneous_rate <= 240.0f) { instantaneous_rate <= 240.0f * m_presented_frames) {
constexpr float SmoothingFactor = 0.15f; constexpr float SmoothingFactor = 0.15f;
if (m_smoothed_present_rate <= 0.0f) { if (m_smoothed_present_rate <= 0.0f) {
m_smoothed_present_rate = instantaneous_rate; m_smoothed_present_rate = instantaneous_rate;
@@ -124,18 +125,9 @@ float EmuWindow_Android::GetFrameTimeVerifiedHint() const {
return QuantizeFrameRateHint(verified_rate); return QuantizeFrameRateHint(verified_rate);
} }
float EmuWindow_Android::GetPresentedFrameMultiplier() {
if (!Settings::values.frame_gen.GetValue()) {
return 1.0f;
}
return static_cast<float>(std::clamp<u32>(Settings::values.frame_gen_multiplier.GetValue(), 2, 4));
}
float EmuWindow_Android::GetFrameRateHint() const { float EmuWindow_Android::GetFrameRateHint() const {
const float presented_multiplier = GetPresentedFrameMultiplier(); const float observed_rate = std::clamp(m_smoothed_present_rate, 0.0f, 240.0f);
const float observed_rate = const float frame_time_verified_hint = GetFrameTimeVerifiedHint() * m_presented_frames;
std::clamp(m_smoothed_present_rate * presented_multiplier, 0.0f, 240.0f);
const float frame_time_verified_hint = GetFrameTimeVerifiedHint() * presented_multiplier;
if (m_last_frame_rate_hint > 0.0f && observed_rate > 0.0f) { if (m_last_frame_rate_hint > 0.0f && observed_rate > 0.0f) {
const float tolerance = std::max(m_last_frame_rate_hint * 0.12f, 4.0f); const float tolerance = std::max(m_last_frame_rate_hint * 0.12f, 4.0f);
@@ -159,7 +151,7 @@ float EmuWindow_Android::GetFrameRateHint() const {
return frame_time_verified_hint; return frame_time_verified_hint;
} }
const float nominal_rate = 60.0f * presented_multiplier; const float nominal_rate = 60.0f * m_presented_frames;
if (!Settings::values.use_speed_limit.GetValue()) { if (!Settings::values.use_speed_limit.GetValue()) {
return QuantizeFrameRateHint(nominal_rate); return QuantizeFrameRateHint(nominal_rate);
} }
@@ -41,7 +41,7 @@ public:
~EmuWindow_Android() = default; ~EmuWindow_Android() = default;
void OnSurfaceChanged(ANativeWindow* surface); void OnSurfaceChanged(ANativeWindow* surface);
void OnFrameDisplayed() override; void OnFrameDisplayed(u32 presented_frames) override;
void OnTouchPressed(int id, float x, float y); void OnTouchPressed(int id, float x, float y);
void OnTouchMoved(int id, float x, float y); void OnTouchMoved(int id, float x, float y);
@@ -58,10 +58,9 @@ private:
using Clock = std::chrono::steady_clock; using Clock = std::chrono::steady_clock;
void UpdateFrameRateHint(); void UpdateFrameRateHint();
void UpdateObservedFrameRate(); void UpdateObservedFrameRate(u32 presented_frames);
[[nodiscard]] float GetFrameRateHint() const; [[nodiscard]] float GetFrameRateHint() const;
[[nodiscard]] float GetFrameTimeVerifiedHint() const; [[nodiscard]] float GetFrameTimeVerifiedHint() const;
[[nodiscard]] static float GetPresentedFrameMultiplier();
[[nodiscard]] static float QuantizeFrameRateHint(float frame_rate); [[nodiscard]] static float QuantizeFrameRateHint(float frame_rate);
float m_window_width{}; float m_window_width{};
@@ -73,6 +72,7 @@ private:
float m_last_frame_rate_hint = -1.0f; float m_last_frame_rate_hint = -1.0f;
float m_pending_frame_rate_hint = -1.0f; float m_pending_frame_rate_hint = -1.0f;
float m_smoothed_present_rate = 0.0f; float m_smoothed_present_rate = 0.0f;
float m_presented_frames = 1.0f;
Clock::time_point m_last_frame_display_time{}; Clock::time_point m_last_frame_display_time{};
Clock::time_point m_pending_frame_rate_since{}; Clock::time_point m_pending_frame_rate_since{};
std::uint32_t m_pending_frame_rate_hint_votes = 0; std::uint32_t m_pending_frame_rate_hint_votes = 0;
+45 -52
View File
@@ -738,6 +738,35 @@ const char* fallback_cpu_detection() {
return s_result.c_str(); return s_result.c_str();
} }
#ifdef ARCHITECTURE_arm64
struct SystemDriverInfo {
VkPhysicalDeviceProperties properties{};
VkPhysicalDeviceDriverProperties driver{};
};
SystemDriverInfo QuerySystemDriverInfo(JNIEnv* env, jstring j_hook_lib_dir) {
const std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir);
const Common::DynamicLibrary library{adrenotools_open_libvulkan(
RTLD_NOW, 0, nullptr, hook_lib_dir.c_str(), nullptr, nullptr, nullptr, nullptr)};
Vulkan::vk::InstanceDispatch dld;
const Vulkan::vk::Instance instance = Vulkan::CreateInstance(library, dld, VK_API_VERSION_1_1);
const std::vector<VkPhysicalDevice> devices = instance.EnumeratePhysicalDevices();
if (devices.empty()) {
throw Vulkan::vk::Exception(VK_ERROR_INITIALIZATION_FAILED);
}
SystemDriverInfo info{};
info.driver.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
VkPhysicalDeviceProperties2 properties2{
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2,
.pNext = &info.driver,
.properties = {},
};
Vulkan::vk::PhysicalDevice(devices[0], dld).GetProperties2(properties2);
info.properties = properties2.properties;
return info;
}
#endif
} // namespace } // namespace
extern "C" { extern "C" {
@@ -788,7 +817,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj, jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId, jstring jprogramId,
jstring jupdatePath) { jstring jupdatePath) {
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId)); u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
std::string updatePath = Common::Android::GetJString(env, jupdatePath); std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>( std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
@@ -796,7 +825,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
for (const auto& item : nsp->GetNCAs()) { for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) { for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) { if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId()); auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
if (update_id == program_id) { if (update_id == program_id) {
return true; return true;
} }
@@ -857,34 +886,18 @@ jboolean JNICALL Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_supportsCustomDri
jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo( jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) { JNIEnv* env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
std::string version_string{"1.1.0"};
std::string driver_name{"generic"};
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
const char* file_redirect_dir_{}; try {
int featureFlags{}; const SystemDriverInfo info = QuerySystemDriverInfo(env, j_hook_lib_dir);
std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir); const u32 driver_version = info.properties.driverVersion;
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), version_string =
nullptr, nullptr, file_redirect_dir_, nullptr);
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
InputCommon::InputSubsystem input_subsystem;
auto window =
std::make_unique<EmuWindow_Android>(ANativeWindow_fromSurface(env, j_surf), driver_library);
Vulkan::vk::InstanceDispatch dld;
Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance(
*driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android);
auto surface = Vulkan::CreateSurface(vk_instance, window->GetWindowInfo());
auto device = Vulkan::CreateDevice(vk_instance, dld, *surface);
auto driver_version = device.GetDriverVersion();
auto version_string =
fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version), fmt::format("{}.{}.{}", VK_API_VERSION_MAJOR(driver_version),
VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version)); VK_API_VERSION_MINOR(driver_version), VK_API_VERSION_PATCH(driver_version));
auto driver_name = device.GetDriverName(); driver_name = Vulkan::vk::GetDriverName(info.driver);
#else } catch (...) {
auto driver_version = "1.0.0"; }
auto version_string = "1.1.0"; //Assume lowest Vulkan level
auto driver_name = "generic";
#endif #endif
jobjectArray j_driver_info = env->NewObjectArray(2, Common::Android::GetStringClass(), Common::Android::ToJString(env, version_string)); jobjectArray j_driver_info = env->NewObjectArray(2, Common::Android::GetStringClass(), Common::Android::ToJString(env, version_string));
env->SetObjectArrayElement(j_driver_info, 1, Common::Android::ToJString(env, driver_name)); env->SetObjectArrayElement(j_driver_info, 1, Common::Android::ToJString(env, driver_name));
@@ -893,32 +906,12 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getSystemDriverInfo(
jstring Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getGpuModel(JNIEnv *env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) { jstring Java_org_yuzu_yuzu_1emu_utils_GpuDriverHelper_getGpuModel(JNIEnv *env, jobject j_obj, jobject j_surf, jstring j_hook_lib_dir) {
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
const char* file_redirect_dir_{}; try {
int featureFlags{}; return Common::Android::ToJString(env, QuerySystemDriverInfo(env, j_hook_lib_dir).properties.deviceName);
std::string hook_lib_dir = Common::Android::GetJString(env, j_hook_lib_dir); } catch (...) {
auto handle = adrenotools_open_libvulkan(RTLD_NOW, featureFlags, nullptr, hook_lib_dir.c_str(), }
nullptr, nullptr, file_redirect_dir_, nullptr);
auto driver_library = std::make_shared<Common::DynamicLibrary>(handle);
InputCommon::InputSubsystem input_subsystem;
auto window =
std::make_unique<EmuWindow_Android>(ANativeWindow_fromSurface(env, j_surf), driver_library);
Vulkan::vk::InstanceDispatch dld;
Vulkan::vk::Instance vk_instance = Vulkan::CreateInstance(
*driver_library, dld, VK_API_VERSION_1_1, Core::Frontend::WindowSystemType::Android);
auto surface = Vulkan::CreateSurface(vk_instance, window->GetWindowInfo());
auto device = Vulkan::CreateDevice(vk_instance, dld, *surface);
const std::string model_name{device.GetModelName()};
window.release();
return Common::Android::ToJString(env, model_name);
#else
return Common::Android::ToJString(env, "no-info");
#endif #endif
return Common::Android::ToJString(env, "no-info");
} }
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) { jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env, jclass clazz) {
@@ -1,96 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<com.google.android.material.switchmaterial.SwitchMaterial
android:id="@+id/switch_enable"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:text="@string/gpu_unswizzle_enable" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_texture_size"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:hint="@string/gpu_unswizzle_texture_size">
<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="@+id/dropdown_texture_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_stream_size"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:hint="@string/gpu_unswizzle_stream_size">
<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="@+id/dropdown_stream_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_chunk_size"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox.ExposedDropdownMenu"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/gpu_unswizzle_chunk_size">
<com.google.android.material.textfield.MaterialAutoCompleteTextView
android:id="@+id/dropdown_chunk_size"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="none" />
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:orientation="horizontal"
android:gravity="end"
android:spacing="8dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_default"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/gpu_unswizzle_default_button" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_cancel"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/cancel" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_ok"
style="@style/Widget.Material3.Button.TextButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@android:string/ok" />
</LinearLayout>
</LinearLayout>
</ScrollView>
@@ -574,12 +574,12 @@
<string name="renderer_force_max_clock_description">يجبر وحدة معالجة الرسومات على العمل بأقصى سرعة ممكنة (سيظل يتم تطبيق القيود الحرارية).</string> <string name="renderer_force_max_clock_description">يجبر وحدة معالجة الرسومات على العمل بأقصى سرعة ممكنة (سيظل يتم تطبيق القيود الحرارية).</string>
<string name="renderer_asynchronous_gpu_emulation">محاكاة غير متزامنة لوحدة معالجة الرسومات</string> <string name="renderer_asynchronous_gpu_emulation">محاكاة غير متزامنة لوحدة معالجة الرسومات</string>
<string name="renderer_asynchronous_gpu_emulation_description">يمكن لهذه الحيلة أن تزيد الأداء عن طريق تشغيل محاكاة وحدة معالجة الرسومات بشكل غير متزامن على حساب مشاكل الرسومات وزيادة معدلات الأعطال بسبب العمليات المتعلقة بالتوقيت.</string> <string name="renderer_asynchronous_gpu_emulation_description">يمكن لهذه الحيلة أن تزيد الأداء عن طريق تشغيل محاكاة وحدة معالجة الرسومات بشكل غير متزامن على حساب مشاكل الرسومات وزيادة معدلات الأعطال بسبب العمليات المتعلقة بالتوقيت.</string>
<string name="renderer_async_presentation">عرض غير متزامن</string>
<string name="renderer_async_presentation_description">يمكن لهذه الحيلة أن تزيد من الأداء عن طريق نقل عملية العرض إلى خيط معالجة منفصل على حساب مشاكل الرسوميات.</string>
<string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string> <string name="renderer_reactive_flushing">استخدم التنظيف التفاعلي</string>
<string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string> <string name="renderer_reactive_flushing_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string> <string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
<string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string> <string name="enable_buffer_history_description">يُتيح هذا الخيار الوصول إلى حالات التخزين المؤقت السابقة. وقد يُحسّن جودة العرض وثبات الأداء في بعض الألعاب.</string>
<string name="enable_gpu_buffer_readback">تفعيل قراءة مخزن وحدة معالجة الرسومات</string>
<string name="enable_gpu_buffer_readback_description">يحافظ هذا النظام على بيانات المخزن المؤقت المُعدّلة بواسطة وحدة معالجة الرسومات عن طريق قراءتها مرة أخرى قبل التحميل. تتطلب بعض الألعاب ذلك لعرض بعض التأثيرات بشكل صحيح. قد يُسبب ذلك مشاكل إذا لم يتمكن الجهاز من التعامل مع عبء العمل الإضافي.</string>
<string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string> <string name="use_optimized_vertex_buffers">مخازن الرؤوس المُحسّنة</string>
<string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string> <string name="use_optimized_vertex_buffers_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
@@ -597,17 +597,6 @@
<string name="rescale_hack_description">يُمكّن هذا الخيار من التعامل مع عملية إعادة تحجيم الألعاب بطريقة تقليدية باستخدام مسار إعادة التحجيم السريع</string> <string name="rescale_hack_description">يُمكّن هذا الخيار من التعامل مع عملية إعادة تحجيم الألعاب بطريقة تقليدية باستخدام مسار إعادة التحجيم السريع</string>
<string name="renderer_asynchronous_shaders">استخدم تظليل غير متزامن</string> <string name="renderer_asynchronous_shaders">استخدم تظليل غير متزامن</string>
<string name="renderer_asynchronous_shaders_description">يقوم بتجميع التظليل بشكل غير متزامن. قد يقلل ذلك من التقطعات ولكنه قد يؤدي أيضًا إلى حدوث أخطاء.</string> <string name="renderer_asynchronous_shaders_description">يقوم بتجميع التظليل بشكل غير متزامن. قد يقلل ذلك من التقطعات ولكنه قد يؤدي أيضًا إلى حدوث أخطاء.</string>
<string name="gpu_unswizzle_settings">إعدادات إلغاء ترتيب بيانات وحدة معالجة الرسومات</string>
<string name="gpu_unswizzle_settings_description">قم بضبط معلمات فكّ تشابك النسيج المستندة إلى وحدة معالجة الرسومات أو تعطيلها تمامًا. اضبط هذه الإعدادات لتحقيق التوازن بين الأداء وجودة تحميل النسيج.</string>
<string name="gpu_unswizzle_enable">تفعيل إلغاء ترتيب بيانات وحدة معالجة الرسومات</string>
<string name="gpu_unswizzle_disabled">تعطيل</string>
<string name="gpu_unswizzle_texture_size">الحد الأقصى لحجم النسيج في وحدة معالجة الرسومات بعد إعادة ترتيب البيانات</string>
<string name="gpu_unswizzle_texture_size_description">يُحدد هذا الخيار الحد الأقصى لحجم (ميغابايت) معالجة الصور باستخدام وحدة معالجة الرسومات. مع أن وحدة معالجة الرسومات أسرع في معالجة الصور المتوسطة والكبيرة، إلا أن وحدة المعالجة المركزية قد تكون أكثر كفاءة في معالجة الصور الصغيرة جدًا. اضبط هذا الخيار لتحقيق التوازن الأمثل بين سرعة معالجة الرسومات واستهلاك وحدة المعالجة المركزية.</string>
<string name="gpu_unswizzle_stream_size">حجم تدفق إلغاء ترتيب بيانات وحدة معالجة الرسومات</string>
<string name="gpu_unswizzle_stream_size_description">يحدد هذا الخيار حد البيانات لكل إطار لمعالجة الصور الكبيرة. القيم الأعلى تُسرّع تحميل الصور على حساب زيادة زمن استجابة الإطارات؛ أما القيم الأقل فتُقلل من الحمل الزائد على وحدة معالجة الرسومات، ولكنها قد تتسبب في ظهور الصور بشكل مفاجئ.</string>
<string name="gpu_unswizzle_chunk_size">حجم كتلة إلغاء ترتيب بيانات وحدة معالجة الرسومات</string>
<string name="gpu_unswizzle_chunk_size_description">يُحدد هذا الخيار عدد شرائح العمق التي تتم معالجتها لكل دفعة من الصور ثلاثية الأبعاد (3D). زيادة هذا العدد تُحسّن كفاءة الإنتاجية على وحدات معالجة الرسومات القوية، ولكنها قد تُسبب تقطعًا أو انقطاعًا في عمل برنامج التشغيل على الأجهزة ذات المواصفات الأقل قوة.</string>
<string name="gpu_unswizzle_default_button">افتراضي</string>
<string name="extensions">إضافات</string> <string name="extensions">إضافات</string>
@@ -1048,25 +1037,10 @@
<string name="fast_gpu_high">كسر السرعة</string> <string name="fast_gpu_high">كسر السرعة</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">صغير جدًا (16 ميغابايت)</string>
<string name="gpu_texturesizeswizzle_small">صغير (32 ميغابايت)</string>
<string name="gpu_texturesizeswizzle_normal">قياسي (128 ميغابايت)</string>
<string name="gpu_texturesizeswizzle_large">كبير (256 ميغابايت)</string>
<string name="gpu_texturesizeswizzle_verylarge">كبير جدًا (512 ميغابايت)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">منخفض جدًا (4 ميغابايت)</string>
<string name="gpu_swizzle_low">منخفض (8 ميغابايت)</string>
<string name="gpu_swizzle_normal">قياسي (16 ميغابايت)</string>
<string name="gpu_swizzle_medium">متوسط (32 ميغابايت)</string>
<string name="gpu_swizzle_high">عالي (64 ميغابايت)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<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>
<string name="gpu_swizzlechunk_high">عالي (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">مئوية</string> <string name="temperature_celsius">مئوية</string>
@@ -1097,6 +1071,7 @@
<string name="gpu_fence_behavior_immediate">فوري</string> <string name="gpu_fence_behavior_immediate">فوري</string>
<string name="gpu_fence_behavior_balanced">متوازن</string> <string name="gpu_fence_behavior_balanced">متوازن</string>
<string name="gpu_fence_behavior_accurate">دقيق</string> <string name="gpu_fence_behavior_accurate">دقيق</string>
<string name="gpu_fence_behavior_strict">صارم</string>
<string name="vram_usage_conservative">محافظ</string> <string name="vram_usage_conservative">محافظ</string>
<string name="vram_usage_aggressive">عدواني</string> <string name="vram_usage_aggressive">عدواني</string>
@@ -508,7 +508,6 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<string name="skip_cpu_inner_invalidation_description">Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Kann in einigen Spielen zu Fehlern oder Abstürzen führen.</string> <string name="skip_cpu_inner_invalidation_description">Überspringt bestimmte Cache-Invalidierungen auf CPU-Seite während Speicherupdates, reduziert die CPU-Auslastung und verbessert die Leistung. Kann in einigen Spielen zu Fehlern oder Abstürzen führen.</string>
<string name="renderer_asynchronous_shaders">Asynchrone Shader</string> <string name="renderer_asynchronous_shaders">Asynchrone Shader</string>
<string name="renderer_asynchronous_shaders_description">Kompiliert Shader asynchron. Dies kann Ruckler reduzieren, aber auch Grafikfehler verursachen.</string> <string name="renderer_asynchronous_shaders_description">Kompiliert Shader asynchron. Dies kann Ruckler reduzieren, aber auch Grafikfehler verursachen.</string>
<string name="gpu_unswizzle_default_button">Standard</string>
<string name="extensions">Erweiterungen</string> <string name="extensions">Erweiterungen</string>
@@ -918,25 +917,10 @@ Wirklich fortfahren?</string>
<string name="fast_gpu_high">Übertaktung</string> <string name="fast_gpu_high">Übertaktung</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Sehr klein (16 MB)</string>
<string name="gpu_texturesizeswizzle_small">Klein (32 MB)</string>
<string name="gpu_texturesizeswizzle_normal">Normal (128 MB)</string>
<string name="gpu_texturesizeswizzle_large">Groß (256 MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">Sehr groß (512 MB)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Sehr niedrig (4 MB)</string>
<string name="gpu_swizzle_low">Niedrig (8 MB)</string>
<string name="gpu_swizzle_normal">Normal (16 MB)</string>
<string name="gpu_swizzle_medium">Mittel (32 MB)</string>
<string name="gpu_swizzle_high">Hoch (64 MB)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">Sehr niedrig (32)</string>
<string name="gpu_swizzlechunk_low">Niedrig (64)</string>
<string name="gpu_swizzlechunk_normal">Normal (128)</string>
<string name="gpu_swizzlechunk_medium">Mittel (256)</string>
<string name="gpu_swizzlechunk_high">Hoch (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string> <string name="temperature_celsius">Celsius</string>
@@ -967,6 +951,7 @@ Wirklich fortfahren?</string>
<string name="gpu_fence_behavior_immediate">Direkt</string> <string name="gpu_fence_behavior_immediate">Direkt</string>
<string name="gpu_fence_behavior_balanced">Ausgewogen</string> <string name="gpu_fence_behavior_balanced">Ausgewogen</string>
<string name="gpu_fence_behavior_accurate">Genau</string> <string name="gpu_fence_behavior_accurate">Genau</string>
<string name="gpu_fence_behavior_strict">Strikt</string>
<string name="vram_usage_conservative">Konservativ</string> <string name="vram_usage_conservative">Konservativ</string>
<string name="vram_usage_aggressive">Aggressiv</string> <string name="vram_usage_aggressive">Aggressiv</string>
@@ -289,7 +289,6 @@
<string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string> <string name="gpu_driver_fetcher">Obtenedor de controladores de la GPU</string>
<string name="gpu_driver_manager">Gestor de controladores de la GPU</string> <string name="gpu_driver_manager">Gestor de controladores de la GPU</string>
<string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string> <string name="install_gpu_driver_description">Instale los controladores alternativos para obtener un posible mejor rendimiento o precisión</string>
<string name="post_processing_add">Añadir efecto</string>
<string name="post_processing_open_list">Abrir lista</string> <string name="post_processing_open_list">Abrir lista</string>
<string name="post_processing_close_list">Cerrar lista</string> <string name="post_processing_close_list">Cerrar lista</string>
<string name="post_processing_reset">Restablecer a predeterminado</string> <string name="post_processing_reset">Restablecer a predeterminado</string>
@@ -518,12 +517,12 @@
<string name="renderer_force_max_clock_description">Fuerza a la GPU a ejecutarse a la velocidad máxima de reloj posible (se seguirán aplicando restricciones térmicas).</string> <string name="renderer_force_max_clock_description">Fuerza a la GPU a ejecutarse a la velocidad máxima de reloj posible (se seguirán aplicando restricciones térmicas).</string>
<string name="renderer_asynchronous_gpu_emulation">Emulación de GPU asíncrona</string> <string name="renderer_asynchronous_gpu_emulation">Emulación de GPU asíncrona</string>
<string name="renderer_asynchronous_gpu_emulation_description">Este hack puede aumentar el rendimiento ejecutando la emulación de la GPU de forma asíncrona, a costa de problemas gráficos y un aumento en la tasa de fallos debido a operaciones relacionadas con la sincronización.</string> <string name="renderer_asynchronous_gpu_emulation_description">Este hack puede aumentar el rendimiento ejecutando la emulación de la GPU de forma asíncrona, a costa de problemas gráficos y un aumento en la tasa de fallos debido a operaciones relacionadas con la sincronización.</string>
<string name="renderer_async_presentation">Presentación asíncrona</string>
<string name="renderer_async_presentation_description">Este hack puede aumentar el rendimiento al mover la presentación a un hilo independiente de la CPU a costa de problemas gráficos.</string>
<string name="renderer_reactive_flushing">Usar limpieza reactiva</string> <string name="renderer_reactive_flushing">Usar limpieza reactiva</string>
<string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string> <string name="renderer_reactive_flushing_description">Mejora la precisión de renderizado en algunos juegos, pero reduce el rendimiento.</string>
<string name="enable_buffer_history">Activar el historial del búfer</string> <string name="enable_buffer_history">Activar el historial del búfer</string>
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string> <string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
<string name="enable_gpu_buffer_readback">Activar la lectura del buffer de la GPU</string>
<string name="enable_gpu_buffer_readback_description">Conserva los datos del búfer modificados por la GPU leyéndolos antes de subirlos.\nAlgunos juegos requieren esto para renderizar correctamente ciertos efectos.\nPuede causar problemas si el hardware no puede soportar la carga de trabajo adicional.</string>
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string> <string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string> <string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
@@ -540,17 +539,6 @@
<string name="rescale_hack_description">Permite el manejo de versiones anteriores para el paso de configuración de reescalado para juegos mediante el uso de una ruta de reescalado rápida.</string> <string name="rescale_hack_description">Permite el manejo de versiones anteriores para el paso de configuración de reescalado para juegos mediante el uso de una ruta de reescalado rápida.</string>
<string name="renderer_asynchronous_shaders">Usar sombreadores asíncronos</string> <string name="renderer_asynchronous_shaders">Usar sombreadores asíncronos</string>
<string name="renderer_asynchronous_shaders_description">Compila los sombreadores de forma asíncrona. Esto puede reducir los tirones, pero también puede introducir errores gráficos.</string> <string name="renderer_asynchronous_shaders_description">Compila los sombreadores de forma asíncrona. Esto puede reducir los tirones, pero también puede introducir errores gráficos.</string>
<string name="gpu_unswizzle_settings">Ajustes de desentrelazado de la GPU</string>
<string name="gpu_unswizzle_settings_description">Configura los parámetros de desentrelazado de texturas basadas ​​en la GPU o desactívelos por completo. Modifique estos ajustes para equilibrar el rendimiento y la calidad de las texturas cargadas.</string>
<string name="gpu_unswizzle_enable">Activar desentrelazado de la GPU</string>
<string name="gpu_unswizzle_disabled">Desactivado</string>
<string name="gpu_unswizzle_texture_size">Tamaño máximo de textura de desentrelazado de la GPU</string>
<string name="gpu_unswizzle_texture_size_description">Establece el tamaño máximo (en MB) para el desentrelazado de texturas basada en GPU. Aunque la GPU es más rápida para texturas medianas y grandes, la CPU puede ser más eficiente para texturas muy pequeñas. Ajuste este valor para encontrar el equilibrio entre la aceleración de la GPU y la sobrecarga de la CPU.</string>
<string name="gpu_unswizzle_stream_size">Tamaño del flujo de desentrelazado de la GPU</string>
<string name="gpu_unswizzle_stream_size_description">Establece el límite de datos por fotograma para desentrelazar texturas grandes. Los valores altos aceleran la carga de texturas, a coste de una mayor latencia por fotograma; los valores bajos reducen la carga de la GPU, pero pueden causar parpadeos visibles en las texturas.</string>
<string name="gpu_unswizzle_chunk_size">Tamaño del trozo de desentrelazado de la GPU</string>
<string name="gpu_unswizzle_chunk_size_description">Determina la cantidad de cortes de profundidad procesados ​​en un solo envío de texturas 3D. Aumentar este valor puede mejorar el rendimiento en una GPU de gama alta, pero puede causar tirones y problemas en los tiempos de respuesta en hardware más modesto.</string>
<string name="gpu_unswizzle_default_button">Por defecto</string>
<string name="extensions">Extensiones</string> <string name="extensions">Extensiones</string>
@@ -987,25 +975,10 @@
<string name="fast_gpu_high">Overclock</string> <string name="fast_gpu_high">Overclock</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Muy pequeño (16 MB)</string>
<string name="gpu_texturesizeswizzle_small">Pequeño (32 MB)</string>
<string name="gpu_texturesizeswizzle_normal">Normal (128 MB)</string>
<string name="gpu_texturesizeswizzle_large">Grande (256 MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">Muy grande (512 MB)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Muy bajo (4 MB)</string>
<string name="gpu_swizzle_low">Bajo (8 MB)</string>
<string name="gpu_swizzle_normal">Normal (16 MB)</string>
<string name="gpu_swizzle_medium">Medio (32 MB)</string>
<string name="gpu_swizzle_high">Alto (64 MB)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">Muy bajo (32)</string>
<string name="gpu_swizzlechunk_low">Bajo (64)</string>
<string name="gpu_swizzlechunk_normal">Normal (128)</string>
<string name="gpu_swizzlechunk_medium">Medio (256)</string>
<string name="gpu_swizzlechunk_high">Alto (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string> <string name="temperature_celsius">Celsius</string>
@@ -1036,6 +1009,7 @@
<string name="gpu_fence_behavior_immediate">Inmediato</string> <string name="gpu_fence_behavior_immediate">Inmediato</string>
<string name="gpu_fence_behavior_balanced">Equilibrado</string> <string name="gpu_fence_behavior_balanced">Equilibrado</string>
<string name="gpu_fence_behavior_accurate">Preciso</string> <string name="gpu_fence_behavior_accurate">Preciso</string>
<string name="gpu_fence_behavior_strict">Estricto</string>
<string name="vram_usage_conservative">Conservador</string> <string name="vram_usage_conservative">Conservador</string>
<string name="vram_usage_aggressive">Agresivo</string> <string name="vram_usage_aggressive">Agresivo</string>
@@ -482,8 +482,6 @@
<string name="emulate_bgr565">Emuler BGR565</string> <string name="emulate_bgr565">Emuler BGR565</string>
<string name="renderer_asynchronous_shaders">Utiliser les shaders asynchrones</string> <string name="renderer_asynchronous_shaders">Utiliser les shaders asynchrones</string>
<string name="renderer_asynchronous_shaders_description">Compile les shaders de manière asynchrone. Cela peut réduire les saccades mais peut aussi provoquer des problèmes graphiques.</string> <string name="renderer_asynchronous_shaders_description">Compile les shaders de manière asynchrone. Cela peut réduire les saccades mais peut aussi provoquer des problèmes graphiques.</string>
<string name="gpu_unswizzle_disabled">Désactivé</string>
<string name="gpu_unswizzle_default_button">Par défaut</string>
<string name="extensions">Extensions</string> <string name="extensions">Extensions</string>
@@ -884,25 +882,10 @@
<string name="memory_8gb">8 Go (Dangereux)</string> <string name="memory_8gb">8 Go (Dangereux)</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Très petit (16 Mo)</string>
<string name="gpu_texturesizeswizzle_small">Petit (32 Mo)</string>
<string name="gpu_texturesizeswizzle_normal">Normal (128 Mo)</string>
<string name="gpu_texturesizeswizzle_large">Large (256 Mo)</string>
<string name="gpu_texturesizeswizzle_verylarge">Très large (512 Mo)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Très faible (4 Mo)</string>
<string name="gpu_swizzle_low">Faible (8 Mo)</string>
<string name="gpu_swizzle_normal">Normal (16 Mo)</string>
<string name="gpu_swizzle_medium">Moyen (32 Mo)</string>
<string name="gpu_swizzle_high">Élevé (64 Mo)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">Très faible (32)</string>
<string name="gpu_swizzlechunk_low">Faible (64)</string>
<string name="gpu_swizzlechunk_normal">Normal (128)</string>
<string name="gpu_swizzlechunk_medium">Moyen (256)</string>
<string name="gpu_swizzlechunk_high">Élevé (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string> <string name="temperature_celsius">Celsius</string>
@@ -318,13 +318,6 @@
<string name="frame_gen_target_rate">Целевая частота кадров</string> <string name="frame_gen_target_rate">Целевая частота кадров</string>
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string> <string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</string>
<string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string> <string name="frame_gen_target_rate_off">Использовать фиксированный множитель</string>
<string name="frame_gen_on">Вкл.</string>
<string name="frame_gen_off">Выкл.</string>
<string name="frame_gen_fixed">Фикс.</string>
<string name="frame_gen_flow_auto">Авто</string>
<string name="frame_gen_quick_description">Включите или выключите генерацию кадров и выберите множитель кадров.</string>
<string name="frame_gen_target_rate_quick_description">Генерация кадров с заданной частотой кадров. Множитель регулируется автоматически.</string>
<string name="frame_gen_flow_scale_quick_description">Разрешение, используемое для оценки движения между кадрами. Меньшие значения экономят время ГПУ.</string>
<string name="frame_gen_queue_target">Целевой размер очереди кадров</string> <string name="frame_gen_queue_target">Целевой размер очереди кадров</string>
<string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string> <string name="frame_gen_queue_target_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string> <string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
@@ -335,14 +328,12 @@
<string name="frame_gen_flow_scale">Разрешение оценки движения</string> <string name="frame_gen_flow_scale">Разрешение оценки движения</string>
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string> <string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</string>
<string name="frame_gen_unsupported">Генерация кадров недоступна</string> <string name="frame_gen_unsupported">Генерация кадров недоступна</string>
<string name="frame_gen_unsupported_description">В этом ГПУ драйвере отсутствует поддержка модели памяти Vulkan или половинной точности (float16), которая требуется шейдерам Lossless Scaling.</string>
<string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string> <string name="lossless_scaling_setup_description">Опционально. Укажите свой Lossless.dll для включения генерации кадров позже.</string>
<string name="lossless_scaling_install">Установить Lossless.dll</string> <string name="lossless_scaling_install">Установить Lossless.dll</string>
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string> <string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string> <string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
<string name="frame_generation_support">Генерация кадров</string> <string name="frame_generation_support">Генерация кадров</string>
<string name="frame_generation_supported">Поддерживается</string> <string name="frame_generation_supported">Поддерживается</string>
<string name="frame_generation_unsupported">Не поддерживается (нет модели памяти Vulkan или float16)</string>
<string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string> <string name="lossless_scaling_description">Предоставьте свою копию Lossless.dll для включения генерации кадров</string>
<string name="lossless_scaling_installed">Установлена</string> <string name="lossless_scaling_installed">Установлена</string>
<string name="lossless_scaling_not_installed">Не установлена</string> <string name="lossless_scaling_not_installed">Не установлена</string>
@@ -563,12 +554,12 @@
<string name="renderer_force_max_clock_description">Заставляет ГПУ работать на максимально возможных тактовых частотах (тепловые ограничения все равно будут применяться).</string> <string name="renderer_force_max_clock_description">Заставляет ГПУ работать на максимально возможных тактовых частотах (тепловые ограничения все равно будут применяться).</string>
<string name="renderer_asynchronous_gpu_emulation">Асинхронная эмуляция ГПУ</string> <string name="renderer_asynchronous_gpu_emulation">Асинхронная эмуляция ГПУ</string>
<string name="renderer_asynchronous_gpu_emulation_description">Может повысить производительность за счёт асинхронного запуска эмуляции ГПУ, но ценой появления графических ошибок и увеличения частоты вылетов из-за операций, зависящих от синхронизации.</string> <string name="renderer_asynchronous_gpu_emulation_description">Может повысить производительность за счёт асинхронного запуска эмуляции ГПУ, но ценой появления графических ошибок и увеличения частоты вылетов из-за операций, зависящих от синхронизации.</string>
<string name="renderer_async_presentation">Асинхронная презентация</string>
<string name="renderer_async_presentation_description">Может повысить производительность за счёт перемещения вывода кадров в отдельный поток ЦП, но ценой возникновения графических проблем.</string>
<string name="renderer_reactive_flushing">Реактивная очистка</string> <string name="renderer_reactive_flushing">Реактивная очистка</string>
<string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string> <string name="renderer_reactive_flushing_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string>
<string name="enable_buffer_history">Включить историю буфера</string> <string name="enable_buffer_history">Включить историю буфера</string>
<string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string> <string name="enable_buffer_history_description">Позволяет обращаться к предыдущим состояниям буфера. Эта опция может повысить качество рендеринга и стабильность производительности в некоторых играх.</string>
<string name="enable_gpu_buffer_readback">Включить обратное чтение буфера ГПУ</string>
<string name="enable_gpu_buffer_readback_description">Сохраняет измененные ГПУ данные буфера путем чтения их обратно перед выгрузками. Некоторые игры требуют этого, чтобы рендерить определенные эффекты правильно. Может вызывать проблемы если оборудование не может обработать дополнительную рабочую нагрузку.</string>
<string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string> <string name="use_optimized_vertex_buffers">Оптимизированные вершинные буферы</string>
<string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string> <string name="use_optimized_vertex_buffers_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string>
@@ -586,17 +577,6 @@
<string name="rescale_hack_description">Включает старый метод обработки этапа перенастройки масштабирования для игр за счёт использования быстрого алгоритма перемасштабирования.</string> <string name="rescale_hack_description">Включает старый метод обработки этапа перенастройки масштабирования для игр за счёт использования быстрого алгоритма перемасштабирования.</string>
<string name="renderer_asynchronous_shaders">Использовать асинхронные шейдеры</string> <string name="renderer_asynchronous_shaders">Использовать асинхронные шейдеры</string>
<string name="renderer_asynchronous_shaders_description">Компилирует шейдеры асинхронно. Это может уменьшить подтормаживания, но также может вызвать графические артефакты.</string> <string name="renderer_asynchronous_shaders_description">Компилирует шейдеры асинхронно. Это может уменьшить подтормаживания, но также может вызвать графические артефакты.</string>
<string name="gpu_unswizzle_settings">Настройки распаковки текстур (Unswizzle)</string>
<string name="gpu_unswizzle_settings_description">Настройте параметры распаковки текстур на стороне ГПУ либо полностью отключите эту функцию. Изменение этих параметров позволяет найти баланс между производительностью и качеством загрузки текстур.</string>
<string name="gpu_unswizzle_enable">Включить распаковку текстур (Unswizzle)</string>
<string name="gpu_unswizzle_disabled">Отключено</string>
<string name="gpu_unswizzle_texture_size">Макс. размер текстуры Unswizzle</string>
<string name="gpu_unswizzle_texture_size_description">Задает максимальный размер (в МБ) текстур для преобразования формата (unswizzle) на ГПУ. Хотя ГПУ быстрее работает со средними и большими текстурами, ЦП может быть эффективнее для очень маленьких. Настройте это значение, чтобы найти баланс между ускорением на ГПУ и нагрузкой на ЦП.</string>
<string name="gpu_unswizzle_stream_size">Размер потока Unswizzle</string>
<string name="gpu_unswizzle_stream_size_description">Задает лимит данных на кадр для преобразования крупных текстур (unswizzle). Высокие значения ускоряют загрузку текстур ценой увеличения задержки кадра; низкие значения снижают нагрузку на ГПУ, но могут вызывать заметную постепенную подгрузку текстур.</string>
<string name="gpu_unswizzle_chunk_size">Размер блока Unswizzle</string>
<string name="gpu_unswizzle_chunk_size_description">Задает количество слоёв глубины, обрабатываемых за одну пачку для 3D-текстур. Увеличение этого значения улучшает пропускную способность на мощных ГПУ, но может вызывать подтормаживания или таймауты драйвера на слабом железе.</string>
<string name="gpu_unswizzle_default_button">По умолчанию</string>
<string name="extensions">Расширения</string> <string name="extensions">Расширения</string>
@@ -1037,25 +1017,10 @@
<string name="fast_gpu_high">Разгон</string> <string name="fast_gpu_high">Разгон</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Очень малый (16 МБ)</string>
<string name="gpu_texturesizeswizzle_small">Малый (32 МБ)</string>
<string name="gpu_texturesizeswizzle_normal">Обычный (128 МБ)</string>
<string name="gpu_texturesizeswizzle_large">Большой (256 МБ)</string>
<string name="gpu_texturesizeswizzle_verylarge">Очень большой (512 МБ)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Очень низкий (4 МБ)</string>
<string name="gpu_swizzle_low">Низкий (8 МБ)</string>
<string name="gpu_swizzle_normal">Обычный (16 МБ)</string>
<string name="gpu_swizzle_medium">Средний (32 МБ)</string>
<string name="gpu_swizzle_high">Высокий (64 МБ)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<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>
<string name="gpu_swizzlechunk_high">Большой (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Цельсий</string> <string name="temperature_celsius">Цельсий</string>
@@ -1086,6 +1051,7 @@
<string name="gpu_fence_behavior_immediate">Мгновенный</string> <string name="gpu_fence_behavior_immediate">Мгновенный</string>
<string name="gpu_fence_behavior_balanced">Сбалансированный</string> <string name="gpu_fence_behavior_balanced">Сбалансированный</string>
<string name="gpu_fence_behavior_accurate">Точный</string> <string name="gpu_fence_behavior_accurate">Точный</string>
<string name="gpu_fence_behavior_strict">Строгий</string>
<string name="vram_usage_conservative">Консервативный</string> <string name="vram_usage_conservative">Консервативный</string>
<string name="vram_usage_aggressive">Агрессивный</string> <string name="vram_usage_aggressive">Агрессивный</string>
@@ -481,8 +481,6 @@
<string name="renderer_force_max_clock_description">Змушує GPU працювати на максимальній тактовій частоті.</string> <string name="renderer_force_max_clock_description">Змушує GPU працювати на максимальній тактовій частоті.</string>
<string name="renderer_asynchronous_gpu_emulation">Асинхронна емуляція ГП</string> <string name="renderer_asynchronous_gpu_emulation">Асинхронна емуляція ГП</string>
<string name="renderer_asynchronous_gpu_emulation_description">Це обхідне рішення може покращити продуктивність завдяки асинхронному виконанню емуляції ГП, але спричинить проблеми з графікою та збільшить частоту збоїв чутливих до таймінгів операцій.</string> <string name="renderer_asynchronous_gpu_emulation_description">Це обхідне рішення може покращити продуктивність завдяки асинхронному виконанню емуляції ГП, але спричинить проблеми з графікою та збільшить частоту збоїв чутливих до таймінгів операцій.</string>
<string name="renderer_async_presentation">Асинхронне подання</string>
<string name="renderer_async_presentation_description">Це обхідне рішення може покращити продуктивність завдяки переміщенню подання на окремий потік ЦП, але спричинить проблеми з графікою.</string>
<string name="renderer_reactive_flushing">Реактивне очищення</string> <string name="renderer_reactive_flushing">Реактивне очищення</string>
<string name="renderer_reactive_flushing_description">Покращує точність рендерингу в деяких іграх.</string> <string name="renderer_reactive_flushing_description">Покращує точність рендерингу в деяких іграх.</string>
<string name="enable_buffer_history">Увімкнути історію буфера</string> <string name="enable_buffer_history">Увімкнути історію буфера</string>
@@ -502,17 +500,6 @@
<string name="rescale_hack_description">Вмикає застарілу обробку масштабування для ігор, використовуючи швидкий шлях масштабування</string> <string name="rescale_hack_description">Вмикає застарілу обробку масштабування для ігор, використовуючи швидкий шлях масштабування</string>
<string name="renderer_asynchronous_shaders">Асинхронні шейдери</string> <string name="renderer_asynchronous_shaders">Асинхронні шейдери</string>
<string name="renderer_asynchronous_shaders_description">Компілює шейдери асинхронно. Це може зменшити затримки, але також може спричинити графічні баги.</string> <string name="renderer_asynchronous_shaders_description">Компілює шейдери асинхронно. Це може зменшити затримки, але також може спричинити графічні баги.</string>
<string name="gpu_unswizzle_settings">Налаштування розпакування за допомогою ГП</string>
<string name="gpu_unswizzle_settings_description">Налаштуйте розпакування текстур за допомогою ГП або повністю вимкнути його. Відкоригуйте ці налаштування, щоб урівноважити продуктивність і якість завантаження текстур.</string>
<string name="gpu_unswizzle_enable">Увімкнути розпакування за допомогою ГП</string>
<string name="gpu_unswizzle_disabled">Вимкнено</string>
<string name="gpu_unswizzle_texture_size">Максимальний розмір текстур для розпакування ГП за допомогою ГП</string>
<string name="gpu_unswizzle_texture_size_description">Встановлює максимальний розмір (МБ) для розпакування текстур за допомогою ГП. ГП швидше справляється з текстурами середніх і великих розмірів, а ЦП ефективніший для дуже маленьких. Налаштуйте, щоб збалансувати ГП-прискоренням і навантаженням на ЦП.</string>
<string name="gpu_unswizzle_stream_size">Розмір потоку розпакування за допомогою ГП</string>
<string name="gpu_unswizzle_stream_size_description">Встановлює обмеження даних на кадр для розпакування великих текстур. Вищі значення пришвидшують завантаження текстур за рахунок більших кадрових затримок; менші значення зменшують перевантаження ГП але може спричинити помітні появи текстур.</string>
<string name="gpu_unswizzle_chunk_size">Розмір блоків розпакування за допомогою ГП</string>
<string name="gpu_unswizzle_chunk_size_description">Визначає кількість зрізів глибини, оброблених за партію 3D-текстур. Збільшення здатне покращити пропускну здатність на потужних ГП, але може призвести до затримок або затримок драйвера зі слабшим устаткуванням.</string>
<string name="gpu_unswizzle_default_button">Стандартно</string>
<string name="extensions">Розширення</string> <string name="extensions">Розширення</string>
@@ -929,25 +916,10 @@
<string name="memory_8gb">8 ГБ (Небезпечно)</string> <string name="memory_8gb">8 ГБ (Небезпечно)</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Дуже малий (16 МБ)</string>
<string name="gpu_texturesizeswizzle_small">Малий (32 МБ)</string>
<string name="gpu_texturesizeswizzle_normal">Нормальний (128 МБ)</string>
<string name="gpu_texturesizeswizzle_large">Великий (256 МБ)</string>
<string name="gpu_texturesizeswizzle_verylarge">Дуже великий (512 МБ)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Дуже низький (4 МБ)</string>
<string name="gpu_swizzle_low">Низький (8 МБ)</string>
<string name="gpu_swizzle_normal">Нормальний (16 МБ)</string>
<string name="gpu_swizzle_medium">Середній (32 МБ)</string>
<string name="gpu_swizzle_high">Високий (64 МБ)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<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>
<string name="gpu_swizzlechunk_high">Високий (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Цельсій</string> <string name="temperature_celsius">Цельсій</string>
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation"> <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://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/QuickStart.md\">了解更多</a>]]></string>
<string name="notice_notification_channel_name">错误与注意事项</string> <string name="notice_notification_channel_name">错误与注意事项</string>
<string name="notice_notification_channel_description">当发生错误时显示通知。</string> <string name="notice_notification_channel_description">当发生错误时显示通知。</string>
<string name="notification_permission_not_granted">未授予通知权限!</string> <string name="notification_permission_not_granted">未授予通知权限!</string>
@@ -291,25 +290,6 @@
<string name="gpu_driver_fetcher">GPU驱动获取器</string> <string name="gpu_driver_fetcher">GPU驱动获取器</string>
<string name="gpu_driver_manager">GPU 驱动管理器</string> <string name="gpu_driver_manager">GPU 驱动管理器</string>
<string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string> <string name="install_gpu_driver_description">安装替代的驱动程序以获得更好的性能和精度</string>
<string name="post_processing">后处理效果</string>
<string name="post_processing_description">在渲染完成后应用 ReShade FX 效果</string>
<string name="post_processing_per_game_description">配置此游戏的效果链</string>
<string name="post_processing_add">添加效果</string>
<string name="post_processing_remove">移除</string>
<string name="post_processing_open_list">打开列表</string>
<string name="post_processing_close_list">关闭列表</string>
<string name="post_processing_remove_all">移除效果</string>
<string name="post_processing_preset_locked">预设已激活。在开始游戏前可以在后处理效果中编辑它。</string>
<string name="post_processing_preset_modified">数值已从原始预设被更改。</string>
<string name="post_processing_presets">预设</string>
<string name="post_processing_preset_new">新建预设</string>
<string name="post_processing_preset_new_description">把您加载的效果及当前数值保存为一个预设,以便今后选用。</string>
<string name="post_processing_preset_name_invalid">请给预设起一个不含等号的名称。</string>
<string name="post_processing_preset_none">无预设</string>
<string name="post_processing_preset_delete">删除预设</string>
<string name="post_processing_preset_reset">重置预设值</string>
<string name="post_processing_reset">重置为默认值</string>
<string name="post_processing_empty">找不到效果。请在此文件中放置 .fx 文件:</string>
<string name="frame_gen">帧生成</string> <string name="frame_gen">帧生成</string>
<string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string> <string name="frame_gen_per_game_description">配置针对此游戏的帧生成设定</string>
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string> <string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
@@ -324,13 +304,6 @@
<string name="frame_gen_target_rate_60">60 FPS</string> <string name="frame_gen_target_rate_60">60 FPS</string>
<string name="frame_gen_target_rate_90">90 FPS</string> <string name="frame_gen_target_rate_90">90 FPS</string>
<string name="frame_gen_target_rate_120">120 FPS</string> <string name="frame_gen_target_rate_120">120 FPS</string>
<string name="frame_gen_on">开</string>
<string name="frame_gen_off">关</string>
<string name="frame_gen_fixed">固定</string>
<string name="frame_gen_flow_auto">自动</string>
<string name="frame_gen_quick_description">打开或关闭帧生成并选择帧生成倍数。</string>
<string name="frame_gen_target_rate_quick_description">生成帧到目标帧率。倍率会自动调整。</string>
<string name="frame_gen_flow_scale_quick_description">用来估算帧间运动的分辨率。较低的值可以节省 GPU 时间。</string>
<string name="frame_gen_queue_target">帧队列目标</string> <string name="frame_gen_queue_target">帧队列目标</string>
<string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string> <string name="frame_gen_queue_target_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string> <string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
@@ -341,14 +314,12 @@
<string name="frame_gen_flow_scale">运动预估分辨率</string> <string name="frame_gen_flow_scale">运动预估分辨率</string>
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string> <string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</string>
<string name="frame_gen_unsupported">帧生成不可用</string> <string name="frame_gen_unsupported">帧生成不可用</string>
<string name="frame_gen_unsupported_description">这个 GPU 驱动缺少 Lossless Scaling 着色器所需的 Vulkan 内存模型或半精度 (float16) 支持。</string>
<string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string> <string name="lossless_scaling_setup_description">作为可选项。请提供您自己的 Lossless.dll 以便在之后可以启用帧生成。</string>
<string name="lossless_scaling_install">安装 Lossless.dll</string> <string name="lossless_scaling_install">安装 Lossless.dll</string>
<string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string> <string name="lossless_scaling_install_description">帧生成需要您自己从 Lossless Scaling 获得合法的 Lossless.dll 副本</string>
<string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string> <string name="lossless_scaling_replace_description">选择其它 Lossless.dll 副本</string>
<string name="frame_generation_support">帧生成</string> <string name="frame_generation_support">帧生成</string>
<string name="frame_generation_supported">支持</string> <string name="frame_generation_supported">支持</string>
<string name="frame_generation_unsupported">不支持 (无 Vulkan 内存模型或 float16)</string>
<string name="lossless_scaling">无损缩放</string> <string name="lossless_scaling">无损缩放</string>
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string> <string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
<string name="lossless_scaling_installed">已安装</string> <string name="lossless_scaling_installed">已安装</string>
@@ -564,12 +535,12 @@
<string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (温控依然生效)。</string> <string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (温控依然生效)。</string>
<string name="renderer_asynchronous_gpu_emulation">GPU 异步模拟</string> <string name="renderer_asynchronous_gpu_emulation">GPU 异步模拟</string>
<string name="renderer_asynchronous_gpu_emulation_description">此技巧可通过异步运行 GPU 模拟来提升性能,但在执行与时序相关的操作时,可能带来图形显示问题以及增加崩溃概率。</string> <string name="renderer_asynchronous_gpu_emulation_description">此技巧可通过异步运行 GPU 模拟来提升性能,但在执行与时序相关的操作时,可能带来图形显示问题以及增加崩溃概率。</string>
<string name="renderer_async_presentation">异步呈现</string>
<string name="renderer_async_presentation_description">此技巧通过将图形呈现移至独立的 CPU 线程来提升性能,但可能会带来图形显示问题。</string>
<string name="renderer_reactive_flushing">启用反应性刷新</string> <string name="renderer_reactive_flushing">启用反应性刷新</string>
<string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string> <string name="renderer_reactive_flushing_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
<string name="enable_buffer_history">启用缓冲区历史</string> <string name="enable_buffer_history">启用缓冲区历史</string>
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string> <string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
<string name="enable_gpu_buffer_readback">启用 GPU 缓冲区回读</string>
<string name="enable_gpu_buffer_readback_description">在上传前回读经由 GPU 修改过的缓冲区数据,以将其保留。一些游戏会用到这项设定以正确渲染某些效果。如果硬件无法处理额外的工作负载,则可能会导致问题。</string>
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string> <string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string> <string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
@@ -587,17 +558,6 @@
<string name="rescale_hack_description">启用通过使用快速缩放路径,来为游戏提供缩放配置处理的传统处理方式</string> <string name="rescale_hack_description">启用通过使用快速缩放路径,来为游戏提供缩放配置处理的传统处理方式</string>
<string name="renderer_asynchronous_shaders">使用异步着色器</string> <string name="renderer_asynchronous_shaders">使用异步着色器</string>
<string name="renderer_asynchronous_shaders_description">以异步方式编译着色器。采用此方式或可减少卡顿,但也可能引入故障点。</string> <string name="renderer_asynchronous_shaders_description">以异步方式编译着色器。采用此方式或可减少卡顿,但也可能引入故障点。</string>
<string name="gpu_unswizzle_settings">GPU Unswizzle 设置</string>
<string name="gpu_unswizzle_settings_description">配置基于 GPU 的纹理 unswizzling 参数,或完全禁用该功能。通过调整这些设置,以尝试在性能与纹理加载质量之间取得平衡。</string>
<string name="gpu_unswizzle_enable">启用 GPU Unswizzle</string>
<string name="gpu_unswizzle_disabled">禁用</string>
<string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大纹理尺寸</string>
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理 unswizzling 的最大尺寸(MB)。虽然 GPU 处理中等和大型纹理的速度更快,但对于非常小的纹理,CPU 可能更为高效。通过调节此项设置,以平衡GPU 加速与 CPU 开销。</string>
<string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加速纹理的加载过程,但会带来更高的帧延迟。而较低的数值则可以降低 GPU 的开销,但也可能会导致可见的纹理闪现。</string>
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle 块大小</string>
<string name="gpu_unswizzle_chunk_size_description">定义了 3D 纹理每批次处理的深度切片数量。增加此数值可在高性能 GPU 上提升吞吐效率,但在性能较弱的硬件上可能会导致卡顿或驱动超时。</string>
<string name="gpu_unswizzle_default_button">默认</string>
<string name="extensions">扩展</string> <string name="extensions">扩展</string>
@@ -638,11 +598,6 @@
<string name="log">日志记录</string> <string name="log">日志记录</string>
<string name="flush_by_line">按行刷新调试日志</string> <string name="flush_by_line">按行刷新调试日志</string>
<string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string> <string name="flush_by_line_description">在每行写入时刷新调试日志,使在崩溃或冻结时调试更容易。</string>
<string name="extended_logging">开启扩展日志</string>
<string name="extended_logging_description">将最大日志文件大小从 100 MiB 提升至 1GiB。</string>
<string name="log_filter">日志筛选器</string>
<string name="log_filter_description">控制 Eden 的日志类别。例如: *:Info Service.LM:Debug</string>
<!-- GPU Logging strings --> <!-- GPU Logging strings -->
<string name="gpu_logging_header">GPU 日志</string> <string name="gpu_logging_header">GPU 日志</string>
<string name="gpu_log_level">日志等级</string> <string name="gpu_log_level">日志等级</string>
@@ -926,8 +881,6 @@
<string name="loader_error_file_not_found">ROM 文件不存在</string> <string name="loader_error_file_not_found">ROM 文件不存在</string>
<string name="loader_requires_firmware">游戏需要固件</string> <string name="loader_requires_firmware">游戏需要固件</string>
<string name="loader_requires_firmware_description"><![CDATA[这个游戏可能需要固件才能正常运行,但您还没有安装任何固件。请在启动前安装固件,或者按 “确定” 继续启动。]]></string>
<!-- Intent Launch strings --> <!-- Intent Launch strings -->
<string name="searching_for_game">正在搜索游戏...</string> <string name="searching_for_game">正在搜索游戏...</string>
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string> <string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
@@ -1038,25 +991,10 @@
<string name="fast_gpu_high">超频</string> <string name="fast_gpu_high">超频</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<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>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<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 --> <!-- GPU swizzle chunks -->
<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>
<string name="gpu_swizzlechunk_high">高 (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">摄氏度</string> <string name="temperature_celsius">摄氏度</string>
@@ -1087,6 +1025,7 @@
<string name="gpu_fence_behavior_immediate">即时</string> <string name="gpu_fence_behavior_immediate">即时</string>
<string name="gpu_fence_behavior_balanced">均衡</string> <string name="gpu_fence_behavior_balanced">均衡</string>
<string name="gpu_fence_behavior_accurate">精确</string> <string name="gpu_fence_behavior_accurate">精确</string>
<string name="gpu_fence_behavior_strict">严格</string>
<string name="vram_usage_conservative">保守式</string> <string name="vram_usage_conservative">保守式</string>
<string name="vram_usage_aggressive">主动式</string> <string name="vram_usage_aggressive">主动式</string>
@@ -229,7 +229,7 @@
<string name="add_directory_success">遊戲目錄新增成功</string> <string name="add_directory_success">遊戲目錄新增成功</string>
<string name="enable_update_checks">檢查更新</string> <string name="enable_update_checks">檢查更新</string>
<string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string> <string name="enable_update_checks_description">在Eden啟動時檢查有無新版本並選擇是否要下載與安裝更新</string>
<string name="update_available">發現新版本</string> <string name="update_available">偵測到新版本</string>
<string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string> <string name="update_available_description">有更新可供安裝:%1$s\n\n您要進行更新嗎?</string>
<string name="downloading_update">下載更新中</string> <string name="downloading_update">下載更新中</string>
<string name="update_download_failed">更新下載失敗</string> <string name="update_download_failed">更新下載失敗</string>
@@ -555,12 +555,12 @@
<string name="renderer_force_max_clock_description">強制 GPU 以可能的最大時脈執行 (熱溫限制仍會被套用)</string> <string name="renderer_force_max_clock_description">強制 GPU 以可能的最大時脈執行 (熱溫限制仍會被套用)</string>
<string name="renderer_asynchronous_gpu_emulation">GPU 非同步模擬</string> <string name="renderer_asynchronous_gpu_emulation">GPU 非同步模擬</string>
<string name="renderer_asynchronous_gpu_emulation_description">此修改可透過使用 GPU 非同步模擬來提升性能,不過可能會導致圖形問題且會提高在進行時序相關操作時當機的機率</string> <string name="renderer_asynchronous_gpu_emulation_description">此修改可透過使用 GPU 非同步模擬來提升性能,不過可能會導致圖形問題且會提高在進行時序相關操作時當機的機率</string>
<string name="renderer_async_presentation">非同步呈現</string>
<string name="renderer_async_presentation_description">此修改可以透過將渲染移至單獨的 CPU 執行緒來提升性能,但可能會導致圖形問題</string>
<string name="renderer_reactive_flushing">使用重新啟用排清</string> <string name="renderer_reactive_flushing">使用重新啟用排清</string>
<string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string> <string name="renderer_reactive_flushing_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
<string name="enable_buffer_history">啟用緩衝區歷史</string> <string name="enable_buffer_history">啟用緩衝區歷史</string>
<string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string> <string name="enable_buffer_history_description">允許存取先前的緩衝區狀態。此選項可能會改善部分遊戲的渲染品質與效能穩定性</string>
<string name="enable_gpu_buffer_readback">啟用 GPU 緩衝區讀回</string>
<string name="enable_gpu_buffer_readback_description">透過在上傳之前先將 GPU 修改過的緩衝區資料讀回來保存資料,部分遊戲需要啟用此功能才能正常渲染遊戲特效。如果硬體無法負荷可能會導致錯誤</string>
<string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string> <string name="use_optimized_vertex_buffers">最佳化頂點緩衝區</string>
<string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string> <string name="use_optimized_vertex_buffers_description">啟用最佳化的頂點緩衝區綁定。需要安裝 Mesa 26.0+ Turnip drivers/Qualcomm drivers。使用舊版 Turnip drivers 會導致當機 (25.3版和更低的版本)</string>
@@ -578,17 +578,6 @@
<string name="rescale_hack_description">透過快速重新縮放處理來啟用遊戲重新縮放設定階段的舊版處理方式</string> <string name="rescale_hack_description">透過快速重新縮放處理來啟用遊戲重新縮放設定階段的舊版處理方式</string>
<string name="renderer_asynchronous_shaders">使用非同步著色器</string> <string name="renderer_asynchronous_shaders">使用非同步著色器</string>
<string name="renderer_asynchronous_shaders_description">使用非同步編譯著色器。這可能會減少卡頓,但也可能導致圖形錯誤。</string> <string name="renderer_asynchronous_shaders_description">使用非同步編譯著色器。這可能會減少卡頓,但也可能導致圖形錯誤。</string>
<string name="gpu_unswizzle_settings">GPU Unswizzle 設定</string>
<string name="gpu_unswizzle_settings_description">設定基於 GPU 的 Unswizzling 參數或完全停用此功能。調整此設定以在性能與紋理載入品質中取得平衡</string>
<string name="gpu_unswizzle_enable">啟用 GPU Unswizzle</string>
<string name="gpu_unswizzle_disabled">停用</string>
<string name="gpu_unswizzle_texture_size">GPU Unswizzle 最大紋理尺寸</string>
<string name="gpu_unswizzle_texture_size_description">設定 GPU 紋理 Unswizzling 的最大值 (MB)。雖然 GPU 處理中型和大型紋理的速度較快,但 CPU 處理非常小的紋理可能更有效率。整此設定以在 GPU 加速與 CPU 負載之間取得平衡</string>
<string name="gpu_unswizzle_stream_size">GPU Unswizzle 流大小</string>
<string name="gpu_unswizzle_stream_size_description">設定每個影格處理大型紋理 Unswizzling 的資料上限。數值越高載入紋理的速度越快,但會增加畫面延遲;數值較低則能降低 GPU 負載,不過有可能導致至紋理載入不完全甚至突然出現</string>
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle 塊大小</string>
<string name="gpu_unswizzle_chunk_size_description">設定 3D 紋理每批次處理的深度切片數量。增加此數值可提升規格較佳 GPU 的處理效率,但在較低規格的硬體上可能導致卡頓或驅動程式逾時</string>
<string name="gpu_unswizzle_default_button">預設</string>
<string name="extensions">擴充功能</string> <string name="extensions">擴充功能</string>
@@ -1018,40 +1007,9 @@
<string name="memory_6gb">6GB (不穩定)</string> <string name="memory_6gb">6GB (不穩定)</string>
<string name="memory_8gb">8GB (不穩定)</string> <string name="memory_8gb">8GB (不穩定)</string>
<!-- CPU clock levels -->
<string name="clock_normal">正常</string>
<string name="clock_boost">加速</string>
<string name="clock_fast">超頻</string>
<!-- GPU clock levels -->
<string name="fast_gpu_normal">正常</string>
<string name="fast_gpu_medium">加速</string>
<string name="fast_gpu_high">超頻</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">極小 (16MB)</string>
<string name="gpu_texturesizeswizzle_small">小(32MB)</string>
<string name="gpu_texturesizeswizzle_normal">正常(128MB)</string>
<string name="gpu_texturesizeswizzle_large">大(256MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">極大(512MB)</string>
<!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">極小(4MB)</string>
<string name="gpu_swizzle_low">小(8MB)</string>
<string name="gpu_swizzle_normal">正常(16MB)</string>
<string name="gpu_swizzle_medium">中(32MB)</string>
<string name="gpu_swizzle_high">大(64MB)</string>
<!-- GPU swizzle chunks -->
<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>
<string name="gpu_swizzlechunk_high">大(512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">攝氏</string> <string name="temperature_celsius">攝氏度</string>
<string name="temperature_fahrenheit">華氏</string> <string name="temperature_fahrenheit">華氏度</string>
<!-- Memory Sizes --> <!-- Memory Sizes -->
<string name="memory_byte_shorthand">B</string> <string name="memory_byte_shorthand">B</string>
@@ -1064,8 +1022,6 @@
<string name="renderer_none">無</string> <string name="renderer_none">無</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_low">效能</string>
<string name="renderer_accuracy_high">準確</string> <string name="renderer_accuracy_high">準確</string>
<!-- DMA Accuracy --> <!-- DMA Accuracy -->
+1 -48
View File
@@ -558,6 +558,7 @@
<item>@string/gpu_fence_behavior_immediate</item> <item>@string/gpu_fence_behavior_immediate</item>
<item>@string/gpu_fence_behavior_balanced</item> <item>@string/gpu_fence_behavior_balanced</item>
<item>@string/gpu_fence_behavior_accurate</item> <item>@string/gpu_fence_behavior_accurate</item>
<item>@string/gpu_fence_behavior_strict</item>
</string-array> </string-array>
<integer-array name="gpuFenceBehaviorValues"> <integer-array name="gpuFenceBehaviorValues">
<item>0</item> <item>0</item>
@@ -590,54 +591,6 @@
<item>2</item> <item>2</item>
</integer-array> </integer-array>
<string-array name="gpuTextureSizeSwizzleEntries">
<item>@string/gpu_texturesizeswizzle_verysmall</item>
<item>@string/gpu_texturesizeswizzle_small</item>
<item>@string/gpu_texturesizeswizzle_normal</item>
<item>@string/gpu_texturesizeswizzle_large</item>
<item>@string/gpu_texturesizeswizzle_verylarge</item>
</string-array>
<integer-array name="gpuTextureSizeSwizzleValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<string-array name="gpuSwizzleEntries">
<item>@string/gpu_swizzle_verylow</item>
<item>@string/gpu_swizzle_low</item>
<item>@string/gpu_swizzle_normal</item>
<item>@string/gpu_swizzle_medium</item>
<item>@string/gpu_swizzle_high</item>
</string-array>
<integer-array name="gpuSwizzleValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<string-array name="gpuSwizzleChunkEntries">
<item>@string/gpu_swizzlechunk_verylow</item>
<item>@string/gpu_swizzlechunk_low</item>
<item>@string/gpu_swizzlechunk_normal</item>
<item>@string/gpu_swizzlechunk_medium</item>
<item>@string/gpu_swizzlechunk_high</item>
</string-array>
<integer-array name="gpuSwizzleChunkValues">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</integer-array>
<string-array name="temperatureUnitEntries"> <string-array name="temperatureUnitEntries">
<item>@string/temperature_celsius</item> <item>@string/temperature_celsius</item>
<item>@string/temperature_fahrenheit</item> <item>@string/temperature_fahrenheit</item>
+12 -29
View File
@@ -105,6 +105,8 @@
<string name="use_sync_core_description">Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the game\'s actual speed.</string> <string name="use_sync_core_description">Synchronize the core tick speed to the maximum speed percentage to improve performance without altering the game\'s actual speed.</string>
<string name="cpuopt_unsafe_host_mmu">Enable Host MMU Emulation</string> <string name="cpuopt_unsafe_host_mmu">Enable Host MMU Emulation</string>
<string name="cpuopt_unsafe_host_mmu_description">This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host\'s MMU. Disabling this forces all memory accesses to use Software MMU Emulation.</string> <string name="cpuopt_unsafe_host_mmu_description">This optimization speeds up memory accesses by the guest program. Enabling it causes guest memory reads/writes to be done directly into memory and make use of Host\'s MMU. Disabling this forces all memory accesses to use Software MMU Emulation.</string>
<string name="relocate_36bit_address_space">Run 36-bit games natively</string>
<string name="relocate_36bit_address_space_description">Gives games built for the 36-bit address space the 39-bit layout so they can run with NCE instead of the JIT. Experimental: a game that relies on 36-bit addresses can crash.</string>
<string name="debug_knobs">Debug knobs</string> <string name="debug_knobs">Debug knobs</string>
<string name="debug_knobs_description">For development use only.</string> <string name="debug_knobs_description">For development use only.</string>
<string name="debug_knobs_hint">0 to 65535</string> <string name="debug_knobs_hint">0 to 65535</string>
@@ -346,7 +348,7 @@
<string name="frame_gen_flow_scale_auto">Match motion estimation to the game</string> <string name="frame_gen_flow_scale_auto">Match motion estimation to the game</string>
<string name="frame_gen_flow_scale_auto_description">Estimate motion at the resolution the game actually renders instead of the upscaled output. Costs nothing in accuracy, since upscaling adds no motion detail.</string> <string name="frame_gen_flow_scale_auto_description">Estimate motion at the resolution the game actually renders instead of the upscaled output. Costs nothing in accuracy, since upscaling adds no motion detail.</string>
<string name="frame_gen_flow_scale">Motion estimation resolution</string> <string name="frame_gen_flow_scale">Motion estimation resolution</string>
<string name="frame_gen_flow_scale_description">Resolution of the optical flow pass, as a fraction of the output. Lowering it is the cheapest way to reclaim performance.</string> <string name="frame_gen_flow_scale_description">Resolution of the optical flow pass, as a fraction of the game\'s render resolution. Lowering it is the cheapest way to reclaim performance.</string>
<string name="frame_gen_unsupported">Frame generation unavailable</string> <string name="frame_gen_unsupported">Frame generation unavailable</string>
<string name="frame_gen_unsupported_description">This GPU driver lacks the Vulkan memory model or half precision (float16) support that the Lossless Scaling shaders require.</string> <string name="frame_gen_unsupported_description">This GPU driver lacks the Vulkan memory model or half precision (float16) support that the Lossless Scaling shaders require.</string>
<string name="lossless_scaling_setup_description">Optional. Provide your own Lossless.dll to enable frame generation later</string> <string name="lossless_scaling_setup_description">Optional. Provide your own Lossless.dll to enable frame generation later</string>
@@ -573,6 +575,8 @@
<string name="accelerate_astc_description">Pick how ASTC-compressed textures are decoded for rendering: CPU (slow, safe), GPU (fast, recommended), or CPU Async (no stutters, may cause issues)</string> <string name="accelerate_astc_description">Pick how ASTC-compressed textures are decoded for rendering: CPU (slow, safe), GPU (fast, recommended), or CPU Async (no stutters, may cause issues)</string>
<string name="sync_memory_operations">Sync Memory Operations</string> <string name="sync_memory_operations">Sync Memory Operations</string>
<string name="stall_on_gpu_fence_wait">Pause CPU on GPU fence timeouts</string>
<string name="stall_on_gpu_fence_wait_description">When a game keeps timing out while waiting for the GPU, pauses every CPU thread until the GPU catches up. Disabling it keeps the other threads running, which can reduce stutter but may break games that rely on it.</string>
<string name="sync_memory_operations_description">Ensures data consistency between compute and memory operations. This option should fix issues in some games, but may also reduce performance in some cases. Unreal Engine 4 games often see the most significant changes thereof.</string> <string name="sync_memory_operations_description">Ensures data consistency between compute and memory operations. This option should fix issues in some games, but may also reduce performance in some cases. Unreal Engine 4 games often see the most significant changes thereof.</string>
<string name="use_disk_shader_cache">Disk shader cache</string> <string name="use_disk_shader_cache">Disk shader cache</string>
<string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string> <string name="use_disk_shader_cache_description">Reduces stuttering by locally storing and loading generated shaders.</string>
@@ -580,12 +584,16 @@
<string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string> <string name="renderer_force_max_clock_description">Forces the GPU to run at the maximum possible clocks (thermal constraints will still be applied).</string>
<string name="renderer_asynchronous_gpu_emulation">GPU async emulation</string> <string name="renderer_asynchronous_gpu_emulation">GPU async emulation</string>
<string name="renderer_asynchronous_gpu_emulation_description">This hack can increase performance by running GPU emulation asynchronously at the cost of graphical issues and increased crash rates by timing-related operations.</string> <string name="renderer_asynchronous_gpu_emulation_description">This hack can increase performance by running GPU emulation asynchronously at the cost of graphical issues and increased crash rates by timing-related operations.</string>
<string name="renderer_async_presentation">Asynchronous presentation</string>
<string name="renderer_async_presentation_description">This hack can increase performance by moving presentation to a separate CPU thread at the cost of graphical issues.</string>
<string name="renderer_reactive_flushing">Use reactive flushing</string> <string name="renderer_reactive_flushing">Use reactive flushing</string>
<string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string> <string name="renderer_reactive_flushing_description">Improves rendering accuracy in some games at the cost of performance.</string>
<string name="renderer_barrier_feedback_loops">Barrier feedback loops</string>
<string name="renderer_barrier_feedback_loops_description">Improves rendering of transparency effects in specific games at the cost of performance.</string>
<string name="enable_buffer_history">Enable buffer history</string> <string name="enable_buffer_history">Enable buffer history</string>
<string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string> <string name="enable_buffer_history_description">Enables access to previous buffer states. This option may improve rendering quality and performance consistency in some games.</string>
<string name="enable_gpu_buffer_readback">Enable GPU Buffer Readback</string>
<string name="use_unified_memory">Unified Memory</string>
<string name="use_unified_memory_description">Backs part of the emulated memory with GPU-shared buffers so textures are unswizzled directly from it, skipping a CPU copy. Needs 12 GB of RAM or more and a GPU with I/O coherency; it turns itself off otherwise. Takes effect on the next game launch.</string>
<string name="enable_gpu_buffer_readback_description">Preserves GPU-modified buffer data by reading it back before uploads. Some games require this to render certain effects properly. May cause issues if the hardware cannot handle the additional workload.</string>
<string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string> <string name="use_optimized_vertex_buffers">Optimized Vertex Buffers</string>
<string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string> <string name="use_optimized_vertex_buffers_description">Enables optimized vertex buffer binding for improved performance. Requires Mesa 26.0+ Turnip drivers/ QCOM drivers. Will crash on older Turnip drivers (25.3 and below).</string>
@@ -603,17 +611,6 @@
<string name="rescale_hack_description">Enables a legacy handling for the rescale configuration pass for games by using a quick rescale path</string> <string name="rescale_hack_description">Enables a legacy handling for the rescale configuration pass for games by using a quick rescale path</string>
<string name="renderer_asynchronous_shaders">Use asynchronous shaders</string> <string name="renderer_asynchronous_shaders">Use asynchronous shaders</string>
<string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string> <string name="renderer_asynchronous_shaders_description">Compiles shaders asynchronously. This may reduce stutters but may also introduce glitches.</string>
<string name="gpu_unswizzle_settings">GPU Unswizzle Settings</string>
<string name="gpu_unswizzle_settings_description">Configure GPU-based texture unswizzling parameters or disable it entirely. Adjust these settings to balance performance and texture loading quality.</string>
<string name="gpu_unswizzle_enable">Enable GPU Unswizzle</string>
<string name="gpu_unswizzle_disabled">Disabled</string>
<string name="gpu_unswizzle_texture_size">GPU Unswizzle Max Texture Size</string>
<string name="gpu_unswizzle_texture_size_description">Sets the maximum size (MB) for GPU-based texture unswizzling. While the GPU is faster for medium and large textures, the CPU may be more efficient for very small ones. Adjust this to find the balance between GPU acceleration and CPU overhead.</string>
<string name="gpu_unswizzle_stream_size">GPU Unswizzle Stream Size</string>
<string name="gpu_unswizzle_stream_size_description">Sets the data limit per frame for unswizzling large textures. Higher values speed up texture loading at the cost of higher frame latency; lower values reduce GPU overhead but may cause visible texture pop-in.</string>
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk Size</string>
<string name="gpu_unswizzle_chunk_size_description">Defines the number of depth slices processed per batch for 3D textures. Increasing this improves throughput efficiency on powerful GPUs but may cause stuttering or driver timeouts on weaker hardware.</string>
<string name="gpu_unswizzle_default_button">Default</string>
<string name="extensions">Extensions</string> <string name="extensions">Extensions</string>
@@ -1063,25 +1060,10 @@
<string name="fast_gpu_high">Overclock</string> <string name="fast_gpu_high">Overclock</string>
<!-- GPU swizzle texture size --> <!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Very Small (16 MB)</string>
<string name="gpu_texturesizeswizzle_small">Small (32 MB)</string>
<string name="gpu_texturesizeswizzle_normal">Normal (128 MB)</string>
<string name="gpu_texturesizeswizzle_large">Large (256 MB)</string>
<string name="gpu_texturesizeswizzle_verylarge">Very Large (512 MB)</string>
<!-- GPU swizzle streams --> <!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Very Low (4 MB)</string>
<string name="gpu_swizzle_low">Low (8 MB)</string>
<string name="gpu_swizzle_normal">Normal (16 MB)</string>
<string name="gpu_swizzle_medium">Medium (32 MB)</string>
<string name="gpu_swizzle_high">High (64 MB)</string>
<!-- GPU swizzle chunks --> <!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">Very Low (32)</string>
<string name="gpu_swizzlechunk_low">Low (64)</string>
<string name="gpu_swizzlechunk_normal">Normal (128)</string>
<string name="gpu_swizzlechunk_medium">Medium (256)</string>
<string name="gpu_swizzlechunk_high">High (512)</string>
<!-- Temperature Units --> <!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string> <string name="temperature_celsius">Celsius</string>
@@ -1136,6 +1118,7 @@
<string name="gpu_fence_behavior_immediate">Immediate</string> <string name="gpu_fence_behavior_immediate">Immediate</string>
<string name="gpu_fence_behavior_balanced">Balanced</string> <string name="gpu_fence_behavior_balanced">Balanced</string>
<string name="gpu_fence_behavior_accurate">Accurate</string> <string name="gpu_fence_behavior_accurate">Accurate</string>
<string name="gpu_fence_behavior_strict">Strict</string>
<!-- ASTC Decoding Method Choices --> <!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string> <string name="accelerate_astc_cpu" translatable="false">CPU</string>
+5 -8
View File
@@ -62,6 +62,7 @@ add_library(
fs/fs_util.h fs/fs_util.h
fs/path_util.cpp fs/path_util.cpp
fs/path_util.h fs/path_util.h
hash.h
heap_tracker.cpp heap_tracker.cpp
heap_tracker.h heap_tracker.h
hex_util.cpp hex_util.cpp
@@ -75,6 +76,7 @@ add_library(
logging.h logging.h
lz4_compression.cpp lz4_compression.cpp
lz4_compression.h lz4_compression.h
make_unique_for_overwrite.h
math_util.h math_util.h
memory_detect.cpp memory_detect.cpp
memory_detect.h memory_detect.h
@@ -106,8 +108,7 @@ add_library(
settings_setting.h settings_setting.h
slot_vector.h slot_vector.h
socket_types.h socket_types.h
sparse_large_vector.cpp spin_lock.h
sparse_large_vector.h
stb.cpp stb.cpp
stb.h stb.h
steady_clock.cpp steady_clock.cpp
@@ -136,8 +137,8 @@ add_library(
uuid.cpp uuid.cpp
uuid.h uuid.h
vector_math.h vector_math.h
zbic_compression.cpp virtual_buffer.cpp
zbic_compression.h virtual_buffer.h
zstd_compression.cpp zstd_compression.cpp
zstd_compression.h zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp fs/ryujinx_compat.h fs/ryujinx_compat.cpp
@@ -148,10 +149,6 @@ add_library(
net/net.h net/net.cpp net/net.h net/net.cpp
container/unordered_map.h container/unordered_set.h) container/unordered_map.h container/unordered_set.h)
set_source_files_properties(zbic_compression.cpp PROPERTIES
INCLUDE_DIRECTORIES "${ZBIC_INCLUDE_DIR}"
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:Clang,GNU>:-Wno-unused-function;-Wno-missing-declarations;-Wno-shadow>")
if(WIN32) if(WIN32)
target_sources(common PRIVATE windows/timer_resolution.cpp target_sources(common PRIVATE windows/timer_resolution.cpp
windows/timer_resolution.h) windows/timer_resolution.h)
+251 -252
View File
@@ -12,94 +12,93 @@
#include "common/android/multiplayer/multiplayer.h" #include "common/android/multiplayer/multiplayer.h"
#include <network/network.h> #include <network/network.h>
static struct {
JavaVM *java_vm;
jclass native_library_class;
jclass disk_cache_progress_class;
jclass load_callback_stage_class;
jclass game_dir_class;
jmethodID game_dir_constructor;
jmethodID exit_emulation_activity;
jmethodID disk_cache_load_progress;
jmethodID on_emulation_started;
jmethodID on_emulation_stopped;
jmethodID on_program_changed;
jmethodID copy_to_storage;
jmethodID file_exists;
jmethodID file_extension;
jclass game_class; static JavaVM *s_java_vm;
jmethodID game_constructor; static jclass s_native_library_class;
jfieldID game_title_field; static jclass s_disk_cache_progress_class;
jfieldID game_path_field; static jclass s_load_callback_stage_class;
jfieldID game_program_id_field; static jclass s_game_dir_class;
jfieldID game_developer_field; static jmethodID s_game_dir_constructor;
jfieldID game_version_field; static jmethodID s_exit_emulation_activity;
jfieldID game_is_homebrew_field; static jmethodID s_disk_cache_load_progress;
static jmethodID s_on_emulation_started;
static jmethodID s_on_emulation_stopped;
static jmethodID s_on_program_changed;
static jmethodID s_copy_to_storage;
static jmethodID s_file_exists;
static jmethodID s_file_extension;
jclass string_class; static jclass s_game_class;
jclass pair_class; static jmethodID s_game_constructor;
jmethodID pair_constructor; static jfieldID s_game_title_field;
jfieldID pair_first_field; static jfieldID s_game_path_field;
jfieldID pair_second_field; static jfieldID s_game_program_id_field;
static jfieldID s_game_developer_field;
static jfieldID s_game_version_field;
static jfieldID s_game_is_homebrew_field;
jclass overlay_control_data_class; static jclass s_string_class;
jmethodID overlay_control_data_constructor; static jclass s_pair_class;
jfieldID overlay_control_data_id_field; static jmethodID s_pair_constructor;
jfieldID overlay_control_data_enabled_field; static jfieldID s_pair_first_field;
jfieldID overlay_control_data_individual_scale_field; static jfieldID s_pair_second_field;
jfieldID overlay_control_data_landscape_position_field;
jfieldID overlay_control_data_portrait_position_field;
jfieldID overlay_control_data_foldable_position_field;
jclass patch_class; static jclass s_overlay_control_data_class;
jmethodID patch_constructor; static jmethodID s_overlay_control_data_constructor;
jfieldID patch_enabled_field; static jfieldID s_overlay_control_data_id_field;
jfieldID patch_name_field; static jfieldID s_overlay_control_data_enabled_field;
jfieldID patch_version_field; static jfieldID s_overlay_control_data_individual_scale_field;
jfieldID patch_type_field; static jfieldID s_overlay_control_data_landscape_position_field;
jfieldID patch_program_id_field; static jfieldID s_overlay_control_data_portrait_position_field;
jfieldID patch_title_id_field; static jfieldID s_overlay_control_data_foldable_position_field;
jclass double_class; static jclass s_patch_class;
jmethodID double_constructor; static jmethodID s_patch_constructor;
jmethodID double_value_method; static jfieldID s_patch_enabled_field;
static jfieldID s_patch_name_field;
static jfieldID s_patch_version_field;
static jfieldID s_patch_type_field;
static jfieldID s_patch_program_id_field;
static jfieldID s_patch_title_id_field;
jclass integer_class; static jclass s_double_class;
jmethodID integer_constructor; static jmethodID s_double_constructor;
jmethodID integer_value_method; static jmethodID s_double_value_method;
jclass boolean_class; static jclass s_integer_class;
jmethodID boolean_constructor; static jmethodID s_integer_constructor;
jmethodID boolean_value_method; static jmethodID s_integer_value_method;
jclass player_input_class; static jclass s_boolean_class;
jmethodID player_input_constructor; static jmethodID s_boolean_constructor;
jfieldID player_input_connected_field; static jmethodID s_boolean_value_method;
jfieldID player_input_buttons_field;
jfieldID player_input_analogs_field;
jfieldID player_input_motions_field;
jfieldID player_input_vibration_enabled_field;
jfieldID player_input_vibration_strength_field;
jfieldID player_input_body_color_left_field;
jfieldID player_input_body_color_right_field;
jfieldID player_input_button_color_left_field;
jfieldID player_input_button_color_right_field;
jfieldID player_input_profile_name_field;
jfieldID player_input_use_system_vibrator_field;
jclass yuzu_input_device_interface; static jclass s_player_input_class;
jmethodID yuzu_input_device_get_name; static jmethodID s_player_input_constructor;
jmethodID yuzu_input_device_get_guid; static jfieldID s_player_input_connected_field;
jmethodID yuzu_input_device_get_port; static jfieldID s_player_input_buttons_field;
jmethodID yuzu_input_device_get_supports_vibration; static jfieldID s_player_input_analogs_field;
jmethodID yuzu_input_device_vibrate; static jfieldID s_player_input_motions_field;
jmethodID yuzu_input_device_get_axes; static jfieldID s_player_input_vibration_enabled_field;
jmethodID yuzu_input_device_has_keys; static jfieldID s_player_input_vibration_strength_field;
static jfieldID s_player_input_body_color_left_field;
static jfieldID s_player_input_body_color_right_field;
static jfieldID s_player_input_button_color_left_field;
static jfieldID s_player_input_button_color_right_field;
static jfieldID s_player_input_profile_name_field;
static jfieldID s_player_input_use_system_vibrator_field;
jmethodID add_netplay_message; static jclass s_yuzu_input_device_interface;
jmethodID clear_chat; static jmethodID s_yuzu_input_device_get_name;
} state; static jmethodID s_yuzu_input_device_get_guid;
static jmethodID s_yuzu_input_device_get_port;
static jmethodID s_yuzu_input_device_get_supports_vibration;
static jmethodID s_yuzu_input_device_vibrate;
static jmethodID s_yuzu_input_device_get_axes;
static jmethodID s_yuzu_input_device_has_keys;
static jmethodID s_add_netplay_message;
static jmethodID s_clear_chat;
static constexpr jint JNI_VERSION = JNI_VERSION_1_6; static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
@@ -107,14 +106,14 @@ namespace Common::Android {
JNIEnv *GetEnvForThread() { JNIEnv *GetEnvForThread() {
thread_local static struct OwnedEnv { thread_local static struct OwnedEnv {
OwnedEnv() { OwnedEnv() {
status = state.java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); status = s_java_vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
if (status == JNI_EDETACHED) if (status == JNI_EDETACHED)
state.java_vm->AttachCurrentThread(&env, nullptr); s_java_vm->AttachCurrentThread(&env, nullptr);
} }
~OwnedEnv() { ~OwnedEnv() {
if (status == JNI_EDETACHED) if (status == JNI_EDETACHED)
state.java_vm->DetachCurrentThread(); s_java_vm->DetachCurrentThread();
} }
int status; int status;
@@ -124,303 +123,303 @@ namespace Common::Android {
} }
jclass GetNativeLibraryClass() { jclass GetNativeLibraryClass() {
return state.native_library_class; return s_native_library_class;
} }
jclass GetDiskCacheProgressClass() { jclass GetDiskCacheProgressClass() {
return state.disk_cache_progress_class; return s_disk_cache_progress_class;
} }
jclass GetDiskCacheLoadCallbackStageClass() { jclass GetDiskCacheLoadCallbackStageClass() {
return state.load_callback_stage_class; return s_load_callback_stage_class;
} }
jclass GetGameDirClass() { jclass GetGameDirClass() {
return state.game_dir_class; return s_game_dir_class;
} }
jmethodID GetGameDirConstructor() { jmethodID GetGameDirConstructor() {
return state.game_dir_constructor; return s_game_dir_constructor;
} }
jmethodID GetExitEmulationActivity() { jmethodID GetExitEmulationActivity() {
return state.exit_emulation_activity; return s_exit_emulation_activity;
} }
jmethodID GetDiskCacheLoadProgress() { jmethodID GetDiskCacheLoadProgress() {
return state.disk_cache_load_progress; return s_disk_cache_load_progress;
} }
jmethodID GetCopyToStorage() { jmethodID GetCopyToStorage() {
return state.copy_to_storage; return s_copy_to_storage;
} }
jmethodID GetFileExists() { jmethodID GetFileExists() {
return state.file_exists; return s_file_exists;
} }
jmethodID GetFileExtension() { jmethodID GetFileExtension() {
return state.file_extension; return s_file_extension;
} }
jmethodID GetOnEmulationStarted() { jmethodID GetOnEmulationStarted() {
return state.on_emulation_started; return s_on_emulation_started;
} }
jmethodID GetOnEmulationStopped() { jmethodID GetOnEmulationStopped() {
return state.on_emulation_stopped; return s_on_emulation_stopped;
} }
jmethodID GetOnProgramChanged() { jmethodID GetOnProgramChanged() {
return state.on_program_changed; return s_on_program_changed;
} }
jclass GetGameClass() { jclass GetGameClass() {
return state.game_class; return s_game_class;
} }
jmethodID GetGameConstructor() { jmethodID GetGameConstructor() {
return state.game_constructor; return s_game_constructor;
} }
jfieldID GetGameTitleField() { jfieldID GetGameTitleField() {
return state.game_title_field; return s_game_title_field;
} }
jfieldID GetGamePathField() { jfieldID GetGamePathField() {
return state.game_path_field; return s_game_path_field;
} }
jfieldID GetGameProgramIdField() { jfieldID GetGameProgramIdField() {
return state.game_program_id_field; return s_game_program_id_field;
} }
jfieldID GetGameDeveloperField() { jfieldID GetGameDeveloperField() {
return state.game_developer_field; return s_game_developer_field;
} }
jfieldID GetGameVersionField() { jfieldID GetGameVersionField() {
return state.game_version_field; return s_game_version_field;
} }
jfieldID GetGameIsHomebrewField() { jfieldID GetGameIsHomebrewField() {
return state.game_is_homebrew_field; return s_game_is_homebrew_field;
} }
jclass GetStringClass() { jclass GetStringClass() {
return state.string_class; return s_string_class;
} }
jclass GetPairClass() { jclass GetPairClass() {
return state.pair_class; return s_pair_class;
} }
jmethodID GetPairConstructor() { jmethodID GetPairConstructor() {
return state.pair_constructor; return s_pair_constructor;
} }
jfieldID GetPairFirstField() { jfieldID GetPairFirstField() {
return state.pair_first_field; return s_pair_first_field;
} }
jfieldID GetPairSecondField() { jfieldID GetPairSecondField() {
return state.pair_second_field; return s_pair_second_field;
} }
jclass GetOverlayControlDataClass() { jclass GetOverlayControlDataClass() {
return state.overlay_control_data_class; return s_overlay_control_data_class;
} }
jmethodID GetOverlayControlDataConstructor() { jmethodID GetOverlayControlDataConstructor() {
return state.overlay_control_data_constructor; return s_overlay_control_data_constructor;
} }
jfieldID GetOverlayControlDataIdField() { jfieldID GetOverlayControlDataIdField() {
return state.overlay_control_data_id_field; return s_overlay_control_data_id_field;
} }
jfieldID GetOverlayControlDataEnabledField() { jfieldID GetOverlayControlDataEnabledField() {
return state.overlay_control_data_enabled_field; return s_overlay_control_data_enabled_field;
} }
jfieldID GetOverlayControlDataIndividualScaleField() { jfieldID GetOverlayControlDataIndividualScaleField() {
return state.overlay_control_data_individual_scale_field; return s_overlay_control_data_individual_scale_field;
} }
jfieldID GetOverlayControlDataLandscapePositionField() { jfieldID GetOverlayControlDataLandscapePositionField() {
return state.overlay_control_data_landscape_position_field; return s_overlay_control_data_landscape_position_field;
} }
jfieldID GetOverlayControlDataPortraitPositionField() { jfieldID GetOverlayControlDataPortraitPositionField() {
return state.overlay_control_data_portrait_position_field; return s_overlay_control_data_portrait_position_field;
} }
jfieldID GetOverlayControlDataFoldablePositionField() { jfieldID GetOverlayControlDataFoldablePositionField() {
return state.overlay_control_data_foldable_position_field; return s_overlay_control_data_foldable_position_field;
} }
jclass GetPatchClass() { jclass GetPatchClass() {
return state.patch_class; return s_patch_class;
} }
jmethodID GetPatchConstructor() { jmethodID GetPatchConstructor() {
return state.patch_constructor; return s_patch_constructor;
} }
jfieldID GetPatchEnabledField() { jfieldID GetPatchEnabledField() {
return state.patch_enabled_field; return s_patch_enabled_field;
} }
jfieldID GetPatchNameField() { jfieldID GetPatchNameField() {
return state.patch_name_field; return s_patch_name_field;
} }
jfieldID GetPatchVersionField() { jfieldID GetPatchVersionField() {
return state.patch_version_field; return s_patch_version_field;
} }
jfieldID GetPatchTypeField() { jfieldID GetPatchTypeField() {
return state.patch_type_field; return s_patch_type_field;
} }
jfieldID GetPatchProgramIdField() { jfieldID GetPatchProgramIdField() {
return state.patch_program_id_field; return s_patch_program_id_field;
} }
jfieldID GetPatchTitleIdField() { jfieldID GetPatchTitleIdField() {
return state.patch_title_id_field; return s_patch_title_id_field;
} }
jclass GetDoubleClass() { jclass GetDoubleClass() {
return state.double_class; return s_double_class;
} }
jmethodID GetDoubleConstructor() { jmethodID GetDoubleConstructor() {
return state.double_constructor; return s_double_constructor;
} }
jmethodID GetDoubleValueMethod() { jmethodID GetDoubleValueMethod() {
return state.double_value_method; return s_double_value_method;
} }
jclass GetIntegerClass() { jclass GetIntegerClass() {
return state.integer_class; return s_integer_class;
} }
jmethodID GetIntegerConstructor() { jmethodID GetIntegerConstructor() {
return state.integer_constructor; return s_integer_constructor;
} }
jmethodID GetIntegerValueMethod() { jmethodID GetIntegerValueMethod() {
return state.integer_value_method; return s_integer_value_method;
} }
jclass GetBooleanClass() { jclass GetBooleanClass() {
return state.boolean_class; return s_boolean_class;
} }
jmethodID GetBooleanConstructor() { jmethodID GetBooleanConstructor() {
return state.boolean_constructor; return s_boolean_constructor;
} }
jmethodID GetBooleanValueMethod() { jmethodID GetBooleanValueMethod() {
return state.boolean_value_method; return s_boolean_value_method;
} }
jclass GetPlayerInputClass() { jclass GetPlayerInputClass() {
return state.player_input_class; return s_player_input_class;
} }
jmethodID GetPlayerInputConstructor() { jmethodID GetPlayerInputConstructor() {
return state.player_input_constructor; return s_player_input_constructor;
} }
jfieldID GetPlayerInputConnectedField() { jfieldID GetPlayerInputConnectedField() {
return state.player_input_connected_field; return s_player_input_connected_field;
} }
jfieldID GetPlayerInputButtonsField() { jfieldID GetPlayerInputButtonsField() {
return state.player_input_buttons_field; return s_player_input_buttons_field;
} }
jfieldID GetPlayerInputAnalogsField() { jfieldID GetPlayerInputAnalogsField() {
return state.player_input_analogs_field; return s_player_input_analogs_field;
} }
jfieldID GetPlayerInputMotionsField() { jfieldID GetPlayerInputMotionsField() {
return state.player_input_motions_field; return s_player_input_motions_field;
} }
jfieldID GetPlayerInputVibrationEnabledField() { jfieldID GetPlayerInputVibrationEnabledField() {
return state.player_input_vibration_enabled_field; return s_player_input_vibration_enabled_field;
} }
jfieldID GetPlayerInputVibrationStrengthField() { jfieldID GetPlayerInputVibrationStrengthField() {
return state.player_input_vibration_strength_field; return s_player_input_vibration_strength_field;
} }
jfieldID GetPlayerInputBodyColorLeftField() { jfieldID GetPlayerInputBodyColorLeftField() {
return state.player_input_body_color_left_field; return s_player_input_body_color_left_field;
} }
jfieldID GetPlayerInputBodyColorRightField() { jfieldID GetPlayerInputBodyColorRightField() {
return state.player_input_body_color_right_field; return s_player_input_body_color_right_field;
} }
jfieldID GetPlayerInputButtonColorLeftField() { jfieldID GetPlayerInputButtonColorLeftField() {
return state.player_input_button_color_left_field; return s_player_input_button_color_left_field;
} }
jfieldID GetPlayerInputButtonColorRightField() { jfieldID GetPlayerInputButtonColorRightField() {
return state.player_input_button_color_right_field; return s_player_input_button_color_right_field;
} }
jfieldID GetPlayerInputProfileNameField() { jfieldID GetPlayerInputProfileNameField() {
return state.player_input_profile_name_field; return s_player_input_profile_name_field;
} }
jfieldID GetPlayerInputUseSystemVibratorField() { jfieldID GetPlayerInputUseSystemVibratorField() {
return state.player_input_use_system_vibrator_field; return s_player_input_use_system_vibrator_field;
} }
jclass GetYuzuInputDeviceInterface() { jclass GetYuzuInputDeviceInterface() {
return state.yuzu_input_device_interface; return s_yuzu_input_device_interface;
} }
jmethodID GetYuzuDeviceGetName() { jmethodID GetYuzuDeviceGetName() {
return state.yuzu_input_device_get_name; return s_yuzu_input_device_get_name;
} }
jmethodID GetYuzuDeviceGetGUID() { jmethodID GetYuzuDeviceGetGUID() {
return state.yuzu_input_device_get_guid; return s_yuzu_input_device_get_guid;
} }
jmethodID GetYuzuDeviceGetPort() { jmethodID GetYuzuDeviceGetPort() {
return state.yuzu_input_device_get_port; return s_yuzu_input_device_get_port;
} }
jmethodID GetYuzuDeviceGetSupportsVibration() { jmethodID GetYuzuDeviceGetSupportsVibration() {
return state.yuzu_input_device_get_supports_vibration; return s_yuzu_input_device_get_supports_vibration;
} }
jmethodID GetYuzuDeviceVibrate() { jmethodID GetYuzuDeviceVibrate() {
return state.yuzu_input_device_vibrate; return s_yuzu_input_device_vibrate;
} }
jmethodID GetYuzuDeviceGetAxes() { jmethodID GetYuzuDeviceGetAxes() {
return state.yuzu_input_device_get_axes; return s_yuzu_input_device_get_axes;
} }
jmethodID GetYuzuDeviceHasKeys() { jmethodID GetYuzuDeviceHasKeys() {
return state.yuzu_input_device_has_keys; return s_yuzu_input_device_has_keys;
} }
jmethodID GetAddNetPlayMessage() { jmethodID GetAddNetPlayMessage() {
return state.add_netplay_message; return s_add_netplay_message;
} }
jmethodID ClearChat() { jmethodID ClearChat() {
return state.clear_chat; return s_clear_chat;
} }
#ifdef __cplusplus #ifdef __cplusplus
@@ -437,20 +436,20 @@ namespace Common::Android {
// UnInitialize Android Storage // UnInitialize Android Storage
Common::FS::Android::UnRegisterCallbacks(); Common::FS::Android::UnRegisterCallbacks();
env->DeleteGlobalRef(state.native_library_class); env->DeleteGlobalRef(s_native_library_class);
env->DeleteGlobalRef(state.disk_cache_progress_class); env->DeleteGlobalRef(s_disk_cache_progress_class);
env->DeleteGlobalRef(state.load_callback_stage_class); env->DeleteGlobalRef(s_load_callback_stage_class);
env->DeleteGlobalRef(state.game_dir_class); env->DeleteGlobalRef(s_game_dir_class);
env->DeleteGlobalRef(state.game_class); env->DeleteGlobalRef(s_game_class);
env->DeleteGlobalRef(state.string_class); env->DeleteGlobalRef(s_string_class);
env->DeleteGlobalRef(state.pair_class); env->DeleteGlobalRef(s_pair_class);
env->DeleteGlobalRef(state.overlay_control_data_class); env->DeleteGlobalRef(s_overlay_control_data_class);
env->DeleteGlobalRef(state.patch_class); env->DeleteGlobalRef(s_patch_class);
env->DeleteGlobalRef(state.double_class); env->DeleteGlobalRef(s_double_class);
env->DeleteGlobalRef(state.integer_class); env->DeleteGlobalRef(s_integer_class);
env->DeleteGlobalRef(state.boolean_class); env->DeleteGlobalRef(s_boolean_class);
env->DeleteGlobalRef(state.player_input_class); env->DeleteGlobalRef(s_player_input_class);
env->DeleteGlobalRef(state.yuzu_input_device_interface); env->DeleteGlobalRef(s_yuzu_input_device_interface);
// UnInitialize applets // UnInitialize applets
SoftwareKeyboard::CleanupJNI(env); SoftwareKeyboard::CleanupJNI(env);
@@ -464,7 +463,7 @@ namespace Common::Android {
#endif #endif
void Initialize(JavaVM* vm, JNIEnv *env) { void Initialize(JavaVM* vm, JNIEnv *env) {
state.java_vm = vm; s_java_vm = vm;
InitFFmpegOnLoad(vm); InitFFmpegOnLoad(vm);
if (env->ExceptionCheck()) { if (env->ExceptionCheck()) {
@@ -473,169 +472,169 @@ void Initialize(JavaVM* vm, JNIEnv *env) {
// Initialize Java classes // Initialize Java classes
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary"); const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
state.native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class)); s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
state.disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef( s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress"))); env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
state.load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass( s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage"))); "org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir"); const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
state.game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class)); s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
state.game_dir_constructor = env->GetMethodID(game_dir_class, "<init>", s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
"(Ljava/lang/String;Z)V"); "(Ljava/lang/String;Z)V");
env->DeleteLocalRef(game_dir_class); env->DeleteLocalRef(game_dir_class);
// Initialize methods // Initialize methods
state.exit_emulation_activity = s_exit_emulation_activity =
env->GetStaticMethodID(state.native_library_class, "exitEmulationActivity", "(I)V"); env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
state.disk_cache_load_progress = s_disk_cache_load_progress =
env->GetStaticMethodID(state.disk_cache_progress_class, "loadProgress", "(III)V"); env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
state.copy_to_storage = env->GetStaticMethodID(state.native_library_class, "copyFileToStorage", s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
"(Ljava/lang/String;Ljava/lang/String;)Z"); "(Ljava/lang/String;Ljava/lang/String;)Z");
state.file_exists = env->GetStaticMethodID(state.native_library_class, "exists", s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
"(Ljava/lang/String;)Z"); "(Ljava/lang/String;)Z");
state.file_extension = env->GetStaticMethodID(state.native_library_class, "getFileExtension", s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
"(Ljava/lang/String;)Ljava/lang/String;"); "(Ljava/lang/String;)Ljava/lang/String;");
state.on_emulation_started = s_on_emulation_started =
env->GetStaticMethodID(state.native_library_class, "onEmulationStarted", "()V"); env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
state.on_emulation_stopped = s_on_emulation_stopped =
env->GetStaticMethodID(state.native_library_class, "onEmulationStopped", "(I)V"); env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
state.on_program_changed = s_on_program_changed =
env->GetStaticMethodID(state.native_library_class, "onProgramChanged", "(I)V"); env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game"); const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
state.game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class)); s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
state.game_constructor = env->GetMethodID(game_class, "<init>", s_game_constructor = env->GetMethodID(game_class, "<init>",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/" "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;Z)V"); "String;Ljava/lang/String;Ljava/lang/String;Z)V");
state.game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;"); s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
state.game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;"); s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
state.game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;"); s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
state.game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;"); s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
state.game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;"); s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
state.game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z"); s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
env->DeleteLocalRef(game_class); env->DeleteLocalRef(game_class);
const jclass string_class = env->FindClass("java/lang/String"); const jclass string_class = env->FindClass("java/lang/String");
state.string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class)); s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
env->DeleteLocalRef(string_class); env->DeleteLocalRef(string_class);
const jclass pair_class = env->FindClass("kotlin/Pair"); const jclass pair_class = env->FindClass("kotlin/Pair");
state.pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class)); s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
state.pair_constructor = s_pair_constructor =
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V"); env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
state.pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;"); s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
state.pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;"); s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
env->DeleteLocalRef(pair_class); env->DeleteLocalRef(pair_class);
const jclass overlay_control_data_class = const jclass overlay_control_data_class =
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData"); env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
state.overlay_control_data_class = s_overlay_control_data_class =
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class)); reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
state.overlay_control_data_constructor = s_overlay_control_data_constructor =
env->GetMethodID(overlay_control_data_class, "<init>", env->GetMethodID(overlay_control_data_class, "<init>",
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V"); "(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
state.overlay_control_data_id_field = s_overlay_control_data_id_field =
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;"); env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
state.overlay_control_data_enabled_field = s_overlay_control_data_enabled_field =
env->GetFieldID(overlay_control_data_class, "enabled", "Z"); env->GetFieldID(overlay_control_data_class, "enabled", "Z");
state.overlay_control_data_landscape_position_field = s_overlay_control_data_landscape_position_field =
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
state.overlay_control_data_portrait_position_field = s_overlay_control_data_portrait_position_field =
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
state.overlay_control_data_foldable_position_field = s_overlay_control_data_foldable_position_field =
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;"); env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
state.overlay_control_data_individual_scale_field = s_overlay_control_data_individual_scale_field =
env->GetFieldID(overlay_control_data_class, "individualScale", "F"); env->GetFieldID(overlay_control_data_class, "individualScale", "F");
env->DeleteLocalRef(overlay_control_data_class); env->DeleteLocalRef(overlay_control_data_class);
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch"); const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
state.patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class)); s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
state.patch_constructor = env->GetMethodID( s_patch_constructor = env->GetMethodID(
patch_class, "<init>", patch_class, "<init>",
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V"); "(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
state.patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z"); s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
state.patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;"); s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
state.patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;"); s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
state.patch_type_field = env->GetFieldID(patch_class, "type", "I"); s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
state.patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;"); s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
state.patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;"); s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
env->DeleteLocalRef(patch_class); env->DeleteLocalRef(patch_class);
const jclass double_class = env->FindClass("java/lang/Double"); const jclass double_class = env->FindClass("java/lang/Double");
state.double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class)); s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
state.double_constructor = env->GetMethodID(double_class, "<init>", "(D)V"); s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
state.double_value_method = env->GetMethodID(double_class, "doubleValue", "()D"); s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
env->DeleteLocalRef(double_class); env->DeleteLocalRef(double_class);
const jclass int_class = env->FindClass("java/lang/Integer"); const jclass int_class = env->FindClass("java/lang/Integer");
state.integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class)); s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
state.integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V"); s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
state.integer_value_method = env->GetMethodID(int_class, "intValue", "()I"); s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
env->DeleteLocalRef(int_class); env->DeleteLocalRef(int_class);
const jclass boolean_class = env->FindClass("java/lang/Boolean"); const jclass boolean_class = env->FindClass("java/lang/Boolean");
state.boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class)); s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
state.boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V"); s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
state.boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z"); s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
env->DeleteLocalRef(boolean_class); env->DeleteLocalRef(boolean_class);
const jclass player_input_class = const jclass player_input_class =
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput"); env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
state.player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class)); s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
state.player_input_constructor = env->GetMethodID( s_player_input_constructor = env->GetMethodID(
player_input_class, "<init>", player_input_class, "<init>",
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V"); "(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
state.player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z"); s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
state.player_input_buttons_field = s_player_input_buttons_field =
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
state.player_input_analogs_field = s_player_input_analogs_field =
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
state.player_input_motions_field = s_player_input_motions_field =
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;"); env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
state.player_input_vibration_enabled_field = s_player_input_vibration_enabled_field =
env->GetFieldID(player_input_class, "vibrationEnabled", "Z"); env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
state.player_input_vibration_strength_field = s_player_input_vibration_strength_field =
env->GetFieldID(player_input_class, "vibrationStrength", "I"); env->GetFieldID(player_input_class, "vibrationStrength", "I");
state.player_input_body_color_left_field = s_player_input_body_color_left_field =
env->GetFieldID(player_input_class, "bodyColorLeft", "J"); env->GetFieldID(player_input_class, "bodyColorLeft", "J");
state.player_input_body_color_right_field = s_player_input_body_color_right_field =
env->GetFieldID(player_input_class, "bodyColorRight", "J"); env->GetFieldID(player_input_class, "bodyColorRight", "J");
state.player_input_button_color_left_field = s_player_input_button_color_left_field =
env->GetFieldID(player_input_class, "buttonColorLeft", "J"); env->GetFieldID(player_input_class, "buttonColorLeft", "J");
state.player_input_button_color_right_field = s_player_input_button_color_right_field =
env->GetFieldID(player_input_class, "buttonColorRight", "J"); env->GetFieldID(player_input_class, "buttonColorRight", "J");
state.player_input_profile_name_field = s_player_input_profile_name_field =
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;"); env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
state.player_input_use_system_vibrator_field = s_player_input_use_system_vibrator_field =
env->GetFieldID(player_input_class, "useSystemVibrator", "Z"); env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
env->DeleteLocalRef(player_input_class); env->DeleteLocalRef(player_input_class);
const jclass yuzu_input_device_interface = const jclass yuzu_input_device_interface =
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice"); env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
state.yuzu_input_device_interface = s_yuzu_input_device_interface =
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface)); reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
state.yuzu_input_device_get_name = s_yuzu_input_device_get_name =
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
state.yuzu_input_device_get_guid = s_yuzu_input_device_get_guid =
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;"); env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
state.yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort", s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
"()I"); "()I");
state.yuzu_input_device_get_supports_vibration = s_yuzu_input_device_get_supports_vibration =
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z"); env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
state.yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate", s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
"(F)V"); "(F)V");
state.yuzu_input_device_get_axes = s_yuzu_input_device_get_axes =
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;"); env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
state.yuzu_input_device_has_keys = s_yuzu_input_device_has_keys =
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z"); env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
env->DeleteLocalRef(yuzu_input_device_interface); env->DeleteLocalRef(yuzu_input_device_interface);
state.add_netplay_message = env->GetStaticMethodID(state.native_library_class, "addNetPlayMessage", s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
"(ILjava/lang/String;)V"); "(ILjava/lang/String;)V");
state.clear_chat = env->GetStaticMethodID(state.native_library_class, "clearChat", "()V"); s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
// Initialize Android Storage // Initialize Android Storage
Common::FS::Android::RegisterCallbacks(env, state.native_library_class); Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
// Initialize applets // Initialize applets
Common::Android::SoftwareKeyboard::InitJNI(env); Common::Android::SoftwareKeyboard::InitJNI(env);
+18 -4
View File
@@ -22,22 +22,36 @@ template <typename T>
return std::size_t(sizeof(T) * CHAR_BIT); return std::size_t(sizeof(T) * CHAR_BIT);
} }
template<typename T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr u32 MostSignificantBit(const T value) {
return u32(sizeof(T) * CHAR_BIT - 1 - std::countl_zero(value));
}
template<typename T> template<typename T>
requires std::is_integral_v<T> requires std::is_integral_v<T>
[[nodiscard]] constexpr T Log2Floor(const T value) { [[nodiscard]] constexpr T Log2Floor(const T value) {
return std::bit_width(value) - 1; return T(MostSignificantBit<T>(value));
} }
template<typename T> template<typename T>
requires std::is_integral_v<T> requires std::is_integral_v<T>
[[nodiscard]] constexpr T Log2Ceil(const T value) { [[nodiscard]] constexpr T Log2Ceil(const T value) {
return std::bit_width(value - 1); const T log2_f = Log2Floor<T>(value);
return T(log2_f + T((value ^ (T(1ULL) << log2_f)) != T(0ULL)));
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] T NextPow2(T value) {
return T(1ULL << (sizeof(T) * CHAR_BIT - std::countl_zero(value - 1U)));
} }
template <size_t bit_index, typename T> template <size_t bit_index, typename T>
requires (std::is_integral_v<T> && bit_index < BitSize<T>()) requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Bit(const T value) { [[nodiscard]] constexpr bool Bit(const T value) {
return (T(value >> bit_index) & T(1)) == T(1); static_assert(bit_index < BitSize<T>(), "bit_index must be smaller than size of T");
return ((value >> bit_index) & T(1)) == T(1);
} }
} // namespace Common } // namespace Common
+13 -5
View File
@@ -25,18 +25,26 @@ template <typename T>
requires std::is_unsigned_v<T> requires std::is_unsigned_v<T>
inline std::size_t HashValue(T val) { inline std::size_t HashValue(T val) {
const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits; const unsigned int size_t_bits = std::numeric_limits<std::size_t>::digits;
const unsigned int length = (std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits); const unsigned int length =
(std::numeric_limits<T>::digits - 1) / static_cast<unsigned int>(size_t_bits);
std::size_t seed = 0; std::size_t seed = 0;
for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits)
seed ^= std::size_t(val >> i) + (seed << 6) + (seed >> 2); for (unsigned int i = length * size_t_bits; i > 0; i -= size_t_bits) {
return seed ^= std::size_t(val) + (seed << 6) + (seed >> 2); seed ^= static_cast<size_t>(val >> i) + (seed << 6) + (seed >> 2);
}
seed ^= static_cast<size_t>(val) + (seed << 6) + (seed >> 2);
return seed;
} }
template <size_t Bits> template <size_t Bits>
struct HashCombineImpl { struct HashCombineImpl {
template <typename T> template <typename T>
static inline T fn(T seed, T value) { static inline T fn(T seed, T value) {
return seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2); seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
return seed;
} }
}; };
+3 -4
View File
@@ -244,8 +244,7 @@ WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0} , ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0} , us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0} , ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
, rdtsc_ns_integer{invariant_ ? rdtsc_frequency_ / NsRatio::den : 1} , rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_, NsRatio::den) : 1}
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_ % NsRatio::den, NsRatio::den) : 0}
, cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0} , cntpct_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(CNTFRQ, rdtsc_frequency_) : 0}
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0} , gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
, invariant{invariant_} , invariant{invariant_}
@@ -292,7 +291,7 @@ bool WallClock::IsNative() const {
} }
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const { u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
return ns.count() * rdtsc_ns_integer + MultiplyHigh(ns.count(), rdtsc_ns_factor); return invariant ? MultiplyHigh(ns.count(), rdtsc_ns_factor) : ns.count();
} }
#elif defined(HAS_NCE) #elif defined(HAS_NCE)
namespace { namespace {
@@ -417,7 +416,7 @@ u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
const WallClock g_wall_clock = [] { const WallClock g_wall_clock = [] {
#if defined(ARCHITECTURE_x86_64) #if defined(ARCHITECTURE_x86_64)
auto const& caps = Common::g_cpu_caps; auto const& caps = Common::g_cpu_caps;
return WallClock(caps.invariant_tsc && caps.tsc_frequency > std::nano::den, caps.tsc_frequency); return WallClock(caps.invariant_tsc && caps.tsc_frequency >= std::nano::den, caps.tsc_frequency);
#elif defined(HAS_NCE) #elif defined(HAS_NCE)
return WallClock(false, 1); return WallClock(false, 1);
#else #else
-1
View File
@@ -96,7 +96,6 @@ public:
u64 ns_rdtsc_factor; u64 ns_rdtsc_factor;
u64 us_rdtsc_factor; u64 us_rdtsc_factor;
u64 ms_rdtsc_factor; u64 ms_rdtsc_factor;
u64 rdtsc_ns_integer;
u64 rdtsc_ns_factor; u64 rdtsc_ns_factor;
u64 cntpct_rdtsc_factor; u64 cntpct_rdtsc_factor;
u64 gputick_rdtsc_factor; u64 gputick_rdtsc_factor;
+2 -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 2020 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -15,14 +12,14 @@ namespace Common {
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeil(N number, D divisor) { [[nodiscard]] constexpr N DivCeil(N number, D divisor) {
return N((D(number) + divisor - 1) / divisor); return static_cast<N>((static_cast<D>(number) + divisor - 1) / divisor);
} }
/// Ceiled integer division with logarithmic divisor in base 2 /// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D> template <typename N, typename D>
requires std::is_integral_v<N> && std::is_unsigned_v<D> requires std::is_integral_v<N> && std::is_unsigned_v<D>
[[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) { [[nodiscard]] constexpr N DivCeilLog2(N value, D alignment_log2) {
return N((D(value) + (D(1) << alignment_log2) - 1) >> alignment_log2); return static_cast<N>((static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2);
} }
} // namespace Common } // namespace Common
+18 -16
View File
@@ -17,33 +17,35 @@
namespace Common { namespace Common {
// glibc, mlibc, musl, and newlib all define their own variants of strerror_r
// We don't need to use the preprocessor, we can just select depending on return type
template<typename T> std::string HandleStrerrorR(T r, char *err_str);
template<> std::string HandleStrerrorR(char* r, char *) { return std::string{r}; }
template<> std::string HandleStrerrorR(const char* r, char *) { return std::string{r}; }
template<> std::string HandleStrerrorR(int r, char *err_str) {
return std::string{r != 0
? "(strerror_r failed to format error)"
: err_str};
}
std::string NativeErrorToString(int e) { std::string NativeErrorToString(int e) {
#ifdef _WIN32 #ifdef _WIN32
LPSTR err_str; LPSTR err_str;
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS, FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
LPSTR(&err_str), 1, nullptr); reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
if (res) { if (!res) {
return "(FormatMessageA failed to format error)";
}
std::string ret(err_str); std::string ret(err_str);
LocalFree(err_str); LocalFree(err_str);
return ret; return ret;
}
return "(FormatMessageA failed to format error)";
#else #else
char err_str[255]; char err_str[255];
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str); #if defined(__ANDROID__) || \
(defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)))
// Thread safe (GNU-specific)
const char* str = strerror_r(e, err_str, sizeof(err_str));
return std::string(str);
#else
// Thread safe (XSI-compliant)
int second_err = strerror_r(e, err_str, sizeof(err_str));
if (second_err != 0) {
return "(strerror_r failed to format error)";
}
return std::string(err_str);
#endif // GLIBC etc.
#endif // _WIN32 #endif // _WIN32
} }
+1
View File
@@ -9,6 +9,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/fiber.h" #include "common/fiber.h"
#include "common/virtual_buffer.h"
#include <boost/context/detail/fcontext.hpp> #include <boost/context/detail/fcontext.hpp>
+11 -64
View File
@@ -5,7 +5,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm> #include <algorithm>
#include <cctype>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "common/container/unordered_map.h" #include "common/container/unordered_map.h"
@@ -481,80 +480,28 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }), [type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
path.end()); path.end());
std::string root; const bool absolute = !path.empty() && path[0] == type2;
std::string_view components{path};
bool drive_relative = false;
#ifdef _WIN32
const bool network = path.size() > 1 && path[0] == type2 && path[1] == type2;
const bool drive =
path.size() > 1 && std::isalpha(static_cast<unsigned char>(path[0])) && path[1] == ':';
if (network) {
root.assign(2, type2);
components.remove_prefix(2);
} else if (drive) {
root.assign(path.data(), 2);
components.remove_prefix(2);
if (!components.empty() && components.front() == type2) {
root += type2;
components.remove_prefix(1);
} else {
drive_relative = true;
}
}
#endif
if (root.empty() && !components.empty() && components.front() == type2) {
root += type2;
components.remove_prefix(1);
}
const auto path_parts = SplitPathComponents(components);
std::size_t root_component_count = 0;
#ifdef _WIN32
if (network) {
root_component_count = 2;
const auto is_unc = [](std::string_view part) {
return part.size() == 3 && (part[0] == 'U' || part[0] == 'u') &&
(part[1] == 'N' || part[1] == 'n') && (part[2] == 'C' || part[2] == 'c');
};
if (path_parts.size() >= 2 && path_parts[0] == "?" && is_unc(path_parts[1])) {
root_component_count = 4;
}
}
#endif
std::vector<std::string_view> parts; std::vector<std::string_view> parts;
for (std::size_t i = 0; i < path_parts.size(); ++i) {
const auto part = path_parts[i]; for (const auto part : SplitPathComponents(path))
if (i < root_component_count) { {
parts.push_back(part); if (part.empty() || part == ".")
} else if (part.empty() || part == ".") {
continue; continue;
} else if (part == "..") { if (part == ".." && !parts.empty() && parts.back() != "..")
if (parts.size() > root_component_count) {
parts.pop_back(); parts.pop_back();
} else if (part != "..") parts.push_back(part);
} else {
parts.push_back(part);
}
} }
const std::size_t root_length = root.size(); std::string resolved = absolute ? std::string(1, type2) : std::string{};
std::string resolved = std::move(root); for (std::size_t i = 0; i < parts.size(); ++i)
for (std::size_t i = 0; i < parts.size(); ++i) { {
if (i != 0 || (!resolved.empty() && resolved.back() != type2 && !drive_relative)) if (i != 0)
resolved += type2; resolved += type2;
resolved.append(parts[i].data(), parts[i].size()); resolved.append(parts[i].data(), parts[i].size());
} }
path = std::move(resolved); path = std::move(resolved);
if (!path.empty() && path.size() == root_length) {
return path;
}
return std::string(RemoveTrailingSlash(path)); return std::string(RemoveTrailingSlash(path));
} }
+2 -3
View File
@@ -347,9 +347,8 @@ enum class DirectorySeparator {
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" } // i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
[[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename); [[nodiscard]] std::vector<std::string> SplitPathComponentsCopy(std::string_view filename);
// Normalizes directory separators, removes duplicate and non-root trailing separators, and resolves // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// '.' and '..' components without traversing above the path root. Windows drive and UNC roots are // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
// preserved.
[[nodiscard]] std::string SanitizePath( [[nodiscard]] std::string SanitizePath(
std::string_view path, std::string_view path,
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
+28
View File
@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: 2015 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstddef>
#include <utility>
#include <boost/functional/hash.hpp>
namespace Common {
struct PairHash {
template <class T1, class T2>
std::size_t operator()(const std::pair<T1, T2>& pair) const noexcept {
std::size_t seed = std::hash<T1>()(pair.first);
boost::hash_combine(seed, std::hash<T2>()(pair.second));
return seed;
}
};
template <typename T>
struct IdentityHash {
[[nodiscard]] size_t operator()(T value) const noexcept {
return static_cast<size_t>(value);
}
};
} // namespace Common
+16 -10
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
// SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-FileCopyrightText: 2014 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@@ -19,12 +16,14 @@ namespace Common {
[[nodiscard]] constexpr u8 ToHexNibble(char c) { [[nodiscard]] constexpr u8 ToHexNibble(char c) {
if (c >= 65 && c <= 70) { if (c >= 65 && c <= 70) {
return u8(c - 55); return static_cast<u8>(c - 55);
} }
if (c >= 97 && c <= 102) { if (c >= 97 && c <= 102) {
return u8(c - 87); return static_cast<u8>(c - 87);
} }
return u8(c - 48);
return static_cast<u8>(c - 48);
} }
[[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); [[nodiscard]] std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
@@ -32,28 +31,35 @@ namespace Common {
template <std::size_t Size, bool le = false> template <std::size_t Size, bool le = false>
[[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) { [[nodiscard]] constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size"); ASSERT_MSG(Size * 2 <= str.size(), "Invalid string size");
std::array<u8, Size> out{}; std::array<u8, Size> out{};
if constexpr (le) { if constexpr (le) {
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) { for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
} }
} else { } else {
for (std::size_t i = 0; i < 2 * Size; i += 2) { for (std::size_t i = 0; i < 2 * Size; i += 2) {
out[i / 2] = u8((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1])); out[i / 2] = static_cast<u8>((ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]));
} }
} }
return out; return out;
} }
template <typename ContiguousContainer> template <typename ContiguousContainer>
requires std::is_same_v<typename ContiguousContainer::value_type, u8>
[[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) { [[nodiscard]] std::string HexToString(const ContiguousContainer& data, bool upper = true) {
static_assert(std::is_same_v<typename ContiguousContainer::value_type, u8>,
"Underlying type within the contiguous container must be u8.");
constexpr std::size_t pad_width = 2; constexpr std::size_t pad_width = 2;
std::string out; std::string out;
out.reserve(std::size(data) * pad_width); out.reserve(std::size(data) * pad_width);
const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}"); const auto format_str = fmt::runtime(upper ? "{:02X}" : "{:02x}");
for (const u8 c : data) for (const u8 c : data) {
out += fmt::format(format_str, c); out += fmt::format(format_str, c);
}
return out; return out;
} }
+13 -41
View File
@@ -178,14 +178,6 @@ public:
Release(); Release();
} }
void* Allocate(size_t size) {
auto* ptr = VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (ptr == nullptr) {
LOG_CRITICAL(HW_Memory, "Failed to allocate fallback buffer with size {:#x}, error {}", size, GetLastError());
}
return ptr;
}
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
std::unique_lock lock{placeholder_mutex}; std::unique_lock lock{placeholder_mutex};
if (!IsNiechePlaceholder(virtual_offset, length)) { if (!IsNiechePlaceholder(virtual_offset, length)) {
@@ -406,10 +398,6 @@ private:
// For managarm: see https://github.com/managarm/managarm/issues/1370 // For managarm: see https://github.com/managarm/managarm/issues/1370
#else // ^^^ Windows ^^^ vvv POSIX vvv #else // ^^^ Windows ^^^ vvv POSIX vvv
#ifndef MAP_NOCORE
#define MAP_NOCORE 0
#endif
#ifdef ARCHITECTURE_arm64 #ifdef ARCHITECTURE_arm64
static void* ChooseVirtualBase(size_t virtual_size) { static void* ChooseVirtualBase(size_t virtual_size) {
@@ -434,7 +422,7 @@ static void* ChooseVirtualBase(size_t virtual_size) {
// Note: we may be able to take advantage of MAP_FIXED_NOREPLACE here. // Note: we may be able to take advantage of MAP_FIXED_NOREPLACE here.
void* map_pointer = void* map_pointer =
mmap(reinterpret_cast<void*>(hint_address), virtual_size, PROT_READ | PROT_WRITE, mmap(reinterpret_cast<void*>(hint_address), virtual_size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_NOCORE, -1, 0); MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
// If we successfully mapped, we're done. // If we successfully mapped, we're done.
if (reinterpret_cast<uintptr_t>(map_pointer) == hint_address) { if (reinterpret_cast<uintptr_t>(map_pointer) == hint_address) {
@@ -454,11 +442,11 @@ static void* ChooseVirtualBase(size_t virtual_size) {
static void* ChooseVirtualBase(size_t virtual_size) { static void* ChooseVirtualBase(size_t virtual_size) {
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER | MAP_NOCORE, -1, 0); void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
if (virtual_base != MAP_FAILED) if (virtual_base != MAP_FAILED)
return virtual_base; return virtual_base;
#endif #endif
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_NOCORE, -1, 0); return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
} }
#endif #endif
@@ -552,13 +540,13 @@ public:
} }
if (use_anon) { if (use_anon) {
LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones"); LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones");
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_NOCORE, -1, 0)); backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
if (fd > 0) { if (fd > 0) {
fd = -1; fd = -1;
close(fd); close(fd);
} }
} else { } else {
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NOCORE, fd, 0)); backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
} }
if (backing_base == MAP_FAILED) { if (backing_base == MAP_FAILED) {
LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno)); LOG_CRITICAL(HW_Memory, "mmap failed: {}", strerror(errno));
@@ -582,14 +570,6 @@ public:
Release(); Release();
} }
void* Allocate(size_t size) {
auto* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (ptr == MAP_FAILED) {
LOG_CRITICAL(HW_Memory, "Failed to allocate fallback buffer with size {:#x}, {}", size, strerror(errno));
}
return ptr;
}
void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) { void Map(size_t virtual_offset, size_t host_offset, size_t length, MemoryPermission perms) {
// Intersect the range with our address space. // Intersect the range with our address space.
AdjustMap(&virtual_offset, &length); AdjustMap(&virtual_offset, &length);
@@ -710,10 +690,12 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
{ {
#if defined(__OPENORBIS__) || defined(__managarm__) #if defined(__OPENORBIS__) || defined(__managarm__)
LOG_WARNING(HW_Memory, "Platform doesn't support fastmem"); LOG_WARNING(HW_Memory, "Platform doesn't support fastmem");
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); fallback_buffer.emplace(backing_size);
backing_base = fallback_buffer->data();
virtual_base = nullptr; virtual_base = nullptr;
#else #else
// Try to allocate a fastmem arena. // Try to allocate a fastmem arena.
// The implementation will fail with std::bad_alloc on errors.
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize); impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize);
if (impl->Init()) { if (impl->Init()) {
backing_base = impl->backing_base; backing_base = impl->backing_base;
@@ -724,26 +706,16 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
virtual_base_offset = virtual_base - impl->virtual_base; virtual_base_offset = virtual_base - impl->virtual_base;
} }
} else { } else {
LOG_WARNING(HW_Memory, "Platform can support fastmem, but can't create it");
fallback_buffer = true;
backing_base = static_cast<u8*>(impl->Allocate(backing_size));
virtual_base = nullptr;
impl.reset(); impl.reset();
LOG_WARNING(HW_Memory, "Platform can support fastmem, but can't create it");
fallback_buffer.emplace(backing_size);
backing_base = fallback_buffer->data();
virtual_base = nullptr;
} }
#endif #endif
} }
HostMemory::~HostMemory() { HostMemory::~HostMemory() = default;
#ifdef _WIN32
if (fallback_buffer) {
VirtualFree(backing_base, backing_size, MEM_RELEASE);
}
#else
if (fallback_buffer) {
munmap(backing_base, backing_size);
}
#endif
}
HostMemory::HostMemory(HostMemory&&) noexcept = default; HostMemory::HostMemory(HostMemory&&) noexcept = default;
+2 -1
View File
@@ -10,6 +10,7 @@
#include <optional> #include <optional>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/virtual_buffer.h"
namespace Common { namespace Common {
@@ -85,7 +86,7 @@ private:
u8* virtual_base{}; u8* virtual_base{};
size_t virtual_base_offset{}; size_t virtual_base_offset{};
// Windows requires it for kernels whom lack proper support for some functions! // Windows requires it for kernels whom lack proper support for some functions!
bool fallback_buffer{false}; std::optional<Common::VirtualBuffer<u8>> fallback_buffer;
}; };
} // namespace Common } // namespace Common
+6 -10
View File
@@ -10,7 +10,6 @@
#include <cstdlib> #include <cstdlib>
#include <regex> #include <regex>
#include <thread> #include <thread>
#include <boost/algorithm/string/predicate.hpp>
#if defined(__ANDROID__) #if defined(__ANDROID__)
#include <android/log.h> #include <android/log.h>
@@ -96,10 +95,9 @@ std::string FormatLogMessage(const Entry& entry) noexcept {
template <typename It> template <typename It>
Level GetLevelByName(const It begin, const It end) { Level GetLevelByName(const It begin, const It end) {
std::string_view const sv{begin, end};
for (u32 i = 0; i < u32(Level::Count); ++i) { for (u32 i = 0; i < u32(Level::Count); ++i) {
auto const level_name = GetLevelName(Level(i)); const char* level_name = GetLevelName(Level(i));
if (boost::iequals(sv, level_name)) if (Common::ComparePartialString(begin, end, level_name))
return Level(i); return Level(i);
} }
return Level::Count; return Level::Count;
@@ -107,10 +105,9 @@ Level GetLevelByName(const It begin, const It end) {
template <typename It> template <typename It>
Class GetClassByName(const It begin, const It end) { Class GetClassByName(const It begin, const It end) {
std::string_view const sv{begin, end};
for (u32 i = 0; i < u32(Class::Count); ++i) { for (u32 i = 0; i < u32(Class::Count); ++i) {
auto const level_name = GetLogClassName(Class(i)); const char* level_name = GetLogClassName(Class(i));
if (boost::iequals(sv, level_name)) if (Common::ComparePartialString(begin, end, level_name))
return Class(i); return Class(i);
} }
return Class::Count; return Class::Count;
@@ -123,13 +120,12 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end)); LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: {}", std::string(begin, end));
return false; return false;
} }
auto const sv = std::string_view{begin, level_separator}; const Level level = GetLevelByName(level_separator + 1, end);
auto const level = GetLevelByName(level_separator + 1, end);
if (level == Level::Count) { if (level == Level::Count) {
LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end)); LOG_ERROR(Log, "Unknown log level in filter: {}", std::string(begin, end));
return false; return false;
} }
if (boost::iequals(sv, "*")) { if (Common::ComparePartialString(begin, level_separator, "*")) {
instance.class_levels.fill(level); instance.class_levels.fill(level);
return true; return true;
} }
+27
View File
@@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <memory>
#include <type_traits>
namespace Common {
template <class T>
requires(!std::is_array_v<T>)
std::unique_ptr<T> make_unique_for_overwrite() {
return std::unique_ptr<T>(new T);
}
template <class T>
requires std::is_unbounded_array_v<T>
std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) {
return std::unique_ptr<T>(new std::remove_extent_t<T>[n]);
}
template <class T, class... Args>
requires std::is_bounded_array_v<T>
void make_unique_for_overwrite(Args&&...) = delete;
} // namespace Common
+32 -4
View File
@@ -13,11 +13,39 @@ PageTable::PageTable() = default;
PageTable::~PageTable() noexcept = default; PageTable::~PageTable() noexcept = default;
void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_bits) { bool PageTable::BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context,
auto const num_page_table_entries = 1ULL << (address_space_width_in_bits - page_bits); Common::ProcessAddress address) const {
entries.ResizeAndClear(num_page_table_entries); out_context->next_offset = GetInteger(address);
out_context->next_page = address / page_size;
return this->ContinueTraversal(out_entry, out_context);
}
bool PageTable::ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const {
// Setup invalid defaults.
out_entry->phys_addr = 0;
out_entry->block_size = page_size;
// Validate that we can read the actual entry.
if (auto const page = context->next_page; page < entries.size()) {
// Validate that the entry is mapped.
if (auto const paddr = entries[page].addr; paddr != 0) {
// Populate the results.
out_entry->phys_addr = paddr + context->next_offset;
context->next_page += 1;
context->next_offset += page_size;
return true;
}
}
context->next_page += 1;
context->next_offset += page_size;
return false;
}
void PageTable::Resize(std::size_t address_space_width_in_bits, std::size_t page_size_in_bits) {
auto const num_page_table_entries = 1ULL << (address_space_width_in_bits - page_size_in_bits);
entries.resize(num_page_table_entries);
current_address_space_width_in_bits = address_space_width_in_bits; current_address_space_width_in_bits = address_space_width_in_bits;
current_page_bits = page_bits; page_size = 1ULL << page_size_in_bits;
} }
} // namespace Common } // namespace Common
+56 -64
View File
@@ -9,22 +9,22 @@
#include <atomic> #include <atomic>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/sparse_large_vector.h"
#include "common/typed_address.h" #include "common/typed_address.h"
#include "common/virtual_buffer.h"
namespace Common { namespace Common {
enum class PageType : u8 { enum class PageType : u8 {
/// Page is unmapped and should cause an access error. /// Page is unmapped and should cause an access error.
Unmapped = 0b00, Unmapped,
/// Page is mapped to regular memory. This is the only type you can get pointers to. /// Page is mapped to regular memory. This is the only type you can get pointers to.
Memory = 0b01, Memory,
/// Page is mapped to regular memory, but inaccessible from CPU fastmem and must use /// Page is mapped to regular memory, but inaccessible from CPU fastmem and must use
/// the callbacks. /// the callbacks.
DebugMemory = 0b10, DebugMemory,
/// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and /// Page is mapped to regular memory, but also needs to check for rasterizer cache flushing and
/// invalidation /// invalidation
RasterizerCachedMemory = 0b11, RasterizerCachedMemory,
}; };
/** /**
@@ -42,86 +42,57 @@ struct PageTable {
u64 next_offset{}; u64 next_offset{};
}; };
/// Masks out bits reserved for attribute tagging. /// Number of bits reserved for attribute tagging.
static constexpr u64 ATTRIBUTE_MASK = ((1ULL << 44) - 1) << 12; /// This can be at most the guaranteed alignment of the pointers in the page table.
static constexpr int ATTRIBUTE_BITS = 2;
/// Specifies sign bit for page table entries.
static constexpr u64 SIGN_BIT = 45 + 12; // 44 bits of data + page offset
/** /**
* Atomic tuple of host pointer, page type, and block id. * Pair of host pointer and page type attribute.
* This uses the lower bits of a given pointer to store the attributes. * This uses the lower bits of a given pointer to store the attribute tag.
* Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method * Writing and reading the pointer attribute pair is guaranteed to be atomic for the same method
* call. In other words, they are guaranteed to be synchronized at all times. * call. In other words, they are guaranteed to be synchronized at all times.
*/ */
class PageEntryData { class PageInfo {
public: public:
struct Data {
Data(bool marked_, PageType type_, u16 block_, u64 page_)
: marked(static_cast<u64>(marked_) & 0b1)
, type(static_cast<u64>(type_) & ((1ULL << 2) - 1))
, block(static_cast<u64>(block_) & ((1ULL << 9) - 1))
, page((page_ >> 12) & ((1ULL << 45) - 1))
, block2((static_cast<u64>(block_) >> 9) & ((1ULL << 7) - 1)) {}
u64 marked : 1;
u64 type : 2;
u64 block : 9;
u64 page : 45; // 44 bits of actual data (64 - page offset (12) - reserved (8)) + a sign bit
u64 block2 : 7;
};
[[nodiscard]] Data Raw() const noexcept {
return std::bit_cast<Data>(data_raw.load(std::memory_order_relaxed));
}
/// Returns the page pointer /// Returns the page pointer
[[nodiscard]] uintptr_t Pointer(bool ignored_marked = false) const noexcept { [[nodiscard]] uintptr_t Pointer() const noexcept {
return ExtractPointer(std::bit_cast<Data>(data_raw.load(std::memory_order_relaxed)), ignored_marked); return ExtractPointer(raw.load(std::memory_order_relaxed));
} }
/// Returns the page type attribute /// Returns the page type attribute
[[nodiscard]] PageType Type() const noexcept { [[nodiscard]] PageType Type() const noexcept {
return static_cast<PageType>(std::bit_cast<Data>(data_raw.load(std::memory_order_relaxed)).type); return ExtractType(raw.load(std::memory_order_relaxed));
}
/// Returns the block identifier.
[[nodiscard]] u16 Block() const noexcept {
return ExtractBlock(std::bit_cast<Data>(data_raw.load(std::memory_order_relaxed)));
} }
/// Returns the page pointer and attribute pair, extracted from the same atomic read /// Returns the page pointer and attribute pair, extracted from the same atomic read
[[nodiscard]] std::tuple<uintptr_t, PageType, u16> PointerTypeBlock(bool ignore_marked = false) const noexcept { [[nodiscard]] std::pair<uintptr_t, PageType> PointerType() const noexcept {
const auto non_atomic_raw = std::bit_cast<Data>(data_raw.load(std::memory_order_relaxed)); const uintptr_t non_atomic_raw = raw.load(std::memory_order_relaxed);
return {ExtractPointer(non_atomic_raw, ignore_marked), static_cast<PageType>(non_atomic_raw.type), ExtractBlock(non_atomic_raw)}; return {ExtractPointer(non_atomic_raw), ExtractType(non_atomic_raw)};
} }
/// Write page info atomically /// Returns the raw representation of the page information.
inline void Store(bool marked, PageType type, u16 block, uintptr_t pointer) noexcept { /// Use ExtractPointer and ExtractType to unpack the value.
data_raw.store(std::bit_cast<u64>(Data{marked, type, block, pointer})); [[nodiscard]] uintptr_t Raw() const noexcept {
return raw.load(std::memory_order_relaxed);
} }
inline void MarkRasterizerCached() noexcept { /// Write a page pointer and type pair atomically
data_raw.fetch_or(0b111); void Store(uintptr_t pointer, PageType type) noexcept {
} raw.store(pointer | uintptr_t(type));
inline void MarkDebug(u64 ptr, u16 block) noexcept {
Store(true, PageType::DebugMemory, block, ptr);
} }
/// Unpack a pointer from a page info raw representation /// Unpack a pointer from a page info raw representation
[[nodiscard]] static uintptr_t ExtractPointer(Data raw, bool ignore_marked = false) noexcept { [[nodiscard]] static uintptr_t ExtractPointer(uintptr_t raw) noexcept {
return raw.marked && !ignore_marked ? 0 return raw & (~uintptr_t{0} << ATTRIBUTE_BITS);
// shift raw.page's fake sign bit to the actual sign bit, then sign extend
: ((s64)(raw.page << (64 - 44))) >> (64 - 44 - 12);
} }
[[nodiscard]] static u16 ExtractBlock(Data raw) noexcept { /// Unpack a page type from a page info raw representation
return static_cast<u16>(raw.block | (raw.block2 << 9)); [[nodiscard]] static PageType ExtractType(uintptr_t raw) noexcept {
return static_cast<PageType>(raw & ((uintptr_t{1} << ATTRIBUTE_BITS) - 1));
} }
private: private:
std::atomic<u64> data_raw; std::atomic<uintptr_t> raw;
static_assert(sizeof(Data) == sizeof(std::atomic<u64>));
}; };
PageTable(); PageTable();
@@ -129,8 +100,13 @@ struct PageTable {
PageTable(const PageTable&) = delete; PageTable(const PageTable&) = delete;
PageTable& operator=(const PageTable&) = delete; PageTable& operator=(const PageTable&) = delete;
PageTable(PageTable&&) noexcept = delete;
PageTable& operator=(PageTable&&) noexcept = delete; PageTable(PageTable&&) noexcept = default;
PageTable& operator=(PageTable&&) noexcept = default;
bool BeginTraversal(TraversalEntry* out_entry, TraversalContext* out_context,
Common::ProcessAddress address) const;
bool ContinueTraversal(TraversalEntry* out_entry, TraversalContext* context) const;
/** /**
* Resizes the page table to be able to accommodate enough pages within * Resizes the page table to be able to accommodate enough pages within
@@ -145,14 +121,30 @@ struct PageTable {
return current_address_space_width_in_bits; return current_address_space_width_in_bits;
} }
bool GetPhysicalAddress(Common::PhysicalAddress* out_phys_addr,
Common::ProcessAddress virt_addr) const {
if (virt_addr > (1ULL << this->GetAddressSpaceBits())) {
return false;
}
*out_phys_addr = entries[virt_addr / page_size].addr + GetInteger(virt_addr);
return true;
}
/// Vector of memory pointers backing each page. An entry can only be non-null if the /// Vector of memory pointers backing each page. An entry can only be non-null if the
/// corresponding attribute element is of type `Memory`. /// corresponding attribute element is of type `Memory`.
SparseLargeVector<PageEntryData> entries; struct PageEntryData {
static_assert(sizeof(PageEntryData) == 8); PageInfo ptr;
u64 block;
u64 addr;
u64 padding;
};
VirtualBuffer<PageEntryData> entries;
static_assert(sizeof(PageEntryData) == 32);
u8* fastmem_arena{}; u8* fastmem_arena{};
std::size_t current_address_space_width_in_bits{}; std::size_t current_address_space_width_in_bits{};
std::size_t current_page_bits{}; std::size_t page_size{};
}; };
} // namespace Common } // namespace Common
+18 -20
View File
@@ -8,9 +8,6 @@
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/replace.hpp>
#include <boost/algorithm/string/split.hpp>
#include "common/logging.h" #include "common/logging.h"
#include "common/param_package.h" #include "common/param_package.h"
@@ -18,16 +15,17 @@
namespace Common { namespace Common {
constexpr auto KEY_VALUE_SEPARATOR = ":"; constexpr char KEY_VALUE_SEPARATOR = ':';
constexpr auto PARAM_SEPARATOR = ","; constexpr char PARAM_SEPARATOR = ',';
constexpr auto ESCAPE_CHARACTER = "$";
constexpr auto KEY_VALUE_SEPARATOR_ESCAPE = "$0"; constexpr char ESCAPE_CHARACTER = '$';
constexpr auto PARAM_SEPARATOR_ESCAPE = "$1"; constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0";
constexpr auto ESCAPE_CHARACTER_ESCAPE = "$2"; constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1";
constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2";
/// A placeholder for empty param packages to avoid empty strings /// A placeholder for empty param packages to avoid empty strings
/// (they may be recognized as "not set" by some frontend libraries like qt) /// (they may be recognized as "not set" by some frontend libraries like qt)
constexpr auto EMPTY_PLACEHOLDER = "[empty]"; constexpr char EMPTY_PLACEHOLDER[] = "[empty]";
ParamPackage::ParamPackage(const std::string& serialized) { ParamPackage::ParamPackage(const std::string& serialized) {
if (serialized == EMPTY_PLACEHOLDER) { if (serialized == EMPTY_PLACEHOLDER) {
@@ -35,20 +33,20 @@ ParamPackage::ParamPackage(const std::string& serialized) {
} }
std::vector<std::string> pairs; std::vector<std::string> pairs;
boost::split(pairs, serialized, boost::is_any_of(PARAM_SEPARATOR)); Common::SplitString(serialized, PARAM_SEPARATOR, pairs);
for (const std::string& pair : pairs) { for (const std::string& pair : pairs) {
std::vector<std::string> key_value; std::vector<std::string> key_value;
boost::split(key_value, pair, boost::is_any_of(KEY_VALUE_SEPARATOR)); Common::SplitString(pair, KEY_VALUE_SEPARATOR, key_value);
if (key_value.size() != 2) { if (key_value.size() != 2) {
LOG_ERROR(Common, "invalid key pair {}", pair); LOG_ERROR(Common, "invalid key pair {}", pair);
continue; continue;
} }
for (auto& part : key_value) { for (std::string& part : key_value) {
boost::replace_all(part, KEY_VALUE_SEPARATOR_ESCAPE, KEY_VALUE_SEPARATOR); part = Common::ReplaceAll(part, KEY_VALUE_SEPARATOR_ESCAPE, {KEY_VALUE_SEPARATOR});
boost::replace_all(part, PARAM_SEPARATOR_ESCAPE, PARAM_SEPARATOR); part = Common::ReplaceAll(part, PARAM_SEPARATOR_ESCAPE, {PARAM_SEPARATOR});
boost::replace_all(part, ESCAPE_CHARACTER_ESCAPE, ESCAPE_CHARACTER); part = Common::ReplaceAll(part, ESCAPE_CHARACTER_ESCAPE, {ESCAPE_CHARACTER});
} }
Set(key_value[0], std::move(key_value[1])); Set(key_value[0], std::move(key_value[1]));
@@ -65,10 +63,10 @@ std::string ParamPackage::Serialize() const {
for (const auto& pair : data) { for (const auto& pair : data) {
std::array<std::string, 2> key_value{{pair.first, pair.second}}; std::array<std::string, 2> key_value{{pair.first, pair.second}};
for (auto& part : key_value) { for (std::string& part : key_value) {
boost::replace_all(part, ESCAPE_CHARACTER, ESCAPE_CHARACTER_ESCAPE); part = Common::ReplaceAll(part, {ESCAPE_CHARACTER}, ESCAPE_CHARACTER_ESCAPE);
boost::replace_all(part, PARAM_SEPARATOR, PARAM_SEPARATOR_ESCAPE); part = Common::ReplaceAll(part, {PARAM_SEPARATOR}, PARAM_SEPARATOR_ESCAPE);
boost::replace_all(part, KEY_VALUE_SEPARATOR, KEY_VALUE_SEPARATOR_ESCAPE); part = Common::ReplaceAll(part, {KEY_VALUE_SEPARATOR}, KEY_VALUE_SEPARATOR_ESCAPE);
} }
result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR; result += key_value[0] + KEY_VALUE_SEPARATOR + key_value[1] + PARAM_SEPARATOR;
} }
+6 -6
View File
@@ -8,7 +8,8 @@
#include <iterator> #include <iterator>
#include <cstring> #include <cstring>
#include <memory>
#include "common/make_unique_for_overwrite.h"
namespace Common { namespace Common {
@@ -37,9 +38,8 @@ public:
ScratchBuffer() = default; ScratchBuffer() = default;
explicit ScratchBuffer(size_type initial_capacity) explicit ScratchBuffer(size_type initial_capacity)
: last_requested_size{initial_capacity} : last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
, buffer_capacity{initial_capacity} buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
, buffer{std::make_unique_for_overwrite<T[]>(initial_capacity)} {}
~ScratchBuffer() = default; ~ScratchBuffer() = default;
ScratchBuffer(const ScratchBuffer&) = delete; ScratchBuffer(const ScratchBuffer&) = delete;
@@ -64,7 +64,7 @@ public:
/// The previously held data will remain intact. /// The previously held data will remain intact.
void resize(size_type size) { void resize(size_type size) {
if (size > buffer_capacity) { if (size > buffer_capacity) {
auto new_buffer = std::make_unique_for_overwrite<T[]>(size); auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T)); std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T));
buffer = std::move(new_buffer); buffer = std::move(new_buffer);
buffer_capacity = size; buffer_capacity = size;
@@ -77,7 +77,7 @@ public:
void resize_destructive(size_type size) { void resize_destructive(size_type size) {
if (size > buffer_capacity) { if (size > buffer_capacity) {
buffer_capacity = size; buffer_capacity = size;
buffer = std::make_unique_for_overwrite<T[]>(buffer_capacity); buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
} }
last_requested_size = size; last_requested_size = size;
} }
+4 -1
View File
@@ -48,7 +48,6 @@ SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false); SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true); SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true); SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true); SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuBackend, true); SWITCHABLE(CpuBackend, true);
SWITCHABLE(CpuAccuracy, true); SWITCHABLE(CpuAccuracy, true);
@@ -178,6 +177,10 @@ bool IsGPUFenceBehaviorAccurate() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate; return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
} }
bool IsGPUFenceBehaviorStrict() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
}
bool IsFastmemEnabled() { bool IsFastmemEnabled() {
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging) if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
return bool(values.cpuopt_fastmem); return bool(values.cpuopt_fastmem);
+22 -40
View File
@@ -65,7 +65,6 @@ SWITCHABLE(AnisotropyMode, true);
SWITCHABLE(AntiAliasing, false); SWITCHABLE(AntiAliasing, false);
SWITCHABLE(AspectRatio, true); SWITCHABLE(AspectRatio, true);
SWITCHABLE(AstcDecodeMode, true); SWITCHABLE(AstcDecodeMode, true);
SWITCHABLE(AstcRecompression, true);
SWITCHABLE(AudioMode, true); SWITCHABLE(AudioMode, true);
SWITCHABLE(CpuBackend, true); SWITCHABLE(CpuBackend, true);
SWITCHABLE(CpuAccuracy, true); SWITCHABLE(CpuAccuracy, true);
@@ -260,6 +259,8 @@ struct Values {
Category::Cpu}; Category::Cpu};
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto, SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
"cpu_accuracy", Category::Cpu}; "cpu_accuracy", Category::Cpu};
SwitchableSetting<bool> relocate_36bit_address_space{
linkage, false, "relocate_36bit_address_space", Category::Cpu};
SwitchableSetting<CpuClock> cpu_clock{linkage, SwitchableSetting<CpuClock> cpu_clock{linkage,
CpuClock::Normal, CpuClock::Normal,
"fast_cpu_time", "fast_cpu_time",
@@ -525,7 +526,7 @@ struct Values {
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage, SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
GpuFenceBehavior::Default, GpuFenceBehavior::Default,
GpuFenceBehavior::Default, GpuFenceBehavior::Default,
GpuFenceBehavior::Accurate, GpuFenceBehavior::Strict,
"gpu_fence_behavior", "gpu_fence_behavior",
Category::RendererAdvanced, Category::RendererAdvanced,
Specialization::Default, Specialization::Default,
@@ -553,22 +554,6 @@ struct Values {
"accelerate_astc", "accelerate_astc",
Category::RendererAdvanced}; Category::RendererAdvanced};
SwitchableSetting<FramePacingMode, true> frame_pacing_mode{linkage,
FramePacingMode::Target_Auto,
FramePacingMode::Target_Auto,
FramePacingMode::Target_120,
"frame_pacing_mode",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<AstcRecompression, true> astc_recompression{linkage,
AstcRecompression::Uncompressed,
"astc_recompression",
Category::RendererAdvanced};
SwitchableSetting<bool> sync_memory_operations{linkage, SwitchableSetting<bool> sync_memory_operations{linkage,
false, false,
"sync_memory_operations", "sync_memory_operations",
@@ -576,6 +561,8 @@ struct Values {
Specialization::Default, Specialization::Default,
true, true,
true}; true};
SwitchableSetting<bool> stall_on_gpu_fence_wait{linkage, true, "stall_on_gpu_fence_wait",
Category::RendererAdvanced};
SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock", SwitchableSetting<bool> renderer_force_max_clock{linkage, false, "force_max_clock",
Category::RendererAdvanced}; Category::RendererAdvanced};
@@ -602,8 +589,13 @@ struct Values {
"use_reactive_flushing", "use_reactive_flushing",
Category::RendererAdvanced}; Category::RendererAdvanced};
SwitchableSetting<bool> barrier_feedback_loops{linkage, true, "barrier_feedback_loops", SwitchableSetting<bool> barrier_feedback_loops{linkage,
Category::RendererAdvanced}; true,
"barrier_feedback_loops",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<bool> enable_buffer_history{linkage, SwitchableSetting<bool> enable_buffer_history{linkage,
false, false,
@@ -641,7 +633,7 @@ struct Values {
true}; true};
SwitchableSetting<bool> async_presentation{linkage, SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__ #ifdef __ANDROID__
false, true,
#else #else
false, false,
#endif #endif
@@ -655,29 +647,18 @@ struct Values {
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack", SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<bool> enable_gpu_buffer_readback{linkage,
false,
"enable_gpu_buffer_readback",
Category::RendererAdvanced,
Specialization::Default,
true,
true};
SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders", SwitchableSetting<bool> use_asynchronous_shaders{linkage, false, "use_asynchronous_shaders",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<GpuUnswizzleSize> gpu_unswizzle_texture_size{linkage, SwitchableSetting<bool> use_unified_memory{linkage, false, "use_unified_memory",
GpuUnswizzleSize::Large,
"gpu_unswizzle_texture_size",
Category::RendererHacks,
Specialization::Default};
SwitchableSetting<GpuUnswizzle> gpu_unswizzle_stream_size{linkage,
GpuUnswizzle::Medium,
"gpu_unswizzle_stream_size",
Category::RendererHacks,
Specialization::Default};
SwitchableSetting<GpuUnswizzleChunk> gpu_unswizzle_chunk_size{linkage,
GpuUnswizzleChunk::Medium,
"gpu_unswizzle_chunk_size",
Category::RendererHacks,
Specialization::Default};
SwitchableSetting<bool> gpu_unswizzle_enabled{linkage, false, "gpu_unswizzle_enabled",
Category::RendererHacks}; Category::RendererHacks};
SwitchableSetting<ExtendedDynamicState> dyna_state{linkage, SwitchableSetting<ExtendedDynamicState> dyna_state{linkage,
@@ -972,6 +953,7 @@ bool IsDMALevelSafe();
bool IsGPUFenceBehaviorDefault(); bool IsGPUFenceBehaviorDefault();
bool IsGPUFenceBehaviorBalanced(); bool IsGPUFenceBehaviorBalanced();
bool IsGPUFenceBehaviorAccurate(); bool IsGPUFenceBehaviorAccurate();
bool IsGPUFenceBehaviorStrict();
bool IsFastmemEnabled(); bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit); void SetNceEnabled(bool is_64bit);
+1 -6
View File
@@ -130,14 +130,12 @@ ENUM(TimeZone, Auto, Default, Cet, Cst6Cdt, Cuba, Eet, Egypt, Eire, Est, Est5Edt
Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu); Roc, Rok, Singapore, Turkey, Uct, Universal, Utc, WSu, Wet, Zulu);
ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16); ENUM(AnisotropyMode, Automatic, Default, X2, X4, X8, X16);
ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous); ENUM(AstcDecodeMode, Cpu, Gpu, CpuAsynchronous);
ENUM(AstcRecompression, Uncompressed, Bc1, Bc3);
ENUM(FramePacingMode, Target_Auto, Target_30, Target_60, Target_90, Target_120);
ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed); ENUM(VSyncMode, Immediate, Mailbox, Fifo, FifoRelaxed);
ENUM(VramUsageMode, Conservative, Aggressive); ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV); ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
ENUM(GpuAccuracy, Low, High); ENUM(GpuAccuracy, Low, High);
ENUM(DmaAccuracy, Default, Unsafe, Safe); ENUM(DmaAccuracy, Default, Unsafe, Safe);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate); ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict);
ENUM(CpuBackend, Dynarmic, Nce); ENUM(CpuBackend, Dynarmic, Nce);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging); ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
ENUM(CpuClock, Normal, Boost, Overclock) ENUM(CpuClock, Normal, Boost, Overclock)
@@ -153,9 +151,6 @@ ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE); ENUM(AppletMode, HLE, LLE);
ENUM(SpirvOptimizeMode, Never, OnLoad, Always); ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuClock, Normal, Boost, Overclock) ENUM(GpuClock, Normal, Boost, Overclock)
ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge)
ENUM(GpuUnswizzle, VeryLow, Low, Normal, Medium, High)
ENUM(GpuUnswizzleChunk, VeryLow, Low, Normal, Medium, High)
ENUM(TemperatureUnits, Celsius, Fahrenheit) ENUM(TemperatureUnits, Celsius, Fahrenheit)
ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3); ENUM(ExtendedDynamicState, Disabled, EDS1, EDS2, EDS3);
ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All) ENUM(GpuLogLevel, Off, Errors, Standard, Verbose, All)
-174
View File
@@ -1,174 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* virtual_buffer.cpp */
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32
#include <algorithm>
#include <windows.h>
#include <mutex>
#else
#include <sys/mman.h>
#endif
#include "common/alignment.h"
#include "common/assert.h"
#include "common/sparse_large_vector.h"
namespace Common {
#ifdef _WIN32
static std::vector<std::pair<u64, u64>> vector_regions {};
static std::mutex vector_regions_mutex {};
// Workaround for handling non-commited memory accessed by Dynarmic; usually result of an error
static LONG WINAPI FakePageFaultHandler(PEXCEPTION_POINTERS info) {
DWORD code = info->ExceptionRecord->ExceptionCode;
u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionInformation[1]);
if (code != EXCEPTION_ACCESS_VIOLATION || info->ExceptionRecord->ExceptionInformation[0] == 1) {
// Not our problem
return EXCEPTION_CONTINUE_SEARCH;
}
u64 addr = 0, addr2 = 0;
{
std::lock_guard lock(vector_regions_mutex);
for (auto region: vector_regions) {
auto addr_shifted = exception_addr >> HostPageBits;
if (region.first <= addr_shifted && addr_shifted <= region.second) {
addr = addr_shifted;
}
// Page-boundary accesses
if (auto addr_ = (exception_addr + 0x40) >> HostPageBits; addr_ != addr_shifted && region.first <= addr_ && addr_ <= region.second) {
addr2 = addr_;
}
if (addr != 0 || addr2 != 0) {
break;
}
}
}
if (addr == 0 && addr2 == 0) {
// Not our problem
return EXCEPTION_CONTINUE_SEARCH;
}
LOG_ERROR(HW_Memory, "Accessing an unallocated region of a SparseLargeVector at {:#x}; this shouldn't happen and is likely a Dynarmic error!", exception_addr);
// Commit this region
if (addr != 0) {
if (!CommitVectorPage(addr << HostPageBits, false)) {
return EXCEPTION_CONTINUE_SEARCH;
}
}
// Commit next region if needed
if (addr2 != 0) {
if (!CommitVectorPage(addr2 << HostPageBits, false)) {
return EXCEPTION_CONTINUE_SEARCH;
}
}
return EXCEPTION_CONTINUE_EXECUTION;
}
bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
MEMORY_BASIC_INFORMATION info {};
auto res = VirtualQuery(reinterpret_cast<void*>(addr), &info, sizeof(info));
if (res == 0) {
LOG_CRITICAL(HW_Memory, "Failed to query large buffer region at {:#x} with error {}, will try committing anyway", addr, GetLastError());
} else if (info.State == MEM_COMMIT) {
DWORD old_protect {};
auto perm = write ? PAGE_READWRITE : PAGE_READONLY;
if (!VirtualProtect(reinterpret_cast<void*>(addr), HostPageSize, perm, &old_protect)) {
LOG_ERROR(HW_Memory, "Failed to change permissions of large buffer region at {:#x}, error {}", addr, GetLastError());
return false;
}
return true;
} else if (info.State != MEM_RESERVE) {
LOG_ERROR(HW_Memory, "Tried to commit an unreserved large buffer region at {:#x} that is not mapped (state {:#x})", addr, info.State);
return false;
}
auto perm = write ? PAGE_READWRITE : PAGE_READONLY;
void* res2 = VirtualAlloc(reinterpret_cast<LPVOID>(addr), HostPageSize, MEM_COMMIT, perm);
if (res2 == nullptr) {
LOG_ERROR(HW_Memory, "Failed to commit large buffer region at {:#x}, error {}", addr, GetLastError());
return false;
}
return true;
}
#endif
#ifndef MAP_NOCORE
#define MAP_NOCORE 0
#endif
#ifndef MADV_FREE
#define MADV_FREE MADV_DONTNEED
#endif
void DecommitVectorPage(uintptr_t base) noexcept {
#if defined(_WIN32)
VirtualFree(reinterpret_cast<LPVOID>(base), HostPageSize, MEM_DECOMMIT);
#elif defined(__linux__)
// Linux's MADV_DONTNEED zeros out pages for us
madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_DONTNEED);
#else
madvise(reinterpret_cast<void*>(base), HostPageSize, MADV_FREE);
std::memset(reinterpret_cast<void*>(base), 0, HostPageSize);
#endif
}
void* AllocateMemoryPages(std::size_t size) noexcept {
if (auto page = HostPageSize; size % page != 0) {
LOG_WARNING(HW_Memory, "Allocating unaligned large vector with size {:#x}; aligning to {} page size", size, page);
size = AlignUp(size, page);
}
#ifdef _WIN32
// We will never use this memory entirely so instead of committing it up front let's just reserve it and commit each page individually
void* base = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (base != nullptr) {
std::lock_guard lock(vector_regions_mutex);
vector_regions.emplace_back(reinterpret_cast<u64>(base) >> HostPageBits, (reinterpret_cast<u64>(base) + size) >> HostPageBits);
static std::once_flag flag;
std::call_once(flag, []() { AddVectoredExceptionHandler(1, FakePageFaultHandler); });
} else {
// Try committing everything instead??
LOG_WARNING(HW_Memory, "Failed to reserve large vector region with error {}, trying to commit instead..", GetLastError());
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
}
ASSERT_MSG(base, "Failed to reserve {:#x} sized region with error {}", size, GetLastError());
#else
void* base = mmap(nullptr, size, PROT_READ, MAP_ANON | MAP_PRIVATE | MAP_NOCORE, -1, 0);
if (base == MAP_FAILED)
base = nullptr;
ASSERT_MSG(base, "Failed to allocate {:#x} sized region with error {}", size, strerror(errno));
#endif
return base;
}
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
if (auto page = HostPageSize; size % page != 0) {
size = AlignUp(size, page);
}
if (!base)
return;
#ifdef _WIN32
std::lock_guard lock(vector_regions_mutex);
std::erase_if(vector_regions, [base](const auto& r) {return r.first == reinterpret_cast<u64>(base); });
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
#else
ASSERT(munmap(base, size) == 0);
#endif
}
} // namespace Common
-214
View File
@@ -1,214 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
/* virtual_buffer.h */
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <bit>
#include <utility>
#include <vector>
#ifndef _WIN32
#include <unistd.h>
#include <sys/mman.h>
#endif
#include "common/alignment.h"
#include "common/assert.h"
namespace Common {
#ifdef _WIN32
constexpr u64 HostPageSize = 0x1000;
constexpr u64 HostPageBits = 12;
constexpr u64 HostPageMask = ~(HostPageSize - 1);
bool CommitVectorPage(uintptr_t addr, bool write) noexcept;
#else
inline const u64 HostPageSize = sysconf(_SC_PAGESIZE);
inline const u64 HostPageBits = std::countr_zero(HostPageSize);
inline const u64 HostPageMask = ~(HostPageSize - 1);
#endif
void* AllocateMemoryPages(std::size_t size) noexcept;
void FreeMemoryPages(void* base, std::size_t size) noexcept;
void DecommitVectorPage(uintptr_t base) noexcept;
/// A large page-aligned buffer that has optimized memory usage for zero-writes.
template <typename T>
// MSVC doesn't regard structs with atomics as trivially copyable
// requires std::is_trivially_copyable_v<T>
class SparseLargeVector final {
public:
constexpr SparseLargeVector() = default;
explicit SparseLargeVector(std::size_t count) noexcept
: alloc_size{count * sizeof(T)}
{
base_ptr = static_cast<T*>(AllocateMemoryPages(alloc_size));
// each item in vector holds information for 64 pages
auto denom = HostPageSize * 64;
committed_pages = std::vector<std::atomic<u64>>((alloc_size + denom - 1) / denom);
}
~SparseLargeVector() noexcept {
FreeMemoryPages(base_ptr, alloc_size);
}
SparseLargeVector(const SparseLargeVector&) = delete;
SparseLargeVector& operator=(const SparseLargeVector&) = delete;
SparseLargeVector(SparseLargeVector&& other) = delete;
SparseLargeVector& operator=(SparseLargeVector&& other) = delete;
void ResizeAndClear(std::size_t count) noexcept {
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
FreeMemoryPages(base_ptr, alloc_size);
alloc_size = new_size;
base_ptr = static_cast<T*>(AllocateMemoryPages(alloc_size));
auto denom = HostPageSize * 64;
committed_pages = std::vector<std::atomic<u64>>((alloc_size + denom - 1) / denom);
}
}
/// Returns a reference to the value of the requested index and allocates memory if needed.
T& GetAndFault(std::size_t index) noexcept {
if (index > alloc_size / sizeof(T)) {
UNREACHABLE_MSG("Out of bounds RW access on SparseLargeVector @ {}", index);
}
if (!IsCommittedPage(index) && !CommitPage(index)) {
UNREACHABLE_MSG("Cannot access SparseLargeVector index {} with RW permission", index);
}
return base_ptr[index];
}
/// Returns a reference to the value of the requested index if initialized, or will otherwise return a zero-initialized object.
const T& GetOrDefault(std::size_t index) const {
#ifdef _WIN32
if (!IsCommittedPage(index)) {
return *reinterpret_cast<const T*>(&default_val);
}
#endif
// On non-Windows, OS page table should optimize this by pointing to a zero page if unallocated.
return base_ptr[index];
}
void Set(std::size_t index, const T& value) noexcept {
if (index > alloc_size / sizeof(T)) {
LOG_CRITICAL(Common_Memory, "Out of bounds write on SparseLargeVector @ {}", index);
return;
}
if (IsCommittedPage(index) || CommitPage(index))
base_ptr[index] = value;
}
void ZeroRegion(std::size_t start, std::size_t end_) noexcept {
u64 base = reinterpret_cast<u64>(&base_ptr[start]);
const u64 end = reinterpret_cast<u64>(&base_ptr[end_]);
const u64 end_page = AlignUp(base, HostPageSize);
const u64 first_size = (std::min)(end_page, end) - base;
if (IsCommittedPage(start)) {
std::memset(reinterpret_cast<void*>(base), 0, first_size);
}
if (end <= end_page)
return;
base = end_page;
for (u64 page = base; page < end; page += HostPageSize) {
auto index = (page - reinterpret_cast<u64>(base_ptr)) / sizeof(T);
if (!IsCommittedPage(index)) {
continue;
}
if (end - page >= HostPageSize) {
DecommitPage(index);
} else {
std::memset(reinterpret_cast<void*>(page), 0, end - page);
}
}
}
constexpr void CommitRegion(size_t index, size_t end_) {
const u64 base = static_cast<u64>(index) * sizeof(T);
const u64 end = static_cast<u64>(end_) * sizeof(T);
for (u64 page = AlignDown(base, HostPageSize); page < end; page += HostPageSize) {
if (!IsCommittedPage(page / sizeof(T))) {
CommitPage(page / sizeof(T));
}
}
}
constexpr T& GetUnchecked(size_t index) {
return base_ptr[index];
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
return GetOrDefault(index);
}
[[nodiscard]] constexpr const T* data() const noexcept {
return base_ptr;
}
[[nodiscard]] constexpr std::size_t size() const noexcept {
return alloc_size / sizeof(T);
}
private:
[[nodiscard]] constexpr bool IsCommittedPage(std::size_t index) const noexcept {
if (index > alloc_size / sizeof(T)) {
LOG_CRITICAL(Common_Memory, "Out of bounds access on large vector @ {}", index);
return false;
}
auto page = (index * sizeof(T)) >> HostPageBits;
auto val = committed_pages[page >> 6].load(std::memory_order_acquire);
return (val >> (page & 63)) & 1;
}
constexpr bool CommitPage(std::size_t index) noexcept {
auto page_index = (index * sizeof(T)) >> HostPageBits;
auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask;
#if defined(_WIN32)
if (!CommitVectorPage(page, true)) {
return false;
}
#else
if (mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE) != 0) {
LOG_ERROR(Common_Memory, "Failed to commit large buffer region at index {}, error {}", index, strerror(errno));
return false;
}
#endif
committed_pages[page_index >> 6].fetch_or(1ULL << (page_index & 63), std::memory_order_release);
return true;
}
constexpr void DecommitPage(std::size_t index) noexcept {
auto page_index = (index * sizeof(T)) >> HostPageBits;
auto page = reinterpret_cast<uintptr_t>(base_ptr + index) & HostPageMask;
committed_pages[page_index >> 6].fetch_and(~(1ULL << (page_index & 63)), std::memory_order_release);
DecommitVectorPage(page);
}
std::size_t alloc_size{};
T* base_ptr{};
std::vector<std::atomic<u64>> committed_pages{};
#ifdef _WIN32
const std::array<u8, sizeof(T)> default_val{};
#endif
};
} // namespace Common
+50
View File
@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#ifdef _MSC_VER
#include <intrin.h>
#elif defined(ARCHITECTURE_x86_64)
#include <xmmintrin.h>
#endif
#include <atomic>
namespace Common {
/// @brief A lock similar to mutex that forces a thread to spin wait instead calling the
/// supervisor. Should be used on short sequences of code.
struct SpinLock {
SpinLock() noexcept = default;
SpinLock(const SpinLock&) noexcept = delete;
SpinLock& operator=(const SpinLock&) noexcept = delete;
SpinLock(SpinLock&&) noexcept = delete;
SpinLock& operator=(SpinLock&&) noexcept = delete;
inline void lock() noexcept {
while (lck.test_and_set(std::memory_order_acquire)) {
#if defined(ARCHITECTURE_x86_64)
_mm_pause();
#elif defined(ARCHITECTURE_arm64) && defined(_MSC_VER)
__yield();
#elif defined(ARCHITECTURE_arm64)
asm("yield");
#endif
}
}
inline void unlock() noexcept {
lck.clear(std::memory_order_release);
}
[[nodiscard]] inline bool try_lock() noexcept {
return !lck.test_and_set(std::memory_order_acquire);
}
std::atomic_flag lck = ATOMIC_FLAG_INIT;
};
} // namespace Common
+51
View File
@@ -24,6 +24,22 @@
namespace Common { namespace Common {
/// Make a string lowercase
std::string ToLower(const std::string_view sv) {
std::string str{sv};
std::transform(str.begin(), str.end(), str.begin(),
[](auto const c) { return char(std::tolower(c)); });
return str;
}
/// Make a string uppercase
std::string ToUpper(const std::string_view sv) {
std::string str{sv};
std::transform(str.begin(), str.end(), str.begin(),
[](auto const c) { return char(std::toupper(c)); });
return str;
}
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
std::string* _pExtension) { std::string* _pExtension) {
if (full_path.empty()) if (full_path.empty())
@@ -64,6 +80,41 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
return true; return true;
} }
void SplitString(const std::string& str, const char delim, std::vector<std::string>& output) {
std::istringstream iss(str);
output.resize(1);
while (std::getline(iss, *output.rbegin(), delim)) {
output.emplace_back();
}
output.pop_back();
}
std::string TabsToSpaces(int tab_size, std::string in) {
std::size_t i = 0;
while ((i = in.find('\t')) != std::string::npos) {
in.replace(i, 1, tab_size, ' ');
}
return in;
}
std::string ReplaceAll(std::string result, const std::string& src, const std::string& dest) {
std::size_t pos = 0;
if (src == dest)
return result;
while ((pos = result.find(src, pos)) != std::string::npos) {
result.replace(pos, src.size(), dest);
pos += dest.length();
}
return result;
}
std::string UTF16ToUTF8(std::u16string_view input) { std::string UTF16ToUTF8(std::u16string_view input) {
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert; std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
return convert.to_bytes(input.data(), input.data() + input.size()); return convert.to_bytes(input.data(), input.data() + input.size());
+56 -4
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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project // SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
@@ -16,6 +16,12 @@
namespace Common { namespace Common {
/// Make a string lowercase
[[nodiscard]] std::string ToLower(const std::string_view sv);
/// Make a string uppercase
[[nodiscard]] std::string ToUpper(const std::string_view sv);
[[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept { [[nodiscard]] inline std::string StringFromBuffer(std::span<const u8> data) noexcept {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
@@ -23,8 +29,37 @@ namespace Common {
return std::string(data.begin(), std::find(data.begin(), data.end(), '\0')); return std::string(data.begin(), std::find(data.begin(), data.end(), '\0'));
} }
/// Turns " hej " into "hej". Also handles tabs.
[[nodiscard]] inline std::string StripSpaces(const std::string_view str) noexcept {
const std::size_t s = str.find_first_not_of(" \t\r\n");
if (str.npos != s)
return std::string{str.substr(s, str.find_last_not_of(" \t\r\n") - s + 1)};
return {};
}
/// "\"hello\"" is turned to "hello"
/// This one assumes that the string has already been space stripped in both
/// ends, as done by StripSpaces above, for example.
[[nodiscard]] inline std::string StripQuotes(const std::string_view s) noexcept {
if (s.size() && '\"' == s[0] && '\"' == *s.rbegin())
return std::string{s.substr(1, s.size() - 2)};
return std::string{s};
}
[[nodiscard]] inline std::string StringFromBool(bool value) noexcept {
return value ? "True" : "False";
}
[[nodiscard]] std::string TabsToSpaces(int tab_size, std::string in);
void SplitString(const std::string& str, char delim, std::vector<std::string>& output);
// "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe" // "C:/Windows/winhelp.exe" to "C:/Windows/", "winhelp", ".exe"
bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename, std::string* _pExtension); bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _pFilename,
std::string* _pExtension);
[[nodiscard]] std::string ReplaceAll(std::string result, const std::string& src,
const std::string& dest);
[[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input); [[nodiscard]] std::string UTF16ToUTF8(std::u16string_view input);
[[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input); [[nodiscard]] std::u16string UTF8ToUTF16(std::string_view input);
@@ -38,13 +73,30 @@ bool SplitPath(const std::string& full_path, std::string* _pPath, std::string* _
[[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length); [[nodiscard]] std::u16string U16StringFromBuffer(const u16* input, std::size_t length);
/**
* Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
* `other` for equality.
*/
template <typename InIt>
[[nodiscard]] inline bool ComparePartialString(InIt begin, InIt end, const char* other) noexcept {
for (; begin != end && *other != '\0'; ++begin, ++other) {
if (*begin != *other) {
return false;
}
}
// Only return true if both strings finished at the same point
return (begin == end) == (*other == '\0');
}
/// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't /// Creates a std::string from a fixed-size NUL-terminated char buffer. If the buffer isn't
/// NUL-terminated then the string ends at max_len characters. /// NUL-terminated then the string ends at max_len characters.
[[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer, std::size_t max_len); [[nodiscard]] std::string StringFromFixedZeroTerminatedBuffer(std::string_view buffer,
std::size_t max_len);
/// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't /// Creates a UTF-16 std::u16string from a fixed-size NUL-terminated char buffer. If the buffer isn't
/// null-terminated, then the string ends at the greatest multiple of two less then or equal to /// null-terminated, then the string ends at the greatest multiple of two less then or equal to
/// max_len_bytes. /// max_len_bytes.
[[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, std::size_t max_len); [[nodiscard]] std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
std::size_t max_len);
} // namespace Common } // namespace Common
+2 -2
View File
@@ -208,9 +208,9 @@ UUID UUID::MakeRandomRFC4122V4() {
return uuid; return uuid;
} }
UUID UUID::MakeRFC4122V5(std::span<u8, 16> sha1) { UUID UUID::MakeRFC4122V5(std::span<u8, 20> sha1) {
UUID uuid{}; UUID uuid{};
std::memcpy(&uuid.uuid, sha1.data(), sha1.size()); std::memcpy(&uuid.uuid, sha1.data(), sizeof(UUID));
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F); uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF); uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF);
return uuid; return uuid;
+1 -1
View File
@@ -104,7 +104,7 @@ struct UUID {
/// @returns A random UUID that is RFC 4122 Version 4 compliant. /// @returns A random UUID that is RFC 4122 Version 4 compliant.
[[nodiscard]] static UUID MakeRandomRFC4122V4(); [[nodiscard]] static UUID MakeRandomRFC4122V4();
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 16> sha1); [[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 20> sha1);
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
}; };
+44
View File
@@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#endif
#include "common/assert.h"
#include "common/virtual_buffer.h"
namespace Common {
void* AllocateMemoryPages(std::size_t size) noexcept {
#ifdef _WIN32
void* base = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
if (base == nullptr) {
// Probably failing to reserve is less likely than failing to commit
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
}
#else
void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (base == MAP_FAILED)
base = nullptr;
#endif
ASSERT(base);
return base;
}
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
if (!base)
return;
#ifdef _WIN32
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
#else
ASSERT(munmap(base, size) == 0);
#endif
}
} // namespace Common
+84
View File
@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <utility>
namespace Common {
void* AllocateMemoryPages(std::size_t size) noexcept;
void FreeMemoryPages(void* base, std::size_t size) noexcept;
template <typename T>
class VirtualBuffer final {
public:
// TODO: Uncomment this and change Common::PageTable::PageInfo to be trivially constructible
// using std::atomic_ref once libc++ has support for it
// static_assert(
// std::is_trivially_constructible_v<T>,
// "T must be trivially constructible, as non-trivial constructors will not be executed "
// "with the current allocator");
constexpr VirtualBuffer() = default;
explicit VirtualBuffer(std::size_t count) noexcept
: alloc_size{count * sizeof(T)}
{
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
}
~VirtualBuffer() noexcept {
FreeMemoryPages(base_ptr, alloc_size);
}
VirtualBuffer(const VirtualBuffer&) = delete;
VirtualBuffer& operator=(const VirtualBuffer&) = delete;
VirtualBuffer(VirtualBuffer&& other) noexcept
: alloc_size{std::exchange(other.alloc_size, 0)}
, base_ptr{std::exchange(other.base_ptr, nullptr)}
{}
VirtualBuffer& operator=(VirtualBuffer&& other) noexcept {
alloc_size = std::exchange(other.alloc_size, 0);
base_ptr = std::exchange(other.base_ptr, nullptr);
return *this;
}
void resize(std::size_t count) noexcept {
if (auto const new_size = count * sizeof(T); new_size != alloc_size) {
FreeMemoryPages(base_ptr, alloc_size);
alloc_size = new_size;
base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
}
}
[[nodiscard]] constexpr const T& operator[](std::size_t index) const noexcept {
return base_ptr[index];
}
[[nodiscard]] constexpr T& operator[](std::size_t index) noexcept {
return base_ptr[index];
}
[[nodiscard]] constexpr T* data() noexcept {
return base_ptr;
}
[[nodiscard]] constexpr const T* data() const noexcept {
return base_ptr;
}
[[nodiscard]] constexpr std::size_t size() const noexcept {
return alloc_size / sizeof(T);
}
private:
std::size_t alloc_size{};
T* base_ptr{};
};
} // namespace Common
-46
View File
@@ -1,46 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
#include "common/zbic_compression.h"
#define ZSTD_ZBIC_SUPPORT 1
#define ZSTDLIB_VISIBLE static
#define ZSTDLIB_HIDDEN static
#define ZSTDERRORLIB_VISIBLE static
#define ZSTDERRORLIB_HIDDEN static
#undef ZSTD_MULTITHREAD
#if defined(__ANDROID__)
#undef _GNU_SOURCE
#endif
#include "zstd.h"
#define g_ZSTD_threading_useless_symbol g_ZSTD_zbic_threading_useless_symbol
#include "zstd.c"
#undef g_ZSTD_threading_useless_symbol
namespace Common::Compression {
bool IsZBIC(std::span<const u8> src) {
if (src.size() < sizeof(u32)) {
return false;
}
u32 magic = 0;
std::memcpy(&magic, src.data(), sizeof(u32));
return magic == ZSTD_MAGICNUMBER; // 0x4349425A ("ZBIC")
}
int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src) {
if (dst.empty() || src.empty()) {
return -1;
}
const size_t res = ZSTD_decompress(dst.data(), dst.size(), src.data(), src.size());
if (ZSTD_isError(res)) {
return -1;
}
return static_cast<int>(res);
}
} // namespace Common::Compression
-15
View File
@@ -1,15 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <span>
#include "common/common_types.h"
namespace Common::Compression {
[[nodiscard]] bool IsZBIC(std::span<const u8> src);
[[nodiscard]] int DecompressDataZBIC(std::span<u8> dst, std::span<const u8> src);
} // namespace Common::Compression
+3 -9
View File
@@ -23,8 +23,6 @@ add_library(core STATIC
core_timing.h core_timing.h
cpu_manager.cpp cpu_manager.cpp
cpu_manager.h cpu_manager.h
launch_params.cpp
launch_params.h
crypto/aes_util.cpp crypto/aes_util.cpp
crypto/aes_util.h crypto/aes_util.h
crypto/ctr_encryption_layer.cpp crypto/ctr_encryption_layer.cpp
@@ -798,8 +796,6 @@ add_library(core STATIC
hle/service/ns/application_manager_interface.h hle/service/ns/application_manager_interface.h
hle/service/ns/application_version_interface.cpp hle/service/ns/application_version_interface.cpp
hle/service/ns/application_version_interface.h hle/service/ns/application_version_interface.h
hle/service/ns/async_result.cpp
hle/service/ns/async_result.h
hle/service/ns/content_management_interface.cpp hle/service/ns/content_management_interface.cpp
hle/service/ns/content_management_interface.h hle/service/ns/content_management_interface.h
hle/service/ns/develop_interface.cpp hle/service/ns/develop_interface.cpp
@@ -814,6 +810,8 @@ add_library(core STATIC
hle/service/ns/ecommerce_interface.h hle/service/ns/ecommerce_interface.h
hle/service/ns/factory_reset_interface.cpp hle/service/ns/factory_reset_interface.cpp
hle/service/ns/factory_reset_interface.h hle/service/ns/factory_reset_interface.h
hle/service/ns/i_async_result.cpp
hle/service/ns/i_async_result.h
hle/service/ns/language.cpp hle/service/ns/language.cpp
hle/service/ns/language.h hle/service/ns/language.h
hle/service/ns/ns.cpp hle/service/ns/ns.cpp
@@ -1205,9 +1203,6 @@ endif()
target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS}) target_include_directories(core PRIVATE ${OPUS_INCLUDE_DIRS})
target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz) target_link_libraries(core PUBLIC common PRIVATE audio_core hid_core network video_core nx_tzdb tz)
if (MSVC)
target_link_libraries(core PRIVATE getopt)
endif()
if (BOOST_NO_HEADERS) if (BOOST_NO_HEADERS)
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc) target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
@@ -1243,8 +1238,7 @@ if (HAS_NCE)
arm/nce/interpreter_visitor.cpp arm/nce/interpreter_visitor.cpp
arm/nce/interpreter_visitor.h arm/nce/interpreter_visitor.h
arm/nce/patcher.cpp arm/nce/patcher.cpp
arm/nce/patcher.h arm/nce/patcher.h)
arm/nce/visitor_base.h)
target_link_libraries(core PRIVATE merry::oaknut) target_link_libraries(core PRIVATE merry::oaknut)
endif() endif()
+37 -29
View File
@@ -22,15 +22,21 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} , m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
{} {}
u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) { u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) {
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read); CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
switch (size) { return m_memory.Read8(vaddr);
case sizeof(u64): return m_memory.Read64(vaddr);
case sizeof(u32): return m_memory.Read32(vaddr);
case sizeof(u16): return m_memory.Read16(vaddr);
case sizeof(u8): return m_memory.Read8(vaddr);
default: UNREACHABLE();
} }
u16 DynarmicCallbacks32::MemoryRead16(u32 vaddr) {
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
return m_memory.Read16(vaddr);
}
u32 DynarmicCallbacks32::MemoryRead32(u32 vaddr) {
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
return m_memory.Read32(vaddr);
}
u64 DynarmicCallbacks32::MemoryRead64(u32 vaddr) {
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return m_memory.Read64(vaddr);
} }
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) { std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
@@ -44,17 +50,27 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
} }
void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) { void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
switch (size) { m_memory.Write8(vaddr, value);
case sizeof(u64): return m_memory.Write64(vaddr, value);
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
default: UNREACHABLE();
} }
} }
void DynarmicCallbacks32::MemoryWrite16(u32 vaddr, u16 value) {
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
m_memory.Write16(vaddr, value);
} }
}
void DynarmicCallbacks32::MemoryWrite32(u32 vaddr, u32 value) {
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
m_memory.Write32(vaddr, value);
}
}
void DynarmicCallbacks32::MemoryWrite64(u32 vaddr, u64 value) {
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
m_memory.Write64(vaddr, value);
}
}
bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) { bool DynarmicCallbacks32::MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) {
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) && return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
m_memory.WriteExclusive8(vaddr, value, expected); m_memory.WriteExclusive8(vaddr, value, expected);
@@ -156,12 +172,12 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
if (page_table) { if (page_table) {
constexpr size_t PageBits = 12; constexpr size_t PageBits = 12;
constexpr size_t NumPageTableEntries = 1 << (32 - PageBits); constexpr size_t NumPageTableEntries = 1 << (32 - PageBits);
constexpr size_t PageLog2Stride = 5;
static_assert(1 << PageLog2Stride == sizeof(Common::PageTable::PageEntryData));
// Dynarmic will not write to the page table, const_cast is safe here config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(page_table->entries.data());
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>( config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data())); config.page_table_log2_stride = PageLog2Stride;
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
config.page_table_marked_bit = uint8_t(0);
config.absolute_offset_page_table = true; config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true; config.only_detect_misalignment_via_page_table_on_page_boundary = true;
@@ -172,13 +188,6 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt; config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt;
config.recompile_on_exclusive_fastmem_failure = true; config.recompile_on_exclusive_fastmem_failure = true;
if (reinterpret_cast<u64>(m_system.DeviceMemory().buffer.BackingBasePointer() +
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
// we have to manually sign extend when our actual pointer is negative.
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
}
} }
// Multi-process state // Multi-process state
@@ -411,7 +420,6 @@ void ArmDynarmic32::SignalInterrupt(Kernel::KThread* thread) {
} }
void ArmDynarmic32::ClearInstructionCache() { void ArmDynarmic32::ClearInstructionCache() {
m_cb->last_code_addr = u64(-1);
m_jit->ClearCache(); m_jit->ClearCache();
} }
+8 -2
View File
@@ -30,12 +30,18 @@ class System;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public: public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process); explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
u64 MemoryRead(u32 vaddr, size_t size) override; u8 MemoryRead8(u32 vaddr) override;
u16 MemoryRead16(u32 vaddr) override;
u32 MemoryRead32(u32 vaddr) override;
u64 MemoryRead64(u32 vaddr) override;
std::optional<u32> MemoryReadCode(u32 vaddr) override; std::optional<u32> MemoryReadCode(u32 vaddr) override;
void InstructionSynchronizationBarrierRaised() override { void InstructionSynchronizationBarrierRaised() override {
last_code_addr = u64(-1); //reset back, force refetch last_code_addr = u64(-1); //reset back, force refetch
} }
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override; void MemoryWrite8(u32 vaddr, u8 value) override;
void MemoryWrite16(u32 vaddr, u16 value) override;
void MemoryWrite32(u32 vaddr, u32 value) override;
void MemoryWrite64(u32 vaddr, u64 value) override;
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override; bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override; bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override; bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
+37 -30
View File
@@ -10,7 +10,6 @@
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "dynarmic/interface/A64/config.h"
namespace Core { namespace Core {
@@ -22,15 +21,21 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()} , m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
{} {}
u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) { u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) {
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read); CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
switch (size) { return m_memory.Read8(vaddr);
case sizeof(u64): return m_memory.Read64(vaddr);
case sizeof(u32): return m_memory.Read32(vaddr);
case sizeof(u16): return m_memory.Read16(vaddr);
case sizeof(u8): return m_memory.Read8(vaddr);
default: UNREACHABLE();
} }
u16 DynarmicCallbacks64::MemoryRead16(u64 vaddr) {
CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Read);
return m_memory.Read16(vaddr);
}
u32 DynarmicCallbacks64::MemoryRead32(u64 vaddr) {
CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Read);
return m_memory.Read32(vaddr);
}
u64 DynarmicCallbacks64::MemoryRead64(u64 vaddr) {
CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Read);
return m_memory.Read64(vaddr);
} }
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) { Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read); CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
@@ -48,16 +53,25 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)]; return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
} }
void DynarmicCallbacks64::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) { void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) { if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
switch (size) { m_memory.Write8(vaddr, value);
case sizeof(u64): return m_memory.Write64(vaddr, u64(value));
case sizeof(u32): return m_memory.Write32(vaddr, u32(value));
case sizeof(u16): return m_memory.Write16(vaddr, u16(value));
case sizeof(u8): return m_memory.Write8(vaddr, u8(value));
default: UNREACHABLE();
} }
} }
void DynarmicCallbacks64::MemoryWrite16(u64 vaddr, u16 value) {
if (CheckMemoryAccess(vaddr, 2, Kernel::DebugWatchpointType::Write)) {
m_memory.Write16(vaddr, value);
}
}
void DynarmicCallbacks64::MemoryWrite32(u64 vaddr, u32 value) {
if (CheckMemoryAccess(vaddr, 4, Kernel::DebugWatchpointType::Write)) {
m_memory.Write32(vaddr, value);
}
}
void DynarmicCallbacks64::MemoryWrite64(u64 vaddr, u64 value) {
if (CheckMemoryAccess(vaddr, 8, Kernel::DebugWatchpointType::Write)) {
m_memory.Write64(vaddr, value);
}
} }
void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) { void DynarmicCallbacks64::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) { if (CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Write)) {
@@ -197,12 +211,13 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
// Memory // Memory
if (page_table) { if (page_table) {
// Dynarmic will not write to the page table, const_cast is safe here constexpr size_t PageLog2Stride = 5;
config.page_table = reinterpret_cast<void**>( static_assert(1 << PageLog2Stride == sizeof(Common::PageTable::PageEntryData));
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
config.page_table = reinterpret_cast<void**>(page_table->entries.data());
config.page_table_address_space_bits = std::uint32_t(address_space_bits); config.page_table_address_space_bits = std::uint32_t(address_space_bits);
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK; config.page_table_pointer_mask_bits = Common::PageTable::ATTRIBUTE_BITS;
config.page_table_marked_bit = uint8_t(0); config.page_table_log2_stride = PageLog2Stride;
config.silently_mirror_page_table = false; config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true; config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128; config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -216,13 +231,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt; config.fastmem_exclusive_access = config.fastmem_pointer != std::nullopt;
config.recompile_on_exclusive_fastmem_failure = true; config.recompile_on_exclusive_fastmem_failure = true;
if (reinterpret_cast<u64>(m_system.DeviceMemory().buffer.BackingBasePointer() +
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize()) < (1ULL << 39)) {
// Systems like FreeBSD allocate memory really low by default, and since we pack our page table entries,
// we have to manually sign extend when our actual pointer is negative.
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
}
} }
// Multi-process state // Multi-process state
@@ -439,7 +447,6 @@ void ArmDynarmic64::SignalInterrupt(Kernel::KThread* thread) {
} }
void ArmDynarmic64::ClearInstructionCache() { void ArmDynarmic64::ClearInstructionCache() {
m_cb->last_code_addr = u64(-1);
m_jit->ClearCache(); m_jit->ClearCache();
} }
+9 -3
View File
@@ -13,9 +13,9 @@
#include <dynarmic/interface/A64/a64.h> #include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/code_page.h> #include <dynarmic/interface/code_page.h>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/hash.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h" #include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "dynarmic/interface/A64/config.h"
namespace Core::Memory { namespace Core::Memory {
class Memory; class Memory;
@@ -36,13 +36,19 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process); explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
u64 MemoryRead(u64 vaddr, size_t size) override; u8 MemoryRead8(u64 vaddr) override;
u16 MemoryRead16(u64 vaddr) override;
u32 MemoryRead32(u64 vaddr) override;
u64 MemoryRead64(u64 vaddr) override;
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override; Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
std::optional<u32> MemoryReadCode(u64 vaddr) override; std::optional<u32> MemoryReadCode(u64 vaddr) override;
void InstructionSynchronizationBarrierRaised() override { void InstructionSynchronizationBarrierRaised() override {
last_code_addr = u64(-1); //reset back, force refetch last_code_addr = u64(-1); //reset back, force refetch
} }
void MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override; void MemoryWrite8(u64 vaddr, u8 value) override;
void MemoryWrite16(u64 vaddr, u16 value) override;
void MemoryWrite32(u64 vaddr, u32 value) override;
void MemoryWrite64(u64 vaddr, u64 value) override;
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override; void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) override;
bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override; bool MemoryWriteExclusive8(u64 vaddr, std::uint8_t value, std::uint8_t expected) override;
bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override; bool MemoryWriteExclusive16(u64 vaddr, std::uint16_t value, std::uint16_t expected) override;
File diff suppressed because it is too large Load Diff
+58 -78
View File
@@ -7,97 +7,77 @@
#pragma once #pragma once
#include <atomic> #include <optional>
#include <signal.h>
#include <unistd.h>
#include <span> #include <span>
#include <signal.h>
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow"
#include <dynarmic/frontend/A64/a64_types.h>
#include <dynarmic/frontend/imm.h>
#pragma GCC diagnostic pop
#include "core/hle/kernel/k_thread.h"
#include "core/memory.h" #include "core/memory.h"
#include "common/logging.h"
#include "core/arm/nce/visitor_base.h"
namespace Core { namespace Core {
namespace Memory { class InterpreterVisitor {
class Memory;
}
class InterpreterVisitor final : public VisitorBase {
public: public:
explicit InterpreterVisitor(Core::Memory::Memory& memory, std::span<u64, 31> regs, explicit InterpreterVisitor(Core::Memory::Memory& memory, std::span<u64, 31> regs,
std::span<u128, 32> fpsimd_regs, u64& sp, const u64& pc) std::span<u128, 32> fpsimd_regs, u64& sp, const u64& pc)
: m_memory(memory), m_regs(regs), m_fpsimd_regs(fpsimd_regs), m_sp(sp), m_pc(pc) {} : m_memory(memory), m_regs(regs), m_fpsimd_regs(fpsimd_regs), m_sp(sp), m_pc(pc) {}
~InterpreterVisitor() override = default;
enum class MemOp { bool Execute(u32 inst);
Load,
Store,
Prefetch,
};
u128 GetVec(Vec v);
u64 GetReg(Reg r);
u64 GetSp();
u64 GetPc();
void SetVec(Vec v, u128 value);
void SetReg(Reg r, u64 value);
void SetSp(u64 value);
u64 ExtendReg(size_t bitsize, Reg reg, Imm<3> option, u8 shift);
// Loads and stores - Load/Store Exclusive
bool Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt);
bool STLLR(Imm<2> size, Reg Rn, Reg Rt) override;
bool STLR(Imm<2> size, Reg Rn, Reg Rt) override;
bool LDLAR(Imm<2> size, Reg Rn, Reg Rt) override;
bool LDAR(Imm<2> size, Reg Rn, Reg Rt) override;
// Loads and stores - Load register (literal)
bool LDR_lit_gen(bool opc_0, Imm<19> imm19, Reg Rt) override;
bool LDR_lit_fpsimd(Imm<2> opc, Imm<19> imm19, Vec Vt) override;
// Loads and stores - Load/Store register pair
bool STP_LDP_gen(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Reg Rt2,
Reg Rn, Reg Rt) override;
bool STP_LDP_fpsimd(Imm<2> opc, bool not_postindex, bool wback, Imm<1> L, Imm<7> imm7, Vec Vt2,
Reg Rn, Vec Vt) override;
// Loads and stores - Load/Store register (immediate)
bool RegisterImmediate(bool wback, bool postindex, size_t scale, u64 offset, Imm<2> size,
Imm<2> opc, Reg Rn, Reg Rt);
bool STRx_LDRx_imm_1(Imm<2> size, Imm<2> opc, Imm<9> imm9, bool not_postindex, Reg Rn,
Reg Rt) override;
bool STRx_LDRx_imm_2(Imm<2> size, Imm<2> opc, Imm<12> imm12, Reg Rn, Reg Rt) override;
bool STURx_LDURx(Imm<2> size, Imm<2> opc, Imm<9> imm9, Reg Rn, Reg Rt) override;
bool SIMDImmediate(bool wback, bool postindex, size_t scale, u64 offset, MemOp memop, Reg Rn,
Vec Vt);
bool STR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
Vec Vt) override;
bool STR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
bool LDR_imm_fpsimd_1(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, bool not_postindex, Reg Rn,
Vec Vt) override;
bool LDR_imm_fpsimd_2(Imm<2> size, Imm<1> opc_1, Imm<12> imm12, Reg Rn, Vec Vt) override;
bool STUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
bool LDUR_fpsimd(Imm<2> size, Imm<1> opc_1, Imm<9> imm9, Reg Rn, Vec Vt) override;
// Loads and stores - Load/Store register (register offset)
bool RegisterOffset(size_t scale, u8 shift, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm,
Imm<3> option, Reg Rn, Reg Rt);
bool STRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) override;
bool LDRx_reg(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Reg Rt) override;
bool SIMDOffset(size_t scale, u8 shift, Imm<1> opc_0, Reg Rm, Imm<3> option, Reg Rn, Vec Vt);
bool STR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Vec Vt) override;
bool LDR_reg_fpsimd(Imm<2> size, Imm<1> opc_1, Reg Rm, Imm<3> option, bool S, Reg Rn,
Vec Vt) override;
private: private:
template <size_t BitSize>
using Imm = Dynarmic::Imm<BitSize>;
using Reg = Dynarmic::A64::Reg;
using Vec = Dynarmic::A64::Vec;
u128 GetVec(Vec v) const {
return m_fpsimd_regs[static_cast<u32>(v)];
}
void SetVec(Vec v, u128 value) {
m_fpsimd_regs[static_cast<u32>(v)] = value;
}
u64 GetReg(Reg r) const {
return m_regs[static_cast<u32>(r)];
}
void SetReg(Reg r, u64 value) {
m_regs[static_cast<u32>(r)] = value;
}
u64 GetRegSp(Reg r) const {
if (r == Reg::SP) {
return m_sp;
}
return m_regs[static_cast<u32>(r)];
}
void SetRegSp(Reg r, u64 value) {
if (r == Reg::SP) {
m_sp = value;
return;
}
m_regs[static_cast<u32>(r)] = value;
}
u64 ExtendReg(Reg reg, Imm<3> option, u8 shift);
bool Ordered(size_t size, bool load, Reg Rn, Reg Rt);
bool LoadLiteral(bool wide, Imm<19> imm19, Reg Rt);
bool LoadLiteralSimd(Imm<2> opc, Imm<19> imm19, Vec Vt);
bool Pair(Imm<2> opc, bool not_postindex, bool wback, bool load, Imm<7> imm7, Reg Rt2, Reg Rn,
Reg Rt);
bool PairSimd(Imm<2> opc, bool not_postindex, bool wback, bool load, Imm<7> imm7, Vec Vt2,
Reg Rn, Vec Vt);
bool RegisterImmediate(bool wback, bool postindex, u64 offset, Imm<2> size, Imm<2> opc, Reg Rn,
Reg Rt);
bool RegisterOffset(bool S, Imm<2> size, Imm<1> opc_1, Imm<1> opc_0, Reg Rm, Imm<3> option,
Reg Rn, Reg Rt);
bool SimdImmediate(bool wback, bool postindex, size_t scale, u64 offset, bool load, Reg Rn,
Vec Vt);
bool SimdOffset(size_t scale, bool S, bool load, Reg Rm, Imm<3> option, Reg Rn, Vec Vt);
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
std::span<u64, 31> m_regs; std::span<u64, 31> m_regs;
std::span<u128, 32> m_fpsimd_regs; std::span<u128, 32> m_fpsimd_regs;
+7 -23
View File
@@ -371,14 +371,9 @@ size_t Patcher::GetPreSectionSize() const noexcept {
} }
void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) { void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) {
// This function was called, which modifies X30, so use that as a scratch register.
// SP contains the guest X30, so save our return X30 to SP + 8, since we have allocated 16 bytes
// of stack.
cg.STR(X30, SP, 8); cg.STR(X30, SP, 8);
cg.MRS(X30, oaknut::SystemReg::TPIDR_EL0); cg.LDR(X30, SP, 0);
cg.LDR(X30, X30, offsetof(NativeExecutionParameters, native_context));
// Load system registers.
cg.LDR(W0, X30, offsetof(GuestContext, fpsr)); cg.LDR(W0, X30, offsetof(GuestContext, fpsr));
cg.MSR(oaknut::SystemReg::FPSR, X0); cg.MSR(oaknut::SystemReg::FPSR, X0);
cg.LDR(W0, X30, offsetof(GuestContext, fpcr)); cg.LDR(W0, X30, offsetof(GuestContext, fpcr));
@@ -386,7 +381,9 @@ void Patcher::WriteLoadContext(oaknut::VectorCodeGenerator& cg) {
cg.LDR(W0, X30, offsetof(GuestContext, nzcv)); cg.LDR(W0, X30, offsetof(GuestContext, nzcv));
cg.MSR(oaknut::SystemReg::NZCV, X0); cg.MSR(oaknut::SystemReg::NZCV, X0);
// Load all vector registers. cg.LDR(X0, X30, 8 * 30);
cg.STR(X0, SP, 0);
static constexpr size_t VEC_OFF = offsetof(GuestContext, vector_registers); static constexpr size_t VEC_OFF = offsetof(GuestContext, vector_registers);
for (int i = 0; i <= 30; i += 2) { for (int i = 0; i <= 30; i += 2) {
cg.LDP(oaknut::QReg{i}, oaknut::QReg{i + 1}, X30, VEC_OFF + 16 * i); cg.LDP(oaknut::QReg{i}, oaknut::QReg{i + 1}, X30, VEC_OFF + 16 * i);
@@ -436,7 +433,7 @@ void Patcher::WriteSaveContext(oaknut::VectorCodeGenerator& cg) {
cg.STR(W0, X30, offsetof(GuestContext, nzcv)); cg.STR(W0, X30, offsetof(GuestContext, nzcv));
cg.LDR(X0, SP, POST_INDEXED, 16); cg.LDR(X0, SP, POST_INDEXED, 16);
// Reload our return X30 from the stack, and return. cg.MOV(X1, X30);
cg.LDR(X30, SP, 8); cg.LDR(X30, SP, 8);
cg.RET(); cg.RET();
} }
@@ -457,8 +454,6 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut
// Now that we've saved all registers, we can use any registers as scratch. // Now that we've saved all registers, we can use any registers as scratch.
// Store PC + 4 to arm interface, since we know the instruction offset from the entry point. // Store PC + 4 to arm interface, since we know the instruction offset from the entry point.
oaknut::Label pc_after_svc; oaknut::Label pc_after_svc;
cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0);
cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context));
cg.LDR(X2, pc_after_svc); cg.LDR(X2, pc_after_svc);
cg.STR(X2, X1, offsetof(GuestContext, pc)); cg.STR(X2, X1, offsetof(GuestContext, pc));
@@ -514,24 +509,13 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut
// Host called this location. Save the return address so we can // Host called this location. Save the return address so we can
// unwind the stack properly when jumping back. // unwind the stack properly when jumping back.
cg.MRS(X2, oaknut::SystemReg::TPIDR_EL0); cg.ADD(X0, X1, offsetof(GuestContext, host_ctx));
cg.LDR(X2, X2, offsetof(NativeExecutionParameters, native_context));
cg.ADD(X0, X2, offsetof(GuestContext, host_ctx));
cg.STR(X30, X0, offsetof(HostContext, host_saved_regs) + 11 * sizeof(u64)); cg.STR(X30, X0, offsetof(HostContext, host_saved_regs) + 11 * sizeof(u64));
// Reload all guest registers except X30 and PC. cg.STR(X1, SP, PRE_INDEXED, -16);
// The function also expects 16 bytes of stack already allocated.
cg.STR(X30, SP, PRE_INDEXED, -16);
cg.BL(load_ctx); cg.BL(load_ctx);
cg.LDR(X30, SP, POST_INDEXED, 16); cg.LDR(X30, SP, POST_INDEXED, 16);
// Use X1 as a scratch register to restore X30.
cg.STR(X1, SP, PRE_INDEXED, -16);
cg.MRS(X1, oaknut::SystemReg::TPIDR_EL0);
cg.LDR(X1, X1, offsetof(NativeExecutionParameters, native_context));
cg.LDR(X30, X1, offsetof(GuestContext, cpu_registers) + sizeof(u64) * 30);
cg.LDR(X1, SP, POST_INDEXED, 16);
// Unlock the context. // Unlock the context.
this->UnlockContext(cg); this->UnlockContext(cg);
File diff suppressed because it is too large Load Diff
+12 -5
View File
@@ -168,7 +168,7 @@ void CpuManager::ShutdownThread(Kernel::KernelCore& kernel) {
UNREACHABLE(); UNREACHABLE();
} }
void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) { void CpuManager::RunThread(std::stop_token token, std::size_t core) {
/// Initialization /// Initialization
system.RegisterCoreThread(core); system.RegisterCoreThread(core);
std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"}; std::string name = is_multicore ? ("CPUCore_" + std::to_string(core)) : std::string{"CPUThread"};
@@ -178,19 +178,26 @@ void CpuManager::RunThread(std::stop_token stop_token, std::size_t core) {
auto& data = core_data[core]; auto& data = core_data[core];
data.host_context = Common::Fiber::ThreadToFiber(); data.host_context = Common::Fiber::ThreadToFiber();
// Cleanup
SCOPE_EXIT {
data.host_context->Exit();
};
// Running // Running
gpu_barrier->arrive_and_wait(); if (!gpu_barrier->Sync(token)) {
if (!stop_token.stop_requested()) { return;
}
if (!is_async_gpu && !is_multicore) { if (!is_async_gpu && !is_multicore) {
system.GPU().ObtainContext(); system.GPU().ObtainContext();
} }
auto& kernel = system.Kernel(); auto& kernel = system.Kernel();
auto& scheduler = *kernel.CurrentScheduler(); auto& scheduler = *kernel.CurrentScheduler();
auto* thread = scheduler.GetSchedulerCurrentThread(); auto* thread = scheduler.GetSchedulerCurrentThread();
Kernel::SetCurrentThread(kernel, thread); Kernel::SetCurrentThread(kernel, thread);
Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext()); Common::Fiber::YieldTo(data.host_context, *thread->GetHostContext());
} }
data.host_context->Exit();
}
} // namespace Core } // namespace Core

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