Compare commits

..

8 Commits

Author SHA1 Message Date
lizzie bda8ba61d6 Fix license headers 2026-09-01 10:04:20 +00:00
lizzie 9443c1590b evil 2026-09-01 06:40:41 +00:00
lizzie da71711bed param vec 2026-09-01 05:56:47 +00:00
lizzie d3b6283f4f [common] remove unused vector_math.h fluff
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-09-01 05:15:56 +00:00
lizzie 858f9e5aea [docs] Various grammar fixes, fix dead links, update deps.md, merge RDOC into Debug.md (#4315)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

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

updates deps.md (freebsd had a package that didnt exist, oops)
netbsd also had outdated packages

moved windows caveats into the user guide (because well, those are user stuff, not build caveats)

MANY redundant wording removals (especially on dynarmic)

proper capitalization of Eden, Dynarmic, Amiibo, and CLion

fixed discord link on metainfo as well
also fixed file associations as well otherwise installed eden wont have icon over NSP/XCI/etc files

"please" is filler

fixes a HANDFUL of dead links as well

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4315
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
2026-09-01 06:45:47 +02:00
crueter e53e76168c [externals] Update CI packages to new format (#4341)
Qt hasn't been updated to the new format yet, will do so later.

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

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

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

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4341
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Lizzie and Samuel <lizzie@eden-emu.dev>
2026-09-01 06:40:52 +02:00
lizzie cb9ec1dc1a [dynarmic] fix perf regression due to hard CPUID queries (#4328)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

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

should fix whatever issue bruno had on Windows

basically CPUID ctor object for xbyak is very VERY heavy, so we just move that to a static we do once on program startup instead!

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4328
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: Maufeat <sahyno1996@gmail.com>
2026-08-31 23:51:56 +02:00
lizzie f7e5ceeacb [video_core/buffer_cache] fix PAGE_SHIFT/BSD macro clash on Linux, *BSD (#4329)
Signed-off-by: lizzie <lizzie@eden-emu.dev>

- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
- [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md)
- [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.

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

PAGE_SHIFT is a macro (sys/user.h on linux, machine/params.h on FBSD), dont name stuff that
https://stackoverflow.com/questions/77611721/get-page-shift-value-in-user-space

BSD is also a macro

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4329
Reviewed-by: CamilleLaVey <camillelavey99@gmail.com>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
2026-08-31 21:34:01 +02:00
139 changed files with 990 additions and 4666 deletions
-66
View File
@@ -1,66 +0,0 @@
#!/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
-3
View File
@@ -63,6 +63,3 @@ artifacts
/install*
vulkansdk*.exe
*.tar.zst
# PS4 toolchain stuff
ps4-toolchain.cmake
-17
View File
@@ -1,17 +0,0 @@
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>
-13
View File
@@ -1,13 +0,0 @@
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
-15
View File
@@ -1,15 +0,0 @@
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
@@ -1,40 +0,0 @@
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}
@@ -1,33 +0,0 @@
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
@@ -1,13 +0,0 @@
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;
/*
-196
View File
@@ -1,196 +0,0 @@
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
-25
View File
@@ -1,25 +0,0 @@
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"
-1
View File
@@ -22,7 +22,6 @@ include(UseCcache)
include(CMakeDependentOption)
include(CTest)
include(CPMUtil)
include(OpenOrbis)
if (NOT DEFINED ARCHITECTURE)
message(FATAL_ERROR "Architecture didn't make it out of scope, did you delete DetectArchitecture.cmake?")
+102 -65
View File
@@ -552,7 +552,6 @@ macro(parse_object object)
get_json_element("${object}" repo repo)
get_json_element("${object}" ci ci OFF)
get_json_element("${object}" version version)
get_json_element("${object}" min_version min_version)
get_json_element("${object}" git_host git_host "github.com")
if (NOT version)
@@ -571,8 +570,8 @@ macro(parse_object object)
set(disabled_platforms "")
endif()
else()
# TODO: correct hash if missing
get_json_element("${object}" hash hash)
get_json_element("${object}" min_version min_version)
get_json_element("${object}" url url)
get_json_element("${object}" artifact artifact)
get_json_element("${object}" source_subdir source_subdir)
@@ -945,8 +944,8 @@ function(AddCIPackage)
REPO
PACKAGE
EXTENSION
MIN_VERSION
GIT_HOST)
GIT_HOST
PKGNAME)
set(multiValueArgs DISABLED_PLATFORMS)
@@ -996,9 +995,104 @@ function(AddCIPackage)
set(ARTIFACT_REPO ${PKG_ARGS_REPO})
set(ARTIFACT_PACKAGE ${PKG_ARGS_PACKAGE})
# TODO: Use amd64/aarch64 naming for everything.
# Also drop macos universal
# plat/archname
if (DEFINED PKG_ARGS_PKGNAME)
set(pkgname ${PKG_ARGS_PKGNAME})
else()
if (MSVC)
set(platname windows)
elseif(MINGW)
set(platname mingw)
elseif(ANDROID)
set(platname android)
elseif(LINUX)
set(platname linux)
elseif(IOS)
set(platname ios)
elseif(APPLE)
set(platname macos)
else()
cpm_utils_message(WARNING
"Unsupported platform ${CMAKE_SYSTEM_NAME} for CI packages")
endif()
if (CPMUTIL_AMD64)
set(archname amd64)
elseif(CPMUTIL_ARM64)
set(archname aarch64)
elseif(CPMUTIL_RISCV64)
set(archname riscv64)
endif()
if (APPLE AND NOT CPMUTIL_ARM64)
cpm_utils_message(WARNING
"Unsupported platform/arch combo for CI packages")
endif()
if (DEFINED platname AND DEFINED archname)
set(pkgname ${platname}-${archname})
endif()
endif()
if (DEFINED pkgname
AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
set(ARTIFACT
"${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
if (PKG_ARGS_MODULE_PATH)
set(EXTRA_ARGS MODULE_PATH)
endif()
# download sha512sum file
# TODO: CI pkgs
set(sha512sum_url
"https://${ARTIFACT_GIT_HOST}/${ARTIFACT_REPO}/releases/download/${ARTIFACT_VERSION}/${ARTIFACT}.sha512sum")
set(sha512sum_file
"${CMAKE_CURRENT_BINARY_DIR}/.cpmutil_${ARTIFACT}_sha512sum")
file(DOWNLOAD "${sha512sum_url}" "${sha512sum_file}"
STATUS sha512sum_status)
list(GET sha512sum_status 0 sha512sum_error)
if(sha512sum_error)
message(FATAL_ERROR "[CPMUtil] Failed to download sha512sum "
"for ${ARTIFACT_NAME} from ${sha512sum_url}")
endif()
file(READ "${sha512sum_file}" sha512sum_hash)
string(STRIP "${sha512sum_hash}" sha512sum_hash)
file(REMOVE "${sha512sum_file}")
AddPackage(
NAME ${ARTIFACT_PACKAGE}
REPO ${ARTIFACT_REPO}
VERSION ${ARTIFACT_VERSION}
ARTIFACT ${ARTIFACT}
CUSTOM_KEY "${ARTIFACT_VERSION}-${pkgname}"
HASH ${sha512sum_hash}
FORCE_BUNDLED_PACKAGE ON
${EXTRA_ARGS})
set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE)
Propagate(${ARTIFACT_PACKAGE}_SOURCE_DIR)
Propagate(CMAKE_PREFIX_PATH)
else()
cpm_utils_message(FATAL_ERROR "${ARTIFACT_NAME}:"
"Unsupported platform ${pkgname} for CI package")
endif()
endfunction()
# Utility function for Qt
function(AddQt repo version)
if (NOT DEFINED repo)
message(FATAL_ERROR "[CPMUtil] AddQt: repo is required")
endif()
if (NOT DEFINED version)
message(FATAL_ERROR "[CPMUtil] AddQt: version is required")
endif()
# TODO: update Qt
if (MSVC)
set(platname windows)
elseif(MINGW)
@@ -1035,64 +1129,6 @@ function(AddCIPackage)
set(pkgname ${platname}-${archname})
endif()
if (DEFINED pkgname
AND NOT "${pkgname}" IN_LIST DISABLED_PLATFORMS)
set(ARTIFACT
"${ARTIFACT_NAME}-${pkgname}-${ARTIFACT_VERSION}.${ARTIFACT_EXT}")
if (PKG_ARGS_MODULE_PATH)
set(EXTRA_ARGS MODULE_PATH)
endif()
# download sha512sum file
# TODO: CI pkgs
set(sha512sum_url
"https://${ARTIFACT_GIT_HOST}/${ARTIFACT_REPO}/releases/download/v${ARTIFACT_VERSION}/${ARTIFACT}.sha512sum")
set(sha512sum_file
"${CMAKE_CURRENT_BINARY_DIR}/.cpmutil_${ARTIFACT}_sha512sum")
file(DOWNLOAD "${sha512sum_url}" "${sha512sum_file}"
STATUS sha512sum_status)
list(GET sha512sum_status 0 sha512sum_error)
if(sha512sum_error)
message(FATAL_ERROR "[CPMUtil] Failed to download sha512sum "
"for ${ARTIFACT_NAME} from ${sha512sum_url}")
endif()
file(READ "${sha512sum_file}" sha512sum_hash)
string(STRIP "${sha512sum_hash}" sha512sum_hash)
file(REMOVE "${sha512sum_file}")
AddPackage(
NAME ${ARTIFACT_PACKAGE}
REPO ${ARTIFACT_REPO}
VERSION "v${ARTIFACT_VERSION}"
ARTIFACT ${ARTIFACT}
CUSTOM_KEY "${ARTIFACT_VERSION}-${pkgname}"
HASH ${sha512sum_hash}
FORCE_BUNDLED_PACKAGE ON
${EXTRA_ARGS})
set(${ARTIFACT_PACKAGE}_ADDED TRUE PARENT_SCOPE)
Propagate(${ARTIFACT_PACKAGE}_SOURCE_DIR)
Propagate(CMAKE_PREFIX_PATH)
else()
cpm_utils_message(FATAL_ERROR "${ARTIFACT_NAME}:"
"Unsupported platform ${pkgname} for CI package")
endif()
endfunction()
# Utility function for Qt
function(AddQt repo version)
if (NOT DEFINED repo)
message(FATAL_ERROR "[CPMUtil] AddQt: repo is required")
endif()
if (NOT DEFINED version)
message(FATAL_ERROR "[CPMUtil] AddQt: version is required")
endif()
AddCIPackage(
NAME qt
PACKAGE Qt6
@@ -1100,7 +1136,8 @@ function(AddQt repo version)
REPO ${repo}
DISABLED_PLATFORMS
android-x86_64 android-aarch64
MODULE_PATH)
MODULE_PATH
PKGNAME ${pkgname})
find_package(Qt6 REQUIRED PATHS ${Qt6_SOURCE_DIR} NO_DEFAULT_PATH)
+1 -4
View File
@@ -18,13 +18,10 @@ if (DEFINED GIT_RELEASE)
set(BUILD_VERSION "${GIT_TAG}")
set(GIT_REFSPEC "${GIT_RELEASE}")
set(IS_DEV_BUILD false)
elseif(DEFINED GIT_COMMIT)
else()
string(SUBSTRING ${GIT_COMMIT} 0 10 BUILD_VERSION)
set(BUILD_VERSION "${BUILD_VERSION}-${GIT_REFSPEC}")
set(IS_DEV_BUILD true)
else()
set(BUILD_VERSION "NoGitInfo")
set(IS_DEV_BUILD true)
endif()
if (NIGHTLY_BUILD)
-46
View File
@@ -1,46 +0,0 @@
# 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 ()
+1 -1
View File
@@ -15,7 +15,7 @@
<br>
</h1>
<h4 align="center"><b>Eden</b> is a free and opensource (FOSS) Switch 1 emulator started by developer Camille LaVey.
<h4 align="center"><b>Eden</b> is a free and open-source (FOSS) Switch 1 emulator started by developer Camille LaVey.
<br>
Written in C++, with builds for Windows, Linux, macOS, Android, FreeBSD and more.
</h4>
+18 -27
View File
@@ -1,4 +1,12 @@
{
"": {
"ci": true,
"hash": "9f50d993c39529e022ad456163de91ac5934e16faf8fc348f305355fc0a643c534f87ded707e11bd03bcbc0a1760bd20852b6533a67ac0558a078385181cb184",
"name": "SDL3",
"package": "SDL3",
"repo": "crueter-ci/SDL3",
"version": "3.4.14-1788231389-147a8ee32d"
},
"biscuit": {
"hash": "1229f345b014f7ca544dedb4edb3311e41ba736f9aa9a67f88b5f26f3c983288c6bb6cdedcfb0b8a02c63088a37e6a0d7ba97d9c2a4d721b213916327cffe28a",
"min_version": "0.9.1",
@@ -12,8 +20,7 @@
"min_version": "1.57",
"package": "Boost",
"patches": [
"0001-clang-cl.patch",
"0004-openorbis.patch"
"0001-clang-cl.patch"
],
"repo": "boostorg/boost",
"version": "boost-1.90.0"
@@ -71,26 +78,19 @@
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
"min_version": "1.3",
"repo": "lsalzman/enet",
"version": "v1.3.18",
"patches": [
"0001-openorbis.patch"
]
"version": "v1.3.18"
},
"ffmpeg": {
"hash": "ed177621176b3961bdcaa339187d3a7688c1c8b060b79c4bb0257cbc67ad7021ae5d5adca5303b45625abbbe3d9aafdd87ce777b8690ac295290d744c875489a",
"repo": "FFmpeg/FFmpeg",
"version": "c7b5f1537d",
"patches": [
"0001-sysctl-openorbis.patch"
]
"version": "c7b5f1537d"
},
"ffmpeg-ci": {
"ci": true,
"min_version": "4.1",
"name": "ffmpeg",
"package": "FFmpeg",
"repo": "crueter-ci/FFmpeg",
"version": "8.0.1-c7b5f1537d"
"version": "9.0.1-1788120736-bf1b838f2a"
},
"fmt": {
"hash": "f0da82c545b01692e9fd30fdfb613dbb8dd9716983dcd0ff19ac2a8d36f74beb5540ef38072fdecc1e34191b3682a8542ecbf3a61ef287dbba0a2679d4e023f2",
@@ -197,19 +197,17 @@
"min_version": "3.0.0",
"package": "OpenSSL",
"patches": [
"0001-add-bundled-cert.patch",
"0002-fix-gnu-openorbis.patch"
"0001-add-bundled-cert.patch"
],
"repo": "openssl/openssl",
"version": "openssl-3.6.2"
},
"openssl-ci": {
"ci": true,
"min_version": "3.0.0",
"name": "openssl",
"package": "OpenSSL",
"repo": "crueter-ci/OpenSSL",
"version": "4.0.0-11b7b6ea3b"
"version": "4.0.1-1788234794-b64f68a94e"
},
"openssl-cmake": {
"bundled": true,
@@ -221,9 +219,7 @@
"0001-cpmutil-compat.patch",
"0002-use-ccache.patch",
"0003-use-cmake-compiler-flags.patch",
"0004-use-shell-wrapper.patch",
"0005-wasm-support.patch",
"0006-openorbis-prefix.patch"
"0004-use-shell-wrapper.patch"
],
"repo": "jimmy-park/openssl-cmake",
"version": "3.6.2"
@@ -261,19 +257,14 @@
"min_version": "3.2.10",
"package": "SDL3",
"repo": "libsdl-org/SDL",
"version": "release-3.4.8",
"patches": [
"0001-ps4.patch",
"0002-ps4-drivers.patch"
]
"version": "release-3.4.8"
},
"sdl3-ci": {
"ci": true,
"min_version": "3.2.10",
"name": "SDL3",
"package": "SDL3",
"repo": "crueter-ci/SDL3",
"version": "3.4.8-d57c3b685c"
"version": "3.4.14-1788231389-147a8ee32d"
},
"simpleini": {
"find_args": "MODULE",
@@ -296,7 +287,7 @@
"name": "sirit",
"package": "sirit",
"repo": "eden-emulator/sirit",
"version": "1.0.5"
"version": "v1.0.7"
},
"spirv-headers": {
"hash": "d624371dd455c66a300344c89812598ffe11b5eedba555779f789e85c29dc67317741858c60e0744a1e6755cc0d2759b8659f0674f4cc31479c4cb6fc25ed23b",
+8 -7
View File
@@ -11,12 +11,12 @@ SPDX-License-Identifier: CC0-1.0
-->
<component type="desktop-application">
<id>org.eden_emu.eden</id>
<id>dev.eden_emu.eden</id>
<metadata_license>CC0-1.0</metadata_license>
<name>eden</name>
<summary>Nintendo Switch emulator</summary>
<description>
<p>Multiplatform FOSS Switch 1 emulator written in C++, derived from Yuzu and Sudachi</p>
<p>Eden is a free and open-source (FOSS) Switch 1 emulator started by developer Camille LaVey. Written in C++, with builds for Windows, Linux, macOS, Android, FreeBSD and more.</p>
</description>
<categories>
<category>Game</category>
@@ -28,14 +28,14 @@ SPDX-License-Identifier: CC0-1.0
</keywords>
<url type="homepage">https://eden-emu.dev/</url>
<url type="bugtracker">https://git.eden-emu.dev/eden-emu/eden/issues</url>
<url type="faq">https://eden-emu.dev/docs</url>
<url type="help">https://eden-emu.dev/docs</url>
<url type="donation">https://eden-emu.dev/donations</url>
<url type="faq">https://eden-emu.dev/about</url>
<url type="help">https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md</url>
<url type="donation">https://liberapay.com/crueter</url>
<url type="translate">https://explore.transifex.com/edenemu/eden-emulator</url>
<url type="contact">https://discord.gg/edenemu</url>
<url type="contact">https://discord.gg/HstXbPch7X</url>
<url type="vcs-browser">https://git.eden-emu.dev</url>
<url type="contribute">https://git.eden-emu.dev/eden-emu/eden</url>
<launchable type="desktop-id">org.eden_emu.eden.desktop</launchable>
<launchable type="desktop-id">dev.eden_emu.eden.desktop</launchable>
<provides>
<binary>yuzu</binary>
<binary>yuzu-cmd</binary>
@@ -44,6 +44,7 @@ SPDX-License-Identifier: CC0-1.0
<control>pointing</control>
<control>keyboard</control>
<control>gamepad</control>
<internet>offline-only</internet>
</supports>
<requires>
<memory>8192</memory>
+4 -4
View File
@@ -14,7 +14,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<mime-type type="application/x-nx-nro">
<comment>Nintendo Switch homebrew executable</comment>
<acronym>NRO</acronym>
<icon name="org.eden_emu.eden"/>
<icon name="dev.eden_emu.eden"/>
<glob pattern="*.nro"/>
<magic><match value="NRO" type="string" offset="16"/></magic>
</mime-type>
@@ -22,7 +22,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<mime-type type="application/x-nx-nso">
<comment>Nintendo Switch homebrew executable</comment>
<acronym>NSO</acronym>
<icon name="org.eden_emu.eden"/>
<icon name="dev.eden_emu.eden"/>
<glob pattern="*.nso"/>
<magic><match value="NSO" type="string" offset="0"/></magic>
</mime-type>
@@ -30,7 +30,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<mime-type type="application/x-nx-nsp">
<comment>Nintendo Switch Package</comment>
<acronym>NSP</acronym>
<icon name="org.eden_emu.eden"/>
<icon name="dev.eden_emu.eden"/>
<glob pattern="*.nsp"/>
<magic><match value="PFS" type="string" offset="0"/></magic>
</mime-type>
@@ -38,7 +38,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
<mime-type type="application/x-nx-xci">
<comment>Nintendo Switch Card Image</comment>
<acronym>XCI</acronym>
<icon name="org.eden_emu.eden"/>
<icon name="dev.eden_emu.eden"/>
<glob pattern="*.xci"/>
</mime-type>
</mime-info>
+3 -1
View File
@@ -2,6 +2,7 @@
Qt has "Translation Rules for Plurals", small example
```cpp
// Take a source line like
tr("Building: %n shader(s)", "", i)
@@ -9,8 +10,9 @@ Qt has "Translation Rules for Plurals", small example
Building: 1 shader
// i = 2:
Building: 2 shaders
```
For yuzu the source language used is English, for all other languages handling of plurals is handled by Qt and the translation collaboration site. Handling plurals in the source language (English) requires special consideration.
For Yuzu the source language used is English, for all other languages handling of plurals is handled by Qt and the translation collaboration site. Handling plurals in the source language (English) requires special consideration.
With CMake flag GENERATE_QT_TRANSLATION a generated_en.ts file is created from the source. It ignored by git (`.gitignore` in the project root). It is placed in this directory so that the relative refrences with the source code is correct.
-223
View File
@@ -1,223 +0,0 @@
<?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>

Before

Width:  |  Height:  |  Size: 16 KiB

+1 -1
View File
@@ -1,6 +1,6 @@
# Translating
This directory stores translation patches (TS files) for yuzu Qt frontend. This directory is linked with the [Eden project on transifex](https://app.transifex.com/edenemu/eden-emulator), so you can update the translation by executing `tx pull -t -a` in the root of this repository. If you want to contribute to the translation, please go the transifex link and submit your translation there.
This directory stores translation patches (TS files) for Yuzu Qt frontend. This directory is linked with the [Eden project on Transifex](https://app.transifex.com/edenemu/eden-emulator), so you can update the translation by executing `tx pull -t -a` in the root of this repository. If you want to contribute to the translation, please go the Transifex link and submit your translation there.
When creating/improving translations, please keep in mind:
+14 -5
View File
@@ -5,6 +5,15 @@
This is a full-fledged guide to build Eden on all supported platforms.
If you already have a development environment set up:
```sh
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -G Ninja
cmake --build build
```
On Linux, macOS, and MinGW/MSYS2, make sure to read the [dependencies guide](Deps.md). On Android, read its [dedicated page](build/Android.md).
## Dependencies
First, you must [install some dependencies](Deps.md).
@@ -125,13 +134,13 @@ cmake -S . -B build -G "<GENERATOR>" -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COM
<img src="https://user-images.githubusercontent.com/42481638/216899164-6cee8482-3d59-428f-b1bc-e6dc793c9b20.png" width="500">
- Click OK; now Clion will build a directory and index your code to allow for IntelliSense. Please be patient.
- Once this process has been completed (No loading bar bottom right), you can now build eden
- In the top right, click on the drop-down menu, select all configurations, then select eden
- Click OK; now CLion will build a directory and index your code to allow for IntelliSense. Please be patient.
- Once this process has been completed (No loading bar bottom right), you can now build Eden
- In the top right, click on the drop-down menu, select all configurations, then select Eden
<img src="https://user-images.githubusercontent.com/42481638/216899226-975048e9-bc6d-4ec1-bc2d-bd8a1e15ed04.png" height="500" >
- Now run by clicking the play button or pressing Shift+F10, and eden will auto-launch once built.
- Now run by clicking the play button or pressing Shift+F10, and Eden will auto-launch once built.
<img src="https://user-images.githubusercontent.com/42481638/216899275-d514ec6a-e563-470e-81e2-3e04f0429b68.png" width="500">
</details>
@@ -153,7 +162,7 @@ If your initial configure failed:
- *Carefully* re-read the [dependencies guide](Deps.md)
- Clear the CPM cache (`.cache/cpm`) and CMake cache (`<build directory>/CMakeCache.txt`)
- Evaluate the error and find any related settings
- See the [CPM docs](CPM.md) to see if you may need to forcefully bundle any packages
- See the [CPM docs](CPMUtil.md) to see if you may need to forcefully bundle any packages
Otherwise, feel free to ask for help in Stoat or Discord.
+5 -35
View File
@@ -12,11 +12,6 @@
- [NetBSD](#netbsd)
- [MSYS2](#msys2)
- [RedoxOS](#redoxos)
- [PlayStation 4](#playstation-4)
- [Windows](#windows)
- [Windows 7, Windows 8 and Windows 8.1](#windows-7-windows-8-and-windows-81)
- [Windows Vista and below](#windows-vista-and-below)
- [Windows on ARM](#windows-on-arm)
<!-- /TOC -->
## Arch Linux
@@ -72,7 +67,7 @@ export LIBGL_ALWAYS_SOFTWARE=1
Install `developer/gcc14` on OmniOS using pkgsrc.
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON`
Since so many dependencies are missing on `OmniOS`, you may wish to use `-DCPMUTIL_FORCE_BUNDLED=ON` and `-DYUZU_USE_BUNDLED_OPENSSL=OFF`.
For OmniOS you are required to build glslang yourself:
```sh
@@ -87,11 +82,13 @@ cmake --install build
It may be tempting to specify `-t glslang`, but this will cause installation to fail. So don't.
Using `--parallel` on CMake incorrectly passes `dmake ... -jn` instead of `dmake ... -j n`, this is a bug with OmniOS's CMake, and as such it's recommended to not use this option until it's fixed.
Using `--parallel` on CMake incorrectly passes `dmake ... -jn` instead of `dmake ... -j n`, this is a bug with OmniOS's CMake, it's recommended to not use this option until it's fixed.
You may also need to install `gmake` in order to properly build FFmpeg, this is provided by the `build-essential` package.
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well:
If it wasn't obvious already, you require a X11 server to properly run the emulator within OmniOS, [this guide](https://web.archive.org/web/20260424200928/https://geekblood.wordpress.com/2017/10/26/installing-x11-and-a-desktop-environment-on-omnios/) is a great starting point for that, the links to pkgsrc are outdated so follow [this exemplar](https://pkgsrc.smartos.org/install-on-illumos/) as well.
For Solaris based OSes, `${CMAKE_SYSTEM_NAME}` isn't properly set on CMake (it's set to i686 on AMD64), you may find issues when building OpenSSL from `openssl-cmake`.
## HaikuOS
@@ -245,30 +242,3 @@ 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.
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
## PlayStation 4
```sh
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain/prefix"
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
```
```sh
cp $OO_PS4_TOOLCHAIN/include/endian.h $OO_PS4_TOOLCHAIN/include/sys/endian.h
```
## Windows
### Windows 7, Windows 8 and Windows 8.1
DirectX 12 is not available - simply copy and paste a random DLL and name it `d3d12.dll`.
Install [Qt6 compatibility libraries](github.com/ANightly/qt6windows7) specifically Qt 6.9.5.
### Windows Vista and below
No support for Windows Vista (or below) is present at the moment. Check back later.
### Windows on ARM
If you're using Snapdragon X or 8CX, use the [the Vulkan translation layer](https://apps.microsoft.com/detail/9nqpsl29bfff?hl=en-us&gl=USE) only if the stock drivers do not work. And of course always keep your system up-to-date.
+54 -5
View File
@@ -6,7 +6,7 @@ When reporting issues or finding bugs, we often need backtraces, debug logs, or
### Graphics Debugging
If your bug is related to a graphical issue--e.g. mismatched colors, vertex explosions, flickering, etc.--then you are required to include graphical debugging logs in your issue reports.
If your bug is related to a graphical issue -- e.g. mismatched colors, vertex explosions, flickering, etc. -- then you are required to include graphical debugging logs in your issue reports.
Graphics Debugging is found in General -> Debug on desktop, and Advanced Settings -> Debug on Android. Android users are all set; however, desktop users may need to install the Vulkan Validation Layers:
@@ -17,7 +17,7 @@ Once Graphics Debugging is enabled, run the problematic game again and continue.
### Debug Logs
Debug logs can be found in General -> Debug -> Open Log Location on desktop, and Share Debug Logs on Android. This MUST be included in all bug reports, except for certain UI bugs--but we still highly recommend them even for UI bugs.
Debug logs can be found in `General -> Debug -> Open Log Location` on desktop, and `Share Debug Logs` on Android. This MUST be included in all bug reports, except for certain UI bugs -- but we still highly recommend them even for UI bugs.
## Debugging (host code)
@@ -38,7 +38,7 @@ You must have GDB installed for aarch64 to debug the target. Install it through
- `sudo emerge --ask crossdev`
- `sudo crossdev -t aarch64-unknown-linux-gnu --ex-gdb`
Run `./build/bin/eden-cli -c <path to your config file (see logs where you run eden normally to see where it is)> -d -g <path to game>`, or `Enable GDB Stub` at General > Debug, then hook up an aarch64-gdb:
Run `./build/bin/eden-cli -c <path to your config file (see logs where you run Eden normally to see where it is)> -d -g <path to game>`, or `Enable GDB Stub` at General > Debug, then hook up an aarch64-gdb:
- `target remote localhost:6543`
@@ -69,6 +69,55 @@ Expressions can be `variable_names` or `1234` (numbers) or `*var` (dereference o
For more information type `info gdb` and read [the man page](https://man7.org/linux/man-pages/man1/gdb.1.html).
# RenderDoc (Graphic Debugging Tool)
# RenderDoc
Guidelines for graphical debugging using RenderDoc: **[RenderDoc usage](./RenderDoc.md)**
RenderDoc is a free, cross platform, multi-graphics API debugger. It is an invaluable tool for diagnosing issues with graphics applications, and includes support for Vulkan. Get it from [renderdoc.org](https://renderdoc.org).
RenderDoc can capture Eden's Vulkan output when its Vulkan layer is loaded before Eden creates the Vulkan device. Before using RenderDoc to diagnose issues, it's always good to make sure there are no validation errors. Any errors means the behavior of the application is undefined. That said, RenderDoc can help debug validation errors if you do have them.
## Usage on Windows
You can either use RenderDoc UI to launch Eden, or you can make Eden attach it internally:
On Windows PowerShell:
```powershell
$env:ENABLE_VULKAN_RENDERDOC_CAPTURE='1'
.\eden.exe
```
When RenderDoc is attached, Eden logs the default Windows capture folder:
```text
%LOCALAPPDATA%\Temp\RenderDoc
```
Press RenderDoc's capture hotkey, usually `F12`, to capture a frame. To stop using RenderDoc, close Eden and launch it again without `ENABLE_VULKAN_RENDERDOC_CAPTURE`.
## Eden Hotkey
Eden also has a separate `Toggle Renderdoc Capture` hotkey behind the debug setting `renderdoc_hotkey`.
That hotkey does not load or unload RenderDoc. It only toggles Eden's own manual capture through RenderDoc's API:
- First press: Starts a capture
- Second press: Ends that capture
## Simple checklist for debugging black screens using Renderdoc
When debugging a black screen, there are many ways the application could have setup Vulkan wrong.
Here is a short checklist of items to look at to make sure are appropriate:
- Draw call counts are correct (aka not zero, or if rendering many triangles, not 3)
- Vertex buffers are bound
- vertex attributes are correct - Make sure the size & offset of each attribute matches what should it should be
- Any bound push constants and descriptors have the right data - including:
- Matrices have correct values - double check the model, view, & projection matrices are uploaded correctly
- Pipeline state is correct
- viewport range is correct - x,y are 0,0; width & height are screen dimensions, minDepth is 0, maxDepth is 1, NDCDepthRange is 0,1
- Fill mode matches expected - usually solid
- Culling mode makes sense - commonly back or none
- The winding direction is correct - typically CCW (counter clockwise)
- Scissor region is correct - usually same as viewport's x,y,width, &height
- Blend state is correct
- Depth state is correct - typically enabled with Function set to Less than or Equal
- Swapchain images are bound when rendering to the swapchain
- Image being rendered to is the same as the one being presented when rendering to the swapchain
Alternatively, a [RenderDoc Extension](https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw) ([Archive](https://web.archive.org/web/20250000000000*/https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw)) exists which automates doing a lot of these manual steps.
+5 -2
View File
@@ -259,7 +259,10 @@ brew install molten-vk
<details>
<summary>FreeBSD</summary>
As root run: `pkg install devel/cmake sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib vulkan-headers quazip-qt6`
As root run:
```sh
pkg install devel/cmake devel/sdl3 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base x11-toolkits/qt6-charts devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib graphics/vulkan-utility-libraries graphics/vulkan-headers graphics/spirv-headers quazip-qt6
```
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
@@ -272,7 +275,7 @@ If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
For NetBSD +10.1:
```sh
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6 cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
pkgin install git cmake boost fmtlib SDL3 catch2 libjwt spirv-headers spirv-tools ffmpeg7 libva nlohmann-json jq libopus qt6-qtbase qt6-qtcharts qt6-qtmultimedia qt6-qttools cpp-httplib lz4 vulkan-headers nasm autoconf enet pkg-config libusb1 libcxx frozen
```
[Caveats](./Caveats.md#netbsd).
+3 -3
View File
@@ -1,6 +1,6 @@
# Design Overview
Modern game consoles require heavy power to be emulated appropriatedly. This is why the emulator uses an approach known as HLE (High-Level-Emulation), in a nuthsell: Instead of accurately emulating every subsystem that forms part of a component, emulate the resulting visible I/O interface instead.
Modern game consoles require heavy power to be emulated appropriately. This is why the emulator uses an approach known as HLE (High-Level-Emulation), in a nutshell: Instead of accurately emulating every subsystem that forms part of a component, emulate the resulting visible I/O interface instead.
For example, take a disk write, instead of emulating a proper SD card we instead use the C++ standard library for I/O. Additionally we use the abstractions provided by the `fs` service to "lie" to programs about certain SD card properties. Notably this includes making up sizes for the fake SD card, giving "realistic" values or expected outputs for a given card, and so on. And instead of writing to an actual SD card, the emulator simply writes to a file.
@@ -20,7 +20,7 @@ Handles everything related to audio, this is where most of the filtering and pro
## src/common/
The [common](../src/common) folder contains just your basic pollyfills for whatever missing functionality. We heavily encourage new PRs to make use of one of the dependencies, or the standard C++ library. Minimizing the amount of things we reinvent the wheel for is always a good thing.
The [common](../src/common) folder contains just your basic polyfills for whatever missing functionality. We heavily encourage new PRs to make use of one of the dependencies, or the standard C++ library. Minimizing the amount of things we reinvent the wheel for is always a good thing.
## src/core/
@@ -40,7 +40,7 @@ Dedicated shader recompiler to translate Maxwell assembly code to either SPIR-V,
## src/video_core/
Most of the things here have their own dedicated section. In short this is basically the entire Tegra NVIDIA Maxwell GPU emulation. Additionally it includes some [extra effects](../src/video_core/host_ahders) to emulate MSAA, D24 copies or as polyfill.
Most of the things here have their own dedicated section. In short this is basically the entire Tegra NVIDIA Maxwell GPU emulation. Additionally it includes some [extra effects](../src/video_core/host_shaders/opengl_smaa.glsl) to emulate MSAA, D24 copies or as polyfill.
Available backends are: Null, Vulkan, and OpenGL.
+2 -2
View File
@@ -91,7 +91,7 @@ You may additionally need the `Qt Extension Pack` extension if building Qt.
# Build speedup
If you have an HDD, use ramdisk (build in RAM), approximatedly you need 4GB for a full build with debug symbols:
If you have an HDD, use ramdisk (build in RAM), approximately you need 4GB for a full build with debug symbols:
```sh
mkdir /tmp/ramdisk
@@ -110,7 +110,7 @@ A general rule of thumb, before uploading files:
- PNG files: Use [optipng](https://web.archive.org/web/20240325055059/https://optipng.sourceforge.net/).
- SVG files: Use [svgo](https://github.com/svg/svgo).
May not be used but worth mentioning nonethless:
May not be used but worth mentioning nonetheless:
- OGG files: Use [OptiVorbis](https://github.com/OptiVorbis/OptiVorbis).
- Video files: Use ffmpeg, preferably re-encode as AV1.
+4 -5
View File
@@ -2,9 +2,9 @@
Are you just a casual user? Take a look at our [User Handbook](./user) then!
If you want to register/signup as a contributor, take a gander at the [signup guide](./SIGNUP.md).
If you want to register/signup as a contributor, take a gander at [CONTRIBUTING.md](../CONTRIBUTING.md).
This contains documentation created by developers. This contains build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil), and more.
This contains documentation created by developers, build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil.md), and more.
- **[General Build Instructions](./Build.md)**
- **[CMake Options](./Options.md)**
@@ -12,11 +12,10 @@ This contains documentation created by developers. This contains build instructi
- **[Development Guidelines](./Development.md)**
- **[Dependencies](./Deps.md)**
- **[Debug Guidelines](./Debug.md)**
- **[RenderDoc usage](./RenderDoc.md)**
- **[CPM - CMake Package Manager](./CPMUtil)**
- **[RenderDoc](./Debug.md#renderdoc)**
- **[CPM - CMake Package Manager](./CPMUtil.md)**
- **[Platform-Specific Caveats](./Caveats.md)**
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
- **[Cross compilation](./CrossCompile.md)**
- **[Driver Bugs](./DriverBugs.md)**
- **[Building Older Commits](./build/OlderCommits.md)**
- Subsystems:
-52
View File
@@ -1,52 +0,0 @@
# RenderDoc
Renderdoc is a free, cross platform, multi-graphics API debugger. It is an invaluable tool for diagnosing issues with graphics applications, and includes support for Vulkan. Get it at [renderdoc.org](https://renderdoc.org).
RenderDoc can capture Eden's Vulkan output when its Vulkan layer is loaded before Eden creates the Vulkan device. Before using renderdoc to diagnose issues, it is always good to make sure there are no validation errors. Any errors means the behavior of the application is undefined. That said, renderdoc can help debug validation errors if you do have them.
## Usage on Windows
You can either use RenderDoc UI to launch eden, or you can make eden attach it internally:
On Windows PowerShell:
```powershell
$env:ENABLE_VULKAN_RENDERDOC_CAPTURE='1'
.\eden.exe
```
When RenderDoc is attached, Eden logs the default Windows capture folder:
```text
%LOCALAPPDATA%\Temp\RenderDoc
```
Press RenderDoc's capture hotkey, usually `F12`, to capture a frame. To stop using RenderDoc, close Eden and launch it again without `ENABLE_VULKAN_RENDERDOC_CAPTURE`.
## Eden Hotkey
Eden also has a separate `Toggle Renderdoc Capture` hotkey behind the debug setting `renderdoc_hotkey`.
That hotkey does not load or unload RenderDoc. It only toggles Eden's own manual capture through RenderDoc's API:
- first press: starts a capture
- second press: ends that capture
## Simple checklist for debugging black screens using Renderdoc
When debugging a black screen, there are many ways the application could have setup Vulkan wrong.
Here is a short checklist of items to look at to make sure are appropriate:
- Draw call counts are correct (aka not zero, or if rendering many triangles, not 3)
- Vertex buffers are bound
- vertex attributes are correct - Make sure the size & offset of each attribute matches what should it should be
- Any bound push constants and descriptors have the right data - including:
- Matrices have correct values - double check the model, view, & projection matrices are uploaded correctly
- Pipeline state is correct
- viewport range is correct - x,y are 0,0; width & height are screen dimensions, minDepth is 0, maxDepth is 1, NDCDepthRange is 0,1
- Fill mode matches expected - usually solid
- Culling mode makes sense - commonly back or none
- The winding direction is correct - typically CCW (counter clockwise)
- Scissor region is correct - usually same as viewport's x,y,width, &height
- Blend state is correct
- Depth state is correct - typically enabled with Function set to Less than or Equal
- Swapchain images are bound when rendering to the swapchain
- Image being rendered to is the same as the one being presented when rendering to the swapchain
Alternatively, a [RenderDoc Extension](https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw) ([Archive](https://web.archive.org/web/20250000000000*/https://github.com/baldurk/renderdoc-contrib/tree/main/baldurk/whereismydraw)) exists which automates doing a lot of these manual steps.
+4 -4
View File
@@ -1,11 +1,11 @@
# Settings
> [!WARNING]
> This guide is intended for developers ONLY. If you're looking for configuring the emulator itself, please read **[the user handbook](./user/README.md)**.
> This guide is intended for developers ONLY. If you're looking for configuring the emulator itself, read **[the user handbook](./user/README.md)**.
Settings on the emulator are very important, toggles and such can be used to guard and/or add branches to paths where some games may crash while others won't, and viceversa.
However, this process can be tedious for those unfamiliar; this document serves as a outline/documentation for the settings subsystem.
However, this process can be tedious for those unfamiliar; this document serves as an outline/documentation for the settings subsystem.
## Index
@@ -80,7 +80,7 @@ INSERT(Settings,
#### Make sure to:
* Keep display naming consistant
* Keep display naming consistent
* Put detailed info in the description
* Use `\n` for line breaks in descriptions
@@ -191,7 +191,7 @@ The setting ranges from 0 to 65535 (0x0000 to 0xFFFF), where each bit represents
### Advantages
The main advantage is to avoid deploying new disposable toggles (those made only for testing stage, and are disposed once new feature gets good to merge). This empowers devs to be free of all frontend burocracy and hassle of new toggles.
The main advantage is to avoid deploying new disposable toggles (those made only for testing stage, and are disposed once new feature gets good to merge). This empowers devs to be free of all frontend bureaucracy and hassle of new toggles.
Common advantages recap:
+42 -42
View File
@@ -1,44 +1,44 @@
# Dynarmic Design Documentation
Dynarmic is a dynamic recompiler for the ARMv6K architecture. Future plans for dynarmic include
Dynarmic is a dynamic recompiler for the ARMv6K architecture. Future plans for Dynarmic include
support for other versions of the ARM architecture, having a interpreter mode, and adding support
for other architectures.
Users of this library interact with it primarily through the interface provided in
[`src/dynarmic/interface`](../src/dynarmic/interface). Users specify how dynarmic's CPU core interacts with
[`src/dynarmic/interface`](../../src/dynarmic/src/dynarmic/interface). Users specify how Dynarmic's CPU core interacts with
the rest of their system providing an implementation of the relevant `UserCallbacks` interface.
Users setup the CPU state using member functions of `Jit`, then call `Jit::Execute` to start CPU
execution. The callbacks defined on `UserCallbacks` may be called from dynamically generated code,
so users of the library should not depend on the stack being in a walkable state for unwinding.
* A32: [`Jit`](../src/dynarmic/interface/A32/a32.h), [`UserCallbacks`](../src/dynarmic/interface/A32/config.h)
* A64: [`Jit`](../src/dynarmic/interface/A64/a64.h), [`UserCallbacks`](../src/dynarmic/interface/A64/config.h)
* A32: [`Jit`](../../src/dynarmic/src/dynarmic/interface/A32/a32.h), [`UserCallbacks`](../../src/dynarmic/src/dynarmic/interface/A32/config.h)
* A64: [`Jit`](../../src/dynarmic/src/dynarmic/interface/A64/a64.h), [`UserCallbacks`](../../src/dynarmic/src/dynarmic/interface/A64/config.h)
Dynarmic reads instructions from memory by calling `UserCallbacks::MemoryReadCode`. These
instructions then pass through several stages:
1. Decoding (Identifying what type of instruction it is and breaking it up into fields)
2. Translation (Generation of high-level IR from the instruction)
3. Optimization (Eliminiation of redundant microinstructions, other speed improvements)
3. Optimization (Elimination of redundant microinstructions, other speed improvements)
4. Emission (Generation of host-executable code into memory)
5. Execution (Host CPU jumps to the start of emitted code and runs it)
Using the A32 frontend with the x64 backend as an example:
* Decoding is done by [double dispatch](https://en.wikipedia.org/wiki/Visitor_pattern) in
[`src/frontend/A32/decoder/{arm.h,thumb16.h,thumb32.h}`](../src/dynarmic/frontend/A32/decoder/).
* Translation is done by the visitors in [`src/dynarmic/frontend/A32/translate/translate_{arm,thumb}.cpp`](../src/dynarmic/frontend/A32/translate/).
The function [`Translate`](../src/dynarmic/frontend/A32/translate/translate.h) takes a starting memory location,
[`src/frontend/A32/decoder/{arm.h,thumb16.h,thumb32.h}`](../../src/dynarmic/src/dynarmic/frontend/A32/decoder/).
* Translation is done by the visitors in [`src/dynarmic/frontend/A32/translate/translate_{arm,thumb}.cpp`](../../src/dynarmic/src/dynarmic/frontend/A32/translate/).
The function [`Translate`](../../src/dynarmic/src/dynarmic/frontend/A32/translate/a32_translate.cpp) takes a starting memory location,
some CPU state, and memory reader callback and returns a basic block of IR.
* The IR can be found under [`src/frontend/ir/`](../src/dynarmic/ir/).
* Optimizations can be found under [`src/ir_opt/`](../src/dynarmic/ir/opt/).
* Emission is done by `EmitX64` which can be found in [`src/dynarmic/backend/x64/emit_x64.{h,cpp}`](../src/dynarmic/backend/x64/).
* Execution is performed by calling `BlockOfCode::RunCode` in [`src/dynarmic/backend/x64/block_of_code.{h,cpp}`](../src/dynarmic/backend/x64/).
* The IR can be found under [`src/frontend/ir/`](../../src/dynarmic/src/dynarmic/ir/).
* Optimizations can be found under [`src/ir/opt_passes.cpp`](../../src/dynarmic/src/dynarmic/ir/opt_passes.cpp).
* Emission is done by `EmitX64` which can be found in [`src/dynarmic/backend/x64/emit_x64.{h,cpp}`](../../src/dynarmic/src/dynarmic/backend/x64/).
* Execution is performed by calling `BlockOfCode::RunCode` in [`src/dynarmic/backend/x64/block_of_code.{h,cpp}`](../../src/dynarmic/src/dynarmic/backend/x64/).
## Decoder
The decoder is a double dispatch decoder. Each instruction is represented by a line in the relevant
instruction table. Here is an example line from [`arm.h`](../src/dynarmic/frontend/A32/decoder/arm.h):
instruction table. Here is an example line from [`arm.h`](../../src/dynarmic/src/dynarmic/frontend/A32/decoder/arm.h):
INST(&V::arm_ADC_imm, "ADC (imm)", "cccc0010101Snnnnddddrrrrvvvvvvvv")
@@ -61,7 +61,7 @@ error results.
## Translator
The translator is a visitor that uses the decoder to decode instructions. The translator generates IR code with the
help of the [`IREmitter` class](../src/dynarmic/ir/ir_emitter.h). An example of a translation function follows:
help of the [`IREmitter` class](../../src/dynarmic/src/dynarmic/ir/ir_emitter.h). An example of a translation function follows:
bool ArmTranslatorVisitor::arm_ADC_imm(Cond cond, bool S, Reg n, Reg d, int rotate, Imm8 imm8) {
u32 imm32 = ArmExpandImm(rotate, imm8);
@@ -107,7 +107,7 @@ function analyser in the medium-term future.
Dynarmic's intermediate representation is typed. Each microinstruction may take zero or more arguments and may
return zero or more arguments. A subset of the microinstructions available is documented below.
A complete list of microinstructions can be found in [src/dynarmic/ir/opcodes.inc](../src/dynarmic/ir/opcodes.inc).
A complete list of microinstructions can be found in [src/dynarmic/ir/opcodes.inc](../../src/dynarmic/src/dynarmic/ir/opcodes.inc).
The below lists some commonly used microinstructions.
@@ -273,7 +273,7 @@ Exclusive OR (i.e.: XOR)
### Callback: {Read,Write}Memory{8,16,32,64}
```c++
```cpp
<u8> ReadMemory8(<u32> vaddr)
<u8> ReadMemory16(<u32> vaddr)
<u8> ReadMemory32(<u32> vaddr)
@@ -288,7 +288,7 @@ Memory access.
### Terminal: ReturnToDispatch
```c++
```cpp
SetTerm(IR::Term::ReturnToDispatch{})
```
@@ -297,7 +297,7 @@ The dispatcher will use the value in R15 to determine what comes next.
### Terminal: LinkBlock
```c++
```cpp
SetTerm(IR::Term::LinkBlock{next})
```
@@ -307,7 +307,7 @@ dispatcher, which will return control to the host.
### Terminal: LinkBlockFast
```c++
```cpp
SetTerm(IR::Term::LinkBlockFast{next})
```
@@ -316,7 +316,7 @@ This promises guarantees that must be held at runtime - i.e that the program won
### Terminal: PopRSBHint
```c++
```cpp
SetTerm(IR::Term::PopRSBHint{})
```
@@ -328,7 +328,7 @@ this optimization or doesn't have a RSB may choose to implement this exactly as
### Terminal: If
```c++
```cpp
SetTerm(IR::Term::If{cond, term_then, term_else})
```
@@ -366,7 +366,7 @@ Do NEVER modify `%r15`, we must make it clear that this register is "immutable"
### `Scratch`
```c++
```cpp
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr);
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm);
```
@@ -375,7 +375,7 @@ At runtime, allocate one of the registers in `desired_locations`. You are free t
### Pure `Use`
```c++
```cpp
Xbyak::Reg64 UseGpr(Argument& arg);
Xbyak::Xmm UseXmm(Argument& arg);
OpArg UseOpArg(Argument& arg);
@@ -391,7 +391,7 @@ This register **must not** have it's value changed.
### `UseScratch`
```c++
```cpp
Xbyak::Reg64 UseScratchGpr(Argument& arg);
Xbyak::Xmm UseScratchXmm(Argument& arg);
void UseScratch(Argument& arg, HostLoc host_loc);
@@ -409,7 +409,7 @@ You are free to modify the value in the register. The register is discarded at t
A `Define` is the defintion of a value. This is the only time when a value may be set.
```c++
```cpp
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
```
@@ -420,7 +420,7 @@ value to the specified register `reg`.
Adding a `Define` to an existing value.
```c++
```cpp
void DefineValue(IR::Inst* inst, Argument& arg);
```
@@ -458,7 +458,7 @@ One complication dynarmic has is that a compiled block is not uniquely identifia
the PC alone, but bits in the FPSCR and CPSR are also relevant. We resolve this by
computing a 64-bit `UniqueHash` that is guaranteed to uniquely identify a block.
```c++
```cpp
u64 LocationDescriptor::UniqueHash() const {
// This value MUST BE UNIQUE.
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
@@ -482,18 +482,18 @@ point. Each element in `rsb_location_descriptors` is a `UniqueHash` and they
each correspond to an element in `rsb_codeptrs`. `rsb_codeptrs` contains the
host addresses for the corresponding the compiled blocks.
`RSBSize` was chosen by performance testing. Note that this is bigger than the
`RSB_SIZE` was chosen by performance testing. Note that this is bigger than the
size of the real RSB in hardware (which has 3 entries). Larger RSBs than 8
showed degraded performance.
```c++
```cpp
struct JitState {
// ...
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
static constexpr size_t RSB_SIZE = 8; // MUST be a power of 2.
u32 rsb_ptr = 0;
std::array<u64, RSBSize> rsb_location_descriptors;
std::array<u64, RSBSize> rsb_codeptrs;
std::array<u64, RSB_SIZE> rsb_location_descriptors;
std::array<u64, RSB_SIZE> rsb_codeptrs;
void ResetRSB();
// ...
@@ -505,7 +505,7 @@ struct JitState {
We insert our prediction at the insertion point iff the RSB doesn't already
contain a prediction with the same `UniqueHash`.
```c++
```cpp
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
using namespace Xbyak::util;
@@ -521,7 +521,7 @@ void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
code->mov(index_reg, dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)]);
code->add(index_reg, 1);
code->and_(index_reg, u32(JitState::RSBSize - 1));
code->and_(index_reg, u32(JitState::RSB_SIZE - 1));
code->mov(loc_desc_reg, u64(imm64));
CodePtr patch_location = code->getCurr<CodePtr>();
@@ -530,7 +530,7 @@ void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
code->EnsurePatchLocationSize(patch_location, 10);
Xbyak::Label label;
for (size_t i = 0; i < JitState::RSBSize; ++i) {
for (size_t i = 0; i < JitState::RSB_SIZE; ++i) {
code->cmp(loc_desc_reg, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
code->je(label, code->T_SHORT);
}
@@ -544,12 +544,12 @@ void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
In pseudocode:
```c++
for (i := 0 .. RSBSize-1)
```cpp
for (i := 0 .. RSB_SIZE-1)
if (rsb_location_descriptors[i] == imm64)
goto label;
rsb_ptr++;
rsb_ptr %= RSBSize;
rsb_ptr %= RSB_SIZE;
rsb_location_desciptors[rsb_ptr] = imm64; //< The UniqueHash
rsb_codeptr[rsb_ptr] = /* codeptr corresponding to the UniqueHash */;
label:
@@ -559,7 +559,7 @@ label:
To check if a predicition is in the RSB, we linearly scan the RSB.
```c++
```cpp
void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescriptor initial_location) {
using namespace Xbyak::util;
@@ -571,7 +571,7 @@ void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescripto
code->or_(rbx, rcx);
code->mov(rax, u64(code->GetReturnFromRunCodeAddress()));
for (size_t i = 0; i < JitState::RSBSize; ++i) {
for (size_t i = 0; i < JitState::RSB_SIZE; ++i) {
code->cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
code->cmove(rax, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]);
}
@@ -582,10 +582,10 @@ void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescripto
In pseudocode:
```c++
```cpp
rbx := ComputeUniqueHash()
rax := ReturnToDispatch
for (i := 0 .. RSBSize-1)
for (i := 0 .. RSB_SIZE-1)
if (rbx == rsb_location_descriptors[i])
rax = rsb_codeptrs[i]
goto rax
+9 -314
View File
@@ -3,175 +3,20 @@ Dynarmic
A dynamic recompiler for ARM.
Highlight features:
*Note that an adversarial guest program [can determine if it's being ran under Dynarmic](#disadvantages-of-dynarmic). Preventing this is not a goal of this project.*
- Fast dynamic binary translation via Just-in-Time compilation
- Clean API
- Implemented in modern C++20
- Hooks exposed for easy code instrumentation
- Code injection support for very fine-grained instrumentation
- Support for unusual address space setups (bring-your-own memory system)
- Native support for most popular operating systems (Windows, macOS, Linux, FreeBSD, OpenBSD, NetBSD, Android)
Cortex-A57 (32 and 64 bit) is the emulated guest target. See [ArchVersion](../../src/dynarmic/src/dynarmic/interface/A32/arch_version.h).
*Please note that an adversarial guest program [can determine if it is being run under dynarmic](#disadvantages-of-dynarmic). Preventing this is not a goal of this project.*
The only supported host architectures are x86-64, and AArch64. There are no plans to support any 32-bit architectures.
### Supported guest architectures
* v3
* v4
* v4T
* v5TE
* v6K
* v6T2
* v7A
* 32-bit v8
* 64-bit v8
You can specify the specific guest version using [ArchVersion](src/dynarmic/interface/A32/arch_version.h).
There are no plans to support v1 or v2.
### Supported host architectures
* x86-64
* AArch64
There are no plans to support any 32-bit architecture.
Important API Changes in v6.x Series
------------------------------------
* **v6.7.0**
* To support use cases where one wants to have the guest to have the same address space as the host, `nullptr` is now a valid value for `fastmem_pointer`.
**This change is not backwards-compatible.** If you were previously using `nullptr` to represent an invalid fastmem arena, you will now have to use `std::nullopt`.
Documentation
-------------
See [an example usage](../../src/dynarmic/tests/print_info.cpp).
Design documentation can be found at [./Design.md](./Design.md).
Usage Example
-------------
The below is a minimal example. Bring-your-own memory system.
```cpp
#include <array>
#include <cstdint>
#include <cstdio>
#include <exception>
#include "dynarmic/interface/A32/a32.h"
#include "dynarmic/interface/A32/config.h"
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
class MyEnvironment final : public Dynarmic::A32::UserCallbacks {
public:
u64 ticks_left = 0;
std::array<u8, 2048> memory{};
u8 MemoryRead8(u32 vaddr) override {
if (vaddr >= memory.size()) {
return 0;
}
return memory[vaddr];
}
u16 MemoryRead16(u32 vaddr) override {
return u16(MemoryRead8(vaddr)) | u16(MemoryRead8(vaddr + 1)) << 8;
}
u32 MemoryRead32(u32 vaddr) override {
return u32(MemoryRead16(vaddr)) | u32(MemoryRead16(vaddr + 2)) << 16;
}
u64 MemoryRead64(u32 vaddr) override {
return u64(MemoryRead32(vaddr)) | u64(MemoryRead32(vaddr + 4)) << 32;
}
void MemoryWrite8(u32 vaddr, u8 value) override {
if (vaddr >= memory.size()) {
return;
}
memory[vaddr] = value;
}
void MemoryWrite16(u32 vaddr, u16 value) override {
MemoryWrite8(vaddr, u8(value));
MemoryWrite8(vaddr + 1, u8(value >> 8));
}
void MemoryWrite32(u32 vaddr, u32 value) override {
MemoryWrite16(vaddr, u16(value));
MemoryWrite16(vaddr + 2, u16(value >> 16));
}
void MemoryWrite64(u32 vaddr, u64 value) override {
MemoryWrite32(vaddr, u32(value));
MemoryWrite32(vaddr + 4, u32(value >> 32));
}
void CallSVC(u32 swi) override {
// Do something.
}
void ExceptionRaised(u32 pc, Dynarmic::A32::Exception exception) override {
// Do something.
}
void AddTicks(u64 ticks) override {
if (ticks > ticks_left) {
ticks_left = 0;
return;
}
ticks_left -= ticks;
}
u64 GetTicksRemaining() override {
return ticks_left;
}
};
int main(int argc, char** argv) {
MyEnvironment env;
Dynarmic::A32::UserConfig user_config;
user_config.callbacks = &env;
Dynarmic::A32::Jit cpu{user_config};
// Execute at least 1 instruction.
// (Note: More than one instruction may be executed.)
env.ticks_left = 1;
// Write some code to memory.
env.MemoryWrite16(0, 0x0088); // lsls r0, r1, #2
env.MemoryWrite16(2, 0xE7FE); // b +#0 (infinite loop)
// Setup registers.
cpu.Regs()[0] = 1;
cpu.Regs()[1] = 2;
cpu.Regs()[15] = 0; // PC = 0
cpu.SetCpsr(0x00000030); // Thumb mode
// Execute!
cpu.Run();
// Here we would expect cpu.Regs()[0] == 8
printf("R0: %u\n", cpu.Regs()[0]);
return 0;
}
```
Alternatives to Dynarmic
------------------------
Here are some projects with the same goals as dynarmic:
Here are some projects with the same goals as Dynarmic:
* [Unicorn](https://www.unicorn-engine.org/) - Recompiling multi-architecture CPU emulator, based on QEMU
* [SkyEye](http://skyeye.sourceforge.net) - Cached interpreter for ARM
@@ -189,8 +34,8 @@ More general alternatives:
Disadvantages of Dynarmic
-------------------------
In the pursuit of speed, some behavior not commonly depended upon is elided. Therefore this emulator does not match spec.
Please note that this would mean that a guest application can easily determine if it is being run under instrumentation.
In the pursuit of speed, some behavior not commonly depended upon is elided. Hence this emulator doesn't match spec.
Note that this would mean that a guest application can easily determine if it's being ran under instrumentation.
Known examples:
@@ -205,156 +50,6 @@ Use this code base at your own risk.
Legal
-----
dynarmic is under a 0BSD license. See LICENSE.txt for more details.
Dynarmic is under a GPLv3 license, check the relevant file headers for more information.
dynarmic uses several other libraries, whose licenses are included below:
### biscuit
```
Copyright 2021 Lioncash/Lioncache
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
```
### catch
```
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
```
### fmt
```
Copyright (c) 2012 - 2016, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
```
### mcl & oaknut
```
MIT License
Copyright (c) 2022 merryhime <https://mary.rs>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
```
### xbyak
```
Copyright (c) 2007 MITSUNARI Shigeo
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
Neither the name of the copyright owner nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------
ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満た
す場合に限り、再頒布および使用が許可されます。
ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項
を含めること。
バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作
権表示、本条件一覧、および下記免責条項を含めること。
書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進
に、著作権者の名前またはコントリビューターの名前を使用してはならない。
本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供さ
れており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性
に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。
著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを
問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為で
あるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、
本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の
喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接
損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、
一切責任を負わないものとします。
```
Dynarmic uses several open-source libraries, whose licenses are included inside thereof.
+1 -1
View File
@@ -24,7 +24,7 @@ All code, AI or not, is held under a **strict standard of excellence**. AI/LLM-g
## Licensing concerns
This is an area of ongoing litigation, and as such is still very iffy. For the time being, know that allowing AI to ingest the codebase may end up with its copyleft code regurgitated into incompatibly-licensed proprietary or permissive software. For you, this means to **not** feed code into LLMs.
This is an area of ongoing litigation, and as such, is still very iffy. For the time being, know that allowing AI to ingest the codebase may end up with its copyleft code regurgitated into incompatibly-licensed proprietary or permissive software. For you, this means to **not** feed code into LLMs.
AI models may have also ingested AGPLv3 code, which is license-incompatible with our codebase.
+5 -5
View File
@@ -24,8 +24,8 @@ Everyone has their own way of viewing good/bad C++ practices, my general outline
- Exploit the fact `std::atomic<uint32_t>/std::atomic<int32_t>` is basically free on most arches that matter.
- In x86_64, an atomic `uint32_t` is basically `mov [m32], r32`, which is essentially free/cheap.
- Avoid template parameters unless you really need them.
- For small inlineable functions this is fine, for more complex ones, please consider the generated assembly.
- Dont make your own memcpy/memset/strcpy/strncpy/etc.
- For small inline-able functions this is fine, for more complex ones, consider the generated assembly.
- Don't make your own memcpy/memset/strcpy/strncpy/etc.
- Seriously DON'T DO THIS. You will NOT beat the compiler.
- Nor 30 years of writing optimized `mem*`.
- If your code is slow, don't blame `mem*`, blame your code.
@@ -37,7 +37,7 @@ Everyone has their own way of viewing good/bad C++ practices, my general outline
- Function parameters are cheap. Don't be afraid to use as many as needed (API usability permitting).
- Don't save a reference in structures of a parent object, i.e:
```c++
```cpp
struct Child {
Parent& parent;
void Mehod() {
@@ -48,7 +48,7 @@ Everyone has their own way of viewing good/bad C++ practices, my general outline
- Instead you can do the following:
```c++
```cpp
struct Child {
void Mehod(Parent& parent) {
parent.Something();
@@ -66,6 +66,6 @@ Programming, alongside the physical act of writing code, also consists of archit
- Dependencies that are legitimately useful to have are few and far between.
- At the same time, NIHing your own implementations of widely adopted algorithms or standards can be quite subpar.
- For dependencies that are very large but contain something you need, consider cherry-picking the individual files it needs (or writing a smaller version of it)
- Try to rely less on indirection for architecturing systems
- Try to rely less on indirection for architecting systems
- If the underlying HLE kernel emulation requires it, try making a solution that keeps things local
- For example, there isn't a need for file descriptors to each be a pointer, when they could be a fixed table size with elements that may be emplaced at will.
+1 -1
View File
@@ -2,7 +2,7 @@
Use this guide whenever you want to modify the Date or Time that Eden reports to games. This can be useful for modifying RNG elements, skipping wait times in games, etc.
**Click [Here](https://evilperson1337.notion.site/Setting-a-Custom-Date-Time-in-Eden-2b357c2edaf680acb8d4e63ccc126564) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Setting-a-Custom-Date-Time-in-Eden-2b357c2edaf680acb8d4e63ccc126564) for an illustrated guide.**
---
+18 -14
View File
@@ -44,7 +44,7 @@ Only Fedora/riscv64 has been tested, but in theory, every riscv64 distribution t
## Other
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it--submit patches!
Other architectures, such as SPARC, MIPS, PowerPC, Loong, and all 32-bit architectures are completely unsupported, as there is no JIT backend or emitter thereof. If you want support for it -- submit patches!
IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not run on IA-64 (assuming you can even find a supported Windows/Linux distribution)
@@ -52,28 +52,32 @@ IA-64 (Itanium) support is completely unknown. Existing amd64 packages will not
The vast majority of Eden's testing is done on Windows, Linux, and Android. However, first-class support is also provided for:
- HaikuOS
- FreeBSD
- OpenBSD
- NetBSD
- OpenIndiana (Solaris)
- macOS
- FreeBSD (amd64, aarch64)
- HaikuOS (amd64)
- OpenBSD (amd64)
- NetBSD (amd64)
- macOS (aarch64)
- OpenIndiana aka. OpenSolaris (amd64)
## Linux
While all modern Linux distributions are supported (Fedora >40, Ubuntu >24.04, Debian >12, Arch, Gentoo, etc.), the vast majority of testing and development for Linux is on Arch and Gentoo. Most major build system changes are tested on Gentoo first and foremost, so if builds fail on any modern distribution no matter what you do, it's likely a bug and should be reported.
Intel and Nvidia GPU support is limited. AMD (RADV) drivers receive first-class testing and are known to provide the most stable Eden experience possible.
Intel and NVIDIA GPU support is limited. AMD (RADV) drivers receive first-class testing and are known to provide the most stable Eden experience possible.
Wayland is not recommended. Testing has shown significantly worse performance on most Wayland compositors compared to X11, alongside mysterious bugs and compatibility errors. For now, set `QT_QPA_PLATFORM=xcb` when running Eden, or pass `-platform xcb` to the launch arguments.
## Windows
Windows 10 and 11 are supported. Support for Windows 8.x is unknown, and Windows 7 support is unlikely to ever be added.
Windows 10 and 11 are supported. Anything below is unsupported.
In order to run Eden, you will probably need to install the [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
To run Eden, you'll need to install [Visual C++ Redistributable](https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170).
Neither AMD nor Nvidia drivers work nearly as well as Linux's RADV drivers. Compatibility is still largely the same, but performance and some hard-to-run games may suffer compared to Linux.
Neither AMD/NVIDIA drivers work nearly as well as Linux's RADV drivers. Compatibility is still largely the same, but performance and some hard-to-run games may suffer compared to Linux.
### Windows on ARM
If you're using Snapdragon X or 8CX, install the [Vulkan translation layer](https://apps.microsoft.com/detail/9nqpsl29bfff?hl=en-us&gl=USE) only if the stock drivers don't work. And of course always keep your system up-to-date.
## Android
@@ -123,13 +127,13 @@ Do note that building the GUI version with Qt versions higher than 6.7.3 will ca
## *BSD, Solaris
BSD and Solaris distributions tend to lag behind Linux in terms of Vulkan and other library compatibility. For example, OpenIndiana (Solaris) does not properly package Qt, meaning the recommended method of usage is to use `eden-cli` only for now. Solaris also generally works better with OpenGL.
BSD and Solaris distributions tend to lag behind Linux in terms of Vulkan and ports. For example, OpenIndiana (Solaris) does not properly package Qt, meaning the recommended method of usage is to use `eden-cli` for now. Solaris also generally works better with OpenGL.
AMD GPU support on these platforms is limited or nonexistent.
AMD GPU support on these platforms is limited or nonexistent, bar for OpenBSD which has a dedicated AMD GPU stack.
## HaikuOS
HaikuOS supports (see below) Vulkan 1.3 and has Mesa 24.0. Because OpenGL ES is used instead of the desktop flavour of OpenGL the OpenGL backend is actually worse than the Vulkan one in terms of stability and system support. OpenGL is highly not recommended due to it being: out of tree builds of Mesa and generally unstable ones at that. Users are advised to use Vulkan whenever possible.
HaikuOS supports (see below) Vulkan 1.3 and has Mesa 24.0. Because OpenGL ES is used instead of the desktop flavour of OpenGL the OpenGL backend is actually worse than the Vulkan one in terms of stability and system support. OpenGL is highly not recommended due to it being out of tree builds of Mesa and generally unstable ones at that. Users are advised to use Vulkan instead.
- Additionally system drivers for NVIDIA and Intel iGPUs exist and provide a native Vulkan ICD with the `Xcb` interface as opposed to the native `BView`
- In order to obtain Vulkan 1.3 support with native `BView` support; Swiftshader can be compiled from source [see this thread](https://discuss.haiku-os.org/t/swiftshader-vulkan-software-renderer-on-haiku/11526/6).
+6 -7
View File
@@ -2,13 +2,13 @@
## Introduction
Eden is a very complicated piece of software, and as such there are many knobs and toggles that can be configured. Most of these are invisible to normal users, however power users may be able to leverage them to their advantage.
Eden is a very complicated piece of software, there are many knobs and toggles that can be configured. Most of these are invisible to normal users, however, power users may be able to leverage them to their advantage.
This handbook primarily describes such knobs and toggles. Normal configuration options are described within the emulator itself and will not be covered in detail.
## Requirements
The emulator is very demanding on hardware, and as such requires a decent mid-range computer/cellphone.
The emulator is very demanding on hardware and requires a decent mid-range computer/cellphone.
See [the requirements page](https://archive.is/sv83h) for recommended and minimum specs.
@@ -22,8 +22,8 @@ If your GPU doesn't support or is just behind by a minor version, see Mesa envir
- RC releases: Release candidate, generally "less stable but still stable" versions.
- Full release: "The stablest possible you could get".
- Nightly: Builds done around 2PM UTC (if there are any changes), generally stable, but not recommended for the average user. These contain daily updates and may contain critical fixes for some games.
- Master: Unstable builds, can lead from a game working exceptionally fine to absolute crashing in some systems because someone forgot to check if NixOS or Solaris worked. These contain straight from the oven fixes, please don't use them unless you plan to contribute something! They're very experimental! Still 95% of the time it will work just fine.
- PR builds: Highly experimental builds, testers may grab from these. The average user should treat them the same as master builds, except sometimes they straight up don't build/work.
- Master: Unstable builds, can range from games working exceptionally well to instantly crashing. These contain straight from the oven fixes, don't use them unless you plan to contribute something! They're very experimental! Still 95% of the time they will work just fine.
- PR builds: Highly experimental builds, testers may grab from these. The average user should treat them the same as master builds.
## User configuration
@@ -35,9 +35,8 @@ Eden will store configuration files in the following directories:
- **Android**: Data is stored internally.
- **Linux, macOS, FreeBSD, Solaris, OpenBSD**: `$XDG_DATA_HOME`, `$XDG_CACHE_HOME`, `$XDG_CONFIG_HOME`.
- **HaikuOS**: `/boot/home/config/settings/eden`
- **PlayStation 4**: `/data/eden`
If a `user` directory is present in the current working directory, that will override all global configuration directories and the emulator will use that instead.
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.
### Environment variables
@@ -65,4 +64,4 @@ Then just running `chmod +x script.sh && source script.sh`.
## Compatibility list
Eden doesn't mantain a compatibility list. However, [EmuReady](https://www.emuready.com/) has a more fine-grained compatibility information for multiple emulators/forks as well.
Eden doesn't maintain a compatibility list. However, [EmuReady](https://www.emuready.com/) has a more fine-grained compatibility information for multiple emulators/forks as well.
+1 -1
View File
@@ -12,7 +12,7 @@ If they don't run - then that's a bug!
## Atmosphere
Fusee Galee, the bootloader and other low-level mechanisms are not emulated at the moment.
Fusée Gelée, the bootloader and other low-level mechanisms are not emulated at the moment.
Having OFW is recommended, but may not be required (untested).
+1 -1
View File
@@ -4,7 +4,7 @@ There are two main applications, an SDL-based app (`eden-cli`) and a Qt based ap
## eden
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behaviour is similar to `eden-cli`; allows dragging and dropping games into the application.
- `./eden <path>`: Running with a single argument and nothing else, will make the emulator look for the given file and load it, this behavior is similar to `eden-cli`; allows dragging and dropping games into the application.
- `-g <path>`: Alternate way to specify what to load, overrides. However let it be noted that arguments that use `-` will be treated as options/ignored, if your game, for some reason, starts with `-`, in order to safely handle it you may need to specify it as an argument.
- `-f`: Use fullscreen.
- `-u <number>`: Select the index of the user to load as.
+6 -7
View File
@@ -1,12 +1,12 @@
# User Handbook - Controllers
Most of the controls should work out of the box. If not, please use a joystick calibrator to ensure it's not an issue with your own controller, for example:
Most of the controls should work out of the box. If not, use a joystick calibrator to ensure it's not an issue with your own controller, for example:
- https://github.com/dkosmari/calibrate-joystick
## Using external controllers on the Steamdeck
In desktop mode ignore your pro controller/xbox contoller external controller and use **Steam Virtual Gamepad 0 as Player 1**. If you have multiple external controllers set **Player 2 to Steam Virtual Gamepad 1**. Steam app must not be closed on desktop mode.
In desktop mode ignore your Pro controller/XBOX controller external controller and use **Steam Virtual Gamepad 0 as Player 1**. If you have multiple external controllers set **Player 2 to Steam Virtual Gamepad 1**. Steam app must not be closed on desktop mode.
Here's the annoying part of it. When waking up the steam deck from sleep try not to touch any button on the Steamdeck and turn on your external controller. Then open the Eden.AppImage. If you're lucky you can get your external controller to be position 0 and also Steam Virtual Gamepad 0 in desktop mode. If not that is ok too unless you need to configure player 1 to have gyro. You might need to repeat this to get your external controller as Steam Virtual Gamepad 0 so you can config Player 1 having gyro. You might be able to config player 1 to have gyro with the Steamdeck itself. Or you can also config player 1, 2, 3, etc, to have gyro somehow. Make sure they are all using Virtual Gamepads though.
@@ -18,7 +18,7 @@ Basically the Steamdeck or the external controller is fighting for position 0 an
Use this guide for when you want to configure specific controller settings to be reused.
**Click [Here](https://evilperson1337.notion.site/Configuring-Controller-Profiles-2be57c2edaf680eabc3ac8c333ec75c4) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Configuring-Controller-Profiles-2be57c2edaf680eabc3ac8c333ec75c4) for an illustrated guide.**
---
@@ -30,8 +30,8 @@ Use this guide for when you want to configure specific controller settings to be
#### Steps
1. Launch Eden and wait for it to load.
2. Navigate to *Emulation > Configure...*
3. Select **Controls** from the left-hand menu and configure your controller for the way you want it to be in game.
2. Navigate to `Emulation > Configure...`
3. Select **Controls** from the left-hand menu and configure your controller for the way you want it to be in-game.
4. Select **New** and enter a name for the profile in the box that appears. Press **OK** to save the profile settings.
5. Select **OK** to close the settings menu.
@@ -39,7 +39,7 @@ Use this guide for when you want to configure specific controller settings to be
Use this guide when you want to set up specific controller profiles for specific games. This can be useful for certain games like *Captain Toad Treasure Tracker* where a blue dot appears in the middle of the screen when you have docked mode enabled, but not handheld mode.
**Click [Here](https://evilperson1337.notion.site/Setting-Controller-Profiles-By-Game-2b057c2edaf681658a57f0c199cb6083) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Setting-Controller-Profiles-By-Game-2b057c2edaf681658a57f0c199cb6083) for an illustrated guide.**
---
@@ -47,7 +47,6 @@ Use this guide when you want to set up specific controller profiles for specific
- Eden Emulator set up and fully configured
- Controller Profile Created
- See [*Configuring Controller Profiles*](./ControllerProfiles.md) for instructions on how to do this if needed.
---
+1 -1
View File
@@ -100,7 +100,7 @@ HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (requir
### Fixes for Windows 10 and above having "Device loss"
Run the following batch script *inside* the Eden folder:
```cmd
```bat
@echo off
pushd "%~dp0"
if exist "%temp%\FixFullScreen.reg" (
+1 -1
View File
@@ -1,7 +1,7 @@
# Getting Gyro/Motion Controls Working on Steam Deck
Use this guide when you want to use the Steam Deck's native gyro functionality for motion controls in Eden.
**Click [Here](https://evilperson1337.notion.site/Getting-Gyro-Motion-Controls-Working-on-Steam-Deck-2b057c2edaf681a1aaade35db6e0fd1b) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Getting-Gyro-Motion-Controls-Working-on-Steam-Deck-2b057c2edaf681a1aaade35db6e0fd1b) for an illustrated guide.**
## Steamdeck
+1 -1
View File
@@ -2,7 +2,7 @@
Use this when you need to review the logs to determine an issue or provide them to a member of the Eden team.
**Click [Here](https://evilperson1337.notion.site/How-to-Access-Logs-2b057c2edaf68105a281fe1688a332d4) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/How-to-Access-Logs-2b057c2edaf68105a281fe1688a332d4) for an illustrated guide.**
---
+1 -1
View File
@@ -2,7 +2,7 @@
Use this guide when you want to manually import save files for use in the Eden emulator.
**Click [Here](https://evilperson1337.notion.site/Importing-Saves-Into-Eden-2b057c2edaf681fe968df8d63821ccae) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Importing-Saves-Into-Eden-2b057c2edaf681fe968df8d63821ccae) for an illustrated guide.**
### Pre-Requisites
- Eden emulator already set up and configured.
+1 -1
View File
@@ -2,7 +2,7 @@
Use this guide for when you want to install an Atmosphere-based mod for use in Eden.
**Click [Here](https://evilperson1337.notion.site/Installing-Atmosphere-Mods-2b057c2edaf681fe8d39cbfc2d0cc799) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Installing-Atmosphere-Mods-2b057c2edaf681fe8d39cbfc2d0cc799) for an illustrated guide.**
---
+1 -1
View File
@@ -8,7 +8,7 @@ Use this guide when you want to install Updates or DLC for your games in Eden.
</aside>
**Click [Here](https://evilperson1337.notion.site/Working-with-Updates-DLC-in-Eden-2b057c2edaf681dfb65dfc4dd96980c0) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Working-with-Updates-DLC-in-Eden-2b057c2edaf681dfb65dfc4dd96980c0) for an illustrated guide.**
---
+12 -12
View File
@@ -4,7 +4,7 @@ Use this guide to answer questions regarding and to start using the multiplayer
## Multiplayer FAQ
This FAQ will serve as a general quick question and answer simple questions.
**Click [Here](https://evilperson1337.notion.site/Multiplayer-FAQ-2c357c2edaf680fca2e9ce59969a220f) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Multiplayer-FAQ-2c357c2edaf680fca2e9ce59969a220f) for an illustrated guide.**
### Can Eden Play Games with a Switch Console?
No - The only emulator that has this kind of functionality is *Ryujinx* and it's forks. This solution requires loading a custom module on a modded switch console to work.
@@ -40,7 +40,7 @@ While it would be nice if everything always worked perfectly - that is not reali
1. Emulator Version Mismatches
1. Occasionally updates to the emulator of choice alter how the LDN functionality is handled. In these situations, unexpected behavior can occur when trying to establish LDN connections. This is a good first step to check if you are having issues playing a game together, but can join the same lobby without issue.
2. Game Version Mismatches
1. It is best practice to have the game version be identical to each other in order to ensure that there is no difference in how the programs are handling the LDN logic. Games are black boxes that the dev team cannot see into to ensure the logic handling operates the same way. For this reason, it is highly advised that the game versions match across all the players. This would be a good 2nd step to check if you are having issues playing a game together, but can join the same lobby without issue.
1. It is best practice to have the game version be identical to each other in order to ensure that there is no difference in how the programs are handling the LDN logic. Games are black boxes that the dev team can't see into to ensure the logic handling operates the same way. For this reason, it is highly advised that the game versions match across all the players. This would be a good 2nd step to check if you are having issues playing a game together, but can join the same lobby without issue.
3. Latency
1. Because this implementation is emulating a LAN/Local Wireless connection - it is extremely sensitive to network latency and drops. Eden has done a good job of trying to account for this and not immediately drop users out - but it is not infallible. If latency is a concern or becomes an issue - consider hosting a room.
@@ -49,7 +49,7 @@ While it would be nice if everything always worked perfectly - that is not reali
## Joining a Multiplayer Room
Use this when you need to connect to a multiplayer room for LDN functionality inside of Eden. This does not cover how to host a room, only joining existing ones.
**Click [Here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for an illustrated guide.**
### Pre-Requisites
- Eden set up and functioning
@@ -66,7 +66,7 @@ There are 2 primary methods that you can use to connect to an existing room, dep
<aside>
***NOTE:*** Just because a lobby appears on the public lobby list, does not mean that the hoster has properly configured the necessary port forwarding/firewall rules to allow a connection. If you cannot connect to a lobby, move onto another entry as the issue is probably not on your end. Start looking at your environment if you are unable to connect to multiple/any lobbies.
***NOTE:*** Just because a lobby appears on the public lobby list, does not mean that the host has properly configured the necessary port forwarding/firewall rules to allow a connection. If you can't connect to a lobby, move onto another entry as the issue is probably not on your end. Start looking at your environment if you are unable to connect to multiple/any lobbies.
</aside>
@@ -82,10 +82,10 @@ There are 2 primary methods that you can use to connect to an existing room, dep
3. You will now see a window showing everyone on the lobby, or an error message.
### Direct Connecting to a Room
If the hoster has not made the lobby public, or you don't want to find it in the public game browser - use this option to connect.
If the host has not made the lobby public, or you don't want to find it in the public game browser - use this option to connect.
1. Open Eden and navigate to *Multiplayer > Direct Connect*.
2. Enter the *Server Address, Port*, *Nickname* (what your user will be called in the room), and a *Password* (if the hoster set one, otherwise leave it blank) and hit **Connect.**
2. Enter the *Server Address, Port*, *Nickname* (what your user will be called in the room), and a *Password* (if the host set one, otherwise leave it blank) and hit **Connect.**
3. You will now see a window showing everyone on the lobby, or an error message.
---
@@ -93,7 +93,7 @@ If the hoster has not made the lobby public, or you don't want to find it in the
## Hosting a Multiplayer Room
Use this guide for when you want to host a multiplayer lobby to play with others in Eden. In order to have someone access the room from outside your local network, see the *Access Your Multiplayer Room Externally* section for next steps.
**Click [Here](https://evilperson1337.notion.site/Hosting-a-Multiplayer-Room-2c357c2edaf6819481dbe8a99926cea2) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Hosting-a-Multiplayer-Room-2c357c2edaf6819481dbe8a99926cea2) for an illustrated guide.**
### Pre-Requisites
- Eden set up and Functioning
@@ -123,7 +123,7 @@ Use this guide for when you want to host a multiplayer lobby to play with others
## Access Your Multiplayer Room Externally
Quite often the person with whom you want to play is located off of your internal network (LAN). If you want to host a room and play with them you will need to get your devices to communicate with each other. This guide will go over your options on how to do this so that you can play together.
**Click [Here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Access-Your-Multiplayer-Room-Externally-2c357c2edaf681c0ab2ce2ee624d809d) for an illustrated guide.**
### Pre-Requisites
- Eden set up and Functioning
@@ -137,7 +137,7 @@ Quite often the person with whom you want to play is located off of your interna
<aside>
Use this option if you want the greatest performance/lowest latency, don't want to install any software, and have the ability to modify your networking equipment's configuration (most notably - your router). Avoid this option if you cannot modify your router's configuration or are uncomfortable with looking up things on your own.
Use this option if you want the greatest performance/lowest latency, don't want to install any software, and have the ability to modify your networking equipment's configuration (most notably - your router). Avoid this option if you can't modify your router's configuration or are uncomfortable with looking up things on your own.
</aside>
@@ -155,7 +155,7 @@ Remember you can't have one port open for multiple devices at the same time - yo
<aside>
Use this option if you don't want to have to worry about other users machine/configuration settings, but also cannot do port forwarding. This will still require that you as the hoster install a program and sign up for an account - but will prevent you from having to deal with port forwards or networking equipment. Avoid this option if there is not a close relay and you are getting issues with latency.
Use this option if you don't want to have to worry about other users machine/configuration settings, but also can't do port forwarding. This will still require that you as the host install a program and sign up for an account - but will prevent you from having to deal with port forwards or networking equipment. Avoid this option if there is not a close relay and you are getting issues with latency.
</aside>
@@ -193,7 +193,7 @@ The VPN solution is a good compromise between the tunnelling solution and port f
## Finding the Server Information for a Multiplayer Room
Use this guide when you need to determine the connection information for the Public Multiplayer Lobby you are connected to.
**Click [Here](https://evilperson1337.notion.site/Finding-the-Server-Information-for-a-Multiplayer-Room-2c557c2edaf6809e94e8ed3429b9eb26) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Finding-the-Server-Information-for-a-Multiplayer-Room-2c557c2edaf6809e94e8ed3429b9eb26) for an illustrated guide.**
### Pre-Requisites
- Eden set up and configured
@@ -256,7 +256,7 @@ Use this guide when you need to determine the connection information for the Pub
## Multiplayer for Local Co-Op Games
Use this guide when you want to play with a friend on a different system for games that only support local co-op.
**Click [Here](https://evilperson1337.notion.site/Multiplayer-for-Local-Co-Op-Games-2c657c2edaf680c59975ec6b52022a2d) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Multiplayer-for-Local-Co-Op-Games-2c657c2edaf680c59975ec6b52022a2d) for an illustrated guide.**
Occasionally you will want to play a game with a friend on a game that does not support LDN multiplayer, and only offer local co-op (multiple controllers connected to a single console), such as with *New Super Mario Bros. U Deluxe.* Emulation solutions have developed 2 primary methods for handling these cases.
+2 -2
View File
@@ -1,9 +1,9 @@
# User Handbook - Native Application Development
Debugging on physical hardware can get tedious and time consuming. Users are empowered with the debugging capabilities of the emulator to ensure their applications run as-is on the system. To the greatest extent possible atleast.
Debugging on physical hardware can get tedious and time consuming. Users are empowered with the debugging capabilities of the emulator to ensure their applications run as-is on the system. To the greatest extent possible at least.
## Debugging
**Standard key prefix**: Allows to redirect the key manager to a file other than `prod.keys` (for example `other` would redirect to `other.keys`). This is useful for testing multiple keysets. Default is `prod`.
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accoutned for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console.
**Changing serial**: Very basic way to set debug values for the serial (and battery number). Developers do not need to write the full serial as only the first digits (excluding the last) will be accounted for. Region settings will affect the generated serial. The serial corresponds to a non-OLED/Lite console.
+3 -3
View File
@@ -2,7 +2,7 @@
Use this guide to get starting using the Eden emulator.
**Click [Here](https://evilperson1337.notion.site/Eden-Quick-Start-2b057c2edaf6817b9859d8bcdb474017) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Eden-Quick-Start-2b057c2edaf6817b9859d8bcdb474017) for an illustrated guide.**
## Windows
@@ -80,7 +80,7 @@ Use this guide to get starting using the Eden emulator.
## macOS
Current macOS support is still experimental and very reliant on MoltenVK developments, plans have shifted to properly provide support for KosmicKrisp and similar new GPU endeavours, but macOS users still are bound to MoltenVK itself.
Current macOS support is still experimental and very reliant on MoltenVK developments, plans have shifted to properly provide support for KosmicKrisp and similar new GPU endeavors, but macOS users still are bound to MoltenVK itself.
Users of macOS may wish to use [Asahi Linux](https://wiki.gentoo.org/wiki/Project:Asahi/Guide) for the rising KosmicKrisp support.
@@ -90,7 +90,7 @@ As of writing, neither macOS nor Asahi has support for NCE; additionally Asahi h
Use this guide when you need to allow Eden to run on a Mac system, but are being blocked by Apple Security policy.
**Click [Here](https://evilperson1337.notion.site/Allowing-Eden-to-Run-on-MacOS-2b057c2edaf681fea63dc81027efeffd) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Allowing-Eden-to-Run-on-MacOS-2b057c2edaf681fea63dc81027efeffd) for an illustrated guide.**
---
-2
View File
@@ -49,6 +49,4 @@ A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/
- **[Gyro Controls](./GyroControls.md)**
- **[Platforms and Architectures](./Architectures.md)**
- **[Native Application Development](./Native.md)**
- **[Adding Boolean Settings Toggles](./AddingBooleanToggles.md)**
- **[Adding Debug Knobs](./AddingDebugKnobs.md)**
- **[Testing](./Testing.md)**
+1 -1
View File
@@ -11,7 +11,7 @@ This guide explains how to set up a public/private self hosted Eden server/lobby
- Next, under Server OS Images, select Ubuntu 24.04 LTS. Configure CPU/RAM/specs as desired for your server. Complete the creation process.
- Enable the Kamatera firewall and set default policy: IN: DROP, OUT: ACCEPT.
- After setting the default policy, add the three following rules: #1: SSH Access - Direction: IN, Interface: net0, Macro: SSH - Secure Shell Traffic, Source: ANY, Port: Blank/Auto (Handeld by SSH), Destination: Blank/Auto (Handeld by SSH), Policy: ACCEPT, leave a comment: SSH access.
- After setting the default policy, add the three following rules: #1: SSH Access - Direction: IN, Interface: net0, Macro: SSH - Secure Shell Traffic, Source: ANY, Port: Blank/Auto (Handled by SSH), Destination: Blank/Auto (Handled by SSH), Policy: ACCEPT, leave a comment: SSH access.
- Then, after creating the first rule, add TCP & UDP Ports for Eden - Direction: IN, Interface: net0, Protocol: TCP or UDP (for respective rule), Source: ANY, Destination Port: 24872, Policy: ACCEPT, leave a comment: Eden server port.
- Note: Only UDP is required for Eden; opening TCP is optional.
+5 -5
View File
@@ -6,11 +6,11 @@ Most of the development adds new settings that enhance performance/compatibility
As such, this guide will NOT mention those kind of settings, we'd rather mention settings which have a long shelf time (i.e won't get removed in future releases) and are likely to be unchanged.
Some of the options are self explainatory, and they do exactly what they say they do (i.e "Pause when not in focus"); such options will be also skipped due to triviality.
Some of the options are self explanatory, and they do exactly what they say they do (i.e "Pause when not in focus"); such options will be also skipped due to triviality.
## Foreword
Before touching the settings, please see the game boots with stock options. We try our best to ensure users can boot any game using the default settings. If they don't work, then you may try fiddling with options - but please, first use stock options.
Before touching the settings, see the game boots with stock options. We try our best to ensure users can boot any game using the default settings. If they don't work, then you may try fiddling with options - but please, first use stock options.
## General
@@ -25,15 +25,15 @@ Before touching the settings, please see the game boots with stock options. We t
## System
- `System/RNG Seed`: Set to 0 (and uncheck) to disable ASLR systemwide (this makes mods like CTGP to stop working); by default it enables ASLR to replicate console behaviour.
- `System/RNG Seed`: Set to 0 (and uncheck) to disable ASLR system-wide (this makes mods like CTGP to stop working); by default it enables ASLR to replicate console behavior.
- `Network/Enable Airplane Mode`: Enable this if a game is crashing before loading AND the logs mention anything related to "web" or "internet" services.
## CPU
- `Fastmem`, aka. `CPU/Enable Host MMU`: Enables "fastmem"; a detailed description of fastmem can be found [here](../dynarmic/Design.md#fast-memory-fastmem).
- `CPU/Unsafe FMA`: Enables deliberate innacurate FMA behaviour which may affect how FMA returns any given operation - this may introduce tiny floating point errors which can cascade in sensitive code (i.e FFmpeg).
- `CPU/Unsafe FMA`: Enables deliberate inaccurate FMA behavior which may affect how FMA returns any given operation - this may introduce tiny floating point errors which can cascade in sensitive code (i.e FFmpeg).
- `CPU/Faster FRSQRTE and FRECPE`: Introduces accuracy errors on square root and reciprocals in exchange for less checks - this introduces inaccuracies with some cases but it's mostly safe.
- `CPU/Faster ASIMD Instructions`: Skips rounding mode checks for ARM ASIMD instructions - this means some code dpeending on these rounding modes may misbehave.
- `CPU/Faster ASIMD Instructions`: Skips rounding mode checks for ARM ASIMD instructions - this means some code depending on these rounding modes may misbehave.
- `CPU/Disable address space checks`: Before each memory access, the emulator checks the address is in range, if not it faults; this option makes it so the emulator skips the check entirely (which may be expensive for a myriad of reasons). However at the same time this allows the guest program to "break out" of the emulation context by writing to arbitrary addresses.
- `CPU/Ignore global monitor`: This relies on a quirk present on x86 to avoid the ARM global monitor emulation, this may increase performance in mutex-heavy contexts (i.e games waiting for next frames or such); but also can cause deadlocks and fun to debug issues.
+3 -3
View File
@@ -4,7 +4,7 @@
Use this when you want to import the Eden AppImage into your Steam Library along with artwork using *Steam ROM Manager.*
**Click [Here](https://evilperson1337.notion.site/Importing-Eden-into-Steam-with-Steam-Rom-Manager-2b757c2edaf68054851bc287b6382cb5) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Importing-Eden-into-Steam-with-Steam-Rom-Manager-2b757c2edaf68054851bc287b6382cb5) for an illustrated guide.**
---
@@ -114,7 +114,7 @@ We will need to create a new parser for the Emulators. Unlike with the EmuDeck
2. **Parser Title**: *Emulators - Emulators*
3. **Steam Directory**: *${steamdirglobal}*
4. **User Accounts**: *Global*
5. **ROMs Directory**: <path to directory containing eden AppImage>
5. **ROMs Directory**: <path to directory containing Eden AppImage>
6. **Steam Collections**: *Emulation* (OPTIONAL)
2. Parser Specific Configuration
1. **Search Glob**: *${title}@(.AppImage|.APPIMAGE|.appimage)*
@@ -167,7 +167,7 @@ Now that we have the parser or shell script created, we can actually add it to S
Use this when you want to import your games inside Eden into Steam to launch with artwork from Steam Game Mode without needing to launch Eden first.
**Click [Here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Importing-Games-into-Steam-with-Steam-Rom-Manager-2b757c2edaf680d7a491c92b138f1fcc) for an illustrated guide.**
---
+1 -1
View File
@@ -2,7 +2,7 @@
Use this guide for when you want to configure automated backup/syncing of your Eden save files using [*Syncthing*](https://syncthing.net/).
**Click [Here](https://evilperson1337.notion.site/Backing-Up-Syncing-Eden-Game-Saves-2b357c2edaf68000b40cfab2c2c3dc0a) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Backing-Up-Syncing-Eden-Game-Saves-2b357c2edaf68000b40cfab2c2c3dc0a) for an illustrated guide.**
### Pre-Requisites
+2 -2
View File
@@ -41,7 +41,7 @@ For regressions/bugs from PRs or commits:
- [ ] Bisected PR? (if it has commits)
- [ ] Found bisected commit?
If an issue sporadically appears, try to do multiple runs, try if possible, to count the number of times it has failed and the number of times it has "worked just fine"; say it worked 3 times but failed 1. then there is a 1/4th chance every run that the issue is replicated - so every bisect step would require 4 runs to ensure there is atleast a chance of triggering the bug.
If an issue sporadically appears, try to do multiple runs, try if possible, to count the number of times it has failed and the number of times it has "worked just fine"; say it worked 3 times but failed 1. then there is a 1/4th chance every run that the issue is replicated - so every bisect step would require 4 runs to ensure there is at least a chance of triggering the bug.
## What to do when something seems off
@@ -96,4 +96,4 @@ The faulty commit then, is 6th of Jan. This is called bisection https://git-scm.
- PR's marked with **WIP** do NOT need to be tested unless explicitly asked (check the git in case)
- Sometimes license checks may fail, hover over the build icon to see if builds did succeed, as the CI will push builds even if license checks fail.
- All open PRs can be viewed [here](https://git.eden-emu.dev/eden-emu/eden/pulls/).
- If site is down use one of the [mirrors](./user/ThirdParty.md#mirrors).
- If site is down use one of the [mirrors](./ThirdParty.md#mirrors).
+4 -4
View File
@@ -1,8 +1,8 @@
# User Handbook - Third party tools and extras
The Eden emulator by itself lacks some functionality - or otherwise requires external files (such as packaging) to operate correctly in a given OS. Addendum to that some repositories provide nightly or specialised builds of the emulator.
The Eden emulator by itself lacks some functionality - or otherwise requires external files (such as packaging) to operate correctly in a given OS. Addendum to that some repositories provide nightly or specialized builds of the emulator.
While most of the links mentioned in this guide are relatively "safe"; we urge users to use their due diligence and appropriatedly verify the integrity of all files downloaded and ensure they're not compromised.
While most of the links mentioned in this guide are relatively "safe"; we urge users to use their due diligence and appropriately verify the integrity of all files downloaded and ensure they're not compromised.
- [NixOS Eden Flake](https://github.com/Grantimatter/eden-flake)
- [ES-DE Frontend Support](https://github.com/GlazedBelmont/es-de-android-custom-systems)
@@ -18,13 +18,13 @@ The main origin repository is always at <https://git.eden-emu.dev/eden-emu/eden>
Other mirrors obviously exist on the internet, but we can't guarantee their reliability and/or availability.
If you're someone wanting to make a mirror, simply setup forgejo and automatically mirror from the origin repository. Or you could mirror a mirror to save us bandwidth... your choice!
If you're someone wanting to make a mirror, simply setup Forgejo and automatically mirror from the origin repository. Or you could mirror a mirror to save us bandwidth... your choice!
## Configuring Obtainium
Very nice handy app, here's a quick rundown how to configure:
1. Copy the URL: <https://git.eden-emu.dev/eden-emu/eden/> (or one of your favourite mirrors)
1. Copy the URL: <https://git.eden-emu.dev/eden-emu/eden/> (or one of your favorite mirrors)
2. Open Obtainium and tap `Add App`.
3. Paste the URL into the `App Source URL` field.
4. Override Source: Look for the `Override Source` dropdown menu and select `Forgejo (Codeberg)`.
+5 -5
View File
@@ -14,7 +14,7 @@
## Eden Fails to Launch and Does Not Leave Any Logs
**Click [Here](https://evilperson1337.notion.site/Windows-Eden-Fails-to-Launch-and-Does-Not-Leave-Any-Logs-2b057c2edaf68156b640cf1ac549870a) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Windows-Eden-Fails-to-Launch-and-Does-Not-Leave-Any-Logs-2b057c2edaf68156b640cf1ac549870a) for an illustrated guide.**
### Error Details
@@ -24,11 +24,11 @@
**Error Log Entries:**
```
```text
None
```
**Example Error Message Entry in Windows Event Viewer**
```
```text
Faulting application name: eden.exe, version: 0.0.0.0, time stamp: 0x6795dc3c
Faulting module name: ntdll.dll, version: 10.0.26100.3037, time stamp: 0x95e6c489
Exception code: 0xc0000005
@@ -73,7 +73,7 @@ Faulting package-relative application ID:
5. Look for an entry with the Level of Error, and look for a message similar to the following
```
```text
Faulting application name: Eden.exe, version: 0.0.0.0, time stamp: 0x6795dc3c
Faulting module name: ntdll.dll, version: 10.0.26100.3037, time stamp: 0x95e6c489
Exception code: 0xc0000005
@@ -90,7 +90,7 @@ Faulting package-relative application ID:
6. Run a Command Prompt terminal Window as Administrator.
7. Enter the following command and wait for it to complete. It will take a while, just be patient and do other things while it completes.
```
```bat
DISM /Online /Cleanup-Image /RestoreHealth
```
+3 -3
View File
@@ -2,7 +2,7 @@
Use this guide when you want to load Amiibo into your games for use with the Eden emulator.
**Click [Here](https://evilperson1337.notion.site/Using-Amiibo-with-Eden-2b057c2edaf681b1b28ec6be600c6d3e) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Using-Amiibo-with-Eden-2b057c2edaf681b1b28ec6be600c6d3e) for an illustrated guide.**
## Android
@@ -17,7 +17,7 @@ TBD
<aside>
***NOTE***: Eden only supports the *.bin* amiibo format, ***NOT*** the *.nfc* format.
***NOTE***: Eden only supports the *.bin* Amiibo format, ***NOT*** the *.nfc* format.
</aside>
@@ -37,7 +37,7 @@ TBD
<aside>
***NOTE***: It seems the scanning functionality is spotty and will sometimes throw a "*The current game is not looking for amiibos*" message, even though it is. Usually you just need to try loading it again or restarting the scanning from the game. In some situations it was only resolved by restarting the game.
***NOTE***: It seems the scanning functionality is spotty and will sometimes throw a "*The current game is not looking for Amiibos*" message, even though it is. Usually you just need to try loading it again or restarting the scanning from the game. In some situations it was only resolved by restarting the game.
</aside>
+1 -1
View File
@@ -2,7 +2,7 @@
Use this guide when you want to add cheats into a game to alter gameplay for use with the Eden emulator.
**Click [Here](https://evilperson1337.notion.site/Using-Cheats-with-Eden-2b057c2edaf6818fab66c276e2304bb4) for a version of this guide with images & visual elements.**
**[See here](https://evilperson1337.notion.site/Using-Cheats-with-Eden-2b057c2edaf6818fab66c276e2304bb4) for an illustrated guide.**
## Android
-8
View File
@@ -161,9 +161,6 @@ if (NOT ANDROID)
AddJsonPackage(sdl3)
else()
message(STATUS "Using bundled SDL3")
if (FREEBSD)
set(BUILD_SHARED_LIBS ON)
endif()
AddJsonPackage(sdl3-ci)
endif()
@@ -257,11 +254,6 @@ target_include_directories(tz PUBLIC ./tz)
add_library(bc_decoder bc_decoder/bc_decoder.cpp)
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)
add_library(renderdoc INTERFACE)
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc)
-2
View File
@@ -4,8 +4,6 @@
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
# TODO(crueter, MaranBr): Externals FFmpeg 8.0
set(FFmpeg_HWACCEL_LIBRARIES)
set(FFmpeg_HWACCEL_FLAGS)
set(FFmpeg_HWACCEL_INCLUDE_DIRS)
-184
View File
@@ -1,184 +0,0 @@
// 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];
}
-44
View File
@@ -1,44 +0,0 @@
// 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;
-6
View File
@@ -254,10 +254,4 @@ else()
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)
-160
View File
@@ -1,160 +0,0 @@
// 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
-43
View File
@@ -1,43 +0,0 @@
// 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
+1 -16
View File
@@ -19,9 +19,6 @@
#ifdef HAVE_SDL3
#include "audio_core/sink/sdl3_sink.h"
#endif
#ifdef __OPENORBIS__
#include "audio_core/sink/ps4_sink.h"
#endif
#include "audio_core/sink/null_sink.h"
#include "common/logging.h"
#include "common/settings_enums.h"
@@ -54,16 +51,6 @@ struct SinkDetails {
// sink_details is ordered in terms of desirability, with the best choice at the top.
constexpr SinkDetails sink_details[] = {
#ifdef __OPENORBIS__
SinkDetails{
Settings::AudioEngine::Ps4,
[](std::string_view device_id) -> std::unique_ptr<Sink> {
return std::make_unique<PS4Sink>(device_id);
},
&ListPS4SinkDevices,
&GetPS4Latency,
},
#endif
#ifdef HAVE_OBOE
SinkDetails{
Settings::AudioEngine::Oboe,
@@ -128,9 +115,7 @@ const SinkDetails& GetOutputSinkDetails(Settings::AudioEngine sink_id) {
// BEGIN REINTRODUCED FROM 3833 - REPLACED CODE BLOCK ABOVE - DIABLO 3 FIX
// Auto-select a backend. Prefer CubeB, but it may report a large minimum latency which
// causes audio issues, in that case go with SDL.
#if defined(__OPENORBIS__)
iter = find_backend(Settings::AudioEngine::Ps4);
#elif defined(HAVE_CUBEB) && defined(HAVE_SDL3)
#if defined(HAVE_CUBEB) && defined(HAVE_SDL3)
iter = find_backend(Settings::AudioEngine::Cubeb);
if (iter->latency() > TargetSampleCount * 3) {
iter = find_backend(Settings::AudioEngine::Sdl3);
-2
View File
@@ -89,7 +89,6 @@ add_library(
param_package.h
parent_of_member.h
point.h
quaternion.h
range_map.h
range_mutex.h
range_sets.h
@@ -230,7 +229,6 @@ if(CXX_CLANG)
$<$<VERSION_LESS:$<CXX_COMPILER_VERSION>,15>:CANNOT_EXPLICITLY_INSTANTIATE>)
endif()
# Has to be BEFORE httplib
if (BOOST_NO_HEADERS)
target_link_libraries(common PUBLIC Boost::algorithm Boost::heap Boost::icl Boost::pool)
else()
+10 -12
View File
@@ -20,9 +20,6 @@
#else
#include <unistd.h>
#endif
#ifdef __OPENORBIS__
#include <sys/stat.h>
#endif
#ifdef _MSC_VER
#define fileno _fileno
@@ -405,27 +402,28 @@ u64 IOFile::GetSize() const {
file_size = Android::GetSize(file_path);
} else {
std::error_code ec;
file_size = fs::file_size(file_path, ec);
if (ec) {
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
LOG_ERROR(Common_Filesystem,
"Failed to retrieve the file size of path={}, ec_message={}",
PathToUTF8String(file_path), ec.message());
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
std::error_code ec;
const auto file_size = fs::file_size(file_path, ec);
if (ec) {
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}", PathToUTF8String(file_path), ec.message());
LOG_ERROR(Common_Filesystem, "Failed to retrieve the file size of path={}, ec_message={}",
PathToUTF8String(file_path), ec.message());
return 0;
}
#endif
return file_size;
}
-3
View File
@@ -174,14 +174,11 @@ bool CreateDir(const fs::path& path) {
return false;
}
// TODO: Maybe this is what causes death?
#ifndef __OPENORBIS__
if (!Exists(path.parent_path())) {
LOG_ERROR(Common_Filesystem, "Parent directory of path={} does not exist",
PathToUTF8String(path));
return false;
}
#endif
if (IsDir(path)) {
LOG_DEBUG(Common_Filesystem, "Filesystem object at path={} exists and is a directory",
+12 -11
View File
@@ -130,10 +130,6 @@ public:
ASSERT(!eden_path.empty());
eden_path_cache = eden_path / CACHE_DIR;
eden_path_config = eden_path / CONFIG_DIR;
#elif defined(__OPENORBIS__)
eden_path = "/data/eden";
eden_path_cache = eden_path / CACHE_DIR;
eden_path_config = eden_path / CONFIG_DIR;
#else
eden_path = GetCurrentDir() / PORTABLE_DIR;
if (!Exists(eden_path) || !IsDir(eden_path)) {
@@ -176,11 +172,12 @@ public:
GenerateEdenPath(EdenPath::ShaderDir, eden_path_cache / SHADER_DIR);
#ifdef _WIN32
GenerateLegacyPath(EmuPath::RyujinxDir, GetAppDataRoamingDirectory() / RYUJINX_DIR);
#elif !defined(__OPENORBIS__)
#else
// 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
GenerateLegacyPath(EmuPath::RyujinxDir, GetDataDirectory("XDG_CONFIG_HOME") / RYUJINX_DIR);
#endif
}
private:
@@ -342,33 +339,36 @@ fs::path GetAppDataRoamingDirectory() {
return fs_appdata_roaming_path;
}
#elif defined(__OPENORBIS__)
// Not required/defined
#else
fs::path GetHomeDirectory() {
const char* home_env_var = getenv("HOME");
if (home_env_var) {
return fs::path{home_env_var};
}
LOG_INFO(Common_Filesystem,
"$HOME is not defined in the environment variables, "
"attempting to query passwd to get the home path of the current user");
"$HOME is not defined in the environment variables, "
"attempting to query passwd to get the home path of the current user");
const auto* pw = getpwuid(getuid());
if (!pw) {
LOG_ERROR(Common_Filesystem, "Failed to get the home path of the current user");
return {};
}
return fs::path{pw->pw_dir};
}
fs::path GetDataDirectory(const std::string& env_name) {
const char* data_env_var = getenv(env_name.c_str());
if (data_env_var) {
return fs::path{data_env_var};
}
if (env_name == "XDG_DATA_HOME") {
return GetHomeDirectory() / ".local/share";
} else if (env_name == "XDG_CACHE_HOME") {
@@ -376,6 +376,7 @@ fs::path GetDataDirectory(const std::string& env_name) {
} else if (env_name == "XDG_CONFIG_HOME") {
return GetHomeDirectory() / ".config";
}
return {};
}
+10 -10
View File
@@ -38,15 +38,15 @@
// FreeBSD
#ifndef MAP_NORESERVE
# define MAP_NORESERVE 0
#define MAP_NORESERVE 0
#endif
// Solaris 11 and illumos
#ifndef MAP_ALIGNED_SUPER
# define MAP_ALIGNED_SUPER 0
#define MAP_ALIGNED_SUPER 0
#endif
// macOS
#ifndef MAP_ANONYMOUS
# define MAP_ANONYMOUS MAP_ANON
#define MAP_ANONYMOUS MAP_ANON
#endif
#endif // ^^^ POSIX ^^^
@@ -441,15 +441,13 @@ static void* ChooseVirtualBase(size_t virtual_size) {
#else
static void* ChooseVirtualBase(size_t size) {
static void* ChooseVirtualBase(size_t virtual_size) {
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
void* virtual_base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
if (virtual_base != MAP_FAILED)
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
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
}
#endif
@@ -731,8 +729,9 @@ void HostMemory::Map(size_t virtual_offset, size_t host_offset, size_t length, M
ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size);
ASSERT(host_offset + length <= backing_size);
if (length == 0 || !virtual_base || !impl)
if (length == 0 || !virtual_base || !impl) {
return;
}
impl->Map(virtual_offset + virtual_base_offset, host_offset, length, perms);
#endif
}
@@ -742,8 +741,9 @@ void HostMemory::Unmap(size_t virtual_offset, size_t length, bool separate_heap)
ASSERT(virtual_offset % PageAlignment == 0);
ASSERT(length % PageAlignment == 0);
ASSERT(virtual_offset + length <= virtual_size);
if (length == 0 || !virtual_base || !impl)
if (length == 0 || !virtual_base || !impl) {
return;
}
impl->Unmap(virtual_offset + virtual_base_offset, length);
#endif
}
+3 -2
View File
@@ -74,13 +74,14 @@ public:
}
private:
size_t backing_size{};
size_t virtual_size{};
#if !(defined(__OPENORBIS__) || defined(__managarm__))
// Low level handler for the platform dependent memory routines
class Impl;
std::unique_ptr<Impl> impl;
#endif
size_t backing_size{};
size_t virtual_size{};
u8* backing_base{};
u8* virtual_base{};
size_t virtual_base_offset{};
-6
View File
@@ -3,14 +3,8 @@
#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_OPENSSL_SUPPORT 1
#endif
#ifdef __GNUC__
#pragma GCC diagnostic push
+8 -1
View File
@@ -236,6 +236,7 @@ struct ColorConsoleBackend final : public Backend {
#endif
};
#ifndef __OPENORBIS__
/// @brief Backend that writes to a file passed into the constructor
struct FileBackend final : public Backend {
explicit FileBackend(const std::filesystem::path filename) noexcept {
@@ -298,7 +299,7 @@ private:
std::size_t bytes_written = 0;
bool enabled = true;
};
#endif
#ifdef _WIN32
/// @brief Backend that writes to Visual Studio's output window
struct DebuggerBackend final : public Backend {
@@ -342,8 +343,10 @@ struct Impl {
template<typename F>
void ForEachBackend(F&& lambda) noexcept {
lambda(static_cast<Backend&>(color_console_backend));
#ifndef __OPENORBIS__
if (file_backend)
lambda(static_cast<Backend&>(*file_backend));
#endif
#ifdef _WIN32
lambda(static_cast<Backend&>(debugger_backend));
#endif
@@ -354,7 +357,9 @@ struct Impl {
Filter filter;
ColorConsoleBackend color_console_backend{};
#ifndef __OPENORBIS__
std::optional<FileBackend> file_backend;
#endif
#ifdef _WIN32
DebuggerBackend debugger_backend{};
#endif
@@ -391,10 +396,12 @@ void Initialize() {
} else {
logging_instance.emplace();
logging_instance->filter.ParseFilterString(Settings::values.log_filter.GetValue());
#ifndef __OPENORBIS__
using namespace Common::FS;
const auto& log_dir = GetEdenPath(EdenPath::LogDir);
void(CreateDir(log_dir));
logging_instance->file_backend.emplace(log_dir / LOG_FILE);
#endif
}
}
+1 -4
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -11,7 +8,7 @@
// clang-format on
#else
#include <sys/types.h>
#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(__OPENORBIS__))
#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>
#elif defined(__linux__)
#include <sys/sysinfo.h>
+1 -1
View File
@@ -213,7 +213,7 @@ std::optional<std::string> MakeRequest(const std::string& url, const std::string
client->set_read_timeout(timeout_seconds);
client->set_write_timeout(timeout_seconds);
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
#ifdef YUZU_BUNDLED_OPENSSL
client->load_ca_cert_store(kCert, sizeof(kCert));
#endif
-79
View File
@@ -1,79 +0,0 @@
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/vector_math.h"
namespace Common {
template <typename T>
class Quaternion {
public:
Vec3<T> xyz;
T w{};
[[nodiscard]] Quaternion<decltype(-T{})> Inverse() const {
return {-xyz, w};
}
[[nodiscard]] Quaternion<decltype(T{} + T{})> operator+(const Quaternion& other) const {
return {xyz + other.xyz, w + other.w};
}
[[nodiscard]] Quaternion<decltype(T{} - T{})> operator-(const Quaternion& other) const {
return {xyz - other.xyz, w - other.w};
}
[[nodiscard]] Quaternion<decltype(T{} * T{} - T{} * T{})> operator*(
const Quaternion& other) const {
return {xyz * other.w + other.xyz * w + Cross(xyz, other.xyz),
w * other.w - Dot(xyz, other.xyz)};
}
[[nodiscard]] Quaternion<T> Normalized() const {
T length = std::sqrt(xyz.Length2() + w * w);
return {xyz / length, w / length};
}
[[nodiscard]] std::array<decltype(-T{}), 16> ToMatrix() const {
const T x2 = xyz[0] * xyz[0];
const T y2 = xyz[1] * xyz[1];
const T z2 = xyz[2] * xyz[2];
const T xy = xyz[0] * xyz[1];
const T wz = w * xyz[2];
const T xz = xyz[0] * xyz[2];
const T wy = w * xyz[1];
const T yz = xyz[1] * xyz[2];
const T wx = w * xyz[0];
return {1.0f - 2.0f * (y2 + z2),
2.0f * (xy + wz),
2.0f * (xz - wy),
0.0f,
2.0f * (xy - wz),
1.0f - 2.0f * (x2 + z2),
2.0f * (yz + wx),
0.0f,
2.0f * (xz + wy),
2.0f * (yz - wx),
1.0f - 2.0f * (x2 + y2),
0.0f,
0.0f,
0.0f,
0.0f,
1.0f};
}
};
template <typename T>
[[nodiscard]] auto QuaternionRotate(const Quaternion<T>& q, const Vec3<T>& v) {
return v + 2 * Cross(q.xyz, Cross(q.xyz, v) + v * q.w);
}
[[nodiscard]] inline Quaternion<float> MakeQuaternion(const Vec3<float>& axis, float angle) {
return {axis * std::sin(angle / 2), std::cos(angle / 2)};
}
} // namespace Common
+6 -3
View File
@@ -27,7 +27,7 @@
#include "common/settings.h"
#include "common/time_zone.h"
#ifdef __unix__
#if defined(__linux__ ) && defined(ARCHITECTURE_arm64)
#include <unistd.h>
#endif
@@ -187,9 +187,12 @@ bool IsFastmemEnabled() {
return bool(values.cpuopt_fastmem);
else if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe)
return bool(values.cpuopt_unsafe_host_mmu);
#if defined(__unix__)
// TODO: Support this since only 4kb systems support host MMU right now
#if defined(__linux__) && defined(ARCHITECTURE_arm64)
// Only 4kb systems support host MMU right now
// TODO: Support this
return getpagesize() == 4096;
#elif !defined(__APPLE__) && !defined(__ANDROID__) && !defined(_WIN32) && !defined(__linux__) && !defined(__FreeBSD__)
return false;
#else
return true;
#endif
+2 -9
View File
@@ -196,14 +196,7 @@ struct Values {
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
// 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<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
MemoryLayout::Memory_4Gb,
"memory_layout_mode",
@@ -337,7 +330,7 @@ struct Values {
// Renderer
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__)
#if defined(__sun__) || defined(__managarm__)
RendererBackend::OpenGL_GLSL,
#else
RendererBackend::Vulkan,
+1 -2
View File
@@ -92,7 +92,7 @@ struct EnumMetadata {
// AudioEngine must be specified discretely due to having existing but slightly different
// canonicalizations
// TODO (lat9nq): Remove explicit definition of AudioEngine/sink_id
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, Ps4, };
enum class AudioEngine : u32 { Auto, Cubeb, Sdl3, Null, Oboe, };
template<>
inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioEngine>::Canonicalizations() {
return {
@@ -100,7 +100,6 @@ inline std::vector<std::pair<std::string_view, AudioEngine>> EnumMetadata<AudioE
{"cubeb", AudioEngine::Cubeb},
{"sdl3", AudioEngine::Sdl3},
{"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
+89 -713
View File
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2014 Tony Wasserka
@@ -7,752 +7,128 @@
#pragma once
#ifdef __ARM_NEON
#include <arm_neon.h>
#endif
#include <cmath>
#include <type_traits>
namespace Common {
template <typename T>
class Vec2;
template <typename T>
class Vec3;
template <typename T>
class Vec4;
template <typename T>
class Vec2 {
template <typename T, size_t N>
class Vec {
public:
T x{};
T y{};
std::array<T, N> elems{};
constexpr Vec2() = default;
constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {}
constexpr Vec() = default;
constexpr Vec(T e0) noexcept : elems{e0} {}
constexpr Vec(T e0, T e1) noexcept : elems{e0, e1} {}
constexpr Vec(T e0, T e1, T e2) noexcept : elems{e0, e1, e2} {}
constexpr Vec(T e0, T e1, T e2, T e4) noexcept : elems{e0, e1, e2, e4} {}
//explicit constexpr Vec(const std::initializer_list<T> elems_) noexcept : elems{elems_} {}
template <typename T2>
[[nodiscard]] constexpr Vec2<T2> Cast() const {
return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y));
[[nodiscard]] constexpr Vec<decltype(T{} + T{}), N> operator+(const Vec o) const noexcept {
Vec<decltype(T{} + T{}), N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = elems[i] + o.elems[i];
return r;
}
constexpr Vec<T, N> operator+=(const Vec<T, N> o) noexcept { return *this = *this + o; }
[[nodiscard]] static constexpr Vec2 AssignToAll(const T& f) {
return Vec2{f, f};
}
[[nodiscard]] constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const {
return {x + other.x, y + other.y};
}
constexpr Vec2& operator+=(const Vec2& other) {
x += other.x;
y += other.y;
return *this;
}
[[nodiscard]] constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const {
return {x - other.x, y - other.y};
}
constexpr Vec2& operator-=(const Vec2& other) {
x -= other.x;
y -= other.y;
return *this;
[[nodiscard]] constexpr Vec<decltype(T{} - T{}), N> operator-(const Vec o) const noexcept {
Vec<decltype(T{} - T{}), N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = elems[i] - o.elems[i];
return r;
}
constexpr Vec<T, N> operator-=(const Vec<T, N> o) noexcept { return *this = *this - o; }
template <typename U = T>
[[nodiscard]] constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y};
}
[[nodiscard]] constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const {
return {x * other.x, y * other.y};
[[nodiscard]] constexpr Vec<std::enable_if_t<std::is_signed_v<U>, U>, N> operator-() const noexcept {
Vec<U, N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = -elems[i];
return r;
}
[[nodiscard]] constexpr Vec<decltype(T{} * T{}), N> operator*(const Vec o) const noexcept {
Vec<decltype(T{} * T{}), N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = elems[i] * o.elems[i];
return r;
}
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const {
[[nodiscard]] constexpr Vec<decltype(T{} * V{}), N> operator*(const V f) const noexcept {
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
};
Vec<TV, N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = TV(C(elems[i]) * C(f));
return r;
}
template <typename V>
constexpr Vec<T, N> operator*=(const V f) noexcept { return *this = *this * f; }
template <typename V>
constexpr Vec2& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
[[nodiscard]] constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const {
[[nodiscard]] constexpr Vec<decltype(T{} / V{}), N> operator/(const V f) const noexcept {
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
};
Vec<TV, N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = TV(C(elems[i]) / C(f));
return r;
}
template <typename V>
constexpr Vec2& operator/=(const V& f) {
*this = *this / f;
return *this;
}
constexpr Vec<T, N> operator/=(const V f) noexcept { return *this = *this / f; }
[[nodiscard]] constexpr T Length2() const {
return x * x + y * y;
[[nodiscard]] constexpr T Length2() const noexcept {
T r{};
for (size_t i = 0; i < N; ++i)
r += elems[i] * elems[i];
return r;
}
// Only implemented for T=float
[[nodiscard]] float Length() const;
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
[[nodiscard]] T Length() const { return T(std::sqrt(float(Length2()))); }
[[nodiscard]] Vec<T, N> Normalized() const { return *this / Length(); }
[[nodiscard]] constexpr T& operator[](std::size_t i) noexcept { return elems[i]; }
[[nodiscard]] constexpr const T& operator[](std::size_t i) const noexcept { return elems[i]; }
[[nodiscard]] constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
[[nodiscard]] std::array<decltype(-T{}), 16> ToMatrix() const {
const T x2 = elems[0] * elems[0];
const T y2 = elems[1] * elems[1];
const T z2 = elems[2] * elems[2];
constexpr void SetZero() {
x = 0;
y = 0;
}
// Common aliases: UV (texel coordinates), ST (texture coordinates)
[[nodiscard]] constexpr T& u() {
return x;
}
[[nodiscard]] constexpr T& v() {
return y;
}
[[nodiscard]] constexpr T& s() {
return x;
}
[[nodiscard]] constexpr T& t() {
return y;
}
[[nodiscard]] constexpr const T& u() const {
return x;
}
[[nodiscard]] constexpr const T& v() const {
return y;
}
[[nodiscard]] constexpr const T& s() const {
return x;
}
[[nodiscard]] constexpr const T& t() const {
return y;
}
// swizzlers - create a subvector of specific components
[[nodiscard]] constexpr Vec2 yx() const {
return Vec2(y, x);
}
[[nodiscard]] constexpr Vec2 vu() const {
return Vec2(y, x);
}
[[nodiscard]] constexpr Vec2 ts() const {
return Vec2(y, x);
const T xy = elems[0] * elems[1];
const T wz = elems[3] * elems[2];
const T xz = elems[0] * elems[2];
const T wy = elems[3] * elems[1];
const T yz = elems[1] * elems[2];
const T wx = elems[3] * elems[0];
return {
1.0f - 2.0f * (y2 + z2),
2.0f * (xy + wz),
2.0f * (xz - wy),
0.0f,
2.0f * (xy - wz),
1.0f - 2.0f * (x2 + z2),
2.0f * (yz + wx),
0.0f,
2.0f * (xz + wy),
2.0f * (yz - wx),
1.0f - 2.0f * (x2 + y2),
0.0f,
0.0f,
0.0f,
0.0f,
1.0f
};
}
};
template <typename T, typename V>
[[nodiscard]] constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) {
template <typename T, size_t N, typename V>
[[nodiscard]] constexpr Vec<T, N> operator*(const V f, const Vec<T, N> v) noexcept {
using C = std::common_type_t<T, V>;
return Vec2<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)));
}
using Vec2f = Vec2<float>;
template <>
inline float Vec2<float>::Length() const {
return std::sqrt(x * x + y * y);
}
template <>
inline float Vec2<float>::Normalize() {
float length = Length();
*this /= length;
return length;
}
template <typename T>
class Vec3 {
public:
T x{};
T y{};
T z{};
constexpr Vec3() = default;
constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {}
template <typename T2>
[[nodiscard]] constexpr Vec3<T2> Cast() const {
return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z));
}
[[nodiscard]] static constexpr Vec3 AssignToAll(const T& f) {
return Vec3(f, f, f);
}
[[nodiscard]] constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const {
return {x + other.x, y + other.y, z + other.z};
}
constexpr Vec3& operator+=(const Vec3& other) {
x += other.x;
y += other.y;
z += other.z;
return *this;
}
[[nodiscard]] constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const {
return {x - other.x, y - other.y, z - other.z};
}
constexpr Vec3& operator-=(const Vec3& other) {
x -= other.x;
y -= other.y;
z -= other.z;
return *this;
}
template <typename U = T>
[[nodiscard]] constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y, -z};
}
[[nodiscard]] constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const {
return {x * other.x, y * other.y, z * other.z};
}
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const {
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
};
}
template <typename V>
constexpr Vec3& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
[[nodiscard]] constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const {
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
};
}
template <typename V>
constexpr Vec3& operator/=(const V& f) {
*this = *this / f;
return *this;
}
void RotateFromOrigin(float roll, float pitch, float yaw) {
float temp = y;
y = std::cos(roll) * y - std::sin(roll) * z;
z = std::sin(roll) * temp + std::cos(roll) * z;
temp = x;
x = std::cos(pitch) * x + std::sin(pitch) * z;
z = -std::sin(pitch) * temp + std::cos(pitch) * z;
temp = x;
x = std::cos(yaw) * x - std::sin(yaw) * y;
y = std::sin(yaw) * temp + std::cos(yaw) * y;
}
[[nodiscard]] constexpr T Length2() const {
return x * x + y * y + z * z;
}
// Only implemented for T=float
[[nodiscard]] float Length() const;
[[nodiscard]] Vec3 Normalized() const;
[[nodiscard]] float Normalize(); // returns the previous length, which is often useful
[[nodiscard]] constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
}
// Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates)
[[nodiscard]] constexpr T& u() {
return x;
}
[[nodiscard]] constexpr T& v() {
return y;
}
[[nodiscard]] constexpr T& w() {
return z;
}
[[nodiscard]] constexpr T& r() {
return x;
}
[[nodiscard]] constexpr T& g() {
return y;
}
[[nodiscard]] constexpr T& b() {
return z;
}
[[nodiscard]] constexpr T& s() {
return x;
}
[[nodiscard]] constexpr T& t() {
return y;
}
[[nodiscard]] constexpr T& q() {
return z;
}
[[nodiscard]] constexpr const T& u() const {
return x;
}
[[nodiscard]] constexpr const T& v() const {
return y;
}
[[nodiscard]] constexpr const T& w() const {
return z;
}
[[nodiscard]] constexpr const T& r() const {
return x;
}
[[nodiscard]] constexpr const T& g() const {
return y;
}
[[nodiscard]] constexpr const T& b() const {
return z;
}
[[nodiscard]] constexpr const T& s() const {
return x;
}
[[nodiscard]] constexpr const T& t() const {
return y;
}
[[nodiscard]] constexpr const T& q() const {
return z;
}
// swizzlers - create a subvector of specific components
// e.g. Vec2 uv() { return Vec2(x,y); }
// _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all
// component names (x<->r) and permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \
_DEFINE_SWIZZLER2(a, b, a##b); \
_DEFINE_SWIZZLER2(a, b, a2##b2); \
_DEFINE_SWIZZLER2(a, b, a3##b3); \
_DEFINE_SWIZZLER2(a, b, a4##b4); \
_DEFINE_SWIZZLER2(b, a, b##a); \
_DEFINE_SWIZZLER2(b, a, b2##a2); \
_DEFINE_SWIZZLER2(b, a, b3##a3); \
_DEFINE_SWIZZLER2(b, a, b4##a4)
DEFINE_SWIZZLER2(x, y, r, g, u, v, s, t);
DEFINE_SWIZZLER2(x, z, r, b, u, w, s, q);
DEFINE_SWIZZLER2(y, z, g, b, v, w, t, q);
#undef DEFINE_SWIZZLER2
#undef _DEFINE_SWIZZLER2
};
template <typename T, typename V>
[[nodiscard]] constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) {
using C = std::common_type_t<T, V>;
return Vec3<T>(static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.y)),
static_cast<T>(static_cast<C>(f) * static_cast<C>(vec.z)));
}
template <>
inline float Vec3<float>::Length() const {
return std::sqrt(x * x + y * y + z * z);
}
template <>
inline Vec3<float> Vec3<float>::Normalized() const {
return *this / Length();
}
template <>
inline float Vec3<float>::Normalize() {
float length = Length();
*this /= length;
return length;
}
using Vec3f = Vec3<float>;
template <typename T>
class Vec4 {
public:
T x{};
T y{};
T z{};
T w{};
constexpr Vec4() = default;
constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_)
: x(x_), y(y_), z(z_), w(w_) {}
template <typename T2>
[[nodiscard]] constexpr Vec4<T2> Cast() const {
return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z),
static_cast<T2>(w));
}
[[nodiscard]] static constexpr Vec4 AssignToAll(const T& f) {
return Vec4(f, f, f, f);
}
[[nodiscard]] constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const {
return {x + other.x, y + other.y, z + other.z, w + other.w};
}
constexpr Vec4& operator+=(const Vec4& other) {
x += other.x;
y += other.y;
z += other.z;
w += other.w;
return *this;
}
[[nodiscard]] constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const {
return {x - other.x, y - other.y, z - other.z, w - other.w};
}
constexpr Vec4& operator-=(const Vec4& other) {
x -= other.x;
y -= other.y;
z -= other.z;
w -= other.w;
return *this;
}
template <typename U = T>
[[nodiscard]] constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const {
return {-x, -y, -z, -w};
}
[[nodiscard]] constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const {
return {x * other.x, y * other.y, z * other.z, w * other.w};
}
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const {
using TV = decltype(T{} * V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) * static_cast<C>(f)),
static_cast<TV>(static_cast<C>(w) * static_cast<C>(f)),
};
}
template <typename V>
constexpr Vec4& operator*=(const V& f) {
*this = *this * f;
return *this;
}
template <typename V>
[[nodiscard]] constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const {
using TV = decltype(T{} / V{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(x) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(y) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(z) / static_cast<C>(f)),
static_cast<TV>(static_cast<C>(w) / static_cast<C>(f)),
};
}
template <typename V>
constexpr Vec4& operator/=(const V& f) {
*this = *this / f;
return *this;
}
[[nodiscard]] constexpr T Length2() const {
return x * x + y * y + z * z + w * w;
}
[[nodiscard]] constexpr T& operator[](std::size_t i) {
return *((&x) + i);
}
[[nodiscard]] constexpr const T& operator[](std::size_t i) const {
return *((&x) + i);
}
constexpr void SetZero() {
x = 0;
y = 0;
z = 0;
w = 0;
}
// Common alias: RGBA (colors)
[[nodiscard]] constexpr T& r() {
return x;
}
[[nodiscard]] constexpr T& g() {
return y;
}
[[nodiscard]] constexpr T& b() {
return z;
}
[[nodiscard]] constexpr T& a() {
return w;
}
[[nodiscard]] constexpr const T& r() const {
return x;
}
[[nodiscard]] constexpr const T& g() const {
return y;
}
[[nodiscard]] constexpr const T& b() const {
return z;
}
[[nodiscard]] constexpr const T& a() const {
return w;
}
// Swizzlers - Create a subvector of specific components
// e.g. Vec2 uv() { return Vec2(x,y); }
// _DEFINE_SWIZZLER2 defines a single such function
// DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
// DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and
// permutations (xy<->yx)
#define _DEFINE_SWIZZLER2(a, b, name) \
[[nodiscard]] constexpr Vec2<T> name() const { return Vec2<T>(a, b); }
#define DEFINE_SWIZZLER2_COMP1(a, a2) \
_DEFINE_SWIZZLER2(a, a, a##a); \
_DEFINE_SWIZZLER2(a, a, a2##a2)
#define DEFINE_SWIZZLER2_COMP2(a, b, a2, b2) \
_DEFINE_SWIZZLER2(a, b, a##b); \
_DEFINE_SWIZZLER2(a, b, a2##b2); \
_DEFINE_SWIZZLER2(b, a, b##a); \
_DEFINE_SWIZZLER2(b, a, b2##a2)
DEFINE_SWIZZLER2_COMP2(x, y, r, g);
DEFINE_SWIZZLER2_COMP2(x, z, r, b);
DEFINE_SWIZZLER2_COMP2(x, w, r, a);
DEFINE_SWIZZLER2_COMP2(y, z, g, b);
DEFINE_SWIZZLER2_COMP2(y, w, g, a);
DEFINE_SWIZZLER2_COMP2(z, w, b, a);
DEFINE_SWIZZLER2_COMP1(x, r);
DEFINE_SWIZZLER2_COMP1(y, g);
DEFINE_SWIZZLER2_COMP1(z, b);
DEFINE_SWIZZLER2_COMP1(w, a);
#undef DEFINE_SWIZZLER2_COMP1
#undef DEFINE_SWIZZLER2_COMP2
#undef _DEFINE_SWIZZLER2
#define _DEFINE_SWIZZLER3(a, b, c, name) \
[[nodiscard]] constexpr Vec3<T> name() const { return Vec3<T>(a, b, c); }
#define DEFINE_SWIZZLER3_COMP1(a, a2) \
_DEFINE_SWIZZLER3(a, a, a, a##a##a); \
_DEFINE_SWIZZLER3(a, a, a, a2##a2##a2)
#define DEFINE_SWIZZLER3_COMP3(a, b, c, a2, b2, c2) \
_DEFINE_SWIZZLER3(a, b, c, a##b##c); \
_DEFINE_SWIZZLER3(a, c, b, a##c##b); \
_DEFINE_SWIZZLER3(b, a, c, b##a##c); \
_DEFINE_SWIZZLER3(b, c, a, b##c##a); \
_DEFINE_SWIZZLER3(c, a, b, c##a##b); \
_DEFINE_SWIZZLER3(c, b, a, c##b##a); \
_DEFINE_SWIZZLER3(a, b, c, a2##b2##c2); \
_DEFINE_SWIZZLER3(a, c, b, a2##c2##b2); \
_DEFINE_SWIZZLER3(b, a, c, b2##a2##c2); \
_DEFINE_SWIZZLER3(b, c, a, b2##c2##a2); \
_DEFINE_SWIZZLER3(c, a, b, c2##a2##b2); \
_DEFINE_SWIZZLER3(c, b, a, c2##b2##a2)
DEFINE_SWIZZLER3_COMP3(x, y, z, r, g, b);
DEFINE_SWIZZLER3_COMP3(x, y, w, r, g, a);
DEFINE_SWIZZLER3_COMP3(x, z, w, r, b, a);
DEFINE_SWIZZLER3_COMP3(y, z, w, g, b, a);
DEFINE_SWIZZLER3_COMP1(x, r);
DEFINE_SWIZZLER3_COMP1(y, g);
DEFINE_SWIZZLER3_COMP1(z, b);
DEFINE_SWIZZLER3_COMP1(w, a);
#undef DEFINE_SWIZZLER3_COMP1
#undef DEFINE_SWIZZLER3_COMP3
#undef _DEFINE_SWIZZLER3
};
template <typename T, typename V>
[[nodiscard]] constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) {
using TV = decltype(V{} * T{});
using C = std::common_type_t<T, V>;
return {
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.x)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.y)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.z)),
static_cast<TV>(static_cast<C>(f) * static_cast<C>(vec.w)),
};
}
using Vec4f = Vec4<float>;
template <typename T>
constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) {
return a.x * b.x + a.y * b.y;
}
template <typename T>
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z;
}
template <typename T>
[[nodiscard]] constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) {
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
}
template <>
[[nodiscard]] inline float Dot(const Vec4<float>& a, const Vec4<float>& b) {
#ifdef __ARM_NEON
float32x4_t va = vld1q_f32(&a.x);
float32x4_t vb = vld1q_f32(&b.x);
float32x4_t result = vmulq_f32(va, vb);
#if defined(__aarch64__) // Use vaddvq_f32 in ARMv8 architectures
return vaddvq_f32(result);
#else // Use manual addition for older architectures
float32x2_t sum2 = vadd_f32(vget_high_f32(result), vget_low_f32(result));
return vget_lane_f32(vpadd_f32(sum2, sum2), 0);
#endif
#else
return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
#endif
}
template <typename T>
[[nodiscard]] constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a,
const Vec3<T>& b) {
return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x};
}
// linear interpolation via float: 0.0=begin, 1.0=end
template <typename X>
[[nodiscard]] constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end,
const float t) {
return begin * (1.f - t) + end * t;
}
// linear interpolation via int: 0=begin, base=end
template <typename X, int base>
[[nodiscard]] constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin,
const X& end,
const int t) {
return (begin * (base - t) + end * t) / base;
}
// bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second
// interpolation.
template <typename X>
[[nodiscard]] constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11,
const float s, const float t) {
auto y0 = Lerp(x00, x01, s);
auto y1 = Lerp(x10, x11, s);
return Lerp(y0, y1, t);
}
// Utility vector factories
template <typename T>
[[nodiscard]] constexpr Vec2<T> MakeVec(const T& x, const T& y) {
return Vec2<T>{x, y};
}
template <typename T>
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) {
return Vec3<T>{x, y, z};
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) {
return MakeVec(x, y, zw[0], zw[1]);
}
template <typename T>
[[nodiscard]] constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) {
return MakeVec(xy[0], xy[1], z);
}
template <typename T>
[[nodiscard]] constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) {
return MakeVec(x, yz[0], yz[1]);
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) {
return Vec4<T>{x, y, z, w};
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) {
return MakeVec(xy[0], xy[1], z, w);
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) {
return MakeVec(x, yz[0], yz[1], w);
}
// NOTE: This has priority over "Vec2<Vec2<T>> MakeVec(const Vec2<T>& x, const Vec2<T>& y)".
// Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error
// out soon enough due to misuse of the returned structure.
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) {
return MakeVec(xy[0], xy[1], zw[0], zw[1]);
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) {
return MakeVec(xyz[0], xyz[1], xyz[2], w);
}
template <typename T>
[[nodiscard]] constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) {
return MakeVec(x, yzw[0], yzw[1], yzw[2]);
Vec<T, N> r{};
for (size_t i = 0; i < N; ++i)
r.elems[i] = T(C(f) * C(v.elems[i]));
return r;
}
} // namespace Common
+9 -172
View File
@@ -10,135 +10,11 @@
#include <sys/mman.h>
#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/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 {
#ifdef __OPENORBIS__
namespace Orbis {
constexpr size_t ORBIS_PAGE_SIZE = 16384;
struct Ucontext {
struct Sigset {
u64 bits[2];
} uc_sigmask;
int field1_0x10[12];
struct Mcontext {
u64 mc_onstack;
u64 mc_rdi;
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];
};
}
static boost::container::static_vector<std::pair<void*, size_t>, 16> swap_regions;
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* base = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
@@ -146,61 +22,22 @@ void* AllocateMemoryPages(std::size_t size) noexcept {
// Probably failing to reserve is less likely than failing to commit
base = 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);
void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
if (base == MAP_FAILED)
base = nullptr;
#endif
return addr;
ASSERT(base);
return base;
}
void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept {
if (!addr)
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
if (!base)
return;
#ifdef _WIN32
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));
}
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
#else
int rc = munmap(addr, size);
ASSERT(rc == 0);
ASSERT(munmap(base, size) == 0);
#endif
}
-1
View File
@@ -12,7 +12,6 @@ namespace Common {
void* AllocateMemoryPages(std::size_t size) noexcept;
void FreeMemoryPages(void* base, std::size_t size) noexcept;
void InitSwap() noexcept;
template <typename T>
class VirtualBuffer final {
+1 -3
View File
@@ -199,9 +199,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) {
config.enable_cycle_counting = !m_uses_wall_clock;
// Code cache size
#if defined(__OPENORBIS__)
config.code_cache_size = std::uint32_t(8_MiB);
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
config.code_cache_size = std::uint32_t(128_MiB);
#else
config.code_cache_size = std::uint32_t(512_MiB);
+1 -3
View File
@@ -252,9 +252,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
config.enable_cycle_counting = !m_uses_wall_clock;
// Code cache size
#if defined(__OPENORBIS__)
config.code_cache_size = std::uint32_t(8_MiB);
#elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__)
config.code_cache_size = std::uint32_t(128_MiB);
#else
config.code_cache_size = std::uint32_t(512_MiB);
+8 -17
View File
@@ -461,19 +461,8 @@ std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
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)};
#ifdef _WIN32
struct _stat64 file_status;
const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
@@ -481,14 +470,16 @@ FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) cons
struct stat file_status;
const auto stat_result = stat(fs_path.c_str(), &file_status);
#endif
if (stat_result != 0)
if (stat_result != 0) {
return {};
}
return {
.created{u64(file_status.st_ctime)},
.accessed{u64(file_status.st_atime)},
.modified{u64(file_status.st_mtime)},
.created{static_cast<u64>(file_status.st_ctime)},
.accessed{static_cast<u64>(file_status.st_atime)},
.modified{static_cast<u64>(file_status.st_mtime)},
};
#endif
}
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
@@ -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_read_timeout(std::chrono::seconds(2));
#if defined(YUZU_BUNDLED_OPENSSL) && !defined(__OPENORBIS__)
#ifdef YUZU_BUNDLED_OPENSSL
cli.load_ca_cert_store(kCert, sizeof(kCert));
#endif
@@ -34,13 +34,12 @@ struct FontRegion {
// 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
[[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_MAGIC = 0x36f81a1e; // What we expect the encrypted bfttf first 4 bytes to be
constexpr u64 SHARED_FONT_MEM_SIZE = 0x1100000;
[[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_MAGIC{0x36f81a1e}; // What we expect the encrypted bfttf first 4 bytes to be
constexpr u64 SHARED_FONT_MEM_SIZE{0x1100000};
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) {
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");
@@ -52,7 +51,6 @@ 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));
offset += transformed_font.size() * sizeof(u32);
}
#endif
void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output) {
ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number");
@@ -72,7 +70,7 @@ void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, s
const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC);
std::vector<u32> transformed_font(input.size() + 2);
transformed_font[0] = Common::swap32(EXPECTED_MAGIC);
transformed_font[1] = Common::swap32(u32(input.size() * sizeof(u32))) ^ key;
transformed_font[1] = Common::swap32(static_cast<u32>(input.size() * sizeof(u32))) ^ 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));
offset += transformed_font.size() * sizeof(u32);
@@ -85,10 +83,8 @@ struct IPlatformServiceManager::Impl {
// Automatically populated based on shared_fonts dump or system archives.
// 6 builtin fonts + extra 2 for whatever may come after
boost::container::static_vector<FontRegion, 8> shared_font_regions;
#ifndef __OPENORBIS__
/// Backing memory for the shared font data
std::array<u8, SHARED_FONT_MEM_SIZE> shared_font;
#endif
};
IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_)
@@ -115,40 +111,49 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
// clang-format on
RegisterHandlers(functions);
#ifndef __OPENORBIS__
auto& fsc = system.GetFileSystemController();
// Attempt to load shared font data from disk
const auto* nand = fsc.GetSystemNANDContents();
std::size_t offset = 0;
// Rebuild shared fonts from data ncas or synthesize
for (auto& font : SHARED_FONTS) {
FileSys::VirtualFile romfs;
if (auto const nca = nand->GetEntry(u64(font.first), FileSys::ContentRecordType::Data); nca)
const auto nca =
nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
if (nca) {
romfs = nca->GetRomFS();
if (!romfs)
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(u64(font.first));
if (romfs) {
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));
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);
}
if (!romfs) {
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(static_cast<u64>(font.first));
}
if (!romfs) {
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;
@@ -182,10 +187,8 @@ Result IPlatformServiceManager::GetSharedMemoryNativeHandle(OutCopyHandle<Kernel
// Map backing memory for the font data
LOG_DEBUG(Service_NS, "called");
#ifndef __OPENORBIS__
// Create shared font memory object
std::memcpy(kernel.GetFontSharedMem().GetPointer(), impl->shared_font.data(), impl->shared_font.size());
#endif
// FIXME: this shouldn't belong to the kernel
*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: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -30,15 +33,15 @@ struct DeviceSettings {
INSERT_PADDING_BYTES(0x20); // Reserved
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
Common::Vec3<f32> console_six_axis_sensor_acceleration_bias;
Common::Vec<f32, 3> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias;
Common::Vec<f32, 3> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias;
Common::Vec<f32, 3> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration;
};
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@@ -153,15 +153,15 @@ struct SystemSettings {
INSERT_PADDING_BYTES(0x7FF8); // Reserved
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
Common::Vec3<f32> console_six_axis_sensor_acceleration_bias;
Common::Vec<f32, 3> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias;
Common::Vec<f32, 3> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias;
Common::Vec<f32, 3> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration;
INSERT_PADDING_BYTES(0x70); // Reserved
+91 -91
View File
@@ -54,11 +54,11 @@ void PutValue(std::span<u8> buffer, const T& t) {
} // Anonymous namespace
void BSD::PollWork::Execute(BSD* bsd) {
void BSD_USA::PollWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->PollImpl(write_buffer, read_buffer, nfds, timeout);
}
void BSD::PollWork::Response(HLERequestContext& ctx) {
void BSD_USA::PollWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
@@ -69,11 +69,11 @@ void BSD::PollWork::Response(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
void BSD::AcceptWork::Execute(BSD* bsd) {
void BSD_USA::AcceptWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->AcceptImpl(fd, write_buffer);
}
void BSD::AcceptWork::Response(HLERequestContext& ctx) {
void BSD_USA::AcceptWork::Response(HLERequestContext& ctx) {
if (write_buffer.size() > 0) {
ctx.WriteBuffer(write_buffer);
}
@@ -85,22 +85,22 @@ void BSD::AcceptWork::Response(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
void BSD::ConnectWork::Execute(BSD* bsd) {
void BSD_USA::ConnectWork::Execute(BSD_USA* bsd) {
bsd_errno = bsd->ConnectImpl(fd, addr);
}
void BSD::ConnectWork::Response(HLERequestContext& ctx) {
void BSD_USA::ConnectWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(bsd_errno == Errno::SUCCESS ? 0 : -1);
rb.PushEnum(bsd_errno);
}
void BSD::RecvWork::Execute(BSD* bsd) {
void BSD_USA::RecvWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvImpl(fd, flags, message);
}
void BSD::RecvWork::Response(HLERequestContext& ctx) {
void BSD_USA::RecvWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message);
IPC::ResponseBuilder rb{ctx, 4};
@@ -109,11 +109,11 @@ void BSD::RecvWork::Response(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
void BSD::RecvFromWork::Execute(BSD* bsd) {
void BSD_USA::RecvFromWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->RecvFromImpl(fd, flags, message, addr);
}
void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
void BSD_USA::RecvFromWork::Response(HLERequestContext& ctx) {
ctx.WriteBuffer(message, 0);
if (!addr.empty()) {
ctx.WriteBuffer(addr, 1);
@@ -126,29 +126,29 @@ void BSD::RecvFromWork::Response(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(addr.size()));
}
void BSD::SendWork::Execute(BSD* bsd) {
void BSD_USA::SendWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->SendImpl(fd, flags, message);
}
void BSD::SendWork::Response(HLERequestContext& ctx) {
void BSD_USA::SendWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(ret);
rb.PushEnum(bsd_errno);
}
void BSD::SendToWork::Execute(BSD* bsd) {
void BSD_USA::SendToWork::Execute(BSD_USA* bsd) {
std::tie(ret, bsd_errno) = bsd->SendToImpl(fd, flags, message, addr);
}
void BSD::SendToWork::Response(HLERequestContext& ctx) {
void BSD_USA::SendToWork::Response(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push<s32>(ret);
rb.PushEnum(bsd_errno);
}
void BSD::RegisterClient(HLERequestContext& ctx) {
void BSD_USA::RegisterClient(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
@@ -157,7 +157,7 @@ void BSD::RegisterClient(HLERequestContext& ctx) {
rb.Push<s32>(0); // bsd errno
}
void BSD::StartMonitoring(HLERequestContext& ctx) {
void BSD_USA::StartMonitoring(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
@@ -165,7 +165,7 @@ void BSD::StartMonitoring(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void BSD::Socket(HLERequestContext& ctx) {
void BSD_USA::Socket(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 domain = rp.Pop<u32>();
const u32 type = rp.Pop<u32>();
@@ -181,7 +181,7 @@ void BSD::Socket(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
void BSD::SocketExempt(HLERequestContext& ctx) {
void BSD_USA::SocketExempt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u32 domain = rp.Pop<u32>();
const u32 type = rp.Pop<u32>();
@@ -200,7 +200,7 @@ void BSD::SocketExempt(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
void BSD::Select(HLERequestContext& ctx) {
void BSD_USA::Select(HLERequestContext& ctx) {
LOG_DEBUG(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
@@ -210,7 +210,7 @@ void BSD::Select(HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
void BSD::Poll(HLERequestContext& ctx) {
void BSD_USA::Poll(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 nfds = rp.Pop<s32>();
const s32 timeout = rp.Pop<s32>();
@@ -225,7 +225,7 @@ void BSD::Poll(HLERequestContext& ctx) {
});
}
void BSD::Accept(HLERequestContext& ctx) {
void BSD_USA::Accept(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -237,7 +237,7 @@ void BSD::Accept(HLERequestContext& ctx) {
});
}
void BSD::Bind(HLERequestContext& ctx) {
void BSD_USA::Bind(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -245,7 +245,7 @@ void BSD::Bind(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, BindImpl(fd, ctx.ReadBuffer()));
}
void BSD::Connect(HLERequestContext& ctx) {
void BSD_USA::Connect(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -257,7 +257,7 @@ void BSD::Connect(HLERequestContext& ctx) {
});
}
void BSD::GetPeerName(HLERequestContext& ctx) {
void BSD_USA::GetPeerName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -275,7 +275,7 @@ void BSD::GetPeerName(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
void BSD::GetSockName(HLERequestContext& ctx) {
void BSD_USA::GetSockName(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -293,7 +293,7 @@ void BSD::GetSockName(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(write_buffer.size()));
}
void BSD::GetSockOpt(HLERequestContext& ctx) {
void BSD_USA::GetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 level = rp.Pop<u32>();
@@ -315,7 +315,7 @@ void BSD::GetSockOpt(HLERequestContext& ctx) {
rb.Push<u32>(static_cast<u32>(optval.size()));
}
void BSD::Listen(HLERequestContext& ctx) {
void BSD_USA::Listen(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const s32 backlog = rp.Pop<s32>();
@@ -325,7 +325,7 @@ void BSD::Listen(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ListenImpl(fd, backlog));
}
void BSD::Fcntl(HLERequestContext& ctx) {
void BSD_USA::Fcntl(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const s32 cmd = rp.Pop<s32>();
@@ -341,7 +341,7 @@ void BSD::Fcntl(HLERequestContext& ctx) {
rb.PushEnum(bsd_errno);
}
void BSD::SetSockOpt(HLERequestContext& ctx) {
void BSD_USA::SetSockOpt(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -355,7 +355,7 @@ void BSD::SetSockOpt(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval));
}
void BSD::Shutdown(HLERequestContext& ctx) {
void BSD_USA::Shutdown(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -366,7 +366,7 @@ void BSD::Shutdown(HLERequestContext& ctx) {
BuildErrnoResponse(ctx, ShutdownImpl(fd, how));
}
void BSD::Recv(HLERequestContext& ctx) {
void BSD_USA::Recv(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -381,7 +381,7 @@ void BSD::Recv(HLERequestContext& ctx) {
});
}
void BSD::RecvFrom(HLERequestContext& ctx) {
void BSD_USA::RecvFrom(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -398,7 +398,7 @@ void BSD::RecvFrom(HLERequestContext& ctx) {
});
}
void BSD::Send(HLERequestContext& ctx) {
void BSD_USA::Send(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -413,7 +413,7 @@ void BSD::Send(HLERequestContext& ctx) {
});
}
void BSD::SendTo(HLERequestContext& ctx) {
void BSD_USA::SendTo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
const u32 flags = rp.Pop<u32>();
@@ -429,7 +429,7 @@ void BSD::SendTo(HLERequestContext& ctx) {
});
}
void BSD::Write(HLERequestContext& ctx) {
void BSD_USA::Write(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -442,7 +442,7 @@ void BSD::Write(HLERequestContext& ctx) {
});
}
void BSD::Read(HLERequestContext& ctx) {
void BSD_USA::Read(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -454,7 +454,7 @@ void BSD::Read(HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
void BSD::Close(HLERequestContext& ctx) {
void BSD_USA::Close(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s32 fd = rp.Pop<s32>();
@@ -464,7 +464,7 @@ void BSD::Close(HLERequestContext& ctx) {
}
/// @brief Only bsd:s is able to dup()
void BSD::DuplicateSocket(HLERequestContext& ctx) {
void BSD_USA::DuplicateSocket(HLERequestContext& ctx) {
struct InputParameters {
s32 fd;
u64 reserved;
@@ -505,7 +505,7 @@ void BSD::DuplicateSocket(HLERequestContext& ctx) {
}
}
void BSD::EventFd(HLERequestContext& ctx) {
void BSD_USA::EventFd(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 initval = rp.Pop<u64>();
const u32 flags = rp.Pop<u32>();
@@ -516,12 +516,12 @@ void BSD::EventFd(HLERequestContext& ctx) {
}
template <typename Work>
void BSD::ExecuteWork(HLERequestContext& ctx, Work work) {
void BSD_USA::ExecuteWork(HLERequestContext& ctx, Work work) {
work.Execute(this);
work.Response(ctx);
}
std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protocol) {
std::pair<s32, Errno> BSD_USA::SocketImpl(Domain domain, Type type, Protocol protocol) {
// user bsd:u has restrictions on SOCK_SEQPACKET and SOCK_RAW
if (is_user && (type == Type::SEQPACKET || type == Type::RAW)) {
if (type == Type::RAW && domain == Domain::INET && protocol == Protocol::ICMP) {
@@ -565,7 +565,7 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco
return {fd, Errno::SUCCESS};
}
std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
std::pair<s32, Errno> BSD_USA::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer,
s32 nfds, s32 timeout) {
if (nfds <= 0) {
// When no entries are provided, -1 is returned with errno zero
@@ -632,7 +632,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con
return Translate(result);
}
std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
std::pair<s32, Errno> BSD_USA::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
@@ -660,7 +660,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) {
return {new_fd, Errno::SUCCESS};
}
Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
Errno BSD_USA::BindImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -675,7 +675,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
}
Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
Errno BSD_USA::ConnectImpl(s32 fd, std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -698,7 +698,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
return result;
}
Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
Errno BSD_USA::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -720,7 +720,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) {
return Translate(bsd_errno);
}
Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
Errno BSD_USA::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -742,7 +742,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) {
return Translate(bsd_errno);
}
Errno BSD::ListenImpl(s32 fd, s32 backlog) {
Errno BSD_USA::ListenImpl(s32 fd, s32 backlog) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -753,7 +753,7 @@ Errno BSD::ListenImpl(s32 fd, s32 backlog) {
return Translate(file_descriptors[fd]->socket->Listen(backlog));
}
std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
std::pair<s32, Errno> BSD_USA::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
@@ -783,7 +783,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) {
}
}
Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
Errno BSD_USA::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -818,7 +818,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o
}
}
Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
Errno BSD_USA::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -872,7 +872,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8
}
}
Errno BSD::ShutdownImpl(s32 fd, s32 how) {
Errno BSD_USA::ShutdownImpl(s32 fd, s32 how) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -884,7 +884,7 @@ Errno BSD::ShutdownImpl(s32 fd, s32 how) {
return Translate(file_descriptors[fd]->socket->Shutdown(host_how));
}
std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
std::pair<s32, Errno> BSD_USA::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
@@ -911,7 +911,7 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message)
return {ret, bsd_errno};
}
std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
std::pair<s32, Errno> BSD_USA::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message,
std::vector<u8>& addr) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
@@ -958,7 +958,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
return {ret, bsd_errno};
}
std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
std::pair<s32, Errno> BSD_USA::SendImpl(s32 fd, u32 flags, std::span<const u8> message) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
}
@@ -969,7 +969,7 @@ std::pair<s32, Errno> BSD::SendImpl(s32 fd, u32 flags, std::span<const u8> messa
return Translate(file_descriptors[fd]->socket->Send(message, flags));
}
std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
std::pair<s32, Errno> BSD_USA::SendToImpl(s32 fd, u32 flags, std::span<const u8> message,
std::span<const u8> addr) {
if (!IsFileDescriptorValid(fd)) {
return {-1, Errno::BADF};
@@ -991,7 +991,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
return Translate(file_descriptors[fd]->socket->SendTo(flags, message, p_addr_in));
}
Errno BSD::CloseImpl(s32 fd) {
Errno BSD_USA::CloseImpl(s32 fd) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -1011,7 +1011,7 @@ Errno BSD::CloseImpl(s32 fd) {
return bsd_errno;
}
std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
std::variant<s32, Errno> BSD_USA::DuplicateSocketImpl(s32 fd) {
if (!IsFileDescriptorValid(fd)) {
return Errno::BADF;
}
@@ -1030,7 +1030,7 @@ std::variant<s32, Errno> BSD::DuplicateSocketImpl(s32 fd) {
return new_fd;
}
std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
std::optional<std::shared_ptr<Network::SocketBase>> BSD_USA::GetSocket(s32 fd) {
if (!IsFileDescriptorValid(fd)) {
return std::nullopt;
}
@@ -1041,7 +1041,7 @@ std::optional<std::shared_ptr<Network::SocketBase>> BSD::GetSocket(s32 fd) {
return file_descriptors[fd]->socket;
}
s32 BSD::FindFreeFileDescriptorHandle() noexcept {
s32 BSD_USA::FindFreeFileDescriptorHandle() noexcept {
for (s32 fd = 0; fd < static_cast<s32>(file_descriptors.size()); ++fd) {
if (!file_descriptors[fd]) {
return fd;
@@ -1050,7 +1050,7 @@ s32 BSD::FindFreeFileDescriptorHandle() noexcept {
return -1;
}
bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
bool BSD_USA::IsFileDescriptorValid(s32 fd) const noexcept {
if (fd > static_cast<s32>(MAX_FD) || fd < 0) {
LOG_ERROR(Service, "Invalid file descriptor handle={}", fd);
return false;
@@ -1062,7 +1062,7 @@ bool BSD::IsFileDescriptorValid(s32 fd) const noexcept {
return true;
}
void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
void BSD_USA::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noexcept {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
@@ -1070,7 +1070,7 @@ void BSD::BuildErrnoResponse(HLERequestContext& ctx, Errno bsd_errno) const noex
rb.PushEnum(bsd_errno);
}
void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
void BSD_USA::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
for (auto& optional_descriptor : file_descriptors) {
if (!optional_descriptor.has_value()) {
continue;
@@ -1080,43 +1080,43 @@ void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) {
}
}
BSD::BSD(Core::System& system_, const char* name, bool is_user_)
BSD_USA::BSD_USA(Core::System& system_, const char* name, bool is_user_)
: ServiceFramework{system_, name}
, is_user{is_user_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BSD::RegisterClient, "RegisterClient"},
{1, &BSD::StartMonitoring, "StartMonitoring"},
{2, &BSD::Socket, "Socket"},
{3, &BSD::SocketExempt, "SocketExempt"},
{0, &BSD_USA::RegisterClient, "RegisterClient"},
{1, &BSD_USA::StartMonitoring, "StartMonitoring"},
{2, &BSD_USA::Socket, "Socket"},
{3, &BSD_USA::SocketExempt, "SocketExempt"},
{4, nullptr, "Open"},
{5, &BSD::Select, "Select"},
{6, &BSD::Poll, "Poll"},
{5, &BSD_USA::Select, "Select"},
{6, &BSD_USA::Poll, "Poll"},
{7, nullptr, "Sysctl"},
{8, &BSD::Recv, "Recv"},
{9, &BSD::RecvFrom, "RecvFrom"},
{10, &BSD::Send, "Send"},
{11, &BSD::SendTo, "SendTo"},
{12, &BSD::Accept, "Accept"},
{13, &BSD::Bind, "Bind"},
{14, &BSD::Connect, "Connect"},
{15, &BSD::GetPeerName, "GetPeerName"},
{16, &BSD::GetSockName, "GetSockName"},
{17, &BSD::GetSockOpt, "GetSockOpt"},
{18, &BSD::Listen, "Listen"},
{8, &BSD_USA::Recv, "Recv"},
{9, &BSD_USA::RecvFrom, "RecvFrom"},
{10, &BSD_USA::Send, "Send"},
{11, &BSD_USA::SendTo, "SendTo"},
{12, &BSD_USA::Accept, "Accept"},
{13, &BSD_USA::Bind, "Bind"},
{14, &BSD_USA::Connect, "Connect"},
{15, &BSD_USA::GetPeerName, "GetPeerName"},
{16, &BSD_USA::GetSockName, "GetSockName"},
{17, &BSD_USA::GetSockOpt, "GetSockOpt"},
{18, &BSD_USA::Listen, "Listen"},
{19, nullptr, "Ioctl"},
{20, &BSD::Fcntl, "Fcntl"},
{21, &BSD::SetSockOpt, "SetSockOpt"},
{22, &BSD::Shutdown, "Shutdown"},
{20, &BSD_USA::Fcntl, "Fcntl"},
{21, &BSD_USA::SetSockOpt, "SetSockOpt"},
{22, &BSD_USA::Shutdown, "Shutdown"},
{23, nullptr, "ShutdownAllSockets"},
{24, &BSD::Write, "Write"},
{25, &BSD::Read, "Read"},
{26, &BSD::Close, "Close"},
{27, &BSD::DuplicateSocket, "DuplicateSocket"},
{24, &BSD_USA::Write, "Write"},
{25, &BSD_USA::Read, "Read"},
{26, &BSD_USA::Close, "Close"},
{27, &BSD_USA::DuplicateSocket, "DuplicateSocket"},
{28, nullptr, "GetResourceStatistics"},
{29, nullptr, "RecvMMsg"}, //3.0.0+
{30, nullptr, "SendMMsg"}, //3.0.0+
{31, &BSD::EventFd, "EventFd"}, //7.0.0+
{31, &BSD_USA::EventFd, "EventFd"}, //7.0.0+
{32, nullptr, "RegisterResourceStatisticsName"}, //7.0.0+
{33, nullptr, "RegisterClientShared"}, //10.0.0+
{34, nullptr, "GetSocketStatistics"}, //15.0.0+
@@ -1144,13 +1144,13 @@ BSD::BSD(Core::System& system_, const char* name, bool is_user_)
}
}
BSD::~BSD() {
BSD_USA::~BSD_USA() {
if (auto room_member = Network::GetRoomMember().lock()) {
room_member->Unbind(proxy_packet_received);
}
}
std::unique_lock<std::mutex> BSD::LockService() noexcept {
std::unique_lock<std::mutex> BSD_USA::LockService() noexcept {
return {};
}
+10 -10
View File
@@ -27,10 +27,10 @@ class Socket;
namespace Service::Sockets {
class BSD final : public ServiceFramework<BSD> {
class BSD_USA final : public ServiceFramework<BSD_USA> {
public:
explicit BSD(Core::System& system_, const char* name, bool is_user);
~BSD() override;
explicit BSD_USA(Core::System& system_, const char* name, bool is_user);
~BSD_USA() override;
// These methods are called from SSL; the first two are also called from
// this class for the corresponding IPC methods.
@@ -50,7 +50,7 @@ private:
};
struct PollWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 nfds;
@@ -62,7 +62,7 @@ private:
};
struct AcceptWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
@@ -72,7 +72,7 @@ private:
};
struct ConnectWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
@@ -81,7 +81,7 @@ private:
};
struct RecvWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
@@ -92,7 +92,7 @@ private:
};
struct RecvFromWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
@@ -104,7 +104,7 @@ private:
};
struct SendWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
@@ -115,7 +115,7 @@ private:
};
struct SendToWork {
void Execute(BSD* bsd);
void Execute(BSD_USA* bsd);
void Response(HLERequestContext& ctx);
s32 fd;
+3 -3
View File
@@ -66,9 +66,9 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("ethc:c", std::make_shared<ETHC_C>(system));
server_manager->RegisterNamedService("ethc:i", std::make_shared<ETHC_I>(system));
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD>(system, "bsd:s", false));
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD>(system, "bsd:u", true));
server_manager->RegisterNamedService("bsd:a", std::make_shared<BSD>(system, "bsd:a", true));
server_manager->RegisterNamedService("bsd:s", std::make_shared<BSD_USA>(system, "bsd:s", false));
server_manager->RegisterNamedService("bsd:u", std::make_shared<BSD_USA>(system, "bsd:u", true));
server_manager->RegisterNamedService("bsd:a", std::make_shared<BSD_USA>(system, "bsd:a", true));
server_manager->RegisterNamedService("bsd:nu", std::make_shared<BSD_NU>(system));
server_manager->RegisterNamedService("bsdcfg", std::make_shared<BSDCFG>(system, "bsdcfg"));
server_manager->RegisterNamedService("ifcfg", std::make_shared<BSDCFG>(system, "ifcfg"));
+2 -2
View File
@@ -129,7 +129,7 @@ public:
LOG_ERROR(Service_SSL,
"do_not_close_socket was changed after setting socket; is this right?");
} else {
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
if (bsd) {
auto err = bsd->CloseImpl(fd);
if (err != Service::Sockets::Errno::SUCCESS) {
@@ -157,7 +157,7 @@ private:
Result SetSocketDescriptorImpl(s32* out_fd, s32 fd) {
LOG_DEBUG(Service_SSL, "called, fd={}", fd);
ASSERT(!did_handshake);
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD>("bsd:u");
auto bsd = system.ServiceManager().GetService<Service::Sockets::BSD_USA>("bsd:u");
ASSERT_OR_EXECUTE(bsd, { return ResultInternalError; });
auto const res_v = bsd->DuplicateSocketImpl(fd);
-7
View File
@@ -1,6 +1,3 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@@ -63,11 +60,7 @@ private:
std::size_t current_index{0};
/// Stores an hour of historical frametime data useful for processing and tracking performance
/// regressions with code changes.
#ifdef __OPENORBIS__
std::array<double, 60> perf_history{};
#else
std::array<double, 216000> perf_history{};
#endif
/// Point when the cumulative counters were reset
Clock::time_point reset_point = Clock::now();
@@ -66,16 +66,12 @@ public:
auto const stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
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{};
signal_stack.ss_sp = signal_stack_memory.get();
signal_stack.ss_size = stack_size;
signal_stack.ss_flags = 0;
if (sigaltstack(&signal_stack, nullptr) != 0) {
fmt::print(stderr, "POSIX SigHandler: init failure at sigaltstack\n");
fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n");
supports_fast_mem = false;
return;
}
@@ -86,17 +82,16 @@ public:
sa.sa_flags = SA_SIGINFO | SA_ONSTACK | SA_RESTART;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGSEGV, &sa, &old_sa_segv) != 0) {
fmt::print(stderr, "POSIX SigHandler: could not set SIGSEGV handler\n");
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGSEGV handler\n");
supports_fast_mem = false;
return;
}
#if defined(__APPLE__)
if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) {
fmt::print(stderr, "POSIX SigHandler: could not set SIGBUS handler\n");
fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n");
supports_fast_mem = false;
return;
}
# endif
#endif
}
@@ -150,9 +145,6 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
}
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;
if (retry_sa->sa_flags & SA_SIGINFO) {
retry_sa->sa_sigaction(sig, info, raw_context);
@@ -166,7 +158,6 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) {
return;
}
retry_sa->sa_handler(sig);
#endif
}
} // anonymous namespace
@@ -67,14 +67,8 @@ public:
const void* code_ptr = nullptr;
};
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 size_t fast_dispatch_table_size = 0x10000;
#endif
void ClearFastDispatchTable();
void GenFastmemFallbacks();
void GenTerminalHandlers();
@@ -60,13 +60,8 @@ public:
const void* code_ptr = nullptr;
};
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 size_t fast_dispatch_table_size = 0x100000;
#endif
void ClearFastDispatchTable();
void GenMemory128Accessors();

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