Compare commits

...

41 Commits

Author SHA1 Message Date
lizzie f1fdb389a4 fix movaps being evil 2026-05-24 19:03:16 +00:00
lizzie 21bb1b8210 [dynarmic] VEX encode movd/movq
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-05-24 18:47:11 +00:00
Eden CI 0d736d49d6 [dist, android] Update translations from Transifex for May 23 (#4007)
Automatic translation update for May 23

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4007
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-24 01:46:29 +02:00
lizzie 0c74a495f5 [video_core/host_shaders] add Snapdragon GSRv1 fragment shaders (#3307)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Co-authored-by: CamilleLaVey <camillelavey99@gmail.com>
Co-authored-by: xbzk <xbzk@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3307
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:38:19 +02:00
maufeat c6afeb2bf8 [nvnflinger] Add case for DefaultDataSpace (#3956)
Amaterasu from Discord asked about why nvnWindowGetNumActiveTextures returns 0 - after researching the console output it was asking for `DefaultDataSpace` (enum val 12) after some tests with the mod and debugging the console, this is my one-liner solution.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3956
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:05:29 +02:00
lizzie d9067d85af [tools] add separate maxwell disassembler, ir dumper, and spirv translator (#3453)
why not?

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3453
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:05:07 +02:00
lizzie 2aa2ac7d9a [hle/service{nvdrv,apm}] fixes for TetrisSwitch (#3983)
- testriswitch submits buffers with a fence id of -1, just skip them instead of trying to process them?
- apm:u, which is removed, but hey, backwards compat never hurted
- another instance of shared_memory crashing NPad

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3983
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:04:32 +02:00
lizzie 90164197dc [dist] Restore normal icon (#3990)
Anniversary is over!

May the next one be as silly :3

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3990
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:03:45 +02:00
MaranBr 573e06131d [texture_cache] Fix a rare visual corruption under specific conditions (#3986)
This fixes a rare visual corruption that can occur under specific conditions depending on the hardware used.

This bug is known to affect the loading screens in The Legend of Zelda: Tears of the Kingdom.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3986
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:03:20 +02:00
MaranBr 06c8926a2e [video_core] Fix initial DMA sync deadlock in OpenGL by initializing synced state (#3987)
This fixes a deadlock issue that prevents any game using OpenGL + GPU Accurate from booting when Sync Memory Operations is enabled.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3987
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-05-24 01:02:19 +02:00
xbzk eabd1017cc [fence_manager, ui] antiflicker fix + toggle integration (#4004)
tldr: we (me and maran) found the missing piece to make delay_fence and should_flush coop and cover all remaining flicker issues tested so far.
the lil change is in src/video_core/fence_manager.h
the rest is toggle stuff.

END

(credits rolls up)

post credits scene for the toggle drama:

i've been forced to use custom builds for around 1 year now, coz gpu mode above fast was pulling performance down yet not covering flicker entirely in most games tested. and we know that it's a mess to rely on gpu mode as it brings along a bunch of undesired stuff.
i need this toggle. and i've seem far less relevant before, so hey, gimme this one so i can call it mine :3

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4004
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-24 01:02:01 +02:00
fl.gs b870bd255c [android] config: load configuration on game start (#3965)
This PR reloads Android configuration when starting a game, so Eden uses the latest config.ini state for the emulation session.

On some Android launchers, Eden can already be running in the background before a game is launched. In that case, config.ini has already been read, so configuration changes made outside of Eden's settings flow while the process is alive are not picked up by the next emulation session.

This improves launch/config behavior for external launcher workflows.

Co-authored-by: FL-gs <efge.crea@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3965
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-23 21:19:34 +02:00
lizzie 37b5cf6003 [audio_core, hle, video_core] force inline of functions that only contain thread loops (#3970)
traditionally, when doing jthread:

```
jthread() calls function parameter operator()() with args
function operator()() calls the code within
code within is, say { ThreadMain(); }
3 calls because why not
```

now this just makes it be 2 calls, mainly benefits non-LTO builds

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3970
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-23 21:16:28 +02:00
lost-chaos d761ecba8c [core/arm/nce] suppress unused variable warnings (#4002)
Add `[[maybe_unused]]` to unused constants in the ARM NCE backend to suppress compiler warnings.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4002
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-23 15:31:23 +02:00
xbzk 83683440b2 [net] ban api.epicgames.dev domain (#3999)
Adding 'api.epicgames.dev' to the banlist, as instructed by lizzie.

MCI insists on connection and randomly crashes at Network::Poll(...).
Airplane mode would do, but then the DLC gets unavailable.

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3999
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-05-22 22:48:15 +02:00
lizzie 9b18d0b111 [tools] refactor, use #!/bin/sh, update license files (#3998)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3998
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-22 21:15:31 +02:00
lizzie 46cfd9b6f3 [net] support SCTP protocols (+all base FBSD protos), ban more NS domains (#3955)
bans more NS domains making hb dns check pass

also fixes bogus "SCTP is not implemented" assertion for translate protocol

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3955
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-21 21:24:18 +02:00
lizzie 889545e1ee [common/virtual_buffer] fix technically wrong usage of std::exchange() (#3992)
simpleish fix https://en.cppreference.com/cpp/utility/exchange

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3992
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-21 03:18:41 +02:00
crueter 24dc3834b6 [desktop] Fix YUZU_USE_QT_MULTIMEDIA compilation (#3993)
Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3993
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-21 03:06:04 +02:00
RedBlackAka 2a66b40267 [common/cpu_detect] Remove SSE/SSE2/FMA4/AVX_VNNI detection (#3979)
Removes Eden's own feature detection for SSE, SSE2, FMA4 and AVX_VNNI, in order to clean up code and make the function slightly lighter. They are all unused and I have specific reasons for their removal:
- SSE/SSE2 are always true for x64
- FMA4 is a deprecated AMD exclusive extension, replaced by the regular FMA and was logged here as "FMA" for no reason
- AVX_VNNI simply does not seem applicable for Eden (but can still be checked for through Xbyak's feature detection if necessary)

Co-authored-by: RedBlackAka <140876408+RedBlackAka@users.noreply.github.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3979
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-20 19:11:09 +02:00
crueter feb8c5f88e [desktop] More qt_common reorganization (#3916)
Ported from QML branch.

Main "big" change is that EmuThread is now a shared state in QtCommon,
not individually managed/passed around by GRenderWindow and MainWindow.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3916
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-20 04:49:16 +02:00
lizzie 300a646a34 [hle] make HBLoader work, add -hlaunch option (#3981)
hbloader is required to launch a bunch of shit (particularly hbmenu)

however due to some restrictive metadata validation, it doesn't get recognized as an NSP file

programs like hbmenu require hbloader (since it feeds them data like ConfigEntries and whatnot), launching hbmenu as-is standalone will result in a launchInit() error

adds an option to launch hbmenu via command line

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3981
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-19 23:35:53 +02:00
lizzie e875a3196b [core/hle/services/sockets] allow 'valid' range from [16,255] for IPv4 (#3491)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3491
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-18 23:54:47 +02:00
lizzie 4eb082485d [video_core] fix odr violation in formatter for pixelFormat (#3504)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3504
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-18 23:54:07 +02:00
lizzie 7455854528 [core/memory] remove duplicates from template when unsafe=T/F, remove increment, remove sad path for exception code on cache op (#3972)
Ideally this should increase perf when doing write/read operations
not by a lot, just enough for it not to suck so much as it does right now

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3972
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-05-18 23:28:01 +02:00
crueter 5ab0227624 [cmake] Fix reversed YUZU_USE_BUNDLED_SDL3 (#3980)
oops

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3980
2026-05-18 21:44:29 +02:00
Kaydax ad2e1cc554 [externals] Update to SDL3 (#3952)
Since the launch of the steam controller I think it's only best to push towards updating to SDL3 allowing for a wider range of controller support

I went ahead and started on getting it working. Everything here should be functional, I've personally tested it all on Arch Linux. Still untested on windows, so looking for feedback on that

Any feedback and help would be appreciated!

Main changes:
- Bump everything to SDL3
- Handle SDL3 audio and input
- Add steam controller support, including HD Rumble
- Improved battery reporting via the status icon by using real % rather than state alone

Co-authored-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3952
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-05-18 19:07:41 +02:00
Marcin Serwin 02521882e7 [dynarmic] drop Xeon Phi features from tests (#3978)
xbyak 7.37 dropped support for them, see
<https://github.com/herumi/xbyak/commit/a33007c908022b46b1a982afe649ded73a15219e>
and <https://github.com/herumi/xbyak/pull/244>.

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3978
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
2026-05-18 17:31:52 +02:00
lizzie 9a7ca3aca4 [dynarmic] fix NetBSD context.h compile error (#3966)
On NetBSD it stupidly aligns the stack acounting for the amd64 redzone.

This isn't... required, to put it lightly.

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3966
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-18 02:09:33 +02:00
crueter ca6bb3ae1d [cmake, dist] Update udev rule to act on all joysticks, and add install option (#3968)
This is needed for gyro access.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3968
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-17 23:44:57 +02:00
crueter 50df88106e [externals] Remove httplib minimum version spec (#3967)
For some Godforsaken reason it uses SameMinorVersion.

Signed-off-by: crueter <crueter@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3967
Reviewed-by: Lizzie <lizzie@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-17 22:54:32 +02:00
Eden CI 945ea630b4 [dist, android] Update translations from Transifex for May 16 (#3960)
Automatic translation update for May 16

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3960
2026-05-17 22:45:59 +02:00
lizzie 5aba461cb3 [common/wall_clock] fix invariant RDTSC divide by 0 (#3961)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3961
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-17 02:17:11 +02:00
lizzie 8330940eca [docs] add CodingStyle + Coding guidelines, HOS kernel basics, 'Settings' and add external resources, add better docs for dtrace-tool.pl (#3964)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3964
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-05-17 02:16:48 +02:00
lizzie 4d49341918 [vk, opengl] recognize and use ETC2 (if available) textures natively (#3237)
this makes it so VK and OGL backends map the NVIDIA's ETC2 into VK_FORMAT_ETC-whatever and GL_ETC-whatever remaps, instead of using the default fallback for AR8G8B8. in short, just make the ETC2 textures be submitted as ETC2 instead of being submit as A8R8G8B8.

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3237
Reviewed-by: Ghost <>
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:08:09 +02:00
lizzie 2f0f8a979c [dynarmic, macroHLE] Use faster ankerl for xbyak maps (#3716)
the nominal std::unordered_map<> isn't enough to warrant it's continued usage in xbyak internal structures, thus using ankerl should greatly remove a lot of indirection/stdc++ specific overhead from the usually poorly performant std::unordered_map

Both dynarmic and macroHLE should benefit greatly from a less-stupid unordered_dense

This should speedup both CPU and shader compilation latency (NOT BY A GREAT MARGIN) just enough to make loading zones in ToTK less horrific

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3716
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:07:45 +02:00
lizzie 413c7543ba [hle] inline HLE cmif request to not allocate on heap stuff (#3605)
so basically each construction of HLEContext and whatever would result in a heap allocation (atleast 1)

so what if instead of that we did a memset() at ctor time and we avoided heap allocations altogether?

reminder that std::vector<> CAN do small object optimisation but it's not guaranteed

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3605
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:07:03 +02:00
lizzie 975aa4e2f2 [common] remove ptr indirection on WallClock (#3864)
also devirtualizes manually since compiler doesn't do it with LTO

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3864
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:06:38 +02:00
lizzie a1f9e68f46 [hid_core] remove contentious mutex from EmulatedController and just rely on atomic semantics for fields (#3866)
inputs shouldnt be that critical to require a full mutex of them

this relies on CPU guaranteeing u32/u16/u8 atomic load/stores for EmulatedController fields, which works on x86_64 but may not have the same behaviour on other architectures - thats why i wrap them in `std::atomic<>`

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3866
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:06:23 +02:00
lizzie 02dee4a20b [file_sys/system_archive] remove uneeded ctor/dtor initializations for std::map<> when creating system archives for nx_tzdb generated files (#3919)
sounds like word salad but let me say:

- std::map<> created a static ctor for EVERY SINGLE ZONEINFO
- fuck that, instead lets just use a raw array and construct things statically
- works the same except with less baggage carried around (+ less heap allocations!!!)

this should help reduce codesize due to the aforementioned global ctor/dtor

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3919
Reviewed-by: crueter <crueter@eden-emu.dev>
2026-05-15 22:05:32 +02:00
lizzie bc9b9480fb [dynarmic] fix 12th-gen Intel CPUs crashing due to UMONITOR (#3954)
see https://github.com/herumi/xbyak/issues/255

> Proof: https://godbolt.org/z/9vseq4Ynj
> Xbyak currently implements it as:
> ```c++
> void umonitor(const Reg& r) {
> int idx = r.getIdx();
> if (idx > 7) XBYAK_THROW(ERR_BAD_PARAMETER) //umonitor DOES accept r8,r9,r10,etc this is NOT correct
> int bit = r.getBit();
> if (BIT != bit) {
>   if ((BIT == 32 && bit == 16) || (BIT == 64 && bit == 32)) {
>     db(0x67);
>   } else {
>     XBYAK_THROW(ERR_BAD_SIZE_OF_REGISTER)
>   }
> }
> db(0xF3); db(0x0F); db(0xAE); setModRM(3, 6, idx);
> }
> ```
> My program was throwing Xbyak::Exception and I tracked it down to this particular umonitor

Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3954
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-05-15 22:01:42 +02:00
256 changed files with 23163 additions and 20985 deletions
+6 -5
View File
@@ -7,7 +7,7 @@
EXCLUDE_FILES="CPM.cmake CPMUtil.cmake GetSCMRev.cmake renderdoc_app.h tools/cpm tools/shellcheck.sh tools/update-cpm.sh tools/windows/vcvarsall.sh externals/stb externals/glad externals/getopt externals/gamemode externals/FidelityFX-FSR externals/demangle externals/bc_decoder externals/cmake-modules"
# license header constants, please change when needed :))))
YEAR=2026
YEAR=$(date "+%Y")
HOLDER="Eden Emulator Project"
LICENSE="GPL-3.0-or-later"
@@ -112,10 +112,10 @@ for file in $FILES; do
[ "$excluded" = "true" ] && continue
case "$file" in
*.cmake|*.sh|*CMakeLists.txt)
*.cmake|*.sh|*.ps1|*.py|*.rb|*.perl|*.pl|*.nix|*CMakeLists.txt)
begin="#"
;;
*.kt*|*.cpp|*.h|*.qml)
*.kt|*.kts|*.cpp|*.h|*.qml|*.c|*.hpp|*.hxx|*.cxx|*.h.in|*.inc)
begin="//"
;;
*)
@@ -185,11 +185,12 @@ if [ "$UPDATE" = "true" ]; then
for file in $SRC_FILES $OTHER_FILES; do
case $(basename -- "$file") in
*.cmake|*CMakeLists.txt)
# Windows Powershell wont use shebangs
*.cmake|*.ps1|*CMakeLists.txt)
begin="#"
shell="false"
;;
*.sh)
*.sh|*.py|*.rb|*.perl|*.pl|*.nix)
begin="#"
shell=true
;;
-22
View File
@@ -1,22 +0,0 @@
#!/bin/bash -ex
# git-archive-all
export PATH="$PATH:/home/$USER/.local/bin"
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
REV_NAME="eden-unified-source-${GITDATE}-${GITREV}"
COMPAT_LIST='dist/compatibility_list/compatibility_list.json'
mkdir artifacts
touch "${COMPAT_LIST}"
git describe --abbrev=0 --always HEAD > GIT-COMMIT
git describe --tags HEAD > GIT-TAG || echo 'unknown' > GIT-TAG
git-archive-all --include "${COMPAT_LIST}" --include GIT-COMMIT --include GIT-TAG --force-submodules artifacts/"${REV_NAME}.tar"
cd artifacts/
xz -T0 -9 "${REV_NAME}.tar"
sha256sum "${REV_NAME}.tar.xz" > "${REV_NAME}.tar.xz.sha256sum"
cd ..
+36 -33
View File
@@ -75,6 +75,8 @@ cmake_dependent_option(YUZU_USE_QT_WEB_ENGINE "Use QtWebEngine for web applet im
set(YUZU_QT_MIRROR "" CACHE STRING "What mirror to use for downloading the bundled Qt libraries")
cmake_dependent_option(YUZU_USE_BUNDLED_QT "Download bundled Qt binaries" "${MSVC}" "ENABLE_QT" OFF)
option(ENABLE_DEBUG_TOOLS "Enable debugging tools (maxwell disassembler, SPIRV translator, etc)" OFF)
# non-linux bundled qt are static
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
set(YUZU_STATIC_BUILD ON)
@@ -119,13 +121,13 @@ if (YUZU_STATIC_BUILD)
set(QuaZip-Qt6_FORCE_BUNDLED ON)
set(YUZU_USE_BUNDLED_FFMPEG ON)
set(YUZU_USE_BUNDLED_SDL2 ON)
set(YUZU_USE_BUNDLED_SDL3 ON)
set(YUZU_USE_BUNDLED_OPENSSL ON)
set(HTTPLIB_USE_BROTLI_IF_AVAILABLE OFF)
elseif(APPLE)
set(YUZU_USE_BUNDLED_FFMPEG ON)
set(YUZU_USE_BUNDLED_SDL2 ON)
set(YUZU_USE_BUNDLED_SDL3 ON)
set(YUZU_USE_BUNDLED_OPENSSL ON)
# these libs do not properly provide static libs/let you do it with cmake
@@ -190,13 +192,11 @@ if(MSVC)
$<$<COMPILE_LANGUAGE:C,CXX>:$<$<CONFIG:Debug>:/${libflag}d>>
$<$<COMPILE_LANGUAGE:C,CXX>:$<$<CONFIG:Release>:/${libflag}>>
$<$<COMPILE_LANGUAGE:C,CXX>:$<$<CONFIG:RelWithDebInfo>:/${libflag}>>
$<$<COMPILE_LANGUAGE:C,CXX>:$<$<CONFIG:MinSizeRel>:/${libflag}>>
)
$<$<COMPILE_LANGUAGE:C,CXX>:$<$<CONFIG:MinSizeRel>:/${libflag}>>)
endif()
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
cmake_dependent_option(YUZU_USE_EXTERNAL_SDL2 "Build SDL2 from external source" OFF "NOT MSVC;NOT ANDROID" OFF)
cmake_dependent_option(YUZU_USE_BUNDLED_SDL2 "Download bundled SDL2 build" "${MSVC}" "NOT ANDROID" OFF)
cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
@@ -230,6 +230,10 @@ cmake_dependent_option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
# Install udev rules on Linux (mainly for gyros)
# Only acts on joysticks and nothing else.
cmake_dependent_option(YUZU_INSTALL_UDEV_RULES "Install udev rules for gyro access" OFF "PLATFORM_LINUX" OFF)
option(YUZU_DOWNLOAD_ANDROID_VVL "Download validation layer binary for android" ON)
option(YUZU_LEGACY "Apply patches that improve compatibility with older GPUs (e.g. Snapdragon 865) at the cost of performance" OFF)
@@ -358,10 +362,6 @@ if (CXX_GCC OR CXX_CLANG)
endif()
endif()
# Other presets, e.g. steamdeck
# TODO(crueter): Just have every Linux/Windows use old sdl2
set(YUZU_SYSTEM_PROFILE "generic" CACHE STRING "CMake and Externals profile to use. One of: generic, steamdeck")
# Configure C++ standard
# ===========================
@@ -559,7 +559,7 @@ if (NOT YUZU_STATIC_ROOM)
endif()
if (NOT ANDROID)
find_package(SDL2)
find_package(SDL3)
endif()
if (USE_DISCORD_PRESENCE)
@@ -584,8 +584,6 @@ if (ENABLE_QT)
else()
AddQt(6.9.3)
endif()
set(YUZU_STATIC_BUILD ON)
else()
message(STATUS "Using system Qt")
if (NOT Qt6_DIR)
@@ -594,23 +592,7 @@ if (ENABLE_QT)
list(APPEND CMAKE_PREFIX_PATH "${Qt6_DIR}")
endif()
find_package(Qt6 CONFIG REQUIRED COMPONENTS Widgets Charts Concurrent)
if (YUZU_USE_QT_MULTIMEDIA)
find_package(Qt6 REQUIRED COMPONENTS Multimedia)
endif()
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
# yes Qt, we get it
set(QT_NO_PRIVATE_MODULE_WARNING ON)
find_package(Qt6 REQUIRED COMPONENTS DBus OPTIONAL_COMPONENTS GuiPrivate)
elseif (UNIX AND NOT APPLE)
find_package(Qt6 REQUIRED COMPONENTS DBus Gui)
endif()
if (ENABLE_QT_TRANSLATION)
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)
endif()
find_package(Qt6 REQUIRED COMPONENTS Core)
if (NOT DEFINED QT_TARGET_PATH)
get_target_property(qtcore_path Qt6::Core LOCATION_Release)
@@ -633,21 +615,27 @@ if (ENABLE_QT)
## Components ##
# Best practice is to ask for all components at once, so they are from the same version
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent)
if (PLATFORM_LINUX)
set(YUZU_QT_COMPONENTS Core Widgets Charts Concurrent Gui)
if (PLATFORM_LINUX OR PLATFORM_FREEBSD)
list(APPEND YUZU_QT_COMPONENTS DBus)
# yes Qt, we get it
set(QT_NO_PRIVATE_MODULE_WARNING ON)
list(APPEND YUZU_QT_OPTIONAL GuiPrivate)
endif()
if (YUZU_USE_QT_MULTIMEDIA)
list(APPEND YUZU_QT_COMPONENTS Multimedia)
endif()
if (YUZU_USE_QT_WEB_ENGINE)
list(APPEND YUZU_QT_COMPONENTS WebEngineCore WebEngineWidgets)
endif()
if (ENABLE_QT_TRANSLATION)
list(APPEND YUZU_QT_COMPONENTS LinguistTools)
endif()
find_package(Qt6 REQUIRED COMPONENTS ${YUZU_QT_COMPONENTS})
find_package(Qt6 REQUIRED COMPONENTS ${YUZU_QT_COMPONENTS} OPTIONAL_COMPONENTS ${YUZU_QT_OPTIONAL})
set(QT_MAJOR_VERSION 6)
# Qt6 sets cxx_std_17 and we need to undo that
set_target_properties(Qt6::Platform PROPERTIES INTERFACE_COMPILE_FEATURES "")
@@ -715,6 +703,12 @@ endif()
add_subdirectory(src)
if (ENABLE_DEBUG_TOOLS)
add_subdirectory(tools/maxwell-disas)
add_subdirectory(tools/maxwell-spirv)
add_subdirectory(tools/maxwell-ir)
endif()
# Set yuzu project or yuzu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not
if(ENABLE_QT)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT yuzu)
@@ -730,6 +724,8 @@ endif()
# https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
# https://specifications.freedesktop.org/shared-mime-info-spec/shared-mime-info-spec-latest.html
# https://www.freedesktop.org/software/appstream/docs/
# TODO: Icon/install handling n such should be put into dist/CMakeLists.txt
if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "dist/dev.eden_emu.eden.desktop"
DESTINATION "share/applications")
@@ -742,3 +738,10 @@ if(ENABLE_QT AND UNIX AND NOT APPLE)
install(FILES "dist/dev.eden_emu.eden.metainfo.xml"
DESTINATION "share/metainfo")
endif()
if (YUZU_INSTALL_UDEV_RULES)
include(GNUInstallDirs)
install(FILES "dist/72-eden-input.rules"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/udev/rules.d")
endif()
+7 -4
View File
@@ -715,8 +715,8 @@ function(AddCIPackage)
"${${ARTIFACT_PACKAGE}_SOURCE_DIR}" PARENT_SCOPE)
if (PKG_ARGS_MODULE)
list(APPEND CMAKE_PREFIX_PATH "${${ARTIFACT_PACKAGE}_SOURCE_DIR}")
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
list(PREPEND CMAKE_PREFIX_PATH "${${ARTIFACT_PACKAGE}_SOURCE_DIR}")
Propagate(CMAKE_PREFIX_PATH)
endif()
else()
find_package(${ARTIFACT_PACKAGE} ${ARTIFACT_MIN_VERSION} REQUIRED)
@@ -730,7 +730,7 @@ function(AddQt version)
endif()
AddCIPackage(
NAME Qt
NAME qt
PACKAGE Qt6
VERSION ${version}
MIN_VERSION 6
@@ -740,5 +740,8 @@ function(AddQt version)
freebsd-amd64 solaris-amd64 openbsd-amd64
MODULE)
set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} PARENT_SCOPE)
find_package(Qt6 REQUIRED PATHS ${Qt6_SOURCE_DIR} NO_DEFAULT_PATH)
Propagate(CMAKE_PREFIX_PATH)
Propagate(Qt6_SOURCE_DIR)
endfunction()
+2 -1
View File
@@ -112,7 +112,8 @@
"options": [
"QUAZIP_QT_MAJOR_VERSION 6",
"QUAZIP_INSTALL OFF",
"QUAZIP_ENABLE_QTEXTCODEC OFF"
"QUAZIP_ENABLE_QTEXTCODEC OFF",
"QUAZIP_BZIP2 OFF"
]
}
}
+8
View File
@@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Allow systemd-logind to manage user access to hidraw with this file
# On most systems, this file should be installed to /etc/udev/rules.d/72-eden-input.rules
# Consult your distro if this is not the case
KERNEL=="hidraw*", SUBSYSTEM=="hidraw", ENV{ID_INPUT_JOYSTICK}=="1", MODE="0660", TAG+="uaccess"
-19
View File
@@ -1,19 +0,0 @@
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# Allow systemd-logind to manage user access to hidraw with this file
# On most systems, this file should be installed to /etc/udev/rules.d/72-yuzu-input.rules
# Consult your distro if this is not the case
# Switch Pro Controller (USB/Bluetooth)
KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="2009", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", KERNELS=="*057e:2009*", MODE="0660", TAG+="uaccess"
# Joy-Con L (Bluetooth)
KERNEL=="hidraw*", KERNELS=="*057e:2006*", MODE="0660", TAG+="uaccess"
# Joy-Con R (Bluetooth)
KERNEL=="hidraw*", KERNELS=="*057e:2007*", MODE="0660", TAG+="uaccess"
# Joy-Con Charging Grip (USB)
KERNEL=="hidraw*", ATTRS{idVendor}=="057e", ATTRS{idProduct}=="200e", MODE="0660", TAG+="uaccess"
+74 -133
View File
@@ -6,8 +6,8 @@
viewBox="0 0 512 512"
version="1.1"
id="svg7"
sodipodi:docname="1stanni.svg"
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
sodipodi:docname="base.svg.2026_01_12_14_43_47.0.svg"
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
@@ -19,34 +19,36 @@
<defs
id="defs7">
<linearGradient
id="linearGradient34"
id="linearGradient1"
inkscape:collect="always">
<stop
style="stop-color:#ffd700;stop-opacity:1;"
style="stop-color:#ff2e88;stop-opacity:0.5;"
offset="0"
id="stop34" />
id="stop3" />
<stop
style="stop-color:#ffd700;stop-opacity:0.48031053;"
offset="1"
id="stop35" />
style="stop-color:#bf42f6;stop-opacity:0.5;"
offset="0.44631511"
id="stop4" />
<stop
style="stop-color:#5da5ed;stop-opacity:0.5;"
offset="0.90088946"
id="stop2" />
</linearGradient>
<rect
x="20.999999"
y="287.30493"
width="487.07235"
height="134.69506"
id="rect22" />
<linearGradient
id="linearGradient21"
id="linearGradient138"
inkscape:collect="always">
<stop
style="stop-color:#3a0057;stop-opacity:1;"
style="stop-color:#ff2e88;stop-opacity:1;"
offset="0"
id="stop21" />
id="stop152" />
<stop
style="stop-color:#830091;stop-opacity:1;"
offset="1"
id="stop22" />
style="stop-color:#bf42f6;stop-opacity:1;"
offset="0.44971901"
id="stop137" />
<stop
style="stop-color:#5da5ed;stop-opacity:1;"
offset="0.89793283"
id="stop138" />
</linearGradient>
<linearGradient
id="swatch37"
@@ -114,6 +116,33 @@
width="521.34025"
height="248.94868"
id="rect24" />
<linearGradient
id="linearGradient11"
inkscape:collect="always">
<stop
style="stop-color:#ff2e88;stop-opacity:1;"
offset="0"
id="stop11" />
<stop
style="stop-color:#bf42f6;stop-opacity:1;"
offset="0.44971901"
id="stop154" />
<stop
style="stop-color:#5da5ed;stop-opacity:1;"
offset="0.89793283"
id="stop12" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient138"
id="linearGradient6"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.118028,0,0,1.116699,-46.314723,-42.388667)"
x1="270.39996"
y1="40.000019"
x2="270.39996"
y2="494.39996"
spreadMethod="pad" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath18">
@@ -136,6 +165,16 @@
inkscape:label="Circle"
r="191.89999" />
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient11"
id="linearGradient27"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-6.9401139e-5,-2.8678628)"
x1="256.00012"
y1="102.94693"
x2="256.00012"
y2="409.05307" />
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath128">
@@ -148,106 +187,14 @@
</clipPath>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient21"
id="linearGradient22"
xlink:href="#linearGradient1"
id="linearGradient2"
x1="256"
y1="0"
y1="64"
x2="256"
y2="512"
gradientUnits="userSpaceOnUse" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient34"
id="linearGradient35"
x1="256"
y1="-0.048701428"
x2="256"
y2="512.04932"
gradientUnits="userSpaceOnUse" />
<filter
inkscape:label="Glowing Bubble"
inkscape:menu="Ridges"
inkscape:menu-tooltip="Bubble effect with refraction and glow"
x="-0.19420711"
y="-0.11239541"
width="1.3884142"
height="1.2247908"
style="color-interpolation-filters:sRGB;"
id="filter61">
<feGaussianBlur
stdDeviation="1"
result="result1"
id="feGaussianBlur56" />
<feGaussianBlur
stdDeviation="10"
result="result6"
in="result1"
id="feGaussianBlur57" />
<feComposite
operator="atop"
in="result6"
in2="result1"
result="result8"
id="feComposite57" />
<feComposite
operator="xor"
result="fbSourceGraphic"
in="result6"
in2="result8"
id="feComposite58" />
<feColorMatrix
result="fbSourceGraphicAlpha"
in="fbSourceGraphic"
values="0 0 0 -1 0 0 0 0 -1 0 0 0 0 -1 0 0 0 0 2 0 "
id="feColorMatrix58" />
<feGaussianBlur
result="result0"
in="fbSourceGraphicAlpha"
stdDeviation="1"
id="feGaussianBlur58" />
<feSpecularLighting
specularExponent="35"
specularConstant="1.5"
surfaceScale="-2"
lighting-color="rgb(255,255,255)"
result="result1"
in="result0"
id="feSpecularLighting58">
<feDistantLight
azimuth="230"
elevation="60"
id="feDistantLight58" />
</feSpecularLighting>
<feComposite
operator="in"
result="result2"
in="result1"
in2="fbSourceGraphicAlpha"
id="feComposite59" />
<feComposite
k3="1.2"
k2="1.1"
operator="arithmetic"
result="result4"
in="fbSourceGraphic"
in2="result2"
id="feComposite60" />
<feGaussianBlur
result="result80"
in="result4"
stdDeviation="0.5"
id="feGaussianBlur60" />
<feComposite
operator="atop"
in="result9"
in2="result80"
result="result91"
id="feComposite61" />
<feBlend
mode="multiply"
in2="result91"
id="feBlend61" />
</filter>
y2="448"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(1.3229974,0,0,1.3214002,-82.687336,-82.290326)" />
</defs>
<sodipodi:namedview
id="namedview7"
@@ -258,29 +205,23 @@
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1"
inkscape:cx="213.49999"
inkscape:cy="248.99999"
inkscape:window-width="1600"
inkscape:window-height="849"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:zoom="1.4142136"
inkscape:cx="261.62951"
inkscape:cy="230.87036"
inkscape:window-width="1920"
inkscape:window-height="1008"
inkscape:window-x="1080"
inkscape:window-y="351"
inkscape:window-maximized="1"
inkscape:current-layer="svg7" />
<circle
style="fill:url(#linearGradient22);fill-opacity:1;stroke:none;stroke-width:8"
id="path21"
cx="256"
cy="256"
r="256" />
<path
id="path8-7"
style="display:inline;mix-blend-mode:normal;fill:url(#linearGradient35);fill-opacity:1;fill-rule:nonzero;stroke:#320081;stroke-width:4.067;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient6);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2);stroke-width:3.9666;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
inkscape:label="Circle"
d="M 256,2.2792898 A 254.0155,253.71401 0 0 0 150.68475,25.115202 c 19.54414,1.070775 38.74692,5.250294 51.56848,11.647658 14.14361,7.056691 28.63804,19.185961 39.4212,29.347551 h 40.60981 c 1.03847,-0.68139 2.10297,-1.36938 3.1938,-2.05957 5.45602,-15.78533 14.79164,-43.183497 19.49612,-57.0097682 A 254.0155,253.71401 0 0 0 256,2.2792898 Z m 61.57106,7.567234 -18.26098,46.1544672 c 7.79702,-4.13918 16.35655,-7.87447 25.20671,-10.87081 23.1229,-7.828433 43.96931,-10.170904 54.94058,-10.868226 A 254.0155,253.71401 0 0 0 317.57106,9.8465238 Z m 65.39277,26.4001532 c -9.68256,4.806644 -33.05532,16.642034 -55.68217,29.863734 H 424.4677 A 254.0155,253.71401 0 0 0 382.96383,36.246677 Z M 113.90698,45.690231 A 254.0155,253.71401 0 0 0 87.532302,66.110411 H 194.2739 c -1.47402,-0.80231 -2.35141,-1.25949 -2.35141,-1.25949 l 10.4496,-11.83348 -38.40568,7.01234 c 0,1e-5 -12.21537,-4.60266 -40.17313,-12.27223 -3.45336,-0.94731 -6.75329,-1.61824 -9.8863,-2.06732 z m -36.803618,30.18635 a 254.0155,253.71401 0 0 0 -34.88372,43.090929 h 59.976738 c 18.11461,-12.04145 40.14252,-22.882149 62.31266,-24.534159 52.93006,-3.9444 70.16538,1.86342 70.16538,1.86342 0,0 -4.612,-4.8206 -14.51938,-13.36656 -2.72366,-2.34942 -6.0844,-4.77373 -9.52455,-7.05363 z m 174.472868,0 c 4.57322,4.7186 7.29716,7.83565 7.29716,7.83565 0,0 3.53501,-3.18484 9.62532,-7.83565 z m 60.27649,0 c -21.56573,15.45339 -25.4703,27.979669 -25.4703,27.979669 0,0 54.83326,-19.215729 100.70543,-0.31228 11.63986,4.79661 21.58481,10.13159 29.94832,15.42354 h 52.74419 A 254.0155,253.71401 0 0 0 434.89664,75.876581 Z M 36.250648,128.73367 A 254.0155,253.71401 0 0 0 16.372095,171.82459 H 147.45478 c 1.45695,-2.5815 3.06539,-5.08648 4.83979,-7.48982 14.23694,-19.28301 27.92088,-30.0088 36.86047,-35.6011 h -30.25323 c -5.87346,0.93472 -12.04945,1.99094 -18.28166,3.16937 -30.12936,5.69727 -81.157618,22.78945 -81.157618,22.78945 0,0 11.47125,-12.39249 29.11369,-25.95882 z m 265.630492,0 c 33.48676,11.2434 52.42799,26.78443 62.7752,43.09092 h 130.97157 a 254.0155,253.71401 0 0 0 -19.87856,-43.09092 h -44.81136 c 14.85233,11.5863 21.59948,20.9854 21.59948,20.9854 0,0 -33.5226,-12.37087 -66.0646,-20.9854 z m -45.96641,16.27007 c -1.00419,0.0106 -10.12705,0.72026 -44.98966,20.64729 -3.12132,1.78406 -6.25434,3.86182 -9.37468,6.17356 h 41.81911 c 7.17181,-17.34774 12.64083,-26.82085 12.64083,-26.82085 0,0 -0.0287,-7.1e-4 -0.0957,0 z m 14.18088,0.0465 c 0,0 -3.31228,9.32762 -7.30492,26.77438 h 51.78554 C 287.6577,146.14158 270.09561,145.0502 270.09561,145.0502 Z M 13.152456,181.59075 A 254.0155,253.71401 0 0 0 3.927651,224.68167 H 134.1447 c 0.56161,-12.72411 2.67825,-28.50188 8.61499,-43.09092 z m 176.661504,0 c -14.27121,13.10564 -27.60733,29.58761 -37.56073,43.09092 h 73.3721 c 4.47018,-16.79061 9.35068,-31.26371 13.86562,-43.09092 z m 70.85787,0 c -2.41384,11.76417 -4.9032,26.20707 -6.94831,43.09092 H 360.4832 c -8.32133,-10.88917 -20.66988,-26.17008 -36.35141,-43.09092 z m 109.17313,0 c 6.63611,15.24089 6.92441,30.5373 5.57882,43.09092 h 132.64857 a 254.0155,253.71401 0 0 0 -9.22481,-43.09092 z M 2.90181,234.44783 A 254.0155,253.71401 0 0 0 1.984498,255.9933 254.0155,253.71401 0 0 0 2.90181,277.53876 h 211.89923 c 2.25762,-15.52555 5.14325,-29.93448 8.3385,-43.09093 h -77.8863 c -6.46396,9.27617 -10.33076,15.56549 -10.33076,15.56549 0,0 -0.82623,-6.14945 -0.9354,-15.56549 z m 249.72093,0 c -1.3692,13.09684 -2.4456,27.49209 -3.02068,43.09093 h 259.49613 a 254.0155,253.71401 0 0 0 0.91731,-21.54546 254.0155,253.71401 0 0 0 -0.91731,-21.54547 H 374.02584 c -0.445,2.5469 -0.90878,4.89768 -1.32817,7.01751 0,0 -1.69726,-2.53821 -4.94056,-7.01751 z M 3.927651,287.30493 a 254.0155,253.71401 0 0 0 9.224805,43.09091 H 214.04393 c -1.29238,-15.40742 -1.57503,-30.04388 -0.41861,-43.09091 z m 245.385009,0 c -0.30355,13.54349 -0.22032,27.92598 0.36951,43.09091 h 249.16537 a 254.0155,253.71401 0 0 0 9.22481,-43.09091 z M 16.369511,340.16201 a 254.0155,253.71401 0 0 0 19.878554,43.09091 H 221.4677 c -2.69781,-14.4523 -4.96108,-29.01285 -6.4832,-43.09091 z m 233.842379,0 c 1.15864,15.47765 3.81286,29.83979 7.51679,43.09091 h 218.02325 a 254.0155,253.71401 0 0 0 19.87856,-43.09091 z M 42.217052,393.01909 a 254.0155,253.71401 0 0 0 34.88372,43.09093 H 233.09561 c -3.40902,-13.67281 -6.76794,-28.2531 -9.73902,-43.09093 z m 218.490958,0 c 5.34985,16.15926 12.22007,30.51982 19.68733,43.09093 h 154.50389 a 254.0155,253.71401 0 0 0 34.88371,-43.09093 z M 87.529722,445.87618 a 254.0155,253.71401 0 0 0 166.229968,63.8208 c -3.67805,-12.0825 -10.85464,-35.49828 -18.18088,-63.8208 z m 199.010328,0 c 17.5887,26.43772 36.99259,43.60598 47.33592,51.61309 a 254.0155,253.71401 0 0 0 90.59431,-51.61309 z" />
<path
id="path27"
style="display:inline;mix-blend-mode:multiply;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:3;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
style="display:inline;mix-blend-mode:multiply;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient27);stroke-width:3;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 318.98012,441.7375 c -9.87518,-6.73978 -64.39137,-49.0272 -67.68975,-127.81978 -3.69298,-88.21893 15.36468,-141.91029 15.36468,-141.91029 0,0 16.00378,0.99513 39.80316,26.53195 23.79939,25.53753 37.74965,46.43102 37.74965,46.43102 3.91262,-19.79992 12.84563,-66.32402 -60.72865,-87.55523 0,0 12.82326,-5.38883 39.3925,-3.81382 26.56907,1.57572 81.6822,21.93799 81.6822,21.93799 0,0 -14.79766,-20.63773 -49.47063,-34.94295 -34.67291,-14.30533 -76.1182,0.23644 -76.1182,0.23644 0,0 3.86959,-12.43127 27.22669,-26.38478 23.35718,-13.9537 49.27409,-26.501533 49.27409,-26.501533 0,0 -21.97854,-0.26548 -47.67725,8.44535 -6.68948,2.267506 -13.15863,5.094213 -19.05208,8.226563 l 16.05803,-40.634103 -4.4617,-1.89059 -5.1305,-0.95965 c 0,0 -11.24072,33.12428 -16.92051,49.576513 -12.13137,7.68489 -20.11005,14.87735 -20.11005,14.87735 0,0 -21.90573,-25.09227 -42.79668,-35.527803 -26.03412,-13.00525 -86.88249,-13.90359 -94.0044,10.401173 0,0 13.56804,-7.884703 34.70032,-2.080917 21.13214,5.803997 30.3644,9.287307 30.3644,9.287307 l 29.02989,-5.30681 -7.89811,8.95527 c 0,0 13.8496,7.21324 21.33822,13.68063 7.48859,6.46722 10.9757,10.11472 10.9757,10.11472 0,0 -13.02739,-4.39388 -53.03507,-1.40893 -40.00771,2.98473 -79.40016,45.60209 -79.40016,45.60209 0,0 38.57037,-12.93531 61.34393,-17.24677 22.77354,-4.31126 44.52166,-6.46757 44.52166,-6.46757 0,0 -17.23298,5.97003 -35.69792,31.00932 -18.46522,25.03987 -13.13146,64.83866 -13.13146,64.83866 0,0 29.33874,-47.7577 57.44675,-63.84249 28.10798,-16.08527 34.0799,-15.6238 34.0799,-15.6238 0,0 -22.56785,39.13486 -31.39017,101.98268 -8.03005,57.2039 26.77689,163.75449 31.1572,178.89699"
sodipodi:nodetypes="cscsccscscscsccccccscscccscscscscscsc"
inkscape:label="MainOutline"

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 556 KiB

After

Width:  |  Height:  |  Size: 335 KiB

+588 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+586 -592
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+586 -592
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+1543 -1447
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+586 -594
View File
File diff suppressed because it is too large Load Diff
+651 -654
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+586 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+590 -596
View File
File diff suppressed because it is too large Load Diff
+586 -594
View File
File diff suppressed because it is too large Load Diff
+588 -594
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 35 KiB

+2 -3
View File
@@ -46,7 +46,7 @@ Qt Widgets appears to be broken. For now, add `-DENABLE_QT=OFF` to your configur
This is needed for some dependencies that call cc directly (tz):
```sh
echo '#!/bin/sh' >cc
echo '#!/bin/sh -e' >cc
echo 'gcc $@' >>cc
chmod +x cc
export PATH="$PATH:$PWD"
@@ -65,14 +65,13 @@ export LIBGL_ALWAYS_SOFTWARE=1
```
- Modify the generated ffmpeg.make (in build dir) if using multiple threads (base system `make` doesn't use `-j4`, so change for `gmake`).
- If using OpenIndiana, due to a bug in SDL2's CMake configuration, audio driver defaults to SunOS `<sys/audioio.h>`, which does not exist on OpenIndiana. Using external or bundled SDL2 may solve this.
- System OpenSSL generally does not work. Instead, use `-DYUZU_USE_BUNDLED_OPENSSL=ON` to use a bundled static OpenSSL, or build a system dependency from source.
## OmniOS
Install `developer/gcc14` on OmniOS using pkgsrc.
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON -DYUZU_USE_EXTERNAL_SDL2=ON`
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON`
For OmniOS you are required to build glslang yourself:
```sh
+31 -19
View File
@@ -35,6 +35,11 @@ If you are on desktop and plan to use the Qt frontend, you *must* install Qt 6,
* For help setting up Qt Creator, run `./install.sh -h qtcreator`
* If you're using clang-cl and want to still use MSVC
* Check the option to add "C++ clang compiler for Windows" on Visual Studio installer and uncheck "x64/x86 build tool for MSVC" while selecting "C++ desktop developement tools" and change Visual Studio to 2026, from 2022.
* At qt creator section generator tab change Visual Studio 17 2022 to 2026.
* Finally, to use clang-cl: `cmake -S . -B build -G "Visual Studio 17 2026" -T ClangCL`
If you are on **Windows** and building with **MSVC** or **clang-cl**, you may go [back home](Build.md) and continue.
## Externals
@@ -42,7 +47,7 @@ If you are on **Windows** and building with **MSVC** or **clang-cl**, you may go
The following are handled by Eden's externals:
* [FFmpeg](https://ffmpeg.org/) (should use `-DYUZU_USE_EXTERNAL_FFMPEG=ON`)
* [SDL2](https://www.libsdl.org/download-2.0.php) 2.0.18+ (should use `-DYUZU_USE_EXTERNAL_SDL2=ON` OR `-DYUZU_USE_BUNDLED_SDL2=ON` to reduce compile time)
* [SDL3](https://www.libsdl.org/download-2.0.php) 3.2.10+ (Use `-DYUZU_USE_BUNDLED_SDL2=ON` to reduce compile time)
All other dependencies will be downloaded and built by [CPM](https://github.com/cpm-cmake/CPM.cmake/) if `YUZU_USE_CPM` is on, but will always use system dependencies if available (UNIX-like only):
@@ -118,7 +123,7 @@ sudo emerge -a \
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
dev-util/vulkan-utility-libraries dev-util/glslang \
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
media-libs/VulkanMemoryAllocator media-libs/libsdl3 media-libs/cubeb \
net-libs/enet \
sys-libs/zlib \
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
@@ -137,7 +142,8 @@ Required USE flags:
* `dev-qt/qtbase network concurrent dbus gui widgets`
* `dev-libs/quazip qt6`
* `media-libs/libsdl2 haptic joystick sound video`
* `media-libs/libsdl3 haptic joystick sound video`
* Adding `X vulkan udev opengl` is recommended but not required
* `dev-cpp/cpp-httplib ssl`
[Caveats](./Caveats.md#gentoo-linux)
@@ -148,7 +154,7 @@ Required USE flags:
<summary>Arch Linux</summary>
```sh
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl opus qt6-base qt6-multimedia qt6-charts sdl2 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glslang libzip lz4 ninja nlohmann-json openssl opus qt6-base qt6-multimedia qt6-charts sdl3 zlib zstd zip unzip vulkan-headers vulkan-utility-libraries libusb spirv-tools spirv-headers
```
* Building with QT Web Engine requires `qt6-webengine` as well.
@@ -161,10 +167,10 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
<summary>Ubuntu, Debian, Mint Linux</summary>
```sh
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev qt6-charts-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl3-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
```
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
* Ubuntu 26.04, Linux Mint 22.3, or Debian 13 or later is required.
* To enable QT Web Engine, add `-DYUZU_USE_QT_WEB_ENGINE=ON` when running CMake.
</details>
@@ -185,13 +191,13 @@ AlmaLinux (use `YUZU_USE_CPM=ON`):
sudo dnf install epel-release dnf-utils
# (run rpmfusion installation afterwards)
# vvv - This will work for most systems
sudo dnf install autoconf cmake libtool libudev cmake gcc gcc-c++ qt6-qtbase-devel zlib-devel openssl-devel boost SDL2 ffmpeg-devel libdrm glslang jq patch
sudo dnf install autoconf cmake libtool libudev cmake gcc gcc-c++ qt6-qtbase-devel zlib-devel openssl-devel boost SDL3 ffmpeg-devel libdrm glslang jq patch
# Qt6 private GUI must be taken from CRB repos
sudo dnf config-manager --enable crb
sudo dnf install qt6-qtbase-private-devel
```
For systems like OpenEuler or derivates, don't forget to also install: `SDL2-devel pkg-config fmt-dev nlohmann-json-dev`.
For systems like OpenEuler or derivates, don't forget to also install: `SDL3-devel pkg-config fmt-dev nlohmann-json-dev`.
* [RPM Fusion](https://rpmfusion.org/Configuration) is required for `ffmpeg-devel`
* Fedora 32 or later is required.
@@ -208,7 +214,7 @@ First, enable the community repository; [see here](https://wiki.alpinelinux.org/
# Enable the community repository
setup-apkrepos -c
# Install
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl2-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libquazip1-qt6 ffmpeg-dev qt6-charts-dev libusb-dev libtool boost-dev sdl3-dev zstd-dev vulkan-utility-libraries spirv-tools-dev openssl-dev nlohmann-json lz4-dev opus-dev jq patch
```
</details>
@@ -216,7 +222,7 @@ apk add g++ git cmake make mesa-dev qt6-qtbase-dev qt6-qtbase-private-dev libqua
<summary>Void Linux</summary>
```sh
xbps-install -Su git make cmake clang pkg-config patch SPIRV-Tools-devel SPIRV-Headers lz4 liblz4-devel boost-devel ffmpeg6-devel catch2 Vulkan-Utility-Libraries Vulkan-Headers glslang openssl-devel SDL2-devel quazip-qt6-devel qt6-base-devel qt6-qt5compat-devel qt6-charts-devel fmt-devel json-c++ libenet-devel libusb-devel
xbps-install -Su git make cmake clang pkg-config patch SPIRV-Tools-devel SPIRV-Headers lz4 liblz4-devel boost-devel ffmpeg6-devel catch2 Vulkan-Utility-Libraries Vulkan-Headers glslang openssl-devel SDL3-devel quazip-qt6-devel qt6-base-devel qt6-qt5compat-devel qt6-charts-devel fmt-devel json-c++ libenet-devel libusb-devel
```
Yes, `nlohmann-json` is just named `json-c++`. Why?
@@ -237,7 +243,7 @@ If you're going for a pure build (i.e no downloaded deps), use `-DYUZU_USE_CPM=O
Install dependencies from **[Homebrew](https://brew.sh/)**
```sh
brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl2 speexdsp zlib zstd cmake Catch2 molten-vk vulkan-loader spirv-tools
brew install autoconf automake boost ffmpeg fmt glslang hidapi libtool libusb lz4 ninja nlohmann-json openssl pkg-config qt@6 sdl3 speexdsp zlib zstd cmake Catch2 molten-vk vulkan-loader spirv-tools
```
If you are compiling on Intel Mac, or are using a Rosetta Homebrew installation, you must replace all references of `/opt/homebrew` with `/usr/local`.
@@ -254,7 +260,7 @@ brew install molten-vk
<details>
<summary>FreeBSD</summary>
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/unordered-dense vulkan-headers quazip-qt6`
As root run: `pkg install devel/cmake sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/unordered-dense vulkan-headers quazip-qt6`
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
@@ -264,7 +270,11 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
<details>
<summary>NetBSD</summary>
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx`.
For NetBSD +10.1:
```sh
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
```
[Caveats](./Caveats.md#netbsd).
@@ -274,7 +284,7 @@ For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv
```sh
pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1-1.0.29
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl3 libusb1-1.0.29 quazip-qt6
```
[Caveats](./Caveats.md#openbsd).
@@ -284,7 +294,7 @@ pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gm
<summary>DragonFlyBSD</summary>
```sh
pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmake jq nlohmann-json enet spirv-tools sdl2 vulkan-utility-libraries vulkan-headers catch2 libfmt openssl liblz4 boost-libs cpp-httplib qt6-base qt6-charts quazip-qt6 unordered-dense libva-vdpau-driver libva-utils libva-intel-driver
pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmake jq nlohmann-json enet spirv-tools sdl3 vulkan-utility-libraries vulkan-headers catch2 libfmt openssl liblz4 boost-libs cpp-httplib qt6-base qt6-charts quazip-qt6 unordered-dense libva-vdpau-driver libva-utils libva-intel-driver
```
[Caveats](./Caveats.md#dragonflybsd).
@@ -294,7 +304,7 @@ pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmak
<summary>OpenIndiana</summary>
```sh
sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt
sudo pkg install git cmake qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl3 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt
```
[Caveats](./Caveats.md#openindiana).
@@ -318,7 +328,7 @@ sudo pkgin install git cmake autoconf build-essential libusb-1 nasm gcc13
```sh
BASE="git make autoconf libtool automake-wrapper jq patch"
MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus libusb unordered_dense openssl SDL2"
MINGW="qt6-base qt6-charts qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus libusb unordered_dense openssl SDL3"
# Either x86_64 or clang-aarch64 (Windows on ARM)
packages="$BASE"
for pkg in $MINGW; do
@@ -344,7 +354,7 @@ pacman -Syuu --needed --noconfirm $packages
<summary>HaikuOS</summary>
```sh
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl2_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel
pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel boost1.90_devel vulkan_devel qt6_base_devel qt6_declarative_devel libsdl3_devel ffmpeg7_devel libx11_devel enet_devel catch2_devel quazip1_qt5_devel qt6_5compat_devel glslang qt6_devel qt6_charts_devel cubeb_devel simpleini quazip_qt6_devel
```
[Caveats](./Caveats.md#haikuos).
@@ -355,9 +365,11 @@ pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel b
```sh
sudo pkg update
sudo pkg install git cmake ffmpeg6 sdl2 zlib llvm18
sudo pkg install git cmake ffmpeg6 zlib llvm18
```
RedoxOS currently does not support SDL3. You will have to compile it yourself and pray.
[Caveats](./Caveats.md#redoxos).
</details>
+31
View File
@@ -0,0 +1,31 @@
# HOS Kernel
In brief, the HOS kernel is a microkernel, some services and programs run in userspace, the primary way to do communication between these is via `HIPC` (not covered here); otherwise most of the primitives reside in the forms of syscalls invoked via `svc #imm`. The kernel supports both 32-bit and 64-bit programs, and has the capacity to use 32, 36 and 39 bits of address space for spawned processes. Most of the networking stack is based off FreeBSD's network stack.
The emulator implements the majority of the syscalls pertaining to the HOS kernel itself. When we talk about the HOS Kernel (in the context of the emulator) we are strictly speaking about the mechanisms from which syscalls are handled (and it's subsequent side effects, such as the page table book-keeping). The emulator at it's current state is unable to load a custom low-level kernel and do supervisor-level emulation.
Most programs in NX eventually invoke an `svc`, which, depending on it's immediate value, will go on to be dispatched into one of the specific syscall handlers.
These can be seen in [svc.cpp](/src/core/hle/kernel/svc.cpp). All of these correspond to syscalls which userspace programs may perform.
In turn, these syscalls create the mechanisms that allows programs to use CMIF/TIPC as their primary IPC form to contact other services/processes running on the system, the details of which will not be covered here, but you can consult the relevant [SwitchBrew article: 'HIPC'](https://switchbrew.org/wiki/HIPC).
From the point of view of the programs, no special devices (such as PCIE, Realtek drivers, Bluetooth or USB) has to be handled by the emulator; this is because most of the fun occurs in specialized services such as `usb:u` or `pcie` services. Which aren't emulated (yet).
Due to the nature of syscalls, many of them interact with memory. The emulated kernel has an internal tree-like structure, borrowed from FreeBSD's intrusive red-black tree; this is used to track and find mappings added or removed. Thus most of the process space is emulated in this way.
The kernel keeps it's own separate pagetable, in a traditional sense, each process has it's own pagetable, this is true for HOS as well.
Every process keeps it's own tracking of the following structures:
- Name (13 characters)
- 64-bit ID
- A handle table
- Exclusive monitor
- Threads
- Held locks
- Thread local pages
- A page table for each process
The emulator willingly restricts itself to only use 4 threads (to emulate 4 cores), this is because most existing applications do not benefit greatly from the added core count, and in fact can be detrimental due to extra contention. This translates equitatively to about 4 `ArmInterface` slots for each process, these are then redirected to whatever is the last `pc` of the last thread running on the core is meant to be; proceed to run it, then when returning (due to halt or interruption), proceed to reschedule the thread.
The scheduler as-is isn't 100% faithful to the original, and has great timing variance (especially due to the fact the emulator can run in systems with wildly different timings).
+2
View File
@@ -853,6 +853,8 @@ Texture Query.
Vote Across SIMD Thread Group
`VOTE_vtg` is a kepler leftover.
# VSET
`0100 000- ---- ----`
+6 -3
View File
@@ -29,8 +29,7 @@ These options control dependencies.
- `YUZU_TZDB_PATH` (string) Path to a pre-downloaded timezone database (useful for nixOS and Gentoo)
- `YUZU_USE_BUNDLED_MOLTENVK` (ON, macOS only) Download bundled MoltenVK lib
- `YUZU_USE_BUNDLED_OPENSSL` (ON for MSVC, Android, Solaris, and OpenBSD) Download bundled OpenSSL build
- `YUZU_USE_EXTERNAL_SDL2` (OFF) Compiles SDL2 from source
- `YUZU_USE_BUNDLED_SDL2` (ON for MSVC) Download a prebuilt SDL2
- `YUZU_USE_BUNDLED_SDL3` (ON for MSVC) Download a prebuilt SDL3
### Miscellaneous
@@ -44,6 +43,9 @@ These options control dependencies.
- UNIX may be better off appending `-flto=thin` to compiler args
- `USE_FASTER_LINKER` (OFF) Check if a faster linker is available
- Not recommended outside of Linux
- `YUZU_INSTALL_UDEV_RULES` (OFF) Install udev rules to enable hidraw access
- Needed for gyroscopes
- Only available on Linux
### Flavors
@@ -60,7 +62,7 @@ These options control executables and build flavors.
**Desktop only**:
- `YUZU_CMD` (ON) Compile the SDL2 frontend (eden-cli)
- `YUZU_CMD` (ON) Compile the SDL-based frontend (eden-cli)
- `YUZU_ROOM` (OFF) Compile dedicated room functionality into the main executable
- `YUZU_ROOM_STANDALONE` (OFF) Compile a separate executable for room functionality
- `YUZU_STATIC_ROOM` (OFF) Compile the room executable *only* as a static, portable executable
@@ -96,5 +98,6 @@ The following options were a part of Eden at one point, but have since been reti
- `ENABLE_SDL2` - While technically possible to *not* use SDL2 on desktop, this is **NOT** a supported configuration under any means, and adding this matrix to our build system was not worth the effort.
- `YUZU_USE_CPM` - This option once had a purpose, but that purpose has long since passed us by. *All* builds use CPMUtil to manage dependencies now.
- If you want to *force* the usage of system dependencies, use `-DCPMUTIL_FORCE_SYSTEM=ON`.
- `YUZU_USE_EXTERNAL_SDL` - This is now handled automatically. It was included even after CPM for purposes that have not applied for a very long time.
See `src/dynarmic/CMakeLists.txt` for additional options--usually, these don't need changed
+21 -7
View File
@@ -2,21 +2,26 @@
Are you just a casual user? Take a look at our [User Handbook](./user) then!
If you want to register/signup as a contributor, take a gander at the [signup guide](./SIGNUP.md).
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)**
- **[CMake Options](Options.md)**
- **[Cross Compiling](CrossCompile.md)**
- **[Development Guidelines](Development.md)**
- **[Dependencies](Deps.md)**
- **[General Build Instructions](./Build.md)**
- **[CMake Options](./Options.md)**
- **[Cross Compiling](./CrossCompile.md)**
- **[Development Guidelines](./Development.md)**
- **[Dependencies](./Deps.md)**
- **[Debug Guidelines](./Debug.md)**
- **[CPM - CMake Package Manager](./CPMUtil)**
- **[Platform-Specific Caveats](Caveats.md)**
- **[Platform-Specific Caveats](./Caveats.md)**
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
- **[Dynarmic](./dynarmic)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**
- **[Building Older Commits](./build/OlderCommits.md)**
- Subsystems:
- **[Dynarmic](./dynarmic/README.md)**
- **[HOS Kernel](./HosKernel.md)**
- **[Settings](./Settings.md)**
## Policies
@@ -25,3 +30,12 @@ Policies and information on development.
- **[AI and LLM Usage](./policies/AI.md)**
- **[Release Policy](./policies/Release.md)**
- **[Coding guidelines](./policies/Coding.md)**
- **[Coding Style guidelines](./policies/CodingStyle.md)**
## Externals
Other useful resources in general, take a quick read if you need.
- **[SwitchBrew](https://switchbrew.org/wiki/Main_Page)**
- **[IPS file format](https://zerosoft.zophar.net/ips.php)**
- **[IPSwitch file format](https://github.com/3096/ipswitch)**
+327
View File
@@ -0,0 +1,327 @@
# Settings
> [!WARNING]
> This guide is intended for developers ONLY. If you're looking for configuring the emulator itself, please read **[the user handbook](./user/README.md)**.
Settings on the emulator are very important, toggles and such can be used to guard and/or add branches to paths where some games may crash while others won't, and viceversa.
However, this process can be tedious for those unfamiliar; this document serves as a outline/documentation for the settings subsystem.
## Index
* [Adding Debug Knobs](#adding-debug-knobs)
* [Advantages](#advantages)
* [Usage](#usage)
* [Accessing Debug Knobs (dev side)](#accessing-debug-knobs-dev-side)
* [Setting Debug Knobs (user side)](#setting-debug-knobs-user-side)
* [Bit Manipulation Examples](#bit-manipulation-examples)
* [Terminology and user communication](#terminology-and-user-communication)
* [Examples](#examples)
* [Example 1: Conditional Debug Logging](#example-1-conditional-debug-logging)
* [Example 2: Performance Tuning](#example-2-performance-tuning)
* [Example 3: Feature Gating](#example-3-feature-gating)
* [Best Practices](#best-practices)
* [Adding Boolean Settings Toggles](#adding-boolean-settings-toggles)
* [Step 1 - Common Setting](#step-1-common-setting)
* [Step 2 - Qt Toggle](#step-2-qt-toggle)
* [Step 3 - Kotlin (Android)](#step-3-kotlin-android)
* [Step 3.1 - BooleanSetting.kt](#step-3-1-booleansetting-kt)
* [Step 3.2 - SettingsItem.kt](#step-3-2-settingsitem-kt)
* [Step 3.3 - SettingsFragmentPresenter.kt](#step-3-3-settingsfragmentpresenter-kt)
* [Step 3.4 - Localization](#step-3-4-localization)
* [Step 4 - Use Your Toggle](#step-4-use-your-toggle)
* [Best Practices](#best-practices)
## Adding Boolean Settings Toggles
This guide will walk you through adding a new boolean toggle setting to Eden's configuration across both Qt's (PC) and Kotlin's (Android) UIs.
---
### Step 1 - Common Setting
Firstly add your desired toggle:
Example: `src/common/setting.h`
```cpp
SwitchableSetting<bool> your_setting_name{linkage, false, "your_setting_name", Category::RendererExtensions};
```
Remember to add your toggle to the appropriate category, for example:
Common Categories:
* Category::Renderer
* Category::RendererAdvanced
* Category::RendererExtensions
* Category::System
* Category::Core
> [!WARNING]
> If you wish for your toggle to be `on by default` then change `false` to `true` after `linkage,`.
---
### Step 2 - Qt Toggle
Add the toggle to the Qt UI, where you wish for it to appear and place it there.
Example: `src/qt_common/config/shared_translation.cpp`
```cpp
INSERT(Settings,
your_setting_name,
tr("Your Setting Display Name"),
tr("Detailed description of what this setting does.\n"
"You can use multiple lines.\n"
"Explain any caveats or requirements."));
```
#### Make sure to:
* Keep display naming consistant
* Put detailed info in the description
* Use `\n` for line breaks in descriptions
---
### Step 3 - Kotlin (Android)
#### Step 3.1 - BooleanSetting.kt
Add where it should be in the settings.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt`
```kts
RENDERER_YOUR_SETTING_NAME("your_setting_name"),
```
#### Make sure to:
* Ensure the prefix naming matches the intended category.
---
#### Step 3.2 - SettingsItem.kt
Add the toggle to the Kotlin (Android) UI
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt`
```kts
put(
SwitchSetting(
BooleanSetting.RENDERER_YOUR_SETTING_NAME,
titleId = R.string.your_setting_name,
descriptionId = R.string.your_setting_name_description
)
)
```
---
#### Step 3.3 - SettingsFragmentPresenter.kt
Add your setting within the right category.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt`
```kts
add(BooleanSetting.RENDERER_YOUR_SETTING_NAME.key)
```
> [!WARNING]
> Remember, placing matters! Settings appear in the order of where you add them.
---
#### Step 3.4 - Localization
Add your setting and description in the appropriate place.
Example: `src/android/app/src/main/res/values/strings.xml`
```xml
<string name="your_setting_name">Your Setting Display Name</string>
<string name="your_setting_name_description">Detailed description of what this setting does. Explain any caveats, requirements, or warnings here.</string>
```
---
### Step 4 - Use Your Toggle!
Now the UI part is done find a place in the code for the toggle,
And use it to your heart's desire!
Example:
```cpp
const bool your_value = Settings::values.your_setting_name.GetValue();
if (your_value) {
// Do something when enabled
}
```
If you wish to do something only when the toggle is disabled,
Use `if (!your_value) {` instead of `if (your_value) {`.
---
### Best Practices
* Naming - Use clear, descriptive names. Something for both the devs and the users.
* Defaults - Choose safe default values (usually false for new features).
* Documentation - Write clear descriptions explaining when and why to use the setting.
* Categories - Put settings in the appropriate category.
* Order - Place related settings near each other.
* Testing - Always test on both PC and Android before committing when possible.
Thank you for reading, I hope this guide helped you making your toggle!
## Adding Debug Knobs
Debug Knobs is a 16-bit integer setting (`debug_knobs`) in the Eden Emulator that serves as a bitmask for gating various testing and debugging features. This allows developers and advanced users to enable or disable specific debug behaviors without requiring deploying of complete but temporary toggles.
The setting ranges from 0 to 65535 (0x0000 to 0xFFFF), where each bit represents a different debug feature flag.
---
### Advantages
The main advantage is to avoid deploying new disposable toggles (those made only for testing stage, and are disposed once new feature gets good to merge). This empowers devs to be free of all frontend burocracy and hassle of new toggles.
Common advantages recap:
* **Fine-Grained Control**: Enable or disable up to 16 individual debug features independently using bit manipulation on a single build
* **Runtime Configuration**: Change debug behavior at runtime the same way as new toggles would do
* **Safe incremental development**: New debug features can be added while impact can be isolated from previous deployments
### Usage
#### Accessing Debug Knobs (dev side)
Use the `Settings::getDebugKnobAt(u8 i)` function to check if a specific bit is set:
```cpp
//cpp side
#include "common/settings.h"
// Check if bit 0 is set
bool feature_enabled = Settings::getDebugKnobAt(0);
// Check if bit 15 is set
bool another_feature = Settings::getDebugKnobAt(15);
```
```kts
//kotlin side
import org.yuzu.yuzu_emu.features.settings.model.Settings
// Check if bit x is set
bool feature_enabled = Settings.getDebugKnobAt(x); //x as integer from 0 to 15
```
The function returns `true` if the specified bit (0-15) is set in the `debug_knobs` value, `false` otherwise.
#### Setting Debug Knobs (user side)
Developers must inform which knobs are tied to each functionality to be tested.
The debug knobs value can be set through:
1. **Desktop UI**: In the Debug configuration tab, there's a spinbox for "Debug knobs" (0-65535)
2. **Android UI**: Available as an integer setting in the Debug section
3. **Configuration Files**: Set the `debug_knobs` value in the emulator's configuration
#### Bit Manipulation Examples
To enable specific features, calculate the decimal value by setting the appropriate bits:
* **Enable only bit 0**: Value = 1 (2^0)
* **Enable only bit 1**: Value = 2 (2^1)
* **Enable bits 0 and 1**: Value = 3 (2^0 + 2^1)
* **Enable bit 15**: Value = 32768 (2^15)
### Terminology and user communication
There are two main confusions when talking about knobs:
#### Whether it's zero-based or one-based
Sometimes when an user reports: knobs 1 and 2 gets better performance, dev may get confuse whether he means the knobs 1 and 2 literally, or the 1st and 2nd knobs (knobs 0 and 1).
Debug knobs are **zero-based**, which means:
* The first knob is the knob(0) (or knob0 henceforth), and the last one is the 15 (knob15, likewise)
* You can talk: "knob0 is enabled/disabled", "In this video i was using only knobs 0 and 2", etc.
#### Whether one is talking about the knob itself or about the entire parameter value (which represents all knobs)
Sometimes when an user reports: knob 3 results, it's unclear whether he's referring to knob setting with value 3 (which means both knob 0 and 1 are enabled), or to knob(3) specifically.
Whenever you're instructing tests or reporting results, be precise about whether one you're talking to avoid confusion:
#### Setting based terminology
ALWAYS use the word in PLURAL (knobs), without mentioning which one, to refer to the setting, aka multiple knobs at once:
Examples:
- **knobs=0**: no knobs enabled
- **knobs=1**: knob0 enabled, others disabled
- **knobs=2**: knob1 enabled, others disabled
- **knobs=3**: knobs 0 and 1 enabled, others disabled
...
#### Knob based terminology
Use the word in SINGULAR (knob), or in plural but referring which ones, when meaning multiple knobs at once:
Examples:
- **knob0**: knob 0 enabled, others disabled
- **knob1**: knob 1 enabled, others disabled
- **knobs 0 and 1**: knobs 0 and 1 enabled, others disabled
...
### Examples
#### Example 1: Conditional Debug Logging
```cpp
void SomeFunction() {
if (Settings::getDebugKnobAt(0)) {
LOG_DEBUG(Common, "Debug feature 0 is enabled");
// Additional debug code here
}
if (Settings::getDebugKnobAt(1)) {
LOG_DEBUG(Common, "Debug feature 1 is enabled");
// Different debug behavior
}
}
```
#### Example 2: Performance Tuning
```cpp
bool UseOptimizedPath() {
// Skip optimization if debug bit 2 is set for testing
return !Settings::getDebugKnobAt(2);
}
```
#### Example 3: Feature Gating
```cpp
void ExperimentalFeature() {
static constexpr u8 EXPERIMENTAL_FEATURE_BIT = 3;
if (!Settings::getDebugKnobAt(EXPERIMENTAL_FEATURE_BIT)) {
// Fallback to stable implementation
StableImplementation();
return;
}
// Experimental implementation
ExperimentalImplementation();
}
```
### Best Practices
* This setting is intended for development and testing purposes only
* Knobs must be unwired before PR creation
* The setting is per-game configurable, allowing different debug setups for different titles
+58 -114
View File
@@ -1,126 +1,70 @@
# Coding guidelines
These are mostly "suggestions", if you feel like your code is readable, comprehensible to others; and most importantly doesn't result in unreadable spaghetti you're fine to go.
These are **not** stylistic guidelines, they're, for the most part, suggestions on how to architecture new systems or improve upon the existing codebase.
But for new developers you may find that following these guidelines will make everything x10 easier.
# Foreword
## Naming conventions
Don't try to micro-optimize out of the get go, while yes, most of the code is pretty, subpar, most of these are aftertoughts and details that can be glossed over **generally**.
Simply put, types/classes are named as `PascalCase`, same for methods and functions like `AddElement`. Variables are named `like_this_snake_case` and constants are `IN_SCREAMING_CASE`.
Architectural issues are more important, for example an API returning a `std::string` is not as efficient as one that operates on `std::string_view` directly (cost of constructing an `std::string` w/o small-string optimization and all of that).
Except for Qt MOC where `functionName` is preferred.
Regardless of the details, try to keep things simple. As a general rule of thumb.
Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well. Do not use names like `SS` as systems like solaris define it for registers, in general do not use any of the following for short names:
# C++ guidelines
- `SS`, `DS`, `GS`, `FS`: Segment registers, defined by Solaris `<ucontext.h>`
- `EAX`, `EBX`, `ECX`, `EDX`, `ESI`, `EDI`, `ESP`, `EBP`, `EIP`: Registers, defined by Solaris.
- `X`: Defined by some utility headers, avoid.
- `_`: Defined by gettext, avoid.
- `N`, `M`, `S`: Preferably don't use this for types, use it for numeric constants.
- `TR`: Used by some weird `<ucontext.h>` whom define the Task Register as a logical register to provide to the user... (Need to remember which OS in specific).
Everyone has their own way of viewing good/bad C++ practices, my general outline:
Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`.
- At your disposal you may use `boost::container::static_vector<>` (beware it has a ctor/initialization cost which goes up the more elements you add).
- Or you may use `boost::container::small_vector<>` (which has an initialization cost as well, and will use extra book-keeping for heap, try to keep a balance).
- Don't use `[[likely]]` or `[[unlikely]]`; PGO builds exist for that.
- Don't use inline assembly to try to outsmart the compiler unless you're 100% sure the assembly you're writing is actually good.
- And if so, try to restructure your C++ code so the compiler vectorizes it/makes it better, right?
- Or if that fails, use intrinsics instead of raw `asm volatile`.
- Use `std::optional<>` instead of `std::unique_ptr<>` if possible.
- `std::unique_ptr<>` carries indirection cost due to it being memory allocated on the heap.
- It isn't often that objects that contain `std::unique_ptr<>`, are allocated on the heap themselves, allocating even more things on the heap seems redundant.
- Avoid `std::recursive_mutex` at all costs.
- It's basically implemented as a linked list most of the time and has HEAVY performance penalties.
- Exploit the fact `std::atomic<uint32_t>/std::atomic<int32_t>` is basically free on most arches that matter.
- In x86_64, an atomic `uint32_t` is basically `mov [m32], r32`, which is essentially free/cheap.
- Avoid template parameters unless you really need them.
- For small inlineable functions this is fine, for more complex ones, please consider the generated assembly.
- Dont make your own memcpy/memset/strcpy/strncpy/etc.
- Seriously DON'T DO THIS. You will NOT beat the compiler.
- Nor 30 years of writing optimized `mem*`.
- If your code is slow, don't blame `mem*`, blame your code.
- Try to avoid using `virtual` since vtable indirection has a cost
- Avoid `dynamic_cast` and `typeid` at all costs.
- The reason is because the project has `-fno-rtti` disabled by default, due to the costs of dynamic polymorphism.
- Always copy-on-value for objects with `sizeof(void *) >= sizeof(T) * 2`, i.e objects sized as 2 pointers or less, for bigger objects you can use ref/pointer as usual.
- Try using move semantics instead of references, whenever possible.
- Remember function parameters are extremelly cheap as fuck, don't be afraid to place upto 8 parameters on a given function.
- Don't save a reference in structures of a parent object, i.e:
```c++
struct Child {
Parent& parent;
void Mehod() {
parent.Something();
}
};
```
- Instead you can do the following:
```c++
struct Child {
void Mehod(Parent& parent) {
parent.Something();
}
};
```
- This reduces the amount of pointers you have lying around, and also works better because of the aforementioned cheapness of parameter functions.
Try not using hungarian notation, if you're able.
# Engineering guidelines
## Formatting
Coding isn't also writing stuff but architecturing stuff, consider the following:
Formatting is extremelly lax, the general rule of thumb is: Don't add new lines just to increase line count. The less lines we have to look at, the better. This means also packing densely your code while not making it a clusterfuck. Strike a balance of "this is a short and comprehensible piece of code" and "my eyes are actually happy to see this!". Don't just drop the entire thing in a single line and call it "dense code", that's just spaghetti posing as code. In general, be mindful of what other devs need to look at.
Do not put if/while/etc braces after lines:
```c++
// no dont do this
// this is more lines of code for no good reason (why braces need their separate lines?)
// and those take space in someone's screen, cumulatively
if (thing)
{ //<--
some(); // ...
} //<-- 2 lines of code for basically "opening" and "closing" an statment
// do this
if (thing) { //<-- [...] and with your brain you can deduce it's this piece of code
// that's being closed
some(); // ...
} //<-- only one line, and it's clearer since you know its closing something [...]
// or this, albeit the extra line isn't needed (at your discretion of course)
if (thing)
some(); // ...
// this is also ok, keeps things in one line and makes it extremely clear
if (thing) some();
// NOT ok, don't be "clever" and use the comma operator to stash a bunch of statments
// in a single line, doing this will definitely ruin someone's day - just do the thing below
// vvv
if (thing) some(), thing(), a2(a1(), y1(), j1()), do_complex_shit(wa(), wo(), ploo());
// ... and in general don't use the comma operator for "multiple statments", EXCEPT if you think
// that it makes the code more readable (the situation may be rare however)
// Wow so much clearer! Now I can actually see what each statment is meant to do!
if (thing) {
some();
thing();
a2(a1(), y1(), j1());
do_complex_shit(wa(), wo(), ploo());
}
```
Brace rules are lax, if you can get the point across, do it:
```c++
// this is fine
do {
if (thing) {
return 0;
}
} while (other);
// this is also ok --- albeit a bit more dense
do if (thing) return 0; while (other);
// ok as well
do {
if (thing) return 0;
} while (other);
```
There is no 80-column limit but preferably be mindful of other developer's readability (like don't just put everything onto one line).
```c++
// someone is going to be mad due to this
SDL_AudioSpec obtained;
device_name.empty() ? device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false) : device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
// maybe consider this
SDL_AudioSpec obtained;
if (device_name.empty()) {
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
} else {
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
}
// or this is fine as well
SDL_AudioSpec obtained;
device = SDL_OpenAudioDevice(device_name.empty() ? nullptr : device_name.c_str(), capture, &spec, &obtained, false);
```
A note about operators: Use them sparingly, yes, the language is lax on them, but some usages can be... tripping to say the least.
```c++
a, b, c; //<-- NOT OK multiple statments with comma operator is definitely a recipe for disaster
return c ? a : b; //<-- OK ternaries at end of return statments are clear and fine
return a, b; //<-- NOT OK return will take value of `b` but also evaluate `a`, just use a separate statment
void f(int a[]) //<-- OK? if you intend to use the pointer as an array, otherwise just mark it as *
```
And about templates, use them sparingly, don't just do meta-templating for the sake of it, do it when you actually need it. This isn't a competition to see who can make the most complicated and robust meta-templating system. Just use what works, and preferably stick to the standard libary instead of reinventing the wheel. Additionally:
```c++
// NOT OK This will create (T * N * C * P) versions of the same function. DO. NOT. DO. THIS.
template<typename T, size_t N, size_t C, size_t P> inline void what() const noexcept;
// OK use parameters like a normal person, don't be afraid to use them :)
template<typename T> inline void what(size_t n, size_t c, size_t p) const noexcept;
```
- Try to reduce dependency on... dependencies
- While some dependencies are useful `boost::container` and `fmt` to name a few, remember each dependency added incurs a cost.
- It may also be subpar with a hand rolled implementation, biggest exemplar of this is `spirv-tools` providing subpar SPIRV optimizations in comparison to the in-house optimizer.
- Try to rely less on indirection for architecturing systems
- If the underlying HLE kernel emulation requires it, try making a solution that keeps things local
- For example, there isn't a need for file descriptors to each be a pointer, when they could be a fixed table size with elements that may be emplaced at will.
+126
View File
@@ -0,0 +1,126 @@
# Coding Style guidelines
These are mostly "suggestions", if you feel like your code is readable, comprehensible to others; and most importantly doesn't result in unreadable spaghetti you're fine to go.
But for new developers you may find that following these guidelines will make everything x10 easier.
## Naming conventions
Simply put, types/classes are named as `PascalCase`, same for methods and functions like `AddElement`. Variables are named `like_this_snake_case` and constants are `IN_SCREAMING_CASE`.
Except for Qt MOC where `functionName` is preferred.
Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well. Do not use names like `SS` as systems like solaris define it for registers, in general do not use any of the following for short names:
- `SS`, `DS`, `GS`, `FS`: Segment registers, defined by Solaris `<ucontext.h>`
- `EAX`, `EBX`, `ECX`, `EDX`, `ESI`, `EDI`, `ESP`, `EBP`, `EIP`: Registers, defined by Solaris.
- `X`: Defined by some utility headers, avoid.
- `_`: Defined by gettext, avoid.
- `N`, `M`, `S`: Preferably don't use this for types, use it for numeric constants.
- `TR`: Used by some weird `<ucontext.h>` whom define the Task Register as a logical register to provide to the user... (Need to remember which OS in specific).
Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`.
Try not using hungarian notation, if you're able.
## Formatting
Formatting is extremelly lax, the general rule of thumb is: Don't add new lines just to increase line count. The less lines we have to look at, the better. This means also packing densely your code while not making it a clusterfuck. Strike a balance of "this is a short and comprehensible piece of code" and "my eyes are actually happy to see this!". Don't just drop the entire thing in a single line and call it "dense code", that's just spaghetti posing as code. In general, be mindful of what other devs need to look at.
Do not put if/while/etc braces after lines:
```c++
// no dont do this
// this is more lines of code for no good reason (why braces need their separate lines?)
// and those take space in someone's screen, cumulatively
if (thing)
{ //<--
some(); // ...
} //<-- 2 lines of code for basically "opening" and "closing" an statment
// do this
if (thing) { //<-- [...] and with your brain you can deduce it's this piece of code
// that's being closed
some(); // ...
} //<-- only one line, and it's clearer since you know its closing something [...]
// or this, albeit the extra line isn't needed (at your discretion of course)
if (thing)
some(); // ...
// this is also ok, keeps things in one line and makes it extremely clear
if (thing) some();
// NOT ok, don't be "clever" and use the comma operator to stash a bunch of statments
// in a single line, doing this will definitely ruin someone's day - just do the thing below
// vvv
if (thing) some(), thing(), a2(a1(), y1(), j1()), do_complex_shit(wa(), wo(), ploo());
// ... and in general don't use the comma operator for "multiple statments", EXCEPT if you think
// that it makes the code more readable (the situation may be rare however)
// Wow so much clearer! Now I can actually see what each statment is meant to do!
if (thing) {
some();
thing();
a2(a1(), y1(), j1());
do_complex_shit(wa(), wo(), ploo());
}
```
Brace rules are lax, if you can get the point across, do it:
```c++
// this is fine
do {
if (thing) {
return 0;
}
} while (other);
// this is also ok --- albeit a bit more dense
do if (thing) return 0; while (other);
// ok as well
do {
if (thing) return 0;
} while (other);
```
There is no 80-column limit but preferably be mindful of other developer's readability (like don't just put everything onto one line).
```c++
// someone is going to be mad due to this
SDL_AudioSpec obtained;
device_name.empty() ? device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false) : device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
// maybe consider this
SDL_AudioSpec obtained;
if (device_name.empty()) {
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
} else {
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
}
// or this is fine as well
SDL_AudioSpec obtained;
device = SDL_OpenAudioDevice(device_name.empty() ? nullptr : device_name.c_str(), capture, &spec, &obtained, false);
```
A note about operators: Use them sparingly, yes, the language is lax on them, but some usages can be... tripping to say the least.
```c++
a, b, c; //<-- NOT OK multiple statments with comma operator is definitely a recipe for disaster
return c ? a : b; //<-- OK ternaries at end of return statments are clear and fine
return a, b; //<-- NOT OK return will take value of `b` but also evaluate `a`, just use a separate statment
void f(int a[]) //<-- OK? if you intend to use the pointer as an array, otherwise just mark it as *
```
And about templates, use them sparingly, don't just do meta-templating for the sake of it, do it when you actually need it. This isn't a competition to see who can make the most complicated and robust meta-templating system. Just use what works, and preferably stick to the standard libary instead of reinventing the wheel. Additionally:
```c++
// NOT OK This will create (T * N * C * P) versions of the same function. DO. NOT. DO. THIS.
template<typename T, size_t N, size_t C, size_t P> inline void what() const noexcept;
// OK use parameters like a normal person, don't be afraid to use them :)
template<typename T> inline void what(size_t n, size_t c, size_t p) const noexcept;
```
-159
View File
@@ -1,159 +0,0 @@
# User Handbook - Adding Boolean Settings Toggles
> [!WARNING]
> This guide is intended for developers ONLY. If you are not a developer, this likely irrelevant to yourself.
>
> If you want to add temporary toggles, please refer to **[Adding Debug Knobs](AddingDebugKnobs.md)**
This guide will walk you through adding a new boolean toggle setting to Eden's configuration across both Qt's (PC) and Kotlin's (Android) UIs.
## Index
1. [Step 1 - Common Setting](#step-1-common-setting)
2. [Step 2 - Qt Toggle](#step-2-qt-toggle)
3. [Step 3 - Kotlin (Android)](#step-3-kotlin-android)
* [Step 3.1 - BooleanSetting.kt](#step-3-1-booleansetting-kt)
* [Step 3.2 - SettingsItem.kt](#step-3-2-settingsitem-kt)
* [Step 3.3 - SettingsFragmentPresenter.kt](#step-3-3-settingsfragmentpresenter-kt)
* [Step 3.4 - Localization](#step-3-4-localization)
4. [Step 4 - Use Your Toggle](#step-4-use-your-toggle)
5. [Best Practices](#best-practices)
---
## Step 1 - Common Setting
Firstly add your desired toggle:
Example: `src/common/setting.h`
```cpp
SwitchableSetting<bool> your_setting_name{linkage, false, "your_setting_name", Category::RendererExtensions};
```
### Remember to add your toggle to the appropriate category, for example:
Common Categories:
* Category::Renderer
* Category::RendererAdvanced
* Category::RendererExtensions
* Category::System
* Category::Core
> [!WARNING]
> If you wish for your toggle to be `on by default` then change `false` to `true` after `linkage,`.
---
## Step 2 - Qt Toggle
Add the toggle to the Qt UI, where you wish for it to appear and place it there.
Example: `src/qt_common/config/shared_translation.cpp`
```cpp
INSERT(Settings,
your_setting_name,
tr("Your Setting Display Name"),
tr("Detailed description of what this setting does.\n"
"You can use multiple lines.\n"
"Explain any caveats or requirements."));
```
### Make sure to:
* Keep display naming consistant
* Put detailed info in the description
* Use `\n` for line breaks in descriptions
---
## Step 3 - Kotlin (Android)
### Step 3.1 - BooleanSetting.kt
Add where it should be in the settings.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt`
```kts
RENDERER_YOUR_SETTING_NAME("your_setting_name"),
```
### Make sure to:
* Ensure the prefix naming matches the intended category.
---
### Step 3.2 - SettingsItem.kt
Add the toggle to the Kotlin (Android) UI
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt`
```kts
put(
SwitchSetting(
BooleanSetting.RENDERER_YOUR_SETTING_NAME,
titleId = R.string.your_setting_name,
descriptionId = R.string.your_setting_name_description
)
)
```
---
### Step 3.3 - SettingsFragmentPresenter.kt
Add your setting within the right category.
Example: `src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt`
```kts
add(BooleanSetting.RENDERER_YOUR_SETTING_NAME.key)
```
> [!WARNING]
> Remember, placing matters! Settings appear in the order of where you add them.
---
### Step 3.4 - Localization
Add your setting and description in the appropriate place.
Example: `src/android/app/src/main/res/values/strings.xml`
```xml
<string name="your_setting_name">Your Setting Display Name</string>
<string name="your_setting_name_description">Detailed description of what this setting does. Explain any caveats, requirements, or warnings here.</string>
```
---
## Step 4 - Use Your Toggle!
Now the UI part is done find a place in the code for the toggle,
And use it to your heart's desire!
Example:
```cpp
const bool your_value = Settings::values.your_setting_name.GetValue();
if (your_value) {
// Do something when enabled
}
```
If you wish to do something only when the toggle is disabled,
Use `if (!your_value) {` instead of `if (your_value) {`.
---
## Best Practices
* Naming - Use clear, descriptive names. Something for both the devs and the users.
* Defaults - Choose safe default values (usually false for new features).
* Documentation - Write clear descriptions explaining when and why to use the setting.
* Categories - Put settings in the appropriate category.
* Order - Place related settings near each other.
* Testing - Always test on both PC and Android before committing when possible.
### Thank you for reading, I hope this guide helped you making your toggle!
-167
View File
@@ -1,167 +0,0 @@
# User Handbook - Adding Debug Knobs
Debug Knobs is a 16-bit integer setting (`debug_knobs`) in the Eden Emulator that serves as a bitmask for gating various testing and debugging features. This allows developers and advanced users to enable or disable specific debug behaviors without requiring deploying of complete but temporary toggles.
The setting ranges from 0 to 65535 (0x0000 to 0xFFFF), where each bit represents a different debug feature flag.
## Index
1. [Advantages](#advantages)
2. [Usage](#usage)
* [Accessing Debug Knobs (dev side)](#accessing-debug-knobs-dev-side)
* [Setting Debug Knobs (user side)](#setting-debug-knobs-user-side)
* [Bit Manipulation Examples](#bit-manipulation-examples)
3. [Terminology and user communication](#terminology-and-user-communication)
4. [Examples](#examples)
* [Example 1: Conditional Debug Logging](#example-1-conditional-debug-logging)
* [Example 2: Performance Tuning](#example-2-performance-tuning)
* [Example 3: Feature Gating](#example-3-feature-gating)
5. [Best Practices](#best-practices)
---
## Advantages
The main advantage is to avoid deploying new disposable toggles (those made only for testing stage, and are disposed once new feature gets good to merge). This empowers devs to be free of all frontend burocracy and hassle of new toggles.
Common advantages recap:
* **Fine-Grained Control**: Enable or disable up to 16 individual debug features independently using bit manipulation on a single build
* **Runtime Configuration**: Change debug behavior at runtime the same way as new toggles would do
* **Safe incremental development**: New debug features can be added while impact can be isolated from previous deployments
## Usage
### Accessing Debug Knobs (dev side)
Use the `Settings::getDebugKnobAt(u8 i)` function to check if a specific bit is set:
```cpp
//cpp side
#include "common/settings.h"
// Check if bit 0 is set
bool feature_enabled = Settings::getDebugKnobAt(0);
// Check if bit 15 is set
bool another_feature = Settings::getDebugKnobAt(15);
```
```kts
//kotlin side
import org.yuzu.yuzu_emu.features.settings.model.Settings
// Check if bit x is set
bool feature_enabled = Settings.getDebugKnobAt(x); //x as integer from 0 to 15
```
The function returns `true` if the specified bit (0-15) is set in the `debug_knobs` value, `false` otherwise.
### Setting Debug Knobs (user side)
Developers must inform which knobs are tied to each functionality to be tested.
The debug knobs value can be set through:
1. **Desktop UI**: In the Debug configuration tab, there's a spinbox for "Debug knobs" (0-65535)
2. **Android UI**: Available as an integer setting in the Debug section
3. **Configuration Files**: Set the `debug_knobs` value in the emulator's configuration
### Bit Manipulation Examples
To enable specific features, calculate the decimal value by setting the appropriate bits:
* **Enable only bit 0**: Value = 1 (2^0)
* **Enable only bit 1**: Value = 2 (2^1)
* **Enable bits 0 and 1**: Value = 3 (2^0 + 2^1)
* **Enable bit 15**: Value = 32768 (2^15)
## Terminology and user communication
There are two main confusions when talking about knobs:
### Whether it's zero-based or one-based
Sometimes when an user reports: knobs 1 and 2 gets better performance, dev may get confuse whether he means the knobs 1 and 2 literally, or the 1st and 2nd knobs (knobs 0 and 1).
Debug knobs are **zero-based**, which means:
* The first knob is the knob(0) (or knob0 henceforth), and the last one is the 15 (knob15, likewise)
* You can talk: "knob0 is enabled/disabled", "In this video i was using only knobs 0 and 2", etc.
### Whether one is talking about the knob itself or about the entire parameter value (which represents all knobs)
Sometimes when an user reports: knob 3 results, it's unclear whether he's referring to knob setting with value 3 (which means both knob 0 and 1 are enabled), or to knob(3) specifically.
Whenever you're instructing tests or reporting results, be precise about whether one you're talking to avoid confusion:
### Setting based terminology
ALWAYS use the word in PLURAL (knobs), without mentioning which one, to refer to the setting, aka multiple knobs at once:
Examples:
- **knobs=0**: no knobs enabled
- **knobs=1**: knob0 enabled, others disabled
- **knobs=2**: knob1 enabled, others disabled
- **knobs=3**: knobs 0 and 1 enabled, others disabled
...
### Knob based terminology
Use the word in SINGULAR (knob), or in plural but referring which ones, when meaning multiple knobs at once:
Examples:
- **knob0**: knob 0 enabled, others disabled
- **knob1**: knob 1 enabled, others disabled
- **knobs 0 and 1**: knobs 0 and 1 enabled, others disabled
...
## Examples
### Example 1: Conditional Debug Logging
```cpp
void SomeFunction() {
if (Settings::getDebugKnobAt(0)) {
LOG_DEBUG(Common, "Debug feature 0 is enabled");
// Additional debug code here
}
if (Settings::getDebugKnobAt(1)) {
LOG_DEBUG(Common, "Debug feature 1 is enabled");
// Different debug behavior
}
}
```
### Example 2: Performance Tuning
```cpp
bool UseOptimizedPath() {
// Skip optimization if debug bit 2 is set for testing
return !Settings::getDebugKnobAt(2);
}
```
### Example 3: Feature Gating
```cpp
void ExperimentalFeature() {
static constexpr u8 EXPERIMENTAL_FEATURE_BIT = 3;
if (!Settings::getDebugKnobAt(EXPERIMENTAL_FEATURE_BIT)) {
// Fallback to stable implementation
StableImplementation();
return;
}
// Experimental implementation
ExperimentalImplementation();
}
```
## Best Practices
* This setting is intended for development and testing purposes only
* Knobs must be unwired before PR creation
* The setting is per-game configurable, allowing different debug setups for different titles
+1 -1
View File
@@ -40,7 +40,7 @@ Windows/riscv64 doesn't exist, and may never (until corporate greed no longer co
Android/riscv64 is interesting. While support for it may be added if and when RISC-V phones/handhelds ever go mainstream, arm64 devices will always be preferred due to NCE.
Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution that has *at least* the standard build tools, Qt, FFmpeg, and SDL2 should work.
Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution that has *at least* the standard build tools, Qt, FFmpeg, and SDL3 should work.
## Other
+8
View File
@@ -9,3 +9,11 @@ At the moment of writing, we do not support CFW such as Atmosphere, due to:
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!
## Atmosphere
Fusee Galee, the bootloader and other low-level mechanisms are not emulated at the moment.
Having OFW is recommended, but may not be required (untested).
Extract the contents of Atmosphere into `sdmc`. Then to launch simply use `-hlaunch` instead (orthogonal to `-qlaunch`).
+6 -1
View File
@@ -1,17 +1,22 @@
# User Handbook - Command Line
There are two main applications, an SDL2 based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
There are two main applications, an SDL-based app (`eden-cli`) and a Qt based app (`eden`); both accept command line arguments.
## eden
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behaviour is similar to `eden-cli`; allows dragging and dropping games into the application.
- `-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
- `-f`: Use fullscreen.
- `-u <number>`: Select the index of the user to load as.
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
- `-qlaunch`: Launch QLaunch.
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
- `-setup`: Launch setup applet.
## eden-cli
- `--debug/-d`: Enter debug mode, allow gdb stub at port `1234`
- `--config/-c`: Specify alternate configuration file.
- `--fullscreen/-f`: Set fullscreen.
+4
View File
@@ -44,6 +44,10 @@ Various graphical filters exist - each of them aimed at a specific target/image
- **MMPX**: Nearest-neighbour filter aimed at providing higher pixel-art quality.
- **Pros**: Offers decent pixel-art upscaling.
- **Cons**: Only works for pixel-art.
- **SGSR**: Uses Snapdragon Studios Game Super Resolution to enhance image quality (similar to FSR, but for Adreno devices).
- **Pros**: Optimized for Adreno devices.
- **Cons**: Doesn't play nicely with non-Adreno devices.
- **SGSR Edge**: Almost the same pipeline as SGSR, but with improved edge detection.
### Anisotropy values
+1 -1
View File
@@ -1,4 +1,4 @@
# Multiplayer
# User Handbook - Multiplayer
Use this guide to answer questions regarding and to start using the multiplayer functionality of Eden.
## Multiplayer FAQ
+8 -7
View File
@@ -25,12 +25,12 @@ A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/
- **[Importing Saves](./ImportingSaves.md)**
- **[Installing Atmosphere Mods](./InstallingAtmosphereMods.md)**
- **[Installing Updates & DLCs](./InstallingUpdatesDLC.md)**
- **[Alter Date & Time](./AlterDateTime.md)**
- **[Multiplayer](./Multiplayer.md)**
## 3rd-party Integration
- **[Configuring Steam ROM Manager](./SteamROM.md)**
- **[Server hosting](ServerHosting.md)**
- **[Server hosting](./ServerHosting.md)**
- **[Syncthing Guide](./SyncthingGuide.md)**
- **[Third Party](./ThirdParty.md)**
- **[Obtainium](./ThirdParty.md#configuring-obtainium)**
@@ -40,12 +40,13 @@ A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/
## Advanced
- **[Command Line](./CommandLine.md)**
- **[Custom Firmware](./CFW.md)**
- **[Alter Date & Time](./AlterDateTime.md)**
- **[How To Access Logs](./HowToAccessLogs.md)**
- **[Gyro Controls](./GyroControls.md)**
- **[Platforms and Architectures](Architectures.md)**
- **[Command Line](CommandLine.md)**
- **[Native Application Development](Native.md)**
- **[Adding Boolean Settings Toggles](AddingBooleanToggles.md)**
- **[Platforms and Architectures](./Architectures.md)**
- **[Native Application Development](./Native.md)**
- **[Adding Boolean Settings Toggles](./AddingBooleanToggles.md)**
- **[Adding Debug Knobs](./AddingDebugKnobs.md)**
- **[Testing](Testing.md)**
- **[Testing](./Testing.md)**
+1 -1
View File
@@ -59,7 +59,7 @@ EmuDeck will automatically create an *Emulators - Emulators* parser for ***Steam
4. Paste the following code into the contents of the file, save and close the file.
```bash
#!/bin/bash
#!/bin/sh -e
emuName="eden" #parameterize me
. "$HOME/.config/EmuDeck/backend/functions/all.sh"
+1
View File
@@ -13,6 +13,7 @@ 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://codeberg.org/eden-emu/eden
- https://collective.taymaerz.de/eden/eden
Other mirrors obviously exist on the internet, but we can't guarantee their reliability and/or availability.
+16 -12
View File
@@ -136,8 +136,7 @@ if(ENABLE_CUBEB)
endif()
if (NOT ANDROID)
if (YUZU_USE_EXTERNAL_SDL2)
message(STATUS "Using SDL2 from externals.")
if (NOT YUZU_USE_BUNDLED_SDL3)
if (NOT WIN32)
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
@@ -158,21 +157,26 @@ if (NOT ANDROID)
set(SDL_FILE ON)
endif()
if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck")
set(SDL_PIPEWIRE OFF) # build errors out with this on
AddJsonPackage("sdl2_steamdeck")
else()
AddJsonPackage("sdl2_generic")
endif()
elseif (YUZU_USE_BUNDLED_SDL2)
message(STATUS "Using bundled SDL2")
AddJsonPackage(sdl3)
else()
message(STATUS "Using bundled SDL3")
if (PLATFORM_FREEBSD)
set(BUILD_SHARED_LIBS ON)
endif()
AddJsonPackage(sdl2)
AddJsonPackage(sdl3-ci)
endif()
find_package(SDL2 2.26.4 REQUIRED)
# Normalize SDL3 link target across package variants.
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
if (NOT TARGET SDL3::SDL3)
if (TARGET SDL3::SDL3-shared)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
elseif (TARGET SDL3::SDL3-static)
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
else()
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
endif()
endif()
endif()
set(BUILD_SHARED_LIBS OFF)
+11 -21
View File
@@ -30,7 +30,6 @@
"tag": "v%VERSION%",
"hash": "5efa8140aadffe105dcf39935b732476e95755f6c7473ada3d0b64df2bc02c557633ae3948a25b45e1cf67e89a3ff6329fb30362e4ac033b9a1d1e453aa2eded",
"git_version": "0.37.0",
"version": "0.18.7",
"find_args": "MODULE GLOBAL",
"patches": [
"0001-mingw.patch",
@@ -123,13 +122,13 @@
"BUNDLE_SPEEX ON"
]
},
"sdl2": {
"sdl3-ci": {
"ci": true,
"package": "SDL2",
"name": "SDL2",
"repo": "crueter-ci/SDL2",
"version": "2.32.10-3c28e8ecc0",
"min_version": "2.26.4"
"package": "SDL3",
"name": "SDL3",
"repo": "crueter-ci/SDL3",
"version": "3.4.8-d57c3b685c",
"min_version": "3.2.10"
},
"catch2": {
"package": "Catch2",
@@ -157,22 +156,13 @@
"find_args": "MODULE",
"git_version": "4.25"
},
"sdl2_generic": {
"package": "SDL2",
"sdl3": {
"package": "SDL3",
"repo": "libsdl-org/SDL",
"tag": "release-%VERSION%",
"hash": "d5622d6bb7266f7942a7b8ad43e8a22524893bf0c2ea1af91204838d9b78d32768843f6faa248757427b8404b8c6443776d4afa6b672cd8571a4e0c03a829383",
"bundled": true,
"git_version": "2.32.10",
"skip_updates": true
},
"sdl2_steamdeck": {
"package": "SDL2",
"repo": "libsdl-org/SDL",
"sha": "cc016b0046",
"hash": "b8d9873446cdb922387471df9968e078714683046674ef0d0edddf8e25da65a539a3bae83d635496b970237f90b07b36a69f8d7855d450de59311d6d6e8c3dbc",
"bundled": true,
"skip_updates": "true"
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
"git_version": "3.4.8",
"version": "3.2.10"
},
"moltenvk": {
"repo": "V380-Ori/Ryujinx.MoltenVK",
+21 -6
View File
@@ -1,3 +1,6 @@
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2023 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
@@ -16,15 +19,24 @@ if (NOT FILE_LIST)
endif()
set(DIRECTORY_NAME ${HEADER_NAME})
set(FILE_DATA "")
string(APPEND FILE_DATA "[[nodiscard]] static inline std::vector<FileSys::VirtualFile> CollectFiles_${DIRECTORY_NAME}() {\n")
string(APPEND FILE_DATA [[
std::vector<FileSys::VirtualFile> vfs_files;
auto const fn = [&](std::string_view name, std::span<const u8> data) {
vfs_files.push_back(std::make_shared<FileSys::VectorVfsFile>(
std::vector<u8>(data.begin(), data.end()),
std::string{name}
));
};
]])
foreach(ZONE_FILE ${FILE_LIST})
if (ZONE_FILE STREQUAL "\n")
continue()
endif()
string(APPEND FILE_DATA "{\"${ZONE_FILE}\",\n{")
string(APPEND FILE_DATA " {\n")
string(APPEND FILE_DATA " constexpr uint8_t tzdb_data[] = {\n")
file(READ ${ZONE_PATH}/${ZONE_FILE} ZONE_DATA HEX)
string(LENGTH "${ZONE_DATA}" ZONE_DATA_LEN)
foreach(I RANGE 0 ${ZONE_DATA_LEN} 2)
@@ -42,9 +54,12 @@ foreach(ZONE_FILE ${FILE_LIST})
string(APPEND FILE_DATA " ")
endif()
endforeach()
string(APPEND FILE_DATA "}},\n")
string(APPEND FILE_DATA " };\n")
string(APPEND FILE_DATA " fn(\"${ZONE_FILE}\", tzdb_data);\n")
string(APPEND FILE_DATA " }\n")
endforeach()
string(APPEND FILE_DATA " return vfs_files;\n")
string(APPEND FILE_DATA "}\n")
file(READ ${NX_TZDB_SOURCE_DIR}/tzdb_template.h.in NX_TZDB_TEMPLATE_H_IN)
file(CONFIGURE OUTPUT ${NX_TZDB_INCLUDE_DIR}/nx_tzdb/${HEADER_NAME}.h CONTENT "${NX_TZDB_TEMPLATE_H_IN}")
+6 -3
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -9,10 +12,10 @@
namespace NxTzdb {
// @DIRECTORY_NAME@
// clang-format off
const static std::map<const char*, const std::vector<uint8_t>> @DIRECTORY_NAME@ =
{
@FILE_DATA@};
@FILE_DATA@
// clang-format on
} // namespace NxTzdb
+7 -6
View File
@@ -1,5 +1,7 @@
#!/bin/sh
#!/bin/sh -e
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: 2015 Citra Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
@@ -10,20 +12,19 @@ paths_to_check="src/ CMakeLists.txt"
# If there are whitespace errors, print the offending file names and fail.
if ! git diff --cached --check -- $paths_to_check ; then
cat<<END
cat<<EOF
Error: This commit would contain trailing spaces or tabs, which is against this repo's policy.
Please correct those issues before committing. (Use 'git diff --check' for more details)
If you know what you are doing, you can try 'git commit --no-verify' to bypass the check
END
EOF
exit 1
fi
# Check for tabs, since tab-in-indent catches only those at the beginning of a line
if git diff --cached -- $paths_to_check | egrep '^\+.* '; then
cat<<END
cat<<EOF
Error: This commit would contain a tab, which is against this repo's policy.
If you know what you are doing, you can try 'git commit --no-verify' to bypass the check.
END
EOF
exit 1
fi
Regular → Executable
+5 -1
View File
@@ -1,3 +1,7 @@
#!/usr/bin/nix-shell
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
let
nixpkgs = fetchTarball "https://github.com/NixOS/nixpkgs/tarball/nixos-24.05";
pkgs = import nixpkgs { config = {}; overlays = []; };
@@ -16,7 +20,7 @@ pkgs.mkShellNoCC {
qt6.qtbase qt6.qtmultimedia qt6.qtwayland qt6.qttools
qt6.qtwebengine qt6.qt5compat
# eden-cli
SDL2
SDL3
# optional components
discord-rpc gamemode
];
@@ -127,6 +127,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener, InputManager
super.onCreate(savedInstanceState)
NativeConfig.reloadGlobalConfig()
InputHandler.updateControllerData()
val players = NativeConfig.getInputSettings(true)
var hasConfiguredControllers = false
@@ -16,6 +16,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
ANTIFLICKER("antiflicker"),
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
EMULATE_BGR565("emulate_bgr565"),
RESCALE_HACK("rescale_hack"),
@@ -750,6 +750,13 @@ abstract class SettingsItem(
descriptionId = R.string.skip_cpu_inner_invalidation_description
)
)
put(
SwitchSetting(
BooleanSetting.ANTIFLICKER,
titleId = R.string.antiflicker,
descriptionId = R.string.antiflicker_description
)
)
put(
SwitchSetting(
BooleanSetting.FIX_BLOOM_EFFECTS,
@@ -76,18 +76,25 @@ class SettingsFragmentPresenter(
}
}
private fun isFsrScalingFilterSelected(): Boolean {
val fsrFilterValue = resolveFsrScalingFilterValue() ?: return false
private fun isSharpnessScalingFilterSelected(): Boolean {
val needsGlobal = getNeedsGlobalForKey(IntSetting.RENDERER_SCALING_FILTER.key)
val selectedFilter = IntSetting.RENDERER_SCALING_FILTER.getInt(needsGlobal)
return selectedFilter == fsrFilterValue
return selectedFilter in resolveSharpnessScalingFilterValues()
}
private fun resolveFsrScalingFilterValue(): Int? {
private fun resolveSharpnessScalingFilterValues(): Set<Int> {
val names = context.resources.getStringArray(R.array.rendererScalingFilterNames)
val values = context.resources.getIntArray(R.array.rendererScalingFilterValues)
val fsrIndex = names.indexOf(context.getString(R.string.scaling_filter_fsr))
return if (fsrIndex in values.indices) values[fsrIndex] else null
val sharpnessFilterNames = setOf(
context.getString(R.string.scaling_filter_fsr),
context.getString(R.string.scaling_filter_sgsr),
context.getString(R.string.scaling_filter_sgsr_edge),
)
return names.asSequence()
.mapIndexedNotNull { index, name ->
if (name in sharpnessFilterNames && index in values.indices) values[index] else null
}
.toSet()
}
// Allows you to show/hide abstract settings based on the paired setting key
@@ -267,7 +274,7 @@ class SettingsFragmentPresenter(
add(IntSetting.RENDERER_RESOLUTION.key)
add(IntSetting.RENDERER_VSYNC.key)
add(IntSetting.RENDERER_SCALING_FILTER.key)
if (isFsrScalingFilterSelected()) {
if (isSharpnessScalingFilterSelected()) {
add(IntSetting.FSR_SHARPENING_SLIDER.key)
}
add(IntSetting.RENDERER_ANTI_ALIASING.key)
@@ -291,6 +298,7 @@ class SettingsFragmentPresenter(
add(IntSetting.FAST_GPU_TIME.key)
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
add(BooleanSetting.ANTIFLICKER.key)
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
add(BooleanSetting.EMULATE_BGR565.key)
add(BooleanSetting.RESCALE_HACK.key)
@@ -1090,7 +1090,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
private fun addQuickSettings() {
binding.quickSettingsSheet.apply {
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
val isFsrSelected = isFsrScalingFilterSelected()
val isSharpnessFilterSelected = isSharpnessScalingFilterSelected()
container.removeAllViews()
@@ -1176,7 +1176,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
addQuickSettings()
}
if (isFsrSelected) {
if (isSharpnessFilterSelected) {
quickSettings.addSliderSetting(
R.string.fsr_sharpness,
container,
@@ -1197,17 +1197,24 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
private fun isFsrScalingFilterSelected(): Boolean {
val fsrFilterValue = resolveFsrScalingFilterValue() ?: return false
private fun isSharpnessScalingFilterSelected(): Boolean {
val selectedFilter = IntSetting.RENDERER_SCALING_FILTER.getInt(needsGlobal = false)
return selectedFilter == fsrFilterValue
return selectedFilter in resolveSharpnessScalingFilterValues()
}
private fun resolveFsrScalingFilterValue(): Int? {
private fun resolveSharpnessScalingFilterValues(): Set<Int> {
val names = resources.getStringArray(R.array.rendererScalingFilterNames)
val values = resources.getIntArray(R.array.rendererScalingFilterValues)
val fsrIndex = names.indexOf(getString(R.string.scaling_filter_fsr))
return if (fsrIndex in values.indices) values[fsrIndex] else null
val sharpnessFilterNames = setOf(
getString(R.string.scaling_filter_fsr),
getString(R.string.scaling_filter_sgsr),
getString(R.string.scaling_filter_sgsr_edge),
)
return names.asSequence()
.mapIndexedNotNull { index, name ->
if (name in sharpnessFilterNames && index in values.indices) values[index] else null
}
.toSet()
}
private fun openQuickSettingsMenu() {
@@ -19,6 +19,9 @@ AndroidConfig::AndroidConfig(const std::string& config_name, ConfigType config_t
}
void AndroidConfig::ReloadAllValues() {
// Ensure the INI file is current before reloading values.
SetUpIni();
Reload();
ReadAndroidValues();
SaveAndroidValues();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 67 KiB

@@ -489,6 +489,8 @@
<string name="enable_buffer_history">Activar el historial del búfer</string>
<string name="enable_buffer_history_description">Permite el acceso al estado del búfer anterior. Esta opción puede mejorar la calidad de renderizado y la consistencia en el rendimiento de algunos juegos.</string>
<string name="use_optimized_vertex_buffers">Búferes de vértices optimizados</string>
<string name="use_optimized_vertex_buffers_description">Permite la optimización del enlace del búfer de vértices para un mejor rendimiento. Requiere controladores Mesa 26.0+ Turnip/ controladores QCOM. Fallará con controladores Turnip más antiguos (versión 25.3 o inferior).</string>
<string name="hacks">Hacks</string>
<string name="fast_gpu_time">Tiempo rápido de la GPU</string>
@@ -500,6 +502,7 @@
<string name="emulate_bgr565">Emular BGR565</string>
<string name="emulate_bgr565_description">Soluciona problemas con colores invertidos en juegos, artefactos o sombras extrañas.</string>
<string name="rescale_hack">Activar la pasada de reescalado heredada</string>
<string name="rescale_hack_description">Permite el manejo de versiones anteriores para el paso de configuración de reescalado para juegos mediante el uso de una ruta de reescalado rápida.</string>
<string name="renderer_asynchronous_shaders">Usar sombreadores asíncronos</string>
<string name="renderer_asynchronous_shaders_description">Compila los sombreadores de forma asíncrona. Esto puede reducir los tirones, pero también puede introducir errores gráficos.</string>
<string name="gpu_unswizzle_settings">Ajustes de desentrelazado de la GPU</string>
@@ -518,8 +521,10 @@
<string name="extensions">Extensiones</string>
<string name="dyna_state">Estado dinámico extendido</string>
<string name="dyna_state_description">Controla la cantidad de características que se pueden usar en ExtendedDynamicState (EDS). Un valor más alto permitirá reducir la cantidad de compilaciones de canalización basadas en el estado dinámico compatible con el controlador.</string>
<string name="disabled">Desactivado</string>
<string name="vertex_input_dynamic_state">Estado dinámico de entrada de vértices</string>
<string name="vertex_input_dynamic_state_description">La activación de esta función permite un manejo más flexible de la entrada de vértices, lo que podría reducir el tiempo de compilación de la canalización en vértices/búfer.</string>
<string name="sample_shading_fraction">Muestreo de sombreado</string>
<string name="sample_shading_fraction_description">Permite que el sombreador de fragmentos se ejecute por muestra en un fragmento multimuestreado, en lugar de una sola vez por fragmento. Mejora la calidad de los gráficos a coste de algo de rendimiento.</string>
@@ -459,6 +459,9 @@
<string name="renderer_anti_aliasing">Méthode d\'anticrénelage</string>
<string name="advanced">Avancé</string>
<string name="renderer_accuracy">Mode GPU</string>
<string name="dma_accuracy">Précision DMA</string>
<string name="dma_accuracy_description">Contrôle la précision du DMA. Une précision sûre peut résoudre les problèmes dans certains jeux, mais peut aussi affecter les performances dans certains cas. Si vous n\'êtes pas sûr, laissez ce paramètre sur Par défaut.</string>
<string name="anisotropic_filtering">Filtrage anisotropique</string>
@@ -474,15 +477,29 @@
<string name="use_disk_shader_cache_description">Réduire les saccades en stockant et en chargeant localement les shaders générés</string>
<string name="renderer_force_max_clock">Forcer les fréquences maximales (Adreno uniquement)</string>
<string name="renderer_force_max_clock_description">Forcer le GPU à fonctionner à ses fréquences maximales possibles (les contraintes thermiques seront toujours appliquées).</string>
<string name="renderer_asynchronous_gpu_emulation">Émulation GPU asynchrone </string>
<string name="renderer_asynchronous_gpu_emulation_description">Ce contournement peut améliorer les performances en faisant tourner l\'émulation GPU de manière asynchrone au détriment de la fidélité graphique et de la stabilité (plantages plus fréquents) dus à des erreurs de cadence.</string>
<string name="renderer_reactive_flushing">Utiliser le vidage réactif</string>
<string name="renderer_reactive_flushing_description">Améliore la précision du rendu dans certains jeux au détriment des performances.</string>
<string name="enable_buffer_history">Activer l\'historique du tampon</string>
<string name="hacks">Contournements</string>
<string name="fast_gpu_time">Temps GPU rapide</string>
<string name="skip_cpu_inner_invalidation">Ignorer l\'invalidation interne du CPU</string>
<string name="skip_cpu_inner_invalidation_description">Ignore certaines invalidations de cache côté CPU lors des mises à jour mémoire, réduisant l\'utilisation du CPU et améliorant ses performances. Peut causer des bugs ou plantages sur certains jeux.</string>
<string name="emulate_bgr565">Emuler BGR565</string>
<string name="renderer_asynchronous_shaders">Utiliser les shaders asynchrones</string>
<string name="renderer_asynchronous_shaders_description">Compile les shaders de manière asynchrone. Cela peut réduire les saccades mais peut aussi provoquer des problèmes graphiques.</string>
<string name="gpu_unswizzle_disabled">Désactivé</string>
<string name="gpu_unswizzle_default_button">Par défaut</string>
<string name="extensions">Extensions</string>
<string name="dyna_state">État dynamique étendu</string>
<string name="disabled">Désactivé</string>
<string name="vertex_input_dynamic_state">État dynamique d\'entrée de sommet</string>
<string name="sample_shading_fraction">Échantillonnage de shading</string>
<string name="display">Affichage</string>
<string name="renderer_screen_layout">Orientation</string>
@@ -508,6 +525,21 @@
<string name="flush_by_line">Vider les journaux de débogage ligne par ligne</string>
<string name="flush_by_line_description">Vide les journaux de débogage à chaque ligne écrite, facilitant le débogage en cas de plantage ou de gel.</string>
<!-- GPU Logging strings -->
<string name="gpu_logging_header">Journalisation GPU</string>
<string name="gpu_logging_enabled">Activer la journalisation GPU</string>
<string name="gpu_log_level">Niveau de journalisation</string>
<string name="gpu_log_vulkan_calls">Journaliser les appels API Vulkan</string>
<string name="gpu_log_shader_dumps">Extraire les shaders</string>
<string name="gpu_log_shader_dumps_description">Sauvegarder le shader SPIR-V complié dans les fichiers</string>
<string name="gpu_log_memory_tracking">Monitorer la mémoire GPU</string>
<string name="gpu_log_memory_tracking_description">Monitorer les allocations et désallocations de la mémoire GPU</string>
<string name="gpu_log_driver_debug">Informations de débogage du pilote</string>
<string name="gpu_log_ring_buffer_size_description">Nombre d\'appels Vulkans récents à monitorer (par défaut : 512)</string>
<string name="gpu_log_ring_buffer_size_hint">64 à 4096 entrées</string>
<string name="general">Général</string>
<!-- Audio settings strings -->
<string name="audio_output_engine">Moteur de sortie</string>
<string name="audio_volume">Volume</string>
@@ -590,6 +622,7 @@
<!-- Miscellaneous -->
<string name="slider_default">Par défaut</string>
<string name="default_string">Par défaut</string>
<string name="loading">Chargement...</string>
<string name="shutting_down">Extinction en cours...</string>
<string name="reset_setting_confirmation">Voulez-vous réinitialiser ce paramètre à sa valeur par défaut ?</string>
@@ -628,6 +661,7 @@
<string name="select_gpu_driver_default">Par défaut</string>
<string name="select_gpu_driver_error">Pilote non valide sélectionné</string>
<string name="driver_already_installed">Pilote déjà installé</string>
<string name="installed_label">%1$s (Installé)</string>
<string name="system_gpu_driver">Pilote du GPU du système</string>
<string name="installing_driver">Installation du pilote...</string>
@@ -647,6 +681,7 @@
<string name="installing">Installation en cours…</string>
<string name="latest">Dernière</string>
<string name="recommended_driver">Pilote recommandé :</string>
<string name="gpu_model">Modèle GPU</string>
<string name="unsupported_gpu">GPU non pris en charge</string>
<string name="unsupported_gpu_warning">Votre GPU ne prend pas en charge l\'injection de pilotes. Il n\'est pas recommandé de définir des pilotes personnalisés.</string>
@@ -656,6 +691,9 @@
<string name="preferences_system_description">Mode TV, région, langue</string>
<string name="preferences_graphics">Vidéo</string>
<string name="preferences_graphics_description">Niveau de précision, résolution, cache de shaders</string>
<string name="quick_settings">Paramètres rapides</string>
<string name="enable_quick_settings">Activer les paramètres rapides</string>
<string name="enable_quick_settings_description">Autoriser l\'accès aux paramètres rapides par le balayage de l\'écran et le bouton du menu</string>
<string name="preferences_audio">Audio</string>
<string name="preferences_audio_description">Moteur de sortie, volume</string>
<string name="preferences_controls">Contrôles</string>
@@ -663,6 +701,25 @@
<string name="preferences_player">Joueur %d</string>
<string name="preferences_debug">Débogage</string>
<string name="preferences_debug_description">Débogage CPU/GPU, API graphique, fastmem</string>
<string name="preferences_custom_paths">Chemins personnalisés</string>
<string name="preferences_custom_paths_description">Sauvegarder le répertoire des données</string>
<!-- Custom Paths settings -->
<string name="custom_save_directory">Sauvegarder le répertoire des données</string>
<string name="custom_save_directory_description">Définir un chemin personnalisé pour les sauvegardes</string>
<string name="reset_to_nand">Réinitialiser par défaut</string>
<string name="migrate_save_data">Migrer les données de sauvegarde</string>
<string name="save_migration_complete">Données de sauvegarde supprimées avec succès</string>
<string name="save_migration_failed">Échec de la migration des données de sauvegarde</string>
<string name="destination_has_saves">La destination contient déjà des données. Voulez-vous les écraser \?</string>
<string name="grant_permission">Accorder la permission</string>
<string name="custom_nand_directory">Dossier NAND</string>
<string name="custom_nand_directory_description">Définir un chemin personnalisé pour le stockage NAND</string>
<string name="custom_sdmc_directory">Répertoire de carte SD</string>
<string name="custom_sdmc_directory_description">Définir un chemin personnalisé pour le stockage de la carte SD virtuelle</string>
<string name="path_set">Chemin défini avec succès</string>
<string name="skip_migration">Sauter</string>
<!-- Game properties -->
<string name="info">Info</string>
<string name="info_description">ID du programme, développeur, version</string>
@@ -676,6 +733,7 @@
<string name="copy_details">Copier les détails</string>
<string name="add_ons">Extensions</string>
<string name="add_ons_description">Activer les mods, mises à jour et DLC</string>
<string name="playtime">Temps de jeu :</string>
<string name="reset_playtime">Réinitialiser le Temps de Jeu</string>
<string name="reset_playtime_description">Réinitialiser le temps de jeu du jeu actuel à 0 seconde</string>
<string name="reset_playtime_warning_description">Cela effacera les données de temps de jeu du jeu actuel. Êtes-vous sûr\?</string>
@@ -683,6 +741,9 @@
<string name="edit_playtime">Modifier le Temps de Jeu</string>
<string name="hours">Heures</string>
<string name="minutes">Minutes</string>
<string name="hours_abbr">h</string>
<string name="minutes_abbr">m</string>
<string name="seconds_abbr">s</string>
<string name="hours_must_be_between_0_and_9999">Les heures doivent être comprises entre 0 et 9999</string>
<string name="minutes_must_be_between_0_and_59">Les minutes doivent être comprises entre 0 et 59</string>
<string name="seconds_must_be_between_0_and_59">Les secondes doivent être comprises entre 0 et 59</string>
@@ -714,6 +775,7 @@
<string name="confirm_uninstall">Confirmer la désinstallation</string>
<string name="confirm_uninstall_description">Êtes-vous sûr de vouloir désinstaller cette extension ?</string>
<string name="verify_integrity">Vérifier l\'intégrité</string>
<string name="verifying">Vérification...</string>
<string name="verify_success">La vérification de l\'intégrité a réussi !</string>
<string name="verify_failure">La vérification de l\'intégrité a échoué !</string>
<string name="verify_failure_description">Le contenu d\'un fichier peut être corrompu</string>
@@ -785,6 +847,7 @@
<string name="emulation_control_opacity">Opacité</string>
<string name="emulation_touch_overlay_reset">Réinitialiser l\'overlay</string>
<string name="emulation_touch_overlay_edit">Modifier l\'overlay</string>
<string name="emulation_snap_to_grid">Aimanter à la grille</string>
<string name="emulation_pause">Mettre en pause l\'émulation</string>
<string name="emulation_unpause">Reprendre l\'émulation</string>
<string name="emulation_input_overlay">Options de l\'overlay</string>
@@ -838,6 +901,32 @@
<string name="clock_boost">Boost (1700MHz)</string>
<string name="clock_fast">Rapide (2000MHz)</string>
<!-- GPU overclock factors -->
<string name="off">Désactivé</string>
<string name="fast_gpu_medium">Moyen (256)</string>
<string name="fast_gpu_high">Élevé (512)</string>
<!-- GPU swizzle texture size -->
<string name="gpu_texturesizeswizzle_verysmall">Très petit (16 Mo)</string>
<string name="gpu_texturesizeswizzle_small">Petit (32 Mo)</string>
<string name="gpu_texturesizeswizzle_normal">Normal (128 Mo)</string>
<string name="gpu_texturesizeswizzle_large">Large (256 Mo)</string>
<string name="gpu_texturesizeswizzle_verylarge">Très large (512 Mo)</string>
<!-- GPU swizzle streams -->
<string name="gpu_swizzle_verylow">Très faible (4 Mo)</string>
<string name="gpu_swizzle_low">Faible (8 Mo)</string>
<string name="gpu_swizzle_normal">Normal (16 Mo)</string>
<string name="gpu_swizzle_medium">Moyen (32 Mo)</string>
<string name="gpu_swizzle_high">Élevé (64 Mo)</string>
<!-- GPU swizzle chunks -->
<string name="gpu_swizzlechunk_verylow">Très faible (32)</string>
<string name="gpu_swizzlechunk_low">Faible (64)</string>
<string name="gpu_swizzlechunk_normal">Normal (128)</string>
<string name="gpu_swizzlechunk_medium">Moyen (256)</string>
<string name="gpu_swizzlechunk_high">Élevé (512)</string>
<!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string>
<string name="temperature_fahrenheit">Fahrenheit</string>
@@ -853,6 +942,11 @@
<string name="renderer_none">Aucune</string>
<!-- Renderer Accuracy -->
<string name="renderer_accuracy_low">Rapide</string>
<string name="renderer_accuracy_medium">Moyen</string>
<string name="renderer_accuracy_high">Précis</string>
<!-- DMA Accuracy -->
<string name="dma_accuracy_default">Défaut</string>
<string name="dma_accuracy_unsafe">Dangereux</string>
@@ -886,6 +980,26 @@
<string name="cpu_accuracy_paranoid">Paranoïaque</string>
<string name="cpu_accuracy_debugging">Débogage</string>
<!-- Freedreno Settings -->
<string name="freedreno_settings_title">Paramètres de Freedreno</string>
<string name="gpu_driver_settings">Paramètres du pilote GPU</string>
<string name="freedreno_presets">Préréglages rapides</string>
<string name="freedreno_current_settings">Paramètres actuels</string>
<string name="freedreno_debug">Paramètres avancés</string>
<string name="freedreno_var_value">Valeur de la variable</string>
<string name="freedreno_add_variable">Ajouter la variable</string>
<string name="freedreno_clear_all">Effacer tout</string>
<string name="freedreno_saved">Configuration Freedreno sauvegardée</string>
<string name="freedreno_cleared_all">Toutes les variables Freedreno effacées</string>
<string name="freedreno_variable_added">Variable %1$s ajouté</string>
<string name="freedreno_preset_applied">Préréglage \'%1$s\' appliqué</string>
<string name="freedreno_error_empty_name">Le nom de la variable ne peut pas être vide</string>
<string name="freedreno_error_setting_variable">Échec de l\'assignation de la variable</string>
<string name="freedreno_info_title">À propos de la configuration Freedreno</string>
<string name="freedreno_per_game_title">Paramètres de Freedreno</string>
<string name="freedreno_per_game_description">Configurer les paramètres du pilote GPU pour ce jeu</string>
<string name="freedreno_per_game_saved">Configuration Freedreno sauvegardée</string>
<!-- Gamepad Buttons -->
<string name="gamepad_d_pad">Pavé directionnel</string>
<string name="gamepad_left_stick">Stick gauche</string>
@@ -902,26 +1016,37 @@
<string name="theme_material_you">Material You</string>
<string name="app_settings">Paramètres de lApp</string>
<string name="theme_and_color">Thème et Couleur</string>
<string name="fullscreen_mode">Mode plein écran</string>
<!-- Theme Modes -->
<string name="change_theme_mode">Changer le mode de thème</string>
<string name="theme_mode_follow_system">Automatique</string>
<string name="theme_mode_light">Lumineux</string>
<string name="theme_mode_dark">Sombre</string>
<string name="multiplier_none">Aucun</string>
<!-- Black backgrounds theme -->
<string name="use_black_backgrounds">Arrière-plan noir</string>
<string name="use_black_backgrounds_description">Lorsque vous utilisez le thème sombre, appliquer un arrière-plan noir.</string>
<!-- Buttons -->
<string name="enable_folder_button">Dossier</string>
<string name="enable_folder_button_description">Afficher le bouton pour ajouter les dossiers de jeu</string>
<string name="enable_qlaunch_button">QLaunch</string>
<string name="enable_qlaunch_button_description">Afficher le bouton pour lancer QLaunch</string>
<!-- App Language -->
<string name="app_language">Language de l\'application</string>
<string name="app_language_description">Changer la langue de l\'interface</string>
<string name="app_language_system">Suivre le système</string>
<!-- Static Themes -->
<string name="static_theme_color">Couleur du thème</string>
<string name="eden_theme">Eden</string>
<string name="violet">Violet (Par défaut)</string>
<string name="blue">Bleu</string>
<string name="cyan">Cyan</string>
<string name="red">Rouge</string>
<string name="green">Vert</string>
<string name="yellow">Jaune</string>
<string name="orange">Orange</string>
<string name="pink">Rose</string>
@@ -940,6 +1065,8 @@
<!-- Applet Modes -->
<string name="applets_menu">Applets</string>
<string name="applets_menu_description">Modifier les frontends et paramètres des applets</string>
<string name="applet_hle">Frontend personnalisé</string>
<string name="applet_lle">Applet réel</string>
@@ -948,7 +1075,39 @@
<string name="airplane_mode">Mode avion</string>
<string name="airplane_mode_description">Passe le mode avion au système d\'exploitation Switch</string>
<string name="enable_overlay">Activer l\'applet d\'overlay</string>
<!-- Profile Management -->
<string name="profile_manager">Gestionnaire de profil</string>
<string name="profile_manager_description">Gérer les profils utilisateurs</string>
<string name="profile_add_user">Ajouter un utilisateur</string>
<string name="profile_new_user">Nouvel utilisateur</string>
<string name="profile_edit_user">Modifier l\'utilisateur</string>
<string name="profile_edit">Éditer</string>
<string name="profile_delete">Supprimer</string>
<string name="profile_username">Nom d\'utilisateur</string>
<string name="profile_uuid">ID de l\'utilisateur (UUID)</string>
<string name="profile_uuid_description">Il s\'agit de l\'identifiant unique de ce profil utilisateur. Il ne peut pas être changé après sa création.</string>
<string name="profile_generate">Générer</string>
<string name="profile_avatar">Avatar de l\'utilisateur</string>
<string name="profile_select_image">Sélectionner l\'image</string>
<string name="profile_firmware_avatars">Avatars du firmware</string>
<string name="profile_firmware_avatars_unavailable">Avatars du firmware non disponibles. Veuillez installer le firmware pour utiliser cette fonctionnalité.</string>
<string name="profile_revert_image">Restaurer à la valeur par défaut</string>
<string name="profile_current_user">Utilisateur actuel</string>
<string name="profile_max_users_title">Nombre d\'Utilisateurs Maximum Atteint</string>
<string name="profile_max_users_message">Vous ne pouvez pas créer plus du 8 profils utilisateurs. Veuillez supprimer un des profils existants pour en créer un nouveau.</string>
<string name="profile_delete_confirm_title">Supprimer le profil \?</string>
<string name="profile_create_failed">Échec de la création du profil utilisateur</string>
<string name="profile_update_failed">Échec de la mise à jour du profil utilisateur</string>
<string name="profile_image_load_error">Échec du chargement de l\'image : %1$s</string>
<string name="profile_image_save_error">Échec de la sauvegarde de l\'image : %1$s</string>
<string name="error">Erreur</string>
<!-- Licenses screen strings -->
<string name="licenses">Licences</string>
<string name="license_fidelityfx_fsr_description">Mise à l\'échelle de haute qualité par AMD.</string>
</resources>
<string name="external_content">Contenu externe</string>
<string name="add_folders">Ajouter un dossier</string>
<string name="percent">%1$d%%</string>
</resources>
@@ -6,8 +6,8 @@
<string name="notification_permission_not_granted">알림 권한이 부여되지 않았습니다!</string>
<!-- Stats Overlay settings -->
<string name="process_ram">프로세스 RAM: %1$d MB</string>
<string name="shaders_prefix">셰이더</string>
<string name="shaders_suffix">빌드 중</string>
<string name="shaders_prefix">구축 중</string>
<string name="shaders_suffix">개 셰이더</string>
<string name="charging">(충전 중)</string>
<string name="system_info_label">시스템:</string>
@@ -3,7 +3,7 @@
<string name="app_disclaimer">Цей застосунок запускає ігри для ігрової консолі Nintendo Switch. Він не містить ігор чи ключів.<br /><br />Перш ніж почати, укажіть розташування файлу <![CDATA[<b> prod.keys </b>]]> у пам’яті вашого пристрою.<br /><br /><![CDATA[<a href=\"https://yuzu-mirror.github.io/help/quickstart\">Дізнатися більше</a>]]></string>
<string name="notice_notification_channel_name">Сповіщення та помилки</string>
<string name="notice_notification_channel_description">Виводить сповіщення у разі виникнення проблем.</string>
<string name="notice_notification_channel_description">Показує сповіщення у разі виникнення проблем.</string>
<string name="notification_permission_not_granted">Дозвіл на сповіщення не надано!</string>
<string name="app_notification_channel_description">Сповіщення емулятора Switch Eden</string>
<string name="app_notification_running">Eden працює</string>
@@ -66,6 +66,8 @@
<string name="show_power_info_description">显示当前功耗和电池剩余容量</string>
<string name="show_shaders_building">显示着色器编译信息</string>
<string name="show_shaders_building_description">显示当前正在编译的着色器数量</string>
<string name="pipeline_worker_cores">管线工作线程</string>
<string name="pipeline_worker_cores_description">管理用于构建 Vulkan 管线的核心数量,数值越高则管线编译性能越好,但温度也会随之升高。</string>
<string name="overlay_position">叠加层位置</string>
<string name="overlay_position_description">选择叠加层在屏幕上显示的位置</string>
<string name="overlay_position_top_left">左上</string>
@@ -104,7 +106,7 @@
<!-- NVDEC Emulation -->
<string name="nvdec_emulation">NVDEC模拟</string>
<string name="nvdec_emulation_description">选择视频解码处理方式</string>
<string name="nvdec_emulation_description">播放过场与开场动画期间的视频解码处理方式(NVDEC)。</string>
<string name="nvdec_emulation_none">禁用</string>
<!-- Optimize SPIRV output -->
@@ -179,14 +181,14 @@
<string name="multiplayer_hide_full_rooms">隐藏满员房间</string>
<string name="multiplayer_hide_empty_rooms">隐藏空房间</string>
<string name="multiplayer_tap_refresh_to_check_again">点击刷新重试</string>
<string name="multiplayer_search_public_lobbies">搜索房间</string>
<string name="multiplayer_search_public_lobbies">搜索游戏大厅</string>
<string name="multiplayer_preferred_game_name">首选游戏</string>
<string name="multiplayer_lobby_type">大厅类型</string>
<string name="multiplayer_lobby_type">游戏大厅类型</string>
<string name="multiplayer_room_name_error">长度需为3-20个字符</string>
<string name="multiplayer_required">必填</string>
<string name="multiplayer_token_required">需要Web令牌,请前往高级设置 -> 系统 -> 网络</string>
<string name="multiplayer_ip_error">IP格式无效</string>
<string name="multiplayer_username_error">必须为4-20个字符(仅字母数字、点号、连字符、下划线和空格</string>
<string name="multiplayer_username_error">必须为420个字符,且仅包含字母数字、点号、连字符、下划线和空格</string>
<string name="multiplayer_nickname_invalid">用户名无效,请在系统→网络中检查设置</string>
<string name="multiplayer_token_error">必须为48个字符,且仅包含小写字母a-z</string>
<string name="multiplayer_port_error">端口需为1-65535</string>
@@ -435,15 +437,15 @@
<string name="custom_cpu_ticks_description">设置自定义的CPU时钟值。更高的值可能提高性能,但也可能导致游戏卡顿。建议范围为77-21000。</string>
<string name="cpu_ticks">时钟</string>
<string name="memory_layout">内存布局</string>
<string name="memory_layout_description">(实验性) 更改模拟内存布局。此设置不会提性能,但可能有助于通过模组使用高分辨率的游戏。不要在 RAM 为 8GB 或更少的手机上使用。</string>
<string name="memory_layout_description">(实验性) 更改模拟内存布局。此设置不会提性能,但可能有助于游戏通过 mods 来利用高分辨率。请不要在内存不大于 8GB 的手机上使用。仅适用于 DynamicJIT)后端。</string>
<string name="generate">生成</string>
<!-- Network settings strings -->
<string name="web_token">网络令牌</string>
<string name="web_token_description">用于创建公共房间的网络令牌。它是一个48个字符的字符串,仅包含小写字母a-z。</string>
<string name="web_token_description">用于创建公共游戏大厅的 web token。这是一个仅包含小写字母 a-z 的 48 位字符串</string>
<string name="web_username">网络用户名</string>
<string name="web_username_description">多人游戏房间中显示的用户名。必须为4-20个字符(仅字母数字、连字符、点号、下划线和空格</string>
<string name="web_username_description">多人游戏大厅中显示的用户名。用户名必须为420个字符,且仅可包含字母数字、连字符、点号、下划线和空格。</string>
<string name="network">网络</string>
<!-- Graphics settings strings -->
@@ -451,7 +453,7 @@
<string name="renderer_vsync">垂直同步模式</string>
<string name="renderer_scaling_filter">窗口滤镜</string>
<string name="fsr_sharpness">FSR 锐化度</string>
<string name="fsr_sharpness_description">定使用 FSR 图像锐化程度</string>
<string name="fsr_sharpness_description">定使用 FSR 的动态对比度功能时的图像锐化程度</string>
<string name="renderer_anti_aliasing">抗锯齿方式</string>
@@ -473,14 +475,18 @@
<string name="use_disk_shader_cache">磁盘着色器缓存</string>
<string name="use_disk_shader_cache_description">将生成的着色器缓存于磁盘中并进行读取,以减少卡顿。</string>
<string name="renderer_force_max_clock">强制最大时钟 (仅限 Adreno)</string>
<string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (仍被温控限制)。</string>
<string name="renderer_force_max_clock_description">强制 GPU 以最大时钟运行 (温控依然生效)。</string>
<string name="renderer_asynchronous_gpu_emulation">GPU 异步模拟</string>
<string name="renderer_asynchronous_gpu_emulation_description">此技巧可通过异步运行 GPU 模拟来提升性能,但在执行与时序相关的操作时,可能引入图形问题和增加崩溃概率。</string>
<string name="renderer_async_presentation">异步呈现</string>
<string name="renderer_async_presentation_description">此技巧通过将图形呈现移至独立的 CPU 线程来提升性能,但可能会引入图形显示问题。</string>
<string name="renderer_reactive_flushing">启用反应性刷新</string>
<string name="renderer_reactive_flushing_description">通过牺牲性能来提高某些游戏的渲染精度。</string>
<string name="enable_buffer_history">启用缓冲区历史</string>
<string name="enable_buffer_history_description">启用对先前缓冲区状态的访问。此选项可在某些游戏中提升渲染质量并保持性能的一致性。</string>
<string name="use_optimized_vertex_buffers">优化顶点缓冲区</string>
<string name="use_optimized_vertex_buffers_description">启用经过优化的顶点缓冲区绑定以提升性能。需要 Mesa 26.0 及以上版本的 Turnip 或 QCOM 驱动程序。若使用较旧版本的 Turnip 驱动 (25.3 及以下版本) 则会导致崩溃。</string>
<string name="hacks">Hacks</string>
<string name="fast_gpu_time">GPU 超频频率</string>
@@ -490,7 +496,9 @@
<string name="fix_bloom_effects">修复 Bloom 效果</string>
<string name="fix_bloom_effects_description">减少《塞尔达传说:智慧的再现》(Adreno A6XX - A7XX/ Turnip)中的 bloom 模糊,并移除《Burnout》中的 bloom 效果。警告:可能会导致在其他游戏中出现图形异常。</string>
<string name="emulate_bgr565">模拟 BGR565</string>
<string name="emulate_bgr565_description">修复游戏中的颜色反转以及出现的异常画面瑕疵或奇怪阴影问题</string>
<string name="emulate_bgr565_description">修复游戏中的颜色反转或是异常画面瑕疵或阴影问题</string>
<string name="rescale_hack">启用旧版缩放处理</string>
<string name="rescale_hack_description">启用通过使用快速缩放路径,来为游戏提供缩放配置处理的传统处理方式</string>
<string name="renderer_asynchronous_shaders">使用异步着色器</string>
<string name="renderer_asynchronous_shaders_description">异步编译着色器。这可能会减少卡顿,但也可能会导致图形错误。</string>
<string name="gpu_unswizzle_settings">GPU 还原设置</string>
@@ -500,17 +508,19 @@
<string name="gpu_unswizzle_texture_size">GPU 还原最大纹理尺寸</string>
<string name="gpu_unswizzle_texture_size_description">设置基于 GPU 的纹理还原的最大尺寸(单位:MiB)。\n虽然 GPU 在处理中型和大型纹理时速度更快,但对于非常小的纹理,CPU 的效率可能更高。\n调整此设置,以便在 GPU 加速和 CPU 开销之间找到最佳平衡点。</string>
<string name="gpu_unswizzle_stream_size">GPU 还原流大小</string>
<string name="gpu_unswizzle_stream_size_description">设置每帧还原大型纹理的数据限制。较高的数值可以加快纹理加载速度,但代价是增加帧延迟(影响响应速度/平滑度);较低的数值可以减少 GPU 开销,但可能会导致明显的纹理突然出现(Pop-in)现象</string>
<string name="gpu_unswizzle_stream_size_description">设置用于 unswizzling 大型纹理时的每帧数据限制。较高的数值可以加快纹理加载速度,但增加帧延迟。而较低的数值可以降低 GPU 开销,但可能会导致可见的纹理 闪现</string>
<string name="gpu_unswizzle_chunk_size">GPU 还原块大小</string>
<string name="gpu_unswizzle_chunk_size_description">定义了 3D 纹理在单个批次(Batch)中处理的深度切片(Depth Slices数量。增加此数值可以提升强力 GPU 吞吐效率,但在性能较弱的硬件上可能会引起卡顿或驱动程序超时(Driver Timeouts</string>
<string name="gpu_unswizzle_chunk_size_description">定义了 3D 纹理每批次处理的深度切片数量。增加此数值可在高性能 GPU 上提升吞吐效率,但在性能较弱的硬件上可能会导致卡顿或驱动超时</string>
<string name="gpu_unswizzle_default_button">默认</string>
<string name="extensions">扩展</string>
<string name="dyna_state">扩展动态状态</string>
<string name="dyna_state_description">控制扩展动态状态 (EDS) 可使用的功能数目。较高的数值将允许根据驱动程序支持的动态状态来减少管线编译的次数。</string>
<string name="disabled">已禁用</string>
<string name="vertex_input_dynamic_state">顶点输入动态状态</string>
<string name="vertex_input_dynamic_state_description">启用此功能可实现更灵活的顶点输入处理,可能减少顶点/缓冲区的管线编译时间。</string>
<string name="sample_shading_fraction">采样着色</string>
<string name="sample_shading_fraction_description">允许片段着色器在多采样片段中每个样本执行一次,而不是每个片段执行一次。以提高性能为代价改善图形质量。</string>
@@ -240,6 +240,8 @@
<item>@string/scaling_filter_bspline</item>
<item>@string/scaling_filter_mitchell</item>
<item>@string/scaling_filter_spline1</item>
<item>@string/scaling_filter_sgsr</item>
<item>@string/scaling_filter_sgsr_edge</item>
</string-array>
<integer-array name="rendererScalingFilterValues">
@@ -256,6 +258,8 @@
<item>10</item>
<item>11</item>
<item>12</item>
<item>13</item>
<item>14</item>
</integer-array>
<string-array name="rendererAntiAliasingNames">
@@ -1 +1 @@
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#ffd700</color></resources>
<?xml version='1.0' encoding='utf-8'?><resources><color name='ic_launcher_background'>#1F143C</color></resources>
@@ -468,8 +468,8 @@
<string name="renderer_resolution">Resolution (Handheld/Docked)</string>
<string name="renderer_vsync">VSync mode</string>
<string name="renderer_scaling_filter">Window adapting filter</string>
<string name="fsr_sharpness">FSR sharpness</string>
<string name="fsr_sharpness_description">Determines how sharpened the image will look while using FSR\'s dynamic contrast</string>
<string name="fsr_sharpness">FSR/SGSR sharpness</string>
<string name="fsr_sharpness_description">Determines how sharpened the image will look while using FSR or SGSR filters</string>
<string name="renderer_anti_aliasing">Anti-aliasing method</string>
@@ -509,6 +509,8 @@
<string name="fast_gpu_time_description">Forces most games to run at their highest native resolution. Use 256 for maximal performance and 512 for maximal graphics fidelity.</string>
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
<string name="antiflicker">Anti-Flicker</string>
<string name="antiflicker_description">Forces GPU fence callbacks to wait for submitted GPU work. Use with Fast GPU mode, to avoid flicker with lower performance impact.</string>
<string name="fix_bloom_effects">Fix Bloom Effects</string>
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
<string name="emulate_bgr565">Emulate BGR565</string>
@@ -1078,6 +1080,8 @@
<string name="scaling_filter_bspline" translatable="false">B-Spline</string>
<string name="scaling_filter_mitchell" translatable="false">Mitchell</string>
<string name="scaling_filter_mmpx" translatable="false">MMPX</string>
<string name="scaling_filter_sgsr" translatable="false">Snapdragon GSR</string>
<string name="scaling_filter_sgsr_edge" translatable="false">Snapdragon GSR EdgeDir</string>
<!-- Anti-Aliasing -->
<string name="anti_aliasing_none">None</string>
+4 -4
View File
@@ -247,11 +247,11 @@ if(ANDROID)
target_compile_definitions(audio_core PUBLIC HAVE_OBOE)
else()
target_sources(audio_core PRIVATE
sink/sdl2_sink.cpp
sink/sdl2_sink.h)
sink/sdl3_sink.cpp
sink/sdl3_sink.h)
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
endif()
create_target_directory_groups(audio_core)
@@ -29,8 +29,96 @@ void AudioRenderer::Start() {
CreateSinkStreams();
mailbox.Initialize(AppMailboxId::AudioRenderer);
// Main AudioRenderer thread, responsible for processing the command lists.
main_thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("DSP_AudioRenderer_Main");
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
main_thread = std::jthread([this](std::stop_token stop_token) { Main(stop_token); });
// TODO: Create buffer map/unmap thread + mailbox
// TODO: Create gMix devices, initialize them here
if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) {
LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!");
return;
}
mailbox.Send(Direction::Host, Message::InitializeOK);
// 0.12 seconds (2,304,000 / 19,200,000)
constexpr u64 max_process_time{2'304'000ULL};
while (!stop_token.stop_requested()) {
auto msg{mailbox.Receive(Direction::DSP)};
switch (msg) {
case Message::Shutdown:
mailbox.Send(Direction::Host, Message::Shutdown);
return;
case Message::Render: {
if (system.IsShuttingDown()) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
mailbox.Send(Direction::Host, Message::RenderResponse);
continue;
}
std::array<bool, MaxRendererSessions> buffers_reset{};
std::array<u64, MaxRendererSessions> render_times_taken{};
const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()};
for (u32 index = 0; index < MaxRendererSessions; index++) {
auto& command_buffer{command_buffers[index]};
auto& command_list_processor{command_list_processors[index]};
// Check this buffer is valid, as it may not be used.
if (command_buffer.buffer != 0) {
// If there are no remaining commands (from the previous list),
// this is a new command list, initialize it.
if (command_buffer.remaining_command_count == 0) {
command_list_processor.Initialize(system, *command_buffer.process,
command_buffer.buffer,
command_buffer.size, streams[index]);
}
if (command_buffer.reset_buffer && !buffers_reset[index]) {
streams[index]->ClearQueue();
buffers_reset[index] = true;
}
u64 max_time{max_process_time};
if (index == 1 && command_buffer.applet_resource_user_id ==
command_buffers[0].applet_resource_user_id) {
max_time = max_process_time - render_times_taken[0];
if (render_times_taken[0] > max_process_time) {
max_time = 0;
}
}
max_time = (std::min)(command_buffer.time_limit, max_time);
command_list_processor.SetProcessTimeMax(max_time);
if (index == 0) {
streams[index]->WaitFreeSpace(stop_token);
}
// Process the command list
{
render_times_taken[index] =
command_list_processor.Process(index) - start_time;
}
const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()};
command_buffer.remaining_command_count =
command_list_processor.GetRemainingCommandCount();
command_buffer.render_time_taken_us = end_time - start_time;
}
}
mailbox.Send(Direction::Host, Message::RenderResponse);
} break;
default:
LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg);
break;
}
}
});
mailbox.Send(Direction::DSP, Message::InitializeOK);
if (mailbox.Receive(Direction::Host) != Message::InitializeOK) {
@@ -129,95 +217,4 @@ void AudioRenderer::CreateSinkStreams() {
}
}
void AudioRenderer::Main(std::stop_token stop_token) {
Common::SetCurrentThreadName("DSP_AudioRenderer_Main");
Common::SetCurrentThreadPriority(Common::ThreadPriority::High);
// TODO: Create buffer map/unmap thread + mailbox
// TODO: Create gMix devices, initialize them here
if (mailbox.Receive(Direction::DSP) != Message::InitializeOK) {
LOG_ERROR(Service_Audio, "ADSP Audio Renderer -- Failed to receive initialize message from host!");
return;
}
mailbox.Send(Direction::Host, Message::InitializeOK);
// 0.12 seconds (2,304,000 / 19,200,000)
constexpr u64 max_process_time{2'304'000ULL};
while (!stop_token.stop_requested()) {
auto msg{mailbox.Receive(Direction::DSP)};
switch (msg) {
case Message::Shutdown:
mailbox.Send(Direction::Host, Message::Shutdown);
return;
case Message::Render: {
if (system.IsShuttingDown()) {
std::this_thread::sleep_for(std::chrono::milliseconds(200));
mailbox.Send(Direction::Host, Message::RenderResponse);
continue;
}
std::array<bool, MaxRendererSessions> buffers_reset{};
std::array<u64, MaxRendererSessions> render_times_taken{};
const auto start_time{system.CoreTiming().GetGlobalTimeUs().count()};
for (u32 index = 0; index < MaxRendererSessions; index++) {
auto& command_buffer{command_buffers[index]};
auto& command_list_processor{command_list_processors[index]};
// Check this buffer is valid, as it may not be used.
if (command_buffer.buffer != 0) {
// If there are no remaining commands (from the previous list),
// this is a new command list, initialize it.
if (command_buffer.remaining_command_count == 0) {
command_list_processor.Initialize(system, *command_buffer.process,
command_buffer.buffer,
command_buffer.size, streams[index]);
}
if (command_buffer.reset_buffer && !buffers_reset[index]) {
streams[index]->ClearQueue();
buffers_reset[index] = true;
}
u64 max_time{max_process_time};
if (index == 1 && command_buffer.applet_resource_user_id ==
command_buffers[0].applet_resource_user_id) {
max_time = max_process_time - render_times_taken[0];
if (render_times_taken[0] > max_process_time) {
max_time = 0;
}
}
max_time = (std::min)(command_buffer.time_limit, max_time);
command_list_processor.SetProcessTimeMax(max_time);
if (index == 0) {
streams[index]->WaitFreeSpace(stop_token);
}
// Process the command list
{
render_times_taken[index] =
command_list_processor.Process(index) - start_time;
}
const auto end_time{system.CoreTiming().GetGlobalTimeUs().count()};
command_buffer.remaining_command_count =
command_list_processor.GetRemainingCommandCount();
command_buffer.render_time_taken_us = end_time - start_time;
}
}
mailbox.Send(Direction::Host, Message::RenderResponse);
} break;
default:
LOG_WARNING(Service_Audio, "ADSP AudioRenderer received an invalid message, msg={:02X}!", msg);
break;
}
}
}
} // namespace AudioCore::ADSP::AudioRenderer
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
@@ -82,11 +82,6 @@ public:
u64 GetRenderingStartTick(s32 session_id) const noexcept;
private:
/**
* Main AudioRenderer thread, responsible for processing the command lists.
*/
void Main(std::stop_token stop_token);
/**
* Creates the streams which will receive the processed samples.
*/
+194 -195
View File
@@ -37,7 +37,9 @@ bool IsValidMultiStreamStreamCounts(s32 total_stream_count, s32 stereo_stream_co
} // namespace
OpusDecoder::OpusDecoder(Core::System& system_) : system{system_} {
init_thread = std::jthread([this](std::stop_token stop_token) { Init(stop_token); });
init_thread = std::jthread([this](std::stop_token stop_token) {
Init(stop_token);
});
}
OpusDecoder::~OpusDecoder() {
@@ -64,206 +66,203 @@ u32 OpusDecoder::Receive(Direction dir, std::stop_token stop_token) {
return mailbox.Receive(dir, stop_token);
}
void OpusDecoder::Init(std::stop_token stop_token) {
void OpusDecoder::Init(std::stop_token rc_stop_token) {
Common::SetCurrentThreadName("DSP_OpusDecoder_Init");
if (Receive(Direction::DSP, stop_token) != Message::Start) {
LOG_ERROR(Service_Audio,
"DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
if (Receive(Direction::DSP, rc_stop_token) != Message::Start) {
LOG_ERROR(Service_Audio, "DSP OpusDecoder failed to receive Start message. Opus initialization failed.");
return;
}
main_thread = std::jthread([this](std::stop_token st) { Main(st); });
// Main OpusDecoder thread, responsible for processing the incoming Opus packets.
main_thread = std::jthread([this](std::stop_token stop_token) {
Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
while (!stop_token.stop_requested()) {
auto msg = Receive(Direction::DSP, stop_token);
switch (msg) {
case Shutdown:
Send(Direction::Host, Message::ShutdownOK);
return;
case GetWorkBufferSize: {
auto channel_count = static_cast<s32>(shared_memory->host_send_data[0]);
ASSERT(IsValidChannelCount(channel_count));
shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count);
Send(Direction::Host, Message::GetWorkBufferSizeOK);
} break;
case InitializeDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
auto buffer_size = shared_memory->host_send_data[1];
auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
ASSERT(sample_rate >= 0);
ASSERT(IsValidChannelCount(channel_count));
ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count));
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] =
decoder_object.InitializeDecoder(sample_rate, channel_count);
Send(Direction::Host, Message::InitializeDecodeObjectOK);
} break;
case ShutdownDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
Send(Direction::Host, Message::ShutdownDecodeObjectOK);
} break;
case DecodeInterleaved: {
auto start_time = system.CoreTiming().GetGlobalTimeUs();
auto buffer = shared_memory->host_send_data[0];
auto input_data = shared_memory->host_send_data[1];
auto input_data_size = shared_memory->host_send_data[2];
auto output_data = shared_memory->host_send_data[3];
auto output_data_size = shared_memory->host_send_data[4];
auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
auto reset_requested = shared_memory->host_send_data[6];
u32 decoded_samples{0};
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
s32 error_code{OPUS_OK};
if (reset_requested) {
error_code = decoder_object.ResetDecoder();
}
if (error_code == OPUS_OK) {
error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
input_data, input_data_size);
}
if (error_code == OPUS_OK) {
if (final_range && decoder_object.GetFinalRange() != final_range) {
error_code = OPUS_INVALID_PACKET;
}
}
auto end_time = system.CoreTiming().GetGlobalTimeUs();
shared_memory->dsp_return_data[0] = error_code;
shared_memory->dsp_return_data[1] = decoded_samples;
shared_memory->dsp_return_data[2] = (end_time - start_time).count();
Send(Direction::Host, Message::DecodeInterleavedOK);
} break;
case MapMemory: {
[[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
Send(Direction::Host, Message::MapMemoryOK);
} break;
case UnmapMemory: {
[[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
Send(Direction::Host, Message::UnmapMemoryOK);
} break;
case GetWorkBufferSizeForMultiStream: {
auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[0]);
auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[1]);
ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize(
total_stream_count, stereo_stream_count);
Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK);
} break;
case InitializeMultiStreamDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
auto buffer_size = shared_memory->host_send_data[1];
auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[5]);
// Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel
// mappings, but [6] is never set, and there is not enough room in the argument data for
// more than 40 channels, when 255 are possible.
// It also means the mapping values are undefined, though likely always 0,
// and the mappings given by the game are ignored. The mappings are copied to this
// dedicated buffer host side, so let's do as intended.
auto mappings = shared_memory->channel_mapping.data();
ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
ASSERT(sample_rate >= 0);
ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize(
total_stream_count, stereo_stream_count));
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder(
sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings);
Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK);
} break;
case ShutdownMultiStreamDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK);
} break;
case DecodeInterleavedForMultiStream: {
auto start_time = system.CoreTiming().GetGlobalTimeUs();
auto buffer = shared_memory->host_send_data[0];
auto input_data = shared_memory->host_send_data[1];
auto input_data_size = shared_memory->host_send_data[2];
auto output_data = shared_memory->host_send_data[3];
auto output_data_size = shared_memory->host_send_data[4];
auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
auto reset_requested = shared_memory->host_send_data[6];
u32 decoded_samples{0};
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
s32 error_code{OPUS_OK};
if (reset_requested) {
error_code = decoder_object.ResetDecoder();
}
if (error_code == OPUS_OK) {
error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
input_data, input_data_size);
}
if (error_code == OPUS_OK) {
if (final_range && decoder_object.GetFinalRange() != final_range) {
error_code = OPUS_INVALID_PACKET;
}
}
auto end_time = system.CoreTiming().GetGlobalTimeUs();
shared_memory->dsp_return_data[0] = error_code;
shared_memory->dsp_return_data[1] = decoded_samples;
shared_memory->dsp_return_data[2] = (end_time - start_time).count();
Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK);
} break;
default:
LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg);
continue;
}
}
});
running = true;
Send(Direction::Host, Message::StartOK);
}
void OpusDecoder::Main(std::stop_token stop_token) {
Common::SetCurrentThreadName("DSP_OpusDecoder_Main");
while (!stop_token.stop_requested()) {
auto msg = Receive(Direction::DSP, stop_token);
switch (msg) {
case Shutdown:
Send(Direction::Host, Message::ShutdownOK);
return;
case GetWorkBufferSize: {
auto channel_count = static_cast<s32>(shared_memory->host_send_data[0]);
ASSERT(IsValidChannelCount(channel_count));
shared_memory->dsp_return_data[0] = OpusDecodeObject::GetWorkBufferSize(channel_count);
Send(Direction::Host, Message::GetWorkBufferSizeOK);
} break;
case InitializeDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
auto buffer_size = shared_memory->host_send_data[1];
auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
ASSERT(sample_rate >= 0);
ASSERT(IsValidChannelCount(channel_count));
ASSERT(buffer_size >= OpusDecodeObject::GetWorkBufferSize(channel_count));
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] =
decoder_object.InitializeDecoder(sample_rate, channel_count);
Send(Direction::Host, Message::InitializeDecodeObjectOK);
} break;
case ShutdownDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
Send(Direction::Host, Message::ShutdownDecodeObjectOK);
} break;
case DecodeInterleaved: {
auto start_time = system.CoreTiming().GetGlobalTimeUs();
auto buffer = shared_memory->host_send_data[0];
auto input_data = shared_memory->host_send_data[1];
auto input_data_size = shared_memory->host_send_data[2];
auto output_data = shared_memory->host_send_data[3];
auto output_data_size = shared_memory->host_send_data[4];
auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
auto reset_requested = shared_memory->host_send_data[6];
u32 decoded_samples{0};
auto& decoder_object = OpusDecodeObject::Initialize(buffer, buffer);
s32 error_code{OPUS_OK};
if (reset_requested) {
error_code = decoder_object.ResetDecoder();
}
if (error_code == OPUS_OK) {
error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
input_data, input_data_size);
}
if (error_code == OPUS_OK) {
if (final_range && decoder_object.GetFinalRange() != final_range) {
error_code = OPUS_INVALID_PACKET;
}
}
auto end_time = system.CoreTiming().GetGlobalTimeUs();
shared_memory->dsp_return_data[0] = error_code;
shared_memory->dsp_return_data[1] = decoded_samples;
shared_memory->dsp_return_data[2] = (end_time - start_time).count();
Send(Direction::Host, Message::DecodeInterleavedOK);
} break;
case MapMemory: {
[[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
Send(Direction::Host, Message::MapMemoryOK);
} break;
case UnmapMemory: {
[[maybe_unused]] auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
Send(Direction::Host, Message::UnmapMemoryOK);
} break;
case GetWorkBufferSizeForMultiStream: {
auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[0]);
auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[1]);
ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
shared_memory->dsp_return_data[0] = OpusMultiStreamDecodeObject::GetWorkBufferSize(
total_stream_count, stereo_stream_count);
Send(Direction::Host, Message::GetWorkBufferSizeForMultiStreamOK);
} break;
case InitializeMultiStreamDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
auto buffer_size = shared_memory->host_send_data[1];
auto sample_rate = static_cast<s32>(shared_memory->host_send_data[2]);
auto channel_count = static_cast<s32>(shared_memory->host_send_data[3]);
auto total_stream_count = static_cast<s32>(shared_memory->host_send_data[4]);
auto stereo_stream_count = static_cast<s32>(shared_memory->host_send_data[5]);
// Nintendo seem to have a bug here, they try to use &host_send_data[6] for the channel
// mappings, but [6] is never set, and there is not enough room in the argument data for
// more than 40 channels, when 255 are possible.
// It also means the mapping values are undefined, though likely always 0,
// and the mappings given by the game are ignored. The mappings are copied to this
// dedicated buffer host side, so let's do as intended.
auto mappings = shared_memory->channel_mapping.data();
ASSERT(IsValidMultiStreamStreamCounts(total_stream_count, stereo_stream_count));
ASSERT(sample_rate >= 0);
ASSERT(buffer_size >= OpusMultiStreamDecodeObject::GetWorkBufferSize(
total_stream_count, stereo_stream_count));
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.InitializeDecoder(
sample_rate, total_stream_count, channel_count, stereo_stream_count, mappings);
Send(Direction::Host, Message::InitializeMultiStreamDecodeObjectOK);
} break;
case ShutdownMultiStreamDecodeObject: {
auto buffer = shared_memory->host_send_data[0];
[[maybe_unused]] auto buffer_size = shared_memory->host_send_data[1];
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
shared_memory->dsp_return_data[0] = decoder_object.Shutdown();
Send(Direction::Host, Message::ShutdownMultiStreamDecodeObjectOK);
} break;
case DecodeInterleavedForMultiStream: {
auto start_time = system.CoreTiming().GetGlobalTimeUs();
auto buffer = shared_memory->host_send_data[0];
auto input_data = shared_memory->host_send_data[1];
auto input_data_size = shared_memory->host_send_data[2];
auto output_data = shared_memory->host_send_data[3];
auto output_data_size = shared_memory->host_send_data[4];
auto final_range = static_cast<u32>(shared_memory->host_send_data[5]);
auto reset_requested = shared_memory->host_send_data[6];
u32 decoded_samples{0};
auto& decoder_object = OpusMultiStreamDecodeObject::Initialize(buffer, buffer);
s32 error_code{OPUS_OK};
if (reset_requested) {
error_code = decoder_object.ResetDecoder();
}
if (error_code == OPUS_OK) {
error_code = decoder_object.Decode(decoded_samples, output_data, output_data_size,
input_data, input_data_size);
}
if (error_code == OPUS_OK) {
if (final_range && decoder_object.GetFinalRange() != final_range) {
error_code = OPUS_INVALID_PACKET;
}
}
auto end_time = system.CoreTiming().GetGlobalTimeUs();
shared_memory->dsp_return_data[0] = error_code;
shared_memory->dsp_return_data[1] = decoded_samples;
shared_memory->dsp_return_data[2] = (end_time - start_time).count();
Send(Direction::Host, Message::DecodeInterleavedForMultiStreamOK);
} break;
default:
LOG_ERROR(Service_Audio, "Invalid OpusDecoder command {}", msg);
continue;
}
}
}
} // namespace AudioCore::ADSP::OpusDecoder
+3 -4
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
@@ -69,10 +72,6 @@ private:
* Initializing thread, launched at audio_core boot to avoid blocking the main emu boot thread.
*/
void Init(std::stop_token stop_token);
/**
* Main OpusDecoder thread, responsible for processing the incoming Opus packets.
*/
void Main(std::stop_token stop_token);
/// Core system
Core::System& system;
@@ -7,16 +7,40 @@
#include <span>
#include <vector>
#include <SDL.h>
#include <SDL3/SDL.h>
#include "audio_core/common/common.h"
#include "audio_core/sink/sdl2_sink.h"
#include "audio_core/sink/sdl3_sink.h"
#include "audio_core/sink/sink_stream.h"
#include "common/logging.h"
#include "common/scope_exit.h"
#include "core/core.h"
namespace AudioCore::Sink {
namespace {
SDL_AudioDeviceID FindAudioDeviceByName(const std::string& device_name, bool capture) {
int device_count = 0;
SDL_AudioDeviceID* devices = capture ? SDL_GetAudioRecordingDevices(&device_count)
: SDL_GetAudioPlaybackDevices(&device_count);
if (devices == nullptr) {
return capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING : SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
}
SDL_AudioDeviceID selected = capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK;
for (int i = 0; i < device_count; ++i) {
const char* current_name = SDL_GetAudioDeviceName(devices[i]);
if (current_name != nullptr && device_name == current_name) {
selected = devices[i];
break;
}
}
SDL_free(devices);
return selected;
}
} // Anonymous namespace
/**
* SDL sink stream, responsible for sinking samples to hardware.
*/
@@ -39,13 +63,10 @@ public:
system_channels = system_channels_;
device_channels = device_channels_;
SDL_AudioSpec spec;
SDL_AudioSpec spec{};
spec.freq = TargetSampleRate;
spec.channels = static_cast<u8>(device_channels);
spec.format = AUDIO_S16SYS;
spec.samples = TargetSampleCount * 2;
spec.callback = &SDLSinkStream::DataCallback;
spec.userdata = this;
spec.format = SDL_AUDIO_S16;
std::string device_name{output_device};
bool capture{false};
@@ -54,22 +75,28 @@ public:
capture = true;
}
SDL_AudioSpec obtained;
if (device_name.empty()) {
device = SDL_OpenAudioDevice(nullptr, capture, &spec, &obtained, false);
} else {
device = SDL_OpenAudioDevice(device_name.c_str(), capture, &spec, &obtained, false);
}
const SDL_AudioDeviceID audio_device =
device_name.empty() ? (capture ? SDL_AUDIO_DEVICE_DEFAULT_RECORDING
: SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK)
: FindAudioDeviceByName(device_name, capture);
if (device == 0) {
stream = SDL_OpenAudioDeviceStream(audio_device, &spec, &SDLSinkStream::DataCallback,
this);
if (stream == nullptr) {
LOG_CRITICAL(Audio_Sink, "Error opening SDL audio device: {}", SDL_GetError());
return;
}
SDL_AudioSpec stream_in{};
SDL_AudioSpec stream_out{};
static_cast<void>(SDL_GetAudioStreamFormat(stream, &stream_in, &stream_out));
LOG_INFO(Service_Audio,
"Opening SDL stream {} with: rate {} channels {} (system channels {}) "
" samples {}",
device, obtained.freq, obtained.channels, system_channels, obtained.samples);
" format {}",
static_cast<const void*>(stream), stream_out.freq, stream_out.channels,
system_channels, static_cast<int>(stream_out.format));
}
/**
@@ -84,13 +111,14 @@ public:
* Finalize the sink stream.
*/
void Finalize() override {
if (device == 0) {
if (stream == nullptr) {
return;
}
Stop();
SDL_ClearQueuedAudio(device);
SDL_CloseAudioDevice(device);
SDL_ClearAudioStream(stream);
SDL_DestroyAudioStream(stream);
stream = nullptr;
}
/**
@@ -100,23 +128,23 @@ public:
* Default false.
*/
void Start(bool resume = false) override {
if (device == 0 || !paused) {
if (stream == nullptr || !paused) {
return;
}
paused = false;
SDL_PauseAudioDevice(device, 0);
static_cast<void>(SDL_ResumeAudioStreamDevice(stream));
}
/**
* Stop the sink stream.
*/
void Stop() override {
if (device == 0 || paused) {
if (stream == nullptr || paused) {
return;
}
SignalPause();
SDL_PauseAudioDevice(device, 1);
static_cast<void>(SDL_PauseAudioStreamDevice(stream));
}
private:
@@ -128,7 +156,8 @@ private:
* @param stream - Buffer of samples to be filled or read.
* @param len - Length of the stream in bytes.
*/
static void DataCallback(void* userdata, Uint8* stream, int len) {
static void DataCallback(void* userdata, SDL_AudioStream* stream, int additional_amount,
int total_amount) {
auto* impl = static_cast<SDLSinkStream*>(userdata);
if (!impl) {
@@ -137,25 +166,46 @@ private:
const std::size_t num_channels = impl->GetDeviceChannels();
const std::size_t frame_size = num_channels;
const std::size_t num_frames{len / num_channels / sizeof(s16)};
if (impl->type == StreamType::In) {
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(stream),
num_frames * frame_size};
const int bytes_available = SDL_GetAudioStreamAvailable(stream);
if (bytes_available <= 0) {
return;
}
std::vector<s16> input(bytes_available / static_cast<int>(sizeof(s16)));
const int bytes_read = SDL_GetAudioStreamData(stream, input.data(), bytes_available);
if (bytes_read <= 0) {
return;
}
const std::size_t num_frames =
static_cast<std::size_t>(bytes_read) / sizeof(s16) / frame_size;
std::span<const s16> input_buffer{input.data(),
static_cast<std::size_t>(bytes_read) / sizeof(s16)};
impl->ProcessAudioIn(input_buffer, num_frames);
} else {
std::span<s16> output_buffer{reinterpret_cast<s16*>(stream), num_frames * frame_size};
if (additional_amount <= 0 && total_amount <= 0) {
return;
}
const int bytes_requested = additional_amount > 0 ? additional_amount : total_amount;
std::vector<s16> output(bytes_requested / static_cast<int>(sizeof(s16)));
const std::size_t num_frames =
static_cast<std::size_t>(bytes_requested) / sizeof(s16) / frame_size;
std::span<s16> output_buffer{output.data(), output.size()};
impl->ProcessAudioOutAndRender(output_buffer, num_frames);
static_cast<void>(SDL_PutAudioStreamData(stream, output.data(), bytes_requested));
}
}
/// SDL device id of the opened input/output device
SDL_AudioDeviceID device{};
/// SDL stream attached to an opened input/output device
SDL_AudioStream* stream{};
};
SDLSink::SDLSink(std::string_view target_device_name) {
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return;
}
@@ -218,18 +268,26 @@ std::vector<std::string> ListSDLSinkDevices(bool capture) {
std::vector<std::string> device_list;
if (!SDL_WasInit(SDL_INIT_AUDIO)) {
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
if (!SDL_InitSubSystem(SDL_INIT_AUDIO)) {
LOG_CRITICAL(Audio_Sink, "SDL_InitSubSystem audio failed: {}", SDL_GetError());
return {};
}
}
const int device_count = SDL_GetNumAudioDevices(capture);
int device_count = 0;
SDL_AudioDeviceID* devices =
capture ? SDL_GetAudioRecordingDevices(&device_count)
: SDL_GetAudioPlaybackDevices(&device_count);
if (devices == nullptr) {
return device_list;
}
for (int i = 0; i < device_count; ++i) {
if (const char* name = SDL_GetAudioDeviceName(i, capture)) {
if (const char* name = SDL_GetAudioDeviceName(devices[i])) {
device_list.emplace_back(name);
}
}
SDL_free(devices);
return device_list;
}
@@ -242,7 +300,7 @@ u32 GetSDLLatency() {
// REVERTED back to 3833 - Below function IsSDLSuitable() removed, reverting to GetSDLLatency() above. - DIABLO 3 FIX
/*
bool IsSDLSuitable() {
#if !defined(HAVE_SDL2)
#if !defined(HAVE_SDL3)
return false;
#else
// Check SDL can init
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+6 -6
View File
@@ -16,8 +16,8 @@
#ifdef HAVE_CUBEB
#include "audio_core/sink/cubeb_sink.h"
#endif
#ifdef HAVE_SDL2
#include "audio_core/sink/sdl2_sink.h"
#ifdef HAVE_SDL3
#include "audio_core/sink/sdl3_sink.h"
#endif
#include "audio_core/sink/null_sink.h"
#include "common/logging.h"
@@ -71,9 +71,9 @@ constexpr SinkDetails sink_details[] = {
&GetCubebLatency,
},
#endif
#ifdef HAVE_SDL2
#ifdef HAVE_SDL3
SinkDetails{
Settings::AudioEngine::Sdl2,
Settings::AudioEngine::Sdl3,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<SDLSink>(device_id);
},
@@ -115,10 +115,10 @@ 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(HAVE_CUBEB) && defined(HAVE_SDL3)
iter = find_backend(Settings::AudioEngine::Cubeb);
if (iter->latency() > TargetSampleCount * 3) {
iter = find_backend(Settings::AudioEngine::Sdl2);
iter = find_backend(Settings::AudioEngine::Sdl3);
}
#else
iter = std::begin(sink_details);
+1 -8
View File
@@ -184,19 +184,12 @@ if(ARCHITECTURE_x86_64)
x64/cpu_detect.h
x64/cpu_wait.cpp
x64/cpu_wait.h
x64/native_clock.cpp
x64/native_clock.h
x64/rdtsc.cpp
x64/rdtsc.h
x64/xbyak_abi.h
x64/xbyak_util.h)
x64/xbyak.h)
target_link_libraries(common PRIVATE xbyak::xbyak)
endif()
if(HAS_NCE)
target_sources(common PRIVATE arm64/native_clock.cpp arm64/native_clock.h)
endif()
if(MSVC)
target_compile_definitions(
common
-87
View File
@@ -1,87 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#ifdef ANDROID
#include <sys/system_properties.h>
#endif
#include "common/arm64/native_clock.h"
namespace Common::Arm64 {
namespace {
NativeClock::FactorType GetFixedPointFactor(u64 num, u64 den) {
return (static_cast<NativeClock::FactorType>(num) << 64) / den;
}
u64 MultiplyHigh(u64 m, NativeClock::FactorType factor) {
return static_cast<u64>((m * factor) >> 64);
}
} // namespace
NativeClock::NativeClock() {
const u64 host_cntfrq = GetHostCNTFRQ();
ns_cntfrq_factor = GetFixedPointFactor(NsRatio::den, host_cntfrq);
us_cntfrq_factor = GetFixedPointFactor(UsRatio::den, host_cntfrq);
ms_cntfrq_factor = GetFixedPointFactor(MsRatio::den, host_cntfrq);
guest_cntfrq_factor = GetFixedPointFactor(CNTFRQ, host_cntfrq);
gputick_cntfrq_factor = GetFixedPointFactor(GPUTickFreq, host_cntfrq);
}
std::chrono::nanoseconds NativeClock::GetTimeNS() const {
return std::chrono::nanoseconds{MultiplyHigh(GetUptime(), ns_cntfrq_factor)};
}
std::chrono::microseconds NativeClock::GetTimeUS() const {
return std::chrono::microseconds{MultiplyHigh(GetUptime(), us_cntfrq_factor)};
}
std::chrono::milliseconds NativeClock::GetTimeMS() const {
return std::chrono::milliseconds{MultiplyHigh(GetUptime(), ms_cntfrq_factor)};
}
s64 NativeClock::GetCNTPCT() const {
return MultiplyHigh(GetUptime(), guest_cntfrq_factor);
}
s64 NativeClock::GetGPUTick() const {
return MultiplyHigh(GetUptime(), gputick_cntfrq_factor);
}
s64 NativeClock::GetUptime() const {
s64 cntvct_el0 = 0;
asm volatile("dsb ish\n\t"
"mrs %[cntvct_el0], cntvct_el0\n\t"
"dsb ish\n\t"
: [cntvct_el0] "=r"(cntvct_el0));
return cntvct_el0;
}
bool NativeClock::IsNative() const {
return true;
}
s64 NativeClock::GetHostCNTFRQ() {
u64 cntfrq_el0 = 0;
std::string_view board{""};
#ifdef ANDROID
char buffer[PROP_VALUE_MAX];
int len{__system_property_get("ro.product.board", buffer)};
board = std::string_view(buffer, static_cast<size_t>(len));
#endif
if (board == "s5e9925") { // Exynos 2200
cntfrq_el0 = 25600000;
} else if (board == "exynos2100") { // Exynos 2100
cntfrq_el0 = 26000000;
} else if (board == "exynos9810") { // Exynos 9810
cntfrq_el0 = 26000000;
} else if (board == "s5e8825") { // Exynos 1280
cntfrq_el0 = 26000000;
} else {
asm("mrs %[cntfrq_el0], cntfrq_el0" : [cntfrq_el0] "=r"(cntfrq_el0));
}
return cntfrq_el0;
}
} // namespace Common::Arm64
-45
View File
@@ -1,45 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/wall_clock.h"
namespace Common::Arm64 {
class NativeClock final : public WallClock {
public:
explicit NativeClock();
std::chrono::nanoseconds GetTimeNS() const override;
std::chrono::microseconds GetTimeUS() const override;
std::chrono::milliseconds GetTimeMS() const override;
s64 GetCNTPCT() const override;
s64 GetGPUTick() const override;
s64 GetUptime() const override;
bool IsNative() const override;
static s64 GetHostCNTFRQ();
public:
using FactorType = unsigned __int128;
FactorType GetGuestCNTFRQFactor() const {
return guest_cntfrq_factor;
}
private:
FactorType ns_cntfrq_factor;
FactorType us_cntfrq_factor;
FactorType ms_cntfrq_factor;
FactorType guest_cntfrq_factor;
FactorType gputick_cntfrq_factor;
};
} // namespace Common::Arm64
+4 -1
View File
@@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -60,7 +63,7 @@ public:
template <typename Func>
void ForEachItemBelow(TickType tick, Func&& func) {
static constexpr bool RETURNS_BOOL =
std::is_same_v<std::invoke_result<Func, ObjectType>, bool>;
std::is_same_v<std::invoke_result_t<Func, ObjectType>, bool>;
Item* iterator = first_item;
while (iterator) {
if (static_cast<s64>(tick) - static_cast<s64>(iterator->tick) < 0) {
+12
View File
@@ -435,4 +435,16 @@ void ToggleSlowMode() {
SetSpeedMode(SpeedMode::Standard);
}
bool IsOpenGL() {
const auto backend = Settings::values.renderer_backend.GetValue();
switch (backend) {
case RendererBackend::OpenGL_GLSL:
case RendererBackend::OpenGL_GLASM:
case RendererBackend::OpenGL_SPIRV:
return true;
default:
return false;
}
}
} // namespace Settings
+9
View File
@@ -545,6 +545,13 @@ struct Values {
Specialization::Default,
true,
true};
SwitchableSetting<bool> antiflicker{linkage,
false,
"antiflicker",
Category::RendererHacks,
Specialization::Default,
true,
true};
SwitchableSetting<bool> async_presentation{linkage,
#ifdef ANDROID
false,
@@ -863,6 +870,8 @@ bool IsFastmemEnabled();
void SetNceEnabled(bool is_64bit);
bool IsNceEnabled();
bool IsOpenGL();
bool IsDockedMode();
float Volume();
+5 -3
View File
@@ -92,11 +92,13 @@ struct EnumMetadata {
// AudioEngine must be specified discretely due to having existing but slightly different
// canonicalizations
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
enum class AudioEngine : u32 { Auto, Cubeb, Sdl2, Null, Oboe, };
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
template<>
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
return {
{"auto", AudioEngine::Auto}, {"cubeb", AudioEngine::Cubeb}, {"sdl2", AudioEngine::Sdl2},
{"auto", AudioEngine::Auto},
{"cubeb", AudioEngine::Cubeb},
{"sdl3", AudioEngine::Sdl3},
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
};
}
@@ -143,7 +145,7 @@ ENUM(ConfirmStop, Ask_Always, Ask_Based_On_Game, Ask_Never);
ENUM(FullscreenMode, Borderless, Exclusive);
ENUM(NvdecEmulation, Off, Cpu, Gpu);
ENUM(ResolutionSetup, Res1_4X, Res1_2X, Res3_4X, Res1X, Res5_4X, Res3_2X, Res2X, Res3X, Res4X, Res5X, Res6X, Res7X, Res8X);
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, MaxEnum);
ENUM(ScalingFilter, NearestNeighbor, Bilinear, Bicubic, Gaussian, Lanczos, ScaleForce, Fsr, Area, ZeroTangent, BSpline, Mitchell, Spline1, Mmpx, Sgsr, SgsrEdge, MaxEnum);
ENUM(AntiAliasing, None, Fxaa, Smaa, MaxEnum);
ENUM(AspectRatio, R16_9, R4_3, R21_9, R16_10, Stretch);
ENUM(ConsoleMode, Handheld, Docked);

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