Compare commits

...

52 Commits

Author SHA1 Message Date
CamilleLaVey c9fa7a7505 remove async vulkan presentation toggle android + async gpu default true 2026-10-06 07:08:57 +03:00
CamilleLaVey a873fde17f Correcting some bugs on the vulkan async presentation thread 2026-10-06 06:59:15 +03:00
xbzk 10bcd2d849 [settings] add PR4490 & PR4492 toggles (#4502)
- [X] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [X] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [X] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
TEMPORARY! Pushed under Camille's instruction. Will be dropped as soon as they get optimized.
Aimed to avoid reported perf impact from PRs 4490 and 4492 on 30-sep-2026 nightly,

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4502
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-05 22:37:30 +02:00
Eden CI 48aeedd3b3 [dist, android] Update translations from Transifex for Oct 05 (#4507)
Automatic translation update for Oct 05

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4507
2026-10-05 21:18:09 +02:00
MaranBr d16735f5b6 [am] Properly handle None frontend applet (#4500)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Properly handle the `AppletId::None` case by returning a null frontend applet instead of falling back to the stub implementation.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4500
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-02 02:24:58 +02:00
lizzie d3550c4571 [qt] Filter collates accents (Unicode NFD) (#4380)
Now "POKEMON" and "pokemon" are the same, and search's no longer case sensitive.
Maybe we could transliterate? But that would require icu which is a bit overkill.
Main point is to be able to search "Pokemon" (accent on 'e') without actually typing the accent

https://unicode.org/reports/tr15/

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4380
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-10-01 07:39:44 +02:00
John 963119e7cc [ffmpeg]Gamescope / Gamemode NVDEC Emulation - GPU Decoding Patches (#4501)
Switch to ffmpeg with liz's gamescope patches.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4501
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-01 03:34:57 +02:00
xbzk 2a7e9b53b1 [android,ui] fixed shader cache clearing when changing drivers (#4496)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Trivial bug pending on backlog, where changing drivers was not clearing up sharder cache as expected.

The driver flow (broken) was deleting externalFilesDir/shader/<game>, while the visible cache-size control (working) DirectoryInitialization.userDirectory/cache/shader/<game>.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4496
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-10-01 00:28:18 +02:00
xbzk 8e2d26c272 [video_core] buffer cache readback for nce invalidations (#4490)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

This is a follow up of 4473, a fix for the next Ender Magnolia known crash, the shackled beast's vaper crash, but specific for NCE.

Imma try to be short:

NCE invalidation was dooming whole guest pages when it shouldn't. If the GPU buffer cache owns some bytes on a page, invalidating first discards their ownership, and the retrying CPU can then observe stale data. On Android, this was corrupting some indirect draw packets and causing huge invalid index count reach staging memory allocation.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4490
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-30 22:13:37 +02:00
Eden CI f8b7651104 [dist, android] Update translations from Transifex for Sep 28 (#4494)
Automatic translation update for Sep 28

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4494
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-30 02:00:44 +02:00
xbzk 3f78512c83 [ro] add TLS patching for runtime NROs (#4492)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Aimed to fix Biomutant which stucks in a bootloop due to guest being unable to reach correct thread local storage (TLS)
This fixes runtime NRO loading by properly patching the guest TLS (TPIDR_EL0) path. Steps:
-Read the loaded NRO image into a temporary buffer.
-Run the NCE patcher on it.
-Produce a patch section / relocated code.
-Map that patch section as executable memory in the target process.
Game still has intermittent visual issues which can be solved with GPU level accurate, but that causes a huge performance drop in exchange. Someone else will resume this one.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4492
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-30 00:58:29 +02:00
xbzk a82f31a310 [settings,qt] merge of "disable controller applet" toggle with "controller applet mode" picker (#4498)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Small good simplification to nuke a toggle which costed me almost an entire day of work when fixing controller applet issues:

There were two settings related to Controller applet:
-"disable controller applet", which is a boolean toggle;
-"controller configuration" applet mode, which is a "Real"/"Custom" picker;

All i did was to nuke the toggle and add a third option "Disabled" to the picker.
Users which used the disable toggle will have to pick Disabled;
Real/Custom settings wont be affected since their indexes remains.
All options tested against diablo 3. All working as intended.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4498
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-30 00:57:23 +02:00
PavelBARABANOV 815325ccec [loader] add ZBIC (zstd variant) NSO decompression support for Switch 22.0+ (#4482)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
A new NSO compression method was introduced in Switch 22.0.0. This is a
customized variant of zstd and is used when NSO flags have bit 7 set.

Key characteristics:
  - ZSTD_MAGICNUMBER is set to 0x4349425A (b'ZBIC') instead of 0xFD2FB528
  - ZSTD_LEGACY_SUPPORT is set to 0
  - ZSTD_TRACE is set to 1, zstd version used is 1.5.7 (10507)
  - FSE_readNCount is replaced with a BIC (Binary Interpolative Coding)
    version which improves compression of entropy tables significantly

Source: https://switchbrew.org/wiki/22.0.0

Implementation:
  - Detect ZBIC segments via NSO flag bit 7 (NsoFlags_UseZbicCompression)
    and/or ZBIC magic scan in nso.cpp
  - Fall back to LZ4 when ZBIC is not detected or returns unexpected size
  - Handle segment 0 alternate offset (0x100 vs 0x108) for both ZBIC and LZ4

References:
  - Atmosphère loader/strat zstd-zbic integration:
    https://github.com/Atmosphere-NX/Atmosphere/commit/082115187a0509cb6b8a757de639a4e4741b8712
  - nxdumptool ZBIC segment compression support:
    https://github.com/DarkMatterCore/nxdumptool/commit/441e5c0904f29427987433be4eb057a2843d222a
  - STORM_SWITCH ZBIC implementation:
    https://github.com/ReiKatari/STORM_SWITCH/commit/1e09eb82b760aaf340b810031400991c0740c091

Tested with firmware 23.0.0 and ZBIC-compressed NSOs.

Co-authored-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4482
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-27 12:48:45 +02:00
Exverge 37fe911952 [common/sparse_large_vector] correct Win32 exception handler (#4481)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Adds mutex to prevent multiple threads from accessing the vector at the same time and corrects the Windows exception handler to use the correct faulting address used by the exception handler (previously used the instruction address instead of the fault address) and properly shifts the stored values for the handler.
Fixes weird compiler-specific bugs on Windows

Co-authored-by: bruno <protoxseven@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4481
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-26 16:02:35 +02:00
MaranBr f273423b2b [buffer_cache] Simplify GPU fence synchronization and remove GPU buffer readback (#4477)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

This is understood to improve GPU synchronization within the buffer cache in certain edge cases.

GPU Fence Strict is no longer necessary. We now apply the stronger synchronization only in the specific case that actually requires it.

The GPU Buffer Readback has been removed, as it is no longer needed following PR #4473.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4477
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-26 05:01:27 +02:00
MaranBr 87d2f03c39 [hid_core] Code cleanup (#4461)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
This is just a code cleanup. This is no longer necessary due to commit #4457.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4461
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-26 02:21:45 +02:00
lizzie bebc19da32 [common] Use std::make_unique_for_overwrite<T> in ScratchBuffer, remove polyfill (#4432)
Original `make_unique_for_overwrite.h` is well defined acc. to standard https://en.cppreference.com/cpp/memory/unique_ptr/make_unique, but by now most libc++ supports the function, so no need for polyfill.

Test that this didn't break anything (for example, Megaman game that has video at the start), or anything using VIC/IPC.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4432
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-25 07:54:49 +02:00
PavelBARABANOV 99bf8cf51a [am, renderer_vulkan] Fix overlay darkening and SGSR black screen on applets (#4475)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
- Overlay applet: use IsOverlayOpenLocked to pick the Z-index, so the darkening background is only layered above the game while the overlay is open.
- Vulkan: skip the SGSR pass for applet layers to avoid presenting a black frame.
- Partial revert fix crashes in games on UE with the overlay applet enabled.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4475
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-25 05:29:08 +02:00
xbzk dbeb73ee01 [video_core] cpu buffer fix + kepler uploads / maxwell macro dirty tracking fixes (#4473)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Aimed to fix two known UE5 crashes: Kepler uploads and Maxwell macros, both caused by CPU/GPU races due dirty tracking issues.

Kepler ComputeInline: preserved dirty tracking across dma continuations and async readback.
Maxwell macros: preserved gpu owned subranges during page granular cpu uploads.
DiscardWrite: stopped clearing neighboring macro arguments by rounding up ranges.
DMA Step: improved continuation aware dirty sampling.

To the Ender Magnolia crew (maybe 1 or 2 persons): This will fix the dash crash, and the random / shackled beast vaper crashes.

There are some more UE5 issues to go next.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4473
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-24 18:44:14 +02:00
PavelBARABANOV cb73a4dcc7 [renderer_vulkan] Skip post-processing on applet layers (#4474)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Detect applet layers via the absence of the Recording bit in layer_stack_mask (only AppletId::Application sets it) and skip PostProcessChain creation and application for them.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4474
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-24 02:48:46 +02:00
lizzie 278f411dad [frontend] Unify cmdline parsing (#4424)
Addresses #4383.

Makes it so both the Qt and SDL frontends now share the same options (bar `-hlaunch` and `-qlaunch`).

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4424
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-23 14:51:51 +02:00
lizzie 3d37a816c6 [glsl] fix clang 23 build error for unused function SetDefinition (#4389)
Reported by @gixel

> unused function template SetDefinition  in: src/shader_recompiler/backend/glsl/emit_glsl.cpp:32:6: error: unused function template 'SetDefinition' [-Werror,-Wunused-template]

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4389
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-23 14:51:18 +02:00
lizzie a25e32676f [hle] Use correct audren:d service framework (#4472)
Trivial change.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4472
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-23 14:39:12 +02:00
Exverge 38df54edfe [common/sparse_large_vector] decommit unused pages + fix first page in zeroed region (#4471)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Fixes a bug where the first page of a zeroed out region would not be properly zeroed, and now frees unused memory.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4471
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-23 13:52:29 +02:00
PavelBARABANOV 3266c20e3f [ips_layer] read magic from IPS file and fix EOF check (#4469)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
PatchIPS was reading the magic bytes from the target file instead
of the IPS patch, and IsEOF used a strict > comparison that never
matched for 3-byte IPS EOF markers. This caused IPS patches to be
silently skipped, breaking the Russian localization mod for
Persona 5.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4469
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-23 00:36:47 +02:00
Eden CI 9cd24e85c2 [dist, android] Update translations from Transifex for Sep 21 (#4466)
Automatic translation update for Sep 21

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4466
2026-09-21 19:25:54 +02:00
xbzk 74b5e10dc5 [native] doesUpdateMatchProgram update mask fix (#4465)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Old silly bug i've been neglecting:
On Android, installing content to NAND, under some content id conditions (ie MK8D DLC), base/update IDs mismatch, and UI prompts "The content that you selected does not match this game. Install anyway?
Useless, yet fixed.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4465
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-20 22:56:06 +02:00
xbzk a277b62fe4 [fs] revert #4319 savedata_factory changes (#4462)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

This one reverts part of the PR 4319 which was aimed to allow child titles to inherit bundle settings.
The fix seems good so far, but by applying it to save folders caused a trap:
Now child's save folders move to bundle folder, hence saves will vanish, and the android/qt save tools are still pointing to old folders.
Since the save part was only a compliance fix, instead of fiddle in master i'd rather revert this part now, then only touch this again if any bug show up.
No worries. I'll be right here waiting.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4462
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-20 04:40:14 +02:00
lizzie 908b1e9a37 [dynarmic] fix bad arm codegen on relocations (#4458)
In an earlier version I had these as constants which were referred to via `db`, I haphazardly left the LDR and didn't notice.
Even still relocations apply to only 1 ins at a time.

Fixes regressions on #4158

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4458
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-20 00:29:28 +02:00
xbzk 847e91c3a8 [applet] add post exit cleanups to frontend applets to avoid accumulation (#4457)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Maran reported MK8D if one press Plus button 38 times.
This could be impacting other games around, but 4442 already quenched the spontaneous accumulation cases, by avoiding multiple event signals. MK8D is an atypical induced example.
The reason was a controller applet accumulation, as we had no proper way to keep track and erase child applets on exit.
Now we have. Enjoy your Plus button rushing fetish!

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4457
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-19 17:44:12 +02:00
lizzie 2d1eb0dab9 [common/error] remove preprocessor macros for strerror_r gating (#4450)
We use C++, we can just use SFINAE for this.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4450
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2026-09-19 08:21:39 +02:00
lizzie 9a30172e45 [dynarmic] Coalesce non-exclusive Write/Read fallback functions (#4158)
the general idea is to have a common procedure form whom to call
this way theres less "jumping around" for values of different sizes
additionally this **should** allow for better codegen since
most of the u8,u16,u32,u64 can be held within a u64
theoretically this means that you could deifne callbacks in suck
a way that it's essentially as costly as a `mov r64, m64`
but that's not doable due to the fact we have to do translations...

Is this a good change?
Primarily aimed for x86 and ARM to benefit, but I suppose LooooooongArch64 can benefit too.

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4158
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-19 01:39:46 +02:00
xbzk 07f40d5cac [npad,hid,am] npad WriteEmptyEntry fix, hid function 551 stub, and applet PopOutData rework (#4442)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
This was intended to fix Dave the Diver issue, but we found a real silly hid bug, then a maybe broader applet issue:

By testing with John it was found out only the last controller connected worked, the others caused the game to freeze peacefully, no crashes, suggesting some loop or deadlock.

After seeking that lead, it was found that the freeze was caused by a malformed HID history entry when the controller applet removed P2.
Pressing P1 opens the controller applet, then Qt applet disconnects P2, which is expected.

Upon seeking callstack and hid sync path, it was found out that NPad::WriteEmptyEntry:
was using: ReadCurrentEntry().sampling_number + 1
instead of: ReadCurrentEntry().state.sampling_number + 1 (checked AtomicStorage in src\hid_core\resources\ring_lifo.h)
Fixing that fixed the freeze, but killed the sound!

Later handheld/docked was accidentally clicked and sound returned. Good lead.
Then i just had to corner which part of the toggle was causing the refresh and do something similar at the controller applet return routine (PopOutData in library_applet_accessor.cpp). This part seems harmless, but i'm not clearly sure about how proper it is, since it was like a transplant and test operation.

UPDATE:
To try Diablo 3 on my machine it was needed to stub HID function 551.

And to fix all abnormalies like multiple applet requests and crash the function PopOutData was reworked to ensurey idempotency among different applet focus conditions:

focus state changed: updates state and signals if needed
no state change, HLE application frontend: requests focus state changed notification
already pending change message: flag remains true and no duplicate pushed to queue entry

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4442
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-18 23:49:17 +02:00
xbzk 3c38afad74 [fs] share parent resources with bundled programs (#4319)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Normal games are Applications;
Bundled games are Application + Programs;

We've been treating both as the same thing, calling both programs, and making programs unable to see settings and saves from application.

References:
https://switchbrew.org/wiki/Filesystem_services
https://switchbrew.org/wiki/NCM_services#ApplicationId
https://switchbrew.org/wiki/Super_Mario_3D_All-Stars
Ryujinx.HLE/HOS/ApplicationLoader.cs:GetMultiProgramInfo

UPDATE:

The first version was a big rework to make AppId/ProgId concepts proper, and it was successful in most tests, but it caused a regression with applets, which are programs that breed straight from no application.
In order to simplify things i've reverted all the rework, added a helper to identify whether a program has a parent Application and bounded it to it's proper stores.

Although this is no big deal coz it doesn't have impact on emulation, it permeates to several routines, so it needs to be tested broadly. Applets, Normal games, Bundled games, Blobbed NSPs/XCIs, Mods, Updates, Saves, DLCs,.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4319
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: lizzie <lizzie@eden-emu.dev>
2026-09-18 23:48:35 +02:00
Feng Chen 0ce29be608 [common] Fix RDTSC nanosecond conversion (#4422)
Split the RDTSC ticks-per-nanosecond ratio into integer and Q0.64 fractional components. This avoids overflowing GetFixedPoint64Factor for TSC frequencies above 1 GHz while preserving the multiply-only conversion path.

Use the invariant clock only above 1 GHz because the reverse nanoseconds-per-tick factor cannot represent an exact ratio of one.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4422
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-17 19:50:19 +02:00
lizzie 1203082a8f [msvc] fix build errors (#4451)
MSVC doesn't consider atomic<u64> to be trivially copyable on x86 (why?).
And other chary idiosyncrasies from constructing `std::optional<uint8_t>`

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4451
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 08:16:18 +02:00
lizzie 14235dc0d0 [ips] fix .pchtxt with >256 bytes on a single line (#4445)
It wasn't correct to assume pchtxt would've been less than 256 bytes per line.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4445
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 08:15:58 +02:00
lizzie 6374f7f51f Partial revert: [dynarmic] fix sign extension and optimize vaddr lookups for 64bit on x64 systems (#4446) (#4448)
Breaks Mario Kart 8 Deluxe.

#4446

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4448
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 05:52:36 +02:00
lizzie 73e004de6e [common/page_table] unmark non-constexpr functions (#4433)
`std::atomic` member functions don't translate unto `constexpr`.

Trivial change, fixes CI warning.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4433
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 05:51:23 +02:00
lizzie f7b8ade40e [hle] stpl:sys, stpl:u initial implementation (#4435)
These cmds are hardcoded to use 0x20b, also the vftable is the same for `nn::sf::hipc`.

Streamplay is probably not gonna be implemented fully, but some future updates *may* hang when querying for the service, thus registering it at once will avoid such issues.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4435
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 05:45:37 +02:00
lizzie 8c1194474e [hle/ssl] Implement Peek(),{Get,Set}RenegotiationMode,Pending,Poll and stub miscellany (#4428)
Mainly because of Pending() as it's used in some games. May as well implement the rest.

Skyline implemented ISslContext::RegisterInternalPki which is just a success stub (for now) for JJBA:ASB

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4428
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-17 05:43:59 +02:00
lizzie 90aafeedc1 [k_scheduler] fix for libc++ that lazily initializes mutexes (#4447)
`__m_` is nullptr when `unlock();` is called, so `try_lock();` will force materialization of the backing mutex.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4447
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-17 00:28:37 +02:00
Exverge 4fe5f62c38 [dynarmic] fix sign extension and optimize vaddr lookups for 64bit on x64 systems (#4446)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------
Same as #4415 + #4444 just ported to A64 because I amazingly forgot

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4446
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-16 22:47:16 +02:00
Feng Chen c3f1e6562b [common/fs] Preserve Windows roots during path sanitization (#4437)
Commit 5b4c29b123 made SanitizePath rebuild paths from split components after resolving traversal. That reconstruction retained only one leading separator, collapsing UNC paths and breaking network-backed directories.

Parse the path root separately from normal components. Preserve UNC prefixes, drive-absolute and drive-relative forms, and extended UNC/device namespaces while normalizing separators and dot components.

Treat the UNC server/share portion as part of the root so parent traversal cannot escape into another share. Also preserve root-only results such as / and C:\\ instead of stripping their final separator.

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4437
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-16 22:12:01 +02:00
lizzie ac35358b3f [common] Replace Common::SpinLock with std::mutex (#4436)
`std::mutex` can be better than the spin-lock specially since we don't waste CPU cycles for no reason.

Test less stuttering/heat consumption.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4436
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-16 15:35:13 +02:00
lizzie 7bf95be2c2 [dynarmic] fix A32 crash due to wrong LEA encoding (#4444)
LEA 1<<n, not just n

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4444
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-16 09:29:12 +02:00
lizzie 4ce45b3b37 [hle] Fix crash on MK8D and SM3DW LDN (#4417)
Crash is due to SIGILL due to mismatched N and span<> ctor().
Also some astray nullptr references.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4417
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-09-16 08:10:29 +02:00
lizzie fd34024f0e [hle/ns] fix build error due to missing async_result.h (#4440)
We may have merged quite a bit too fast before letting CI finish.

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4440
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-16 04:45:45 +02:00
lizzie d76f8f91c4 [hle] Fix nullptr on ListApplicationIcon (#4438)
Control could be null, handle such case

Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4438
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-16 04:00:59 +02:00
PavelBARABANOV a7061eb4c8 [ns] Rename i_async_result -> async_result (#4439)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4439
Reviewed-by: lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-16 03:46:44 +02:00
PavelBARABANOV fa4e7c6992 [vk_texture_cache] drop depth comparison sampler fallback (#4408)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

This fixes the flashlight in Alan Wake.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4408
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-16 01:42:37 +02:00
xbzk b77308ced6 [applet] ReconfigureControllers fallback unconditional disconnect fix (#4420)
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

-------------------

So, about Absolum's no overlay applet P2 issue:

The fallback controller applet ignored keep_controllers_connected, according comment: "This makes it easy to connect the desired controllers". Unfortunately it was not good enough. It disconnected every controller, then reconnected only the minimum player count. That disconnect interacts with some guests (absolum in this case) causing undesired behaviors.

The fix is entwined to original routine but it is a lot simple tho: preserves compatible connected controllers within the requested player range, while the existing routine configures only the remaining slots.

This may fix some games, and should not harm others. Let us give it a go.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4420
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-09-15 21:53:07 +02:00
157 changed files with 17262 additions and 16242 deletions
+6 -1
View File
@@ -79,7 +79,7 @@
"name": "ffmpeg",
"package": "FFmpeg",
"repo": "crueter-ci/FFmpeg",
"version": "9.0.1-1788120736-bf1b838f2a"
"version": "9.0.2-1790726865-946fcce07b"
},
"fmt": {
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
@@ -333,6 +333,11 @@
"repo": "herumi/xbyak",
"version": "v7.40.1"
},
"zbic": {
"hash": "fbe2f37986377d7f0d96ae3224c80b5971df6e8b6961f68061f1975ebb2e8cb78f07b90f014b007be4023dbf5513581504e7f7d61a5237cb2a8a7a61ae11e482",
"repo": "kinnay/zbic",
"version": "11b08f2712264bbed731545085cbd9702096ceb7"
},
"zlib": {
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
"min_version": "1.2",
+663 -647
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+547 -536
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+547 -530
View File
File diff suppressed because it is too large Load Diff
+555 -537
View File
File diff suppressed because it is too large Load Diff
+546 -529
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+546 -528
View File
File diff suppressed because it is too large Load Diff
+546 -529
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+547 -536
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+546 -529
View File
File diff suppressed because it is too large Load Diff
+546 -529
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+547 -536
View File
File diff suppressed because it is too large Load Diff
+551 -539
View File
File diff suppressed because it is too large Load Diff
+546 -528
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+573 -561
View File
File diff suppressed because it is too large Load Diff
+549 -531
View File
File diff suppressed because it is too large Load Diff
+33 -21
View File
@@ -1,32 +1,44 @@
# User Handbook - Command Line
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
## eden
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept the same command line arguments.
- `./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.
- `-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.
- `-f`: Use fullscreen.
- `-u <number>`: Select the index of the user to load as.
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
- `--config/-c`: Specify alternate configuration file.
- `--fullscreen/-f`: Use fullscreen.
- `--help/-h`: Display help.
- `--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.
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
- `-setup`: Launch setup applet.
## eden-cli
`eden` (provided with `--room`), and `eden-room` supports the following options as well:
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
- `--config/-c`: Specify alternate configuration file.
- `--fullscreen/-f`: Set fullscreen.
- `--help/-h`: Display help.
- `--game/-g`: Specify the game to run.
- `--multiplayer/-m`: Specify multiplayer options.
- `--program/-p`: Specify the program arguments to pass (optional).
- `--user/-u`: Specify the user index.
- `--version/-v`: Display version and quit.
- `--input-profile/-i`: 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.
- `-n/--room-name`: The name of the room.
- `-d/--room-description`: The room description.
- `-s/--bind-address`: The bind address for the room.
- `-p/--port`: The port used for the room.
- `-m/--max-members`: The maximum number of players for this room.
- `-w/--password`: The password for the room.
- `-g/--preferred-game`: The preferred game for this room.
- `-i/--preferred-game-id`: The preferred game-id for this room.
- `-u/--username`: The username used for announce.
- `-t/--token`: The token used for announce.
- `-a/--web-api-url`: yuzu Web API url.
- `-b/--ban-list-file`: The file for storing the room ban list.
- `-l/--log-file`: The file for storing the room log.
- `-h/--help`: Display this help and exit.
- `-v/--version`: Output version information and exit.
+5
View File
@@ -48,6 +48,11 @@ if (NOT TARGET stb::headers)
add_library(stb::headers ALIAS stb)
endif()
AddJsonPackage(NAME zbic DOWNLOAD_ONLY)
set(ZBIC_INCLUDE_DIR
"${zbic_SOURCE_DIR}/src"
PARENT_SCOPE)
# ItaniumDemangle (Windows only)
if (WIN32 AND NOT TARGET LLVM::Demangle)
add_library(demangle demangle/ItaniumDemangle.cpp)
@@ -16,6 +16,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
NCE_RUNTIME_NRO_PATCH("nce_runtime_nro_patch"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"),
@@ -25,12 +27,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache"),
RENDERER_FORCE_MAX_CLOCK("force_max_clock"),
RENDERER_ASYNCHRONOUS_GPU_EMULATION("use_asynchronous_gpu_emulation"),
RENDERER_ASYNC_PRESENTATION("async_presentation"),
RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders"),
RENDERER_REACTIVE_FLUSHING("use_reactive_flushing"),
ENABLE_BUFFER_HISTORY("enable_buffer_history"),
USE_OPTIMIZED_VERTEX_BUFFERS("use_optimized_vertex_buffers"),
ENABLE_GPU_BUFFER_READBACK("enable_gpu_buffer_readback"),
SYNC_MEMORY_OPERATIONS("sync_memory_operations"),
BUFFER_REORDER_DISABLE("disable_buffer_reorder"),
RENDERER_DEBUG("debug"),
@@ -753,13 +753,6 @@ abstract class SettingsItem(
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(
SingleChoiceSetting(
IntSetting.DMA_ACCURACY,
@@ -866,6 +859,20 @@ abstract class SettingsItem(
descriptionId = R.string.skip_cpu_inner_invalidation_description
)
)
put(
SwitchSetting(
BooleanSetting.NCE_INVALIDATION_GPU_READBACK,
titleId = R.string.nce_invalidation_gpu_readback,
descriptionId = R.string.nce_invalidation_gpu_readback_description
)
)
put(
SwitchSetting(
BooleanSetting.NCE_RUNTIME_NRO_PATCH,
titleId = R.string.nce_runtime_nro_patch,
descriptionId = R.string.nce_runtime_nro_patch_description
)
)
put(
SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -908,13 +915,6 @@ abstract class SettingsItem(
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_OPTIMIZED_VERTEX_BUFFERS,
@@ -549,18 +549,18 @@ class SettingsFragmentPresenter(
add(BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key)
add(BooleanSetting.RENDERER_REACTIVE_FLUSHING.key)
add(BooleanSetting.ENABLE_BUFFER_HISTORY.key)
add(BooleanSetting.ENABLE_GPU_BUFFER_READBACK.key)
add(BooleanSetting.USE_OPTIMIZED_VERTEX_BUFFERS.key)
add(HeaderSetting(R.string.hacks))
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
add(BooleanSetting.NCE_RUNTIME_NRO_PATCH.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
add(IntSetting.ANDROID_PIPELINE_WORKERS.key)
add(BooleanSetting.RENDERER_ASYNCHRONOUS_GPU_EMULATION.key)
add(BooleanSetting.RENDERER_ASYNC_PRESENTATION.key)
add(SettingsItem.GPU_UNSWIZZLE_COMBINED)
add(HeaderSetting(R.string.extensions))
@@ -23,6 +23,7 @@ import org.yuzu.yuzu_emu.model.Driver.Companion.toDriver
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.utils.GpuDriverMetadata
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import org.yuzu.yuzu_emu.utils.NativeConfig
import java.io.File
@@ -146,11 +147,11 @@ class DriverViewModel : ViewModel() {
private fun wipeGameShaders(game: Game) {
viewModelScope.launch {
withContext(Dispatchers.IO) {
val externalFilesDir = YuzuApplication.appContext.getExternalFilesDir(null)
val userDirectory = DirectoryInitialization.userDirectory
?: return@withContext
val shaderDir = File(
externalFilesDir.absolutePath +
"/shader/" + game.settingsName.lowercase()
userDirectory +
"/cache/shader/" + game.settingsName.lowercase()
)
if (shaderDir.exists()) {
shaderDir.deleteRecursively()
+2 -2
View File
@@ -788,7 +788,7 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* env, jobject jobj,
jstring jprogramId,
jstring jupdatePath) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
const u64 program_id = FileSys::GetBaseTitleID(EmulationSession::GetProgramId(env, jprogramId));
std::string updatePath = Common::Android::GetJString(env, jupdatePath);
std::shared_ptr<FileSys::NSP> nsp = std::make_shared<FileSys::NSP>(
EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(
@@ -796,7 +796,7 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_doesUpdateMatchProgram(JNIEnv* en
for (const auto& item : nsp->GetNCAs()) {
for (const auto& nca_details : item.second) {
if (nca_details.second->GetName().ends_with(".cnmt.nca")) {
auto update_id = nca_details.second->GetTitleId() & ~0xFFFULL;
const auto update_id = FileSys::GetBaseTitleID(nca_details.second->GetTitleId());
if (update_id == program_id) {
return true;
}
@@ -28,7 +28,7 @@
<string name="input_overlay_behavior">السلوك</string>
<string name="overlay_auto_hide">إخفاء الطبقة تلقائيًا</string>
<string name="overlay_auto_hide_description">إخفاء طبقة ذراع التحكم باللمس تلقائيًا بعد مرور الوقت المحدد من عدم النشاط.</string>
<string name="enable_input_overlay_auto_hide">تمكين إخفاء الطبقة تلقائيًا</string>
<string name="enable_input_overlay_auto_hide">تفعيل إخفاء الطبقة تلقائيًا</string>
<string name="hide_overlay_on_controller_input">إخفاء الطبقة عند إدخال ذراع التحكم</string>
<string name="hide_overlay_on_controller_input_description">إخفاء تلقائي لطبقة عناصر التحكم باللمس عند استخدام ذراع تحكم فعلية. تظهر الطبقة مرة أخرى عند فصل ذراع التحكم.</string>
<string name="invert_confirm_back_controller_buttons">عكس أزرار التأكيد/الرجوع في وحدة التحكم</string>
@@ -51,7 +51,7 @@
<string name="stats_overlay_customization">التخصيص</string>
<string name="stats_overlay_items">الرؤية</string>
<string name="stats_overlay_options">طبقة الأداء</string>
<string name="enable_stats_overlay_">تمكين طبقة إحصائيات الأداء</string>
<string name="enable_stats_overlay_">تفعيل طبقة إحصائيات الأداء</string>
<string name="stats_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة إحصائيات الأداء</string>
<string name="show_fps">عرض معدل الإطارات</string>
<string name="show_fps_description">عرض معدل الإطارات الحالي</string>
@@ -81,7 +81,7 @@
<!-- Device Overlay settings -->
<string name="show_soc_overlay">عرض طبقة معلومات الجهاز</string>
<string name="enable_soc_overlay">تمكين طبقة الجهاز</string>
<string name="enable_soc_overlay">تفعيل طبقة الجهاز</string>
<string name="soc_overlay_options">طبقة الجهاز</string>
<string name="soc_overlay_options_description">ضبط المعلومات التي يتم عرضها في طبقة الجهاز</string>
@@ -98,8 +98,8 @@
<string name="use_sync_core">مزامنة سرعة النواة</string>
<string name="use_sync_core_description">قم بمزامنة سرعة النواة مع النسبة المئوية للسرعة القصوى لتحسين الأداء دون تغيير السرعة الفعلية للعبة.</string>
<string name="cpuopt_unsafe_host_mmu">تمكين محاكاة MMU المضيف</string>
<string name="cpuopt_unsafe_host_mmu_description">يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تمكينه إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية.</string>
<string name="cpuopt_unsafe_host_mmu">تفعيل محاكاة MMU المضيف</string>
<string name="cpuopt_unsafe_host_mmu_description">يعمل هذا التحسين على تسريع وصول الذاكرة بواسطة البرنامج الضيف. يؤدي تفعيله إلى إجراء عمليات قراءة/كتابة ذاكرة الضيف مباشرة في الذاكرة والاستفادة من MMU المضيف. يؤدي تعطيل هذا إلى إجبار جميع عمليات الوصول إلى الذاكرة على استخدام محاكاة MMU البرمجية.</string>
<string name="debug_knobs">مقابض تصحيح الأخطاء</string>
<string name="debug_knobs_description">للإستخدام في التطوير فقط.</string>
<string name="debug_knobs_hint">0 إلى 65535</string>
@@ -342,7 +342,7 @@
<string name="frame_gen_flow_scale_description">دقة مسار التدفق البصري، كجزء من الناتج. ويُعد خفض هذه القيمة أرخص طريقة لاستعادة الأداء.</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_description">يتطلب إنشاء الإطارات أن تكون لديك نسخة قانونية خاصة بك من ملف Lossless.dll المأخوذ من برنامج Lossless Scaling</string>
<string name="lossless_scaling_replace_description">اختر نسخة أخرى من ملف Lossless.dll</string>
@@ -350,7 +350,7 @@
<string name="frame_generation_supported">مدعوم</string>
<string name="frame_generation_unsupported">غير مدعوم (لا يتوفر نموذج ذاكرة Vulkan أو float16)</string>
<string name="lossless_scaling">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_not_installed">غير مثبت</string>
<string name="lossless_scaling_replace">استبدل</string>
@@ -502,9 +502,9 @@
<string name="frame_limit_slider">نسبة الحد الأقصى للسرعة</string>
<string name="frame_limit_slider_description">يحدد النسبة المئوية للحد من سرعة المحاكاة. %100 هي السرعة الطبيعية. القيم الأعلى أو الأقل ستزيد أو تقلل من الحد الأقصى للسرعة.</string>
<string name="turbo_speed_limit">سرعة تيربو</string>
<string name="turbo_speed_limit_description">عند تمكين وضع التيربو، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="turbo_speed_limit_description">عند تفعيل وضع التيربو، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="slow_speed_limit">سرعة بطيئة</string>
<string name="slow_speed_limit_description">عند تمكين الوضع البطيء، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="slow_speed_limit_description">عند تفعيل الوضع البطيء، سيتم تشغيل المحاكاة بهذه السرعة.</string>
<string name="cpu_backend">خلفية وحدة المعالجة المركزية</string>
<string name="cpu_accuracy">دقة وحدة المعالجة المركزية</string>
<string name="value_with_units">%1$s%2$s</string>
@@ -574,14 +574,10 @@
<string name="renderer_force_max_clock_description">يجبر وحدة معالجة الرسومات على العمل بأقصى سرعة ممكنة (سيظل يتم تطبيق القيود الحرارية).</string>
<string name="renderer_asynchronous_gpu_emulation">محاكاة غير متزامنة لوحدة معالجة الرسومات</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_description">يحسن دقة العرض في بعض الألعاب على حساب الأداء.</string>
<string name="enable_buffer_history">تمكين سجل التخزين المؤقت</string>
<string name="enable_buffer_history">تفعيل سجل التخزين المؤقت</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_description">يُتيح ربطًا مُحسَّنًا لمخازن الرؤوس لتحسين الأداء. يتطلب برامج تشغيل Mesa 26.0+ Turnip/ برامج تشغيل QCOM. قد يتعطل على برامج تشغيل Turnip القديمة (25.3 وما دون).</string>
@@ -618,7 +614,7 @@
<string name="dyna_state_description">يتحكم هذا الخيار في عدد الميزات التي يمكن استخدامها في ExtendedDynamicState (EDS). كلما زادت القيمة، قلّ عدد عمليات تجميع خط الأنابيب بناءً على الحالة الديناميكية التي يدعمها برنامج التشغيل.</string>
<string name="disabled">معطل</string>
<string name="vertex_input_dynamic_state">حالة ديناميكية لإدخال الرأس</string>
<string name="vertex_input_dynamic_state_description">يتيح تمكين هذه الميزة معالجة أكثر مرونة لمدخلات الرؤوس، مما قد يقلل من وقت تجميع خط الأنابيب في vertex/buffer.</string>
<string name="vertex_input_dynamic_state_description">يتيح تفعيل هذه الميزة معالجة أكثر مرونة لمدخلات الرؤوس، مما قد يقلل من وقت تجميع خط الأنابيب في vertex/buffer.</string>
<string name="sample_shading_fraction">تظليل العينة</string>
<string name="sample_shading_fraction_description">يسمح هذا الخيار بتنفيذ مُظلل الأجزاء لكل عينة في جزء متعدد العينات بدلاً من تنفيذه مرة واحدة لكل جزء. يُحسّن هذا من جودة الرسومات على حساب بعض الأداء.</string>
@@ -827,9 +823,9 @@
<string name="preferences_system">النظام</string>
<string name="preferences_system_description">وضع الإرساء، المنطقة، اللغة</string>
<string name="preferences_graphics">الرسومات</string>
<string name="preferences_graphics_description">مستوى الدقة، الدقة، ذاكرة التخزين المؤقتة للتظليل</string>
<string name="preferences_graphics_description">مستوى دقة المحاكاة، الدقة، ذاكرة التخزين المؤقتة للتظليل</string>
<string name="quick_settings">الإعدادات السريعة</string>
<string name="enable_quick_settings">تمكين الإعدادات السريعة</string>
<string name="enable_quick_settings">تفعيل الإعدادات السريعة</string>
<string name="enable_quick_settings_description">السماح بالوصول إلى قائمة الإعدادات السريعة عن طريق التمرير و زر القائمة</string>
<string name="preferences_audio">الصوت</string>
<string name="preferences_audio_description">محرك الإخراج، مستوى الصوت</string>
@@ -1099,7 +1095,6 @@
<string name="gpu_fence_behavior_immediate">فوري</string>
<string name="gpu_fence_behavior_balanced">متوازن</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_aggressive">عدواني</string>
@@ -1226,8 +1221,8 @@
<string name="airplane_mode">وضع الطيران</string>
<string name="airplane_mode_description">يمرر وضع الطيران إلى نظام تشغيل Switch</string>
<string name="enable_overlay">تمكين التطبيق الصغير للطبقة</string>
<string name="enable_overlay_description">تمكين التطبيق الصغير المدمج في Horizon. اضغط مع الاستمرار على زر الشاشة الرئيسية لمدة 1 ثانية لإظهاره.</string>
<string name="enable_overlay">تفعيل التطبيق الصغير للطبقة</string>
<string name="enable_overlay_description">تفعيل التطبيق الصغير المدمج في Horizon. اضغط مع الاستمرار على زر الشاشة الرئيسية لمدة 1 ثانية لإظهاره.</string>
<!-- Profile Management -->
<string name="profile_manager">إدارة ملف التعريف</string>
@@ -967,7 +967,6 @@ Wirklich fortfahren?</string>
<string name="gpu_fence_behavior_immediate">Direkt</string>
<string name="gpu_fence_behavior_balanced">Ausgewogen</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_aggressive">Aggressiv</string>
@@ -289,6 +289,7 @@
<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="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_close_list">Cerrar lista</string>
<string name="post_processing_reset">Restablecer a predeterminado</string>
@@ -517,14 +518,10 @@
<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_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_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_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_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>
@@ -1037,7 +1034,6 @@
<string name="gpu_fence_behavior_immediate">Inmediato</string>
<string name="gpu_fence_behavior_balanced">Equilibrado</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_aggressive">Agresivo</string>
@@ -318,6 +318,13 @@
<string name="frame_gen_target_rate">Целевая частота кадров</string>
<string name="frame_gen_target_rate_description">Выберите значение под ваш дисплей. Множитель подстроится сам, чтобы его держать, и откатит изменения, если игра начнёт тормозить.</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_description">Сколько готовых кадров может ожидать перед выводом на экран. Более длинные очереди сглаживают скачки ГПУ ценой задержки ввода.</string>
<string name="frame_gen_queue_target_0">Минимальная задержка (Без буферизации)</string>
@@ -328,12 +335,14 @@
<string name="frame_gen_flow_scale">Разрешение оценки движения</string>
<string name="frame_gen_flow_scale_description">Разрешение прохода оптического потока в долях от выходного разрешения. Его понижение — самый дешёвый способ вернуть производительность.</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_install">Установить Lossless.dll</string>
<string name="lossless_scaling_install_description">Для генерации кадров требуется ваша собственная легальная копия Lossless.dll из Lossless Scaling</string>
<string name="lossless_scaling_replace_description">Выбрать другой файл Lossless.dll</string>
<string name="frame_generation_support">Генерация кадров</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_installed">Установлена</string>
<string name="lossless_scaling_not_installed">Не установлена</string>
@@ -554,14 +563,10 @@
<string name="renderer_force_max_clock_description">Заставляет ГПУ работать на максимально возможных тактовых частотах (тепловые ограничения все равно будут применяться).</string>
<string name="renderer_asynchronous_gpu_emulation">Асинхронная эмуляция ГПУ</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_description">Повышение точности рендеринга в некоторых играх за счет снижения производительности.</string>
<string name="enable_buffer_history">Включить историю буфера</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_description">Включает оптимизированную привязку вершинного буфера для повышения производительности. Требует Mesa Turnip 26.0+ / QCOM. Приводит к вылету на старых версиях драйверов Turnip (25.3 и ниже).</string>
@@ -1079,7 +1084,6 @@
<string name="gpu_fence_behavior_immediate">Мгновенный</string>
<string name="gpu_fence_behavior_balanced">Сбалансированный</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_aggressive">Агрессивный</string>
@@ -481,8 +481,6 @@
<string name="renderer_force_max_clock_description">Змушує GPU працювати на максимальній тактовій частоті.</string>
<string name="renderer_asynchronous_gpu_emulation">Асинхронна емуляція ГП</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_description">Покращує точність рендерингу в деяких іграх.</string>
<string name="enable_buffer_history">Увімкнути історію буфера</string>
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
<string name="app_disclaimer">本软件可以运行用于 Nintendo Switch 游戏机的游戏。不包含任何游戏或密钥。<br /><br />在您开始之前, 请定位您设备存储上的 <![CDATA[<b> prod.keys </b>]]> 文件。<br /><br /><![CDATA[<a href=\"https://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_description">当发生错误时显示通知。</string>
<string name="notification_permission_not_granted">未授予通知权限!</string>
@@ -290,6 +291,25 @@
<string name="gpu_driver_fetcher">GPU驱动获取器</string>
<string name="gpu_driver_manager">GPU 驱动管理器</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_per_game_description">配置针对此游戏的帧生成设定</string>
<string name="frame_gen_description">设定要在使用无损缩放渲染的帧之间应用的插帧。启用后强制采用FIFO呈现模式 。</string>
@@ -304,6 +324,13 @@
<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_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_description">在显示之前有多少已完成渲染的帧正在等待。较大的队列可以缓解 GPU 突发的压力,但会增加输入延迟。</string>
<string name="frame_gen_queue_target_0">最低延迟 (无缓冲)</string>
@@ -314,12 +341,14 @@
<string name="frame_gen_flow_scale">运动预估分辨率</string>
<string name="frame_gen_flow_scale_description">光流通道的分辨率,以输出的比例表示。降低它是提升性能最经济的做法。</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_install">安装 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="frame_generation_support">帧生成</string>
<string name="frame_generation_supported">支持</string>
<string name="frame_generation_unsupported">不支持 (无 Vulkan 内存模型或 float16)</string>
<string name="lossless_scaling">无损缩放</string>
<string name="lossless_scaling_description">提供您自己的 Lossless.dll 文件以启用帧生成</string>
<string name="lossless_scaling_installed">已安装</string>
@@ -535,14 +564,10 @@
<string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (温控依然生效)。</string>
<string name="renderer_asynchronous_gpu_emulation">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_description">通过牺牲性能来提升某些游戏的渲染精度。</string>
<string name="enable_buffer_history">启用缓冲区历史</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_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
@@ -611,6 +636,11 @@
<string name="log">日志记录</string>
<string name="flush_by_line">按行刷新调试日志</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 -->
<string name="gpu_logging_header">GPU 日志</string>
<string name="gpu_log_level">日志等级</string>
@@ -894,6 +924,8 @@
<string name="loader_error_file_not_found">ROM 文件不存在</string>
<string name="loader_requires_firmware">游戏需要固件</string>
<string name="loader_requires_firmware_description"><![CDATA[这个游戏可能需要固件才能正常运行,但您还没有安装任何固件。请在启动前安装固件,或者按 “确定” 继续启动。]]></string>
<!-- Intent Launch strings -->
<string name="searching_for_game">正在搜索游戏...</string>
<string name="game_not_found_for_title_id">未找到标题ID的游戏: %1$s</string>
@@ -1053,7 +1085,6 @@
<string name="gpu_fence_behavior_immediate">即时</string>
<string name="gpu_fence_behavior_balanced">均衡</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_aggressive">主动式</string>
@@ -16,7 +16,7 @@
<string name="value_too_high">範圍最大必須為%1$d</string>
<string name="invalid_value">無效的範圍</string>
<string name="using_per_game_config">使用個別設定中</string>
<string name="using_per_game_config">使用個別遊戲設定中</string>
<!-- Input Overlay -->
<string name="show_input_overlay">顯示虛擬按鍵</string>
@@ -67,7 +67,7 @@
<string name="show_shaders_building">當著色器在編譯時顯示</string>
<string name="show_shaders_building_description">顯示正在編譯的著色器數量</string>
<string name="pipeline_worker_cores">管線工作執行緒</string>
<string name="pipeline_worker_cores_description">設定用於建置 Vulkan 管線的 CPU 核心數量,設定的數值越大效能越好,但溫度也會上升更快</string>
<string name="pipeline_worker_cores_description">設定用於建置Vulkan管線的CPU核心數量,設定的數值越大效能越好,但溫度也會上升更快</string>
<string name="overlay_position">疊加層位置</string>
<string name="overlay_position_description">選擇疊加層在畫面上的顯示位置</string>
<string name="overlay_position_top_left">左上</string>
@@ -98,15 +98,15 @@
<string name="use_sync_core">同步核心速度</string>
<string name="use_sync_core_description">將核心速度與最大速度百分比同步,在不改變遊戲實際速度的情況下提高效能</string>
<string name="cpuopt_unsafe_host_mmu">啟用主機 MMU 模擬</string>
<string name="cpuopt_unsafe_host_mmu_description">此最佳化可加速客體程式的記憶體存取。啟用後,客體記憶體讀取/寫入將直接在記憶體中執行並利用主機的 MMU。停用此功能將強制所有記憶體存取使用軟體 MMU 模擬。</string>
<string name="cpuopt_unsafe_host_mmu">啟用主機MMU模擬</string>
<string name="cpuopt_unsafe_host_mmu_description">此最佳化可加速客體程式的記憶體存取。啟用後,客體記憶體讀取/寫入將直接在記憶體中執行並利用主機的MMU。停用此功能將強制所有記憶體存取使用軟體MMU模擬</string>
<string name="debug_knobs">偵錯開關</string>
<string name="debug_knobs_description">僅限開發用途</string>
<string name="debug_knobs_hint">0到65535</string>
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC模擬</string>
<string name="nvdec_emulation_description">若在過場動畫中當機請切換成 CPU</string>
<string name="nvdec_emulation_description">若在過場動畫中當機請切換成CPU</string>
<string name="nvdec_emulation_none">無</string>
<!-- Optimize SPIRV output -->
@@ -151,7 +151,7 @@
<string name="multiplayer_member_leave">%1$s 離開</string>
<string name="multiplayer_member_kicked">%1$s 被踢出</string>
<string name="multiplayer_member_banned">%1$s 被封鎖</string>
<string name="multiplayer_address_unbanned">位址已解封</string>
<string name="multiplayer_address_unbanned">IP位址已解封</string>
<string name="multiplayer_kick_member">踢出成員</string>
<string name="multiplayer_password">密碼</string>
<string name="multiplayer_joining">正在加入…</string>
@@ -173,7 +173,7 @@
<string name="multiplayer_ban">封鎖使用者</string>
<string name="multiplayer_room_browser">公開房間</string>
<string name="multiplayer_no_rooms_found">未找到公開房間</string>
<string name="multiplayer_password_required">需要輸入密碼</string>
<string name="multiplayer_password_required">請輸入密碼</string>
<string name="multiplayer_player_count">:%1$d/%2$d</string>
<string name="multiplayer_game">遊戲</string>
<string name="multiplayer_no_game_info">任意遊戲</string>
@@ -189,7 +189,7 @@
<string name="multiplayer_token_required">需要Web令牌,請前往進階設定 -> 系統 -> 網路</string>
<string name="multiplayer_ip_error">IP格式無效</string>
<string name="multiplayer_username_error">必須介於4-20個字元之間,並且僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string>
<string name="multiplayer_nickname_invalid">使用者名稱無效,請在系統→網路中檢查設定</string>
<string name="multiplayer_nickname_invalid">使用者名稱無效,請在系統 -&gt; 網路中檢查設定</string>
<string name="multiplayer_token_error">必須為48個字元,且僅包含小寫字母a-z</string>
<string name="multiplayer_port_error">埠號需為1-65535</string>
<string name="cancel">取消</string>
@@ -201,16 +201,16 @@
<!-- Setup strings -->
<string name="welcome">歡迎!</string>
<string name="welcome_description">瞭解如何設定 <b>Eden</b> 並開始模擬。</string>
<string name="welcome_description">瞭解如何設定 <b>Eden</b> 並開始模擬</string>
<string name="get_started">開始使用</string>
<string name="keys">金鑰</string>
<string name="keys_description">使用下方的按鈕安裝您的 <b>prod.keys</b> 檔案。</string>
<string name="keys_description">使用下方的按鈕安裝您的 <b>prod.keys</b> 檔案</string>
<string name="firmware">韌體</string>
<string name="firmware_description">使用下方的按鈕安裝您的<b>firmware.zip</b>檔案</string>
<string name="games">遊戲資料夾</string>
<string name="games_description">使用下方的按鈕選擇您的<b>遊戲</b>資料夾。</string>
<string name="done">完成</string>
<string name="done_description">您已準備就緒。\n盡情遊玩您的遊戲!</string>
<string name="done_description">您已準備就緒\n盡情遊玩您的遊戲!</string>
<string name="next">下一步</string>
<string name="back">上一步</string>
<string name="add_games">新增遊戲</string>
@@ -229,7 +229,7 @@
<string name="add_directory_success">遊戲目錄新增成功</string>
<string name="enable_update_checks">檢查更新</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="downloading_update">下載更新中</string>
<string name="update_download_failed">更新下載失敗</string>
@@ -237,7 +237,7 @@
<string name="update_install_failed">更新安裝失敗:%1$s</string>
<string name="home_search">搜尋</string>
<string name="home_settings">設定</string>
<string name="empty_gamelist">找不到檔案,或者尚未選取遊戲目錄</string>
<string name="empty_gamelist">找不到遊戲檔案,或者尚未選取遊戲目錄</string>
<string name="manage_game_folders">管理遊戲資料夾</string>
<string name="select_games_folder_description">允許 Eden 尋找您的遊戲檔案</string>
<string name="add_games_warning">跳過選擇遊戲資料夾?</string>
@@ -287,9 +287,9 @@
<string name="warning_skip">跳過</string>
<string name="warning_cancel">取消</string>
<string name="install_amiibo_keys">安裝 Amiibo 金鑰</string>
<string name="install_amiibo_keys_description">若要在遊戲中使用 Amiibo 得先安裝</string>
<string name="install_amiibo_keys_description">需要先安裝才能在遊戲中使用Amiibo</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="post_processing">後製處理效果</string>
<string name="post_processing_description">在渲染完成後套用 ReShade FX 效果</string>
@@ -299,7 +299,7 @@
<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_locked">濾鏡已啟用。請在開啟遊戲前於\"後製處理效果\"中調整</string>
<string name="post_processing_preset_modified">數值已變更,與原始濾鏡設定不同</string>
<string name="post_processing_presets">濾鏡</string>
<string name="post_processing_preset_new">新增濾鏡</string>
@@ -312,93 +312,102 @@
<string name="post_processing_empty">找不到設定檔。請將濾鏡效果的 .fx 檔案放置於此資料夾:</string>
<string name="frame_gen">影格生成</string>
<string name="frame_gen_per_game_description">調整此遊戲的影格生成設定</string>
<string name="frame_gen_description">使用 Lossless Scaling 在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用 FIFO 垂直同步</string>
<string name="frame_gen_description">使用Lossless Scaling在已渲染的影格之間插入補間影格。啟用此功能時,會強制採用FIFO垂直同步</string>
<string name="frame_gen_multiplier">影格倍率</string>
<string name="frame_gen_multiplier_description">設定在每個已渲染的影格中要顯示的影格數。數值越高所需的 GPU 運算時間也會按比例增加。若要求的影格數超過裝置顯示器能呈現的數量將會降低模擬速度</string>
<string name="frame_gen_multiplier_description">設定在每個已渲染的影格中要顯示的影格數,數值越高所需的GPU運算時間也會按比例增加。若要求的影格數超過裝置顯示器能呈現的數量將會降低模擬速度</string>
<string name="frame_gen_multiplier_2x">2x</string>
<string name="frame_gen_multiplier_3x">3x</string>
<string name="frame_gen_multiplier_4x">4x</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_60">60 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_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_description">最多允許多少個已完成的影格在顯示器前等待,較大的佇列可以吸收 GPU 突發負載,但會增加輸入延遲</string>
<string name="frame_gen_queue_target_0">最低延遲(無緩衝)</string>
<string name="frame_gen_queue_target_1">平衡(1影格)</string>
<string name="frame_gen_queue_target_2">最流暢(2影格)</string>
<string name="frame_gen_flow_scale_auto">配合遊戲調整運動預測</string>
<string name="frame_gen_flow_scale_auto_description">以遊戲實際渲染的解析度而非升頻後的輸出進行運動預測。由於升頻後不會增加任何動態細節,因此不會影響準確度</string>
<string name="frame_gen_flow_scale_auto_description">以遊戲實際渲染的解析度而非升頻後的輸出進行運動預測,由於升頻後不會增加任何動態細節,因此不會影響準確度</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_description">此GPU驅動程式缺少Lossless Scaling著色器所需的Vulkan記憶體模型或半精度浮點數(float16)支援</string>
<string name="lossless_scaling_setup_description">可選擇安裝自己擁有的 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_replace_description">安裝不同的 Lossless.dll 檔案</string>
<string name="frame_generation_support">影格生成</string>
<string name="frame_generation_supported">支援</string>
<string name="frame_generation_unsupported">不支援(無Vulkan記憶體模型或float16)</string>
<string name="lossless_scaling">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_not_installed">未安裝</string>
<string name="lossless_scaling_replace">替換</string>
<string name="lossless_scaling_replace">更換</string>
<string name="lossless_scaling_remove">刪除</string>
<string name="lossless_scaling_remove_description">刪除已安裝的 Lossless.dll 及預先編譯的著色器</string>
<string name="lossless_scaling_remove_confirmation">影格生成功能會停止運作直到您重新安裝 Lossless.dll 。您的 Lossless.dll 原始檔並不會被 Eden 修改</string>
<string name="lossless_scaling_remove_description">刪除已安裝的Lossless.dll及預先編譯的著色器</string>
<string name="lossless_scaling_remove_confirmation">影格生成功能會停止運作直到您重新安裝Lossless.dll,您的Lossless.dll原始檔不會被 Eden 修改</string>
<string name="lossless_scaling_missing">Lossless.dll 未安裝</string>
<string name="lossless_scaling_missing_description">前往 設定 -&gt; Lossless Scaling 安裝以使用影格生成功能</string>
<string name="lossless_scaling_locked">請先關閉遊戲</string>
<string name="lossless_scaling_locked_description">Lossless.dll 無法在遊戲執行時進行更換</string>
<string name="lossless_scaling_locked_description">Lossless.dll無法在遊戲執行時進行更換</string>
<string name="lossless_scaling_remove_unavailable">沒有東西可以刪除</string>
<string name="lossless_scaling_remove_unavailable_description">尚未安裝 Lossless.dll</string>
<string name="lossless_scaling_remove_unavailable_description">尚未安裝Lossless.dll</string>
<string name="lossless_scaling_installing">準備影格生成著色器中...</string>
<string name="lossless_scaling_install_success">成功安裝 Lossless.dll</string>
<string name="lossless_scaling_install_failed">無法安裝 Lossless.dll</string>
<string name="lossless_scaling_install_success">成功安裝Lossless.dll</string>
<string name="lossless_scaling_install_failed">無法安裝Lossless.dll</string>
<string name="error_lossless_copy_failed">無法複製選取的檔案</string>
<string name="error_lossless_unreadable">無法讀取選取的檔案</string>
<string name="error_lossless_not_pe">選取的檔案並不是 Windows 程式庫。請在 Lossless Scaling 的安裝位置(資料夾)中選擇 Lossless.dll</string>
<string name="error_lossless_missing_shaders">這個 Lossless.dll 的副本並未包含影格生成著色器。請更新 Lossless Scaling 後再試一次</string>
<string name="error_lossless_translation_failed">無法轉譯影格生成著色器。尚不支援此 Lossless Scaling 版本</string>
<string name="error_lossless_cache_failed">轉譯的著色器無法寫入到儲存空間。請確認手機容量是否充足</string>
<string name="error_lossless_not_pe">選取的檔案並不是Windows程式庫。請在Lossless Scaling的安裝位置(資料夾)中選擇Lossless.dll</string>
<string name="error_lossless_missing_shaders">這個Lossless.dll的副本並未包含影格生成著色器。請更新Lossless Scaling後重試</string>
<string name="error_lossless_translation_failed">無法轉譯影格生成著色器,尚不支援此Lossless Scaling版本</string>
<string name="error_lossless_cache_failed">轉譯的著色器無法寫入到儲存空間,請確認手機容量是否充足</string>
<string name="advanced_settings">進階設定</string>
<string name="settings_description">調整模擬器設定</string>
<string name="search_recently_played">最近遊玩</string>
<string name="search_recently_added">最近新增</string>
<string name="open_user_folder">開啟 Eden 資料夾</string>
<string name="open_user_folder_description">管理 Eden 的內部檔案</string>
<string name="open_user_folder">開啟Eden資料夾</string>
<string name="open_user_folder_description">管理Eden的內部檔案</string>
<string name="app_settings_description">自訂Eden的主題與介面</string>
<string name="no_file_manager">找不到檔案管理員</string>
<string name="notification_no_directory_link">無法開啟 Eden 目錄</string>
<string name="notification_no_directory_link">無法開啟Eden目錄</string>
<string name="notification_no_directory_link_description">請使用檔案管理員的側邊面板手動定位到使用者資料夾</string>
<string name="manage_save_data">管理儲存資料</string>
<string name="manage_save_data_description">導入/導出遊戲的儲存資料\n壓縮檔必須為.zip格式\n壓縮檔中首個子資料夾名稱必須為遊戲 ID</string>
<string name="manage_save_data_description">導入/導出遊戲的儲存資料\n壓縮檔必須為.zip格式\n壓縮檔中首個子資料夾名稱必須為遊戲ID</string>
<string name="import_save_warning">導入儲存資料</string>
<string name="import_save_warning_description">這將會以提供的檔案覆寫現有的該遊戲儲存資料,您確定要繼續嗎?</string>
<string name="save_files_importing">正在導入儲存資料…</string>
<string name="save_files_exporting">正在導出儲存資料…</string>
<string name="save_file_imported_success">已成功導入</string>
<string name="save_file_invalid_zip_structure">無效的儲存目錄結構</string>
<string name="save_file_invalid_zip_structure_description">首個子資料夾名稱必須為遊戲 ID</string>
<string name="save_file_invalid_zip_structure_description">首個子資料夾名稱必須為遊戲ID</string>
<string name="install_firmware">安裝韌體</string>
<string name="install_firmware_description">韌體必須為 ZIP 壓縮檔,將會用於部分遊戲的啟動</string>
<string name="install_firmware_description">韌體必須為ZIP壓縮檔,將會用於部分遊戲的啟動</string>
<string name="firmware_installing">正在安裝韌體</string>
<string name="firmware_installed_failure">韌體安裝失敗</string>
<string name="firmware_installed_failure_description">請確保韌體 nca 檔案位於 zip 壓縮檔的根目錄,然後再試一次。</string>
<string name="firmware_installed_failure_description">請確保韌體nca檔案位於zip壓縮檔的根目錄後再試一次</string>
<string name="firmware_uninstalled_failure">韌體解除安裝失敗</string>
<string name="share_log">分享偵錯記錄</string>
<string name="share_log_description">分享 Eden 的記錄檔以便對相關問題進行偵錯</string>
<string name="share_log_description">分享Eden的記錄檔以便對相關問題進行偵錯</string>
<string name="share_log_missing">找不到日誌檔案</string>
<string name="share_gpu_log">分享 GPU 日誌</string>
<string name="share_gpu_log_description">分享 Eden 的 GPU 日誌以對圖形問題進行偵錯</string>
<string name="share_gpu_log_missing">找不到 GPU 日誌檔案</string>
<string name="share_gpu_log">分享GPU日誌</string>
<string name="share_gpu_log_description">分享Eden的GPU日誌以對圖形問題進行偵錯</string>
<string name="share_gpu_log_missing">找不到GPU日誌檔案</string>
<string name="install_game_content">安裝遊戲內容</string>
<string name="install_game_content_description">安裝遊戲更新或 DLC</string>
<string name="install_game_content_description">安裝遊戲更新或DLC</string>
<string name="installing_game_content">正在安裝內容…</string>
<string name="install_game_content_failure">安裝檔案至 NAND 時發生錯誤</string>
<string name="install_game_content_failure_description">請確保內容有效並且 prod.keys 檔案已安裝</string>
<string name="install_game_content_failure">安裝檔案至NAND時發生錯誤</string>
<string name="install_game_content_failure_description">請確保內容有效並且prod.keys檔案已安裝</string>
<string name="install_game_content_failure_base">為避免產生衝突,無法直接安裝遊戲本體</string>
<string name="install_game_content_failed_count">%1$d 安裝錯誤</string>
<string name="install_game_content_success">遊戲內容已成功安裝</string>
@@ -406,8 +415,8 @@
<string name="install_game_content_success_overwrite">%1$d 覆寫成功</string>
<string name="install_game_content_help_link">https://yuzu-mirror.github.io/help/quickstart/#dumping-installed-updates</string>
<string name="custom_driver_not_supported">您的裝置不支援自訂驅動程式</string>
<string name="custom_driver_not_supported_description">此裝置不支援注入自訂驅動程式。\n請以後再來查看是否已新增支援!</string>
<string name="manage_yuzu_data">管理 Eden 資料</string>
<string name="custom_driver_not_supported_description">此裝置不支援注入自訂驅動程式\n請以後再來查看是否已新增支援!</string>
<string name="manage_yuzu_data">管理Eden資料</string>
<string name="manage_yuzu_data_description">安裝韌體、金鑰,導入/導出使用者資料及安裝其它項目!</string>
<string name="game_folders">遊戲資料夾</string>
<string name="deep_scan">深度掃描</string>
@@ -424,7 +433,7 @@
<string name="verify_installed_content">驗證已安裝內容的完整性</string>
<string name="verify_installed_content_description">檢查所有已安裝的內容是否有損壞</string>
<string name="keys_missing">缺少 prod.keys</string>
<string name="keys_missing">缺少prod.keys</string>
<string name="keys_missing_description">無法解密韌體和零售遊戲</string>
<string name="keys_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys</string>
@@ -437,8 +446,8 @@
<string name="keys_failed">金鑰安裝失敗</string>
<string name="keys_install_success">金鑰安裝成功</string>
<string name="error_keys_copy_failed">一個或多個金鑰安裝失敗</string>
<string name="error_keys_invalid_filename">請確保金鑰檔案具有.keys副檔名後重試。</string>
<string name="error_keys_failed_init">金鑰初始化失敗。請檢查您的轉儲工具是否為最新版本並重新轉儲金鑰。</string>
<string name="error_keys_invalid_filename">請確保金鑰檔案具有.keys副檔名後重試</string>
<string name="error_keys_failed_init">金鑰初始化失敗,請檢查您的轉儲工具是否為最新版本並重新轉儲金鑰</string>
<!-- Applet launcher strings -->
<string name="qlaunch_applet">Qlaunch</string>
@@ -450,48 +459,48 @@
<string name="applets_error_description"><![CDATA[請確定您的<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys\">prod.keys</a>檔案和<a href=\"https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware\">韌體</a>已安裝並重試]]></string>
<string name="album_applet">相簿</string>
<string name="album_applet_description">使用系統相片檢視器查看儲存在使用者螢幕截圖資料夾中的影像</string>
<string name="mii_edit_applet">Mii 編輯</string>
<string name="mii_edit_applet_description">使用系統編輯器來檢視並編輯 Mii</string>
<string name="mii_edit_applet">Mii編輯</string>
<string name="mii_edit_applet_description">使用系統編輯器來檢視並編輯Mii</string>
<string name="cabinet_applet">Cabinet</string>
<string name="cabinet_applet_description">編輯、刪除儲存在 amiibo 上的資料</string>
<string name="cabinet_launcher">Cabinet 啟動器</string>
<string name="cabinet_applet_description">編輯、刪除儲存在amiibo上的資料</string>
<string name="cabinet_launcher">Cabinet啟動器</string>
<string name="cabinet_nickname_and_owner">暱稱和擁有者設定</string>
<string name="cabinet_game_data_eraser">刪除遊戲資料</string>
<string name="cabinet_restorer">還原程式</string>
<string name="cabinet_formatter">格式化程式</string>
<!-- About screen strings -->
<string name="gaia_is_not_real">Gaia 不存在</string>
<string name="gaia_is_not_real">Gaia不存在</string>
<string name="copied_to_clipboard">已複製到剪貼簿</string>
<string name="about_app_description">一個開放原始碼的 Switch 模擬器</string>
<string name="about_app_description">一個開放原始碼的Switch模擬器</string>
<string name="contributors">參與者</string>
<string name="contributors_description">這些人讓 Eden Android 版成為可能</string>
<string name="licenses_description">這些專案使 Eden Android 版成為可能</string>
<string name="contributors_description">這些人讓Eden Android版成為可能</string>
<string name="licenses_description">這些專案使Eden Android版成為可能</string>
<string name="build">組建版本</string>
<string name="user_data">使用者資料</string>
<string name="user_data_description">導入/導出所有應用程式資料。\n\n導入使用者資料時,現有的使用者資料將被取代!\n\n直接從 Citron 導入使用者資料可能會出現問題,建議手動導入所有所需資料。</string>
<string name="user_data_description">導入/導出所有應用程式資料\n\n導入使用者資料時,現有的使用者資料將被取代!\n\n直接從 Citron 導入使用者資料可能會出現問題,建議手動導入所有所需資料</string>
<string name="exporting_user_data">正在導出使用者資料…</string>
<string name="importing_user_data">正在導入使用者資料…</string>
<string name="invalid_yuzu_backup">無效的 Eden 備份</string>
<string name="invalid_yuzu_backup">無效的Eden備份</string>
<string name="user_data_export_success">使用者資料導出成功</string>
<string name="user_data_import_success">使用者資料導入成功</string>
<string name="user_data_export_cancelled">導出已取消</string>
<string name="user_data_import_failed_description">請確保使用者資料夾位於 zip 壓縮檔的根目錄,並在 config/config.ini 路徑中包含組態檔案,並再試一次</string>
<string name="user_data_import_failed_description">請確保使用者資料夾位於zip壓縮檔的根目錄,並在 config/config.ini 路徑中包含組態檔案後重試</string>
<!-- General settings strings -->
<string name="frame_limit_enable">限制模擬速度</string>
<string name="frame_limit_enable_description">將模擬速度限制在標準速度的指定百分比</string>
<string name="frame_limit_slider">限制速度百分比</string>
<string name="frame_limit_slider_description">指定模擬速度的百分比。100% 為標準速度,更高或更低的值將會減少或增加速度限制</string>
<string name="frame_limit_slider_description">指定模擬速度的百分比,100%為標準速度,更高或更低的值將會減少或增加速度限制</string>
<string name="turbo_speed_limit">加速模式</string>
<string name="turbo_speed_limit_description">當開啟加速模式時,模擬器將以此速度執行</string>
<string name="slow_speed_limit">慢速模式</string>
<string name="slow_speed_limit_description">當慢速模式開啟時,模擬器將會以此速度執行</string>
<string name="cpu_backend">CPU 後端</string>
<string name="cpu_accuracy">CPU 準確度</string>
<string name="cpu_backend">CPU後端</string>
<string name="cpu_accuracy">CPU準確度</string>
<string name="value_with_units">%1$s%2$s</string>
<string name="program_args">Homebrew 參數</string>
<string name="program_args_description">在啟動時傳遞給 Homebrew 的命令列參數(例如:-noglsl)</string>
<string name="program_args">Homebrew參數</string>
<string name="program_args_description">在啟動時傳遞給Homebrew的命令列參數(例如:-noglsl)</string>
<!-- System settings strings -->
<string name="device_name">裝置名稱</string>
@@ -499,26 +508,26 @@
<string name="use_docked_mode_description">提高解析度,降低效能。停用後將會使用手提模式,會降低解析度並提高效能</string>
<string name="emulated_region">模擬區域</string>
<string name="emulated_language">模擬語言</string>
<string name="select_rtc_date">選擇 RTC 日期</string>
<string name="select_rtc_time">選擇 RTC 時間</string>
<string name="use_custom_rtc">自訂 RTC</string>
<string name="select_rtc_date">選擇RTC日期</string>
<string name="select_rtc_time">選擇RTC時間</string>
<string name="use_custom_rtc">自訂RTC</string>
<string name="use_custom_rtc_description">允許您設定與您的目前系統時間相互獨立的自訂時間</string>
<string name="set_custom_rtc">設定自訂 RTC</string>
<string name="set_custom_rtc">設定自訂RTC</string>
<!-- CPU -->
<string name="fast_cpu_time">CPU 時脈</string>
<string name="fast_cpu_time_description">提高模擬 CPU 回報的時脈,可以減少某些 FPS 限制。較弱的 CPU 可能會出現效能下降的情況,部分遊戲可能會出現異常</string>
<string name="fast_cpu_time">CPU時脈</string>
<string name="fast_cpu_time_description">提高模擬CPU回報的時脈,可以減少某些FPS限制。較弱的CPU可能會出現效能下降的情況,部分遊戲可能會出現異常</string>
<string name="custom_cpu_ticks">自訂CPU時脈</string>
<string name="custom_cpu_ticks_description">自訂CPU時脈。更高的值可能提高效能,但也可能導致遊戲卡死。建議範圍為77-21000。</string>
<string name="custom_cpu_ticks_description">自訂CPU時脈,更高的值可能提高效能,但也可能導致遊戲卡死。建議範圍為77-21000</string>
<string name="cpu_ticks">時脈</string>
<string name="memory_layout">記憶體佈局</string>
<string name="memory_layout_description">(實驗性)更改模擬記憶體佈局。此設定不會提高效能,但可能有助於使用模組來提高解析度的遊戲的載入。不要在 RAM 為 8GB 或更少的手機上使用。若遊戲崩潰請將進階設定裡偵錯選項中的CPU後端改為 Dynarmic (JIT)</string>
<string name="memory_layout">記憶體布局</string>
<string name="memory_layout_description">(實驗性)更改模擬記憶體布局,此設定不會提高效能,但可能有助於使用模組來提高解析度的遊戲的載入。不要在RAM為8GB或更少的手機上使用。若遊戲崩潰請將進階設定裡偵錯選項中的CPU後端改為Dynarmic (JIT)</string>
<string name="generate">生成</string>
<!-- Network settings strings -->
<string name="web_token">網路令牌</string>
<string name="web_token_description">用於建立公開大廳的網路令牌。由48個小寫字母a-z組成</string>
<string name="web_token_description">用於建立公開大廳的網路令牌,由48個小寫字母a-z組成</string>
<string name="web_username">網路使用者名稱</string>
<string name="web_username_description">多人遊戲房間中顯示的使用者名稱。必須為4-20個字元,僅能使用英文字母、數字、句點、破折號、底線和空格(標點符號須為英文格式)</string>
<string name="network">網路</string>
@@ -527,19 +536,19 @@
<string name="renderer_resolution">解析度 (手提/底座)</string>
<string name="renderer_vsync">垂直同步</string>
<string name="renderer_scaling_filter">視窗自適應濾波器</string>
<string name="fsr_sharpness">FSR/SGSR 銳化度</string>
<string name="fsr_sharpness_description">使用 FSR/SGSR 時圖片的銳化程度</string>
<string name="fsr_sharpness">FSR/SGSR銳化度</string>
<string name="fsr_sharpness_description">使用FSR/SGSR時圖片的銳化程度</string>
<string name="renderer_anti_aliasing">抗鋸齒</string>
<string name="advanced">進階</string>
<string name="renderer_accuracy">GPU 模式</string>
<string name="renderer_accuracy_description">設定 GPU 模擬的準確度。大多數遊戲在設定為快速時即可正常渲染,但有些需要渲染粒子的遊戲仍需設為準確來避免圖形錯誤</string>
<string name="dma_accuracy">DMA 準確度</string>
<string name="dma_accuracy_description">控制 DMA 準確度。將準確度設為穩定可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為預設</string>
<string name="renderer_accuracy">GPU模式</string>
<string name="renderer_accuracy_description">設定GPU模擬的準確度,大多數遊戲在設定為快速時即可正常渲染,但有些需要渲染粒子的遊戲仍需設為準確來避免圖形錯誤</string>
<string name="dma_accuracy">DMA準確度</string>
<string name="dma_accuracy_description">控制DMA準確度,將準確度設為穩定可以修復某些遊戲中的問題,但在某些情況下也可能影響效能。如果不確定,請保留為預設</string>
<string name="gpu_fence_behavior">GPU 同步柵欄模式</string>
<string name="gpu_fence_behavior_description">控制 GPU 同步柵欄模式。即時是速度最快的選項,但可能會導致一些問題。使用平衡可以提供更好的相容性並修復某些遊戲中的錯誤。準確則是在犧牲部分效能的情況下進一步提升相容性。嚴格是最慢的選項,但可以修復那些對同步要求更嚴格的遊戲中的問題。預設則會依照 GPU 準確度設定</string>
<string name="gpu_fence_behavior_description">控制 GPU 同步柵欄模式,即時是速度最快的選項,但可能會導致一些問題;使用平衡可以提供更好的相容性並修復某些遊戲中的錯誤;準確則是在犧牲部分效能的情況下進一步提升相容性;嚴格是最慢的選項,但可以修復那些對同步要求更嚴格的遊戲中的問題;預設則會依照 GPU 準確度設定</string>
<string name="anisotropic_filtering">各向異性過濾</string>
<string name="anisotropic_filtering_description">改善斜角檢視時的紋理品質</string>
<string name="vram_usage_mode">VRAM使用模式</string>
@@ -548,55 +557,51 @@
<string name="accelerate_astc_description">選擇ASTC壓縮紋理的解碼方式:CPU(慢速、穩定)、GPU(快速、推薦)或CPU非同步(無卡頓,可能導致問題)</string>
<string name="sync_memory_operations">同步記憶體操作</string>
<string name="sync_memory_operations_description">確保計算和記憶體操作之間的資料一致性。 此選項應能修復某些遊戲中的問題,但在某些情況下可能會降低效能。 使用Unreal Engine 4的遊戲似乎受影響最大</string>
<string name="sync_memory_operations_description">確保計算和記憶體操作之間的資料一致性,此選項應能修復某些遊戲中的問題,但在某些情況下可能會降低效能。使用Unreal Engine 4的遊戲似乎受影響最大</string>
<string name="use_disk_shader_cache">磁碟著色器快取</string>
<string name="use_disk_shader_cache_description">將產生的著色器快取儲存至硬碟以減少中斷</string>
<string name="renderer_force_max_clock">強制使用最大時脈 (僅限Adreno)</string>
<string name="renderer_force_max_clock_description">強制 GPU 以可能的最大時脈執行 (熱溫限制仍會被套用)</string>
<string name="renderer_asynchronous_gpu_emulation">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_description">犧牲效能,以改善部分遊戲的轉譯準確度</string>
<string name="renderer_reactive_flushing_description">犧牲效能以改善部分遊戲的轉譯準確度</string>
<string name="enable_buffer_history">啟用緩衝區歷史</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="enable_buffer_history_description">允許存取先前的緩衝區狀態,此選項可能會改善部分遊戲的渲染品質與效能穩定性</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>
<string name="hacks">修改</string>
<string name="fast_gpu_time">GPU 時脈</string>
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
<string name="fast_gpu_time">GPU時脈</string>
<string name="fast_gpu_time_description">讓遊戲誤以為GPU工作能更快完成,避免遊戲為了配合Switch的時脈而降低解析度與渲染距離</string>
<string name="skip_cpu_inner_invalidation">跳過CPU內部失效處理</string>
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些CPU端快取的失效處理,減少CPU使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
<string name="fix_bloom_effects">修正光暈特效</string>
<string name="fix_bloom_effects_description">在 薩爾達傳說:織夢島 和 薩爾達傳說:智慧的再現 中 減少光暈模糊的問題並移除 橫衝直撞:狂飆樂園重製版 中的光暈效果 (Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
<string name="emulate_bgr565">模擬 BGR565</string>
<string name="emulate_bgr565_description">修正遊戲中出現的顏色反轉、圖形異常或陰影異常</string>
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
<string name="emulate_bgr565">模擬BGR565</string>
<string name="emulate_bgr565_description">修正遊戲中出現的色彩反轉、圖形異常或陰影異常</string>
<string name="rescale_hack">啟用舊版重新縮放處理</string>
<string name="rescale_hack_description">透過快速重新縮放處理來啟用遊戲重新縮放設定階段的舊版處理方式</string>
<string name="renderer_asynchronous_shaders">使用非同步著色器</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="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_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 Stream大小</string>
<string name="gpu_unswizzle_stream_size_description">設定每個影格處理大型紋理Unswizzling的資料上限,數值越高載入紋理的速度越快,但會增加畫面延遲;數值較低則能降低 GPU 負載,不過有可能導致至紋理載入不完全甚至突然出現</string>
<string name="gpu_unswizzle_chunk_size">GPU Unswizzle Chunk大小</string>
<string name="gpu_unswizzle_chunk_size_description">設定 3D 紋理每批次處理的深度切片數量,增加此數值可提升規格較佳GPU的處理效率,但在較低規格的硬體上可能導致卡頓或驅動程式逾時</string>
<string name="gpu_unswizzle_default_button">預設</string>
<string name="extensions">擴充功能</string>
<string name="dyna_state">擴展動態狀態</string>
<string name="dyna_state_description">控制擴展動態狀態中可使用的功能數量。較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數。</string>
<string name="dyna_state_description">控制擴展動態狀態中可使用的功能數量,較高的數值可根據驅動程式支援的動態狀態減少管線編譯的次數</string>
<string name="disabled">停用</string>
<string name="vertex_input_dynamic_state">頂點輸入動態狀態</string>
<string name="vertex_input_dynamic_state_description">啟用此功能可提供更彈性的頂點輸入處理方式,並可能減少頂點/緩衝區的管線編譯時間</string>
@@ -618,43 +623,43 @@
<string name="cpu">CPU</string>
<string name="clocks">時脈</string>
<string name="use_auto_stub">使用自動存根</string>
<string name="use_auto_stub_description">自動補上缺少的服務和功能。可提高相容性但可能導致當機和穩定性問題。</string>
<string name="use_auto_stub_description">自動補上缺少的服務和功能,可提高相容性但可能導致當機和穩定性問題</string>
<string name="gpu">GPU</string>
<string name="renderer_api">API</string>
<string name="renderer_debug">圖形偵錯</string>
<string name="renderer_debug_description">將圖形 API 設為慢速偵錯模式</string>
<string name="patch_old_qcom_drivers">BCn 區塊壓縮紋理修補</string>
<string name="patch_old_qcom_drivers_description">覆寫 Adreno GPU 的 BCn 紋理格式自動偵測。通常會根據 Android 版本自動偵測(會在API 28 以上自動啟用)</string>
<string name="renderer_debug_description">將圖形API設為慢速偵錯模式</string>
<string name="patch_old_qcom_drivers">BCn區塊壓縮紋理修補</string>
<string name="patch_old_qcom_drivers_description">覆寫Adreno GPU的BCn紋理格式自動偵測。通常會根據Android版本自動偵測(會在API 28以上的裝置自動啟用)</string>
<string name="fastmem">Fastmem</string>
<string name="log">日誌</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">將日誌檔的最大檔案限制從 100MB 提高到 1GB</string>
<string name="extended_logging_description">將日誌檔的最大檔案限制從100MB提高到1GB</string>
<string name="log_filter">日誌過濾器</string>
<string name="log_filter_description">控制 Eden 日誌的紀錄類別。例如: *:Info Service.LM:Debug</string>
<!-- 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_description">GPU 日誌的詳細層級 (越高日誌越詳細,不過會更容易過熱)</string>
<string name="gpu_log_vulkan_calls">記錄 Vulkan API 呼叫</string>
<string name="gpu_log_vulkan_calls_description">在環形緩衝區中記錄所有 Vulkan API 呼叫</string>
<string name="gpu_log_shader_dumps">傾印 SPIR-V 著色器</string>
<string name="gpu_log_shader_dumps_description">將重新編譯後的 SPIR-V 二進位檔案 (.spv) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 spirv-dis/spirv-cross/spirv-val 進行檢查</string>
<string name="gpu_log_level_description">GPU日誌的詳細層級(越高日誌越詳細,不過會更容易過熱)</string>
<string name="gpu_log_vulkan_calls">記錄Vulkan API呼叫</string>
<string name="gpu_log_vulkan_calls_description">在環形緩衝區中記錄所有Vulkan API呼叫</string>
<string name="gpu_log_shader_dumps">傾印SPIR-V著色器</string>
<string name="gpu_log_shader_dumps_description">將重新編譯後的SPIR-V二進位檔案(.spv)儲存至Eden資料夾裡的dump資料夾中。可使用 spirv-dis/spirv-cross/spirv-val 進行檢查</string>
<string name="dump_guest_shaders">傾印客體(Maxwell)著色器</string>
<string name="dump_guest_shaders_description">將 Maxwell 客體著色器位元組碼檔案 (.ash) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 nvdisasm 進行檢查</string>
<string name="dump_macros">傾印 Maxwell 巨集</string>
<string name="dump_macros_description">將 Maxwell 巨集程式檔案 (.macro) 儲存至 Eden 資料夾裡的 dump 資料夾中。可使用 envydis 進行檢查</string>
<string name="gpu_log_memory_tracking">追蹤 GPU 記憶體</string>
<string name="gpu_log_memory_tracking_description">監控 GPU 記憶體的分配和釋放</string>
<string name="dump_guest_shaders_description">將Maxwell客體著色器位元組碼檔案(.ash)儲存至Eden資料夾裡的dump資料夾中。可使用 nvdisasm 進行檢查</string>
<string name="dump_macros">傾印Maxwell巨集</string>
<string name="dump_macros_description">將Maxwell巨集程式檔案(.macro)儲存至Eden資料夾裡的dump資料夾中。可使用 envydis 進行檢查</string>
<string name="gpu_log_memory_tracking">追蹤GPU記憶體</string>
<string name="gpu_log_memory_tracking_description">監控GPU記憶體的分配和釋放</string>
<string name="gpu_log_driver_debug">驅動程式偵錯資料</string>
<string name="gpu_log_driver_debug_description">擷取驅動程式的特定偵錯資料(例如 Turnip breadcrumbs)</string>
<string name="gpu_log_ring_buffer_size">環形緩衝區大小</string>
<string name="gpu_log_ring_buffer_size_description">追蹤的近期 Vulkan 呼叫數量(預設為 512 )</string>
<string name="gpu_log_ring_buffer_size_hint">64 至 4096 個項目</string>
<string name="gpu_log_ring_buffer_size_description">追蹤的近期Vulkan呼叫數量(預設為512)</string>
<string name="gpu_log_ring_buffer_size_hint">64至4096個項目</string>
<string name="general">一般</string>
@@ -678,17 +683,17 @@
<string name="left_stick">左搖桿</string>
<string name="control_stick">控制搖桿</string>
<string name="right_stick">右搖桿</string>
<string name="c_stick">C 搖桿</string>
<string name="c_stick">C搖桿</string>
<string name="pressed">按壓</string>
<string name="range">靈敏度</string>
<string name="deadzone">無感帶</string>
<string name="modifier">用按鈕、按鍵來模擬搖桿</string>
<string name="modifier_range">修改按鈕模擬左/右搖桿的值,視遊戲不同而有所差異\n(模擬左搖桿時,若將此數值設為50,則按下按鈕時遊戲裡的人物可能只會走動而不是奔跑;模擬右搖桿時所使用的值則是會影響到轉視角的速度,數值越高代表使用的模擬值越大)</string>
<string name="triggers">肩部按鍵</string>
<string name="button_sl_left">左 SL</string>
<string name="button_sr_left">左 SR</string>
<string name="button_sl_right">右 SL</string>
<string name="button_sr_right">右 SR</string>
<string name="button_sl_left">左SL</string>
<string name="button_sr_left">左SR</string>
<string name="button_sl_right">右SL</string>
<string name="button_sr_right">右SR</string>
<string name="invalid">無效</string>
<string name="not_set">無</string>
<string name="unknown">未知</string>
@@ -703,12 +708,12 @@
<string name="auto_map_description">選擇一個控制器以嘗試自動配對按鈕、搖桿</string>
<string name="attempted_auto_map">嘗試為 %1$s 自動配對</string>
<string name="controller_type">控制器類型</string>
<string name="pro_controller">Pro 手把</string>
<string name="pro_controller">Pro手把</string>
<string name="handheld">掌機模式</string>
<string name="dual_joycons">雙 Joycon 手把</string>
<string name="left_joycon">左 Joycon 手把</string>
<string name="right_joycon">右 Joycon 手把</string>
<string name="gamecube_controller">GameCube 手把</string>
<string name="dual_joycons">雙Joycon手把</string>
<string name="left_joycon">左Joycon手把</string>
<string name="right_joycon">右Joycon手把</string>
<string name="gamecube_controller">GameCube手把</string>
<string name="invert_axis">方向反轉</string>
<string name="invert_button">反轉按鈕</string>
<string name="toggle_button">切換按鍵</string>
@@ -801,7 +806,7 @@
<string name="recommended_driver">推薦驅動程式:</string>
<string name="gpu_model">GPU型號</string>
<string name="unsupported_gpu">不支援的GPU</string>
<string name="unsupported_gpu_warning">您的GPU不支援驅動程式注入。不建議嘗試設定自訂驅動程式。</string>
<string name="unsupported_gpu_warning">您的GPU不支援驅動程式注入,不建議嘗試設定自訂驅動程式</string>
<!-- Preferences Screen -->
<string name="preferences_settings">設定</string>
@@ -1020,9 +1025,40 @@
<string name="memory_6gb">6GB (不穩定)</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 -->
<string name="temperature_celsius">攝氏度</string>
<string name="temperature_fahrenheit">華氏度</string>
<string name="temperature_celsius">攝氏</string>
<string name="temperature_fahrenheit">華氏</string>
<!-- Memory Sizes -->
<string name="memory_byte_shorthand">B</string>
@@ -1035,6 +1071,8 @@
<string name="renderer_none">無</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_low">效能</string>
<string name="renderer_accuracy_high">準確</string>
<!-- DMA Accuracy -->
@@ -558,7 +558,6 @@
<item>@string/gpu_fence_behavior_immediate</item>
<item>@string/gpu_fence_behavior_balanced</item>
<item>@string/gpu_fence_behavior_accurate</item>
<item>@string/gpu_fence_behavior_strict</item>
</string-array>
<integer-array name="gpuFenceBehaviorValues">
<item>0</item>
@@ -580,14 +580,10 @@
<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_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_description">Improves rendering accuracy in some games at the cost of performance.</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_gpu_buffer_readback">Enable GPU Buffer Readback</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_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>
@@ -597,6 +593,10 @@
<string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string>
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
<string name="nce_runtime_nro_patch">Patch Runtime NROs for NCE</string>
<string name="nce_runtime_nro_patch_description">Temporary. Fix Biomutant boot. May impact performance. Improvement in progress.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="emulate_bgr565">Emulate BGR565</string>
@@ -1138,7 +1138,6 @@
<string name="gpu_fence_behavior_immediate">Immediate</string>
<string name="gpu_fence_behavior_balanced">Balanced</string>
<string name="gpu_fence_behavior_accurate">Accurate</string>
<string name="gpu_fence_behavior_strict">Strict</string>
<!-- ASTC Decoding Method Choices -->
<string name="accelerate_astc_cpu" translatable="false">CPU</string>
+6 -2
View File
@@ -76,7 +76,6 @@ add_library(
logging.h
lz4_compression.cpp
lz4_compression.h
make_unique_for_overwrite.h
math_util.h
memory_detect.cpp
memory_detect.h
@@ -110,7 +109,6 @@ add_library(
socket_types.h
sparse_large_vector.cpp
sparse_large_vector.h
spin_lock.h
stb.cpp
stb.h
steady_clock.cpp
@@ -139,6 +137,8 @@ add_library(
uuid.cpp
uuid.h
vector_math.h
zbic_compression.cpp
zbic_compression.h
zstd_compression.cpp
zstd_compression.h
fs/ryujinx_compat.h fs/ryujinx_compat.cpp
@@ -149,6 +149,10 @@ add_library(
net/net.h net/net.cpp
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)
target_sources(common PRIVATE windows/timer_resolution.cpp
windows/timer_resolution.h)
+4 -3
View File
@@ -244,7 +244,8 @@ WallClock::WallClock(bool invariant_, u64 rdtsc_frequency_) noexcept
, ns_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(NsRatio::den, rdtsc_frequency_) : 0}
, us_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(UsRatio::den, rdtsc_frequency_) : 0}
, ms_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(MsRatio::den, rdtsc_frequency_) : 0}
, rdtsc_ns_factor{invariant_ ? GetFixedPoint64Factor(rdtsc_frequency_, NsRatio::den) : 1}
, rdtsc_ns_integer{invariant_ ? 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}
, gputick_rdtsc_factor{invariant_ ? GetFixedPoint64Factor(GPUTickFreq, rdtsc_frequency_) : 0}
, invariant{invariant_}
@@ -291,7 +292,7 @@ bool WallClock::IsNative() const {
}
u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
return invariant ? MultiplyHigh(ns.count(), rdtsc_ns_factor) : ns.count();
return ns.count() * rdtsc_ns_integer + MultiplyHigh(ns.count(), rdtsc_ns_factor);
}
#elif defined(HAS_NCE)
namespace {
@@ -416,7 +417,7 @@ u64 WallClock::NsToTicks(std::chrono::nanoseconds ns) const {
const WallClock g_wall_clock = [] {
#if defined(ARCHITECTURE_x86_64)
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)
return WallClock(false, 1);
#else
+1
View File
@@ -96,6 +96,7 @@ public:
u64 ns_rdtsc_factor;
u64 us_rdtsc_factor;
u64 ms_rdtsc_factor;
u64 rdtsc_ns_integer;
u64 rdtsc_ns_factor;
u64 cntpct_rdtsc_factor;
u64 gputick_rdtsc_factor;
+18 -20
View File
@@ -17,35 +17,33 @@
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) {
#ifdef _WIN32
LPSTR err_str;
DWORD res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr, e, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPSTR>(&err_str), 1, nullptr);
if (!res) {
return "(FormatMessageA failed to format error)";
LPSTR(&err_str), 1, nullptr);
if (res) {
std::string ret(err_str);
LocalFree(err_str);
return ret;
}
std::string ret(err_str);
LocalFree(err_str);
return ret;
return "(FormatMessageA failed to format error)";
#else
char err_str[255];
#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.
return HandleStrerrorR(strerror_r(e, err_str, sizeof(err_str)), err_str);
#endif // _WIN32
}
+66 -13
View File
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <cctype>
#include <iostream>
#include <sstream>
#include "common/container/unordered_map.h"
@@ -480,28 +481,80 @@ std::string SanitizePath(std::string_view path_, DirectorySeparator directory_se
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
path.end());
const bool absolute = !path.empty() && path[0] == type2;
std::vector<std::string_view> parts;
std::string root;
std::string_view components{path};
bool drive_relative = false;
for (const auto part : SplitPathComponents(path))
{
if (part.empty() || part == ".")
continue;
if (part == ".." && !parts.empty() && parts.back() != "..")
parts.pop_back();
else if (part != "..") parts.push_back(part);
#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);
}
std::string resolved = absolute ? std::string(1, type2) : std::string{};
for (std::size_t i = 0; i < parts.size(); ++i)
{
if (i != 0)
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;
for (std::size_t i = 0; i < path_parts.size(); ++i) {
const auto part = path_parts[i];
if (i < root_component_count) {
parts.push_back(part);
} else if (part.empty() || part == ".") {
continue;
} else if (part == "..") {
if (parts.size() > root_component_count) {
parts.pop_back();
}
} else {
parts.push_back(part);
}
}
const std::size_t root_length = root.size();
std::string resolved = std::move(root);
for (std::size_t i = 0; i < parts.size(); ++i) {
if (i != 0 || (!resolved.empty() && resolved.back() != type2 && !drive_relative))
resolved += type2;
resolved.append(parts[i].data(), parts[i].size());
}
path = std::move(resolved);
if (!path.empty() && path.size() == root_length) {
return path;
}
return std::string(RemoveTrailingSlash(path));
}
+3 -2
View File
@@ -347,8 +347,9 @@ enum class DirectorySeparator {
// 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);
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
// Normalizes directory separators, removes duplicate and non-root trailing separators, and resolves
// '.' and '..' components without traversing above the path root. Windows drive and UNC roots are
// preserved.
[[nodiscard]] std::string SanitizePath(
std::string_view path,
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
-27
View File
@@ -1,27 +0,0 @@
// 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
+3 -3
View File
@@ -96,15 +96,15 @@ struct PageTable {
}
/// Write page info atomically
constexpr void Store(bool marked, PageType type, u16 block, uintptr_t pointer) noexcept {
inline void Store(bool marked, PageType type, u16 block, uintptr_t pointer) noexcept {
data_raw.store(std::bit_cast<u64>(Data{marked, type, block, pointer}));
}
constexpr void MarkRasterizerCached() noexcept {
inline void MarkRasterizerCached() noexcept {
data_raw.fetch_or(0b111);
}
constexpr void MarkDebug(u64 ptr, u16 block) noexcept {
inline void MarkDebug(u64 ptr, u16 block) noexcept {
Store(true, PageType::DebugMemory, block, ptr);
}
+6 -6
View File
@@ -8,8 +8,7 @@
#include <iterator>
#include <cstring>
#include "common/make_unique_for_overwrite.h"
#include <memory>
namespace Common {
@@ -38,8 +37,9 @@ public:
ScratchBuffer() = default;
explicit ScratchBuffer(size_type initial_capacity)
: last_requested_size{initial_capacity}, buffer_capacity{initial_capacity},
buffer{Common::make_unique_for_overwrite<T[]>(initial_capacity)} {}
: last_requested_size{initial_capacity}
, buffer_capacity{initial_capacity}
, buffer{std::make_unique_for_overwrite<T[]>(initial_capacity)} {}
~ScratchBuffer() = default;
ScratchBuffer(const ScratchBuffer&) = delete;
@@ -64,7 +64,7 @@ public:
/// The previously held data will remain intact.
void resize(size_type size) {
if (size > buffer_capacity) {
auto new_buffer = Common::make_unique_for_overwrite<T[]>(size);
auto new_buffer = std::make_unique_for_overwrite<T[]>(size);
std::memcpy(new_buffer.get(), buffer.get(), buffer_capacity * sizeof(T));
buffer = std::move(new_buffer);
buffer_capacity = size;
@@ -77,7 +77,7 @@ public:
void resize_destructive(size_type size) {
if (size > buffer_capacity) {
buffer_capacity = size;
buffer = Common::make_unique_for_overwrite<T[]>(buffer_capacity);
buffer = std::make_unique_for_overwrite<T[]>(buffer_capacity);
}
last_requested_size = size;
}
-4
View File
@@ -178,10 +178,6 @@ bool IsGPUFenceBehaviorAccurate() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Accurate;
}
bool IsGPUFenceBehaviorStrict() {
return values.gpu_fence_behavior.GetValue() == GpuFenceBehavior::Strict;
}
bool IsFastmemEnabled() {
if (values.cpu_accuracy.GetValue() == Settings::CpuAccuracy::Debugging)
return bool(values.cpuopt_fastmem);
+8 -17
View File
@@ -472,13 +472,8 @@ struct Values {
SwitchableSetting<bool> frame_gen_dump_flow{linkage, false, "frame_gen_dump_flow",
Category::Renderer};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{linkage,
#ifdef __ANDROID__
false,
#else
true,
#endif
"use_asynchronous_gpu_emulation", Category::Renderer};
SwitchableSetting<bool> use_asynchronous_gpu_emulation{linkage, true, "use_asynchronous_gpu_emulation",
Category::Renderer};
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
SwitchableSetting<FullscreenMode, true> fullscreen_mode{linkage,
@@ -525,7 +520,7 @@ struct Values {
SwitchableSetting<GpuFenceBehavior, true> gpu_fence_behavior{linkage,
GpuFenceBehavior::Default,
GpuFenceBehavior::Default,
GpuFenceBehavior::Strict,
GpuFenceBehavior::Accurate,
"gpu_fence_behavior",
Category::RendererAdvanced,
Specialization::Default,
@@ -639,9 +634,13 @@ struct Values {
Specialization::Default,
true,
true};
SwitchableSetting<bool> nce_invalidation_gpu_readback{
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
SwitchableSetting<bool> nce_runtime_nro_patch{
linkage, false, "nce_runtime_nro_patch", Category::RendererHacks};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef __ANDROID__
false,
true,
#else
false,
#endif
@@ -655,13 +654,6 @@ struct Values {
SwitchableSetting<bool> rescale_hack{linkage, false, "rescale_hack",
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",
Category::RendererHacks};
@@ -979,7 +971,6 @@ bool IsDMALevelSafe();
bool IsGPUFenceBehaviorDefault();
bool IsGPUFenceBehaviorBalanced();
bool IsGPUFenceBehaviorAccurate();
bool IsGPUFenceBehaviorStrict();
bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit);
+2 -2
View File
@@ -137,7 +137,7 @@ ENUM(VramUsageMode, Conservative, Aggressive);
ENUM(RendererBackend, OpenGL_GLSL, Vulkan, Null, OpenGL_GLASM, OpenGL_SPIRV);
ENUM(GpuAccuracy, Low, High);
ENUM(DmaAccuracy, Default, Unsafe, Safe);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate, Strict);
ENUM(GpuFenceBehavior, Default, Immediate, Balanced, Accurate);
ENUM(CpuBackend, Dynarmic, Nce);
ENUM(CpuAccuracy, Auto, Accurate, Unsafe, Paranoid, Debugging);
ENUM(CpuClock, Normal, Boost, Overclock)
@@ -150,7 +150,7 @@ ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, Scale
ENUM(AntiAliasing, None, Fxaa, Smaa);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked);
ENUM(AppletMode, HLE, LLE);
ENUM(AppletMode, HLE, LLE, Disabled);
ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuClock, Normal, Boost, Overclock)
ENUM(GpuUnswizzleSize, VerySmall, Small, Normal, Large, VeryLarge)
+46 -15
View File
@@ -6,6 +6,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef _WIN32
#include <algorithm>
#include <windows.h>
#include <mutex>
#else
@@ -20,32 +21,36 @@ 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->ExceptionAddress);
u64 exception_addr = reinterpret_cast<u64>(info->ExceptionRecord->ExceptionInformation[1]);
if (code != EXCEPTION_ACCESS_VIOLATION) {
if (code != EXCEPTION_ACCESS_VIOLATION || info->ExceptionRecord->ExceptionInformation[0] == 1) {
// Not our problem
return EXCEPTION_CONTINUE_SEARCH;
}
u64 addr = 0, addr2 = 0;
for (auto region: vector_regions) {
auto addr_shifted = exception_addr >> HostPageBits;
if (region.first <= addr_shifted && addr_shifted <= region.second) {
addr = addr_shifted;
}
{
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_;
}
// 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) {
break;
}
}
}
@@ -77,8 +82,16 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
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 or is already committed (state {:#x})", addr, info.State);
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;
}
@@ -96,6 +109,21 @@ bool CommitVectorPage(uintptr_t addr, bool write) noexcept {
#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) {
@@ -108,7 +136,8 @@ void* AllocateMemoryPages(std::size_t size) noexcept {
void* base = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE);
if (base != nullptr) {
vector_regions.emplace_back(reinterpret_cast<u64>(base), reinterpret_cast<u64>(base) + size);
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); });
@@ -134,6 +163,8 @@ void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
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);
+35 -15
View File
@@ -28,17 +28,19 @@ constexpr u64 HostPageBits = 12;
constexpr u64 HostPageMask = ~(HostPageSize - 1);
bool CommitVectorPage(uintptr_t addr, bool write) noexcept;
#else
const u64 HostPageSize = sysconf(_SC_PAGESIZE);
const u64 HostPageBits = std::countr_zero(HostPageSize);
const u64 HostPageMask = ~(HostPageSize - 1);
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>
requires std::is_trivially_copyable_v<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;
@@ -79,8 +81,8 @@ public:
UNREACHABLE_MSG("Out of bounds RW access on SparseLargeVector @ {}", index);
}
if (!IsCommittedPage(index)) {
CommitPage(index);
if (!IsCommittedPage(index) && !CommitPage(index)) {
UNREACHABLE_MSG("Cannot access SparseLargeVector index {} with RW permission", index);
}
return base_ptr[index];
}
@@ -101,9 +103,8 @@ public:
LOG_CRITICAL(Common_Memory, "Out of bounds write on SparseLargeVector @ {}", index);
return;
}
if (!IsCommittedPage(index))
CommitPage(index);
base_ptr[index] = value;
if (IsCommittedPage(index) || CommitPage(index))
base_ptr[index] = value;
}
void ZeroRegion(std::size_t start, std::size_t end_) noexcept {
@@ -113,7 +114,7 @@ public:
const u64 end_page = AlignUp(base, HostPageSize);
const u64 first_size = (std::min)(end_page, end) - base;
if (IsCommittedPage(start / sizeof(T))) {
if (IsCommittedPage(start)) {
std::memset(reinterpret_cast<void*>(base), 0, first_size);
}
@@ -123,11 +124,16 @@ public:
base = end_page;
for (u64 page = base; page < end; page += HostPageSize) {
if (!IsCommittedPage((page - reinterpret_cast<u64>(base_ptr)) / sizeof(T))) {
auto index = (page - reinterpret_cast<u64>(base_ptr)) / sizeof(T);
if (!IsCommittedPage(index)) {
continue;
}
std::memset(reinterpret_cast<void*>(page), 0, (std::min)( HostPageSize, end - page));
if (end - page >= HostPageSize) {
DecommitPage(index);
} else {
std::memset(reinterpret_cast<void*>(page), 0, end - page);
}
}
}
@@ -170,16 +176,30 @@ private:
return (val >> (page & 63)) & 1;
}
constexpr void CommitPage(std::size_t index) noexcept {
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)
CommitVectorPage(page, true);
if (!CommitVectorPage(page, true)) {
return false;
}
#else
mprotect(reinterpret_cast<void*>(page), HostPageSize, PROT_READ | PROT_WRITE);
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{};
-50
View File
@@ -1,50 +0,0 @@
// 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
+2 -2
View File
@@ -208,9 +208,9 @@ UUID UUID::MakeRandomRFC4122V4() {
return uuid;
}
UUID UUID::MakeRFC4122V5(std::span<u8, 20> sha1) {
UUID UUID::MakeRFC4122V5(std::span<u8, 16> sha1) {
UUID uuid{};
std::memcpy(&uuid.uuid, sha1.data(), sizeof(UUID));
std::memcpy(&uuid.uuid, sha1.data(), sha1.size());
uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F);
uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF);
return uuid;
+1 -1
View File
@@ -104,7 +104,7 @@ struct UUID {
/// @returns A random UUID that is RFC 4122 Version 4 compliant.
[[nodiscard]] static UUID MakeRandomRFC4122V4();
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 20> sha1);
[[nodiscard]] static UUID MakeRFC4122V5(std::span<u8, 16> sha1);
friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default;
};
+46
View File
@@ -0,0 +1,46 @@
// 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
@@ -0,0 +1,15 @@
// 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
+7 -2
View File
@@ -23,6 +23,8 @@ add_library(core STATIC
core_timing.h
cpu_manager.cpp
cpu_manager.h
launch_params.cpp
launch_params.h
crypto/aes_util.cpp
crypto/aes_util.h
crypto/ctr_encryption_layer.cpp
@@ -796,6 +798,8 @@ add_library(core STATIC
hle/service/ns/application_manager_interface.h
hle/service/ns/application_version_interface.cpp
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.h
hle/service/ns/develop_interface.cpp
@@ -810,8 +814,6 @@ add_library(core STATIC
hle/service/ns/ecommerce_interface.h
hle/service/ns/factory_reset_interface.cpp
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.h
hle/service/ns/ns.cpp
@@ -1203,6 +1205,9 @@ endif()
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)
if (MSVC)
target_link_libraries(core PRIVATE getopt)
endif()
if (BOOST_NO_HEADERS)
target_link_libraries(core PUBLIC Boost::container Boost::heap Boost::asio Boost::process Boost::crc)
+20 -36
View File
@@ -22,21 +22,15 @@ DynarmicCallbacks32::DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
{}
u8 DynarmicCallbacks32::MemoryRead8(u32 vaddr) {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
return m_memory.Read8(vaddr);
}
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);
u64 DynarmicCallbacks32::MemoryRead(u32 vaddr, size_t size) {
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
switch (size) {
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();
}
}
std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
@@ -50,27 +44,17 @@ std::optional<u32> DynarmicCallbacks32::MemoryReadCode(u32 vaddr) {
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
void DynarmicCallbacks32::MemoryWrite8(u32 vaddr, u8 value) {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
m_memory.Write8(vaddr, value);
void DynarmicCallbacks32::MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) {
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
switch (size) {
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) {
return CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write) &&
m_memory.WriteExclusive8(vaddr, value, expected);
@@ -177,7 +161,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
config.page_table = reinterpret_cast<std::array<std::uint8_t*, NumPageTableEntries>*>(
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
config.page_table_marked_bit = 0;
config.page_table_marked_bit = uint8_t(0);
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
config.only_detect_misalignment_via_page_table_on_page_boundary = true;
@@ -193,7 +177,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
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 = Common::PageTable::SIGN_BIT;
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
}
}
+2 -8
View File
@@ -30,18 +30,12 @@ class System;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process);
u8 MemoryRead8(u32 vaddr) override;
u16 MemoryRead16(u32 vaddr) override;
u32 MemoryRead32(u32 vaddr) override;
u64 MemoryRead64(u32 vaddr) override;
u64 MemoryRead(u32 vaddr, size_t size) override;
std::optional<u32> MemoryReadCode(u32 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = u64(-1); //reset back, force refetch
}
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;
void MemoryWrite(Dynarmic::A32::VAddr vaddr, u64 value, size_t size) override;
bool MemoryWriteExclusive8(u32 vaddr, u8 value, u8 expected) override;
bool MemoryWriteExclusive16(u32 vaddr, u16 value, u16 expected) override;
bool MemoryWriteExclusive32(u32 vaddr, u32 value, u32 expected) override;
+21 -35
View File
@@ -10,6 +10,7 @@
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_process.h"
#include "dynarmic/interface/A64/config.h"
namespace Core {
@@ -21,21 +22,15 @@ DynarmicCallbacks64::DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess
, m_check_memory_access{m_debugger_enabled || !Settings::values.cpuopt_ignore_memory_aborts.GetValue()}
{}
u8 DynarmicCallbacks64::MemoryRead8(u64 vaddr) {
CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Read);
return m_memory.Read8(vaddr);
}
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);
u64 DynarmicCallbacks64::MemoryRead(u64 vaddr, size_t size) {
CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Read);
switch (size) {
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();
}
}
Dynarmic::A64::Vector DynarmicCallbacks64::MemoryRead128(u64 vaddr) {
CheckMemoryAccess(vaddr, 16, Kernel::DebugWatchpointType::Read);
@@ -53,24 +48,15 @@ std::optional<u32> DynarmicCallbacks64::MemoryReadCode(u64 vaddr) {
return cached_code_page.inst[(vaddr & Core::Memory::YUZU_PAGEMASK) / sizeof(u32)];
}
void DynarmicCallbacks64::MemoryWrite8(u64 vaddr, u8 value) {
if (CheckMemoryAccess(vaddr, 1, Kernel::DebugWatchpointType::Write)) {
m_memory.Write8(vaddr, value);
}
}
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::MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) {
if (CheckMemoryAccess(vaddr, size, Kernel::DebugWatchpointType::Write)) {
switch (size) {
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::MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) {
@@ -216,7 +202,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
const_cast<Common::PageTable::PageEntryData*>(page_table->entries.data()));
config.page_table_address_space_bits = std::uint32_t(address_space_bits);
config.page_table_pointer_mask = Common::PageTable::ATTRIBUTE_MASK;
config.page_table_marked_bit = 0;
config.page_table_marked_bit = uint8_t(0);
config.silently_mirror_page_table = false;
config.absolute_offset_page_table = true;
config.detect_misaligned_access_via_page_table = 16 | 32 | 64 | 128;
@@ -235,7 +221,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
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 = Common::PageTable::SIGN_BIT;
config.page_table_sign_extension = std::uint8_t(Common::PageTable::SIGN_BIT);
}
}
+3 -8
View File
@@ -16,6 +16,7 @@
#include "common/hash.h"
#include "core/arm/arm_interface.h"
#include "core/arm/dynarmic/dynarmic_exclusive_monitor.h"
#include "dynarmic/interface/A64/config.h"
namespace Core::Memory {
class Memory;
@@ -36,19 +37,13 @@ class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process);
u8 MemoryRead8(u64 vaddr) override;
u16 MemoryRead16(u64 vaddr) override;
u32 MemoryRead32(u64 vaddr) override;
u64 MemoryRead64(u64 vaddr) override;
u64 MemoryRead(u64 vaddr, size_t size) override;
Dynarmic::A64::Vector MemoryRead128(u64 vaddr) override;
std::optional<u32> MemoryReadCode(u64 vaddr) override;
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = u64(-1); //reset back, force refetch
}
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 MemoryWrite(Dynarmic::A64::VAddr vaddr, u64 value, std::size_t size) override;
void MemoryWrite128(u64 vaddr, Dynarmic::A64::Vector value) 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;
+25 -22
View File
@@ -35,19 +35,22 @@ static IPSFileType IdentifyMagic(std::span<const u8> magic) {
}
static bool IsEOF(IPSFileType type, std::span<const u8> magic) {
return (type == IPSFileType::IPS && magic.size() > 3 && std::memcmp(magic.data(), "EOF", 3) == 0)
|| (type == IPSFileType::IPS32 && magic.size() > 4 && std::memcmp(magic.data(), "EEOF", 4) == 0);
return (type == IPSFileType::IPS && magic.size() >= 3 && std::memcmp(magic.data(), "EOF", 3) == 0)
|| (type == IPSFileType::IPS32 && magic.size() >= 4 && std::memcmp(magic.data(), "EEOF", 4) == 0);
}
VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
if (in == nullptr || ips == nullptr)
return nullptr;
auto in_data = in->ReadAllBytes();
auto const type = IdentifyMagic(in_data);
const auto type = IdentifyMagic(ips->ReadBytes(0x5));
if (type == IPSFileType::Error)
return nullptr;
auto in_data = in->ReadAllBytes();
if (in_data.size() == 0)
return nullptr;
std::vector<u8> temp(type == IPSFileType::IPS ? 3 : 4);
u64 offset = 5; // After header
while (ips->Read(temp.data(), temp.size(), offset) == temp.size()) {
@@ -100,8 +103,7 @@ VirtualFile PatchIPS(const VirtualFile& in, const VirtualFile& ips) {
struct IPSwitchRecord {
std::array<uint8_t, 256 - sizeof(size_t)> data;
size_t count;
std::vector<uint8_t> data;
};
struct IPSwitchCompiler::IPSwitchPatch {
::Common::unordered_map<u32, IPSwitchRecord> records;
@@ -122,22 +124,23 @@ static IPSwitchRecord EscapeStringSequences(std::string_view sv) {
IPSwitchRecord r{};
for (auto it = sv.cbegin(); it < sv.cend(); ) {
if (*it == '\\' && it + 1 < sv.cend()) {
switch (it[1]) {
case 'a': r.data[r.count] = '\a'; break;
case 'b': r.data[r.count] = '\b'; break;
case 'e': r.data[r.count] = '\e'; break;
case 'f': r.data[r.count] = '\f'; break;
case 'n': r.data[r.count] = '\n'; break;
case 'r': r.data[r.count] = '\r'; break;
case 't': r.data[r.count] = '\t'; break;
case 'v': r.data[r.count] = '\v'; break;
case '?': r.data[r.count] = '\?'; break;
default: r.data[r.count] = it[1]; break;
}
++r.count;
r.data.push_back([it]() {
switch (it[1]) {
case 'a': return '\a';
case 'b': return '\b';
case 'e': return '\e';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
case '?': return '\?';
default: return it[1];
}
}());
it += 2;
} else {
++r.count;
r.data.push_back(*it);
++it;
}
}
@@ -223,8 +226,8 @@ void IPSwitchCompiler::Parse(std::span<u8 const> bytes) {
if (start <= line.cend() && end <= line.cend()) {
// Actually IPS wants ordering from {lsb, ..., msb} -- so LE and BE are inverted, fun!
auto const hs = Common::HexStringToVector({start, end}, is_little_endian);
r.data.resize(hs.size());
std::memcpy(r.data.data(), hs.data(), hs.size());
r.count = hs.size();
LOG_INFO(Loader, "[H] value @ {:#08X}", offset);
patches.back().records.insert_or_assign(u32(offset), std::move(r));
} else {
@@ -293,7 +296,7 @@ VirtualFile IPSwitchCompiler::Apply(const VirtualFile& in) const {
if (patch.enabled) {
for (const auto& record : patch.records) {
if (record.first < in_data.size()) {
auto replace_size = record.second.count;
auto replace_size = record.second.data.size();
if (record.first + replace_size > in_data.size())
replace_size = in_data.size() - record.first;
std::memcpy(in_data.data() + record.first, record.second.data.data(), replace_size);
+50 -18
View File
@@ -9,6 +9,7 @@
#include <cstddef>
#include <cstring>
#include "common/assert.h"
#include "common/hex_util.h"
#include "common/logging.h"
#include "common/settings.h"
@@ -156,12 +157,15 @@ std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64
NACP nacp{nacp_file};
return nacp.GetVersionString();
}
YUZU_NO_INLINE std::optional<u64> GetParentApplicationId(const ContentProvider* provider, u64 title_id) {
return provider == nullptr ? std::nullopt : provider->GetParentApplicationId(title_id);
}
} // Anonymous namespace
PatchManager::PatchManager(u64 title_id_,
const Service::FileSystem::FileSystemController& fs_controller_,
const ContentProvider& content_provider_)
: title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
: title_id{title_id_}, parent_title_id{GetParentApplicationId(std::addressof(content_provider_), title_id_)}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
PatchManager::~PatchManager() = default;
@@ -169,13 +173,35 @@ u64 PatchManager::GetTitleID() const {
return title_id;
}
VirtualDir PatchManager::GetModificationLoadRoot(bool sdmc) const {
const auto get_root = [&](u64 id) {
return sdmc ? fs_controller.GetSDMCModificationLoadRoot(id) : fs_controller.GetModificationLoadRoot(id);
};
auto root = get_root(title_id);
if (!parent_title_id) {
return root;
}
std::vector<VirtualDir> roots{std::move(root), get_root(*parent_title_id)};
std::erase(roots, nullptr);
return LayeredVfsDirectory::MakeLayeredDirectory(std::move(roots));
}
std::vector<std::string> PatchManager::GetDisabledAddons() const {
auto disabled = Settings::values.disabled_addons[title_id];
if (parent_title_id) {
const auto& shared = Settings::values.disabled_addons[*parent_title_id];
disabled.insert(disabled.end(), shared.begin(), shared.end());
}
return disabled;
}
VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
LOG_INFO(Loader, "Patching ExeFS for title_id={:016X}", title_id);
if (exefs == nullptr)
return exefs;
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto disabled = GetDisabledAddons();
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -303,8 +329,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
// LayeredExeFS
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
const auto load_dir = GetModificationLoadRoot();
const auto sdmc_load_dir = GetModificationLoadRoot(true);
std::vector<VirtualDir> patch_dirs = {sdmc_load_dir};
if (load_dir != nullptr) {
@@ -346,7 +372,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
std::vector<VirtualFile> PatchManager::CollectPatches(const std::vector<VirtualDir>& patch_dirs, const std::string& build_id) const {
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto disabled = GetDisabledAddons();
const auto nso_build_id = fmt::format("{:0<64}", build_id);
std::vector<VirtualFile> out;
@@ -405,7 +431,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto load_dir = GetModificationLoadRoot();
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso;
@@ -448,7 +474,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}, name={}", build_id, name);
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto load_dir = GetModificationLoadRoot();
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false;
@@ -462,13 +488,13 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
}
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto load_dir = GetModificationLoadRoot();
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {};
}
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto disabled = GetDisabledAddons();
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
@@ -502,17 +528,16 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
return out;
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
const Service::FileSystem::FileSystemController& fs_controller) {
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
const auto sdmc_load_dir = fs_controller.GetSDMCModificationLoadRoot(title_id);
void PatchManager::ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const {
const auto load_dir = GetModificationLoadRoot();
const auto sdmc_load_dir = GetModificationLoadRoot(true);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data &&
type != ContentRecordType::HtmlDocument) ||
(load_dir == nullptr && sdmc_load_dir == nullptr)) {
return;
}
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto disabled = GetDisabledAddons();
std::vector<VirtualDir> patch_dirs = load_dir->GetSubdirectories();
if (std::find(disabled.cbegin(), disabled.cend(), "SDMC") == disabled.cend()) {
patch_dirs.push_back(sdmc_load_dir);
@@ -591,7 +616,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto disabled = GetDisabledAddons();
bool update_disabled = true;
std::optional<u32> enabled_version;
@@ -698,7 +723,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
// LayeredFS
if (apply_layeredfs) {
ApplyLayeredFS(romfs, title_id, type, fs_controller);
ApplyLayeredFS(romfs, type);
}
return romfs;
@@ -1072,15 +1097,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
std::optional<u32> PatchManager::GetGameVersion() const {
const auto update_tid = GetUpdateTitleID(title_id);
if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
return content_provider.GetEntryVersion(update_tid);
const auto version = content_provider.GetEntryVersion(update_tid);
return version || !parent_title_id ? version : content_provider.GetEntryVersion(GetUpdateTitleID(*parent_title_id));
}
return content_provider.GetEntryVersion(title_id);
const auto version = content_provider.GetEntryVersion(title_id);
return version || !parent_title_id ? version : content_provider.GetEntryVersion(*parent_title_id);
}
PatchManager::Metadata PatchManager::GetControlMetadata() const {
const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
if (base_control_nca == nullptr) {
if (parent_title_id) {
const auto control_id = content_provider.HasEntry(*parent_title_id, ContentRecordType::Control) ? *parent_title_id : GetUpdateTitleID(*parent_title_id);
const PatchManager parent{control_id, fs_controller, content_provider};
return parent.GetControlMetadata();
}
return {};
}
+4
View File
@@ -109,10 +109,14 @@ public:
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
private:
[[nodiscard]] VirtualDir GetModificationLoadRoot(bool sdmc = false) const;
[[nodiscard]] std::vector<std::string> GetDisabledAddons() const;
void ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const;
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
const std::string& build_id) const;
u64 title_id;
std::optional<u64> parent_title_id;
const Service::FileSystem::FileSystemController& fs_controller;
const ContentProvider& content_provider;
};
+17
View File
@@ -5,6 +5,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <limits>
#include <random>
#include <regex>
#include <openssl/evp.h>
@@ -348,6 +349,22 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
}
std::optional<u64> ContentProvider::GetParentApplicationId(u64 program_id) const {
const auto application_id = GetBaseTitleID(program_id);
const auto program_index = program_id - application_id;
if (program_index == 0 || program_index > std::numeric_limits<u8>::max()) {
return std::nullopt;
}
if (!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, program_id).empty()) {
return std::nullopt;
}
if ((!ListEntriesFilter(TitleType::Application, ContentRecordType::Meta, application_id).empty() && HasEntry(program_id, ContentRecordType::Program))
|| (!ListEntriesFilter(TitleType::Update, ContentRecordType::Meta, GetUpdateTitleID(application_id)).empty() && HasEntry(GetUpdateTitleID(program_id), ContentRecordType::Program))) {
return application_id;
}
return std::nullopt;
}
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
+2
View File
@@ -100,6 +100,8 @@ public:
std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
std::optional<u64> title_id = {}) const = 0;
[[nodiscard]] std::optional<u64> GetParentApplicationId(u64 program_id) const;
protected:
// A single instance of KeyManager to be used by GetEntry()
Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+3 -4
View File
@@ -109,8 +109,7 @@ VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::op
auto reference = std::make_unique<FileReference>();
this->InsertReferenceIntoListLocked(*reference);
auto file = std::shared_ptr<RealVfsFile>(
new RealVfsFile(*this, std::move(reference), path, perms, size, std::move(parent_path)));
auto file = std::make_shared<RealVfsFile>(*this, std::move(reference), path, perms, size, std::move(parent_path));
cache[path] = file;
return file;
@@ -177,7 +176,7 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
return std::make_shared<RealVfsDirectory>(*this, path, perms);
}
VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
@@ -185,7 +184,7 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode p
if (!FS::CreateDirs(path)) {
return nullptr;
}
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
return std::make_shared<RealVfsDirectory>(*this, path, perms);
}
VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
+5 -6
View File
@@ -82,6 +82,9 @@ class RealVfsFile : public VfsFile {
friend class RealVfsFilesystem;
public:
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
const std::string& path, OpenMode perms = OpenMode::Read,
std::optional<u64> size = {}, std::optional<std::string> parent_path = {});
~RealVfsFile() override;
std::string GetName() const override;
@@ -95,9 +98,6 @@ public:
bool Rename(std::string_view name) override;
private:
RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
const std::string& path, OpenMode perms = OpenMode::Read,
std::optional<u64> size = {}, std::optional<std::string> parent_path = {});
RealVfsFilesystem& base;
std::unique_ptr<FileReference> reference;
@@ -113,6 +113,8 @@ class RealVfsDirectory : public VfsDirectory {
friend class RealVfsFilesystem;
public:
RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
OpenMode perms = OpenMode::Read);
~RealVfsDirectory() override;
VirtualFile GetFileRelative(std::string_view relative_path) const override;
@@ -138,9 +140,6 @@ public:
std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override;
private:
RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
OpenMode perms = OpenMode::Read);
template <typename T, typename R>
std::vector<std::shared_ptr<R>> IterateEntries() const;
+25 -8
View File
@@ -12,6 +12,7 @@
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
#include <array>
namespace Core::Frontend {
@@ -29,23 +30,39 @@ void DefaultControllerApplet::ReconfigureControllers(ReconfigureCallback callbac
const std::size_t min_supported_players =
parameters.enable_single_mode ? 1 : parameters.min_players;
using Core::HID::NpadStyleIndex;
const std::size_t max_supported_players = parameters.enable_single_mode ? 1 : parameters.max_players;
std::size_t num_selected_players = 0;
std::array<bool, HID::HIDCore::available_controllers> keep_connected{};
// Disconnect Handheld first.
// reserve existing AND valid players before filling slots. include Handheld, but not other
for (std::size_t index = 0; index < hid_core.available_controllers - 1; ++index) {
const auto* controller = hid_core.GetEmulatedControllerByIndex(index);
if (!parameters.keep_controllers_connected || !controller->IsConnected() || num_selected_players >= max_supported_players) continue;
const auto style = controller->GetNpadStyleIndex();
keep_connected[index] =
(style == NpadStyleIndex::Fullkey && parameters.allow_pro_controller) ||
(style == NpadStyleIndex::JoyconDual && parameters.allow_dual_joycons) ||
(style == NpadStyleIndex::JoyconLeft && parameters.allow_left_joycon) ||
(style == NpadStyleIndex::JoyconRight && parameters.allow_right_joycon) ||
(style == NpadStyleIndex::Handheld && parameters.enable_single_mode && parameters.allow_handheld && !Settings::IsDockedMode()) ||
(style == NpadStyleIndex::GameCube && parameters.allow_gamecube_controller);
num_selected_players += keep_connected[index];
}
auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
handheld->Disconnect();
if (!keep_connected[hid_core.available_controllers - 2]) handheld->Disconnect();
// Deduce the best configuration based on the input parameters.
for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
// First, disconnect all controllers regardless of the value of keep_controllers_connected.
// This makes it easy to connect the desired controllers.
if (keep_connected[index]) continue;
controller->Disconnect();
// Only connect the minimum number of required players.
if (index >= min_supported_players) {
continue;
}
// only add players still needed to reach the minimum
if (num_selected_players >= min_supported_players) continue;
++num_selected_players;
// Connect controllers based on the following priority list from highest to lowest priority:
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
+8
View File
@@ -465,6 +465,10 @@ void KScheduler::ScheduleImplFiber(KernelCore& kernel) {
// Check if we need scheduling. If we do, then we can't complete the switch and should
// retry.
if (m_state.needs_scheduling.load(std::memory_order_seq_cst)) {
// Some libc++ lazily init mutex
[[maybe_unused]] auto const can_lock = highest_priority_thread->m_context_guard.try_lock();
DEBUG_ASSERT(!can_lock);
// Our switch failed.
// We should unlock the thread context, and then retry.
highest_priority_thread->m_context_guard.unlock();
@@ -496,6 +500,10 @@ void KScheduler::Unload(KernelCore& kernel, KThread* thread) {
// Check if the thread is terminated by checking the DPC flags.
if ((thread->GetStackParameters().dpc_flags & static_cast<u32>(DpcFlag::Terminated)) == 0) {
// Some libc++ lazily init mutex
[[maybe_unused]] auto const can_lock = thread->m_context_guard.try_lock();
DEBUG_ASSERT(!can_lock);
// The thread isn't terminated, so we want to unlock it.
thread->m_context_guard.unlock();
}
+3 -4
View File
@@ -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-FileCopyrightText: Copyright 2020 yuzu Emulator Project
@@ -12,7 +12,6 @@
#include "common/atomic_ops.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/spin_lock.h"
namespace Kernel {
@@ -30,7 +29,7 @@ public:
};
public:
constexpr KSlabHeapImpl() = default;
KSlabHeapImpl() = default;
void Initialize() {
ASSERT(m_head == nullptr);
@@ -68,7 +67,7 @@ public:
private:
std::atomic<Node*> m_head{};
Common::SpinLock m_lock;
std::mutex m_lock;
};
} // namespace impl
+1 -2
View File
@@ -19,7 +19,6 @@
#include "common/intrusive_red_black_tree.h"
#include "common/scratch_buffer.h"
#include "common/spin_lock.h"
#include "core/arm/arm_interface.h"
#include "core/hle/kernel/k_affinity_mask.h"
#include "core/hle/kernel/k_light_lock.h"
@@ -920,7 +919,7 @@ private:
bool m_resource_limit_release_hint{};
bool m_is_kernel_address_key{};
StackParameters m_stack_parameters{};
Common::SpinLock m_context_guard{};
std::mutex m_context_guard{};
// For emulation
std::shared_ptr<Common::Fiber> m_host_context{};
@@ -23,6 +23,12 @@ constexpr std::size_t profile_username_size{32};
using ProfileUsername = std::array<u8, profile_username_size>;
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
// This is nn::account::Uid
struct Uid {
std::array<u8, 0x10> unk0;
};
static_assert(sizeof(Uid) == 0x10);
/// Contains extra data related to a user.
/// TODO: RE this structure
struct UserData {
+14 -6
View File
@@ -29,6 +29,7 @@
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Frontend {
@@ -72,10 +73,16 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
void FrontendApplet::Exit() {
auto applet_ = applet.lock();
std::scoped_lock lk{applet_->lock};
applet_->is_completed = true;
applet_->state_changed_event.Signal(system.Kernel());
{
std::scoped_lock lk{applet_->lock};
applet_->is_completed = true;
applet_->state_changed_event.Signal(system.Kernel());
}
if (auto caller_applet = applet_->caller_applet.lock()) {
std::scoped_lock lk{caller_applet->lock};
std::erase(caller_applet->child_applets, applet_);
}
if (auto* window_system = system.GetAppletManager().GetWindowSystem()) window_system->RequestUpdate();
}
FrontendAppletSet::FrontendAppletSet() = default;
@@ -243,9 +250,10 @@ std::shared_ptr<FrontendApplet> FrontendAppletHolder::GetApplet(std::shared_ptr<
return std::make_shared<PhotoViewer>(system, applet, mode, *frontend.photo_viewer);
case AppletId::NetConnect:
return std::make_shared<NetConnect>(system, applet, mode, *frontend.net_connect);
case AppletId::None:
return nullptr;
default:
LOG_ERROR(Service_AM, "No backend implementation exists for applet_id={:02X} program_id={:016X}"
"Falling back to stub applet", static_cast<u8>(id), applet->program_id);
UNIMPLEMENTED_MSG("No frontend implementation exists for applet_id={:02X} program_id={:016X}! Using stub applet.", static_cast<u8>(id), applet->program_id);
return std::make_shared<StubApplet>(system, applet, id, mode);
}
}
@@ -92,6 +92,13 @@ public:
}
}
void RequestFocusStateChangedNotification(Kernel::KernelCore& kernel) {
if (m_focus_state_changed_notification_enabled) {
m_has_focus_state_changed = true;
this->SignalSystemEventIfNeeded(kernel);
}
}
void OnOperationAndPerformanceModeChanged(Kernel::KernelCore& kernel);
public:
@@ -347,21 +347,22 @@ Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(stubbed)");
R_UNLESS(out_pseudo_device_id, ResultUnknown);
R_UNLESS(out_pseudo_device_id != nullptr, ResultUnknown);
// This should be hashed with the device specific hash
// for now this will do
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id);
u8 hash[EVP_MAX_MD_SIZE];
R_UNLESS(res.first != nullptr, ResultUnknown);
std::array<u8, EVP_MAX_MD_SIZE> hash;
unsigned int hash_len = 0;
auto const seed = res.first->raw.seed_for_pseudo_device_id;
EVP_MD_CTX *ctx = EVP_MD_CTX_new();
auto const algorithm = EVP_sha1();
EVP_DigestInit_ex(ctx, algorithm, nullptr);
EVP_DigestUpdate(ctx, &seed, sizeof(seed));
EVP_DigestFinal_ex(ctx, hash, &hash_len);
EVP_DigestFinal_ex(ctx, hash.data(), &hash_len);
EVP_MD_CTX_free(ctx);
*out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span<u8, 20>{hash, std::size(hash)});
*out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span<u8, 16>{hash.begin(), hash.begin() + 16});
R_SUCCEED();
}
@@ -164,14 +164,14 @@ Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
LOG_DEBUG(Service_AM, "called");
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
caller_applet->lifecycle_manager.GetSystemEvent().Signal(system.Kernel());
caller_applet->lifecycle_manager.RequestResumeNotification();
caller_applet->lifecycle_manager.GetSystemEvent().Clear(system.Kernel());
caller_applet->lifecycle_manager.UpdateRequestedFocusState();
}
R_TRY(m_broker->GetOutData().Pop(system.Kernel(), out_storage.Get()));
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
std::scoped_lock lk{caller_applet->lock};
const bool focus_state_changed = caller_applet->lifecycle_manager.UpdateRequestedFocusState();
const bool is_front_app = m_applet->frontend && caller_applet->lifecycle_manager.IsApplication();
if (focus_state_changed) caller_applet->lifecycle_manager.SignalSystemEventIfNeeded(system.Kernel());
else if (is_front_app) caller_applet->lifecycle_manager.RequestFocusStateChangedNotification(system.Kernel());
}
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
auto impl = (*out_storage)->GetImpl();
@@ -122,7 +122,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
caller_applet->child_applets.push_back(applet);
{
std::scoped_lock lk{caller_applet->lock};
caller_applet->child_applets.push_back(applet);
}
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
@@ -148,10 +151,10 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
caller_applet->child_applets.push_back(applet);
window_system.TrackApplet(applet, false);
{
std::scoped_lock lk{caller_applet->lock};
caller_applet->child_applets.push_back(applet);
}
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
}
+1 -1
View File
@@ -517,7 +517,7 @@ void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground, b
// Layer ordering. Composition sorts back-to-front. Now with enums for calrity.
s32 z_index = Background;
if (is_overlay) {
z_index = Overlay;
z_index = this->IsOverlayOpenLocked(*applet) ? Overlay : Background;
} else if (inherited_foreground) {
z_index = is_obscured ? Foreground : ForegroundVisible;
}
+1 -1
View File
@@ -191,7 +191,7 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("audout:d", std::make_shared<IAudioOutManagerForDebugger>(system), 30);
server_manager->RegisterNamedService("audin:d", std::make_shared<IAudioInManagerForDebugger>(system), 30);
server_manager->RegisterNamedService("audrec:d", std::make_shared<IFinalOutputRecorderManagerForDebugger>(system), 30);
server_manager->RegisterNamedService("audren:d", std::make_shared<IAudioInManager>(system), 30);
server_manager->RegisterNamedService("audren:d", std::make_shared<IAudioRendererManagerForDebugger>(system), 30);
server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system), 30);
server_manager->RegisterNamedService("audin:a", std::make_shared<IAudioInManagerForApplet>(system), 30);
@@ -154,6 +154,9 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{720, nullptr, "AbandonAccessFailure"},
{800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
{810, nullptr, "RegisterProgramIndexMapInfo"},
{820, nullptr, "GetContentStorageInfoIndex"},
{830, nullptr, "EncryptStreamPlaySaveData"},
{831, nullptr, "DecryptStreamPlaySaveData"},
{1000, nullptr, "SetBisRootForHost"},
{1001, nullptr, "SetSaveDataSize"},
{1002, nullptr, "SetSaveDataRootPath"},
@@ -121,7 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{547, nullptr, "GetAllowedBluetoothLinksCount"},
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
{549, nullptr, "GetConnectableRegisteredDevices"},
{551, nullptr, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+
{551, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+ //mocked via 548 for Diablo 3 (at least)
{700, nullptr, "ActivateUniquePad"},
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
@@ -758,7 +758,7 @@ void IHidSystemServer::AcquireDeviceRegisteredEventForControllerSupport(HLEReque
}
void IHidSystemServer::GetRegisteredDevices(HLERequestContext& ctx) {
LOG_WARNING(Service_HID, "(STUBBED) called");
LOG_WARNING(Service_HID, "(STUBBED) called, command={}", ctx.GetCommand()); //548 or 551
struct RegisterData {
std::array<u8, 0x68> data;
+1
View File
@@ -22,6 +22,7 @@
namespace IPC {
constexpr Result ResultNotSupported{ErrorModule::HIPC, 1};
constexpr Result ResultSessionClosed{ErrorModule::HIPC, 301};
struct ResponseBuilder {
+28 -34
View File
@@ -71,17 +71,14 @@ public:
void InstructionSynchronizationBarrierRaised() override {
last_code_addr = u64(-1); //reset back, force refetch
}
u8 MemoryRead8(u64 vaddr) override {
return ReadMemory<u8>(vaddr);
}
u16 MemoryRead16(u64 vaddr) override {
return ReadMemory<u16>(vaddr);
}
u32 MemoryRead32(u64 vaddr) override {
return ReadMemory<u32>(vaddr);
}
u64 MemoryRead64(u64 vaddr) override {
return ReadMemory<u64>(vaddr);
u64 MemoryRead(u64 vaddr, size_t size) override {
switch (size) {
case sizeof(u64): return ReadMemory<u64>(vaddr);
case sizeof(u32): return ReadMemory<u32>(vaddr);
case sizeof(u16): return ReadMemory<u16>(vaddr);
case sizeof(u8): return ReadMemory<u8>(vaddr);
default: UNREACHABLE();
}
}
u128 MemoryRead128(u64 vaddr) override {
return ReadMemory<u128>(vaddr);
@@ -89,22 +86,19 @@ public:
std::string MemoryReadCString(u64 vaddr) {
std::string result{};
u8 next;
while ((next = MemoryRead8(vaddr++)) != 0)
while ((next = u8(MemoryRead(vaddr++, sizeof(u8)))) != 0)
result += char(next);
return result;
}
void MemoryWrite8(u64 vaddr, u8 value) override {
WriteMemory<u8>(vaddr, value);
}
void MemoryWrite16(u64 vaddr, u16 value) override {
WriteMemory<u16>(vaddr, value);
}
void MemoryWrite32(u64 vaddr, u32 value) override {
WriteMemory<u32>(vaddr, value);
}
void MemoryWrite64(u64 vaddr, u64 value) override {
WriteMemory<u64>(vaddr, value);
void MemoryWrite(u64 vaddr, u64 value, size_t size) override {
switch (size) {
case sizeof(u64): WriteMemory<u64>(vaddr, u64(value)); break;
case sizeof(u32): WriteMemory<u32>(vaddr, u32(value)); break;
case sizeof(u16): WriteMemory<u16>(vaddr, u16(value)); break;
case sizeof(u8): WriteMemory<u8>(vaddr, u8(value)); break;
default: UNREACHABLE();
}
}
void MemoryWrite128(u64 vaddr, u128 value) override {
WriteMemory<u128>(vaddr, value);
@@ -193,14 +187,14 @@ public:
// The loaded NRO file has ELF relocations that must be processed before it can run.
// Normally this would be processed by RTLD, but in HLE context, we don't have
// the linker available, so we have to do it ourselves.
const VAddr mod_offset{callbacks->MemoryRead32(4)};
if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0'))
const VAddr mod_offset{callbacks->MemoryRead(4, sizeof(u32))};
if (callbacks->MemoryRead(mod_offset, sizeof(u32)) != Common::MakeMagic('M', 'O', 'D', '0'))
return false;
// For more info about dynamic entries, see the ELF ABI specification:
// https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html
// https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)};
VAddr dynamic_offset{mod_offset + callbacks->MemoryRead(mod_offset + 4, sizeof(u32))};
VAddr rela_dyn = 0, relr_dyn = 0;
size_t num_rela = 0, num_relr = 0;
while (true) {
@@ -222,8 +216,8 @@ public:
for (size_t i = 0; i < num_rela; i++) {
const auto rela{callbacks->ReadMemory<Elf64_Rela>(rela_dyn + i * sizeof(Elf64_Rela))};
if (Elf64RelType(rela.r_info) == ElfAArch64Relative) {
const VAddr contents{callbacks->MemoryRead64(rela.r_offset)};
callbacks->MemoryWrite64(rela.r_offset, contents + rela.r_addend);
const VAddr contents{callbacks->MemoryRead(rela.r_offset, sizeof(u64))};
callbacks->MemoryWrite(rela.r_offset, contents + rela.r_addend, sizeof(u64));
}
}
@@ -231,7 +225,7 @@ public:
for (size_t i = 0; i < num_relr; i++) {
const auto relr = callbacks->ReadMemory<Elf64_Relr>(relr_dyn + i * sizeof(Elf64_Relr));
const auto incr = [&](VAddr where) {
callbacks->MemoryWrite64(where, callbacks->MemoryRead64(where) + relocbase);
callbacks->MemoryWrite(where, callbacks->MemoryRead(where, sizeof(u64)) + relocbase, sizeof(u64));
};
if ((relr & 1) == 0) {
// where pointer
@@ -294,7 +288,7 @@ public:
if (argument_stack.size() > 8) {
const VAddr new_sp = Common::AlignDown(top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN);
for (size_t i = 8; i < argument_stack.size(); i++)
callbacks->MemoryWrite64(new_sp + (i - 8) * sizeof(u64), argument_stack[i]);
callbacks->MemoryWrite(new_sp + (i - 8) * sizeof(u64), argument_stack[i], sizeof(u64));
jit->SetSP(new_sp);
}
// Reset the call state for the next invocation
@@ -385,17 +379,17 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
if (dest < src) {
for (size_t i = 0; i < n; i++)
MemoryWrite8(dest + i, MemoryRead8(src + i));
MemoryWrite(dest + i, u8(MemoryRead(src + i, sizeof(u8))), sizeof(u8));
} else {
for (size_t i = n; i > 0; i--)
MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1));
MemoryWrite(dest + i - 1, u8(MemoryRead(src + i - 1, sizeof(u8))), sizeof(u8));
}
} else if (pc == parent.helpers[size_t(HelperFn::Memset)]) {
const VAddr dest{parent.jit->GetRegister(0)};
const u64 c{parent.jit->GetRegister(1)};
const size_t n{parent.jit->GetRegister(2)};
for (size_t i = 0; i < n; i++)
MemoryWrite8(dest + i, u8(c));
MemoryWrite(dest + i, u8(c), sizeof(u8));
} else if (pc == parent.helpers[size_t(HelperFn::Resolve)]) {
// X0 contains a char* for a symbol to resolve
const auto name{MemoryReadCString(parent.jit->GetRegister(0))};
@@ -422,7 +416,7 @@ void DynarmicCallbacks64::CallSVC(u32 swi) {
}
void DynarmicCallbacks64::ExceptionRaised(u64 pc, Dynarmic::A64::Exception exception) {
auto const inst = MemoryRead32(pc);
auto const inst = MemoryRead(pc, sizeof(u32));
LOG_CRITICAL(Service_JIT, "{} PC @ {:08x}, data = {:08x}", exception, pc, inst);
parent.jit->HaltExecution();
}
+117
View File
@@ -6,10 +6,16 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_client_session.h"
#include "core/hle/result.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ngc/ngc.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "frontend_common/firmware_manager.h"
namespace Service::NGC {
@@ -166,12 +172,123 @@ public:
}
};
struct SaveDataHandle {
u64 unk0;
};
static_assert(sizeof(SaveDataHandle) == 0x08);
class IUserShimScopedObject final : public ServiceFramework<IUserShimScopedObject> {
public:
explicit IUserShimScopedObject(Core::System& system_) : ServiceFramework(system_, "IUserShimScopedObject") {
// clang-format off
static const FunctionInfo functions[] = {
{450, nullptr, "InitializeForSaveData"},
{451, nullptr, "FinalizeForSaveData"},
{452, D<&IUserShimScopedObject::OpenSaveData>, "OpenSaveData"},
{453, nullptr, "CloseSaveData"},
{454, D<&IUserShimScopedObject::ReadSaveSlot>, "ReadSaveSlot"},
{455, D<&IUserShimScopedObject::WriteSaveSlot>, "WriteSaveSlot"},
{456, nullptr, "FlushSaveSlot"},
{457, nullptr, "CommitSaveData"},
};
// clang-format on
RegisterHandlers(functions);
}
Result OpenSaveData(Account::Uid unk0, Out<SaveDataHandle> unk1) {
LOG_WARNING(Service_NGC, "stubbed");
R_THROW(IPC::ResultNotSupported);
}
Result ReadSaveSlot(s32 offset, SaveDataHandle handle, OutBuffer<BufferAttr_HipcAutoSelect> out_data, Out<u32> out_size) {
LOG_WARNING(Service_NGC, "stubbed");
R_THROW(IPC::ResultNotSupported);
}
Result WriteSaveSlot(s32 offset, SaveDataHandle handle, InBuffer<BufferAttr_HipcAutoSelect> out_data) {
LOG_WARNING(Service_NGC, "stubbed");
// to implement
R_SUCCEED();
}
};
class IUserService final : public ServiceFramework<IUserService> {
public:
explicit IUserService(Core::System& system_) : ServiceFramework(system_, "stpl:u") {
// clang-format off
static const FunctionInfo functions[] = {
{0 , D<&IUserService::Cmd0>, "Cmd0"},
};
// clang-format on
RegisterHandlers(functions);
}
Result Cmd0(u32 unk0, OutInterface<IUserShimScopedObject> out_interface) {
LOG_WARNING(Service_NGC, "stubbed");
*out_interface = std::make_shared<IUserShimScopedObject>(system);
R_SUCCEED();
}
};
class ISystemShimScopedObject final : public ServiceFramework<ISystemShimScopedObject> {
public:
explicit ISystemShimScopedObject(Core::System& system_) : ServiceFramework(system_, "ISystemShimScopedObject") {
// clang-format off
static const FunctionInfo functions[] = {
{106, nullptr, "Cmd106"},
{107, nullptr, "Cmd107"},
{108, D<&ISystemShimScopedObject::Cmd108>, "Cmd108"},
{207, nullptr, "Cmd207"},
{208, D<&ISystemShimScopedObject::Cmd208>, "Cmd208"},
{209, nullptr, "Cmd209"},
{210, nullptr, "Cmd210"},
{211, nullptr, "Cmd211"},
{212, nullptr, "Cmd212"},
};
// clang-format on
RegisterHandlers(functions);
}
Result Cmd108() {
LOG_WARNING(Service_NGC, "stubbed");
R_THROW(IPC::ResultNotSupported);
}
Result Cmd208(Out<std::array<u8, 0x20>> unk0) {
LOG_WARNING(Service_NGC, "stubbed");
R_THROW(IPC::ResultNotSupported);
}
};
class ISystemService final : public ServiceFramework<ISystemService> {
public:
explicit ISystemService(Core::System& system_) : ServiceFramework(system_, "stpl:sys") {
// clang-format off
static const FunctionInfo functions[] = {
{0 , D<&ISystemService::Cmd0>, "Cmd0"},
};
// clang-format on
RegisterHandlers(functions);
}
Result Cmd0(OutInterface<ISystemShimScopedObject> out_interface) {
LOG_WARNING(Service_NGC, "stubbed");
*out_interface = std::make_shared<ISystemShimScopedObject>(system);
R_SUCCEED();
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ngct:u", std::make_shared<IService>(system), 4);
server_manager->RegisterNamedService("ngct:s", std::make_shared<IServiceWithManagementApi>(system), 4);
server_manager->RegisterNamedService("ngc:u", std::make_shared<NgcServiceImpl>(system), 4);
// +23.0.0
if (FirmwareManager::GetFirmwareVersion(system).first.major >= 23) {
server_manager->RegisterNamedService("stpl:u", std::make_shared<IUserService>(system), 4);
server_manager->RegisterNamedService("stpl:sys", std::make_shared<ISystemService>(system), 4);
}
ServerManager::RunServer(std::move(server_manager));
}
@@ -7,7 +7,7 @@
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ns/i_async_result.h"
#include "core/hle/service/ns/async_result.h"
#include "core/hle/service/ns/language.h"
#include "core/hle/service/ns/ns_types.h"
#include "core/hle/service/os/event.h"
@@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ns/i_async_result.h"
#include "core/hle/service/ns/async_result.h"
#include <cstring>
@@ -32,4 +32,4 @@ Result IAsyncResult::Cancel() {
R_SUCCEED();
}
} // namespace Service::NS
} // namespace Service::NS
@@ -311,27 +311,30 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestCon
// u64 - app count
memory.WriteBlock(t_mem_address + out_length, &app_count, sizeof(u64));
out_length += sizeof(u64);
ASSERT(out_length <= t_mem->GetSize());
// [list of u64] - size of icons
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
u64 full_size = control.second->GetSize();
memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64));
if (const auto control = pm.GetControlMetadata(); control.second) {
u64 full_size = control.second->GetSize();
memory.WriteBlock(t_mem_address + out_length, &full_size, sizeof(u64));
}
out_length += sizeof(u64);
ASSERT(out_length <= t_mem->GetSize());
}
// [list of raw icon data]
std::vector<u8> full_icon_data;
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
auto const full_size = control.second->GetSize();
if (full_size > 0) {
full_icon_data.resize(full_size);
control.second->Read(full_icon_data.data(), full_size, 0);
memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size);
out_length += full_size;
if (const auto control = pm.GetControlMetadata(); control.second) {
if (auto const full_size = control.second->GetSize(); full_size > 0) {
std::vector<u8> full_icon_data(full_size);
control.second->Read(full_icon_data.data(), full_size, 0);
memory.WriteBlock(t_mem_address + out_length, full_icon_data.data(), full_size);
out_length += full_size;
ASSERT(out_length <= t_mem->GetSize());
}
}
}
}
@@ -345,6 +348,12 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationIcon(HLERequestCon
void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestContext& ctx) {
const auto app_ids_buffer = ctx.ReadBuffer();
const size_t app_count = app_ids_buffer.size() / sizeof(u64);
std::vector<u64> application_ids(app_count);
if (app_count > 0) {
std::memcpy(application_ids.data(), app_ids_buffer.data(), app_count * sizeof(u64));
}
auto t_mem_obj = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
auto* t_mem = t_mem_obj.GetPointerUnsafe();
constexpr size_t title_entry_size = sizeof(FileSys::LanguageEntry);
@@ -354,8 +363,9 @@ void IReadOnlyApplicationControlDataInterface::ListApplicationTitle(HLERequestCo
auto& memory = system.ApplicationMemory();
const auto t_mem_address = t_mem->GetSourceAddress();
for (size_t i = 0; i < app_count; ++i) {
const u64 app_id = app_ids_buffer[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(), system.GetContentProvider()};
const u64 app_id = application_ids[i];
const FileSys::PatchManager pm{app_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
FileSys::LanguageEntry entry{};
if (control.first != nullptr) {
@@ -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-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@@ -24,7 +24,7 @@ IReceiverService::~IReceiverService() = default;
Result IReceiverService::OpenReceiver(Out<SharedPointer<IReceiver>> out_receiver) {
LOG_DEBUG(Service_PSC, "called");
*out_receiver = std::shared_ptr<IReceiver>(new IReceiver(system));
*out_receiver = std::make_shared<IReceiver>(system);
R_SUCCEED();
}
+32 -2
View File
@@ -16,6 +16,10 @@
#include "core/hle/service/ro/ro_types.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#ifdef HAS_NCE
#include "core/arm/nce/patcher.h"
#include "core/hle/kernel/k_shared_memory.h"
#endif
namespace Service::RO {
@@ -386,7 +390,7 @@ public:
R_SUCCEED();
}
Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address,
Result MapManualLoadModuleMemory(Kernel::KernelCore& kernel, u64* out_address, size_t context_id, u64 nro_address,
u64 nro_size, u64 bss_address, u64 bss_size) {
// Get context.
ProcessContext* context = this->GetContextById(context_id);
@@ -421,7 +425,33 @@ public:
R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
std::addressof(ro_size), std::addressof(rw_size),
nro_info->base_address, nro_size, bss_size));
#ifdef HAS_NCE
if (Settings::values.nce_runtime_nro_patch.GetValue()) {
if (Settings::IsNceEnabled()) {
auto* process = context->GetProcess();
auto& memory = process->GetMemory();
std::vector<u8> image(total_size);
memory.ReadBlock(nro_info->base_address, image.data(), rx_size);
Kernel::CodeSet::Segment code{.size = static_cast<u32>(rx_size)};
Core::NCE::Patcher patch;
patch.PatchText(image, code);
patch.RelocateAndCopy(nro_info->base_address, code, image, nullptr);
const u64 patch_address = nro_info->base_address + total_size;
const size_t patch_size = patch.GetSectionSize();
constexpr auto permission = Kernel::Svc::MemoryPermission::ReadExecute;
auto* patch_memory = Kernel::KSharedMemory::Create(kernel);
R_TRY(patch_memory->Initialize(kernel, kernel.System().DeviceMemory(), process, permission, permission, patch_size));
std::memcpy(patch_memory->GetPointer(), image.data() + total_size, patch_size);
R_TRY(process->AddSharedMemory(kernel, patch_memory, patch_address, patch_size));
R_TRY(patch_memory->Map(*process, patch_address, patch_size, permission));
memory.WriteBlock(nro_info->base_address, image.data(), rx_size);
}
}
#endif
// Set NRO perms.
R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
rw_size + bss_size));
@@ -531,7 +561,7 @@ public:
Result MapManualLoadModuleMemory(Out<u64> out_load_address, ClientProcessId client_pid,
u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size) {
R_TRY(m_ro->ValidateProcess(m_context_id, *client_pid));
R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address.Get(), m_context_id, nro_address,
R_RETURN(m_ro->MapManualLoadModuleMemory(system.Kernel(), out_load_address.Get(), m_context_id, nro_address,
nro_size, bss_address, bss_size));
}
+218 -244
View File
@@ -48,6 +48,12 @@ enum class OptionType : u32 {
EnableAlpn = 3,
};
// This is nn::ssl::sf::RenegotiationMode
enum RenegotiationMode : u32 {
None = 0, ///< None
Secure = 1, ///< Secure
};
// This is nn::ssl::sf::SslVersion
struct SslVersion {
union {
@@ -75,34 +81,34 @@ public:
shared_data{shared_data_in}, backend{std::move(backend_in)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISslConnection::SetSocketDescriptor, "SetSocketDescriptor"},
{1, &ISslConnection::SetHostName, "SetHostName"},
{2, &ISslConnection::SetVerifyOption, "SetVerifyOption"},
{3, &ISslConnection::SetIoMode, "SetIoMode"},
{4, nullptr, "GetSocketDescriptor"},
{5, nullptr, "GetHostName"},
{0, D<&ISslConnection::SetSocketDescriptor>, "SetSocketDescriptor"},
{1, D<&ISslConnection::SetHostName>, "SetHostName"},
{2, D<&ISslConnection::SetVerifyOption>, "SetVerifyOption"},
{3, D<&ISslConnection::SetIoMode>, "SetIoMode"},
{4, D<&ISslConnection::GetSocketDescriptor>, "GetSocketDescriptor"},
{5, D<&ISslConnection::GetHostName>, "GetHostName"},
{6, nullptr, "GetVerifyOption"},
{7, nullptr, "GetIoMode"},
{8, &ISslConnection::DoHandshake, "DoHandshake"},
{7, D<&ISslConnection::GetIoMode>, "GetIoMode"},
{8, D<&ISslConnection::DoHandshake>, "DoHandshake"},
{9, &ISslConnection::DoHandshakeGetServerCert, "DoHandshakeGetServerCert"},
{10, &ISslConnection::Read, "Read"},
{11, &ISslConnection::Write, "Write"},
{12, &ISslConnection::Pending, "Pending"},
{13, nullptr, "Peek"},
{14, nullptr, "Poll"},
{15, nullptr, "GetVerifyCertError"},
{16, nullptr, "GetNeededServerCertBufferSize"},
{17, &ISslConnection::SetSessionCacheMode, "SetSessionCacheMode"},
{18, nullptr, "GetSessionCacheMode"},
{19, nullptr, "FlushSessionCache"},
{20, nullptr, "SetRenegotiationMode"},
{21, nullptr, "GetRenegotiationMode"},
{22, &ISslConnection::SetOption, "SetOption"},
{23, &ISslConnection::GetOption, "GetOption"},
{10, D<&ISslConnection::Read>, "Read"},
{11, D<&ISslConnection::Write>, "Write"},
{12, D<&ISslConnection::Pending>, "Pending"},
{13, D<&ISslConnection::Peek>, "Peek"},
{14, D<&ISslConnection::Poll>, "Poll"},
{15, D<&ISslConnection::GetVerifyCertError>, "GetVerifyCertError"},
{16, D<&ISslConnection::GetNeededServerCertBufferSize>, "GetNeededServerCertBufferSize"},
{17, D<&ISslConnection::SetSessionCacheMode>, "SetSessionCacheMode"},
{18, D<&ISslConnection::GetSessionCacheMode>, "GetSessionCacheMode"},
{19, D<&ISslConnection::FlushSessionCache>, "FlushSessionCache"},
{20, D<&ISslConnection::SetRenegotiationMode>, "SetRenegotiationMode"},
{21, D<&ISslConnection::GetRenegotiationMode>, "GetRenegotiationMode"},
{22, D<&ISslConnection::SetOption>, "SetOption"},
{23, D<&ISslConnection::GetOption>, "GetOption"},
{24, nullptr, "GetVerifyCertErrors"},
{25, nullptr, "GetCipherInfo"},
{26, &ISslConnection::SetNextAlpnProto, "SetNextAlpnProto"},
{27, &ISslConnection::GetNextAlpnProto, "GetNextAlpnProto"},
{26, D<&ISslConnection::SetNextAlpnProto>, "SetNextAlpnProto"},
{27, D<&ISslConnection::GetNextAlpnProto>, "GetNextAlpnProto"},
{28, nullptr, "SetDtlsSocketDescriptor"},
{29, nullptr, "GetDtlsHandshakeTimeout"},
{30, nullptr, "SetPrivateOption"},
@@ -141,80 +147,6 @@ public:
}
private:
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
std::unique_ptr<SSLConnectionBackend> backend;
std::optional<int> fd_to_close;
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
bool skip_default_verify = false;
bool enable_alpn = false;
std::shared_ptr<Network::SocketBase> socket;
std::vector<u8> next_alpn_proto;
bool did_handshake = false;
u32 verify_option = 0;
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
auto const res_v = bsd->DuplicateSocketImpl(fd);
if (auto *res = std::get_if<s32>(&res_v)) {
const s32 duplicated_fd = *res;
if (do_not_close_socket) {
*out_fd = duplicated_fd;
} else {
*out_fd = -1;
fd_to_close = duplicated_fd;
}
std::optional<std::shared_ptr<Network::SocketBase>> sock = bsd->GetSocket(duplicated_fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", duplicated_fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
backend->SetSocket(socket);
return ResultSuccess;
}
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", fd);
return ResultInvalidSocket;
}
Result SetHostNameImpl(const std::string& hostname) {
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
return backend->SetHostName(hostname);
}
Result SetVerifyOptionImpl(u32 option) {
ASSERT(!did_handshake);
LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
verify_option = 0;
backend->SetVerifyOption(0);
return ResultSuccess;
}
Result SetIoModeImpl(u32 input_mode) {
auto mode = static_cast<IoMode>(input_mode);
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
ASSERT_OR_EXECUTE(socket, { return ResultNoSocket; });
const bool non_block = mode == IoMode::NonBlocking;
const Network::Errno error = socket->SetNonBlock(non_block);
if (error != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
}
return ResultSuccess;
}
Result SetSessionCacheModeImpl(u32 mode) {
ASSERT(!did_handshake);
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
return ResultSuccess;
}
Result DoHandshakeImpl() {
ASSERT_OR_EXECUTE(!did_handshake && socket, { return ResultNoSocket; });
Result res = backend->DoHandshake();
@@ -234,19 +166,17 @@ private:
};
if (!get_server_cert_chain) {
// Just return the first one, unencoded.
ASSERT_OR_EXECUTE_MSG(
!certs.empty(), { return {}; }, "Should be at least one server cert");
ASSERT_OR_EXECUTE_MSG(!certs.empty(), { return {}; }, "Should be at least one server cert");
return certs[0];
}
std::vector<u8> ret;
Header header{0x4E4D684374726543, static_cast<u32>(certs.size()), 0};
Header header{0x4E4D684374726543, u32(certs.size()), 0};
ret.insert(ret.end(), reinterpret_cast<u8*>(&header), reinterpret_cast<u8*>(&header + 1));
size_t data_offset = sizeof(Header) + certs.size() * sizeof(EntryHeader);
for (auto& cert : certs) {
EntryHeader entry_header{static_cast<u32>(cert.size()), static_cast<u32>(data_offset)};
EntryHeader entry_header{u32(cert.size()), u32(data_offset)};
data_offset += cert.size();
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header),
reinterpret_cast<u8*>(&entry_header + 1));
ret.insert(ret.end(), reinterpret_cast<u8*>(&entry_header), reinterpret_cast<u8*>(&entry_header + 1));
}
for (auto& cert : certs) {
ret.insert(ret.end(), cert.begin(), cert.end());
@@ -254,65 +184,77 @@ private:
return ret;
}
Result ReadImpl(std::vector<u8>* out_data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
if (res != ResultSuccess) {
return res;
Result SetSocketDescriptor(s32 in_fd, Out<s32> out_fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", in_fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
auto const res_v = bsd->DuplicateSocketImpl(in_fd);
if (auto *res = std::get_if<s32>(&res_v)) {
const s32 dup_fd = *res;
*out_fd = do_not_close_socket ? dup_fd : -1;
if (!do_not_close_socket)
fd_to_close = dup_fd;
auto const sock = bsd->GetSocket(dup_fd);
if (!sock.has_value()) {
LOG_ERROR(Service_SSL, "invalid socket fd {} after duplication", dup_fd);
return ResultInvalidSocket;
}
socket = std::move(*sock);
backend->SetSocket(std::move(socket));
return ResultSuccess;
}
out_data->resize(actual_size);
return res;
LOG_ERROR(Service_SSL, "Failed to duplicate socket with fd {}", in_fd);
return ResultInvalidSocket;
}
Result WriteImpl(size_t* out_size, std::span<const u8> data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
return backend->Write(out_size, data);
Result SetHostName(InBuffer<BufferAttr_HipcMapAlias> buf) {
auto const hostname = Common::StringFromBuffer(buf);
LOG_DEBUG(Service_SSL, "called. hostname={}", hostname);
ASSERT(!did_handshake);
return backend->SetHostName(hostname.c_str());
}
Result PendingImpl(s32* out_pending) {
LOG_WARNING(Service_SSL, "(STUBBED) called.");
*out_pending = 0;
return ResultSuccess;
Result SetVerifyOption(u32 option) {
LOG_DEBUG(Service_SSL, "called. option={} (forcing 0)", option);
ASSERT(!did_handshake);
verify_option = 0;
backend->SetVerifyOption(0);
R_SUCCEED();
}
void SetSocketDescriptor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 in_fd = rp.Pop<s32>();
s32 out_fd{-1};
const Result res = SetSocketDescriptorImpl(&out_fd, in_fd);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push<s32>(out_fd);
Result SetIoMode(u32 input_mode) {
auto mode = IoMode(input_mode);
ASSERT(mode == IoMode::Blocking || mode == IoMode::NonBlocking);
R_UNLESS(socket, ResultNoSocket);
const bool non_block = mode == IoMode::NonBlocking;
const Network::Errno error = socket->SetNonBlock(non_block);
if (error != Network::Errno::SUCCESS) {
LOG_ERROR(Service_SSL, "Failed to set native socket non-block flag to {}", non_block);
}
R_SUCCEED();
}
void SetHostName(HLERequestContext& ctx) {
const std::string hostname = Common::StringFromBuffer(ctx.ReadBuffer());
const Result res = SetHostNameImpl(hostname);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
Result GetSocketDescriptor(Out<u32> out_fd) {
LOG_WARNING(Service_SSL, "(STUBBED)");
*out_fd = uint32_t(socket->GetFD());
R_SUCCEED();
}
void SetVerifyOption(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 option = rp.Pop<u32>();
const Result res = SetVerifyOptionImpl(option);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
Result GetHostName(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
LOG_WARNING(Service_SSL, "(STUBBED)");
ASSERT(!did_handshake);
return backend->GetHostName(std::span<u8>{data.begin(), data.end()}, out_size);
}
void SetIoMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 mode = rp.Pop<u32>();
const Result res = SetIoModeImpl(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
Result GetIoMode(Out<u32> out_mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
void DoHandshake(HLERequestContext& ctx) {
const Result res = DoHandshakeImpl();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
Result DoHandshake() {
return DoHandshakeImpl();
}
void DoHandshakeGetServerCert(HLERequestContext& ctx) {
@@ -351,131 +293,158 @@ private:
rb.PushRaw(out);
}
void Read(HLERequestContext& ctx) {
std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
const Result res = ReadImpl(&output_bytes);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
if (res == ResultSuccess) {
rb.Push(static_cast<u32>(output_bytes.size()));
ctx.WriteBuffer(output_bytes);
} else {
rb.Push(static_cast<u32>(0));
}
Result Read(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
R_UNLESS(did_handshake, ResultInternalError);
size_t tmp{};
auto const res = backend->Read(&tmp, data);
*out_size = u32(tmp);
return res;
}
void Write(HLERequestContext& ctx) {
size_t write_size{0};
const Result res = WriteImpl(&write_size, ctx.ReadBuffer());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push(static_cast<u32>(write_size));
Result Write(InBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
R_UNLESS(did_handshake, ResultInternalError);
size_t tmp{};
auto const res = backend->Write(&tmp, data);
*out_size = u32(tmp);
return res;
}
void Pending(HLERequestContext& ctx) {
s32 pending_size{0};
const Result res = PendingImpl(&pending_size);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
rb.Push<s32>(pending_size);
Result Pending(Out<s32> out_pending_size) {
LOG_WARNING(Service_SSL, "(STUBBED)");
*out_pending_size = s32(backend->Pending());
R_SUCCEED();
}
void SetSessionCacheMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 mode = rp.Pop<u32>();
const Result res = SetSessionCacheModeImpl(mode);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(res);
Result Peek(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> out_size) {
LOG_WARNING(Service_SSL, "(STUBBED)");
size_t tmp{};
auto const res = backend->Peek(&tmp, data);
*out_size = u32(tmp);
return res;
}
void SetOption(HLERequestContext& ctx) {
struct Parameters {
OptionType option;
s32 value;
};
static_assert(sizeof(Parameters) == 0x8, "Parameters is an invalid size");
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
switch (parameters.option) {
case OptionType::DoNotCloseSocket:
do_not_close_socket = static_cast<bool>(parameters.value);
break;
case OptionType::GetServerCertChain:
get_server_cert_chain = static_cast<bool>(parameters.value);
break;
case OptionType::SkipDefaultVerify:
skip_default_verify = static_cast<bool>(parameters.value);
break;
case OptionType::EnableAlpn:
enable_alpn = static_cast<bool>(parameters.value);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", parameters.option,
parameters.value);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
Result Poll(u32 in_pollevent, u32 timer, Out<u32> out_pollevent) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
void GetOption(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto option = rp.PopRaw<OptionType>();
Result GetVerifyCertError() {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
u8 value = 0;
Result GetNeededServerCertBufferSize(Out<u32> out_needed_buffer_size) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
Result SetSessionCacheMode(u32 mode) {
LOG_WARNING(Service_SSL, "(STUBBED) called. value={}", mode);
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result GetSessionCacheMode(Out<u32> mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result FlushSessionCache() {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_UNLESS(!did_handshake, ResultInternalError);
R_SUCCEED();
}
Result SetRenegotiationMode(RenegotiationMode mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
backend->SetRenegotiationMode(u32(mode));
R_SUCCEED();
}
Result GetRenegotiationMode(Out<RenegotiationMode> mode) {
LOG_WARNING(Service_SSL, "(STUBBED)");
u32 tmp{};
auto const res = backend->GetRenegotiationMode(&tmp);
*mode = RenegotiationMode(tmp);
return res;
}
Result SetOption(OptionType option, s32 value) {
switch (option) {
case OptionType::DoNotCloseSocket:
value = static_cast<u8>(do_not_close_socket);
do_not_close_socket = bool(value);
break;
case OptionType::GetServerCertChain:
value = static_cast<u8>(get_server_cert_chain);
get_server_cert_chain = bool(value);
break;
case OptionType::SkipDefaultVerify:
value = static_cast<u8>(skip_default_verify);
skip_default_verify = bool(value);
break;
case OptionType::EnableAlpn:
value = static_cast<u8>(enable_alpn);
enable_alpn = bool(value);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}", option);
value = 0;
LOG_WARNING(Service_SSL, "Unknown option={}, value={}", option, value);
}
R_SUCCEED();
}
Result GetOption(OptionType option, Out<u8> value) {
switch (option) {
case OptionType::DoNotCloseSocket:
*value = u8(do_not_close_socket);
break;
case OptionType::GetServerCertChain:
*value = u8(get_server_cert_chain);
break;
case OptionType::SkipDefaultVerify:
*value = u8(skip_default_verify);
break;
case OptionType::EnableAlpn:
*value = u8(enable_alpn);
break;
default:
LOG_WARNING(Service_SSL, "Unknown option={}", u32(option));
*value = 0;
break;
}
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", option, value);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(value);
LOG_DEBUG(Service_SSL, "GetOption called, option={}, ret value={}", u32(option), *value);
R_SUCCEED();
}
void SetNextAlpnProto(HLERequestContext& ctx) {
const auto data = ctx.ReadBuffer(0);
next_alpn_proto.assign(data.begin(), data.end());
Result SetNextAlpnProto(InBuffer<BufferAttr_HipcMapAlias> data) {
auto const to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
next_alpn_proto.assign(data.begin(), data.begin() + to_write);
LOG_DEBUG(Service_SSL, "SetNextAlpnProto called, size={}", next_alpn_proto.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
void GetNextAlpnProto(HLERequestContext& ctx) {
const size_t writable = ctx.GetWriteBufferSize();
const size_t to_write = (std::min)(next_alpn_proto.size(), writable);
if (to_write != 0) {
ctx.WriteBuffer(std::span<const u8>(next_alpn_proto.data(), to_write));
}
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", to_write);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(static_cast<u32>(to_write));
Result GetNextAlpnProto(OutBuffer<BufferAttr_HipcMapAlias> data, Out<u32> to_write) {
*to_write = u32((std::min)(next_alpn_proto.size(), data.size()));
next_alpn_proto.assign(data.begin(), data.begin() + *to_write);
LOG_DEBUG(Service_SSL, "GetNextAlpnProto called, size={}", *to_write);
R_SUCCEED();
}
Result GetVerifyCertErrors(OutBuffer<BufferAttr_HipcMapAlias> unk0, Out<u32> unk1, Out<u32> unk2) {
LOG_WARNING(Service_SSL, "(STUBBED)");
R_SUCCEED();
}
SslVersion ssl_version;
std::shared_ptr<SslContextSharedData> shared_data;
std::unique_ptr<SSLConnectionBackend> backend;
std::optional<int> fd_to_close;
std::shared_ptr<Network::SocketBase> socket;
std::vector<u8> next_alpn_proto;
u32 verify_option = 0;
bool do_not_close_socket = false;
bool get_server_cert_chain = false;
bool skip_default_verify = false;
bool enable_alpn = false;
bool did_handshake = false;
};
class ISslContext final : public ServiceFramework<ISslContext> {
@@ -492,7 +461,7 @@ public:
{5, &ISslContext::ImportClientPki, "ImportClientPki"},
{6, nullptr, "RemoveServerPki"},
{7, nullptr, "RemoveClientPki"},
{8, nullptr, "RegisterInternalPki"},
{8, D<&ISslContext::RegisterInternalPki>, "RegisterInternalPki"},
{9, nullptr, "AddPolicyOid"},
{10, nullptr, "ImportCrl"},
{11, nullptr, "RemoveCrl"},
@@ -587,6 +556,11 @@ private:
rb.Push(ResultSuccess);
rb.Push(client_id);
}
Result RegisterInternalPki() {
LOG_WARNING(Service_SSL, "(STUBBED) called");
R_SUCCEED();
}
};
class ISslService final : public ServiceFramework<ISslService> {

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