Compare commits

..

45 commits

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

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

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

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

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

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

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

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

Note: Code still needs a bit of cleanup.

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

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

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

Authored by amicuchu

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Can be 0.0.4 or 0.0.5 up to the team.

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

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

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

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

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

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

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

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

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

Utilised by Ultracam 3.0. Credit to Zephyron (Citron)

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

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

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

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

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

Safe and functional.

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

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

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

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

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

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

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

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

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

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

Reviewed-on: eden-emu/eden#2708
2025-10-10 05:59:31 +02:00
280 changed files with 4672 additions and 1979 deletions

View file

@ -1,63 +0,0 @@
#!/bin/bash -e
# SPDX-FileCopyrightText: 2025 eden Emulator Project
# SPDX-License-Identifier: GPL-3.0-or-later
QT_VERSION="6.8.3"
QT_SRC_DIR="$HOME/qt-src-$QT_VERSION"
QT_BUILD_DIR="$HOME/qt-build-$QT_VERSION"
QT_INSTALL_DIR="$HOME/qt-clang-$QT_VERSION"
CLANG_BIN="/usr/bin/clang"
CLANGPP_BIN="/usr/bin/clang++"
if [ "${INSTALL_DEPS}" = "ON" ]; then
sudo apt-get update
sudo apt-get install -y build-essential perl python3 git \
"^libxcb.*" libx11-dev libx11-xcb-dev libxcb-xinerama0-dev \
libxcb-keysyms1-dev libxcb-icccm4-dev libxcb-image0-dev \
libxkbcommon-dev libxkbcommon-x11-dev libgl-dev libdbus-1-dev \
libasound2-dev libpulse-dev libudev-dev libfontconfig1-dev \
libcap-dev libssl-dev
fi
if [ ! -d "$QT_SRC_DIR" ]; then
mkdir -p "$QT_SRC_DIR"
cd "$QT_SRC_DIR"
wget https://download.qt.io/archive/qt/6.8/$QT_VERSION/single/qt-everywhere-src-$QT_VERSION.tar.xz
tar xf qt-everywhere-src-$QT_VERSION.tar.xz --strip-components=1
fi
mkdir -p "$QT_BUILD_DIR"
cd "$QT_BUILD_DIR"
"$QT_SRC_DIR/configure" \
-prefix "$QT_INSTALL_DIR" \
-opensource -confirm-license \
-nomake examples -nomake tests \
-no-pch \
-skip qt3d \
-skip qtcanvas3d \
-skip qtconnectivity \
-skip qtdatavis3d \
-skip qtdoc \
-skip qtgraphicaleffects \
-skip qtgamepad \
-skip qtquick3d \
-skip qtquicktimeline \
-skip qtx11extras \
-skip qtwebengine \
-skip qtgraphs \
-skip qtquick3dphysics \
-skip qtspeech \
-platform linux-clang \
-device-option CXX="$CLANGPP_BIN" \
-device-option CC="$CLANG_BIN" \
-release \
-force-debug-info \
"CFLAGS=-march=native -mtune=native -O3 -pipe" \
"CXXFLAGS=-march=native -mtune=native -O3 -pipe"
cmake --build . --parallel $(nproc)
cmake --install .

6
.gitignore vendored
View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,8 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(PLATFORM_FREEBSD ON) set(PLATFORM_FREEBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
set(PLATFORM_OPENBSD ON) set(PLATFORM_OPENBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
set(PLATFORM_NETBSD ON)
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux") elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(PLATFORM_LINUX ON) set(PLATFORM_LINUX ON)
endif() endif()
@ -41,8 +43,7 @@ if (PLATFORM_SUN)
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/qt/6.6/lib/amd64/cmake") list(APPEND CMAKE_PREFIX_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
list(APPEND CMAKE_MODULE_PATH "/usr/lib/qt/6.6/lib/amd64/cmake") list(APPEND CMAKE_MODULE_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
# amazing # Amazing - absolutely incredible
# absolutely incredible
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/amd64/cmake") list(APPEND CMAKE_PREFIX_PATH "/usr/lib/amd64/cmake")
list(APPEND CMAKE_MODULE_PATH "/usr/lib/amd64/cmake") list(APPEND CMAKE_MODULE_PATH "/usr/lib/amd64/cmake")
@ -52,6 +53,10 @@ if (PLATFORM_SUN)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")
endif() endif()
if (CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
endif()
endif() endif()
# Needed for FFmpeg w/ VAAPI and DRM # Needed for FFmpeg w/ VAAPI and DRM
@ -59,6 +64,15 @@ if (PLATFORM_OPENBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R6/include") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R6/include")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R6/include") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R6/include")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R6/lib") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R6/lib")
elseif (PLATFORM_NETBSD)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R7/include")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R7/include")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R7/lib")
endif()
# NetBSD: Fun for the whole family!
if (PLATFORM_NETBSD)
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:/usr/pkg/lib/ffmpeg7/pkgconfig")
endif() endif()
# Detect current compilation architecture and create standard definitions # Detect current compilation architecture and create standard definitions
@ -145,6 +159,7 @@ endif()
if (PLATFORM_FREEBSD) if (PLATFORM_FREEBSD)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
endif() endif()
# Set bundled sdl2/qt as dependent options. # Set bundled sdl2/qt as dependent options.
@ -260,7 +275,11 @@ if (ENABLE_WEB_SERVICE)
endif() endif()
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL}) option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
if (ENABLE_OPENSSL) if (ENABLE_OPENSSL)
cmake_dependent_option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" "${MSVC}" "NOT ANDROID" ON) set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
if (EXT_DEFAULT OR PLATFORM_SUN)
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL ON)
endif()
option(YUZU_USE_BUNDLED_OPENSSL "Download bundled OpenSSL build" ${DEFAULT_YUZU_USE_BUNDLED_OPENSSL})
endif() endif()
if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL) if (ANDROID AND YUZU_DOWNLOAD_ANDROID_VVL)
@ -347,7 +366,7 @@ if (YUZU_ROOM)
add_compile_definitions(YUZU_ROOM) add_compile_definitions(YUZU_ROOM)
endif() endif()
if (ANDROID OR PLATFORM_FREEBSD OR PLATFORM_OPENBSD OR PLATFORM_SUN OR APPLE) if ((ANDROID OR APPLE OR UNIX) AND (NOT PLATFORM_LINUX OR ANDROID) AND NOT WIN32)
if(CXX_APPLE OR CXX_CLANG) if(CXX_APPLE OR CXX_CLANG)
# libc++ has stop_token and jthread as experimental # libc++ has stop_token and jthread as experimental
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fexperimental-library")
@ -573,11 +592,12 @@ if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
find_package(xbyak) find_package(xbyak)
endif() endif()
if (ENABLE_WEB_SERVICE) if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER)
find_package(httplib) # Workaround: httplib will kill itself if you attempt to do a find_package propagation
# find_package(httplib CONFIG)
endif() endif()
if (ENABLE_WEB_SERVICE OR ENABLE_QT_UPDATE_CHECKER) if (ENABLE_WEB_SERVICE)
find_package(cpp-jwt) find_package(cpp-jwt)
endif() endif()

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

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

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

View file

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 883 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

View file

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

View file

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

View file

@ -8,6 +8,9 @@ Eden-specific options:
- `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing - `YUZU_USE_CPM` is set by default on MSVC and Android. Other platforms should use this if certain "required" system dependencies (e.g. OpenSSL) are broken or missing
* If this is `OFF`, required system dependencies will be searched via `find_package`, although most externals use CPM regardless. * If this is `OFF`, required system dependencies will be searched via `find_package`, although most externals use CPM regardless.
- Force system libraries via CMake arguments:
* SDL2: `YUZU_USE_BUNDLED_SDL2` and `YUZU_USE_EXTERNAL_SDL2`
* FFmpeg: `YUZU_USE_EXTERNAL_FFMPEG`
## Tooling ## Tooling

View file

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

View file

@ -102,7 +102,7 @@ sudo pacman -Syu --needed base-devel boost catch2 cmake enet ffmpeg fmt git glsl
<summary>Ubuntu, Debian, Mint Linux</summary> <summary>Ubuntu, Debian, Mint Linux</summary>
```sh ```sh
sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2t64 libboost-context-dev libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev vulkan-utility-libraries-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev sudo apt-get install autoconf cmake g++ gcc git glslang-tools libglu1-mesa-dev libhidapi-dev libpulse-dev libtool libudev-dev libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-render-util0 libxcb-xinerama0 libxcb-xkb1 libxext-dev libxkbcommon-x11-0 mesa-common-dev nasm ninja-build qt6-base-private-dev libmbedtls-dev catch2 libfmt-dev liblz4-dev nlohmann-json3-dev libzstd-dev libssl-dev libavfilter-dev libavcodec-dev libswscale-dev pkg-config zlib1g-dev libva-dev libvdpau-dev qt6-tools-dev libzydis-dev zydis-tools libzycore-dev libvulkan-dev spirv-tools spirv-headers libusb-1.0-0-dev libxbyak-dev libboost-dev libboost-fiber-dev libboost-context-dev libsdl2-dev libopus-dev libasound2t64 vulkan-utility-libraries-dev
``` ```
* Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required. * Ubuntu 22.04, Linux Mint 20, or Debian 12 or later is required.
@ -110,18 +110,28 @@ sudo apt-get install autoconf cmake g++ gcc git glslang-tools libasound2t64 libb
</details> </details>
<details> <details>
<summary>Fedora Linux</summary> <summary>AlmaLinux, Fedora, Red Hat Linux</summary>
Fedora:
```sh ```sh
sudo dnf install autoconf ccache cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel sudo dnf install autoconf cmake fmt-devel gcc{,-c++} glslang hidapi-devel json-devel libtool libusb1-devel libzstd-devel lz4-devel nasm ninja-build openssl-devel pulseaudio-libs-devel qt6-linguist qt6-qtbase{-private,}-devel qt6-qtwebengine-devel qt6-qtmultimedia-devel speexdsp-devel wayland-devel zlib-devel ffmpeg-devel libXext-devel boost jq
``` ```
* Force system libraries via CMake arguments: AlmaLinux (use `YUZU_USE_CPM=ON`):
* SDL2: `-DYUZU_USE_BUNDLED_SDL2=OFF -DYUZU_USE_EXTERNAL_SDL2=OFF` ```sh
* FFmpeg: `-DYUZU_USE_EXTERNAL_FFMPEG=OFF` # vvv - Only if RPMfusion is not installed or EPEL isn't either
* [RPM Fusion](https://rpmfusion.org/) is required for `ffmpeg-devel` sudo dnf install epel-release dnf-utils
# (run rpmfusion installation afterwards)
# vvv - This will work for most systems
sudo dnf install autoconf cmake libtool libudev cmake gcc gcc-c++ qt6-qtbase-devel zlib-devel openssl-devel boost SDL2 ffmpeg-devel libdrm glslang jq patch
# Qt6 private GUI must be taken from CRB repos
sudo dnf config-manager --enable crb
sudo dnf install qt6-qtbase-private-devel
```
* [RPM Fusion](https://rpmfusion.org/Configuration) is required for `ffmpeg-devel`
* Fedora 32 or later is required. * Fedora 32 or later is required.
* Fedora 36+ users with GCC 12 need Clang and should configure CMake with: * Fedora 36+ users with GCC 12 need Clang and should configure CMake with: `cmake -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang -B build`
</details> </details>
<details> <details>
@ -145,44 +155,43 @@ brew install molten-vk vulkan-loader
<details> <details>
<summary>FreeBSD</summary> <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/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense devel/zydis`
devel/cmake
devel/sdl20
devel/boost-libs
devel/catch2
devel/libfmt
devel/nlohmann-json
devel/ninja
devel/nasm
devel/autoconf
devel/pkgconf
devel/qt6-base
net/enet
multimedia/ffnvcodec-headers
multimedia/ffmpeg
audio/opus
archivers/liblz4
lang/gcc12
graphics/glslang
graphics/vulkan-utility-libraries
```
If using FreeBSD 12 or prior, use `devel/pkg-config` instead. If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
</details> </details>
<details>
<summary>NetBSD</summary>
Install `pkgin` if not already `pkg_add pkgin`, see also the general [pkgsrc guide](https://www.netbsd.org/docs/pkgsrc/using.html). For NetBSD 10.1 provide `cat 'PKG_PATH="https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/x86_64/10.0_2025Q3/All/"' >/etc/pkg_install.conf`. If `pkgin` is taking too much time consider adding the following to `/etc/rc.conf`:
```
ip6addrctl=YES
ip6addrctl_policy=ipv4_prefer
```
For NetBSD +10.1: `pkgin install git cmake boost fmtlib SDL2 catch2 libjwt spirv-headers ffmpeg7 libva nlohmann-json jq libopus qt6 mbedtls3 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1`.
glslang is not available on NetBSD, to circumvent this simply build glslang by yourself:
```sh
pkgin python313
git clone https://github.com/KhronosGroup/glslang.git
cd glslang
python3.13 ./update_glslang_sources.py
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j`nproc`
cmake --install build
```
</details>
<details> <details>
<summary>OpenBSD</summary> <summary>OpenBSD</summary>
```sh ```sh
pkg_add -u pkg_add -u
pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1.1.0.27 pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gmake llvm-19.1.7p3 qt6 jq fmt nlohmann-json enet boost vulkan-utility-libraries vulkan-headers spirv-headers spirv-tools catch2 sdl2 libusb1-1.0.27
``` ```
</details> </details>
<details> <details>
@ -210,6 +219,16 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
* `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc` * `echo 'PATH=$(readlink -e /c/VulkanSDK/*/Bin/):$PATH' >> ~/.bashrc`
</details> </details>
<details>
<summary>RedoxOS</summary>
```sh
sudo pkg update && sudo pkg install git cmake
sudo pkg install ffmpeg6 sdl2 zlib llvm18
```
</details>
## All Done ## All Done
You may now return to the **[root build guide](Build.md)**. You may now return to the **[root build guide](Build.md)**.

View file

@ -54,6 +54,7 @@ The vast majority of Eden's testing is done on Windows, Linux, and Android. Howe
- FreeBSD - FreeBSD
- OpenBSD - OpenBSD
- NetBSD
- OpenIndiana (Solaris) - OpenIndiana (Solaris)
- macOS - macOS
@ -127,6 +128,6 @@ AMD GPU support on these platforms is limited or nonexistent.
## VMs ## VMs
Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60fps. Eden "can" run in a VM, but only with the software renderer, *unless* you create a hardware-accelerated KVM with GPU passthrough. If you *really* want to do this and don't have a spare GPU lying around, RX 570 and 580 GPUs are extremely cheap on the black market and are powerful enough to run most commercial games at 60 FPS.
Some users and developers have had success using a pure OpenGL-accelerated KVM on Linux with a Windows VM, but this is ridiculously tedious to set up. You're probably better off dual-booting. Some users and developers have had success using a pure OpenGL-accelerated KVM on Linux with a Windows VM, but this is ridiculously tedious to set up. You're probably better off dual-booting.

View file

@ -29,7 +29,8 @@
"repo": "yhirose/cpp-httplib", "repo": "yhirose/cpp-httplib",
"tag": "v%VERSION%", "tag": "v%VERSION%",
"hash": "b364500f76e2ecb0fe21b032d831272e3f1dfeea71af74e325f8fc4ce9dcdb3c941b97a5b422bdeafb9facd058597b90f8bfc284fb9afe3c33fefa15dd5a010b", "hash": "b364500f76e2ecb0fe21b032d831272e3f1dfeea71af74e325f8fc4ce9dcdb3c941b97a5b422bdeafb9facd058597b90f8bfc284fb9afe3c33fefa15dd5a010b",
"git_version": "0.26.0" "git_version": "0.26.0",
"find_args": "MODULE GLOBAL"
}, },
"cpp-jwt": { "cpp-jwt": {
"version": "1.4", "version": "1.4",
@ -45,9 +46,10 @@
"package": "xbyak", "package": "xbyak",
"repo": "herumi/xbyak", "repo": "herumi/xbyak",
"tag": "v%VERSION%", "tag": "v%VERSION%",
"hash": "e84992c65ad62c577e2746ec5180132fd2875166d1e6b1521a0ff619787e1645792fe5f6a858fe94ed66f297912b6a6b89a509b5d5f5e81a2db1dd7e6790b1f5", "hash": "b40dade90fb0e46a2bd52934f7ce461e37be931b571e58cbe2203bc08ed5b54c7ff1a29026c74c7f9805e4e3f6c9636deca528e6b4a8093ce7eae145218599f1",
"git_version": "7.29",
"bundled": true, "bundled": true,
"git_version": "7.30" "skip_updates": true
}, },
"xbyak": { "xbyak": {
"package": "xbyak", "package": "xbyak",
@ -96,7 +98,11 @@
"version": "3", "version": "3",
"git_version": "3.6.4", "git_version": "3.6.4",
"artifact": "%TAG%.tar.bz2", "artifact": "%TAG%.tar.bz2",
"skip_updates": true "skip_updates": true,
"patches": [
"0002-aesni-fix.patch",
"0003-aesni-fix.patch"
]
}, },
"enet": { "enet": {
"repo": "lsalzman/enet", "repo": "lsalzman/enet",
@ -123,6 +129,9 @@
"git_version": "2025.4", "git_version": "2025.4",
"options": [ "options": [
"SPIRV_SKIP_EXECUTABLES ON" "SPIRV_SKIP_EXECUTABLES ON"
],
"patches": [
"0001-netbsd-fix.patch"
] ]
}, },
"spirv-headers": { "spirv-headers": {
@ -163,7 +172,10 @@
"tag": "v%VERSION%", "tag": "v%VERSION%",
"hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f", "hash": "a95495142f915d6e9c2a23e80fe360343e9097680066a2f9d3037a070ba5f81ee5559a0407cc9e972dc2afae325873f1fc7ea07a64012c0f01aac6e549f03e3f",
"version": "3.0.1", "version": "3.0.1",
"git_version": "3.11.0" "git_version": "3.11.0",
"patches": [
"0001-solaris-isnan-fix.patch"
]
}, },
"discord-rpc": { "discord-rpc": {
"package": "DiscordRPC", "package": "DiscordRPC",

View file

@ -4,6 +4,9 @@
"tag": "v%VERSION%", "tag": "v%VERSION%",
"hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5", "hash": "98c5f7940ff06b25c9aa65aa98e23de4c79a4c1067595f4c73cc145af23a1c286639e1ba11185cd91bab702081f307b973f08a4c9746576dc8d01b3620a3aeb5",
"find_args": "MODULE", "find_args": "MODULE",
"git_version": "1.0.29" "git_version": "1.0.29",
"patches": [
"0001-netbsd-gettime.patch"
]
} }
} }

View file

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

View file

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

View file

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

View file

@ -58,8 +58,7 @@ android {
defaultConfig { defaultConfig {
applicationId = "dev.eden.eden_emulator" applicationId = "dev.eden.eden_emulator"
minSdk = 24
minSdk = 28
targetSdk = 36 targetSdk = 36
versionName = getGitVersion() versionName = getGitVersion()

View file

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

View file

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

View file

@ -61,6 +61,7 @@ import org.yuzu.yuzu_emu.utils.ThemeHelper
import java.text.NumberFormat import java.text.NumberFormat
import kotlin.math.roundToInt import kotlin.math.roundToInt
import org.yuzu.yuzu_emu.utils.ForegroundService import org.yuzu.yuzu_emu.utils.ForegroundService
import androidx.core.os.BundleCompat
class EmulationActivity : AppCompatActivity(), SensorEventListener { class EmulationActivity : AppCompatActivity(), SensorEventListener {
private lateinit var binding: ActivityEmulationBinding private lateinit var binding: ActivityEmulationBinding
@ -202,6 +203,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
stopForegroundService(this) stopForegroundService(this)
NativeLibrary.playTimeManagerStop()
} }
@ -230,7 +232,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun dispatchKeyEvent(event: KeyEvent): Boolean { override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK && if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) { ) {
return super.dispatchKeyEvent(event) return super.dispatchKeyEvent(event)
} }
@ -244,7 +248,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean { override fun dispatchGenericMotionEvent(event: MotionEvent): Boolean {
if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK && if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&
event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD &&
event.source and InputDevice.SOURCE_KEYBOARD != InputDevice.SOURCE_KEYBOARD &&
event.source and InputDevice.SOURCE_MOUSE != InputDevice.SOURCE_MOUSE
) { ) {
return super.dispatchGenericMotionEvent(event) return super.dispatchGenericMotionEvent(event)
} }
@ -526,6 +532,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
fun onEmulationStarted() { fun onEmulationStarted() {
emulationViewModel.setEmulationStarted(true) emulationViewModel.setEmulationStarted(true)
NativeLibrary.playTimeManagerStart()
} }
fun onEmulationStopped(status: Int) { fun onEmulationStopped(status: Int) {

View file

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

View file

@ -10,7 +10,6 @@ import org.yuzu.yuzu_emu.utils.NativeConfig
enum class BooleanSetting(override val key: String) : AbstractBooleanSetting { enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
AUDIO_MUTED("audio_muted"), AUDIO_MUTED("audio_muted"),
CPU_DEBUG_MODE("cpu_debug_mode"),
FASTMEM("cpuopt_fastmem"), FASTMEM("cpuopt_fastmem"),
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"), FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
CORE_SYNC_CORE_SPEED("sync_core_speed"), CORE_SYNC_CORE_SPEED("sync_core_speed"),

View file

@ -764,13 +764,6 @@ abstract class SettingsItem(
descriptionId = R.string.use_auto_stub_description descriptionId = R.string.use_auto_stub_description
) )
) )
put(
SwitchSetting(
BooleanSetting.CPU_DEBUG_MODE,
titleId = R.string.cpu_debug_mode,
descriptionId = R.string.cpu_debug_mode_description
)
)
val fastmem = object : AbstractBooleanSetting { val fastmem = object : AbstractBooleanSetting {
override fun getBoolean(needsGlobal: Boolean): Boolean = override fun getBoolean(needsGlobal: Boolean): Boolean =
@ -784,7 +777,6 @@ abstract class SettingsItem(
override val key: String = FASTMEM_COMBINED override val key: String = FASTMEM_COMBINED
override val isRuntimeModifiable: Boolean = false override val isRuntimeModifiable: Boolean = false
override val pairedSettingKey = BooleanSetting.CPU_DEBUG_MODE.key
override val defaultValue: Boolean = true override val defaultValue: Boolean = true
override val isSwitchable: Boolean = true override val isSwitchable: Boolean = true
override var global: Boolean override var global: Boolean

View file

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

View file

@ -1158,7 +1158,6 @@ class SettingsFragmentPresenter(
add(IntSetting.CPU_BACKEND.key) add(IntSetting.CPU_BACKEND.key)
add(IntSetting.CPU_ACCURACY.key) add(IntSetting.CPU_ACCURACY.key)
add(BooleanSetting.USE_AUTO_STUB.key) add(BooleanSetting.USE_AUTO_STUB.key)
add(BooleanSetting.CPU_DEBUG_MODE.key)
add(SettingsItem.FASTMEM_COMBINED) add(SettingsItem.FASTMEM_COMBINED)
add(HeaderSetting(R.string.log)) add(HeaderSetting(R.string.log))

View file

@ -1635,6 +1635,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
Log.debug("[EmulationFragment] Pausing emulation.") Log.debug("[EmulationFragment] Pausing emulation.")
NativeLibrary.pauseEmulation() NativeLibrary.pauseEmulation()
NativeLibrary.playTimeManagerStop()
state = State.PAUSED state = State.PAUSED
} else { } else {
@ -1725,6 +1726,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
State.PAUSED -> { State.PAUSED -> {
Log.debug("[EmulationFragment] Resuming emulation.") Log.debug("[EmulationFragment] Resuming emulation.")
NativeLibrary.unpauseEmulation() NativeLibrary.unpauseEmulation()
NativeLibrary.playTimeManagerStart()
} }
else -> Log.debug("[EmulationFragment] Bug, run called while already running.") else -> Log.debug("[EmulationFragment] Bug, run called while already running.")

View file

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

View file

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

View file

@ -1039,7 +1039,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
scale /= 100f scale /= 100f
// Apply individual scale // Apply individual scale
scale *= overlayControlData.individualScale scale *= overlayControlData.individualScale.let { if (it > 0f) it else 1f }
// Initialize the InputOverlayDrawableButton. // Initialize the InputOverlayDrawableButton.
val defaultStateBitmap = getBitmap(context, defaultResId, scale) val defaultStateBitmap = getBitmap(context, defaultResId, scale)
@ -1114,7 +1114,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
// Apply individual scale // Apply individual scale
if (dpadData != null) { if (dpadData != null) {
scale *= dpadData.individualScale scale *= dpadData.individualScale.let { if (it > 0f) it else 1f }
} }
// Initialize the InputOverlayDrawableDpad. // Initialize the InputOverlayDrawableDpad.
@ -1191,7 +1191,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) :
scale /= 100f scale /= 100f
// Apply individual scale // Apply individual scale
scale *= overlayControlData.individualScale scale *= overlayControlData.individualScale.let { if (it > 0f) it else 1f }
// Initialize the InputOverlayDrawableJoystick. // Initialize the InputOverlayDrawableJoystick.
val bitmapOuter = getBitmap(context, resOuter, scale) val bitmapOuter = getBitmap(context, resOuter, scale)

View file

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

View file

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

View file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 438 KiB

After

Width:  |  Height:  |  Size: 244 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 112 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View file

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

View file

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

View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_hours"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:hint="@string/hours"
app:boxBackgroundMode="outline">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_hours"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="4" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_minutes"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginEnd="8dp"
android:hint="@string/minutes"
app:boxBackgroundMode="outline">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_minutes"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="2" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/layout_seconds"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="@string/seconds"
app:boxBackgroundMode="outline">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/input_seconds"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:maxLength="2" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>

View file

@ -74,12 +74,22 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="12dp" android:layout_marginTop="12dp"
android:layout_marginBottom="12dp" android:layout_marginBottom="2dp"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:requiresFadingEdge="horizontal" android:requiresFadingEdge="horizontal"
android:textAlignment="center" android:textAlignment="center"
tools:text="deko_basic" /> tools:text="deko_basic" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/playtime"
style="?attr/textAppearanceBodyMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:textAlignment="center"
tools:text="Game Playtime" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/list_properties" android:id="@+id/list_properties"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -540,8 +540,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">وحدة المعالج المركزية</string> <string name="cpu">وحدة المعالج المركزية</string>
<string name="cpu_debug_mode">تصحيح أخطاء وحدة المعالجة المركزية</string>
<string name="cpu_debug_mode_description">يضع وحدة المعالجة المركزية في وضع التصحيح البطيء.</string>
<string name="gpu">وحدة معالجة الرسومات</string> <string name="gpu">وحدة معالجة الرسومات</string>
<string name="renderer_api">واجهة برمجة التطبيقات</string> <string name="renderer_api">واجهة برمجة التطبيقات</string>
<string name="renderer_debug">تصحيح الأخطاء الرسومية</string> <string name="renderer_debug">تصحيح الأخطاء الرسومية</string>

View file

@ -516,8 +516,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">چاککردنەوەی CPU</string>
<string name="cpu_debug_mode_description">CPU لە دۆخی چاککردنەوەی هێواش دادەنێت.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">چاککردنەوەی گرافیک</string> <string name="renderer_debug">چاککردنەوەی گرافیک</string>

View file

@ -496,8 +496,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Ladění CPU</string>
<string name="cpu_debug_mode_description">Pomalý ladící režim</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Ladění grafiky</string> <string name="renderer_debug">Ladění grafiky</string>

View file

@ -520,8 +520,6 @@ Wird der Handheld-Modus verwendet, verringert es die Auflösung und erhöht die
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU-Debugging</string>
<string name="cpu_debug_mode_description">Aktiviert den langsamen Debug-Modus.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Grafik-Debugging</string> <string name="renderer_debug">Grafik-Debugging</string>

View file

@ -540,8 +540,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Depuración de CPU</string>
<string name="cpu_debug_mode_description">Pone la CPU en un modo de depuración lento.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Depuración de gráficos</string> <string name="renderer_debug">Depuración de gráficos</string>

View file

@ -538,8 +538,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">پردازنده</string> <string name="cpu">پردازنده</string>
<string name="cpu_debug_mode">اشکال‌زدایی پردازنده</string>
<string name="cpu_debug_mode_description">پردازنده را در حالت اشکال‌زدایی کندتر قرار می‌دهد.</string>
<string name="gpu">پردازنده گرافیکی</string> <string name="gpu">پردازنده گرافیکی</string>
<string name="renderer_api">رابط برنامه‌نویسی</string> <string name="renderer_api">رابط برنامه‌نویسی</string>
<string name="renderer_debug">اشکال‌زدایی پردازنده گرافیکی</string> <string name="renderer_debug">اشکال‌زدایی پردازنده گرافیکی</string>

View file

@ -540,8 +540,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Débogage du CPU</string>
<string name="cpu_debug_mode_description">Place le CPU en mode lent de débogage.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Débogage des graphismes</string> <string name="renderer_debug">Débogage des graphismes</string>

View file

@ -542,8 +542,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">מעבד</string> <string name="cpu">מעבד</string>
<string name="cpu_debug_mode">דיבאגינג למעבד</string>
<string name="cpu_debug_mode_description">מכניס את המעבד למצב דיבאג איטי</string>
<string name="gpu">מעבד גרפי</string> <string name="gpu">מעבד גרפי</string>
<string name="renderer_api">ממשק תוכנה</string> <string name="renderer_api">ממשק תוכנה</string>
<string name="renderer_debug">דיבאגינג בגרפיקה</string> <string name="renderer_debug">דיבאגינג בגרפיקה</string>

View file

@ -535,8 +535,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU hibakeresés</string>
<string name="cpu_debug_mode_description">Lassú hibakereső módba állítja a CPU-t.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Grafikai hibakeresés</string> <string name="renderer_debug">Grafikai hibakeresés</string>

View file

@ -536,8 +536,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Debugging CPU</string>
<string name="cpu_debug_mode_description">Menempatkan CPU dalam mode debugging lambat</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Debugging Grafis</string> <string name="renderer_debug">Debugging Grafis</string>

View file

@ -539,8 +539,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Debug della CPU</string>
<string name="cpu_debug_mode_description">Imposta la CPU in modalità Debug (Più lento)</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Debug GPU</string> <string name="renderer_debug">Debug GPU</string>

View file

@ -521,7 +521,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPUデバッグ</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">グラフィックデバッグ</string> <string name="renderer_debug">グラフィックデバッグ</string>

View file

@ -533,8 +533,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU 디버깅</string>
<string name="cpu_debug_mode_description">CPU를 느린 디버깅 모드로 설정합니다.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">그래픽 디버깅</string> <string name="renderer_debug">그래픽 디버깅</string>

View file

@ -516,8 +516,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU-feilsøking</string>
<string name="cpu_debug_mode_description">Setter CPU i feilsøkingsmodus</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Grafikkfeilsøking</string> <string name="renderer_debug">Grafikkfeilsøking</string>

View file

@ -520,8 +520,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Debugowanie CPU</string>
<string name="cpu_debug_mode_description">Włącza wolny tryb debugowania.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">Interfejs graficzny</string> <string name="renderer_api">Interfejs graficzny</string>
<string name="renderer_debug">Debugowanie grafiki</string> <string name="renderer_debug">Debugowanie grafiki</string>

View file

@ -540,8 +540,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Depuração da CPU</string>
<string name="cpu_debug_mode_description">Coloca a CPU em um modo de depuração lento.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Depuração de gráficos</string> <string name="renderer_debug">Depuração de gráficos</string>

View file

@ -540,8 +540,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Depuração da CPU</string>
<string name="cpu_debug_mode_description">Coloca a CPU em um modo de depuração lento.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Ativar depuração de gráficos</string> <string name="renderer_debug">Ativar depuração de gráficos</string>

View file

@ -542,8 +542,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">ЦП</string> <string name="cpu">ЦП</string>
<string name="cpu_debug_mode">Отладка ЦП</string>
<string name="cpu_debug_mode_description">Переводит ЦП в режим медленной отладки.</string>
<string name="gpu">ГПУ</string> <string name="gpu">ГПУ</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Отладка графики</string> <string name="renderer_debug">Отладка графики</string>

View file

@ -502,8 +502,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">ЦПУ</string> <string name="cpu">ЦПУ</string>
<string name="cpu_debug_mode">ЦПУ уклањање погрешака</string>
<string name="cpu_debug_mode_description">Ставља ЦПУ у спор режим уклањања погрешака.</string>
<string name="gpu">ГПУ</string> <string name="gpu">ГПУ</string>
<string name="renderer_api">АПИ</string> <string name="renderer_api">АПИ</string>

View file

@ -533,8 +533,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Налагодження CPU</string>
<string name="cpu_debug_mode_description">Уповільнює CPU для налагодження.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">Налагодження графіки</string> <string name="renderer_debug">Налагодження графіки</string>

View file

@ -514,8 +514,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">Chế độ gỡ lỗi CPU</string>
<string name="cpu_debug_mode_description">Đặt CPU vào chế độ gỡ lỗi chậm.</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>

View file

@ -534,8 +534,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU 调试</string>
<string name="cpu_debug_mode_description">将 CPU 设置为较慢的调试模式。</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">图形调试</string> <string name="renderer_debug">图形调试</string>

View file

@ -539,8 +539,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU 偵錯</string>
<string name="cpu_debug_mode_description">將 CPU 設定為慢速偵錯模式。</string>
<string name="gpu">GPU</string> <string name="gpu">GPU</string>
<string name="renderer_api">API</string> <string name="renderer_api">API</string>
<string name="renderer_debug">圖形偵錯</string> <string name="renderer_debug">圖形偵錯</string>

View file

@ -333,6 +333,7 @@
<item>@string/cpu_accuracy_accurate</item> <item>@string/cpu_accuracy_accurate</item>
<item>@string/cpu_accuracy_unsafe</item> <item>@string/cpu_accuracy_unsafe</item>
<item>@string/cpu_accuracy_paranoid</item> <item>@string/cpu_accuracy_paranoid</item>
<item>@string/cpu_accuracy_debugging</item>
</string-array> </string-array>
<integer-array name="cpuAccuracyValues"> <integer-array name="cpuAccuracyValues">
@ -340,6 +341,7 @@
<item>1</item> <item>1</item>
<item>2</item> <item>2</item>
<item>3</item> <item>3</item>
<item>4</item>
</integer-array> </integer-array>
<string-array name="gamepadButtons"> <string-array name="gamepadButtons">

View file

@ -543,8 +543,6 @@
<!-- Debug settings strings --> <!-- Debug settings strings -->
<string name="cpu">CPU</string> <string name="cpu">CPU</string>
<string name="cpu_debug_mode">CPU Debugging</string>
<string name="cpu_debug_mode_description">Puts the CPU in a slow debugging mode.</string>
<string name="use_auto_stub">Use Auto Stub</string> <string name="use_auto_stub">Use Auto Stub</string>
<string name="use_auto_stub_description">Automatically stub missing services and functions. This may improve compatibility but can cause crashes and stability issues.</string> <string name="use_auto_stub_description">Automatically stub missing services and functions. This may improve compatibility but can cause crashes and stability issues.</string>
@ -677,6 +675,7 @@
<string name="fetch">Fetch</string> <string name="fetch">Fetch</string>
<string name="delete">Delete</string> <string name="delete">Delete</string>
<string name="edit">Edit</string> <string name="edit">Edit</string>
<string name="import_success">Imported successfully</string>
<string name="export_success">Exported successfully</string> <string name="export_success">Exported successfully</string>
<string name="start">Start</string> <string name="start">Start</string>
<string name="clear">Clear</string> <string name="clear">Clear</string>
@ -757,6 +756,18 @@
<string name="copy_details">Copy details</string> <string name="copy_details">Copy details</string>
<string name="add_ons">Add-ons</string> <string name="add_ons">Add-ons</string>
<string name="add_ons_description">Toggle mods, updates and DLC</string> <string name="add_ons_description">Toggle mods, updates and DLC</string>
<string name="playtime">Playtime:</string>
<string name="reset_playtime">Clear Playtime</string>
<string name="reset_playtime_description">Reset the current game\'s playtime back to 0 seconds</string>
<string name="reset_playtime_warning_description">This will clear the current game\'s playtime data. Are you sure?</string>
<string name="playtime_reset_successfully">Playtime has been reset</string>
<string name="edit_playtime">Edit Playtime</string>
<string name="hours">Hours</string>
<string name="minutes">Minutes</string>
<string name="hours_must_be_between_0_and_9999">Hours must be between 0 and 9999</string>
<string name="minutes_must_be_between_0_and_59">Minutes must be between 0 and 59</string>
<string name="seconds_must_be_between_0_and_59">Seconds must be between 0 and 59</string>
<string name="playtime_updated_successfully">Playtime updated successfully</string>
<string name="clear_shader_cache">Clear shader cache</string> <string name="clear_shader_cache">Clear shader cache</string>
<string name="clear_shader_cache_description">Removes all shaders built while playing this game</string> <string name="clear_shader_cache_description">Removes all shaders built while playing this game</string>
<string name="clear_shader_cache_warning_description">You will experience more stuttering as the shader cache regenerates</string> <string name="clear_shader_cache_warning_description">You will experience more stuttering as the shader cache regenerates</string>
@ -791,6 +802,10 @@
<string name="verify_no_result">Integrity verification couldn\'t be performed</string> <string name="verify_no_result">Integrity verification couldn\'t be performed</string>
<string name="verify_no_result_description">File contents were not checked for validity</string> <string name="verify_no_result_description">File contents were not checked for validity</string>
<string name="verification_failed_for">Verification failed for the following files:\n%1$s</string> <string name="verification_failed_for">Verification failed for the following files:\n%1$s</string>
<string name="share_game_settings">Share Config</string>
<string name="import_config">Import Config</string>
<string name="export_config">Export Config</string>
<string name="share_config_failed">Failed to share configuration file</string>
<!-- ROM loading errors --> <!-- ROM loading errors -->
<string name="loader_error_encrypted">Your ROM is encrypted</string> <string name="loader_error_encrypted">Your ROM is encrypted</string>
@ -1050,6 +1065,7 @@
<string name="cpu_accuracy_accurate">Accurate</string> <string name="cpu_accuracy_accurate">Accurate</string>
<string name="cpu_accuracy_unsafe">Unsafe</string> <string name="cpu_accuracy_unsafe">Unsafe</string>
<string name="cpu_accuracy_paranoid">Paranoid</string> <string name="cpu_accuracy_paranoid">Paranoid</string>
<string name="cpu_accuracy_debugging">Debugging</string>
<!-- Gamepad Buttons --> <!-- Gamepad Buttons -->
<string name="gamepad_d_pad">D-pad</string> <string name="gamepad_d_pad">D-pad</string>

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -12,7 +15,6 @@
#include "audio_core/adsp/mailbox.h" #include "audio_core/adsp/mailbox.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/polyfill_thread.h" #include "common/polyfill_thread.h"
#include "common/reader_writer_queue.h"
#include "common/thread.h" #include "common/thread.h"
namespace Core { namespace Core {

View file

@ -16,7 +16,7 @@
#include <ranges> #include <ranges>
namespace AudioCore { namespace AudioCore {
constexpr u32 CurrentRevision = 16; constexpr u32 CurrentRevision = 15;
enum class SupportTags { enum class SupportTags {
CommandProcessingTimeEstimatorVersion4, CommandProcessingTimeEstimatorVersion4,
@ -47,6 +47,10 @@ enum class SupportTags {
DelayChannelMappingChange, DelayChannelMappingChange,
ReverbChannelMappingChange, ReverbChannelMappingChange,
I3dl2ReverbChannelMappingChange, I3dl2ReverbChannelMappingChange,
SplitterPrevVolumeReset,
SplitterBiquadFilterParameter,
SplitterDestinationV2b,
VoiceInParameterV2,
// Not a real tag, just here to get the count. // Not a real tag, just here to get the count.
Size Size
@ -91,6 +95,10 @@ constexpr bool CheckFeatureSupported(SupportTags tag, u32 user_revision) {
{SupportTags::DelayChannelMappingChange, 11}, {SupportTags::DelayChannelMappingChange, 11},
{SupportTags::ReverbChannelMappingChange, 11}, {SupportTags::ReverbChannelMappingChange, 11},
{SupportTags::I3dl2ReverbChannelMappingChange, 11}, {SupportTags::I3dl2ReverbChannelMappingChange, 11},
{SupportTags::SplitterBiquadFilterParameter, 12},
{SupportTags::SplitterPrevVolumeReset, 13},
{SupportTags::SplitterDestinationV2b, 15},
{SupportTags::VoiceInParameterV2, 15},
}}; }};
const auto& feature = const auto& feature =

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -11,6 +14,21 @@
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
// See texture_cache/util.h
template<typename T, size_t N>
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
return v;
}
#else
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
std::vector<T> u;
for (auto const& e : v)
u.push_back(e);
return u;
}
#endif
namespace AudioCore::AudioIn { namespace AudioCore::AudioIn {
System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_) System::System(Core::System& system_, Kernel::KEvent* event_, const size_t session_id_)
@ -92,7 +110,7 @@ Result System::Start() {
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{}; boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
buffers.RegisterBuffers(buffers_to_flush); buffers.RegisterBuffers(buffers_to_flush);
session->AppendBuffers(buffers_to_flush); session->AppendBuffers(FixStaticVectorADL(buffers_to_flush));
session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
return ResultSuccess; return ResultSuccess;
@ -137,7 +155,7 @@ void System::RegisterBuffers() {
if (state == State::Started) { if (state == State::Started) {
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{}; boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
buffers.RegisterBuffers(registered_buffers); buffers.RegisterBuffers(registered_buffers);
session->AppendBuffers(registered_buffers); session->AppendBuffers(FixStaticVectorADL(registered_buffers));
} }
} }

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -11,6 +14,21 @@
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_event.h"
// See texture_cache/util.h
template<typename T, size_t N>
#if BOOST_VERSION >= 108100 || __GNUC__ > 12
[[nodiscard]] boost::container::static_vector<T, N> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
return v;
}
#else
[[nodiscard]] std::vector<T> FixStaticVectorADL(const boost::container::static_vector<T, N>& v) {
std::vector<T> u;
for (auto const& e : v)
u.push_back(e);
return u;
}
#endif
namespace AudioCore::AudioOut { namespace AudioCore::AudioOut {
System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_) System::System(Core::System& system_, Kernel::KEvent* event_, size_t session_id_)
@ -91,7 +109,7 @@ Result System::Start() {
boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{}; boost::container::static_vector<AudioBuffer, BufferCount> buffers_to_flush{};
buffers.RegisterBuffers(buffers_to_flush); buffers.RegisterBuffers(buffers_to_flush);
session->AppendBuffers(buffers_to_flush); session->AppendBuffers(FixStaticVectorADL(buffers_to_flush));
session->SetRingSize(static_cast<u32>(buffers_to_flush.size())); session->SetRingSize(static_cast<u32>(buffers_to_flush.size()));
return ResultSuccess; return ResultSuccess;
@ -136,7 +154,7 @@ void System::RegisterBuffers() {
if (state == State::Started) { if (state == State::Started) {
boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{}; boost::container::static_vector<AudioBuffer, BufferCount> registered_buffers{};
buffers.RegisterBuffers(registered_buffers); buffers.RegisterBuffers(registered_buffers);
session->AppendBuffers(registered_buffers); session->AppendBuffers(FixStaticVectorADL(registered_buffers));
} }
} }

View file

@ -193,4 +193,20 @@ bool BehaviorInfo::IsI3dl2ReverbChannelMappingChanged() const {
return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision); return CheckFeatureSupported(SupportTags::I3dl2ReverbChannelMappingChange, user_revision);
} }
bool BehaviorInfo::IsSplitterPrevVolumeResetSupported() const {
return CheckFeatureSupported(SupportTags::SplitterPrevVolumeReset, user_revision);
}
bool BehaviorInfo::IsSplitterDestinationV2bSupported() const {
return CheckFeatureSupported(SupportTags::SplitterDestinationV2b, user_revision);
}
bool BehaviorInfo::IsVoiceInParameterV2Supported() const {
return CheckFeatureSupported(SupportTags::VoiceInParameterV2, user_revision);
}
bool BehaviorInfo::IsBiquadFilterParameterForSplitterEnabled() const {
return CheckFeatureSupported(SupportTags::SplitterBiquadFilterParameter, user_revision);
}
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -361,6 +364,38 @@ public:
*/ */
bool IsI3dl2ReverbChannelMappingChanged() const; bool IsI3dl2ReverbChannelMappingChanged() const;
/**
* Check if explicit previous mix volume reset is supported for splitters.
* This allows splitters to explicitly reset their previous mix volumes instead of
* doing so implicitly on first use.
*
* @return True if supported, otherwise false.
*/
bool IsSplitterPrevVolumeResetSupported() const;
/**
* Check if splitter destination v2b parameter format is supported (revision 15+).
* This uses the extended parameter format with biquad filter fields.
*
* @return True if supported, otherwise false.
*/
bool IsSplitterDestinationV2bSupported() const;
/**
* Check if voice input parameter v2 format is supported (revision 15+).
* This uses the extended parameter format with float biquad filters.
*
* @return True if supported, otherwise false.
*/
bool IsVoiceInParameterV2Supported() const;
/**
* Check if splitter destinations can carry biquad filter parameters (revision 12+).
*
* @return True if supported, otherwise false.
*/
bool IsBiquadFilterParameterForSplitterEnabled() const;
/// Host version /// Host version
u32 process_revision; u32 process_revision;
/// User version /// User version

View file

@ -64,8 +64,6 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
const PoolMapper pool_mapper(process_handle, memory_pools, memory_pool_count, const PoolMapper pool_mapper(process_handle, memory_pools, memory_pool_count,
behaviour.IsMemoryForceMappingEnabled()); behaviour.IsMemoryForceMappingEnabled());
const auto voice_count{voice_context.GetCount()}; const auto voice_count{voice_context.GetCount()};
std::span<const VoiceInfo::InParameter> in_params{
reinterpret_cast<const VoiceInfo::InParameter*>(input), voice_count};
std::span<VoiceInfo::OutStatus> out_params{reinterpret_cast<VoiceInfo::OutStatus*>(output), std::span<VoiceInfo::OutStatus> out_params{reinterpret_cast<VoiceInfo::OutStatus*>(output),
voice_count}; voice_count};
@ -76,8 +74,104 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
u32 new_voice_count{0}; u32 new_voice_count{0};
// Two input formats exist: legacy (0x170) and v2 with float biquad (0x188).
const bool use_v2 = behaviour.IsVoiceInParameterV2Supported();
const u32 in_stride = use_v2 ? 0x188u : static_cast<u32>(sizeof(VoiceInfo::InParameter));
for (u32 i = 0; i < voice_count; i++) { for (u32 i = 0; i < voice_count; i++) {
const auto& in_param{in_params[i]}; VoiceInfo::InParameter local_in{};
std::array<VoiceInfo::BiquadFilterParameter2, MaxBiquadFilters> float_biquads{};
if (!use_v2) {
const auto* in_param_ptr = reinterpret_cast<const VoiceInfo::InParameter*>(
input + i * sizeof(VoiceInfo::InParameter));
local_in = *in_param_ptr;
} else {
struct VoiceInParameterV2 {
u32 id;
u32 node_id;
bool is_new;
bool in_use;
PlayState play_state;
SampleFormat sample_format;
u32 sample_rate;
u32 priority;
u32 sort_order;
u32 channel_count;
f32 pitch;
f32 volume;
// Two BiquadFilterParameter2 (0x18 each) -> ignored/converted
struct BiquadV2 {
bool enable;
u8 r1;
u8 r2;
u8 r3;
std::array<f32, 3> b;
std::array<f32, 2> a;
} biquads[2];
u32 wave_buffer_count;
u32 wave_buffer_index;
u32 reserved1;
u64 src_data_address;
u64 src_data_size;
s32 mix_id;
u32 splitter_id;
std::array<VoiceInfo::WaveBufferInternal, MaxWaveBuffers> wavebuffers;
std::array<u32, MaxChannels> channel_resource_ids;
bool clear_voice_drop;
u8 flush_wave_buffer_count;
u16 reserved2;
VoiceInfo::Flags flags;
SrcQuality src_quality;
u32 external_ctx;
u32 external_ctx_size;
u32 reserved3[2];
};
const auto* vin = reinterpret_cast<const VoiceInParameterV2*>(input + i * in_stride);
local_in.id = vin->id;
local_in.node_id = vin->node_id;
local_in.is_new = vin->is_new;
local_in.in_use = vin->in_use;
local_in.play_state = vin->play_state;
local_in.sample_format = vin->sample_format;
local_in.sample_rate = vin->sample_rate;
local_in.priority = static_cast<s32>(vin->priority);
local_in.sort_order = static_cast<s32>(vin->sort_order);
local_in.channel_count = vin->channel_count;
local_in.pitch = vin->pitch;
local_in.volume = vin->volume;
// For REV15+, we keep float coefficients separate and only convert for compatibility
for (size_t filter_idx = 0; filter_idx < MaxBiquadFilters; filter_idx++) {
const auto& src = vin->biquads[filter_idx];
auto& dst = local_in.biquads[filter_idx];
dst.enabled = src.enable;
// Convert float coefficients to fixed-point Q2.14 for legacy path
dst.b[0] = static_cast<s16>(std::clamp(src.b[0] * 16384.0f, -32768.0f, 32767.0f));
dst.b[1] = static_cast<s16>(std::clamp(src.b[1] * 16384.0f, -32768.0f, 32767.0f));
dst.b[2] = static_cast<s16>(std::clamp(src.b[2] * 16384.0f, -32768.0f, 32767.0f));
dst.a[0] = static_cast<s16>(std::clamp(src.a[0] * 16384.0f, -32768.0f, 32767.0f));
dst.a[1] = static_cast<s16>(std::clamp(src.a[1] * 16384.0f, -32768.0f, 32767.0f));
// Also store the native float version
float_biquads[filter_idx].enabled = src.enable;
float_biquads[filter_idx].numerator = src.b;
float_biquads[filter_idx].denominator = src.a;
}
local_in.wave_buffer_count = vin->wave_buffer_count;
local_in.wave_buffer_index = static_cast<u16>(vin->wave_buffer_index);
local_in.src_data_address = static_cast<CpuAddr>(vin->src_data_address);
local_in.src_data_size = vin->src_data_size;
local_in.mix_id = static_cast<u32>(vin->mix_id);
local_in.splitter_id = vin->splitter_id;
local_in.wave_buffer_internal = vin->wavebuffers;
local_in.channel_resource_ids = vin->channel_resource_ids;
local_in.clear_voice_drop = vin->clear_voice_drop;
local_in.flush_buffer_count = vin->flush_wave_buffer_count;
local_in.flags = vin->flags;
local_in.src_quality = vin->src_quality;
}
const auto& in_param = local_in;
std::array<VoiceState*, MaxChannels> voice_states{}; std::array<VoiceState*, MaxChannels> voice_states{};
if (!in_param.in_use) { if (!in_param.in_use) {
@ -101,6 +195,14 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
BehaviorInfo::ErrorInfo update_error{}; BehaviorInfo::ErrorInfo update_error{};
voice_info.UpdateParameters(update_error, in_param, pool_mapper, behaviour); voice_info.UpdateParameters(update_error, in_param, pool_mapper, behaviour);
// For REV15+, store the native float biquad coefficients
if (use_v2) {
voice_info.use_float_biquads = true;
voice_info.biquads_float = float_biquads;
} else {
voice_info.use_float_biquads = false;
}
if (!update_error.error_code.IsSuccess()) { if (!update_error.error_code.IsSuccess()) {
behaviour.AppendError(update_error); behaviour.AppendError(update_error);
} }
@ -121,7 +223,7 @@ Result InfoUpdater::UpdateVoices(VoiceContext& voice_context,
new_voice_count += in_param.channel_count; new_voice_count += in_param.channel_count;
} }
auto consumed_input_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::InParameter))}; auto consumed_input_size{voice_count * in_stride};
auto consumed_output_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::OutStatus))}; auto consumed_output_size{voice_count * static_cast<u32>(sizeof(VoiceInfo::OutStatus))};
if (consumed_input_size != in_header->voices_size) { if (consumed_input_size != in_header->voices_size) {
LOG_ERROR(Service_Audio, "Consumed an incorrect voices size, header size={}, consumed={}", LOG_ERROR(Service_Audio, "Consumed an incorrect voices size, header size={}, consumed={}",
@ -257,18 +359,31 @@ Result InfoUpdater::UpdateMixes(MixContext& mix_context, const u32 mix_buffer_co
EffectContext& effect_context, SplitterContext& splitter_context) { EffectContext& effect_context, SplitterContext& splitter_context) {
s32 mix_count{0}; s32 mix_count{0};
u32 consumed_input_size{0}; u32 consumed_input_size{0};
u32 input_mix_size{0};
if (behaviour.IsMixInParameterDirtyOnlyUpdateSupported()) { if (behaviour.IsMixInParameterDirtyOnlyUpdateSupported()) {
auto in_dirty_params{reinterpret_cast<const MixInfo::InDirtyParameter*>(input)}; auto in_dirty_params{reinterpret_cast<const MixInfo::InDirtyParameter*>(input)};
mix_count = in_dirty_params->count; mix_count = in_dirty_params->count;
// Validate against expected header size to ensure structure is correct
if (mix_count < 0 || mix_count > 0x100) {
LOG_ERROR(
Service_Audio,
"Invalid mix count from dirty parameter: count={}, magic=0x{:X}, expected_size={}",
mix_count, in_dirty_params->magic, in_header->mix_size);
return Service::Audio::ResultInvalidUpdateInfo;
}
consumed_input_size += static_cast<u32>(sizeof(MixInfo::InDirtyParameter));
input += sizeof(MixInfo::InDirtyParameter); input += sizeof(MixInfo::InDirtyParameter);
consumed_input_size = static_cast<u32>(sizeof(MixInfo::InDirtyParameter) +
mix_count * sizeof(MixInfo::InParameter));
} else { } else {
mix_count = mix_context.GetCount(); mix_count = mix_context.GetCount();
consumed_input_size = static_cast<u32>(mix_count * sizeof(MixInfo::InParameter));
} }
input_mix_size = static_cast<u32>(mix_count * sizeof(MixInfo::InParameter));
consumed_input_size += input_mix_size;
if (mix_buffer_count == 0) { if (mix_buffer_count == 0) {
return Service::Audio::ResultInvalidUpdateInfo; return Service::Audio::ResultInvalidUpdateInfo;
} }

View file

@ -237,6 +237,13 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, VoiceInfo& vo
cmd.biquad = voice_info.biquads[biquad_index]; cmd.biquad = voice_info.biquads[biquad_index];
if (voice_info.use_float_biquads) {
cmd.biquad_float = voice_info.biquads_float[biquad_index];
cmd.use_float_coefficients = true;
} else {
cmd.use_float_coefficients = false;
}
cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()), cmd.state = memory_pool->Translate(CpuAddr(voice_state.biquad_states[biquad_index].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
@ -263,6 +270,9 @@ void CommandBuffer::GenerateBiquadFilterCommand(const s32 node_id, EffectInfoBas
cmd.biquad.b = parameter.b; cmd.biquad.b = parameter.b;
cmd.biquad.a = parameter.a; cmd.biquad.a = parameter.a;
// Effects use legacy fixed-point format
cmd.use_float_coefficients = false;
cmd.state = memory_pool->Translate(CpuAddr(state), cmd.state = memory_pool->Translate(CpuAddr(state),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));
@ -658,6 +668,13 @@ void CommandBuffer::GenerateMultitapBiquadFilterCommand(const s32 node_id, Voice
cmd.output = buffer_count + channel; cmd.output = buffer_count + channel;
cmd.biquads = voice_info.biquads; cmd.biquads = voice_info.biquads;
if (voice_info.use_float_biquads) {
cmd.biquads_float = voice_info.biquads_float;
cmd.use_float_coefficients = true;
} else {
cmd.use_float_coefficients = false;
}
cmd.states[0] = cmd.states[0] =
memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()), memory_pool->Translate(CpuAddr(voice_state.biquad_states[0].data()),
MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState)); MaxBiquadFilters * sizeof(VoiceState::BiquadFilterState));

View file

@ -51,6 +51,40 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
state.s3 = Common::BitCast<s64>(s[3]); state.s3 = Common::BitCast<s64>(s[3]);
} }
/**
* Biquad filter float implementation with native float coefficients.
*/
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
std::array<f32, 3>& b, std::array<f32, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count) {
constexpr f64 min{std::numeric_limits<s32>::min()};
constexpr f64 max{std::numeric_limits<s32>::max()};
std::array<f64, 3> b_double{static_cast<f64>(b[0]), static_cast<f64>(b[1]),
static_cast<f64>(b[2])};
std::array<f64, 2> a_double{static_cast<f64>(a[0]), static_cast<f64>(a[1])};
std::array<f64, 4> s{Common::BitCast<f64>(state.s0), Common::BitCast<f64>(state.s1),
Common::BitCast<f64>(state.s2), Common::BitCast<f64>(state.s3)};
for (u32 i = 0; i < sample_count; i++) {
f64 in_sample{static_cast<f64>(input[i])};
auto sample{in_sample * b_double[0] + s[0] * b_double[1] + s[1] * b_double[2] +
s[2] * a_double[0] + s[3] * a_double[1]};
output[i] = static_cast<s32>(std::clamp(sample, min, max));
s[1] = s[0];
s[0] = in_sample;
s[3] = s[2];
s[2] = sample;
}
state.s0 = Common::BitCast<s64>(s[0]);
state.s1 = Common::BitCast<s64>(s[1]);
state.s2 = Common::BitCast<s64>(s[2]);
state.s3 = Common::BitCast<s64>(s[3]);
}
/** /**
* Biquad filter s32 implementation. * Biquad filter s32 implementation.
* *
@ -98,8 +132,14 @@ void BiquadFilterCommand::Process(const AudioRenderer::CommandListProcessor& pro
processor.mix_buffers.subspan(output * processor.sample_count, processor.sample_count)}; processor.mix_buffers.subspan(output * processor.sample_count, processor.sample_count)};
if (use_float_processing) { if (use_float_processing) {
// REV15+: Use native float coefficients if available
if (use_float_coefficients) {
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquad_float.numerator,
biquad_float.denominator, *state_, processor.sample_count);
} else {
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_, ApplyBiquadFilterFloat(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
processor.sample_count); processor.sample_count);
}
} else { } else {
ApplyBiquadFilterInt(output_buffer, input_buffer, biquad.b, biquad.a, *state_, ApplyBiquadFilterInt(output_buffer, input_buffer, biquad.b, biquad.a, *state_,
processor.sample_count); processor.sample_count);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -50,12 +53,16 @@ struct BiquadFilterCommand : ICommand {
s16 output; s16 output;
/// Input parameters for biquad /// Input parameters for biquad
VoiceInfo::BiquadFilterParameter biquad; VoiceInfo::BiquadFilterParameter biquad;
/// Input parameters for biquad (REV15+ native float)
VoiceInfo::BiquadFilterParameter2 biquad_float;
/// Biquad state, updated each call /// Biquad state, updated each call
CpuAddr state; CpuAddr state;
/// If true, reset the state /// If true, reset the state
bool needs_init; bool needs_init;
/// If true, use float processing rather than int /// If true, use float processing rather than int
bool use_float_processing; bool use_float_processing;
/// If true, use native float coefficients (REV15+)
bool use_float_coefficients;
}; };
/** /**
@ -72,4 +79,18 @@ void ApplyBiquadFilterFloat(std::span<s32> output, std::span<const s32> input,
std::array<s16, 3>& b, std::array<s16, 2>& a, std::array<s16, 3>& b, std::array<s16, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count); VoiceState::BiquadFilterState& state, const u32 sample_count);
/**
* Biquad filter float implementation with native float coefficients (SDK REV15+).
*
* @param output - Output container for filtered samples.
* @param input - Input container for samples to be filtered.
* @param b - Feedforward coefficients (float).
* @param a - Feedback coefficients (float).
* @param state - State to track previous samples.
* @param sample_count - Number of samples to process.
*/
void ApplyBiquadFilterFloat2(std::span<s32> output, std::span<const s32> input,
std::array<f32, 3>& b, std::array<f32, 2>& a,
VoiceState::BiquadFilterState& state, const u32 sample_count);
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -33,10 +36,16 @@ void MultiTapBiquadFilterCommand::Process(const AudioRenderer::CommandListProces
*state = {}; *state = {};
} }
// REV15+: Use native float coefficients if available
if (use_float_coefficients) {
ApplyBiquadFilterFloat2(output_buffer, input_buffer, biquads_float[i].numerator,
biquads_float[i].denominator, *state, processor.sample_count);
} else {
ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state, ApplyBiquadFilterFloat(output_buffer, input_buffer, biquads[i].b, biquads[i].a, *state,
processor.sample_count); processor.sample_count);
} }
} }
}
bool MultiTapBiquadFilterCommand::Verify(const AudioRenderer::CommandListProcessor& processor) { bool MultiTapBiquadFilterCommand::Verify(const AudioRenderer::CommandListProcessor& processor) {
return true; return true;

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
@ -49,12 +52,16 @@ struct MultiTapBiquadFilterCommand : ICommand {
s16 output; s16 output;
/// Biquad parameters /// Biquad parameters
std::array<VoiceInfo::BiquadFilterParameter, MaxBiquadFilters> biquads; std::array<VoiceInfo::BiquadFilterParameter, MaxBiquadFilters> biquads;
/// Biquad parameters (REV15+ native float)
std::array<VoiceInfo::BiquadFilterParameter2, MaxBiquadFilters> biquads_float;
/// Biquad states, updated each call /// Biquad states, updated each call
std::array<CpuAddr, MaxBiquadFilters> states; std::array<CpuAddr, MaxBiquadFilters> states;
/// If each biquad needs initialisation /// If each biquad needs initialisation
std::array<bool, MaxBiquadFilters> needs_init; std::array<bool, MaxBiquadFilters> needs_init;
/// Number of active biquads /// Number of active biquads
u8 filter_tap_count; u8 filter_tap_count;
/// If true, use native float coefficients (REV15+)
bool use_float_coefficients;
}; };
} // namespace AudioCore::Renderer } // namespace AudioCore::Renderer

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