Compare commits
45 commits
scripts/bu
...
master
Author | SHA1 | Date | |
---|---|---|---|
d24db9c3cb | |||
f55e560ac5 | |||
84ab54c4bc | |||
9333393a7b | |||
cb83a258db | |||
6bdf479488 | |||
9c7ed0f59d | |||
de46b8e817 | |||
3e8fe622a7 | |||
1c90b099d3 | |||
e2a8f3154f | |||
c0fb872d1a | |||
171a1d23e4 | |||
3d6a784e62 | |||
440ee4916d | |||
551f244dfd | |||
ef14303c48 | |||
b7021afff6 | |||
bfc10723bc | |||
30482692c7 | |||
31463142e1 | |||
bb836ed6c2 | |||
f273ac446b | |||
3f725c979d | |||
2a5e6f98b6 | |||
fff8e2026f | |||
5f9dba40a0 | |||
0a54ac63f0 | |||
94ca83a6ca | |||
2f88463203 | |||
11200714e8 | |||
ac59b6eae5 | |||
b389a72697 | |||
b3f28d29c0 | |||
053f4e95d4 | |||
8ae7cfe96a | |||
e157b3fa96 | |||
56e2dbc619 | |||
a3ef2cc183 | |||
1e1b8ad33f | |||
91493fa39b | |||
973a65c4c5 | |||
8a017951aa | |||
776958c79d | |||
3656253262 |
|
@ -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
|
@ -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
|
||||||
|
|
12
.patch/catch2/0001-solaris-isnan-fix.patch
Normal 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>
|
25
.patch/libusb/0001-netbsd-gettime.patch
Normal 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)
|
||||||
|
{
|
13
.patch/mbedtls/0002-aesni-fix.patch
Normal 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 */
|
22
.patch/mbedtls/0003-aesni-fix.patch
Normal 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)
|
||||||
|
/*
|
55
.patch/mcl/0001-assert-macro.patch
Normal 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
|
14
.patch/spirv-tools/0001-netbsd-fix.patch
Normal 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()
|
45
.reuse/dep5
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,33 @@
|
||||||
|
# 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)
|
||||||
|
|
||||||
find_library(DiscordRPC_LIBRARY discord-rpc)
|
if (NOT DiscordRPC_FOUND)
|
||||||
|
find_path(DiscordRPC_INCLUDE_DIR discord_rpc.h)
|
||||||
|
find_library(DiscordRPC_LIBRARY discord-rpc)
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(DiscordRPC
|
find_package_handle_standard_args(DiscordRPC
|
||||||
REQUIRED_VARS
|
REQUIRED_VARS
|
||||||
DiscordRPC_LIBRARY
|
DiscordRPC_LIBRARY
|
||||||
DiscordRPC_INCLUDE_DIR
|
DiscordRPC_INCLUDE_DIR
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DiscordRPC_FOUND AND NOT TARGET DiscordRPC::discord-rpc)
|
if (DiscordRPC_FOUND AND NOT TARGET DiscordRPC::discord-rpc)
|
||||||
add_library(DiscordRPC::discord-rpc UNKNOWN IMPORTED)
|
add_library(DiscordRPC::discord-rpc UNKNOWN IMPORTED)
|
||||||
set_target_properties(DiscordRPC::discord-rpc PROPERTIES
|
set_target_properties(DiscordRPC::discord-rpc PROPERTIES
|
||||||
IMPORTED_LOCATION "${DiscordRPC_LIBRARY}"
|
IMPORTED_LOCATION "${DiscordRPC_LIBRARY}"
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${DiscordRPC_INCLUDE_DIR}"
|
INTERFACE_INCLUDE_DIRECTORIES "${DiscordRPC_INCLUDE_DIR}"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
mark_as_advanced(
|
mark_as_advanced(
|
||||||
DiscordRPC_INCLUDE_DIR
|
DiscordRPC_INCLUDE_DIR
|
||||||
DiscordRPC_LIBRARY
|
DiscordRPC_LIBRARY
|
||||||
)
|
)
|
||||||
|
endif()
|
||||||
|
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/download.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/upload.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
dist/qt_themes/colorful/icons/48x48/user-trash.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
3
dist/qt_themes/colorful/style.qrc
vendored
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
3
dist/qt_themes/default/default.qrc
vendored
|
@ -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>
|
||||||
|
|
BIN
dist/qt_themes/default/icons/256x256/eden.png
vendored
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
BIN
dist/qt_themes/default/icons/48x48/download.png
vendored
Normal file
After Width: | Height: | Size: 853 B |
BIN
dist/qt_themes/default/icons/48x48/upload.png
vendored
Normal file
After Width: | Height: | Size: 820 B |
BIN
dist/qt_themes/default/icons/48x48/user-trash.png
vendored
Normal file
After Width: | Height: | Size: 584 B |
3
dist/qt_themes/default_dark/style.qrc
vendored
|
@ -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>
|
||||||
|
|
BIN
dist/qt_themes/qdarkstyle/icons/48x48/download.png
vendored
Normal file
After Width: | Height: | Size: 883 B |
BIN
dist/qt_themes/qdarkstyle/icons/48x48/upload.png
vendored
Normal file
After Width: | Height: | Size: 853 B |
BIN
dist/qt_themes/qdarkstyle/icons/48x48/user-trash.png
vendored
Normal file
After Width: | Height: | Size: 584 B |
3
dist/qt_themes/qdarkstyle/style.qrc
vendored
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
91
docs/Deps.md
|
@ -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)**.
|
||||||
|
|
|
@ -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.
|
22
externals/cpmfile.json
vendored
|
@ -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",
|
||||||
|
|
5
externals/libusb/cpmfile.json
vendored
|
@ -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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
18
externals/nx_tzdb/CMakeLists.txt
vendored
|
@ -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})
|
||||||
|
|
6
externals/nx_tzdb/cpmfile.json
vendored
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
2
externals/renderdoc/renderdoc_app.h
vendored
|
@ -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"
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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.")
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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")
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 '/'
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 438 KiB After Width: | Height: | Size: 244 KiB |
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 112 KiB |
BIN
src/android/app/src/main/res/drawable/ic_launcher.png
Normal file
After Width: | Height: | Size: 48 KiB |
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
59
src/android/app/src/main/res/layout/dialog_edit_playtime.xml
Normal 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>
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,9 +36,15 @@ 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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|