1
0
Fork 0
forked from eden-emu/eden

Compare commits

..

102 commits

Author SHA1 Message Date
d24db9c3cb
[frontend] fix compile error (#2767)
Reviewed-on: eden-emu/eden#2767
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-10-18 02:45:25 +02:00
f55e560ac5
[compat] Debian stable gcc12/clang14 compilation fixes (#2763)
Mainly because - while we can just give out an AppImage and call it a day - building natively should be an option for all major distros.
And "base" stable debian doesn't provide a new enough g++/clang++ so... we need to make some "fixups".

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

Reviewed-on: eden-emu/eden#2763
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-18 01:54:43 +02:00
84ab54c4bc
[core] Comment Firmware > 19 warning (#2765)
Commented the firmware too new check, as we support the current firmware. Left as a comment, for future firmware updates.

Reviewed-on: eden-emu/eden#2765
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-10-18 01:53:59 +02:00
9333393a7b
Removed unneeded translations (#2764)
Co-authored-by: Denis Dupeyron <denis.dupeyron@gmail.com>
Reviewed-on: eden-emu/eden#2764
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-10-18 01:53:32 +02:00
cb83a258db
Fix Android Build (#2762)
Fixes some mistakes in my playtime tracking for Android PR which caused the build to fail.

Reviewed-on: eden-emu/eden#2762
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Inix <Nixy01@proton.me>
Co-committed-by: Inix <Nixy01@proton.me>
2025-10-18 00:20:36 +02:00
6bdf479488
[core, android] Initial playtime implementation (#2535)
So firstly, playtime code is moved to src/common and qt specific code to yuzu/utils.cpp.

The dependency on ProfileManager was removed because it was working properly on Android, and I think a shared playtime is better behavior.
Now, playtime is stored in a file called "playtime.bin".

JNI code is from Azahar although modified by me, as well as that I added code to reset the game's playtime which was missing for some reason on there.

Before this gets merged, I plan to add the ability to manually edit the database as well.

Note: Code still needs a bit of cleanup.

Reviewed-on: eden-emu/eden#2535
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: inix <Nixy01@proton.me>
Co-committed-by: inix <Nixy01@proton.me>
2025-10-17 22:47:43 +02:00
9c7ed0f59d
[hid_core] Fix a specific case where all controllers get disconnected by certain games (#2759)
There's a bug in some games where all controllers get disconnected. This fixes those specific cases where controllers set to Handheld or Player 1 need to remain connected.

Reviewed-on: eden-emu/eden#2759
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-17 22:24:38 +02:00
de46b8e817
[fs, qlaunch] add CreateSaveDataFileSystemWithCreationInfo2 and make qlaunch work again (#2760)
Fixes qlaunch regression I introduced previously. Add a few known structs.
Adds CreateSaveDataFileSystemWithCreationInfo2, which is called when games are started via qlaunch and corrupts save files.

Reviewed-on: eden-emu/eden#2760
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-10-17 22:23:21 +02:00
3e8fe622a7
[compat] Solaris build fixes for openssl, catch2; NetBSD build fixes (#2752)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2752
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-17 22:12:58 +02:00
1c90b099d3
[texuter_cache] #ifdef image type linear return windows only (#2720)
fixes some mario rabbits issue

Authored by amicuchu

Reviewed-on: eden-emu/eden#2720
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-10-17 22:12:22 +02:00
e2a8f3154f
[android, gameProperties] Add support for sharing per-game config file (#478)
Firstly i added secondary action support for the Sub Menu Properties as a button on the right side of the card. This may be handy in the future when adding more complex functions to Game Properties. For now i just added the ability to share the per game config file like the already existing log sharing function, this could be useful for EmuReady maybe.

Reviewed-on: eden-emu/eden#478
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: inix <Nixy01@proton.me>
Co-committed-by: inix <Nixy01@proton.me>
2025-10-17 22:11:44 +02:00
c0fb872d1a
[arm] Add "debugging" cpu accuracy option to replace CPU debug toggle (#2640)
The debug toggle and the CPU accuracy options are mutually exclusive, if debug toggle on => cpu accuracy is ignored, if debug toggle off => cpu accuracy is used. So just add it to cpu accuracy and avoid the extra hassle.

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

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2640
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-17 22:09:19 +02:00
171a1d23e4
[qt_common] Fix system frozen target (#2758)
When installled the frozen package exports `frozen::frozen-headers`, not
`frozen::frozen` target.

Signed-off-by: Marcin Serwin <marcin@serwin.dev>

Reviewed-on: eden-emu/eden#2758
Co-authored-by: Marcin Serwin <marcin@serwin.dev>
Co-committed-by: Marcin Serwin <marcin@serwin.dev>
2025-10-17 20:09:15 +02:00
3d6a784e62
[qt] Add missing margin to firmware label (#2757)
This just adds a missing margin to the firmware label.

Reviewed-on: eden-emu/eden#2757
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-17 17:23:52 +02:00
440ee4916d
[nca] Use better tight loop allocation schemes (none at all) for AES decrypt/encrypt and force MbedTLS to use AES x86_64 instructions (#2750)
Uses stack instead of allocating stuff haphazardly (16 bytes and 512 bytes respectively) - removes malloc() pollution and all that nasty stuff from tight loops
Original work by Ribbit but edited by me.
Will NOT bring a massive speedup since the main bottleneck is mbedtls itself, but may bring nice oddities to STARTUP TIMES nonetheless.
AES instructions being forced wont affect CPUs without them since there is always a runtime check for them.

Signed-off-by: lizzie lizzie@eden-emu.dev
Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2750
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-17 05:08:51 +02:00
551f244dfd
[dynarmic, qt] fix build with QuaZip <=1.4 and fmt v9 (#2755)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2755
2025-10-17 04:20:11 +02:00
ef14303c48
[common] Ensures that the Custom Web Applet will never be enabled if it has not been compiled with the project (#2754)
This ensures that the Custom Web Applet will never be enabled under any circumstances if it has not been compiled with the project.

Reviewed-on: eden-emu/eden#2754
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-17 01:23:48 +02:00
b7021afff6
[hid_core] Quick fix for PR 2747 (#2753)
Ensures that only the controllers enabled in the settings remain active when the game is running.

Reviewed-on: eden-emu/eden#2753
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-16 20:33:38 +02:00
bfc10723bc
Revert "[vk] Tighten queue wait stages (#2734)" (#2751)
Proprietary Qualcomm drivers will not like this change after further research.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2751
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-16 06:48:17 +02:00
30482692c7
Revert "[vk] Fix Vulkan Upload & Present Barriers for Spec Compliance (#2681)" (#2748)
Vulkan layout and barrier edits made the GPU use a different shader path that compiled a TLDS instruction with an unaligned register (R157).

The old path never generated that case, so the translator’s missing unaligned-register handling only surfaced after this change.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2748
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-16 03:33:24 +02:00
31463142e1
[audio] replace ReaderWriterQueue with the generic SPSC queue (#2745)
A bit overkill for something that is only used once in the source code - should rather pertain to the generic SPSC queue just to avoid redundant code. If anything should be vendored.

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

Reviewed-on: eden-emu/eden#2745
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-16 03:15:20 +02:00
bb836ed6c2
[hid_core] Fix a crash related to setting controls while the game is running (#2747)
This fixes a crash related to setting controls while the game is running. Fixes BOTW, TOTK, MK8D and possibly others as well.

Reviewed-on: eden-emu/eden#2747
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-16 03:14:39 +02:00
f273ac446b
[vk] Tighten queue wait stages (#2734)
Wait only at the transfer and color stages instead of every stage. That keeps things in sync without stalling the whole GPU.

This should work according to spec, just need to test and verify no regressions across all platforms (Windows, Linux, Android, Mac OS)

Can be 0.0.4 or 0.0.5 up to the team.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2734
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-15 22:12:25 +02:00
3f725c979d
[nx_tzdb] test: try cpm approach w/ msvc (#2709)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2709
2025-10-15 20:44:24 +02:00
2a5e6f98b6
[qt_common] fix build on QuaZip <= 1.4 (#2744)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2744
2025-10-15 05:20:03 +02:00
fff8e2026f
[qt_common] reorg + checkstate abstraction (#2735)
no diff. in functionality, just confirm builds on ubuntu 24.04/debian 12

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

Reviewed-on: eden-emu/eden#2735
2025-10-15 05:05:03 +02:00
5f9dba40a0
[desktop] Data Manager, data import/export (#2700)
This adds a "Data Manager" dialog to the Tools menu. The Data Manager allows for the following operations:
- Open w/ system file manager
- Clear
- Export
- Import

On any of the following directories:
- Save (w/ profile selector)
- UserNAND
- SysNAND
- Mods
- Shaders

TODO for the future:
- "Cleanup" for each directory
- TitleID -> Game name--let users clean data for a specific game if applicable

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2700
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2025-10-15 04:54:41 +02:00
0a54ac63f0
[vk] fix accidental functor param swap (#2743)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2743
2025-10-15 04:27:40 +02:00
94ca83a6ca
[meta] fix some compilation errors (#2741)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2741
2025-10-15 04:25:56 +02:00
2f88463203
[cmake] do not link discord_impl to httplib (#2740)
This is unnecessary

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

Reviewed-on: eden-emu/eden#2740
2025-10-15 01:03:23 +02:00
11200714e8
[cmake] fix httplib find (#2739)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2739
2025-10-15 00:33:07 +02:00
ac59b6eae5
[android] Android 7.0 support (#2654)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2654
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-14 20:47:17 +02:00
b389a72697
[vk] Initial Qualcomm proprietary driver fixes (#2732)
Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2732
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-14 19:14:35 +02:00
b3f28d29c0
[android] allow use of mouse and keyboard on motion events (#2652)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#2652
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-14 03:18:36 +02:00
053f4e95d4
[common] Better approach to enabling and disabling the Web Applet (#2729)
This implements a better approach to enabling and disabling the Web Applet, whether compiled or not.

Reviewed-on: eden-emu/eden#2729
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-14 02:38:04 +02:00
8ae7cfe96a
[romfs] Add romfslite mod folder support (Totk Ultracam) (#2730)
Support the romfslite folder type introduced in Atmosphere 1.9.5 for
memory-optimized mod loading. The emulator now detects and loads
romfslite folders the same way as romfs folders.

Utilised by Ultracam 3.0. Credit to Zephyron (Citron)

Co-authored-by: Zephyron <zephyron@citron-emu.org>

Co-authored-by: Zephyron <zephyron@citron-emu.org>
Reviewed-on: eden-emu/eden#2730
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu@eden-emu.dev>
Co-committed-by: JPikachu <jpikachu@eden-emu.dev>
2025-10-14 00:12:12 +02:00
e157b3fa96
[am] Add Unknown90 to ILibraryAppletAccessor (#2728)
Fixes crashes in BOTW 1.8.2 and EOW 1.1.0 when not using Auto-Stub
TODO: Rename once documented in SwitchBrew

Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Reviewed-on: eden-emu/eden#2728
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu@eden-emu.dev>
Co-committed-by: JPikachu <jpikachu@eden-emu.dev>
2025-10-14 00:10:30 +02:00
56e2dbc619
added barriers against zero valued overlayControlData.individualScale (#2721)
Some recent change already in master caused some @android users to reach a state in which they were missing individualScale value to some input overlay controls.

I was affected, and some fella in #tester-chat even shared a video.

These 3 new barriers makes eden ignore individualScales if they're zeroed (feeding 1f instead), avoiding the crash, and allowing users to further adjust controls scales.

Safe and functional.

Co-authored-by: Allison Cunha <allisonbzk@gmail.com>
Reviewed-on: eden-emu/eden#2721
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2025-10-13 15:37:41 +02:00
a3ef2cc183
[audio_core/hid] Audio REV12+15 support + HID fixes (#2719)
This fixes newer updates / games.

Implements partial audio rev15, rev13, rev12 and HID issues on SDK20+ games.

Credits to LotP (Ryubing) and Zephyron (Citron) for their research and implementation.

Co-authored-by: Zephyron <zephyron@citron-emu.org>
Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-on: eden-emu/eden#2719
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-10-12 17:03:14 +02:00
1e1b8ad33f
[common] Properly skip Custom Web Applet if YUZU_USE_QT_WEB_ENGINE is not defined (#2717)
This restores the Offline Web Applet LLE setting as default and properly skip Custom Web Applet if YUZU_USE_QT_WEB_ENGINE is not defined preventing crashes.

Reviewed-on: eden-emu/eden#2717
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-11 14:45:14 +02:00
91493fa39b
[vk] Fast UBO: fix tracking (#2712)
Fixes or mitigates memory errors in TOTK and possibly other games as well.

Credit: Ribbit
Reviewed-on: eden-emu/eden#2712
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-11 06:34:21 +02:00
973a65c4c5
[qt_common] fix typo (#2715)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2715
2025-10-11 04:31:14 +02:00
8a017951aa
[qt_common] fix building with Qt 6.10 (#2713)
Qt old style include variables are deprecated in Qt, see <https://github.com/qt/qtbase/blob/v6.10.0/cmake/QtModuleConfig.cmake.in#L84>, and Qt 6.10 stopped exporting them after <ad7b94e163>.

Signed-off-by: Marcin Serwin <marcin@serwin.dev>

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2713
Co-authored-by: Marcin Serwin <marcin@serwin.dev>
Co-committed-by: Marcin Serwin <marcin@serwin.dev>
2025-10-10 22:33:15 +02:00
776958c79d
[vk] Introduce Ring Buffers for Uniform Buffer (#2698)
Create 3 ring buffers which rotates between buffers each frame to avoid GPU/CPU conflicts
BindMappedUniformBuffer first tries to allocate from the ring buffer and falls back to staging pool only if allocation is too large.
Note to testers:- please test the performance since it is primarily a performance optimization and also look for visual bugs.

Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Reviewed-on: eden-emu/eden#2698
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-committed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2025-10-10 19:24:20 +02:00
3656253262
[acc] do not consider system profile as orphaned (#2708)
Profile 00000000000000000000000000000000 is apparently needed for acnh,
etc

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

Reviewed-on: eden-emu/eden#2708
2025-10-10 05:59:31 +02:00
b6241e4148
revert [vk] StreamBuffer Changes (#2684) (#2707)
revert [vk] StreamBuffer Changes (#2684)

Streambuffer changes did broke stuff in other games that got out of our scope of testing, we're going to study this changes in the future for better graphic stability.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2684
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
Reviewed-on: eden-emu/eden#2707
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: CamilleLaVey <camillelavey99@gmail.com>
Co-committed-by: CamilleLaVey <camillelavey99@gmail.com>
2025-10-10 01:55:43 +02:00
bfffafe68b
[common] Change web offline applet default setting to HLE (#2705)
This prevents some games from ignoring the disable web applet setting.

Reviewed-on: eden-emu/eden#2705
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-10 01:36:55 +02:00
3c6ef765af
revert [vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695) (#2706)
revert [vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695)

Well, stuff showed up after testing phase, that showed us this change break SMO and some mods after being merged directly into master, we will keep stuying why happens this and add a better handling later.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2695
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>

Reviewed-on: eden-emu/eden#2706
Co-authored-by: CamilleLaVey <camillelavey99@gmail.com>
Co-committed-by: CamilleLaVey <camillelavey99@gmail.com>
2025-10-09 21:37:27 +02:00
954c17c18a
[frontend] change order of filters to match append rules (#2696)
otherwise, FSR would change to Gaussian etc.

in general, sans resolution, new enum values should always be appended

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

Reviewed-on: eden-emu/eden#2696
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2025-10-08 06:39:58 +02:00
8078990b9b
[vk] Fast UBO: fix tracking, resize heuristics, add debug guard (#2695)
Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2695
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-08 05:39:08 +02:00
db65f10768
[vk] Unify RAII in Vulkan (#2679)
This PR consolidates Vulkan RAII on video_core/vulkan_common/vulkan_wrapper.h’s vk::Handle and remove the unused duplicate src/video_core/vulkan_common/vulkan_raii.h, reducing confusion and maintenance. Swapchain now uses RAII‑managed per‑image semaphores and clears them in Destroy(), providing correct present synchronization and automatic cleanup. Expected result: simpler lifetimes, fewer leak risks, and more stable presentation with negligible overhead.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2679
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-08 04:01:24 +02:00
acd7d792a3
[hle] Stubbed QueryLastPlayTime (#389)
Ported from Torzu, made by Jarrod Norwell.

Co-authored-by: Jarrod Norwell <official.antique@gmail.com>

Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com>
Reviewed-on: eden-emu/eden#389
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Gamer64 <gamer64@eden-emu.dev>
Co-committed-by: Gamer64 <gamer64@eden-emu.dev>
2025-10-08 02:08:13 +02:00
9acb6006b8
[ci] improve ccache and add support on Android (#2673)
* disable PCH
* fix missing headers after disabling PCH
* add support to extra cmake flags on Android building
* remove debug symbols on Release building (also fixing ccache on windows)

Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-on: eden-emu/eden#2673
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-10-08 01:04:18 +02:00
cf0628af46
[compat] improve thread naming logic (#271)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#271
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-07 06:38:22 +02:00
dbeae7add0
[vk, ogl] Add VK_QCOM ZTC, Bspline, Mitchell filter weights, add MMPX filter (#2577)
Adds native support for QCOM cubic filter weights, and for devices whom do not support said weights, just implement them in shaders

TODO: ZTC filter is wrong!?

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

Reviewed-on: eden-emu/eden#2577
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-07 06:35:57 +02:00
62369aa2d5
[vk] StreamBuffer Changes (#2684)
Tighter ring allocation + sync tracking with correct wrap/no-wrap, alignment, and per-range sync_ticks; update head/tail only when needed (wrap to 0 if tail won’t fit).

Adds safer sizing under debug tools by preferring device-local host-visible heaps with fallback.

Expected result: fewer stalls, steadier reuse, higher upload throughput.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2684
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-07 03:26:54 +02:00
badd913bee
[desktop] fix save data location, orphaned profiles finder (#2678)
Previously, if the user had their NAND in a nonstandard location,
profiles.dat would be read from the standard Eden path and thus return
effectively garbage data. What this would result in is:

- The Qt profile manager would be completely nonfunctional
- "Open Save Data Location" would put you into the completely wrong
  place
- Games would read from incorrect locations for their saves

To solve this, I made it so that profiles.dat is re-read *after*
QtConfig initializes. It's not the perfect solution, but it works.

Additionally, this adds an orphaned profiles finder:
- walks through the save folders in nand/user/save/000.../
- for each subdirectory, checks to see if profiles.dat contains a
  corresponding UUID
- If not, the profile is "orphaned". It may contain legit save data, so
  let the user decide how to handle it (famous last words)
- Empty profiles are just removed. If they really matter, they're
  instantly recreated anyways.

The orphaned profiles check runs right *after* the decryption keys
check, but before the game list ever gets populated

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

Reviewed-on: eden-emu/eden#2678
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2025-10-07 01:32:09 +02:00
6a4fa11ac3
[externals] only build spirv-tools as static (#2680)
Upstream forcefully builds the shared lib and also builds shared and
static separately for... some reason. I made a PR that fixes that, so
for now let's use it here

should speed up build on Android and Windows

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

Reviewed-on: eden-emu/eden#2680
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2025-10-07 01:31:36 +02:00
5d4cfe195b
[vk] Fix Vulkan Upload & Present Barriers for Spec Compliance (#2681)
The barrier before the CPU-upload copy was using VK_PIPELINE_STAGE_HOST_BIT. Validation rules only allow HOST as the source stage if you’re also specifying host-side access flags; inside a command buffer the GPU isn’t executing “host work,” so pairing that stage with the usual image layout transition is technically invalid.

Switching the source stage to VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT keeps the ordering guarantee we need and satisfies the spec, while the actual host visibility is still handled correctly by the preceding vmaFlushAllocation.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2681
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-06 17:39:32 +02:00
bc1d093fe9
[frontend] add 1.25x resolution option (#2566)
It sits at 900p or 1350p.

Signed-off-by: Aleksandr Popovich <popovich@eden-emu.dev>

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2566
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Aleksandr Popovich <popovich@eden-emu.dev>
Co-committed-by: Aleksandr Popovich <popovich@eden-emu.dev>
2025-10-06 03:08:00 +02:00
f6d99e5032
[docs] initial user handbook draft (#2629)
This is the initial draft of a "User Handbook", or FAQ. Currently contains useful info on the basics, graphics, and architecture/platform info.

Archive.org OR archive.is should be used for linking external websites, especially since their content should not change. And most often than not, in a few years these could change.

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2629
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-05 20:44:48 +02:00
a52ddf78a6
[docs] add packaging status to README (#2658)
Very surprising we are on repology already. Anyways this may help power users track which packages are outdated and whatnot wrt to others.

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

Reviewed-on: eden-emu/eden#2658
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-05 05:42:59 +02:00
Bix
191dd892e5
[android] Legacy build flavor (#51)
This adds a "legacy" build flavor, similar to the genshinSpoof flavor. The legacy flavor uses a white icon bg, alongside building with `YUZU_LEGACY=ON`, which applies the previously-made SD865 patches iff that value is truthy.

Co-authored-by: Bixthefin <114880614+Bixthefin@users.noreply.github.com>
Co-authored-by: Calchan <denis.dupeyron@gmail.com>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#51
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Bix <bix@bixed.xyz>
Co-committed-by: Bix <bix@bixed.xyz>
2025-10-05 05:41:20 +02:00
9f385bf627
[tools, cmake] refactor: update/hash check scripts, use tags for some more deps, proper CPMUtil separation (#2666)
Uses tags for a bunch of deps that can use them

Also adds a bunmch of scripts to tools/cpm, notably for checking hashes
and checking for updates.

TODO for the future:
- CI target to check hashes
- Weekly CI to check for updates

Need to get that other CI runner up

additional stuff

- Ports gentoo fixes
- makes solaris work (TODO: sdl2)
- way better docs
- properly separates CPMUtil as a standalone project

Reviewed-on: eden-emu/eden#2666
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2025-10-05 03:04:53 +02:00
1a13e79c3d
[cmake] fix video_core and tests comp errors on Windows (#2631)
did not link to video_core thus did not properly propagate the GPUOpen
target thus failed to find vk_mem_alloc

also msvc sucks

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2631
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2025-10-05 00:00:52 +02:00
268918aece
[vk] Implement Shader Read Barrier (#2671)
Adding the shader read barrier keeps every render/compute/transfer write visible before the image is sampled, so it prevents the “read-before-writes-finish” hazards. Without it you can get random stale frames, flickering post process passes, partially updated HUD textures, and corrupted depth-to-color conversions especially in scenes that render into an offscreen image and immediately feed that image to a shader (reflections, bloom, dynamic resolution, depth visualizers, etc.). This fix makes those R2T chains deterministic again across all Vulkan drivers.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2671
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-04 23:58:08 +02:00
83730cd4c1
[cmake] update CI deps, feat: sirit CI + new CI spec (#2655)
Updates sirit to our fork's latest version w/ SPIRV Headers included
(end goal is to remove spirv-headers entirely, as spirv-tools-ci should
include them inline as well)

Adds a sirit CI on our fork for all platforms (saves a bit of compile
time)

My CI spec has changed a little bit, and now there is no need for an
additional CMake file after the initial CMakeLists.txt (since targets
are now global imported). Plus, UNIX amd64 now has the amd64 suffix like
aarch64 and windows

Updates SDL2 to 2.32.10 and OpenSSL to 3.6.0

Finally, on Solaris all CI packages (sans FFmpeg) are now built with OmniOS, which
should in theory be fully compatible with OpenIndiana (our recommended
Sun-based target) but obviously will need testing

Need testing:
- [ ] Make sure I didn't nuke shader emission
- [ ] Make sure FreeBSD, OpenBSD, and OpenIndiana work fine with bundled
  sirit (check linking especially)
- [ ] Make sure SDL2, OpenSSL work with OpenIndiana now
- [ ] SDL2 on all platforms (input, etc)

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

Reviewed-on: eden-emu/eden#2655
2025-10-04 09:27:13 +02:00
272df1fa83
[settings] default to opengl on solaris (#2659)
Vulkan support still wonky on most distros.

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

Reviewed-on: eden-emu/eden#2659
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-04 02:48:39 +02:00
71a87b2c55
[video_core] Fix stutters and freezes when playing FMV content in some games (#2650)
This fixes stutters and freezes when playing FMV content in some games.

Reviewed-on: eden-emu/eden#2650
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-03 23:08:20 +02:00
f4f3425d86
[sockets] block more domains (#2632)
* Bring in the domain-blocking code from the legacy branch
* Make blockedDomains a `static constexpr const std::array<std::string,6>`

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2632
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Calchan <denis.dupeyron@gmail.com>
Co-committed-by: Calchan <denis.dupeyron@gmail.com>
2025-10-03 04:46:27 +02:00
9173eec402
[compat] fix logind DBus on non-linux unixes (#2648)
Backported from FreeBSD ports patches

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

Reviewed-on: eden-emu/eden#2648
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-02 23:39:59 +02:00
de594c8792
[dynarmic] add safe-opt to skip IR verification (#2613)
Most programs are well behaved and don't cause internal IR issues. Hence, verification can be safely skipped.

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

Reviewed-on: eden-emu/eden#2613
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-02 23:20:45 +02:00
2d8cb2d457
[file_sys] Properly fix the installation of new updates (#2651)
This removes the workaround and properly fix the installation of new updates.

Reviewed-on: eden-emu/eden#2651
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-02 22:48:52 +02:00
990a43a48c
[vk] Add missing flush per spec (#2624)
We copy pixels into a CPU-side staging buffer and then ask the GPU to read from it. On some systems those CPU writes aren’t automatically visible to the GPU unless explicitly flushed, so the GPU can sometimes read stale data. By calling buffer.Flush() immediately after writing, we force those CPU changes to become visible to the device, ensuring the GPU sees the latest frame. However, this is an emulator, so sometimes what spec says may not work cause reasons.

Co-authored-by: Ribbit <ribbit@placeholder.com>
Reviewed-on: eden-emu/eden#2624
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Ribbit <ribbit@eden-emu.dev>
Co-committed-by: Ribbit <ribbit@eden-emu.dev>
2025-10-02 20:00:34 +02:00
1a5b3fb239
[audio_core] Fix audio reverb effect (#2646)
This fixes the audio reverb effect that was causing loud noise in some games and on some platforms.

Reviewed-on: eden-emu/eden#2646
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-02 01:30:05 +02:00
24e6c62109
[vk, ogl] invalidate pipeline caches from <=0.0.3 (#2637)
Invalidates caches before next upcoming release, this will make transitions smoother especially for users whom do not know how to clear caches. The reasoning behind this is the recent changes to async shaders and other pipeline stuffs that may break compat

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

Reviewed-on: eden-emu/eden#2637
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-02 00:25:41 +02:00
326865cba2
[host1x] Improve FFmpeg error handling (#2643)
This improves the FFmpeg error handling.

Reviewed-on: eden-emu/eden#2643
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-02 00:15:14 +02:00
76b5d6778e
[common/logging] faster logging by avoiding constructing unused strings/results (and filtering first) (#2603)
basically std::string would be invoked even when the logging was filtered, then destroyed instantly, invoking malloc/free and polluting mem arenas for no good reason

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

Reviewed-on: eden-emu/eden#2603
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-01 23:18:37 +02:00
61adc85c4b
[ci] Minor change to fix building (#2644)
MSVC did not like that one of our variables was a constexpr since it was defined in the externals as a constexpr. Changed to const auto like the rest to ensure it built properly.

Reviewed-on: eden-emu/eden#2644
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-committed-by: Shinmegumi <shinmegumi@eden-emu.dev>
2025-10-01 21:09:27 +02:00
4be6d30cd9
[fixup] fix bad variable names (#2642)
* Mo[l]tenVK is only for apple, so desc is unnecessary
* fix mistipo on BUILD_AUTO_UPDATE_WEB[SI]TE

Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>

Reviewed-on: eden-emu/eden#2642
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-10-01 16:36:07 +02:00
020f1cdb1f
[qt] fix ci missing build_id (#2638)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#2638
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-01 12:16:42 +02:00
dfe10bc851
[common] use libc++ provided jthread instead of in-house one (which deadlocks on FBSD 14) (#351)
Needs test on our CI targets to see I didn't miss anything. Worried about android.

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

Reviewed-on: eden-emu/eden#351
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-01 06:59:35 +02:00
9a098441de
[audio_core] Fix audio issue in The Legend of Zelda - Echoes of Wisdom (#2594)
This fixes the audio issue in The Legend of Zelda - Echoes of Wisdom on Windows.

Reviewed-on: eden-emu/eden#2594
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-10-01 05:33:37 +02:00
91fb1df624
[meta] allow customisation of auto-updater, remove hardcoded title names and fix dup title names (#2588)
Right now on all platforms, sdl2 will display something like "Eden Eden | master-8gd8fg8", this fixes so it only displays `Eden` (the REPO_NAME) once.

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

Reviewed-on: eden-emu/eden#2588
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-10-01 05:07:59 +02:00
43a7470a7d
[Maxwell]: Fix shaders compilation memory leak (#2606)
Co-authored-by: collecting <collecting@citron-emu.org>

"The ObjectPool<Statement> was never being cleared after use. When compiling complex shaders, this would allocate gigabytes of memory, causing the emulator to run out of RAM and be killed by the operating system. This is a critical fix that prevents out-of-memory crashes on all operating systems when playing games with complex shaders."

Co-authored-by: Gamer64 <76565986+Gamer64ytb@users.noreply.github.com>
Reviewed-on: eden-emu/eden#2606
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: Gamer64 <gamer64@eden-emu.dev>
Co-committed-by: Gamer64 <gamer64@eden-emu.dev>
2025-10-01 01:21:12 +02:00
dfca07f4e3
Initial a9 (minsdk=28) support (#2600)
Minimal changes to make android 10 installable and emulationFragment not immediately crashable.
Testers (mainly android 10) NEEDED!!!

Co-authored-by: Allison Cunha <allisonbzk@gmail.com>
Reviewed-on: eden-emu/eden#2600
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2025-10-01 00:10:59 +02:00
2e0a4163cf
common: include missing headers after PCH disable (#2626)
Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Reviewed-on: eden-emu/eden#2626
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-09-30 04:25:29 +02:00
815d85677a
CMake improvements: ccache, bundled Qt, MoltenVK, LTO, and Linux deps (#2622)
- Fix YUZU_USE_BUNDLED_QT on Linux (correct path is gcc_64 for Qt 6.8.3).
- Implement USE_CCACHE correctly (additional changes on #2580).
- Categorize and organize CMake options for clarity.
- Add missing Linux dependencies
- Set CMP0069 (LTO) default behavior to NEW to reduce warnings.
- Replace USE_SYSTEM_MOLTENVK with YUZU_APPLE_USE_BUNDLED_MONTENVK and remove duplicate download_moltenvk.

Reviewed-on: eden-emu/eden#2622
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-09-30 02:51:48 +02:00
f422d855b7
[cmake] fix apple, android builds (#2619)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2619
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-30 02:18:31 +02:00
03c7d6ce4a
[android] input over(lay)haul 1: Auto-hide input overlay setting (#493)
This is step 1 of eden-emu/eden#47 which was the easiest to implement. How was this not implemented on yuzu already?
Would prefer if more people tested this than the usual amount.

Reviewed-on: eden-emu/eden#493
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: nyx-ynx <contact@nyxynx.dev>
Co-committed-by: nyx-ynx <contact@nyxynx.dev>
2025-09-29 22:40:03 +02:00
nyx
824dc6948e
[android] input over(lay)haul 2: Individual scaling of buttons (#2562)
### (Needs testing)

This PR makes it possible to adjust the scale of each touch input overlay button independently from the global scale
This individual value always goes on top of the global scale.

Reviewed-on: eden-emu/eden#2562
Co-authored-by: nyx <contact@innix.space>
Co-committed-by: nyx <contact@innix.space>
2025-09-29 22:38:26 +02:00
85b5e650cc
[dist, docs] Clearer wording for settings, guidelines for new settings (#2570)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#2570
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 19:41:01 +02:00
324ace3cd6
[macos] associate .XCI/NSP file extensions (#2617)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: eden-emu/eden#2617
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 18:43:13 +02:00
33f93ad003
[macos, qt] workaround upstream rendering bug (#2616)
See https://bugreports.qt.io/browse/QTBUG-138942

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

Reviewed-on: eden-emu/eden#2616
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 18:42:51 +02:00
9f423a24b8
[linux] fix aarch64 builds (again) + fix with slightly outdated qt (#2612)
Fixes issues building on aarch64 linux with a slightly outdated system qt; also fixes linker selection process

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

Reviewed-on: eden-emu/eden#2612
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 18:42:28 +02:00
50ceb9a43a
[.ci] install-msvc: fix installation on MSVC (#2611)
* changed from Build Tools to Community (congrats Microsoft very cool)
* add spining to show it didnt stopped installing

Signed-off-by: Caio Oliveira <caiooliveirafarias0@gmail.com>

Reviewed-on: eden-emu/eden#2611
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
Co-committed-by: Caio Oliveira <caiooliveirafarias0@gmail.com>
2025-09-29 18:42:04 +02:00
ecb811ad04
[qt] move addons row to rightmost side (#2610)
This is because the rightmost row is "extended" to the rest of the table, and add-ons have long names, play time doesn't need that much space.

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

Reviewed-on: eden-emu/eden#2610
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 18:41:28 +02:00
bf302d7917
[common] No need to specify min/max for settings; fix crash when OOB value is given for some settings (#2609)
This fixes issues when migrating settings that refer to invalid filters/scales. For example if we had 5 filters, but we set filter=6, the program would crash.
This also makes so specifying min/max manually isn't needed (but can still be set for cases like NCE).

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

Reviewed-on: eden-emu/eden#2609
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-29 18:40:29 +02:00
d19a7c3782
[service] unstub process winding (#2590)
It's used on FW19+ and FW20+ but since all 20+ applets stuck on HID, you still can't boot into applets.
Should fix: Bioshock Infinite on FW19

Reviewed-on: eden-emu/eden#2590
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: unknown <sahyno1996@gmail.com>
Co-committed-by: unknown <sahyno1996@gmail.com>
2025-09-28 18:43:01 +02:00
c725641f13
[video_core] Fix fast buffers without performance loss (#2605)
Fixes games that have some elements flickering on the screen, such as Kirby Star Allies and others, without impacting performance.

Reviewed-on: eden-emu/eden#2605
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-09-28 07:29:19 +02:00
nyx
02016697d6
[cmake, macos] Suppress warnings for unused private members (#2583)
Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: eden-emu/eden#2583
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: nyx <contact@innix.space>
Co-committed-by: nyx <contact@innix.space>
2025-09-27 22:40:18 +02:00
c77ad128b9
[cmake] whole-program LTO, prefer lld on clang (#2581)
Reviewed-on: eden-emu/eden#2581
2025-09-27 22:40:08 +02:00
460 changed files with 9292 additions and 4916 deletions

View file

@ -13,8 +13,8 @@ fi
cd src/android
chmod +x ./gradlew
./gradlew assembleRelease
./gradlew bundleRelease
./gradlew assembleMainlineRelease
./gradlew bundleMainlineRelease
if [ ! -z "${ANDROID_KEYSTORE_B64}" ]; then
rm "${ANDROID_KEYSTORE_FILE}"

View file

@ -10,7 +10,7 @@ if (-not ([bool](net session 2>$null))) {
}
$VSVer = "17"
$ExeFile = "vs_BuildTools.exe"
$ExeFile = "vs_community.exe"
$Uri = "https://aka.ms/vs/$VSVer/release/$ExeFile"
$Destination = "./$ExeFile"
@ -19,21 +19,39 @@ $WebClient = New-Object System.Net.WebClient
$WebClient.DownloadFile($Uri, $Destination)
Write-Host "Finished downloading $ExeFile"
$VSROOT = "C:/VSBuildTools/$VSVer"
$Arguments = @(
"--installPath `"$VSROOT`"", # set custom installation path
"--quiet", # suppress UI
"--wait", # wait for installation to complete
"--norestart", # prevent automatic restart
"--add Microsoft.VisualStudio.Workload.VCTools", # add C++ build tools workload
"--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64", # add core x86/x64 C++ tools
"--add Microsoft.VisualStudio.Component.Windows10SDK.19041" # add specific Windows SDK
"--quiet", # Suppress installer UI
"--wait", # Wait for installation to complete
"--norestart", # Prevent automatic restart
"--force", # Force installation even if components are already installed
"--add Microsoft.VisualStudio.Workload.NativeDesktop", # Desktop development with C++
"--add Microsoft.VisualStudio.Component.VC.Tools.x86.x64", # Core C++ compiler/tools for x86/x64
"--add Microsoft.VisualStudio.Component.Windows11SDK.26100",# Windows 11 SDK (26100)
"--add Microsoft.VisualStudio.Component.Windows10SDK.19041",# Windows 10 SDK (19041)
"--add Microsoft.VisualStudio.Component.VC.Llvm.Clang", # LLVM Clang compiler
"--add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset", # LLVM Clang integration toolset
"--add Microsoft.VisualStudio.Component.Windows11SDK.22621",# Windows 11 SDK (22621)
"--add Microsoft.VisualStudio.Component.VC.CMake.Project", # CMake project support
"--add Microsoft.VisualStudio.ComponentGroup.VC.Tools.142.x86.x64", # VC++ 14.2 toolset
"--add Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Llvm.Clang" # LLVM Clang for native desktop
)
Write-Host "Installing Visual Studio Build Tools"
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -Wait -ArgumentList $Arguments
$ExitCode = $InstallProcess.ExitCode
$InstallProcess = Start-Process -FilePath $Destination -NoNewWindow -PassThru -ArgumentList $Arguments
# Spinner while installing
$Spinner = "|/-\"
$i = 0
while (-not $InstallProcess.HasExited) {
Write-Host -NoNewline ("`rInstalling... " + $Spinner[$i % $Spinner.Length])
Start-Sleep -Milliseconds 250
$i++
}
# Clear spinner line
Write-Host "`rSetup completed! "
$ExitCode = $InstallProcess.ExitCode
if ($ExitCode -ne 0) {
Write-Host "Error installing Visual Studio Build Tools (Error: $ExitCode)"
Exit $ExitCode

6
.gitignore vendored
View file

@ -10,6 +10,12 @@ doc-build/
AppDir/
uruntime
# dtrace and ktrace stuffs
[dk]trace-out/
[dk]trace.out
*.core
log.txt
# Generated source files
src/common/scm_rev.cpp
dist/english_plurals/generated_en.ts

View file

@ -0,0 +1,12 @@
diff --git a/src/catch2/matchers/catch_matchers_floating_point.cpp b/src/catch2/matchers/catch_matchers_floating_point.cpp
index fc7b444..0e1a3c2 100644
--- a/src/catch2/matchers/catch_matchers_floating_point.cpp
+++ b/src/catch2/matchers/catch_matchers_floating_point.cpp
@@ -5,6 +5,7 @@
// https://www.boost.org/LICENSE_1_0.txt)
// SPDX-License-Identifier: BSL-1.0
+#include <catch2/internal/catch_polyfills.hpp>
#include <catch2/matchers/catch_matchers_floating_point.hpp>
#include <catch2/internal/catch_enforce.hpp>
#include <catch2/internal/catch_polyfills.hpp>

View file

@ -0,0 +1,25 @@
diff --git a/libusb/os/netbsd_usb.c b/libusb/os/netbsd_usb.c
index a9a50b2..56e681b 100644
--- a/libusb/os/netbsd_usb.c
+++ b/libusb/os/netbsd_usb.c
@@ -580,6 +580,20 @@ _access_endpoint(struct libusb_transfer *transfer)
return hpriv->endpoints[endpt];
}
+void usbi_get_monotonic_time(struct timespec *tp) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ tp->tv_sec = tv.tv_sec;
+ tp->tv_nsec = tv.tv_usec * 1000ull;
+}
+
+void usbi_get_real_time(struct timespec *tp) {
+ struct timeval tv;
+ gettimeofday(&tv, NULL);
+ tp->tv_sec = tv.tv_sec;
+ tp->tv_nsec = tv.tv_usec * 1000ull;
+}
+
int
_sync_gen_transfer(struct usbi_transfer *itransfer)
{

View file

@ -0,0 +1,13 @@
diff --git a/library/aesni.h b/library/aesni.h
index 754c984c79..59e27afd3e 100644
--- a/library/aesni.h
+++ b/library/aesni.h
@@ -35,7 +35,7 @@
/* GCC-like compilers: currently, we only support intrinsics if the requisite
* target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2`
* or `clang -maes -mpclmul`). */
-#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__)
+#if defined(__GNUC__) || defined(__clang__)
#define MBEDTLS_AESNI_HAVE_INTRINSICS
#endif
/* For 32-bit, we only support intrinsics */

View file

@ -0,0 +1,22 @@
diff --git a/library/aesni.c b/library/aesni.c
index 2857068..3e104ab 100644
--- a/library/aesni.c
+++ b/library/aesni.c
@@ -31,16 +31,14 @@
#include <immintrin.h>
#endif
-#if defined(MBEDTLS_ARCH_IS_X86)
#if defined(MBEDTLS_COMPILER_IS_GCC)
#pragma GCC push_options
#pragma GCC target ("pclmul,sse2,aes")
#define MBEDTLS_POP_TARGET_PRAGMA
-#elif defined(__clang__) && (__clang_major__ >= 5)
+#elif defined(__clang__)
#pragma clang attribute push (__attribute__((target("pclmul,sse2,aes"))), apply_to=function)
#define MBEDTLS_POP_TARGET_PRAGMA
#endif
-#endif
#if !defined(MBEDTLS_AES_USE_HARDWARE_ONLY)
/*

View file

@ -0,0 +1,55 @@
diff --git a/include/mcl/assert.hpp b/include/mcl/assert.hpp
index f77dbe7..9ec0b9c 100644
--- a/include/mcl/assert.hpp
+++ b/include/mcl/assert.hpp
@@ -23,8 +23,11 @@ template<typename... Ts>
} // namespace mcl::detail
+#ifndef UNREACHABLE
#define UNREACHABLE() ASSERT_FALSE("Unreachable code!")
+#endif
+#ifndef ASSERT
#define ASSERT(expr) \
[&] { \
if (std::is_constant_evaluated()) { \
@@ -37,7 +40,9 @@ template<typename... Ts>
} \
} \
}()
+#endif
+#ifndef ASSERT_MSG
#define ASSERT_MSG(expr, ...) \
[&] { \
if (std::is_constant_evaluated()) { \
@@ -50,13 +55,24 @@ template<typename... Ts>
} \
} \
}()
+#endif
+#ifndef ASSERT_FALSE
#define ASSERT_FALSE(...) ::mcl::detail::assert_terminate("false", __VA_ARGS__)
+#endif
#if defined(NDEBUG) || defined(MCL_IGNORE_ASSERTS)
-# define DEBUG_ASSERT(expr) ASSUME(expr)
-# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
+# ifndef DEBUG_ASSERT
+# define DEBUG_ASSERT(expr) ASSUME(expr)
+# endif
+# ifndef DEBUG_ASSERT_MSG
+# define DEBUG_ASSERT_MSG(expr, ...) ASSUME(expr)
+# endif
#else
-# define DEBUG_ASSERT(expr) ASSERT(expr)
-# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
+# ifndef DEBUG_ASSERT
+# define DEBUG_ASSERT(expr) ASSERT(expr)
+# endif
+# ifndef DEBUG_ASSERT_MSG
+# define DEBUG_ASSERT_MSG(expr, ...) ASSERT_MSG(expr, __VA_ARGS__)
+# endif
#endif

View file

@ -0,0 +1,14 @@
diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt
index eb4e69e..3155805 100644
--- a/external/CMakeLists.txt
+++ b/external/CMakeLists.txt
@@ -72,7 +72,8 @@ if (SPIRV_TOOLS_USE_MIMALLOC)
pop_variable(MI_BUILD_TESTS)
endif()
-if (DEFINED SPIRV-Headers_SOURCE_DIR)
+# NetBSD doesn't have SPIRV-Headers readily available on system
+if (DEFINED SPIRV-Headers_SOURCE_DIR AND NOT ${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
# This allows flexible position of the SPIRV-Headers repo.
set(SPIRV_HEADER_DIR ${SPIRV-Headers_SOURCE_DIR})
else()

View file

@ -13,12 +13,13 @@ Copyright: yuzu Emulator Project
License: GPL-2.0-or-later
Files: dist/qt_themes/default/icons/256x256/eden.png
dist/qt_themes/default/icons/256x256/eden_named.png
dist/yuzu.bmp
dist/yuzu.icns
dist/eden.icns
dist/eden.ico
dist/eden.svg
Copyright: yuzu Emulator Project
License: GPL-2.0-or-later
dist/dev.eden_emu.eden.svg
Copyright: 2025 Eden Emulator Project
License: GPL-3.0-or-later
Files: dist/qt_themes/qdarkstyle*/LICENSE.*
dist/qt_themes/qdarkstyle*/style.qrc
@ -155,3 +156,39 @@ License: BSD-3-Clause
Files: src/android/app/debug.keystore
Copyright: 2023 yuzu Emulator Project
License: GPL-3.0-or-later
Files: dist/qt_themes/colorful/icons/48x48/user-trash.png
dist/qt_themes/colorful/icons/48x48/upload.png
dist/qt_themes/colorful/icons/48x48/download.png
Copyright: 2014 Uri Herrera
1996-2025 KDE Software Foundation
License: LGPL-2.0-or-later
Files: dist/qt_themes/default/icons/48x48/user-trash.png
dist/qt_themes/default/icons/48x48/upload.png
dist/qt_themes/default/icons/48x48/download.png
dist/qt_themes/default_dark/icons/48x48/user-trash.png
dist/qt_themes/default_dark/icons/48x48/upload.png
dist/qt_themes/default_dark/icons/48x48/download.png
Copyright: 2025 Fonticons, Inc.
License: CC-BY-4.0
Comment: All of these icons have been modified by crueter <crueter@crueter.xyz>
Files: CMakeModules/CPM.cmake
Copyright: 2019-2023 Lars Melchior
License: MIT
Files: CMakeModules/CPMUtil.cmake
CMakeModules/CPM.cmake
CMakeModules/GetSCMRev.cmake
CMakeModules/DetectArchitecture.cmake
tools/cpm/*
tools/update-cpm.sh
tools/shellcheck.sh
docs/CPMUtil.md
**cpmfile.json
Copyright: 2025 crueter <crueter@crueter.xyz>
License: GPL-3.0-or-later
Comment: CPM.cmake has had additional modifications from crueter to better work with CPMUtil
https://git.crueter.xyz/CMake/CPMUtil
https://git.crueter.xyz/CMake/Modules

1
.shellcheckrc Normal file
View file

@ -0,0 +1 @@
shell=sh

View file

@ -11,6 +11,8 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(PLATFORM_FREEBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(PLATFORM_OPENBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
set(PLATFORM_NETBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(PLATFORM_LINUX ON)
endif()
@ -32,16 +34,29 @@ endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
# NB: this does not account for SPARC
# If you get Eden working on SPARC, please shoot crueter@crueter.xyz multiple emails
# and you will be hailed for eternity
if (PLATFORM_SUN)
# Terrific Solaris pkg shenanigans
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
list(APPEND CMAKE_MODULE_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
# Amazing - absolutely incredible
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/amd64/cmake")
list(APPEND CMAKE_MODULE_PATH "/usr/lib/amd64/cmake")
# For some mighty reason, doing a normal release build sometimes may not trigger
# the proper -O3 switch to materialize
if (CMAKE_BUILD_TYPE MATCHES "Release")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif()
if (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
endif()
endif()
# Needed for FFmpeg w/ VAAPI and DRM
@ -49,6 +64,15 @@ if (PLATFORM_OPENBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R6/include")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R6/include")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R6/lib")
elseif (PLATFORM_NETBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R7/include")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R7/include")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R7/lib")
endif()
# NetBSD: Fun for the whole family!
if (PLATFORM_NETBSD)
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:/usr/pkg/lib/ffmpeg7/pkgconfig")
endif()
# Detect current compilation architecture and create standard definitions
@ -135,77 +159,105 @@ endif()
if (PLATFORM_FREEBSD)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
endif()
# Set bundled sdl2/qt as dependent options.
# On Linux system SDL2 is likely to be lacking HIDAPI support which have drawbacks but is needed for SDL motion
CMAKE_DEPENDENT_OPTION(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
cmake_dependent_option(ENABLE_SDL2 "Enable the SDL2 frontend" ON "NOT ANDROID" OFF)
if (ENABLE_SDL2)
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" OFF "NOT MSVC" OFF)
option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}")
endif()
# qt stuff
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
set(EXT_DEFAULT OFF)
if (MSVC OR ANDROID)
set(EXT_DEFAULT ON)
endif()
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
CMAKE_DEPENDENT_OPTION(YUZU_USE_EXTERNAL_SDL2 "Compile external SDL2" ${EXT_DEFAULT} "ENABLE_SDL2;NOT MSVC" OFF)
# ffmpeg
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" "${PLATFORM_SUN}" "NOT WIN32 AND NOT ANDROID" OFF)
# sirit
option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${EXT_DEFAULT})
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "NOT ANDROID" OFF)
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT WIN32 OR NOT ARCHITECTURE_arm64" OFF)
mark_as_advanced(FORCE ENABLE_OPENGL)
option(ENABLE_QT "Enable the Qt frontend" ON)
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
option(ENABLE_QT_UPDATE_CHECKER "Enable update checker for the Qt frontend" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
option(YUZU_USE_CPM "Use CPM to fetch system dependencies (fmt, boost, etc) if needed. Externals will still be fetched." ${EXT_DEFAULT})
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
option(ENABLE_WIFI_SCAN "Enable WiFi scanning" OFF)
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from source" OFF "NOT WIN32 AND NOT ANDROID" OFF)
option(YUZU_USE_QT_MULTIMEDIA "Use QtMultimedia for Camera" OFF)
option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet implementation" OFF)
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
CMAKE_DEPENDENT_OPTION(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
cmake_dependent_option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF "ENABLE_QT" OFF)
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ${EXT_DEFAULT})
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
if (YUZU_USE_PRECOMPILED_HEADERS)
message(STATUS "Using Precompiled Headers.")
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
endif()
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
if(YUZU_ENABLE_LTO)
include(CheckIPOSupported)
check_ipo_supported(RESULT COMPILER_SUPPORTS_LTO)
if(NOT COMPILER_SUPPORTS_LTO)
message(FATAL_ERROR "Your compiler does not support interprocedural optimization (IPO). Re-run CMake with -DYUZU_ENABLE_LTO=OFF.")
endif()
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${COMPILER_SUPPORTS_LTO})
endif()
option(USE_CCACHE "Use ccache for compilation" OFF)
set(CCACHE_PATH "ccache" CACHE STRING "Path to ccache binary")
if(USE_CCACHE)
find_program(CCACHE_BINARY ${CCACHE_PATH})
if(CCACHE_BINARY)
message(STATUS "Found ccache at: ${CCACHE_BINARY}")
set(CMAKE_C_COMPILER_LAUNCHER ${CCACHE_BINARY})
set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE_BINARY})
if (YUZU_USE_PRECOMPILED_HEADERS)
message(FATAL_ERROR "Precompiled headers are incompatible with ccache. Re-run CMake with -DYUZU_USE_PRECOMPILED_HEADERS=OFF.")
endif()
else()
message(WARNING "USE_CCACHE enabled, but no executable found at: ${CCACHE_PATH}")
endif()
endif()
# TODO(crueter): CI this?
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "ENABLE_SDL2" OFF)
option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.g. Snapdragon 865) at the cost of performance" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
cmake_dependent_option(YUZU_ROOM "Enable dedicated room functionality" ON "NOT ANDROID" OFF)
cmake_dependent_option(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_ROOM_STANDALONE "Enable standalone room executable" ON "YUZU_ROOM" OFF)
cmake_dependent_option(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_CMD "Compile the eden-cli executable" ON "ENABLE_SDL2;NOT ANDROID" OFF)
CMAKE_DEPENDENT_OPTION(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
option(YUZU_ENABLE_LTO "Enable link-time optimization" OFF)
cmake_dependent_option(YUZU_CRASH_DUMPS "Compile crash dump (Minidump) support" OFF "WIN32 OR LINUX" OFF)
option(YUZU_DOWNLOAD_TIME_ZONE_DATA "Always download time zone binaries" ON)
CMAKE_DEPENDENT_OPTION(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "NOT WIN32" OFF)
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_MOLTENVK "Use the system MoltenVK lib (instead of the bundled one)" OFF "APPLE" OFF)
set(YUZU_TZDB_PATH "" CACHE STRING "Path to a pre-downloaded timezone database")
cmake_dependent_option(YUZU_USE_FASTER_LD "Check if a faster linker is available" ON "LINUX" OFF)
cmake_dependent_option(YUZU_USE_BUNDLED_MOLTENVK "Download bundled MoltenVK lib" ON "APPLE" OFF)
option(YUZU_DISABLE_LLVM "Disable LLVM (useful for CI)" OFF)
set(DEFAULT_ENABLE_OPENSSL ON)
@ -218,15 +270,16 @@ if (ANDROID OR WIN32 OR APPLE OR PLATFORM_SUN)
# your own copy of it.
set(DEFAULT_ENABLE_OPENSSL OFF)
endif()
if (ENABLE_WEB_SERVICE)
set(DEFAULT_ENABLE_OPENSSL ON)
endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
if (ENABLE_OPENSSL)
CMAKE_DEPENDENT_OPTION(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
if (EXT_DEFAULT OR PLATFORM_SUN)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
endif()
option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL})
endif()
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
@ -253,19 +306,11 @@ if (ANDROID)
set(CMAKE_POLICY_VERSION_MINIMUM 3.5) # Workaround for Oboe
endif()
if (YUZU_USE_PRECOMPILED_HEADERS)
if (MSVC AND CCACHE)
# buildcache does not properly cache PCH files, leading to compilation errors.
# See https://github.com/mbitsnbites/buildcache/discussions/230
message(WARNING "buildcache does not properly support Precompiled Headers. Disabling PCH")
set(DYNARMIC_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
set(YUZU_USE_PRECOMPILED_HEADERS OFF CACHE BOOL "" FORCE)
endif()
endif()
if (YUZU_USE_PRECOMPILED_HEADERS)
message(STATUS "Using Precompiled Headers.")
set(CMAKE_PCH_INSTANTIATE_TEMPLATES ON)
# We need to downgrade debug info (/Zi -> /Z7) to use an older but more cacheable format
# See https://github.com/nanoant/CMakePCHCompiler/issues/21
if(WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
endif()
# Default to a Release build
@ -307,16 +352,32 @@ if (UNIX)
add_compile_definitions(YUZU_UNIX=1)
endif()
if (YUZU_LEGACY)
message(WARNING "Making legacy build. Performance may suffer.")
add_compile_definitions(YUZU_LEGACY)
endif()
if (ARCHITECTURE_arm64 AND (ANDROID OR PLATFORM_LINUX))
set(HAS_NCE 1)
add_compile_definitions(HAS_NCE=1)
find_package(oaknut 2.0.1)
endif()
if (YUZU_ROOM)
add_compile_definitions(YUZU_ROOM)
endif()
if ((ANDROID OR APPLE OR UNIX) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32)
if(CXX_APPLE OR CXX_CLANG)
# libc++ has stop_token and jthread as experimental
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fexperimental-library")
else()
# Uses glibc, mostly?
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_LIBCPP_ENABLE_EXPERIMENTAL=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_LIBCPP_ENABLE_EXPERIMENTAL=1")
endif()
endif()
# Build/optimization presets
if (PLATFORM_LINUX OR CXX_CLANG)
if (ARCHITECTURE_x86_64)
@ -436,22 +497,7 @@ if (YUZU_USE_CPM)
if (zstd_ADDED)
add_library(zstd::zstd ALIAS libzstd_static)
endif()
# Catch2
if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2)
endif()
# ENet
AddJsonPackage(enet)
if (enet_ADDED)
target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include)
endif()
if (NOT TARGET enet::enet)
add_library(enet::enet ALIAS enet)
add_library(zstd::libzstd ALIAS libzstd_static)
endif()
# Opus
@ -468,31 +514,10 @@ if (YUZU_USE_CPM)
if (NOT TARGET Opus::opus)
add_library(Opus::opus ALIAS opus)
endif()
# VulkanUtilityHeaders - pulls in headers and utility libs
AddJsonPackage(vulkan-utility-headers)
# small hack
if (NOT VulkanUtilityLibraries_ADDED)
find_package(VulkanHeaders 1.3.274 REQUIRED)
endif()
# SPIRV Headers
AddJsonPackage(spirv-headers)
# SPIRV Tools
AddJsonPackage(spirv-tools)
if (SPIRV-Tools_ADDED)
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static)
target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link)
endif()
# mbedtls
AddJsonPackage(mbedtls)
else()
# Enforce the search mode of non-required packages for better and shorter failure messages
find_package(fmt 8 REQUIRED)
if (NOT YUZU_DISABLE_LLVM)
find_package(LLVM MODULE COMPONENTS Demangle)
endif()
@ -501,39 +526,16 @@ else()
find_package(lz4 REQUIRED)
find_package(RenderDoc MODULE)
find_package(stb MODULE)
find_package(enet 1.3 MODULE REQUIRED)
find_package(Opus 1.3 MODULE REQUIRED)
find_package(ZLIB 1.2 REQUIRED)
find_package(zstd 1.5 REQUIRED MODULE)
# wow
if (PLATFORM_LINUX)
find_package(Boost 1.57.0 REQUIRED headers context system fiber)
find_package(Boost 1.57.0 CONFIG REQUIRED headers context system fiber)
else()
find_package(Boost 1.57.0 REQUIRED)
endif()
# OpenBSD does not package mbedtls3 (only 2)
if (PLATFORM_OPENBSD)
AddJsonPackage(mbedtls)
else()
find_package(MbedTLS 3 REQUIRED)
endif()
find_package(VulkanUtilityLibraries REQUIRED)
find_package(VulkanHeaders 1.3.274 REQUIRED)
# FreeBSD does not package spirv-headers
if (PLATFORM_FREEBSD)
AddJsonPackage(spirv-headers)
else()
find_package(SPIRV-Headers 1.3.274 REQUIRED)
endif()
find_package(SPIRV-Tools MODULE REQUIRED)
if (YUZU_TESTS)
find_package(Catch2 3.0.1 REQUIRED)
find_package(Boost 1.57.0 CONFIG REQUIRED)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR ANDROID)
@ -549,90 +551,6 @@ if(NOT TARGET Boost::headers)
AddJsonPackage(boost_headers)
endif()
# DiscordRPC
if (USE_DISCORD_PRESENCE)
if (ARCHITECTURE_arm64)
add_compile_definitions(RAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN)
endif()
AddJsonPackage(discord-rpc)
target_include_directories(discord-rpc INTERFACE ${discord-rpc_SOURCE_DIR}/include)
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
endif()
# SimpleIni
AddJsonPackage(simpleini)
# Most linux distros don't package cubeb, so enable regardless of cpm settings
if(ENABLE_CUBEB)
AddJsonPackage(cubeb)
if (cubeb_ADDED)
if (NOT MSVC)
if (TARGET speex)
target_compile_options(speex PRIVATE -Wno-sign-compare)
endif()
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
target_compile_options(cubeb INTERFACE
-Wno-implicit-const-int-float-conversion
-Wno-shadow
-Wno-missing-declarations
-Wno-return-type
-Wno-uninitialized
)
else()
target_compile_options(cubeb PRIVATE
/wd4456
/wd4458
)
endif()
endif()
if (NOT TARGET cubeb::cubeb)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
endif()
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
if (ENABLE_SDL2)
if (YUZU_USE_EXTERNAL_SDL2)
message(STATUS "Using SDL2 from externals.")
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
set(HIDAPI ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
set(SDL_PIPEWIRE OFF) # build errors out with this on
AddJsonPackage("sdl2_steamdeck")
else()
AddJsonPackage("sdl2_generic")
endif()
elseif (YUZU_USE_BUNDLED_SDL2)
message(STATUS "Using bundled SDL2")
AddJsonPackage(sdl2)
endif()
find_package(SDL2 2.26.4 REQUIRED)
endif()
# List of all FFmpeg components required
set(FFmpeg_COMPONENTS
avcodec
@ -663,19 +581,46 @@ add_subdirectory(externals)
# pass targets from externals
find_package(libusb)
find_package(VulkanMemoryAllocator)
find_package(enet)
find_package(MbedTLS)
find_package(VulkanUtilityLibraries)
find_package(SimpleIni)
find_package(SPIRV-Tools)
find_package(sirit)
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
find_package(xbyak)
endif()
if (ENABLE_WEB_SERVICE)
find_package(httplib)
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
# Workaround: httplib will kill itself if you attempt to do a find_package propagation
# find_package(httplib CONFIG)
endif()
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
if (ENABLE_WEB_SERVICE)
find_package(cpp-jwt)
endif()
if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS)
find_package(oaknut)
endif()
if (ENABLE_SDL2)
find_package(SDL2)
endif()
if (USE_DISCORD_PRESENCE)
find_package(DiscordRPC)
endif()
if (ENABLE_CUBEB)
find_package(cubeb)
endif()
if (YUZU_TESTS OR DYNARMIC_TESTS)
find_package(Catch2)
endif()
if (ENABLE_QT)
if (YUZU_USE_BUNDLED_QT)
download_qt(6.8.3)
@ -694,6 +639,8 @@ if (ENABLE_QT)
endif()
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
# yes Qt, we get it
set(QT_NO_PRIVATE_MODULE_WARNING ON)
find_package(Qt6 REQUIRED COMPONENTS DBus OPTIONAL_COMPONENTS GuiPrivate)
elseif (UNIX AND NOT APPLE)
find_package(Qt6 REQUIRED COMPONENTS DBus Gui)
@ -884,18 +831,46 @@ if (MSVC AND CXX_CLANG)
link_libraries(llvm-mingw-runtime)
endif()
if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# We will assume that if the compiler is GCC, it will attempt to use ld.bfd by default.
# Try to pick a faster linker.
find_program(LLD lld)
find_program(MOLD mold)
#[[
search order:
- gold (GCC only) - the best, generally, but unfortunately not packaged anymore
- mold (GCC only) - generally does well on GCC
- ldd - preferred on clang
- bfd - the final fallback
- If none are found (macOS uses ld.prime, etc) just use the default linker
]]
if (YUZU_USE_FASTER_LD)
find_program(LINKER_BFD bfd)
if (LINKER_BFD)
set(LINKER bfd)
endif()
if (MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
message(NOTICE "Selecting mold as linker")
add_link_options("-fuse-ld=mold")
elseif (LLD)
message(NOTICE "Selecting lld as linker")
add_link_options("-fuse-ld=lld")
find_program(LINKER_LLD lld)
if (LINKER_LLD)
set(LINKER lld)
endif()
if (CXX_GCC)
find_program(LINKER_MOLD mold)
if (LINKER_MOLD AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "12.1")
set(LINKER mold)
endif()
find_program(LINKER_GOLD gold)
if (LINKER_GOLD)
set(LINKER gold)
endif()
endif()
if (LINKER)
message(NOTICE "Selecting ${LINKER} as linker")
add_link_options("-fuse-ld=${LINKER}")
else()
message(WARNING "No faster linker found--using default")
endif()
if (LINKER STREQUAL "lld" AND CXX_GCC)
message(WARNING "Using lld on GCC may cause issues with certain LTO settings. If the program fails to compile, disable YUZU_USE_FASTER_LD, or install mold or GNU gold.")
endif()
endif()

View file

@ -743,9 +743,11 @@ function(CPMAddPackage)
if(NOT DEFINED CPM_ARGS_NAME)
set(CPM_ARGS_NAME ${nameFromUrl})
endif()
if(NOT DEFINED CPM_ARGS_VERSION)
set(CPM_ARGS_VERSION ${verFromUrl})
endif()
# this is dumb and should not be done
# if(NOT DEFINED CPM_ARGS_VERSION)
# set(CPM_ARGS_VERSION ${verFromUrl})
# endif()
list(APPEND CPM_ARGS_UNPARSED_ARGUMENTS URL "${CPM_ARGS_URL}")
endif()

View file

@ -107,7 +107,6 @@ function(AddJsonPackage)
get_json_element("${object}" name name "${JSON_NAME}")
get_json_element("${object}" extension extension "tar.zst")
get_json_element("${object}" min_version min_version "")
get_json_element("${object}" cmake_filename cmake_filename "")
get_json_element("${object}" raw_disabled disabled_platforms "")
if (raw_disabled)
@ -124,7 +123,6 @@ function(AddJsonPackage)
EXTENSION ${extension}
MIN_VERSION ${min_version}
DISABLED_PLATFORMS ${disabled_platforms}
CMAKE_FILENAME ${cmake_filename}
)
# pass stuff to parent scope
@ -139,6 +137,7 @@ function(AddJsonPackage)
endif()
get_json_element("${object}" hash hash "")
get_json_element("${object}" hash_suffix hash_suffix "")
get_json_element("${object}" sha sha "")
get_json_element("${object}" url url "")
get_json_element("${object}" key key "")
@ -208,6 +207,7 @@ function(AddJsonPackage)
VERSION "${version}"
URL "${url}"
HASH "${hash}"
HASH_SUFFIX "${hash_suffix}"
SHA "${sha}"
REPO "${repo}"
KEY "${key}"
@ -277,6 +277,7 @@ function(AddPackage)
KEY
BUNDLED_PACKAGE
FORCE_BUNDLED_PACKAGE
FIND_PACKAGE_ARGUMENTS
)
@ -426,7 +427,9 @@ function(AddPackage)
- BUNDLED_PACKAGE
- default to allow local
]]#
if (${PKG_ARGS_NAME}_FORCE_SYSTEM)
if (PKG_ARGS_FORCE_BUNDLED_PACKAGE)
set_precedence(OFF OFF)
elseif (${PKG_ARGS_NAME}_FORCE_SYSTEM)
set_precedence(ON ON)
elseif (${PKG_ARGS_NAME}_FORCE_BUNDLED)
set_precedence(OFF OFF)
@ -446,9 +449,14 @@ function(AddPackage)
set_precedence(ON OFF)
endif()
if (DEFINED PKG_ARGS_VERSION)
list(APPEND EXTRA_ARGS
VERSION ${PKG_ARGS_VERSION}
)
endif()
CPMAddPackage(
NAME ${PKG_ARGS_NAME}
VERSION ${PKG_ARGS_VERSION}
URL ${pkg_url}
URL_HASH ${pkg_hash}
CUSTOM_CACHE_KEY ${pkg_key}
@ -459,6 +467,8 @@ function(AddPackage)
PATCHES ${PKG_ARGS_PATCHES}
EXCLUDE_FROM_ALL ON
${EXTRA_ARGS}
${PKG_ARGS_UNPARSED_ARGUMENTS}
)
@ -511,12 +521,12 @@ function(add_ci_package key)
NAME ${ARTIFACT_PACKAGE}
REPO ${ARTIFACT_REPO}
TAG v${ARTIFACT_VERSION}
VERSION ${ARTIFACT_VERSION}
GIT_VERSION ${ARTIFACT_VERSION}
ARTIFACT ${ARTIFACT}
KEY ${key}
KEY ${key}-${ARTIFACT_VERSION}
HASH_SUFFIX sha512sum
BUNDLED_PACKAGE ON
FORCE_BUNDLED_PACKAGE ON
)
set(ARTIFACT_DIR ${${ARTIFACT_PACKAGE}_SOURCE_DIR} PARENT_SCOPE)
@ -533,7 +543,6 @@ function(AddCIPackage)
EXTENSION
MIN_VERSION
DISABLED_PLATFORMS
CMAKE_FILENAME
)
cmake_parse_arguments(PKG_ARGS "" "${oneValueArgs}" "" ${ARGN})
@ -589,25 +598,28 @@ function(AddCIPackage)
add_ci_package(android)
endif()
if(PLATFORM_SUN AND NOT "solaris" IN_LIST DISABLED_PLATFORMS)
add_ci_package(solaris)
if(PLATFORM_SUN AND NOT "solaris-amd64" IN_LIST DISABLED_PLATFORMS)
add_ci_package(solaris-amd64)
endif()
if(PLATFORM_FREEBSD AND NOT "freebsd" IN_LIST DISABLED_PLATFORMS)
add_ci_package(freebsd)
if(PLATFORM_FREEBSD AND NOT "freebsd-amd64" IN_LIST DISABLED_PLATFORMS)
add_ci_package(freebsd-amd64)
endif()
if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux" IN_LIST DISABLED_PLATFORMS)
add_ci_package(linux)
if((PLATFORM_LINUX AND ARCHITECTURE_x86_64) AND NOT "linux-amd64" IN_LIST DISABLED_PLATFORMS)
add_ci_package(linux-amd64)
endif()
if((PLATFORM_LINUX AND ARCHITECTURE_arm64) AND NOT "linux-aarch64" IN_LIST DISABLED_PLATFORMS)
add_ci_package(linux-aarch64)
endif()
if (DEFINED ARTIFACT_DIR)
include(${ARTIFACT_DIR}/${ARTIFACT_CMAKE}.cmake)
# TODO(crueter): macOS amd64/aarch64 split mayhaps
if (APPLE AND NOT "macos-universal" IN_LIST DISABLED_PLATFORMS)
add_ci_package(macos-universal)
endif()
if (DEFINED ARTIFACT_DIR)
set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE)
set(${ARTIFACT_PACKAGE}_SOURCE_DIR "${ARTIFACT_DIR}" PARENT_SCOPE)
else()

View file

@ -10,6 +10,7 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
set(package_base_url "https://github.com/eden-emulator/")
set(package_repo "no_platform")
set(package_extension "no_platform")
set(CACHE_KEY "")
# TODO(crueter): Need to convert ffmpeg to a CI.
if (WIN32 OR FORCE_WIN_ARCHIVES)
@ -33,8 +34,9 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
else()
message(FATAL_ERROR "No package available for this platform")
endif()
set(package_url "${package_base_url}${package_repo}")
set(full_url ${package_url}${remote_path}${lib_name}${package_extension})
string(CONCAT package_url "${package_base_url}" "${package_repo}")
string(CONCAT full_url "${package_url}" "${remote_path}" "${lib_name}" "${package_extension}")
message(STATUS "Resolved bundled URL: ${full_url}")
# TODO(crueter): DELETE THIS ENTIRELY, GLORY BE TO THE CI!
AddPackage(
@ -47,26 +49,12 @@ function(download_bundled_external remote_path lib_name cpm_key prefix_var versi
# TODO(crueter): hash
)
if (DEFINED ${cpm_key}_SOURCE_DIR)
set(${prefix_var} "${${cpm_key}_SOURCE_DIR}" PARENT_SCOPE)
message(STATUS "Using bundled binaries at ${${cpm_key}_SOURCE_DIR}")
endfunction()
function(download_moltenvk_external platform version)
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
if (NOT EXISTS ${MOLTENVK_DIR})
if (NOT EXISTS ${MOLTENVK_TAR})
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar
${MOLTENVK_TAR} SHOW_PROGRESS)
else()
message(FATAL_ERROR "AddPackage did not set ${cpm_key}_SOURCE_DIR")
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
endif()
# Add the MoltenVK library path to the prefix so find_library can locate it.
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endfunction()
# Determine installation parameters for OS, architecture, and compiler
@ -108,7 +96,7 @@ function(determine_qt_parameters target host_out type_out arch_out arch_path_out
set(host "linux")
set(type "desktop")
set(arch "linux_gcc_64")
set(arch_path "linux")
set(arch_path "gcc_64")
endif()
set(${host_out} "${host}" PARENT_SCOPE)
@ -143,56 +131,79 @@ function(download_qt_configuration prefix_out target host type arch arch_path ba
set(install_args -c "${CURRENT_MODULE_DIR}/aqt_config.ini")
if (tool)
set(prefix "${base_path}/Tools")
set(install_args ${install_args} install-tool --outputdir ${base_path} ${host} desktop ${target})
list(APPEND install_args install-tool --outputdir "${base_path}" "${host}" desktop "${target}")
else()
set(prefix "${base_path}/${target}/${arch_path}")
set(install_args ${install_args} install-qt --outputdir ${base_path} ${host} ${type} ${target} ${arch} -m qt_base)
list(APPEND install_args install-qt --outputdir "${base_path}" "${host}" "${type}" "${target}" "${arch}" -m qt_base)
if (YUZU_USE_QT_MULTIMEDIA)
set(install_args ${install_args} qtmultimedia)
list(APPEND install_args qtmultimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
set(install_args ${install_args} qtpositioning qtwebchannel qtwebengine)
list(APPEND install_args qtpositioning qtwebchannel qtwebengine)
endif()
if (NOT ${YUZU_QT_MIRROR} STREQUAL "")
if (NOT "${YUZU_QT_MIRROR}" STREQUAL "")
message(STATUS "Using Qt mirror ${YUZU_QT_MIRROR}")
set(install_args ${install_args} -b ${YUZU_QT_MIRROR})
list(APPEND install_args -b "${YUZU_QT_MIRROR}")
endif()
endif()
message(STATUS "Install Args ${install_args}")
message(STATUS "Install Args: ${install_args}")
if (NOT EXISTS "${prefix}")
message(STATUS "Downloading Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path}")
set(AQT_PREBUILD_BASE_URL "https://github.com/miurahr/aqtinstall/releases/download/v3.3.0")
if (WIN32)
set(aqt_path "${base_path}/aqt.exe")
if (NOT EXISTS "${aqt_path}")
file(DOWNLOAD
${AQT_PREBUILD_BASE_URL}/aqt.exe
${aqt_path} SHOW_PROGRESS)
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt.exe" "${aqt_path}" SHOW_PROGRESS)
endif()
execute_process(COMMAND "${aqt_path}" ${install_args}
WORKING_DIRECTORY "${base_path}"
RESULT_VARIABLE aqt_res
OUTPUT_VARIABLE aqt_out
ERROR_VARIABLE aqt_err)
if (NOT aqt_res EQUAL 0)
message(FATAL_ERROR "aqt.exe failed: ${aqt_err}")
endif()
execute_process(COMMAND ${aqt_path} ${install_args}
WORKING_DIRECTORY ${base_path})
elseif (APPLE)
set(aqt_path "${base_path}/aqt-macos")
if (NOT EXISTS "${aqt_path}")
file(DOWNLOAD
${AQT_PREBUILD_BASE_URL}/aqt-macos
${aqt_path} SHOW_PROGRESS)
file(DOWNLOAD "${AQT_PREBUILD_BASE_URL}/aqt-macos" "${aqt_path}" SHOW_PROGRESS)
endif()
execute_process(COMMAND chmod +x "${aqt_path}")
execute_process(COMMAND "${aqt_path}" ${install_args}
WORKING_DIRECTORY "${base_path}"
RESULT_VARIABLE aqt_res
ERROR_VARIABLE aqt_err)
if (NOT aqt_res EQUAL 0)
message(FATAL_ERROR "aqt-macos failed: ${aqt_err}")
endif()
execute_process(COMMAND chmod +x ${aqt_path})
execute_process(COMMAND ${aqt_path} ${install_args}
WORKING_DIRECTORY ${base_path})
else()
find_program(PYTHON3_EXECUTABLE python3)
if (NOT PYTHON3_EXECUTABLE)
message(FATAL_ERROR "python3 is required to install Qt using aqt (pip mode).")
endif()
set(aqt_install_path "${base_path}/aqt")
file(MAKE_DIRECTORY "${aqt_install_path}")
execute_process(COMMAND python3 -m pip install --target=${aqt_install_path} aqtinstall
WORKING_DIRECTORY ${base_path})
execute_process(COMMAND ${CMAKE_COMMAND} -E env PYTHONPATH=${aqt_install_path} python3 -m aqt ${install_args}
WORKING_DIRECTORY ${base_path})
execute_process(COMMAND "${PYTHON3_EXECUTABLE}" -m pip install --target="${aqt_install_path}" aqtinstall
WORKING_DIRECTORY "${base_path}"
RESULT_VARIABLE pip_res
ERROR_VARIABLE pip_err)
if (NOT pip_res EQUAL 0)
message(FATAL_ERROR "pip install aqtinstall failed: ${pip_err}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}" -E env PYTHONPATH="${aqt_install_path}" "${PYTHON3_EXECUTABLE}" -m aqt ${install_args}
WORKING_DIRECTORY "${base_path}"
RESULT_VARIABLE aqt_res
ERROR_VARIABLE aqt_err)
if (NOT aqt_res EQUAL 0)
message(FATAL_ERROR "aqt (python) failed: ${aqt_err}")
endif()
endif()
message(STATUS "Downloaded Qt binaries for ${target}:${host}:${type}:${arch}:${arch_path} to ${prefix}")
@ -210,7 +221,7 @@ endfunction()
function(download_qt target)
determine_qt_parameters("${target}" host type arch arch_path host_type host_arch host_arch_path)
get_external_prefix(qt base_path)
set(base_path "${CMAKE_BINARY_DIR}/externals/qt")
file(MAKE_DIRECTORY "${base_path}")
download_qt_configuration(prefix "${target}" "${host}" "${type}" "${arch}" "${arch_path}" "${base_path}")
@ -227,26 +238,34 @@ function(download_qt target)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endfunction()
function(download_moltenvk)
set(MOLTENVK_PLATFORM "macOS")
function(download_moltenvk version platform)
if(NOT version)
message(FATAL_ERROR "download_moltenvk: version argument is required")
endif()
if(NOT platform)
message(FATAL_ERROR "download_moltenvk: platform argument is required")
endif()
set(MOLTENVK_DIR "${CMAKE_BINARY_DIR}/externals/MoltenVK")
set(MOLTENVK_TAR "${CMAKE_BINARY_DIR}/externals/MoltenVK.tar")
if (NOT EXISTS ${MOLTENVK_DIR})
if (NOT EXISTS ${MOLTENVK_TAR})
file(DOWNLOAD https://github.com/KhronosGroup/MoltenVK/releases/download/v1.2.10-rc2/MoltenVK-all.tar
${MOLTENVK_TAR} SHOW_PROGRESS)
if(NOT EXISTS "${MOLTENVK_DIR}")
if(NOT EXISTS "${MOLTENVK_TAR}")
file(DOWNLOAD "https://github.com/KhronosGroup/MoltenVK/releases/download/${version}/MoltenVK-${platform}.tar"
"${MOLTENVK_TAR}" SHOW_PROGRESS)
endif()
execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals")
execute_process(
COMMAND ${CMAKE_COMMAND} -E tar xf "${MOLTENVK_TAR}"
WORKING_DIRECTORY "${CMAKE_BINARY_DIR}/externals"
RESULT_VARIABLE tar_res
ERROR_VARIABLE tar_err
)
if(NOT tar_res EQUAL 0)
message(FATAL_ERROR "Extracting MoltenVK failed: ${tar_err}")
endif()
# Add the MoltenVK library path to the prefix so find_library can locate it.
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${MOLTENVK_PLATFORM}")
endif()
list(APPEND CMAKE_PREFIX_PATH "${MOLTENVK_DIR}/MoltenVK/dylib/${platform}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
endfunction()
function(get_external_prefix lib_name prefix_var)
set(${prefix_var} "${CMAKE_BINARY_DIR}/externals/${lib_name}" PARENT_SCOPE)
endfunction()

View file

@ -1,9 +1,14 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2022 Alexandre Bouvier <contact@amb.tf>
#
# SPDX-License-Identifier: GPL-3.0-or-later
find_path(DiscordRPC_INCLUDE_DIR discord_rpc.h)
find_package(DiscordRPC CONFIG QUIET)
if (NOT DiscordRPC_FOUND)
find_path(DiscordRPC_INCLUDE_DIR discord_rpc.h)
find_library(DiscordRPC_LIBRARY discord-rpc)
include(FindPackageHandleStandardArgs)
@ -25,3 +30,4 @@ mark_as_advanced(
DiscordRPC_INCLUDE_DIR
DiscordRPC_LIBRARY
)
endif()

View file

@ -13,9 +13,12 @@ find_package_handle_standard_args(zstd
if (zstd_FOUND AND NOT TARGET zstd::zstd)
if (TARGET zstd::libzstd_shared)
add_library(zstd::zstd ALIAS zstd::libzstd_shared)
add_library(zstd::libzstd ALIAS zstd::libzstd_shared)
elseif (TARGET zstd::libzstd_static)
add_library(zstd::zstd ALIAS zstd::libzstd_static)
add_library(zstd::libzstd ALIAS zstd::libzstd_static)
else()
add_library(zstd::zstd ALIAS PkgConfig::ZSTD)
add_library(zstd::libzstd ALIAS PkgConfig::ZSTD)
endif()
endif()

View file

@ -31,7 +31,11 @@ set(GIT_DESC ${BUILD_VERSION})
set(REPO_NAME "Eden")
set(BUILD_ID ${GIT_REFSPEC})
set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ")
set(CXX_COMPILER "${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
# Auto-updater metadata! Must somewhat mirror GitHub API endpoint
set(BUILD_AUTO_UPDATE_WEBSITE "https://github.com")
set(BUILD_AUTO_UPDATE_API "http://api.github.com")
set(BUILD_AUTO_UPDATE_REPO "eden-emulator/Releases")
configure_file(scm_rev.cpp.in scm_rev.cpp @ONLY)

View file

@ -48,6 +48,8 @@ A list of supported games will be available in future. Please be patient.
Check out our [website](https://eden-emu.dev) for the latest news on exciting features, monthly progress reports, and more!
[![Packaging status](https://repology.org/badge/vertical-allrepos/eden-emulator.svg)](https://repology.org/project/eden-emulator/versions)
## Development
Most of the development happens on our Git server. It is also where [our central repository](https://git.eden-emu.dev/eden-emu/eden) is hosted. For development discussions, please join us on [Discord](https://discord.gg/kXAmGCXBGD) or [Revolt](https://rvlt.gg/qKgFEAbH).
@ -63,6 +65,8 @@ Alternatively, if you wish to add translations, go to the [Eden project on Trans
See the [General Build Guide](docs/Build.md)
For information on provided development tooling, see the [Tools directory](./tools)
## Download
You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).

View file

@ -4,8 +4,11 @@
"package": "OpenSSL",
"name": "openssl",
"repo": "crueter-ci/OpenSSL",
"version": "3.5.3",
"min_version": "1.1.1"
"version": "3.6.0",
"min_version": "1.1.1",
"disabled_platforms": [
"macos-universal"
]
},
"boost": {
"package": "Boost",
@ -15,6 +18,7 @@
"hash": "4fb7f6fde92762305aad8754d7643cd918dd1f3f67e104e9ab385b18c73178d72a17321354eb203b790b6702f2cf6d725a5d6e2dfbc63b1e35f9eb59fb42ece9",
"git_version": "1.89.0",
"version": "1.57",
"find_args": "CONFIG",
"patches": [
"0001-clang-cl.patch",
"0002-use-marmasm.patch",
@ -23,12 +27,10 @@
},
"fmt": {
"repo": "fmtlib/fmt",
"sha": "40626af88b",
"hash": "d59f06c24339f223de4ec2afeba1c67b5835a0f350a1ffa86242a72fc3e616a6b8b21798355428d4200c75287308b66634619ffa0b52ba5bd74cc01772ea1a8a",
"tag": "%VERSION%",
"hash": "c4ab814c20fbad7e3f0ae169125a4988a2795631194703251481dc36b18da65c886c4faa9acd046b0a295005217b3689eb0126108a9ba5aac2ca909aae263c2f",
"version": "8",
"options": [
"FMT_INSTALL OFF"
]
"git_version": "12.0.0"
},
"lz4": {
"name": "lz4",
@ -40,16 +42,18 @@
"nlohmann": {
"package": "nlohmann_json",
"repo": "nlohmann/json",
"sha": "55f93686c0",
"hash": "b739749b066800e21154506ea150d2c5cbce8a45344177f46f884547a1399d26753166fd0df8135269ce28cf223552b1b65cd625b88c844d54753f2434900486",
"version": "3.8"
"tag": "v%VERSION%",
"hash": "6cc1e86261f8fac21cc17a33da3b6b3c3cd5c116755651642af3c9e99bb3538fd42c1bd50397a77c8fb6821bc62d90e6b91bcdde77a78f58f2416c62fc53b97d",
"version": "3.8",
"git_version": "3.12.0"
},
"zlib": {
"package": "ZLIB",
"repo": "madler/zlib",
"sha": "51b7f2abda",
"hash": "16eaf1f3752489d12fd9ce30f7b5f7cbd5cb8ff53d617005a9847ae72d937f65e01e68be747f62d7ac19fd0c9aeba9956e60f16d6b465c5fdc2f3d08b4db2e6c",
"tag": "v%VERSION%",
"hash": "8c9642495bafd6fad4ab9fb67f09b268c69ff9af0f4f20cf15dfc18852ff1f312bd8ca41de761b3f8d8e90e77d79f2ccacd3d4c5b19e475ecf09d021fdfe9088",
"version": "1.2",
"git_version": "1.3.1",
"options": [
"ZLIB_BUILD_SHARED OFF",
"ZLIB_INSTALL OFF"
@ -57,8 +61,8 @@
},
"zstd": {
"repo": "facebook/zstd",
"sha": "f8745da6ff",
"hash": "3037007f990040fe32573b46f9bef8762fd5dbeeb07ffffcbfeba51ec98167edae39bb9c87f9299efcd61c4e467c5e84f7c19f0df7799bc1fc04864a278792ee",
"sha": "b8d6101fba",
"hash": "a6c8e5272214fd3e65e03ae4fc375f452bd2f646623886664ee23e239e35751cfc842db4d34a84a8039d89fc8f76556121f2a4ae350d017bdff5e22150f9c3de",
"version": "1.5",
"source_subdir": "build/cmake",
"find_args": "MODULE",
@ -66,20 +70,6 @@
"ZSTD_BUILD_SHARED OFF"
]
},
"catch2": {
"package": "Catch2",
"repo": "catchorg/Catch2",
"sha": "644821ce28",
"hash": "f8795f98acf2c02c0db8e734cc866d5caebab4b4a306e93598b97cb3c0c728dafe8283dce27ffe8d42460e5ae7302f3f32e7e274a7f991b73511ac88eef21b1f",
"version": "3.0.1"
},
"enet": {
"repo": "lsalzman/enet",
"sha": "2662c0de09",
"hash": "3de1beb4fa3d6b1e03eda8dd1e7580694f854af3ed3975dcdabfdcdf76b97f322b9734d35ea7f185855bb490d957842b938b26da4dd2dfded509390f8d2794dd",
"version": "1.3",
"find_args": "MODULE"
},
"opus": {
"package": "Opus",
"repo": "crueter/opus",
@ -91,101 +81,16 @@
"OPUS_PRESUME_NEON ON"
]
},
"vulkan-utility-headers": {
"package": "VulkanUtilityLibraries",
"repo": "scripts/VulkanUtilityHeaders",
"tag": "1.4.326",
"artifact": "VulkanUtilityHeaders.tar.zst",
"git_host": "git.crueter.xyz",
"hash": "5924629755cb1605c4aa4eee20ef7957a9dd8d61e4df548be656d98054f2730c4109693c1bd35811f401f4705d2ccff9fc849be32b0d8480bc3f73541a5e0964"
},
"spirv-tools": {
"package": "SPIRV-Tools",
"repo": "KhronosGroup/SPIRV-Tools",
"sha": "40eb301f32",
"hash": "58d0fb1047d69373cf24c73e6f78c73a72a6cca3b4df1d9f083b9dcc0962745ef154abf3dbe9b3623b835be20c6ec769431cf11733349f45e7568b3525f707aa",
"find_args": "MODULE",
"options": [
"SPIRV_SKIP_EXECUTABLES ON"
]
},
"spirv-headers": {
"package": "SPIRV-Headers",
"repo": "KhronosGroup/SPIRV-Headers",
"sha": "4e209d3d7e",
"hash": "f48bbe18341ed55ea0fe280dbbbc0a44bf222278de6e716e143ca1e95ca320b06d4d23d6583fbf8d03e1428f3dac8fa00e5b82ddcd6b425e6236d85af09550a4",
"options": [
"SPIRV_WERROR OFF"
]
},
"mbedtls": {
"package": "MbedTLS",
"repo": "Mbed-TLS/mbedtls",
"tag": "mbedtls-%VERSION%",
"hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da",
"version": "3",
"git_version": "3.6.4",
"artifact": "%TAG%.tar.bz2"
},
"cubeb": {
"repo": "mozilla/cubeb",
"sha": "fa02160712",
"hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61",
"find_args": "CONFIG",
"options": [
"USE_SANITIZERS OFF",
"BUILD_TESTS OFF",
"BUILD_TOOLS OFF",
"BUNDLE_SPEEX ON"
]
},
"boost_headers": {
"repo": "boostorg/headers",
"sha": "95930ca8f5",
"hash": "d1dece16f3b209109de02123c537bfe1adf07a62b16c166367e7e5d62e0f7c323bf804c89b3192dd6871bc58a9d879d25a1cc3f7b9da0e497cf266f165816e2a",
"bundled": true
},
"discord-rpc": {
"repo": "eden-emulator/discord-rpc",
"sha": "1cf7772bb6",
"hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97"
},
"simpleini": {
"package": "SimpleIni",
"repo": "brofield/simpleini",
"sha": "09c21bda1d",
"hash": "99779ca9b6e040d36558cadf484f9ffdab5b47bcc8fc72e4d33639d1d60c0ceb4410d335ba445d72a4324e455167fd6769d99b459943aa135bec085dff2d4b7c",
"find_args": "MODULE"
},
"sdl2_generic": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"sha": "54772f345a",
"hash": "2a68a0e01c390043aa9d9df63d8a20a52076c88bb460ac4e0f33194ca7d9bc8fadbbcc04e7506872ac4b6354a73fbc267c036f82200da59465789b87c7d9e3a4",
"key": "generic",
"bundled": true
},
"sdl2_steamdeck": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"sha": "cc016b0046",
"hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b",
"key": "steamdeck",
"bundled": true
},
"sdl2": {
"ci": true,
"package": "SDL2",
"name": "SDL2",
"repo": "crueter-ci/SDL2",
"version": "2.32.8",
"min_version": "2.26.4",
"cmake_filename": "sdl2"
},
"llvm-mingw": {
"repo": "misc/llvm-mingw",
"git_host": "git.crueter.xyz",
"tag": "20250828",
"tag": "%VERSION%",
"version": "20250828",
"artifact": "clang-rt-builtins.tar.zst",
"hash": "d902392caf94e84f223766e2cc51ca5fab6cae36ab8dc6ef9ef6a683ab1c483bfcfe291ef0bd38ab16a4ecc4078344fa8af72da2f225ab4c378dee23f6186181"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -18,6 +18,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">icons/48x48/download.png</file>
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>

View file

@ -11,6 +11,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">../colorful/icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">../colorful/icons/48x48/download.png</file>
<file alias="48x48/upload.png">../colorful/icons/48x48/upload.png</file>
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
<file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>

View file

@ -14,6 +14,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">icons/48x48/download.png</file>
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
<file alias="48x48/star.png">icons/48x48/star.png</file>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

View file

@ -13,6 +13,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
<file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">../colorful/icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">../colorful/icons/48x48/download.png</file>
<file alias="48x48/upload.png">../colorful/icons/48x48/upload.png</file>
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
<file alias="48x48/list-add.png">../colorful/icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

View file

@ -9,6 +9,9 @@
<file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">icons/48x48/chip.png</file>
<file alias="48x48/folder.png">icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">icons/48x48/download.png</file>
<file alias="48x48/upload.png">icons/48x48/upload.png</file>
<file alias="48x48/no_avatar.png">icons/48x48/no_avatar.png</file>
<file alias="48x48/list-add.png">icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>

View file

@ -6,6 +6,9 @@
<file alias="48x48/bad_folder.png">../qdarkstyle/icons/48x48/bad_folder.png</file>
<file alias="48x48/chip.png">../qdarkstyle/icons/48x48/chip.png</file>
<file alias="48x48/folder.png">../qdarkstyle/icons/48x48/folder.png</file>
<file alias="48x48/user-trash.png">../qdarkstyle/icons/48x48/user-trash.png</file>
<file alias="48x48/download.png">../qdarkstyle/icons/48x48/download.png</file>
<file alias="48x48/upload.png">../qdarkstyle/icons/48x48/upload.png</file>
<file alias="48x48/no_avatar.png">../qdarkstyle/icons/48x48/no_avatar.png</file>
<file alias="48x48/list-add.png">../qdarkstyle/icons/48x48/list-add.png</file>
<file alias="48x48/sd_card.png">../qdarkstyle/icons/48x48/sd_card.png</file>

View file

@ -1,250 +0,0 @@
# CPM
CPM (CMake Package Manager) is the preferred method of managing dependencies within Eden.
Global Options:
- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing
* If this is `OFF`, required system dependencies will be searched via `find_package`, although certain externals use CPM regardless.
- `CPMUTIL_FORCE_SYSTEM` (default `OFF`): Require all CPM dependencies to use system packages. NOT RECOMMENDED!
* Many packages, e.g. mcl, sirit, xbyak, discord-rpc, are not generally available as a system package.
* You may optionally override these (see CPMUtil section)
- `CPMUTIL_FORCE_BUNDLED` (default `ON` on MSVC and Android, `OFF` elsewhere): Require all CPM dependencies to use bundled packages.
## CPMUtil
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
### AddPackage
`AddPackage` is the core of the CPMUtil wrapper, and is generally the lowest level you will need to go when dealing with dependencies.
**Identification/Fetching**
- `NAME` (required): The package name (must be the same as the `find_package` name if applicable)
- `VERSION`: The minimum version of this package that can be used on the system
- `GIT_VERSION`: The "version" found within git
- `URL`: The URL to fetch.
- `REPO`: The GitHub repo to use (`owner/repo`).
* Only GitHub is supported for now, though other platforms will see support at some point
- `TAG`: The tag to fetch, if applicable.
- `ARTIFACT`: The name of the artifact, if applicable.
- `SHA`: Commit sha to fetch, if applicable.
- `BRANCH`: Branch to fetch, if applicable.
The following configurations are supported, in descending order of precedence:
- `URL`: Bare URL download, useful for custom artifacts
* If this is set, `GIT_URL` or `REPO` should be set to allow the dependency viewer to link to the project's Git repository.
* If this is NOT set, `REPO` must be defined.
- `REPO + TAG + ARTIFACT`: GitHub release artifact
* The final download URL will be `https://github.com/${REPO}/releases/download/${TAG}/${ARTIFACT}`
* Useful for prebuilt libraries and prefetched archives
- `REPO + TAG`: GitHub tag archive
* The final download URL will be `https://github.com/${REPO}/archive/refs/tags/${TAG}.tar.gz`
* Useful for pinning to a specific tag, better for build identification
- `REPO + SHA`: GitHub commit archive
* The final download URL will be `https://github.com/${REPO}/archive/${SHA}.zip`
* Useful for pinning to a specific commit
- `REPO + BRANCH`: GitHub branch archive
* The final download URL will be `https://github.com/${REPO}/archive/refs/heads/${BRANCH}.zip`
* Generally not recommended unless the branch is frozen
- `REPO`: GitHub master archive
* The final download URL will be `https://github.com/${REPO}/archive/refs/heads/master.zip`
* Generally not recommended unless the project is dead
**Hashing**
Hashing is used for verifying downloads. It's highly recommended to use these.
- `HASH_ALGO` (default `SHA512`): Hash algorithm to use
Hashing strategies, descending order of precedence:
- `HASH`: Bare hash verification, useful for static downloads e.g. commit archives
- `HASH_SUFFIX`: Download the hash as `${DOWNLOAD_URL}.${HASH_SUFFIX}`
* The downloaded hash *must* match the hash algorithm and contain nothing but the hash; no filenames or extra content.
- `HASH_URL`: Download the hash from a separate URL
**Additional Options**
- `KEY`: Custom cache key to use (stored as `.cache/cpm/${packagename_lower}/${key}`)
* Default is based on, in descending order of precedence:
- First 4 characters of the sha
- `GIT_VERSION`
- Tag
- `VERSION`
- Otherwise, CPM defaults will be used. This is not recommended as it doesn't produce reproducible caches
- `DOWNLOAD_ONLY`: Whether or not to configure the downloaded package via CMake
* Useful to turn `OFF` if the project doesn't use CMake
- `SOURCE_SUBDIR`: Subdirectory of the project containing a CMakeLists.txt file
- `FIND_PACKAGE_ARGUMENTS`: Arguments to pass to the `find_package` call
- `BUNDLED_PACKAGE`: Set to `ON` to force the usage of a bundled package
- `OPTIONS`: Options to pass to the configuration of the package
- `PATCHES`: Patches to apply to the package, stored in `.patch/${packagename_lower}/0001-patch-name.patch` and so on
- Other arguments can be passed to CPM as well
**Extra Variables**
For each added package, users may additionally force usage of the system/bundled package.
- `${package}_FORCE_SYSTEM`: Require the package to be installed on the system
- `${package}_FORCE_BUNDLED`: Force the package to be fetched and use the bundled version
**Bundled/System Switching**
Descending order of precedence:
- If `${package}_FORCE_SYSTEM` is true, requires the package to be on the system
- If `${package}_FORCE_BUNDLED` is true, forcefully uses the bundled package
- If `CPMUTIL_FORCE_SYSTEM` is true, requires the package to be on the system
- If `CPMUTIL_FORCE_BUNDLED` is true, forcefully uses the bundled package
- If the `BUNDLED_PACKAGE` argument is true, forcefully uses the bundled package
- Otherwise, CPM will search for the package first, and if not found, will use the bundled package
**Identification**
All dependencies must be identifiable in some way for usage in the dependency viewer. Lists are provided in descending order of precedence.
URLs:
- `GIT_URL`
- `REPO` as a GitHub repository
- `URL`
Versions (bundled):
- `SHA`
- `GIT_VERSION`
- `VERSION`
- `TAG`
- "unknown"
If the package is a system package, AddPackage will attempt to determine the package version and append ` (system)` to the identifier. Otherwise, it will be marked as `unknown (system)`
### AddCIPackage
Adds a package that follows crueter's CI repository spec.
- `VERSION` (required): The version to get (the tag will be `v${VERSION}`)
- `NAME` (required): Name used within the artifacts
- `REPO` (required): CI repository, e.g. `crueter-ci/OpenSSL`
- `PACKAGE` (required): `find_package` package name
- `EXTENSION`: Artifact extension (default `tar.zst`)
- `MIN_VERSION`: Minimum version for `find_package`. Only used if platform does not support this package as a bundled artifact
- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. One of:
* `windows-amd64`
* `windows-arm64`
* `android`
* `solaris`
* `freebsd`
* `linux`
* `linux-aarch64`
- `CMAKE_FILENAME`: Custom CMake filename, relative to the package root (default `${PACKAGE_ROOT}/${NAME}.cmake`)
### AddJsonPackage
This is the recommended method of usage for CPMUtil. In each directory that utilizes `CPMUtil`, there must be a `cpmfile.json` that defines dependencies in a similar manner to the individual calls.
The cpmfile is an object of objects, with each sub-object being named according to the package's identifier, e.g. `openssl`, which can then be fetched with `AddJsonPackage(<identifier>)`. Options are designed to map closely to the argument names, and are always strings unless otherwise specified.
- `package` -> `NAME` (`PACKAGE` for CI), defaults to the object key
- `repo` -> `REPO`
- `version` -> `VERSION`
- `ci` (bool)
If `ci` is `false`:
- `hash` -> `HASH`
- `sha` -> `SHA`
- `tag` -> `TAG`
- `artifact` -> `ARTIFACT`
- `git_version` -> `GIT_VERSION`
- `source_subdir` -> `SOURCE_SUBDIR`
- `bundled` -> `BUNDLED_PACKAGE`
- `find_args` -> `FIND_PACKAGE_ARGUMENTS`
- `patches` -> `PATCHES` (array)
- `options` -> `OPTIONS` (array)
Other arguments aren't currently supported. If you wish to add them, see the `AddJsonPackage` function in `CMakeModules/CPMUtil.cmake`.
If `ci` is `true`:
- `name` -> `NAME`, defaults to the object key
- `extension` -> `EXTENSION`, defaults to `tar.zst`
- `min_version` -> `MIN_VERSION`
- `cmake_filename` -> `CMAKE_FILENAME`
- `extension` -> `EXTENSION`
### Examples
In order: OpenSSL CI, Boost (tag + artifact), Opus (options + find_args), discord-rpc (sha + options + patches)
```json
{
"openssl": {
"ci": true,
"package": "OpenSSL",
"name": "openssl",
"repo": "crueter-ci/OpenSSL",
"version": "3.5.2",
"min_version": "1.1.1"
},
"boost": {
"package": "Boost",
"repo": "boostorg/boost",
"tag": "boost-1.88.0",
"artifact": "boost-1.88.0-cmake.7z",
"hash": "e5b049e5b61964480ca816395f63f95621e66cb9bcf616a8b10e441e0e69f129e22443acb11e77bc1e8170f8e4171b9b7719891efc43699782bfcd4b3a365f01",
"git_version": "1.88.0",
"version": "1.57"
},
"opus": {
"package": "Opus",
"repo": "xiph/opus",
"sha": "5ded705cf4",
"hash": "0dc89e58ddda1f3bc6a7037963994770c5806c10e66f5cc55c59286fc76d0544fe4eca7626772b888fd719f434bc8a92f792bdb350c807968b2ac14cfc04b203",
"version": "1.3",
"find_args": "MODULE",
"options": [
"OPUS_BUILD_TESTING OFF",
"OPUS_BUILD_PROGRAMS OFF",
"OPUS_INSTALL_PKG_CONFIG_MODULE OFF",
"OPUS_INSTALL_CMAKE_CONFIG_MODULE OFF"
]
},
"discord-rpc": {
"repo": "discord/discord-rpc",
"sha": "963aa9f3e5",
"hash": "386e1344e9a666d730f2d335ee3aef1fd05b1039febefd51aa751b705009cc764411397f3ca08dffd46205c72f75b235c870c737b2091a4ed0c3b061f5919bde",
"options": [
"BUILD_EXAMPLES OFF"
],
"patches": [
"0001-cmake-version.patch",
"0002-no-clang-format.patch",
"0003-fix-cpp17.patch"
]
},
}
```
### Inclusion
To include CPMUtil:
```cmake
include(CPMUtil)
```
## Prefetching
- To prefetch a CPM dependency (requires cpmfile):
* `tools/cpm-fetch.sh <packages>`
- To prefetch all CPM dependencies:
* `tools/cpm-fetch-all.sh`
Currently, `cpm-fetch.sh` defines the following directories for cpmfiles (max depth of 2, so subdirs are caught as well):
`externals src/qt_common src/dynarmic .`
Whenever you add a new cpmfile, update the script accordingly

17
docs/CPMUtil.md Normal file
View file

@ -0,0 +1,17 @@
# CPMUtil
CPMUtil is a wrapper around CPM that aims to reduce boilerplate and add useful utility functions to make dependency management a piece of cake.
See more in [its repository](https://git.crueter.xyz/CMake/CPMUtil)
Eden-specific options:
- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing
* If this is `OFF`, required system dependencies will be searched via `find_package`, although most externals use CPM regardless.
- Force system libraries via CMake arguments:
* SDL2: `YUZU_USE_BUNDLED_SDL2` and `YUZU_USE_EXTERNAL_SDL2`
* FFmpeg: `YUZU_USE_EXTERNAL_FFMPEG`
## Tooling
See the [tooling docs](../tools/cpm)

View file

@ -45,8 +45,18 @@ export LIBGL_ALWAYS_SOFTWARE=1
After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`.
`-lc++-experimental` doesn't exist in OpenBSD but the LLVM driver still tries to link against it, to solve just symlink `ln -s /usr/lib/libc++.a /usr/lib/libc++experimental.a`.
If clang has errors, try using `g++-11`.
## FreeBSD
Eden is not currently available as a port on FreeBSD, though it is in the works. For now, the recommended method of usage is to compile it yourself.
The available OpenSSL port (3.0.17) is out-of-date, and using a bundled static library instead is recommended; to do so, add `-DYUZU_USE_BUNDLED_OPENSSL=ON` to your CMake configure command.
## NetBSD
System provides a default `g++-10` which doesn't support the current C++ codebase; install `clang-19` with `pkgin install clang-19`. Then build with `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`.
Make may error out when generating C++ headers of SPIRV shaders, hence it's recommended to use `gmake` over the default system one.

View file

@ -4,8 +4,8 @@ To build Eden, you MUST have a C++ compiler.
* On Linux, this is usually [GCC](https://gcc.gnu.org/) 11+ or [Clang](https://clang.llvm.org/) v14+
- GCC 12 also requires Clang 14+
* On Windows, this is either:
- **[MSVC](https://visualstudio.microsoft.com/downloads/)**,
* *A convenience script to install the **minimal** version (Visual Build Tools) is provided in `.ci/windows/install-msvc.ps1`*
- **[MSVC](https://visualstudio.microsoft.com/downloads/)** (you should select *Community* option),
* *A convenience script to install the Visual Community Studio 2022 with necessary tools is provided in `.ci/windows/install-msvc.ps1`*
- clang-cl - can be downloaded from the MSVC installer,
- or **[MSYS2](https://www.msys2.org)**
* On macOS, this is Apple Clang
@ -63,6 +63,7 @@ Certain other dependencies will be fetched by CPM regardless. System packages *c
* [VulkanMemoryAllocator](https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator)
* [sirit](https://github.com/eden-emulator/sirit)
* [httplib](https://github.com/yhirose/cpp-httplib) - if `ENABLE_QT_UPDATE_CHECKER` or `ENABLE_WEB_SERVICE` are on
- This package is known to be broken on the AUR.
* [cpp-jwt](https://github.com/arun11299/cpp-jwt) 1.4+ - if `ENABLE_WEB_SERVICE` is on
* [unordered-dense](https://github.com/martinus/unordered_dense)
* [mcl](https://github.com/azahar-emu/mcl) - subject to removal
@ -101,7 +102,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
<summary>Ubuntu, Debian, Mint Linux</summary>
```sh
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
```
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
@ -109,18 +110,28 @@ sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2 libboos
</details>
<details>
<summary>Fedora Linux</summary>
<summary>AlmaLinux, Fedora, Red Hat Linux</summary>
Fedora:
```sh
sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel
sudo dnf install autoconf cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel boost jq
```
* Force system libraries via CMake arguments:
* SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF`
* FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF`
* [RPM Fusion](https://rpmfusion.org/) is required for `ffmpeg-devel`
AlmaLinux (use `YUZU_USE_CPM=ON`):
```sh
# vvv - Only if RPMfusion is not installed or EPEL isn't either
sudo dnf install epel-release dnf-utils
# (run rpmfusion installation afterwards)
# vvv - This will work for most systems
sudo dnf install autoconf cmake libtool libudev cmake gcc gcc-c++ qt6-qtbase-devel zlib-devel openssl-devel boost SDL2 ffmpeg-devel libdrm glslang jq patch
# Qt6 private GUI must be taken from CRB repos
sudo dnf config-manager --enable crb
sudo dnf install qt6-qtbase-private-devel
```
* [RPM Fusion](https://rpmfusion.org/Configuration) is required for `ffmpeg-devel`
* Fedora 32 or later is required.
* Fedora 36+ users with GCC 12 need Clang and should configure CMake with:
* Fedora 36+ users with GCC 12 need Clang and should configure CMake with: `cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`
</details>
<details>
@ -144,44 +155,43 @@ brew install molten-vk vulkan-loader
<details>
<summary>FreeBSD</summary>
```
devel/cmake
devel/sdl20
devel/boost-libs
devel/catch2
devel/libfmt
devel/nlohmann-json
devel/ninja
devel/nasm
devel/autoconf
devel/pkgconf
devel/qt6-base
net/enet
multimedia/ffnvcodec-headers
multimedia/ffmpeg
audio/opus
archivers/liblz4
lang/gcc12
graphics/glslang
graphics/vulkan-utility-libraries
```
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense devel/zydis`
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
</details>
<details>
<summary>NetBSD</summary>
Install `pkgin` if not already `pkg_add pkgin`, see also the general [pkgsrc guide](https://www.netbsd.org/docs/pkgsrc/using.html). For NetBSD 10.1 provide `cat 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.0_2025Q3/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
```
ip6addrctl=YES
ip6addrctl_policy=ipv4_prefer
```
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1`.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
```sh
pkgin python313
git clone https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
```
</details>
<details>
<summary>OpenBSD</summary>
```sh
pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1.1.0.27
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1-1.0.27
```
</details>
<details>
@ -194,7 +204,7 @@ Run the usual update + install of essential toolings: `sudo pkg update && sudo p
- **gcc**: `sudo pkg install developer/gcc-14`.
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
</details>
<details>
@ -209,6 +219,16 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
* `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc`
</details>
<details>
<summary>RedoxOS</summary>
```sh
sudo pkg update && sudo pkg install git cmake
sudo pkg install ffmpeg6 sdl2 zlib llvm18
```
</details>
## All Done
You may now return to the **[root build guide](Build.md)**.

View file

@ -36,6 +36,28 @@ Pull requests are only to be merged by core developers when properly tested and
- Maintainers are permitted to change namespaces at will.
- Commits within PRs are not required to be namespaced, but it is highly recommended.
## Adding new settings
When adding new settings, use `tr("Setting:")` if the setting is meant to be a field, otherwise use `tr("Setting")` if the setting is meant to be a Yes/No or checkmark type of setting, see [this short style guide](https://learn.microsoft.com/en-us/style-guide/punctuation/colons#in-ui).
- The majority of software must work with the default option selected for such setting. Unless the setting significantly degrades performance.
- Debug settings must never be turned on by default.
- Provide reasonable bounds (for example, a setting controlling the amount of VRAM should never be 0).
- The description of the setting must be short and concise, if the setting "does a lot of things" consider splitting the setting into multiple if possible.
- Try to avoid excessive/redundant explainations "recommended for most users and games" can just be "(recommended)".
- Try to not write "slow/fast" options unless it clearly degrades/increases performance for a given case, as most options may modify behaviour that result in different metrics accross different systems. If for example the option is an "accuracy" option, writing "High" is sufficient to imply "Slow". No need to write "High (Slow)".
Some examples:
- "[...] negatively affecting image quality", "[...] degrading image quality": Same wording but with less filler.
- "[...] this may cause some glitches or crashes in some games", "[...] this may cause soft-crashes": Crashes implies there may be glitches (as crashes are technically a form of a fatal glitch). The entire sentence is structured as "may cause [...] on some games", which is redundant, because "may cause [...] in games" has the same semantic meaning ("may" is a chance that it will occur on "some" given set).
- "FIFO Relaxed is similar to FIFO [...]", "FIFO Relaxed [...]": The name already implies similarity.
- "[...] but may also reduce performance in some cases", "[...] but may degrade performance": Again, "some cases" and "may" implies there is a probability.
- "[...] it can [...] in some cases", "[...] it can [...]": Implied probability.
Before adding a new setting, consider:
- Does the piece of code that the setting pertains to, make a significant difference if it's on/off?
- Can it be auto-detected?
# IDE setup
## VSCode

View file

@ -31,7 +31,7 @@ Notes:
* Currently, build fails without this
- `YUZU_USE_FASTER_LD` (ON) Check if a faster linker is available
* Only available on UNIX
- `USE_SYSTEM_MOLTENVK` (OFF, macOS only) Use the system MoltenVK lib (instead of the bundled one)
- `YUZU_USE_BUNDLED_MOLTENVK` (ON, macOS only) Download bundled MoltenVK lib)
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS)
- `ENABLE_OPENSSL` (ON for Linux and *BSD) Enable OpenSSL backend for the ssl service
* Always enabled if the web service is enabled

View file

@ -5,6 +5,6 @@ This contains documentation created by developers. This contains build instructi
- **[General Build Instructions](Build.md)**
- **[Development Guidelines](Development.md)**
- **[Dependencies](Deps.md)**
- **[CPM - CMake Package Manager](CPM.md)**
- **[CPM - CMake Package Manager](CPMUtil.md)**
- **[Platform-Specific Caveats](Caveats.md)**
- **[User Directory Handling](User.md)**
- **[User Handbook](User.md)**

View file

@ -27,6 +27,7 @@ The following are not valid reasons to sign up:
* To download and use Eden, see our [Releases page](https://github.com/eden-emulator/Releases/releases)!
- I want to see the source code.
* To see Eden's source code, go [here](https://git.eden-emu.dev/eden-emu/eden).
## Other Information
Requests that appear suspicious, automated, OR blank will generally be automatically filtered. In cases of suspicion, or any of the invalid reasons listed above, you may receive an email back asking for clarification.

View file

@ -1,11 +1,10 @@
# User configuration
# User Handbook
## Configuration directories
The "FAQ".
Eden will store configuration in the following directories:
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
- **Windows**: `%AppData%\Roaming`.
- **Android**: Data is stored internally.
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.
- **[The Basics](user/Basics.md)**
- **[Audio](user/Audio.md)**
- **[Graphics](user/Graphics.md)**
- **[Platforms and Architectures](user/Architectures.md)**

View file

@ -33,6 +33,7 @@ Eden by default will be cloned into -
4. Navigate to `eden/src/android`.
5. Then Build with `./gradlew assembleRelWithDebInfo`.
6. To build the optimised build use `./gradlew assembleGenshinSpoofRelWithDebInfo`.
7. You can pass extra variables to cmake via `-PYUZU_ANDROID_ARGS="-D..."`
### Script
A convenience script for building is provided in `.ci/android/build.sh`. The built APK can be put into an `artifacts` directory via `.ci/android/package.sh`. On Windows, these must be done in the Git Bash or MinGW terminal.

133
docs/user/Architectures.md Normal file
View file

@ -0,0 +1,133 @@
# User Handbook - Architectures and Platforms
Notes and caveats for different architectures and platforms.
# Architectures
Eden is primarily designed to run on amd64 (x86_64--Intel/AMD 64-bit) and aarch64 (arm64--ARM 64-bit) CPUs. Each architecture tends to have their own quirks and fun stuff; this page serves as a reference for these quirks.
## amd64
AMD64, aka x86_64, is the most tested and supported architecture for desktop targets. Android is entirely unsupported.
### Caveats
AMD64 systems are almost always limited by the CPU. For example, a Zen 5/RX 6600 system will often hit max CPU usage before the GPU ever reaches 70% usage, with minimal exceptions (that tend to pop up only at >200fps). JIT is slow!
Computers on Linux will almost always run Eden strictly better than an equivalent machine on Windows. This is largely due to the way the Linux kernel handles memory management (and the lack of Microsoft spyware).
Intel Macs are believed to be supported, but no CI is provided for them. Performance will likely be awful on all but the highest-end iMacs and Pro-level Macs, and the MoltenVK requirement generally means Vulkan compatibility will suffer.
## aarch64
ARM64, aka aarch64, is the only supported architecture for Android, with limited experimental support available on Linux, Windows, and macOS.
### Caveats
NCE (Native Code Execution) is currently only available on Android and (experimentally) Linux. Support for macOS is in the works, but Windows is extremely unlikely to ever happen (if you want it--submit patches!). Generally, if NCE is available, you should pretty much always use it due to the massive performance hit JIT has.
When NCE is enabled, do note that the GPU will almost always be the limiting factor. This is especially the case for Android, as well as desktops that lack dedicated GPUs; Adreno, Mali, PowerVR, etc. GPUs are generally significantly weaker relative to their respective CPUs.
Windows/arm64 is *very* experimental and is unlikely to work at all. Support and testing is in the works.
## riscv64
RISC-V, aka riscv64, is sparsely tested, but preliminary tests from developers have reported at least partial support on Milk-V's Fedora/riscv64 Linux distribution. Performance, Vulkan support, compatibility, and build system caveats are largely unknown for the time being.
### Caveats
Windows/riscv64 doesn't exist, and may never (until corporate greed no longer consumes Microsoft).
Android/riscv64 is interesting. While support for it may be added if and when RISC-V phones/handhelds ever go mainstream, arm64 devices will always be preferred due to NCE.
Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution that has *at least* the standard build tools, Qt, FFmpeg, and SDL2 should work.
## Other
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it--submit patches!
IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not run on IA-64 (assuming you can even find a supported Windows/Linux distribution)
# Platforms
The vast majority of Eden's testing is done on Windows, Linux, and Android. However, first-class support is also provided for:
- FreeBSD
- OpenBSD
- NetBSD
- OpenIndiana (Solaris)
- macOS
## Linux
While all modern Linux distributions are supported (Fedora >40, Ubuntu >24.04, Debian >12, Arch, Gentoo, etc.), the vast majority of testing and development for Linux is on Arch and Gentoo. Most major build system changes are tested on Gentoo first and foremost, so if builds fail on any modern distribution no matter what you do, it's likely a bug and should be reported.
Intel and Nvidia GPU support is limited. AMD (RADV) drivers receive first-class testing and are known to provide the most stable Eden experience possible.
Wayland is not recommended. Testing has shown significantly worse performance on most Wayland compositors compared to X11, alongside mysterious bugs and compatibility errors. For now, set `QT_QPA_PLATFORM=xcb` when running Eden, or pass `-platform xcb` to the launch arguments.
## Windows
Windows 10 and 11 are supported. Support for Windows 8.x is unknown, and Windows 7 support is unlikely to ever be added.
In order to run Eden, you will probably need to install the [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
Neither AMD nor Nvidia drivers work nearly as well as Linux's RADV drivers. Compatibility is still largely the same, but performance and some hard-to-run games may suffer compared to Linux.
## Android
A cooler is always recommended. Phone SoCs tend to get very hot, especially those manufactured with the Samsung process or those lacking in power.
Adreno 6xx and 7xx GPUs with Turnip drivers will always have the best compatibility. "Stock" (system) drivers will have better performance on Adreno, but compatibility will suffer. Better support for stock drivers (including Adreno 8xx) is in the works.
Android 16 is always recommended, as it brought major improvements to Vulkan requirements and compatibility, *plus* significant performance gains. Some users reported an over 50% performance gain on some Pixel phones after updating.
Mali, PowerVR, Xclipse, and other GPU vendors generally lack in performance and compatibility. Notably:
- No PowerVR GPUs *except* the DXT-48-1536 are known to work with Eden at all.
- No Xclipse GPUs *except* the very latest (e.g. Xclipse 950) are known to work with Eden at all.
- Mali has especially bad performance, though the Mali-G715 (Tensor G4) and Immortalis-G925 are known to generally run surprisingly well, especially on Android 16.
- The status of all other GPU vendors is unknown. As long as they support Vulkan, they theoretically can run Eden.
- Note that these GPUs generally don't play well with driver injection. If you choose to inject custom drivers via a rooted system (Panfrost, RADV, etc), you may see good results.
Qualcomm Snapdragon SoCs are generally the most well supported.
- Google Tensor chips have pretty terrible performance, but even the G1 has been proven to be able to run some games well on the Pixel 6 Pro.
* The Tensor G4 is the best-supported at the time. How the G5 currently fares is unknown, but on paper, it should do about as well as a Snapdragon 8 Gen 2 with stock drivers.
- Samsung Exynos chips made before 2022 are not supported.
- MediaTek Dimensity chips are extremely weak and most before mid-2023 don't work at all.
* This means that most budget phones won't work, as they tend to use old MediaTek SoCs.
* Generally, if your phone doesn't cost *at least* as much as a Switch itself, it will not *emulate* the Switch very well.
- Snapdragon 865 and other old-ish SoCs may benefit from the Legacy build. These will reduce performance but *should* drastically improve compatibility.
- If you're not sure how powerful your SoC is, check [NanoReview](https://nanoreview.net/en/soc-compare) - e.g. [Tensor G5](https://archive.is/ylC4Z).
* A good base to compare to is the Snapdragon 865--e.g. [Tensor vs SD865](https://archive.is/M1P58)
* Some benchmarks may be misleading due to thermal throttling OR RAM requirements.
- For example, a Pixel 6a (Tensor G1) performs about 1/3 as well as an 865 due to its lack of RAM and poor thermals.
* Remember--always use a cooler if you can, and you MUST have *at least* 8GB of RAM!
- If you're not sure what SoC you have, check [GSMArena](https://www.gsmarena.com) - e.g. [Pixel 9 Pro](https://archive.ph/91VhA)
Custom ROMs are recommended, *as long as* you know what you're doing.
- For most devices, [LineageOS](https://lineageos.org/) is preferred.
- [CalyxOS](https://calyxos.org/) is available as well.
- For Google Pixel devices ONLY... and [soon another OEM](https://archive.ph/cPpMd)... [GrapheneOS](https://grapheneos.org/) is highly recommended.
* As of October 5, 2025, the Pixel 10 line is unsupported, however, [it will be](https://archive.is/viAUl) in the very near future!
* Keep checking the [FAQ page](https://grapheneos.org/faq#supported-devices) for news.
- Custom ROMs will likely be exclusively recommended in the future due to Google's upcoming [draconian](https://archive.is/hGIjZ), [anti-privacy, anti-user](https://archive.is/mc1CJ) verification requirements.
Eden is currently unavailable on F-Droid or the Play Store. Check back occasionally.
## macOS
macOS is relatively stable, with only the occasional crash and bug. Compatibility may suffer due to the MoltenVK layer, however.
Do note that building the GUI version with Qt versions higher than 6.7.3 will cause mysterious bugs, Vulkan errors, and crashes, alongside the cool feature of freezing the entire system UI randomly; we recommend you build with 6.7.3 (via aqtinstall) or earlier as the CI does.
## *BSD, Solaris
BSD and Solaris distributions tend to lag behind Linux in terms of Vulkan and other library compatibility. For example, OpenIndiana (Solaris) does not properly package Qt, meaning the recommended method of usage is to use `eden-cli` only for now. Solaris also generally works better with OpenGL.
AMD GPU support on these platforms is limited or nonexistent.
## VMs
Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60 FPS.
Some users and developers have had success using a pure OpenGL-accelerated KVM on Linux with a Windows VM, but this is ridiculously tedious to set up. You're probably better off dual-booting.

3
docs/user/Audio.md Normal file
View file

@ -0,0 +1,3 @@
# User Handbook - Audio
`PULSE_SERVER=none` forces cubeb to use ALSA.

57
docs/user/Basics.md Normal file
View file

@ -0,0 +1,57 @@
# User Handbook - The Basics
## Introduction
Eden is a very complicated piece of software, and as such there are many knobs and toggles that can be configured. Most of these are invisible to normal users, however power users may be able to leverage them to their advantage.
This handbook primarily describes such knobs and toggles. Normal configuration options are described within the emulator itself and will not be covered in detail.
## Requirements
The emulator is very demanding on hardware, and as such requires a decent mid-range computer/cellphone.
See [the requirements page](https://archive.is/sv83h) for recommended and minimum specs.
The CPU must support FMA for an optimal gameplay experience. The GPU needs to support OpenGL 4.6 ([compatibility list](https://opengl.gpuinfo.org/)), or Vulkan 1.1 ([compatibility list](https://vulkan.gpuinfo.org/)).
If your GPU doesn't support or is just behind by a minor version, see Mesa environment variables below (*nix only).
## User configuration
### Configuration directories
Eden will store configuration files in the following directories:
- **Windows**: `%AppData%\Roaming`.
- **Android**: Data is stored internally.
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.
### Environment variables
Throughout the handbook, environment variables are mentioned. These are often either global (system wide) or local (set in a script, bound only to the current session). It's heavily recommended to use them in a local context only, as this allows you to rollback changes easily (if for example, there are regressions setting them).
The recommended way is to create a `.bat` file alongside the emulator `.exe`; contents of which could resemble something like:
```bat
set "__GL_THREADED_OPTIMIZATIONS=1"
set "SOME_OTHER_VAR=1"
eden.exe
```
Android doesn't have a convenient way to set environment variables.
For other platforms, the recommended method is using a shell script:
```sh
export __GL_THREADED_OPTIMIZATIONS=1
export SOME_OTHER_VAR=1
./eden
```
Then just running `chmod +x script.sh && source script.sh`.
## Compatibility list
Eden doesn't mantain a compatibility list. However, [EmuReady](https://www.emuready.com/) has a more fine-grained compatibility information for multiple emulators/forks as well.

62
docs/user/Graphics.md Normal file
View file

@ -0,0 +1,62 @@
# User Handbook - Graphics
## Visual Enhancements
### Anti-aliasing
Enhancements aimed at removing jagged lines/sharp edges and/or masking artifacts.
- **No AA**: Default, provides no anti-aliasing.
- **FXAA**: Fast Anti-Aliasing, an implementation as described on [this blog post](https://web.archive.org/web/20110831051323/http://timothylottes.blogspot.com/2011/03/nvidia-fxaa.html). Generally fast but with some innocuos artifacts.
- **SMAA**: Subpixel Morphological Anti-Aliasing, an implementation as described on [this article](https://web.archive.org/web/20250000000000*/https://www.iryoku.com/smaa/).
### Filters
Various graphical filters exist - each of them aimed at a specific target/image quality preset.
- **Nearest**: Provides no filtering - useful for debugging.
- **Pros**: Fast, works in any hardware.
- **Cons**: Less image quality.
- **Bilinear**: Provides the hardware default filtering of the Tegra X1.
- **Pros**: Fast with acceptable image quality.
- **Bicubic**: Provides a bicubic interpolation using a Catmull-Rom (or hardware-accelerated) implementation.
- **Pros**: Better image quality with more rounded edges.
- **Zero-Tangent, B-Spline, Mitchell**: Provides bicubic interpolation using the respective matrix weights. They're normally not hardware accelerated unless the device supports the `VK_QCOM_filter_cubic_weights` extension. The matrix weights are those matching [the specification itself](https://registry.khronos.org/vulkan/specs/latest/html/vkspec.html#VkSamplerCubicWeightsCreateInfoQCOM).
- **Pros/Cons**: Each of them is a variation of the Bicubic interpolation model with different weights, they offer different methods to fix some artifacts present in Catmull-Rom.
- **Spline-1**: Bicubic interpolation (similar to Mitchell) but with a faster texel fetch method. Generally less blurry than bicubic.
- **Pros**: Faster than bicubic even without hardware accelerated bicubic.
- **Gaussian**: Whole-area blur, an applied gaussian blur is done to the entire frame.
- **Pros**: Less edge artifacts.
- **Cons**: Slow and sometimes blurry.
- **Lanczos**: An implementation using `a = 3` (49 texel fetches). Provides sharper edges but blurrier artifacts.
- **Pros**: Less edge artifacts and less blurry than gaussian.
- **Cons**: Slow.
- **ScaleForce**: Experimental texture upscale method, see [ScaleFish](https://github.com/BreadFish64/ScaleFish).
- **Pros**: Relatively fast.
- **FSR**: Uses AMD FidelityFX Super Resolution to enhance image quality.
- **Pros**: Great for upscaling, and offers sharper visual quality.
- **Cons**: Somewhat slow, and may be offputtingly sharp.
- **Area**: Area interpolation (high kernel count).
- **Pros**: Best for downscaling (internal resolution > display resolution).
- **Cons**: Costly and slow.
- **MMPX**: Nearest-neighbour filter aimed at providing higher pixel-art quality.
- **Pros**: Offers decent pixel-art upscaling.
- **Cons**: Only works for pixel-art.
### External
While stock shaders offer a basic subset of options for most users, programs such as [ReShade](https://github.com/crosire/reshade) offer a more flexible experience. In addition to that users can also seek out modifications (mods) for enhancing visual experience (60 FPS mods, HDR, etc).
## Driver specifics
### Mesa environment variable hacks
The software requires a certain version of Vulkan and a certain version of OpenGL to work - otherwise it will refuse to load, this can be easily bypassed by setting an environment variable: `MESA_GL_VERSION_OVERRIDE=4.6 MESA_GLSL_VERSION_OVERRIDE=460` (OpenGL) and `MESA_VK_VERSION_OVERRIDE=1.3` (Vulkan), for more information see [Environment variables for Mesa](https://web.archive.org/web/20250000000000*/https://docs.mesa3d.org/envvars.html).
### NVIDIA OpenGL environment variables
Unstable multithreaded optimisations are offered by the stock proprietary NVIDIA driver on X11 platforms. Setting `__GL_THREADED_OPTIMIZATIONS` to `1` would enable such optimisations. This mainly benefits the OpenGL backend. For more information see [Environment Variables for X11 NVIDIA](https://web.archive.org/web/20250115162518/https://download.nvidia.com/XFree86/Linux-x86_64/435.17/README/openglenvvariables.html).
### swrast/LLVMpipe crashes under high load
The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe writing an invalid SSA IR (on old versions of Mesa), and then proceeding to crash. The solution is using a script found in [tools/llvmpipe-run.sh](../../tools/llvmpipe-run.sh).

View file

@ -39,6 +39,147 @@ if (ARCHITECTURE_arm64 OR DYNARMIC_TESTS)
AddJsonPackage(oaknut)
endif()
# enet
AddJsonPackage(enet)
if (enet_ADDED)
target_include_directories(enet INTERFACE ${enet_SOURCE_DIR}/include)
endif()
if (NOT TARGET enet::enet)
add_library(enet::enet ALIAS enet)
endif()
# mbedtls
AddJsonPackage(mbedtls)
# VulkanUtilityHeaders - pulls in headers and utility libs
AddJsonPackage(vulkan-utility-headers)
# small hack
if (NOT VulkanUtilityLibraries_ADDED)
find_package(VulkanHeaders 1.3.274 REQUIRED)
endif()
# DiscordRPC
if (USE_DISCORD_PRESENCE)
if (ARCHITECTURE_arm64)
add_compile_definitions(RAPIDJSON_ENDIAN=RAPIDJSON_LITTLEENDIAN)
endif()
AddJsonPackage(discord-rpc)
if (DiscordRPC_ADDED)
target_include_directories(discord-rpc INTERFACE ${DiscordRPC_SOURCE_DIR}/include)
add_library(DiscordRPC::discord-rpc ALIAS discord-rpc)
endif()
endif()
# SimpleIni
AddJsonPackage(simpleini)
# Most linux distros don't package cubeb, so enable regardless of cpm settings
if(ENABLE_CUBEB)
AddJsonPackage(cubeb)
if (cubeb_ADDED)
if (NOT MSVC)
if (TARGET speex)
target_compile_options(speex PRIVATE -Wno-sign-compare)
endif()
set_target_properties(cubeb PROPERTIES COMPILE_OPTIONS "")
target_compile_options(cubeb INTERFACE
-Wno-implicit-const-int-float-conversion
-Wno-shadow
-Wno-missing-declarations
-Wno-return-type
-Wno-uninitialized
)
else()
target_compile_options(cubeb PRIVATE
/wd4456
/wd4458
)
endif()
endif()
if (NOT TARGET cubeb::cubeb)
add_library(cubeb::cubeb ALIAS cubeb)
endif()
endif()
# find SDL2 exports a bunch of variables that are needed, so its easier to do this outside of the YUZU_find_package
if (ENABLE_SDL2)
if (YUZU_USE_EXTERNAL_SDL2)
message(STATUS "Using SDL2 from externals.")
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
set(SDL_UNUSED_SUBSYSTEMS
File Filesystem
Locale Power Render)
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
string(TOUPPER ${_SUB} _OPT)
set(SDL_${_OPT} OFF)
endforeach()
set(HIDAPI ON)
endif()
if (APPLE)
set(SDL_FILE ON)
endif()
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
set(SDL_PIPEWIRE OFF) # build errors out with this on
AddJsonPackage("sdl2_steamdeck")
else()
AddJsonPackage("sdl2_generic")
endif()
elseif (YUZU_USE_BUNDLED_SDL2)
message(STATUS "Using bundled SDL2")
AddJsonPackage(sdl2)
endif()
find_package(SDL2 2.26.4 REQUIRED)
endif()
# SPIRV Headers
AddJsonPackage(spirv-headers)
# Sirit
if (YUZU_USE_BUNDLED_SIRIT)
AddJsonPackage(sirit-ci)
else()
AddJsonPackage(sirit)
# Change to old-but-more-cacheable debug info on Windows
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
get_target_property(sirit_opts sirit COMPILE_OPTIONS)
list(FILTER sirit_opts EXCLUDE REGEX "/Zi")
list(APPEND sirit_opts "/Z7")
set_target_properties(sirit PROPERTIES COMPILE_OPTIONS "${sirit_opts}")
endif()
if(MSVC AND CXX_CLANG)
target_compile_options(siritobj PRIVATE -Wno-error=unused-command-line-argument)
endif()
endif()
# SPIRV Tools
AddJsonPackage(spirv-tools)
if (SPIRV-Tools_ADDED)
add_library(SPIRV-Tools::SPIRV-Tools ALIAS SPIRV-Tools-static)
target_link_libraries(SPIRV-Tools-static PRIVATE SPIRV-Tools-opt SPIRV-Tools-link)
endif()
# Catch2
if (YUZU_TESTS OR DYNARMIC_TESTS)
AddJsonPackage(catch2)
endif()
# getopt
if (MSVC)
add_subdirectory(getopt)
@ -67,18 +208,6 @@ if (VulkanMemoryAllocator_ADDED)
endif()
endif()
# Sirit
AddJsonPackage(sirit)
if(MSVC AND USE_CCACHE AND sirit_ADDED)
get_target_property(_opts sirit COMPILE_OPTIONS)
list(FILTER _opts EXCLUDE REGEX "/Zi")
list(APPEND _opts "/Z7")
set_target_properties(sirit PROPERTIES COMPILE_OPTIONS "${_opts}")
elseif(MSVC AND CXX_CLANG)
target_compile_options(sirit PRIVATE -Wno-error=unused-command-line-argument)
endif()
# httplib
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
AddJsonPackage(httplib)

182
externals/cpmfile.json vendored
View file

@ -2,23 +2,35 @@
"vulkan-memory-allocator": {
"package": "VulkanMemoryAllocator",
"repo": "GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator",
"sha": "1076b348ab",
"hash": "a46b44e4286d08cffda058e856c47f44c7fed3da55fe9555976eb3907fdcc20ead0b1860b0c38319cda01dbf9b1aa5d4b4038c7f1f8fbd97283d837fa9af9772",
"find_args": "CONFIG"
"tag": "v%VERSION%",
"hash": "deb5902ef8db0e329fbd5f3f4385eb0e26bdd9f14f3a2334823fb3fe18f36bc5d235d620d6e5f6fe3551ec3ea7038638899db8778c09f6d5c278f5ff95c3344b",
"find_args": "CONFIG",
"git_version": "3.3.0"
},
"sirit": {
"repo": "eden-emulator/sirit",
"sha": "db1f1e8ab5",
"hash": "73eb3a042848c63a10656545797e85f40d142009dfb7827384548a385e1e28e1ac72f42b25924ce530d58275f8638554281e884d72f9c7aaf4ed08690a414b05",
"git_version": "1.0.2",
"tag": "v%VERSION%",
"artifact": "sirit-source-%VERSION%.tar.zst",
"hash_suffix": "sha512sum",
"find_args": "CONFIG",
"options": [
"SIRIT_USE_SYSTEM_SPIRV_HEADERS ON"
]
},
"sirit-ci": {
"ci": true,
"package": "sirit",
"name": "sirit",
"repo": "eden-emulator/sirit",
"version": "1.0.2"
},
"httplib": {
"repo": "yhirose/cpp-httplib",
"sha": "a609330e4c",
"hash": "dd3fd0572f8367d8549e1319fd98368b3e75801a293b0c3ac9b4adb806473a4506a484b3d389dc5bee5acc460cb90af7a20e5df705a1696b56496b30b9ce7ed2"
"tag": "v%VERSION%",
"hash": "b364500f76e2ecb0fe21b032d831272e3f1dfeea71af74e325f8fc4ce9dcdb3c941b97a5b422bdeafb9facd058597b90f8bfc284fb9afe3c33fefa15dd5a010b",
"git_version": "0.26.0",
"find_args": "MODULE GLOBAL"
},
"cpp-jwt": {
"version": "1.4",
@ -33,22 +45,27 @@
"xbyak_sun": {
"package": "xbyak",
"repo": "herumi/xbyak",
"sha": "9bb219333a",
"hash": "303165d45c8c19387ec49d9fda7d7a4e0d86d4c0153898c23f25ce2d58ece567f44c0bbbfe348239b933edb6e1a1e34f4bc1c0ab3a285bee5da0e548879387b0",
"bundled": true
"tag": "v%VERSION%",
"hash": "b40dade90fb0e46a2bd52934f7ce461e37be931b571e58cbe2203bc08ed5b54c7ff1a29026c74c7f9805e4e3f6c9636deca528e6b4a8093ce7eae145218599f1",
"git_version": "7.29",
"bundled": true,
"skip_updates": true
},
"xbyak": {
"package": "xbyak",
"repo": "herumi/xbyak",
"sha": "4e44f4614d",
"hash": "5824e92159e07fa36a774aedd3b3ef3541d0241371d522cffa4ab3e1f215fa5097b1b77865b47b2481376c704fa079875557ea463ca63d0a7fd6a8a20a589e70",
"bundled": true
"tag": "v%VERSION%",
"hash": "1042090405c426e339506c179d53e91d4d545ce9c9f53d8f797caa092d589f913a9bcb9c8f31c4c60870acb954c556e305fb6732c66bc3c8f1cd924f9172def9",
"git_version": "7.22",
"bundled": true,
"skip_updates": true
},
"oaknut": {
"repo": "eden-emulator/oaknut",
"version": "2.0.1",
"repo": "merryhime/oaknut",
"sha": "94c726ce03",
"hash": "d8d082242fa1881abce3c82f8dafa002c4e561e66a69e7fc038af67faa5eff2630f082d3d19579c88c4c9f9488e54552accc8cb90e7ce743efe043b6230c08ac"
"git_version": "2.0.3",
"tag": "v%VERSION%",
"hash": "9697e80a7d5d9bcb3ce51051a9a24962fb90ca79d215f1f03ae6b58da8ba13a63b5dda1b4dde3d26ac6445029696b8ef2883f4e5a777b342bba01283ed293856"
},
"libadrenotools": {
"repo": "bylaws/libadrenotools",
@ -60,15 +77,138 @@
},
"oboe": {
"repo": "google/oboe",
"sha": "2bc873e53c",
"hash": "02329058a7f9cf7d5039afaae5ab170d9f42f60f4c01e21eaf4f46073886922b057a9ae30eeac040b3ac182f51b9c1bfe9fe1050a2c9f6ce567a1a9a0ec2c768",
"tag": "%VERSION%",
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
"git_version": "1.10.0",
"bundled": true
},
"unordered-dense": {
"package": "unordered_dense",
"repo": "martinus/unordered_dense",
"sha": "73f3cbb237",
"hash": "c08c03063938339d61392b687562909c1a92615b6ef39ec8df19ea472aa6b6478e70d7d5e33d4a27b5d23f7806daf57fe1bacb8124c8a945c918c7663a9e8532",
"find_args": "CONFIG"
"tag": "v%VERSION%",
"hash": "f9c819e28e1c1a387acfee09277d6af5e366597a0d39acf1c687acf0608a941ba966af8aaebdb8fba0126c7360269c4a51754ef4cab17c35c01a30215f953368",
"find_args": "CONFIG",
"git_version": "4.5.0"
},
"mbedtls": {
"package": "MbedTLS",
"repo": "Mbed-TLS/mbedtls",
"tag": "mbedtls-%VERSION%",
"hash": "6671fb8fcaa832e5b115dfdce8f78baa6a4aea71f5c89a640583634cdee27aefe3bf4be075744da91f7c3ae5ea4e0c765c8fc3937b5cfd9ea73d87ef496524da",
"version": "3",
"git_version": "3.6.4",
"artifact": "%TAG%.tar.bz2",
"skip_updates": true,
"patches": [
"0002-aesni-fix.patch",
"0003-aesni-fix.patch"
]
},
"enet": {
"repo": "lsalzman/enet",
"tag": "v%VERSION%",
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
"version": "1.3",
"git_version": "1.3.18",
"find_args": "MODULE"
},
"vulkan-utility-headers": {
"package": "VulkanUtilityLibraries",
"repo": "scripts/VulkanUtilityHeaders",
"tag": "%VERSION%",
"git_version": "1.4.328",
"artifact": "VulkanUtilityHeaders.tar.zst",
"git_host": "git.crueter.xyz",
"hash": "9922217b39faf73cd4fc1510f2fdba14a49aa5c0d77f9ee24ee0512cef16b234d0cabc83c1fec861fa5df1d43e7f086ca9b6501753899119f39c5ca530cb0dae"
},
"spirv-tools": {
"package": "SPIRV-Tools",
"repo": "crueter/SPIRV-Tools",
"sha": "2fa2d44485",
"hash": "45b198be1d09974ccb2438e8bfa5683f23a0421b058297c28eacfd77e454ec2cf87e77850eddd202efff34b004d8d6b4d12e9615e59bd72be904c196f5eb2169",
"git_version": "2025.4",
"options": [
"SPIRV_SKIP_EXECUTABLES ON"
],
"patches": [
"0001-netbsd-fix.patch"
]
},
"spirv-headers": {
"package": "SPIRV-Headers",
"repo": "KhronosGroup/SPIRV-Headers",
"sha": "01e0577914",
"hash": "d0f905311faf7d743de686fdf241dc4cb0a4f08e2184f5a3b3b2946e680db3cd89eeb72954eafe6fa457f93550e27d516575c8709cb134d8aecc0b43064636ce",
"options": [
"SPIRV_WERROR OFF"
]
},
"cubeb": {
"repo": "mozilla/cubeb",
"sha": "fa02160712",
"hash": "82d808356752e4064de48c8fecbe7856715ade1e76b53937116bf07129fc1cc5b3de5e4b408de3cd000187ba8dc32ca4109661cb7e0355a52e54bd81b9be1c61",
"find_args": "CONFIG",
"options": [
"USE_SANITIZERS OFF",
"BUILD_TESTS OFF",
"BUILD_TOOLS OFF",
"BUNDLE_SPEEX ON"
]
},
"sdl2": {
"ci": true,
"package": "SDL2",
"name": "SDL2",
"repo": "crueter-ci/SDL2",
"version": "2.32.10",
"min_version": "2.26.4",
"disabled_platforms": [
"macos-universal"
]
},
"catch2": {
"package": "Catch2",
"repo": "catchorg/Catch2",
"tag": "v%VERSION%",
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
"version": "3.0.1",
"git_version": "3.11.0",
"patches": [
"0001-solaris-isnan-fix.patch"
]
},
"discord-rpc": {
"package": "DiscordRPC",
"repo": "eden-emulator/discord-rpc",
"sha": "1cf7772bb6",
"hash": "e9b35e6f2c075823257bcd59f06fe7bb2ccce1976f44818d2e28810435ef79c712a3c4f20f40da41f691342a4058cf86b078eb7f9d9e4dae83c0547c21ec4f97",
"find_args": "MODULE"
},
"simpleini": {
"package": "SimpleIni",
"repo": "brofield/simpleini",
"tag": "v%VERSION%",
"hash": "6c198636816a0018adbf7f735d402c64245c6fcd540b7360d4388d46f007f3a520686cdaec4705cb8cb31401b2cb4797a80b42ea5d08a6a5807c0848386f7ca1",
"find_args": "MODULE",
"git_version": "4.22"
},
"sdl2_generic": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"tag": "release-%VERSION%",
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
"key": "generic",
"bundled": true,
"git_version": "2.32.10",
"skip_updates": true
},
"sdl2_steamdeck": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"sha": "cc016b0046",
"hash": "34d5ef58da6a4f9efa6689c82f67badcbd741f5a4f562a9c2c30828fa839830fb07681c5dc6a7851520e261c8405a416ac0a2c2513b51984fb3b4fa4dcb3e20b",
"key": "steamdeck",
"bundled": true,
"skip_updates": "true"
}
}

View file

@ -13,8 +13,9 @@
"version": "8.0",
"min_version": "4.1",
"disabled_platforms": [
"freebsd",
"solaris"
"freebsd-amd64",
"solaris-amd64",
"macos-universal"
]
}
}

View file

@ -6,18 +6,7 @@
include(CPMUtil)
# we love our libraries don't we folks
if (PLATFORM_SUN)
set(libusb_bundled ON)
else()
set(libusb_bundled OFF)
endif()
# TODO(crueter): Fix on Solaris
AddJsonPackage(
NAME libusb
BUNDLED_PACKAGE ${libusb_bundled}
)
AddJsonPackage(libusb)
if (NOT libusb_ADDED)
return()

View file

@ -1,8 +1,12 @@
{
"libusb": {
"repo": "libusb/libusb",
"sha": "c060e9ce30",
"hash": "44647357ba1179020cfa6674d809fc35cf6f89bff1c57252fe3a610110f5013ad678fc6eb5918e751d4384c30e2fe678868dbffc5f85736157e546cb9d10accc",
"find_args": "MODULE"
"tag": "v%VERSION%",
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
"find_args": "MODULE",
"git_version": "1.0.29",
"patches": [
"0001-netbsd-gettime.patch"
]
}
}

View file

@ -35,17 +35,14 @@ endif()
if(NOT YUZU_TZDB_PATH STREQUAL "")
set(NX_TZDB_BASE_DIR "${YUZU_TZDB_PATH}")
set(NX_TZDB_TZ_DIR "${NX_TZDB_BASE_DIR}/zoneinfo")
elseif (MSVC)
# TODO(crueter): This is a terrible solution, but MSVC fails to link without it
# Need to investigate further but I still can't reproduce...
elseif (MSVC AND NOT CXX_CLANG AND YUZU_ENABLE_LTO)
# TODO(crueter): boot up the windows vm
set(NX_TZDB_VERSION "250725")
set(NX_TZDB_ARCHIVE "${CPM_SOURCE_CACHE}/nx_tzdb/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_BASE_DIR "${CPM_SOURCE_CACHE}/nx_tzdb/tz")
set(NX_TZDB_TZ_DIR "${NX_TZDB_BASE_DIR}/zoneinfo")
set(NX_TZDB_DOWNLOAD_URL "https://github.com/crueter/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
set(NX_TZDB_DOWNLOAD_URL "https://git.crueter.xyz/misc/tzdb_to_nx/releases/download/${NX_TZDB_VERSION}/${NX_TZDB_VERSION}.zip")
message(STATUS "Downloading time zone data from ${NX_TZDB_DOWNLOAD_URL}...")
file(DOWNLOAD ${NX_TZDB_DOWNLOAD_URL} ${NX_TZDB_ARCHIVE}
@ -65,14 +62,11 @@ else()
message(STATUS "Downloading time zone data...")
AddJsonPackage(tzdb)
target_include_directories(nx_tzdb
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
INTERFACE ${NX_TZDB_INCLUDE_DIR})
set(NX_TZDB_BASE_DIR "${CPM_SOURCE_CACHE}/nx_tzdb")
set(NX_TZDB_TZ_DIR "${nx_tzdb_SOURCE_DIR}")
set(NX_TZDB_BASE_DIR "${nx_tzdb_SOURCE_DIR}")
endif()
set(NX_TZDB_TZ_DIR "${NX_TZDB_BASE_DIR}/zoneinfo")
target_include_directories(nx_tzdb
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include
INTERFACE ${NX_TZDB_INCLUDE_DIR})

View file

@ -3,9 +3,9 @@
"package": "nx_tzdb",
"repo": "misc/tzdb_to_nx",
"git_host": "git.crueter.xyz",
"artifact": "%VERSION%.zip",
"artifact": "%VERSION%.tar.gz",
"tag": "%VERSION%",
"hash": "8f60b4b29f285e39c0443f3d5572a73780f3dbfcfd5b35004451fadad77f3a215b2e2aa8d0fffe7e348e2a7b0660882b35228b6178dda8804a14ce44509fd2ca",
"version": "250725"
"hash": "87abb2aeca716d5d77b05317086dbc2f8acfc2f3f76ce4778345ee3df19973e6cd8ecbf16cfab5ad94c9636a6c44fd3588f9aadd3cba89403cfd56c8bec645c5",
"version": "091025"
}
}

View file

@ -43,7 +43,7 @@
#define RENDERDOC_CC __cdecl
#elif defined(__linux__) || defined(__FreeBSD__) || defined(__sun__)
#define RENDERDOC_CC
#elif defined(__APPLE__)
#elif defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define RENDERDOC_CC
#else
#error "Unknown platform"

View file

@ -101,15 +101,9 @@ if (MSVC AND NOT CXX_CLANG)
)
endif()
if (USE_CCACHE OR YUZU_USE_PRECOMPILED_HEADERS)
# when caching, we need to use /Z7 to downgrade debug info to use an older but more cacheable format
# Precompiled headers are deleted if not using /Z7. See https://github.com/nanoant/CMakePCHCompiler/issues/21
add_compile_options(/Z7)
# Avoid D9025 warning
string(REPLACE "/Zi" "" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
else()
add_compile_options(/Zi)
if (WIN32 AND (CMAKE_BUILD_TYPE STREQUAL "Debug" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo"))
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
string(REPLACE "/Zi" "/Z7" CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
endif()
if (ARCHITECTURE_x86_64)
@ -141,7 +135,7 @@ else()
-Wno-missing-field-initializers
)
if (CXX_CLANG OR CXX_ICC) # Clang or AppleClang
if (CXX_CLANG OR CXX_ICC OR CXX_APPLE) # Clang, AppleClang, or Intel C++
if (NOT MSVC)
add_compile_options(
-Werror=shadow-uncaptured-local

View file

@ -57,9 +57,8 @@ android {
}
defaultConfig {
// TODO If this is ever modified, change application_id in strings.xml
applicationId = "dev.eden.eden_emulator"
minSdk = 30
minSdk = 24
targetSdk = 36
versionName = getGitVersion()
@ -72,7 +71,32 @@ android {
buildConfigField("String", "GIT_HASH", "\"${getGitHash()}\"")
buildConfigField("String", "BRANCH", "\"${getBranch()}\"")
externalNativeBuild {
cmake {
val extraCMakeArgs = (project.findProperty("YUZU_ANDROID_ARGS") as String?)?.split("\\s+".toRegex()) ?: emptyList()
arguments.addAll(listOf(
"-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DENABLE_WEB_SERVICE=1", // Enable web service
"-DENABLE_OPENSSL=ON",
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DYUZU_USE_CPM=ON",
"-DCPMUTIL_FORCE_BUNDLED=ON",
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DBUILD_TESTING=OFF",
"-DYUZU_TESTS=OFF",
"-DDYNARMIC_TESTS=OFF",
*extraCMakeArgs.toTypedArray()
))
abiFilters("arm64-v8a")
}
}
}
val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
signingConfigs {
@ -94,7 +118,6 @@ android {
// Define build types, which are orthogonal to product flavors.
buildTypes {
// Signed by release key, allowing for upload to Play Store.
release {
signingConfig = if (keystoreFile != null) {
@ -103,7 +126,6 @@ android {
signingConfigs.getByName("default")
}
resValue("string", "app_name_suffixed", "Eden")
isMinifyEnabled = true
isDebuggable = false
proguardFiles(
@ -116,7 +138,6 @@ android {
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
register("relWithDebInfo") {
isDefault = true
resValue("string", "app_name_suffixed", "Eden Debug Release")
signingConfig = signingConfigs.getByName("default")
isDebuggable = true
proguardFiles(
@ -132,7 +153,6 @@ android {
// Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
debug {
signingConfig = signingConfigs.getByName("default")
resValue("string", "app_name_suffixed", "Eden Debug")
isDebuggable = true
isJniDebuggable = true
versionNameSuffix = "-debug"
@ -140,19 +160,62 @@ android {
}
}
// this is really annoying but idk any other ways to fix this behavior
applicationVariants.all {
val variant = this
when {
variant.flavorName == "legacy" && variant.buildType.name == "debug" -> {
variant.resValue("string", "app_name_suffixed", "Eden Legacy Debug")
}
variant.flavorName == "mainline" && variant.buildType.name == "debug" -> {
variant.resValue("string", "app_name_suffixed", "Eden Debug")
}
variant.flavorName == "genshinSpoof" && variant.buildType.name == "debug" -> {
variant.resValue("string", "app_name_suffixed", "Eden Optimized Debug")
}
variant.flavorName == "legacy" && variant.buildType.name == "relWithDebInfo" -> {
variant.resValue("string", "app_name_suffixed", "Eden Legacy Debug Release")
}
variant.flavorName == "mainline" && variant.buildType.name == "relWithDebInfo" -> {
variant.resValue("string", "app_name_suffixed", "Eden Debug Release")
}
variant.flavorName == "genshinSpoof" && variant.buildType.name == "relWithDebInfo" -> {
variant.resValue("string", "app_name_suffixed", "Eden Optimized Debug Release")
}
}
}
android {
flavorDimensions.add("version")
productFlavors {
create("mainline") {
dimension = "version"
// No need to set applicationId here
resValue("string", "app_name_suffixed", "Eden")
}
create("genshinSpoof") {
dimension = "version"
resValue("string", "app_name_suffixed", "Eden Optimised")
resValue("string", "app_name_suffixed", "Eden Optimized")
applicationId = "com.miHoYo.Yuanshen"
}
create("legacy") {
dimension = "version"
resValue("string", "app_name_suffixed", "Eden Legacy")
applicationId = "dev.legacy.eden_emulator"
externalNativeBuild {
cmake {
arguments.add("-DYUZU_LEGACY=ON")
}
}
sourceSets {
getByName("legacy") {
res.srcDirs("src/main/legacy")
}
}
}
}
}
@ -162,31 +225,6 @@ android {
path = file("../../../CMakeLists.txt")
}
}
defaultConfig {
externalNativeBuild {
cmake {
arguments(
"-DENABLE_QT=0", // Don't use QT
"-DENABLE_SDL2=0", // Don't use SDL
"-DENABLE_WEB_SERVICE=1", // Enable web service
"-DENABLE_OPENSSL=ON",
"-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
"-DYUZU_USE_CPM=ON",
"-DCPMUTIL_FORCE_BUNDLED=ON",
"-DYUZU_USE_BUNDLED_FFMPEG=ON",
"-DYUZU_ENABLE_LTO=ON",
"-DCMAKE_EXPORT_COMPILE_COMMANDS=ON",
"-DBUILD_TESTING=OFF",
"-DYUZU_TESTS=OFF",
"-DDYNARMIC_TESTS=OFF",
"-DDYNARMIC_ENABLE_LTO=ON"
)
abiFilters("arm64-v8a")
}
}
}
}
tasks.register<Delete>("ktlintReset", fun Delete.() {

View file

@ -206,6 +206,17 @@ object NativeLibrary {
ErrorUnknown
}
/**
* playtime tracking
*/
external fun playTimeManagerInit()
external fun playTimeManagerStart()
external fun playTimeManagerStop()
external fun playTimeManagerGetPlayTime(programId: String): Long
external fun playTimeManagerGetCurrentTitleId(): Long
external fun playTimeManagerResetProgramPlayTime(programId: String)
external fun playTimeManagerSetPlayTime(programId: String, playTimeSeconds: Long)
var coreErrorAlertResult = false
val coreErrorAlertLock = Object()

View file

@ -53,6 +53,7 @@ class YuzuApplication : Application() {
application = this
documentsTree = DocumentsTree()
DirectoryInitialization.start()
NativeLibrary.playTimeManagerInit()
GpuDriverHelper.initializeDriverParameters()
NativeInput.reloadInputDevices()
NativeLibrary.logDeviceInfo()

View file

@ -61,6 +61,7 @@ import org.yuzu.yuzu_emu.utils.ThemeHelper
import java.text.NumberFormat
import kotlin.math.roundToInt
import org.yuzu.yuzu_emu.utils.ForegroundService
import androidx.core.os.BundleCompat
class EmulationActivity : AppCompatActivity(), SensorEventListener {
private lateinit var binding: ActivityEmulationBinding
@ -68,6 +69,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
var isActivityRecreated = false
private lateinit var nfcReader: NfcReader
private var touchDownTime: Long = 0
private val maxTapDuration = 500L
private val gyro = FloatArray(3)
private val accel = FloatArray(3)
private var motionTimestamp: Long = 0
@ -199,6 +203,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onDestroy() {
super.onDestroy()
stopForegroundService(this)
NativeLibrary.playTimeManagerStop()
}
@ -227,7 +232,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) {
return super.dispatchKeyEvent(event)
}
@ -241,7 +248,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) {
return super.dispatchGenericMotionEvent(event)
}
@ -489,8 +498,42 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
}
}
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val navHostFragment = supportFragmentManager.findFragmentById(R.id.fragment_container) as? NavHostFragment
val emulationFragment = navHostFragment?.childFragmentManager?.fragments?.firstOrNull() as? org.yuzu.yuzu_emu.fragments.EmulationFragment
emulationFragment?.let { fragment ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
touchDownTime = System.currentTimeMillis()
// show overlay immediately on touch and cancel timer
if (!emulationViewModel.drawerOpen.value) {
fragment.handler.removeCallbacksAndMessages(null)
fragment.showOverlay()
}
}
MotionEvent.ACTION_UP -> {
if (!emulationViewModel.drawerOpen.value) {
val touchDuration = System.currentTimeMillis() - touchDownTime
if (touchDuration <= maxTapDuration) {
fragment.handleScreenTap(false)
} else {
// just start the auto-hide timer without toggling visibility
fragment.handleScreenTap(true)
}
}
}
}
}
return super.dispatchTouchEvent(event)
}
fun onEmulationStarted() {
emulationViewModel.setEmulationStarted(true)
NativeLibrary.playTimeManagerStart()
}
fun onEmulationStopped(status: Int) {

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -83,6 +86,34 @@ class GamePropertiesAdapter(
} else {
binding.details.setVisible(false)
}
val hasVisibleActions = submenuProperty.secondaryActions?.any { it.isShown } == true
if (hasVisibleActions) {
binding.dividerSecondaryActions.setVisible(true)
binding.layoutSecondaryActions.setVisible(true)
submenuProperty.secondaryActions!!.forEach { secondaryAction ->
if (secondaryAction.isShown) {
val button = com.google.android.material.button.MaterialButton(
binding.root.context,
null,
com.google.android.material.R.attr.materialButtonOutlinedStyle
).apply {
setIconResource(secondaryAction.iconId)
iconSize = (18 * binding.root.context.resources.displayMetrics.density).toInt()
text = binding.root.context.getString(secondaryAction.descriptionId)
contentDescription = binding.root.context.getString(secondaryAction.descriptionId)
setOnClickListener { secondaryAction.action.invoke() }
}
binding.layoutSecondaryActions.addView(button)
}
}
} else {
binding.dividerSecondaryActions.setVisible(false)
binding.layoutSecondaryActions.setVisible(false)
}
}
}

View file

@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
AUDIO_MUTED("audio_muted"),
CPU_DEBUG_MODE("cpu_debug_mode"),
FASTMEM("cpuopt_fastmem"),
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
CORE_SYNC_CORE_SPEED("sync_core_speed"),
@ -51,10 +50,11 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SOC_OVERLAY_BACKGROUND("soc_overlay_background"),
ENABLE_RAII("enable_raii"),
FRAME_INTERPOLATION("frame_interpolation"),
// FRAME_SKIPPING("frame_skipping"),
ENABLE_INPUT_OVERLAY_AUTO_HIDE("enable_input_overlay_auto_hide"),
PERF_OVERLAY_BACKGROUND("perf_overlay_background"),
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
@ -69,7 +69,6 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
DEBUG_FLUSH_BY_LINE("flush_line"),
USE_LRU_CACHE("use_lru_cache");
external fun isRaiiEnabled(): Boolean
// external fun isFrameSkippingEnabled(): Boolean
external fun isFrameInterpolationEnabled(): Boolean

View file

@ -59,7 +59,8 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
OFFLINE_WEB_APPLET("offline_web_applet_mode"),
LOGIN_SHARE_APPLET("login_share_applet_mode"),
WIFI_WEB_AUTH_APPLET("wifi_web_auth_applet_mode"),
MY_PAGE_APPLET("my_page_applet_mode")
MY_PAGE_APPLET("my_page_applet_mode"),
INPUT_OVERLAY_AUTO_HIDE("input_overlay_auto_hide")
;
override fun getInt(needsGlobal: Boolean): Int = NativeConfig.getInt(key, needsGlobal)

View file

@ -12,6 +12,7 @@ object Settings {
SECTION_SYSTEM(R.string.preferences_system),
SECTION_RENDERER(R.string.preferences_graphics),
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
SECTION_AUDIO(R.string.preferences_audio),
SECTION_INPUT(R.string.preferences_controls),

View file

@ -96,6 +96,7 @@ abstract class SettingsItem(
const val TYPE_INT_SINGLE_CHOICE = 9
const val TYPE_INPUT_PROFILE = 10
const val TYPE_STRING_INPUT = 11
const val TYPE_SPINBOX = 12
const val FASTMEM_COMBINED = "fastmem_combined"
@ -228,13 +229,6 @@ abstract class SettingsItem(
override fun reset() = BooleanSetting.USE_DOCKED_MODE.reset()
}
put(
SwitchSetting(
BooleanSetting.ENABLE_RAII,
titleId = R.string.enable_raii,
descriptionId = R.string.enable_raii_description
)
)
put(
SwitchSetting(
BooleanSetting.FRAME_INTERPOLATION,
@ -385,6 +379,22 @@ abstract class SettingsItem(
warningMessage = R.string.warning_resolution
)
)
put(
SwitchSetting(
BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE,
titleId = R.string.enable_input_overlay_auto_hide,
)
)
put(
SpinBoxSetting(
IntSetting.INPUT_OVERLAY_AUTO_HIDE,
titleId = R.string.overlay_auto_hide,
descriptionId = R.string.overlay_auto_hide_description,
min = 1,
max = 999,
valueHint = R.string.seconds
)
)
put(
SwitchSetting(
@ -754,13 +764,6 @@ abstract class SettingsItem(
descriptionId = R.string.use_auto_stub_description
)
)
put(
SwitchSetting(
BooleanSetting.CPU_DEBUG_MODE,
titleId = R.string.cpu_debug_mode,
descriptionId = R.string.cpu_debug_mode_description
)
)
val fastmem = object : AbstractBooleanSetting {
override fun getBoolean(needsGlobal: Boolean): Boolean =
@ -774,7 +777,6 @@ abstract class SettingsItem(
override val key: String = FASTMEM_COMBINED
override val isRuntimeModifiable: Boolean = false
override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
override val defaultValue: Boolean = true
override val isSwitchable: Boolean = true
override var global: Boolean
@ -816,3 +818,4 @@ abstract class SettingsItem(
}
}
}

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model.view
import androidx.annotation.StringRes
import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting
class SpinBoxSetting(
setting: AbstractSetting,
@StringRes titleId: Int = 0,
titleString: String = "",
@StringRes descriptionId: Int = 0,
descriptionString: String = "",
val valueHint: Int,
val min: Int,
val max: Int
) : SettingsItem(setting, titleId, titleString, descriptionId, descriptionString) {
override val type = TYPE_SPINBOX
fun getSelectedValue(needsGlobal: Boolean = false) =
when (setting) {
is AbstractByteSetting -> setting.getByte(needsGlobal).toInt()
is AbstractShortSetting -> setting.getShort(needsGlobal).toInt()
is AbstractIntSetting -> setting.getInt(needsGlobal)
is AbstractFloatSetting -> setting.getFloat(needsGlobal).toInt()
else -> 0
}
fun setSelectedValue(value: Int) =
when (setting) {
is AbstractByteSetting -> setting.setByte(value.toByte())
is AbstractShortSetting -> setting.setShort(value.toShort())
is AbstractFloatSetting -> setting.setFloat(value.toFloat())
else -> (setting as AbstractIntSetting).setInt(value)
}
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -149,7 +152,9 @@ class InputDialogFragment : DialogFragment() {
private fun onKeyEvent(event: KeyEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) {
return false
}
@ -173,7 +178,9 @@ class InputDialogFragment : DialogFragment() {
private fun onMotionEvent(event: MotionEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) {
return false
}

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui
@ -61,6 +61,10 @@ class SettingsAdapter(
SliderViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_SPINBOX -> {
SpinBoxViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
SettingsItem.TYPE_SUBMENU -> {
SubmenuViewHolder(ListItemSettingBinding.inflate(inflater), this)
}
@ -191,6 +195,14 @@ class SettingsAdapter(
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
fun onSpinBoxClick(item: SpinBoxSetting, position: Int) {
SettingsDialogFragment.newInstance(
settingsViewModel,
item,
SettingsItem.TYPE_SPINBOX,
position
).show(fragment.childFragmentManager, SettingsDialogFragment.TAG)
}
fun onSubmenuClick(item: SubmenuSetting) {
val action = SettingsNavigationDirections.actionGlobalSettingsFragment(item.menuKey, null)

View file

@ -14,6 +14,7 @@ import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.activityViewModels
@ -22,6 +23,7 @@ import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.DialogEditTextBinding
import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
import org.yuzu.yuzu_emu.databinding.DialogSpinboxBinding
import org.yuzu.yuzu_emu.features.input.NativeInput
import org.yuzu.yuzu_emu.features.input.model.AnalogDirection
import org.yuzu.yuzu_emu.features.settings.model.view.AnalogInputSetting
@ -30,6 +32,7 @@ import org.yuzu.yuzu_emu.features.settings.model.view.IntSingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringInputSetting
import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting
import org.yuzu.yuzu_emu.utils.ParamPackage
@ -46,6 +49,7 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private lateinit var sliderBinding: DialogSliderBinding
private lateinit var stringInputBinding: DialogEditTextBinding
private lateinit var spinboxBinding: DialogSpinboxBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -142,6 +146,76 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
.create()
}
SettingsItem.TYPE_SPINBOX -> {
spinboxBinding = DialogSpinboxBinding.inflate(layoutInflater)
val item = settingsViewModel.clickedItem as SpinBoxSetting
val currentValue = item.getSelectedValue()
spinboxBinding.editValue.setText(currentValue.toString())
spinboxBinding.textInputLayout.hint = getString(item.valueHint)
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(item.title)
.setView(spinboxBinding.root)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, defaultCancelListener)
.create()
val updateButtonState = { enabled: Boolean ->
dialog.setOnShowListener { dialogInterface ->
(dialogInterface as AlertDialog).getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
}
if (dialog.isShowing) {
dialog.getButton(DialogInterface.BUTTON_POSITIVE)?.isEnabled = enabled
}
}
val updateValidity = { value: Int ->
val isValid = value in item.min..item.max
if (isValid) {
spinboxBinding.textInputLayout.error = null
} else {
spinboxBinding.textInputLayout.error = getString(
if (value < item.min) R.string.value_too_low else R.string.value_too_high,
if (value < item.min) item.min else item.max
)
}
updateButtonState(isValid)
}
spinboxBinding.buttonDecrement.setOnClickListener {
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
val newValue = current - 1
spinboxBinding.editValue.setText(newValue.toString())
updateValidity(newValue)
}
spinboxBinding.buttonIncrement.setOnClickListener {
val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue
val newValue = current + 1
spinboxBinding.editValue.setText(newValue.toString())
updateValidity(newValue)
}
spinboxBinding.editValue.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable?) {
val value = s.toString().toIntOrNull()
if (value != null) {
updateValidity(value)
} else {
spinboxBinding.textInputLayout.error = getString(R.string.invalid_value)
updateButtonState(false)
}
}
})
updateValidity(currentValue)
dialog
}
SettingsItem.TYPE_STRING_INPUT -> {
stringInputBinding = DialogEditTextBinding.inflate(layoutInflater)
val item = settingsViewModel.clickedItem as StringInputSetting
@ -281,6 +355,14 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
sliderSetting.setSelectedValue(settingsViewModel.sliderProgress.value)
}
is SpinBoxSetting -> {
val spinBoxSetting = settingsViewModel.clickedItem as SpinBoxSetting
val value = spinboxBinding.editValue.text.toString().toIntOrNull()
if (value != null && value in spinBoxSetting.min..spinBoxSetting.max) {
spinBoxSetting.setSelectedValue(value)
}
}
is StringInputSetting -> {
val stringInputSetting = settingsViewModel.clickedItem as StringInputSetting
stringInputSetting.setSelectedValue(

View file

@ -97,6 +97,7 @@ class SettingsFragmentPresenter(
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
MenuTag.SECTION_AUDIO -> addAudioSettings(sl)
MenuTag.SECTION_INPUT -> addInputSettings(sl)
MenuTag.SECTION_INPUT_PLAYER_ONE -> addInputPlayer(sl, 0)
@ -156,6 +157,14 @@ class SettingsFragmentPresenter(
menuKey = MenuTag.SECTION_SOC_OVERLAY
)
)
add(
SubmenuSetting(
titleId = R.string.input_overlay_options,
iconId = R.drawable.ic_controller,
descriptionId = R.string.input_overlay_options_description,
menuKey = MenuTag.SECTION_INPUT_OVERLAY
)
)
}
add(
SubmenuSetting(
@ -264,6 +273,13 @@ class SettingsFragmentPresenter(
}
}
private fun addInputOverlaySettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.key)
add(IntSetting.INPUT_OVERLAY_AUTO_HIDE.key)
}
}
private fun addSocOverlaySettings(sl: ArrayList<SettingsItem>) {
sl.apply {
add(HeaderSetting(R.string.stats_overlay_customization))
@ -446,7 +462,6 @@ class SettingsFragmentPresenter(
add(IntSetting.RENDERER_SAMPLE_SHADING_FRACTION.key)
add(HeaderSetting(R.string.veil_renderer))
add(BooleanSetting.ENABLE_RAII.key)
add(BooleanSetting.RENDERER_EARLY_RELEASE_FENCES.key)
add(IntSetting.DMA_ACCURACY.key)
add(BooleanSetting.BUFFER_REORDER_DISABLE.key)
@ -1143,7 +1158,6 @@ class SettingsFragmentPresenter(
add(IntSetting.CPU_BACKEND.key)
add(IntSetting.CPU_ACCURACY.key)
add(BooleanSetting.USE_AUTO_STUB.key)
add(BooleanSetting.CPU_DEBUG_MODE.key)
add(SettingsItem.FASTMEM_COMBINED)
add(HeaderSetting(R.string.log))

View file

@ -0,0 +1,44 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.ui.viewholder
import android.view.View
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
import org.yuzu.yuzu_emu.features.settings.model.view.SpinBoxSetting
import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
import org.yuzu.yuzu_emu.utils.ViewUtils.setVisible
class SpinBoxViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
SettingViewHolder(binding.root, adapter) {
private lateinit var setting: SpinBoxSetting
override fun bind(item: SettingsItem) {
setting = item as SpinBoxSetting
binding.textSettingName.text = setting.title
binding.textSettingDescription.setVisible(item.description.isNotEmpty())
binding.textSettingDescription.text = setting.description
binding.textSettingValue.setVisible(true)
binding.textSettingValue.text = setting.getSelectedValue().toString()
binding.buttonClear.setVisible(setting.clearable)
binding.buttonClear.setOnClickListener {
adapter.onClearClick(setting, bindingAdapterPosition)
}
setStyle(setting.isEditable, binding)
}
override fun onClick(clicked: View) {
if (setting.isEditable) {
adapter.onSpinBoxClick(setting, bindingAdapterPosition)
}
}
override fun onLongClick(clicked: View): Boolean {
if (setting.isEditable) {
return adapter.onLongClick(setting, bindingAdapterPosition)
}
return false
}
}

View file

@ -96,6 +96,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private var perfStatsUpdater: (() -> Unit)? = null
private var socUpdater: (() -> Unit)? = null
val handler = Handler(Looper.getMainLooper())
private var isOverlayVisible = true
private var _binding: FragmentEmulationBinding? = null
private val binding get() = _binding!!
@ -452,7 +455,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
/**
* Ask user if they want to launch with default settings when custom settings fail
*/
private suspend fun askUserToLaunchWithDefaultSettings(gameTitle: String, errorMessage: String): Boolean {
private suspend fun askUserToLaunchWithDefaultSettings(
gameTitle: String,
errorMessage: String
): Boolean {
return suspendCoroutine { continuation ->
requireActivity().runOnUiThread {
MaterialAlertDialogBuilder(requireContext())
@ -728,6 +734,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
updateShowStatsOverlay()
updateSocOverlay()
initializeOverlayAutoHide()
// Re update binding when the specs values get initialized properly
binding.inGameMenu.getHeaderView(0).apply {
val titleView = findViewById<TextView>(R.id.text_game_title)
@ -917,6 +925,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
updatePauseMenuEntry(emulationState.isPaused)
}
}
// if the overlay auto-hide setting is changed while paused,
// we need to reinitialize the auto-hide timer
initializeOverlayAutoHide()
}
private fun resetInputOverlay() {
@ -924,6 +937,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
IntSetting.OVERLAY_OPACITY.reset()
binding.surfaceInputOverlay.post {
binding.surfaceInputOverlay.resetLayoutVisibilityAndPlacement()
binding.surfaceInputOverlay.resetIndividualControlScale()
}
}
@ -1546,6 +1560,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50)
setControlOpacity(100)
binding.surfaceInputOverlay.resetIndividualControlScale()
}
.show()
}
@ -1620,6 +1635,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
Log.debug("[EmulationFragment] Pausing emulation.")
NativeLibrary.pauseEmulation()
NativeLibrary.playTimeManagerStop()
state = State.PAUSED
} else {
@ -1710,6 +1726,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
State.PAUSED -> {
Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
}
else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
@ -1726,4 +1743,61 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
private val socUpdateHandler = Handler(Looper.myLooper()!!)
}
private fun startOverlayAutoHideTimer(seconds: Int) {
handler.removeCallbacksAndMessages(null)
handler.postDelayed({
if (isOverlayVisible) {
hideOverlay()
}
}, seconds * 1000L)
}
fun handleScreenTap(isLongTap: Boolean) {
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
val shouldProceed = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean() && BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
if (!shouldProceed) {
return
}
// failsafe
if (autoHideSeconds == 0) {
showOverlay()
return
}
if (!isOverlayVisible && !isLongTap) {
showOverlay()
}
startOverlayAutoHideTimer(autoHideSeconds)
}
private fun initializeOverlayAutoHide() {
val autoHideSeconds = IntSetting.INPUT_OVERLAY_AUTO_HIDE.getInt()
val autoHideEnabled = BooleanSetting.ENABLE_INPUT_OVERLAY_AUTO_HIDE.getBoolean()
val showOverlay = BooleanSetting.SHOW_INPUT_OVERLAY.getBoolean()
if (autoHideEnabled && showOverlay) {
showOverlay()
startOverlayAutoHideTimer(autoHideSeconds)
}
}
fun showOverlay() {
if (!isOverlayVisible) {
isOverlayVisible = true
ViewUtils.showView(binding.surfaceInputOverlay, 500)
}
}
private fun hideOverlay() {
if (isOverlayVisible) {
isOverlayVisible = false
ViewUtils.hideView(binding.surfaceInputOverlay, 500)
}
}
}

View file

@ -1,11 +1,13 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.content.Intent
import android.content.pm.ShortcutInfo
import android.content.pm.ShortcutManager
import android.os.Bundle
import android.provider.DocumentsContract
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -14,6 +16,7 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
@ -25,16 +28,19 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.HomeNavigationDirections
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.adapters.GamePropertiesAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamePropertiesBinding
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.features.settings.model.Settings
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.GameProperty
import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.model.InstallableProperty
import org.yuzu.yuzu_emu.model.SubMenuPropertySecondaryAction
import org.yuzu.yuzu_emu.model.SubmenuProperty
import org.yuzu.yuzu_emu.model.TaskState
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
@ -104,6 +110,8 @@ class GamePropertiesFragment : Fragment() {
binding.title.text = args.game.title
binding.title.marquee()
getPlayTime()
binding.buttonStart.setOnClickListener {
LaunchGameDialogFragment.newInstance(args.game)
.show(childFragmentManager, LaunchGameDialogFragment.TAG)
@ -128,6 +136,110 @@ class GamePropertiesFragment : Fragment() {
gamesViewModel.reloadGames(true)
}
private fun getPlayTime() {
binding.playtime.text = buildString {
val playTimeSeconds = NativeLibrary.playTimeManagerGetPlayTime(args.game.programId)
val hours = playTimeSeconds / 3600
val minutes = (playTimeSeconds % 3600) / 60
val seconds = playTimeSeconds % 60
val readablePlayTime = when {
hours > 0 -> "${hours}h ${minutes}m ${seconds}s"
minutes > 0 -> "${minutes}m ${seconds}s"
else -> "${seconds}s"
}
append(getString(R.string.playtime))
append(readablePlayTime)
}
binding.playtime.setOnClickListener {
showEditPlaytimeDialog()
}
}
private fun showEditPlaytimeDialog() {
val dialogView = layoutInflater.inflate(R.layout.dialog_edit_playtime, null)
val hoursLayout =
dialogView.findViewById<com.google.android.material.textfield.TextInputLayout>(R.id.layout_hours)
val minutesLayout =
dialogView.findViewById<com.google.android.material.textfield.TextInputLayout>(R.id.layout_minutes)
val secondsLayout =
dialogView.findViewById<com.google.android.material.textfield.TextInputLayout>(R.id.layout_seconds)
val hoursInput =
dialogView.findViewById<com.google.android.material.textfield.TextInputEditText>(R.id.input_hours)
val minutesInput =
dialogView.findViewById<com.google.android.material.textfield.TextInputEditText>(R.id.input_minutes)
val secondsInput =
dialogView.findViewById<com.google.android.material.textfield.TextInputEditText>(R.id.input_seconds)
val playTimeSeconds = NativeLibrary.playTimeManagerGetPlayTime(args.game.programId)
val hours = playTimeSeconds / 3600
val minutes = (playTimeSeconds % 3600) / 60
val seconds = playTimeSeconds % 60
hoursInput.setText(hours.toString())
minutesInput.setText(minutes.toString())
secondsInput.setText(seconds.toString())
val dialog = com.google.android.material.dialog.MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.edit_playtime)
.setView(dialogView)
.setPositiveButton(android.R.string.ok, null)
.setNegativeButton(android.R.string.cancel, null)
.create()
dialog.setOnShowListener {
val positiveButton = dialog.getButton(android.app.AlertDialog.BUTTON_POSITIVE)
positiveButton.setOnClickListener {
hoursLayout.error = null
minutesLayout.error = null
secondsLayout.error = null
val hoursText = hoursInput.text.toString()
val minutesText = minutesInput.text.toString()
val secondsText = secondsInput.text.toString()
val hoursValue = hoursText.toLongOrNull() ?: 0
val minutesValue = minutesText.toLongOrNull() ?: 0
val secondsValue = secondsText.toLongOrNull() ?: 0
var hasError = false
// normally cant be above 9999
if (hoursValue < 0 || hoursValue > 9999) {
hoursLayout.error = getString(R.string.hours_must_be_between_0_and_9999)
hasError = true
}
if (minutesValue < 0 || minutesValue > 59) {
minutesLayout.error = getString(R.string.minutes_must_be_between_0_and_59)
hasError = true
}
if (secondsValue < 0 || secondsValue > 59) {
secondsLayout.error = getString(R.string.seconds_must_be_between_0_and_59)
hasError = true
}
if (!hasError) {
val totalSeconds = hoursValue * 3600 + minutesValue * 60 + secondsValue
NativeLibrary.playTimeManagerSetPlayTime(args.game.programId, totalSeconds)
getPlayTime()
Toast.makeText(
requireContext(),
R.string.playtime_updated_successfully,
Toast.LENGTH_SHORT
).show()
dialog.dismiss()
}
}
}
dialog.show()
}
private fun reloadList() {
_binding ?: return
@ -137,25 +249,66 @@ class GamePropertiesFragment : Fragment() {
SubmenuProperty(
R.string.info,
R.string.info_description,
R.drawable.ic_info_outline
) {
R.drawable.ic_info_outline,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToGameInfoFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
add(
SubmenuProperty(
R.string.preferences_settings,
R.string.per_game_settings_description,
R.drawable.ic_settings
) {
R.drawable.ic_settings,
action = {
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
args.game,
Settings.MenuTag.SECTION_ROOT
)
binding.root.findNavController().navigate(action)
},
secondaryActions = buildList {
val configExists = File(
DirectoryInitialization.userDirectory +
"/config/custom/" + args.game.settingsName + ".ini"
).exists()
add(SubMenuPropertySecondaryAction(
isShown = configExists,
descriptionId = R.string.import_config,
iconId = R.drawable.ic_import,
action = {
importConfig.launch(arrayOf("text/ini", "application/octet-stream"))
}
))
add(SubMenuPropertySecondaryAction(
isShown = configExists,
descriptionId = R.string.export_config,
iconId = R.drawable.ic_export,
action = {
exportConfig.launch(args.game.settingsName + ".ini")
}
))
add(SubMenuPropertySecondaryAction(
isShown = configExists,
descriptionId = R.string.share_game_settings,
iconId = R.drawable.ic_share,
action = {
val configFile = File(
DirectoryInitialization.userDirectory +
"/config/custom/" + args.game.settingsName + ".ini"
)
if (configFile.exists()) {
shareConfigFile(configFile)
}
}
))
}
)
)
if (GpuDriverHelper.supportsCustomDriverLoading()) {
@ -164,13 +317,14 @@ class GamePropertiesFragment : Fragment() {
R.string.gpu_driver_manager,
R.string.install_gpu_driver_description,
R.drawable.ic_build,
detailsFlow = driverViewModel.selectedDriverTitle
) {
detailsFlow = driverViewModel.selectedDriverTitle,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToDriverManagerFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
}
if (!args.game.isHomebrew) {
@ -178,13 +332,14 @@ class GamePropertiesFragment : Fragment() {
SubmenuProperty(
R.string.add_ons,
R.string.add_ons_description,
R.drawable.ic_edit
) {
R.drawable.ic_edit,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
add(
InstallableProperty(
R.string.save_data,
@ -245,7 +400,7 @@ class GamePropertiesFragment : Fragment() {
R.string.clear_shader_cache,
R.string.clear_shader_cache_description,
R.drawable.ic_delete,
{
details = {
if (shaderCacheDir.exists()) {
val bytes = shaderCacheDir.walkTopDown().filter { it.isFile }
.map { it.length() }.sum()
@ -253,8 +408,8 @@ class GamePropertiesFragment : Fragment() {
} else {
MemoryUtil.bytesToSizeUnit(0f)
}
}
) {
},
action = {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.clear_shader_cache,
@ -271,6 +426,33 @@ class GamePropertiesFragment : Fragment() {
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
)
)
}
if (NativeLibrary.playTimeManagerGetPlayTime(args.game.programId) > 0) {
add(
SubmenuProperty(
R.string.reset_playtime,
R.string.reset_playtime_description,
R.drawable.ic_delete,
action = {
MessageDialogFragment.newInstance(
requireActivity(),
titleId = R.string.reset_playtime,
descriptionId = R.string.reset_playtime_warning_description,
positiveAction = {
NativeLibrary.playTimeManagerResetProgramPlayTime(args.game.programId)
Toast.makeText(
YuzuApplication.appContext,
R.string.playtime_reset_successfully,
Toast.LENGTH_SHORT
).show()
getPlayTime()
homeViewModel.reloadPropertiesList(true)
}
).show(parentFragmentManager, MessageDialogFragment.TAG)
}
)
)
}
}
}
@ -284,6 +466,8 @@ class GamePropertiesFragment : Fragment() {
override fun onResume() {
super.onResume()
driverViewModel.updateDriverNameForGame(args.game)
getPlayTime()
reloadList()
}
private fun setInsets() =
@ -420,4 +604,89 @@ class GamePropertiesFragment : Fragment() {
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
/**
* Imports an ini file from external storage to internal app directory and override per-game config
*/
private val importConfig = registerForActivityResult(
ActivityResultContracts.OpenDocument()
) { result ->
if (result == null) {
return@registerForActivityResult
}
val iniResult = FileUtil.copyUriToInternalStorage(
sourceUri = result,
destinationParentPath =
DirectoryInitialization.userDirectory + "/config/custom/",
destinationFilename = args.game.settingsName + ".ini"
)
if (iniResult?.exists() == true) {
Toast.makeText(
requireContext(),
getString(R.string.import_success),
Toast.LENGTH_SHORT
).show()
homeViewModel.reloadPropertiesList(true)
} else {
Toast.makeText(
requireContext(),
getString(R.string.import_failed),
Toast.LENGTH_SHORT
).show()
}
}
/**
* Exports game's config ini to the specified location in external storage
*/
private val exportConfig = registerForActivityResult(
ActivityResultContracts.CreateDocument("text/ini")
) { result ->
if (result == null) {
return@registerForActivityResult
}
ProgressDialogFragment.newInstance(
requireActivity(),
R.string.save_files_exporting,
false
) { _, _ ->
val configLocation = DirectoryInitialization.userDirectory +
"/config/custom/" + args.game.settingsName + ".ini"
val iniResult = FileUtil.copyToExternalStorage(
sourcePath = configLocation,
destUri = result
)
return@newInstance when (iniResult) {
TaskState.Completed -> getString(R.string.export_success)
TaskState.Cancelled, TaskState.Failed -> getString(R.string.export_failed)
}
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
}
private fun shareConfigFile(configFile: File) {
val file = DocumentFile.fromSingleUri(
requireContext(),
DocumentsContract.buildDocumentUri(
DocumentProvider.AUTHORITY,
"${DocumentProvider.ROOT_ID}/${configFile}"
)
)!!
val intent = Intent(Intent.ACTION_SEND)
.setDataAndType(file.uri, FileUtil.TEXT_PLAIN)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
if (file.exists()) {
intent.putExtra(Intent.EXTRA_STREAM, file.uri)
startActivity(Intent.createChooser(intent, getText(R.string.share_game_settings)))
} else {
Toast.makeText(
requireContext(),
getText(R.string.share_config_failed),
Toast.LENGTH_SHORT
).show()
}
}
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -24,9 +27,17 @@ data class SubmenuProperty(
override val iconId: Int,
val details: (() -> String)? = null,
val detailsFlow: StateFlow<String>? = null,
val action: () -> Unit
val action: () -> Unit,
val secondaryActions: List<SubMenuPropertySecondaryAction>? = null
) : GameProperty
data class SubMenuPropertySecondaryAction(
val isShown : Boolean,
val descriptionId: Int,
val iconId: Int,
val action: () -> Unit
)
data class InstallableProperty(
override val titleId: Int,
override val descriptionId: Int,

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay
@ -13,6 +13,8 @@ import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.graphics.drawable.VectorDrawable
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.AttributeSet
import android.view.HapticFeedbackConstants
import android.view.MotionEvent
@ -52,6 +54,12 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
private var dpadBeingConfigured: InputOverlayDrawableDpad? = null
private var joystickBeingConfigured: InputOverlayDrawableJoystick? = null
private var scaleDialog: OverlayScaleDialog? = null
private var touchStartX = 0f
private var touchStartY = 0f
private var hasMoved = false
private val moveThreshold = 20f
private lateinit var windowInsets: WindowInsets
var layout = OverlayLayout.Landscape
@ -254,23 +262,44 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
) {
buttonBeingConfigured = button
buttonBeingConfigured!!.onConfigureTouch(event)
touchStartX = event.getX(pointerIndex)
touchStartY = event.getY(pointerIndex)
hasMoved = false
}
MotionEvent.ACTION_MOVE -> if (buttonBeingConfigured != null) {
val moveDistance = kotlin.math.sqrt(
(event.getX(pointerIndex) - touchStartX).let { it * it } +
(event.getY(pointerIndex) - touchStartY).let { it * it }
)
if (moveDistance > moveThreshold) {
hasMoved = true
buttonBeingConfigured!!.onConfigureTouch(event)
invalidate()
return true
}
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_POINTER_UP -> if (buttonBeingConfigured === button) {
// Persist button position by saving new place.
if (!hasMoved) {
showScaleDialog(
buttonBeingConfigured,
null,
null,
fingerPositionX,
fingerPositionY
)
} else {
saveControlPosition(
buttonBeingConfigured!!.overlayControlData.id,
buttonBeingConfigured!!.bounds.centerX(),
buttonBeingConfigured!!.bounds.centerY(),
individuaScale = buttonBeingConfigured!!.overlayControlData.individualScale,
layout
)
}
buttonBeingConfigured = null
}
}
@ -287,23 +316,46 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
) {
dpadBeingConfigured = dpad
dpadBeingConfigured!!.onConfigureTouch(event)
touchStartX = event.getX(pointerIndex)
touchStartY = event.getY(pointerIndex)
hasMoved = false
}
MotionEvent.ACTION_MOVE -> if (dpadBeingConfigured != null) {
val moveDistance = kotlin.math.sqrt(
(event.getX(pointerIndex) - touchStartX).let { it * it } +
(event.getY(pointerIndex) - touchStartY).let { it * it }
)
if (moveDistance > moveThreshold) {
hasMoved = true
dpadBeingConfigured!!.onConfigureTouch(event)
invalidate()
return true
}
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_POINTER_UP -> if (dpadBeingConfigured === dpad) {
// Persist button position by saving new place.
if (!hasMoved) {
// This was a click, show scale dialog for dpad
showScaleDialog(
null,
dpadBeingConfigured,
null,
fingerPositionX,
fingerPositionY
)
} else {
// This was a move, save position
saveControlPosition(
OverlayControl.COMBINED_DPAD.id,
dpadBeingConfigured!!.bounds.centerX(),
dpadBeingConfigured!!.bounds.centerY(),
individuaScale = dpadBeingConfigured!!.individualScale,
layout
)
}
dpadBeingConfigured = null
}
}
@ -317,21 +369,43 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
) {
joystickBeingConfigured = joystick
joystickBeingConfigured!!.onConfigureTouch(event)
touchStartX = event.getX(pointerIndex)
touchStartY = event.getY(pointerIndex)
hasMoved = false
}
MotionEvent.ACTION_MOVE -> if (joystickBeingConfigured != null) {
val moveDistance = kotlin.math.sqrt(
(event.getX(pointerIndex) - touchStartX).let { it * it } +
(event.getY(pointerIndex) - touchStartY).let { it * it }
)
if (moveDistance > moveThreshold) {
hasMoved = true
joystickBeingConfigured!!.onConfigureTouch(event)
invalidate()
}
}
MotionEvent.ACTION_UP,
MotionEvent.ACTION_POINTER_UP -> if (joystickBeingConfigured != null) {
if (!hasMoved) {
showScaleDialog(
null,
null,
joystickBeingConfigured,
fingerPositionX,
fingerPositionY
)
} else {
saveControlPosition(
joystickBeingConfigured!!.prefId,
joystickBeingConfigured!!.bounds.centerX(),
joystickBeingConfigured!!.bounds.centerY(),
individuaScale = joystickBeingConfigured!!.individualScale,
layout
)
}
joystickBeingConfigured = null
}
}
@ -607,24 +681,116 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
invalidate()
}
private fun saveControlPosition(id: String, x: Int, y: Int, layout: OverlayLayout) {
private fun saveControlPosition(
id: String,
x: Int,
y: Int,
individuaScale: Float,
layout: OverlayLayout
) {
val windowSize = getSafeScreenSize(context, Pair(measuredWidth, measuredHeight))
val min = windowSize.first
val max = windowSize.second
val overlayControlData = NativeConfig.getOverlayControlData()
val data = overlayControlData.firstOrNull { it.id == id }
val newPosition = Pair((x - min.x).toDouble() / max.x, (y - min.y).toDouble() / max.y)
when (layout) {
OverlayLayout.Landscape -> data?.landscapePosition = newPosition
OverlayLayout.Portrait -> data?.portraitPosition = newPosition
OverlayLayout.Foldable -> data?.foldablePosition = newPosition
}
data?.individualScale = individuaScale
NativeConfig.setOverlayControlData(overlayControlData)
}
fun setIsInEditMode(editMode: Boolean) {
inEditMode = editMode
if (!editMode) {
scaleDialog?.dismiss()
scaleDialog = null
}
}
private fun showScaleDialog(
button: InputOverlayDrawableButton?,
dpad: InputOverlayDrawableDpad?,
joystick: InputOverlayDrawableJoystick?,
x: Int, y: Int
) {
val overlayControlData = NativeConfig.getOverlayControlData()
// prevent dialog from being spam opened
scaleDialog?.dismiss()
when {
button != null -> {
val buttonData =
overlayControlData.firstOrNull { it.id == button.overlayControlData.id }
if (buttonData != null) {
scaleDialog =
OverlayScaleDialog(context, button.overlayControlData) { newScale ->
saveControlPosition(
button.overlayControlData.id,
button.bounds.centerX(),
button.bounds.centerY(),
individuaScale = newScale,
layout
)
refreshControls()
}
scaleDialog?.showDialog(x,y, button.bounds.width(), button.bounds.height())
}
}
dpad != null -> {
val dpadData =
overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
if (dpadData != null) {
scaleDialog = OverlayScaleDialog(context, dpadData) { newScale ->
saveControlPosition(
OverlayControl.COMBINED_DPAD.id,
dpad.bounds.centerX(),
dpad.bounds.centerY(),
newScale,
layout
)
refreshControls()
}
scaleDialog?.showDialog(x,y, dpad.bounds.width(), dpad.bounds.height())
}
}
joystick != null -> {
val joystickData = overlayControlData.firstOrNull { it.id == joystick.prefId }
if (joystickData != null) {
scaleDialog = OverlayScaleDialog(context, joystickData) { newScale ->
saveControlPosition(
joystick.prefId,
joystick.bounds.centerX(),
joystick.bounds.centerY(),
individuaScale = newScale,
layout
)
refreshControls()
}
scaleDialog?.showDialog(x,y, joystick.bounds.width(), joystick.bounds.height())
}
}
}
}
/**
* Applies and saves all default values for the overlay
@ -664,12 +830,24 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
val overlayControlData = NativeConfig.getOverlayControlData()
overlayControlData.forEach {
it.enabled = OverlayControl.from(it.id)?.defaultVisibility == true
it.individualScale = OverlayControl.from(it.id)?.defaultIndividualScaleResource!!
}
NativeConfig.setOverlayControlData(overlayControlData)
refreshControls()
}
fun resetIndividualControlScale() {
val overlayControlData = NativeConfig.getOverlayControlData()
overlayControlData.forEach { data ->
val defaultControlData = OverlayControl.from(data.id) ?: return@forEach
data.individualScale = defaultControlData.defaultIndividualScaleResource
}
NativeConfig.setOverlayControlData(overlayControlData)
NativeConfig.saveGlobalConfig()
refreshControls()
}
private fun defaultOverlayPositionByLayout(layout: OverlayLayout) {
val overlayControlData = NativeConfig.getOverlayControlData()
for (data in overlayControlData) {
@ -860,6 +1038,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Apply individual scale
scale *= overlayControlData.individualScale.let { if (it > 0f) it else 1f }
// Initialize the InputOverlayDrawableButton.
val defaultStateBitmap = getBitmap(context, defaultResId, scale)
val pressedStateBitmap = getBitmap(context, pressedResId, scale)
@ -922,11 +1103,20 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// Resources handle for fetching the initial Drawable resource.
val res = context.resources
// Get the dpad control data for individual scale
val overlayControlData = NativeConfig.getOverlayControlData()
val dpadData = overlayControlData.firstOrNull { it.id == OverlayControl.COMBINED_DPAD.id }
// Decide scale based on button ID and user preference
var scale = 0.25f
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Apply individual scale
if (dpadData != null) {
scale *= dpadData.individualScale.let { if (it > 0f) it else 1f }
}
// Initialize the InputOverlayDrawableDpad.
val defaultStateBitmap =
getBitmap(context, defaultResId, scale)
@ -1000,6 +1190,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
scale *= (IntSetting.OVERLAY_SCALE.getInt() + 50).toFloat()
scale /= 100f
// Apply individual scale
scale *= overlayControlData.individualScale.let { if (it > 0f) it else 1f }
// Initialize the InputOverlayDrawableJoystick.
val bitmapOuter = getBitmap(context, resOuter, scale)
val bitmapInnerDefault = getBitmap(context, defaultResInner, 1.0f)

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay
@ -42,6 +42,8 @@ class InputOverlayDrawableDpad(
val width: Int
val height: Int
var individualScale: Float = 1.0f
private val defaultStateBitmap: BitmapDrawable
private val pressedOneDirectionStateBitmap: BitmapDrawable
private val pressedTwoDirectionsStateBitmap: BitmapDrawable

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay
@ -51,6 +51,8 @@ class InputOverlayDrawableJoystick(
val width: Int
val height: Int
var individualScale: Float = 1.0f
private var opacity: Int = 0
private var virtBounds: Rect

View file

@ -0,0 +1,124 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay
import android.app.Dialog
import android.content.Context
import android.view.Gravity
import android.view.LayoutInflater
import android.view.WindowManager
import android.widget.TextView
import com.google.android.material.button.MaterialButton
import com.google.android.material.slider.Slider
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.overlay.model.OverlayControlData
class OverlayScaleDialog(
context: Context,
private val overlayControlData: OverlayControlData,
private val onScaleChanged: (Float) -> Unit
) : Dialog(context) {
private var currentScale = overlayControlData.individualScale
private val originalScale = overlayControlData.individualScale
private lateinit var scaleValueText: TextView
private lateinit var scaleSlider: Slider
init {
setupDialog()
}
private fun setupDialog() {
val view = LayoutInflater.from(context).inflate(R.layout.dialog_overlay_scale, null)
setContentView(view)
window?.setBackgroundDrawable(null)
window?.apply {
attributes = attributes.apply {
flags = flags and WindowManager.LayoutParams.FLAG_DIM_BEHIND.inv()
flags = flags or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
}
}
scaleValueText = view.findViewById(R.id.scaleValueText)
scaleSlider = view.findViewById(R.id.scaleSlider)
val resetButton = view.findViewById<MaterialButton>(R.id.resetButton)
val confirmButton = view.findViewById<MaterialButton>(R.id.confirmButton)
val cancelButton = view.findViewById<MaterialButton>(R.id.cancelButton)
scaleValueText.text = String.format("%.1fx", currentScale)
scaleSlider.value = currentScale
scaleSlider.addOnChangeListener { _, value, input ->
if (input) {
currentScale = value
scaleValueText.text = String.format("%.1fx", currentScale)
}
}
scaleSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
override fun onStartTrackingTouch(slider: Slider) {
// pass
}
override fun onStopTrackingTouch(slider: Slider) {
onScaleChanged(currentScale)
}
})
resetButton.setOnClickListener {
currentScale = 1.0f
scaleSlider.value = 1.0f
scaleValueText.text = String.format("%.1fx", currentScale)
onScaleChanged(currentScale)
}
confirmButton.setOnClickListener {
overlayControlData.individualScale = currentScale
//slider value is already saved on touch dispatch but just to be sure
onScaleChanged(currentScale)
dismiss()
}
// both cancel button and back gesture should revert the scale change
cancelButton.setOnClickListener {
onScaleChanged(originalScale)
dismiss()
}
setOnCancelListener {
onScaleChanged(originalScale)
dismiss()
}
}
fun showDialog(anchorX: Int, anchorY: Int, anchorHeight: Int, anchorWidth: Int) {
show()
show()
// TODO: this calculation is a bit rough, improve it later on
window?.let { window ->
val layoutParams = window.attributes
layoutParams.gravity = Gravity.TOP or Gravity.START
val density = context.resources.displayMetrics.density
val dialogWidthPx = (320 * density).toInt()
val dialogHeightPx = (400 * density).toInt() // set your estimated dialog height
val screenHeight = context.resources.displayMetrics.heightPixels
layoutParams.x = anchorX + anchorWidth / 2 - dialogWidthPx / 2
layoutParams.y = anchorY + anchorHeight / 2 - dialogHeightPx / 2
layoutParams.width = dialogWidthPx
window.attributes = layoutParams
}
}
}

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay.model
@ -12,126 +12,144 @@ enum class OverlayControl(
val defaultVisibility: Boolean,
@IntegerRes val defaultLandscapePositionResources: Pair<Int, Int>,
@IntegerRes val defaultPortraitPositionResources: Pair<Int, Int>,
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>
@IntegerRes val defaultFoldablePositionResources: Pair<Int, Int>,
val defaultIndividualScaleResource: Float,
) {
BUTTON_A(
"button_a",
true,
Pair(R.integer.BUTTON_A_X, R.integer.BUTTON_A_Y),
Pair(R.integer.BUTTON_A_X_PORTRAIT, R.integer.BUTTON_A_Y_PORTRAIT),
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE)
Pair(R.integer.BUTTON_A_X_FOLDABLE, R.integer.BUTTON_A_Y_FOLDABLE),
1.0f
),
BUTTON_B(
"button_b",
true,
Pair(R.integer.BUTTON_B_X, R.integer.BUTTON_B_Y),
Pair(R.integer.BUTTON_B_X_PORTRAIT, R.integer.BUTTON_B_Y_PORTRAIT),
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE)
Pair(R.integer.BUTTON_B_X_FOLDABLE, R.integer.BUTTON_B_Y_FOLDABLE),
1.0f
),
BUTTON_X(
"button_x",
true,
Pair(R.integer.BUTTON_X_X, R.integer.BUTTON_X_Y),
Pair(R.integer.BUTTON_X_X_PORTRAIT, R.integer.BUTTON_X_Y_PORTRAIT),
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE)
Pair(R.integer.BUTTON_X_X_FOLDABLE, R.integer.BUTTON_X_Y_FOLDABLE),
1.0f
),
BUTTON_Y(
"button_y",
true,
Pair(R.integer.BUTTON_Y_X, R.integer.BUTTON_Y_Y),
Pair(R.integer.BUTTON_Y_X_PORTRAIT, R.integer.BUTTON_Y_Y_PORTRAIT),
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE)
Pair(R.integer.BUTTON_Y_X_FOLDABLE, R.integer.BUTTON_Y_Y_FOLDABLE),
1.0f
),
BUTTON_PLUS(
"button_plus",
true,
Pair(R.integer.BUTTON_PLUS_X, R.integer.BUTTON_PLUS_Y),
Pair(R.integer.BUTTON_PLUS_X_PORTRAIT, R.integer.BUTTON_PLUS_Y_PORTRAIT),
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE)
Pair(R.integer.BUTTON_PLUS_X_FOLDABLE, R.integer.BUTTON_PLUS_Y_FOLDABLE),
1.0f
),
BUTTON_MINUS(
"button_minus",
true,
Pair(R.integer.BUTTON_MINUS_X, R.integer.BUTTON_MINUS_Y),
Pair(R.integer.BUTTON_MINUS_X_PORTRAIT, R.integer.BUTTON_MINUS_Y_PORTRAIT),
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE)
Pair(R.integer.BUTTON_MINUS_X_FOLDABLE, R.integer.BUTTON_MINUS_Y_FOLDABLE),
1.0f
),
BUTTON_HOME(
"button_home",
false,
Pair(R.integer.BUTTON_HOME_X, R.integer.BUTTON_HOME_Y),
Pair(R.integer.BUTTON_HOME_X_PORTRAIT, R.integer.BUTTON_HOME_Y_PORTRAIT),
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE)
Pair(R.integer.BUTTON_HOME_X_FOLDABLE, R.integer.BUTTON_HOME_Y_FOLDABLE),
1.0f
),
BUTTON_CAPTURE(
"button_capture",
false,
Pair(R.integer.BUTTON_CAPTURE_X, R.integer.BUTTON_CAPTURE_Y),
Pair(R.integer.BUTTON_CAPTURE_X_PORTRAIT, R.integer.BUTTON_CAPTURE_Y_PORTRAIT),
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE)
Pair(R.integer.BUTTON_CAPTURE_X_FOLDABLE, R.integer.BUTTON_CAPTURE_Y_FOLDABLE),
1.0f
),
BUTTON_L(
"button_l",
true,
Pair(R.integer.BUTTON_L_X, R.integer.BUTTON_L_Y),
Pair(R.integer.BUTTON_L_X_PORTRAIT, R.integer.BUTTON_L_Y_PORTRAIT),
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE)
Pair(R.integer.BUTTON_L_X_FOLDABLE, R.integer.BUTTON_L_Y_FOLDABLE),
1.0f
),
BUTTON_R(
"button_r",
true,
Pair(R.integer.BUTTON_R_X, R.integer.BUTTON_R_Y),
Pair(R.integer.BUTTON_R_X_PORTRAIT, R.integer.BUTTON_R_Y_PORTRAIT),
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE)
Pair(R.integer.BUTTON_R_X_FOLDABLE, R.integer.BUTTON_R_Y_FOLDABLE),
1.0f
),
BUTTON_ZL(
"button_zl",
true,
Pair(R.integer.BUTTON_ZL_X, R.integer.BUTTON_ZL_Y),
Pair(R.integer.BUTTON_ZL_X_PORTRAIT, R.integer.BUTTON_ZL_Y_PORTRAIT),
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE)
Pair(R.integer.BUTTON_ZL_X_FOLDABLE, R.integer.BUTTON_ZL_Y_FOLDABLE),
1.0f
),
BUTTON_ZR(
"button_zr",
true,
Pair(R.integer.BUTTON_ZR_X, R.integer.BUTTON_ZR_Y),
Pair(R.integer.BUTTON_ZR_X_PORTRAIT, R.integer.BUTTON_ZR_Y_PORTRAIT),
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE)
Pair(R.integer.BUTTON_ZR_X_FOLDABLE, R.integer.BUTTON_ZR_Y_FOLDABLE),
1.0f
),
BUTTON_STICK_L(
"button_stick_l",
true,
Pair(R.integer.BUTTON_STICK_L_X, R.integer.BUTTON_STICK_L_Y),
Pair(R.integer.BUTTON_STICK_L_X_PORTRAIT, R.integer.BUTTON_STICK_L_Y_PORTRAIT),
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE)
Pair(R.integer.BUTTON_STICK_L_X_FOLDABLE, R.integer.BUTTON_STICK_L_Y_FOLDABLE),
1.0f
),
BUTTON_STICK_R(
"button_stick_r",
true,
Pair(R.integer.BUTTON_STICK_R_X, R.integer.BUTTON_STICK_R_Y),
Pair(R.integer.BUTTON_STICK_R_X_PORTRAIT, R.integer.BUTTON_STICK_R_Y_PORTRAIT),
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE)
Pair(R.integer.BUTTON_STICK_R_X_FOLDABLE, R.integer.BUTTON_STICK_R_Y_FOLDABLE),
1.0f
),
STICK_L(
"stick_l",
true,
Pair(R.integer.STICK_L_X, R.integer.STICK_L_Y),
Pair(R.integer.STICK_L_X_PORTRAIT, R.integer.STICK_L_Y_PORTRAIT),
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE)
Pair(R.integer.STICK_L_X_FOLDABLE, R.integer.STICK_L_Y_FOLDABLE),
1.0f
),
STICK_R(
"stick_r",
true,
Pair(R.integer.STICK_R_X, R.integer.STICK_R_Y),
Pair(R.integer.STICK_R_X_PORTRAIT, R.integer.STICK_R_Y_PORTRAIT),
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE)
Pair(R.integer.STICK_R_X_FOLDABLE, R.integer.STICK_R_Y_FOLDABLE),
1.0f
),
COMBINED_DPAD(
"combined_dpad",
true,
Pair(R.integer.COMBINED_DPAD_X, R.integer.COMBINED_DPAD_Y),
Pair(R.integer.COMBINED_DPAD_X_PORTRAIT, R.integer.COMBINED_DPAD_Y_PORTRAIT),
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE)
Pair(R.integer.COMBINED_DPAD_X_FOLDABLE, R.integer.COMBINED_DPAD_Y_FOLDABLE),
1.0f
);
fun getDefaultPositionForLayout(layout: OverlayLayout): Pair<Double, Double> {
@ -173,7 +191,8 @@ enum class OverlayControl(
defaultVisibility,
getDefaultPositionForLayout(OverlayLayout.Landscape),
getDefaultPositionForLayout(OverlayLayout.Portrait),
getDefaultPositionForLayout(OverlayLayout.Foldable)
getDefaultPositionForLayout(OverlayLayout.Foldable),
defaultIndividualScaleResource
)
companion object {

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.overlay.model
@ -8,7 +8,8 @@ data class OverlayControlData(
var enabled: Boolean,
var landscapePosition: Pair<Double, Double>,
var portraitPosition: Pair<Double, Double>,
var foldablePosition: Pair<Double, Double>
var foldablePosition: Pair<Double, Double>,
var individualScale: Float
) {
fun positionFromLayout(layout: OverlayLayout): Pair<Double, Double> =
when (layout) {

View file

@ -1,8 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
package org.yuzu.yuzu_emu.utils
object AddonUtil {
val validAddonDirectories = listOf("cheats", "exefs", "romfs")
val validAddonDirectories = listOf("cheats", "exefs", "romfs", "romfslite")
}

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
@ -170,7 +170,8 @@ object DirectoryInitialization {
buttonEnabled,
Pair(landscapeXPosition, landscapeYPosition),
Pair(portraitXPosition, portraitYPosition),
Pair(foldableXPosition, foldableYPosition)
Pair(foldableXPosition, foldableYPosition),
OverlayControl.map[buttonId]?.defaultIndividualScaleResource ?: 1.0f
)
overlayControlDataMap[buttonId] = controlData
setOverlayData = true

View file

@ -18,6 +18,7 @@ import java.net.URLDecoder
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.features.DocumentProvider
import org.yuzu.yuzu_emu.model.MinimalDocumentFile
import org.yuzu.yuzu_emu.model.TaskState
import java.io.BufferedOutputStream
@ -291,6 +292,39 @@ object FileUtil {
null
}
/**
* Copies a file from internal appdata storage to an external Uri.
*/
fun copyToExternalStorage(
sourcePath: String,
destUri: Uri,
progressCallback: (max: Long, progress: Long) -> Boolean = { _, _ -> false }
): TaskState {
try {
val totalBytes = getFileSize(sourcePath)
var progressBytes = 0L
val inputStream = getInputStream(sourcePath)
BufferedInputStream(inputStream).use { bis ->
context.contentResolver.openOutputStream(destUri, "wt")?.use { outputStream ->
val buffer = ByteArray(1024 * 4)
var len: Int
while (bis.read(buffer).also { len = it } != -1) {
if (progressCallback.invoke(totalBytes, progressBytes)) {
return TaskState.Cancelled
}
outputStream.write(buffer, 0, len)
progressBytes += len
}
outputStream.flush()
} ?: return TaskState.Failed
}
} catch (e: Exception) {
Log.error("[FileUtil] Failed exporting file - ${e.message}")
return TaskState.Failed
}
return TaskState.Completed
}
/**
* Extracts the given zip file into the given directory.
* @param path String representation of a [Uri] or a typical path delimited by '/'

View file

@ -19,6 +19,7 @@ import org.yuzu.yuzu_emu.adapters.GameAdapter
import androidx.core.view.doOnNextLayout
import org.yuzu.yuzu_emu.YuzuApplication
import androidx.preference.PreferenceManager
import androidx.core.view.WindowInsetsCompat
/**
* CarouselRecyclerView encapsulates all carousel logic for the games UI.
@ -205,8 +206,8 @@ class CarouselRecyclerView @JvmOverloads constructor(
if (enabled) {
useCustomDrawingOrder = true
val insets = rootWindowInsets
val bottomInset = insets?.getInsets(android.view.WindowInsets.Type.systemBars())?.bottom ?: 0
val insets = rootWindowInsets?.let { WindowInsetsCompat.toWindowInsetsCompat(it, this) }
val bottomInset = insets?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: 0
val internalFactor = resources.getFraction(R.fraction.carousel_card_size_factor, 1, 1)
val userFactor = preferences.getFloat(CAROUSEL_CARD_SIZE_FACTOR, internalFactor).coerceIn(
0f,

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <common/logging/log.h>
#include <input_common/main.h>
@ -103,6 +103,7 @@ void AndroidConfig::ReadOverlayValues() {
ReadDoubleSetting(std::string("foldable\\x_position"));
control_data.foldable_position.second =
ReadDoubleSetting(std::string("foldable\\y_position"));
control_data.individual_scale = static_cast<float>(ReadDoubleSetting(std::string("individual_scale")));
AndroidSettings::values.overlay_control_data.push_back(control_data);
}
EndArray();
@ -255,6 +256,7 @@ void AndroidConfig::SaveOverlayValues() {
control_data.foldable_position.first);
WriteDoubleSetting(std::string("foldable\\y_position"),
control_data.foldable_position.second);
WriteDoubleSetting(std::string("individual_scale"), static_cast<double>(control_data.individual_scale));
}
EndArray();

View file

@ -24,6 +24,7 @@ namespace AndroidSettings {
std::pair<double, double> landscape_position;
std::pair<double, double> portrait_position;
std::pair<double, double> foldable_position;
float individual_scale;
};
struct Values {
@ -79,6 +80,15 @@ namespace AndroidSettings {
Settings::Category::Overlay,
Settings::Specialization::Paired, true,
true};
Settings::Setting<bool> enable_input_overlay_auto_hide{linkage, false,
"enable_input_overlay_auto_hide",
Settings::Category::Overlay,
Settings::Specialization::Default, true,
true,};
Settings::Setting<u32> input_overlay_auto_hide{linkage, 5, "input_overlay_auto_hide",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true, &enable_input_overlay_auto_hide};
Settings::Setting<bool> perf_overlay_background{linkage, false, "perf_overlay_background",
Settings::Category::Overlay,
Settings::Specialization::Default, true,

View file

@ -36,6 +36,7 @@
#include "common/scope_exit.h"
#include "common/settings.h"
#include "common/string_util.h"
#include "frontend_common/play_time_manager.h"
#include "core/core.h"
#include "core/cpu_manager.h"
#include "core/crypto/key_manager.h"
@ -85,6 +86,9 @@ std::atomic<int> g_battery_percentage = {100};
std::atomic<bool> g_is_charging = {false};
std::atomic<bool> g_has_battery = {true};
// playtime
std::unique_ptr<PlayTime::PlayTimeManager> play_time_manager;
EmulationSession::EmulationSession() {
m_vfs = std::make_shared<FileSys::RealVfsFilesystem>();
}
@ -733,6 +737,56 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmptyUserDirectory(JNIEnv*
}
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerInit(JNIEnv* env, jobject obj) {
// for some reason the full user directory isnt initialized in Android, so we need to create it
const auto play_time_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::PlayTimeDir);
if (!Common::FS::IsDir(play_time_dir)) {
if (!Common::FS::CreateDir(play_time_dir)) {
LOG_WARNING(Frontend, "Failed to create play time directory");
}
}
play_time_manager = std::make_unique<PlayTime::PlayTimeManager>();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerStart(JNIEnv* env, jobject obj) {
if (play_time_manager) {
play_time_manager->SetProgramId(EmulationSession::GetInstance().System().GetApplicationProcessProgramID());
play_time_manager->Start();
}
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerStop(JNIEnv* env, jobject obj) {
play_time_manager->Stop();
}
jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetPlayTime(JNIEnv* env, jobject obj,
jstring jprogramId) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
return play_time_manager->GetPlayTime(program_id);
}
jlong Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerGetCurrentTitleId(JNIEnv* env,
jobject obj) {
return EmulationSession::GetInstance().System().GetApplicationProcessProgramID();
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerResetProgramPlayTime(JNIEnv* env, jobject obj,
jstring jprogramId) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
if (play_time_manager) {
play_time_manager->ResetProgramPlayTime(program_id);
}
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_playTimeManagerSetPlayTime(JNIEnv* env, jobject obj,
jstring jprogramId, jlong playTimeSeconds) {
u64 program_id = EmulationSession::GetProgramId(env, jprogramId);
if (play_time_manager) {
play_time_manager->SetPlayTime(program_id, static_cast<u64>(playTimeSeconds));
}
}
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletLaunchPath(JNIEnv* env, jclass clazz,
jlong jid) {
auto bis_system =

View file

@ -1,5 +1,5 @@
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <string>
@ -369,7 +369,9 @@ jobjectArray Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getOverlayControlData(JN
env->NewObject(Common::Android::GetOverlayControlDataClass(),
Common::Android::GetOverlayControlDataConstructor(),
Common::Android::ToJString(env, control_data.id), control_data.enabled,
jlandscapePosition, jportraitPosition, jfoldablePosition);
jlandscapePosition, jportraitPosition, jfoldablePosition,
control_data.individual_scale);
env->SetObjectArrayElement(joverlayControlDataArray, i, jcontrolData);
}
return joverlayControlDataArray;
@ -418,9 +420,12 @@ void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setOverlayControlData(
env,
env->GetObjectField(jfoldablePosition, Common::Android::GetPairSecondField())));
float individual_scale = static_cast<float>(env->GetFloatField(
joverlayControlData, Common::Android::GetOverlayControlDataIndividualScaleField()));
AndroidSettings::values.overlay_control_data.push_back(AndroidSettings::OverlayControlData{
Common::Android::GetJString(env, jidString), enabled, landscape_position,
portrait_position, foldable_position});
portrait_position, foldable_position, individual_scale});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

@ -105,6 +105,16 @@
android:textAlignment="center"
tools:text="deko_basic" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/playtime"
style="?attr/textAppearanceBodyMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginBottom="8dp"
android:textAlignment="center"
tools:text="Game Playtime" />
</LinearLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton

View file

@ -11,6 +11,11 @@
android:clickable="true"
android:focusable="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -69,4 +74,22 @@
</LinearLayout>
<com.google.android.material.divider.MaterialDivider
android:id="@+id/dividerSecondaryActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/layoutSecondaryActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="24dp"
android:paddingVertical="8dp"
android:visibility="gone"
app:singleLine="false"
tools:visibility="visible" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

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