mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-04 19:36:27 +00:00
Compare commits
126 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fe0606298e | |||
| 55a7c0e3f9 | |||
| 46affbf3c9 | |||
| a90df8e11e | |||
| 531e708ba3 | |||
| 9ea08d843f | |||
| 37c52470ab | |||
| 5bd67257b3 | |||
| 6edac132c7 | |||
| f52a3e9498 | |||
| 97cad240bb | |||
| a2de6bd86f | |||
| 35d930b1e3 | |||
| 28fb103cc5 | |||
| 20e36588de | |||
| 89301f83a9 | |||
| 2e9be05ddd | |||
| 907f104763 | |||
| 38e3a4d0e5 | |||
| 7754ef4ec2 | |||
| 1381b462ef | |||
| aba7fcddf9 | |||
| fa8d6a8bf3 | |||
| 58fe483d10 | |||
| 0a8bdf4bfd | |||
| ec2b7d78af | |||
| e508164f28 | |||
| 106eefb19f | |||
| 1298e21c04 | |||
| ea9afef59a | |||
| 6ab577f18f | |||
| ee9685dc8b | |||
| 381256f6a4 | |||
| 0d0f5fe7d4 | |||
| 6e2e522f85 | |||
| 7bf4e74824 | |||
| 345408af43 | |||
| e8db75f70e | |||
| bb1cbc7473 | |||
| f51e77de68 | |||
| abd1f7aefb | |||
| 68b192170c | |||
| 9995989caa | |||
| 799b6843ad | |||
| 3e8e907d2e | |||
| e28ef027fd | |||
| b72d609da3 | |||
| 9dc2005706 | |||
| 94ac967a47 | |||
| 54ce1f34fe | |||
| 76b09033cc | |||
| 47aea8cc9b | |||
| 4f2b5e59e0 | |||
| b8fcf0b0eb | |||
| a91a0cf52e | |||
| eb6ade136d | |||
| de93bd8b82 | |||
| 2fb81e23ed | |||
| d76aab5336 | |||
| b3481ea9ed | |||
| 896d4d5f29 | |||
| d2bed53497 | |||
| 92f590835e | |||
| b024a42881 | |||
| 5d18ada08c | |||
| 24af265111 | |||
| 2b78ca21e4 | |||
| 9802ab9192 | |||
| bb663948a4 | |||
| c481e0149c | |||
| 7a878ea926 | |||
| 26b665b997 | |||
| b4cf4f4189 | |||
| f1a1dd6ca6 | |||
| aae4f043c6 | |||
| c31e661fb9 | |||
| 36dcbebf77 | |||
| b9e2fdfe7e | |||
| 89a6e706f7 | |||
| 8da13a51f6 | |||
| bebf33cbe9 | |||
| 00c7764691 | |||
| 86286dc846 | |||
| 3d8b986de7 | |||
| 543a9dc085 | |||
| b42f527d51 | |||
| b3a7361b8a | |||
| be74a8e0be | |||
| 46e617cd37 | |||
| 2bd3588f5f | |||
| ab9b8f67f5 | |||
| 405b858103 | |||
| a63e530d8e | |||
| d208da01c1 | |||
| 12cd05e874 | |||
| 427a5a3c26 | |||
| b89f3cf56b | |||
| 0064c906e1 | |||
| 8dd97772dc | |||
| 6a8a4664c8 | |||
| 758435a59c | |||
| 1c82c15bc7 | |||
| b2c74e9afa | |||
| f6b010ecc8 | |||
| 613f66528e | |||
| 848c58fb61 | |||
| 6f7ccf56b5 | |||
| 97dc0c3858 | |||
| ffac8491a6 | |||
| 06eff00e09 | |||
| 95755e2989 | |||
| 99230c5bc7 | |||
| 98fe8b53ec | |||
| 0e801a7cb5 | |||
| dabe3bd9dd | |||
| e5916cf38c | |||
| 3fdce3c553 | |||
| 378c563b44 | |||
| a0005df87c | |||
| b5a996b3b5 | |||
| 5a6b6c72a7 | |||
| 9fe0a6a4e0 | |||
| 63bd4dfa03 | |||
| 0a9f9d8a02 | |||
| e826eb2063 | |||
| 9a9de01a03 |
Executable
+66
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/local/bin/bash -ex
|
||||||
|
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
[ -z ${OO_PS4_TOOLCHAIN+x} ] && exit
|
||||||
|
|
||||||
|
# cmake
|
||||||
|
[ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake"
|
||||||
|
set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN")
|
||||||
|
set(CMAKE_STAGING_PREFIX "$OO_PS4_TOOLCHAIN")
|
||||||
|
set(CMAKE_SYSTEM_NAME "OpenOrbis")
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables -femulated-tls")
|
||||||
|
set(CMAKE_CXX_FLAGS "-D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=btver2 -march=btver2 -fPIC -funwind-tables -femulated-tls")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||||
|
|
||||||
|
set(CMAKE_C_COMPILER clang)
|
||||||
|
set(CMAKE_CXX_COMPILER clang++)
|
||||||
|
set(CMAKE_LINKER ld.lld)
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||||
|
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||||
|
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
|
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||||
|
|
||||||
|
# TODO: Why does cmake not set this?
|
||||||
|
set(CMAKE_SIZEOF_VOID_P 8)
|
||||||
|
EOF
|
||||||
|
|
||||||
|
[ -z ${NPROC+x} ] && NPROC=$(nproc || 1)
|
||||||
|
|
||||||
|
# Normally a platform has a package manager
|
||||||
|
# PS4 does not, atleast not in the normal sense
|
||||||
|
export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@)
|
||||||
|
[ -f "build/Makefile" ] || cmake -S . -B build -G "Unix Makefiles" \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \
|
||||||
|
-DENABLE_QT_TRANSLATION=OFF \
|
||||||
|
-DENABLE_CUBEB=OFF \
|
||||||
|
-DCMAKE_BUILD_TYPE=Release \
|
||||||
|
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
||||||
|
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||||
|
-DENABLE_SDL2=ON \
|
||||||
|
-DENABLE_LIBUSB=OFF \
|
||||||
|
-DENABLE_UPDATE_CHECKER=OFF \
|
||||||
|
-DENABLE_QT=OFF \
|
||||||
|
-DENABLE_OPENGL=ON \
|
||||||
|
-DENABLE_WEB_SERVICE=OFF \
|
||||||
|
-DUSE_DISCORD_PRESENCE=OFF \
|
||||||
|
-DCPMUTIL_FORCE_BUNDLED=ON \
|
||||||
|
-DYUZU_USE_EXTERNAL_FFMPEG=ON \
|
||||||
|
-DYUZU_USE_CPM=ON \
|
||||||
|
-DDYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=OFF \
|
||||||
|
-DDYNARMIC_TESTS=ON \
|
||||||
|
-DYUZU_TESTS=ON \
|
||||||
|
-DYUZU_USE_EXTERNAL_SDL2=ON \
|
||||||
|
"${EXTRA_CMAKE_FLAGS[@]}" || exit
|
||||||
|
|
||||||
|
cmake --build build -t yuzu-cmd_pkg -- -j$NPROC
|
||||||
|
#cmake --build build -t dynarmic_tests_pkg -- -j$NPROC
|
||||||
|
#cmake --build build -t testps4_pkg -- -j$NPROC
|
||||||
+2
-2
@@ -64,5 +64,5 @@ artifacts
|
|||||||
vulkansdk*.exe
|
vulkansdk*.exe
|
||||||
*.tar.zst
|
*.tar.zst
|
||||||
|
|
||||||
# Build-time generated external sources
|
# PS4 toolchain stuff
|
||||||
externals/generated
|
ps4-toolchain.cmake
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
index 0129511c..10fc9b04 100644
|
||||||
|
--- a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
+++ b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||||
|
@@ -15,6 +15,12 @@
|
||||||
|
# pragma once
|
||||||
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||||
|
|
||||||
|
+// hacky fix for ps4
|
||||||
|
+#if defined(__OPENORBIS__)
|
||||||
|
+# define FIONBIO 0
|
||||||
|
+# define FIONREAD 1
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#include <boost/asio/detail/config.hpp>
|
||||||
|
|
||||||
|
#include <cctype>
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/unix.c b/unix.c
|
||||||
|
index 6669216..86a2faa 100644
|
||||||
|
--- a/unix.c
|
||||||
|
+++ b/unix.c
|
||||||
|
@@ -53,7 +53,7 @@
|
||||||
|
#include <poll.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||||
|
+#if !defined(__OPENORBIS__) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||||
|
typedef int socklen_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
diff --git a/libavutil/cpu.c b/libavutil/cpu.c
|
||||||
|
index 03e2720..874258f 100644
|
||||||
|
--- a/libavutil/cpu.c
|
||||||
|
+++ b/libavutil/cpu.c
|
||||||
|
@@ -43,8 +43,10 @@
|
||||||
|
#include <sys/param.h>
|
||||||
|
#endif
|
||||||
|
#include <sys/types.h>
|
||||||
|
+#ifndef __OPENORBIS__
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
#endif
|
||||||
|
+#endif
|
||||||
|
#if HAVE_UNISTD_H
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
index 3012e05..2ae23ff 100644
|
||||||
|
--- a/cmake/ConfigureOpenSSL.cmake
|
||||||
|
+++ b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
@@ -108,7 +108,8 @@ function(configure_openssl)
|
||||||
|
)
|
||||||
|
|
||||||
|
if(NOT "${CONFIGURE_OPTIONS_OLD}" STREQUAL "")
|
||||||
|
- if(CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||||
|
+ # TODO(lizzie): Emscripten has issues with rebuilding due to the wrapper it uses
|
||||||
|
+ if(CMAKE_SYSTEM_NAME MATCHES "Emscripten" OR CONFIGURE_OPTIONS STREQUAL CONFIGURE_OPTIONS_OLD)
|
||||||
|
message(STATUS "Found previous configure results. Don't perform configuration")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
@@ -134,10 +135,24 @@ function(configure_openssl)
|
||||||
|
set(VERBOSE_OPTION OUTPUT_QUIET)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+ if (CMAKE_SYSTEM_NAME MATCHES "Emscripten")
|
||||||
|
+ set(EMSCRIPTEN_CMAKE_WRAPPER "emcmake")
|
||||||
|
+ find_program(EMCC emcc REQUIRED)
|
||||||
|
+ set(EMSCRIPTEN_LINKER ${EMCC})
|
||||||
|
+ list(APPEND CONFIGURE_COMMAND wasm64)
|
||||||
|
+ else()
|
||||||
|
+ set(EMSCRIPTEN_CMAKE_WRAPPER "")
|
||||||
|
+ set(EMSCRIPTEN_LINKER ${CMAKE_LINKER})
|
||||||
|
+ endif ()
|
||||||
|
+
|
||||||
|
execute_process(
|
||||||
|
- COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
+ COMMAND ${EMSCRIPTEN_CMAKE_WRAPPER} ${CMAKE_COMMAND} -E env
|
||||||
|
"CFLAGS=${CMAKE_C_FLAGS}"
|
||||||
|
"CXXFLAGS=${CMAKE_CXX_FLAGS}"
|
||||||
|
+ "LDFLAGS=${CMAKE_CXX_LINK_FLAGS}"
|
||||||
|
+ "CC=${CMAKE_C_COMPILER}"
|
||||||
|
+ "CXX=${CMAKE_CXX_COMPILER}"
|
||||||
|
+ "LD=${EMSCRIPTEN_LINKER}"
|
||||||
|
${CONFIGURE_COMMAND}
|
||||||
|
WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR}
|
||||||
|
${VERBOSE_OPTION}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 1ca57e1..593fd62 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -148,6 +148,16 @@ if(NOT BUILD_SHARED_LIBS)
|
||||||
|
list(APPEND OPENSSL_CONFIGURE_OPTIONS no-shared)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+list(APPEND OPENSSL_CONFIGURE_OPTIONS
|
||||||
|
+ no-threads no-thread-pool no-shared no-afalgeng no-async no-capieng no-cmp no-cms no-comp no-ct
|
||||||
|
+ no-docs no-dgram no-dso no-dynamic-engine no-engine no-filenames no-gost
|
||||||
|
+ no-http no-legacy no-module no-nextprotoneg no-ocsp no-padlockeng no-quic
|
||||||
|
+ no-srp no-srtp no-ssl-trace no-static-engine no-tests no-thread-pool no-ts
|
||||||
|
+ no-ui-console no-uplink no-ssl3-method no-tls1-method no-tls1_1-method
|
||||||
|
+ no-dtls1-method no-dtls1_2-method no-argon2 no-bf no-blake2 no-cast
|
||||||
|
+ no-dsa no-idea no-md4 no-mdc2 no-ocb no-rc2 no-rc4 no-rmd160 no-scrypt
|
||||||
|
+ no-siphash no-siv no-sm2 no-sm3 no-sm4 no-whirlpool no-apps)
|
||||||
|
+
|
||||||
|
list(SORT OPENSSL_CONFIGURE_OPTIONS)
|
||||||
|
list(REMOVE_DUPLICATES OPENSSL_CONFIGURE_OPTIONS)
|
||||||
|
list(PREPEND OPENSSL_CONFIGURE_OPTIONS ${OPENSSL_TARGET_PLATFORM})
|
||||||
|
diff --git a/cmake/ConfigureOpenSSL.cmake b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
index 2ae23ff..22a4a27 100644
|
||||||
|
--- a/cmake/ConfigureOpenSSL.cmake
|
||||||
|
+++ b/cmake/ConfigureOpenSSL.cmake
|
||||||
|
@@ -154,6 +154,7 @@ function(configure_openssl)
|
||||||
|
"CXX=${CMAKE_CXX_COMPILER}"
|
||||||
|
"LD=${EMSCRIPTEN_LINKER}"
|
||||||
|
${CONFIGURE_COMMAND}
|
||||||
|
+ "--prefix=${CMAKE_SYSROOT}"
|
||||||
|
WORKING_DIRECTORY ${CONFIGURE_BUILD_DIR}
|
||||||
|
${VERBOSE_OPTION}
|
||||||
|
COMMAND_ERROR_IS_FATAL ANY
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
diff --git a/crypto/o_str.c b/crypto/o_str.c
|
||||||
|
index 8aadff5..ba427c9 100644
|
||||||
|
--- a/crypto/o_str.c
|
||||||
|
+++ b/crypto/o_str.c
|
||||||
|
@@ -385,7 +385,7 @@ int openssl_strerror_r(int errnum, char *buf, size_t buflen)
|
||||||
|
* It can return a pointer to some (immutable) static string in which case
|
||||||
|
* buf is left unused.
|
||||||
|
*/
|
||||||
|
- err = strerror_r(errnum, buf, buflen);
|
||||||
|
+ err = (char *)strerror_r(errnum, buf, buflen);
|
||||||
|
if (err == NULL || buflen == 0)
|
||||||
|
return 0;
|
||||||
|
/*
|
||||||
@@ -0,0 +1,196 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index 8872895..b0eeca8 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -1770,7 +1770,6 @@ elseif(EMSCRIPTEN)
|
||||||
|
|
||||||
|
CheckPTHREAD()
|
||||||
|
CheckLibUnwind()
|
||||||
|
-
|
||||||
|
elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||||
|
|
||||||
|
set(SDL_DISABLE_DLOPEN_NOTES TRUE)
|
||||||
|
@@ -3647,10 +3646,30 @@ if(NOT HAVE_CAMERA)
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
+# Always on?
|
||||||
|
+if (OPENORBIS)
|
||||||
|
+ sdl_sources(
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systhread.c"
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysmutex.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_syscond.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_sysrwlock.c" # Can be faked, if necessary
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/pthread/SDL_systls.c"
|
||||||
|
+ "${SDL3_SOURCE_DIR}/src/thread/generic/SDL_syssem.c"
|
||||||
|
+ )
|
||||||
|
+ sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c")
|
||||||
|
+ sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/unix/*.c")
|
||||||
|
+ set(HAVE_SDL_THREADS TRUE)
|
||||||
|
+ set(HAVE_SDL_TIMERS TRUE)
|
||||||
|
+ set(HAVE_SDL_TIME TRUE)
|
||||||
|
+ set(SDL_TIME_UNIX 1)
|
||||||
|
+ set(SDL_TIMER_UNIX 1)
|
||||||
|
+ set(SDL_THREAD_PTHREAD 1)
|
||||||
|
+endif ()
|
||||||
|
+
|
||||||
|
# We always need to have threads and timers around
|
||||||
|
if(NOT HAVE_SDL_THREADS)
|
||||||
|
# The Emscripten and N-Gage platform has been carefully vetted to work without threads
|
||||||
|
- if(EMSCRIPTEN OR NGAGE)
|
||||||
|
+ if(EMSCRIPTEN OR NGAGE OR OPENORBIS)
|
||||||
|
set(SDL_THREADS_DISABLED 1)
|
||||||
|
sdl_glob_sources(
|
||||||
|
"${SDL3_SOURCE_DIR}/src/thread/generic/*.c"
|
||||||
|
diff --git a/build-scripts/rename_macros.py b/build-scripts/rename_macros.py
|
||||||
|
index 978120c..b6063dd 100755
|
||||||
|
--- a/build-scripts/rename_macros.py
|
||||||
|
+++ b/build-scripts/rename_macros.py
|
||||||
|
@@ -124,6 +124,7 @@ RENAMED_MACROS = {
|
||||||
|
"__RISCOS__": "SDL_PLATFORM_RISCOS",
|
||||||
|
"__SOLARIS__": "SDL_PLATFORM_SOLARIS",
|
||||||
|
"__PSP__": "SDL_PLATFORM_PSP",
|
||||||
|
+ "__PS4__": "SDL_PLATFORM_PS4",
|
||||||
|
"__PS2__": "SDL_PLATFORM_PS2",
|
||||||
|
"__VITA__": "SDL_PLATFORM_VITA",
|
||||||
|
"__3DS__": "SDL_PLATFORM_3DS",
|
||||||
|
diff --git a/include/SDL3/SDL_platform_defines.h b/include/SDL3/SDL_platform_defines.h
|
||||||
|
index 7963149..6c0dd5d 100644
|
||||||
|
--- a/include/SDL3/SDL_platform_defines.h
|
||||||
|
+++ b/include/SDL3/SDL_platform_defines.h
|
||||||
|
@@ -442,6 +442,16 @@
|
||||||
|
#define SDL_PLATFORM_PSP 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#if defined(__PS4__) || defined(__OPENORBIS__)
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * A preprocessor macro that is only defined if compiling for Sony PSP.
|
||||||
|
+ *
|
||||||
|
+ * \since This macro is available since SDL 3.2.0.
|
||||||
|
+ */
|
||||||
|
+#define SDL_PLATFORM_PS4 1
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#if defined(__PS2__) || defined(PS2)
|
||||||
|
|
||||||
|
/**
|
||||||
|
diff --git a/src/SDL.c b/src/SDL.c
|
||||||
|
index b1a1a56..0a3fec6 100644
|
||||||
|
--- a/src/SDL.c
|
||||||
|
+++ b/src/SDL.c
|
||||||
|
@@ -714,7 +714,7 @@ void SDL_Quit(void)
|
||||||
|
SDL_DBus_Quit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-#if defined(SDL_PLATFORM_UNIX) && !defined(SDL_PLATFORM_ANDROID) && !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_PLATFORM_PRIVATE)
|
||||||
|
+#if defined(SDL_PLATFORM_UNIX) && !defined(SDL_PLATFORM_ANDROID) && !defined(SDL_PLATFORM_EMSCRIPTEN) && !defined(SDL_PLATFORM_PRIVATE) && !defined(SDL_PLATFORM_PS4)
|
||||||
|
SDL_Gtk_Quit();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -813,6 +813,8 @@ const char *SDL_GetPlatform(void)
|
||||||
|
return "tvOS";
|
||||||
|
#elif defined(SDL_PLATFORM_PS2)
|
||||||
|
return "PlayStation 2";
|
||||||
|
+#elif defined(SDL_PLATFORM_PS4)
|
||||||
|
+ return "PlayStation 4";
|
||||||
|
#elif defined(SDL_PLATFORM_PSP)
|
||||||
|
return "PlayStation Portable";
|
||||||
|
#elif defined(SDL_PLATFORM_VITA)
|
||||||
|
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
|
||||||
|
index c1e4241..65b1e6d 100644
|
||||||
|
--- a/src/audio/SDL_audio.c
|
||||||
|
+++ b/src/audio/SDL_audio.c
|
||||||
|
@@ -80,6 +80,9 @@ static const AudioBootStrap *const bootstrap[] = {
|
||||||
|
#ifdef SDL_AUDIO_DRIVER_NGAGE
|
||||||
|
&NGAGEAUDIO_bootstrap,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_AUDIO_DRIVER_PS4
|
||||||
|
+ &PS4AUDIO_bootstrap,
|
||||||
|
+#endif
|
||||||
|
#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN
|
||||||
|
&EMSCRIPTENAUDIO_bootstrap,
|
||||||
|
#endif
|
||||||
|
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
|
||||||
|
index 60c9743..2d12c3a 100644
|
||||||
|
--- a/src/joystick/SDL_joystick.c
|
||||||
|
+++ b/src/joystick/SDL_joystick.c
|
||||||
|
@@ -106,6 +106,9 @@ static SDL_JoystickDriver *SDL_joystick_drivers[] = {
|
||||||
|
#ifdef SDL_JOYSTICK_N3DS
|
||||||
|
&SDL_N3DS_JoystickDriver,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_JOYSTICK_PS4
|
||||||
|
+ &SDL_PS4_JoystickDriver,
|
||||||
|
+#endif
|
||||||
|
#if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
|
||||||
|
&SDL_DUMMY_JoystickDriver
|
||||||
|
#endif
|
||||||
|
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
|
||||||
|
index 47ce42c..42ab9de 100644
|
||||||
|
--- a/src/joystick/SDL_sysjoystick.h
|
||||||
|
+++ b/src/joystick/SDL_sysjoystick.h
|
||||||
|
@@ -253,6 +253,7 @@ extern SDL_JoystickDriver SDL_HAIKU_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_HIDAPI_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_RAWINPUT_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_IOS_JoystickDriver;
|
||||||
|
+extern SDL_JoystickDriver SDL_PS4_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_LINUX_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_VIRTUAL_JoystickDriver;
|
||||||
|
extern SDL_JoystickDriver SDL_WGI_JoystickDriver;
|
||||||
|
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
|
||||||
|
index a1bb44a..51843c4 100644
|
||||||
|
--- a/src/render/SDL_sysrender.h
|
||||||
|
+++ b/src/render/SDL_sysrender.h
|
||||||
|
@@ -381,6 +381,7 @@ extern SDL_RenderDriver NGAGE_RenderDriver;
|
||||||
|
extern SDL_RenderDriver VULKAN_RenderDriver;
|
||||||
|
extern SDL_RenderDriver PS2_RenderDriver;
|
||||||
|
extern SDL_RenderDriver PSP_RenderDriver;
|
||||||
|
+extern SDL_RenderDriver PS4_RenderDriver;
|
||||||
|
extern SDL_RenderDriver SW_RenderDriver;
|
||||||
|
extern SDL_RenderDriver VITA_GXM_RenderDriver;
|
||||||
|
extern SDL_RenderDriver GPU_RenderDriver;
|
||||||
|
diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
|
||||||
|
index 4a870f6..69ca1db 100644
|
||||||
|
--- a/src/stdlib/SDL_string.c
|
||||||
|
+++ b/src/stdlib/SDL_string.c
|
||||||
|
@@ -32,7 +32,9 @@
|
||||||
|
|
||||||
|
#include "SDL_casefolding.h"
|
||||||
|
|
||||||
|
-#if defined(__SIZEOF_WCHAR_T__)
|
||||||
|
+#if defined(SDL_PLATFORM_PS4)
|
||||||
|
+#define SDL_SIZEOF_WCHAR_T 2
|
||||||
|
+#elif defined(__SIZEOF_WCHAR_T__)
|
||||||
|
#define SDL_SIZEOF_WCHAR_T __SIZEOF_WCHAR_T__
|
||||||
|
#elif defined(SDL_PLATFORM_NGAGE)
|
||||||
|
#define SDL_SIZEOF_WCHAR_T 2
|
||||||
|
@@ -43,7 +45,6 @@
|
||||||
|
#endif
|
||||||
|
SDL_COMPILE_TIME_ASSERT(sizeof_wchar_t, sizeof(wchar_t) == SDL_SIZEOF_WCHAR_T);
|
||||||
|
|
||||||
|
-
|
||||||
|
char *SDL_UCS4ToUTF8(Uint32 codepoint, char *dst)
|
||||||
|
{
|
||||||
|
if (!dst) {
|
||||||
|
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
|
||||||
|
index f650f27..e23424f 100644
|
||||||
|
--- a/src/video/SDL_video.c
|
||||||
|
+++ b/src/video/SDL_video.c
|
||||||
|
@@ -131,6 +131,9 @@ static VideoBootStrap *bootstrap[] = {
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_NGAGE
|
||||||
|
&NGAGE_bootstrap,
|
||||||
|
#endif
|
||||||
|
+#ifdef SDL_VIDEO_DRIVER_PS4
|
||||||
|
+ &PS4_bootstrap,
|
||||||
|
+#endif
|
||||||
|
#ifdef SDL_VIDEO_DRIVER_KMSDRM
|
||||||
|
&KMSDRM_bootstrap,
|
||||||
|
#endif
|
||||||
|
@@ -314,6 +317,7 @@ static bool SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window,
|
||||||
|
SDL_GetWindowSizeInPixels(window, &w, &h);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
+
|
||||||
|
SDL_Renderer *renderer = NULL;
|
||||||
|
const char *render_driver = NULL;
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,25 @@
|
|||||||
|
diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp
|
||||||
|
index e41c044..a51b53b 100644
|
||||||
|
--- a/source/opt/loop_dependence.cpp
|
||||||
|
+++ b/source/opt/loop_dependence.cpp
|
||||||
|
@@ -12,6 +12,12 @@
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
+// PS4: issue?
|
||||||
|
+#ifdef __PS4__
|
||||||
|
+#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||||
|
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#include "source/opt/loop_dependence.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
@@ -19,6 +25,7 @@
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
+#include <cstdlib>
|
||||||
|
|
||||||
|
#include "source/opt/instruction.h"
|
||||||
|
#include "source/opt/scalar_analysis_nodes.h"
|
||||||
+4
-5
@@ -22,6 +22,7 @@ include(UseCcache)
|
|||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
include(CPMUtil)
|
include(CPMUtil)
|
||||||
|
include(OpenOrbis)
|
||||||
|
|
||||||
if (NOT DEFINED ARCHITECTURE)
|
if (NOT DEFINED ARCHITECTURE)
|
||||||
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
|
||||||
@@ -84,8 +85,6 @@ option(ENABLE_WERROR "Enable -Werror diagnostics" ON)
|
|||||||
# Lossless Scaling frame generation. Only Android.
|
# Lossless Scaling frame generation. Only Android.
|
||||||
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
cmake_dependent_option(ENABLE_LSFG "Enable Lossless Scaling frame generation" ON "ANDROID" OFF)
|
||||||
|
|
||||||
option(ENABLE_RESHADE "Enable ReShade FX post-processing effects" ON)
|
|
||||||
|
|
||||||
# non-linux bundled qt are static
|
# non-linux bundled qt are static
|
||||||
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
if (YUZU_USE_BUNDLED_QT AND (APPLE OR NOT UNIX))
|
||||||
set(YUZU_STATIC_BUILD ON)
|
set(YUZU_STATIC_BUILD ON)
|
||||||
@@ -216,6 +215,8 @@ if(MSVC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
# TODO(crueter): Cleanup, each dep that has a bundled option should allow to choose between bundled, external, system
|
||||||
|
cmake_dependent_option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" "${MSVC}" "NOT ANDROID" OFF)
|
||||||
|
|
||||||
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||||
|
|
||||||
set(EXT_DEFAULT OFF)
|
set(EXT_DEFAULT OFF)
|
||||||
@@ -223,8 +224,6 @@ if (MSVC OR ANDROID)
|
|||||||
set(EXT_DEFAULT ON)
|
set(EXT_DEFAULT ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(YUZU_USE_BUNDLED_SDL3 "Download bundled SDL3 build" ${EXT_DEFAULT})
|
|
||||||
|
|
||||||
# ffmpeg
|
# ffmpeg
|
||||||
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
option(YUZU_USE_BUNDLED_FFMPEG "Download bundled FFmpeg" ${EXT_DEFAULT})
|
||||||
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
|
cmake_dependent_option(YUZU_USE_EXTERNAL_FFMPEG "Build FFmpeg from external source" "${SOLARIS}" "NOT WIN32 AND NOT ANDROID" OFF)
|
||||||
@@ -240,7 +239,7 @@ option(YUZU_USE_BUNDLED_SIRIT "Download bundled sirit" ${BUNDLED_SIRIT_DEFAULT})
|
|||||||
# FreeBSD 15+ has libusb, versions below should disable it
|
# FreeBSD 15+ has libusb, versions below should disable it
|
||||||
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
cmake_dependent_option(ENABLE_LIBUSB "Enable the use of LibUSB" ON "WIN32 OR LINUX OR FREEBSD OR APPLE" OFF)
|
||||||
|
|
||||||
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE AND NOT ANDROID" OFF)
|
cmake_dependent_option(ENABLE_OPENGL "Enable OpenGL" ON "NOT (WIN32 AND ARCHITECTURE_arm64) AND NOT APPLE" OFF)
|
||||||
mark_as_advanced(FORCE ENABLE_OPENGL)
|
mark_as_advanced(FORCE ENABLE_OPENGL)
|
||||||
|
|
||||||
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
option(ENABLE_WEB_SERVICE "Enable web services (telemetry, etc.)" ON)
|
||||||
|
|||||||
@@ -18,10 +18,13 @@ if (DEFINED GIT_RELEASE)
|
|||||||
set(BUILD_VERSION "${GIT_TAG}")
|
set(BUILD_VERSION "${GIT_TAG}")
|
||||||
set(GIT_REFSPEC "${GIT_RELEASE}")
|
set(GIT_REFSPEC "${GIT_RELEASE}")
|
||||||
set(IS_DEV_BUILD false)
|
set(IS_DEV_BUILD false)
|
||||||
else()
|
elseif(DEFINED GIT_COMMIT)
|
||||||
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
|
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
|
||||||
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
|
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
|
||||||
set(IS_DEV_BUILD true)
|
set(IS_DEV_BUILD true)
|
||||||
|
else()
|
||||||
|
set(BUILD_VERSION "NoGitInfo")
|
||||||
|
set(IS_DEV_BUILD true)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NIGHTLY_BUILD)
|
if (NIGHTLY_BUILD)
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
function(create_ps4_eboot project target content_id)
|
||||||
|
set(sce_sys_dir sce_sys)
|
||||||
|
set(sce_sys_param ${sce_sys_dir}/param.sfo)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${target}.pkg"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
|
||||||
|
VERBATIM
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
DEPENDS ${project}
|
||||||
|
)
|
||||||
|
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(create_ps4_pkg project target content_id)
|
||||||
|
set(sce_sys_dir sce_sys)
|
||||||
|
set(sce_sys_param ${sce_sys_dir}/param.sfo)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT "${target}.pkg"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin
|
||||||
|
COMMAND mkdir -p ${sce_sys_dir}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_new ${sce_sys_param}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_TYPE --type Integer --maxsize 4 --value 1
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_VER --type Utf8 --maxsize 8 --value 1.03
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} ATTRIBUTE --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CATEGORY --type Utf8 --maxsize 4 --value gd
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CONTENT_ID --type Utf8 --maxsize 48 --value ${content_id}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} DOWNLOAD_DATA_SIZE --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} SYSTEM_VER --type Integer --maxsize 4 --value 0
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE --type Utf8 --maxsize 128 --value ${target}
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE_ID --type Utf8 --maxsize 12 --value BREW00090
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} VERSION --type Utf8 --maxsize 8 --value 1.03
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/create-gp4 -out ${target}.gp4 --content-id=${content_id} --files "${target}_eboot.bin ${sce_sys_param} sce_module/libc.prx sce_module/libSceFios2.prx"
|
||||||
|
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${target}.gp4 .
|
||||||
|
VERBATIM
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||||
|
DEPENDS ${project}
|
||||||
|
)
|
||||||
|
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN})
|
||||||
|
set(ENV{OO_PS4_TOOLCHAIN} ${CMAKE_SYSROOT})
|
||||||
|
endif ()
|
||||||
+26
-11
@@ -20,7 +20,8 @@
|
|||||||
"min_version": "1.57",
|
"min_version": "1.57",
|
||||||
"package": "Boost",
|
"package": "Boost",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-clang-cl.patch"
|
"0001-clang-cl.patch",
|
||||||
|
"0004-openorbis.patch"
|
||||||
],
|
],
|
||||||
"repo": "boostorg/boost",
|
"repo": "boostorg/boost",
|
||||||
"version": "boost-1.90.0"
|
"version": "boost-1.90.0"
|
||||||
@@ -78,12 +79,18 @@
|
|||||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||||
"min_version": "1.3",
|
"min_version": "1.3",
|
||||||
"repo": "lsalzman/enet",
|
"repo": "lsalzman/enet",
|
||||||
"version": "v1.3.18"
|
"version": "v1.3.18",
|
||||||
|
"patches": [
|
||||||
|
"0001-openorbis.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"ffmpeg": {
|
"ffmpeg": {
|
||||||
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
|
||||||
"repo": "FFmpeg/FFmpeg",
|
"repo": "FFmpeg/FFmpeg",
|
||||||
"version": "c7b5f1537d"
|
"version": "c7b5f1537d",
|
||||||
|
"patches": [
|
||||||
|
"0001-sysctl-openorbis.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"ffmpeg-ci": {
|
"ffmpeg-ci": {
|
||||||
"ci": true,
|
"ci": true,
|
||||||
@@ -186,12 +193,19 @@
|
|||||||
"repo": "eden-emulator/oaknut",
|
"repo": "eden-emulator/oaknut",
|
||||||
"version": "v2.0.3"
|
"version": "v2.0.3"
|
||||||
},
|
},
|
||||||
|
"oboe": {
|
||||||
|
"bundled": true,
|
||||||
|
"hash": "ce4011afe7345370d4ead3b891cd69a5ef224b129535783586c0ca75051d303ed446e6c7f10bde8da31fff58d6e307f1732a3ffd03b249f9ef1fd48fd4132715",
|
||||||
|
"repo": "google/oboe",
|
||||||
|
"version": "1.10.0"
|
||||||
|
},
|
||||||
"openssl": {
|
"openssl": {
|
||||||
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
|
"hash": "29002ce50cb95a4f4f1d0e9d3f684401fbd4eac34203dc2eef3b6334af5d44aa46bf788b63a6f5c139c383eafb7269ae87a58a9a3ad5912903b9773e545ccc0a",
|
||||||
"min_version": "3.0.0",
|
"min_version": "3.0.0",
|
||||||
"package": "OpenSSL",
|
"package": "OpenSSL",
|
||||||
"patches": [
|
"patches": [
|
||||||
"0001-add-bundled-cert.patch"
|
"0001-add-bundled-cert.patch",
|
||||||
|
"0002-fix-gnu-openorbis.patch"
|
||||||
],
|
],
|
||||||
"repo": "openssl/openssl",
|
"repo": "openssl/openssl",
|
||||||
"version": "openssl-3.6.2"
|
"version": "openssl-3.6.2"
|
||||||
@@ -213,7 +227,9 @@
|
|||||||
"0001-cpmutil-compat.patch",
|
"0001-cpmutil-compat.patch",
|
||||||
"0002-use-ccache.patch",
|
"0002-use-ccache.patch",
|
||||||
"0003-use-cmake-compiler-flags.patch",
|
"0003-use-cmake-compiler-flags.patch",
|
||||||
"0004-use-shell-wrapper.patch"
|
"0004-use-shell-wrapper.patch",
|
||||||
|
"0005-wasm-support.patch",
|
||||||
|
"0006-openorbis-prefix.patch"
|
||||||
],
|
],
|
||||||
"repo": "jimmy-park/openssl-cmake",
|
"repo": "jimmy-park/openssl-cmake",
|
||||||
"version": "3.6.2"
|
"version": "3.6.2"
|
||||||
@@ -246,17 +262,16 @@
|
|||||||
"repo": "stachenov/quazip",
|
"repo": "stachenov/quazip",
|
||||||
"version": "2e95c9001b"
|
"version": "2e95c9001b"
|
||||||
},
|
},
|
||||||
"reshade": {
|
|
||||||
"hash": "a1bd3fcf135fb6d018c1831ae45a8942d9777d0418b55e1189921e2ab775d1b53b0a9808924e09ef1c3e68ea11d69b3bcbebc7f4b59de14f6deec2dc24531d5e",
|
|
||||||
"repo": "crosire/reshade",
|
|
||||||
"version": "v6.7.3"
|
|
||||||
},
|
|
||||||
"sdl3": {
|
"sdl3": {
|
||||||
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
"hash": "df5a323af7ac366661a3c0e887969c72584d232f3cc211419d59b0487b620b6b2859d4549c9e8df002ee489290062e466fcfddf7edc0872a37b1f2845e81c0f3",
|
||||||
"min_version": "3.2.10",
|
"min_version": "3.2.10",
|
||||||
"package": "SDL3",
|
"package": "SDL3",
|
||||||
"repo": "libsdl-org/SDL",
|
"repo": "libsdl-org/SDL",
|
||||||
"version": "release-3.4.8"
|
"version": "release-3.4.8",
|
||||||
|
"patches": [
|
||||||
|
"0001-ps4.patch",
|
||||||
|
"0002-ps4-drivers.patch"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"sdl3-ci": {
|
"sdl3-ci": {
|
||||||
"ci": true,
|
"ci": true,
|
||||||
|
|||||||
Vendored
+223
@@ -0,0 +1,223 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
width="512"
|
||||||
|
height="512"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
version="1.1"
|
||||||
|
id="svg7"
|
||||||
|
sodipodi:docname="ps4.svg"
|
||||||
|
inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
|
||||||
|
inkscape:export-filename="base.svg.2026_01_12_14_43_47.0.svg"
|
||||||
|
inkscape:export-xdpi="96"
|
||||||
|
inkscape:export-ydpi="96"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<defs
|
||||||
|
id="defs7">
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient5"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#003e74;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop4" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#2ea8ff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop5" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient1"
|
||||||
|
inkscape:collect="always">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#3579ff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop2" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#0b00ff;stop-opacity:1;"
|
||||||
|
offset="1"
|
||||||
|
id="stop3" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch37"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop37" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch28"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#252525;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop28" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch27"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#000000;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop27" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch15"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop16" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="linearGradient14"
|
||||||
|
inkscape:swatch="gradient">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop14" />
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:0;"
|
||||||
|
offset="1"
|
||||||
|
id="stop15" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch9"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop10" />
|
||||||
|
</linearGradient>
|
||||||
|
<linearGradient
|
||||||
|
id="swatch8"
|
||||||
|
inkscape:swatch="solid">
|
||||||
|
<stop
|
||||||
|
style="stop-color:#ffffff;stop-opacity:1;"
|
||||||
|
offset="0"
|
||||||
|
id="stop9" />
|
||||||
|
</linearGradient>
|
||||||
|
<rect
|
||||||
|
x="22.627417"
|
||||||
|
y="402.76802"
|
||||||
|
width="521.34025"
|
||||||
|
height="248.94868"
|
||||||
|
id="rect24" />
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath18">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
id="circle18"
|
||||||
|
cx="-246.8315"
|
||||||
|
cy="246.8338"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
r="191.89999" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath22">
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:normal;fill:none;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10.8382;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
id="circle22"
|
||||||
|
cx="256"
|
||||||
|
cy="256"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
r="191.89999" />
|
||||||
|
</clipPath>
|
||||||
|
<clipPath
|
||||||
|
clipPathUnits="userSpaceOnUse"
|
||||||
|
id="clipPath128">
|
||||||
|
<circle
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#03ffff;stroke-width:0;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="circle128"
|
||||||
|
cx="256"
|
||||||
|
cy="256"
|
||||||
|
r="192" />
|
||||||
|
</clipPath>
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient1"
|
||||||
|
id="linearGradient3"
|
||||||
|
x1="256"
|
||||||
|
y1="64"
|
||||||
|
x2="256"
|
||||||
|
y2="448"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(1.1874952,0,0,-1.1874952,-47.370662,560.66391)" />
|
||||||
|
<linearGradient
|
||||||
|
inkscape:collect="always"
|
||||||
|
xlink:href="#linearGradient5"
|
||||||
|
id="linearGradient4"
|
||||||
|
gradientUnits="userSpaceOnUse"
|
||||||
|
gradientTransform="matrix(-1.1874952,0,0,1.1874952,560.61528,-47.345282)"
|
||||||
|
x1="256"
|
||||||
|
y1="64"
|
||||||
|
x2="256"
|
||||||
|
y2="448" />
|
||||||
|
</defs>
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview7"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:zoom="1.4142136"
|
||||||
|
inkscape:cx="262.69017"
|
||||||
|
inkscape:cy="76.367532"
|
||||||
|
inkscape:window-width="1600"
|
||||||
|
inkscape:window-height="849"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-y="27"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="svg7" />
|
||||||
|
<circle
|
||||||
|
style="opacity:1;mix-blend-mode:screen;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:15.907;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path1"
|
||||||
|
cx="256.61652"
|
||||||
|
cy="257.31778"
|
||||||
|
r="227.33479" />
|
||||||
|
<path
|
||||||
|
id="path8-7"
|
||||||
|
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient3);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
d="m 256.62812,484.66422 a 227.99908,228.00372 0 0 1 -94.5288,-20.52182 c 17.54241,-0.96226 34.77843,-4.71825 46.2868,-10.46733 12.69502,-6.3416 25.70492,-17.24174 35.38366,-26.3736 h 36.45053 c 0.93211,0.61234 1.88758,1.23061 2.86668,1.85086 4.89722,14.18571 13.27668,38.80747 17.49933,51.23264 a 227.99908,228.00372 0 0 1 -43.9582,4.27925 z m 55.26491,-6.80041 -16.39068,-41.47736 c 6.99845,3.71973 14.6813,7.07649 22.62503,9.76921 20.75463,7.03513 39.46594,9.14022 49.31353,9.76688 a 227.99908,228.00372 0 0 1 -55.54788,21.94127 z m 58.6952,-23.72487 c -8.69086,-4.31956 -29.66977,-14.9556 -49.97917,-26.83747 h 87.23219 a 227.99908,228.00372 0 0 1 -37.25302,26.83747 z m -241.49988,-8.48659 a 227.99908,228.00372 0 0 1 -23.67337,-18.35088 h 95.80906 c -1.32304,0.72101 -2.11058,1.13186 -2.11058,1.13186 l 9.37935,10.63433 -34.47214,-6.30174 c 0,-2e-5 -10.96427,4.13624 -36.05858,11.02861 -3.09966,0.85131 -6.06162,1.45425 -8.87374,1.85782 z M 96.054184,418.52496 A 227.99908,228.00372 0 0 1 64.743277,379.80069 h 53.833883 c 16.2593,10.82121 36.03109,20.56336 55.93056,22.04797 47.50893,3.54468 62.979,-1.67459 62.979,-1.67459 0,0 -4.13964,4.3321 -13.0323,12.01204 -2.4447,2.11135 -5.46123,4.28998 -8.54904,6.33885 z m 156.603246,0 c 4.10483,-4.24043 6.54978,-7.04162 6.54978,-7.04162 0,0 3.17296,2.8621 8.63949,7.04162 z m 54.10293,0 c -19.35695,-13.88741 -22.86161,-25.14433 -22.86161,-25.14433 0,0 49.2172,17.2685 90.39112,0.28064 10.4477,-4.31055 19.37408,-9.1049 26.88099,-13.86058 h 47.3421 a 227.99908,228.00372 0 0 1 -31.31091,38.72427 z M 59.385631,371.02418 A 227.99908,228.00372 0 0 1 41.543041,332.29992 H 159.20017 c 1.30773,2.3199 2.75142,4.57103 4.34409,6.73083 12.77878,17.32895 25.06121,26.96783 33.0852,31.99343 h -27.15468 c -5.2719,-0.84 -10.81534,-1.78919 -16.40924,-2.84819 -27.04349,-5.11994 -72.845405,-20.48007 -72.845405,-20.48007 0,0 10.296355,11.13669 26.131855,23.32826 z m 238.424449,0 c 30.05703,-10.10404 47.05829,-24.07021 56.34572,-38.72426 h 117.55739 a 227.99908,228.00372 0 0 1 -17.84258,38.72426 h -40.22176 c 13.33114,-10.41219 19.38725,-18.85882 19.38725,-18.85882 0,0 -30.08919,11.11726 -59.29823,18.85882 z m -41.2585,-14.62133 c -0.90134,-0.01 -9.08983,-0.64727 -40.38179,-18.55498 -2.80164,-1.60327 -5.61377,-3.47048 -8.41452,-5.54795 h 37.53597 c 6.43727,15.58979 11.34615,24.10293 11.34615,24.10293 0,0 -0.0258,6.4e-4 -0.0858,0 z m 12.72847,-0.0418 c 0,0 -2.97304,-8.3824 -6.55675,-24.06118 h 46.48163 c -24.16151,23.08045 -39.92488,24.06123 -39.92488,24.06123 z M 38.653164,323.52341 a 227.99908,228.00372 0 0 1 -8.28,-38.72426 H 147.25331 c 0.50409,11.4347 2.40394,25.61361 7.73264,38.72426 z m 158.567726,0 c -12.80955,-11.77756 -24.77977,-26.58932 -33.71374,-38.72426 h 65.85729 c 4.01234,15.08912 8.39298,28.09557 12.44549,38.72426 z m 63.60057,0 c -2.16662,-10.57203 -4.40101,-23.55135 -6.23667,-38.72426 h 95.8253 c -7.46906,9.7857 -18.55287,23.51811 -32.62829,38.72426 z m 97.99155,0 c 5.95644,-13.69644 6.2152,-27.44278 5.00743,-38.72426 h 119.06262 a 227.99908,228.00372 0 0 1 -8.28,38.72426 z M 29.452392,276.02264 A 227.99908,228.00372 0 0 1 28.62903,256.6605 227.99908,228.00372 0 0 1 29.452392,237.29836 H 219.64878 c 2.02639,13.95226 4.61647,26.90106 7.48446,38.72428 H 157.2241 c -5.80191,-8.33616 -9.27267,-13.98815 -9.27267,-13.98815 0,0 -0.7416,5.5263 -0.8396,13.98815 z m 224.144368,0 c -1.22897,-11.76966 -2.19512,-24.70616 -2.7113,-38.72428 h 232.91837 a 227.99908,228.00372 0 0 1 0.82337,19.36214 227.99908,228.00372 0 0 1 -0.82337,19.36214 H 362.56568 c -0.39943,-2.2888 -0.8157,-4.40137 -1.19214,-6.30638 0,0 -1.52342,2.281 -4.43454,6.30638 z M 30.373164,228.52186 a 227.99908,228.00372 0 0 1 8.28,-38.72427 H 218.96921 c -1.16001,13.8461 -1.41371,26.99937 -0.37573,38.72427 z m 220.252536,0 c -0.27246,-12.17105 -0.19776,-25.09608 0.33166,-38.72427 h 223.6457 a 227.99908,228.00372 0 0 1 8.28,38.72427 z M 41.540725,181.02109 a 227.99908,228.00372 0 0 1 17.84259,-38.72427 H 225.63264 c -2.42151,12.98777 -4.45297,26.07281 -5.81919,38.72427 z m 209.892105,0 c 1.03997,-13.90922 3.42234,-26.81596 6.74692,-38.72427 h 195.69317 a 227.99908,228.00372 0 0 1 17.84258,38.72427 z M 64.740961,133.52032 A 227.99908,228.00372 0 0 1 96.051856,94.796041 H 236.06961 c -3.05987,12.287259 -6.07477,25.390049 -8.74155,38.724279 z m 196.112969,0 c 4.80192,-14.52175 10.96848,-27.42708 17.67095,-38.724279 h 138.6795 a 227.99908,228.00372 0 0 1 31.3109,38.724279 z M 105.41267,86.019537 A 227.99908,228.00372 0 0 1 254.61726,28.666053 c -3.30134,10.858112 -9.7429,31.901037 -16.31878,57.353484 z m 178.62756,0 C 299.82749,62.260898 317.24402,46.83239 326.52798,39.636692 a 227.99908,228.00372 0 0 1 81.31559,46.382845 z"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<path
|
||||||
|
id="path8-7-2"
|
||||||
|
style="display:inline;mix-blend-mode:multiply;fill:url(#linearGradient4);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;stroke-dasharray:none;stroke-opacity:0.566238;paint-order:stroke fill markers"
|
||||||
|
inkscape:label="Circle"
|
||||||
|
d="m 256.61651,28.654412 a 227.99908,228.00372 0 0 1 94.5288,20.521817 C 333.6029,50.138492 316.36688,53.89448 304.85851,59.64356 292.1635,65.985164 279.15359,76.8853 269.47486,86.017162 h -36.45054 c -0.93211,-0.612343 -1.88758,-1.230613 -2.86668,-1.850865 -4.89722,-14.18571 -13.27667,-38.807461 -17.49932,-51.232639 a 227.99908,228.00372 0 0 1 43.95819,-4.279246 z m -55.26491,6.800405 16.39068,41.477366 c -6.99844,-3.719734 -14.6813,-7.076497 -22.62503,-9.769213 -20.75463,-7.035126 -39.46594,-9.140222 -49.31352,-9.766875 A 227.99908,228.00372 0 0 1 201.3516,35.454817 Z m -58.6952,23.724872 c 8.69086,4.319561 29.66977,14.955598 49.97917,26.837473 H 105.40338 A 227.99908,228.00372 0 0 1 142.6564,59.179689 Z m 241.49988,8.486589 a 227.99908,228.00372 0 0 1 23.67337,18.350884 h -95.80906 c 1.32305,-0.721011 2.11058,-1.131861 2.11058,-1.131861 l -9.37935,-10.634328 34.47215,6.30174 c 0,1.2e-5 10.96426,-4.136248 36.05857,-11.028611 3.09966,-0.851315 6.06162,-1.454254 8.87374,-1.857824 z m 33.03417,27.127388 a 227.99908,228.00372 0 0 1 31.31091,38.724274 h -53.83388 c -16.25931,-10.82121 -36.0311,-20.56336 -55.93057,-22.04797 -47.50892,-3.54468 -62.97899,1.67459 -62.97899,1.67459 0,0 4.13963,-4.3321 13.03229,-12.01204 2.4447,-2.111347 5.46123,-4.289985 8.54904,-6.338854 z m -156.60325,0 c -4.10482,4.240439 -6.54978,7.041624 -6.54978,7.041624 0,0 -3.17295,-2.862104 -8.63949,-7.041624 z m -54.10293,0 c 19.35695,13.887414 22.86161,25.144334 22.86161,25.144334 0,0 -49.2172,-17.2685 -90.39112,-0.28064 -10.4477,4.31055 -19.37408,9.1049 -26.88099,13.86058 H 64.73166 A 227.99908,228.00372 0 0 1 96.042582,94.793666 Z m 247.37474,47.500784 a 227.99908,228.00372 0 0 1 17.84257,38.72426 H 354.04446 c -1.30773,-2.3199 -2.75142,-4.57103 -4.34409,-6.73083 -12.77878,-17.32895 -25.06121,-26.96783 -33.0852,-31.99343 h 27.15468 c 5.2719,0.84 10.81534,1.78919 16.40924,2.84819 27.04349,5.11994 72.84541,20.48007 72.84541,20.48007 0,0 -10.29636,-11.13669 -26.13186,-23.32826 z m -238.42446,0 c -30.05702,10.10404 -47.05829,24.07021 -56.34572,38.72426 H 41.531435 a 227.99908,228.00372 0 0 1 17.842579,-38.72426 h 40.221767 c -13.331141,10.41219 -19.387248,18.85882 -19.387248,18.85882 0,0 30.089197,-11.11726 59.298227,-18.85882 z m 41.2585,14.62133 c 0.90134,0.009 9.08984,0.64727 40.38179,18.55498 2.80164,1.60327 5.61377,3.47048 8.41452,5.54795 h -37.53597 c -6.43727,-15.58979 -11.34615,-24.10293 -11.34615,-24.10293 0,0 0.0258,-6.4e-4 0.0859,0 z m -12.72847,0.0418 c 0,0 2.97304,8.3824 6.55675,24.06118 H 204.0397 c 24.16152,-23.08045 39.92488,-24.06123 39.92488,-24.06123 z m 230.62688,32.83764 a 227.99908,228.00372 0 0 1 8.28,38.72426 H 365.99132 c -0.50409,-11.4347 -2.40394,-25.61361 -7.73264,-38.72426 z m -158.56772,0 c 12.80955,11.77756 24.77977,26.58932 33.71374,38.72426 h -65.85729 c -4.01234,-15.08912 -8.39298,-28.09557 -12.44549,-38.72426 z m -63.60057,0 c 2.16662,10.57203 4.40101,23.55135 6.23667,38.72426 h -95.8253 c 7.46906,-9.7857 18.55287,-23.51811 32.62829,-38.72426 z m -97.99154,0 c -5.95644,13.69644 -6.21521,27.44278 -5.00743,38.72426 H 30.361558 a 227.99908,228.00372 0 0 1 8.280001,-38.72426 z m 329.3606,47.50077 a 227.99908,228.00372 0 0 1 0.82336,19.36214 227.99908,228.00372 0 0 1 -0.82336,19.36214 H 293.59585 c -2.02639,-13.95226 -4.61647,-26.90106 -7.48446,-38.72428 h 69.90914 c 5.80191,8.33616 9.27267,13.98815 9.27267,13.98815 0,0 0.74161,-5.5263 0.8396,-13.98815 z m -224.14436,0 c 1.22897,11.76966 2.19512,24.70616 2.7113,38.72428 H 29.440786 a 227.99908,228.00372 0 0 1 -0.823361,-19.36214 227.99908,228.00372 0 0 1 0.823361,-19.36214 H 150.67895 c 0.39943,2.2888 0.8157,4.40137 1.19214,6.30638 0,0 1.52343,-2.281 4.43455,-6.30638 z m 223.22359,47.50078 a 227.99908,228.00372 0 0 1 -8.28,38.72427 H 294.27542 c 1.16002,-13.8461 1.41371,-26.99937 0.37574,-38.72427 z m -220.25252,0 c 0.27245,12.17105 0.19775,25.09608 -0.33167,38.72427 H 38.641559 a 227.99908,228.00372 0 0 1 -8.280001,-38.72427 z m 209.08496,47.50077 a 227.99908,228.00372 0 0 1 -17.84258,38.72427 H 287.61199 c 2.42151,-12.98777 4.45297,-26.07281 5.81919,-38.72427 z m -209.89209,0 c -1.03998,13.90921 -3.42235,26.81596 -6.74692,38.72427 H 59.371698 A 227.99908,228.00372 0 0 1 41.52912,332.29754 Z m 186.69187,47.50077 a 227.99908,228.00372 0 0 1 -31.3109,38.72428 H 277.17503 c 3.05986,-12.28726 6.07476,-25.39005 8.74154,-38.72428 z m -196.11297,0 c -4.80193,14.52175 -10.96849,27.42708 -17.67095,38.72428 H 96.040255 A 227.99908,228.00372 0 0 1 64.729344,379.79831 Z m 155.44125,47.50078 a 227.99908,228.00372 0 0 1 -149.20459,57.35348 c 3.30135,-10.85811 9.7429,-31.90104 16.31879,-57.35348 z m -178.62756,0 c -15.78726,23.75863 -33.20379,39.18714 -42.48775,46.38284 a 227.99908,228.00372 0 0 1 -81.31558,-46.38284 z"
|
||||||
|
sodipodi:insensitive="true" />
|
||||||
|
<ellipse
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="path192"
|
||||||
|
cx="88.20919"
|
||||||
|
cy="216.80666"
|
||||||
|
rx="43.306744"
|
||||||
|
ry="42.75507" />
|
||||||
|
<path
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="M 211.35225,346.71976 151.38374,303.96994 137.1338,384.12586 Z"
|
||||||
|
id="path195" />
|
||||||
|
<path
|
||||||
|
id="path196-7"
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:17.5749;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
d="m 309.50171,362.30735 86.0678,57.93833 m -75.48269,11.93227 57.93833,-86.0678" />
|
||||||
|
<rect
|
||||||
|
style="fill:none;fill-opacity:0.679924;stroke:#97f0e5;stroke-width:13.9781;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
id="rect197"
|
||||||
|
width="66.112526"
|
||||||
|
height="59.501274"
|
||||||
|
x="93.831078"
|
||||||
|
y="-503.61469"
|
||||||
|
transform="rotate(108)" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 16 KiB |
Vendored
-62
@@ -1,62 +0,0 @@
|
|||||||
texture EdenBackBufferTex : COLOR;
|
|
||||||
sampler EdenBackBuffer { Texture = EdenBackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Saturation <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Saturation";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Brightness <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Brightness";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Contrast <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Contrast";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
uniform float Gamma <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Gamma";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_Eden(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(0.0, 0.0);
|
|
||||||
if (id == 2)
|
|
||||||
{
|
|
||||||
uv.x = 2.0;
|
|
||||||
}
|
|
||||||
if (id == 1)
|
|
||||||
{
|
|
||||||
uv.y = 2.0;
|
|
||||||
}
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_ColorGrade(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float3 rgb = tex2D(EdenBackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
float luma = dot(rgb, float3(0.2126, 0.7152, 0.0722));
|
|
||||||
rgb = lerp(float3(luma, luma, luma), rgb, Saturation);
|
|
||||||
rgb *= Brightness;
|
|
||||||
rgb = (rgb - 0.5) * Contrast + 0.5;
|
|
||||||
rgb = pow(max(rgb, 0.0), 1.0 / max(Gamma, 0.0001));
|
|
||||||
|
|
||||||
return float4(saturate(rgb), 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique EdenColorGrade
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_Eden;
|
|
||||||
PixelShader = PS_ColorGrade;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-45
@@ -1,45 +0,0 @@
|
|||||||
texture EdenBackBufferTex : COLOR;
|
|
||||||
sampler EdenBackBuffer { Texture = EdenBackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Amount <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Amount";
|
|
||||||
ui_min = 0.0; ui_max = 3.0; ui_step = 0.01;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
void VS_Eden(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(0.0, 0.0);
|
|
||||||
if (id == 2)
|
|
||||||
{
|
|
||||||
uv.x = 2.0;
|
|
||||||
}
|
|
||||||
if (id == 1)
|
|
||||||
{
|
|
||||||
uv.y = 2.0;
|
|
||||||
}
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Sharpen(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 texel = float2(BUFFER_RCP_WIDTH, BUFFER_RCP_HEIGHT);
|
|
||||||
|
|
||||||
float3 centre = tex2D(EdenBackBuffer, uv).rgb;
|
|
||||||
float3 blur = tex2D(EdenBackBuffer, uv + float2(-texel.x, 0.0)).rgb;
|
|
||||||
blur += tex2D(EdenBackBuffer, uv + float2(texel.x, 0.0)).rgb;
|
|
||||||
blur += tex2D(EdenBackBuffer, uv + float2(0.0, -texel.y)).rgb;
|
|
||||||
blur += tex2D(EdenBackBuffer, uv + float2(0.0, texel.y)).rgb;
|
|
||||||
blur *= 0.25;
|
|
||||||
|
|
||||||
return float4(centre + (centre - blur) * Amount, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique EdenSharpen
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_Eden;
|
|
||||||
PixelShader = PS_Sharpen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Vendored
-50
@@ -1,50 +0,0 @@
|
|||||||
texture EdenBackBufferTex : COLOR;
|
|
||||||
sampler EdenBackBuffer { Texture = EdenBackBufferTex; };
|
|
||||||
|
|
||||||
uniform float Strength <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Strength";
|
|
||||||
ui_tooltip = "How dark the corners become.";
|
|
||||||
ui_min = 0.0; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 0.6;
|
|
||||||
|
|
||||||
uniform float Aspect <
|
|
||||||
ui_type = "slider";
|
|
||||||
ui_label = "Aspect";
|
|
||||||
ui_min = 0.5; ui_max = 2.0; ui_step = 0.01;
|
|
||||||
> = 1.0;
|
|
||||||
|
|
||||||
void VS_Eden(in uint id : SV_VertexID, out float4 pos : SV_Position, out float2 uv : TEXCOORD)
|
|
||||||
{
|
|
||||||
uv = float2(0.0, 0.0);
|
|
||||||
if (id == 2)
|
|
||||||
{
|
|
||||||
uv.x = 2.0;
|
|
||||||
}
|
|
||||||
if (id == 1)
|
|
||||||
{
|
|
||||||
uv.y = 2.0;
|
|
||||||
}
|
|
||||||
pos = float4(uv * float2(2.0, -2.0) + float2(-1.0, 1.0), 0.0, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
float4 PS_Vignette(float4 pos : SV_Position, float2 uv : TEXCOORD) : SV_Target
|
|
||||||
{
|
|
||||||
float2 diff = uv - 0.5;
|
|
||||||
diff.x *= Aspect;
|
|
||||||
diff.y /= max(Aspect, 0.0001);
|
|
||||||
|
|
||||||
float falloff = 1.0 - min(1.0, Strength * dot(diff, diff) * 2.0);
|
|
||||||
float3 rgb = tex2D(EdenBackBuffer, uv).rgb;
|
|
||||||
|
|
||||||
return float4(rgb * falloff, 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
technique EdenVignette
|
|
||||||
{
|
|
||||||
pass
|
|
||||||
{
|
|
||||||
VertexShader = VS_Eden;
|
|
||||||
PixelShader = PS_Vignette;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
- [NetBSD](#netbsd)
|
- [NetBSD](#netbsd)
|
||||||
- [MSYS2](#msys2)
|
- [MSYS2](#msys2)
|
||||||
- [RedoxOS](#redoxos)
|
- [RedoxOS](#redoxos)
|
||||||
|
- [PlayStation 4](#playstation-4)
|
||||||
<!-- /TOC -->
|
<!-- /TOC -->
|
||||||
|
|
||||||
## Arch Linux
|
## Arch Linux
|
||||||
@@ -242,3 +243,14 @@ find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
|
|||||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||||
|
|
||||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||||
|
|
||||||
|
## PlayStation 4
|
||||||
|
|
||||||
|
```sh
|
||||||
|
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain/prefix"
|
||||||
|
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cp $OO_PS4_TOOLCHAIN/include/endian.h $OO_PS4_TOOLCHAIN/include/sys/endian.h
|
||||||
|
```
|
||||||
|
|||||||
+1
-1
@@ -76,7 +76,7 @@ The following options are desktop only.
|
|||||||
|
|
||||||
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
|
- `ENABLE_LIBUSB` (ON) Enable the use of the libusb input backend (HIGHLY RECOMMENDED)
|
||||||
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
|
- `ENABLE_OPENGL` (ON) Enable the OpenGL graphics backend
|
||||||
- Unavailable on Windows/ARM64 and on Android
|
- Unavailable on Windows/ARM64
|
||||||
- You probably shouldn't turn this off.
|
- You probably shouldn't turn this off.
|
||||||
|
|
||||||
### Qt
|
### Qt
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ Eden will store configuration files in the following directories:
|
|||||||
- **Android**: Data is stored internally.
|
- **Android**: Data is stored internally.
|
||||||
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
|
||||||
- **HaikuOS**: `/boot/home/config/settings/eden`
|
- **HaikuOS**: `/boot/home/config/settings/eden`
|
||||||
|
- **PlayStation 4**: `/data/eden`
|
||||||
|
|
||||||
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use the `user` directory instead.
|
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use the `user` directory instead.
|
||||||
|
|
||||||
|
|||||||
Vendored
+48
-70
@@ -136,50 +136,49 @@ if(ENABLE_CUBEB)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT YUZU_USE_BUNDLED_SDL3)
|
if (NOT ANDROID)
|
||||||
if (NOT WIN32)
|
if (NOT YUZU_USE_BUNDLED_SDL3)
|
||||||
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
if (NOT WIN32)
|
||||||
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
# Yuzu itself needs: Atomic Audio Events Joystick Haptic Sensor Threads Timers
|
||||||
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
# Since 2.0.18 Atomic+Threads required for HIDAPI/libusb (see https://github.com/libsdl-org/SDL/issues/5095)
|
||||||
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
# Yuzu-cmd also needs: Video (depends on Loadso/Dlopen)
|
||||||
set(SDL_UNUSED_SUBSYSTEMS
|
# CPUinfo also required for SDL Audio, at least until 2.28.0 (see https://github.com/libsdl-org/SDL/issues/7809)
|
||||||
File Filesystem
|
set(SDL_UNUSED_SUBSYSTEMS
|
||||||
Locale Power Render)
|
File Filesystem
|
||||||
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
Locale Power Render)
|
||||||
string(TOUPPER ${_SUB} _OPT)
|
foreach(_SUB ${SDL_UNUSED_SUBSYSTEMS})
|
||||||
set(SDL_${_OPT} OFF)
|
string(TOUPPER ${_SUB} _OPT)
|
||||||
endforeach()
|
set(SDL_${_OPT} OFF)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
set(HIDAPI ON)
|
set(HIDAPI ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(SDL_FILE ON)
|
set(SDL_FILE ON)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
AddJsonPackage(sdl3)
|
AddJsonPackage(sdl3)
|
||||||
else()
|
|
||||||
message(STATUS "Using bundled SDL3")
|
|
||||||
AddJsonPackage(sdl3-ci)
|
|
||||||
|
|
||||||
# copy sdl java sources for consumption by Gradle
|
|
||||||
if (ANDROID)
|
|
||||||
file(COPY ${SDL3_SOURCE_DIR}/java DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/generated/sdl)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Normalize SDL3 link target across package variants.
|
|
||||||
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
|
|
||||||
if (NOT TARGET SDL3::SDL3)
|
|
||||||
if (TARGET SDL3::SDL3-shared)
|
|
||||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
|
|
||||||
elseif (TARGET SDL3::SDL3-static)
|
|
||||||
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
|
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
|
message(STATUS "Using bundled SDL3")
|
||||||
|
AddJsonPackage(sdl3-ci)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Normalize SDL3 link target across package variants.
|
||||||
|
# Some SDL3 packages export only SDL3::SDL3-shared or SDL3::SDL3-static.
|
||||||
|
if (NOT TARGET SDL3::SDL3)
|
||||||
|
if (TARGET SDL3::SDL3-shared)
|
||||||
|
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-shared)
|
||||||
|
elseif (TARGET SDL3::SDL3-static)
|
||||||
|
add_library(SDL3::SDL3 ALIAS SDL3::SDL3-static)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "SDL3 package found, but no usable SDL3 target was exported")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
|
||||||
# SPIRV Headers
|
# SPIRV Headers
|
||||||
AddJsonPackage(spirv-headers)
|
AddJsonPackage(spirv-headers)
|
||||||
|
|
||||||
@@ -195,39 +194,6 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# reshadefx
|
|
||||||
if (ENABLE_RESHADE)
|
|
||||||
AddJsonPackage(NAME reshade DOWNLOAD_ONLY)
|
|
||||||
|
|
||||||
set(RESHADEFX_SHIM_DIR ${CMAKE_CURRENT_BINARY_DIR}/reshadefx_shim)
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/spirv.hpp "#include <spirv/unified1/spirv.hpp>\n")
|
|
||||||
file(WRITE ${RESHADEFX_SHIM_DIR}/GLSL.std.450.h "#include <spirv/unified1/GLSL.std.450.h>\n")
|
|
||||||
|
|
||||||
add_library(reshadefx STATIC
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_codegen_spirv.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_expression.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_lexer.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_exp.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_parser_stmt.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_preprocessor.cpp
|
|
||||||
${reshade_SOURCE_DIR}/source/effect_symbol_table.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
target_include_directories(reshadefx SYSTEM PUBLIC ${reshade_SOURCE_DIR}/source)
|
|
||||||
target_include_directories(reshadefx PRIVATE ${RESHADEFX_SHIM_DIR})
|
|
||||||
target_link_libraries(reshadefx PUBLIC SPIRV-Headers::SPIRV-Headers)
|
|
||||||
|
|
||||||
if (NOT MSVC)
|
|
||||||
target_compile_options(reshadefx PRIVATE -w)
|
|
||||||
else()
|
|
||||||
target_compile_options(reshadefx PRIVATE /w)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT TARGET reshadefx::reshadefx)
|
|
||||||
add_library(reshadefx::reshadefx ALIAS reshadefx)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Catch2
|
# Catch2
|
||||||
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
if (YUZU_TESTS OR DYNARMIC_TESTS)
|
||||||
AddJsonPackage(catch2)
|
AddJsonPackage(catch2)
|
||||||
@@ -288,6 +254,11 @@ target_include_directories(tz PUBLIC ./tz)
|
|||||||
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
|
||||||
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
target_include_directories(bc_decoder PUBLIC ./bc_decoder)
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
add_library(ps4sup ps4sup/emutls.c ps4sup/stub.cpp)
|
||||||
|
target_include_directories(ps4sup PUBLIC ./ps4sup)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (NOT TARGET RenderDoc::API)
|
if (NOT TARGET RenderDoc::API)
|
||||||
add_library(renderdoc INTERFACE)
|
add_library(renderdoc INTERFACE)
|
||||||
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
|
||||||
@@ -419,6 +390,13 @@ if (YUZU_CRASH_DUMPS AND NOT TARGET libbreakpad_client)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# oboe
|
||||||
|
if (ANDROID)
|
||||||
|
AddJsonPackage(oboe)
|
||||||
|
|
||||||
|
add_library(oboe::oboe ALIAS oboe)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
# moltenvk
|
# moltenvk
|
||||||
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
|
if (NOT YUZU_USE_BUNDLED_MOLTENVK)
|
||||||
|
|||||||
Vendored
+184
@@ -0,0 +1,184 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
/* ===---------- emutls.c - Implements __emutls_get_address ---------------===
|
||||||
|
*
|
||||||
|
* The LLVM Compiler Infrastructure
|
||||||
|
*
|
||||||
|
* This file is dual licensed under the MIT and the University of Illinois Open
|
||||||
|
* Source Licenses. See LICENSE.TXT for details.
|
||||||
|
*
|
||||||
|
* ===----------------------------------------------------------------------===
|
||||||
|
*/
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//#include "int_util.h"
|
||||||
|
|
||||||
|
/* Default is not to use posix_memalign, so systems like Android
|
||||||
|
* can use thread local data without heavier POSIX memory allocators.
|
||||||
|
*/
|
||||||
|
#ifndef EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
#define EMUTLS_USE_POSIX_MEMALIGN 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* For every TLS variable xyz,
|
||||||
|
* there is one __emutls_control variable named __emutls_v.xyz.
|
||||||
|
* If xyz has non-zero initial value, __emutls_v.xyz's "value"
|
||||||
|
* will point to __emutls_t.xyz, which has the initial value.
|
||||||
|
*/
|
||||||
|
typedef struct __emutls_control {
|
||||||
|
size_t size; /* size of the object in bytes */
|
||||||
|
size_t align; /* alignment of the object in bytes */
|
||||||
|
union {
|
||||||
|
uintptr_t index; /* data[index-1] is the object address */
|
||||||
|
void* address; /* object address, when in single thread env */
|
||||||
|
} object;
|
||||||
|
void* value; /* null or non-zero initial value for the object */
|
||||||
|
} __emutls_control;
|
||||||
|
|
||||||
|
static inline void* emutls_memalign_alloc(size_t align, size_t size) {
|
||||||
|
void *base;
|
||||||
|
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
if (posix_memalign(&base, align, size) != 0)
|
||||||
|
abort();
|
||||||
|
#else
|
||||||
|
#define EXTRA_ALIGN_PTR_BYTES (align - 1 + sizeof(void*))
|
||||||
|
char* object;
|
||||||
|
if ((object = malloc(EXTRA_ALIGN_PTR_BYTES + size)) == NULL)
|
||||||
|
abort();
|
||||||
|
base = (void*)(((uintptr_t)(object + EXTRA_ALIGN_PTR_BYTES))
|
||||||
|
& ~(uintptr_t)(align - 1));
|
||||||
|
|
||||||
|
((void**)base)[-1] = object;
|
||||||
|
#endif
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void emutls_memalign_free(void* base) {
|
||||||
|
#if EMUTLS_USE_POSIX_MEMALIGN
|
||||||
|
free(base);
|
||||||
|
#else
|
||||||
|
/* The mallocated address is in ((void**)base)[-1] */
|
||||||
|
free(((void**)base)[-1]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Emulated TLS objects are always allocated at run-time. */
|
||||||
|
static inline void* emutls_allocate_object(__emutls_control* control) {
|
||||||
|
/* Use standard C types, check with gcc's emutls.o. */
|
||||||
|
//typedef unsigned int gcc_word __attribute__((mode(word)));
|
||||||
|
//typedef unsigned int gcc_pointer __attribute__((mode(pointer)));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(size_t) == sizeof(gcc_word));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(gcc_pointer));
|
||||||
|
//COMPILE_TIME_ASSERT(sizeof(uintptr_t) == sizeof(void*));
|
||||||
|
|
||||||
|
size_t size = control->size;
|
||||||
|
size_t align = control->align;
|
||||||
|
if (align < sizeof(void*))
|
||||||
|
align = sizeof(void*);
|
||||||
|
/* Make sure that align is power of 2. */
|
||||||
|
if ((align & (align - 1)) != 0)
|
||||||
|
abort();
|
||||||
|
|
||||||
|
void* base = emutls_memalign_alloc(align, size);
|
||||||
|
if (control->value)
|
||||||
|
memcpy(base, control->value, size);
|
||||||
|
else
|
||||||
|
memset(base, 0, size);
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
|
||||||
|
static pthread_mutex_t emutls_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
static size_t emutls_num_object = 0; /* number of allocated TLS objects */
|
||||||
|
|
||||||
|
typedef struct emutls_address_array {
|
||||||
|
uintptr_t size; /* number of elements in the 'data' array */
|
||||||
|
void* data[];
|
||||||
|
} emutls_address_array;
|
||||||
|
|
||||||
|
static pthread_key_t emutls_pthread_key;
|
||||||
|
|
||||||
|
static void emutls_key_destructor(void* ptr) {
|
||||||
|
emutls_address_array* array = (emutls_address_array*)ptr;
|
||||||
|
uintptr_t i;
|
||||||
|
for (i = 0; i < array->size; ++i) {
|
||||||
|
if (array->data[i])
|
||||||
|
emutls_memalign_free(array->data[i]);
|
||||||
|
}
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emutls_init(void) {
|
||||||
|
if (pthread_key_create(&emutls_pthread_key, emutls_key_destructor) != 0)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns control->object.index; set index if not allocated yet. */
|
||||||
|
static inline uintptr_t emutls_get_index(__emutls_control* control) {
|
||||||
|
uintptr_t index = __atomic_load_n(&control->object.index, __ATOMIC_ACQUIRE);
|
||||||
|
if (!index) {
|
||||||
|
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||||
|
pthread_once(&once, emutls_init);
|
||||||
|
pthread_mutex_lock(&emutls_mutex);
|
||||||
|
index = control->object.index;
|
||||||
|
if (!index) {
|
||||||
|
index = ++emutls_num_object;
|
||||||
|
__atomic_store_n(&control->object.index, index, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&emutls_mutex);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Updates newly allocated thread local emutls_address_array. */
|
||||||
|
static inline void emutls_check_array_set_size(emutls_address_array* array,
|
||||||
|
uintptr_t size) {
|
||||||
|
if (array == NULL)
|
||||||
|
abort();
|
||||||
|
array->size = size;
|
||||||
|
pthread_setspecific(emutls_pthread_key, (void*)array);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the new 'data' array size, number of elements,
|
||||||
|
* which must be no smaller than the given index.
|
||||||
|
*/
|
||||||
|
static inline uintptr_t emutls_new_data_array_size(uintptr_t index) {
|
||||||
|
/* Need to allocate emutls_address_array with one extra slot
|
||||||
|
* to store the data array size.
|
||||||
|
* Round up the emutls_address_array size to multiple of 16.
|
||||||
|
*/
|
||||||
|
return ((index + 1 + 15) & ~((uintptr_t)15)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the thread local emutls_address_array.
|
||||||
|
* Extends its size if necessary to hold address at index.
|
||||||
|
*/
|
||||||
|
static inline emutls_address_array* emutls_get_address_array(uintptr_t index) {
|
||||||
|
emutls_address_array* array = pthread_getspecific(emutls_pthread_key);
|
||||||
|
if (array == NULL) {
|
||||||
|
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||||
|
array = calloc(new_size + 1, sizeof(void*));
|
||||||
|
emutls_check_array_set_size(array, new_size);
|
||||||
|
} else if (index > array->size) {
|
||||||
|
uintptr_t orig_size = array->size;
|
||||||
|
uintptr_t new_size = emutls_new_data_array_size(index);
|
||||||
|
array = realloc(array, (new_size + 1) * sizeof(void*));
|
||||||
|
if (array)
|
||||||
|
memset(array->data + orig_size, 0,
|
||||||
|
(new_size - orig_size) * sizeof(void*));
|
||||||
|
emutls_check_array_set_size(array, new_size);
|
||||||
|
}
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* __emutls_get_address(__emutls_control* control) {
|
||||||
|
uintptr_t index = emutls_get_index(control);
|
||||||
|
emutls_address_array* array = emutls_get_address_array(index);
|
||||||
|
if (array->data[index - 1] == NULL)
|
||||||
|
array->data[index - 1] = emutls_allocate_object(control);
|
||||||
|
return array->data[index - 1];
|
||||||
|
}
|
||||||
Vendored
+44
@@ -0,0 +1,44 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define STUB_WEAK(name) \
|
||||||
|
extern "C" void name() { \
|
||||||
|
printf("called " #name); \
|
||||||
|
asm volatile("ud2"); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define STUB_ZERO(name) \
|
||||||
|
extern "C" int name() { \
|
||||||
|
printf("called " #name " = ret zero"); \
|
||||||
|
return 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern "C" int __pthread_cxa_finalize();
|
||||||
|
extern "C" void __cxa_thread_atexit_impl() {
|
||||||
|
//printf("__cxa_thread_atexit_impl called!\n");
|
||||||
|
//__pthread_cxa_finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
STUB_WEAK(ZSTD_trace_compress_begin)
|
||||||
|
STUB_WEAK(ZSTD_trace_compress_end)
|
||||||
|
STUB_WEAK(ZSTD_trace_decompress_begin)
|
||||||
|
STUB_WEAK(ZSTD_trace_decompress_end)
|
||||||
|
|
||||||
|
extern "C" thread_local struct {
|
||||||
|
char pad[512];
|
||||||
|
} _ThreadRuneLocale = {};
|
||||||
|
extern "C" struct {
|
||||||
|
char pad[512];
|
||||||
|
} __h_errno = {};
|
||||||
|
|
||||||
|
FILE* __stderrp = stdout;
|
||||||
|
FILE* __stdinp = stdin;
|
||||||
|
|
||||||
|
#undef STUB_WEAK
|
||||||
|
|
||||||
|
// THIS MAKES STD::COUT AND SUCH WORK :)
|
||||||
|
#include <iostream>
|
||||||
|
std::ios_base::Init init;
|
||||||
@@ -272,13 +272,6 @@ android {
|
|||||||
resValue("string", "app_name_suffixed", "$currentName$suffix")
|
resValue("string", "app_name_suffixed", "$currentName$suffix")
|
||||||
resValue("string", "app_name", "Eden$suffix")
|
resValue("string", "app_name", "Eden$suffix")
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
|
||||||
named("main") {
|
|
||||||
java.srcDir("${edenDir}/externals/generated/sdl/java")
|
|
||||||
kotlin.srcDir("${edenDir}/externals/generated/sdl/java")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
idea {
|
idea {
|
||||||
|
|||||||
Vendored
-3
@@ -9,9 +9,6 @@
|
|||||||
-keep class org.ini4j.spi.IniBuilder
|
-keep class org.ini4j.spi.IniBuilder
|
||||||
-keep class org.ini4j.spi.IniFormatter
|
-keep class org.ini4j.spi.IniFormatter
|
||||||
|
|
||||||
-keep class org.libsdl.app.** { *; }
|
|
||||||
-keepclassmembers class org.libsdl.app.** { *; }
|
|
||||||
|
|
||||||
# Suppress warnings for R8
|
# Suppress warnings for R8
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
-dontwarn org.bouncycastle.jsse.BCSSLParameters
|
||||||
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
-dontwarn org.bouncycastle.jsse.BCSSLSocket
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import android.widget.TextView
|
|||||||
import androidx.annotation.Keep
|
import androidx.annotation.Keep
|
||||||
import androidx.core.net.toUri
|
import androidx.core.net.toUri
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import org.libsdl.app.SDL
|
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
|
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
|
||||||
@@ -53,8 +52,6 @@ object NativeLibrary {
|
|||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("yuzu-android")
|
System.loadLibrary("yuzu-android")
|
||||||
SDL.setupJNI()
|
|
||||||
initJvm()
|
|
||||||
} catch (ex: UnsatisfiedLinkError) {
|
} catch (ex: UnsatisfiedLinkError) {
|
||||||
error("[NativeLibrary] $ex")
|
error("[NativeLibrary] $ex")
|
||||||
}
|
}
|
||||||
@@ -370,7 +367,6 @@ object NativeLibrary {
|
|||||||
NetPlayManager.clearChat()
|
NetPlayManager.clearChat()
|
||||||
}
|
}
|
||||||
|
|
||||||
external fun initJvm()
|
|
||||||
external fun initMultiplayer()
|
external fun initMultiplayer()
|
||||||
|
|
||||||
@Keep
|
@Keep
|
||||||
|
|||||||
-103
@@ -1,103 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.features.settings.model
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import kotlin.math.roundToInt
|
|
||||||
|
|
||||||
abstract class FxUniformSetting(
|
|
||||||
protected val index: Int,
|
|
||||||
protected val uniform: NativePostProcessing.Uniform,
|
|
||||||
protected val component: Int
|
|
||||||
) : AbstractSetting {
|
|
||||||
override val key: String
|
|
||||||
get() = "fx_${index}_${uniform.name}_$component"
|
|
||||||
|
|
||||||
override val isRuntimeModifiable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override val pairedSettingKey: String
|
|
||||||
get() = ""
|
|
||||||
|
|
||||||
override val isSwitchable: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val isSaveable: Boolean
|
|
||||||
get() = true
|
|
||||||
|
|
||||||
override var global: Boolean
|
|
||||||
get() = true
|
|
||||||
set(_) {}
|
|
||||||
|
|
||||||
protected fun currentValue(): Float {
|
|
||||||
if (NativePostProcessing.hasValue(index, uniform.name)) {
|
|
||||||
return NativePostProcessing.getValue(index, uniform.name, component)
|
|
||||||
}
|
|
||||||
return uniform.defaultAt(component)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun commit(value: Float) {
|
|
||||||
NativePostProcessing.setValue(index, uniform.name, component, value)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun reset() = commit(uniform.defaultAt(component))
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformSliderSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = ((uniform.defaultAt(component) - uniform.min) / uniform.step).roundToInt()
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int =
|
|
||||||
((currentValue() - uniform.min) / uniform.step).roundToInt()
|
|
||||||
|
|
||||||
override fun setInt(value: Int) = commit(uniform.min + value * uniform.step)
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String {
|
|
||||||
if (uniform.kind == NativePostProcessing.KIND_FLOAT) {
|
|
||||||
return String.format("%.3f", currentValue())
|
|
||||||
}
|
|
||||||
return currentValue().roundToInt().toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformChoiceSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractIntSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = uniform.defaultAt(component).roundToInt()
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int = currentValue().roundToInt()
|
|
||||||
|
|
||||||
override fun setInt(value: Int) = commit(value.toFloat())
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
class FxUniformBooleanSetting(
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform,
|
|
||||||
component: Int
|
|
||||||
) : FxUniformSetting(index, uniform, component), AbstractBooleanSetting {
|
|
||||||
override val defaultValue: Any
|
|
||||||
get() = uniform.defaultAt(component) != 0f
|
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean = currentValue() != 0f
|
|
||||||
|
|
||||||
override fun setBoolean(value: Boolean) {
|
|
||||||
if (value) {
|
|
||||||
commit(1f)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
commit(0f)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getBoolean().toString()
|
|
||||||
}
|
|
||||||
@@ -12,7 +12,6 @@ object Settings {
|
|||||||
SECTION_SYSTEM(R.string.preferences_system),
|
SECTION_SYSTEM(R.string.preferences_system),
|
||||||
SECTION_RENDERER(R.string.preferences_graphics),
|
SECTION_RENDERER(R.string.preferences_graphics),
|
||||||
SECTION_FRAME_GEN(R.string.frame_gen),
|
SECTION_FRAME_GEN(R.string.frame_gen),
|
||||||
SECTION_POST_PROCESSING(R.string.post_processing),
|
|
||||||
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
SECTION_PERFORMANCE_STATS(R.string.stats_overlay_options),
|
||||||
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
SECTION_INPUT_OVERLAY(R.string.input_overlay_options),
|
||||||
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
SECTION_SOC_OVERLAY(R.string.soc_overlay_options),
|
||||||
|
|||||||
-1
@@ -13,7 +13,6 @@ enum class StringSetting(override val key: String) : AbstractStringSetting {
|
|||||||
DEVICE_NAME("device_name"),
|
DEVICE_NAME("device_name"),
|
||||||
LOG_FILTER("log_filter"),
|
LOG_FILTER("log_filter"),
|
||||||
PROGRAM_ARGS("program_args"),
|
PROGRAM_ARGS("program_args"),
|
||||||
POST_SHADER_CHAIN("post_shader_chain"),
|
|
||||||
|
|
||||||
WEB_TOKEN("eden_token"),
|
WEB_TOKEN("eden_token"),
|
||||||
WEB_USERNAME("eden_username")
|
WEB_USERNAME("eden_username")
|
||||||
|
|||||||
-218
@@ -18,9 +18,6 @@ import org.yuzu.yuzu_emu.features.input.model.NpadStyleIndex
|
|||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformBooleanSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformChoiceSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.FxUniformSliderSetting
|
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
import org.yuzu.yuzu_emu.features.settings.model.ByteSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
import org.yuzu.yuzu_emu.features.settings.model.IntSetting
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
import org.yuzu.yuzu_emu.features.settings.model.LongSetting
|
||||||
@@ -33,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.view.*
|
|||||||
import org.yuzu.yuzu_emu.utils.InputHandler
|
import org.yuzu.yuzu_emu.utils.InputHandler
|
||||||
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
import org.yuzu.yuzu_emu.utils.LosslessScalingHelper
|
||||||
import org.yuzu.yuzu_emu.utils.NativeConfig
|
import org.yuzu.yuzu_emu.utils.NativeConfig
|
||||||
import org.yuzu.yuzu_emu.utils.NativePostProcessing
|
|
||||||
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
import org.yuzu.yuzu_emu.utils.DirectoryInitialization
|
||||||
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
import org.yuzu.yuzu_emu.utils.FullscreenHelper
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
@@ -167,7 +163,6 @@ class SettingsFragmentPresenter(
|
|||||||
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
MenuTag.SECTION_SYSTEM -> addSystemSettings(sl)
|
||||||
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
MenuTag.SECTION_RENDERER -> addGraphicsSettings(sl)
|
||||||
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
MenuTag.SECTION_FRAME_GEN -> addFrameGenSettings(sl)
|
||||||
MenuTag.SECTION_POST_PROCESSING -> addPostProcessingSettings(sl)
|
|
||||||
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
MenuTag.SECTION_PERFORMANCE_STATS -> addPerformanceOverlaySettings(sl)
|
||||||
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
MenuTag.SECTION_SOC_OVERLAY -> addSocOverlaySettings(sl)
|
||||||
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
MenuTag.SECTION_INPUT_OVERLAY -> addInputOverlaySettings(sl)
|
||||||
@@ -195,219 +190,6 @@ class SettingsFragmentPresenter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPostProcessingSettings(sl: ArrayList<SettingsItem>) {
|
|
||||||
val usable = NativePostProcessing.catalog().filter { it.valid }
|
|
||||||
|
|
||||||
sl.apply {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_reload,
|
|
||||||
descriptionId = R.string.post_processing_reload_description,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.reload()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (usable.isEmpty()) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_empty,
|
|
||||||
descriptionString = NativePostProcessing.getShaderDirectory(),
|
|
||||||
isRunnable = false
|
|
||||||
) {}
|
|
||||||
)
|
|
||||||
return@apply
|
|
||||||
}
|
|
||||||
|
|
||||||
val labels = mutableListOf<String>()
|
|
||||||
val files = mutableListOf<String>()
|
|
||||||
val techniques = mutableListOf<String>()
|
|
||||||
for (effect in usable) {
|
|
||||||
for (technique in effect.techniques) {
|
|
||||||
if (effect.techniques.size == 1) {
|
|
||||||
labels.add(effect.name)
|
|
||||||
} else {
|
|
||||||
labels.add(effect.name + " \u00b7 " + technique)
|
|
||||||
}
|
|
||||||
files.add(effect.file)
|
|
||||||
techniques.add(technique)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val chain = NativePostProcessing.chain()
|
|
||||||
for (index in chain.indices) {
|
|
||||||
val entry = chain[index]
|
|
||||||
val effect = usable.firstOrNull { it.file == entry.file }
|
|
||||||
|
|
||||||
var header = entry.file
|
|
||||||
if (effect != null) {
|
|
||||||
header = effect.name
|
|
||||||
}
|
|
||||||
add(HeaderSetting(titleString = header))
|
|
||||||
|
|
||||||
add(
|
|
||||||
IntSingleChoiceSetting(
|
|
||||||
buildSlotSelector(index, entry, files, techniques),
|
|
||||||
titleId = R.string.post_processing_effect,
|
|
||||||
choices = labels.toTypedArray(),
|
|
||||||
values = labels.indices.toList().toTypedArray()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (effect != null) {
|
|
||||||
for (uniform in effect.uniforms) {
|
|
||||||
addUniform(this, index, uniform)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (index > 0) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_move_up,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.move(index, -1)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (index < chain.size - 1) {
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_move_down,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.move(index, 1)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_reset,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.resetValues(index)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_remove,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.remove(index)
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
add(
|
|
||||||
RunnableSetting(
|
|
||||||
titleId = R.string.post_processing_add,
|
|
||||||
isRunnable = true
|
|
||||||
) {
|
|
||||||
NativePostProcessing.append(files[0], techniques[0])
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildSlotSelector(
|
|
||||||
index: Int,
|
|
||||||
entry: NativePostProcessing.ChainEntry,
|
|
||||||
files: List<String>,
|
|
||||||
techniques: List<String>
|
|
||||||
): AbstractIntSetting = object : AbstractIntSetting {
|
|
||||||
override val key = "fx_slot_$index"
|
|
||||||
|
|
||||||
override fun getInt(needsGlobal: Boolean): Int {
|
|
||||||
for (i in files.indices) {
|
|
||||||
if (files[i] == entry.file && techniques[i] == entry.technique) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setInt(value: Int) {
|
|
||||||
NativePostProcessing.replace(index, files[value], techniques[value])
|
|
||||||
NativePostProcessing.store()
|
|
||||||
settingsViewModel.setReloadListAndNotifyDataset(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
override val defaultValue = 0
|
|
||||||
override fun getValueAsString(needsGlobal: Boolean): String = getInt().toString()
|
|
||||||
override fun reset() {}
|
|
||||||
override val isRuntimeModifiable = true
|
|
||||||
override val pairedSettingKey = ""
|
|
||||||
override val isSwitchable = false
|
|
||||||
override val isSaveable = true
|
|
||||||
override var global: Boolean
|
|
||||||
get() = true
|
|
||||||
set(_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUniform(
|
|
||||||
sl: ArrayList<SettingsItem>,
|
|
||||||
index: Int,
|
|
||||||
uniform: NativePostProcessing.Uniform
|
|
||||||
) {
|
|
||||||
if (uniform.uiType == NativePostProcessing.UI_CHECKBOX ||
|
|
||||||
uniform.kind == NativePostProcessing.KIND_BOOL
|
|
||||||
) {
|
|
||||||
sl.add(
|
|
||||||
SwitchSetting(
|
|
||||||
FxUniformBooleanSetting(index, uniform, 0),
|
|
||||||
titleString = uniform.label,
|
|
||||||
descriptionString = uniform.tooltip
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uniform.items.isNotEmpty() &&
|
|
||||||
(uniform.uiType == NativePostProcessing.UI_COMBO ||
|
|
||||||
uniform.uiType == NativePostProcessing.UI_RADIO)
|
|
||||||
) {
|
|
||||||
sl.add(
|
|
||||||
IntSingleChoiceSetting(
|
|
||||||
FxUniformChoiceSetting(index, uniform, 0),
|
|
||||||
titleString = uniform.label,
|
|
||||||
descriptionString = uniform.tooltip,
|
|
||||||
choices = uniform.items.toTypedArray(),
|
|
||||||
values = uniform.items.indices.toList().toTypedArray()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for (component in 0 until uniform.components) {
|
|
||||||
var title = uniform.label
|
|
||||||
if (uniform.components > 1) {
|
|
||||||
title = uniform.label + " [" + component + "]"
|
|
||||||
}
|
|
||||||
sl.add(
|
|
||||||
SliderSetting(
|
|
||||||
FxUniformSliderSetting(index, uniform, component),
|
|
||||||
titleString = title,
|
|
||||||
descriptionString = uniform.tooltip,
|
|
||||||
min = 0,
|
|
||||||
max = uniform.steps
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
private fun addConfigSettings(sl: ArrayList<SettingsItem>) {
|
||||||
sl.apply {
|
sl.apply {
|
||||||
add(
|
add(
|
||||||
|
|||||||
@@ -383,20 +383,6 @@ class GamePropertiesFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
add(
|
|
||||||
SubmenuProperty(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_per_game_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
action = {
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
args.game,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (GpuDriverHelper.isAdrenoGpu()) {
|
if (GpuDriverHelper.isAdrenoGpu()) {
|
||||||
add(
|
add(
|
||||||
|
|||||||
@@ -171,20 +171,6 @@ class HomeSettingsFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
add(
|
|
||||||
HomeSetting(
|
|
||||||
R.string.post_processing,
|
|
||||||
R.string.post_processing_description,
|
|
||||||
R.drawable.ic_post_processing,
|
|
||||||
{
|
|
||||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
|
||||||
null,
|
|
||||||
Settings.MenuTag.SECTION_POST_PROCESSING
|
|
||||||
)
|
|
||||||
binding.root.findNavController().navigate(action)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
add(
|
add(
|
||||||
HomeSetting(
|
HomeSetting(
|
||||||
R.string.lossless_scaling,
|
R.string.lossless_scaling,
|
||||||
|
|||||||
@@ -1,175 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu.utils
|
|
||||||
|
|
||||||
import org.json.JSONArray
|
|
||||||
import org.json.JSONObject
|
|
||||||
|
|
||||||
object NativePostProcessing {
|
|
||||||
const val KIND_BOOL = 0
|
|
||||||
const val KIND_INT = 1
|
|
||||||
const val KIND_FLOAT = 2
|
|
||||||
|
|
||||||
const val UI_HIDDEN = 0
|
|
||||||
const val UI_SLIDER = 1
|
|
||||||
const val UI_DRAG = 2
|
|
||||||
const val UI_COMBO = 3
|
|
||||||
const val UI_RADIO = 4
|
|
||||||
const val UI_CHECKBOX = 5
|
|
||||||
const val UI_COLOR = 6
|
|
||||||
const val UI_INPUT_BOX = 7
|
|
||||||
|
|
||||||
external fun getCatalogJson(): String
|
|
||||||
|
|
||||||
external fun getChainJson(): String
|
|
||||||
|
|
||||||
external fun append(file: String, technique: String)
|
|
||||||
|
|
||||||
external fun replace(index: Int, file: String, technique: String)
|
|
||||||
|
|
||||||
external fun remove(index: Int)
|
|
||||||
|
|
||||||
external fun move(index: Int, delta: Int)
|
|
||||||
|
|
||||||
external fun resetValues(index: Int)
|
|
||||||
|
|
||||||
external fun getValue(index: Int, uniform: String, component: Int): Float
|
|
||||||
|
|
||||||
external fun hasValue(index: Int, uniform: String): Boolean
|
|
||||||
|
|
||||||
external fun setValue(index: Int, uniform: String, component: Int, value: Float)
|
|
||||||
|
|
||||||
external fun store()
|
|
||||||
|
|
||||||
external fun reload()
|
|
||||||
|
|
||||||
external fun getShaderDirectory(): String
|
|
||||||
|
|
||||||
data class Uniform(
|
|
||||||
val name: String,
|
|
||||||
val label: String,
|
|
||||||
val tooltip: String,
|
|
||||||
val category: String,
|
|
||||||
val kind: Int,
|
|
||||||
val uiType: Int,
|
|
||||||
val components: Int,
|
|
||||||
val min: Float,
|
|
||||||
val max: Float,
|
|
||||||
val step: Float,
|
|
||||||
val items: List<String>,
|
|
||||||
val defaults: List<Float>
|
|
||||||
) {
|
|
||||||
val steps: Int
|
|
||||||
get() {
|
|
||||||
val span = max - min
|
|
||||||
if (step <= 0f) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
val count = Math.round(span / step)
|
|
||||||
if (count < 1) {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
fun defaultAt(component: Int): Float {
|
|
||||||
if (component < defaults.size) {
|
|
||||||
return defaults[component]
|
|
||||||
}
|
|
||||||
return 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Effect(
|
|
||||||
val file: String,
|
|
||||||
val name: String,
|
|
||||||
val error: String,
|
|
||||||
val techniques: List<String>,
|
|
||||||
val uniforms: List<Uniform>
|
|
||||||
) {
|
|
||||||
val valid: Boolean
|
|
||||||
get() = error.isEmpty() && techniques.isNotEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ChainEntry(val file: String, val technique: String)
|
|
||||||
|
|
||||||
fun catalog(): List<Effect> {
|
|
||||||
val out = mutableListOf<Effect>()
|
|
||||||
val array = JSONArray(getCatalogJson())
|
|
||||||
for (i in 0 until array.length()) {
|
|
||||||
val obj = array.getJSONObject(i)
|
|
||||||
out.add(
|
|
||||||
Effect(
|
|
||||||
file = obj.optString("file"),
|
|
||||||
name = obj.optString("name"),
|
|
||||||
error = obj.optString("error"),
|
|
||||||
techniques = obj.optJSONArray("techniques").toStringList(),
|
|
||||||
uniforms = obj.optJSONArray("uniforms").toUniformList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
fun chain(): List<ChainEntry> {
|
|
||||||
val out = mutableListOf<ChainEntry>()
|
|
||||||
val array = JSONArray(getChainJson())
|
|
||||||
for (i in 0 until array.length()) {
|
|
||||||
val obj = array.getJSONObject(i)
|
|
||||||
out.add(ChainEntry(obj.optString("file"), obj.optString("technique")))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
fun findEffect(file: String): Effect? = catalog().firstOrNull { it.file == file }
|
|
||||||
|
|
||||||
private fun JSONArray?.toStringList(): List<String> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<String>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
out.add(optString(i))
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun JSONArray?.toFloatList(): List<Float> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<Float>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
out.add(optDouble(i, 0.0).toFloat())
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun JSONArray?.toUniformList(): List<Uniform> {
|
|
||||||
if (this == null) {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
val out = mutableListOf<Uniform>()
|
|
||||||
for (i in 0 until length()) {
|
|
||||||
val obj: JSONObject = optJSONObject(i) ?: continue
|
|
||||||
out.add(
|
|
||||||
Uniform(
|
|
||||||
name = obj.optString("name"),
|
|
||||||
label = obj.optString("label"),
|
|
||||||
tooltip = obj.optString("tooltip"),
|
|
||||||
category = obj.optString("category"),
|
|
||||||
kind = obj.optInt("kind", KIND_FLOAT),
|
|
||||||
uiType = obj.optInt("uiType", UI_HIDDEN),
|
|
||||||
components = obj.optInt("components", 1),
|
|
||||||
min = obj.optDouble("min", 0.0).toFloat(),
|
|
||||||
max = obj.optDouble("max", 1.0).toFloat(),
|
|
||||||
step = obj.optDouble("step", 0.01).toFloat(),
|
|
||||||
items = obj.optJSONArray("items").toStringList(),
|
|
||||||
defaults = obj.optJSONArray("defaults").toFloatList()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -17,13 +17,12 @@ add_library(yuzu-android SHARED
|
|||||||
android_config.cpp
|
android_config.cpp
|
||||||
android_config.h
|
android_config.h
|
||||||
native_input.cpp
|
native_input.cpp
|
||||||
native_post_processing.cpp
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
|
||||||
|
|
||||||
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common video_core)
|
target_link_libraries(yuzu-android PRIVATE audio_core common core input_common frontend_common video_core)
|
||||||
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log GLESv2)
|
target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad jnigraphics log)
|
||||||
if (ARCHITECTURE_arm64)
|
if (ARCHITECTURE_arm64)
|
||||||
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
target_link_libraries(yuzu-android PRIVATE adrenotools)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1730,15 +1730,6 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_loadAmiibo(JNIEnv* env, jobject jobj,
|
|||||||
return static_cast<jint>(info);
|
return static_cast<jint>(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void JNICALL
|
|
||||||
Java_org_yuzu_yuzu_1emu_NativeLibrary_initJvm(JNIEnv *env, jclass clazz) {
|
|
||||||
JavaVM *vm;
|
|
||||||
if (env->GetJavaVM(&vm) != JNI_OK)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Common::Android::Initialize(vm, env);
|
|
||||||
}
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL
|
||||||
Java_org_yuzu_yuzu_1emu_NativeLibrary_initMultiplayer(
|
Java_org_yuzu_yuzu_1emu_NativeLibrary_initMultiplayer(
|
||||||
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
JNIEnv* env, [[maybe_unused]] jobject obj) {
|
||||||
|
|||||||
@@ -1,218 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <jni.h>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include "common/android/android_common.h"
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
nlohmann::json SerializeUniform(const VideoCore::FxUniformDesc& uniform) {
|
|
||||||
nlohmann::json out;
|
|
||||||
out["name"] = uniform.name;
|
|
||||||
out["label"] = uniform.label;
|
|
||||||
out["tooltip"] = uniform.tooltip;
|
|
||||||
out["category"] = uniform.category;
|
|
||||||
out["kind"] = static_cast<int>(uniform.kind);
|
|
||||||
out["uiType"] = static_cast<int>(uniform.ui_type);
|
|
||||||
out["components"] = uniform.components;
|
|
||||||
out["min"] = uniform.ui_min;
|
|
||||||
out["max"] = uniform.ui_max;
|
|
||||||
out["step"] = uniform.ui_step;
|
|
||||||
out["items"] = uniform.items;
|
|
||||||
|
|
||||||
nlohmann::json defaults = nlohmann::json::array();
|
|
||||||
for (u32 i = 0; i < uniform.components; ++i) {
|
|
||||||
defaults.push_back(uniform.default_value[i]);
|
|
||||||
}
|
|
||||||
out["defaults"] = defaults;
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> DefaultValueOf(size_t index, const std::string& uniform) {
|
|
||||||
const auto entries = VideoCore::FxChain::Instance().Entries();
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const VideoCore::FxEffectDesc* effect = VideoCore::FindFxEffect(entries[index].file);
|
|
||||||
if (effect == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const VideoCore::FxUniformDesc* desc = VideoCore::FindFxUniform(*effect, uniform);
|
|
||||||
if (desc == nullptr) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return desc->default_value;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getCatalogJson(JNIEnv* env,
|
|
||||||
jobject obj) {
|
|
||||||
nlohmann::json out = nlohmann::json::array();
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
for (const auto& effect : VideoCore::GetFxCatalog()) {
|
|
||||||
nlohmann::json entry;
|
|
||||||
entry["file"] = effect.file;
|
|
||||||
entry["name"] = effect.name;
|
|
||||||
entry["error"] = effect.error;
|
|
||||||
entry["techniques"] = effect.techniques;
|
|
||||||
|
|
||||||
nlohmann::json uniforms = nlohmann::json::array();
|
|
||||||
for (const auto& uniform : effect.uniforms) {
|
|
||||||
uniforms.push_back(SerializeUniform(uniform));
|
|
||||||
}
|
|
||||||
entry["uniforms"] = uniforms;
|
|
||||||
|
|
||||||
out.push_back(entry);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return Common::Android::ToJString(env, out.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getChainJson(JNIEnv* env, jobject obj) {
|
|
||||||
nlohmann::json out = nlohmann::json::array();
|
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
for (const auto& entry : VideoCore::FxChain::Instance().Entries()) {
|
|
||||||
nlohmann::json item;
|
|
||||||
item["file"] = entry.file;
|
|
||||||
item["technique"] = entry.technique;
|
|
||||||
|
|
||||||
nlohmann::json values = nlohmann::json::object();
|
|
||||||
for (const auto& [name, value] : entry.values) {
|
|
||||||
values[name] = {value[0], value[1], value[2], value[3]};
|
|
||||||
}
|
|
||||||
item["values"] = values;
|
|
||||||
|
|
||||||
out.push_back(item);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return Common::Android::ToJString(env, out.dump());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_append(JNIEnv* env, jobject obj,
|
|
||||||
jstring jfile, jstring jtechnique) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Append(Common::Android::GetJString(env, jfile),
|
|
||||||
Common::Android::GetJString(env, jtechnique));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_replace(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring jfile,
|
|
||||||
jstring jtechnique) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Replace(static_cast<size_t>(index),
|
|
||||||
Common::Android::GetJString(env, jfile),
|
|
||||||
Common::Android::GetJString(env, jtechnique));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_remove(JNIEnv* env, jobject obj,
|
|
||||||
jint index) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Remove(static_cast<size_t>(index));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_move(JNIEnv* env, jobject obj, jint index,
|
|
||||||
jint delta) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().Move(static_cast<size_t>(index), delta);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_resetValues(JNIEnv* env, jobject obj,
|
|
||||||
jint index) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().ResetValues(static_cast<size_t>(index));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jfloat Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring juniform,
|
|
||||||
jint component) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (component < 0 || component >= 4) {
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
const auto value = VideoCore::FxChain::Instance().GetValue(
|
|
||||||
static_cast<size_t>(index), Common::Android::GetJString(env, juniform));
|
|
||||||
return value[static_cast<size_t>(component)];
|
|
||||||
#else
|
|
||||||
return 0.0f;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_hasValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index,
|
|
||||||
jstring juniform) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
return static_cast<jboolean>(VideoCore::FxChain::Instance().HasValue(
|
|
||||||
static_cast<size_t>(index), Common::Android::GetJString(env, juniform)));
|
|
||||||
#else
|
|
||||||
return static_cast<jboolean>(false);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_setValue(JNIEnv* env, jobject obj,
|
|
||||||
jint index, jstring juniform,
|
|
||||||
jint component, jfloat value) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (component < 0 || component >= 4) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const std::string uniform = Common::Android::GetJString(env, juniform);
|
|
||||||
auto& chain = VideoCore::FxChain::Instance();
|
|
||||||
const auto slot = static_cast<size_t>(index);
|
|
||||||
|
|
||||||
auto current = chain.GetValue(slot, uniform);
|
|
||||||
if (!chain.HasValue(slot, uniform)) {
|
|
||||||
current = DefaultValueOf(slot, uniform);
|
|
||||||
}
|
|
||||||
|
|
||||||
current[static_cast<size_t>(component)] = value;
|
|
||||||
chain.SetValue(slot, uniform, current);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_store(JNIEnv* env, jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::FxChain::Instance().StoreToSettings();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_reload(JNIEnv* env, jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
VideoCore::ReloadFxCatalog();
|
|
||||||
VideoCore::FxChain::Instance().DropUnknownEntries();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_utils_NativePostProcessing_getShaderDirectory(JNIEnv* env,
|
|
||||||
jobject obj) {
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
return Common::Android::ToJString(env, VideoCore::GetFxRootDirectory().string());
|
|
||||||
#else
|
|
||||||
return Common::Android::ToJString(env, "");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // extern "C"
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:width="24dp"
|
|
||||||
android:height="24dp"
|
|
||||||
android:viewportWidth="24"
|
|
||||||
android:viewportHeight="24">
|
|
||||||
<path
|
|
||||||
android:fillColor="?attr/colorControlNormal"
|
|
||||||
android:fillType="evenOdd"
|
|
||||||
android:pathData="M8.5,3 L19.4,3 Q21,3 21,4.6 L21,16.5 L19.4,16.5 L19.4,4.6 L8.5,4.6 Z M5,7 L15,7 Q17,7 17,9 L17,19 Q17,21 15,21 L5,21 Q3,21 3,19 L3,9 Q3,7 5,7 Z M5.2,8.6 L14.8,8.6 Q15.4,8.6 15.4,9.2 L15.4,18.8 Q15.4,19.4 14.8,19.4 L5.2,19.4 Q4.6,19.4 4.6,18.8 L4.6,9.2 Q4.6,8.6 5.2,8.6 Z M10,10.9 A3.1,3.1 0 0 1 10,17.1 Z"/>
|
|
||||||
</vector>
|
|
||||||
@@ -800,6 +800,7 @@
|
|||||||
<string name="theme_mode_dark">تاریک</string>
|
<string name="theme_mode_dark">تاریک</string>
|
||||||
|
|
||||||
<!-- Audio output engines -->
|
<!-- Audio output engines -->
|
||||||
|
<string name="oboe">oboe</string>
|
||||||
<string name="cubeb">cubeb</string>
|
<string name="cubeb">cubeb</string>
|
||||||
|
|
||||||
<!-- Anisotropic filtering options -->
|
<!-- Anisotropic filtering options -->
|
||||||
|
|||||||
@@ -465,13 +465,13 @@
|
|||||||
|
|
||||||
<string-array name="outputEngineEntries">
|
<string-array name="outputEngineEntries">
|
||||||
<item>@string/auto</item>
|
<item>@string/auto</item>
|
||||||
<item>@string/sdl3</item>
|
<item>@string/oboe</item>
|
||||||
<item>@string/cubeb</item>
|
<item>@string/cubeb</item>
|
||||||
<item>@string/string_null</item>
|
<item>@string/string_null</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<integer-array name="outputEngineValues">
|
<integer-array name="outputEngineValues">
|
||||||
<item>0</item>
|
<item>0</item>
|
||||||
<item>2</item>
|
<item>4</item>
|
||||||
<item>1</item>
|
<item>1</item>
|
||||||
<item>3</item>
|
<item>3</item>
|
||||||
</integer-array>
|
</integer-array>
|
||||||
|
|||||||
@@ -298,18 +298,6 @@
|
|||||||
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
<string name="gpu_driver_fetcher">GPU driver fetcher</string>
|
||||||
<string name="gpu_driver_manager">GPU driver manager</string>
|
<string name="gpu_driver_manager">GPU driver manager</string>
|
||||||
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
<string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
|
||||||
<string name="post_processing">Post-Processing Effects</string>
|
|
||||||
<string name="post_processing_description">ReShade FX effects applied after rendering</string>
|
|
||||||
<string name="post_processing_per_game_description">Configure the effect chain for this game</string>
|
|
||||||
<string name="post_processing_effect">Effect</string>
|
|
||||||
<string name="post_processing_add">Add effect</string>
|
|
||||||
<string name="post_processing_remove">Remove</string>
|
|
||||||
<string name="post_processing_move_up">Move up</string>
|
|
||||||
<string name="post_processing_move_down">Move down</string>
|
|
||||||
<string name="post_processing_reset">Reset to defaults</string>
|
|
||||||
<string name="post_processing_reload">Reload from disk</string>
|
|
||||||
<string name="post_processing_reload_description">Rescan the shader folder for .fx files</string>
|
|
||||||
<string name="post_processing_empty">No effects found. Place .fx files in this folder:</string>
|
|
||||||
<string name="frame_gen">Frame generation</string>
|
<string name="frame_gen">Frame generation</string>
|
||||||
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
<string name="frame_gen_per_game_description">Configure frame generation for this game</string>
|
||||||
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
<string name="frame_gen_description">Insert interpolated frames between rendered ones using Lossless Scaling. Forces FIFO presentation while enabled.</string>
|
||||||
@@ -1252,7 +1240,7 @@
|
|||||||
<string name="theme_mode_dark">Dark</string>
|
<string name="theme_mode_dark">Dark</string>
|
||||||
|
|
||||||
<!-- Audio output engines -->
|
<!-- Audio output engines -->
|
||||||
<string name="sdl3" translatable="false">SDL3</string>
|
<string name="oboe" translatable="false">oboe</string>
|
||||||
<string name="cubeb" translatable="false">cubeb</string>
|
<string name="cubeb" translatable="false">cubeb</string>
|
||||||
|
|
||||||
<!-- Anisotropic filtering options -->
|
<!-- Anisotropic filtering options -->
|
||||||
|
|||||||
@@ -238,11 +238,26 @@ if (ENABLE_CUBEB)
|
|||||||
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
target_compile_definitions(audio_core PRIVATE HAVE_CUBEB=1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_sources(audio_core PRIVATE
|
if(ANDROID)
|
||||||
sink/sdl3_sink.cpp
|
target_sources(audio_core PRIVATE
|
||||||
sink/sdl3_sink.h)
|
sink/oboe_sink.cpp
|
||||||
|
sink/oboe_sink.h)
|
||||||
|
|
||||||
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
target_link_libraries(audio_core PRIVATE oboe)
|
||||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
target_compile_definitions(audio_core PUBLIC HAVE_OBOE)
|
||||||
|
else()
|
||||||
|
target_sources(audio_core PRIVATE
|
||||||
|
sink/sdl3_sink.cpp
|
||||||
|
sink/sdl3_sink.h)
|
||||||
|
|
||||||
|
target_link_libraries(audio_core PRIVATE SDL3::SDL3)
|
||||||
|
target_compile_definitions(audio_core PRIVATE HAVE_SDL3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(OPENORBIS)
|
||||||
|
target_sources(audio_core PRIVATE
|
||||||
|
sink/ps4_sink.cpp
|
||||||
|
sink/ps4_sink.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(audio_core)
|
create_target_directory_groups(audio_core)
|
||||||
|
|||||||
@@ -0,0 +1,230 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <oboe/Oboe.h>
|
||||||
|
|
||||||
|
#include "audio_core/common/common.h"
|
||||||
|
#include "audio_core/sink/oboe_sink.h"
|
||||||
|
#include "audio_core/sink/sink_stream.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
|
class OboeSinkStream final : public SinkStream,
|
||||||
|
public oboe::AudioStreamDataCallback,
|
||||||
|
public oboe::AudioStreamErrorCallback {
|
||||||
|
public:
|
||||||
|
explicit OboeSinkStream(Core::System& system_, StreamType type_, const std::string& name_,
|
||||||
|
u32 system_channels_)
|
||||||
|
: SinkStream(system_, type_) {
|
||||||
|
name = name_;
|
||||||
|
system_channels = system_channels_;
|
||||||
|
|
||||||
|
this->OpenStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
~OboeSinkStream() override {
|
||||||
|
LOG_INFO(Audio_Sink, "Destroyed Oboe stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() override {
|
||||||
|
this->Stop();
|
||||||
|
m_stream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(bool resume = false) override {
|
||||||
|
if (!m_stream || !paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
paused = false;
|
||||||
|
|
||||||
|
if (m_stream->start() != oboe::Result::OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error starting Oboe stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop() override {
|
||||||
|
if (!m_stream || paused) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->SignalPause();
|
||||||
|
|
||||||
|
if (m_stream->stop() != oboe::Result::OK) {
|
||||||
|
LOG_CRITICAL(Audio_Sink, "Error stopping Oboe stream");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
static s32 QueryChannelCount(oboe::Direction direction) {
|
||||||
|
std::shared_ptr<oboe::AudioStream> temp_stream;
|
||||||
|
oboe::AudioStreamBuilder builder;
|
||||||
|
|
||||||
|
const auto result = ConfigureBuilder(builder, direction)->openStream(temp_stream);
|
||||||
|
if (result == oboe::Result::OK) {
|
||||||
|
return temp_stream->getChannelCount() >= 6 ? 6 : 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERROR(Audio_Sink, "Failed to open {} stream. Using default channel count 2",
|
||||||
|
direction == oboe::Direction::Output ? "output" : "input");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
oboe::DataCallbackResult onAudioReady(oboe::AudioStream*, void* audio_data,
|
||||||
|
s32 num_buffer_frames) override {
|
||||||
|
const size_t num_channels = this->GetDeviceChannels();
|
||||||
|
const size_t frame_size = num_channels;
|
||||||
|
const size_t num_frames = static_cast<size_t>(num_buffer_frames);
|
||||||
|
|
||||||
|
if (type == StreamType::In) {
|
||||||
|
std::span<const s16> input_buffer{reinterpret_cast<const s16*>(audio_data),
|
||||||
|
num_frames * frame_size};
|
||||||
|
this->ProcessAudioIn(input_buffer, num_frames);
|
||||||
|
} else {
|
||||||
|
std::span<s16> output_buffer{reinterpret_cast<s16*>(audio_data),
|
||||||
|
num_frames * frame_size};
|
||||||
|
this->ProcessAudioOutAndRender(output_buffer, num_frames);
|
||||||
|
}
|
||||||
|
|
||||||
|
return oboe::DataCallbackResult::Continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void onErrorAfterClose(oboe::AudioStream*, oboe::Result) override {
|
||||||
|
LOG_INFO(Audio_Sink, "Audio stream closed, reinitializing");
|
||||||
|
|
||||||
|
if (this->OpenStream()) {
|
||||||
|
m_stream->start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static oboe::AudioStreamBuilder* ConfigureBuilder(oboe::AudioStreamBuilder& builder,
|
||||||
|
oboe::Direction direction) {
|
||||||
|
// TODO: investigate callback delay issues when using AAudio
|
||||||
|
return builder.setPerformanceMode(oboe::PerformanceMode::LowLatency)
|
||||||
|
->setAudioApi(oboe::AudioApi::OpenSLES)
|
||||||
|
->setDirection(direction)
|
||||||
|
->setSampleRate(TargetSampleRate)
|
||||||
|
->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::High)
|
||||||
|
->setFormat(oboe::AudioFormat::I16)
|
||||||
|
->setFormatConversionAllowed(true)
|
||||||
|
->setUsage(oboe::Usage::Game)
|
||||||
|
->setBufferCapacityInFrames(TargetSampleCount * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenStream() {
|
||||||
|
const auto direction = [&]() {
|
||||||
|
switch (type) {
|
||||||
|
case StreamType::In:
|
||||||
|
return oboe::Direction::Input;
|
||||||
|
case StreamType::Out:
|
||||||
|
case StreamType::Render:
|
||||||
|
return oboe::Direction::Output;
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
return oboe::Direction::Output;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
const auto expected_channels = QueryChannelCount(direction);
|
||||||
|
const auto expected_mask = [&]() {
|
||||||
|
switch (expected_channels) {
|
||||||
|
case 1:
|
||||||
|
return oboe::ChannelMask::Mono;
|
||||||
|
case 2:
|
||||||
|
return oboe::ChannelMask::Stereo;
|
||||||
|
case 6:
|
||||||
|
return oboe::ChannelMask::CM5Point1;
|
||||||
|
default:
|
||||||
|
ASSERT(false);
|
||||||
|
return oboe::ChannelMask::Unspecified;
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
oboe::AudioStreamBuilder builder;
|
||||||
|
const auto result = ConfigureBuilder(builder, direction)
|
||||||
|
->setChannelCount(expected_channels)
|
||||||
|
->setChannelMask(expected_mask)
|
||||||
|
->setChannelConversionAllowed(true)
|
||||||
|
->setDataCallback(this)
|
||||||
|
->setErrorCallback(this)
|
||||||
|
->openStream(m_stream);
|
||||||
|
ASSERT(result == oboe::Result::OK);
|
||||||
|
return result == oboe::Result::OK && this->SetStreamProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SetStreamProperties() {
|
||||||
|
ASSERT(m_stream);
|
||||||
|
|
||||||
|
m_stream->setBufferSizeInFrames(TargetSampleCount * 2);
|
||||||
|
device_channels = m_stream->getChannelCount();
|
||||||
|
|
||||||
|
const auto sample_rate = m_stream->getSampleRate();
|
||||||
|
const auto buffer_capacity = m_stream->getBufferCapacityInFrames();
|
||||||
|
const auto stream_backend =
|
||||||
|
m_stream->getAudioApi() == oboe::AudioApi::AAudio ? "AAudio" : "OpenSLES";
|
||||||
|
|
||||||
|
LOG_INFO(Audio_Sink, "Opened Oboe {} stream with {} channels sample rate {} capacity {}",
|
||||||
|
stream_backend, device_channels, sample_rate, buffer_capacity);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<oboe::AudioStream> m_stream{};
|
||||||
|
};
|
||||||
|
|
||||||
|
OboeSink::OboeSink() {
|
||||||
|
// TODO: This is not generally knowable
|
||||||
|
// The channel count is distinct based on direction and can change
|
||||||
|
device_channels = OboeSinkStream::QueryChannelCount(oboe::Direction::Output);
|
||||||
|
}
|
||||||
|
|
||||||
|
OboeSink::~OboeSink() = default;
|
||||||
|
|
||||||
|
SinkStream* OboeSink::AcquireSinkStream(Core::System& system, u32 system_channels,
|
||||||
|
const std::string& name, StreamType type) {
|
||||||
|
SinkStreamPtr& stream = sink_streams.emplace_back(
|
||||||
|
std::make_unique<OboeSinkStream>(system, type, name, system_channels));
|
||||||
|
|
||||||
|
return stream.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OboeSink::CloseStream(SinkStream* to_remove) {
|
||||||
|
sink_streams.remove_if([&](auto& stream) { return stream.get() == to_remove; });
|
||||||
|
}
|
||||||
|
|
||||||
|
void OboeSink::CloseStreams() {
|
||||||
|
sink_streams.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 OboeSink::GetDeviceVolume() const {
|
||||||
|
if (sink_streams.empty()) {
|
||||||
|
return 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sink_streams.front()->GetDeviceVolume();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OboeSink::SetDeviceVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams) {
|
||||||
|
stream->SetDeviceVolume(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OboeSink::SetSystemVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams) {
|
||||||
|
stream->SetSystemVolume(volume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "audio_core/sink/sink.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
class SinkStream;
|
||||||
|
|
||||||
|
class OboeSink final : public Sink {
|
||||||
|
public:
|
||||||
|
explicit OboeSink();
|
||||||
|
~OboeSink() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new sink stream.
|
||||||
|
*
|
||||||
|
* @param system - Core system.
|
||||||
|
* @param system_channels - Number of channels the audio system expects.
|
||||||
|
* May differ from the device's channel count.
|
||||||
|
* @param name - Name of this stream.
|
||||||
|
* @param type - Type of this stream, render/in/out.
|
||||||
|
*
|
||||||
|
* @return A pointer to the created SinkStream
|
||||||
|
*/
|
||||||
|
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels,
|
||||||
|
const std::string& name, StreamType type) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close a given stream.
|
||||||
|
*
|
||||||
|
* @param stream - The stream to close.
|
||||||
|
*/
|
||||||
|
void CloseStream(SinkStream* stream) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close all streams.
|
||||||
|
*/
|
||||||
|
void CloseStreams() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the device volume. Set from calls to the IAudioDevice service.
|
||||||
|
*
|
||||||
|
* @return Volume of the device.
|
||||||
|
*/
|
||||||
|
f32 GetDeviceVolume() const override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the device volume. Set from calls to the IAudioDevice service.
|
||||||
|
*
|
||||||
|
* @param volume - New volume of the device.
|
||||||
|
*/
|
||||||
|
void SetDeviceVolume(f32 volume) override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the system volume. Comes from the audio system using this stream.
|
||||||
|
*
|
||||||
|
* @param volume - New volume of the system.
|
||||||
|
*/
|
||||||
|
void SetSystemVolume(f32 volume) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/// List of streams managed by this sink
|
||||||
|
std::list<SinkStreamPtr> sink_streams{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include <span>
|
||||||
|
#include <stop_token>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <orbis/AudioOut.h>
|
||||||
|
|
||||||
|
#include "audio_core/common/common.h"
|
||||||
|
#include "audio_core/sink/ps4_sink.h"
|
||||||
|
#include "audio_core/sink/sink_stream.h"
|
||||||
|
#include "common/alignment.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
#include "common/scope_exit.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
|
||||||
|
/// @brief PS4 sink stream, responsible for sinking samples to hardware.
|
||||||
|
struct PS4SinkStream final : public SinkStream {
|
||||||
|
/// @brief Create a new sink stream.
|
||||||
|
/// @param device_channels_ - Number of channels supported by the hardware.
|
||||||
|
/// @param system_channels_ - Number of channels the audio systems expect.
|
||||||
|
/// @param output_device - Name of the output device to use for this stream.
|
||||||
|
/// @param input_device - Name of the input device to use for this stream.
|
||||||
|
/// @param type_ - Type of this stream.
|
||||||
|
/// @param system_ - Core system.
|
||||||
|
/// @param event - Event used only for audio renderer, signalled on buffer consume.
|
||||||
|
PS4SinkStream(u32 device_channels_, u32 system_channels_, const std::string& output_device, const std::string& input_device, StreamType type_, Core::System& system_)
|
||||||
|
: SinkStream{system_, type_}
|
||||||
|
{
|
||||||
|
system_channels = system_channels_;
|
||||||
|
device_channels = device_channels_;
|
||||||
|
|
||||||
|
constexpr size_t PREFERRED_SAMPLE_COUNT = 1024;
|
||||||
|
auto const param = (device_channels > 1 ? ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_STEREO : ORBIS_AUDIO_OUT_PARAM_FORMAT_S16_MONO);
|
||||||
|
audio_dev = sceAudioOutOpen(ORBIS_USER_SERVICE_USER_ID_SYSTEM, ORBIS_AUDIO_OUT_PORT_TYPE_MAIN, 0, PREFERRED_SAMPLE_COUNT, TargetSampleRate, param);
|
||||||
|
if (audio_dev > 0) {
|
||||||
|
audio_thread = std::jthread([=, this](std::stop_token stop_token) {
|
||||||
|
std::array<s16, PREFERRED_SAMPLE_COUNT * MaxChannels> buffer;
|
||||||
|
while (!stop_token.stop_requested()) {
|
||||||
|
if (this->type == StreamType::In) {
|
||||||
|
this->ProcessAudioIn(buffer, PREFERRED_SAMPLE_COUNT);
|
||||||
|
(void)buffer; // TODO: microphone support
|
||||||
|
} else {
|
||||||
|
int err = 0;
|
||||||
|
std::fill(buffer.begin(), buffer.end(), 0);
|
||||||
|
this->ProcessAudioOutAndRender(buffer, PREFERRED_SAMPLE_COUNT);
|
||||||
|
sceAudioOutOutput(audio_dev, nullptr);
|
||||||
|
if ((err = sceAudioOutOutput(audio_dev, buffer.data())) < 0)
|
||||||
|
LOG_ERROR(Service_Audio, "{}", err);
|
||||||
|
}
|
||||||
|
// Wait for pause, we don't really have a native pause
|
||||||
|
// so this is the best i can do
|
||||||
|
while (paused && !stop_token.stop_requested())
|
||||||
|
asm volatile ("pause"); //dont shootup cpu usage to 100%
|
||||||
|
}
|
||||||
|
sceAudioOutClose(audio_dev);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_Audio, "Failed to create audio device! {:#x}", uint32_t(audio_dev));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~PS4SinkStream() override {
|
||||||
|
LOG_DEBUG(Service_Audio, "Destroying PS4 stream {}", name);
|
||||||
|
if (audio_thread.joinable()) {
|
||||||
|
audio_thread.request_stop();
|
||||||
|
audio_thread.join();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finalize() override {
|
||||||
|
if (audio_dev > 0) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Start(bool resume = false) override {
|
||||||
|
if (audio_dev > 0 && paused) {
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Stop() override {
|
||||||
|
if (audio_dev > 0 && !paused) {
|
||||||
|
SignalPause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::jthread audio_thread;
|
||||||
|
int32_t audio_dev{};
|
||||||
|
};
|
||||||
|
|
||||||
|
PS4Sink::PS4Sink(std::string_view target_device_name) {
|
||||||
|
int32_t rc = sceAudioOutInit();
|
||||||
|
if (rc == 0 || unsigned(rc) == ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
|
||||||
|
if (target_device_name != auto_device_name && !target_device_name.empty()) {
|
||||||
|
output_device = target_device_name;
|
||||||
|
} else {
|
||||||
|
output_device.clear();
|
||||||
|
}
|
||||||
|
device_channels = 2;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_Audio, "Unable to open audio out! {:#x}", uint32_t(rc));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PS4Sink::~PS4Sink() = default;
|
||||||
|
|
||||||
|
/// @brief Create a new sink stream.
|
||||||
|
/// @param system - Core system.
|
||||||
|
/// @param system_channels - Number of channels the audio system expects. May differ from the device's channel count.
|
||||||
|
/// @param name - Name of this stream.
|
||||||
|
/// @param type - Type of this stream, render/in/out.
|
||||||
|
/// @return A pointer to the created SinkStream
|
||||||
|
SinkStream* PS4Sink::AcquireSinkStream(Core::System& system, u32 system_channels_, const std::string&, StreamType type) {
|
||||||
|
system_channels = system_channels_;
|
||||||
|
SinkStreamPtr& stream = sink_streams.emplace_back(std::make_unique<PS4SinkStream>(device_channels, system_channels, output_device, input_device, type, system));
|
||||||
|
return stream.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::CloseStream(SinkStream* stream) {
|
||||||
|
for (size_t i = 0; i < sink_streams.size(); i++) {
|
||||||
|
if (sink_streams[i].get() == stream) {
|
||||||
|
sink_streams[i].reset();
|
||||||
|
sink_streams.erase(sink_streams.begin() + i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::CloseStreams() {
|
||||||
|
sink_streams.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
f32 PS4Sink::GetDeviceVolume() const {
|
||||||
|
return sink_streams.size() > 0 ? sink_streams[0]->GetDeviceVolume() : 1.f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::SetDeviceVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams)
|
||||||
|
stream->SetDeviceVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PS4Sink::SetSystemVolume(f32 volume) {
|
||||||
|
for (auto& stream : sink_streams)
|
||||||
|
stream->SetSystemVolume(volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> ListPS4SinkDevices(bool capture) {
|
||||||
|
return {{"Default"}};
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetPS4Latency() {
|
||||||
|
return TargetSampleCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "audio_core/sink/sink.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace AudioCore::Sink {
|
||||||
|
class SinkStream;
|
||||||
|
|
||||||
|
/// @brief PS4 backend sink, holds multiple output streams and is responsible for sinking samples to
|
||||||
|
/// hardware. Used by Audio Render, Audio In and Audio Out.
|
||||||
|
struct PS4Sink final : public Sink {
|
||||||
|
explicit PS4Sink(std::string_view device_id);
|
||||||
|
~PS4Sink() override;
|
||||||
|
SinkStream* AcquireSinkStream(Core::System& system, u32 system_channels, const std::string& name, StreamType type) override;
|
||||||
|
void CloseStream(SinkStream* stream) override;
|
||||||
|
void CloseStreams() override;
|
||||||
|
f32 GetDeviceVolume() const override;
|
||||||
|
void SetDeviceVolume(f32 volume) override;
|
||||||
|
void SetSystemVolume(f32 volume) override;
|
||||||
|
/// Name of the output device used by streams
|
||||||
|
std::string output_device;
|
||||||
|
/// Name of the input device used by streams
|
||||||
|
std::string input_device;
|
||||||
|
/// Vector of streams managed by this sink
|
||||||
|
std::vector<SinkStreamPtr> sink_streams;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> ListPS4SinkDevices(bool capture);
|
||||||
|
u32 GetPS4Latency();
|
||||||
|
|
||||||
|
} // namespace AudioCore::Sink
|
||||||
@@ -10,12 +10,18 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "audio_core/sink/sink_details.h"
|
#include "audio_core/sink/sink_details.h"
|
||||||
|
#ifdef HAVE_OBOE
|
||||||
|
#include "audio_core/sink/oboe_sink.h"
|
||||||
|
#endif
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
#include "audio_core/sink/cubeb_sink.h"
|
#include "audio_core/sink/cubeb_sink.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
#include "audio_core/sink/sdl3_sink.h"
|
#include "audio_core/sink/sdl3_sink.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include "audio_core/sink/ps4_sink.h"
|
||||||
|
#endif
|
||||||
#include "audio_core/sink/null_sink.h"
|
#include "audio_core/sink/null_sink.h"
|
||||||
#include "common/logging.h"
|
#include "common/logging.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
@@ -40,8 +46,34 @@ struct SinkDetails {
|
|||||||
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
|
/// SuitableFn is_suitable; // REVERTED FOR LatencyFn latency ABOVE - DIABLO 3 FIX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// NOTE TO PROBABLY FIX LATER FOR ANDROID - the return value "0u" for the first HAVE_OBOE
|
||||||
|
// section below was just copied from the null section so there's a somewhat valid value
|
||||||
|
// being returned, since the previous "true" value probably isn't compatible with the
|
||||||
|
// previous EA-3833 code. (HAVE_OBOE was introduced in a later release.) Eventually need
|
||||||
|
// to change "0u" for something else directly from the oboe_sink.cpp functions.
|
||||||
|
|
||||||
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
// sink_details is ordered in terms of desirability, with the best choice at the top.
|
||||||
constexpr SinkDetails sink_details[] = {
|
constexpr SinkDetails sink_details[] = {
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
SinkDetails{
|
||||||
|
Settings::AudioEngine::Ps4,
|
||||||
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
|
return std::make_unique<PS4Sink>(device_id);
|
||||||
|
},
|
||||||
|
&ListPS4SinkDevices,
|
||||||
|
&GetPS4Latency,
|
||||||
|
},
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_OBOE
|
||||||
|
SinkDetails{
|
||||||
|
Settings::AudioEngine::Oboe,
|
||||||
|
[](std::string_view device_id) -> std::unique_ptr<Sink> {
|
||||||
|
return std::make_unique<OboeSink>();
|
||||||
|
},
|
||||||
|
[](bool capture) { return std::vector<std::string>{"Default"}; },
|
||||||
|
[]() { return 0u; },
|
||||||
|
},
|
||||||
|
#endif
|
||||||
#ifdef HAVE_CUBEB
|
#ifdef HAVE_CUBEB
|
||||||
SinkDetails{
|
SinkDetails{
|
||||||
Settings::AudioEngine::Cubeb,
|
Settings::AudioEngine::Cubeb,
|
||||||
@@ -96,7 +128,9 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
|
|||||||
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
|
||||||
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
|
||||||
// causes audio issues, in that case go with SDL.
|
// causes audio issues, in that case go with SDL.
|
||||||
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
#if defined(__OPENORBIS__)
|
||||||
|
iter = find_backend(Settings::AudioEngine::Ps4);
|
||||||
|
#elif defined(HAVE_CUBEB) && defined(HAVE_SDL3)
|
||||||
iter = find_backend(Settings::AudioEngine::Cubeb);
|
iter = find_backend(Settings::AudioEngine::Cubeb);
|
||||||
if (iter->latency() > TargetSampleCount * 3) {
|
if (iter->latency() > TargetSampleCount * 3) {
|
||||||
iter = find_backend(Settings::AudioEngine::Sdl3);
|
iter = find_backend(Settings::AudioEngine::Sdl3);
|
||||||
|
|||||||
@@ -230,6 +230,7 @@ if(CXX_CLANG)
|
|||||||
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>)
|
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Has to be BEFORE httplib
|
||||||
if (BOOST_NO_HEADERS)
|
if (BOOST_NO_HEADERS)
|
||||||
target_link_libraries(common PUBLIC Boost::algorithm Boost::heap Boost::icl Boost::pool)
|
target_link_libraries(common PUBLIC Boost::algorithm Boost::heap Boost::icl Boost::pool)
|
||||||
else()
|
else()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// 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
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "android_common.h"
|
#include "android_common.h"
|
||||||
@@ -51,7 +51,7 @@ jstring ToJString(JNIEnv* env, std::u16string_view str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double GetJDouble(JNIEnv* env, jobject jdouble) {
|
double GetJDouble(JNIEnv* env, jobject jdouble) {
|
||||||
return env->CallDoubleMethod(jdouble, GetDoubleValueMethod());
|
return env->GetDoubleField(jdouble, GetDoubleValueField());
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject ToJDouble(JNIEnv* env, double value) {
|
jobject ToJDouble(JNIEnv* env, double value) {
|
||||||
@@ -59,7 +59,7 @@ jobject ToJDouble(JNIEnv* env, double value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
|
s32 GetJInteger(JNIEnv* env, jobject jinteger) {
|
||||||
return env->CallIntMethod(jinteger, GetIntegerValueMethod());
|
return env->GetIntField(jinteger, GetIntegerValueField());
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject ToJInteger(JNIEnv* env, s32 value) {
|
jobject ToJInteger(JNIEnv* env, s32 value) {
|
||||||
@@ -67,7 +67,7 @@ jobject ToJInteger(JNIEnv* env, s32 value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
|
bool GetJBoolean(JNIEnv* env, jobject jboolean) {
|
||||||
return env->CallBooleanMethod(jboolean, GetBooleanValueMethod());
|
return env->GetBooleanField(jboolean, GetBooleanValueField());
|
||||||
}
|
}
|
||||||
|
|
||||||
jobject ToJBoolean(JNIEnv* env, bool value) {
|
jobject ToJBoolean(JNIEnv* env, bool value) {
|
||||||
|
|||||||
+192
-188
@@ -63,15 +63,15 @@ static jfieldID s_patch_title_id_field;
|
|||||||
|
|
||||||
static jclass s_double_class;
|
static jclass s_double_class;
|
||||||
static jmethodID s_double_constructor;
|
static jmethodID s_double_constructor;
|
||||||
static jmethodID s_double_value_method;
|
static jfieldID s_double_value_field;
|
||||||
|
|
||||||
static jclass s_integer_class;
|
static jclass s_integer_class;
|
||||||
static jmethodID s_integer_constructor;
|
static jmethodID s_integer_constructor;
|
||||||
static jmethodID s_integer_value_method;
|
static jfieldID s_integer_value_field;
|
||||||
|
|
||||||
static jclass s_boolean_class;
|
static jclass s_boolean_class;
|
||||||
static jmethodID s_boolean_constructor;
|
static jmethodID s_boolean_constructor;
|
||||||
static jmethodID s_boolean_value_method;
|
static jfieldID s_boolean_value_field;
|
||||||
|
|
||||||
static jclass s_player_input_class;
|
static jclass s_player_input_class;
|
||||||
static jmethodID s_player_input_constructor;
|
static jmethodID s_player_input_constructor;
|
||||||
@@ -103,6 +103,7 @@ static jmethodID s_clear_chat;
|
|||||||
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
static constexpr jint JNI_VERSION = JNI_VERSION_1_6;
|
||||||
|
|
||||||
namespace Common::Android {
|
namespace Common::Android {
|
||||||
|
|
||||||
JNIEnv *GetEnvForThread() {
|
JNIEnv *GetEnvForThread() {
|
||||||
thread_local static struct OwnedEnv {
|
thread_local static struct OwnedEnv {
|
||||||
OwnedEnv() {
|
OwnedEnv() {
|
||||||
@@ -298,8 +299,8 @@ namespace Common::Android {
|
|||||||
return s_double_constructor;
|
return s_double_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetDoubleValueMethod() {
|
jfieldID GetDoubleValueField() {
|
||||||
return s_double_value_method;
|
return s_double_value_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetIntegerClass() {
|
jclass GetIntegerClass() {
|
||||||
@@ -310,8 +311,8 @@ namespace Common::Android {
|
|||||||
return s_integer_constructor;
|
return s_integer_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetIntegerValueMethod() {
|
jfieldID GetIntegerValueField() {
|
||||||
return s_integer_value_method;
|
return s_integer_value_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetBooleanClass() {
|
jclass GetBooleanClass() {
|
||||||
@@ -322,8 +323,8 @@ namespace Common::Android {
|
|||||||
return s_boolean_constructor;
|
return s_boolean_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
jmethodID GetBooleanValueMethod() {
|
jfieldID GetBooleanValueField() {
|
||||||
return s_boolean_value_method;
|
return s_boolean_value_field;
|
||||||
}
|
}
|
||||||
|
|
||||||
jclass GetPlayerInputClass() {
|
jclass GetPlayerInputClass() {
|
||||||
@@ -428,6 +429,188 @@ namespace Common::Android {
|
|||||||
|
|
||||||
jint InitFFmpegOnLoad(JavaVM *vm);
|
jint InitFFmpegOnLoad(JavaVM *vm);
|
||||||
|
|
||||||
|
jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
|
s_java_vm = vm;
|
||||||
|
InitFFmpegOnLoad(vm);
|
||||||
|
|
||||||
|
JNIEnv *env;
|
||||||
|
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK)
|
||||||
|
return JNI_ERR;
|
||||||
|
|
||||||
|
// Initialize Java classes
|
||||||
|
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
||||||
|
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
||||||
|
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
||||||
|
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
||||||
|
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
||||||
|
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
||||||
|
|
||||||
|
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
||||||
|
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
||||||
|
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
||||||
|
"(Ljava/lang/String;Z)V");
|
||||||
|
env->DeleteLocalRef(game_dir_class);
|
||||||
|
|
||||||
|
// Initialize methods
|
||||||
|
s_exit_emulation_activity =
|
||||||
|
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
||||||
|
s_disk_cache_load_progress =
|
||||||
|
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
|
||||||
|
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
||||||
|
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
|
||||||
|
"(Ljava/lang/String;)Z");
|
||||||
|
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
|
||||||
|
"(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
|
s_on_emulation_started =
|
||||||
|
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
||||||
|
s_on_emulation_stopped =
|
||||||
|
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
||||||
|
s_on_program_changed =
|
||||||
|
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
||||||
|
|
||||||
|
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
||||||
|
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
||||||
|
s_game_constructor = env->GetMethodID(game_class, "<init>",
|
||||||
|
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
||||||
|
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
||||||
|
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
||||||
|
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
||||||
|
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
||||||
|
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
||||||
|
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
||||||
|
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
||||||
|
env->DeleteLocalRef(game_class);
|
||||||
|
|
||||||
|
const jclass string_class = env->FindClass("java/lang/String");
|
||||||
|
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
||||||
|
env->DeleteLocalRef(string_class);
|
||||||
|
|
||||||
|
const jclass pair_class = env->FindClass("kotlin/Pair");
|
||||||
|
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
||||||
|
s_pair_constructor =
|
||||||
|
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
||||||
|
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
||||||
|
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
||||||
|
env->DeleteLocalRef(pair_class);
|
||||||
|
|
||||||
|
const jclass overlay_control_data_class =
|
||||||
|
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
||||||
|
s_overlay_control_data_class =
|
||||||
|
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
||||||
|
s_overlay_control_data_constructor =
|
||||||
|
env->GetMethodID(overlay_control_data_class, "<init>",
|
||||||
|
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
||||||
|
s_overlay_control_data_id_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
||||||
|
s_overlay_control_data_enabled_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
||||||
|
s_overlay_control_data_landscape_position_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
||||||
|
s_overlay_control_data_portrait_position_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
||||||
|
s_overlay_control_data_foldable_position_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
||||||
|
s_overlay_control_data_individual_scale_field =
|
||||||
|
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
||||||
|
env->DeleteLocalRef(overlay_control_data_class);
|
||||||
|
|
||||||
|
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
||||||
|
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||||
|
s_patch_constructor = env->GetMethodID(
|
||||||
|
patch_class, "<init>",
|
||||||
|
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
||||||
|
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||||
|
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||||
|
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||||
|
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
||||||
|
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
||||||
|
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
||||||
|
env->DeleteLocalRef(patch_class);
|
||||||
|
|
||||||
|
const jclass double_class = env->FindClass("java/lang/Double");
|
||||||
|
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
||||||
|
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
||||||
|
s_double_value_field = env->GetFieldID(double_class, "value", "D");
|
||||||
|
env->DeleteLocalRef(double_class);
|
||||||
|
|
||||||
|
const jclass int_class = env->FindClass("java/lang/Integer");
|
||||||
|
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
||||||
|
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
||||||
|
s_integer_value_field = env->GetFieldID(int_class, "value", "I");
|
||||||
|
env->DeleteLocalRef(int_class);
|
||||||
|
|
||||||
|
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
||||||
|
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
||||||
|
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
||||||
|
s_boolean_value_field = env->GetFieldID(boolean_class, "value", "Z");
|
||||||
|
env->DeleteLocalRef(boolean_class);
|
||||||
|
|
||||||
|
const jclass player_input_class =
|
||||||
|
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
||||||
|
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
||||||
|
s_player_input_constructor = env->GetMethodID(
|
||||||
|
player_input_class, "<init>",
|
||||||
|
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
||||||
|
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
||||||
|
s_player_input_buttons_field =
|
||||||
|
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
||||||
|
s_player_input_analogs_field =
|
||||||
|
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
||||||
|
s_player_input_motions_field =
|
||||||
|
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
||||||
|
s_player_input_vibration_enabled_field =
|
||||||
|
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
||||||
|
s_player_input_vibration_strength_field =
|
||||||
|
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
||||||
|
s_player_input_body_color_left_field =
|
||||||
|
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
||||||
|
s_player_input_body_color_right_field =
|
||||||
|
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
||||||
|
s_player_input_button_color_left_field =
|
||||||
|
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
||||||
|
s_player_input_button_color_right_field =
|
||||||
|
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
||||||
|
s_player_input_profile_name_field =
|
||||||
|
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
||||||
|
s_player_input_use_system_vibrator_field =
|
||||||
|
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
||||||
|
env->DeleteLocalRef(player_input_class);
|
||||||
|
|
||||||
|
const jclass yuzu_input_device_interface =
|
||||||
|
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
||||||
|
s_yuzu_input_device_interface =
|
||||||
|
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
||||||
|
s_yuzu_input_device_get_name =
|
||||||
|
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
||||||
|
s_yuzu_input_device_get_guid =
|
||||||
|
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
||||||
|
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
||||||
|
"()I");
|
||||||
|
s_yuzu_input_device_get_supports_vibration =
|
||||||
|
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
||||||
|
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
||||||
|
"(F)V");
|
||||||
|
s_yuzu_input_device_get_axes =
|
||||||
|
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
||||||
|
s_yuzu_input_device_has_keys =
|
||||||
|
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
||||||
|
env->DeleteLocalRef(yuzu_input_device_interface);
|
||||||
|
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
|
||||||
|
"(ILjava/lang/String;)V");
|
||||||
|
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize Android Storage
|
||||||
|
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
||||||
|
|
||||||
|
// Initialize applets
|
||||||
|
Common::Android::SoftwareKeyboard::InitJNI(env);
|
||||||
|
Common::Android::WebBrowser::InitJNI(env);
|
||||||
|
|
||||||
|
return JNI_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
void JNI_OnUnload(JavaVM *vm, void *reserved) {
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
|
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION) != JNI_OK) {
|
||||||
@@ -462,183 +645,4 @@ namespace Common::Android {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Initialize(JavaVM* vm, JNIEnv *env) {
|
|
||||||
s_java_vm = vm;
|
|
||||||
InitFFmpegOnLoad(vm);
|
|
||||||
|
|
||||||
if (env->ExceptionCheck()) {
|
|
||||||
env->ExceptionClear();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize Java classes
|
|
||||||
const jclass native_library_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary");
|
|
||||||
s_native_library_class = reinterpret_cast<jclass>(env->NewGlobalRef(native_library_class));
|
|
||||||
s_disk_cache_progress_class = reinterpret_cast<jclass>(env->NewGlobalRef(
|
|
||||||
env->FindClass("org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress")));
|
|
||||||
s_load_callback_stage_class = reinterpret_cast<jclass>(env->NewGlobalRef(env->FindClass(
|
|
||||||
"org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress$LoadCallbackStage")));
|
|
||||||
|
|
||||||
const jclass game_dir_class = env->FindClass("org/yuzu/yuzu_emu/model/GameDir");
|
|
||||||
s_game_dir_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_dir_class));
|
|
||||||
s_game_dir_constructor = env->GetMethodID(game_dir_class, "<init>",
|
|
||||||
"(Ljava/lang/String;Z)V");
|
|
||||||
env->DeleteLocalRef(game_dir_class);
|
|
||||||
|
|
||||||
// Initialize methods
|
|
||||||
s_exit_emulation_activity =
|
|
||||||
env->GetStaticMethodID(s_native_library_class, "exitEmulationActivity", "(I)V");
|
|
||||||
s_disk_cache_load_progress =
|
|
||||||
env->GetStaticMethodID(s_disk_cache_progress_class, "loadProgress", "(III)V");
|
|
||||||
s_copy_to_storage = env->GetStaticMethodID(s_native_library_class, "copyFileToStorage",
|
|
||||||
"(Ljava/lang/String;Ljava/lang/String;)Z");
|
|
||||||
s_file_exists = env->GetStaticMethodID(s_native_library_class, "exists",
|
|
||||||
"(Ljava/lang/String;)Z");
|
|
||||||
s_file_extension = env->GetStaticMethodID(s_native_library_class, "getFileExtension",
|
|
||||||
"(Ljava/lang/String;)Ljava/lang/String;");
|
|
||||||
s_on_emulation_started =
|
|
||||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStarted", "()V");
|
|
||||||
s_on_emulation_stopped =
|
|
||||||
env->GetStaticMethodID(s_native_library_class, "onEmulationStopped", "(I)V");
|
|
||||||
s_on_program_changed =
|
|
||||||
env->GetStaticMethodID(s_native_library_class, "onProgramChanged", "(I)V");
|
|
||||||
|
|
||||||
const jclass game_class = env->FindClass("org/yuzu/yuzu_emu/model/Game");
|
|
||||||
s_game_class = reinterpret_cast<jclass>(env->NewGlobalRef(game_class));
|
|
||||||
s_game_constructor = env->GetMethodID(game_class, "<init>",
|
|
||||||
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
|
|
||||||
"String;Ljava/lang/String;Ljava/lang/String;Z)V");
|
|
||||||
s_game_title_field = env->GetFieldID(game_class, "title", "Ljava/lang/String;");
|
|
||||||
s_game_path_field = env->GetFieldID(game_class, "path", "Ljava/lang/String;");
|
|
||||||
s_game_program_id_field = env->GetFieldID(game_class, "programId", "Ljava/lang/String;");
|
|
||||||
s_game_developer_field = env->GetFieldID(game_class, "developer", "Ljava/lang/String;");
|
|
||||||
s_game_version_field = env->GetFieldID(game_class, "version", "Ljava/lang/String;");
|
|
||||||
s_game_is_homebrew_field = env->GetFieldID(game_class, "isHomebrew", "Z");
|
|
||||||
env->DeleteLocalRef(game_class);
|
|
||||||
|
|
||||||
const jclass string_class = env->FindClass("java/lang/String");
|
|
||||||
s_string_class = reinterpret_cast<jclass>(env->NewGlobalRef(string_class));
|
|
||||||
env->DeleteLocalRef(string_class);
|
|
||||||
|
|
||||||
const jclass pair_class = env->FindClass("kotlin/Pair");
|
|
||||||
s_pair_class = reinterpret_cast<jclass>(env->NewGlobalRef(pair_class));
|
|
||||||
s_pair_constructor =
|
|
||||||
env->GetMethodID(pair_class, "<init>", "(Ljava/lang/Object;Ljava/lang/Object;)V");
|
|
||||||
s_pair_first_field = env->GetFieldID(pair_class, "first", "Ljava/lang/Object;");
|
|
||||||
s_pair_second_field = env->GetFieldID(pair_class, "second", "Ljava/lang/Object;");
|
|
||||||
env->DeleteLocalRef(pair_class);
|
|
||||||
|
|
||||||
const jclass overlay_control_data_class =
|
|
||||||
env->FindClass("org/yuzu/yuzu_emu/overlay/model/OverlayControlData");
|
|
||||||
s_overlay_control_data_class =
|
|
||||||
reinterpret_cast<jclass>(env->NewGlobalRef(overlay_control_data_class));
|
|
||||||
s_overlay_control_data_constructor =
|
|
||||||
env->GetMethodID(overlay_control_data_class, "<init>",
|
|
||||||
"(Ljava/lang/String;ZLkotlin/Pair;Lkotlin/Pair;Lkotlin/Pair;F)V");
|
|
||||||
s_overlay_control_data_id_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "id", "Ljava/lang/String;");
|
|
||||||
s_overlay_control_data_enabled_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "enabled", "Z");
|
|
||||||
s_overlay_control_data_landscape_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "landscapePosition", "Lkotlin/Pair;");
|
|
||||||
s_overlay_control_data_portrait_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "portraitPosition", "Lkotlin/Pair;");
|
|
||||||
s_overlay_control_data_foldable_position_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "foldablePosition", "Lkotlin/Pair;");
|
|
||||||
s_overlay_control_data_individual_scale_field =
|
|
||||||
env->GetFieldID(overlay_control_data_class, "individualScale", "F");
|
|
||||||
env->DeleteLocalRef(overlay_control_data_class);
|
|
||||||
|
|
||||||
const jclass patch_class = env->FindClass("org/yuzu/yuzu_emu/model/Patch");
|
|
||||||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
|
||||||
s_patch_constructor = env->GetMethodID(
|
|
||||||
patch_class, "<init>",
|
|
||||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;JI)V");
|
|
||||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
|
||||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
|
||||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
|
||||||
s_patch_type_field = env->GetFieldID(patch_class, "type", "I");
|
|
||||||
s_patch_program_id_field = env->GetFieldID(patch_class, "programId", "Ljava/lang/String;");
|
|
||||||
s_patch_title_id_field = env->GetFieldID(patch_class, "titleId", "Ljava/lang/String;");
|
|
||||||
env->DeleteLocalRef(patch_class);
|
|
||||||
|
|
||||||
const jclass double_class = env->FindClass("java/lang/Double");
|
|
||||||
s_double_class = reinterpret_cast<jclass>(env->NewGlobalRef(double_class));
|
|
||||||
s_double_constructor = env->GetMethodID(double_class, "<init>", "(D)V");
|
|
||||||
s_double_value_method = env->GetMethodID(double_class, "doubleValue", "()D");
|
|
||||||
env->DeleteLocalRef(double_class);
|
|
||||||
|
|
||||||
const jclass int_class = env->FindClass("java/lang/Integer");
|
|
||||||
s_integer_class = reinterpret_cast<jclass>(env->NewGlobalRef(int_class));
|
|
||||||
s_integer_constructor = env->GetMethodID(int_class, "<init>", "(I)V");
|
|
||||||
s_integer_value_method = env->GetMethodID(int_class, "intValue", "()I");
|
|
||||||
env->DeleteLocalRef(int_class);
|
|
||||||
|
|
||||||
const jclass boolean_class = env->FindClass("java/lang/Boolean");
|
|
||||||
s_boolean_class = reinterpret_cast<jclass>(env->NewGlobalRef(boolean_class));
|
|
||||||
s_boolean_constructor = env->GetMethodID(boolean_class, "<init>", "(Z)V");
|
|
||||||
s_boolean_value_method = env->GetMethodID(boolean_class, "booleanValue", "()Z");
|
|
||||||
env->DeleteLocalRef(boolean_class);
|
|
||||||
|
|
||||||
const jclass player_input_class =
|
|
||||||
env->FindClass("org/yuzu/yuzu_emu/features/input/model/PlayerInput");
|
|
||||||
s_player_input_class = reinterpret_cast<jclass>(env->NewGlobalRef(player_input_class));
|
|
||||||
s_player_input_constructor = env->GetMethodID(
|
|
||||||
player_input_class, "<init>",
|
|
||||||
"(Z[Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;ZIJJJJLjava/lang/String;Z)V");
|
|
||||||
s_player_input_connected_field = env->GetFieldID(player_input_class, "connected", "Z");
|
|
||||||
s_player_input_buttons_field =
|
|
||||||
env->GetFieldID(player_input_class, "buttons", "[Ljava/lang/String;");
|
|
||||||
s_player_input_analogs_field =
|
|
||||||
env->GetFieldID(player_input_class, "analogs", "[Ljava/lang/String;");
|
|
||||||
s_player_input_motions_field =
|
|
||||||
env->GetFieldID(player_input_class, "motions", "[Ljava/lang/String;");
|
|
||||||
s_player_input_vibration_enabled_field =
|
|
||||||
env->GetFieldID(player_input_class, "vibrationEnabled", "Z");
|
|
||||||
s_player_input_vibration_strength_field =
|
|
||||||
env->GetFieldID(player_input_class, "vibrationStrength", "I");
|
|
||||||
s_player_input_body_color_left_field =
|
|
||||||
env->GetFieldID(player_input_class, "bodyColorLeft", "J");
|
|
||||||
s_player_input_body_color_right_field =
|
|
||||||
env->GetFieldID(player_input_class, "bodyColorRight", "J");
|
|
||||||
s_player_input_button_color_left_field =
|
|
||||||
env->GetFieldID(player_input_class, "buttonColorLeft", "J");
|
|
||||||
s_player_input_button_color_right_field =
|
|
||||||
env->GetFieldID(player_input_class, "buttonColorRight", "J");
|
|
||||||
s_player_input_profile_name_field =
|
|
||||||
env->GetFieldID(player_input_class, "profileName", "Ljava/lang/String;");
|
|
||||||
s_player_input_use_system_vibrator_field =
|
|
||||||
env->GetFieldID(player_input_class, "useSystemVibrator", "Z");
|
|
||||||
env->DeleteLocalRef(player_input_class);
|
|
||||||
|
|
||||||
const jclass yuzu_input_device_interface =
|
|
||||||
env->FindClass("org/yuzu/yuzu_emu/features/input/YuzuInputDevice");
|
|
||||||
s_yuzu_input_device_interface =
|
|
||||||
reinterpret_cast<jclass>(env->NewGlobalRef(yuzu_input_device_interface));
|
|
||||||
s_yuzu_input_device_get_name =
|
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getName", "()Ljava/lang/String;");
|
|
||||||
s_yuzu_input_device_get_guid =
|
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getGUID", "()Ljava/lang/String;");
|
|
||||||
s_yuzu_input_device_get_port = env->GetMethodID(yuzu_input_device_interface, "getPort",
|
|
||||||
"()I");
|
|
||||||
s_yuzu_input_device_get_supports_vibration =
|
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getSupportsVibration", "()Z");
|
|
||||||
s_yuzu_input_device_vibrate = env->GetMethodID(yuzu_input_device_interface, "vibrate",
|
|
||||||
"(F)V");
|
|
||||||
s_yuzu_input_device_get_axes =
|
|
||||||
env->GetMethodID(yuzu_input_device_interface, "getAxes", "()[Ljava/lang/Integer;");
|
|
||||||
s_yuzu_input_device_has_keys =
|
|
||||||
env->GetMethodID(yuzu_input_device_interface, "hasKeys", "([I)[Z");
|
|
||||||
env->DeleteLocalRef(yuzu_input_device_interface);
|
|
||||||
s_add_netplay_message = env->GetStaticMethodID(s_native_library_class, "addNetPlayMessage",
|
|
||||||
"(ILjava/lang/String;)V");
|
|
||||||
s_clear_chat = env->GetStaticMethodID(s_native_library_class, "clearChat", "()V");
|
|
||||||
|
|
||||||
// Initialize Android Storage
|
|
||||||
Common::FS::Android::RegisterCallbacks(env, s_native_library_class);
|
|
||||||
|
|
||||||
// Initialize applets
|
|
||||||
Common::Android::SoftwareKeyboard::InitJNI(env);
|
|
||||||
Common::Android::WebBrowser::InitJNI(env);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Common::Android
|
} // namespace Common::Android
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
namespace Common::Android {
|
namespace Common::Android {
|
||||||
|
|
||||||
void Initialize(JavaVM* vm, JNIEnv *env);
|
|
||||||
JNIEnv* GetEnvForThread();
|
JNIEnv* GetEnvForThread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -81,15 +80,15 @@ jfieldID GetPatchTitleIdField();
|
|||||||
|
|
||||||
jclass GetDoubleClass();
|
jclass GetDoubleClass();
|
||||||
jmethodID GetDoubleConstructor();
|
jmethodID GetDoubleConstructor();
|
||||||
jmethodID GetDoubleValueMethod();
|
jfieldID GetDoubleValueField();
|
||||||
|
|
||||||
jclass GetIntegerClass();
|
jclass GetIntegerClass();
|
||||||
jmethodID GetIntegerConstructor();
|
jmethodID GetIntegerConstructor();
|
||||||
jmethodID GetIntegerValueMethod();
|
jfieldID GetIntegerValueField();
|
||||||
|
|
||||||
jclass GetBooleanClass();
|
jclass GetBooleanClass();
|
||||||
jmethodID GetBooleanConstructor();
|
jmethodID GetBooleanConstructor();
|
||||||
jmethodID GetBooleanValueMethod();
|
jfieldID GetBooleanValueField();
|
||||||
|
|
||||||
jclass GetPlayerInputClass();
|
jclass GetPlayerInputClass();
|
||||||
jmethodID GetPlayerInputConstructor();
|
jmethodID GetPlayerInputConstructor();
|
||||||
|
|||||||
+12
-10
@@ -20,6 +20,9 @@
|
|||||||
#else
|
#else
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define fileno _fileno
|
#define fileno _fileno
|
||||||
@@ -402,28 +405,27 @@ u64 IOFile::GetSize() const {
|
|||||||
file_size = Android::GetSize(file_path);
|
file_size = Android::GetSize(file_path);
|
||||||
} else {
|
} else {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
file_size = fs::file_size(file_path, ec);
|
file_size = fs::file_size(file_path, ec);
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
LOG_ERROR(Common_Filesystem,
|
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
|
||||||
"Failed to retrieve the file size of path={}, ec_message={}",
|
|
||||||
PathToUTF8String(file_path), ec.message());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
// TODO: implementation of fs::file_size() is buggy on PS4, why?
|
||||||
|
// probably toolchain issue... ugh
|
||||||
|
OrbisKernelStat st{};
|
||||||
|
stat(file_path.c_str(), reinterpret_cast<struct stat *>(std::addressof(st)));
|
||||||
|
auto const file_size = st.st_size;
|
||||||
|
LOG_DEBUG(Common_Filesystem, "size for {} = {}", file_path.c_str(), file_size);
|
||||||
#else
|
#else
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
|
|
||||||
const auto file_size = fs::file_size(file_path, ec);
|
const auto file_size = fs::file_size(file_path, ec);
|
||||||
|
|
||||||
if (ec) {
|
if (ec) {
|
||||||
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
|
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
|
||||||
PathToUTF8String(file_path), ec.message());
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return file_size;
|
return file_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -174,11 +174,14 @@ bool CreateDir(const fs::path& path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Maybe this is what causes death?
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (!Exists(path.parent_path())) {
|
if (!Exists(path.parent_path())) {
|
||||||
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
|
||||||
PathToUTF8String(path));
|
PathToUTF8String(path));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (IsDir(path)) {
|
if (IsDir(path)) {
|
||||||
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
|
||||||
|
|||||||
@@ -23,7 +23,6 @@
|
|||||||
#define LOSSLESS_DIR "lossless"
|
#define LOSSLESS_DIR "lossless"
|
||||||
#define NAND_DIR "nand"
|
#define NAND_DIR "nand"
|
||||||
#define PLAY_TIME_DIR "play_time"
|
#define PLAY_TIME_DIR "play_time"
|
||||||
#define POST_SHADER_DIR "post_shaders"
|
|
||||||
#define SCREENSHOTS_DIR "screenshots"
|
#define SCREENSHOTS_DIR "screenshots"
|
||||||
#define SDMC_DIR "sdmc"
|
#define SDMC_DIR "sdmc"
|
||||||
#define SHADER_DIR "shader"
|
#define SHADER_DIR "shader"
|
||||||
|
|||||||
+11
-13
@@ -130,6 +130,10 @@ public:
|
|||||||
ASSERT(!eden_path.empty());
|
ASSERT(!eden_path.empty());
|
||||||
eden_path_cache = eden_path / CACHE_DIR;
|
eden_path_cache = eden_path / CACHE_DIR;
|
||||||
eden_path_config = eden_path / CONFIG_DIR;
|
eden_path_config = eden_path / CONFIG_DIR;
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
eden_path = "/data/eden";
|
||||||
|
eden_path_cache = eden_path / CACHE_DIR;
|
||||||
|
eden_path_config = eden_path / CONFIG_DIR;
|
||||||
#else
|
#else
|
||||||
eden_path = GetCurrentDir() / PORTABLE_DIR;
|
eden_path = GetCurrentDir() / PORTABLE_DIR;
|
||||||
if (!Exists(eden_path) || !IsDir(eden_path)) {
|
if (!Exists(eden_path) || !IsDir(eden_path)) {
|
||||||
@@ -160,7 +164,6 @@ public:
|
|||||||
GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR);
|
GenerateEdenPath(EdenPath::LosslessDir, eden_path / LOSSLESS_DIR);
|
||||||
GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
|
GenerateEdenPath(EdenPath::NANDDir, eden_path / NAND_DIR);
|
||||||
GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
|
GenerateEdenPath(EdenPath::PlayTimeDir, eden_path / PLAY_TIME_DIR);
|
||||||
GenerateEdenPath(EdenPath::PostShaderDir, eden_path / POST_SHADER_DIR);
|
|
||||||
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
|
GenerateEdenPath(EdenPath::SaveDir, eden_path / NAND_DIR);
|
||||||
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
|
GenerateEdenPath(EdenPath::ScreenshotsDir, eden_path / SCREENSHOTS_DIR);
|
||||||
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
|
GenerateEdenPath(EdenPath::SDMCDir, eden_path / SDMC_DIR);
|
||||||
@@ -173,12 +176,11 @@ public:
|
|||||||
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
|
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
|
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
|
||||||
#else
|
#elif !defined(__OPENORBIS__)
|
||||||
// In Ryujinx's infinite wisdom, it places EVERYTHING in the config directory on UNIX
|
// In Ryujinx's infinite wisdom, it places EVERYTHING in the config directory on UNIX
|
||||||
// This is incredibly stupid and violates a million XDG standards, but whatever
|
// This is incredibly stupid and violates a million XDG standards, but whatever
|
||||||
GenerateLegacyPath(EmuPath::RyujinxDir, GetDataDirectory("XDG_CONFIG_HOME") / RYUJINX_DIR);
|
GenerateLegacyPath(EmuPath::RyujinxDir, GetDataDirectory("XDG_CONFIG_HOME") / RYUJINX_DIR);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -340,36 +342,33 @@ fs::path GetAppDataRoamingDirectory() {
|
|||||||
return fs_appdata_roaming_path;
|
return fs_appdata_roaming_path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
|
||||||
|
// Not required/defined
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
fs::path GetHomeDirectory() {
|
fs::path GetHomeDirectory() {
|
||||||
const char* home_env_var = getenv("HOME");
|
const char* home_env_var = getenv("HOME");
|
||||||
|
|
||||||
if (home_env_var) {
|
if (home_env_var) {
|
||||||
return fs::path{home_env_var};
|
return fs::path{home_env_var};
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INFO(Common_Filesystem,
|
LOG_INFO(Common_Filesystem,
|
||||||
"$HOME is not defined in the environment variables, "
|
"$HOME is not defined in the environment variables, "
|
||||||
"attempting to query passwd to get the home path of the current user");
|
"attempting to query passwd to get the home path of the current user");
|
||||||
|
|
||||||
const auto* pw = getpwuid(getuid());
|
const auto* pw = getpwuid(getuid());
|
||||||
|
|
||||||
if (!pw) {
|
if (!pw) {
|
||||||
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
|
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs::path{pw->pw_dir};
|
return fs::path{pw->pw_dir};
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path GetDataDirectory(const std::string& env_name) {
|
fs::path GetDataDirectory(const std::string& env_name) {
|
||||||
const char* data_env_var = getenv(env_name.c_str());
|
const char* data_env_var = getenv(env_name.c_str());
|
||||||
|
|
||||||
if (data_env_var) {
|
if (data_env_var) {
|
||||||
return fs::path{data_env_var};
|
return fs::path{data_env_var};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env_name == "XDG_DATA_HOME") {
|
if (env_name == "XDG_DATA_HOME") {
|
||||||
return GetHomeDirectory() / ".local/share";
|
return GetHomeDirectory() / ".local/share";
|
||||||
} else if (env_name == "XDG_CACHE_HOME") {
|
} else if (env_name == "XDG_CACHE_HOME") {
|
||||||
@@ -377,7 +376,6 @@ fs::path GetDataDirectory(const std::string& env_name) {
|
|||||||
} else if (env_name == "XDG_CONFIG_HOME") {
|
} else if (env_name == "XDG_CONFIG_HOME") {
|
||||||
return GetHomeDirectory() / ".config";
|
return GetHomeDirectory() / ".config";
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ enum class EdenPath {
|
|||||||
LosslessDir, // Where the user-supplied Lossless Scaling library is stored.
|
LosslessDir, // Where the user-supplied Lossless Scaling library is stored.
|
||||||
NANDDir, // Where the emulated NAND is stored.
|
NANDDir, // Where the emulated NAND is stored.
|
||||||
PlayTimeDir, // Where play time data is stored.
|
PlayTimeDir, // Where play time data is stored.
|
||||||
PostShaderDir, // Where user post-processing shaders are stored.
|
|
||||||
SaveDir, // Where save data is stored.
|
SaveDir, // Where save data is stored.
|
||||||
ScreenshotsDir, // Where yuzu screenshots are stored.
|
ScreenshotsDir, // Where yuzu screenshots are stored.
|
||||||
SDMCDir, // Where the emulated SDMC is stored.
|
SDMCDir, // Where the emulated SDMC is stored.
|
||||||
|
|||||||
+10
-10
@@ -38,15 +38,15 @@
|
|||||||
|
|
||||||
// FreeBSD
|
// FreeBSD
|
||||||
#ifndef MAP_NORESERVE
|
#ifndef MAP_NORESERVE
|
||||||
#define MAP_NORESERVE 0
|
# define MAP_NORESERVE 0
|
||||||
#endif
|
#endif
|
||||||
// Solaris 11 and illumos
|
// Solaris 11 and illumos
|
||||||
#ifndef MAP_ALIGNED_SUPER
|
#ifndef MAP_ALIGNED_SUPER
|
||||||
#define MAP_ALIGNED_SUPER 0
|
# define MAP_ALIGNED_SUPER 0
|
||||||
#endif
|
#endif
|
||||||
// macOS
|
// macOS
|
||||||
#ifndef MAP_ANONYMOUS
|
#ifndef MAP_ANONYMOUS
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
# define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // ^^^ POSIX ^^^
|
#endif // ^^^ POSIX ^^^
|
||||||
@@ -441,13 +441,15 @@ static void* ChooseVirtualBase(size_t virtual_size) {
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
static void* ChooseVirtualBase(size_t virtual_size) {
|
static void* ChooseVirtualBase(size_t size) {
|
||||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
|
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
|
||||||
void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
|
void* virtual_base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
|
||||||
if (virtual_base != MAP_FAILED)
|
if (virtual_base != MAP_FAILED)
|
||||||
return virtual_base;
|
return virtual_base;
|
||||||
|
return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||||
|
#else
|
||||||
|
return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||||
#endif
|
#endif
|
||||||
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -729,9 +731,8 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, M
|
|||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
ASSERT(host_offset + length <= backing_size);
|
ASSERT(host_offset + length <= backing_size);
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@@ -741,9 +742,8 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
|
|||||||
ASSERT(virtual_offset % PageAlignment == 0);
|
ASSERT(virtual_offset % PageAlignment == 0);
|
||||||
ASSERT(length % PageAlignment == 0);
|
ASSERT(length % PageAlignment == 0);
|
||||||
ASSERT(virtual_offset + length <= virtual_size);
|
ASSERT(virtual_offset + length <= virtual_size);
|
||||||
if (length == 0 || !virtual_base || !impl) {
|
if (length == 0 || !virtual_base || !impl)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
impl->Unmap(virtual_offset + virtual_base_offset, length);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,14 +74,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t backing_size{};
|
|
||||||
size_t virtual_size{};
|
|
||||||
|
|
||||||
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
#if !(defined(__OPENORBIS__) || defined(__managarm__))
|
||||||
// Low level handler for the platform dependent memory routines
|
// Low level handler for the platform dependent memory routines
|
||||||
class Impl;
|
class Impl;
|
||||||
std::unique_ptr<Impl> impl;
|
std::unique_ptr<Impl> impl;
|
||||||
#endif
|
#endif
|
||||||
|
size_t backing_size{};
|
||||||
|
size_t virtual_size{};
|
||||||
u8* backing_base{};
|
u8* backing_base{};
|
||||||
u8* virtual_base{};
|
u8* virtual_base{};
|
||||||
size_t virtual_base_offset{};
|
size_t virtual_base_offset{};
|
||||||
|
|||||||
@@ -3,8 +3,14 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
// TODO: httplib port can't use OpenSSL because of package misconfigs on OO toolchain
|
||||||
|
// right now the solution is to tell httplib that OpenSSL doesn't exist, but that's bad
|
||||||
|
// and the issue is a bit more of how OpenSSL lacks some essential functionality
|
||||||
|
// which is a bit annoying to reconfigure atm.
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
|
#define CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES 1
|
||||||
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
|
#define CPPHTTPLIB_OPENSSL_SUPPORT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
|
|||||||
@@ -236,7 +236,6 @@ struct ColorConsoleBackend final : public Backend {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
/// @brief Backend that writes to a file passed into the constructor
|
/// @brief Backend that writes to a file passed into the constructor
|
||||||
struct FileBackend final : public Backend {
|
struct FileBackend final : public Backend {
|
||||||
explicit FileBackend(const std::filesystem::path filename) noexcept {
|
explicit FileBackend(const std::filesystem::path filename) noexcept {
|
||||||
@@ -299,7 +298,7 @@ private:
|
|||||||
std::size_t bytes_written = 0;
|
std::size_t bytes_written = 0;
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
/// @brief Backend that writes to Visual Studio's output window
|
/// @brief Backend that writes to Visual Studio's output window
|
||||||
struct DebuggerBackend final : public Backend {
|
struct DebuggerBackend final : public Backend {
|
||||||
@@ -343,10 +342,8 @@ struct Impl {
|
|||||||
template<typename F>
|
template<typename F>
|
||||||
void ForEachBackend(F&& lambda) noexcept {
|
void ForEachBackend(F&& lambda) noexcept {
|
||||||
lambda(static_cast<Backend&>(color_console_backend));
|
lambda(static_cast<Backend&>(color_console_backend));
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
if (file_backend)
|
if (file_backend)
|
||||||
lambda(static_cast<Backend&>(*file_backend));
|
lambda(static_cast<Backend&>(*file_backend));
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
lambda(static_cast<Backend&>(debugger_backend));
|
lambda(static_cast<Backend&>(debugger_backend));
|
||||||
#endif
|
#endif
|
||||||
@@ -357,9 +354,7 @@ struct Impl {
|
|||||||
|
|
||||||
Filter filter;
|
Filter filter;
|
||||||
ColorConsoleBackend color_console_backend{};
|
ColorConsoleBackend color_console_backend{};
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
std::optional<FileBackend> file_backend;
|
std::optional<FileBackend> file_backend;
|
||||||
#endif
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
DebuggerBackend debugger_backend{};
|
DebuggerBackend debugger_backend{};
|
||||||
#endif
|
#endif
|
||||||
@@ -396,12 +391,10 @@ void Initialize() {
|
|||||||
} else {
|
} else {
|
||||||
logging_instance.emplace();
|
logging_instance.emplace();
|
||||||
logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue());
|
||||||
#ifndef __OPENORBIS__
|
|
||||||
using namespace Common::FS;
|
using namespace Common::FS;
|
||||||
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
|
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
|
||||||
void(CreateDir(log_dir));
|
void(CreateDir(log_dir));
|
||||||
logging_instance->file_backend.emplace(log_dir / LOG_FILE);
|
logging_instance->file_backend.emplace(log_dir / LOG_FILE);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -8,7 +11,7 @@
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
#else
|
#else
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(__OPENORBIS__))
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#elif defined(__linux__)
|
#elif defined(__linux__)
|
||||||
#include <sys/sysinfo.h>
|
#include <sys/sysinfo.h>
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ std::optional<std::string> MakeRequest(const std::string& url, const std::string
|
|||||||
client->set_read_timeout(timeout_seconds);
|
client->set_read_timeout(timeout_seconds);
|
||||||
client->set_write_timeout(timeout_seconds);
|
client->set_write_timeout(timeout_seconds);
|
||||||
|
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
|
||||||
client->load_ca_cert_store(kCert, sizeof(kCert));
|
client->load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/time_zone.h"
|
#include "common/time_zone.h"
|
||||||
|
|
||||||
#if defined(__linux__ ) && defined(ARCHITECTURE_arm64)
|
#ifdef __unix__
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -187,12 +187,9 @@ bool IsFastmemEnabled() {
|
|||||||
return bool(values.cpuopt_fastmem);
|
return bool(values.cpuopt_fastmem);
|
||||||
else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe)
|
else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe)
|
||||||
return bool(values.cpuopt_unsafe_host_mmu);
|
return bool(values.cpuopt_unsafe_host_mmu);
|
||||||
#if defined(__linux__) && defined(ARCHITECTURE_arm64)
|
#if defined(__unix__)
|
||||||
// Only 4kb systems support host MMU right now
|
// TODO: Support this since only 4kb systems support host MMU right now
|
||||||
// TODO: Support this
|
|
||||||
return getpagesize() == 4096;
|
return getpagesize() == 4096;
|
||||||
#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__)
|
|
||||||
return false;
|
|
||||||
#else
|
#else
|
||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+9
-10
@@ -196,7 +196,14 @@ struct Values {
|
|||||||
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||||
|
|
||||||
// Core
|
// Core
|
||||||
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
SwitchableSetting<bool> use_multi_core{linkage,
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// Re-enable once proper TLS support is added
|
||||||
|
false,
|
||||||
|
#else
|
||||||
|
true,
|
||||||
|
#endif
|
||||||
|
"use_multi_core", Category::Core};
|
||||||
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||||
MemoryLayout::Memory_4Gb,
|
MemoryLayout::Memory_4Gb,
|
||||||
"memory_layout_mode",
|
"memory_layout_mode",
|
||||||
@@ -330,7 +337,7 @@ struct Values {
|
|||||||
|
|
||||||
// Renderer
|
// Renderer
|
||||||
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
||||||
#if defined(__sun__) || defined(__managarm__)
|
#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__)
|
||||||
RendererBackend::OpenGL_GLSL,
|
RendererBackend::OpenGL_GLSL,
|
||||||
#else
|
#else
|
||||||
RendererBackend::Vulkan,
|
RendererBackend::Vulkan,
|
||||||
@@ -388,14 +395,6 @@ struct Values {
|
|||||||
true,
|
true,
|
||||||
true};
|
true};
|
||||||
|
|
||||||
SwitchableSetting<std::string> post_shader_chain{linkage,
|
|
||||||
std::string(),
|
|
||||||
"post_shader_chain",
|
|
||||||
Category::Renderer,
|
|
||||||
Specialization::Default,
|
|
||||||
true,
|
|
||||||
true};
|
|
||||||
|
|
||||||
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
SwitchableSetting<bool> frame_gen{linkage, false, "frame_gen", Category::Renderer,
|
||||||
Specialization::Default, true, false};
|
Specialization::Default, true, false};
|
||||||
|
|
||||||
|
|||||||
@@ -92,14 +92,15 @@ struct EnumMetadata {
|
|||||||
// AudioEngine must be specified discretely due to having existing but slightly different
|
// AudioEngine must be specified discretely due to having existing but slightly different
|
||||||
// canonicalizations
|
// canonicalizations
|
||||||
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
|
||||||
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, };
|
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, Ps4, };
|
||||||
template<>
|
template<>
|
||||||
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
|
||||||
return {
|
return {
|
||||||
{"auto", AudioEngine::Auto},
|
{"auto", AudioEngine::Auto},
|
||||||
{"cubeb", AudioEngine::Cubeb},
|
{"cubeb", AudioEngine::Cubeb},
|
||||||
{"sdl3", AudioEngine::Sdl3},
|
{"sdl3", AudioEngine::Sdl3},
|
||||||
{"null", AudioEngine::Null},
|
{"null", AudioEngine::Null}, {"oboe", AudioEngine::Oboe},
|
||||||
|
{"ps4", AudioEngine::Ps4},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
/// @brief This is just a sufficiently large number that is more than the number of other enums declared here
|
||||||
@@ -113,7 +114,7 @@ inline AudioEngine EnumMetadata<AudioEngine>::GetFirst() {
|
|||||||
}
|
}
|
||||||
template<>
|
template<>
|
||||||
inline AudioEngine EnumMetadata<AudioEngine>::GetLast() {
|
inline AudioEngine EnumMetadata<AudioEngine>::GetLast() {
|
||||||
return AudioEngine::Null;
|
return AudioEngine::Oboe;
|
||||||
}
|
}
|
||||||
|
|
||||||
ENUM(AudioMode, Mono, Stereo, Surround);
|
ENUM(AudioMode, Mono, Stereo, Surround);
|
||||||
|
|||||||
+181
-18
@@ -10,34 +10,197 @@
|
|||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
#include <ranges>
|
||||||
|
#include <csignal>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <boost/container/static_vector.hpp>
|
||||||
|
#include <orbis/SystemService.h>
|
||||||
|
#include <orbis/libkernel.h>
|
||||||
|
typedef void (*SceKernelExceptionHandler)(int32_t, void*);
|
||||||
|
extern "C" int32_t sceKernelInstallExceptionHandler(int32_t signum, SceKernelExceptionHandler handler);
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/virtual_buffer.h"
|
#include "common/virtual_buffer.h"
|
||||||
|
#include "common/logging.h"
|
||||||
|
|
||||||
|
// PlayStation 4
|
||||||
|
// Flag needs to be undef-ed on non PS4 since it has different semantics
|
||||||
|
// on some platforms.
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
# ifndef MAP_SYSTEM
|
||||||
|
# define MAP_SYSTEM 0x2000
|
||||||
|
# endif
|
||||||
|
# ifndef MAP_VOID
|
||||||
|
# define MAP_VOID 0x100
|
||||||
|
# endif
|
||||||
|
// sigaction(2) has a motherfucking bug on musl where the thing isnt even properly prefixed
|
||||||
|
# undef sa_sigaction
|
||||||
|
# define sa_sigaction __sa_handler.__sa_sigaction
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
||||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
#ifdef __OPENORBIS__
|
||||||
#ifdef _WIN32
|
|
||||||
void* base = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
namespace Orbis {
|
||||||
if (base == nullptr) {
|
constexpr size_t ORBIS_PAGE_SIZE = 16384;
|
||||||
// Probably failing to reserve is less likely than failing to commit
|
|
||||||
base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
struct Ucontext {
|
||||||
}
|
struct Sigset {
|
||||||
#else
|
u64 bits[2];
|
||||||
void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
} uc_sigmask;
|
||||||
if (base == MAP_FAILED)
|
int field1_0x10[12];
|
||||||
base = nullptr;
|
struct Mcontext {
|
||||||
#endif
|
u64 mc_onstack;
|
||||||
ASSERT(base);
|
u64 mc_rdi;
|
||||||
return base;
|
u64 mc_rsi;
|
||||||
|
u64 mc_rdx;
|
||||||
|
u64 mc_rcx;
|
||||||
|
u64 mc_r8;
|
||||||
|
u64 mc_r9;
|
||||||
|
u64 mc_rax;
|
||||||
|
u64 mc_rbx;
|
||||||
|
u64 mc_rbp;
|
||||||
|
u64 mc_r10;
|
||||||
|
u64 mc_r11;
|
||||||
|
u64 mc_r12;
|
||||||
|
u64 mc_r13;
|
||||||
|
u64 mc_r14;
|
||||||
|
u64 mc_r15;
|
||||||
|
int mc_trapno;
|
||||||
|
u16 mc_fs;
|
||||||
|
u16 mc_gs;
|
||||||
|
u64 mc_addr;
|
||||||
|
int mc_flags;
|
||||||
|
u16 mc_es;
|
||||||
|
u16 mc_ds;
|
||||||
|
u64 mc_err;
|
||||||
|
u64 mc_rip;
|
||||||
|
u64 mc_cs;
|
||||||
|
u64 mc_rflags;
|
||||||
|
u64 mc_rsp;
|
||||||
|
u64 mc_ss;
|
||||||
|
u64 mc_len;
|
||||||
|
u64 mc_fpformat;
|
||||||
|
u64 mc_ownedfp;
|
||||||
|
u64 mc_lbrfrom;
|
||||||
|
u64 mc_lbrto;
|
||||||
|
u64 mc_aux1;
|
||||||
|
u64 mc_aux2;
|
||||||
|
u64 mc_fpstate[104];
|
||||||
|
u64 mc_fsbase;
|
||||||
|
u64 mc_gsbase;
|
||||||
|
u64 mc_spare[6];
|
||||||
|
} uc_mcontext;
|
||||||
|
struct Ucontext* uc_link;
|
||||||
|
struct ExStack {
|
||||||
|
void* ss_sp;
|
||||||
|
std::size_t ss_size;
|
||||||
|
int ss_flags;
|
||||||
|
int _align;
|
||||||
|
} uc_stack;
|
||||||
|
int uc_flags;
|
||||||
|
int __spare[4];
|
||||||
|
int field7_0x4f4[3];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
|
static boost::container::static_vector<std::pair<void*, size_t>, 16> swap_regions;
|
||||||
if (!base)
|
static std::mutex evil_swap_mutex;
|
||||||
|
extern "C" int sceKernelRemoveExceptionHandler(s32 sig_num);
|
||||||
|
static void SwapHandler(int sig, void* raw_context) {
|
||||||
|
std::unique_lock lk{evil_swap_mutex};
|
||||||
|
auto& mctx = ((Orbis::Ucontext*)raw_context)->uc_mcontext;
|
||||||
|
if (auto const it = std::ranges::find_if(swap_regions, [addr = mctx.mc_addr](auto const& e) {
|
||||||
|
return uintptr_t(addr) >= uintptr_t(e.first) && uintptr_t(addr) < uintptr_t(e.first) + e.second;
|
||||||
|
}); it != swap_regions.end()) {
|
||||||
|
size_t const page_size = Orbis::ORBIS_PAGE_SIZE * 128; //128K
|
||||||
|
size_t const page_mask = ~(page_size - 1);
|
||||||
|
// should replace the existing mapping... ugh
|
||||||
|
void* aligned_addr = reinterpret_cast<void*>(uintptr_t(mctx.mc_addr) & page_mask);
|
||||||
|
void* res = mmap(aligned_addr, page_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
|
if (res == MAP_FAILED) {
|
||||||
|
LOG_ERROR(HW_Memory, "{:#x},{} @ {}:{:#x}", mctx.mc_addr, aligned_addr, it->first, it->second);
|
||||||
|
sceKernelRemoveExceptionHandler(SIGSEGV); // to not catch the next signal
|
||||||
|
} else {
|
||||||
|
LOG_DEBUG(HW_Memory, "{:#x},{} @ {}:{:#x}", mctx.mc_addr, aligned_addr, it->first, it->second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(HW_Memory, "fault in addr {:#x} at {:#x}", mctx.mc_addr, mctx.mc_rip); // print caller address
|
||||||
|
sceKernelRemoveExceptionHandler(SIGSEGV); // to not catch the next signal
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void InitSwap() noexcept {
|
||||||
|
sceKernelInstallExceptionHandler(SIGSEGV, &SwapHandler);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void InitSwap() noexcept {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||||
|
#ifdef _WIN32
|
||||||
|
void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
|
||||||
|
if (addr == nullptr) {
|
||||||
|
// Probably failing to reserve is less likely than failing to commit
|
||||||
|
addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||||
|
}
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
bool use_void_mem = true;
|
||||||
|
void* addr = nullptr;
|
||||||
|
if (size < 4294967296ull) {
|
||||||
|
size_t align = Orbis::ORBIS_PAGE_SIZE;
|
||||||
|
off_t offset;
|
||||||
|
int32_t res;
|
||||||
|
size = (size + align - 1) / align * align;
|
||||||
|
if ((res = sceKernelAllocateDirectMemory(0, ORBIS_KERNEL_MAIN_DMEM_SIZE, size, align, ORBIS_KERNEL_WB_ONION, &offset)) == 0) {
|
||||||
|
if ((res = sceKernelMapDirectMemory(&addr, size, ORBIS_KERNEL_PROT_CPU_READ | ORBIS_KERNEL_PROT_CPU_WRITE, 0, offset, size)) == 0) {
|
||||||
|
if ((res = sceKernelMprotect(addr, size, VM_PROT_ALL)) == 0 && addr != nullptr) {
|
||||||
|
LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", size, addr);
|
||||||
|
use_void_mem = false; //Memory properly mapped
|
||||||
|
} else {
|
||||||
|
sceKernelReleaseDirectMemory(offset, size);
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelMprotect({}, {})", res, offset, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sceKernelReleaseDirectMemory(offset, size);
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelMapDirectMemory({}, {})", res, offset, size);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(HW_Memory, "{} = sceKernelAllocateDirectMemory({}, {}, {})", res, size, align, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (use_void_mem) {
|
||||||
|
addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0);
|
||||||
|
LOG_WARNING(HW_Memory, "Using VoidMem for {} bytes area @ {}", size, addr);
|
||||||
|
ASSERT(addr != MAP_FAILED);
|
||||||
|
swap_regions.emplace_back(addr, size);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||||
|
ASSERT(addr != MAP_FAILED);
|
||||||
|
#endif
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept {
|
||||||
|
if (!addr)
|
||||||
return;
|
return;
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
|
VirtualFree(addr, 0, MEM_RELEASE);
|
||||||
|
#elif defined(__OPENORBIS__)
|
||||||
|
if (auto const it = std::ranges::find_if(swap_regions, [=](auto const& e) {
|
||||||
|
return uintptr_t(addr) >= uintptr_t(e.first) && uintptr_t(addr) < uintptr_t(e.first) + e.second;
|
||||||
|
}); it != swap_regions.end()) {
|
||||||
|
int rc = munmap(addr, size);
|
||||||
|
ASSERT(rc == 0);
|
||||||
|
} else {
|
||||||
|
sceKernelCheckedReleaseDirectMemory(off_t(addr), size_t(size));
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
ASSERT(munmap(base, size) == 0);
|
int rc = munmap(addr, size);
|
||||||
|
ASSERT(rc == 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ namespace Common {
|
|||||||
|
|
||||||
void* AllocateMemoryPages(std::size_t size) noexcept;
|
void* AllocateMemoryPages(std::size_t size) noexcept;
|
||||||
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
||||||
|
void InitSwap() noexcept;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class VirtualBuffer final {
|
class VirtualBuffer final {
|
||||||
|
|||||||
@@ -199,7 +199,9 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
|
|||||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
#if defined(__OPENORBIS__)
|
||||||
|
config.code_cache_size = std::uint32_t(8_MiB);
|
||||||
|
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||||
config.code_cache_size = std::uint32_t(128_MiB);
|
config.code_cache_size = std::uint32_t(128_MiB);
|
||||||
#else
|
#else
|
||||||
config.code_cache_size = std::uint32_t(512_MiB);
|
config.code_cache_size = std::uint32_t(512_MiB);
|
||||||
|
|||||||
@@ -252,7 +252,9 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
|
|||||||
config.enable_cycle_counting = !m_uses_wall_clock;
|
config.enable_cycle_counting = !m_uses_wall_clock;
|
||||||
|
|
||||||
// Code cache size
|
// Code cache size
|
||||||
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
#if defined(__OPENORBIS__)
|
||||||
|
config.code_cache_size = std::uint32_t(8_MiB);
|
||||||
|
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
|
||||||
config.code_cache_size = std::uint32_t(128_MiB);
|
config.code_cache_size = std::uint32_t(128_MiB);
|
||||||
#else
|
#else
|
||||||
config.code_cache_size = std::uint32_t(512_MiB);
|
config.code_cache_size = std::uint32_t(512_MiB);
|
||||||
|
|||||||
@@ -358,7 +358,7 @@ private:
|
|||||||
|
|
||||||
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
ConnectionState(boost::asio::ip::tcp::socket&& client_socket_, async_pipe signal_pipe_, Kernel::KernelCore& kernel)
|
||||||
: client_socket{std::move(client_socket_)}
|
: client_socket{std::move(client_socket_)}
|
||||||
, signal_pipe{std::move(signal_pipe_)}
|
, signal_pipe{signal_pipe_}
|
||||||
, active_thread{kernel, nullptr}
|
, active_thread{kernel, nullptr}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|||||||
@@ -461,8 +461,19 @@ std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
|
|||||||
|
|
||||||
FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
|
FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
|
||||||
const auto full_path = FS::SanitizePath(path + '/' + std::string(path_));
|
const auto full_path = FS::SanitizePath(path + '/' + std::string(path_));
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// DO NOT USE NORMAL STAT, it's bugged on OO toolchain
|
||||||
|
OrbisKernelStat st{};
|
||||||
|
const auto stat_result = stat(full_path.c_str(), reinterpret_cast<struct stat *>(std::addressof(st)));
|
||||||
|
if (stat_result != 0)
|
||||||
|
return {};
|
||||||
|
return {
|
||||||
|
.created{u64(st.st_ctime)},
|
||||||
|
.accessed{u64(st.st_atime)},
|
||||||
|
.modified{u64(st.st_mtime)},
|
||||||
|
};
|
||||||
|
#else
|
||||||
const auto fs_path = std::filesystem::path{FS::ToU8String(full_path)};
|
const auto fs_path = std::filesystem::path{FS::ToU8String(full_path)};
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
struct _stat64 file_status;
|
struct _stat64 file_status;
|
||||||
const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
|
const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
|
||||||
@@ -470,16 +481,14 @@ FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) cons
|
|||||||
struct stat file_status;
|
struct stat file_status;
|
||||||
const auto stat_result = stat(fs_path.c_str(), &file_status);
|
const auto stat_result = stat(fs_path.c_str(), &file_status);
|
||||||
#endif
|
#endif
|
||||||
|
if (stat_result != 0)
|
||||||
if (stat_result != 0) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
.created{static_cast<u64>(file_status.st_ctime)},
|
.created{u64(file_status.st_ctime)},
|
||||||
.accessed{static_cast<u64>(file_status.st_atime)},
|
.accessed{u64(file_status.st_atime)},
|
||||||
.modified{static_cast<u64>(file_status.st_mtime)},
|
.modified{u64(file_status.st_mtime)},
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
|
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
|
||||||
|
|||||||
@@ -1021,9 +1021,6 @@ Result KProcess::Run(KernelCore& kernel, s32 priority, size_t stack_size) {
|
|||||||
|
|
||||||
// Suspend for debug, if we should.
|
// Suspend for debug, if we should.
|
||||||
if (kernel.System().DebuggerEnabled()) {
|
if (kernel.System().DebuggerEnabled()) {
|
||||||
LOG_INFO(Debug_GDBStub,
|
|
||||||
"GDB stub enabled; suspending guest process until a debugger continues execution on port {}",
|
|
||||||
Settings::values.gdbstub_port.GetValue());
|
|
||||||
main_thread->RequestSuspend(kernel, SuspendType::Debug);
|
main_thread->RequestSuspend(kernel, SuspendType::Debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ std::vector<u8> DownloadImage(const std::string& url_path, const std::filesystem
|
|||||||
cli.set_connection_timeout(std::chrono::seconds(2));
|
cli.set_connection_timeout(std::chrono::seconds(2));
|
||||||
cli.set_read_timeout(std::chrono::seconds(2));
|
cli.set_read_timeout(std::chrono::seconds(2));
|
||||||
|
|
||||||
#ifdef YUZU_BUNDLED_OPENSSL
|
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
|
||||||
cli.load_ca_cert_store(kCert, sizeof(kCert));
|
cli.load_ca_cert_store(kCert, sizeof(kCert));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -34,12 +34,13 @@ struct FontRegion {
|
|||||||
|
|
||||||
// The below data is specific to shared font data dumped from Switch on f/w 2.2
|
// The below data is specific to shared font data dumped from Switch on f/w 2.2
|
||||||
// Virtual address and offsets/sizes likely will vary by dump
|
// Virtual address and offsets/sizes likely will vary by dump
|
||||||
[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR{0x00000009d3016000ULL};
|
[[maybe_unused]] constexpr VAddr SHARED_FONT_MEM_VADDR = 0x00000009d3016000ULL;
|
||||||
constexpr u32 EXPECTED_RESULT{0x7f9a0218}; // What we expect the decrypted bfttf first 4 bytes to be
|
constexpr u32 EXPECTED_RESULT = 0x7f9a0218; // What we expect the decrypted bfttf first 4 bytes to be
|
||||||
constexpr u32 EXPECTED_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
|
constexpr u32 EXPECTED_MAGIC = 0x36f81a1e; // What we expect the encrypted bfttf first 4 bytes to be
|
||||||
constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
|
constexpr u64 SHARED_FONT_MEM_SIZE = 0x1100000;
|
||||||
constexpr FontRegion EMPTY_REGION{0, 0};
|
constexpr FontRegion EMPTY_REGION{0, 0};
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> output, std::size_t& offset) {
|
static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> output, std::size_t& offset) {
|
||||||
ASSERT(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE && "Shared fonts exceeds 17mb!");
|
ASSERT(offset + (input.size() * sizeof(u32)) < SHARED_FONT_MEM_SIZE && "Shared fonts exceeds 17mb!");
|
||||||
ASSERT(input[0] == EXPECTED_MAGIC && "Failed to derive key, unexpected magic number");
|
ASSERT(input[0] == EXPECTED_MAGIC && "Failed to derive key, unexpected magic number");
|
||||||
@@ -51,6 +52,7 @@ static void DecryptSharedFont(const std::span<u32 const> input, std::span<u8> ou
|
|||||||
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
||||||
offset += transformed_font.size() * sizeof(u32);
|
offset += transformed_font.size() * sizeof(u32);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
|
void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
|
||||||
ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
|
ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
|
||||||
@@ -70,7 +72,7 @@ void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, s
|
|||||||
const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC);
|
const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC);
|
||||||
std::vector<u32> transformed_font(input.size() + 2);
|
std::vector<u32> transformed_font(input.size() + 2);
|
||||||
transformed_font[0] = Common::swap32(EXPECTED_MAGIC);
|
transformed_font[0] = Common::swap32(EXPECTED_MAGIC);
|
||||||
transformed_font[1] = Common::swap32(static_cast<u32>(input.size() * sizeof(u32))) ^ key;
|
transformed_font[1] = Common::swap32(u32(input.size() * sizeof(u32))) ^ key;
|
||||||
std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; });
|
std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; });
|
||||||
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32));
|
||||||
offset += transformed_font.size() * sizeof(u32);
|
offset += transformed_font.size() * sizeof(u32);
|
||||||
@@ -83,8 +85,10 @@ struct IPlatformServiceManager::Impl {
|
|||||||
// Automatically populated based on shared_fonts dump or system archives.
|
// Automatically populated based on shared_fonts dump or system archives.
|
||||||
// 6 builtin fonts + extra 2 for whatever may come after
|
// 6 builtin fonts + extra 2 for whatever may come after
|
||||||
boost::container::static_vector<FontRegion, 8> shared_font_regions;
|
boost::container::static_vector<FontRegion, 8> shared_font_regions;
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
/// Backing memory for the shared font data
|
/// Backing memory for the shared font data
|
||||||
std::array<u8, SHARED_FONT_MEM_SIZE> shared_font;
|
std::array<u8, SHARED_FONT_MEM_SIZE> shared_font;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
|
IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
|
||||||
@@ -111,49 +115,40 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
|
|||||||
// clang-format on
|
// clang-format on
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
auto& fsc = system.GetFileSystemController();
|
auto& fsc = system.GetFileSystemController();
|
||||||
|
|
||||||
// Attempt to load shared font data from disk
|
// Attempt to load shared font data from disk
|
||||||
const auto* nand = fsc.GetSystemNANDContents();
|
const auto* nand = fsc.GetSystemNANDContents();
|
||||||
std::size_t offset = 0;
|
std::size_t offset = 0;
|
||||||
// Rebuild shared fonts from data ncas or synthesize
|
// Rebuild shared fonts from data ncas or synthesize
|
||||||
for (auto& font : SHARED_FONTS) {
|
for (auto& font : SHARED_FONTS) {
|
||||||
FileSys::VirtualFile romfs;
|
FileSys::VirtualFile romfs;
|
||||||
const auto nca =
|
if (auto const nca = nand->GetEntry(u64(font.first), FileSys::ContentRecordType::Data); nca)
|
||||||
nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
|
|
||||||
if (nca) {
|
|
||||||
romfs = nca->GetRomFS();
|
romfs = nca->GetRomFS();
|
||||||
}
|
if (!romfs)
|
||||||
|
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(u64(font.first));
|
||||||
if (!romfs) {
|
if (romfs) {
|
||||||
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(static_cast<u64>(font.first));
|
if (auto const extracted_romfs = FileSys::ExtractRomFS(romfs); extracted_romfs) {
|
||||||
}
|
if (auto const font_fp = extracted_romfs->GetFile(font.second); font_fp) {
|
||||||
|
std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32));
|
||||||
if (!romfs) {
|
font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize());
|
||||||
|
// We need to be BigEndian as u32s for the xor encryption
|
||||||
|
std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(), Common::swap32);
|
||||||
|
// Font offset and size do not account for the header
|
||||||
|
const FontRegion region{u32(offset + 8), u32((font_data_u32.size() * sizeof(u32)) - 8)};
|
||||||
|
DecryptSharedFont(font_data_u32, impl->shared_font, offset);
|
||||||
|
impl->shared_font_regions.push_back(region);
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first);
|
LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto extracted_romfs = FileSys::ExtractRomFS(romfs);
|
|
||||||
if (!extracted_romfs) {
|
|
||||||
LOG_ERROR(Service_NS, "Failed to extract RomFS for {:016X}! Skipping", font.first);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto font_fp = extracted_romfs->GetFile(font.second);
|
|
||||||
if (!font_fp) {
|
|
||||||
LOG_ERROR(Service_NS, "{:016X} has no file \"{}\"! Skipping", font.first, font.second);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
std::vector<u32> font_data_u32(font_fp->GetSize() / sizeof(u32));
|
|
||||||
font_fp->ReadBytes<u32>(font_data_u32.data(), font_fp->GetSize());
|
|
||||||
// We need to be BigEndian as u32s for the xor encryption
|
|
||||||
std::transform(font_data_u32.begin(), font_data_u32.end(), font_data_u32.begin(),
|
|
||||||
Common::swap32);
|
|
||||||
// Font offset and size do not account for the header
|
|
||||||
const FontRegion region{u32(offset + 8), u32((font_data_u32.size() * sizeof(u32)) - 8)};
|
|
||||||
DecryptSharedFont(font_data_u32, impl->shared_font, offset);
|
|
||||||
impl->shared_font_regions.push_back(region);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
IPlatformServiceManager::~IPlatformServiceManager() = default;
|
IPlatformServiceManager::~IPlatformServiceManager() = default;
|
||||||
@@ -187,8 +182,10 @@ Result IPlatformServiceManager::GetSharedMemoryNativeHandle(OutCopyHandle<Kernel
|
|||||||
// Map backing memory for the font data
|
// Map backing memory for the font data
|
||||||
LOG_DEBUG(Service_NS, "called");
|
LOG_DEBUG(Service_NS, "called");
|
||||||
|
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
// Create shared font memory object
|
// Create shared font memory object
|
||||||
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font.data(), impl->shared_font.size());
|
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font.data(), impl->shared_font.size());
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME: this shouldn't belong to the kernel
|
// FIXME: this shouldn't belong to the kernel
|
||||||
*out_shared_memory_native_handle = &kernel.GetFontSharedMem();
|
*out_shared_memory_native_handle = &kernel.GetFontSharedMem();
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -60,7 +63,11 @@ private:
|
|||||||
std::size_t current_index{0};
|
std::size_t current_index{0};
|
||||||
/// Stores an hour of historical frametime data useful for processing and tracking performance
|
/// Stores an hour of historical frametime data useful for processing and tracking performance
|
||||||
/// regressions with code changes.
|
/// regressions with code changes.
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
std::array<double, 60> perf_history{};
|
||||||
|
#else
|
||||||
std::array<double, 216000> perf_history{};
|
std::array<double, 216000> perf_history{};
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Point when the cumulative counters were reset
|
/// Point when the cumulative counters were reset
|
||||||
Clock::time_point reset_point = Clock::now();
|
Clock::time_point reset_point = Clock::now();
|
||||||
|
|||||||
@@ -66,12 +66,16 @@ public:
|
|||||||
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
||||||
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
signal_stack_memory = std::make_unique<uint8_t[]>(stack_size);
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
fmt::print(stderr, "no fastmem on PS4\n");
|
||||||
|
supports_fast_mem = false;
|
||||||
|
#else
|
||||||
stack_t signal_stack{};
|
stack_t signal_stack{};
|
||||||
signal_stack.ss_sp = signal_stack_memory.get();
|
signal_stack.ss_sp = signal_stack_memory.get();
|
||||||
signal_stack.ss_size = stack_size;
|
signal_stack.ss_size = stack_size;
|
||||||
signal_stack.ss_flags = 0;
|
signal_stack.ss_flags = 0;
|
||||||
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
if (sigaltstack(&signal_stack, nullptr) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
|
fmt::print(stderr, "POSIX SigHandler: init failure at sigaltstack\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -82,16 +86,17 @@ public:
|
|||||||
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
if (sigaction(SIGSEGV, &sa, &old_sa_segv) != 0) {
|
if (sigaction(SIGSEGV, &sa, &old_sa_segv) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGSEGV handler\n");
|
fmt::print(stderr, "POSIX SigHandler: could not set SIGSEGV handler\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
|
||||||
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
|
fmt::print(stderr, "POSIX SigHandler: could not set SIGBUS handler\n");
|
||||||
supports_fast_mem = false;
|
supports_fast_mem = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,6 +150,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
}
|
}
|
||||||
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
LOG_ERROR(Core, "Unhandled {} at {:#018x}\n", sig == SIGSEGV ? "SIGSEGV" : "SIGBUS", CTX_PC);
|
||||||
|
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
// No fastmem
|
||||||
|
#else
|
||||||
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
struct sigaction* retry_sa = sig == SIGSEGV ? &sig_handler->old_sa_segv : &sig_handler->old_sa_bus;
|
||||||
if (retry_sa->sa_flags & SA_SIGINFO) {
|
if (retry_sa->sa_flags & SA_SIGINFO) {
|
||||||
retry_sa->sa_sigaction(sig, info, raw_context);
|
retry_sa->sa_sigaction(sig, info, raw_context);
|
||||||
@@ -158,6 +166,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
retry_sa->sa_handler(sig);
|
retry_sa->sa_handler(sig);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|||||||
@@ -67,8 +67,14 @@ public:
|
|||||||
const void* code_ptr = nullptr;
|
const void* code_ptr = nullptr;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
static constexpr u64 fast_dispatch_table_mask = 0xFF0;
|
||||||
|
static constexpr size_t fast_dispatch_table_size = 0x100;
|
||||||
|
#else
|
||||||
static constexpr u64 fast_dispatch_table_mask = 0xFFFF0;
|
static constexpr u64 fast_dispatch_table_mask = 0xFFFF0;
|
||||||
static constexpr size_t fast_dispatch_table_size = 0x10000;
|
static constexpr size_t fast_dispatch_table_size = 0x10000;
|
||||||
|
#endif
|
||||||
|
|
||||||
void ClearFastDispatchTable();
|
void ClearFastDispatchTable();
|
||||||
void GenFastmemFallbacks();
|
void GenFastmemFallbacks();
|
||||||
void GenTerminalHandlers();
|
void GenTerminalHandlers();
|
||||||
|
|||||||
@@ -60,8 +60,13 @@ public:
|
|||||||
const void* code_ptr = nullptr;
|
const void* code_ptr = nullptr;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
static_assert(sizeof(FastDispatchEntry) == 0x10);
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
static constexpr u64 fast_dispatch_table_mask = 0xFF0;
|
||||||
|
static constexpr size_t fast_dispatch_table_size = 0x100;
|
||||||
|
#else
|
||||||
static constexpr u64 fast_dispatch_table_mask = 0xFFFFF0;
|
static constexpr u64 fast_dispatch_table_mask = 0xFFFFF0;
|
||||||
static constexpr size_t fast_dispatch_table_size = 0x100000;
|
static constexpr size_t fast_dispatch_table_size = 0x100000;
|
||||||
|
#endif
|
||||||
|
|
||||||
void ClearFastDispatchTable();
|
void ClearFastDispatchTable();
|
||||||
void GenMemory128Accessors();
|
void GenMemory128Accessors();
|
||||||
|
|||||||
@@ -41,9 +41,10 @@ EmitContext::EmitContext(RegAlloc& reg_alloc, IR::Block& block, boost::container
|
|||||||
|
|
||||||
EmitContext::~EmitContext() = default;
|
EmitContext::~EmitContext() = default;
|
||||||
|
|
||||||
EmitX64::EmitX64(BlockOfCode& code)
|
EmitX64::EmitX64(BlockOfCode& code) : code(code) {
|
||||||
: code(code) {
|
#ifndef __OPENORBIS__
|
||||||
exception_handler.Register(code);
|
exception_handler.Register(code);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
EmitX64::~EmitX64() = default;
|
EmitX64::~EmitX64() = default;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@
|
|||||||
# define CTX_Q(i) (fpctx->vregs[i])
|
# define CTX_Q(i) (fpctx->vregs[i])
|
||||||
# define CTX_FPSR (fpctx->fpsr)
|
# define CTX_FPSR (fpctx->fpsr)
|
||||||
# define CTX_FPCR (fpctx->fpcr)
|
# define CTX_FPCR (fpctx->fpcr)
|
||||||
# elif defined(__FreeBSD__)
|
# elif defined(__FreeBSD__) || defined(__DragonFly__)
|
||||||
# define CTX_PC (mctx.mc_gpregs.gp_elr)
|
# define CTX_PC (mctx.mc_gpregs.gp_elr)
|
||||||
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
# define CTX_SP (mctx.mc_gpregs.gp_sp)
|
||||||
# define CTX_LR (mctx.mc_gpregs.gp_lr)
|
# define CTX_LR (mctx.mc_gpregs.gp_lr)
|
||||||
@@ -131,6 +131,9 @@
|
|||||||
# elif defined(__managarm__)
|
# elif defined(__managarm__)
|
||||||
# define CTX_PC (mctx.__pollution(gregs)[REG_RIP])
|
# define CTX_PC (mctx.__pollution(gregs)[REG_RIP])
|
||||||
# define CTX_SP (mctx.__pollution(gregs)[REG_RSP])
|
# define CTX_SP (mctx.__pollution(gregs)[REG_RSP])
|
||||||
|
# elif defined(__OPENORBIS__)
|
||||||
|
# define CTX_RIP (mctx.gregs[REG_RIP])
|
||||||
|
# define CTX_RSP (mctx.gregs[REG_RSP])
|
||||||
# else
|
# else
|
||||||
# error "unknown platform"
|
# error "unknown platform"
|
||||||
# endif
|
# endif
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "dynarmic/backend/x64/abi.h"
|
#include "dynarmic/backend/x64/abi.h"
|
||||||
#include "dynarmic/backend/x64/hostloc.h"
|
#include "dynarmic/backend/x64/hostloc.h"
|
||||||
#include "dynarmic/common/spin_lock.h"
|
#include "dynarmic/common/spin_lock.h"
|
||||||
|
#include "xbyak/xbyak.h"
|
||||||
|
|
||||||
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
|
#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT
|
||||||
static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
|
static const auto default_cg_mode = Xbyak::DontSetProtectRWE;
|
||||||
@@ -78,7 +79,7 @@ namespace {
|
|||||||
struct SpinLockImpl {
|
struct SpinLockImpl {
|
||||||
void Initialize() noexcept;
|
void Initialize() noexcept;
|
||||||
static void GlobalInitialize() noexcept;
|
static void GlobalInitialize() noexcept;
|
||||||
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(4096, default_cg_mode);
|
Xbyak::CodeGenerator code = Xbyak::CodeGenerator(Xbyak::inner::getPageSize(), default_cg_mode);
|
||||||
void (*lock)(volatile int*) = nullptr;
|
void (*lock)(volatile int*) = nullptr;
|
||||||
void (*unlock)(volatile int*) = nullptr;
|
void (*unlock)(volatile int*) = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -134,3 +134,8 @@ target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS})
|
|||||||
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1)
|
||||||
|
|
||||||
add_test(NAME dynarmic_tests COMMAND dynarmic_tests --durations yes)
|
add_test(NAME dynarmic_tests COMMAND dynarmic_tests --durations yes)
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
target_link_libraries(dynarmic_tests PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService ps4sup)
|
||||||
|
create_ps4_eboot(dynarmic_tests dynarmic_tests IV0000-BREW00090_00-DYNARMICTS000000)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ std::set<s32> Android::GetDeviceAxes(JNIEnv* env, jobject& j_device) const {
|
|||||||
std::set<s32> axes;
|
std::set<s32> axes;
|
||||||
for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
|
for (int i = 0; i < env->GetArrayLength(j_axes); ++i) {
|
||||||
jobject axis = env->GetObjectArrayElement(j_axes, i);
|
jobject axis = env->GetObjectArrayElement(j_axes, i);
|
||||||
axes.insert(env->CallIntMethod(axis, Common::Android::GetIntegerValueMethod()));
|
axes.insert(env->GetIntField(axis, Common::Android::GetIntegerValueField()));
|
||||||
}
|
}
|
||||||
return axes;
|
return axes;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1033,27 +1033,20 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonMapping SDLDriver::GetSingleControllerMapping(
|
ButtonMapping SDLDriver::GetSingleControllerMapping(const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button, const ZButtonBindings& switch_to_sdl_axis) const {
|
||||||
const std::shared_ptr<SDLJoystick>& joystick, const ButtonBindings& switch_to_sdl_button,
|
|
||||||
const ZButtonBindings& switch_to_sdl_axis) const {
|
|
||||||
ButtonMapping mapping;
|
ButtonMapping mapping;
|
||||||
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
|
||||||
auto* controller = joystick->GetSDLGameController();
|
if (auto* controller = joystick->GetSDLGameController(); controller) {
|
||||||
const auto bindings = GetBindings(controller);
|
const auto bindings = GetBindings(controller);
|
||||||
|
|
||||||
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
|
||||||
const auto binding = GetBindingForButton(bindings, sdl_button);
|
const auto binding = GetBindingForButton(bindings, sdl_button);
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(switch_button, BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
switch_button,
|
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
|
||||||
}
|
}
|
||||||
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
|
||||||
const auto binding = GetBindingForAxis(bindings, sdl_axis);
|
const auto binding = GetBindingForAxis(bindings, sdl_axis);
|
||||||
mapping.insert_or_assign(
|
mapping.insert_or_assign(switch_button, BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
||||||
switch_button,
|
}
|
||||||
BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mapping;
|
return mapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,10 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
RegisterEngine("gcpad", gcadapter);
|
RegisterEngine("gcpad", gcadapter);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
|
// TODO: Issue in PS4, crash for UDP_client
|
||||||
RegisterEngine("cemuhookudp", udp_client);
|
RegisterEngine("cemuhookudp", udp_client);
|
||||||
|
#endif
|
||||||
RegisterEngine("tas", tas_input);
|
RegisterEngine("tas", tas_input);
|
||||||
RegisterEngine("camera", camera);
|
RegisterEngine("camera", camera);
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@@ -116,7 +119,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
UnregisterEngine(gcadapter);
|
UnregisterEngine(gcadapter);
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
UnregisterEngine(udp_client);
|
UnregisterEngine(udp_client);
|
||||||
|
#endif
|
||||||
UnregisterEngine(tas_input);
|
UnregisterEngine(tas_input);
|
||||||
UnregisterEngine(camera);
|
UnregisterEngine(camera);
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
@@ -152,8 +157,10 @@ struct InputSubsystem::Impl {
|
|||||||
auto gcadapter_devices = gcadapter->GetInputDevices();
|
auto gcadapter_devices = gcadapter->GetInputDevices();
|
||||||
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
auto udp_devices = udp_client->GetInputDevices();
|
auto udp_devices = udp_client->GetInputDevices();
|
||||||
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
auto joycon_devices = joycon->GetInputDevices();
|
auto joycon_devices = joycon->GetInputDevices();
|
||||||
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end());
|
||||||
@@ -186,9 +193,11 @@ struct InputSubsystem::Impl {
|
|||||||
return gcadapter;
|
return gcadapter;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return udp_client;
|
return udp_client;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
if (engine == sdl->GetEngineName()) {
|
if (engine == sdl->GetEngineName()) {
|
||||||
return sdl;
|
return sdl;
|
||||||
@@ -271,9 +280,11 @@ struct InputSubsystem::Impl {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
if (engine == udp_client->GetEngineName()) {
|
if (engine == udp_client->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (engine == tas_input->GetEngineName()) {
|
if (engine == tas_input->GetEngineName()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -300,7 +311,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
gcadapter->BeginConfiguration();
|
gcadapter->BeginConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
udp_client->BeginConfiguration();
|
udp_client->BeginConfiguration();
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
sdl->BeginConfiguration();
|
sdl->BeginConfiguration();
|
||||||
joycon->BeginConfiguration();
|
joycon->BeginConfiguration();
|
||||||
@@ -316,7 +329,9 @@ struct InputSubsystem::Impl {
|
|||||||
#ifdef ENABLE_LIBUSB
|
#ifdef ENABLE_LIBUSB
|
||||||
gcadapter->EndConfiguration();
|
gcadapter->EndConfiguration();
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
udp_client->EndConfiguration();
|
udp_client->EndConfiguration();
|
||||||
|
#endif
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
sdl->EndConfiguration();
|
sdl->EndConfiguration();
|
||||||
joycon->EndConfiguration();
|
joycon->EndConfiguration();
|
||||||
@@ -341,7 +356,9 @@ struct InputSubsystem::Impl {
|
|||||||
std::shared_ptr<Mouse> mouse;
|
std::shared_ptr<Mouse> mouse;
|
||||||
std::shared_ptr<TouchScreen> touch_screen;
|
std::shared_ptr<TouchScreen> touch_screen;
|
||||||
std::shared_ptr<TasInput::Tas> tas_input;
|
std::shared_ptr<TasInput::Tas> tas_input;
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
||||||
|
#endif
|
||||||
std::shared_ptr<Camera> camera;
|
std::shared_ptr<Camera> camera;
|
||||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||||
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
std::shared_ptr<VirtualGamepad> virtual_gamepad;
|
||||||
@@ -470,7 +487,9 @@ bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void InputSubsystem::ReloadInputDevices() {
|
void InputSubsystem::ReloadInputDevices() {
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
impl->udp_client.get()->ReloadSockets();
|
impl->udp_client.get()->ReloadSockets();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void InputSubsystem::BeginMapping(Polling::InputType type) {
|
void InputSubsystem::BeginMapping(Polling::InputType type) {
|
||||||
|
|||||||
@@ -150,7 +150,6 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent) {
|
|||||||
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
|
INSERT(Settings, anti_aliasing, tr("Anti-Aliasing Method:"),
|
||||||
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
|
tr("The anti-aliasing method to use.\nSMAA offers the best quality.\nFXAA "
|
||||||
"can produce a more stable picture in lower resolutions."));
|
"can produce a more stable picture in lower resolutions."));
|
||||||
INSERT(Settings, post_shader_chain, QString(), QString());
|
|
||||||
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
|
INSERT(Settings, fullscreen_mode, tr("Fullscreen Mode:"),
|
||||||
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
tr("The method used to render the window in fullscreen.\nBorderless offers the best "
|
||||||
"compatibility with the on-screen keyboard that some games request for "
|
"compatibility with the on-screen keyboard that some games request for "
|
||||||
|
|||||||
@@ -160,7 +160,13 @@ struct Values {
|
|||||||
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
||||||
|
|
||||||
// logging
|
// logging
|
||||||
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
|
Setting<bool> show_console{linkage,
|
||||||
|
#ifdef __OPENORBIS__
|
||||||
|
true,
|
||||||
|
#else
|
||||||
|
false,
|
||||||
|
#endif
|
||||||
|
"showConsole", Category::Ui};
|
||||||
|
|
||||||
// Screenshots
|
// Screenshots
|
||||||
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
||||||
|
|||||||
@@ -37,3 +37,8 @@ if (NOT MSVC)
|
|||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-unused-parameter>
|
||||||
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
$<$<COMPILE_LANGUAGE:C,CXX>:-Wno-missing-field-initializers>)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (OPENORBIS)
|
||||||
|
target_link_libraries(tests PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService ps4sup)
|
||||||
|
create_ps4_eboot(tests tests IV0000-BREW00090_00-DYNARMICTS000000)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -209,3 +209,74 @@ TEST_CASE("HostMemory: Partial sparse middle unmap and check bindings", "[common
|
|||||||
REQUIRE(ptr[0x0000] == 19);
|
REQUIRE(ptr[0x0000] == 19);
|
||||||
REQUIRE(ptr[0x3fff] == 12);
|
REQUIRE(ptr[0x3fff] == 12);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Nieche allocation", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x20000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x0000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x1000, 0, 0x2000, PERMS, HEAP);
|
||||||
|
mem.Map(0x3000, 0, 0x1000, PERMS, HEAP);
|
||||||
|
mem.Map(0, 0, 0x1000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Full unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x6000, 0, 0x16000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Right out of bounds unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x2000, 0x80000, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Left out of bounds unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x6000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x2000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Multiple placeholder unmap", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x1b000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x3000, 0x1c000, HEAP);
|
||||||
|
mem.Map(0x3000, 0, 0x20000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap between placeholders", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x0000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x2000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x2000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap to origin", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x4000, 0x4000, HEAP);
|
||||||
|
mem.Map(0, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("HostMemory: Unmap to right", "[common]") {
|
||||||
|
HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE);
|
||||||
|
REQUIRE(mem.BackingBasePointer() != nullptr);
|
||||||
|
mem.Map(0x4000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
mem.Unmap(0x8000, 0x4000, HEAP);
|
||||||
|
mem.Map(0x8000, 0, 0x4000, PERMS, HEAP);
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@
|
|||||||
#include "input_common/drivers/udp_client.h"
|
#include "input_common/drivers/udp_client.h"
|
||||||
#include "input_common/helpers/udp_protocol.h"
|
#include "input_common/helpers/udp_protocol.h"
|
||||||
|
|
||||||
|
// PS4 doesn't support cemuhook
|
||||||
|
#ifndef __OPENORBIS__
|
||||||
class FakeCemuhookServer {
|
class FakeCemuhookServer {
|
||||||
public:
|
public:
|
||||||
FakeCemuhookServer()
|
FakeCemuhookServer()
|
||||||
@@ -132,3 +133,4 @@ TEST_CASE("CalibrationConfigurationJob completed", "[input_common]") {
|
|||||||
REQUIRE(max_x == 200);
|
REQUIRE(max_x == 200);
|
||||||
REQUIRE(max_y == 200);
|
REQUIRE(max_y == 200);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -299,21 +299,6 @@ if (ENABLE_LSFG)
|
|||||||
target_compile_definitions(video_core PUBLIC HAS_LSFG)
|
target_compile_definitions(video_core PUBLIC HAS_LSFG)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (ENABLE_RESHADE)
|
|
||||||
target_sources(video_core PRIVATE
|
|
||||||
post_processing/fx_chain.cpp
|
|
||||||
post_processing/fx_chain.h
|
|
||||||
post_processing/fx_compile.cpp
|
|
||||||
post_processing/fx_compile.h
|
|
||||||
post_processing/fx_effect.cpp
|
|
||||||
post_processing/fx_effect.h
|
|
||||||
renderer_vulkan/present/post_process.cpp
|
|
||||||
renderer_vulkan/present/post_process.h
|
|
||||||
)
|
|
||||||
target_link_libraries(video_core PRIVATE reshadefx::reshadefx)
|
|
||||||
target_compile_definitions(video_core PUBLIC HAS_RESHADE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ENABLE_OPENGL)
|
if (ENABLE_OPENGL)
|
||||||
target_sources(video_core PRIVATE
|
target_sources(video_core PRIVATE
|
||||||
renderer_opengl/present/filters.cpp
|
renderer_opengl/present/filters.cpp
|
||||||
|
|||||||
@@ -1,293 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
|
||||||
|
|
||||||
#include "common/settings.h"
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
std::vector<std::string_view> Split(std::string_view value, char separator) {
|
|
||||||
std::vector<std::string_view> out;
|
|
||||||
size_t start = 0;
|
|
||||||
while (start <= value.size()) {
|
|
||||||
size_t end = value.find(separator, start);
|
|
||||||
if (end == std::string_view::npos) {
|
|
||||||
end = value.size();
|
|
||||||
}
|
|
||||||
out.push_back(value.substr(start, end - start));
|
|
||||||
start = end + 1;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsSerializableName(std::string_view value) {
|
|
||||||
return value.find_first_of(";|,=") == std::string_view::npos;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> ParseFxChain(std::string_view value) {
|
|
||||||
std::vector<FxChainEntry> parsed;
|
|
||||||
|
|
||||||
for (const std::string_view record : Split(value, ';')) {
|
|
||||||
if (record.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto fields = Split(record, '|');
|
|
||||||
if (fields.size() < 2 || fields[0].empty() || fields[1].empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(fields[0]);
|
|
||||||
entry.technique = std::string(fields[1]);
|
|
||||||
|
|
||||||
if (fields.size() >= 3) {
|
|
||||||
for (const std::string_view assignment : Split(fields[2], ',')) {
|
|
||||||
const size_t equals = assignment.find('=');
|
|
||||||
if (equals == std::string_view::npos) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const std::string name(assignment.substr(0, equals));
|
|
||||||
if (name.empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> components{};
|
|
||||||
size_t index = 0;
|
|
||||||
for (const std::string_view piece : Split(assignment.substr(equals + 1), '/')) {
|
|
||||||
if (index >= components.size()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
const std::string text(piece);
|
|
||||||
if (!text.empty()) {
|
|
||||||
components[index] = std::strtof(text.c_str(), nullptr);
|
|
||||||
}
|
|
||||||
++index;
|
|
||||||
}
|
|
||||||
entry.values.emplace(name, components);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parsed.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string SerializeFxChain(std::span<const FxChainEntry> entries) {
|
|
||||||
std::string out;
|
|
||||||
|
|
||||||
for (const auto& entry : entries) {
|
|
||||||
if (!IsSerializableName(entry.file) || !IsSerializableName(entry.technique)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!out.empty()) {
|
|
||||||
out += ';';
|
|
||||||
}
|
|
||||||
out += entry.file;
|
|
||||||
out += '|';
|
|
||||||
out += entry.technique;
|
|
||||||
out += '|';
|
|
||||||
|
|
||||||
bool first = true;
|
|
||||||
for (const auto& [name, value] : entry.values) {
|
|
||||||
if (!IsSerializableName(name)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!first) {
|
|
||||||
out += ',';
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
out += name;
|
|
||||||
out += '=';
|
|
||||||
for (size_t i = 0; i < value.size(); ++i) {
|
|
||||||
if (i > 0) {
|
|
||||||
out += '/';
|
|
||||||
}
|
|
||||||
out += fmt::format("{}", value[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChain& FxChain::Instance() {
|
|
||||||
static FxChain instance;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxChainSnapshot FxChain::Snapshot() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return FxChainSnapshot{
|
|
||||||
.entries = entries,
|
|
||||||
.generation = generation.load(std::memory_order_relaxed),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> FxChain::Entries() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return entries;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FxChain::Size() const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
return entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Append(std::string_view file, std::string_view technique) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(file);
|
|
||||||
entry.technique = std::string(technique);
|
|
||||||
entries.push_back(std::move(entry));
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Replace(size_t index, std::string_view file, std::string_view technique) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (entries[index].file == file && entries[index].technique == technique) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
FxChainEntry entry;
|
|
||||||
entry.file = std::string(file);
|
|
||||||
entry.technique = std::string(technique);
|
|
||||||
entries[index] = std::move(entry);
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Remove(size_t index) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries.erase(entries.begin() + static_cast<std::ptrdiff_t>(index));
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Move(size_t index, int delta) {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const std::ptrdiff_t target = static_cast<std::ptrdiff_t>(index) + delta;
|
|
||||||
if (target < 0 || target >= static_cast<std::ptrdiff_t>(entries.size())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::swap(entries[index], entries[static_cast<size_t>(target)]);
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::Clear() {
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
entries.clear();
|
|
||||||
}
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value) {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries[index].values[std::string(uniform)] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<f32, 4> FxChain::GetValue(size_t index, std::string_view uniform) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
const auto it = entries[index].values.find(std::string(uniform));
|
|
||||||
if (it == entries[index].values.end()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<std::string, std::array<f32, 4>> FxChain::EntryValues(size_t index) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
return entries[index].values;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FxChain::HasValue(size_t index, std::string_view uniform) const {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return entries[index].values.contains(std::string(uniform));
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::ResetValues(size_t index) {
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
if (index >= entries.size()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
entries[index].values.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::LoadFromSettings() {
|
|
||||||
auto loaded = ParseFxChain(Settings::values.post_shader_chain.GetValue());
|
|
||||||
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
entries = std::move(loaded);
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::StoreToSettings() const {
|
|
||||||
std::string serialized;
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
serialized = SerializeFxChain(entries);
|
|
||||||
}
|
|
||||||
Settings::values.post_shader_chain.SetValue(serialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FxChain::DropUnknownEntries() {
|
|
||||||
bool changed = false;
|
|
||||||
{
|
|
||||||
std::scoped_lock lock{mutex};
|
|
||||||
const auto removed = std::remove_if(entries.begin(), entries.end(), [](const FxChainEntry& entry) {
|
|
||||||
const FxEffectDesc* effect = FindFxEffect(entry.file);
|
|
||||||
if (effect == nullptr || !effect->Valid()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return std::find(effect->techniques.begin(), effect->techniques.end(),
|
|
||||||
entry.technique) == effect->techniques.end();
|
|
||||||
});
|
|
||||||
if (removed != entries.end()) {
|
|
||||||
entries.erase(removed, entries.end());
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (changed) {
|
|
||||||
generation.fetch_add(1, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <atomic>
|
|
||||||
#include <map>
|
|
||||||
#include <mutex>
|
|
||||||
#include <span>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
struct FxChainEntry {
|
|
||||||
std::string file;
|
|
||||||
std::string technique;
|
|
||||||
std::map<std::string, std::array<f32, 4>> values;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxChainSnapshot {
|
|
||||||
std::vector<FxChainEntry> entries;
|
|
||||||
u64 generation{};
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> ParseFxChain(std::string_view value);
|
|
||||||
|
|
||||||
std::string SerializeFxChain(std::span<const FxChainEntry> entries);
|
|
||||||
|
|
||||||
class FxChain {
|
|
||||||
public:
|
|
||||||
static FxChain& Instance();
|
|
||||||
|
|
||||||
FxChainSnapshot Snapshot() const;
|
|
||||||
|
|
||||||
std::vector<FxChainEntry> Entries() const;
|
|
||||||
|
|
||||||
size_t Size() const;
|
|
||||||
|
|
||||||
void Append(std::string_view file, std::string_view technique);
|
|
||||||
|
|
||||||
void Replace(size_t index, std::string_view file, std::string_view technique);
|
|
||||||
|
|
||||||
void Remove(size_t index);
|
|
||||||
|
|
||||||
void Move(size_t index, int delta);
|
|
||||||
|
|
||||||
void Clear();
|
|
||||||
|
|
||||||
void SetValue(size_t index, std::string_view uniform, const std::array<f32, 4>& value);
|
|
||||||
|
|
||||||
std::array<f32, 4> GetValue(size_t index, std::string_view uniform) const;
|
|
||||||
|
|
||||||
std::map<std::string, std::array<f32, 4>> EntryValues(size_t index) const;
|
|
||||||
|
|
||||||
bool HasValue(size_t index, std::string_view uniform) const;
|
|
||||||
|
|
||||||
void ResetValues(size_t index);
|
|
||||||
|
|
||||||
void LoadFromSettings();
|
|
||||||
|
|
||||||
void StoreToSettings() const;
|
|
||||||
|
|
||||||
void DropUnknownEntries();
|
|
||||||
|
|
||||||
private:
|
|
||||||
FxChain() = default;
|
|
||||||
|
|
||||||
mutable std::mutex mutex;
|
|
||||||
std::vector<FxChainEntry> entries;
|
|
||||||
std::atomic<u64> generation{1};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <memory>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include "effect_codegen.hpp"
|
|
||||||
#include "effect_parser.hpp"
|
|
||||||
#include "effect_preprocessor.hpp"
|
|
||||||
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/fs_util.h"
|
|
||||||
#include "video_core/post_processing/fx_compile.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
|
|
||||||
u32 color_bit_depth) {
|
|
||||||
FxCompileResult result;
|
|
||||||
|
|
||||||
if (!Common::FS::Exists(path)) {
|
|
||||||
result.error = "Effect file not found: " + Common::FS::PathToUTF8String(path);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
reshadefx::preprocessor preprocessor;
|
|
||||||
preprocessor.add_macro_definition("__RESHADE__", "50000");
|
|
||||||
preprocessor.add_macro_definition("__RESHADE_PERFORMANCE_MODE__", "1");
|
|
||||||
preprocessor.add_macro_definition("__RENDERER__", "0x20000");
|
|
||||||
preprocessor.add_macro_definition("__VENDOR__", "0");
|
|
||||||
preprocessor.add_macro_definition("__DEVICE__", "0");
|
|
||||||
preprocessor.add_macro_definition("__APPLICATION__", "0");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_WIDTH", std::to_string(width));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_HEIGHT", std::to_string(height));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_RCP_WIDTH", "(1.0 / BUFFER_WIDTH)");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_RCP_HEIGHT", "(1.0 / BUFFER_HEIGHT)");
|
|
||||||
preprocessor.add_macro_definition("BUFFER_COLOR_DEPTH", std::to_string(color_bit_depth));
|
|
||||||
preprocessor.add_macro_definition("BUFFER_COLOR_BIT_DEPTH", std::to_string(color_bit_depth));
|
|
||||||
|
|
||||||
for (const auto& include : GetFxIncludePaths(path)) {
|
|
||||||
preprocessor.add_include_path(include);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!preprocessor.append_file(path)) {
|
|
||||||
result.error = preprocessor.errors();
|
|
||||||
if (result.error.empty()) {
|
|
||||||
result.error = "Failed to preprocess " + Common::FS::PathToUTF8String(path);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unique_ptr<reshadefx::codegen> backend(
|
|
||||||
reshadefx::create_codegen_spirv(true, false, false, false, true));
|
|
||||||
|
|
||||||
reshadefx::parser parser;
|
|
||||||
if (!parser.parse(preprocessor.output(), backend.get())) {
|
|
||||||
result.error = parser.errors();
|
|
||||||
if (result.error.empty()) {
|
|
||||||
result.error = "Failed to parse " + Common::FS::PathToUTF8String(path);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.module = backend->module();
|
|
||||||
|
|
||||||
std::set<std::string> wanted;
|
|
||||||
for (const auto& technique : result.module.techniques) {
|
|
||||||
for (const auto& pass : technique.passes) {
|
|
||||||
if (!pass.vs_entry_point.empty()) {
|
|
||||||
wanted.insert(pass.vs_entry_point);
|
|
||||||
}
|
|
||||||
if (!pass.ps_entry_point.empty()) {
|
|
||||||
wanted.insert(pass.ps_entry_point);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& name : wanted) {
|
|
||||||
std::string binary;
|
|
||||||
std::string assembly;
|
|
||||||
std::string errors;
|
|
||||||
if (!backend->assemble_code_for_entry_point(name, binary, assembly, errors)) {
|
|
||||||
result.error = "Failed to assemble entry point '" + name + "': " + errors;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
if (binary.size() % sizeof(u32) != 0) {
|
|
||||||
result.error = "Entry point '" + name + "' produced a malformed SPIR-V module";
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<u32> words(binary.size() / sizeof(u32));
|
|
||||||
std::memcpy(words.data(), binary.data(), binary.size());
|
|
||||||
result.entry_points.emplace(name, std::move(words));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result.entry_points.empty()) {
|
|
||||||
result.error = "Effect declares no usable entry points";
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
#include "effect_module.hpp"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
struct FxCompileResult {
|
|
||||||
reshadefx::effect_module module;
|
|
||||||
std::map<std::string, std::vector<u32>> entry_points;
|
|
||||||
std::string error;
|
|
||||||
|
|
||||||
bool Succeeded() const {
|
|
||||||
return error.empty() && !entry_points.empty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
FxCompileResult CompileFxEffect(const std::filesystem::path& path, u32 width, u32 height,
|
|
||||||
u32 color_bit_depth);
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "common/fs/fs.h"
|
|
||||||
#include "common/fs/fs_util.h"
|
|
||||||
#include "common/fs/path_util.h"
|
|
||||||
#include "common/logging.h"
|
|
||||||
#include "video_core/post_processing/fx_compile.h"
|
|
||||||
#include "video_core/post_processing/fx_effect.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr u32 CATALOG_PROBE_WIDTH = 1280;
|
|
||||||
constexpr u32 CATALOG_PROBE_HEIGHT = 720;
|
|
||||||
constexpr u32 CATALOG_PROBE_DEPTH = 8;
|
|
||||||
|
|
||||||
std::vector<FxEffectDesc> catalog;
|
|
||||||
|
|
||||||
const reshadefx::annotation* FindAnnotation(const std::vector<reshadefx::annotation>& annotations,
|
|
||||||
std::string_view name) {
|
|
||||||
const auto it = std::find_if(annotations.begin(), annotations.end(),
|
|
||||||
[&](const reshadefx::annotation& a) { return a.name == name; });
|
|
||||||
if (it == annotations.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AnnotationString(const std::vector<reshadefx::annotation>& annotations,
|
|
||||||
std::string_view name) {
|
|
||||||
const reshadefx::annotation* a = FindAnnotation(annotations, name);
|
|
||||||
if (a == nullptr) {
|
|
||||||
return std::string();
|
|
||||||
}
|
|
||||||
return a->value.string_data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AnnotationFloat(const std::vector<reshadefx::annotation>& annotations, std::string_view name,
|
|
||||||
f32& out) {
|
|
||||||
const reshadefx::annotation* a = FindAnnotation(annotations, name);
|
|
||||||
if (a == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (a->type.is_floating_point()) {
|
|
||||||
out = a->value.as_float[0];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (a->type.is_integral()) {
|
|
||||||
out = static_cast<f32>(a->value.as_int[0]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxUiType ParseUiType(std::string_view value) {
|
|
||||||
if (value == "slider") {
|
|
||||||
return FxUiType::Slider;
|
|
||||||
}
|
|
||||||
if (value == "drag") {
|
|
||||||
return FxUiType::Drag;
|
|
||||||
}
|
|
||||||
if (value == "combo") {
|
|
||||||
return FxUiType::Combo;
|
|
||||||
}
|
|
||||||
if (value == "radio") {
|
|
||||||
return FxUiType::Radio;
|
|
||||||
}
|
|
||||||
if (value == "check" || value == "checkbox") {
|
|
||||||
return FxUiType::CheckBox;
|
|
||||||
}
|
|
||||||
if (value == "color") {
|
|
||||||
return FxUiType::Color;
|
|
||||||
}
|
|
||||||
if (value == "input") {
|
|
||||||
return FxUiType::InputBox;
|
|
||||||
}
|
|
||||||
return FxUiType::Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> SplitItems(const std::string& items) {
|
|
||||||
std::vector<std::string> out;
|
|
||||||
std::string current;
|
|
||||||
for (const char c : items) {
|
|
||||||
if (c == '\0') {
|
|
||||||
out.push_back(current);
|
|
||||||
current.clear();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
current += c;
|
|
||||||
}
|
|
||||||
if (!current.empty()) {
|
|
||||||
out.push_back(current);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxUniformDesc DescribeUniform(const reshadefx::uniform& info) {
|
|
||||||
FxUniformDesc desc;
|
|
||||||
desc.name = info.name;
|
|
||||||
desc.components = std::min<u32>(info.type.components(), 4);
|
|
||||||
|
|
||||||
if (info.type.is_boolean()) {
|
|
||||||
desc.kind = FxUniformKind::Boolean;
|
|
||||||
} else if (info.type.is_integral()) {
|
|
||||||
desc.kind = FxUniformKind::Integer;
|
|
||||||
} else {
|
|
||||||
desc.kind = FxUniformKind::Floating;
|
|
||||||
}
|
|
||||||
|
|
||||||
desc.label = AnnotationString(info.annotations, "ui_label");
|
|
||||||
if (desc.label.empty()) {
|
|
||||||
desc.label = info.name;
|
|
||||||
}
|
|
||||||
desc.tooltip = AnnotationString(info.annotations, "ui_tooltip");
|
|
||||||
desc.category = AnnotationString(info.annotations, "ui_category");
|
|
||||||
desc.ui_type = ParseUiType(AnnotationString(info.annotations, "ui_type"));
|
|
||||||
desc.items = SplitItems(AnnotationString(info.annotations, "ui_items"));
|
|
||||||
|
|
||||||
if (desc.kind == FxUniformKind::Boolean) {
|
|
||||||
desc.ui_min = 0.0f;
|
|
||||||
desc.ui_max = 1.0f;
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
} else if (desc.kind == FxUniformKind::Integer) {
|
|
||||||
desc.ui_min = 0.0f;
|
|
||||||
desc.ui_max = 100.0f;
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_min", desc.ui_min));
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_max", desc.ui_max));
|
|
||||||
void(AnnotationFloat(info.annotations, "ui_step", desc.ui_step));
|
|
||||||
|
|
||||||
if (desc.ui_step <= 0.0f) {
|
|
||||||
desc.ui_step = 0.01f;
|
|
||||||
if (desc.kind != FxUniformKind::Floating) {
|
|
||||||
desc.ui_step = 1.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (desc.ui_max < desc.ui_min) {
|
|
||||||
std::swap(desc.ui_min, desc.ui_max);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info.has_initializer_value) {
|
|
||||||
for (u32 i = 0; i < desc.components; ++i) {
|
|
||||||
if (desc.kind == FxUniformKind::Floating) {
|
|
||||||
desc.default_value[i] = info.initializer_value.as_float[i];
|
|
||||||
} else {
|
|
||||||
desc.default_value[i] = static_cast<f32>(info.initializer_value.as_int[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
FxEffectDesc DescribeEffect(const std::filesystem::path& path, const std::filesystem::path& root) {
|
|
||||||
FxEffectDesc desc;
|
|
||||||
desc.file = Common::FS::PathToUTF8String(std::filesystem::relative(path, root));
|
|
||||||
desc.name = Common::FS::PathToUTF8String(path.stem());
|
|
||||||
|
|
||||||
const auto compiled =
|
|
||||||
CompileFxEffect(path, CATALOG_PROBE_WIDTH, CATALOG_PROBE_HEIGHT, CATALOG_PROBE_DEPTH);
|
|
||||||
if (!compiled.Succeeded()) {
|
|
||||||
desc.error = compiled.error;
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& technique : compiled.module.techniques) {
|
|
||||||
desc.techniques.push_back(technique.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& uniform : compiled.module.uniforms) {
|
|
||||||
FxUniformDesc uniform_desc = DescribeUniform(uniform);
|
|
||||||
if (uniform_desc.ui_type == FxUiType::Hidden) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
desc.uniforms.push_back(std::move(uniform_desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Anonymous namespace
|
|
||||||
|
|
||||||
std::filesystem::path GetFxRootDirectory() {
|
|
||||||
return Common::FS::GetEdenPath(Common::FS::EdenPath::PostShaderDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path) {
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
std::vector<std::filesystem::path> paths;
|
|
||||||
paths.push_back(effect_path.parent_path());
|
|
||||||
paths.push_back(root);
|
|
||||||
paths.push_back(root / "Shaders");
|
|
||||||
|
|
||||||
const auto last = std::unique(paths.begin(), paths.end());
|
|
||||||
paths.erase(last, paths.end());
|
|
||||||
return paths;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
|
|
||||||
std::string_view source) {
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
const std::filesystem::path name{source};
|
|
||||||
|
|
||||||
const std::array candidates{
|
|
||||||
effect_path.parent_path() / name,
|
|
||||||
root / "Textures" / name,
|
|
||||||
root / name,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const auto& candidate : candidates) {
|
|
||||||
if (Common::FS::Exists(candidate)) {
|
|
||||||
return candidate;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::filesystem::path();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ReloadFxCatalog() {
|
|
||||||
catalog.clear();
|
|
||||||
|
|
||||||
const auto root = GetFxRootDirectory();
|
|
||||||
if (!Common::FS::Exists(root)) {
|
|
||||||
void(Common::FS::CreateDirs(root));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> effect_files;
|
|
||||||
Common::FS::IterateDirEntriesRecursively(
|
|
||||||
root,
|
|
||||||
[&](const std::filesystem::directory_entry& entry) {
|
|
||||||
if (entry.path().extension() == ".fx") {
|
|
||||||
effect_files.push_back(entry.path());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
Common::FS::DirEntryFilter::File);
|
|
||||||
|
|
||||||
std::sort(effect_files.begin(), effect_files.end());
|
|
||||||
|
|
||||||
for (const auto& file : effect_files) {
|
|
||||||
FxEffectDesc desc = DescribeEffect(file, root);
|
|
||||||
if (!desc.error.empty()) {
|
|
||||||
LOG_WARNING(Render, "Post-processing effect '{}' failed to compile:\n{}", desc.file,
|
|
||||||
desc.error);
|
|
||||||
}
|
|
||||||
catalog.push_back(std::move(desc));
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t usable = std::count_if(catalog.begin(), catalog.end(),
|
|
||||||
[](const FxEffectDesc& d) { return d.Valid(); });
|
|
||||||
LOG_INFO(Render, "Loaded {} post-processing effects ({} usable)", catalog.size(), usable);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::vector<FxEffectDesc>& GetFxCatalog() {
|
|
||||||
return catalog;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FxEffectDesc* FindFxEffect(std::string_view file) {
|
|
||||||
const auto it = std::find_if(catalog.begin(), catalog.end(),
|
|
||||||
[&](const FxEffectDesc& d) { return d.file == file; });
|
|
||||||
if (it == catalog.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name) {
|
|
||||||
const auto it = std::find_if(effect.uniforms.begin(), effect.uniforms.end(),
|
|
||||||
[&](const FxUniformDesc& u) { return u.name == name; });
|
|
||||||
if (it == effect.uniforms.end()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <filesystem>
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace VideoCore {
|
|
||||||
|
|
||||||
enum class FxUniformKind {
|
|
||||||
Boolean,
|
|
||||||
Integer,
|
|
||||||
Floating,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class FxUiType {
|
|
||||||
Hidden,
|
|
||||||
Slider,
|
|
||||||
Drag,
|
|
||||||
Combo,
|
|
||||||
Radio,
|
|
||||||
CheckBox,
|
|
||||||
Color,
|
|
||||||
InputBox,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxUniformDesc {
|
|
||||||
std::string name;
|
|
||||||
std::string label;
|
|
||||||
std::string tooltip;
|
|
||||||
std::string category;
|
|
||||||
FxUniformKind kind{FxUniformKind::Floating};
|
|
||||||
u32 components{1};
|
|
||||||
FxUiType ui_type{FxUiType::Hidden};
|
|
||||||
f32 ui_min{0.0f};
|
|
||||||
f32 ui_max{1.0f};
|
|
||||||
f32 ui_step{0.01f};
|
|
||||||
std::vector<std::string> items;
|
|
||||||
std::array<f32, 4> default_value{};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FxEffectDesc {
|
|
||||||
std::string file;
|
|
||||||
std::string name;
|
|
||||||
std::vector<std::string> techniques;
|
|
||||||
std::vector<FxUniformDesc> uniforms;
|
|
||||||
std::string error;
|
|
||||||
|
|
||||||
bool Valid() const {
|
|
||||||
return error.empty() && !techniques.empty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
std::filesystem::path GetFxRootDirectory();
|
|
||||||
|
|
||||||
std::vector<std::filesystem::path> GetFxIncludePaths(const std::filesystem::path& effect_path);
|
|
||||||
|
|
||||||
std::filesystem::path ResolveFxTexturePath(const std::filesystem::path& effect_path,
|
|
||||||
std::string_view source);
|
|
||||||
|
|
||||||
void ReloadFxCatalog();
|
|
||||||
|
|
||||||
const std::vector<FxEffectDesc>& GetFxCatalog();
|
|
||||||
|
|
||||||
const FxEffectDesc* FindFxEffect(std::string_view file);
|
|
||||||
|
|
||||||
const FxUniformDesc* FindFxUniform(const FxEffectDesc& effect, std::string_view name);
|
|
||||||
|
|
||||||
} // namespace VideoCore
|
|
||||||
@@ -18,10 +18,6 @@
|
|||||||
#include "video_core/renderer_vulkan/present/sgsr.h"
|
#include "video_core/renderer_vulkan/present/sgsr.h"
|
||||||
#include "video_core/renderer_vulkan/present/fxaa.h"
|
#include "video_core/renderer_vulkan/present/fxaa.h"
|
||||||
#include "video_core/renderer_vulkan/present/layer.h"
|
#include "video_core/renderer_vulkan/present/layer.h"
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/post_processing/fx_chain.h"
|
|
||||||
#include "video_core/renderer_vulkan/present/post_process.h"
|
|
||||||
#endif
|
|
||||||
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
#include "video_core/renderer_vulkan/present/present_push_constants.h"
|
||||||
#include "video_core/renderer_vulkan/present/smaa.h"
|
#include "video_core/renderer_vulkan/present/smaa.h"
|
||||||
#include "video_core/renderer_vulkan/present/util.h"
|
#include "video_core/renderer_vulkan/present/util.h"
|
||||||
@@ -97,9 +93,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
|
|||||||
|
|
||||||
RefreshResources(device, framebuffer);
|
RefreshResources(device, framebuffer);
|
||||||
SetAntiAliasPass(device);
|
SetAntiAliasPass(device);
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
SetPostProcessPass(device);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Finish any pending renderpass
|
// Finish any pending renderpass
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
@@ -122,12 +115,6 @@ void Layer::ConfigureDraw(const Device& device, PresentPushConstants* out_push_c
|
|||||||
smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
smaa->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
if (post_process.has_value()) {
|
|
||||||
post_process->Draw(device, scheduler, image_index, &source_image, &source_image_view);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
|
auto crop_rect = Tegra::NormalizeCrop(framebuffer, texture_width, texture_height);
|
||||||
const VkExtent2D render_extent{
|
const VkExtent2D render_extent{
|
||||||
.width = scaled_width,
|
.width = scaled_width,
|
||||||
@@ -227,40 +214,6 @@ void Layer::SetAntiAliasPass(const Device& device) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
void Layer::SetPostProcessPass(const Device& device) {
|
|
||||||
const VkExtent2D render_area{
|
|
||||||
.width = Settings::values.resolution_info.ScaleUp(raw_width),
|
|
||||||
.height = Settings::values.resolution_info.ScaleUp(raw_height),
|
|
||||||
};
|
|
||||||
|
|
||||||
const u64 generation = VideoCore::FxChain::Instance().Snapshot().generation;
|
|
||||||
|
|
||||||
if (post_process_generation == generation && post_process_extent.width == render_area.width &&
|
|
||||||
post_process_extent.height == render_area.height) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const u64 tick : resource_ticks) {
|
|
||||||
scheduler.Wait(tick);
|
|
||||||
}
|
|
||||||
|
|
||||||
post_process_generation = generation;
|
|
||||||
post_process_extent = render_area;
|
|
||||||
post_process.reset();
|
|
||||||
|
|
||||||
if (VideoCore::FxChain::Instance().Size() == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
post_process.emplace(device, memory_allocator, scheduler, image_count, render_area);
|
|
||||||
|
|
||||||
if (post_process->Empty()) {
|
|
||||||
post_process.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void Layer::ReleaseRawImages() {
|
void Layer::ReleaseRawImages() {
|
||||||
for (const u64 tick : resource_ticks) {
|
for (const u64 tick : resource_ticks) {
|
||||||
scheduler.Wait(tick);
|
scheduler.Wait(tick);
|
||||||
|
|||||||
@@ -15,9 +15,6 @@
|
|||||||
#include "video_core/renderer_vulkan/present/fsr.h"
|
#include "video_core/renderer_vulkan/present/fsr.h"
|
||||||
#include "video_core/renderer_vulkan/present/sgsr.h"
|
#include "video_core/renderer_vulkan/present/sgsr.h"
|
||||||
#include "video_core/renderer_vulkan/present/fxaa.h"
|
#include "video_core/renderer_vulkan/present/fxaa.h"
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
#include "video_core/renderer_vulkan/present/post_process.h"
|
|
||||||
#endif
|
|
||||||
#include "video_core/renderer_vulkan/present/smaa.h"
|
#include "video_core/renderer_vulkan/present/smaa.h"
|
||||||
|
|
||||||
namespace Layout {
|
namespace Layout {
|
||||||
@@ -69,9 +66,6 @@ private:
|
|||||||
|
|
||||||
void RefreshResources(const Device& device, const Tegra::FramebufferConfig& framebuffer);
|
void RefreshResources(const Device& device, const Tegra::FramebufferConfig& framebuffer);
|
||||||
void SetAntiAliasPass(const Device& device);
|
void SetAntiAliasPass(const Device& device);
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
void SetPostProcessPass(const Device& device);
|
|
||||||
#endif
|
|
||||||
void ReleaseRawImages();
|
void ReleaseRawImages();
|
||||||
|
|
||||||
u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
|
u64 CalculateBufferSize(const Tegra::FramebufferConfig& framebuffer) const;
|
||||||
@@ -101,11 +95,6 @@ private:
|
|||||||
Settings::AntiAliasing anti_alias_setting{};
|
Settings::AntiAliasing anti_alias_setting{};
|
||||||
std::variant<std::monostate, FXAA, SMAA> anti_alias{};
|
std::variant<std::monostate, FXAA, SMAA> anti_alias{};
|
||||||
std::variant<std::monostate, SGSR, FSR> sr_filter{};
|
std::variant<std::monostate, SGSR, FSR> sr_filter{};
|
||||||
#ifdef HAS_RESHADE
|
|
||||||
std::optional<PostProcessChain> post_process{};
|
|
||||||
u64 post_process_generation{};
|
|
||||||
VkExtent2D post_process_extent{};
|
|
||||||
#endif
|
|
||||||
std::vector<u64> resource_ticks{};
|
std::vector<u64> resource_ticks{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user