Compare commits

...

109 commits

Author SHA1 Message Date
lizzie
5dbc9dac2c needs libscienternal 2026-03-08 23:08:18 +00:00
lizzie
73e3f387cc try fix musl 2 2026-03-08 23:07:56 +00:00
lizzie
ad8d6de8bc native ps4 audio sink 2026-03-08 23:07:07 +00:00
lizzie
8275903b65 fix invalid esc symbosl on logs 2026-03-08 23:07:07 +00:00
lizzie
387c543121 init audio 2026-03-08 23:07:07 +00:00
lizzie
0b77edc8b6 fix virtual buffers 2026-03-08 23:07:07 +00:00
lizzie
e962499d4d fix openssl 2026-03-08 23:07:07 +00:00
lizzie
79e0f98a0c disable stdio buffering 2026-03-08 23:07:07 +00:00
lizzie
1eb481975f FX 2026-03-08 23:07:07 +00:00
lizzie
0d4a402bbe let it rip 2026-03-08 23:07:07 +00:00
lizzie
95b05d1dca leave pending param package stuff 2026-03-08 23:07:07 +00:00
lizzie
d5af8b5072 restore protection 2026-03-08 23:07:07 +00:00
lizzie
c6df1670a5 immediately terminate in OO, use 2MB swap handler 2026-03-08 23:07:07 +00:00
lizzie
1eb9404421 use btver2 2026-03-08 23:07:07 +00:00
lizzie
53c55ecc49 reduce fiber sizes 2026-03-08 23:07:07 +00:00
lizzie
b041c6824f fix yuzu cpp 2026-03-08 23:07:07 +00:00
lizzie
75588f6406 use dmem for swap buffers, restore full jit sizes 2026-03-08 23:07:07 +00:00
lizzie
58499f5fc1 force ankerl + fixup for OO with prelude commits 2026-03-08 23:07:07 +00:00
lizzie
745a12b3d1 add hash 2026-03-08 23:07:07 +00:00
lizzie
1b429c4bbf fix 2026-03-08 23:07:07 +00:00
lizzie
33d140fa7b fixup shit 2026-03-08 23:07:04 +00:00
lizzie
83173a21e5 SDL2 PS4 patch 2026-03-08 23:06:54 +00:00
lizzie
cdb0e97239 use newer sdl2, make bigger stack 2026-03-08 23:06:54 +00:00
lizzie
d23fa2142d mark codeblocks as noexcept 2026-03-08 23:06:54 +00:00
lizzie
b35a34e41c fix ps4/orbis 2026-03-08 23:06:54 +00:00
lizzie
921c8d9406 fix2 2026-03-08 23:06:54 +00:00
lizzie
d365a3050a make a bit more mergeable 2026-03-08 23:06:54 +00:00
lizzie
fa0d0a9ba0 Use updated SDL2 2026-03-08 23:06:54 +00:00
lizzie
3936f0e3b7 revert input system to main 2026-03-08 23:06:54 +00:00
lizzie
834fa15ab7 stub add proper iostream init 2026-03-08 23:06:54 +00:00
lizzie
597080d4ff ps4 icon 2026-03-08 23:06:54 +00:00
lizzie
691e3786d6 update loicense 2026-03-08 23:06:54 +00:00
lizzie
610003387c restore stupid lock, make ps4sup library 2026-03-08 23:06:53 +00:00
lizzie
86a99ace4c bs fix 2026-03-08 23:06:53 +00:00
lizzie
cfffaf6d41 fix eboot 2026-03-08 23:06:53 +00:00
lizzie
e29aad3f04 temp fix for dpad 2026-03-08 23:06:53 +00:00
lizzie
654117245b add emutls.c 2026-03-08 23:06:53 +00:00
lizzie
99a67199e3 reduce arm codeisze, force 16x4 pages again 2026-03-08 23:06:53 +00:00
lizzie
d1f10e9394 extra buffer precautions to not exhaust DMem, format better + perf history nerf 2026-03-08 23:06:53 +00:00
lizzie
9df314c914 more inline pt2 2026-03-08 23:06:53 +00:00
lizzie
cfd11d8a5e fix atexit impl 2026-03-08 23:06:53 +00:00
lizzie
46a00cc978 fibers that don't immediately crash?!!?!?!!? 2026-03-08 23:06:53 +00:00
lizzie
7a08f340dc add fallback buffer back 2026-03-08 23:06:53 +00:00
lizzie
23d7c6aacf force running services on host 2026-03-08 23:06:53 +00:00
lizzie
42a29d09d2 fix alloc failures 2026-03-08 23:06:53 +00:00
lizzie
9fd522ccbe fix sdl2 2026-03-08 23:06:53 +00:00
lizzie
cf2d3a15bc fix for crashes on TLS due to openorbis being W E I R D 2026-03-08 23:06:53 +00:00
lizzie
c9c3762c8e opengl bullshit 2026-03-08 23:06:53 +00:00
lizzie
14984625b7 proper memswap mechanism 2026-03-08 23:06:53 +00:00
lizzie
733c596a14 more stupid stuff 2026-03-08 23:06:53 +00:00
lizzie
9e0ac816ae fixes 4 stuff 2026-03-08 23:06:53 +00:00
lizzie
bc49a8ca0b swap handling 2026-03-08 23:06:53 +00:00
lizzie
1c4f568d56 license 2026-03-08 23:06:53 +00:00
lizzie
7f2e42ad40 add sce_module so it loads on real hw 2026-03-08 23:06:53 +00:00
lizzie
5bc13df3eb fixes for mbedtls 2026-03-08 23:06:53 +00:00
lizzie
39b8107b5c adapt to new master 2026-03-08 23:06:53 +00:00
lizzie
81b953affc evil haxx 2026-03-08 23:06:53 +00:00
lizzie
98ac8ab13c extra ps4 defs 2026-03-08 23:06:51 +00:00
lizzie
6765e7cd17 make virtual buffer become an optional 2026-03-08 23:06:27 +00:00
lizzie
5d1e74533c force NO fastmem 2026-03-08 23:06:27 +00:00
lizzie
9051fcb33b more memory shit 2026-03-08 23:06:27 +00:00
lizzie
9f2447357b MAP_SYSTEM 2026-03-08 23:06:27 +00:00
lizzie
98a7a81396 (likely) fixes for virtual dmem? 2026-03-08 23:06:27 +00:00
lizzie
c5ac1f9cc2 disable fastmem 2026-03-08 23:06:27 +00:00
lizzie
692dd09dda try to fix the paths 2026-03-08 23:06:27 +00:00
lizzie
a58b1e975e sysconf stub cuz crash(?) + some stderrp stuff 2026-03-08 23:06:27 +00:00
lizzie
b02e0ccc76 the orb 2026-03-08 23:06:27 +00:00
lizzie
c840015ba2 fself + pkg stuffs 2026-03-08 23:06:27 +00:00
lizzie
f1d1e09c4c make .pkg and .self 2026-03-08 23:06:27 +00:00
lizzie
564aac846a exclude more stuff from vulkan 2026-03-08 23:06:27 +00:00
lizzie
86ffa7932e exclude from vulkan surface selection 2026-03-08 23:06:27 +00:00
lizzie
1ebc3ba89d buildable toolchain script + fixes for ffmpeg 2026-03-08 23:06:27 +00:00
lizzie
8f810a2f1b merge 2026-03-08 23:06:27 +00:00
lizzie
75ae6de81e merge 2026-03-08 23:06:27 +00:00
lizzie
d97c3b25a0 fix 2026-03-08 23:06:27 +00:00
lizzie
4e9764f42a toolchain-fix 2026-03-08 23:06:27 +00:00
lizzie
77feee7a7b fuck you 2026-03-08 23:06:27 +00:00
lizzie
a4035ce2d8 no conversion fixs 2026-03-08 23:06:27 +00:00
crueter
f5e2b1fb13
[dynarmic] Remove incorrect LICENSE (#3698)
Our dynarmic is GPLv3, not BSD.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3698
2026-03-08 23:22:51 +01:00
lizzie
6693b99ae4
[core] coalesce tracking entries for GPU (#3677)
I think I may have attempted this before, but I doubt it.

Anyways this should reduce virtual buffers from 3 to just 1, also improved access times :)

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3677
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-08 22:45:38 +01:00
MaranBr
f8ea09fa0f
[video_core] Simplify TextureCache GC and remove redundant code (#3652)
This enhances the garbage collection in TextureCache to make it more responsive and reliable during long gameplay sessions.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3652
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-03-08 22:45:35 +01:00
smiRaphi
361e6209b2
[settings] Add back & properly implement use_dev_keys (#3631)
Was removed recently but also wasn't really working before, this adds it to the debug UI (under the kiosk option) and also makes it properly reload the keys on launch & setting change.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3631
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: smiRaphi <neogt404@gmail.com>
Co-committed-by: smiRaphi <neogt404@gmail.com>
2026-03-08 22:37:20 +01:00
crueter
3d1a67af18
[externals] Update dependencies (#3664)
* zlib: 1.3.1.2 -> 1.3.2
* vulkan-validation-layers: 1.4.335.0 -> 1.4.341.0
* sirit: 1.0.3 -> 1.0.4
* httplib: 0.35.0 -> 0.37.0
* xbyak: 7.33.3 -> 7.35.2
* catch2: 3.12.0 -> 3.13.0
* vulkan-headers: 1.4.342 -> 1.4.345
* vulkan-utility-libraries: 1.4.342 -> 1.4.345

Also fixed a build error with newer xbyak.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3664
2026-03-08 22:33:51 +01:00
crueter
c7b23f4a1a
[time] fix: guard timezone out buffer logging (#3668)
Original text, per the emailed patch:

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

Hello,

I am submitting a small fix to prevent an unintended abort when _GLIBCXX_ASSERTIONS is enabled, caused by out-of-bounds access in debug logging.
Background / Issue

In the server-side implementations of ITimeZoneService::ToPosixTime and ToPosixTimeWithMyRule, the SCOPE_EXIT debug logging previously accessed out_times[0] and out_times[1] unconditionally.

However, out_times is an IPC-provided output buffer (OutArray, which inherits from std::span). Its length depends on the caller-provided buffer capacity. During debugging, I encountered a case where out_times.size() == 1.

Under _GLIBCXX_ASSERTIONS, accessing out_times[1] triggers a std::span::operator[] assertion failure (std::__glibcxx_assert_fail) and aborts the process, causing the service thread to crash. This results in an unintended crash caused solely by debug logging.
Change Description

In the SCOPE_EXIT logging blocks of both ToPosixTime and ToPosixTimeWithMyRule, I added bounds checks before accessing out_times[0] and out_times[1]:

    Access out_times[0] only if out_times.size() > 0

    Access out_times[1] only if out_times.size() > 1

    Print 0 when the corresponding element is unavailable

This change only affects debug log output. It does not modify IPC semantics or the time conversion logic itself.
Reproduction Context (for reference)

I encountered this issue while running 13 Sentinels: Aegis Rim (title ID: 01008D7016438000). During the “Load Game” flow, ToPosixTimeWithMyRule is invoked with an out_times buffer of length 1, which previously led to the out-of-bounds access in the logging code.

Thank you for your time and review.

Best regards,
darkpaper

Environment: Arch Linux / KDE / X11

This email and the accompanying patch were prepared with assistance from
an LLM.

Authored-by: darkpaper <lirunzhou2021@gamil.com>
Signed-off-by: crueter <crueter@eden-emu.dev>

Co-authored-by: darkpaper <lirunzhou2021@gamil.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3668
2026-03-08 20:53:37 +01:00
lizzie
38aa2bc5e1
[hle/services] use ankerl:: for Service's function handlers map, use const char* instead of std::string{} (#3671)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3671
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-08 20:50:29 +01:00
lizzie
1864160326
[qt] remove 'None' interface since net code already uses first avail interface anyways, disable changing ifaces at runtime (#3683)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3683
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-08 20:49:17 +01:00
lizzie
0a169dec4d
[qt] fix crash when having an invalid graphics backend (#3693)
closely related to #3692, however the crash may also occur when sharing configs between macOS and a system that had OpenGL

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3693
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-08 20:48:47 +01:00
wildcard
80bafc8fe8
[vulkan] Fix incorrect offset application for Array2D textures (#3696)
Earlier we were taking the coords and adding them to coords instead of actually taking offsets and adding it to coord

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3696
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-08 20:48:19 +01:00
lizzie
f2c46eadc1
[ports] build fixes for *BSD make (#3496)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3496
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-08 19:32:24 +01:00
xbzk
7a17fd8c71
[android,ui] chore: minor standardization layout (#3694)
Amost no visual differences, but tons of layout cleanups and fixes
Most notable change, Freedreno option only show on Adreno GPUs

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3694
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-08 16:16:23 +01:00
xbzk
9423a33fc2
[android,ui] fix addons list not refresh upon rotation (#3687)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
Fixes a bug reported by Pavel, in which an RC as returning empty patchList after phone rotated.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3687
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-08 00:41:40 +01:00
lizzie
afec66f598
core/hle/services/audio] Fix audioctl being started before audout/audin (which are required for ctor) (#3695)
`audctl` depends on `audout`, simply start `audout` and `audin` before!

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3695
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-07 23:44:58 +01:00
SchweGELBin
a022560991
[desktop] tas: add option to disable file overwrite dialog (#3657)
Hello everybody, thank you for letting me participate in the development of the Eden emulator!

I've been playing around with the TAS functionality and didn't want to always click "Yes" in the dialog that askes if I want to "Overwrite file of player 1?" after recording the inputs.
So I can't record and play TAS files with keybinds only, because I'd still need to switching from my contoller to my keyboard and back.

So I added the option "Show recording dialog" into the configure_tas screen.
(The final naming and string can be changed of course.)
It's a checkbox that is enabled by default (so no changes if ignored), but can be unchecked to disable the popup.
The change has been tested on top of the current master branch.

I've also created a commit to add the relevant translation data, where german is translated and the rest unfinished.
I'm not sure how this would be handled as this project uses transifex for it localization, so I can remove this commit if preferred.

Have a great day!
- Michi

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3657
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: SchweGELBin <abramjannikmichael06@gmail.com>
Co-committed-by: SchweGELBin <abramjannikmichael06@gmail.com>
2026-03-07 20:08:47 +01:00
lizzie
11ad71b1e7
[docs] Obtanium, installing mods, external ES-DE config, section about CFW and settings (#3678)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3678
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-07 18:16:05 +01:00
xbzk
ddac8c8eb5
[vk] fix crash introduced in 9a07bd0570 (#3685)
Some checks are pending
tx-src / sources (push) Waiting to run
Check Strings / check-strings (push) Waiting to run
Fix for current crash on master.
Just reverted only the necessary stuff so that PresentManager can hold a reference to khr and resist death upon application hold/restore.
@Lizzie shall judge.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3685
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-06 19:52:17 +01:00
lizzie
c062931c9b
[qt] add translation table entry for debug_knobs,serial_battery and serial_unit (#3682)
trivial qt change

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3682
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 16:38:39 +01:00
crueter
e4122dae1d
[desktop] addons: open mod folder in rc menu (#3662)
also fixed the multiselection being absolutely horrendous

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3662
2026-03-06 16:38:21 +01:00
lizzie
b75e81af5e
[video_core/engines] implement stub NV01 timer, inline other channel engines (#3640)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3640
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:05:39 +01:00
lizzie
2ed1328c93
[vk] use static_vector instead of small_vector for TFB and other bindings (#3641)
MK8D is a big offender, taking up lots of time memcpy'ing and memmov'ing small_vector<> AND to add salt to the wound it doesn't even do heap allocations (no game does I think) - so basically useless waste of compute time in hot path for NO reason :^)

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3641
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:05:05 +01:00
lizzie
c70b857c4f
[video_core/engines] Macro HLE inline (#3653)
Should slightly boost perf on android, Desktop is mainly unaffected (for now)

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3653
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2026-03-06 15:04:38 +01:00
MaranBr
23566a1f7d
[prepo] Add support for missing PlayReport commands (#3674)
This fixes:

`[ 433.095195] Debug <Critical> core\hle\service\service.cpp:operator ():69: Assertion Failed!
Unknown / unimplemented function '10107': port='prepo:u' cmd_buf={[0]=0x110006, [1]=0x80000014, [2]=0x1, [3]=0x0, [4]=0x0, [5]=0x191080, [6]=0x5A7350F8, [7]=0x112, [8]=0x5A735158}`

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3674
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2026-03-06 15:02:59 +01:00
xbzk
529b069499
[android,ui] fixed top disalignment between buttons of each column in settings fragment (#3675)
this silly little thing tickles obsessive compulsive disturbed fellas a lot hu3
was shipped along PR 3660, which was rediscussed for other reason, hence this tiny lonely PR.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3675
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-05 13:58:46 +01:00
lizzie
9a07bd0570
[vk] unify VkSurfaceKHR with Android and the rest of platforms; remove technically incorrect nullptr() ctor for handles (#2971)
Removes some odd #ifdef-ing that just can use a shrimple opaque type.

Also removes nullptr() ctor'ing for vulkan handles and such; it's not incorrect per se like how `void *p = 0;` isn't incorrect, just that, y'know, any static analyzer will go "woah". Also there isn't any guarantee that handles `sizeof(Handle) == sizeof(void*)` so may as well :)

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2971
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>
2026-03-05 07:32:18 +01:00
xbzk
05f6942bef
[android, ui] fixed setting reset to defaults infinite loop (#3659)
fixed a bug discovered by Pavel in which the settings' "reset to defaults" dialog would get stuck in a infinite loop, due to a recall prior to cleaning state.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3659
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-05 00:58:49 +01:00
nekle
70c1e9abed
[android] Try and fix SD Card storage mount points for external paths (#3436)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3436
Reviewed-by: DraVee <chimera@dravee.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: nekle <nekle@protonmail.com>
Co-committed-by: nekle <nekle@protonmail.com>
2026-03-05 00:56:25 +01:00
wildcard
69e47bd2c0
[vulkan] Fix wrong stage index in prepare_stage render area check (#3672)
The OpenGL correctly uses const auto& info{stage_infos[stage]};

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3672
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-05 00:54:48 +01:00
wildcard
cdf9b556b2
[vulkan]fix vuid 02751 (#3573)
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3573
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: DraVee <chimera@dravee.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-05 00:54:26 +01:00
xbzk
7f5de6bcd6
[android/fs] external content loader + nca/xci patches (#3596)
Foreword: WHY DON'T EVERYBODY USE ONE FOLDER FOR EACH GAME+CONTENTS? AIN'T THIS THE FORMAT GAMES COME WHEN YOU BUE THEM? DO YOU LIVE WITH ALL YOUR FRIENDS AND HAVE A 2ND HOUSE FOR ALL THE CHILDREN?

Nice, i feel better now.

This feat extends Maufeat's work on external content loading. It harmonically additions:
"...also, if in each game folder X, you find a folder Y, and in this folder Y you detect ONLY a single game, then mount all external content for that game found in that folder Y and its subfolders."
Permanent (not toggleable). External Content folders are supported equally.

Also:
-Reworked several routines for preserving single source of truth between android and other systems;
-Fixed the annoying unknown format error for content files, by providing proper format detection.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3596
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Co-committed-by: xbzk <xbzk@eden-emu.dev>
2026-03-04 22:51:35 +01:00
wildcard
c682306788
[vulkan] Implement push descriptors for compute pipelines (#3666)
Implements push descriptor for compute pipelines along with a bug fix, the increment logic was, offset += sizeof(DescriptorUpdateEntry);
This only advances the byte offset by a single descriptor slot, regardless of the array's size (descriptorCount).Now suppose if a shader utilized an array of descriptors (eg, layout(binding = 0) uniform sampler2D textures[4]) and if this happened to fit within the MaxPushDescriptors limit, the template would consume 4 * sizeof(DescriptorUpdateEntry) bytes, but the offset for the next binding would only advance by 1 slot.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3666
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2026-03-04 22:46:55 +01:00
199 changed files with 5240 additions and 2433 deletions

67
.ci/ps4/build.sh Executable file
View file

@ -0,0 +1,67 @@
#!/usr/local/bin/bash -ex
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
[ -z ${OO_PS4_TOOLCHAIN+x} ] && exit
[ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake"
set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN")
set(CMAKE_STAGING_PREFIX "$OO_PS4_TOOLCHAIN")
set(CMAKE_SYSTEM_NAME "OpenOrbis")
set(CMAKE_C_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables")
set(CMAKE_CXX_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables")
set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
set(CMAKE_C_COMPILER clang)
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_LINKER ld.lld)
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
# TODO: Why does cmake not set this?
set(CMAKE_SIZEOF_VOID_P 8)
EOF
NPROC=$(nproc || 1)
# Normally a platform has a package manager
# PS4 does not, atleast not in the normal sense
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
cmake -S . -B build -G "Unix Makefiles" \
-DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \
-DENABLE_QT_TRANSLATION=OFF \
-DENABLE_CUBEB=OFF \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
-DENABLE_SDL2=ON \
-DENABLE_LIBUSB=OFF \
-DENABLE_UPDATE_CHECKER=OFF \
-DENABLE_QT=OFF \
-DENABLE_OPENSSL=OFF \
-DENABLE_WEB_SERVICE=OFF \
-DUSE_DISCORD_PRESENCE=OFF \
-DCPMUTIL_FORCE_BUNDLED=ON \
-DOPENSSL_ROOT_DIR="$OO_PS4_TOOLCHAIN" \
-DOPENSSL_SSL_LIBRARY="$OO_PS4_TOOLCHAIN/lib/libssl.a" \
-DOPENSSL_CRYPTO_LIBRARY="$OO_PS4_TOOLCHAIN/lib/libcrypto.a" \
-DOPENSSL_INCLUDE_DIR="$OO_PS4_TOOLCHAIN/include/openssl" \
-DYUZU_USE_EXTERNAL_FFMPEG=ON \
-DYUZU_USE_CPM=ON \
-DDYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=OFF \
-DDYNARMIC_TESTS=ON \
-DYUZU_USE_EXTERNAL_SDL2=ON \
"${EXTRA_CMAKE_FLAGS[@]}" || exit
cmake --build build -t yuzu-cmd_pkg -- -j$NPROC
#cmake --build build -t dynarmic_tests_pkg -- -j$NPROC
#cmake --build build -t testps4_pkg -- -j$NPROC

176
.ci/ps4/make-toolchain.sh Executable file
View file

@ -0,0 +1,176 @@
#!/usr/local/bin/bash -ex
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# Define global vars
# These flags are used everywhere, so let's reuse them.
export OO_PS4_TOOLCHAIN="$PWD/prefix"
export PREFIX="$OO_PS4_TOOLCHAIN"
export CC="clang"
export CXX="clang++"
export AR="llvm-ar"
export CFLAGS="-fPIC -DPS4 -D_LIBUNWIND_IS_BAREMETAL=1"
export CXXFLAGS="$CFLAGS -D__STDC_VERSION__=0"
export TARGET="x86_64-scei-ps4"
export LLVM_ROOT="$PWD/llvm-project"
export LLVM_PATH="$PWD/llvm-project/llvm"
export WORK_PATH="$PWD"
prepare_prefix() {
[ -d OpenOrbis-PS4-Toolchain ] || git clone --depth=1 https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain
[ -d musl ] || git clone --depth=1 https://github.com/OpenOrbis/musl
[ -d llvm-project ] || git clone --depth=1 --branch openorbis/20.x https://github.com/seuros/llvm-project
[ -d create-fself ] || git clone --depth=1 https://github.com/OpenOrbis/create-fself
[ -d create-gp4 ] || git clone --depth=1 https://github.com/OpenOrbis/create-gp4
[ -d readoelf ] || git clone --depth=1 https://github.com/OpenOrbis/readoelf
[ -d LibOrbisPkg ] || git clone --depth=1 https://github.com/maxton/LibOrbisPkg
mkdir -p $PREFIX "$PREFIX/bin" "$PREFIX/include"
[ -f "$PREFIX/include/orbis/libkernel.h" ] || cp -r OpenOrbis-PS4-Toolchain/include/* "$PREFIX/include/"
mkdir -p $PREFIX/usr
[ -L "$PREFIX/usr/include" ] || ln -s $PREFIX/include $PREFIX/usr/include || echo 1
[ -L "$PREFIX/usr/share" ] || ln -s $PREFIX/share $PREFIX/usr/share || echo 1
[ -L "$PREFIX/usr/lib" ] || ln -s $PREFIX/lib $PREFIX/usr/lib || echo 1
[ -L "$PREFIX/usr/bin" ] || ln -s $PREFIX/bin $PREFIX/usr/bin || echo 1
}
build_musl() {
mkdir -p musl-build
cd musl-build
../musl/configure --target=$TARGET --disable-shared CC="$CC" CFLAGS="$CFLAGS" --prefix=$PREFIX
gmake -j8 && gmake install
cd ..
}
build_llvm() {
# Build compiler-rt
cmake "$LLVM_ROOT/compiler-rt" -B "$WORK_PATH/llvm-build/compiler-rt" \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \
-DCMAKE_C_FLAGS="$CFLAGS" -DCMAKE_CXX_FLAGS="$CXXFLAGS" \
-DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \
-DLLVM_PATH="$LLVM_PATH" -DCOMPILER_RT_DEFAULT_TARGET_TRIPLE="$TARGET" \
-DCOMPILER_RT_BAREMETAL_BUILD=YES -DCOMPILER_RT_BUILD_BUILTINS=ON \
-DCOMPILER_RT_BUILD_CRT=OFF -DCOMPILER_RT_BUILD_SANITIZERS=OFF \
-DCOMPILER_RT_BUILD_XRAY=OFF -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \
-DCOMPILER_RT_BUILD_PROFILE=OFF -DCOMPILER_RT_STANDALONE_BUILD=ON
# Build libunwind
cmake "$LLVM_ROOT/libunwind" -B "$WORK_PATH/llvm-build/libunwind" \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \
-DCMAKE_C_FLAGS="$CFLAGS -fcxx-exceptions" -DCMAKE_CXX_FLAGS="$CXXFLAGS -fcxx-exceptions" \
-DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \
-DLLVM_PATH="$LLVM_PATH" -DLIBUNWIND_USE_COMPILER_RT=YES \
-DLIBUNWIND_BUILD_32_BITS=NO -DLIBUNWIND_ENABLE_STATIC=ON \
-DLIBUNWIND_ENABLE_SHARED=OFF -DLIBUNWIND_IS_BAREMETAL=ON
# Build libcxxabi
cmake "$LLVM_ROOT/libcxxabi" -B "$WORK_PATH/llvm-build/libcxxabi" \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \
-DCMAKE_C_FLAGS="$CFLAGS -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $LLVM_ROOT/libcxx/include -isystem $PREFIX/include -isystem $WORK_PATH/llvm-build/libcxx/include/c++/v1" \
-DCMAKE_CXX_FLAGS="$CXXFLAGS -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $LLVM_ROOT/libcxx/include -isystem $PREFIX/include -isystem $WORK_PATH/llvm-build/libcxx/include/c++/v1" \
-DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \
-DLLVM_PATH="$LLVM_PATH" -DLIBCXXABI_ENABLE_SHARED=NO \
-DLLVM_ENABLE_RUNTIMES="rt;libunwind" \
-DLIBCXXABI_ENABLE_STATIC=YES -DLIBCXXABI_ENABLE_EXCEPTIONS=YES \
-DLIBCXXABI_USE_COMPILER_RT=YES -DLIBCXXABI_USE_LLVM_UNWINDER=YES \
-DLIBCXXABI_LIBUNWIND_PATH="$LLVM_ROOT/libunwind" \
-DLIBCXXABI_LIBCXX_INCLUDES="$LLVM_ROOT/libcxx/include" \
-DLIBCXXABI_ENABLE_PIC=YES
# Build libcxx
cmake "$LLVM_ROOT/libcxx" -B "$WORK_PATH/llvm-build/libcxx" \
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \
-DCMAKE_C_FLAGS="$CFLAGS -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $PREFIX/include/c++/v1 -isystem $PREFIX/include" \
-DCMAKE_CXX_FLAGS="$CXXFLAGS -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $PREFIX/include/c++/v1 -isystem $PREFIX/include" \
-DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \
-DLLVM_PATH="$LLVM_PATH" -DLIBCXX_ENABLE_RTTI=YES \
-DLIBCXX_HAS_MUSL_LIBC=YES -DLIBCXX_ENABLE_SHARED=NO \
-DLIBCXX_CXX_ABI=libcxxabi -DLIBCXX_CXX_ABI_INCLUDE_PATHS="$LLVM_ROOT/libcxxabi/include" \
-DLIBCXX_CXX_ABI_LIBRARY_PATH="$LLVM_ROOT/libcxxabi/build/lib"
cmake --build "$WORK_PATH/llvm-build/compiler-rt" --parallel
cmake --install "$WORK_PATH/llvm-build/compiler-rt"
cmake --build "$WORK_PATH/llvm-build/libunwind" --parallel
cmake --install "$WORK_PATH/llvm-build/libunwind"
cmake --build "$WORK_PATH/llvm-build/libcxxabi" --parallel
cmake --install "$WORK_PATH/llvm-build/libcxxabi"
touch "$WORK_PATH/llvm-build/libcxx/include/c++/v1/libcxx.imp"
cmake --build "$WORK_PATH/llvm-build/libcxx" --parallel
cmake --install "$WORK_PATH/llvm-build/libcxx"
}
build_tools() {
# Build create-fself
cd create-fself/cmd/create-fself
cp go-linux.mod go.mod
go build -ldflags "-linkmode external -extldflags -static" -o create-fself
mv ./create-fself $PREFIX/bin/create-fself
cd ../../../
# Build create-gp4
cd create-gp4/cmd/create-gp4
go build -ldflags "-linkmode external -extldflags -static" -o create-gp4
mv ./create-gp4 $PREFIX/bin/create-gp4
cd ../../../
# Build readoelf
cd readoelf/cmd/readoelf
go build -ldflags "-linkmode external -extldflags -static" -o readoelf
mv ./readoelf $PREFIX/bin/readoelf
cd ../../../
# # Pull maxton's publishing tools (<3)
# # Sadly maxton has passed on, we have forked the repository and will continue to update it in the future. RIP <3
# cd $PREFIX/bin
# [ -f PkgTool.Core-linux-x64-0.2.231.zip ] || wget https://github.com/maxton/LibOrbisPkg/releases/download/v0.2/PkgTool.Core-linux-x64-0.2.231.zip
# [ -f PkgTool.Core ] || unzip PkgTool.Core-linux-x64-0.2.231.zip
# chmod +x PkgTool.Core
}
finish_prefix() {
as $WORK_PATH/OpenOrbis-PS4-Toolchain/src/crt/crtlib.S -o $PREFIX/lib/crtlib.o
cp -a $WORK_PATH/OpenOrbis-PS4-Toolchain/link.x $PREFIX/
cp -a ~/OpenOrbis/PS4Toolchain/lib/libkernel* $PREFIX/lib/
cp -a ~/OpenOrbis/PS4Toolchain/lib/libSce* $PREFIX/lib/
cp -a ~/OpenOrbis/PS4Toolchain/lib/libSDL* $PREFIX/lib/
cp -r ~/OpenOrbis/PS4Toolchain/include/SDL2 $PREFIX/include/SDL2
cp $WORK_PATH/llvm-build/compiler-rt/lib/freebsd/libclang_rt.builtins-x86_64.a $PREFIX/lib/
# Combine libc++, libc++abi and libunwind into a single archive
cat << EOF >"mri.txt"
CREATE $PREFIX/lib/libc++M.a
ADDLIB $PREFIX/lib/libunwind.a
ADDLIB $PREFIX/lib/libc++abi.a
ADDLIB $PREFIX/lib/libc++.a
SAVE
END
EOF
$AR -M < mri.txt
cp $PREFIX/lib/libc++M.a $PREFIX/lib/libc++.a
# Merge compiler-rt into libc
cat << EOF >"mri.txt"
CREATE $PREFIX/lib/libcM.a
ADDLIB $PREFIX/lib/libc.a
ADDLIB $PREFIX/lib/libclang_rt.builtins-x86_64.a
SAVE
END
EOF
$AR -M < mri.txt
cp $PREFIX/lib/libcM.a $PREFIX/lib/libc.a
rm mri.txt
}
prepare_prefix
build_musl
build_llvm
build_tools
finish_prefix

3
.gitignore vendored
View file

@ -64,3 +64,6 @@ artifacts
/install*
vulkansdk*.exe
*.tar.zst
# PS4 toolchain stuff
ps4-toolchain.cmake

View file

@ -0,0 +1,17 @@
diff --git a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
index 0129511c..10fc9b04 100644
--- a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
+++ b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
@@ -15,6 +15,12 @@
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
+// hacky fix for ps4
+#if defined(__OPENORBIS__)
+# define FIONBIO 0
+# define FIONREAD 1
+#endif
+
#include <boost/asio/detail/config.hpp>
#include <cctype>

View file

@ -0,0 +1,13 @@
diff --git a/unix.c b/unix.c
index 6669216..86a2faa 100644
--- a/unix.c
+++ b/unix.c
@@ -53,7 +53,7 @@
#include <poll.h>
#endif
-#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
+#if !defined(__OPENORBIS__) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
typedef int socklen_t;
#endif

View file

@ -0,0 +1,89 @@
From 509be32bbfa6eb95014860f7c9ea6d45c8ddaa56 Mon Sep 17 00:00:00 2001
From: crueter <crueter@eden-emu.dev>
Date: Sun, 8 Mar 2026 15:11:12 -0400
Subject: [PATCH] [cmake] Simplify zstd find logic, and support pre-existing
zstd target
Some deduplication work on the zstd required/if-available logic. Also
adds support for pre-existing `zstd::libzstd` which is useful for
projects that bundle their own zstd in a way that doesn't get caught by
`CONFIG`
Signed-off-by: crueter <crueter@eden-emu.dev>
---
CMakeLists.txt | 46 ++++++++++++++++++++++++++--------------------
1 file changed, 26 insertions(+), 20 deletions(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1874e36be0..8d31198006 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -241,28 +241,34 @@ endif()
# NOTE:
# zstd < 1.5.6 does not provide the CMake imported target `zstd::libzstd`.
# Older versions must be consumed via their pkg-config file.
-if(HTTPLIB_REQUIRE_ZSTD)
- find_package(zstd 1.5.6 CONFIG)
- if(NOT zstd_FOUND)
- find_package(PkgConfig REQUIRED)
- pkg_check_modules(zstd REQUIRED IMPORTED_TARGET libzstd)
- add_library(zstd::libzstd ALIAS PkgConfig::zstd)
- endif()
- set(HTTPLIB_IS_USING_ZSTD TRUE)
-elseif(HTTPLIB_USE_ZSTD_IF_AVAILABLE)
- find_package(zstd 1.5.6 CONFIG QUIET)
- if(NOT zstd_FOUND)
- find_package(PkgConfig QUIET)
- if(PKG_CONFIG_FOUND)
- pkg_check_modules(zstd QUIET IMPORTED_TARGET libzstd)
-
- if(TARGET PkgConfig::zstd)
+if (HTTPLIB_REQUIRE_ZSTD)
+ set(HTTPLIB_ZSTD_REQUESTED ON)
+ set(HTTPLIB_ZSTD_REQUIRED REQUIRED)
+elseif (HTTPLIB_USE_ZSTD_IF_AVAILABLE)
+ set(HTTPLIB_ZSTD_REQUESTED ON)
+ set(HTTPLIB_ZSTD_REQUIRED QUIET)
+endif()
+
+if (HTTPLIB_ZSTD_REQUESTED)
+ if (TARGET zstd::libzstd)
+ set(HTTPLIB_IS_USING_ZSTD TRUE)
+ else()
+ find_package(zstd 1.5.6 CONFIG QUIET)
+
+ if (NOT zstd_FOUND)
+ find_package(PkgConfig ${HTTPLIB_ZSTD_REQUIRED})
+ pkg_check_modules(zstd ${HTTPLIB_ZSTD_REQUIRED} IMPORTED_TARGET libzstd)
+
+ if (TARGET PkgConfig::zstd)
add_library(zstd::libzstd ALIAS PkgConfig::zstd)
endif()
endif()
+
+ # This will always be true if zstd is required.
+ # If zstd *isn't* found when zstd is set to required,
+ # CMake will error out earlier in this block.
+ set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND})
endif()
- # Both find_package and PkgConf set a XXX_FOUND var
- set(HTTPLIB_IS_USING_ZSTD ${zstd_FOUND})
endif()
# Used for default, common dirs that the end-user can change (if needed)
@@ -317,13 +323,13 @@ if(HTTPLIB_COMPILE)
$<BUILD_INTERFACE:${_httplib_build_includedir}/httplib.h>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/httplib.h>
)
-
+
# Add C++20 module support if requested
# Include from separate file to prevent parse errors on older CMake versions
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.28")
include(cmake/modules.cmake)
endif()
-
+
set_target_properties(${PROJECT_NAME}
PROPERTIES
VERSION ${${PROJECT_NAME}_VERSION}

View file

@ -0,0 +1,13 @@
diff --git a/library/entropy_poll.c b/library/entropy_poll.c
index 611768c..8950ee4 100644
--- a/library/entropy_poll.c
+++ b/library/entropy_poll.c
@@ -118,7 +118,7 @@ static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags)
*
* Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7
*/
-#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM)
+#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM) && !defined(__OPENORBIS__)
#include <sys/param.h>
#include <sys/sysctl.h>
#if defined(KERN_ARND)

View file

@ -0,0 +1,359 @@
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7c230473ac..b1275edb61 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -331,6 +331,13 @@ if(CYGWIN)
list(APPEND SDL_CFLAGS "-I/usr/include/mingw")
endif()
+######### *FIXME*
+if(PS4 OR ORBIS)
+ set(USE_GENERATED_CONFIG Off)
+else()
+ set(USE_GENERATED_CONFIG On)
+endif()
+
# General includes
target_compile_definitions(sdl-build-options INTERFACE "-DUSING_GENERATED_CONFIG_H")
target_include_directories(sdl-build-options BEFORE INTERFACE "${SDL2_BINARY_DIR}/include" "${SDL2_BINARY_DIR}/include-config-$<LOWER_CASE:$<CONFIG>>")
@@ -359,6 +366,15 @@ if(EMSCRIPTEN)
set(SDL_CPUINFO_ENABLED_BY_DEFAULT OFF)
endif()
+if(PS4 OR ORBIS)
+ set(SDL_ATOMIC_ENABLED_BY_DEFAULT ON)
+ set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
+ set(SDL_THREADS_ENABLED_BY_DEFAULT ON)
+ set(SDL_PTHREADS_ENABLED_BY_DEFAULT ON)
+ set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF)
+ set(SDL_DLOPEN_ENABLED_BY_DEFAULT OFF)
+endif()
+
if(VITA OR PSP OR PS2 OR N3DS)
set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF)
@@ -1478,7 +1494,42 @@ elseif(EMSCRIPTEN)
CheckPTHREAD()
CheckLibUnwind()
+elseif(PS4 OR ORBIS)
+ CheckPTHREAD()
+ if(SDL_AUDIO)
+ set(SDL_AUDIO_DRIVER_PS4 1)
+ file(GLOB PS4_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/ps4/*.c)
+ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_AUDIO_SOURCES})
+ set(HAVE_SDL_AUDIO TRUE)
+ endif()
+# if(SDL_FILESYSTEM)
+# set(SDL_FILESYSTEM_PS4 1)
+# file(GLOB PS4_FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/ps4/*.c)
+# set(SOURCE_FILES ${SOURCE_FILES} ${PS4_FILESYSTEM_SOURCES})
+# set(HAVE_SDL_FILESYSTEM TRUE)
+# endif()
+ if(SDL_JOYSTICK)
+ set(SDL_JOYSTICK_PS4 1)
+ file(GLOB PS4_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/ps4/*.c)
+ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_JOYSTICK_SOURCES})
+ set(HAVE_SDL_JOYSTICK TRUE)
+ endif()
+ if(SDL_TIMERS)
+ set(SDL_TIMER_UNIX 1)
+ file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/unix/*.c)
+ set(SOURCE_FILES ${SOURCE_FILES} ${TIMER_SOURCES})
+ set(HAVE_SDL_TIMERS TRUE)
+ if(CLOCK_GETTIME)
+ set(HAVE_CLOCK_GETTIME 1)
+ endif()
+ endif()
+ if(SDL_VIDEO)
+ set(SDL_VIDEO_DRIVER_PS4 1)
+ file(GLOB PS4_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/ps4/*.c)
+ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_VIDEO_SOURCES})
+ set(HAVE_SDL_VIDEO TRUE)
+ endif()
elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
if(SDL_AUDIO)
if(SYSV5 OR SOLARIS OR HPUX)
@@ -3039,7 +3090,7 @@ endif()
# We always need to have threads and timers around
if(NOT HAVE_SDL_THREADS)
# The emscripten platform has been carefully vetted to work without threads
- if (EMSCRIPTEN)
+ if (EMSCRIPTEN OR PS4 OR ORBIS)
set(SDL_THREADS_DISABLED 1)
file(GLOB THREADS_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/*.c)
list(APPEND SOURCE_FILES ${THREADS_SOURCES})
diff --git a/README.md b/README.md
index fa7f7ba0b5..8d5a375694 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-# Simple DirectMedia Layer (SDL) Version 2.0
+# Simple DirectMedia Layer (SDL) Version 2.0 (For OpenOrbis PS4 SDK)
https://www.libsdl.org/
diff --git a/include/SDL_config.h b/include/SDL_config.h
index a628d86252..a101532d16 100644
--- a/include/SDL_config.h
+++ b/include/SDL_config.h
@@ -41,6 +41,10 @@
#include "SDL_config_iphoneos.h"
#elif defined(__ANDROID__)
#include "SDL_config_android.h"
+#elif defined(__PSP__)
+#include "SDL_config_psp.h"
+#elif defined(__OPENORBIS__)
+#include "SDL_config_ps4.h"
#elif defined(__OS2__)
#include "SDL_config_os2.h"
#elif defined(__EMSCRIPTEN__)
diff --git a/include/SDL_platform.h b/include/SDL_platform.h
index 36df782a4e..0cc20dc4e2 100644
--- a/include/SDL_platform.h
+++ b/include/SDL_platform.h
@@ -214,6 +214,10 @@
#if defined(PS2)
#define __PS2__ 1
#endif
+#if defined(__OPENORBIS__)
+#undef __PS4__
+#define __PS4__ 1
+#endif
/* The NACL compiler defines __native_client__ and __pnacl__
* Ref: http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi
diff --git a/src/SDL.c b/src/SDL.c
index cfeea077e7..33fce965c0 100644
--- a/src/SDL.c
+++ b/src/SDL.c
@@ -642,6 +642,8 @@ const char *SDL_GetPlatform(void)
return "Nokia N-Gage";
#elif defined(__3DS__)
return "Nintendo 3DS";
+#elif defined(__PS4__)
+ return "PlayStation4";
#else
return "Unknown (see SDL_platform.h)";
#endif
diff --git a/src/SDL_error.c b/src/SDL_error.c
index 993f5bac55..083ebf3027 100644
--- a/src/SDL_error.c
+++ b/src/SDL_error.c
@@ -50,11 +50,14 @@ int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...)
va_end(ap);
}
}
-
+#ifndef __OPENORBIS__ // Yeah this is stupid but whatever
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) {
+#endif
/* If we are in debug mode, print out the error message */
SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", error->str);
+#ifndef __OPENORBIS__ // Yeah this is stupid but whatever
}
+#endif
}
return -1;
diff --git a/src/SDL_log.c b/src/SDL_log.c
index 7a5f1dbc03..a7f3d85782 100644
--- a/src/SDL_log.c
+++ b/src/SDL_log.c
@@ -390,10 +390,12 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va
int len;
va_list aq;
+#ifndef __OPENORBIS__
/* Nothing to do if we don't have an output function */
if (!SDL_log_function) {
return;
}
+#endif
/* Make sure we don't exceed array bounds */
if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) {
@@ -442,7 +444,11 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va
}
SDL_LockMutex(log_function_mutex);
+#ifdef __OPENORBIS__
+ printf("%s\n", message); // just fucking do it
+#else
SDL_log_function(SDL_log_userdata, category, priority, message);
+#endif
SDL_UnlockMutex(log_function_mutex);
/* Free only if dynamically allocated */
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 421adbc76a..82d087a2f8 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -114,7 +114,10 @@ static const AudioBootStrap *const bootstrap[] = {
#ifdef SDL_AUDIO_DRIVER_N3DS
&N3DSAUDIO_bootstrap,
#endif
-#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
+#if SDL_AUDIO_DRIVER_PS4
+ &PS4AUDIO_bootstrap,
+#endif
+#if SDL_AUDIO_DRIVER_EMSCRIPTEN
&EMSCRIPTENAUDIO_bootstrap,
#endif
#ifdef SDL_AUDIO_DRIVER_JACK
diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h
index 87387692ce..b1c00ba9dc 100644
--- a/src/audio/SDL_sysaudio.h
+++ b/src/audio/SDL_sysaudio.h
@@ -207,6 +207,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap;
extern AudioBootStrap PSPAUDIO_bootstrap;
extern AudioBootStrap VITAAUD_bootstrap;
extern AudioBootStrap N3DSAUDIO_bootstrap;
+extern AudioBootStrap PS4AUDIO_bootstrap;
extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap;
extern AudioBootStrap OS2AUDIO_bootstrap;
diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h
index 178218c053..a6e298a9fe 100644
--- a/src/dynapi/SDL_dynapi.h
+++ b/src/dynapi/SDL_dynapi.h
@@ -69,6 +69,8 @@
#define SDL_DYNAMIC_API 0 /* devkitARM doesn't support dynamic linking */
#elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN)
#define SDL_DYNAMIC_API 0 /* we need dlopen(), but don't have it.... */
+#elif defined(__OPENORBIS__) // Apparently __PS4__ getting defined is missed somewhere, I get broken static builds so force the issue
+#define SDL_DYNAMIC_API 0
#endif
/* everyone else. This is where we turn on the API if nothing forced it off. */
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 60b0daf790..34433166e8 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -106,6 +106,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
#ifdef SDL_JOYSTICK_N3DS
&SDL_N3DS_JoystickDriver
#endif
+#ifdef SDL_JOYSTICK_PS4
+ &SDL_PS4_JoystickDriver,
+#endif
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
&SDL_DUMMY_JoystickDriver
#endif
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index d36f784143..6671aff2fd 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -243,6 +243,7 @@ extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
extern SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver;
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
+extern SDL_JoystickDriver SDL_PS4_JoystickDriver;
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
extern SDL_JoystickDriver SDL_WGI_JoystickDriver;
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 35f80664ab..cd8f9d3615 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -137,6 +137,10 @@ static const SDL_RenderDriver *render_drivers[] = {
#if SDL_VIDEO_RENDER_VITA_GXM
&VITA_GXM_RenderDriver,
#endif
+#if SDL_VIDEO_RENDER_PS4 && 0 // *FIXME* PS4_RenderDriver Disabled, it's software anyhow lets not reinvent...
+#error Use SoftRender for PS4 currently!
+ &PS4_RenderDriver,
+#endif
#if SDL_VIDEO_RENDER_SW
&SW_RenderDriver
#endif
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index ac5426b676..d9b5bfbc39 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -307,6 +307,7 @@ extern SDL_RenderDriver DirectFB_RenderDriver;
extern SDL_RenderDriver METAL_RenderDriver;
extern SDL_RenderDriver PS2_RenderDriver;
extern SDL_RenderDriver PSP_RenderDriver;
+extern SDL_RenderDriver PS4_RenderDriver;
extern SDL_RenderDriver SW_RenderDriver;
extern SDL_RenderDriver VITA_GXM_RenderDriver;
diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c
index 212fe9c000..a920afba0b 100644
--- a/src/thread/pthread/SDL_systhread.c
+++ b/src/thread/pthread/SDL_systhread.c
@@ -29,8 +29,10 @@
#include <pthread_np.h>
#endif
+#ifdef HAVE_SIGNAL_H
#include <signal.h>
#include <errno.h>
+#endif
#ifdef __LINUX__
#include <sys/time.h>
@@ -60,7 +62,7 @@
#endif
-#ifndef __NACL__
+#if !defined(__NACL__) && !defined(__OPENORBIS__)
/* List of signals to mask in the subthreads */
static const int sig_list[] = {
SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH,
@@ -162,7 +164,7 @@ void SDL_SYS_SetupThread(const char *name)
}
/* NativeClient does not yet support signals.*/
-#if !defined(__NACL__)
+#if !defined(__NACL__) && !defined(__OPENORBIS__)
/* Mask asynchronous signals for this thread */
sigemptyset(&mask);
for (i = 0; sig_list[i]; ++i) {
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index badb1a3edc..e17beb9f5c 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -471,6 +471,7 @@ extern VideoBootStrap PSP_bootstrap;
extern VideoBootStrap VITA_bootstrap;
extern VideoBootStrap RISCOS_bootstrap;
extern VideoBootStrap N3DS_bootstrap;
+extern VideoBootStrap PS4_bootstrap;
extern VideoBootStrap RPI_bootstrap;
extern VideoBootStrap KMSDRM_bootstrap;
extern VideoBootStrap KMSDRM_LEGACY_bootstrap;
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index 134cc05e13..f40d6104e2 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -121,6 +121,9 @@ static VideoBootStrap *bootstrap[] = {
#ifdef SDL_VIDEO_DRIVER_N3DS
&N3DS_bootstrap,
#endif
+#ifdef SDL_VIDEO_DRIVER_PS4
+ &PS4_bootstrap,
+#endif
#ifdef SDL_VIDEO_DRIVER_KMSDRM
&KMSDRM_bootstrap,
#endif
@@ -241,6 +244,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
SDL_GetWindowSizeInPixels(window, &w, &h);
if (!data) {
+
SDL_Renderer *renderer = NULL;
const char *render_driver = NULL;
const char *hint;
@@ -297,7 +301,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U
SDL_assert(renderer != NULL); /* should have explicitly checked this above. */
/* Create the data after we successfully create the renderer (bug #1116) */
- data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data));
+ data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(SDL_WindowTextureData));
if (!data) {
SDL_DestroyRenderer(renderer);
return SDL_OutOfMemory();

View file

@ -0,0 +1,25 @@
diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp
index e41c044..a51b53b 100644
--- a/source/opt/loop_dependence.cpp
+++ b/source/opt/loop_dependence.cpp
@@ -12,6 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+// PS4: issue?
+#ifdef __PS4__
+#pragma clang diagnostic ignored "-Wabsolute-value"
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
+#endif
+
#include "source/opt/loop_dependence.h"
#include <functional>
@@ -19,6 +25,7 @@
#include <string>
#include <utility>
#include <vector>
+#include <cstdlib>
#include "source/opt/instruction.h"
#include "source/opt/scalar_analysis_nodes.h"

View file

@ -0,0 +1,21 @@
diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h
index ed7706a..51b520d 100644
--- a/xbyak/xbyak.h
+++ b/xbyak/xbyak.h
@@ -37,6 +37,7 @@
#define XBYAK_GNUC_PREREQ(major, minor) 0
#endif
+#if !defined(XBYAK_STD_UNORDERED_SET)
// This covers -std=(gnu|c)++(0x|11|1y), -stdlib=libc++, and modern Microsoft.
#if ((defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_LIBCPP_VERSION) ||\
((__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)))
@@ -71,6 +72,8 @@
#define XBYAK_STD_UNORDERED_MAP std::map
#define XBYAK_STD_UNORDERED_MULTIMAP std::multimap
#endif
+#endif
+
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN

View file

@ -0,0 +1,21 @@
diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h
index ed7706a..51b520d 100644
--- a/xbyak/xbyak.h
+++ b/xbyak/xbyak.h
@@ -37,6 +37,7 @@
#define XBYAK_GNUC_PREREQ(major, minor) 0
#endif
+#if !defined(XBYAK_STD_UNORDERED_SET)
// This covers -std=(gnu|c)++(0x|11|1y), -stdlib=libc++, and modern Microsoft.
#if ((defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_LIBCPP_VERSION) ||\
((__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__)))
@@ -71,6 +72,8 @@
#define XBYAK_STD_UNORDERED_MAP std::map
#define XBYAK_STD_UNORDERED_MULTIMAP std::multimap
#endif
+#endif
+
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN

View file

@ -20,6 +20,7 @@ include(UseCcache)
include(CMakeDependentOption)
include(CTest)
include(CPMUtil)
include(OpenOrbis)
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")

View file

@ -18,10 +18,13 @@ if (DEFINED GIT_RELEASE)
set(BUILD_VERSION "${GIT_TAG}")
set(GIT_REFSPEC "${GIT_RELEASE}")
set(IS_DEV_BUILD false)
else()
elseif(DEFINED GIT_COMMIT)
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
set(IS_DEV_BUILD true)
else()
set(BUILD_VERSION "NoGitInfo")
set(IS_DEV_BUILD true)
endif()
if (NIGHTLY_BUILD)

View file

@ -0,0 +1,46 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
function(create_ps4_eboot project target content_id)
set(sce_sys_dir sce_sys)
set(sce_sys_param ${sce_sys_dir}/param.sfo)
add_custom_command(
OUTPUT "${target}.pkg"
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
VERBATIM
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS ${project}
)
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
endfunction()
function(create_ps4_pkg project target content_id)
set(sce_sys_dir sce_sys)
set(sce_sys_param ${sce_sys_dir}/param.sfo)
add_custom_command(
OUTPUT "${target}.pkg"
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
COMMAND mkdir -p ${sce_sys_dir}
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_new ${sce_sys_param}
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_TYPE --type Integer --maxsize 4 --value 1
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_VER --type Utf8 --maxsize 8 --value 1.03
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} ATTRIBUTE --type Integer --maxsize 4 --value 0
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CATEGORY --type Utf8 --maxsize 4 --value gd
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CONTENT_ID --type Utf8 --maxsize 48 --value ${content_id}
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} DOWNLOAD_DATA_SIZE --type Integer --maxsize 4 --value 0
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} SYSTEM_VER --type Integer --maxsize 4 --value 0
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE --type Utf8 --maxsize 128 --value ${target}
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE_ID --type Utf8 --maxsize 12 --value BREW00090
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} VERSION --type Utf8 --maxsize 8 --value 1.03
COMMAND ${CMAKE_SYSROOT}/bin/create-gp4 -out ${target}.gp4 --content-id=${content_id} --files "${target}_eboot.bin ${sce_sys_param} sce_module/libc.prx sce_module/libSceFios2.prx"
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${target}.gp4 .
VERBATIM
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
DEPENDS ${project}
)
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
endfunction()
if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN})
set(ENV{OO_PS4_TOOLCHAIN} ${CMAKE_SYSROOT})
endif ()

View file

@ -61,6 +61,10 @@ See the [sign-up instructions](docs/SIGNUP.md) for information on registration.
Alternatively, if you wish to add translations, go to the [Eden project on Transifex](https://app.transifex.com/edenemu/eden-emulator) and review [the translations README](./dist/languages).
## Documentation
We have a user manual! See our [User Handbook](./docs/user/README.md).
## Building
See the [General Build Guide](docs/Build.md)
@ -69,7 +73,9 @@ For information on provided development tooling, see the [Tools directory](./too
## Download
You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases).
You can download the latest releases from [here](https://git.eden-emu.dev/eden-emu/eden/releases).
Save us some bandwidth! We have [mirrors available](./docs/user/ThirdParty.md#mirrors) as well.
## Support

View file

@ -17,7 +17,8 @@
"version": "1.57",
"find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem",
"patches": [
"0001-clang-cl.patch"
"0001-clang-cl.patch",
"0004-openorbis.patch"
]
},
"fmt": {
@ -46,9 +47,9 @@
"package": "ZLIB",
"repo": "madler/zlib",
"tag": "v%VERSION%",
"hash": "06eaa3a1eaaeb31f461a2283b03a91ed8eb2406e62cd97ea1c69836324909edeecd93edd03ff0bf593d9dde223e3376149134c5b1fe2e8688c258cadf8cd60ff",
"hash": "16fea4df307a68cf0035858abe2fd550250618a97590e202037acd18a666f57afc10f8836cbbd472d54a0e76539d0e558cb26f059d53de52ff90634bbf4f47d4",
"version": "1.2",
"git_version": "1.3.1.2",
"git_version": "1.3.2",
"options": [
"ZLIB_BUILD_SHARED OFF",
"ZLIB_INSTALL OFF"
@ -98,9 +99,9 @@
"package": "VVL",
"repo": "KhronosGroup/Vulkan-ValidationLayers",
"tag": "vulkan-sdk-%VERSION%",
"git_version": "1.4.335.0",
"git_version": "1.4.341.0",
"artifact": "android-binaries-%VERSION%.zip",
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
"hash": "8812ae84cbe49e6a3418ade9c458d3be6d74a3dffd319d4502007b564d580998056e8190414368ec11b27bc83993c7a0dad713c31bcc3d9553b51243efee3753"
},
"quazip": {
"package": "QuaZip-Qt6",

215
dist/icon_variations/ps4.svg vendored Normal file
View file

@ -0,0 +1,215 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="512"
height="512"
fill="none"
viewBox="0 0 512 512"
version="1.1"
id="svg7"
sodipodi:docname="ps4.svg"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs7">
<linearGradient
id="linearGradient5"
inkscape:collect="always">
<stop
style="stop-color:#003e74;stop-opacity:1;"
offset="0"
id="stop4" />
<stop
style="stop-color:#2ea8ff;stop-opacity:1;"
offset="1"
id="stop5" />
</linearGradient>
<linearGradient
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#3579ff;stop-opacity:1;"
offset="0"
id="stop2" />
<stop
style="stop-color:#0b00ff;stop-opacity:1;"
offset="1"
id="stop3" />
</linearGradient>
<linearGradient
id="swatch37"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop37" />
</linearGradient>
<linearGradient
id="swatch28"
inkscape:swatch="solid">
<stop
style="stop-color:#252525;stop-opacity:1;"
offset="0"
id="stop28" />
</linearGradient>
<linearGradient
id="swatch27"
inkscape:swatch="solid">
<stop
style="stop-color:#000000;stop-opacity:1;"
offset="0"
id="stop27" />
</linearGradient>
<linearGradient
id="swatch15"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop16" />
</linearGradient>
<linearGradient
id="linearGradient14"
inkscape:swatch="gradient">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop14" />
<stop
style="stop-color:#ffffff;stop-opacity:0;"
offset="1"
id="stop15" />
</linearGradient>
<linearGradient
id="swatch9"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop10" />
</linearGradient>
<linearGradient
id="swatch8"
inkscape:swatch="solid">
<stop
style="stop-color:#ffffff;stop-opacity:1;"
offset="0"
id="stop9" />
</linearGradient>
<rect
x="22.627417"
y="402.76802"
width="521.34025"
height="248.94868"
id="rect24" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18">
<circle
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
id="circle18"
cx="-246.8315"
cy="246.8338"
inkscape:label="Circle"
r="191.89999" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath22">
<circle
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
id="circle22"
cx="256"
cy="256"
inkscape:label="Circle"
r="191.89999" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath128">
<circle
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
id="circle128"
cx="256"
cy="256"
r="192" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1"
id="linearGradient3"
x1="256"
y1="64"
x2="256"
y2="448"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.1874952,0,0,-1.1874952,-47.370662,560.66391)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient5"
id="linearGradient4"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(-1.1874952,0,0,1.1874952,560.61528,-47.345282)"
x1="256"
y1="64"
x2="256"
y2="448" />
</defs>
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1"
inkscape:cx="286.49999"
inkscape:cy="236.99999"
inkscape:window-width="1600"
inkscape:window-height="849"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<path
id="path8-7"
style="display:inline;mix-blend-mode:color;fill:url(#linearGradient3);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
inkscape:label="Circle"
d="m 256.62812,484.66422 a 227.99908,228.00372 0 0 1 -94.5288,-20.52182 c 17.54241,-0.96226 34.77843,-4.71825 46.2868,-10.46733 12.69502,-6.3416 25.70492,-17.24174 35.38366,-26.3736 h 36.45053 c 0.93211,0.61234 1.88758,1.23061 2.86668,1.85086 4.89722,14.18571 13.27668,38.80747 17.49933,51.23264 a 227.99908,228.00372 0 0 1 -43.9582,4.27925 z m 55.26491,-6.80041 -16.39068,-41.47736 c 6.99845,3.71973 14.6813,7.07649 22.62503,9.76921 20.75463,7.03513 39.46594,9.14022 49.31353,9.76688 a 227.99908,228.00372 0 0 1 -55.54788,21.94127 z m 58.6952,-23.72487 c -8.69086,-4.31956 -29.66977,-14.9556 -49.97917,-26.83747 h 87.23219 a 227.99908,228.00372 0 0 1 -37.25302,26.83747 z m -241.49988,-8.48659 a 227.99908,228.00372 0 0 1 -23.67337,-18.35088 h 95.80906 c -1.32304,0.72101 -2.11058,1.13186 -2.11058,1.13186 l 9.37935,10.63433 -34.47214,-6.30174 c 0,-2e-5 -10.96427,4.13624 -36.05858,11.02861 -3.09966,0.85131 -6.06162,1.45425 -8.87374,1.85782 z M 96.054184,418.52496 A 227.99908,228.00372 0 0 1 64.743277,379.80069 h 53.833883 c 16.2593,10.82121 36.03109,20.56336 55.93056,22.04797 47.50893,3.54468 62.979,-1.67459 62.979,-1.67459 0,0 -4.13964,4.3321 -13.0323,12.01204 -2.4447,2.11135 -5.46123,4.28998 -8.54904,6.33885 z m 156.603246,0 c 4.10483,-4.24043 6.54978,-7.04162 6.54978,-7.04162 0,0 3.17296,2.8621 8.63949,7.04162 z m 54.10293,0 c -19.35695,-13.88741 -22.86161,-25.14433 -22.86161,-25.14433 0,0 49.2172,17.2685 90.39112,0.28064 10.4477,-4.31055 19.37408,-9.1049 26.88099,-13.86058 h 47.3421 a 227.99908,228.00372 0 0 1 -31.31091,38.72427 z M 59.385631,371.02418 A 227.99908,228.00372 0 0 1 41.543041,332.29992 H 159.20017 c 1.30773,2.3199 2.75142,4.57103 4.34409,6.73083 12.77878,17.32895 25.06121,26.96783 33.0852,31.99343 h -27.15468 c -5.2719,-0.84 -10.81534,-1.78919 -16.40924,-2.84819 -27.04349,-5.11994 -72.845405,-20.48007 -72.845405,-20.48007 0,0 10.296355,11.13669 26.131855,23.32826 z m 238.424449,0 c 30.05703,-10.10404 47.05829,-24.07021 56.34572,-38.72426 h 117.55739 a 227.99908,228.00372 0 0 1 -17.84258,38.72426 h -40.22176 c 13.33114,-10.41219 19.38725,-18.85882 19.38725,-18.85882 0,0 -30.08919,11.11726 -59.29823,18.85882 z m -41.2585,-14.62133 c -0.90134,-0.01 -9.08983,-0.64727 -40.38179,-18.55498 -2.80164,-1.60327 -5.61377,-3.47048 -8.41452,-5.54795 h 37.53597 c 6.43727,15.58979 11.34615,24.10293 11.34615,24.10293 0,0 -0.0258,6.4e-4 -0.0858,0 z m 12.72847,-0.0418 c 0,0 -2.97304,-8.3824 -6.55675,-24.06118 h 46.48163 c -24.16151,23.08045 -39.92488,24.06123 -39.92488,24.06123 z M 38.653164,323.52341 a 227.99908,228.00372 0 0 1 -8.28,-38.72426 H 147.25331 c 0.50409,11.4347 2.40394,25.61361 7.73264,38.72426 z m 158.567726,0 c -12.80955,-11.77756 -24.77977,-26.58932 -33.71374,-38.72426 h 65.85729 c 4.01234,15.08912 8.39298,28.09557 12.44549,38.72426 z m 63.60057,0 c -2.16662,-10.57203 -4.40101,-23.55135 -6.23667,-38.72426 h 95.8253 c -7.46906,9.7857 -18.55287,23.51811 -32.62829,38.72426 z m 97.99155,0 c 5.95644,-13.69644 6.2152,-27.44278 5.00743,-38.72426 h 119.06262 a 227.99908,228.00372 0 0 1 -8.28,38.72426 z M 29.452392,276.02264 A 227.99908,228.00372 0 0 1 28.62903,256.6605 227.99908,228.00372 0 0 1 29.452392,237.29836 H 219.64878 c 2.02639,13.95226 4.61647,26.90106 7.48446,38.72428 H 157.2241 c -5.80191,-8.33616 -9.27267,-13.98815 -9.27267,-13.98815 0,0 -0.7416,5.5263 -0.8396,13.98815 z m 224.144368,0 c -1.22897,-11.76966 -2.19512,-24.70616 -2.7113,-38.72428 h 232.91837 a 227.99908,228.00372 0 0 1 0.82337,19.36214 227.99908,228.00372 0 0 1 -0.82337,19.36214 H 362.56568 c -0.39943,-2.2888 -0.8157,-4.40137 -1.19214,-6.30638 0,0 -1.52342,2.281 -4.43454,6.30638 z M 30.373164,228.52186 a 227.99908,228.00372 0 0 1 8.28,-38.72427 H 218.96921 c -1.16001,13.8461 -1.41371,26.99937 -0.37573,38.72427 z m 220.252536,0 c -0.27246,-12.17105 -0.19776,-25.09608 0.33166,-38.72427 h 223.6457 a 227.99908,228.00372 0 0 1 8.28,38.72427 z M 41.540725,181.02109 a 227.99908,228.00372 0 0 1 17.84259,-38.72427 H 225.63264 c -2.42151,12.98777 -4.45297,26.07281 -5.81919,38.72427 z m 209.892105,0 c 1.03997,-13.90922 3.42234,-26.81596 6.74692,-38.72427 h 195.69317 a 227.99908,228.00372 0 0 1 17.84258,38.72427 z M 64.740961,133.52032 A 227.99908,228.00372 0 0 1 96.051856,94.796041 H 236.06961 c -3.05987,12.287259 -6.07477,25.390049 -8.74155,38.724279 z m 196.112969,0 c 4.80192,-14.52175 10.96848,-27.42708 17.67095,-38.724279 h 138.6795 a 227.99908,228.00372 0 0 1 31.3109,38.724279 z M 105.41267,86.019537 A 227.99908,228.00372 0 0 1 254.61726,28.666053 c -3.30134,10.858112 -9.7429,31.901037 -16.31878,57.353484 z m 178.62756,0 C 299.82749,62.260898 317.24402,46.83239 326.52798,39.636692 a 227.99908,228.00372 0 0 1 81.31559,46.382845 z" />
<path
id="path8-7-2"
style="display:inline;mix-blend-mode:color;fill:url(#linearGradient4);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
inkscape:label="Circle"
d="m 256.61651,28.654412 a 227.99908,228.00372 0 0 1 94.5288,20.521817 C 333.6029,50.138492 316.36688,53.89448 304.85851,59.64356 292.1635,65.985164 279.15359,76.8853 269.47486,86.017162 h -36.45054 c -0.93211,-0.612343 -1.88758,-1.230613 -2.86668,-1.850865 -4.89722,-14.18571 -13.27667,-38.807461 -17.49932,-51.232639 a 227.99908,228.00372 0 0 1 43.95819,-4.279246 z m -55.26491,6.800405 16.39068,41.477366 c -6.99844,-3.719734 -14.6813,-7.076497 -22.62503,-9.769213 -20.75463,-7.035126 -39.46594,-9.140222 -49.31352,-9.766875 A 227.99908,228.00372 0 0 1 201.3516,35.454817 Z m -58.6952,23.724872 c 8.69086,4.319561 29.66977,14.955598 49.97917,26.837473 H 105.40338 A 227.99908,228.00372 0 0 1 142.6564,59.179689 Z m 241.49988,8.486589 a 227.99908,228.00372 0 0 1 23.67337,18.350884 h -95.80906 c 1.32305,-0.721011 2.11058,-1.131861 2.11058,-1.131861 l -9.37935,-10.634328 34.47215,6.30174 c 0,1.2e-5 10.96426,-4.136248 36.05857,-11.028611 3.09966,-0.851315 6.06162,-1.454254 8.87374,-1.857824 z m 33.03417,27.127388 a 227.99908,228.00372 0 0 1 31.31091,38.724274 h -53.83388 c -16.25931,-10.82121 -36.0311,-20.56336 -55.93057,-22.04797 -47.50892,-3.54468 -62.97899,1.67459 -62.97899,1.67459 0,0 4.13963,-4.3321 13.03229,-12.01204 2.4447,-2.111347 5.46123,-4.289985 8.54904,-6.338854 z m -156.60325,0 c -4.10482,4.240439 -6.54978,7.041624 -6.54978,7.041624 0,0 -3.17295,-2.862104 -8.63949,-7.041624 z m -54.10293,0 c 19.35695,13.887414 22.86161,25.144334 22.86161,25.144334 0,0 -49.2172,-17.2685 -90.39112,-0.28064 -10.4477,4.31055 -19.37408,9.1049 -26.88099,13.86058 H 64.73166 A 227.99908,228.00372 0 0 1 96.042582,94.793666 Z m 247.37474,47.500784 a 227.99908,228.00372 0 0 1 17.84257,38.72426 H 354.04446 c -1.30773,-2.3199 -2.75142,-4.57103 -4.34409,-6.73083 -12.77878,-17.32895 -25.06121,-26.96783 -33.0852,-31.99343 h 27.15468 c 5.2719,0.84 10.81534,1.78919 16.40924,2.84819 27.04349,5.11994 72.84541,20.48007 72.84541,20.48007 0,0 -10.29636,-11.13669 -26.13186,-23.32826 z m -238.42446,0 c -30.05702,10.10404 -47.05829,24.07021 -56.34572,38.72426 H 41.531435 a 227.99908,228.00372 0 0 1 17.842579,-38.72426 h 40.221767 c -13.331141,10.41219 -19.387248,18.85882 -19.387248,18.85882 0,0 30.089197,-11.11726 59.298227,-18.85882 z m 41.2585,14.62133 c 0.90134,0.009 9.08984,0.64727 40.38179,18.55498 2.80164,1.60327 5.61377,3.47048 8.41452,5.54795 h -37.53597 c -6.43727,-15.58979 -11.34615,-24.10293 -11.34615,-24.10293 0,0 0.0258,-6.4e-4 0.0859,0 z m -12.72847,0.0418 c 0,0 2.97304,8.3824 6.55675,24.06118 H 204.0397 c 24.16152,-23.08045 39.92488,-24.06123 39.92488,-24.06123 z m 230.62688,32.83764 a 227.99908,228.00372 0 0 1 8.28,38.72426 H 365.99132 c -0.50409,-11.4347 -2.40394,-25.61361 -7.73264,-38.72426 z m -158.56772,0 c 12.80955,11.77756 24.77977,26.58932 33.71374,38.72426 h -65.85729 c -4.01234,-15.08912 -8.39298,-28.09557 -12.44549,-38.72426 z m -63.60057,0 c 2.16662,10.57203 4.40101,23.55135 6.23667,38.72426 h -95.8253 c 7.46906,-9.7857 18.55287,-23.51811 32.62829,-38.72426 z m -97.99154,0 c -5.95644,13.69644 -6.21521,27.44278 -5.00743,38.72426 H 30.361558 a 227.99908,228.00372 0 0 1 8.280001,-38.72426 z m 329.3606,47.50077 a 227.99908,228.00372 0 0 1 0.82336,19.36214 227.99908,228.00372 0 0 1 -0.82336,19.36214 H 293.59585 c -2.02639,-13.95226 -4.61647,-26.90106 -7.48446,-38.72428 h 69.90914 c 5.80191,8.33616 9.27267,13.98815 9.27267,13.98815 0,0 0.74161,-5.5263 0.8396,-13.98815 z m -224.14436,0 c 1.22897,11.76966 2.19512,24.70616 2.7113,38.72428 H 29.440786 a 227.99908,228.00372 0 0 1 -0.823361,-19.36214 227.99908,228.00372 0 0 1 0.823361,-19.36214 H 150.67895 c 0.39943,2.2888 0.8157,4.40137 1.19214,6.30638 0,0 1.52343,-2.281 4.43455,-6.30638 z m 223.22359,47.50078 a 227.99908,228.00372 0 0 1 -8.28,38.72427 H 294.27542 c 1.16002,-13.8461 1.41371,-26.99937 0.37574,-38.72427 z m -220.25252,0 c 0.27245,12.17105 0.19775,25.09608 -0.33167,38.72427 H 38.641559 a 227.99908,228.00372 0 0 1 -8.280001,-38.72427 z m 209.08496,47.50077 a 227.99908,228.00372 0 0 1 -17.84258,38.72427 H 287.61199 c 2.42151,-12.98777 4.45297,-26.07281 5.81919,-38.72427 z m -209.89209,0 c -1.03998,13.90921 -3.42235,26.81596 -6.74692,38.72427 H 59.371698 A 227.99908,228.00372 0 0 1 41.52912,332.29754 Z m 186.69187,47.50077 a 227.99908,228.00372 0 0 1 -31.3109,38.72428 H 277.17503 c 3.05986,-12.28726 6.07476,-25.39005 8.74154,-38.72428 z m -196.11297,0 c -4.80193,14.52175 -10.96849,27.42708 -17.67095,38.72428 H 96.040255 A 227.99908,228.00372 0 0 1 64.729344,379.79831 Z m 155.44125,47.50078 a 227.99908,228.00372 0 0 1 -149.20459,57.35348 c 3.30135,-10.85811 9.7429,-31.90104 16.31879,-57.35348 z m -178.62756,0 c -15.78726,23.75863 -33.20379,39.18714 -42.48775,46.38284 a 227.99908,228.00372 0 0 1 -81.31558,-46.38284 z" />
<ellipse
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
id="path192"
cx="88.20919"
cy="216.80666"
rx="43.306744"
ry="42.75507" />
<path
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
d="M 211.35225,346.71976 151.38374,303.96994 137.1338,384.12586 Z"
id="path195" />
<path
id="path196-7"
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
d="m 309.50171,362.30735 86.0678,57.93833 m -75.48269,11.93227 57.93833,-86.0678" />
<rect
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:13.9781;stroke-dasharray:none;stroke-opacity:1"
id="rect197"
width="66.112526"
height="59.501274"
x="93.831078"
y="-503.61469"
transform="rotate(108)" />
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View file

@ -11,6 +11,7 @@
- [NetBSD](#netbsd)
- [MSYS2](#msys2)
- [RedoxOS](#redoxos)
- [PlayStation 4](#playstation-4)
- [Windows](#windows)
- [Windows 7, Windows 8 and Windows 8.1](#windows-7-windows-8-and-windows-81)
- [Windows Vista and below](#windows-vista-and-below)
@ -91,7 +92,7 @@ After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-
`-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`. Builds are currently not working due to lack of `std::jthread` and such, either compile libc++ manually or wait for ports to catch up.
If clang has errors, try using `g++-11`.
If clang has errors, try using `g++11`.
## FreeBSD
@ -107,6 +108,8 @@ hw.usb.usbhid.enable="0"
## NetBSD
2026-02-07: `vulkan-headers` must not be installed, since the version found in `pkgsrc` is older than required. Either wait for binary packages to update or build newer versions from source.
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 `echo 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/amd64/10.1/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
```sh
@ -116,7 +119,7 @@ ip6addrctl_policy=ipv4_prefer
System provides a default `g++-10` which doesn't support the current C++ codebase; install `clang-19` with `pkgin install clang-19`. Or install `gcc14` (or `gcc15` with current pkgsrc). Provided that, the following CMake commands may work:
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -Bbuild`
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -Bbuild` (Recommended)
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/pkg/gcc14/bin/gcc -DCMAKE_CXX_COMPILER=/usr/pkg/gcc14/bin/g++ -Bbuild`
- `cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/pkg/gcc15/bin/gcc -DCMAKE_CXX_COMPILER=/usr/pkg/gcc15/bin/g++ -Bbuild`
@ -138,8 +141,12 @@ cmake --install build
However, pkgsrc is highly recommended, see [getting pkgsrc](https://iso.us.netbsd.org/pub/pkgsrc/current/pkgsrc/doc/pkgsrc.html#getting). You must get `current` not the `2025Q2` version.
`QtCore` on NetBSD is included, but due to misconfigurations(!) we MUST include one of the standard headers that include `bits/c++config.h`, since source_location (required by `QtCore`) isn't properly configured to intake `bits/c++config.h` (none of the experimental library is). This is a bug with NetBSD packaging and not our fault, but alas.
## DragonFlyBSD
2026-02-07: `vulkan-headers` and `vulkan-utility-libraries` must NOT be uninstalled, since they're too old: `1.3.289`. Either wait for binary packages to update or build newer versions from source.
If `libstdc++.so.6` is not found (`GLIBCXX_3.4.30`) then attempt:
```sh
@ -214,6 +221,17 @@ The package install may randomly hang at times, in which case it has to be resta
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
## PlayStation 4
```sh
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain/prefix"
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
```
```sh
cp $OO_PS4_TOOLCHAIN/include/endian.h $OO_PS4_TOOLCHAIN/include/sys/endian.h
```
## Windows
### Windows 7, Windows 8 and Windows 8.1

View file

@ -1,5 +1,7 @@
# Eden Build Documentation
Are you just a casual user? Take a look at our [User Handbook](./user) then!
This contains documentation created by developers. This contains build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil), and more.
- **[General Build Instructions](Build.md)**
@ -11,7 +13,6 @@ This contains documentation created by developers. This contains build instructi
- **[CPM - CMake Package Manager](./CPMUtil)**
- **[Platform-Specific Caveats](Caveats.md)**
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
- **[User Handbook](./user)**
- **[Dynarmic](./dynarmic)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**

View file

@ -1,100 +0,0 @@
# Importing Games into Steam with Steam Rom Manager
Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
---
### Pre-Requisites
- Steam Deck Set up and Configured
- Eden set up and Configured
- Internet Access
---
## Steps
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
---
### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
### Installing Through *EmuDeck*
<aside>
***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
</aside>
1. Open **EmuDeck**, then navigate to *Manage Emulators.*
2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
3. Click the **Install** button on the right hand side to install it.
---
2. Open the Start Menu and Launch ***Steam ROM Manager***
1. The program will now launch and show you a window with parsers.
<aside>
***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
</aside>
2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
---
### Creating the Eden Parser
1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
6. Leave everything else the same and hit **Save** to save the parser.
---
4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
1. When you are happy with the results, click the **Add Games****Parse** to start the actual Parsing.
1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
2. Review the game matches and ensure everything is there.
---
### Correcting a Mismatch
If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
1. Hover over the game card and click the magnifying glass icon.
2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
---
### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
1. Hit the **Exclude Games** button in the bottom right.
2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
3. Hit **Save Excludes** when you are happy with your selections.
---
3. When you are happy with the results, select **Save to Steam** to save the results.
1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
3. Try to launch a game and ensure everything is working. You are now good to go.

View file

@ -26,6 +26,7 @@ Eden will store configuration files in the following directories:
- **Android**: Data is stored internally.
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
- **HaikuOS**: `/boot/home/config/settings/eden`
- **PlayStation 4**: `/data/eden`
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.

11
docs/user/CFW.md Normal file
View file

@ -0,0 +1,11 @@
# User Handbook - Custom Firmware (CFW)
At the moment of writing, we do not support CFW such as Atmosphere, due to:
- Lacking the required LLE emulation capabilities to properly emulate the full firmware.
- Lack of implementation on some of the key internals.
- Nobody has bothered to do it (PRs always welcome!)
We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments.
If they don't run - then that's a bug!

View file

@ -1,5 +1,7 @@
# User Handbook - Graphics
Graphical enhancements and visual quality improvments. This doesn't cover texture mods.
## Visual Enhancements
### Anti-aliasing
@ -89,7 +91,7 @@ The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe w
### HaikuOS compatibility
HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purpouses `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purposes `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through.
### Fixes for Windows 10 and above having "Device loss"

206
docs/user/Mods.md Normal file
View file

@ -0,0 +1,206 @@
# User Handbook - Installing Mods
## General Notes
**Note:** When installing a mod, always read the mod's installation instructions.
This is especially important if a mod uses a framework such as **ARCropolis**, **Skyline**, or **Atmosphere plugins**. In those cases, follow the framework's instructions instead of using Eden's normal mod folder.
For example, **Super Smash Bros. Ultimate** uses such a framework. See the related section below for details.
---
# Installing Mods for Most Games
1. Right click a game in the game list.
2. Click **"Open Mod Data Location"**.
3. Extract the mod into that folder.
Each mod should be placed inside **its own subfolder**.
---
# Enabling or Disabling Mods
1. Right click the game in the game list.
2. Click **Configure Game**.
3. In the **Add-Ons** tab, enable or disable mods, updates, and DLC by ticking or unticking their boxes.
---
# Important Note About SD Card Paths
Some mods are designed for real Nintendo Switch consoles and refer to the **SD card root**.
The emulated SD card is located at:
```
%AppData%\eden\sdmc
```
Example:
```
Switch instruction: sd:/ultimate/mods
Eden equivalent: sdmc/ultimate/mods
```
---
# Framework-Based Mods (Super Smash Bros. Ultimate)
Some games require external mod frameworks instead of the built-in mod loader.
The most common example is **Super Smash Bros. Ultimate**.
These mods are installed directly to the **emulated SD card**, not the normal Eden mod folder.
---
# Installing the ARCropolis Modding Framework
**Note:** Some mod packs bundle ARCropolis with their installer (for example, Smash Ult-S).
---
## 1. Download ARCropolis
Download the latest release:
https://github.com/Raytwo/ARCropolis/releases/
---
## 2. Install ARCropolis
Extract the **`atmosphere`** folder into:
```
%AppData%\eden\sdmc
```
This is the **emulated SD card directory**.
Verify installation by checking that the following file exists:
```
sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins\libarcropolis.nro
```
---
## 3. Download Skyline
Download the latest Skyline release:
https://github.com/skyline-dev/skyline/releases
Skyline used to be bundled with ARCropolis but is now distributed separately to avoid compatibility issues caused by outdated bundled versions.
---
## 4. Install Skyline
Extract the **`exefs`** folder into:
```
sdmc\atmosphere\contents\01006A800016E000
```
The `exefs` folder should be **next to the `romfs` folder**.
Verify installation by checking that the following file exists:
```
%AppData%\eden\sdmc\atmosphere\contents\01006A800016E000\exefs\subsdk9
```
---
## 5. Launch the Game Once
Start the game and make sure you see the **ARCropolis version text on the title screen**.
This will also create the folders required for installing mods.
---
## 6. Install Smash Ultimate Mods
Install mods inside:
```
sdmc\ultimate\mods
```
Each mod must be placed inside **its own subfolder**.
Example:
```
sdmc\ultimate\mods\ExampleMod
```
---
# Troubleshooting
## ARCropolis text does not appear on startup
Check the following:
- `libarcropolis.nro` exists in:
```
sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins
```
- `subsdk9` exists in:
```
sdmc\atmosphere\contents\01006A800016E000\exefs
```
- Files were extracted to:
```
%AppData%\eden\sdmc
```
---
## Mods are not loading
Make sure mods are installed inside:
```
sdmc\ultimate\mods
```
Each mod must have its **own subfolder**.
Correct example:
```
sdmc\ultimate\mods\ExampleMod
```
Incorrect example:
```
sdmc\ultimate\mods\ExampleMod\ExampleMod
```
---
## Installing mods in the wrong folder
ARCropolis mods **do not go in Eden's normal mod folder**.
Do **not** install Smash mods here:
```
user\load\01006A800016E000
```
That folder is only used for traditional **RomFS mods**, not ARCropolis.

View file

@ -4,10 +4,14 @@ The "FAQ".
This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience.
A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md).
## Basics
- **[The Basics](Basics.md)**
- **[Quickstart](./QuickStart.md)**
- **[Settings](./Settings.md)**
- **[Installing Mods](./Mods.md)**
- **[Run On macOS](./RunOnMacOS.md)**
- **[Audio](Audio.md)**
- **[Graphics](Graphics.md)**
@ -17,22 +21,29 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e
- **[Using Amiibo](./UsingAmiibo.md)**
- **[Using Cheats](./UsingCheats.md)**
- **[Importing Saves](./ImportingSaves.md)**
- **[Add Eden to Steam ROM Manager](./AddEdenToSRM.md)**
- **[Add Games to Steam ROM Manager](./AddGamesToSRM.md)**
- **[Installing Atmosphere Mods](./InstallingAtmosphereMods.md)**
- **[Installing Updates & DLCs](./InstallingUpdatesDLC.md)**
- **[Controller Profiles](./ControllerProfiles.md)**
- **[Alter Date & Time](./AlterDateTime.md)**
## 3rd-party Integration
- **[Configuring Steam ROM Manager](./SteamROM.md)**
- **[Server hosting](ServerHosting.md)**
- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Third Party](./ThirdParty.md)**
- **[Obtainium](./ThirdParty.md#configuring-obtainium)**
- **[ES-DE](./ThirdParty.md#configuring-es-de)**
- **[Mirrors](./ThirdParty.md#mirrors)**
## Advanced
- **[Custom Firmware](./CFW.md)**
- **[How To Access Logs](./HowToAccessLogs.md)**
- **[Gyro Controls](./GyroControls.md)**
- **[Platforms and Architectures](Architectures.md)**
- **[Server hosting](ServerHosting.md)**
- **[Command Line](CommandLine.md)**
- **[Native Application Development](Native.md)**
- **[Adding Boolean Settings Toggles](AddingBooleanToggles.md)**
- **[Adding Debug Knobs](./AddingDebugKnobs.md)**
- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Testing](Testing.md)**

54
docs/user/Settings.md Normal file
View file

@ -0,0 +1,54 @@
# User Handbook - Settings
As the emulator continues to grow, so does the number of settings that come and go.
Most of the development adds new settings that enhance performance/compatibility, only to be removed later in newer versions due to newfound discoveries or because they were "a hacky workaround".
As such, this guide will NOT mention those kind of settings, we'd rather mention settings which have a long shelf time (i.e won't get removed in future releases) and are likely to be unchanged.
Some of the options are self explainatory, and they do exactly what they say they do (i.e "Pause when not in focus"); such options will be also skipped due to triviality.
## Foreword
Before touching the settings, please see the game boots with stock options. We try our best to ensure users can boot any game using the default settings. If they don't work, then you may try fiddling with options - but please, first use stock options.
## General
- `General/Force X11 as Graphics Backend`: Wayland on *NIX has prominent issues that are unlikely to be resolved; the kind that are "not our fault, it's Wayland issue", this "temporary" hack forces X11 as the backend, regardless of the desktop manager's default.
- `General/Enable Gamemode`: This only does anything when you have Feral Interactive's Gamemode library installed somewhere, if you do, this will help boost FPS by telling the OS to explicitly prioritize *this* application for "gaming" - only for *NIX systems.
- `Hotkeys`: Deceptively to remove a hotkey you must right click and a menu will appear to remove that specific hotkey.
- `UI/Language`: Changes language *of the interface* NOT the emulated program!
- `Debug/Enable Auto Stub`: May help to "fix" some games by just lying and saying that everything they do returns "success" instead of outright crashing for any function/service that is NOT implemented.
- `Debug/Show log in console`: Does as said, note that the program may need to be reopened (Windows) for changes to take effect.
- `Debug/Flush log output`: Classically, every write to the log is "buffered", that is, changes aren't written to the disk UNTIL the program has decided it is time to write, until then it keeps data in a buffer which resides on RAM. If the program crashes, the OS will automatically discard said buffer (any RAM associated with a dead process is automatically discarded/reused for some other purpose); this means critical data may not be logged to the disk on time, which may lead to missing log lines. Use this if you're wanting to remove that factor when debugging, sometimes a hard crash may "eat" some of the log lines IF this option isn't enabled.
- `Debug/Disable Macro HLE:` The emulator has HLE emulation of macro programs for Maxwell, this means that some details are purpousefully skipped; this option forces all macro programs to be ran without skipping anything.
## System
- `System/RNG Seed`: Set to 0 (and uncheck) to disable ASLR systemwide (this makes mods like CTGP to stop working); by default it enables ASLR to replicate console behaviour.
- `Network/Enable Airplane Mode`: Enable this if a game is crashing before loading AND the logs mention anything related to "web" or "internet" services.
## CPU
- `CPU/Virtual table bouncing`: Some games have the tendency to crash on loading due to an indirect bad jump (Pokemon ZA being the worst offender); this option lies to the game and tells it to just pretend it never executed a given function. This is fine for most casual users, but developers of switch applications **must** disable this. This temporary "hack" should hopefully be gone in 6-7 months from now on.
- `Fastmem`, aka. `CPU/Enable Host MMU`: Enables "fastmem"; a detailed description of fastmem can be found [here](../dynarmic/Design.md#fast-memory-fastmem).
- `CPU/Unsafe FMA`: Enables deliberate innacurate FMA behaviour which may affect how FMA returns any given operation - this may introduce tiny floating point errors which can cascade in sensitive code (i.e FFmpeg).
- `CPU/Faster FRSQRTE and FRECPE`: Introduces accuracy errors on square root and reciprocals in exchange for less checks - this introduces inaccuracies with some cases but it's mostly safe.
- `CPU/Faster ASIMD Instructions`: Skips rounding mode checks for ARM ASIMD instructions - this means some code dpeending on these rounding modes may misbehave.
- `CPU/Disable address space checks`: Before each memory access, the emulator checks the address is in range, if not it faults; this option makes it so the emulator skips the check entirely (which may be expensive for a myriad of reasons). However at the same time this allows the guest program to "break out" of the emulation context by writing to arbitrary addresses.
- `CPU/Ignore global monitor`: This relies on a quirk present on x86 to avoid the ARM global monitor emulation, this may increase performance in mutex-heavy contexts (i.e games waiting for next frames or such); but also can cause deadlocks and fun to debug issues.
It is important to note the majority of precision-reducing instructions do not benefit cases where they are not used, which means the performance gains will vary per game.
# Graphics
See also [an extended breakdown of some options](./Graphics.md).
- `Extras/Extended Dynamic State` and `Extras/Vertex Input Dynamic State`: These Vulkan extensions essentially allow you to reuse the same pipeline but just change the state between calls (so called "dynamic state"); the "extended" levels signifies how much state can be placed on this "dynamic" range, for example the amount of depth culling to use can be placed on the dynamic state, avoiding costly reloads and flushes. While this by itself is a fine option, SOME vendors (notably PowerVR and Mali) have problems with anything related to EDS3. EDS3 contains EDS2, and EDS2 contains EDS1. Essentially this means more extended data the driver has to keep track of, at the benefit of avoiding costly flushes.
- `Advanced/Use persistent cache`: This saves compiled shaders onto the disk, independent of any driver's own disk saved shaders (yes, some drivers, notably NVIDIA, save a secondary shader cache onto disk) - disable this only if you're debugging or working on the GPU backend. This option is meant to massively help to reduce shader stutters (after playing for one session that compiles them).
- `Advanced/Use Vulkan pipeline cache`: This is NOT the same as `Use persistent cache`; it's a separate flag that tells the Vulkan backend to create pipeline caches, which are a detail that can be used to massively improve performance and remove pipeline creation overhead. This is a Vulkan feature.
## Controls
Most of the controls should work out of the box. If not, please use a joystick calibrator to ensure it's not an issue with your own controller, for example:
- https://github.com/dkosmari/calibrate-joystick

View file

@ -1,4 +1,6 @@
# Importing Eden into Steam with Steam Rom Manager
# User Handbook - Configuring Steam ROM Manager
## Importing Eden into Steam with Steam Rom Manager
Use this when you want to import the Eden AppImage into your Steam Library along with artwork using *Steam ROM Manager.*
@ -6,7 +8,7 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Pre-Requisites
#### Pre-Requisites
- Eden set up and configured
- Internet Connection
@ -14,9 +16,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
## Steps
### Steps
### Initial Setup
#### Initial Setup
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
@ -24,14 +26,14 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Manual Installation
#### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
### Installing Through *EmuDeck*
#### Installing Through *EmuDeck*
<aside>
@ -45,9 +47,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along
---
### Adding Eden into *Steam ROM Manager*
#### Adding Eden into *Steam ROM Manager*
### EmuDeck Users
#### EmuDeck Users
EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam ROM Manager*** that uses shell scripts to launch them. We will follow this convention.
@ -87,7 +89,7 @@ EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam
---
### Non-EmuDeck Users
#### Non-EmuDeck Users
We will need to create a new parser for the Emulators. Unlike with the EmuDeck model, we will have the parser look for AppImages.
@ -126,7 +128,7 @@ We will need to create a new parser for the Emulators. Unlike with the EmuDeck
---
### Adding Eden to Steam
#### Adding Eden to Steam
Now that we have the parser or shell script created, we can actually add it to Steam.
@ -137,7 +139,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
### Correcting a Mismatch
#### Correcting a Mismatch
If the emulator is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
@ -147,7 +149,7 @@ Now that we have the parser or shell script created, we can actually add it to S
---
### Excluding Matches
#### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files that it finds in the directory. This is how you do so.
@ -160,3 +162,104 @@ Now that we have the parser or shell script created, we can actually add it to S
5. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
6. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
7. Try to launch the Emulator from Steam and ensure everything is working. You are now good to go.
## Importing Games into Steam with Steam Rom Manager
Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
---
#### Pre-Requisites
- Steam Deck Set up and Configured
- Eden set up and Configured
- Internet Access
---
### Steps
1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode.
1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads).
---
#### Manual Installation
1. Open the *Discover Store* and search for *Steam ROM Manager.*
2. Select the **Install** button to install the program.
---
#### Installing Through *EmuDeck*
<aside>
***NOTE***: This assumes you have already set up EmuDeck, if not - just run through the guided installation and select *Steam ROM Manager* as one of the options.
</aside>
1. Open **EmuDeck**, then navigate to *Manage Emulators.*
2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**.
3. Click the **Install** button on the right hand side to install it.
---
2. Open the Start Menu and Launch ***Steam ROM Manager***
1. The program will now launch and show you a window with parsers.
<aside>
***TIP***: Your layout may look different depending on how you installed *Steam ROM Manager*. You may need to go to **Settings → Theme** and change it to *Classic* to follow along.
</aside>
2. Switch off all Parsers by hitting the *Toggle Parsers* switch.
3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing.
---
#### Creating the Eden Parser
1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**.
2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.*
3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs.
4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended.
5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage.
6. Leave everything else the same and hit **Save** to save the parser.
---
4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly.
1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field.
1. When you are happy with the results, click the **Add Games****Parse** to start the actual Parsing.
1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/).
2. Review the game matches and ensure everything is there.
---
#### Correcting a Mismatch
If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually.
1. Hover over the game card and click the magnifying glass icon.
2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want.
3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update.
---
#### Excluding Matches
You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so.
1. Hit the **Exclude Games** button in the bottom right.
2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add.
3. Hit **Save Excludes** when you are happy with your selections.
---
3. When you are happy with the results, select **Save to Steam** to save the results.
1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed.
2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser.
3. Try to launch a game and ensure everything is working. You are now good to go.

View file

@ -7,3 +7,62 @@ While most of the links mentioned in this guide are relatively "safe"; we urge u
- [Nightly Eden builds](https://github.com/pflyly/eden-nightly)
- [NixOS Eden Flake](https://github.com/Grantimatter/eden-flake)
- [ES-DE Frontend Support](https://github.com/GlazedBelmont/es-de-android-custom-systems)
## Mirrors
The main origin repository is always at https://git.eden-emu.dev/eden-emu/eden.
- https://github.com/eden-emulator/mirror
- https://git.crueter.xyz/mirror/eden
- https://collective.taymaerz.de/eden/eden
Other mirrors obviously exist on the internet, but we can't guarantee their reliability and/or availability.
If you're someone wanting to make a mirror, simply setup forgejo and automatically mirror from the origin repository. Or you could mirror a mirror to save us bandwidth... your choice!
## Configuring Obtainium
Very nice handy app, here's a quick rundown how to configure:
1. Copy the URL: https://git.eden-emu.dev/eden-emu/eden/ (or one of your favourite mirrors)
2. Open Obtainium and tap `Add App`.
3. Paste the URL into the `App Source URL` field.
4. Override Source: Look for the `Override Source` dropdown menu and select `Forgejo (Codeberg)`.
5. Click `Add:` Obtainium should now be able to parse the releases and find the APK files.
Note: Even though the site isn't Codeberg, it uses the same Forgejo/Gitea backend, and this setting tells Obtainium how to read the release data.
## Configuring ES-DE
### Method 1
1. Download ZIP from [here](https://github.com/GlazedBelmont/es-de-android-custom-systems)
2. Unzip the file and extract `es_systems.xml` and `es_find_rules.xml` to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
3. Press `Start -> Other Settings -> Alternative Emulators` and set it to Eden (Standalone).
### Method 2
1. Navigate to `\Odin2\Internal shared storage\ES-DE\custom_systems`.
2. Add this to your `es_find_rules.xml`:
```xml
<!-- Standard aka. normal release -->
<emulator name="EDEN">
<rule type="androidpackage">
<entry>dev.eden.eden_emulator/org.yuzu.yuzu_emu.activities.EmulationActivity</entry>
</rule>
</emulator>
<!-- Optimized -->
<emulator name="EDEN">
<rule type="androidpackage">
<entry>com.miHoYo.Yuanshen/org.yuzu.yuzu_emu.activities.EmulationActivity</entry>
</rule>
</emulator>
```
3. Add this line of text to your `es_systems.xml` underneath where the rest of your switch system entries are:
```xml
<command label="Eden (Standalone)">%EMULATOR_EDEN% %ACTION%=android.nfc.action.TECH_DISCOVERED %DATA%=%ROMPROVIDER%</command>
```

View file

@ -159,6 +159,10 @@ if (NOT ANDROID)
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
set(SDL_PIPEWIRE OFF) # build errors out with this on
AddJsonPackage("sdl2_steamdeck")
elseif (PLATFORM_PS4)
set(PS4 ON)
set(ORBIS ON)
AddJsonPackage("sdl2_ps4")
else()
AddJsonPackage("sdl2_generic")
endif()
@ -259,6 +263,11 @@ target_include_directories(tz PUBLIC ./tz)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
if (PLATFORM_PS4)
add_library(ps4sup ps4sup/emutls.c ps4sup/stub.cpp)
target_include_directories(ps4sup PUBLIC ./ps4sup)
endif()
if (NOT TARGET RenderDoc::API)
add_library(renderdoc INTERFACE)
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)

View file

@ -17,6 +17,8 @@
if (${CMAKE_SYSTEM_NAME} STREQUAL "SunOS")
set(PLATFORM_SUN ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenOrbis")
set(PLATFORM_PS4 ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(PLATFORM_FREEBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")

View file

@ -9,7 +9,7 @@
},
"sirit": {
"repo": "eden-emulator/sirit",
"git_version": "1.0.3",
"git_version": "1.0.4",
"tag": "v%VERSION%",
"artifact": "sirit-source-%VERSION%.tar.zst",
"hash_suffix": "sha512sum",
@ -28,11 +28,12 @@
"httplib": {
"repo": "yhirose/cpp-httplib",
"tag": "v%VERSION%",
"hash": "a229e24cca4afe78e5c0aa2e482f15108ac34101fd8dbd927365f15e8c37dec4de38c5277d635017d692a5b320e1b929f8bfcc076f52b8e4dcdab8fe53bfdf2e",
"git_version": "0.30.1",
"hash": "5efa8140aadffe105dcf39935b732476e95755f6c7473ada3d0b64df2bc02c557633ae3948a25b45e1cf67e89a3ff6329fb30362e4ac033b9a1d1e453aa2eded",
"git_version": "0.37.0",
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch"
"0001-mingw.patch",
"0002-fix-zstd.patch"
],
"options": [
"HTTPLIB_REQUIRE_OPENSSL ON"
@ -55,8 +56,8 @@
"package": "xbyak",
"repo": "herumi/xbyak",
"tag": "v%VERSION%",
"hash": "ac333d7bea1d61865bebebb116201a58db431946aa2f11aa042ef5795c390ff30af4d6c90ed3b3d24443a1d430703b08f14fc13b2fa405c155a241456ed78a47",
"git_version": "7.33.2"
"hash": "b6475276b2faaeb315734ea8f4f8bd87ededcee768961b39679bee547e7f3e98884d8b7851e176d861dab30a80a76e6ea302f8c111483607dde969b4797ea95a",
"git_version": "7.35.2"
},
"oaknut": {
"repo": "eden-emulator/oaknut",
@ -97,7 +98,10 @@
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
"version": "1.3",
"git_version": "1.3.18",
"find_args": "MODULE"
"find_args": "MODULE",
"patches": [
"0001-openorbis.patch"
]
},
"spirv-tools": {
"package": "SPIRV-Tools",
@ -110,7 +114,8 @@
],
"patches": [
"0001-netbsd-fix.patch",
"0002-allow-static-only.patch"
"0002-allow-static-only.patch",
"0003-openorbis.patch"
]
},
"spirv-headers": {
@ -146,9 +151,9 @@
"package": "Catch2",
"repo": "catchorg/Catch2",
"tag": "v%VERSION%",
"hash": "acb3f463a7404d6a3bce52e474075cdadf9bb241d93feaf147c182d756e5a2f8bd412f4658ca186d15ab8fed36fc587d79ec311f55642d8e4ded16df9e213656",
"hash": "7eea385d79d88a5690cde131fe7ccda97d5c54ea09d6f515000d7bf07c828809d61c1ac99912c1ee507cf933f61c1c47ecdcc45df7850ffa82714034b0fccf35",
"version": "3.0.1",
"git_version": "3.12.0",
"git_version": "3.13.0",
"patches": [
"0001-solaris-isnan-fix.patch"
]
@ -185,6 +190,18 @@
"bundled": true,
"skip_updates": "true"
},
"sdl2_ps4": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"sha": "0c7042477a",
"hash": "91d897257fe1134e65234618a96bc8f4f9b61dd3ba42241a65c293cd406139e308a6c79eadfa7c3969271c88d73149e75c4310fff37c79387c80d9c982c1f322",
"key": "ps4",
"bundled": true,
"skip_updates": true,
"patches": [
"0001-ps4.patch"
]
},
"moltenvk": {
"repo": "V380-Ori/Ryujinx.MoltenVK",
"tag": "v%VERSION%-ryujinx",
@ -256,15 +273,15 @@
"repo": "KhronosGroup/Vulkan-Headers",
"package": "VulkanHeaders",
"version": "1.4.317",
"hash": "26e0ad8fa34ab65a91ca62ddc54cc4410d209a94f64f2817dcdb8061dc621539a4262eab6387e9b9aa421db3dbf2cf8e2a4b041b696d0d03746bae1f25191272",
"git_version": "1.4.342",
"hash": "d2846ea228415772645eea4b52a9efd33e6a563043dd3de059e798be6391a8f0ca089f455ae420ff22574939ed0f48ed7c6ff3d5a9987d5231dbf3b3f89b484b",
"git_version": "1.4.345",
"tag": "v%VERSION%"
},
"vulkan-utility-libraries": {
"repo": "KhronosGroup/Vulkan-Utility-Libraries",
"package": "VulkanUtilityLibraries",
"hash": "8147370f964fd82c315d6bb89adeda30186098427bf3efaa641d36282d42a263f31e96e4586bfd7ae0410ff015379c19aa4512ba160630444d3d8553afd1ec14",
"git_version": "1.4.342",
"hash": "114f6b237a6dcba923ccc576befb5dea3f1c9b3a30de7dc741f234a831d1c2d52d8a224afb37dd57dffca67ac0df461eaaab6a5ab5e503b393f91c166680c3e1",
"git_version": "1.4.345",
"tag": "v%VERSION%"
},
"frozen": {

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
@ -11,42 +11,81 @@ set(FFmpeg_HWACCEL_FLAGS)
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
set(FFmpeg_HWACCEL_LDFLAGS)
if (UNIX AND NOT ANDROID)
if (NOT YUZU_USE_BUNDLED_FFMPEG)
set(FFmpeg_CROSS_COMPILE_FLAGS "")
if (ANDROID)
# TODO: Maybe use CMAKE_SYSROOT? and probably provide a toolchain file for android
# I mean isn't that the "proper" way anyways?
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
set(SYSROOT "${TOOLCHAIN}/sysroot")
set(FFmpeg_CPU "armv8-a")
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch=arm64
#--cpu=${FFmpeg_CPU}
--cross-prefix="${TOOLCHAIN}/bin/aarch64-linux-android-"
--sysroot="${SYSROOT}"
--target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib"
)
set(FFmpeg_IS_CROSS_COMPILING TRUE)
# User attempts to do a FFmpeg cross compilation because...
# Here we just quickly test against host/system processors not matching
# TODO: Test for versions not matching as well?
elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR
AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME))
string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME)
if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis")
set(FFmpeg_SYSTEM_NAME "freebsd") # Emulates FBSD :)
endif()
# TODO: Can we really do better? Auto-detection? Something clever?
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--enable-cross-compile
--arch="${CMAKE_SYSTEM_PROCESSOR}"
--target-os="${FFmpeg_SYSTEM_NAME}"
--sysroot="${CMAKE_SYSROOT}"
)
if (DEFINED FFmpeg_CROSS_PREFIX)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}")
else()
message(WARNING "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-")
endif()
set(FFmpeg_IS_CROSS_COMPILING TRUE)
endif()
endif()
if (PLATFORM_PS4)
list(APPEND FFmpeg_HWACCEL_FLAGS
--disable-vaapi
)
elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING)
find_package(PkgConfig REQUIRED)
if (NOT ANDROID)
pkg_check_modules(LIBVA libva)
pkg_check_modules(CUDA cuda)
pkg_check_modules(FFNVCODEC ffnvcodec)
pkg_check_modules(VDPAU vdpau)
endif()
find_package(X11)
if(X11_FOUND)
if (NOT APPLE)
# In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so
if(PLATFORM_SUN)
find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib)
if(LIBDRM_LIB)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
X11
"${LIBDRM_LIB}")
message(STATUS "Found libdrm at: ${LIBDRM_LIB}")
else()
message(WARNING "libdrm not found, disabling libdrm support")
list(APPEND FFmpeg_HWACCEL_FLAGS
--disable-libdrm)
endif()
"${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so")
else()
pkg_check_modules(LIBDRM libdrm REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
${LIBDRM_LIBRARIES})
list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS
${LIBDRM_INCLUDE_DIRS})
endif()
list(APPEND FFmpeg_HWACCEL_FLAGS
--enable-libdrm)
endif()
endif()
if(LIBVA_FOUND)
find_package(X11 REQUIRED)
pkg_check_modules(LIBVA-DRM libva-drm REQUIRED)
pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED)
list(APPEND FFmpeg_HWACCEL_LIBRARIES
@ -69,6 +108,10 @@ if (UNIX AND NOT ANDROID)
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...")
endif()
else()
list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi)
message(WARNING "ffmpeg: X11 libraries not found, disabling VA-API...")
endif()
if (FFNVCODEC_FOUND)
list(APPEND FFmpeg_HWACCEL_FLAGS
@ -111,6 +154,23 @@ if (UNIX AND NOT ANDROID)
endif()
endif()
if (PLATFORM_PS4)
list(APPEND FFmpeg_CROSS_COMPILE_LIBS
-lc
-lkernel
-lSceUserService
-lSceSysmodule
-lSceNet
-lSceLibcInternal
)
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--disable-pthreads
--extra-cflags=${CMAKE_SYSROOT}/usr/include
--extra-cxxflags=${CMAKE_SYSROOT}/usr/include
--extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}"
)
endif()
if (YUZU_USE_BUNDLED_FFMPEG)
AddJsonPackage(ffmpeg-ci)
@ -181,24 +241,6 @@ else()
find_program(BASH_PROGRAM bash REQUIRED)
set(FFmpeg_CROSS_COMPILE_FLAGS "")
if (ANDROID)
string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME)
set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}")
set(SYSROOT "${TOOLCHAIN}/sysroot")
set(FFmpeg_CPU "armv8-a")
list(APPEND FFmpeg_CROSS_COMPILE_FLAGS
--arch=arm64
#--cpu=${FFmpeg_CPU}
--enable-cross-compile
--cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android-
--sysroot=${SYSROOT}
--target-os=android
--extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld"
--extra-ldflags="-nostdlib"
)
endif()
# `configure` parameters builds only exactly what yuzu needs from FFmpeg
# `--disable-vdpau` is needed to avoid linking issues
set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER})
@ -221,8 +263,12 @@ else()
--enable-decoder=vp9
--enable-filter=yadif,scale
--enable-pic
--cc="${FFmpeg_CC}"
--cxx="${FFmpeg_CXX}"
--cc=${FFmpeg_CC}
--cxx=${FFmpeg_CXX}
--ld=${CMAKE_LINKER}
--extra-cflags=${CMAKE_C_FLAGS}
--extra-cxxflags=${CMAKE_CXX_FLAGS}
--extra-ldflags=${CMAKE_C_LINK_FLAGS}
${FFmpeg_HWACCEL_FLAGS}
${FFmpeg_CROSS_COMPILE_FLAGS}
WORKING_DIRECTORY
@ -254,7 +300,7 @@ else()
OUTPUT
${FFmpeg_BUILD_LIBRARIES}
COMMAND
make ${FFmpeg_MAKE_ARGS}
gmake ${FFmpeg_MAKE_ARGS}
WORKING_DIRECTORY
${FFmpeg_BUILD_DIR}
)

181
externals/ps4sup/emutls.c vendored Normal file
View file

@ -0,0 +1,181 @@
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
*
* The LLVM Compiler Infrastructure
*
* This file is dual licensed under the MIT and the University of Illinois Open
* Source Licenses. See LICENSE.TXT for details.
*
* ===----------------------------------------------------------------------===
*/
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
//#include "int_util.h"
/* Default is not to use posix_memalign, so systems like Android
* can use thread local data without heavier POSIX memory allocators.
*/
#ifndef EMUTLS_USE_POSIX_MEMALIGN
#define EMUTLS_USE_POSIX_MEMALIGN 0
#endif
/* For every TLS variable xyz,
* there is one __emutls_control variable named __emutls_v.xyz.
* If xyz has non-zero initial value, __emutls_v.xyz's "value"
* will point to __emutls_t.xyz, which has the initial value.
*/
typedef struct __emutls_control {
size_t size; /* size of the object in bytes */
size_t align; /* alignment of the object in bytes */
union {
uintptr_t index; /* data[index-1] is the object address */
void* address; /* object address, when in single thread env */
} object;
void* value; /* null or non-zero initial value for the object */
} __emutls_control;
static inline void* emutls_memalign_alloc(size_t align, size_t size) {
void *base;
#if EMUTLS_USE_POSIX_MEMALIGN
if (posix_memalign(&base, align, size) != 0)
abort();
#else
#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
char* object;
if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
abort();
base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
& ~(uintptr_t)(align - 1));
((void**)base)[-1] = object;
#endif
return base;
}
static inline void emutls_memalign_free(void* base) {
#if EMUTLS_USE_POSIX_MEMALIGN
free(base);
#else
/* The mallocated address is in ((void**)base)[-1] */
free(((void**)base)[-1]);
#endif
}
/* Emulated TLS objects are always allocated at run-time. */
static inline void* emutls_allocate_object(__emutls_control* control) {
/* Use standard C types, check with gcc's emutls.o. */
//typedef unsigned int gcc_word __attribute__((mode(word)));
//typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
//COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
size_t size = control->size;
size_t align = control->align;
if (align < sizeof(void*))
align = sizeof(void*);
/* Make sure that align is power of 2. */
if ((align & (align - 1)) != 0)
abort();
void* base = emutls_memalign_alloc(align, size);
if (control->value)
memcpy(base, control->value, size);
else
memset(base, 0, size);
return base;
}
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
static size_t emutls_num_object = 0; /* number of allocated TLS objects */
typedef struct emutls_address_array {
uintptr_t size; /* number of elements in the 'data' array */
void* data[];
} emutls_address_array;
static pthread_key_t emutls_pthread_key;
static void emutls_key_destructor(void* ptr) {
emutls_address_array* array = (emutls_address_array*)ptr;
uintptr_t i;
for (i = 0; i < array->size; ++i) {
if (array->data[i])
emutls_memalign_free(array->data[i]);
}
free(ptr);
}
static void emutls_init(void) {
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
abort();
}
/* Returns control->object.index; set index if not allocated yet. */
static inline uintptr_t emutls_get_index(__emutls_control* control) {
uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
if (!index) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
pthread_once(&once, emutls_init);
pthread_mutex_lock(&emutls_mutex);
index = control->object.index;
if (!index) {
index = ++emutls_num_object;
__atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
}
pthread_mutex_unlock(&emutls_mutex);
}
return index;
}
/* Updates newly allocated thread local emutls_address_array. */
static inline void emutls_check_array_set_size(emutls_address_array* array,
uintptr_t size) {
if (array == NULL)
abort();
array->size = size;
pthread_setspecific(emutls_pthread_key, (void*)array);
}
/* Returns the new 'data' array size, number of elements,
* which must be no smaller than the given index.
*/
static inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
/* Need to allocate emutls_address_array with one extra slot
* to store the data array size.
* Round up the emutls_address_array size to multiple of 16.
*/
return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
}
/* Returns the thread local emutls_address_array.
* Extends its size if necessary to hold address at index.
*/
static inline emutls_address_array* emutls_get_address_array(uintptr_t index) {
emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
if (array == NULL) {
uintptr_t new_size = emutls_new_data_array_size(index);
array = calloc(new_size + 1, sizeof(void*));
emutls_check_array_set_size(array, new_size);
} else if (index > array->size) {
uintptr_t orig_size = array->size;
uintptr_t new_size = emutls_new_data_array_size(index);
array = realloc(array, (new_size + 1) * sizeof(void*));
if (array)
memset(array->data + orig_size, 0,
(new_size - orig_size) * sizeof(void*));
emutls_check_array_set_size(array, new_size);
}
return array;
}
void* __emutls_get_address(__emutls_control* control) {
uintptr_t index = emutls_get_index(control);
emutls_address_array* array = emutls_get_address_array(index);
if (array->data[index - 1] == NULL)
array->data[index - 1] = emutls_allocate_object(control);
return array->data[index - 1];
}

31
externals/ps4sup/stub.cpp vendored Normal file
View file

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <stdio.h>
#define STUB_WEAK(name) \
extern "C" void name() { \
printf("called " #name); \
asm volatile("ud2"); \
}
extern "C" int __pthread_cxa_finalize();
extern "C" void __cxa_thread_atexit_impl() {
//printf("__cxa_thread_atexit_impl called!\n");
//__pthread_cxa_finalize();
}
STUB_WEAK(__assert)
STUB_WEAK(ZSTD_trace_compress_begin)
STUB_WEAK(ZSTD_trace_compress_end)
STUB_WEAK(ZSTD_trace_decompress_begin)
STUB_WEAK(ZSTD_trace_decompress_end)
FILE* __stderrp = stdout;
FILE* __stdinp = stdin;
#undef STUB_WEAK
// THIS MAKES STD::COUT AND SUCH WORK :)
#include <iostream>
std::ios_base::Init init;

View file

@ -1,5 +1,6 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later

View file

@ -607,6 +607,12 @@ object NativeLibrary {
*/
external fun addFileToFilesystemProvider(path: String)
/**
* Adds a game-folder file to the manual filesystem provider, respecting the internal gate for
* game-folder external-content mounting.
*/
external fun addGameFolderFileToFilesystemProvider(path: String)
/**
* Clears all files added to the manual filesystem provider in our EmulationSession instance
*/

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@ -10,6 +10,8 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.content.res.ResourcesCompat
import androidx.lifecycle.LifecycleOwner
import com.google.android.material.button.MaterialButton
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.CardInstallableIconBinding
import org.yuzu.yuzu_emu.databinding.CardSimpleOutlinedBinding
import org.yuzu.yuzu_emu.model.GameProperty
@ -89,29 +91,33 @@ class GamePropertiesAdapter(
val hasVisibleActions = submenuProperty.secondaryActions?.any { it.isShown } == true
binding.layoutSecondaryActions.removeAllViews()
binding.dividerSecondaryActions.setVisible(false)
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() }
val visibleActions = submenuProperty.secondaryActions!!.filter { it.isShown }
val inflater = LayoutInflater.from(binding.root.context)
visibleActions.forEachIndexed { index, secondaryAction ->
val button = inflater.inflate(
R.layout.item_secondary_action_button,
binding.layoutSecondaryActions,
false
) as MaterialButton
button.setIconResource(secondaryAction.iconId)
button.text = ""
button.contentDescription = binding.root.context
.getString(secondaryAction.descriptionId)
button.tooltipText = binding.root.context
.getString(secondaryAction.descriptionId)
if (index == visibleActions.lastIndex) {
(button.layoutParams as ViewGroup.MarginLayoutParams).marginEnd = 0
}
button.setOnClickListener { secondaryAction.action.invoke() }
binding.layoutSecondaryActions.addView(button)
}
}
} else {
binding.dividerSecondaryActions.setVisible(false)
binding.layoutSecondaryActions.setVisible(false)
}
}

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.dialogs
@ -14,6 +14,7 @@ import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.FrameLayout
import androidx.core.content.getSystemService
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.DividerItemDecoration
@ -58,6 +59,30 @@ class LobbyBrowser(context: Context) : BottomSheetDialog(context) {
setupSearchBar()
}
override fun onStart() {
super.onStart()
window?.setLayout(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT
)
val bottomSheet =
findViewById<FrameLayout>(com.google.android.material.R.id.design_bottom_sheet)
if (bottomSheet != null) {
bottomSheet.layoutParams = bottomSheet.layoutParams.apply {
width = ViewGroup.LayoutParams.MATCH_PARENT
height = ViewGroup.LayoutParams.MATCH_PARENT
}
bottomSheet.requestLayout()
}
behavior.isFitToContents = false
behavior.expandedOffset = 0
behavior.skipCollapsed = true
behavior.state = BottomSheetBehavior.STATE_EXPANDED
}
private fun setupRecyclerView() {
adapter = LobbyRoomAdapter { room -> handleRoomSelection(room) }

View file

@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.fetcher
import android.graphics.Rect
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() {
@ -15,8 +16,20 @@ class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecorat
state: RecyclerView.State
) {
outRect.bottom = spacing
if (parent.getChildAdapterPosition(view) == 0) {
val position = parent.getChildAdapterPosition(view)
if (position == RecyclerView.NO_POSITION) return
if (position == 0) {
outRect.top = spacing
return
}
// If the item is in the first row, but NOT in first column add top spacing as well
val layoutManager = parent.layoutManager
if (layoutManager is GridLayoutManager && layoutManager.spanSizeLookup.getSpanGroupIndex(position, layoutManager.spanCount) == 0) {
outRect.top = spacing
return
}
}
}

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.features.settings.model
@ -27,7 +27,7 @@ object Settings {
SECTION_APP_SETTINGS(R.string.app_settings),
SECTION_CUSTOM_PATHS(R.string.preferences_custom_paths),
SECTION_DEBUG(R.string.preferences_debug),
SECTION_FREEDRENO(R.string.gpu_driver_settings),
SECTION_FREEDRENO(R.string.freedreno_settings_title),
SECTION_APPLETS(R.string.applets_menu);
}

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@ -111,10 +111,18 @@ class SettingsActivity : AppCompatActivity() {
if (navHostFragment.childFragmentManager.backStackEntryCount > 0) {
navHostFragment.navController.popBackStack()
} else {
finish()
finishWithFragmentLikeAnimation()
}
}
private fun finishWithFragmentLikeAnimation() {
finish()
overridePendingTransition(
androidx.navigation.ui.R.anim.nav_default_pop_enter_anim,
androidx.navigation.ui.R.anim.nav_default_pop_exit_anim
)
}
override fun onStart() {
super.onStart()
if (!DirectoryInitialization.areDirectoriesReady) {
@ -170,7 +178,7 @@ class SettingsActivity : AppCompatActivity() {
getString(R.string.settings_reset),
Toast.LENGTH_LONG
).show()
finish()
finishWithFragmentLikeAnimation()
}
private fun setInsets() {

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@ -68,7 +68,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
MaterialAlertDialogBuilder(requireContext())
.setMessage(R.string.reset_setting_confirmation)
.setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int ->
when (val item = settingsViewModel.clickedItem) {
val item = settingsViewModel.clickedItem ?: return@setPositiveButton
clearDialogState()
when (item) {
is AnalogInputSetting -> {
val stickParam = NativeInput.getStickParam(
item.playerIndex,
@ -107,12 +109,17 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
}
else -> {
settingsViewModel.clickedItem!!.setting.reset()
item.setting.reset()
settingsViewModel.setAdapterItemChanged(position)
}
}
}
.setNegativeButton(android.R.string.cancel, null)
.setNegativeButton(android.R.string.cancel) { _: DialogInterface, _: Int ->
clearDialogState()
}
.setOnCancelListener {
clearDialogState()
}
.create()
}
@ -186,27 +193,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
updateButtonState(isValid)
}
/*
* xbzk: these two events, along with attachRepeat feature,
* were causing spinbox buttons to respond twice per press
* cutting these out to retain accelerated press functionality
* TODO: clean this out later if no issues arise
*
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)
}
*/
fun attachRepeat(button: View, delta: Int) {
val handler = Handler(Looper.getMainLooper())
var runnable: Runnable? = null
@ -439,9 +425,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener
private fun closeDialog() {
settingsViewModel.setAdapterItemChanged(position)
clearDialogState()
dismiss()
}
private fun clearDialogState() {
settingsViewModel.clickedItem = null
settingsViewModel.setSliderProgress(-1f)
dismiss()
}
private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int {

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
@ -98,23 +98,8 @@ class SettingsFragment : Fragment() {
activity
)
binding.toolbarSettingsLayout.title = if (args.menuTag == Settings.MenuTag.SECTION_ROOT &&
args.game != null
) {
args.game!!.title
} else {
when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
else -> getString(args.menuTag.titleId)
}
}
val toolbarTitle = resolveToolbarTitle()
configureToolbar(toolbarTitle)
binding.listSettings.apply {
adapter = settingsAdapter
@ -193,11 +178,9 @@ class SettingsFragment : Fragment() {
}
presenter.onViewCreated()
setInsets()
}
private fun getPlayerIndex(): Int =
private fun getPlayerIndex(): Int =
when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> 0
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> 1
@ -210,6 +193,27 @@ class SettingsFragment : Fragment() {
else -> -1
}
private fun resolveToolbarTitle(): String {
if (args.menuTag == Settings.MenuTag.SECTION_ROOT && args.game != null) {
return args.game!!.title
}
return when (args.menuTag) {
Settings.MenuTag.SECTION_INPUT_PLAYER_ONE -> Settings.getPlayerString(1)
Settings.MenuTag.SECTION_INPUT_PLAYER_TWO -> Settings.getPlayerString(2)
Settings.MenuTag.SECTION_INPUT_PLAYER_THREE -> Settings.getPlayerString(3)
Settings.MenuTag.SECTION_INPUT_PLAYER_FOUR -> Settings.getPlayerString(4)
Settings.MenuTag.SECTION_INPUT_PLAYER_FIVE -> Settings.getPlayerString(5)
Settings.MenuTag.SECTION_INPUT_PLAYER_SIX -> Settings.getPlayerString(6)
Settings.MenuTag.SECTION_INPUT_PLAYER_SEVEN -> Settings.getPlayerString(7)
Settings.MenuTag.SECTION_INPUT_PLAYER_EIGHT -> Settings.getPlayerString(8)
else -> getString(args.menuTag.titleId)
}
}
private fun configureToolbar(title: String) {
binding.toolbarSettings.title = title
}
private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(
binding.root

View file

@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.features.settings.ui
import android.annotation.SuppressLint
import android.os.Build
import android.widget.Toast
import androidx.preference.PreferenceManager
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.YuzuApplication
@ -27,11 +26,9 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings.MenuTag
import org.yuzu.yuzu_emu.features.settings.model.ShortSetting
import org.yuzu.yuzu_emu.features.settings.model.StringSetting
import org.yuzu.yuzu_emu.features.settings.model.view.*
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
import androidx.core.content.edit
import androidx.fragment.app.FragmentActivity
import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
@ -183,16 +180,6 @@ class SettingsFragmentPresenter(
menuKey = MenuTag.SECTION_DEBUG
)
)
if (GpuDriverHelper.isAdrenoGpu() && !NativeConfig.isPerGameConfigLoaded()) {
add(
SubmenuSetting(
titleId = R.string.gpu_driver_settings,
descriptionId = R.string.freedreno_settings_title,
iconId = R.drawable.ic_graphics,
menuKey = MenuTag.SECTION_FREEDRENO
)
)
}
add(
SubmenuSetting(
titleId = R.string.applets_menu,
@ -1066,7 +1053,10 @@ class SettingsFragmentPresenter(
IntSetting.THEME.getValueAsString()
override val defaultValue: Int = IntSetting.THEME.defaultValue
override fun reset() = IntSetting.THEME.setInt(defaultValue)
override fun reset() {
IntSetting.THEME.setInt(defaultValue)
settingsViewModel.setShouldRecreate(true)
}
}
add(HeaderSetting(R.string.app_settings))
@ -1081,27 +1071,6 @@ class SettingsFragmentPresenter(
add(HeaderSetting(R.string.theme_and_color))
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(
SingleChoiceSetting(
theme,
titleId = R.string.change_app_theme,
choicesId = R.array.themeEntriesA12,
valuesId = R.array.themeValuesA12
)
)
} else {
add(
SingleChoiceSetting(
theme,
titleId = R.string.change_app_theme,
choicesId = R.array.themeEntries,
valuesId = R.array.themeValues
)
)
}
val themeMode: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int = IntSetting.THEME_MODE.getInt()
override fun setInt(value: Int) {
@ -1123,6 +1092,35 @@ class SettingsFragmentPresenter(
}
}
add(
SingleChoiceSetting(
themeMode,
titleId = R.string.change_theme_mode,
choicesId = R.array.themeModeEntries,
valuesId = R.array.themeModeValues
)
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
add(
SingleChoiceSetting(
theme,
titleId = R.string.change_app_theme,
choicesId = R.array.themeEntriesA12,
valuesId = R.array.themeValuesA12
)
)
} else {
add(
SingleChoiceSetting(
theme,
titleId = R.string.change_app_theme,
choicesId = R.array.themeEntries,
valuesId = R.array.themeValues
)
)
}
val staticThemeColor: AbstractIntSetting = object : AbstractIntSetting {
override fun getInt(needsGlobal: Boolean): Int =
IntSetting.STATIC_THEME_COLOR.getInt(needsGlobal)
@ -1146,15 +1144,6 @@ class SettingsFragmentPresenter(
}
}
add(
SingleChoiceSetting(
themeMode,
titleId = R.string.change_theme_mode,
choicesId = R.array.themeModeEntries,
valuesId = R.array.themeModeValues
)
)
if (IntSetting.THEME.getInt() != 1) {
add(
SingleChoiceSetting(

View file

@ -1,7 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@ -54,8 +51,8 @@ class AboutFragment : Fragment() {
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarAbout.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@ -19,7 +19,6 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.transition.MaterialSharedAxis
import kotlinx.coroutines.launch
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.AddonAdapter
import org.yuzu.yuzu_emu.databinding.FragmentAddonsBinding
@ -42,7 +41,7 @@ class AddonsFragment : Fragment() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
addonViewModel.onOpenAddons(args.game)
addonViewModel.onAddonsViewCreated(args.game)
enterTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
@ -122,13 +121,15 @@ class AddonsFragment : Fragment() {
override fun onResume() {
super.onResume()
addonViewModel.refreshAddons()
addonViewModel.onAddonsViewStarted(args.game)
}
override fun onDestroy() {
super.onDestroy()
if (activity?.isChangingConfigurations != true) {
addonViewModel.onCloseAddons()
}
super.onDestroy()
}
val installAddon =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
@ -167,7 +168,7 @@ class AddonsFragment : Fragment() {
} catch (_: Exception) {
return@newInstance errorMessage
}
addonViewModel.refreshAddons()
addonViewModel.refreshAddons(force = true)
return@newInstance getString(R.string.addon_installed_successfully)
}.show(parentFragmentManager, ProgressDialogFragment.TAG)
} else {

View file

@ -29,6 +29,7 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter
import org.yuzu.yuzu_emu.model.DriverViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.IOException
@ -87,6 +88,7 @@ class DriverFetcherFragment : Fragment() {
private lateinit var driverGroupAdapter: DriverGroupAdapter
private val driverViewModel: DriverViewModel by activityViewModels()
private val homeViewModel: HomeViewModel by activityViewModels()
private fun parseAdrenoModel(): Int {
if (gpuModel == null) {
@ -138,7 +140,7 @@ class DriverFetcherFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = false)
binding.toolbarDrivers.setNavigationOnClickListener {
binding.root.findNavController().popBackStack()
}

View file

@ -22,6 +22,7 @@ import org.yuzu.yuzu_emu.databinding.FragmentFreedrenoSettingsBinding
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.NativeFreedrenoConfig
import org.yuzu.yuzu_emu.utils.FreedrenoPresets
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class FreedrenoSettingsFragment : Fragment() {
@ -74,10 +75,15 @@ class FreedrenoSettingsFragment : Fragment() {
binding.toolbarFreedreno.setNavigationOnClickListener {
requireActivity().onBackPressedDispatcher.onBackPressed()
}
binding.toolbarFreedreno.title = getString(
if (isPerGameConfig) {
binding.toolbarFreedreno.title = getString(R.string.freedreno_per_game_title)
binding.toolbarFreedreno.subtitle = game!!.title
R.string.freedreno_per_game_title
} else {
R.string.freedreno_settings_title
}
)
binding.toolbarFreedreno.subtitle = null
}
private fun setupAdapters() {
@ -175,17 +181,19 @@ class FreedrenoSettingsFragment : Fragment() {
private fun setupWindowInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val systemInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
binding.root.updatePadding(
left = systemInsets.left,
right = systemInsets.right,
bottom = systemInsets.bottom
)
val barInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = insets.getInsets(WindowInsetsCompat.Type.displayCutout())
val leftInsets = barInsets.left + cutoutInsets.left
val rightInsets = barInsets.right + cutoutInsets.right
binding.appbarFreedreno.updateMargins(left = leftInsets, right = rightInsets)
binding.scrollFreedreno.updateMargins(left = leftInsets, right = rightInsets)
binding.scrollFreedreno.updatePadding(bottom = barInsets.bottom)
insets
}
}
private fun showSnackbar(message: String) {
private fun showSnackbar(message: String) {
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
@ -310,6 +310,21 @@ class GamePropertiesFragment : Fragment() {
)
)
if (!args.game.isHomebrew) {
add(
SubmenuProperty(
R.string.add_ons,
R.string.add_ons_description,
R.drawable.ic_edit,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
}
if (GpuDriverHelper.supportsCustomDriverLoading()) {
add(
SubmenuProperty(
@ -341,18 +356,6 @@ class GamePropertiesFragment : Fragment() {
}
if (!args.game.isHomebrew) {
add(
SubmenuProperty(
R.string.add_ons,
R.string.add_ons_description,
R.drawable.ic_edit,
action = {
val action = GamePropertiesFragmentDirections
.actionPerGamePropertiesFragmentToAddonsFragment(args.game)
binding.root.findNavController().navigate(action)
}
)
)
add(
InstallableProperty(
R.string.save_data,

View file

@ -1,9 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.fragments
import android.Manifest
@ -44,7 +41,9 @@ import org.yuzu.yuzu_emu.model.HomeSetting
import org.yuzu.yuzu_emu.model.HomeViewModel
import org.yuzu.yuzu_emu.ui.main.MainActivity
import org.yuzu.yuzu_emu.utils.FileUtil
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
class HomeSettingsFragment : Fragment() {
private var _binding: FragmentHomeSettingsBinding? = null
@ -71,8 +70,12 @@ class HomeSettingsFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
homeViewModel.setStatusBarShadeVisibility(visible = true)
homeViewModel.setStatusBarShadeVisibility(visible = false)
mainActivity = requireActivity() as MainActivity
binding.toolbarHomeSettings.setNavigationOnClickListener {
findNavController().popBackStack()
}
binding.toolbarHomeSettings.title = getString(R.string.preferences_settings)
val optionsList: MutableList<HomeSetting> = mutableListOf<HomeSetting>().apply {
add(
@ -144,6 +147,18 @@ class HomeSettingsFragment : Fragment() {
driverViewModel.selectedDriverTitle
)
)
if (GpuDriverHelper.isAdrenoGpu()) {
add(
HomeSetting(
R.string.freedreno_settings_title,
R.string.gpu_driver_settings,
R.drawable.ic_graphics,
{
binding.root.findNavController().navigate(R.id.freedrenoSettingsFragment)
}
)
)
}
add(
HomeSetting(
R.string.multiplayer,
@ -465,19 +480,22 @@ class HomeSettingsFragment : Fragment() {
}
private fun setInsets() =
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view, windowInsets ->
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, windowInsets ->
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
binding.appbarHomeSettings.updateMargins(
left = barInsets.left + cutoutInsets.left,
right = barInsets.right + cutoutInsets.right
)
binding.scrollViewSettings.updatePadding(
top = barInsets.top
bottom = barInsets.bottom
)
binding.homeSettingsList.updatePadding(
left = barInsets.left + cutoutInsets.left,
top = cutoutInsets.top,
right = barInsets.right + cutoutInsets.right,
bottom = barInsets.bottom
right = barInsets.right + cutoutInsets.right
)
windowInsets

View file

@ -18,7 +18,7 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
import java.util.concurrent.atomic.AtomicBoolean
class AddonViewModel : ViewModel() {
private val _patchList = MutableStateFlow(mutableListOf<Patch>())
private val _patchList = MutableStateFlow<List<Patch>>(emptyList())
val addonList get() = _patchList.asStateFlow()
private val _showModInstallPicker = MutableStateFlow(false)
@ -31,34 +31,62 @@ class AddonViewModel : ViewModel() {
val addonToDelete = _addonToDelete.asStateFlow()
var game: Game? = null
private var loadedGameKey: String? = null
private val isRefreshing = AtomicBoolean(false)
private val pendingRefresh = AtomicBoolean(false)
fun onOpenAddons(game: Game) {
fun onAddonsViewCreated(game: Game) {
this.game = game
refreshAddons()
refreshAddons(commitEmpty = false)
}
fun refreshAddons() {
if (isRefreshing.get() || game == null) {
fun onAddonsViewStarted(game: Game) {
this.game = game
val hasLoadedCurrentGame = loadedGameKey == gameKey(game)
refreshAddons(force = !hasLoadedCurrentGame)
}
fun refreshAddons(force: Boolean = false, commitEmpty: Boolean = true) {
val currentGame = game ?: return
val currentGameKey = gameKey(currentGame)
if (!force && loadedGameKey == currentGameKey) {
return
}
isRefreshing.set(true)
if (!isRefreshing.compareAndSet(false, true)) {
if (force) {
pendingRefresh.set(true)
}
return
}
viewModelScope.launch {
withContext(Dispatchers.IO) {
val patchList = (
NativeLibrary.getPatchesForFile(game!!.path, game!!.programId)
?: emptyArray()
).toMutableList()
try {
val patches = withContext(Dispatchers.IO) {
NativeLibrary.getPatchesForFile(currentGame.path, currentGame.programId)
} ?: return@launch
val patchList = patches.toMutableList()
patchList.sortBy { it.name }
// Ensure only one update is enabled
ensureSingleUpdateEnabled(patchList)
removeDuplicates(patchList)
if (patchList.isEmpty() && !commitEmpty) {
return@launch
}
if (gameKey(game ?: return@launch) != currentGameKey) {
return@launch
}
_patchList.value = patchList
_patchList.value = patchList.toList()
loadedGameKey = currentGameKey
} finally {
isRefreshing.set(false)
if (pendingRefresh.compareAndSet(true, false)) {
refreshAddons(force = true)
}
}
}
}
@ -119,28 +147,33 @@ class AddonViewModel : ViewModel() {
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
}
refreshAddons()
refreshAddons(force = true)
}
fun onCloseAddons() {
if (_patchList.value.isEmpty()) {
val currentGame = game ?: run {
_patchList.value = emptyList()
loadedGameKey = null
return
}
val currentList = _patchList.value
if (currentList.isEmpty()) {
_patchList.value = emptyList()
loadedGameKey = null
game = null
return
}
// Check if there are multiple update versions
val updates = _patchList.value.filter { PatchType.from(it.type) == PatchType.Update }
val hasMultipleUpdates = updates.size > 1
NativeConfig.setDisabledAddons(
game!!.programId,
_patchList.value.mapNotNull {
currentGame.programId,
currentList.mapNotNull {
if (it.enabled) {
null
} else {
if (PatchType.from(it.type) == PatchType.Update) {
if (it.name.contains("(NAND)") || it.name.contains("(SDMC)")) {
it.name
} else if (hasMultipleUpdates) {
} else if (it.numericVersion != 0L) {
"Update@${it.numericVersion}"
} else {
it.name
@ -152,7 +185,8 @@ class AddonViewModel : ViewModel() {
}.toTypedArray()
)
NativeConfig.saveGlobalConfig()
_patchList.value.clear()
_patchList.value = emptyList()
loadedGameKey = null
game = null
}
@ -163,4 +197,8 @@ class AddonViewModel : ViewModel() {
fun showModNoticeDialog(show: Boolean) {
_showModNoticeDialog.value = show
}
private fun gameKey(game: Game): String {
return "${game.programId}|${game.path}"
}
}

View file

@ -424,7 +424,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
)
val uriString = result.toString()
val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString }
val folder = gamesViewModel.folders.value.firstOrNull {
it.uriString == uriString && it.type == org.yuzu.yuzu_emu.model.DirectoryType.EXTERNAL_CONTENT
}
if (folder != null) {
Toast.makeText(
applicationContext,
@ -640,7 +642,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
}
}
addonViewModel.refreshAddons()
addonViewModel.refreshAddons(force = true)
val separator = System.lineSeparator() ?: "\n"
val installResult = StringBuilder()

View file

@ -51,11 +51,24 @@ object GameHelper {
// Scan External Content directories and register all NSP/XCI files
val externalContentDirs = NativeConfig.getExternalContentDirs()
for (externalDir in externalContentDirs) {
val uniqueExternalContentDirs = linkedSetOf<String>()
externalContentDirs.forEach { externalDir ->
if (externalDir.isNotEmpty()) {
uniqueExternalContentDirs.add(externalDir)
}
}
val mountedContainerUris = mutableSetOf<String>()
for (externalDir in uniqueExternalContentDirs) {
if (externalDir.isNotEmpty()) {
val externalDirUri = externalDir.toUri()
if (FileUtil.isTreeUriValid(externalDirUri)) {
scanExternalContentRecursive(FileUtil.listFiles(externalDirUri), 3)
scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) {
val containerUri = it.uri.toString()
if (mountedContainerUris.add(containerUri)) {
NativeLibrary.addFileToFilesystemProvider(containerUri)
}
}
}
}
}
@ -65,10 +78,13 @@ object GameHelper {
val gameDirUri = gameDir.uriString.toUri()
val isValid = FileUtil.isTreeUriValid(gameDirUri)
if (isValid) {
val scanDepth = if (gameDir.deepScan) 3 else 1
addGamesRecursive(
games,
FileUtil.listFiles(gameDirUri),
if (gameDir.deepScan) 3 else 1
scanDepth,
mountedContainerUris
)
} else {
badDirs.add(index)
@ -103,9 +119,10 @@ object GameHelper {
// be done better imo.
private val externalContentExtensions = setOf("nsp", "xci")
private fun scanExternalContentRecursive(
private fun scanContentContainersRecursive(
files: Array<MinimalDocumentFile>,
depth: Int
depth: Int,
onContainerFound: (MinimalDocumentFile) -> Unit
) {
if (depth <= 0) {
return
@ -113,14 +130,15 @@ object GameHelper {
files.forEach {
if (it.isDirectory) {
scanExternalContentRecursive(
scanContentContainersRecursive(
FileUtil.listFiles(it.uri),
depth - 1
depth - 1,
onContainerFound
)
} else {
val extension = FileUtil.getExtension(it.uri).lowercase()
if (externalContentExtensions.contains(extension)) {
NativeLibrary.addFileToFilesystemProvider(it.uri.toString())
onContainerFound(it)
}
}
}
@ -129,7 +147,8 @@ object GameHelper {
private fun addGamesRecursive(
games: MutableList<Game>,
files: Array<MinimalDocumentFile>,
depth: Int
depth: Int,
mountedContainerUris: MutableSet<String>
) {
if (depth <= 0) {
return
@ -140,11 +159,20 @@ object GameHelper {
addGamesRecursive(
games,
FileUtil.listFiles(it.uri),
depth - 1
depth - 1,
mountedContainerUris
)
} else {
if (Game.extensions.contains(FileUtil.getExtension(it.uri))) {
val game = getGame(it.uri, true)
val extension = FileUtil.getExtension(it.uri).lowercase()
val filePath = it.uri.toString()
if (externalContentExtensions.contains(extension) &&
mountedContainerUris.add(filePath)) {
NativeLibrary.addGameFolderFileToFilesystemProvider(filePath)
}
if (Game.extensions.contains(extension)) {
val game = getGame(it.uri, true, false)
if (game != null) {
games.add(game)
}
@ -153,14 +181,20 @@ object GameHelper {
}
}
fun getGame(uri: Uri, addedToLibrary: Boolean): Game? {
fun getGame(
uri: Uri,
addedToLibrary: Boolean,
registerFilesystemProvider: Boolean = true
): Game? {
val filePath = uri.toString()
if (!GameMetadata.getIsValid(filePath)) {
return null
}
if (registerFilesystemProvider) {
// Needed to update installed content information
NativeLibrary.addFileToFilesystemProvider(filePath)
}
var name = GameMetadata.getTitle(filePath)

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
package org.yuzu.yuzu_emu.utils
@ -80,17 +80,15 @@ object PathUtil {
}
}
// This really shouldn't be necessary, but the Android API seemingly
// doesn't have a way of doing this?
// Apparently, on certain devices the mount location can vary, so add
// extra cases here if we discover any new ones.
fun getRemovableStoragePath(idString: String): String? {
var pathFile: File
val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString")
pathFile = File("/mnt/media_rw/$idString");
for (mountPath in possibleMountPaths) {
val pathFile = File(mountPath);
if (pathFile.exists()) {
return pathFile.absolutePath
}
}
return null
}

View file

@ -33,6 +33,12 @@ void AndroidConfig::ReadAndroidValues() {
if (global) {
ReadAndroidUIValues();
ReadUIValues();
BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage));
Settings::values.ext_content_from_game_dirs = ReadBooleanSetting(
std::string("ext_content_from_game_dirs"),
std::make_optional(
Settings::values.ext_content_from_game_dirs.GetDefault()));
EndGroup();
ReadOverlayValues();
}
ReadDriverValues();

View file

@ -96,6 +96,11 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
return false;
}
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) &&
!Loader::IsBootableGameContainer(file, file_type)) {
return false;
}
u64 program_id = 0;
Loader::ResultStatus res = loader->ReadProgramId(program_id);
if (res != Loader::ResultStatus::Success) {

View file

@ -217,108 +217,9 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath)
return;
}
const auto extension = Common::ToLower(filepath.substr(filepath.find_last_of('.') + 1));
if (extension == "nsp") {
auto nsp = std::make_shared<FileSys::NSP>(file);
if (nsp->GetStatus() == Loader::ResultStatus::Success) {
std::map<u64, u32> nsp_versions;
std::map<u64, std::string> nsp_version_strings;
for (const auto& [title_id, nca_map] : nsp->GetNCAs()) {
for (const auto& [type_pair, nca] : nca_map) {
const auto& [title_type, content_type] = type_pair;
if (content_type == FileSys::ContentRecordType::Meta) {
const auto meta_nca = std::make_shared<FileSys::NCA>(nca->GetBaseFile());
if (meta_nca->GetStatus() == Loader::ResultStatus::Success) {
const auto section0 = meta_nca->GetSubdirectories();
if (!section0.empty()) {
for (const auto& meta_file : section0[0]->GetFiles()) {
if (meta_file->GetExtension() == "cnmt") {
FileSys::CNMT cnmt(meta_file);
nsp_versions[cnmt.GetTitleID()] = cnmt.GetTitleVersion();
}
}
}
}
}
if (content_type == FileSys::ContentRecordType::Control &&
title_type == FileSys::TitleType::Update) {
auto romfs = nca->GetRomFS();
if (romfs) {
auto extracted = FileSys::ExtractRomFS(romfs);
if (extracted) {
auto nacp_file = extracted->GetFile("control.nacp");
if (!nacp_file) {
nacp_file = extracted->GetFile("Control.nacp");
}
if (nacp_file) {
FileSys::NACP nacp(nacp_file);
auto ver_str = nacp.GetVersionString();
if (!ver_str.empty()) {
nsp_version_strings[title_id] = ver_str;
}
}
}
}
}
}
}
for (const auto& [title_id, nca_map] : nsp->GetNCAs()) {
for (const auto& [type_pair, nca] : nca_map) {
const auto& [title_type, content_type] = type_pair;
if (title_type == FileSys::TitleType::Update) {
u32 version = 0;
auto ver_it = nsp_versions.find(title_id);
if (ver_it != nsp_versions.end()) {
version = ver_it->second;
}
std::string version_string;
auto str_it = nsp_version_strings.find(title_id);
if (str_it != nsp_version_strings.end()) {
version_string = str_it->second;
}
m_manual_provider->AddEntryWithVersion(
title_type, content_type, title_id, version, version_string,
nca->GetBaseFile());
LOG_DEBUG(Frontend, "Added NSP update entry - TitleID: {:016X}, Version: {}, VersionStr: {}",
title_id, version, version_string);
} else {
// Use regular AddEntry for non-updates
m_manual_provider->AddEntry(title_type, content_type, title_id,
nca->GetBaseFile());
LOG_DEBUG(Frontend, "Added NSP entry - TitleID: {:016X}, TitleType: {}, ContentType: {}",
title_id, static_cast<int>(title_type), static_cast<int>(content_type));
}
}
}
if (m_manual_provider->AddEntriesFromContainer(file)) {
return;
}
}
// Handle XCI files
if (extension == "xci") {
FileSys::XCI xci{file};
if (xci.GetStatus() == Loader::ResultStatus::Success) {
const auto nsp = xci.GetSecurePartitionNSP();
if (nsp) {
for (const auto& title : nsp->GetNCAs()) {
for (const auto& entry : title.second) {
m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first,
entry.second->GetBaseFile());
}
}
}
return;
}
}
auto loader = Loader::GetLoader(m_system, file);
if (!loader) {
@ -339,6 +240,13 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath)
}
}
void EmulationSession::ConfigureFilesystemProviderFromGameFolder(const std::string& filepath) {
if (!Settings::values.ext_content_from_game_dirs.GetValue()) {
return;
}
ConfigureFilesystemProvider(filepath);
}
void EmulationSession::InitializeSystem(bool reload) {
if (!reload) {
// Initialize logging system
@ -1609,6 +1517,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* e
Common::Android::GetJString(env, jpath));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_addGameFolderFileToFilesystemProvider(
JNIEnv* env, jobject jobj, jstring jpath) {
EmulationSession::GetInstance().ConfigureFilesystemProviderFromGameFolder(
Common::Android::GetJString(env, jpath));
}
void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) {
EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
}

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -46,6 +49,7 @@ public:
const Core::PerfStatsResults& PerfStats();
int ShadersBuilding();
void ConfigureFilesystemProvider(const std::string& filepath);
void ConfigureFilesystemProviderFromGameFolder(const std::string& filepath);
void InitializeSystem(bool reload);
void SetAppletId(int applet_id);
Core::SystemResultStatus InitializeEmulation(const std::string& filepath,

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/colorSurface" />
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="?attr/colorOutline" />

View file

@ -0,0 +1,237 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<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"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingTop="16dp"
android:paddingHorizontal="16dp">
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="start|center_vertical"
android:text="@string/multiplayer_room_browser"
android:textAppearance="@style/TextAppearance.Material3.TitleLarge"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.card.MaterialCardView
android:id="@+id/search_background"
style="?attr/materialCardViewFilledStyle"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginEnd="16dp"
android:layout_weight="1"
app:cardBackgroundColor="?attr/colorSurfaceVariant"
app:cardCornerRadius="24dp">
<LinearLayout
android:id="@+id/search_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:orientation="horizontal">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:contentDescription="@string/home_search"
android:src="@drawable/ic_search"
app:tint="?attr/colorOnSurfaceVariant" />
<EditText
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:autofillHints=""
android:background="@android:color/transparent"
android:hint="@string/multiplayer_search_public_lobbies"
android:imeOptions="flagNoFullscreen"
android:inputType="text"
android:maxLines="1"
android:textColor="?attr/colorOnSurface" />
</LinearLayout>
<ImageView
android:id="@+id/clear_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="48dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/clear"
android:src="@drawable/ic_clear"
android:visibility="invisible"
app:tint="?attr/colorOnSurfaceVariant"
tools:visibility="visible" />
<ImageView
android:id="@+id/btn_submit"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical|end"
android:layout_marginEnd="16dp"
android:background="?attr/selectableItemBackground"
android:contentDescription="@string/submit"
android:src="@drawable/ic_send"
app:tint="?attr/colorOnSurfaceVariant"
tools:visibility="visible" />
</com.google.android.material.card.MaterialCardView>
<FrameLayout
android:layout_width="48dp"
android:layout_height="48dp">
<com.google.android.material.button.MaterialButton
android:id="@+id/refresh_button"
style="@style/Widget.Material3.Button.IconButton"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:text="@string/refresh"
app:icon="@drawable/ic_refresh" />
<ProgressBar
android:id="@+id/progress_bar"
style="?android:attr/progressBarStyleSmall"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:visibility="gone" />
</FrameLayout>
</LinearLayout>
<HorizontalScrollView
android:id="@+id/horizontalScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginVertical="8dp"
android:clipToPadding="false"
android:fadingEdge="horizontal"
android:paddingHorizontal="16dp"
android:scrollbars="none">
<LinearLayout
android:id="@+id/chips"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false">
<com.google.android.material.chip.Chip
android:id="@+id/chip_hide_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:checkable="true"
android:checked="false"
android:paddingStart="8dp"
android:paddingTop="6dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp"
android:text="@string/multiplayer_hide_empty_rooms"
app:chipCornerRadius="16dp"
app:chipIconSize="18dp"
app:chipIconTint="?attr/colorOnSurface" />
<com.google.android.material.chip.Chip
android:id="@+id/chip_hide_full"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:checkable="true"
android:checked="false"
android:paddingStart="8dp"
android:paddingTop="6dp"
android:paddingEnd="8dp"
android:paddingBottom="6dp"
android:text="@string/multiplayer_hide_full_rooms"
app:chipCornerRadius="16dp"
app:chipIconSize="18dp"
app:chipIconTint="?attr/colorOnSurface" />
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/room_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:contentDescription="@string/room_list"
android:paddingBottom="16dp"
android:scrollbars="vertical"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<LinearLayout
android:id="@+id/empty_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:orientation="vertical"
android:padding="32dp"
android:visibility="gone">
<ImageView
android:layout_width="72dp"
android:layout_height="72dp"
android:layout_marginBottom="16dp"
android:alpha="0.5"
android:contentDescription="@string/refresh"
android:src="@drawable/ic_refresh"
app:tint="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/multiplayer_no_rooms_found"
android:textAppearance="@style/TextAppearance.Material3.TitleMedium"
android:textColor="?attr/colorOnSurface" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@string/multiplayer_tap_refresh_to_check_again"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.button.MaterialButton
android:id="@+id/empty_refresh_button"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="@string/refresh"
app:icon="@drawable/ic_refresh" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/theme_dialog_background"
android:orientation="vertical">
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
android:id="@+id/drag_handle"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginEnd="20dp"
android:layout_weight="0.75">
<ImageView
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_gravity="center"
android:contentDescription="@string/multiplayer"
android:src="@drawable/ic_network"
app:tint="?attr/colorPrimary" />
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1.25"
android:orientation="vertical">
<TextView
android:id="@+id/text_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_marginBottom="16dp"
android:gravity="center"
android:text="@string/multiplayer"
android:textAppearance="?attr/textAppearanceHeadline6"
android:textColor="?attr/colorOnSurface" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_lobby_browser"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_public_room"
android:textColor="?attr/colorOnPrimary"
app:backgroundTint="?attr/colorPrimary"
app:cornerRadius="16dp"
app:icon="@drawable/ic_search"
app:iconPadding="12dp"
app:iconTint="?attr/colorOnPrimary" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_join"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_join_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_install"
app:iconPadding="12dp" />
<Space
android:layout_width="16dp"
android:layout_height="match_parent" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_create"
style="@style/Widget.Material3.Button.ElevatedButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:minHeight="56dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:text="@string/multiplayer_create_room"
app:cornerRadius="16dp"
app:icon="@drawable/ic_add"
app:iconPadding="12dp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View file

@ -44,7 +44,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="4dp"
>
@ -103,7 +108,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@ -127,7 +137,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@ -151,7 +166,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>

View file

@ -12,11 +12,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
@ -29,7 +34,6 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
@ -52,31 +56,40 @@
</LinearLayout>
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
android:layout_marginTop="10dp"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
app:icon="@drawable/ic_import"
tools:visibility="visible" />
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
app:icon="@drawable/ic_export"
tools:visibility="visible" />
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -5,6 +5,7 @@
android:id="@+id/coordinator_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
>
<com.google.android.material.appbar.AppBarLayout

View file

@ -7,9 +7,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true">
android:focusable="true"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"

View file

@ -2,11 +2,15 @@
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="?attr/materialCardViewOutlinedStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"

View file

@ -27,10 +27,10 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="14dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingBottom="6dp">
android:paddingTop="4dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="2dp">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/image_game_screen"
@ -48,11 +48,14 @@
style="@style/SynthwaveText.Body"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="2dp"
android:gravity="center"
android:requiresFadingEdge="horizontal"
android:textAlignment="center"
android:textSize="14sp"
android:textStyle="bold"
android:maxLines="1"
android:ellipsize="end"
app:layout_constraintEnd_toEndOf="@+id/image_game_screen"
app:layout_constraintStart_toStartOf="@+id/image_game_screen"
app:layout_constraintTop_toBottomOf="@+id/image_game_screen"

View file

@ -27,10 +27,10 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="14dp"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:paddingBottom="6dp">
android:paddingTop="3dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:paddingBottom="3dp">
<FrameLayout
android:id="@+id/image_container"

View file

@ -11,7 +11,7 @@
android:transitionName="card_game"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/eden_card_background"
app:cardBackgroundColor="@android:color/transparent"
app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
@ -27,6 +27,8 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
app:strokeColor="@color/eden_card_background"
app:strokeWidth="4dp"
tools:src="@drawable/default_icon" />
<com.google.android.material.textview.MaterialTextView

View file

@ -8,9 +8,14 @@
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginHorizontal="8dp"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardCornerRadius="16dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:id="@+id/option_layout"
@ -60,6 +65,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="viewStart"
android:textColor="?attr/colorPrimary"
android:textSize="14sp"
android:textStyle="bold"
android:singleLine="true"

View file

@ -2,11 +2,15 @@
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
@ -42,12 +46,18 @@
</LinearLayout>
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center_horizontal"
android:orientation="vertical">
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"
@ -56,11 +66,10 @@
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="12dp"
android:layout_marginTop="12dp"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
@ -69,4 +78,6 @@
</LinearLayout>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>

View file

@ -6,17 +6,27 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp">
android:layout_marginVertical="12dp"
android:background="@android:color/transparent"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal"
android:gravity="center_vertical"
android:orientation="vertical"
android:paddingHorizontal="24dp"
android:paddingVertical="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:id="@+id/icon"
android:layout_width="24dp"
@ -29,7 +39,6 @@
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:layout_weight="1"
android:orientation="vertical">
@ -52,17 +61,20 @@
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_marginTop="10dp"
android:gravity="end|center_vertical"
android:orientation="horizontal">
<Button
android:id="@+id/button_install"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:contentDescription="@string/string_import"
android:tooltipText="@string/string_import"
android:visibility="gone"
@ -71,11 +83,10 @@
<Button
android:id="@+id/button_export"
style="@style/Widget.Material3.Button.IconButton.Filled.Tonal"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="8dp"
android:layout_marginStart="12dp"
android:contentDescription="@string/export"
android:tooltipText="@string/export"
android:visibility="gone"

View file

@ -7,9 +7,13 @@
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:background="?attr/selectableItemBackground"
android:background="@android:color/transparent"
android:clickable="true"
android:focusable="true">
android:focusable="true"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
@ -81,14 +85,15 @@
android:visibility="gone"
tools:visibility="visible" />
<com.google.android.material.chip.ChipGroup
<LinearLayout
android:id="@+id/layoutSecondaryActions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="end|center_vertical"
android:orientation="horizontal"
android:paddingHorizontal="24dp"
android:paddingVertical="8dp"
android:visibility="gone"
app:singleLine="false"
tools:visibility="visible" />
</LinearLayout>

View file

@ -8,16 +8,14 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorSurface"
android:elevation="0dp">
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_scrollFlags="scroll|enterAlways|snap">
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"

View file

@ -59,8 +59,11 @@
android:layout_marginBottom="16dp"
android:text="@string/multiplayer_public_room"
app:cornerRadius="16dp"
app:backgroundTint="?attr/colorPrimary"
app:icon="@drawable/ic_search"
app:iconPadding="12dp" />
app:iconPadding="12dp"
app:iconTint="?attr/colorOnPrimary"
android:textColor="?attr/colorOnPrimary" />
<Space
android:layout_width="20dp"

View file

@ -5,6 +5,7 @@
android:id="@+id/coordinator_about"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
>
<com.google.android.material.appbar.AppBarLayout
@ -51,12 +52,15 @@
android:src="@drawable/ic_yuzu" />
<com.google.android.material.card.MaterialCardView
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="16dp"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -84,14 +88,17 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/button_contributors"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -119,14 +126,17 @@
<com.google.android.material.card.MaterialCardView
android:id="@+id/button_licenses"
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="12dp"
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp">
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@ -161,7 +171,7 @@
android:clickable="true"
android:focusable="true"
app:cardCornerRadius="16dp"
app:cardBackgroundColor="?attr/colorSurface"
app:cardBackgroundColor="@android:color/transparent"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:cardElevation="0dp">

View file

@ -8,6 +8,7 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_addons"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@ -18,6 +19,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_addons"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -8,6 +8,7 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_applets"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@ -15,6 +16,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_applets"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -7,19 +7,22 @@
android:layout_height="match_parent"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_drivers"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:liftOnScrollTargetViewId="@id/list_drivers">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_drivers"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -13,14 +13,15 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_drivers"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:liftOnScrollTargetViewId="@id/list_drivers">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_drivers"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -12,14 +12,15 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_folders"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:liftOnScrollTargetViewId="@id/list_folders">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_folders"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -8,35 +8,24 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_freedreno"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_freedreno_layout"
style="?attr/collapsingToolbarLayoutMediumStyle"
android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorSurface"
app:scrimVisibleHeightTrigger="100dp">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_freedreno"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_back"
app:title="@string/gpu_driver_settings" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_freedreno"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
@ -63,8 +52,12 @@
android:id="@+id/list_freedreno_presets"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="6dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:paddingBottom="8dp"
android:scrollbars="horizontal"
android:scrollbarStyle="outsideInset"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
<!-- Current Settings Section -->
@ -135,22 +128,23 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="16dp"
android:spacing="8dp">
android:orientation="horizontal">
<Button
android:id="@+id/button_clear_all"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_weight="1"
android:text="@string/freedreno_clear_all"
style="?attr/materialButtonOutlinedStyle" />
style="?attr/materialButtonOutlinedStyle"
android:text="@string/freedreno_clear_all" />
<Button
android:id="@+id/button_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_weight="1"
android:text="@string/save" />
@ -161,6 +155,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeWidth="1dp"
app:strokeColor="?attr/colorOutline">

View file

@ -33,9 +33,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_back"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
@ -44,9 +47,12 @@
style="?attr/materialIconButtonStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:backgroundTint="@android:color/transparent"
app:icon="@drawable/ic_shortcut"
app:iconSize="24dp"
app:iconTint="?attr/colorOnSurface"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />

View file

@ -37,7 +37,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@ -61,7 +66,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@ -85,7 +95,12 @@
style="@style/EdenCard"
android:layout_width="42dp"
android:layout_height="42dp"
android:background="@android:color/transparent"
app:cardCornerRadius="21dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="8dp"
>
@ -117,7 +132,12 @@
style="@style/EdenCard"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="@android:color/transparent"
app:cardCornerRadius="24dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:padding="4dp"
>

View file

@ -1,30 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scroll_view_settings"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
android:fadeScrollbars="false"
android:background="?attr/colorSurface">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_home_settings"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_home_settings"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:navigationIcon="@drawable/ic_back"
app:title="@string/preferences_settings" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:id="@+id/scroll_view_settings"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/transparent"
android:clipToPadding="false"
android:background="?attr/colorSurface"
android:defaultFocusHighlightEnabled="false">
android:defaultFocusHighlightEnabled="false"
android:fadeScrollbars="false"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/appbar_home_settings">
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/linear_layout_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="16dp">
<ImageView
android:id="@+id/logo_image"
android:layout_width="120dp"
android:layout_height="120dp"
android:layout_marginTop="48dp"
android:layout_marginBottom="24dp"
android:layout_gravity="center_horizontal"
android:src="@drawable/ic_yuzu" />
android:paddingHorizontal="16dp"
android:paddingTop="16dp">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/home_settings_list"
@ -35,4 +59,6 @@
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.core.widget.NestedScrollView>
</androidx.core.widget.NestedScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,6 +8,7 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_installables"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
@ -15,6 +16,7 @@
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_installables"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"

View file

@ -10,12 +10,14 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_profiles"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:title="@string/profile_manager"

View file

@ -8,31 +8,20 @@
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appbar_settings"
style="@style/Widget.Eden.TransparentTopAppBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fitsSystemWindows="true"
android:touchscreenBlocksFocus="false"
app:elevation="0dp">
<com.google.android.material.appbar.CollapsingToolbarLayout
android:id="@+id/toolbar_settings_layout"
style="?attr/collapsingToolbarLayoutMediumStyle"
android:layout_width="match_parent"
android:layout_height="?attr/collapsingToolbarLayoutMediumSize"
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
app:contentScrim="?attr/colorSurface"
app:scrimVisibleHeightTrigger="100dp">
android:touchscreenBlocksFocus="false">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar_settings"
style="@style/Widget.Eden.TransparentTopToolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:touchscreenBlocksFocus="false"
app:layout_collapseMode="pin"
app:navigationIcon="@drawable/ic_back" />
</com.google.android.material.appbar.CollapsingToolbarLayout>
</com.google.android.material.appbar.AppBarLayout>
<androidx.recyclerview.widget.RecyclerView

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.button.MaterialButton xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
style="@style/Widget.Material3.Button.IconButton.Filled"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="12dp" />

View file

@ -11,8 +11,11 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="12dp"
app:cardElevation="2dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
@ -78,8 +81,11 @@
android:layout_width="48dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
app:cardBackgroundColor="@android:color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="2dp"
app:cardElevation="0dp"
app:strokeColor="?attr/colorOutline"
app:strokeWidth="1dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless"
@ -100,7 +106,7 @@
android:layout_gravity="center"
android:background="@null"
android:src="@drawable/ic_delete"
app:tint="@color/eden_border_gradient_end"
app:tint="?attr/colorPrimary"
android:contentDescription="@string/delete" />
</FrameLayout>

View file

@ -40,6 +40,10 @@
<action
android:id="@+id/action_global_settingsActivity"
app:destination="@id/settingsActivity" />
app:destination="@id/settingsActivity"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
</navigation>

View file

@ -101,7 +101,11 @@
<action
android:id="@+id/action_global_settingsActivity"
app:destination="@id/settingsActivity" />
app:destination="@id/settingsActivity"
app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
<fragment
android:id="@+id/installableFragment"
android:name="org.yuzu.yuzu_emu.fragments.InstallableFragment"

View file

@ -191,6 +191,22 @@
<item name="android:textColor">@color/eden_primary</item>
<item name="rippleColor">@color/eden_glow_pink</item>
</style>
<style name="Widget.Eden.TransparentTopAppBarLayout" parent="">
<item name="android:background">@android:color/transparent</item>
<item name="android:elevation">0dp</item>
<item name="android:stateListAnimator">@null</item>
<item name="elevation">0dp</item>
<item name="liftOnScroll">false</item>
<item name="statusBarForeground">@android:color/transparent</item>
</style>
<style name="Widget.Eden.TransparentTopToolbar" parent="">
<item name="android:background">@android:color/transparent</item>
<item name="android:elevation">0dp</item>
<item name="backgroundTint">@android:color/transparent</item>
</style>
<style name="EdenPopupMenu" parent="Widget.Material3.PopupMenu">
<item name="android:popupBackground">@drawable/popup_menu_background</item>
</style>

View file

@ -1,4 +1,4 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2018 yuzu Emulator Project
@ -256,4 +256,10 @@ else()
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
endif()
if(PLATFORM_PS4)
target_sources(audio_core PRIVATE
sink/ps4_sink.cpp
sink/ps4_sink.h)
endif()
create_target_directory_groups(audio_core)

View file

@ -0,0 +1,156 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <span>
#include <stop_token>
#include <vector>
#include <orbis/AudioOut.h>
#include "audio_core/common/common.h"
#include "audio_core/sink/ps4_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "core/core.h"
namespace AudioCore::Sink {
/// @brief PS4 sink stream, responsible for sinking samples to hardware.
struct PS4SinkStream final : public SinkStream {
/// @brief Create a new sink stream.
/// @param device_channels_ - Number of channels supported by the hardware.
/// @param system_channels_ - Number of channels the audio systems expect.
/// @param output_device - Name of the output device to use for this stream.
/// @param input_device - Name of the input device to use for this stream.
/// @param type_ - Type of this stream.
/// @param system_ - Core system.
/// @param event - Event used only for audio renderer, signalled on buffer consume.
PS4SinkStream(u32 device_channels_, u32 system_channels_, const std::string& output_device, const std::string& input_device, StreamType type_, Core::System& system_)
: SinkStream{system_, type_}
{
system_channels = system_channels_;
device_channels = device_channels_;
auto const length = 0x800;
auto const sample_rate = 48000;
auto const num_channels = this->GetDeviceChannels();
output_buffer.resize(length * num_channels * sizeof(s16));
auto const param_type = num_channels == 1 ? ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO : ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO;
audio_dev = sceAudioOutOpen(ORBIS_USER_SERVICE_USER_ID_SYSTEM, ORBIS_AUDIO_OUT_PORT_TYPE_MAIN, 0, length, sample_rate, param_type);
if (audio_dev > 0) {
audio_thread = std::jthread([=, this](std::stop_token stop_token) {
while (!stop_token.stop_requested()) {
if (this->type == StreamType::In) {
// this->ProcessAudioIn(input_buffer, length);
} else {
sceAudioOutOutput(audio_dev, nullptr);
this->ProcessAudioOutAndRender(output_buffer, length);
sceAudioOutOutput(audio_dev, output_buffer.data());
}
}
});
} else {
LOG_ERROR(Service_Audio, "Failed to create audio device! {:#x}", uint32_t(audio_dev));
}
}
~PS4SinkStream() override {
LOG_DEBUG(Service_Audio, "Destroying PS4 stream {}", name);
sceAudioOutClose(audio_dev);
if (audio_thread.joinable()) {
audio_thread.request_stop();
audio_thread.join();
}
}
void Finalize() override {
if (audio_dev > 0) {
Stop();
sceAudioOutClose(audio_dev);
}
}
void Start(bool resume = false) override {
if (audio_dev > 0 && paused) {
paused = false;
}
}
void Stop() override {
if (audio_dev > 0 && !paused) {
}
}
std::vector<s16> output_buffer;
std::jthread audio_thread;
int32_t audio_dev{};
};
PS4Sink::PS4Sink(std::string_view target_device_name) {
int32_t rc = sceAudioOutInit();
if (rc == 0 || unsigned(rc) == ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
if (target_device_name != auto_device_name && !target_device_name.empty()) {
output_device = target_device_name;
} else {
output_device.clear();
}
device_channels = 2;
} else {
LOG_ERROR(Service_Audio, "Unable to open audio out! {:#x}", uint32_t(rc));
}
}
PS4Sink::~PS4Sink() = default;
/// @brief Create a new sink stream.
/// @param system - Core system.
/// @param system_channels - Number of channels the audio system expects. May differ from the device's channel count.
/// @param name - Name of this stream.
/// @param type - Type of this stream, render/in/out.
/// @return A pointer to the created SinkStream
SinkStream* PS4Sink::AcquireSinkStream(Core::System& system, u32 system_channels_, const std::string&, StreamType type) {
system_channels = system_channels_;
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<PS4SinkStream>(device_channels, system_channels, output_device, input_device, type, system));
return stream.get();
}
void PS4Sink::CloseStream(SinkStream* stream) {
for (size_t i = 0; i < sink_streams.size(); i++) {
if (sink_streams[i].get() == stream) {
sink_streams[i].reset();
sink_streams.erase(sink_streams.begin() + i);
break;
}
}
}
void PS4Sink::CloseStreams() {
sink_streams.clear();
}
f32 PS4Sink::GetDeviceVolume() const {
return sink_streams.size() > 0 ? sink_streams[0]->GetDeviceVolume() : 1.f;
}
void PS4Sink::SetDeviceVolume(f32 volume) {
for (auto& stream : sink_streams)
stream->SetDeviceVolume(volume);
}
void PS4Sink::SetSystemVolume(f32 volume) {
for (auto& stream : sink_streams)
stream->SetSystemVolume(volume);
}
std::vector<std::string> ListPS4SinkDevices(bool capture) {
return {{"Default"}};
}
u32 GetPS4Latency() {
return TargetSampleCount * 2;
}
} // namespace AudioCore::Sink

View file

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <vector>
#include "audio_core/sink/sink.h"
namespace Core {
class System;
}
namespace AudioCore::Sink {
class SinkStream;
/// @brief PS4 backend sink, holds multiple output streams and is responsible for sinking samples to
/// hardware. Used by Audio Render, Audio In and Audio Out.
struct PS4Sink final : public Sink {
explicit PS4Sink(std::string_view device_id);
~PS4Sink() override;
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels, const std::string& name, StreamType type) override;
void CloseStream(SinkStream* stream) override;
void CloseStreams() override;
f32 GetDeviceVolume() const override;
void SetDeviceVolume(f32 volume) override;
void SetSystemVolume(f32 volume) override;
/// Name of the output device used by streams
std::string output_device;
/// Name of the input device used by streams
std::string input_device;
/// Vector of streams managed by this sink
std::vector<SinkStreamPtr> sink_streams;
};
std::vector<std::string> ListPS4SinkDevices(bool capture);
u32 GetPS4Latency();
} // namespace AudioCore::Sink

View file

@ -19,6 +19,9 @@
#ifdef HAVE_SDL2
#include "audio_core/sink/sdl2_sink.h"
#endif
#ifdef __OPENORBIS__
#include "audio_core/sink/ps4_sink.h"
#endif
#include "audio_core/sink/null_sink.h"
#include "common/logging/log.h"
#include "common/settings_enums.h"
@ -51,6 +54,16 @@ struct SinkDetails {
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef __OPENORBIS__
SinkDetails{
Settings::AudioEngine::Ps4,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<PS4Sink>(device_id);
},
&ListPS4SinkDevices,
&GetPS4Latency,
},
#endif
#ifdef HAVE_OBOE
SinkDetails{
Settings::AudioEngine::Oboe,
@ -115,7 +128,9 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
// causes audio issues, in that case go with SDL.
#if defined(HAVE_CUBEB) && defined(HAVE_SDL2)
#if defined(__OPENORBIS__)
iter = find_backend(Settings::AudioEngine::Ps4);
#elif defined(HAVE_CUBEB) && defined(HAVE_SDL2)
iter = find_backend(Settings::AudioEngine::Cubeb);
if (iter->latency() > TargetSampleCount * 3) {
iter = find_backend(Settings::AudioEngine::Sdl2);

View file

@ -16,7 +16,7 @@
namespace Common {
#ifdef __OPENORBIS__
constexpr size_t DEFAULT_STACK_SIZE = 128 * 4096;
constexpr size_t DEFAULT_STACK_SIZE = 32 * 4096;
#else
constexpr size_t DEFAULT_STACK_SIZE = 512 * 4096;
#endif

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -171,11 +174,14 @@ bool CreateDir(const fs::path& path) {
return false;
}
// TODO: Maybe this is what causes death?
#ifndef __OPENORBIS__
if (!Exists(path.parent_path())) {
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
PathToUTF8String(path));
return false;
}
#endif
if (IsDir(path)) {
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",

View file

@ -130,6 +130,10 @@ public:
ASSERT(!eden_path.empty());
eden_path_cache = eden_path / CACHE_DIR;
eden_path_config = eden_path / CONFIG_DIR;
#elif defined(__OPENORBIS__)
eden_path = "/data/eden";
eden_path_cache = eden_path / CACHE_DIR;
eden_path_config = eden_path / CONFIG_DIR;
#else
eden_path = GetCurrentDir() / PORTABLE_DIR;
if (!Exists(eden_path) || !IsDir(eden_path)) {

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