From 04f96c6b2e7bec5fe711cf54f47a87060895dc66 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 16 Jan 2026 03:09:03 +0000 Subject: [PATCH 001/181] no conversion fixs --- src/video_core/macro.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 3fe69be4dd..5fed762fe0 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -21,6 +21,14 @@ #pragma clang diagnostic ignored "-Wshadow" #endif #include + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + #endif #include "common/assert.h" From 0605a88da535868b3ae1bf945128f5d787a07e33 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 16 Jan 2026 03:27:08 +0000 Subject: [PATCH 002/181] fuck you --- src/video_core/macro.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 5fed762fe0..3fe69be4dd 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -21,14 +21,6 @@ #pragma clang diagnostic ignored "-Wshadow" #endif #include - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - #endif #include "common/assert.h" From 6eba8843e755fffd948d7e71a44c59e67086539d Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 3 Jan 2026 21:13:42 +0000 Subject: [PATCH 003/181] toolchain-fix --- .ci/ps4/build.sh | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ .gitignore | 3 +++ docs/Caveats.md | 8 ++++++++ 3 files changed, 63 insertions(+) create mode 100755 .ci/ps4/build.sh diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh new file mode 100755 index 0000000000..f51056262e --- /dev/null +++ b/.ci/ps4/build.sh @@ -0,0 +1,52 @@ +#!/usr/local/bin/bash -ex + +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +cat << EOF >"ps4-toolchain.cmake" +set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN") + +set(CMAKE_C_FLAGS "--target=x86_64-pc-freebsd12-elf -funwind-tables -fuse-ld=ldd") +set(CMAKE_CXX_FLAGS "--target=x86_64-pc-freebsd12-elf -funwind-tables -fuse-ld=lld") + +set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lc++ -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lc++ -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") + +set(CMAKE_C_COMPILER clang) +set(CMAKE_CXX_COMPILER clang++) +set(CMAKE_LINKER ld.lld) +set(CMAKE_C_LINK_EXECUTABLE " -o ") +set(CMAKE_CXX_LINK_EXECUTABLE " -o ") + +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) +EOF + +export ARCH_FLAGS="$ARCH_FLAGS -O3" +if [ -z "$NPROC" ]; then + NPROC="$(nproc)" +fi + +# Normally a platform has a package manager +# PS4 does not, atleast not in the normal sense +export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) +mkdir -p build +cd build && cmake .. -G Ninja \ + -DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \ + -DENABLE_QT_TRANSLATION=OFF \ + -DUSE_DISCORD_PRESENCE=OFF \ + -DENABLE_CUBEB=OFF \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \ + -DCMAKE_C_FLAGS="$ARCH_FLAGS" \ + -DENABLE_SDL2=OFF \ + -DENABLE_QT=OFF \ + -DENABLE_OPENSSL=OFF \ + -DCPMUTIL_FORCE_BUNDLED=ON \ + -DYUZU_USE_CPM=ON \ + "${EXTRA_CMAKE_FLAGS[@]}" || exit + +cd build && ninja -j${NPROC} || exit diff --git a/.gitignore b/.gitignore index 67bdd8adf4..b304411646 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ artifacts /install* vulkansdk*.exe *.tar.zst + +# PS4 toolchain stuff +ps4-toolchain.cmake diff --git a/docs/Caveats.md b/docs/Caveats.md index 39b5ab15e6..f07c8e7e66 100644 --- a/docs/Caveats.md +++ b/docs/Caveats.md @@ -11,6 +11,7 @@ - [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) @@ -214,6 +215,13 @@ The package install may randomly hang at times, in which case it has to be resta 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" +export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 +``` + ## Windows ### Windows 7, Windows 8 and Windows 8.1 From 3e0b7de22da5f1d89bf597613acc00285e591db4 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 29 Nov 2025 22:53:31 +0000 Subject: [PATCH 004/181] fix --- .ci/ps4/build.sh | 17 ++-- CMakeModules/GenerateSCMRev.cmake | 5 +- externals/ffmpeg/CMakeLists.txt | 146 +++++++++++++++++------------- 3 files changed, 97 insertions(+), 71 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index f51056262e..87fd00a470 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -6,8 +6,8 @@ cat << EOF >"ps4-toolchain.cmake" set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN") -set(CMAKE_C_FLAGS "--target=x86_64-pc-freebsd12-elf -funwind-tables -fuse-ld=ldd") -set(CMAKE_CXX_FLAGS "--target=x86_64-pc-freebsd12-elf -funwind-tables -fuse-ld=lld") +set(CMAKE_C_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -funwind-tables -isystem $OO_PS4_TOOLCHAIN/include -isystem $OO_PS4_TOOLCHAIN/include/c++/v1") +set(CMAKE_CXX_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -funwind-tables -isystem $OO_PS4_TOOLCHAIN/include -isystem $OO_PS4_TOOLCHAIN/include/c++/v1") set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lc++ -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") @@ -23,6 +23,9 @@ 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 export ARCH_FLAGS="$ARCH_FLAGS -O3" @@ -34,10 +37,10 @@ fi # PS4 does not, atleast not in the normal sense export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) mkdir -p build -cd build && cmake .. -G Ninja \ +cd build +cmake .. -G Ninja \ -DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \ -DENABLE_QT_TRANSLATION=OFF \ - -DUSE_DISCORD_PRESENCE=OFF \ -DENABLE_CUBEB=OFF \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \ @@ -45,8 +48,10 @@ cd build && cmake .. -G Ninja \ -DENABLE_SDL2=OFF \ -DENABLE_QT=OFF \ -DENABLE_OPENSSL=OFF \ + -DENABLE_WEB_SERVICE=OFF \ + -DUSE_DISCORD_PRESENCE=OFF \ -DCPMUTIL_FORCE_BUNDLED=ON \ + -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit - -cd build && ninja -j${NPROC} || exit +ninja -j${NPROC} || exit diff --git a/CMakeModules/GenerateSCMRev.cmake b/CMakeModules/GenerateSCMRev.cmake index 5b0adad8dd..0c8c9cedec 100644 --- a/CMakeModules/GenerateSCMRev.cmake +++ b/CMakeModules/GenerateSCMRev.cmake @@ -18,10 +18,13 @@ if (DEFINED GIT_RELEASE) set(BUILD_VERSION "${GIT_TAG}") set(GIT_REFSPEC "${GIT_RELEASE}") set(IS_DEV_BUILD false) -else() +elseif(DEFINED GIT_COMMIT) 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) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 3140f8e545..dd3c6f36c6 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -11,63 +11,98 @@ set(FFmpeg_HWACCEL_FLAGS) set(FFmpeg_HWACCEL_INCLUDE_DIRS) set(FFmpeg_HWACCEL_LDFLAGS) -if (UNIX AND NOT ANDROID) - find_package(PkgConfig REQUIRED) - if (NOT ANDROID) - pkg_check_modules(LIBVA libva) - pkg_check_modules(CUDA cuda) - pkg_check_modules(FFNVCODEC ffnvcodec) - pkg_check_modules(VDPAU vdpau) +if (NOT YUZU_USE_BUNDLED_FFMPEG) + set(FFmpeg_CROSS_COMPILE_FLAGS "") + if (ANDROID) + # TODO: Maybe use CMAKE_SYSROOT? and probably provide a toolchain file for android + # I mean isn't that the "proper" way anyways? + string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME) + set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") + set(SYSROOT "${TOOLCHAIN}/sysroot") + set(FFmpeg_CPU "armv8-a") + list(APPEND FFmpeg_CROSS_COMPILE_FLAGS + --enable-cross-compile + --arch=arm64 + #--cpu=${FFmpeg_CPU} + --cross-prefix="${TOOLCHAIN}/bin/aarch64-linux-android-" + --sysroot="${SYSROOT}" + --target-os=android + --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" + --extra-ldflags="-nostdlib" + ) + set(FFmpeg_IS_CROSS_COMPILING TRUE) + # User attempts to do a FFmpeg cross compilation because... + # Here we just quickly test against host/system processors not matching + # TODO: Test for versions not matching as well? + elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR + AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME)) + string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME) + # TODO: Can we really do better? Auto-detection? Something clever? + if (NOT DEFINED FFmpeg_CROSS_PREFIX) + message(ERROR "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-") + endif() + list(APPEND FFmpeg_CROSS_COMPILE_FLAGS + --enable-cross-compile + --arch="${CMAKE_SYSTEM_PROCESSOR}" + --target-os="${FFmpeg_SYSTEM_NAME}" + --sysroot="${CMAKE_SYSROOT}" + --cross-prefix="${FFmpeg_CROSS_PREFIX}" + ) + set(FFmpeg_IS_CROSS_COMPILING TRUE) endif() +endif() - if (NOT APPLE) - # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so - if(PLATFORM_SUN) - find_library(LIBDRM_LIB libdrm PATHS /usr/lib/64 /usr/lib/amd64 /usr/lib) - if(LIBDRM_LIB) +if (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING) + find_package(PkgConfig REQUIRED) + pkg_check_modules(LIBVA libva) + pkg_check_modules(CUDA cuda) + pkg_check_modules(FFNVCODEC ffnvcodec) + pkg_check_modules(VDPAU vdpau) + + find_package(X11) + if(X11_FOUND) + if (NOT APPLE) + # In Solaris needs explicit linking for ffmpeg which links to /lib/amd64/libX11.so + if(PLATFORM_SUN) list(APPEND FFmpeg_HWACCEL_LIBRARIES X11 - "${LIBDRM_LIB}") - message(STATUS "Found libdrm at: ${LIBDRM_LIB}") + "${CMAKE_SYSROOT}/usr/lib/xorg/amd64/libdrm.so") else() - message(WARNING "libdrm not found, disabling libdrm support") - list(APPEND FFmpeg_HWACCEL_FLAGS - --disable-libdrm) + pkg_check_modules(LIBDRM libdrm REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${LIBDRM_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${LIBDRM_INCLUDE_DIRS}) endif() - else() - pkg_check_modules(LIBDRM libdrm REQUIRED) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${LIBDRM_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${LIBDRM_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_FLAGS --enable-libdrm) endif() - endif() - - if(LIBVA_FOUND) - find_package(X11 REQUIRED) - pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) - pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) - list(APPEND FFmpeg_HWACCEL_LIBRARIES - ${X11_LIBRARIES} - ${LIBVA-DRM_LIBRARIES} - ${LIBVA-X11_LIBRARIES} - ${LIBVA_LIBRARIES}) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-hwaccel=h264_vaapi - --enable-hwaccel=vp8_vaapi - --enable-hwaccel=vp9_vaapi) - list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS - ${X11_INCLUDE_DIRS} - ${LIBVA-DRM_INCLUDE_DIRS} - ${LIBVA-X11_INCLUDE_DIRS} - ${LIBVA_INCLUDE_DIRS} - ) - message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found") + if(LIBVA_FOUND) + pkg_check_modules(LIBVA-DRM libva-drm REQUIRED) + pkg_check_modules(LIBVA-X11 libva-x11 REQUIRED) + list(APPEND FFmpeg_HWACCEL_LIBRARIES + ${X11_LIBRARIES} + ${LIBVA-DRM_LIBRARIES} + ${LIBVA-X11_LIBRARIES} + ${LIBVA_LIBRARIES}) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-hwaccel=h264_vaapi + --enable-hwaccel=vp8_vaapi + --enable-hwaccel=vp9_vaapi) + list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS + ${X11_INCLUDE_DIRS} + ${LIBVA-DRM_INCLUDE_DIRS} + ${LIBVA-X11_INCLUDE_DIRS} + ${LIBVA_INCLUDE_DIRS} + ) + message(STATUS "ffmpeg: va-api libraries version ${LIBVA_VERSION} found") + else() + list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) + message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...") + endif() else() list(APPEND FFmpeg_HWACCEL_FLAGS --disable-vaapi) - message(WARNING "ffmpeg: libva-dev not found, disabling Video Acceleration API (VA-API)...") + message(WARNING "ffmpeg: X11 libraries not found, disabling VA-API...") endif() if (FFNVCODEC_FOUND) @@ -181,24 +216,6 @@ else() find_program(BASH_PROGRAM bash REQUIRED) - set(FFmpeg_CROSS_COMPILE_FLAGS "") - if (ANDROID) - string(TOLOWER "${CMAKE_HOST_SYSTEM_NAME}" FFmpeg_HOST_SYSTEM_NAME) - set(TOOLCHAIN "${ANDROID_NDK}/toolchains/llvm/prebuilt/${FFmpeg_HOST_SYSTEM_NAME}-${CMAKE_HOST_SYSTEM_PROCESSOR}") - set(SYSROOT "${TOOLCHAIN}/sysroot") - set(FFmpeg_CPU "armv8-a") - list(APPEND FFmpeg_CROSS_COMPILE_FLAGS - --arch=arm64 - #--cpu=${FFmpeg_CPU} - --enable-cross-compile - --cross-prefix=${TOOLCHAIN}/bin/aarch64-linux-android- - --sysroot=${SYSROOT} - --target-os=android - --extra-ldflags="--ld-path=${TOOLCHAIN}/bin/ld.lld" - --extra-ldflags="-nostdlib" - ) - endif() - # `configure` parameters builds only exactly what yuzu needs from FFmpeg # `--disable-vdpau` is needed to avoid linking issues set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) @@ -223,6 +240,7 @@ else() --enable-pic --cc="${FFmpeg_CC}" --cxx="${FFmpeg_CXX}" + ${FFmpeg_CROSS_COMPILE_FLAG} ${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_CROSS_COMPILE_FLAGS} WORKING_DIRECTORY From 320342c93ee3f090e0784aa23ae8f68247b7b363 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:49:26 +0000 Subject: [PATCH 005/181] merge --- .ci/ps4/build.sh | 20 ++++++++++---------- .patch/boost/0004-openorbis.patch | 17 +++++++++++++++++ .patch/enet/0001-openorbis.patch | 13 +++++++++++++ .patch/mbedtls/0002-aesni-fix.patch | 13 +++++++++++++ .patch/spirv-tools/0003-openorbis.patch | 25 +++++++++++++++++++++++++ cpmfile.json | 3 ++- externals/cpmfile.json | 6 +++++- externals/ffmpeg/CMakeLists.txt | 5 ++++- src/common/memory_detect.cpp | 4 ++-- 9 files changed, 91 insertions(+), 15 deletions(-) create mode 100644 .patch/boost/0004-openorbis.patch create mode 100644 .patch/enet/0001-openorbis.patch create mode 100644 .patch/mbedtls/0002-aesni-fix.patch create mode 100644 .patch/spirv-tools/0003-openorbis.patch diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 87fd00a470..b80e2a2e6f 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -3,15 +3,17 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -cat << EOF >"ps4-toolchain.cmake" +OO_PS4_TOOLCHAIN="/home/xerix/src/ps4-sdk/prefix" + +[ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake" set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN") -set(CMAKE_C_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -funwind-tables -isystem $OO_PS4_TOOLCHAIN/include -isystem $OO_PS4_TOOLCHAIN/include/c++/v1") -set(CMAKE_CXX_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -funwind-tables -isystem $OO_PS4_TOOLCHAIN/include -isystem $OO_PS4_TOOLCHAIN/include/c++/v1") +set(CMAKE_C_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables -nostdinc -isystem $OO_PS4_TOOLCHAIN/include/c++/v1 -isystem $OO_PS4_TOOLCHAIN/include") +set(CMAKE_CXX_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables -nostdinc -isystem $OO_PS4_TOOLCHAIN/include/c++/v1 -isystem $OO_PS4_TOOLCHAIN/include") -set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lc++ -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") -set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") -set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib -lc -lkernel -lc++ -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib") +set(CMAKE_C_LINK_FLAGS "-lc -lkernel -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_CXX_LINK_FLAGS " -lc++") set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) @@ -36,9 +38,7 @@ fi # Normally a platform has a package manager # PS4 does not, atleast not in the normal sense export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) -mkdir -p build -cd build -cmake .. -G Ninja \ +cmake -S . -B build -G Ninja \ -DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \ -DENABLE_QT_TRANSLATION=OFF \ -DENABLE_CUBEB=OFF \ @@ -54,4 +54,4 @@ cmake .. -G Ninja \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit -ninja -j${NPROC} || exit +cmake --build build --parallel diff --git a/.patch/boost/0004-openorbis.patch b/.patch/boost/0004-openorbis.patch new file mode 100644 index 0000000000..c027956500 --- /dev/null +++ b/.patch/boost/0004-openorbis.patch @@ -0,0 +1,17 @@ +diff --git a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp +index 0129511c..10fc9b04 100644 +--- a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp ++++ b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp +@@ -15,6 +15,12 @@ + # pragma once + #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) + ++// hacky fix for ps4 ++#if defined(_LIBCPP_HAS_MUSL_LIBC) ++# define FIONBIO 0 ++# define FIONREAD 1 ++#endif ++ + #include + + #include diff --git a/.patch/enet/0001-openorbis.patch b/.patch/enet/0001-openorbis.patch new file mode 100644 index 0000000000..4e6dab279e --- /dev/null +++ b/.patch/enet/0001-openorbis.patch @@ -0,0 +1,13 @@ +diff --git a/unix.c b/unix.c +index 6669216..86a2faa 100644 +--- a/unix.c ++++ b/unix.c +@@ -53,7 +53,7 @@ + #include + #endif + +-#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) ++#if !defined(_LIBCPP_HAS_MUSL_LIBC) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) + typedef int socklen_t; + #endif + diff --git a/.patch/mbedtls/0002-aesni-fix.patch b/.patch/mbedtls/0002-aesni-fix.patch new file mode 100644 index 0000000000..5112ded892 --- /dev/null +++ b/.patch/mbedtls/0002-aesni-fix.patch @@ -0,0 +1,13 @@ +diff --git a/library/aesni.h b/library/aesni.h +index 754c984c79..59e27afd3e 100644 +--- a/library/aesni.h ++++ b/library/aesni.h +@@ -35,7 +35,7 @@ + /* GCC-like compilers: currently, we only support intrinsics if the requisite + * target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2` + * or `clang -maes -mpclmul`). */ +-#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__) ++#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_HAS_MUSL_LIBC) + #define MBEDTLS_AESNI_HAVE_INTRINSICS + #endif + /* For 32-bit, we only support intrinsics */ diff --git a/.patch/spirv-tools/0003-openorbis.patch b/.patch/spirv-tools/0003-openorbis.patch new file mode 100644 index 0000000000..f2c19d893f --- /dev/null +++ b/.patch/spirv-tools/0003-openorbis.patch @@ -0,0 +1,25 @@ +diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp +index e41c044..a51b53b 100644 +--- a/source/opt/loop_dependence.cpp ++++ b/source/opt/loop_dependence.cpp +@@ -12,6 +12,12 @@ + // See the License for the specific language governing permissions and + // limitations under the License. + ++// PS4: issue? ++#ifdef __PS4__ ++#pragma clang diagnostic ignored "-Wabsolute-value" ++#pragma clang diagnostic ignored "-Wshorten-64-to-32" ++#endif ++ + #include "source/opt/loop_dependence.h" + + #include +@@ -19,6 +25,7 @@ + #include + #include + #include ++#include + + #include "source/opt/instruction.h" + #include "source/opt/scalar_analysis_nodes.h" diff --git a/cpmfile.json b/cpmfile.json index 774f160360..d13f47b613 100644 --- a/cpmfile.json +++ b/cpmfile.json @@ -17,7 +17,8 @@ "version": "1.57", "find_args": "CONFIG OPTIONAL_COMPONENTS headers context system fiber filesystem", "patches": [ - "0001-clang-cl.patch" + "0001-clang-cl.patch", + "0004-openorbis.patch" ] }, "fmt": { diff --git a/externals/cpmfile.json b/externals/cpmfile.json index 9644647638..e08d1cc055 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -97,7 +97,10 @@ "hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9", "version": "1.3", "git_version": "1.3.18", - "find_args": "MODULE" + "find_args": "MODULE", + "patches": [ + "0001-openorbis.patch" + ] }, "spirv-tools": { "package": "SPIRV-Tools", @@ -111,6 +114,7 @@ "patches": [ "0001-netbsd-fix.patch", "0002-allow-static-only.patch" + "0003-openorbis.patch" ] }, "spirv-headers": { diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index dd3c6f36c6..336427450c 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -240,7 +240,10 @@ else() --enable-pic --cc="${FFmpeg_CC}" --cxx="${FFmpeg_CXX}" - ${FFmpeg_CROSS_COMPILE_FLAG} + --ld="${CMAKE_LINKER}" + --ldflags="${CMAKE_C_LINK_FLAGS}" + --cflags="${CMAKE_C_FLAGS}" + --cxxflags="${CMAKE_CXX_FLAGS}" ${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_CROSS_COMPILE_FLAGS} WORKING_DIRECTORY diff --git a/src/common/memory_detect.cpp b/src/common/memory_detect.cpp index 86a3abcc6d..a8e43a1e4b 100644 --- a/src/common/memory_detect.cpp +++ b/src/common/memory_detect.cpp @@ -8,7 +8,7 @@ // clang-format on #else #include -#if defined(__APPLE__) || defined(__FreeBSD__) +#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(_LIBCPP_HAS_MUSL_LIBC)) #include #elif defined(__linux__) #include @@ -43,7 +43,7 @@ static MemoryInfo Detect() { sysctlbyname("vm.swapusage", &vmusage, &sizeof_vmusage, nullptr, 0); mem_info.TotalPhysicalMemory = ramsize; mem_info.TotalSwapMemory = vmusage.xsu_total; -#elif defined(__FreeBSD__) +#elif defined(__FreeBSD__) && !defined(_LIBCPP_HAS_MUSL_LIBC) u_long physmem, swap_total; std::size_t sizeof_u_long = sizeof(u_long); // sysctlbyname(const char *, void *, size_t *, const void *, size_t); From 4117d0067827ba8d47f608c19a218fd612449906 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:49:45 +0000 Subject: [PATCH 006/181] merge --- .ci/ps4/build.sh | 18 +++++++++--------- .patch/boost/0004-openorbis.patch | 2 +- .patch/enet/0001-openorbis.patch | 2 +- .patch/mbedtls/0002-aesni-fix.patch | 2 +- externals/ffmpeg/CMakeLists.txt | 13 ++++++++++--- src/common/memory_detect.cpp | 4 ++-- .../backend/exception_handler_posix.cpp | 17 +++++++++++++---- src/dynarmic/src/dynarmic/common/context.h | 10 +++++----- 8 files changed, 42 insertions(+), 26 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index b80e2a2e6f..3b2f6e5481 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -3,23 +3,23 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -OO_PS4_TOOLCHAIN="/home/xerix/src/ps4-sdk/prefix" - [ -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_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables -nostdinc -isystem $OO_PS4_TOOLCHAIN/include/c++/v1 -isystem $OO_PS4_TOOLCHAIN/include") -set(CMAKE_CXX_FLAGS "-D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables -nostdinc -isystem $OO_PS4_TOOLCHAIN/include/c++/v1 -isystem $OO_PS4_TOOLCHAIN/include") +set(CMAKE_C_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables") +set(CMAKE_CXX_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables") -set(CMAKE_EXE_LINKER_FLAGS "-m elf_x86_64 -pie --script $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib") -set(CMAKE_C_LINK_FLAGS "-lc -lkernel -lSceUserService -lSceVideoOut -lSceAudioOut -lScePad -lSceSysmodule -lSceFreeType $OO_PS4_TOOLCHAIN/lib/crt1.o") -set(CMAKE_CXX_LINK_FLAGS " -lc++") +set(CMAKE_EXE_LINKER_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -L$OO_PS4_TOOLCHAIN/lib") +set(CMAKE_C_LINK_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -L$OO_PS4_TOOLCHAIN/lib") +set(CMAKE_CXX_LINK_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -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 " -o ") -set(CMAKE_CXX_LINK_EXECUTABLE " -o ") +set(CMAKE_C_LINK_EXECUTABLE " -o -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_CXX_LINK_EXECUTABLE " -o -lc -lkernel -lunwind -lc++ -lc++abi -lc++experimental -lrt -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) diff --git a/.patch/boost/0004-openorbis.patch b/.patch/boost/0004-openorbis.patch index c027956500..09071b599c 100644 --- a/.patch/boost/0004-openorbis.patch +++ b/.patch/boost/0004-openorbis.patch @@ -7,7 +7,7 @@ index 0129511c..10fc9b04 100644 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) +// hacky fix for ps4 -+#if defined(_LIBCPP_HAS_MUSL_LIBC) ++#if defined(__OPENORBIS__) +# define FIONBIO 0 +# define FIONREAD 1 +#endif diff --git a/.patch/enet/0001-openorbis.patch b/.patch/enet/0001-openorbis.patch index 4e6dab279e..744e2f879d 100644 --- a/.patch/enet/0001-openorbis.patch +++ b/.patch/enet/0001-openorbis.patch @@ -7,7 +7,7 @@ index 6669216..86a2faa 100644 #endif -#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) -+#if !defined(_LIBCPP_HAS_MUSL_LIBC) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) ++#if !defined(__OPENORBIS__) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined) typedef int socklen_t; #endif diff --git a/.patch/mbedtls/0002-aesni-fix.patch b/.patch/mbedtls/0002-aesni-fix.patch index 5112ded892..e9a1bce5e6 100644 --- a/.patch/mbedtls/0002-aesni-fix.patch +++ b/.patch/mbedtls/0002-aesni-fix.patch @@ -7,7 +7,7 @@ index 754c984c79..59e27afd3e 100644 * target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2` * or `clang -maes -mpclmul`). */ -#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__) -+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_HAS_MUSL_LIBC) ++#if (defined(__GNUC__) || defined(__clang__)) && !defined(__OPENORBIS__) #define MBEDTLS_AESNI_HAVE_INTRINSICS #endif /* For 32-bit, we only support intrinsics */ diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index 336427450c..d97b9b30ed 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -146,6 +146,13 @@ if (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING) endif() endif() +if (PLATFORM_PS4) + list(APPEND FFmpeg_HWACCEL_FLAGS + --enable-stdatomic + --disable-threads + ) +endif() + if (YUZU_USE_BUNDLED_FFMPEG) AddJsonPackage(ffmpeg-ci) @@ -241,9 +248,9 @@ else() --cc="${FFmpeg_CC}" --cxx="${FFmpeg_CXX}" --ld="${CMAKE_LINKER}" - --ldflags="${CMAKE_C_LINK_FLAGS}" - --cflags="${CMAKE_C_FLAGS}" - --cxxflags="${CMAKE_CXX_FLAGS}" + --extra-ldflags="$CMAKE_C_LINK_FLAGS" + --extra-cflags="$CMAKE_C_FLAGS" + --extra-cxxflags="$CMAKE_CXX_FLAGS" ${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_CROSS_COMPILE_FLAGS} WORKING_DIRECTORY diff --git a/src/common/memory_detect.cpp b/src/common/memory_detect.cpp index a8e43a1e4b..074c02a9c3 100644 --- a/src/common/memory_detect.cpp +++ b/src/common/memory_detect.cpp @@ -8,7 +8,7 @@ // clang-format on #else #include -#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(_LIBCPP_HAS_MUSL_LIBC)) +#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(__OPENORBIS__)) #include #elif defined(__linux__) #include @@ -43,7 +43,7 @@ static MemoryInfo Detect() { sysctlbyname("vm.swapusage", &vmusage, &sizeof_vmusage, nullptr, 0); mem_info.TotalPhysicalMemory = ramsize; mem_info.TotalSwapMemory = vmusage.xsu_total; -#elif defined(__FreeBSD__) && !defined(_LIBCPP_HAS_MUSL_LIBC) +#elif defined(__FreeBSD__) && !defined(__OPENORBIS__) u_long physmem, swap_total; std::size_t sizeof_u_long = sizeof(u_long); // sysctlbyname(const char *, void *, size_t *, const void *, size_t); diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp index 9f508f72e5..8470d77b2d 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp @@ -59,12 +59,16 @@ public: signal_stack_size = std::max(SIGSTKSZ, 2 * 1024 * 1024); signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +#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; signal_stack.ss_size = signal_stack_size; signal_stack.ss_flags = 0; if (sigaltstack(&signal_stack, nullptr) != 0) { - fmt::print(stderr, "dynarmic: POSIX SigHandler: init failure at sigaltstack\n"); + fmt::print(stderr, "POSIX SigHandler: init failure at sigaltstack\n"); supports_fast_mem = false; return; } @@ -75,16 +79,17 @@ 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, "dynarmic: POSIX SigHandler: could not set SIGSEGV handler\n"); + fmt::print(stderr, "POSIX SigHandler: could not set SIGSEGV handler\n"); supports_fast_mem = false; return; } -#ifdef __APPLE__ +# ifdef __APPLE__ if (sigaction(SIGBUS, &sa, &old_sa_bus) != 0) { - fmt::print(stderr, "dynarmic: POSIX SigHandler: could not set SIGBUS handler\n"); + fmt::print(stderr, "POSIX SigHandler: could not set SIGBUS handler\n"); supports_fast_mem = false; return; } +# endif #endif } @@ -145,6 +150,9 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) { # error "Invalid architecture" #endif +#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); @@ -158,6 +166,7 @@ void SigHandler::SigAction(int sig, siginfo_t* info, void* raw_context) { return; } retry_sa->sa_handler(sig); +#endif } } // anonymous namespace diff --git a/src/dynarmic/src/dynarmic/common/context.h b/src/dynarmic/src/dynarmic/common/context.h index 941289cb94..48c72cb5c9 100644 --- a/src/dynarmic/src/dynarmic/common/context.h +++ b/src/dynarmic/src/dynarmic/common/context.h @@ -60,7 +60,7 @@ # elif defined(__linux__) # define CTX_RIP (mctx.gregs[REG_RIP]) # define CTX_RSP (mctx.gregs[REG_RSP]) -# elif defined(__FreeBSD__) +# elif defined(__FreeBSD__) || defined(__DragonFly__) # define CTX_RIP (mctx.mc_rip) # define CTX_RSP (mctx.mc_rsp) # elif defined(__NetBSD__) @@ -72,9 +72,9 @@ # elif defined(__sun__) # define CTX_RIP (mctx.gregs[REG_RIP]) # define CTX_RSP (mctx.gregs[REG_RSP]) -# elif defined(__DragonFly__) -# define CTX_RIP (mctx.mc_rip) -# define CTX_RSP (mctx.mc_rsp) +# elif defined(__OPENORBIS__) +# define CTX_RIP (mctx.gregs[REG_RIP]) +# define CTX_RSP (mctx.gregs[REG_RSP]) # else # error "Unknown platform" # endif @@ -97,7 +97,7 @@ # define CTX_Q(i) (fpctx->vregs[i]) # define CTX_FPSR (fpctx->fpsr) # define CTX_FPCR (fpctx->fpcr) -# elif defined(__FreeBSD__) +# elif defined(__FreeBSD__) || defined(__DragonFly__) # define CTX_PC (mctx.mc_gpregs.gp_elr) # define CTX_SP (mctx.mc_gpregs.gp_sp) # define CTX_LR (mctx.mc_gpregs.gp_lr) From 604a5b24b7f3e45135d7b6ab050436b4e9a03d70 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:50:05 +0000 Subject: [PATCH 007/181] buildable toolchain script + fixes for ffmpeg --- .ci/ps4/build.sh | 21 ++-- .ci/ps4/make-toolchain.sh | 168 ++++++++++++++++++++++++++++++++ externals/ffmpeg/CMakeLists.txt | 48 ++++++--- 3 files changed, 210 insertions(+), 27 deletions(-) create mode 100644 .ci/ps4/make-toolchain.sh diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 3b2f6e5481..0dda2e9c9a 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -3,23 +3,25 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later +OO_PS4_TOOLCHAIN="/home/xerix/src/ps4-sdk/prefix" + [ -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=x86-64 -march=x86-64 -funwind-tables") -set(CMAKE_CXX_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -funwind-tables") +set(CMAKE_C_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -fPIC -funwind-tables") +set(CMAKE_CXX_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -fPIC -funwind-tables") -set(CMAKE_EXE_LINKER_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -L$OO_PS4_TOOLCHAIN/lib") -set(CMAKE_C_LINK_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -L$OO_PS4_TOOLCHAIN/lib") -set(CMAKE_CXX_LINK_FLAGS "-T $OO_PS4_TOOLCHAIN/link.x -L$OO_PS4_TOOLCHAIN/lib") +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 " -o -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o") -set(CMAKE_CXX_LINK_EXECUTABLE " -o -lc -lkernel -lunwind -lc++ -lc++abi -lc++experimental -lrt -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o") +set(CMAKE_C_LINK_EXECUTABLE " -o -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o ") +set(CMAKE_CXX_LINK_EXECUTABLE " -o -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o ") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) @@ -30,11 +32,6 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_SIZEOF_VOID_P 8) EOF -export ARCH_FLAGS="$ARCH_FLAGS -O3" -if [ -z "$NPROC" ]; then - NPROC="$(nproc)" -fi - # Normally a platform has a package manager # PS4 does not, atleast not in the normal sense export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) diff --git a/.ci/ps4/make-toolchain.sh b/.ci/ps4/make-toolchain.sh new file mode 100644 index 0000000000..b7848f5ddb --- /dev/null +++ b/.ci/ps4/make-toolchain.sh @@ -0,0 +1,168 @@ +#!/usr/local/bin/bash -ex + +# Define global vars +# These flags are used everywhere, so let's reuse them. +export OO_PS4_TOOLCHAIN="$PWD/prefix" +export PREFIX="$OO_PS4_TOOLCHAIN" +export CC="clang" +export CXX="clang++" +export AR="llvm-ar" +export CFLAGS="-fPIC -DPS4 -D_LIBUNWIND_IS_BAREMETAL=1" +export CXXFLAGS="$CFLAGS -D__STDC_VERSION__=0" +export TARGET="x86_64-scei-ps4" +export LLVM_ROOT="$PWD/llvm-project" +export LLVM_PATH="$PWD/llvm-project/llvm" +export WORK_PATH="$PWD" + +prepare_prefix() { + [ -d OpenOrbis-PS4-Toolchain ] || git clone --depth=1 https://github.com/OpenOrbis/OpenOrbis-PS4-Toolchain + [ -d musl ] || git clone --depth=1 https://github.com/OpenOrbis/musl + [ -d llvm-project ] || git clone --depth=1 --branch openorbis/20.x https://github.com/seuros/llvm-project + [ -d create-fself ] || git clone --depth=1 https://github.com/OpenOrbis/create-fself + [ -d create-gp4 ] || git clone --depth=1 https://github.com/OpenOrbis/create-gp4 + [ -d readoelf ] || git clone --depth=1 https://github.com/OpenOrbis/readoelf + + mkdir -p $PREFIX "$PREFIX/bin" "$PREFIX/include" + [ -f "$PREFIX/include/orbis/libkernel.h" ] || cp -r OpenOrbis-PS4-Toolchain/include/* "$PREFIX/include/" + mkdir -p $PREFIX/usr + [ -L "$PREFIX/usr/include" ] || ln -s $PREFIX/include $PREFIX/usr/include || echo 1 + [ -L "$PREFIX/usr/share" ] || ln -s $PREFIX/share $PREFIX/usr/share || echo 1 + [ -L "$PREFIX/usr/lib" ] || ln -s $PREFIX/lib $PREFIX/usr/lib || echo 1 + [ -L "$PREFIX/usr/bin" ] || ln -s $PREFIX/bin $PREFIX/usr/bin || echo 1 +} + +build_musl() { + mkdir -p musl-build + cd musl-build + ../musl/configure --target=$TARGET --disable-shared CC="$CC" CFLAGS="$CFLAGS" --prefix=$PREFIX + gmake -j8 && gmake install + cd .. +} + +build_llvm() { + # Build compiler-rt + cmake "$LLVM_ROOT/compiler-rt" -B "$WORK_PATH/llvm-build/compiler-rt" \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \ + -DCMAKE_C_FLAGS="$CFLAGS" -DCMAKE_CXX_FLAGS="$CXXFLAGS" \ + -DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \ + -DLLVM_PATH="$LLVM_PATH" -DCOMPILER_RT_DEFAULT_TARGET_TRIPLE="$TARGET" \ + -DCOMPILER_RT_BAREMETAL_BUILD=YES -DCOMPILER_RT_BUILD_BUILTINS=ON \ + -DCOMPILER_RT_BUILD_CRT=OFF -DCOMPILER_RT_BUILD_SANITIZERS=OFF \ + -DCOMPILER_RT_BUILD_XRAY=OFF -DCOMPILER_RT_BUILD_LIBFUZZER=OFF \ + -DCOMPILER_RT_BUILD_PROFILE=OFF -DCOMPILER_RT_STANDALONE_BUILD=ON + # Build libunwind + cmake "$LLVM_ROOT/libunwind" -B "$WORK_PATH/llvm-build/libunwind" \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \ + -DCMAKE_C_FLAGS="$CFLAGS -fcxx-exceptions" -DCMAKE_CXX_FLAGS="$CXXFLAGS -fcxx-exceptions" \ + -DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \ + -DLLVM_PATH="$LLVM_PATH" -DLIBUNWIND_USE_COMPILER_RT=YES \ + -DLIBUNWIND_BUILD_32_BITS=NO -DLIBUNWIND_ENABLE_STATIC=ON \ + -DLIBUNWIND_ENABLE_SHARED=OFF -DLIBUNWIND_IS_BAREMETAL=ON + # Build libcxxabi + cmake "$LLVM_ROOT/libcxxabi" -B "$WORK_PATH/llvm-build/libcxxabi" \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \ + -DCMAKE_C_FLAGS="$CFLAGS -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $LLVM_ROOT/libcxx/include -isystem $PREFIX/include -isystem $WORK_PATH/llvm-build/libcxx/include/c++/v1" \ + -DCMAKE_CXX_FLAGS="$CXXFLAGS -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $LLVM_ROOT/libcxx/include -isystem $PREFIX/include -isystem $WORK_PATH/llvm-build/libcxx/include/c++/v1" \ + -DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \ + -DLLVM_PATH="$LLVM_PATH" -DLIBCXXABI_ENABLE_SHARED=NO \ + -DLLVM_ENABLE_RUNTIMES="rt;libunwind" \ + -DLIBCXXABI_ENABLE_STATIC=YES -DLIBCXXABI_ENABLE_EXCEPTIONS=YES \ + -DLIBCXXABI_USE_COMPILER_RT=YES -DLIBCXXABI_USE_LLVM_UNWINDER=YES \ + -DLIBCXXABI_LIBUNWIND_PATH="$LLVM_ROOT/libunwind" \ + -DLIBCXXABI_LIBCXX_INCLUDES="$LLVM_ROOT/libcxx/include" \ + -DLIBCXXABI_ENABLE_PIC=YES + # Build libcxx + cmake "$LLVM_ROOT/libcxx" -B "$WORK_PATH/llvm-build/libcxx" \ + -DCMAKE_INSTALL_PREFIX="$PREFIX" \ + -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" \ + -DCMAKE_C_FLAGS="$CFLAGS -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $PREFIX/include/c++/v1 -isystem $PREFIX/include" \ + -DCMAKE_CXX_FLAGS="$CXXFLAGS -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 -isysroot $PREFIX -isystem $PREFIX/include/c++/v1 -isystem $PREFIX/include" \ + -DCMAKE_ASM_COMPILER="$CC" -DCMAKE_ASM_FLAGS="$CFLAGS -x assembler-with-cpp" \ + -DLLVM_PATH="$LLVM_PATH" -DLIBCXX_ENABLE_RTTI=YES \ + -DLIBCXX_HAS_MUSL_LIBC=YES -DLIBCXX_ENABLE_SHARED=NO \ + -DLIBCXX_CXX_ABI=libcxxabi -DLIBCXX_CXX_ABI_INCLUDE_PATHS="$LLVM_ROOT/libcxxabi/include" \ + -DLIBCXX_CXX_ABI_LIBRARY_PATH="$LLVM_ROOT/libcxxabi/build/lib" + + cmake --build "$WORK_PATH/llvm-build/compiler-rt" --parallel + cmake --install "$WORK_PATH/llvm-build/compiler-rt" + + cmake --build "$WORK_PATH/llvm-build/libunwind" --parallel + cmake --install "$WORK_PATH/llvm-build/libunwind" + + cmake --build "$WORK_PATH/llvm-build/libcxxabi" --parallel + cmake --install "$WORK_PATH/llvm-build/libcxxabi" + + touch "$WORK_PATH/llvm-build/libcxx/include/c++/v1/libcxx.imp" + cmake --build "$WORK_PATH/llvm-build/libcxx" --parallel + cmake --install "$WORK_PATH/llvm-build/libcxx" +} + +build_tools() { + # Build create-fself + cd create-fself/cmd/create-fself + cp go-linux.mod go.mod + go build -o create-fself + mv ./create-fself $PREFIX/bin/create-fself + cd ../../../ + + # Build create-gp4 + cd create-gp4/cmd/create-gp4 + go build -o create-gp4 + mv ./create-gp4 $PREFIX/bin/create-gp4 + cd ../../../ + + # Build readoelf + cd readoelf/cmd/readoelf + go build -o readoelf + mv ./readoelf $PREFIX/bin/readoelf + cd ../../../ + + # Pull maxton's publishing tools (<3) + # Sadly maxton has passed on, we have forked the repository and will continue to update it in the future. RIP <3 + cd $PREFIX/bin + [ -f PkgTool.Core-linux-x64-0.2.231.zip ] || wget https://github.com/maxton/LibOrbisPkg/releases/download/v0.2/PkgTool.Core-linux-x64-0.2.231.zip + [ -f PkgTool.Core ] || unzip PkgTool.Core-linux-x64-0.2.231.zip + chmod +x PkgTool.Core +} + +finish_prefix() { + as $WORK_PATH/OpenOrbis-PS4-Toolchain/src/crt/crtlib.S -o $PREFIX/lib/crtlib.o + cp -a $WORK_PATH/OpenOrbis-PS4-Toolchain/link.x $PREFIX/ + + cp -a ~/OpenOrbis/PS4Toolchain/lib/libkernel* $PREFIX/lib/ + cp -a ~/OpenOrbis/PS4Toolchain/lib/libSce* $PREFIX/lib/ + + cp $WORK_PATH/llvm-build/compiler-rt/lib/freebsd/libclang_rt.builtins-x86_64.a $PREFIX/lib/ + + # Combine libc++, libc++abi and libunwind into a single archive + cat << EOF >"mri.txt" +CREATE $PREFIX/lib/libc++M.a +ADDLIB $PREFIX/lib/libunwind.a +ADDLIB $PREFIX/lib/libc++abi.a +ADDLIB $PREFIX/lib/libc++.a +SAVE +END +EOF + $AR -M < mri.txt + cp $PREFIX/lib/libc++M.a $PREFIX/lib/libc++.a + # Merge compiler-rt into libc + cat << EOF >"mri.txt" +CREATE $PREFIX/lib/libcM.a +ADDLIB $PREFIX/lib/libc.a +ADDLIB $PREFIX/lib/libclang_rt.builtins-x86_64.a +SAVE +END +EOF + $AR -M < mri.txt + cp $PREFIX/lib/libcM.a $PREFIX/lib/libc.a + rm mri.txt +} + +prepare_prefix +build_musl +build_llvm +build_tools +finish_prefix diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index d97b9b30ed..ab9d2d04cf 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -37,22 +37,30 @@ if (NOT YUZU_USE_BUNDLED_FFMPEG) elseif (NOT (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES CMAKE_SYSTEM_PROCESSOR AND CMAKE_HOST_SYSTEM_NAME MATCHES CMAKE_SYSTEM_NAME)) string(TOLOWER "${CMAKE_SYSTEM_NAME}" FFmpeg_SYSTEM_NAME) - # TODO: Can we really do better? Auto-detection? Something clever? - if (NOT DEFINED FFmpeg_CROSS_PREFIX) - message(ERROR "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-") + if (FFmpeg_SYSTEM_NAME STREQUAL "openorbis") + set(FFmpeg_SYSTEM_NAME "freebsd") # Emulates FBSD :) endif() + # TODO: Can we really do better? Auto-detection? Something clever? list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --enable-cross-compile --arch="${CMAKE_SYSTEM_PROCESSOR}" --target-os="${FFmpeg_SYSTEM_NAME}" --sysroot="${CMAKE_SYSROOT}" - --cross-prefix="${FFmpeg_CROSS_PREFIX}" ) + if (DEFINED FFmpeg_CROSS_PREFIX) + list(APPEND FFmpeg_CROSS_COMPILE_FLAGS --cross-prefix="${FFmpeg_CROSS_PREFIX}") + else() + message(WARNING "Please set FFmpeg_CROSS_PREFIX to your cross toolchain prefix, for example: \${CMAKE_STAGING_PREFIX}/bin/${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_SYSTEM_NAME}-") + endif() set(FFmpeg_IS_CROSS_COMPILING TRUE) endif() endif() -if (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING) +if (PLATFORM_PS4) + list(APPEND FFmpeg_HWACCEL_FLAGS + --disable-vaapi + ) +elseif (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING) find_package(PkgConfig REQUIRED) pkg_check_modules(LIBVA libva) pkg_check_modules(CUDA cuda) @@ -147,9 +155,19 @@ if (UNIX AND NOT DEFINED FFmpeg_IS_CROSS_COMPILING) endif() if (PLATFORM_PS4) - list(APPEND FFmpeg_HWACCEL_FLAGS - --enable-stdatomic - --disable-threads + list(APPEND FFmpeg_CROSS_COMPILE_LIBS + -lc + -lkernel + -lSceUserService + -lSceSysmodule + -lSceNet + -lSceLibcInternal + ) + list(APPEND FFmpeg_CROSS_COMPILE_FLAGS + --disable-pthreads + --extra-cflags=${CMAKE_SYSROOT}/usr/include + --extra-cxxflags=${CMAKE_SYSROOT}/usr/include + --extra-libs="${FFmpeg_CROSS_COMPILE_LIBS}" ) endif() @@ -245,12 +263,12 @@ else() --enable-decoder=vp9 --enable-filter=yadif,scale --enable-pic - --cc="${FFmpeg_CC}" - --cxx="${FFmpeg_CXX}" - --ld="${CMAKE_LINKER}" - --extra-ldflags="$CMAKE_C_LINK_FLAGS" - --extra-cflags="$CMAKE_C_FLAGS" - --extra-cxxflags="$CMAKE_CXX_FLAGS" + --cc=${FFmpeg_CC} + --cxx=${FFmpeg_CXX} + --ld=${CMAKE_LINKER} + --extra-cflags=${CMAKE_C_FLAGS} + --extra-cxxflags=${CMAKE_CXX_FLAGS} + --extra-ldflags=${CMAKE_C_LINK_FLAGS} ${FFmpeg_HWACCEL_FLAGS} ${FFmpeg_CROSS_COMPILE_FLAGS} WORKING_DIRECTORY @@ -282,7 +300,7 @@ else() OUTPUT ${FFmpeg_BUILD_LIBRARIES} COMMAND - make ${FFmpeg_MAKE_ARGS} + gmake ${FFmpeg_MAKE_ARGS} WORKING_DIRECTORY ${FFmpeg_BUILD_DIR} ) From 6b39545ece94b7acaaa71ba34ef033b065c237d2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 02:32:31 +0000 Subject: [PATCH 008/181] exclude from vulkan surface selection --- .ci/ps4/make-toolchain.sh | 3 +++ src/video_core/vulkan_common/vulkan.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/.ci/ps4/make-toolchain.sh b/.ci/ps4/make-toolchain.sh index b7848f5ddb..ca0f079d96 100644 --- a/.ci/ps4/make-toolchain.sh +++ b/.ci/ps4/make-toolchain.sh @@ -135,6 +135,9 @@ finish_prefix() { cp -a ~/OpenOrbis/PS4Toolchain/lib/libkernel* $PREFIX/lib/ cp -a ~/OpenOrbis/PS4Toolchain/lib/libSce* $PREFIX/lib/ + cp -a ~/OpenOrbis/PS4Toolchain/lib/libSDL* $PREFIX/lib/ + cp -r ~/OpenOrbis/PS4Toolchain/include/SDL2 $PREFIX/include/SDL2 + cp $WORK_PATH/llvm-build/compiler-rt/lib/freebsd/libclang_rt.builtins-x86_64.a $PREFIX/lib/ # Combine libc++, libc++abi and libunwind into a single archive diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 8d2e8e2a37..9cbabd1ca7 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -15,6 +15,8 @@ #define VK_USE_PLATFORM_ANDROID_KHR #elif defined(__HAIKU__) #define VK_USE_PLATFORM_XCB_KHR +#elif defined(__OPENORBIS__) +// No fucking vulkan on the PlayStation 4 #else #define VK_USE_PLATFORM_XLIB_KHR #define VK_USE_PLATFORM_WAYLAND_KHR From 48c59e0bdea370edff70cfc1468fa9343653adae Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 02:51:57 +0000 Subject: [PATCH 009/181] exclude more stuff from vulkan --- externals/CMakeLists.txt | 6 +++++- src/video_core/vulkan_common/vulkan_instance.cpp | 2 ++ src/video_core/vulkan_common/vulkan_surface.cpp | 2 ++ src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | 6 ++++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 7b4c481ba5..f79f776be4 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -170,7 +170,11 @@ if (NOT ANDROID) AddJsonPackage(sdl2) endif() - find_package(SDL2 2.26.4 REQUIRED) + if (PLATFORM_PS4) + set(SDL2_LIBRARY ${CMAKE_SYSROOT}/lib/libSDL2.a) + set(SDL2_INCLUDE_DIR ${CMAKE_SYSROOT}/include/SDL2) + endif() + find_package(SDL2 REQUIRED) endif() set(BUILD_SHARED_LIBS OFF) diff --git a/src/video_core/vulkan_common/vulkan_instance.cpp b/src/video_core/vulkan_common/vulkan_instance.cpp index 47e18dd6a5..2cbc06d80a 100644 --- a/src/video_core/vulkan_common/vulkan_instance.cpp +++ b/src/video_core/vulkan_common/vulkan_instance.cpp @@ -59,6 +59,8 @@ namespace { case Core::Frontend::WindowSystemType::Xcb: extensions.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); break; +#elif defined(__OPENORBIS__) + // No vulkan #else case Core::Frontend::WindowSystemType::X11: extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp index dc65d3960a..fe6b4daa21 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -76,6 +76,8 @@ vk::SurfaceKHR CreateSurface( throw vk::Exception(VK_ERROR_INITIALIZATION_FAILED); } } +#elif defined(__OPENORBIS__) + // No native #else if (window_info.type == Core::Frontend::WindowSystemType::X11) { const VkXlibSurfaceCreateInfoKHR xlib_ci{ diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index f509652bf6..a21eea1219 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -74,6 +74,12 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste window_info.type = Core::Frontend::WindowSystemType::Android; window_info.render_surface = reinterpret_cast(wm.info.android.window); break; +#endif +#ifdef SDL_VIDEO_DRIVER_DIRECTFB + case SDL_SYSWM_TYPE::SDL_SYSWM_DIRECTFB: + window_info.type = Core::Frontend::WindowSystemType::Headless; + window_info.render_surface = reinterpret_cast(wm.info.dfb.window); + break; #endif default: LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem); From cf7c80b472831a4c0282c5ee882a4d78a6446246 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:50:45 +0000 Subject: [PATCH 010/181] make .pkg and .self --- CMakeLists.txt | 1 + CMakeModules/OpenOrbis.cmake | 42 ++++++++++++++++++++++++++++++++++++ src/yuzu_cmd/CMakeLists.txt | 7 ++++++ src/yuzu_cmd/yuzu.cpp | 10 +++++++++ 4 files changed, 60 insertions(+) create mode 100644 CMakeModules/OpenOrbis.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4490df21cb..fa5a85c724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,6 +20,7 @@ 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?") diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake new file mode 100644 index 0000000000..7b7b0c005c --- /dev/null +++ b/CMakeModules/OpenOrbis.cmake @@ -0,0 +1,42 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + +function(add_fself project target) + add_custom_command( + OUTPUT "${target}.self" + COMMAND ${CMAKE_SYSROOT}/bin/create-fself + -in=${CMAKE_BINARY_DIR}/bin/${target} + -out=${CMAKE_BINARY_DIR}/bin/${target}.oelf + --eboot ${CMAKE_BINARY_DIR}/bin/eboot.bin + VERBATIM + DEPENDS "${project}" + ) + add_custom_target("${project}_self" ALL DEPENDS "${target}.self") +endfunction() + +function(add_pkg project target) + set(sce_sys_dir ${CMAKE_BINARY_DIR}/sce_sys) + set(sce_sys_param ${sce_sys_dir}/param.sfo) + add_custom_command( + OUTPUT "${target}.pkg" + 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 'IV0000-BREW00090_00-EDENEMULAT000000' + 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 'Eden Emulator' + 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' + VERBATIM + DEPENDS "${target}.self" + ) + 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 () diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index a1f16be75c..ba24de8b62 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -34,6 +34,8 @@ target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common target_link_libraries(yuzu-cmd PRIVATE glad) if (MSVC) target_link_libraries(yuzu-cmd PRIVATE getopt) +elseif(PLATFORM_PS4) + target_link_libraries(yuzu-cmd PRIVATE SceVideoOut SceAudioOut ScePad) endif() target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) @@ -65,3 +67,8 @@ if (NOT MSVC) -Wno-unused-parameter -Wno-missing-field-initializers) endif() + +if (PLATFORM_PS4) + add_fself(yuzu-cmd eden-cli) + add_pkg(yuzu-cmd eden-cli) +endif() diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index b292b4886b..869904b60f 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -51,6 +51,16 @@ #include #endif +#ifdef __OPENORBIS__ +# define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); } +STUB_WEAK(__cxa_thread_atexit) +STUB_WEAK(__assert) +STUB_WEAK(ZSTD_trace_compress_begin) +STUB_WEAK(ZSTD_trace_compress_end) +STUB_WEAK(ZSTD_trace_decompress_begin) +STUB_WEAK(ZSTD_trace_decompress_end) +# undef STUB_WEAK +#endif #ifdef _WIN32 extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable From 4efd4e5c2e9ebcc52b8ed50b2e2bcbf649f00f06 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 05:08:23 +0000 Subject: [PATCH 011/181] fself + pkg stuffs --- CMakeModules/OpenOrbis.cmake | 25 ++++++++++++++----------- src/yuzu_cmd/CMakeLists.txt | 4 ++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index 7b7b0c005c..2ee8cb4942 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -1,9 +1,9 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -function(add_fself project target) +function(create_ps4_fself project target) add_custom_command( - OUTPUT "${target}.self" + OUTPUT "${CMAKE_BINARY_DIR}/${target}.self" COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=${CMAKE_BINARY_DIR}/bin/${target} -out=${CMAKE_BINARY_DIR}/bin/${target}.oelf @@ -11,30 +11,33 @@ function(add_fself project target) VERBATIM DEPENDS "${project}" ) - add_custom_target("${project}_self" ALL DEPENDS "${target}.self") + add_custom_target("${project}_self" ALL DEPENDS ${project}) endfunction() -function(add_pkg project target) - set(sce_sys_dir ${CMAKE_BINARY_DIR}/sce_sys) +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" + OUTPUT "${CMAKE_BINARY_DIR}/${target}.pkg" 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 'IV0000-BREW00090_00-EDENEMULAT000000' + COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CATEGORY --type Utf8 --maxsize 4 --value 'E' + 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 'Eden Emulator' + 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 "bin/eboot.bin ${sce_sys_param}" + COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${CMAKE_BINARY_DIR}/${target}.gp4 . VERBATIM - DEPENDS "${target}.self" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${project}_self ) - add_custom_target("${project}_pkg" ALL DEPENDS "${target}.pkg") + add_custom_target(${project}_pkg ALL DEPENDS "${CMAKE_BINARY_DIR}/${target}.pkg") endfunction() if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN}) diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index ba24de8b62..0f53566e94 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -69,6 +69,6 @@ if (NOT MSVC) endif() if (PLATFORM_PS4) - add_fself(yuzu-cmd eden-cli) - add_pkg(yuzu-cmd eden-cli) + create_ps4_fself(yuzu-cmd eden-cli) + create_ps4_pkg(yuzu-cmd eden-cli "IV0000-BREW00090_00-EDENEMULAT000000") endif() From 4d03401bbada4ef256246c6fdcb2ba734ec022dd Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 05:32:35 +0000 Subject: [PATCH 012/181] the orb --- .ci/ps4/make-toolchain.sh | 20 +++++++++++--------- CMakeModules/OpenOrbis.cmake | 36 ++++++++++++------------------------ src/yuzu_cmd/CMakeLists.txt | 3 +-- 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/.ci/ps4/make-toolchain.sh b/.ci/ps4/make-toolchain.sh index ca0f079d96..727596ae36 100644 --- a/.ci/ps4/make-toolchain.sh +++ b/.ci/ps4/make-toolchain.sh @@ -21,6 +21,7 @@ prepare_prefix() { [ -d create-fself ] || git clone --depth=1 https://github.com/OpenOrbis/create-fself [ -d create-gp4 ] || git clone --depth=1 https://github.com/OpenOrbis/create-gp4 [ -d readoelf ] || git clone --depth=1 https://github.com/OpenOrbis/readoelf + [ -d LibOrbisPkg ] || git clone --depth=1 https://github.com/maxton/LibOrbisPkg mkdir -p $PREFIX "$PREFIX/bin" "$PREFIX/include" [ -f "$PREFIX/include/orbis/libkernel.h" ] || cp -r OpenOrbis-PS4-Toolchain/include/* "$PREFIX/include/" @@ -101,31 +102,32 @@ build_llvm() { } build_tools() { + # Build create-fself cd create-fself/cmd/create-fself cp go-linux.mod go.mod - go build -o create-fself + go build -ldflags "-linkmode external -extldflags -static" -o create-fself mv ./create-fself $PREFIX/bin/create-fself cd ../../../ # Build create-gp4 cd create-gp4/cmd/create-gp4 - go build -o create-gp4 + go build -ldflags "-linkmode external -extldflags -static" -o create-gp4 mv ./create-gp4 $PREFIX/bin/create-gp4 cd ../../../ # Build readoelf cd readoelf/cmd/readoelf - go build -o readoelf + go build -ldflags "-linkmode external -extldflags -static" -o readoelf mv ./readoelf $PREFIX/bin/readoelf cd ../../../ - # Pull maxton's publishing tools (<3) - # Sadly maxton has passed on, we have forked the repository and will continue to update it in the future. RIP <3 - cd $PREFIX/bin - [ -f PkgTool.Core-linux-x64-0.2.231.zip ] || wget https://github.com/maxton/LibOrbisPkg/releases/download/v0.2/PkgTool.Core-linux-x64-0.2.231.zip - [ -f PkgTool.Core ] || unzip PkgTool.Core-linux-x64-0.2.231.zip - chmod +x PkgTool.Core + # # Pull maxton's publishing tools (<3) + # # Sadly maxton has passed on, we have forked the repository and will continue to update it in the future. RIP <3 + # cd $PREFIX/bin + # [ -f PkgTool.Core-linux-x64-0.2.231.zip ] || wget https://github.com/maxton/LibOrbisPkg/releases/download/v0.2/PkgTool.Core-linux-x64-0.2.231.zip + # [ -f PkgTool.Core ] || unzip PkgTool.Core-linux-x64-0.2.231.zip + # chmod +x PkgTool.Core } finish_prefix() { diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index 2ee8cb4942..4e76731f6a 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -1,43 +1,31 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -function(create_ps4_fself project target) - add_custom_command( - OUTPUT "${CMAKE_BINARY_DIR}/${target}.self" - COMMAND ${CMAKE_SYSROOT}/bin/create-fself - -in=${CMAKE_BINARY_DIR}/bin/${target} - -out=${CMAKE_BINARY_DIR}/bin/${target}.oelf - --eboot ${CMAKE_BINARY_DIR}/bin/eboot.bin - VERBATIM - DEPENDS "${project}" - ) - add_custom_target("${project}_self" ALL DEPENDS ${project}) -endfunction() - function(create_ps4_pkg project target content_id) - set(sce_sys_dir ./sce_sys) + set(sce_sys_dir sce_sys) set(sce_sys_param ${sce_sys_dir}/param.sfo) add_custom_command( - OUTPUT "${CMAKE_BINARY_DIR}/${target}.pkg" + OUTPUT "${target}.pkg" + COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot 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} 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 'E' - 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} 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 "bin/eboot.bin ${sce_sys_param}" - COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${CMAKE_BINARY_DIR}/${target}.gp4 . + 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 "eboot.bin ${sce_sys_param}" + COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${target}.gp4 . VERBATIM WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - DEPENDS ${project}_self + DEPENDS ${project} ) - add_custom_target(${project}_pkg ALL DEPENDS "${CMAKE_BINARY_DIR}/${target}.pkg") + add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg") endfunction() if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN}) diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 0f53566e94..10b55fd865 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -69,6 +69,5 @@ if (NOT MSVC) endif() if (PLATFORM_PS4) - create_ps4_fself(yuzu-cmd eden-cli) - create_ps4_pkg(yuzu-cmd eden-cli "IV0000-BREW00090_00-EDENEMULAT000000") + create_ps4_pkg(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) endif() From 81f2ba5f9e04fcb10cb780abc3b2033ca46bff32 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 09:33:59 +0000 Subject: [PATCH 013/181] sysconf stub cuz crash(?) + some stderrp stuff --- .ci/ps4/build.sh | 14 +- CMakeModules/FindSDL2.cmake | 388 ++++++++++++++++++ docs/user/Basics.md | 1 + src/common/fs/path_util.cpp | 4 + src/common/host_memory.cpp | 7 +- src/common/memory_detect.cpp | 4 +- src/input_common/drivers/joycon.cpp | 13 +- src/input_common/drivers/joycon.h | 9 +- src/input_common/drivers/sdl_driver.cpp | 39 +- src/input_common/helpers/joycon_driver.cpp | 35 +- .../joycon_protocol/common_protocol.cpp | 52 ++- .../helpers/joycon_protocol/joycon_types.h | 9 +- src/yuzu_cmd/CMakeLists.txt | 3 +- src/yuzu_cmd/yuzu.cpp | 1 + 14 files changed, 506 insertions(+), 73 deletions(-) create mode 100644 CMakeModules/FindSDL2.cmake diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 0dda2e9c9a..0bffdca680 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -3,8 +3,6 @@ # SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later -OO_PS4_TOOLCHAIN="/home/xerix/src/ps4-sdk/prefix" - [ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake" set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN") set(CMAKE_STAGING_PREFIX "$OO_PS4_TOOLCHAIN") @@ -20,8 +18,8 @@ set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-fr set(CMAKE_C_COMPILER clang) set(CMAKE_CXX_COMPILER clang++) set(CMAKE_LINKER ld.lld) -set(CMAKE_C_LINK_EXECUTABLE " -o -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o ") -set(CMAKE_CXX_LINK_EXECUTABLE " -o -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet -lSceLibcInternal $OO_PS4_TOOLCHAIN/lib/crt1.o ") +set(CMAKE_C_LINK_EXECUTABLE " -o -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o ") +set(CMAKE_CXX_LINK_EXECUTABLE " -o -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o ") set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) @@ -35,14 +33,16 @@ EOF # Normally a platform has a package manager # PS4 does not, atleast not in the normal sense export EXTRA_CMAKE_FLAGS=("${EXTRA_CMAKE_FLAGS[@]}" $@) -cmake -S . -B build -G Ninja \ +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=OFF \ + -DENABLE_SDL2=ON \ + -DENABLE_LIBUSB=OFF \ + -DENABLE_UPDATE_CHECKER=OFF \ -DENABLE_QT=OFF \ -DENABLE_OPENSSL=OFF \ -DENABLE_WEB_SERVICE=OFF \ @@ -51,4 +51,4 @@ cmake -S . -B build -G Ninja \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit -cmake --build build --parallel +cmake --build build -t yuzu-cmd_pkg -- -j8 diff --git a/CMakeModules/FindSDL2.cmake b/CMakeModules/FindSDL2.cmake new file mode 100644 index 0000000000..2445d36ec5 --- /dev/null +++ b/CMakeModules/FindSDL2.cmake @@ -0,0 +1,388 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# Copyright 2019 Amine Ben Hassouna +# Copyright 2000-2019 Kitware, Inc. and Contributors +# 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 Kitware, Inc. nor the names of 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 +# HOLDER 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. + +#[=======================================================================[.rst: +FindSDL2 +-------- + +Locate SDL2 library + +This module defines the following 'IMPORTED' targets: + +:: + + SDL2::Core + The SDL2 library, if found. + Libraries should link to SDL2::Core + + SDL2::Main + The SDL2main library, if found. + Applications should link to SDL2::Main instead of SDL2::Core + + + +This module will set the following variables in your project: + +:: + + SDL2_LIBRARIES, the name of the library to link against + SDL2_INCLUDE_DIRS, where to find SDL.h + SDL2_FOUND, if false, do not try to link to SDL2 + SDL2MAIN_FOUND, if false, do not try to link to SDL2main + SDL2_VERSION_STRING, human-readable string containing the version of SDL2 + + + +This module responds to the following cache variables: + +:: + + SDL2_PATH + Set a custom SDL2 Library path (default: empty) + + SDL2_NO_DEFAULT_PATH + Disable search SDL2 Library in default path. + If SDL2_PATH (default: ON) + Else (default: OFF) + + SDL2_INCLUDE_DIR + SDL2 headers path. + + SDL2_LIBRARY + SDL2 Library (.dll, .so, .a, etc) path. + + SDL2MAIN_LIBRAY + SDL2main Library (.a) path. + + SDL2_BUILDING_LIBRARY + This flag is useful only when linking to SDL2_LIBRARIES insead of + SDL2::Main. It is required only when building a library that links to + SDL2_LIBRARIES, because only applications need main() (No need to also + link to SDL2main). + If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES + and no SDL2::Main target will be created. + + +Don't forget to include SDLmain.h and SDLmain.m in your project for the +OS X framework based version. (Other versions link to -lSDL2main which +this module will try to find on your behalf.) Also for OS X, this +module will automatically add the -framework Cocoa on your behalf. + + +Additional Note: If you see an empty SDL2_LIBRARY in your project +configuration, it means CMake did not find your SDL2 library +(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point +to your SDL2 library, and configure again. Similarly, if you see an +empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These +values are used to generate the final SDL2_LIBRARIES variable and the +SDL2::Core and SDL2::Main targets, but when these values are unset, +SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created. + + +$SDL2DIR is an environment variable that would correspond to the +./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 + + + +Created by Amine Ben Hassouna: + Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake). + Add cache variables for more flexibility: + SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above). + Mark 'Threads' as a required dependency for non-OSX systems. + Modernize the FindSDL2.cmake module by creating specific targets: + SDL2::Core and SDL2::Main (for details, see doc above). + + +Original FindSDL.cmake module: + Modified by Eric Wing. Added code to assist with automated building + by using environmental variables and providing a more + controlled/consistent search behavior. Added new modifications to + recognize OS X frameworks and additional Unix paths (FreeBSD, etc). + Also corrected the header search path to follow "proper" SDL + guidelines. Added a search for SDLmain which is needed by some + platforms. Added a search for threads which is needed by some + platforms. Added needed compile switches for MinGW. + +On OSX, this will prefer the Framework version (if found) over others. +People will have to manually change the cache value of SDL2_LIBRARY to +override this selection or set the SDL2_PATH variable or the CMake +environment CMAKE_INCLUDE_PATH to modify the search paths. + +Note that the header path has changed from SDL/SDL.h to just SDL.h +This needed to change because "proper" SDL convention is #include +"SDL.h", not . This is done for portability reasons +because not all systems place things in SDL/ (see FreeBSD). +#]=======================================================================] + +# Define options for searching SDL2 Library in a custom path + +set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path") + +set(_SDL2_NO_DEFAULT_PATH OFF) +if(SDL2_PATH) + set(_SDL2_NO_DEFAULT_PATH ON) +endif() + +set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH} + CACHE BOOL "Disable search SDL2 Library in default path") +unset(_SDL2_NO_DEFAULT_PATH) + +set(SDL2_NO_DEFAULT_PATH_CMD) +if(SDL2_NO_DEFAULT_PATH) + set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH) +endif() + +# Search for the SDL2 include directory +find_path(SDL2_INCLUDE_DIR SDL.h + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES SDL2 + # path suffixes to search inside ENV{SDL2DIR} + include/SDL2 include + PATHS ${SDL2_PATH} + DOC "Where the SDL2 headers can be found" +) + +set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}") + +if(CMAKE_SIZEOF_VOID_P EQUAL 8) + set(VC_LIB_PATH_SUFFIX lib/x64) +else() + set(VC_LIB_PATH_SUFFIX lib/x86) +endif() + +# SDL-2.0 is the name used by FreeBSD ports... +# don't confuse it for the version number. +find_library(SDL2_LIBRARY + NAMES SDL2 SDL-2.0 + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2_PATH} + DOC "Where the SDL2 Library can be found" +) + +set(SDL2_LIBRARIES "${SDL2_LIBRARY}") + +if(NOT SDL2_BUILDING_LIBRARY) + if(NOT SDL2_INCLUDE_DIR MATCHES ".framework") + # Non-OS X framework versions expect you to also dynamically link to + # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms + # seem to provide SDL2main for compatibility even though they don't + # necessarily need it. + + if(SDL2_PATH) + set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}") + endif() + + if(NOT SDL2_NO_DEFAULT_PATH) + set(SDL2MAIN_LIBRARY_PATHS + /sw + /opt/local + /opt/csw + /opt + "${SDL2MAIN_LIBRARY_PATHS}" + ) + endif() + + find_library(SDL2MAIN_LIBRARY + NAMES SDL2main + HINTS + ENV SDL2DIR + ${SDL2_NO_DEFAULT_PATH_CMD} + PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} + PATHS ${SDL2MAIN_LIBRARY_PATHS} + DOC "Where the SDL2main library can be found" + ) + unset(SDL2MAIN_LIBRARY_PATHS) + endif() +endif() + +# SDL2 may require threads on your system. +# The Apple build may not need an explicit flag because one of the +# frameworks may already provide it. +# But for non-OSX systems, I will use the CMake Threads package. +if(NOT APPLE) + find_package(Threads QUIET) + if(NOT Threads_FOUND) + set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).") + if(SDL2_FIND_REQUIRED) + message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND}) + else() + if(NOT SDL2_FIND_QUIETLY) + message(STATUS ${SDL2_THREADS_NOT_FOUND}) + endif() + return() + endif() + unset(SDL2_THREADS_NOT_FOUND) + endif() +endif() + +# MinGW needs an additional link flag, -mwindows +# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows +if(MINGW) + set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW") +endif() + +if(SDL2_LIBRARY) + # For SDL2main + if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY) + list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX) + if(_SDL2_MAIN_INDEX EQUAL -1) + set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES}) + endif() + unset(_SDL2_MAIN_INDEX) + endif() + + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # CMake doesn't display the -framework Cocoa string in the UI even + # though it actually is there if I modify a pre-used variable. + # I think it has something to do with the CACHE STRING. + # So I use a temporary variable until the end so I can set the + # "real" variable in one-shot. + if(APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa) + endif() + + # For threads, as mentioned Apple doesn't need this. + # In fact, there seems to be a problem if I used the Threads package + # and try using this line, so I'm just skipping it entirely for OS X. + if(NOT APPLE) + set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + endif() + + # For MinGW library + if(MINGW) + set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES}) + endif() + +endif() + +# Read SDL2 version +if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$") + file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$") + string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}") + string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}") + set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}) + unset(SDL2_VERSION_MAJOR_LINE) + unset(SDL2_VERSION_MINOR_LINE) + unset(SDL2_VERSION_PATCH_LINE) + unset(SDL2_VERSION_MAJOR) + unset(SDL2_VERSION_MINOR) + unset(SDL2_VERSION_PATCH) +endif() + +include(FindPackageHandleStandardArgs) + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 + REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) + +if(SDL2MAIN_LIBRARY) + FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main + REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR + VERSION_VAR SDL2_VERSION_STRING) +endif() + + +mark_as_advanced(SDL2_PATH + SDL2_NO_DEFAULT_PATH + SDL2_LIBRARY + SDL2MAIN_LIBRARY + SDL2_INCLUDE_DIR + SDL2_BUILDING_LIBRARY) + + +# SDL2:: targets (SDL2::Core and SDL2::Main) +if(SDL2_FOUND) + + # SDL2::Core target + if(SDL2_LIBRARY AND NOT TARGET SDL2::Core) + add_library(SDL2::Core UNKNOWN IMPORTED) + set_target_properties(SDL2::Core PROPERTIES + IMPORTED_LOCATION "${SDL2_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}") + + if(APPLE) + # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_OPTIONS -framework Cocoa) + else() + # For threads, as mentioned Apple doesn't need this. + # For more details, please see above. + set_property(TARGET SDL2::Core APPEND PROPERTY + INTERFACE_LINK_LIBRARIES Threads::Threads) + endif() + endif() + + # SDL2::Main target + # Applications should link to SDL2::Main instead of SDL2::Core + # For more details, please see above. + if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main) + + if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY) + add_library(SDL2::Main INTERFACE IMPORTED) + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + elseif(SDL2MAIN_LIBRARY) + # MinGW requires that the mingw32 library is specified before the + # libSDL2main.a static library when linking. + # The SDL2::MainInternal target is used internally to make sure that + # CMake respects this condition. + add_library(SDL2::MainInternal UNKNOWN IMPORTED) + set_property(TARGET SDL2::MainInternal PROPERTY + IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}") + set_property(TARGET SDL2::MainInternal PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::Core) + + add_library(SDL2::Main INTERFACE IMPORTED) + + if(MINGW) + # MinGW needs an additional link flag '-mwindows' and link to mingw32 + set_property(TARGET SDL2::Main PROPERTY + INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows") + endif() + + set_property(TARGET SDL2::Main APPEND PROPERTY + INTERFACE_LINK_LIBRARIES SDL2::MainInternal) + endif() + + endif() +endif() diff --git a/docs/user/Basics.md b/docs/user/Basics.md index 5101f4d9c3..b8719a9310 100644 --- a/docs/user/Basics.md +++ b/docs/user/Basics.md @@ -26,6 +26,7 @@ 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. diff --git a/src/common/fs/path_util.cpp b/src/common/fs/path_util.cpp index 3f928ac327..0cacb50596 100644 --- a/src/common/fs/path_util.cpp +++ b/src/common/fs/path_util.cpp @@ -130,6 +130,10 @@ 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)) { diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index a75152eec0..55c4a914e0 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -495,9 +495,12 @@ class HostMemory::Impl { public: explicit Impl(size_t backing_size_, size_t virtual_size_) : backing_size{backing_size_}, virtual_size{virtual_size_} { +#ifdef __OPENORBIS__ + +#else long page_size = sysconf(_SC_PAGESIZE); - ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", - page_size); + ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", page_size); +#endif // Backing memory initialization #if defined(__sun__) || defined(__HAIKU__) || defined(__NetBSD__) || defined(__DragonFly__) fd = shm_open_anon(O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); diff --git a/src/common/memory_detect.cpp b/src/common/memory_detect.cpp index 074c02a9c3..8bd544e3e2 100644 --- a/src/common/memory_detect.cpp +++ b/src/common/memory_detect.cpp @@ -43,7 +43,9 @@ static MemoryInfo Detect() { sysctlbyname("vm.swapusage", &vmusage, &sizeof_vmusage, nullptr, 0); mem_info.TotalPhysicalMemory = ramsize; mem_info.TotalSwapMemory = vmusage.xsu_total; -#elif defined(__FreeBSD__) && !defined(__OPENORBIS__) +#elif defined(__OPENORBIS__) + mem_info.TotalPhysicalMemory = mem_info.TotalSwapMemory = 0; +#elif defined(__FreeBSD__) u_long physmem, swap_total; std::size_t sizeof_u_long = sizeof(u_long); // sysctlbyname(const char *, void *, size_t *, const void *, size_t); diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index fb2d75e384..83a57f96a7 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -23,12 +23,14 @@ Joycons::Joycons(const std::string& input_engine_) : InputEngine(input_engine_) return; } LOG_INFO(Input, "Joycon driver Initialization started"); - const int init_res = SDL_hid_init(); - if (init_res == 0) { +#if SDL_VERSION_ATLEAST(2, 26, 4) + int const res = SDL_hid_init(); + if (res == 0) { Setup(); } else { - LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", init_res); + LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", res); } +#endif } Joycons::~Joycons() { @@ -55,7 +57,9 @@ void Joycons::Reset() { } device->Stop(); } +#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_exit(); +#endif } void Joycons::Setup() { @@ -80,9 +84,9 @@ void Joycons::Setup() { } void Joycons::ScanThread(std::stop_token stop_token) { +#if SDL_VERSION_ATLEAST(2, 26, 4) constexpr u16 nintendo_vendor_id = 0x057e; Common::SetCurrentThreadName("JoyconScanThread"); - do { SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); SDL_hid_device_info* cur_dev = devs; @@ -98,6 +102,7 @@ void Joycons::ScanThread(std::stop_token stop_token) { SDL_hid_free_enumeration(devs); } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5})); +#endif } bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 112e970e15..cc07958a0f 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -6,7 +6,14 @@ #include #include #include -#include + +#include +#if SDL_VERSION_ATLEAST(2, 26, 4) +# include +#else +struct SDL_hid_device; +struct SDL_hid_device_info; +#endif #include "input_common/input_engine.h" diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 81b0a2313a..93f7d5c1ea 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -42,6 +42,7 @@ public: } void EnableMotion() { +#if SDL_VERSION_ATLEAST(2, 26, 4) if (!sdl_controller) { return; } @@ -58,12 +59,14 @@ public: if (has_gyro) { SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); } +#endif } bool HasMotion() const { return has_gyro || has_accel; } +#if SDL_VERSION_ATLEAST(2, 26, 4) bool UpdateMotion(SDL_ControllerSensorEvent event) { constexpr float gravity_constant = 9.80665f; std::scoped_lock lock{mutex}; @@ -105,6 +108,7 @@ public: motion.delta_timestamp = time_difference * 1000; return true; } +#endif const BasicMotion& GetMotion() const { return motion; @@ -149,13 +153,15 @@ public: } bool HasHDRumble() const { +#if SDL_VERSION_ATLEAST(2, 26, 4) if (sdl_controller) { - const auto type = SDL_GameControllerGetType(sdl_controller.get()); + auto const type = SDL_GameControllerGetType(sdl_controller.get()); return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || (type == SDL_CONTROLLER_TYPE_PS5); } +#endif return false; } @@ -252,26 +258,21 @@ public: } std::string GetControllerName() const { +#if SDL_VERSION_ATLEAST(2, 26, 4) if (sdl_controller) { switch (SDL_GameControllerGetType(sdl_controller.get())) { - case SDL_CONTROLLER_TYPE_XBOX360: - return "Xbox 360 Controller"; - case SDL_CONTROLLER_TYPE_XBOXONE: - return "Xbox One Controller"; - case SDL_CONTROLLER_TYPE_PS3: - return "DualShock 3 Controller"; - case SDL_CONTROLLER_TYPE_PS4: - return "DualShock 4 Controller"; - case SDL_CONTROLLER_TYPE_PS5: - return "DualSense Controller"; + case SDL_CONTROLLER_TYPE_XBOX360: return "Xbox 360 Controller"; + case SDL_CONTROLLER_TYPE_XBOXONE: return "Xbox One Controller"; + case SDL_CONTROLLER_TYPE_PS3: return "DualShock 3 Controller"; + case SDL_CONTROLLER_TYPE_PS4: return "DualShock 4 Controller"; + case SDL_CONTROLLER_TYPE_PS5: return "DualSense Controller"; default: + if (auto const name = SDL_GameControllerName(sdl_controller.get()); name) + return name; break; } - const auto name = SDL_GameControllerName(sdl_controller.get()); - if (name) { - return name; - } } +#endif if (sdl_joystick) { const auto name = SDL_JoystickName(sdl_joystick.get()); @@ -456,6 +457,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } +#if SDL_VERSION_ATLEAST(2, 26, 4) case SDL_CONTROLLERSENSORUPDATE: { if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { if (joystick->UpdateMotion(event.csensor)) { @@ -472,6 +474,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } +#endif case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -489,6 +492,7 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { +#if SDL_VERSION_ATLEAST(2, 26, 4) // Set our application name. Currently passed to DBus by SDL and visible to the user through // their desktop environment. SDL_SetHint(SDL_HINT_APP_NAME, "Eden"); @@ -529,6 +533,7 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // driver on Linux. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); +#endif // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; @@ -833,6 +838,7 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; +#if SDL_VERSION_ATLEAST(2, 26, 4) if (joystick->IsJoyconLeft()) { sll_button = SDL_CONTROLLER_BUTTON_PADDLE2; srl_button = SDL_CONTROLLER_BUTTON_PADDLE4; @@ -841,6 +847,7 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( slr_button = SDL_CONTROLLER_BUTTON_PADDLE3; srr_button = SDL_CONTROLLER_BUTTON_PADDLE1; } +#endif return { std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, @@ -862,7 +869,9 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( {Settings::NativeButton::SLRight, slr_button}, {Settings::NativeButton::SRRight, srr_button}, {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, +#if SDL_VERSION_ATLEAST(2, 26, 4) {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1}, +#endif }; } diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 0dd1c958a2..10c2878cea 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -38,8 +38,8 @@ Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_inf return Common::Input::DriverResult::UnsupportedControllerType; } - hidapi_handle->handle = - SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); +#if SDL_VERSION_ATLEAST(2, 26, 4) + hidapi_handle->handle = SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); std::memcpy(&handle_serial_number, device_info->serial_number, 15); if (!hidapi_handle->handle) { LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", @@ -48,6 +48,9 @@ Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_inf } SDL_hid_set_nonblocking(hidapi_handle->handle, 1); return Common::Input::DriverResult::Success; +#else + return Common::Input::DriverResult::UnsupportedControllerType; +#endif } Common::Input::DriverResult JoyconDriver::InitializeDevice() { @@ -138,8 +141,6 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { Common::SetCurrentThreadName("JoyconInput"); input_thread_running = true; - // Max update rate is 5ms, ensure we are always able to read a bit faster - constexpr int ThreadDelay = 3; std::vector buffer(MaxBufferSize); while (!stop_token.stop_requested()) { @@ -150,14 +151,17 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { continue; } +#if SDL_VERSION_ATLEAST(2, 26, 4) + // Max update rate is 5ms, ensure we are always able to read a bit faster + int constexpr thread_delay = 3; // By disabling the input thread we can ensure custom commands will succeed as no package is // skipped if (!disable_input_thread) { - status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), - ThreadDelay); + status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), thread_delay); } else { - std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay)); + std::this_thread::sleep_for(std::chrono::milliseconds(thread_delay)); } +#endif if (IsPayloadCorrect(status, buffer)) { OnNewData(buffer); @@ -690,19 +694,18 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { joycon_poller->SetCallbacks(callbacks); } -Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, - ControllerType& controller_type) { +Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) { +#if SDL_VERSION_ATLEAST(2, 26, 4) static constexpr std::array, 6> supported_devices{ std::pair{0x2006, ControllerType::Left}, {0x2007, ControllerType::Right}, {0x2009, ControllerType::Pro}, }; - constexpr u16 nintendo_vendor_id = 0x057e; + constexpr u16 nintendo_vendor_id = 0x057e; controller_type = ControllerType::None; - if (device_info->vendor_id != nintendo_vendor_id) { + if (device_info->vendor_id != nintendo_vendor_id) return Common::Input::DriverResult::UnsupportedControllerType; - } for (const auto& [product_id, type] : supported_devices) { if (device_info->product_id == static_cast(product_id)) { @@ -710,16 +713,20 @@ Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* dev return Common::Input::DriverResult::Success; } } +#endif return Common::Input::DriverResult::UnsupportedControllerType; } -Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, - SerialNumber& serial_number) { +Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, SerialNumber& serial_number) { +#if SDL_VERSION_ATLEAST(2, 26, 4) if (device_info->serial_number == nullptr) { return Common::Input::DriverResult::Unknown; } std::memcpy(&serial_number, device_info->serial_number, 15); return Common::Input::DriverResult::Success; +#else + return Common::Input::DriverResult::Unknown; +#endif } } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index a6eecf9802..669e89f064 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -15,11 +15,15 @@ u8 JoyconCommonProtocol::GetCounter() { } void JoyconCommonProtocol::SetBlocking() { +#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_set_nonblocking(hidapi_handle->handle, 0); +#endif } void JoyconCommonProtocol::SetNonBlocking() { +#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_set_nonblocking(hidapi_handle->handle, 1); +#endif } Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { @@ -35,26 +39,23 @@ Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& return result; } -Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess( - SDL_hid_device_info* device_info) { +Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { ControllerType controller_type{ControllerType::None}; const auto result = GetDeviceType(controller_type); - if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) { return Common::Input::DriverResult::UnsupportedControllerType; } - - hidapi_handle->handle = - SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); - +#if SDL_VERSION_ATLEAST(2, 26, 4) + hidapi_handle->handle = SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); if (!hidapi_handle->handle) { - LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", - device_info->vendor_id, device_info->product_id); + LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", device_info->vendor_id, device_info->product_id); return Common::Input::DriverResult::HandleInUse; } - SetNonBlocking(); return Common::Input::DriverResult::Success; +#else + return Common::Input::DriverResult::UnsupportedControllerType; +#endif } Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { @@ -63,21 +64,21 @@ Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode repor } Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span buffer) { - const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); - - if (result == -1) { +#if SDL_VERSION_ATLEAST(2, 26, 4) + auto const result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); + if (result == -1) return Common::Input::DriverResult::ErrorWritingData; - } - return Common::Input::DriverResult::Success; +#else + return Common::Input::DriverResult::ErrorWritingData; +#endif } -Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse( - SubCommand sc, SubCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, SubCommandResponse& output) { +#if SDL_VERSION_ATLEAST(2, 26, 4) constexpr int timeout_mili = 66; constexpr int MaxTries = 10; int tries = 0; - do { int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast(&output), sizeof(SubCommandResponse), timeout_mili); @@ -88,9 +89,8 @@ Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse( if (tries++ > MaxTries) { return Common::Input::DriverResult::Timeout; } - } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && - output.sub_command != sc); - + } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && output.sub_command != sc); +#endif return Common::Input::DriverResult::Success; } @@ -218,12 +218,11 @@ Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& return result; } -Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, - MCUCommandResponse& output) { +Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, MCUCommandResponse& output) { +#if SDL_VERSION_ATLEAST(2, 26, 4) constexpr int TimeoutMili = 200; constexpr int MaxTries = 9; int tries = 0; - do { int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast(&output), sizeof(MCUCommandResponse), TimeoutMili); @@ -234,9 +233,8 @@ Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode if (tries++ > MaxTries) { return Common::Input::DriverResult::Timeout; } - } while (output.input_report.report_mode != report_mode || - output.mcu_report == MCUReport::EmptyAwaitingCmd); - + } while (output.input_report.report_mode != report_mode || output.mcu_report == MCUReport::EmptyAwaitingCmd); +#endif return Common::Input::DriverResult::Success; } diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 792f124e14..9be84b36a2 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -10,7 +10,14 @@ #include #include -#include + +#include +#if SDL_VERSION_ATLEAST(2, 26, 4) +# include +#else +struct SDL_hid_device; +struct SDL_hid_device_info; +#endif #include "common/bit_field.h" #include "common/common_funcs.h" diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 10b55fd865..605ef410a8 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -42,7 +42,8 @@ target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) create_resource("../../dist/eden.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon") target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) -target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2) +target_include_directories(yuzu-cmd PRIVATE ${CMAKE_SYSROOT}/include/SDL2) +target_link_libraries(yuzu-cmd PRIVATE SDL2) if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 869904b60f..02f2aee856 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -59,6 +59,7 @@ STUB_WEAK(ZSTD_trace_compress_begin) STUB_WEAK(ZSTD_trace_compress_end) STUB_WEAK(ZSTD_trace_decompress_begin) STUB_WEAK(ZSTD_trace_decompress_end) +FILE* __stderrp = stdout; # undef STUB_WEAK #endif #ifdef _WIN32 From 5e9aff65b0a85c71012d2d3b456af0fdb5f9f731 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:51:05 +0000 Subject: [PATCH 014/181] try to fix the paths --- src/common/fs/fs.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 174aed49b8..c86a8e565d 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -171,11 +171,14 @@ 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", From 01bd49818463b06fafd5d6a2ea8a95a25c186026 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 10:31:03 +0000 Subject: [PATCH 015/181] disable fastmem --- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 912a15475b..6fafbd9042 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -286,7 +286,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Curated optimizations case Settings::CpuAccuracy::Auto: config.unsafe_optimizations = true; -#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__) +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OPENORBIS__) config.fastmem_pointer = std::nullopt; config.fastmem_exclusive_access = false; #endif From c7586397d9dcc102e26ae95b44dd5249770606a7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 10:58:26 +0000 Subject: [PATCH 016/181] (likely) fixes for virtual dmem? --- src/common/host_memory.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 55c4a914e0..0ff5807d9a 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -34,15 +34,19 @@ // 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 +// PlayStation 4 +#ifndef MAP_SYSTEM +# define MAP_SYSTEM 0 #endif #endif // ^^^ POSIX ^^^ @@ -434,8 +438,8 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else 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, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) || defined(__OPENORBIS__) + void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER | MAP_SYSTEM, -1, 0); if (virtual_base != MAP_FAILED) return virtual_base; #endif @@ -534,13 +538,13 @@ public: } if (use_anon) { LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones"); - backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); + backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_SYSTEM, -1, 0)); if (fd > 0) { fd = -1; close(fd); } } else { - backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); + backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_SYSTEM, fd, 0)); } ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); From 32af670e1fa18bdbe84873b49f45da2313684bac Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 18:54:57 +0000 Subject: [PATCH 017/181] MAP_SYSTEM --- src/common/host_memory.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 0ff5807d9a..f0262dac15 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -45,8 +45,15 @@ # define MAP_ANONYMOUS MAP_ANON #endif // PlayStation 4 +// Flag needs to be undef-ed on non PS4 since it has different semantics +// on some platforms. #ifndef MAP_SYSTEM -# define MAP_SYSTEM 0 +# ifdef __OPENORBIS__ +# define MAP_SYSTEM 0x2000 +# else +# undef MAP_SYSTEM +# define MAP_SYSTEM 0 +# endif #endif #endif // ^^^ POSIX ^^^ From 1653f6e6ded512441ff4876d3af80da1c31833f9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 19:29:40 +0000 Subject: [PATCH 018/181] more memory shit --- src/common/host_memory.cpp | 12 +++++++++--- src/yuzu_cmd/yuzu.cpp | 3 +-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index f0262dac15..3181eb96cf 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -30,6 +30,8 @@ #include #include #include +#elif defined(__OPENORBIS__) +#include #endif // FreeBSD @@ -445,12 +447,16 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else static void* ChooseVirtualBase(size_t virtual_size) { -#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) || defined(__OPENORBIS__) - void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER | MAP_SYSTEM, -1, 0); +#if defined(__OPENORBIS__) + return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_SYSTEM, -1, 0); +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) + void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); if (virtual_base != MAP_FAILED) return virtual_base; -#endif return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); +#else + return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); +#endif } #endif diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 02f2aee856..f58d805f5b 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -61,8 +61,7 @@ STUB_WEAK(ZSTD_trace_decompress_begin) STUB_WEAK(ZSTD_trace_decompress_end) FILE* __stderrp = stdout; # undef STUB_WEAK -#endif -#ifdef _WIN32 +#elif defined(_WIN32) extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable // graphics From b5f6cfa818b3778b9721fe19e4d4a363f085cdc6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 20:07:43 +0000 Subject: [PATCH 019/181] force NO fastmem --- src/common/host_memory.cpp | 19 +++++++++++------- src/common/virtual_buffer.cpp | 37 +++++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 17 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 3181eb96cf..1665df2a54 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -446,16 +446,14 @@ static void* ChooseVirtualBase(size_t virtual_size) { #else -static void* ChooseVirtualBase(size_t virtual_size) { -#if defined(__OPENORBIS__) - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_SYSTEM, -1, 0); -#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__) - void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0); +static void* ChooseVirtualBase(size_t 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); if (virtual_base != MAP_FAILED) return virtual_base; - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); #else - return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); #endif } @@ -690,6 +688,12 @@ private: #endif // ^^^ POSIX ^^^ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) : backing_size(backing_size_), virtual_size(virtual_size_) { +#ifdef __OPENORBIS__ + LOG_WARNING(HW_Memory, "Platform doesn't support fastmem"); + fallback_buffer = std::make_unique>(backing_size); + backing_base = fallback_buffer->data(); + virtual_base = nullptr; +#else // Try to allocate a fastmem arena. // The implementation will fail with std::bad_alloc on errors. impl = std::make_unique(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize); @@ -700,6 +704,7 @@ HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) : backing_siz virtual_base = reinterpret_cast(Common::AlignUp(uintptr_t(virtual_base), HugePageSize)); virtual_base_offset = virtual_base - impl->virtual_base; } +#endif } HostMemory::~HostMemory() = default; diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 55ddfc243a..ef9113c557 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -6,6 +6,8 @@ #ifdef _WIN32 #include +#elif defined(__OPENORBIS__) +#include #else #include #endif @@ -17,23 +19,38 @@ namespace Common { void* AllocateMemoryPages(std::size_t size) noexcept { #ifdef _WIN32 - void* base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); + void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); + ASSERT(addr != nullptr); +#elif defined(__OPENORBIS__) + u64 align = 16384; + void *addr = nullptr; + off_t direct_mem_off; + int32_t rc; + if ((rc = sceKernelAllocateDirectMemory(0, sceKernelGetDirectMemorySize(), size, align, 3, &direct_mem_off)) < 0) { + ASSERT(false && "sceKernelAllocateDirectMemory"); + return nullptr; + } + if ((rc = sceKernelMapDirectMemory(&addr, size, 0x33, 0, direct_mem_off, align)) < 0) { + ASSERT(false && "sceKernelMapDirectMemory"); + return nullptr; + } + ASSERT(addr != nullptr); #else - void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (base == MAP_FAILED) - base = nullptr; + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + ASSERT(addr != MAP_FAILED); #endif - ASSERT(base); - return base; + return addr; } -void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept { - if (!base) +void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { + if (!addr) return; #ifdef _WIN32 - ASSERT(VirtualFree(base, 0, MEM_RELEASE)); + VirtualFree(addr, 0, MEM_RELEASE) +#elif defined(__OPENORBIS__) #else - ASSERT(munmap(base, size) == 0); + int rc = munmap(addr, size); + ASSERT(rc == 0); #endif } From f386b211869cc9a12d056213588555a8e2aab158 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 20:21:16 +0000 Subject: [PATCH 020/181] make virtual buffer become an optional --- src/common/host_memory.cpp | 2 +- src/common/host_memory.h | 1 + src/common/virtual_buffer.h | 7 ++++--- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 1665df2a54..e84bdfc033 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -690,7 +690,7 @@ private: HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) : backing_size(backing_size_), virtual_size(virtual_size_) { #ifdef __OPENORBIS__ LOG_WARNING(HW_Memory, "Platform doesn't support fastmem"); - fallback_buffer = std::make_unique>(backing_size); + fallback_buffer.emplace(backing_size); backing_base = fallback_buffer->data(); virtual_base = nullptr; #else diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 8dd30aa9de..31af3cc9f1 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include "common/common_funcs.h" #include "common/common_types.h" #include "common/virtual_buffer.h" diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 4f6e3e6e5c..74cc3a66f9 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -32,9 +32,10 @@ public: VirtualBuffer(const VirtualBuffer&) = delete; VirtualBuffer& operator=(const VirtualBuffer&) = delete; - VirtualBuffer(VirtualBuffer&& other) noexcept - : alloc_size{std::exchange(other.alloc_size, 0)}, base_ptr{std::exchange(other.base_ptr), - nullptr} {} + VirtualBuffer(VirtualBuffer&& other) noexcept { + alloc_size = std::exchange(other.alloc_size, 0); + base_ptr = std::exchange(other.base_ptr, nullptr); + } VirtualBuffer& operator=(VirtualBuffer&& other) noexcept { alloc_size = std::exchange(other.alloc_size, 0); From 130a9d44a8f33623b5e83a504ed6f3b9a0a7eb1f Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 21:29:18 +0000 Subject: [PATCH 021/181] extra ps4 defs --- src/common/host_memory.cpp | 11 ----------- src/common/virtual_buffer.cpp | 29 +++++++++++++++-------------- src/core/device_memory.h | 13 ++++--------- src/core/device_memory_manager.inc | 2 +- 4 files changed, 20 insertions(+), 35 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index e84bdfc033..8dce51763d 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -46,17 +46,6 @@ #ifndef MAP_ANONYMOUS # define MAP_ANONYMOUS MAP_ANON #endif -// PlayStation 4 -// Flag needs to be undef-ed on non PS4 since it has different semantics -// on some platforms. -#ifndef MAP_SYSTEM -# ifdef __OPENORBIS__ -# define MAP_SYSTEM 0x2000 -# else -# undef MAP_SYSTEM -# define MAP_SYSTEM 0 -# endif -#endif #endif // ^^^ POSIX ^^^ diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index ef9113c557..1d4929d233 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -14,6 +14,19 @@ #include "common/assert.h" #include "common/virtual_buffer.h" +#include "common/logging/log.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 +#endif namespace Common { @@ -22,19 +35,8 @@ void* AllocateMemoryPages(std::size_t size) noexcept { void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - u64 align = 16384; - void *addr = nullptr; - off_t direct_mem_off; - int32_t rc; - if ((rc = sceKernelAllocateDirectMemory(0, sceKernelGetDirectMemorySize(), size, align, 3, &direct_mem_off)) < 0) { - ASSERT(false && "sceKernelAllocateDirectMemory"); - return nullptr; - } - if ((rc = sceKernelMapDirectMemory(&addr, size, 0x33, 0, direct_mem_off, align)) < 0) { - ASSERT(false && "sceKernelMapDirectMemory"); - return nullptr; - } - ASSERT(addr != nullptr); + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + ASSERT(addr != MAP_FAILED); #else void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); @@ -47,7 +49,6 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { return; #ifdef _WIN32 VirtualFree(addr, 0, MEM_RELEASE) -#elif defined(__OPENORBIS__) #else int rc = munmap(addr, size); ASSERT(rc == 0); diff --git a/src/core/device_memory.h b/src/core/device_memory.h index 11bf0e3268..b96717871c 100644 --- a/src/core/device_memory.h +++ b/src/core/device_memory.h @@ -26,27 +26,22 @@ public: template Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const { - return (reinterpret_cast(ptr) - - reinterpret_cast(buffer.BackingBasePointer())) + - DramMemoryMap::Base; + return (uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer())) + DramMemoryMap::Base; } template PAddr GetRawPhysicalAddr(const T* ptr) const { - return static_cast(reinterpret_cast(ptr) - - reinterpret_cast(buffer.BackingBasePointer())); + return PAddr(uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer())); } template T* GetPointer(Common::PhysicalAddress addr) { - return reinterpret_cast(buffer.BackingBasePointer() + - (GetInteger(addr) - DramMemoryMap::Base)); + return reinterpret_cast(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base)); } template const T* GetPointer(Common::PhysicalAddress addr) const { - return reinterpret_cast(buffer.BackingBasePointer() + - (GetInteger(addr) - DramMemoryMap::Base)); + return reinterpret_cast(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base)); } template diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 08fe799174..953d32eb01 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -166,7 +166,7 @@ struct DeviceMemoryManagerAllocator { template DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memory_) - : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, + : physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}, device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb From 60fc94de8e5b4d4db92ce80bb589fe774441a0c2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 1 Dec 2025 21:35:01 +0000 Subject: [PATCH 022/181] evil haxx --- src/common/host_memory.cpp | 4 ++-- src/common/virtual_buffer.cpp | 2 -- src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp | 4 ++++ 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 8dce51763d..4691c99e54 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -538,13 +538,13 @@ public: } if (use_anon) { LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones"); - backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_SYSTEM, -1, 0)); + backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); if (fd > 0) { fd = -1; close(fd); } } else { - backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_SYSTEM, fd, 0)); + backing_base = static_cast(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)); } ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno)); diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 1d4929d233..5a05f12d47 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -6,8 +6,6 @@ #ifdef _WIN32 #include -#elif defined(__OPENORBIS__) -#include #else #include #endif diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp index 1446653916..2e6a6aa364 100644 --- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp +++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp @@ -85,7 +85,11 @@ size_t KSystemControl::Init::GetIntendedMemorySize() { switch (GetMemorySizeForInit()) { case Smc::MemorySize_4GB: default: // All invalid modes should go to 4GB. +#ifdef __OPENORBIS__ + return 2_GiB; +#else return 4_GiB; +#endif case Smc::MemorySize_6GB: return 6_GiB; case Smc::MemorySize_8GB: From 9c2ffc41632582102f1fc9036ccdcc083bf83448 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 5 Dec 2025 03:52:18 +0000 Subject: [PATCH 023/181] adapt to new master --- .patch/mbedtls/0002-aesni-fix.patch | 13 ------------- externals/cmake-modules/DetectPlatform.cmake | 2 ++ 2 files changed, 2 insertions(+), 13 deletions(-) delete mode 100644 .patch/mbedtls/0002-aesni-fix.patch diff --git a/.patch/mbedtls/0002-aesni-fix.patch b/.patch/mbedtls/0002-aesni-fix.patch deleted file mode 100644 index e9a1bce5e6..0000000000 --- a/.patch/mbedtls/0002-aesni-fix.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/library/aesni.h b/library/aesni.h -index 754c984c79..59e27afd3e 100644 ---- a/library/aesni.h -+++ b/library/aesni.h -@@ -35,7 +35,7 @@ - /* GCC-like compilers: currently, we only support intrinsics if the requisite - * target flag is enabled when building the library (e.g. `gcc -mpclmul -msse2` - * or `clang -maes -mpclmul`). */ --#if (defined(__GNUC__) || defined(__clang__)) && defined(__AES__) && defined(__PCLMUL__) -+#if (defined(__GNUC__) || defined(__clang__)) && !defined(__OPENORBIS__) - #define MBEDTLS_AESNI_HAVE_INTRINSICS - #endif - /* For 32-bit, we only support intrinsics */ diff --git a/externals/cmake-modules/DetectPlatform.cmake b/externals/cmake-modules/DetectPlatform.cmake index 6475884f1f..5d305438b9 100644 --- a/externals/cmake-modules/DetectPlatform.cmake +++ b/externals/cmake-modules/DetectPlatform.cmake @@ -17,6 +17,8 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "SunOS") set(PLATFORM_SUN ON) +elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenOrbis") + set(PLATFORM_PS4 ON) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD") set(PLATFORM_FREEBSD ON) elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") From 216e3c26217e262445b323596c3aa53524649f52 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 6 Dec 2025 20:50:36 +0000 Subject: [PATCH 024/181] fixes for mbedtls --- .patch/mbedtls/0003-openorbis.patch | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .patch/mbedtls/0003-openorbis.patch diff --git a/.patch/mbedtls/0003-openorbis.patch b/.patch/mbedtls/0003-openorbis.patch new file mode 100644 index 0000000000..46cfbd408f --- /dev/null +++ b/.patch/mbedtls/0003-openorbis.patch @@ -0,0 +1,13 @@ +diff --git a/library/entropy_poll.c b/library/entropy_poll.c +index 611768c..8950ee4 100644 +--- a/library/entropy_poll.c ++++ b/library/entropy_poll.c +@@ -118,7 +118,7 @@ static int getrandom_wrapper(void *buf, size_t buflen, unsigned int flags) + * + * Documentation: https://netbsd.gw.com/cgi-bin/man-cgi?sysctl+7 + */ +-#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM) ++#if (defined(__FreeBSD__) || defined(__NetBSD__)) && !defined(HAVE_GETRANDOM) && !defined(__OPENORBIS__) + #include + #include + #if defined(KERN_ARND) From ecbffcbbd107897880706f59d36cc78ea4518443 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 6 Dec 2025 21:31:14 +0000 Subject: [PATCH 025/181] add sce_module so it loads on real hw --- CMakeModules/OpenOrbis.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index 4e76731f6a..593c951e30 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -19,7 +19,7 @@ function(create_ps4_pkg project target content_id) 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 "eboot.bin ${sce_sys_param}" + COMMAND ${CMAKE_SYSROOT}/bin/create-gp4 -out ${target}.gp4 --content-id=${content_id} --files "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} From ffba45acdbf1717810c80012d5d5b354e99409c9 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 6 Dec 2025 21:35:32 +0000 Subject: [PATCH 026/181] license --- .ci/ps4/make-toolchain.sh | 3 +++ CMakeModules/FindSDL2.cmake | 3 +++ src/common/fs/fs.cpp | 3 +++ src/common/memory_detect.cpp | 3 +++ src/common/virtual_buffer.h | 3 +++ src/core/device_memory.h | 3 +++ src/input_common/drivers/joycon.h | 3 +++ src/input_common/helpers/joycon_driver.cpp | 3 +++ src/input_common/helpers/joycon_protocol/common_protocol.cpp | 3 +++ src/input_common/helpers/joycon_protocol/joycon_types.h | 3 +++ src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | 3 +++ 11 files changed, 33 insertions(+) mode change 100644 => 100755 .ci/ps4/make-toolchain.sh diff --git a/.ci/ps4/make-toolchain.sh b/.ci/ps4/make-toolchain.sh old mode 100644 new mode 100755 index 727596ae36..7903a79169 --- a/.ci/ps4/make-toolchain.sh +++ b/.ci/ps4/make-toolchain.sh @@ -1,5 +1,8 @@ #!/usr/local/bin/bash -ex +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # Define global vars # These flags are used everywhere, so let's reuse them. export OO_PS4_TOOLCHAIN="$PWD/prefix" diff --git a/CMakeModules/FindSDL2.cmake b/CMakeModules/FindSDL2.cmake index 2445d36ec5..a7e7225dbb 100644 --- a/CMakeModules/FindSDL2.cmake +++ b/CMakeModules/FindSDL2.cmake @@ -1,3 +1,6 @@ +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-License-Identifier: GPL-3.0-or-later + # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index c86a8e565d..1c9c3b697a 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/common/memory_detect.cpp b/src/common/memory_detect.cpp index 8bd544e3e2..b755c1a77e 100644 --- a/src/common/memory_detect.cpp +++ b/src/common/memory_detect.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 74cc3a66f9..bb012196fe 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/core/device_memory.h b/src/core/device_memory.h index b96717871c..17b585d67a 100644 --- a/src/core/device_memory.h +++ b/src/core/device_memory.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index cc07958a0f..fa8e32958d 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 10c2878cea..2b70129bfc 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 669e89f064..1c9f1a690c 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index 9be84b36a2..e7c4867ff4 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index a21eea1219..165dc5245f 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 From 4fe78fa2a7a80b1a89585c154637553a41851327 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 11 Dec 2025 05:01:48 +0000 Subject: [PATCH 027/181] swap handling --- src/common/host_memory.cpp | 1 + src/common/virtual_buffer.cpp | 28 +++++++++++++++++++++++++++- src/common/virtual_buffer.h | 1 + src/yuzu_cmd/yuzu.cpp | 16 ++++++++++++++-- 4 files changed, 43 insertions(+), 3 deletions(-) diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index 4691c99e54..ce28b36527 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -678,6 +678,7 @@ private: HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_) : backing_size(backing_size_), virtual_size(virtual_size_) { #ifdef __OPENORBIS__ + Common::InitSwap(); LOG_WARNING(HW_Memory, "Platform doesn't support fastmem"); fallback_buffer.emplace(backing_size); backing_base = fallback_buffer->data(); diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 5a05f12d47..34f9c57463 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -10,6 +10,10 @@ #include #endif +#ifdef __OPENORBIS__ +#include +#endif + #include "common/assert.h" #include "common/virtual_buffer.h" #include "common/logging/log.h" @@ -33,7 +37,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept { void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); #else void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); @@ -53,4 +57,26 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { #endif } +#ifdef __OPENORBIS__ +static struct sigaction old_sa_segv; +static void SwapHandler(int sig, siginfo_t* si, void* raw_context) { + void* a_addr = reinterpret_cast(uintptr_t(si->si_addr) & ~0xfff); + mmap(a_addr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + //mprotect(a_addr, 4096, PROT_READ | PROT_WRITE); +} + +bool InitSwap() noexcept { + struct sigaction sa; + sa.sa_handler = NULL; + sa.sa_sigaction = &SwapHandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + return sigaction(SIGSEGV, &sa, &old_sa_segv) == 0; +} +#else +bool InitSwap() noexcept { + return true; +} +#endif + } // namespace Common diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index bb012196fe..407f6eb3d3 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -12,6 +12,7 @@ namespace Common { void* AllocateMemoryPages(std::size_t size) noexcept; void FreeMemoryPages(void* base, std::size_t size) noexcept; +bool InitSwap() noexcept; template class VirtualBuffer final { diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index f58d805f5b..eb23a1f8c6 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -52,6 +52,7 @@ #endif #ifdef __OPENORBIS__ +#include # define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); } STUB_WEAK(__cxa_thread_atexit) STUB_WEAK(__assert) @@ -431,10 +432,20 @@ int main(int argc, char** argv) { [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); } - system.RegisterExitCallback([&] { + auto const exit_fn = [&] { +#ifdef __OPENORBIS__ + sceSystemServiceLoadExec("EXIT", nullptr); +#else // Just exit right away. exit(0); - }); +#endif + }; + system.RegisterExitCallback(exit_fn); + +#ifdef __linux__ + Common::Linux::StartGamemode(); +#endif + void(system.Run()); if (system.DebuggerEnabled()) { system.InitializeDebugger(); @@ -446,6 +457,7 @@ int main(int argc, char** argv) { void(system.Pause()); system.ShutdownMainProcess(); detached_tasks.WaitForAllTasks(); + exit_fn(); return 0; } From a2982c5e3b28bfe9beb26afbc84fd2cdcbaa1817 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 6 Dec 2025 23:02:09 +0000 Subject: [PATCH 028/181] fixes 4 stuff --- src/common/virtual_buffer.cpp | 10 +++++----- .../hle/kernel/board/nintendo/nx/k_system_control.cpp | 4 ---- .../src/dynarmic/backend/exception_handler_posix.cpp | 2 +- src/yuzu_cmd/CMakeLists.txt | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 34f9c57463..3e5f327245 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -37,7 +37,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept { void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); + void* addr = mmap(nullptr, size, PROT_NONE, MAP_VOID | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); #else void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); @@ -60,15 +60,15 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { #ifdef __OPENORBIS__ static struct sigaction old_sa_segv; static void SwapHandler(int sig, siginfo_t* si, void* raw_context) { - void* a_addr = reinterpret_cast(uintptr_t(si->si_addr) & ~0xfff); - mmap(a_addr, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - //mprotect(a_addr, 4096, PROT_READ | PROT_WRITE); + void* aligned_addr = reinterpret_cast(uintptr_t(si->si_addr) & ~0xfff); + void* res = mmap(aligned_addr, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + ASSERT(res != MAP_FAILED); } bool InitSwap() noexcept { struct sigaction sa; sa.sa_handler = NULL; - sa.sa_sigaction = &SwapHandler; + sa.__sa_handler.__sa_sigaction = &SwapHandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_SIGINFO | SA_RESTART; return sigaction(SIGSEGV, &sa, &old_sa_segv) == 0; diff --git a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp index 2e6a6aa364..1446653916 100644 --- a/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp +++ b/src/core/hle/kernel/board/nintendo/nx/k_system_control.cpp @@ -85,11 +85,7 @@ size_t KSystemControl::Init::GetIntendedMemorySize() { switch (GetMemorySizeForInit()) { case Smc::MemorySize_4GB: default: // All invalid modes should go to 4GB. -#ifdef __OPENORBIS__ - return 2_GiB; -#else return 4_GiB; -#endif case Smc::MemorySize_6GB: return 6_GiB; case Smc::MemorySize_8GB: diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp index 8470d77b2d..fc2d8d6284 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp @@ -60,7 +60,7 @@ public: signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); #ifdef __OPENORBIS__ - fmt::print(stderr, "no fastmem on ps4\n"); + fmt::print(stderr, "no fastmem on PS4\n"); supports_fast_mem = false; #else stack_t signal_stack{}; diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 605ef410a8..8707e8ce7e 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -35,7 +35,7 @@ target_link_libraries(yuzu-cmd PRIVATE glad) if (MSVC) target_link_libraries(yuzu-cmd PRIVATE getopt) elseif(PLATFORM_PS4) - target_link_libraries(yuzu-cmd PRIVATE SceVideoOut SceAudioOut ScePad) + target_link_libraries(yuzu-cmd PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService) endif() target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) From f55fc45646824a53c63d386eb479a377eeab4797 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 7 Dec 2025 00:39:38 +0000 Subject: [PATCH 029/181] more stupid stuff --- src/common/virtual_buffer.cpp | 71 +++++++++++++++++++++++------------ src/yuzu_cmd/yuzu.cpp | 5 +++ 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 3e5f327245..d444e81edf 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -11,7 +11,9 @@ #endif #ifdef __OPENORBIS__ +#include #include +#include #endif #include "common/assert.h" @@ -28,10 +30,54 @@ # 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__ +static struct sigaction old_sa_segv; +static boost::container::static_vector, 16> swap_regions; +static void SwapHandler(int sig, siginfo_t* si, void* raw_context) { + if (std::ranges::find_if(swap_regions, [addr = si->si_addr](auto const& e) { + return uintptr_t(addr) >= uintptr_t(e.first) && uintptr_t(addr) < uintptr_t(e.first) + e.second; + }) != swap_regions.end()) { + size_t const page_size = 4096; + size_t const page_mask = ~0xfff; + // should replace the existing mapping... ugh + void* aligned_addr = reinterpret_cast(uintptr_t(si->si_addr) & page_mask); + void* res = mmap(aligned_addr, page_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); + ASSERT(res != MAP_FAILED); + } else { + struct sigaction* retry_sa = &old_sa_segv; + if ((retry_sa->sa_flags & SA_SIGINFO) != 0) { + retry_sa->sa_sigaction(sig, si, raw_context); + } else if (retry_sa->sa_handler == SIG_DFL) { + signal(sig, SIG_DFL); + } else if (retry_sa->sa_handler == SIG_IGN) { + // ignore? + } else { + retry_sa->sa_handler(sig); + } + } +} + +bool InitSwap() noexcept { + struct sigaction sa; + sa.sa_handler = NULL; + sa.sa_sigaction = &SwapHandler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_SIGINFO | SA_RESTART; + return sigaction(SIGSEGV, &sa, &old_sa_segv) == 0; +} +#else +bool InitSwap() noexcept { + return true; +} +#endif + void* AllocateMemoryPages(std::size_t size) noexcept { #ifdef _WIN32 void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); @@ -39,6 +85,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept { #elif defined(__OPENORBIS__) void* addr = mmap(nullptr, size, PROT_NONE, MAP_VOID | MAP_PRIVATE, -1, 0); 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); @@ -50,33 +97,11 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { if (!addr) return; #ifdef _WIN32 - VirtualFree(addr, 0, MEM_RELEASE) + VirtualFree(addr, 0, MEM_RELEASE); #else int rc = munmap(addr, size); ASSERT(rc == 0); #endif } -#ifdef __OPENORBIS__ -static struct sigaction old_sa_segv; -static void SwapHandler(int sig, siginfo_t* si, void* raw_context) { - void* aligned_addr = reinterpret_cast(uintptr_t(si->si_addr) & ~0xfff); - void* res = mmap(aligned_addr, 4096, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); - ASSERT(res != MAP_FAILED); -} - -bool InitSwap() noexcept { - struct sigaction sa; - sa.sa_handler = NULL; - sa.__sa_handler.__sa_sigaction = &SwapHandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO | SA_RESTART; - return sigaction(SIGSEGV, &sa, &old_sa_segv) == 0; -} -#else -bool InitSwap() noexcept { - return true; -} -#endif - } // namespace Common diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index eb23a1f8c6..018b886130 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -236,6 +236,11 @@ int main(int argc, char** argv) { // clang-format on }; +#ifdef __OPENORBIS__ + // PS4 will use this path by default UNLESS overriden; this is so users + // can quickly launch whatever they want. + filepath = "/data/eden/games/test.nro"; +#endif while (optind < argc) { int arg = getopt_long(argc, argv, "g:fhvp::c:u:d:", long_options, &option_index); if (arg != -1) { From 72deb0d98777cc2663d1a69b5267a76287ef66f6 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 8 Dec 2025 03:08:25 +0000 Subject: [PATCH 030/181] proper memswap mechanism --- src/common/virtual_buffer.cpp | 101 ++++++++++++++++++++++-------- src/common/virtual_buffer.h | 2 +- src/qt_common/config/uisettings.h | 8 ++- src/yuzu_cmd/yuzu.cpp | 5 +- 4 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index d444e81edf..7a6e7b8352 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -14,6 +14,9 @@ #include #include #include +#include +typedef void (*SceKernelExceptionHandler)(int32_t, void*); +extern "C" int32_t sceKernelInstallExceptionHandler(int32_t signum, SceKernelExceptionHandler handler); #endif #include "common/assert.h" @@ -38,44 +41,90 @@ namespace Common { #ifdef __OPENORBIS__ -static struct sigaction old_sa_segv; + +namespace Orbis { +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, 16> swap_regions; -static void SwapHandler(int sig, siginfo_t* si, void* raw_context) { - if (std::ranges::find_if(swap_regions, [addr = si->si_addr](auto const& e) { +static void SwapHandler(int sig, void* raw_context) { + auto& mctx = ((Orbis::Ucontext*)raw_context)->uc_mcontext; + if (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; }) != swap_regions.end()) { size_t const page_size = 4096; size_t const page_mask = ~0xfff; // should replace the existing mapping... ugh - void* aligned_addr = reinterpret_cast(uintptr_t(si->si_addr) & page_mask); + void* aligned_addr = reinterpret_cast(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); ASSERT(res != MAP_FAILED); } else { - struct sigaction* retry_sa = &old_sa_segv; - if ((retry_sa->sa_flags & SA_SIGINFO) != 0) { - retry_sa->sa_sigaction(sig, si, raw_context); - } else if (retry_sa->sa_handler == SIG_DFL) { - signal(sig, SIG_DFL); - } else if (retry_sa->sa_handler == SIG_IGN) { - // ignore? - } else { - retry_sa->sa_handler(sig); - } + LOG_ERROR(HW_Memory, "fault in addr {:#x}", mctx.mc_addr); + sceSystemServiceLoadExec("EXIT", nullptr); } } - -bool InitSwap() noexcept { - struct sigaction sa; - sa.sa_handler = NULL; - sa.sa_sigaction = &SwapHandler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_SIGINFO | SA_RESTART; - return sigaction(SIGSEGV, &sa, &old_sa_segv) == 0; +void InitSwap() noexcept { + sceKernelInstallExceptionHandler(SIGSEGV, &SwapHandler); } #else -bool InitSwap() noexcept { - return true; -} +void InitSwap() noexcept {} #endif void* AllocateMemoryPages(std::size_t size) noexcept { @@ -83,7 +132,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept { void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - void* addr = mmap(nullptr, size, PROT_NONE, MAP_VOID | MAP_PRIVATE, -1, 0); + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); swap_regions.emplace_back(addr, size); #else diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index 407f6eb3d3..c25b52a51a 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -12,7 +12,7 @@ namespace Common { void* AllocateMemoryPages(std::size_t size) noexcept; void FreeMemoryPages(void* base, std::size_t size) noexcept; -bool InitSwap() noexcept; +void InitSwap() noexcept; template class VirtualBuffer final { diff --git a/src/qt_common/config/uisettings.h b/src/qt_common/config/uisettings.h index 49205c5b84..363b0dad76 100644 --- a/src/qt_common/config/uisettings.h +++ b/src/qt_common/config/uisettings.h @@ -159,7 +159,13 @@ struct Values { Setting enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui}; // logging - Setting show_console{linkage, false, "showConsole", Category::Ui}; + Setting show_console{linkage, +#ifdef __OPENORBIS__ + true, +#else + false, +#endif + "showConsole", Category::Ui}; // Screenshots Setting enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as", diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 018b886130..8271ea713d 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -53,8 +53,10 @@ #ifdef __OPENORBIS__ #include +#include +#include <__thread/support.h> # define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); } -STUB_WEAK(__cxa_thread_atexit) +void *__cxa_thread_atexit_impl = nullptr; STUB_WEAK(__assert) STUB_WEAK(ZSTD_trace_compress_begin) STUB_WEAK(ZSTD_trace_compress_end) @@ -235,7 +237,6 @@ int main(int argc, char** argv) { {0, 0, 0, 0}, // clang-format on }; - #ifdef __OPENORBIS__ // PS4 will use this path by default UNLESS overriden; this is so users // can quickly launch whatever they want. From 83e7a73451878bb6569ddd53fe72be5c7c8cfb92 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 18 Jan 2026 16:34:51 +0000 Subject: [PATCH 031/181] opengl bullshit --- src/common/settings.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/settings.h b/src/common/settings.h index 7ea4136576..b3d5e6f287 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -332,7 +332,7 @@ struct Values { // Renderer SwitchableSetting renderer_backend{linkage, -#if defined(__sun__) || defined(__managarm__) +#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__) RendererBackend::OpenGL_GLSL, #else RendererBackend::Vulkan, From 3d82c831f789564d1d65b8d4cc157780e72beb8c Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 26 Dec 2025 12:11:05 +0000 Subject: [PATCH 032/181] fix for crashes on TLS due to openorbis being W E I R D --- src/common/settings.h | 9 ++++++++- src/common/virtual_buffer.cpp | 5 +++-- src/input_common/main.cpp | 19 +++++++++++++++++++ 3 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/common/settings.h b/src/common/settings.h index b3d5e6f287..7ceb6c8e30 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -196,7 +196,14 @@ struct Values { linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false}; // Core - SwitchableSetting use_multi_core{linkage, true, "use_multi_core", Category::Core}; + SwitchableSetting use_multi_core{linkage, +#ifdef __OPENORBIS__ + // Re-enable once proper TLS support is added + false, +#else + true, +#endif + "use_multi_core", Category::Core}; SwitchableSetting memory_layout_mode{linkage, MemoryLayout::Memory_4Gb, "memory_layout_mode", diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 7a6e7b8352..a4ccd84d38 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -104,6 +104,7 @@ struct Ucontext { } static boost::container::static_vector, 16> swap_regions; +extern "C" int sceKernelRemoveExceptionHandler(s32 sig_num); static void SwapHandler(int sig, void* raw_context) { auto& mctx = ((Orbis::Ucontext*)raw_context)->uc_mcontext; if (std::ranges::find_if(swap_regions, [addr = mctx.mc_addr](auto const& e) { @@ -116,8 +117,8 @@ static void SwapHandler(int sig, void* raw_context) { void* res = mmap(aligned_addr, page_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0); ASSERT(res != MAP_FAILED); } else { - LOG_ERROR(HW_Memory, "fault in addr {:#x}", mctx.mc_addr); - sceSystemServiceLoadExec("EXIT", nullptr); + 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 { diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b04a70590a..2fc8aa4e8a 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -82,7 +82,10 @@ struct InputSubsystem::Impl { #ifdef ENABLE_LIBUSB RegisterEngine("gcpad", gcadapter); #endif +#ifndef __OPENORBIS__ + // TODO: Issue in PS4, crash for UDP_client RegisterEngine("cemuhookudp", udp_client); +#endif RegisterEngine("tas", tas_input); RegisterEngine("camera", camera); #ifdef ANDROID @@ -116,7 +119,9 @@ struct InputSubsystem::Impl { #ifdef ENABLE_LIBUSB UnregisterEngine(gcadapter); #endif +#ifndef __OPENORBIS__ UnregisterEngine(udp_client); +#endif UnregisterEngine(tas_input); UnregisterEngine(camera); #ifdef ANDROID @@ -152,8 +157,10 @@ struct InputSubsystem::Impl { auto gcadapter_devices = gcadapter->GetInputDevices(); devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); #endif +#ifndef __OPENORBIS__ auto udp_devices = udp_client->GetInputDevices(); devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); +#endif #ifdef HAVE_SDL2 auto joycon_devices = joycon->GetInputDevices(); devices.insert(devices.end(), joycon_devices.begin(), joycon_devices.end()); @@ -186,9 +193,11 @@ struct InputSubsystem::Impl { return gcadapter; } #endif +#ifndef __OPENORBIS__ if (engine == udp_client->GetEngineName()) { return udp_client; } +#endif #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { return sdl; @@ -271,9 +280,11 @@ struct InputSubsystem::Impl { return true; } #endif +#ifndef __OPENORBIS__ if (engine == udp_client->GetEngineName()) { return true; } +#endif if (engine == tas_input->GetEngineName()) { return true; } @@ -300,7 +311,9 @@ struct InputSubsystem::Impl { #ifdef ENABLE_LIBUSB gcadapter->BeginConfiguration(); #endif +#ifndef __OPENORBIS__ udp_client->BeginConfiguration(); +#endif #ifdef HAVE_SDL2 sdl->BeginConfiguration(); joycon->BeginConfiguration(); @@ -316,7 +329,9 @@ struct InputSubsystem::Impl { #ifdef ENABLE_LIBUSB gcadapter->EndConfiguration(); #endif +#ifndef __OPENORBIS__ udp_client->EndConfiguration(); +#endif #ifdef HAVE_SDL2 sdl->EndConfiguration(); joycon->EndConfiguration(); @@ -341,7 +356,9 @@ struct InputSubsystem::Impl { std::shared_ptr mouse; std::shared_ptr touch_screen; std::shared_ptr tas_input; +#ifndef __OPENORBIS__ std::shared_ptr udp_client; +#endif std::shared_ptr camera; std::shared_ptr virtual_amiibo; std::shared_ptr virtual_gamepad; @@ -470,7 +487,9 @@ bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const { } void InputSubsystem::ReloadInputDevices() { +#ifndef __OPENORBIS__ impl->udp_client.get()->ReloadSockets(); +#endif } void InputSubsystem::BeginMapping(Polling::InputType type) { From e7be657805a3afcb4d0be412234090f2d774be93 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 8 Jan 2026 13:44:03 +0000 Subject: [PATCH 033/181] fix sdl2 --- externals/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index f79f776be4..5ca90b2b23 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -173,8 +173,10 @@ if (NOT ANDROID) if (PLATFORM_PS4) set(SDL2_LIBRARY ${CMAKE_SYSROOT}/lib/libSDL2.a) set(SDL2_INCLUDE_DIR ${CMAKE_SYSROOT}/include/SDL2) + find_package(SDL2 REQUIRED) + else() + find_package(SDL2 2.26.4 REQUIRED) endif() - find_package(SDL2 REQUIRED) endif() set(BUILD_SHARED_LIBS OFF) From 346afecf217c73eb444f92b314eafc5975b8063a Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 8 Jan 2026 22:45:20 +0000 Subject: [PATCH 034/181] fix alloc failures --- src/common/virtual_buffer.cpp | 43 +++++++++++++++---- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 8 +++- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 8 +++- .../src/dynarmic/backend/x64/a32_emit_x64.h | 6 +++ .../src/dynarmic/backend/x64/a64_emit_x64.h | 5 +++ 5 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index a4ccd84d38..407bf2e157 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -13,6 +13,7 @@ #ifdef __OPENORBIS__ #include #include +#include #include #include typedef void (*SceKernelExceptionHandler)(int32_t, void*); @@ -107,15 +108,19 @@ static boost::container::static_vector, 16> swap_region extern "C" int sceKernelRemoveExceptionHandler(s32 sig_num); static void SwapHandler(int sig, void* raw_context) { auto& mctx = ((Orbis::Ucontext*)raw_context)->uc_mcontext; - if (std::ranges::find_if(swap_regions, [addr = mctx.mc_addr](auto const& e) { + 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; - }) != swap_regions.end()) { - size_t const page_size = 4096; - size_t const page_mask = ~0xfff; + }); it != swap_regions.end()) { + size_t const page_size = 4096 * 8; + size_t const page_mask = ~(page_size - 1); // should replace the existing mapping... ugh void* aligned_addr = reinterpret_cast(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); - ASSERT(res != MAP_FAILED); + if (res == MAP_FAILED) { + LOG_ERROR(HW_Memory, "FAIL mapped addr {},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); + } else { + LOG_INFO(HW_Memory, "OK mapped addr {},{} @ {}:{}", 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 @@ -128,14 +133,36 @@ void InitSwap() noexcept { void InitSwap() noexcept {} #endif +static const char *swapfile_names[] { + "/data/eden/games/swap0.bin", + "/data/eden/games/swap1.bin", + "/data/eden/games/swap2.bin", + "/data/eden/games/swap3.bin", + "/data/eden/games/swap4.bin" +}; +static size_t swapfile_count = 0; + void* AllocateMemoryPages(std::size_t size) noexcept { #ifdef _WIN32 void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); - ASSERT(addr != MAP_FAILED); - swap_regions.emplace_back(addr, size); + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (addr == MAP_FAILED) { + LOG_WARNING(HW_Memory, "failed to mmap({} bytes) using swapfile {}", size, swapfile_names[swapfile_count]); + // int fd = open(swapfile_names[swapfile_count], O_TRUNC | O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + // ASSERT(fd > 0); + // ftruncate(fd, size); + // addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + // ASSERT(addr != MAP_FAILED); + // ++swapfile_count; + + addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); + ASSERT(addr != MAP_FAILED); + swap_regions.emplace_back(addr, size); + } else { + LOG_INFO(HW_Memory, "mmap {} bytes", size); + } #else void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 6fafbd9042..a485ba9a78 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -202,7 +202,9 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { config.enable_cycle_counting = !m_uses_wall_clock; // Code cache size -#if defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) +#if defined(__OPENORBIS__) + config.code_cache_size = std::uint32_t(32_MiB); +#elif 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); @@ -304,6 +306,10 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { default: break; } +#ifdef __OPENORBIS__ + config.unsafe_optimizations = false; + config.optimizations = Dynarmic::no_optimizations; +#endif m_jit.emplace(config); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 55584d0e38..bfd531dabc 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -254,7 +254,9 @@ 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(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) +#if defined(__OPENORBIS__) + config.code_cache_size = std::uint32_t(32_MiB); +#elif 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); @@ -355,6 +357,10 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s default: break; } +#ifdef __OPENORBIS__ + config.unsafe_optimizations = false; + config.optimizations = Dynarmic::no_optimizations; +#endif m_jit.emplace(config); } diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h index 5ec78ff50e..7b794b9289 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h @@ -66,8 +66,14 @@ 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(); diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h index dd556e36ce..b0c0db5f83 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h @@ -59,8 +59,13 @@ 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(); From 071884beb333bdfe1a3b32db59c4b244143b6f22 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 8 Jan 2026 23:12:41 +0000 Subject: [PATCH 035/181] force running services on host --- .ci/ps4/build.sh | 4 +++- src/core/hle/service/services.cpp | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 0bffdca680..a4bfc97540 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -30,6 +30,8 @@ set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) set(CMAKE_SIZEOF_VOID_P 8) EOF +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[@]}" $@) @@ -51,4 +53,4 @@ cmake -S . -B build -G "Unix Makefiles" \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit -cmake --build build -t yuzu-cmd_pkg -- -j8 +cmake --build build -t yuzu-cmd_pkg -- -j$NPROC diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp index 636f54ad49..7d9372e694 100644 --- a/src/core/hle/service/services.cpp +++ b/src/core/hle/service/services.cpp @@ -73,6 +73,13 @@ Services::Services(std::shared_ptr& sm, Core::System& system system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false); +#ifdef __OPENORBIS__ + // PS4 requires us to run this on a single thread so we don't immediately die + bool const run_on_host = false; +#else + bool const run_on_host = true; +#endif + // Just a quick C++ lesson // Capturing lambdas will silently create new variables for the objects referenced via = // and create a `auto&` sorts of for `&`; with all your usual reference shenanigans. @@ -92,9 +99,12 @@ Services::Services(std::shared_ptr& sm, Core::System& system {"Loader", &LDR::LoopProcess}, {"nvservices", &Nvidia::LoopProcess}, {"bsdsocket", &Sockets::LoopProcess}, - }) - kernel.RunOnHostCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }).detach(); - kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach(); + }) { + if (run_on_host) kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach(); + else kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); }); + } + if (run_on_host) kernel.RunOnHostCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }).detach(); + else kernel.RunOnGuestCoreProcess("vi", [&, token] { VI::LoopProcess(system, token); }); // Avoid cold clones of lambdas -- succintly for (auto const& e : std::vector>{ {"sm", &SM::LoopProcess}, From 79a41e147fe5147fe71bdac640bedc72d4a22e81 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 13 Jan 2026 08:10:02 +0000 Subject: [PATCH 036/181] add fallback buffer back --- src/common/host_memory.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/host_memory.h b/src/common/host_memory.h index 31af3cc9f1..f26804b55b 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -83,6 +83,9 @@ private: u8* backing_base{}; u8* virtual_base{}; size_t virtual_base_offset{}; +#ifdef __OPENORBIS__ + std::optional> fallback_buffer; +#endif }; } // namespace Common From bdbd857d054ddabbdbd6df7afc2c57fc176407e2 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 13 Jan 2026 10:42:46 +0000 Subject: [PATCH 037/181] fibers that don't immediately crash?!!?!?!!? --- src/common/fiber.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 69eca732eb..1b201c47af 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -33,6 +33,9 @@ struct Fiber::FiberImpl { boost::context::detail::fcontext_t context{}; boost::context::detail::fcontext_t rewind_context{}; + boost::context::detail::fcontext_t context{}; + boost::context::detail::fcontext_t rewind_context{}; + std::mutex guard; std::function entry_point; std::function rewind_point; From c26c61fce2af34ea68398b21ff62ff0b999df043 Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 13 Jan 2026 10:42:57 +0000 Subject: [PATCH 038/181] fix atexit impl --- src/yuzu_cmd/yuzu.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 8271ea713d..59ff32796f 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -56,7 +56,9 @@ #include #include <__thread/support.h> # define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); } -void *__cxa_thread_atexit_impl = nullptr; +extern "C" void __cxa_thread_atexit_impl() { + //printf("atexit called"); +} STUB_WEAK(__assert) STUB_WEAK(ZSTD_trace_compress_begin) STUB_WEAK(ZSTD_trace_compress_end) From e21c2539236700dc1200e257b176f513a4badaae Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 13 Jan 2026 11:26:30 +0000 Subject: [PATCH 039/181] more inline pt2 --- .../service/ns/platform_service_manager.cpp | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/src/core/hle/service/ns/platform_service_manager.cpp b/src/core/hle/service/ns/platform_service_manager.cpp index e91e6451a8..a615037c24 100644 --- a/src/core/hle/service/ns/platform_service_manager.cpp +++ b/src/core/hle/service/ns/platform_service_manager.cpp @@ -34,10 +34,10 @@ 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}; static void DecryptSharedFont(const std::span input, std::span output, std::size_t& offset) { @@ -70,7 +70,7 @@ void EncryptSharedFont(const std::vector& input, std::vector& output, s const auto key = Common::swap32(EXPECTED_RESULT ^ EXPECTED_MAGIC); std::vector transformed_font(input.size() + 2); transformed_font[0] = Common::swap32(EXPECTED_MAGIC); - transformed_font[1] = Common::swap32(static_cast(input.size() * sizeof(u32))) ^ key; + transformed_font[1] = Common::swap32(u32(input.size() * sizeof(u32))) ^ key; std::transform(input.begin(), input.end(), transformed_font.begin() + 2, [key](u32 in) { return in ^ key; }); std::memcpy(output.data() + offset, transformed_font.data(), transformed_font.size() * sizeof(u32)); offset += transformed_font.size() * sizeof(u32); @@ -119,40 +119,30 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch // Rebuild shared fonts from data ncas or synthesize for (auto& font : SHARED_FONTS) { FileSys::VirtualFile romfs; - const auto nca = - nand->GetEntry(static_cast(font.first), FileSys::ContentRecordType::Data); - if (nca) { + if (auto const nca = nand->GetEntry(u64(font.first), FileSys::ContentRecordType::Data); nca) romfs = nca->GetRomFS(); - } - - if (!romfs) { - romfs = FileSys::SystemArchive::SynthesizeSystemArchive(static_cast(font.first)); - } - - if (!romfs) { + 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 font_data_u32(font_fp->GetSize() / sizeof(u32)); + font_fp->ReadBytes(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); - 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 font_data_u32(font_fp->GetSize() / sizeof(u32)); - font_fp->ReadBytes(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); } } From 3934b307c6643641fc30c78a98f73a78193e4e5b Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 16 Jan 2026 08:46:20 +0000 Subject: [PATCH 040/181] extra buffer precautions to not exhaust DMem, format better + perf history nerf --- src/common/fiber.cpp | 3 --- src/common/virtual_buffer.cpp | 40 +++++++++++------------------------ src/core/perf_stats.h | 4 ++++ 3 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 1b201c47af..69eca732eb 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -33,9 +33,6 @@ struct Fiber::FiberImpl { boost::context::detail::fcontext_t context{}; boost::context::detail::fcontext_t rewind_context{}; - boost::context::detail::fcontext_t context{}; - boost::context::detail::fcontext_t rewind_context{}; - std::mutex guard; std::function entry_point; std::function rewind_point; diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 407bf2e157..5b9764d236 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -111,15 +111,15 @@ static void SwapHandler(int sig, void* raw_context) { 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 = 4096 * 8; + size_t const page_size = 4096 * 4; //16K size_t const page_mask = ~(page_size - 1); // should replace the existing mapping... ugh void* aligned_addr = reinterpret_cast(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, "FAIL mapped addr {},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); + LOG_ERROR(HW_Memory, "{},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); } else { - LOG_INFO(HW_Memory, "OK mapped addr {},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); + LOG_TRACE(HW_Memory, "{},{} @ {}:{}", 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 @@ -133,36 +133,20 @@ void InitSwap() noexcept { void InitSwap() noexcept {} #endif -static const char *swapfile_names[] { - "/data/eden/games/swap0.bin", - "/data/eden/games/swap1.bin", - "/data/eden/games/swap2.bin", - "/data/eden/games/swap3.bin", - "/data/eden/games/swap4.bin" -}; -static size_t swapfile_count = 0; - void* AllocateMemoryPages(std::size_t size) noexcept { #ifdef _WIN32 void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - if (addr == MAP_FAILED) { - LOG_WARNING(HW_Memory, "failed to mmap({} bytes) using swapfile {}", size, swapfile_names[swapfile_count]); - // int fd = open(swapfile_names[swapfile_count], O_TRUNC | O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); - // ASSERT(fd > 0); - // ftruncate(fd, size); - // addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); - // ASSERT(addr != MAP_FAILED); - // ++swapfile_count; - - addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); - ASSERT(addr != MAP_FAILED); - swap_regions.emplace_back(addr, size); - } else { - LOG_INFO(HW_Memory, "mmap {} bytes", size); - } + // void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + // if (addr == MAP_FAILED) { + LOG_WARNING(HW_Memory, "Using VoidMem for {}B area", size); + void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); + ASSERT(addr != MAP_FAILED); + swap_regions.emplace_back(addr, size); + // } else { + // LOG_INFO(HW_Memory, "mmap {} bytes", size); + // } #else void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); ASSERT(addr != MAP_FAILED); diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h index dd6becc02d..92910a959f 100644 --- a/src/core/perf_stats.h +++ b/src/core/perf_stats.h @@ -60,7 +60,11 @@ 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 perf_history{}; +#else std::array perf_history{}; +#endif /// Point when the cumulative counters were reset Clock::time_point reset_point = Clock::now(); From e48c80f4179c96022d1e619f2dd8e8c3de7827eb Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 17 Jan 2026 00:52:51 +0000 Subject: [PATCH 041/181] reduce arm codeisze, force 16x4 pages again --- src/common/virtual_buffer.cpp | 36 +++++++++++++++-------- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 5b9764d236..f3a3a695e0 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -105,21 +105,24 @@ struct Ucontext { } static boost::container::static_vector, 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 = 4096 * 4; //16K + size_t const page_size = 4096 * 8; //16K size_t const page_mask = ~(page_size - 1); // should replace the existing mapping... ugh void* aligned_addr = reinterpret_cast(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, "{},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); + 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_TRACE(HW_Memory, "{},{} @ {}:{}", mctx.mc_addr, aligned_addr, it->first, it->second); + LOG_TRACE(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 @@ -138,15 +141,17 @@ void* AllocateMemoryPages(std::size_t size) noexcept { void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE); ASSERT(addr != nullptr); #elif defined(__OPENORBIS__) - // void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); - // if (addr == MAP_FAILED) { - LOG_WARNING(HW_Memory, "Using VoidMem for {}B area", size); - void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); - ASSERT(addr != MAP_FAILED); - swap_regions.emplace_back(addr, size); - // } else { - // LOG_INFO(HW_Memory, "mmap {} bytes", size); - // } + void* addr; + if (size <= 8192 * 4096) { + addr = malloc(size); + LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", size, addr); + ASSERT(addr != nullptr); + } else { + 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); @@ -159,6 +164,13 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { return; #ifdef _WIN32 VirtualFree(addr, 0, MEM_RELEASE); +#elif defined(__OPENORBIS__) + if (size <= 8192 * 4096) { + free(addr); + } else { + int rc = munmap(addr, size); + ASSERT(rc == 0); + } #else int rc = munmap(addr, size); ASSERT(rc == 0); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index a485ba9a78..f41a2be482 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -203,7 +203,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(32_MiB); + config.code_cache_size = std::uint32_t(8_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index bfd531dabc..4da2c2b211 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -255,7 +255,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(32_MiB); + config.code_cache_size = std::uint32_t(8_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else From 0f6faf6df57cb5646fdcae3cdf023812bd87c349 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 18 Jan 2026 16:33:17 +0000 Subject: [PATCH 042/181] add emutls.c --- src/yuzu_cmd/CMakeLists.txt | 4 +- src/yuzu_cmd/emutls.c | 181 ++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+), 1 deletion(-) create mode 100644 src/yuzu_cmd/emutls.c diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 8707e8ce7e..720b7449c7 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -27,6 +27,7 @@ add_executable(yuzu-cmd sdl_config.cpp sdl_config.h yuzu.cpp + emutls.c yuzu.rc ) @@ -70,5 +71,6 @@ if (NOT MSVC) endif() if (PLATFORM_PS4) - create_ps4_pkg(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) + create_ps4_eboot(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) + #create_ps4_pkg(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) endif() diff --git a/src/yuzu_cmd/emutls.c b/src/yuzu_cmd/emutls.c new file mode 100644 index 0000000000..3b0a0cc909 --- /dev/null +++ b/src/yuzu_cmd/emutls.c @@ -0,0 +1,181 @@ +/* ===---------- 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 +#include +#include +#include + +//#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]; +} From 4daa2b095e6adf264f1633c156194336cd90a8c7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 18 Jan 2026 16:33:50 +0000 Subject: [PATCH 043/181] temp fix for dpad --- .../service/ns/platform_service_manager.cpp | 9 ++++++- src/hid_core/resource_manager.cpp | 26 +++++++++---------- .../resources/abstracted_pad/abstract_pad.cpp | 2 +- .../resources/debug_pad/debug_pad.cpp | 2 +- .../resources/digitizer/digitizer.cpp | 2 +- src/hid_core/resources/keyboard/keyboard.cpp | 2 +- src/hid_core/resources/mouse/debug_mouse.cpp | 2 +- src/hid_core/resources/mouse/mouse.cpp | 2 +- src/hid_core/resources/npad/npad.cpp | 11 ++++---- .../resources/six_axis/console_six_axis.cpp | 2 +- src/hid_core/resources/six_axis/six_axis.cpp | 2 +- .../system_buttons/capture_button.cpp | 2 +- .../resources/system_buttons/home_button.cpp | 2 +- .../resources/system_buttons/sleep_button.cpp | 2 +- .../touch_screen/touch_screen_resource.cpp | 14 +++++----- 15 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/core/hle/service/ns/platform_service_manager.cpp b/src/core/hle/service/ns/platform_service_manager.cpp index a615037c24..4caea67d2c 100644 --- a/src/core/hle/service/ns/platform_service_manager.cpp +++ b/src/core/hle/service/ns/platform_service_manager.cpp @@ -40,6 +40,7 @@ constexpr u32 EXPECTED_MAGIC = 0x36f81a1e; // What we expect the encrypted bftt constexpr u64 SHARED_FONT_MEM_SIZE = 0x1100000; constexpr FontRegion EMPTY_REGION{0, 0}; +#ifndef __OPENORBIS__ static void DecryptSharedFont(const std::span input, std::span 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"); @@ -51,6 +52,7 @@ static void DecryptSharedFont(const std::span input, std::span 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& input, std::vector& output) { ASSERT_MSG(input[0] == EXPECTED_MAGIC, "Failed to derive key, unexpected magic number"); @@ -83,8 +85,10 @@ 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 shared_font_regions; +#ifndef __OPENORBIS__ /// Backing memory for the shared font data std::array shared_font; +#endif }; IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_) @@ -111,8 +115,8 @@ 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; @@ -144,6 +148,7 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch LOG_ERROR(Service_NS, "Failed to find or synthesize {:016X}! Skipping", font.first); } } +#endif } IPlatformServiceManager::~IPlatformServiceManager() = default; @@ -177,8 +182,10 @@ Result IPlatformServiceManager::GetSharedMemoryNativeHandle(OutCopyHandleshared_font.data(), impl->shared_font.size()); +#endif // FIXME: this shouldn't belong to the kernel *out_shared_memory_native_handle = &kernel.GetFontSharedMem(); diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 62fec03b1a..2e1e9e3dfc 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -201,7 +201,7 @@ Result ResourceManager::CreateAppletResource(u64 aruid) { } Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; return applet_resource->CreateAppletResource(aruid); } @@ -291,17 +291,17 @@ void ResourceManager::InitializeAHidSampler() { } Result ResourceManager::RegisterCoreAppletResource() { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; return applet_resource->RegisterCoreAppletResource(); } Result ResourceManager::UnregisterCoreAppletResource() { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; return applet_resource->UnregisterCoreAppletResource(); } Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; auto result = applet_resource->RegisterAppletResourceUserId(aruid, bool_value); if (result.IsSuccess()) { result = npad->RegisterAppletResourceUserId(aruid); @@ -310,40 +310,40 @@ Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) } void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->UnregisterAppletResourceUserId(aruid); npad->UnregisterAppletResourceUserId(aruid); // palma->UnregisterAppletResourceUserId(aruid); } Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; return applet_resource->GetSharedMemoryHandle(out_handle, aruid); } void ResourceManager::FreeAppletResourceId(u64 aruid) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->FreeAppletResourceId(aruid); npad->FreeAppletResourceId(aruid); } void ResourceManager::EnableInput(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->EnableInput(aruid, is_enabled); } void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->EnableSixAxisSensor(aruid, is_enabled); } void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->EnablePadInput(aruid, is_enabled); } void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; applet_resource->EnableTouchScreen(aruid, is_enabled); } @@ -368,7 +368,7 @@ NpadGcVibrationDevice* ResourceManager::GetGcVibrationDevice( } Result ResourceManager::SetAruidValidForVibration(u64 aruid, bool is_enabled) { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; const bool has_changed = applet_resource->SetAruidValidForVibration(aruid, is_enabled); if (has_changed) { @@ -391,7 +391,7 @@ void ResourceManager::SetForceHandheldStyleVibration(bool is_forced) { } Result ResourceManager::IsVibrationAruidActive(u64 aruid, bool& is_active) const { - std::scoped_lock lock{shared_mutex}; + //std::scoped_lock lock{shared_mutex}; is_active = applet_resource->IsVibrationAruidActive(aruid); return ResultSuccess; } diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp index d7cf2bba9b..8ba67f131e 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp @@ -273,7 +273,7 @@ void AbstractPad::Update() { interface_type = properties_handler.GetInterfaceType(); - std::scoped_lock lock{*applet_resource_holder->shared_mutex}; + //std::scoped_lock lock{*applet_resource_holder->shared_mutex}; properties_handler.UpdateAllDeviceProperties(); battery_handler.UpdateCoreBatteryState(); button_handler.UpdateCoreBatteryState(); diff --git a/src/hid_core/resources/debug_pad/debug_pad.cpp b/src/hid_core/resources/debug_pad/debug_pad.cpp index 1102dad6c9..99c35d7687 100644 --- a/src/hid_core/resources/debug_pad/debug_pad.cpp +++ b/src/hid_core/resources/debug_pad/debug_pad.cpp @@ -23,7 +23,7 @@ void DebugPad::OnInit() {} void DebugPad::OnRelease() {} void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp index 5d7dcadfe3..7bb5a43376 100644 --- a/src/hid_core/resources/digitizer/digitizer.cpp +++ b/src/hid_core/resources/digitizer/digitizer.cpp @@ -17,7 +17,7 @@ void Digitizer::OnInit() {} void Digitizer::OnRelease() {} void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/keyboard/keyboard.cpp b/src/hid_core/resources/keyboard/keyboard.cpp index 340e8a65ce..96b6ad067f 100644 --- a/src/hid_core/resources/keyboard/keyboard.cpp +++ b/src/hid_core/resources/keyboard/keyboard.cpp @@ -22,7 +22,7 @@ void Keyboard::OnInit() {} void Keyboard::OnRelease() {} void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/mouse/debug_mouse.cpp b/src/hid_core/resources/mouse/debug_mouse.cpp index 5f6f6e8e1a..313e8ef415 100644 --- a/src/hid_core/resources/mouse/debug_mouse.cpp +++ b/src/hid_core/resources/mouse/debug_mouse.cpp @@ -21,7 +21,7 @@ void DebugMouse::OnInit() {} void DebugMouse::OnRelease() {} void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/mouse/mouse.cpp b/src/hid_core/resources/mouse/mouse.cpp index 53a8938a1b..4531d8a6cd 100644 --- a/src/hid_core/resources/mouse/mouse.cpp +++ b/src/hid_core/resources/mouse/mouse.cpp @@ -21,7 +21,7 @@ void Mouse::OnInit() {} void Mouse::OnRelease() {} void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index a0f72ab298..24e9b33b30 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -74,7 +74,7 @@ Result NPad::Activate() { Result NPad::Activate(u64 aruid) { std::scoped_lock lock{mutex}; - std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; auto* data = applet_resource_holder.applet_resource->GetAruidData(aruid); const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid); @@ -393,7 +393,7 @@ void NPad::WriteEmptyEntry(NpadInternalState* npad) { } void NPad::RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id) { - std::scoped_lock lock{*applet_resource_holder.shared_mutex}; + //std::scoped_lock lock{*applet_resource_holder.shared_mutex}; auto& controller = GetControllerFromNpadIdType(aruid, npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); @@ -466,7 +466,7 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { return; } - std::scoped_lock lock{*applet_resource_holder.shared_mutex}; + //std::scoped_lock lock{*applet_resource_holder.shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); @@ -1221,7 +1221,7 @@ Result NPad::SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled) { const auto result = npad_resource.SetNpadSystemExtStateEnabled(aruid, is_enabled); if (result.IsSuccess()) { - std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; // TODO: abstracted_pad->EnableAppletToGetInput(aruid); } @@ -1339,8 +1339,7 @@ void NPad::UpdateHandheldAbstractState() { void NPad::EnableAppletToGetInput(u64 aruid) { std::scoped_lock lock{mutex}; - std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; - + //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; for (auto& abstract_pad : abstracted_pads) { abstract_pad.EnableAppletToGetInput(aruid); } diff --git a/src/hid_core/resources/six_axis/console_six_axis.cpp b/src/hid_core/resources/six_axis/console_six_axis.cpp index 4f733cc76f..85c45a2d6d 100644 --- a/src/hid_core/resources/six_axis/console_six_axis.cpp +++ b/src/hid_core/resources/six_axis/console_six_axis.cpp @@ -20,7 +20,7 @@ void ConsoleSixAxis::OnInit() {} void ConsoleSixAxis::OnRelease() {} void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index b407a5c76e..2624deaf6f 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -27,7 +27,7 @@ void SixAxis::OnInit() {} void SixAxis::OnRelease() {} void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { const auto* data = applet_resource->GetAruidDataByIndex(aruid_index); diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp index 95eb604241..411f4808a0 100644 --- a/src/hid_core/resources/system_buttons/capture_button.cpp +++ b/src/hid_core/resources/system_buttons/capture_button.cpp @@ -19,7 +19,7 @@ void CaptureButton::OnInit() {} void CaptureButton::OnRelease() {} void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp index f665338f32..cacfb221e2 100644 --- a/src/hid_core/resources/system_buttons/home_button.cpp +++ b/src/hid_core/resources/system_buttons/home_button.cpp @@ -19,7 +19,7 @@ void HomeButton::OnInit() {} void HomeButton::OnRelease() {} void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp index 1596632465..6649594ef0 100644 --- a/src/hid_core/resources/system_buttons/sleep_button.cpp +++ b/src/hid_core/resources/system_buttons/sleep_button.cpp @@ -17,7 +17,7 @@ void SleepButton::OnInit() {} void SleepButton::OnRelease() {} void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - std::scoped_lock shared_lock{*shared_mutex}; + //std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp index 5d45f861c6..dd0b71f448 100644 --- a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp +++ b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp @@ -34,7 +34,7 @@ Result TouchResource::ActivateTouch() { } if (global_ref_counter == 0) { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; const auto result = touch_driver->StartTouchSensor(); if (result.IsError()) { @@ -60,7 +60,7 @@ Result TouchResource::ActivateTouch() { } Result TouchResource::ActivateTouch(u64 aruid) { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -121,7 +121,7 @@ Result TouchResource::ActivateGesture() { } Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -300,7 +300,7 @@ void TouchResource::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 } Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -321,7 +321,7 @@ Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) Result TouchResource::SetTouchScreenConfiguration( const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid) { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -341,7 +341,7 @@ Result TouchResource::SetTouchScreenConfiguration( Result TouchResource::GetTouchScreenConfiguration( Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const { - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -518,7 +518,7 @@ void TouchResource::OnTouchUpdate(s64 timestamp) { gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count, timestamp); - std::scoped_lock lock{*shared_mutex}; + //std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); From e1394a09ebd14b92c0071cae4d5871e3c0fc1495 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 18 Jan 2026 16:45:05 +0000 Subject: [PATCH 044/181] fix eboot --- CMakeModules/OpenOrbis.cmake | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index 593c951e30..f5701ecc62 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -1,6 +1,19 @@ # SPDX-FileCopyrightText: Copyright 2025 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 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) From f792712a668f9eef54a063191b81637faff18fab Mon Sep 17 00:00:00 2001 From: lizzie Date: Tue, 20 Jan 2026 00:17:46 +0000 Subject: [PATCH 045/181] bs fix --- src/hid_core/resource_manager.cpp | 3 +++ src/hid_core/resources/debug_pad/debug_pad.cpp | 3 +++ src/hid_core/resources/digitizer/digitizer.cpp | 3 +++ src/hid_core/resources/keyboard/keyboard.cpp | 3 +++ src/hid_core/resources/mouse/debug_mouse.cpp | 3 +++ src/hid_core/resources/mouse/mouse.cpp | 3 +++ src/hid_core/resources/six_axis/console_six_axis.cpp | 3 +++ src/hid_core/resources/six_axis/six_axis.cpp | 3 +++ src/hid_core/resources/system_buttons/capture_button.cpp | 3 +++ src/hid_core/resources/system_buttons/home_button.cpp | 3 +++ src/hid_core/resources/system_buttons/sleep_button.cpp | 3 +++ 11 files changed, 33 insertions(+) diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 2e1e9e3dfc..4fa1e9a6ae 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/hid_core/resources/debug_pad/debug_pad.cpp b/src/hid_core/resources/debug_pad/debug_pad.cpp index 99c35d7687..89e5ce86e6 100644 --- a/src/hid_core/resources/debug_pad/debug_pad.cpp +++ b/src/hid_core/resources/debug_pad/debug_pad.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp index 7bb5a43376..4df72fd6d0 100644 --- a/src/hid_core/resources/digitizer/digitizer.cpp +++ b/src/hid_core/resources/digitizer/digitizer.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/keyboard/keyboard.cpp b/src/hid_core/resources/keyboard/keyboard.cpp index 96b6ad067f..d82062b3c6 100644 --- a/src/hid_core/resources/keyboard/keyboard.cpp +++ b/src/hid_core/resources/keyboard/keyboard.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/mouse/debug_mouse.cpp b/src/hid_core/resources/mouse/debug_mouse.cpp index 313e8ef415..28657ee2e4 100644 --- a/src/hid_core/resources/mouse/debug_mouse.cpp +++ b/src/hid_core/resources/mouse/debug_mouse.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/mouse/mouse.cpp b/src/hid_core/resources/mouse/mouse.cpp index 4531d8a6cd..05eff94093 100644 --- a/src/hid_core/resources/mouse/mouse.cpp +++ b/src/hid_core/resources/mouse/mouse.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/six_axis/console_six_axis.cpp b/src/hid_core/resources/six_axis/console_six_axis.cpp index 85c45a2d6d..f68f639bf4 100644 --- a/src/hid_core/resources/six_axis/console_six_axis.cpp +++ b/src/hid_core/resources/six_axis/console_six_axis.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index 2624deaf6f..9eb06be856 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp index 411f4808a0..d8afa70a58 100644 --- a/src/hid_core/resources/system_buttons/capture_button.cpp +++ b/src/hid_core/resources/system_buttons/capture_button.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp index cacfb221e2..084cc6ccec 100644 --- a/src/hid_core/resources/system_buttons/home_button.cpp +++ b/src/hid_core/resources/system_buttons/home_button.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp index 6649594ef0..5c5cc05ed5 100644 --- a/src/hid_core/resources/system_buttons/sleep_button.cpp +++ b/src/hid_core/resources/system_buttons/sleep_button.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 From 9dbd0bb57b3c0c69a0c2986e80d14d26b07fa53f Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 22 Jan 2026 19:13:56 +0000 Subject: [PATCH 046/181] restore stupid lock, make ps4sup library --- CMakeModules/OpenOrbis.cmake | 6 ++--- externals/CMakeLists.txt | 3 +++ {src/yuzu_cmd => externals/ps4sup}/emutls.c | 0 externals/ps4sup/stub.cpp | 18 +++++++++++++ src/core/perf_stats.h | 3 +++ src/dynarmic/tests/CMakeLists.txt | 6 +++++ src/hid_core/resource_manager.cpp | 26 +++++++++---------- .../resources/abstracted_pad/abstract_pad.cpp | 2 +- .../resources/debug_pad/debug_pad.cpp | 2 +- .../resources/digitizer/digitizer.cpp | 2 +- src/hid_core/resources/keyboard/keyboard.cpp | 2 +- src/hid_core/resources/mouse/debug_mouse.cpp | 2 +- src/hid_core/resources/mouse/mouse.cpp | 2 +- src/hid_core/resources/npad/npad.cpp | 10 +++---- .../resources/six_axis/console_six_axis.cpp | 2 +- src/hid_core/resources/six_axis/six_axis.cpp | 2 +- .../system_buttons/capture_button.cpp | 2 +- .../resources/system_buttons/home_button.cpp | 2 +- .../resources/system_buttons/sleep_button.cpp | 2 +- .../touch_screen/touch_screen_resource.cpp | 14 +++++----- src/yuzu_cmd/CMakeLists.txt | 6 ++--- 21 files changed, 71 insertions(+), 43 deletions(-) rename {src/yuzu_cmd => externals/ps4sup}/emutls.c (100%) create mode 100644 externals/ps4sup/stub.cpp diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index f5701ecc62..af2e862a7e 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -6,7 +6,7 @@ function(create_ps4_eboot project target content_id) 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 eboot.bin + COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot ${target}_eboot.bin VERBATIM WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS ${project} @@ -19,7 +19,7 @@ function(create_ps4_pkg project target content_id) 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 eboot.bin + 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 @@ -32,7 +32,7 @@ function(create_ps4_pkg project target content_id) 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 "eboot.bin ${sce_sys_param} sce_module/libc.prx sce_module/libSceFios2.prx" + 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} diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 5ca90b2b23..428fc6f9f1 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -265,6 +265,9 @@ target_include_directories(tz PUBLIC ./tz) add_library(bc_decoder bc_decoder/bc_decoder.cpp) target_include_directories(bc_decoder PUBLIC ./bc_decoder) +add_library(ps4sup ps4sup/emutls.c ps4sup/stub.cpp) +target_include_directories(ps4sup PUBLIC ./ps4sup) + if (NOT TARGET RenderDoc::API) add_library(renderdoc INTERFACE) target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc) diff --git a/src/yuzu_cmd/emutls.c b/externals/ps4sup/emutls.c similarity index 100% rename from src/yuzu_cmd/emutls.c rename to externals/ps4sup/emutls.c diff --git a/externals/ps4sup/stub.cpp b/externals/ps4sup/stub.cpp new file mode 100644 index 0000000000..f422477f20 --- /dev/null +++ b/externals/ps4sup/stub.cpp @@ -0,0 +1,18 @@ +#include + +#define STUB_WEAK(name) \ + extern "C" void name() { \ + printf("called " #name); \ + asm volatile("ud2"); \ + } + +extern "C" void __cxa_thread_atexit_impl() {} + +STUB_WEAK(__assert) +STUB_WEAK(ZSTD_trace_compress_begin) +STUB_WEAK(ZSTD_trace_compress_end) +STUB_WEAK(ZSTD_trace_decompress_begin) +STUB_WEAK(ZSTD_trace_decompress_end) +FILE* __stderrp = stdout; + +#undef STUB_WEAK diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h index 92910a959f..6fbf05671a 100644 --- a/src/core/perf_stats.h +++ b/src/core/perf_stats.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2025 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 diff --git a/src/dynarmic/tests/CMakeLists.txt b/src/dynarmic/tests/CMakeLists.txt index 395181efe3..a31d88dfd0 100644 --- a/src/dynarmic/tests/CMakeLists.txt +++ b/src/dynarmic/tests/CMakeLists.txt @@ -134,3 +134,9 @@ target_compile_options(dynarmic_tests PRIVATE ${DYNARMIC_CXX_FLAGS}) target_compile_definitions(dynarmic_tests PRIVATE FMT_USE_USER_DEFINED_LITERALS=1) add_test(NAME dynarmic_tests COMMAND dynarmic_tests --durations yes) + +if (PLATFORM_PS4) + target_link_libraries(dynarmic_tests PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService) + target_link_libraries(dynarmic_tests PRIVATE ps4sup) + create_ps4_eboot(dynarmic_tests dynarmic_tests IV0000-BREW00090_00-DYNARMICTS000000) +endif() diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index 4fa1e9a6ae..cecadd84ed 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -204,7 +204,7 @@ Result ResourceManager::CreateAppletResource(u64 aruid) { } Result ResourceManager::CreateAppletResourceImpl(u64 aruid) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; return applet_resource->CreateAppletResource(aruid); } @@ -294,17 +294,17 @@ void ResourceManager::InitializeAHidSampler() { } Result ResourceManager::RegisterCoreAppletResource() { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; return applet_resource->RegisterCoreAppletResource(); } Result ResourceManager::UnregisterCoreAppletResource() { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; return applet_resource->UnregisterCoreAppletResource(); } Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; auto result = applet_resource->RegisterAppletResourceUserId(aruid, bool_value); if (result.IsSuccess()) { result = npad->RegisterAppletResourceUserId(aruid); @@ -313,40 +313,40 @@ Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) } void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->UnregisterAppletResourceUserId(aruid); npad->UnregisterAppletResourceUserId(aruid); // palma->UnregisterAppletResourceUserId(aruid); } Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; return applet_resource->GetSharedMemoryHandle(out_handle, aruid); } void ResourceManager::FreeAppletResourceId(u64 aruid) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->FreeAppletResourceId(aruid); npad->FreeAppletResourceId(aruid); } void ResourceManager::EnableInput(u64 aruid, bool is_enabled) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->EnableInput(aruid, is_enabled); } void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->EnableSixAxisSensor(aruid, is_enabled); } void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->EnablePadInput(aruid, is_enabled); } void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; applet_resource->EnableTouchScreen(aruid, is_enabled); } @@ -371,7 +371,7 @@ NpadGcVibrationDevice* ResourceManager::GetGcVibrationDevice( } Result ResourceManager::SetAruidValidForVibration(u64 aruid, bool is_enabled) { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; const bool has_changed = applet_resource->SetAruidValidForVibration(aruid, is_enabled); if (has_changed) { @@ -394,7 +394,7 @@ void ResourceManager::SetForceHandheldStyleVibration(bool is_forced) { } Result ResourceManager::IsVibrationAruidActive(u64 aruid, bool& is_active) const { - //std::scoped_lock lock{shared_mutex}; + std::scoped_lock lock{shared_mutex}; is_active = applet_resource->IsVibrationAruidActive(aruid); return ResultSuccess; } diff --git a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp index 8ba67f131e..d7cf2bba9b 100644 --- a/src/hid_core/resources/abstracted_pad/abstract_pad.cpp +++ b/src/hid_core/resources/abstracted_pad/abstract_pad.cpp @@ -273,7 +273,7 @@ void AbstractPad::Update() { interface_type = properties_handler.GetInterfaceType(); - //std::scoped_lock lock{*applet_resource_holder->shared_mutex}; + std::scoped_lock lock{*applet_resource_holder->shared_mutex}; properties_handler.UpdateAllDeviceProperties(); battery_handler.UpdateCoreBatteryState(); button_handler.UpdateCoreBatteryState(); diff --git a/src/hid_core/resources/debug_pad/debug_pad.cpp b/src/hid_core/resources/debug_pad/debug_pad.cpp index 89e5ce86e6..831bbfdd22 100644 --- a/src/hid_core/resources/debug_pad/debug_pad.cpp +++ b/src/hid_core/resources/debug_pad/debug_pad.cpp @@ -26,7 +26,7 @@ void DebugPad::OnInit() {} void DebugPad::OnRelease() {} void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp index 4df72fd6d0..87ba872dd7 100644 --- a/src/hid_core/resources/digitizer/digitizer.cpp +++ b/src/hid_core/resources/digitizer/digitizer.cpp @@ -20,7 +20,7 @@ void Digitizer::OnInit() {} void Digitizer::OnRelease() {} void Digitizer::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/keyboard/keyboard.cpp b/src/hid_core/resources/keyboard/keyboard.cpp index d82062b3c6..5627d4b4aa 100644 --- a/src/hid_core/resources/keyboard/keyboard.cpp +++ b/src/hid_core/resources/keyboard/keyboard.cpp @@ -25,7 +25,7 @@ void Keyboard::OnInit() {} void Keyboard::OnRelease() {} void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/mouse/debug_mouse.cpp b/src/hid_core/resources/mouse/debug_mouse.cpp index 28657ee2e4..eede909eea 100644 --- a/src/hid_core/resources/mouse/debug_mouse.cpp +++ b/src/hid_core/resources/mouse/debug_mouse.cpp @@ -24,7 +24,7 @@ void DebugMouse::OnInit() {} void DebugMouse::OnRelease() {} void DebugMouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/mouse/mouse.cpp b/src/hid_core/resources/mouse/mouse.cpp index 05eff94093..8b9c6a7523 100644 --- a/src/hid_core/resources/mouse/mouse.cpp +++ b/src/hid_core/resources/mouse/mouse.cpp @@ -24,7 +24,7 @@ void Mouse::OnInit() {} void Mouse::OnRelease() {} void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 24e9b33b30..b4df235d7c 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -74,7 +74,7 @@ Result NPad::Activate() { Result NPad::Activate(u64 aruid) { std::scoped_lock lock{mutex}; - //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; auto* data = applet_resource_holder.applet_resource->GetAruidData(aruid); const auto aruid_index = applet_resource_holder.applet_resource->GetIndexFromAruid(aruid); @@ -393,7 +393,7 @@ void NPad::WriteEmptyEntry(NpadInternalState* npad) { } void NPad::RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id) { - //std::scoped_lock lock{*applet_resource_holder.shared_mutex}; + std::scoped_lock lock{*applet_resource_holder.shared_mutex}; auto& controller = GetControllerFromNpadIdType(aruid, npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); @@ -466,7 +466,7 @@ void NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { return; } - //std::scoped_lock lock{*applet_resource_holder.shared_mutex}; + std::scoped_lock lock{*applet_resource_holder.shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { const auto* data = applet_resource_holder.applet_resource->GetAruidDataByIndex(aruid_index); @@ -1221,7 +1221,7 @@ Result NPad::SetNpadSystemExtStateEnabled(u64 aruid, bool is_enabled) { const auto result = npad_resource.SetNpadSystemExtStateEnabled(aruid, is_enabled); if (result.IsSuccess()) { - //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; // TODO: abstracted_pad->EnableAppletToGetInput(aruid); } @@ -1339,7 +1339,7 @@ void NPad::UpdateHandheldAbstractState() { void NPad::EnableAppletToGetInput(u64 aruid) { std::scoped_lock lock{mutex}; - //std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; for (auto& abstract_pad : abstracted_pads) { abstract_pad.EnableAppletToGetInput(aruid); } diff --git a/src/hid_core/resources/six_axis/console_six_axis.cpp b/src/hid_core/resources/six_axis/console_six_axis.cpp index f68f639bf4..62d3b4ddc2 100644 --- a/src/hid_core/resources/six_axis/console_six_axis.cpp +++ b/src/hid_core/resources/six_axis/console_six_axis.cpp @@ -23,7 +23,7 @@ void ConsoleSixAxis::OnInit() {} void ConsoleSixAxis::OnRelease() {} void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index 9eb06be856..f2aadd9ed1 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -30,7 +30,7 @@ void SixAxis::OnInit() {} void SixAxis::OnRelease() {} void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; ++aruid_index) { const auto* data = applet_resource->GetAruidDataByIndex(aruid_index); diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp index d8afa70a58..79d75f423a 100644 --- a/src/hid_core/resources/system_buttons/capture_button.cpp +++ b/src/hid_core/resources/system_buttons/capture_button.cpp @@ -22,7 +22,7 @@ void CaptureButton::OnInit() {} void CaptureButton::OnRelease() {} void CaptureButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp index 084cc6ccec..2edb4557c1 100644 --- a/src/hid_core/resources/system_buttons/home_button.cpp +++ b/src/hid_core/resources/system_buttons/home_button.cpp @@ -22,7 +22,7 @@ void HomeButton::OnInit() {} void HomeButton::OnRelease() {} void HomeButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp index 5c5cc05ed5..3ae5883bfa 100644 --- a/src/hid_core/resources/system_buttons/sleep_button.cpp +++ b/src/hid_core/resources/system_buttons/sleep_button.cpp @@ -20,7 +20,7 @@ void SleepButton::OnInit() {} void SleepButton::OnRelease() {} void SleepButton::OnUpdate(const Core::Timing::CoreTiming& core_timing) { - //std::scoped_lock shared_lock{*shared_mutex}; + std::scoped_lock shared_lock{*shared_mutex}; const u64 aruid = applet_resource->GetActiveAruid(); auto* data = applet_resource->GetAruidData(aruid); diff --git a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp index dd0b71f448..5d45f861c6 100644 --- a/src/hid_core/resources/touch_screen/touch_screen_resource.cpp +++ b/src/hid_core/resources/touch_screen/touch_screen_resource.cpp @@ -34,7 +34,7 @@ Result TouchResource::ActivateTouch() { } if (global_ref_counter == 0) { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; const auto result = touch_driver->StartTouchSensor(); if (result.IsError()) { @@ -60,7 +60,7 @@ Result TouchResource::ActivateTouch() { } Result TouchResource::ActivateTouch(u64 aruid) { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -121,7 +121,7 @@ Result TouchResource::ActivateGesture() { } Result TouchResource::ActivateGesture(u64 aruid, u32 basic_gesture_id) { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -300,7 +300,7 @@ void TouchResource::SetTouchScreenMagnification(f32 point1_x, f32 point1_y, f32 } Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -321,7 +321,7 @@ Result TouchResource::SetTouchScreenResolution(u32 width, u32 height, u64 aruid) Result TouchResource::SetTouchScreenConfiguration( const Core::HID::TouchScreenConfigurationForNx& touch_configuration, u64 aruid) { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -341,7 +341,7 @@ Result TouchResource::SetTouchScreenConfiguration( Result TouchResource::GetTouchScreenConfiguration( Core::HID::TouchScreenConfigurationForNx& out_touch_configuration, u64 aruid) const { - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); @@ -518,7 +518,7 @@ void TouchResource::OnTouchUpdate(s64 timestamp) { gesture_handler.SetTouchState(current_touch_state.states, current_touch_state.entry_count, timestamp); - //std::scoped_lock lock{*shared_mutex}; + std::scoped_lock lock{*shared_mutex}; for (std::size_t aruid_index = 0; aruid_index < AruidIndexMax; aruid_index++) { const auto* applet_data = applet_resource->GetAruidDataByIndex(aruid_index); diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index 720b7449c7..bc1a94082b 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -27,7 +27,6 @@ add_executable(yuzu-cmd sdl_config.cpp sdl_config.h yuzu.cpp - emutls.c yuzu.rc ) @@ -35,8 +34,6 @@ target_link_libraries(yuzu-cmd PRIVATE common core input_common frontend_common target_link_libraries(yuzu-cmd PRIVATE glad) if (MSVC) target_link_libraries(yuzu-cmd PRIVATE getopt) -elseif(PLATFORM_PS4) - target_link_libraries(yuzu-cmd PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService) endif() target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) @@ -71,6 +68,7 @@ if (NOT MSVC) endif() if (PLATFORM_PS4) + target_link_libraries(yuzu-cmd PRIVATE SceVideoOut SceAudioOut ScePad SceSystemService) + target_link_libraries(yuzu-cmd PRIVATE ps4sup) create_ps4_eboot(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) - #create_ps4_pkg(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000) endif() From 1df6ed512f5f847fbe786ed9ef2762a5fdb46e59 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 22 Jan 2026 19:16:13 +0000 Subject: [PATCH 047/181] update loicense --- .ci/ps4/build.sh | 1 + .ci/ps4/make-toolchain.sh | 2 +- CMakeModules/FindSDL2.cmake | 2 +- CMakeModules/OpenOrbis.cmake | 2 +- externals/ffmpeg/CMakeLists.txt | 2 +- externals/ps4sup/stub.cpp | 3 +++ src/common/fs/fs.cpp | 2 +- src/common/host_memory.h | 2 +- src/common/memory_detect.cpp | 2 +- src/common/virtual_buffer.cpp | 2 +- src/common/virtual_buffer.h | 2 +- src/core/device_memory.h | 2 +- src/core/hle/service/services.cpp | 2 +- src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp | 2 +- src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h | 2 +- src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h | 2 +- src/dynarmic/src/dynarmic/common/context.h | 2 +- src/hid_core/resource_manager.cpp | 2 +- src/hid_core/resources/debug_pad/debug_pad.cpp | 2 +- src/hid_core/resources/digitizer/digitizer.cpp | 2 +- src/hid_core/resources/keyboard/keyboard.cpp | 2 +- src/hid_core/resources/mouse/debug_mouse.cpp | 2 +- src/hid_core/resources/mouse/mouse.cpp | 2 +- src/hid_core/resources/npad/npad.cpp | 2 +- src/hid_core/resources/six_axis/console_six_axis.cpp | 2 +- src/hid_core/resources/six_axis/six_axis.cpp | 2 +- src/hid_core/resources/system_buttons/capture_button.cpp | 2 +- src/hid_core/resources/system_buttons/home_button.cpp | 2 +- src/hid_core/resources/system_buttons/sleep_button.cpp | 2 +- src/input_common/drivers/joycon.cpp | 2 +- src/input_common/drivers/joycon.h | 2 +- src/input_common/helpers/joycon_driver.cpp | 2 +- src/input_common/helpers/joycon_protocol/common_protocol.cpp | 2 +- src/input_common/helpers/joycon_protocol/joycon_types.h | 2 +- src/input_common/main.cpp | 2 +- src/video_core/vulkan_common/vulkan.h | 2 +- src/yuzu_cmd/CMakeLists.txt | 2 +- src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp | 2 +- src/yuzu_cmd/yuzu.cpp | 2 +- 39 files changed, 41 insertions(+), 37 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index a4bfc97540..2bba7e185d 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -52,5 +52,6 @@ cmake -S . -B build -G "Unix Makefiles" \ -DCPMUTIL_FORCE_BUNDLED=ON \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ + -DDYNARMIC_TESTS=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit cmake --build build -t yuzu-cmd_pkg -- -j$NPROC diff --git a/.ci/ps4/make-toolchain.sh b/.ci/ps4/make-toolchain.sh index 7903a79169..2b4f994b79 100755 --- a/.ci/ps4/make-toolchain.sh +++ b/.ci/ps4/make-toolchain.sh @@ -1,6 +1,6 @@ #!/usr/local/bin/bash -ex -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # Define global vars diff --git a/CMakeModules/FindSDL2.cmake b/CMakeModules/FindSDL2.cmake index a7e7225dbb..b039031b4a 100644 --- a/CMakeModules/FindSDL2.cmake +++ b/CMakeModules/FindSDL2.cmake @@ -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 # Distributed under the OSI-approved BSD 3-Clause License. See accompanying diff --git a/CMakeModules/OpenOrbis.cmake b/CMakeModules/OpenOrbis.cmake index af2e862a7e..6babccdd6d 100644 --- a/CMakeModules/OpenOrbis.cmake +++ b/CMakeModules/OpenOrbis.cmake @@ -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 function(create_ps4_eboot project target content_id) diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index ab9d2d04cf..45697d23f4 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -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: 2021 yuzu Emulator Project diff --git a/externals/ps4sup/stub.cpp b/externals/ps4sup/stub.cpp index f422477f20..89dc983599 100644 --- a/externals/ps4sup/stub.cpp +++ b/externals/ps4sup/stub.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + #include #define STUB_WEAK(name) \ diff --git a/src/common/fs/fs.cpp b/src/common/fs/fs.cpp index 1c9c3b697a..bdeeae911d 100644 --- a/src/common/fs/fs.cpp +++ b/src/common/fs/fs.cpp @@ -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 2021 yuzu Emulator Project diff --git a/src/common/host_memory.h b/src/common/host_memory.h index f26804b55b..6095230154 100644 --- a/src/common/host_memory.h +++ b/src/common/host_memory.h @@ -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 2019 yuzu Emulator Project diff --git a/src/common/memory_detect.cpp b/src/common/memory_detect.cpp index b755c1a77e..5063b28b2d 100644 --- a/src/common/memory_detect.cpp +++ b/src/common/memory_detect.cpp @@ -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 2020 yuzu Emulator Project diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index f3a3a695e0..48f26ec298 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -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 2020 yuzu Emulator Project diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h index c25b52a51a..8094df14c7 100644 --- a/src/common/virtual_buffer.h +++ b/src/common/virtual_buffer.h @@ -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 2020 yuzu Emulator Project diff --git a/src/core/device_memory.h b/src/core/device_memory.h index 17b585d67a..29d2ff7a2b 100644 --- a/src/core/device_memory.h +++ b/src/core/device_memory.h @@ -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 2020 yuzu Emulator Project diff --git a/src/core/hle/service/services.cpp b/src/core/hle/service/services.cpp index 7d9372e694..4d04b0fdf0 100644 --- a/src/core/hle/service/services.cpp +++ b/src/core/hle/service/services.cpp @@ -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 2024 yuzu Emulator Project diff --git a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp index fc2d8d6284..cf56288a82 100644 --- a/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp +++ b/src/dynarmic/src/dynarmic/backend/exception_handler_posix.cpp @@ -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 /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h index 7b794b9289..6f5a97a903 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/a32_emit_x64.h @@ -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 /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h index b0c0db5f83..e8f46d0580 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h +++ b/src/dynarmic/src/dynarmic/backend/x64/a64_emit_x64.h @@ -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 /* This file is part of the dynarmic project. diff --git a/src/dynarmic/src/dynarmic/common/context.h b/src/dynarmic/src/dynarmic/common/context.h index 48c72cb5c9..cce77a6a97 100644 --- a/src/dynarmic/src/dynarmic/common/context.h +++ b/src/dynarmic/src/dynarmic/common/context.h @@ -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 #pragma once diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index cecadd84ed..d0cb098d85 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project diff --git a/src/hid_core/resources/debug_pad/debug_pad.cpp b/src/hid_core/resources/debug_pad/debug_pad.cpp index 831bbfdd22..bab49b55f8 100644 --- a/src/hid_core/resources/debug_pad/debug_pad.cpp +++ b/src/hid_core/resources/debug_pad/debug_pad.cpp @@ -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 diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp index 87ba872dd7..e158e55e6c 100644 --- a/src/hid_core/resources/digitizer/digitizer.cpp +++ b/src/hid_core/resources/digitizer/digitizer.cpp @@ -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 diff --git a/src/hid_core/resources/keyboard/keyboard.cpp b/src/hid_core/resources/keyboard/keyboard.cpp index 5627d4b4aa..4e929e1260 100644 --- a/src/hid_core/resources/keyboard/keyboard.cpp +++ b/src/hid_core/resources/keyboard/keyboard.cpp @@ -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 diff --git a/src/hid_core/resources/mouse/debug_mouse.cpp b/src/hid_core/resources/mouse/debug_mouse.cpp index eede909eea..e56c1de656 100644 --- a/src/hid_core/resources/mouse/debug_mouse.cpp +++ b/src/hid_core/resources/mouse/debug_mouse.cpp @@ -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 diff --git a/src/hid_core/resources/mouse/mouse.cpp b/src/hid_core/resources/mouse/mouse.cpp index 8b9c6a7523..80de81efe4 100644 --- a/src/hid_core/resources/mouse/mouse.cpp +++ b/src/hid_core/resources/mouse/mouse.cpp @@ -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 diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index b4df235d7c..63ffd90d04 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -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 diff --git a/src/hid_core/resources/six_axis/console_six_axis.cpp b/src/hid_core/resources/six_axis/console_six_axis.cpp index 62d3b4ddc2..c58c14e453 100644 --- a/src/hid_core/resources/six_axis/console_six_axis.cpp +++ b/src/hid_core/resources/six_axis/console_six_axis.cpp @@ -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 2021 yuzu Emulator Project diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index f2aadd9ed1..abda9e8e09 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp index 79d75f423a..417d384e6b 100644 --- a/src/hid_core/resources/system_buttons/capture_button.cpp +++ b/src/hid_core/resources/system_buttons/capture_button.cpp @@ -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 diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp index 2edb4557c1..b0131767af 100644 --- a/src/hid_core/resources/system_buttons/home_button.cpp +++ b/src/hid_core/resources/system_buttons/home_button.cpp @@ -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 diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp index 3ae5883bfa..21e78e2d44 100644 --- a/src/hid_core/resources/system_buttons/sleep_button.cpp +++ b/src/hid_core/resources/system_buttons/sleep_button.cpp @@ -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 diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index 83a57f96a7..ea95693a1c 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -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 2022 yuzu Emulator Project diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index fa8e32958d..189fe1b846 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -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 2022 yuzu Emulator Project diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 2b70129bfc..867ecb7465 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -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 2022 yuzu Emulator Project diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index 1c9f1a690c..fc6281938a 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -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 2022 yuzu Emulator Project diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index e7c4867ff4..acac627097 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -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 2022 yuzu Emulator Project diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 2fc8aa4e8a..3cbc6bbed5 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -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: 2017 Citra Emulator Project diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 9cbabd1ca7..d4d47e1222 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index bc1a94082b..c153e9fb78 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -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: 2018 yuzu Emulator Project diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp index 165dc5245f..735ef3c327 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_vk.cpp @@ -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 diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 59ff32796f..baba1c1d0a 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -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 Citra Emulator Project From b444a96082ca8bc8ca5d13aee8d3c74528afd49f Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 22 Jan 2026 19:20:22 +0000 Subject: [PATCH 048/181] ps4 icon --- dist/icon_variations/ps4.svg | 215 +++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 dist/icon_variations/ps4.svg diff --git a/dist/icon_variations/ps4.svg b/dist/icon_variations/ps4.svg new file mode 100644 index 0000000000..0ee32c660c --- /dev/null +++ b/dist/icon_variations/ps4.svg @@ -0,0 +1,215 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 370cfe40e1e22d31c61f9a27ff0c8a64a31fd573 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 06:48:07 +0000 Subject: [PATCH 049/181] stub add proper iostream init --- .ci/ps4/build.sh | 2 +- externals/ps4sup/stub.cpp | 4 ++++ src/core/perf_stats.h | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 2bba7e185d..b792529ec7 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -1,6 +1,6 @@ #!/usr/local/bin/bash -ex -# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later [ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake" diff --git a/externals/ps4sup/stub.cpp b/externals/ps4sup/stub.cpp index 89dc983599..bee5613486 100644 --- a/externals/ps4sup/stub.cpp +++ b/externals/ps4sup/stub.cpp @@ -19,3 +19,7 @@ STUB_WEAK(ZSTD_trace_decompress_end) FILE* __stderrp = stdout; #undef STUB_WEAK + +// THIS MAKES STD::COUT AND SUCH WORK :) +#include +std::ios_base::Init init; diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h index 6fbf05671a..fef83b2d4b 100644 --- a/src/core/perf_stats.h +++ b/src/core/perf_stats.h @@ -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: 2017 Citra Emulator Project From aead210ffa27c348ee011b997c413f3cf10cbd64 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 18:34:49 +0000 Subject: [PATCH 050/181] revert input system to main --- src/hid_core/resource_manager.cpp | 3 - .../resources/debug_pad/debug_pad.cpp | 3 - .../resources/digitizer/digitizer.cpp | 3 - src/hid_core/resources/keyboard/keyboard.cpp | 3 - src/hid_core/resources/mouse/debug_mouse.cpp | 3 - src/hid_core/resources/mouse/mouse.cpp | 3 - .../resources/six_axis/console_six_axis.cpp | 3 - src/hid_core/resources/six_axis/six_axis.cpp | 3 - .../system_buttons/capture_button.cpp | 3 - .../resources/system_buttons/home_button.cpp | 3 - .../resources/system_buttons/sleep_button.cpp | 3 - src/input_common/drivers/joycon.cpp | 15 ++--- src/input_common/drivers/joycon.h | 12 +--- src/input_common/drivers/sdl_driver.cpp | 41 ++++++-------- src/input_common/helpers/joycon_driver.cpp | 38 +++++-------- .../joycon_protocol/common_protocol.cpp | 55 +++++++++---------- .../helpers/joycon_protocol/joycon_types.h | 12 +--- 17 files changed, 64 insertions(+), 142 deletions(-) diff --git a/src/hid_core/resource_manager.cpp b/src/hid_core/resource_manager.cpp index d0cb098d85..62fec03b1a 100644 --- a/src/hid_core/resource_manager.cpp +++ b/src/hid_core/resource_manager.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/hid_core/resources/debug_pad/debug_pad.cpp b/src/hid_core/resources/debug_pad/debug_pad.cpp index bab49b55f8..1102dad6c9 100644 --- a/src/hid_core/resources/debug_pad/debug_pad.cpp +++ b/src/hid_core/resources/debug_pad/debug_pad.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/digitizer/digitizer.cpp b/src/hid_core/resources/digitizer/digitizer.cpp index e158e55e6c..5d7dcadfe3 100644 --- a/src/hid_core/resources/digitizer/digitizer.cpp +++ b/src/hid_core/resources/digitizer/digitizer.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/keyboard/keyboard.cpp b/src/hid_core/resources/keyboard/keyboard.cpp index 4e929e1260..340e8a65ce 100644 --- a/src/hid_core/resources/keyboard/keyboard.cpp +++ b/src/hid_core/resources/keyboard/keyboard.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/mouse/debug_mouse.cpp b/src/hid_core/resources/mouse/debug_mouse.cpp index e56c1de656..5f6f6e8e1a 100644 --- a/src/hid_core/resources/mouse/debug_mouse.cpp +++ b/src/hid_core/resources/mouse/debug_mouse.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/mouse/mouse.cpp b/src/hid_core/resources/mouse/mouse.cpp index 80de81efe4..53a8938a1b 100644 --- a/src/hid_core/resources/mouse/mouse.cpp +++ b/src/hid_core/resources/mouse/mouse.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/six_axis/console_six_axis.cpp b/src/hid_core/resources/six_axis/console_six_axis.cpp index c58c14e453..4f733cc76f 100644 --- a/src/hid_core/resources/six_axis/console_six_axis.cpp +++ b/src/hid_core/resources/six_axis/console_six_axis.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later diff --git a/src/hid_core/resources/six_axis/six_axis.cpp b/src/hid_core/resources/six_axis/six_axis.cpp index abda9e8e09..b407a5c76e 100644 --- a/src/hid_core/resources/six_axis/six_axis.cpp +++ b/src/hid_core/resources/six_axis/six_axis.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later diff --git a/src/hid_core/resources/system_buttons/capture_button.cpp b/src/hid_core/resources/system_buttons/capture_button.cpp index 417d384e6b..95eb604241 100644 --- a/src/hid_core/resources/system_buttons/capture_button.cpp +++ b/src/hid_core/resources/system_buttons/capture_button.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/system_buttons/home_button.cpp b/src/hid_core/resources/system_buttons/home_button.cpp index b0131767af..f665338f32 100644 --- a/src/hid_core/resources/system_buttons/home_button.cpp +++ b/src/hid_core/resources/system_buttons/home_button.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/hid_core/resources/system_buttons/sleep_button.cpp b/src/hid_core/resources/system_buttons/sleep_button.cpp index 21e78e2d44..1596632465 100644 --- a/src/hid_core/resources/system_buttons/sleep_button.cpp +++ b/src/hid_core/resources/system_buttons/sleep_button.cpp @@ -1,6 +1,3 @@ -// 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 diff --git a/src/input_common/drivers/joycon.cpp b/src/input_common/drivers/joycon.cpp index ea95693a1c..fb2d75e384 100644 --- a/src/input_common/drivers/joycon.cpp +++ b/src/input_common/drivers/joycon.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project @@ -23,14 +23,12 @@ Joycons::Joycons(const std::string& input_engine_) : InputEngine(input_engine_) return; } LOG_INFO(Input, "Joycon driver Initialization started"); -#if SDL_VERSION_ATLEAST(2, 26, 4) - int const res = SDL_hid_init(); - if (res == 0) { + const int init_res = SDL_hid_init(); + if (init_res == 0) { Setup(); } else { - LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", res); + LOG_ERROR(Input, "Hidapi could not be initialized. failed with error = {}", init_res); } -#endif } Joycons::~Joycons() { @@ -57,9 +55,7 @@ void Joycons::Reset() { } device->Stop(); } -#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_exit(); -#endif } void Joycons::Setup() { @@ -84,9 +80,9 @@ void Joycons::Setup() { } void Joycons::ScanThread(std::stop_token stop_token) { -#if SDL_VERSION_ATLEAST(2, 26, 4) constexpr u16 nintendo_vendor_id = 0x057e; Common::SetCurrentThreadName("JoyconScanThread"); + do { SDL_hid_device_info* devs = SDL_hid_enumerate(nintendo_vendor_id, 0x0); SDL_hid_device_info* cur_dev = devs; @@ -102,7 +98,6 @@ void Joycons::ScanThread(std::stop_token stop_token) { SDL_hid_free_enumeration(devs); } while (Common::StoppableTimedWait(stop_token, std::chrono::seconds{5})); -#endif } bool Joycons::IsDeviceNew(SDL_hid_device_info* device_info) const { diff --git a/src/input_common/drivers/joycon.h b/src/input_common/drivers/joycon.h index 189fe1b846..112e970e15 100644 --- a/src/input_common/drivers/joycon.h +++ b/src/input_common/drivers/joycon.h @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -9,14 +6,7 @@ #include #include #include - -#include -#if SDL_VERSION_ATLEAST(2, 26, 4) -# include -#else -struct SDL_hid_device; -struct SDL_hid_device_info; -#endif +#include #include "input_common/input_engine.h" diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 93f7d5c1ea..6fc2f47f6a 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -42,7 +42,6 @@ public: } void EnableMotion() { -#if SDL_VERSION_ATLEAST(2, 26, 4) if (!sdl_controller) { return; } @@ -59,14 +58,12 @@ public: if (has_gyro) { SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); } -#endif } bool HasMotion() const { return has_gyro || has_accel; } -#if SDL_VERSION_ATLEAST(2, 26, 4) bool UpdateMotion(SDL_ControllerSensorEvent event) { constexpr float gravity_constant = 9.80665f; std::scoped_lock lock{mutex}; @@ -108,7 +105,6 @@ public: motion.delta_timestamp = time_difference * 1000; return true; } -#endif const BasicMotion& GetMotion() const { return motion; @@ -153,15 +149,13 @@ public: } bool HasHDRumble() const { -#if SDL_VERSION_ATLEAST(2, 26, 4) if (sdl_controller) { - auto const type = SDL_GameControllerGetType(sdl_controller.get()); + const auto type = SDL_GameControllerGetType(sdl_controller.get()); return (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) || (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT) || (type == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT) || (type == SDL_CONTROLLER_TYPE_PS5); } -#endif return false; } @@ -258,21 +252,26 @@ public: } std::string GetControllerName() const { -#if SDL_VERSION_ATLEAST(2, 26, 4) if (sdl_controller) { switch (SDL_GameControllerGetType(sdl_controller.get())) { - case SDL_CONTROLLER_TYPE_XBOX360: return "Xbox 360 Controller"; - case SDL_CONTROLLER_TYPE_XBOXONE: return "Xbox One Controller"; - case SDL_CONTROLLER_TYPE_PS3: return "DualShock 3 Controller"; - case SDL_CONTROLLER_TYPE_PS4: return "DualShock 4 Controller"; - case SDL_CONTROLLER_TYPE_PS5: return "DualSense Controller"; + case SDL_CONTROLLER_TYPE_XBOX360: + return "Xbox 360 Controller"; + case SDL_CONTROLLER_TYPE_XBOXONE: + return "Xbox One Controller"; + case SDL_CONTROLLER_TYPE_PS3: + return "DualShock 3 Controller"; + case SDL_CONTROLLER_TYPE_PS4: + return "DualShock 4 Controller"; + case SDL_CONTROLLER_TYPE_PS5: + return "DualSense Controller"; default: - if (auto const name = SDL_GameControllerName(sdl_controller.get()); name) - return name; break; } + const auto name = SDL_GameControllerName(sdl_controller.get()); + if (name) { + return name; + } } -#endif if (sdl_joystick) { const auto name = SDL_JoystickName(sdl_joystick.get()); @@ -457,7 +456,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } -#if SDL_VERSION_ATLEAST(2, 26, 4) case SDL_CONTROLLERSENSORUPDATE: { if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { if (joystick->UpdateMotion(event.csensor)) { @@ -474,7 +472,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { } break; } -#endif case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); @@ -492,7 +489,6 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { -#if SDL_VERSION_ATLEAST(2, 26, 4) // Set our application name. Currently passed to DBus by SDL and visible to the user through // their desktop environment. SDL_SetHint(SDL_HINT_APP_NAME, "Eden"); @@ -533,7 +529,6 @@ SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_en // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native // driver on Linux. SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); -#endif // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; @@ -838,7 +833,6 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( auto slr_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; auto srr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; -#if SDL_VERSION_ATLEAST(2, 26, 4) if (joystick->IsJoyconLeft()) { sll_button = SDL_CONTROLLER_BUTTON_PADDLE2; srl_button = SDL_CONTROLLER_BUTTON_PADDLE4; @@ -847,7 +841,6 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( slr_button = SDL_CONTROLLER_BUTTON_PADDLE3; srr_button = SDL_CONTROLLER_BUTTON_PADDLE1; } -#endif return { std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, @@ -869,9 +862,7 @@ ButtonBindings SDLDriver::GetDefaultButtonBinding( {Settings::NativeButton::SLRight, slr_button}, {Settings::NativeButton::SRRight, srr_button}, {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, -#if SDL_VERSION_ATLEAST(2, 26, 4) {Settings::NativeButton::Screenshot, SDL_CONTROLLER_BUTTON_MISC1}, -#endif }; } diff --git a/src/input_common/helpers/joycon_driver.cpp b/src/input_common/helpers/joycon_driver.cpp index 867ecb7465..0dd1c958a2 100644 --- a/src/input_common/helpers/joycon_driver.cpp +++ b/src/input_common/helpers/joycon_driver.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -41,8 +38,8 @@ Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_inf return Common::Input::DriverResult::UnsupportedControllerType; } -#if SDL_VERSION_ATLEAST(2, 26, 4) - hidapi_handle->handle = SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); + hidapi_handle->handle = + SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); std::memcpy(&handle_serial_number, device_info->serial_number, 15); if (!hidapi_handle->handle) { LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", @@ -51,9 +48,6 @@ Common::Input::DriverResult JoyconDriver::RequestDeviceAccess(SDL_hid_device_inf } SDL_hid_set_nonblocking(hidapi_handle->handle, 1); return Common::Input::DriverResult::Success; -#else - return Common::Input::DriverResult::UnsupportedControllerType; -#endif } Common::Input::DriverResult JoyconDriver::InitializeDevice() { @@ -144,6 +138,8 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { Common::SetCurrentThreadName("JoyconInput"); input_thread_running = true; + // Max update rate is 5ms, ensure we are always able to read a bit faster + constexpr int ThreadDelay = 3; std::vector buffer(MaxBufferSize); while (!stop_token.stop_requested()) { @@ -154,17 +150,14 @@ void JoyconDriver::InputThread(std::stop_token stop_token) { continue; } -#if SDL_VERSION_ATLEAST(2, 26, 4) - // Max update rate is 5ms, ensure we are always able to read a bit faster - int constexpr thread_delay = 3; // By disabling the input thread we can ensure custom commands will succeed as no package is // skipped if (!disable_input_thread) { - status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), thread_delay); + status = SDL_hid_read_timeout(hidapi_handle->handle, buffer.data(), buffer.size(), + ThreadDelay); } else { - std::this_thread::sleep_for(std::chrono::milliseconds(thread_delay)); + std::this_thread::sleep_for(std::chrono::milliseconds(ThreadDelay)); } -#endif if (IsPayloadCorrect(status, buffer)) { OnNewData(buffer); @@ -697,18 +690,19 @@ void JoyconDriver::SetCallbacks(const JoyconCallbacks& callbacks) { joycon_poller->SetCallbacks(callbacks); } -Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, ControllerType& controller_type) { -#if SDL_VERSION_ATLEAST(2, 26, 4) +Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* device_info, + ControllerType& controller_type) { static constexpr std::array, 6> supported_devices{ std::pair{0x2006, ControllerType::Left}, {0x2007, ControllerType::Right}, {0x2009, ControllerType::Pro}, }; - constexpr u16 nintendo_vendor_id = 0x057e; + controller_type = ControllerType::None; - if (device_info->vendor_id != nintendo_vendor_id) + if (device_info->vendor_id != nintendo_vendor_id) { return Common::Input::DriverResult::UnsupportedControllerType; + } for (const auto& [product_id, type] : supported_devices) { if (device_info->product_id == static_cast(product_id)) { @@ -716,20 +710,16 @@ Common::Input::DriverResult JoyconDriver::GetDeviceType(SDL_hid_device_info* dev return Common::Input::DriverResult::Success; } } -#endif return Common::Input::DriverResult::UnsupportedControllerType; } -Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, SerialNumber& serial_number) { -#if SDL_VERSION_ATLEAST(2, 26, 4) +Common::Input::DriverResult JoyconDriver::GetSerialNumber(SDL_hid_device_info* device_info, + SerialNumber& serial_number) { if (device_info->serial_number == nullptr) { return Common::Input::DriverResult::Unknown; } std::memcpy(&serial_number, device_info->serial_number, 15); return Common::Input::DriverResult::Success; -#else - return Common::Input::DriverResult::Unknown; -#endif } } // namespace InputCommon::Joycon diff --git a/src/input_common/helpers/joycon_protocol/common_protocol.cpp b/src/input_common/helpers/joycon_protocol/common_protocol.cpp index fc6281938a..a6eecf9802 100644 --- a/src/input_common/helpers/joycon_protocol/common_protocol.cpp +++ b/src/input_common/helpers/joycon_protocol/common_protocol.cpp @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -18,15 +15,11 @@ u8 JoyconCommonProtocol::GetCounter() { } void JoyconCommonProtocol::SetBlocking() { -#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_set_nonblocking(hidapi_handle->handle, 0); -#endif } void JoyconCommonProtocol::SetNonBlocking() { -#if SDL_VERSION_ATLEAST(2, 26, 4) SDL_hid_set_nonblocking(hidapi_handle->handle, 1); -#endif } Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& controller_type) { @@ -42,23 +35,26 @@ Common::Input::DriverResult JoyconCommonProtocol::GetDeviceType(ControllerType& return result; } -Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess(SDL_hid_device_info* device_info) { +Common::Input::DriverResult JoyconCommonProtocol::CheckDeviceAccess( + SDL_hid_device_info* device_info) { ControllerType controller_type{ControllerType::None}; const auto result = GetDeviceType(controller_type); + if (result != Common::Input::DriverResult::Success || controller_type == ControllerType::None) { return Common::Input::DriverResult::UnsupportedControllerType; } -#if SDL_VERSION_ATLEAST(2, 26, 4) - hidapi_handle->handle = SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); + + hidapi_handle->handle = + SDL_hid_open(device_info->vendor_id, device_info->product_id, device_info->serial_number); + if (!hidapi_handle->handle) { - LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", device_info->vendor_id, device_info->product_id); + LOG_ERROR(Input, "Yuzu can't gain access to this device: ID {:04X}:{:04X}.", + device_info->vendor_id, device_info->product_id); return Common::Input::DriverResult::HandleInUse; } + SetNonBlocking(); return Common::Input::DriverResult::Success; -#else - return Common::Input::DriverResult::UnsupportedControllerType; -#endif } Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode report_mode) { @@ -67,21 +63,21 @@ Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode repor } Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span buffer) { -#if SDL_VERSION_ATLEAST(2, 26, 4) - auto const result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); - if (result == -1) + const auto result = SDL_hid_write(hidapi_handle->handle, buffer.data(), buffer.size()); + + if (result == -1) { return Common::Input::DriverResult::ErrorWritingData; + } + return Common::Input::DriverResult::Success; -#else - return Common::Input::DriverResult::ErrorWritingData; -#endif } -Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubCommand sc, SubCommandResponse& output) { -#if SDL_VERSION_ATLEAST(2, 26, 4) +Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse( + SubCommand sc, SubCommandResponse& output) { constexpr int timeout_mili = 66; constexpr int MaxTries = 10; int tries = 0; + do { int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast(&output), sizeof(SubCommandResponse), timeout_mili); @@ -92,8 +88,9 @@ Common::Input::DriverResult JoyconCommonProtocol::GetSubCommandResponse(SubComma if (tries++ > MaxTries) { return Common::Input::DriverResult::Timeout; } - } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && output.sub_command != sc); -#endif + } while (output.input_report.report_mode != ReportMode::SUBCMD_REPLY && + output.sub_command != sc); + return Common::Input::DriverResult::Success; } @@ -221,11 +218,12 @@ Common::Input::DriverResult JoyconCommonProtocol::ConfigureMCU(const MCUConfig& return result; } -Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, MCUCommandResponse& output) { -#if SDL_VERSION_ATLEAST(2, 26, 4) +Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode report_mode, + MCUCommandResponse& output) { constexpr int TimeoutMili = 200; constexpr int MaxTries = 9; int tries = 0; + do { int result = SDL_hid_read_timeout(hidapi_handle->handle, reinterpret_cast(&output), sizeof(MCUCommandResponse), TimeoutMili); @@ -236,8 +234,9 @@ Common::Input::DriverResult JoyconCommonProtocol::GetMCUDataResponse(ReportMode if (tries++ > MaxTries) { return Common::Input::DriverResult::Timeout; } - } while (output.input_report.report_mode != report_mode || output.mcu_report == MCUReport::EmptyAwaitingCmd); -#endif + } while (output.input_report.report_mode != report_mode || + output.mcu_report == MCUReport::EmptyAwaitingCmd); + return Common::Input::DriverResult::Success; } diff --git a/src/input_common/helpers/joycon_protocol/joycon_types.h b/src/input_common/helpers/joycon_protocol/joycon_types.h index acac627097..792f124e14 100644 --- a/src/input_common/helpers/joycon_protocol/joycon_types.h +++ b/src/input_common/helpers/joycon_protocol/joycon_types.h @@ -1,6 +1,3 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -// SPDX-License-Identifier: GPL-3.0-or-later - // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -13,14 +10,7 @@ #include #include - -#include -#if SDL_VERSION_ATLEAST(2, 26, 4) -# include -#else -struct SDL_hid_device; -struct SDL_hid_device_info; -#endif +#include #include "common/bit_field.h" #include "common/common_funcs.h" From f2b979be70fbdacaf6164220a0e36d9e86e43192 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 19:03:04 +0000 Subject: [PATCH 051/181] Use updated SDL2 --- .ci/ps4/build.sh | 1 + externals/CMakeLists.txt | 6 ++++++ externals/cpmfile.json | 8 ++++++++ 3 files changed, 15 insertions(+) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index b792529ec7..b167b65ef5 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -53,5 +53,6 @@ cmake -S . -B build -G "Unix Makefiles" \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ -DDYNARMIC_TESTS=ON \ + -DYUZU_USE_EXTERNAL_SDL2=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit cmake --build build -t yuzu-cmd_pkg -- -j$NPROC diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 428fc6f9f1..f3a8e54450 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -159,6 +159,12 @@ if (NOT ANDROID) if ("${YUZU_SYSTEM_PROFILE}" STREQUAL "steamdeck") set(SDL_PIPEWIRE OFF) # build errors out with this on AddJsonPackage("sdl2_steamdeck") + elseif (PLATFORM_PS4) + set(PS4 ON) + set(ORBIS ON) + AddJsonPackage("sdl2_ps4") + unset(ORBIS) + unset(PS4) else() AddJsonPackage("sdl2_generic") endif() diff --git a/externals/cpmfile.json b/externals/cpmfile.json index e08d1cc055..e39e47cb3a 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -189,6 +189,14 @@ "bundled": true, "skip_updates": "true" }, + "sdl2_ps4": { + "package": "SDL2", + "repo": "xinitrcn1/SDL", + "sha": "f577141fc4", + "key": "ps4", + "bundled": true, + "skip_updates": true + }, "moltenvk": { "repo": "V380-Ori/Ryujinx.MoltenVK", "tag": "v%VERSION%-ryujinx", From edbabcf6bdced08d572fc362e24551ca805c05f7 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 20:02:12 +0000 Subject: [PATCH 052/181] make a bit more mergeable --- .ci/ps4/build.sh | 1 + src/audio_core/CMakeLists.txt | 2 +- src/hid_core/resources/npad/npad.cpp | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index b167b65ef5..2fdcd01c68 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -52,6 +52,7 @@ cmake -S . -B build -G "Unix Makefiles" \ -DCPMUTIL_FORCE_BUNDLED=ON \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ + -DDYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=OFF \ -DDYNARMIC_TESTS=ON \ -DYUZU_USE_EXTERNAL_SDL2=ON \ "${EXTRA_CMAKE_FLAGS[@]}" || exit diff --git a/src/audio_core/CMakeLists.txt b/src/audio_core/CMakeLists.txt index 4f8cc7d1ca..22106fc74d 100644 --- a/src/audio_core/CMakeLists.txt +++ b/src/audio_core/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2018 yuzu Emulator Project diff --git a/src/hid_core/resources/npad/npad.cpp b/src/hid_core/resources/npad/npad.cpp index 63ffd90d04..a0f72ab298 100644 --- a/src/hid_core/resources/npad/npad.cpp +++ b/src/hid_core/resources/npad/npad.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project @@ -1340,6 +1340,7 @@ void NPad::UpdateHandheldAbstractState() { void NPad::EnableAppletToGetInput(u64 aruid) { std::scoped_lock lock{mutex}; std::scoped_lock shared_lock{*applet_resource_holder.shared_mutex}; + for (auto& abstract_pad : abstracted_pads) { abstract_pad.EnableAppletToGetInput(aruid); } From b98b364d63c325e96a7170ec0787876c36749036 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 20:37:16 +0000 Subject: [PATCH 053/181] fix2 --- CMakeModules/FindSDL2.cmake | 391 ------------------------------------ externals/CMakeLists.txt | 8 +- 2 files changed, 1 insertion(+), 398 deletions(-) delete mode 100644 CMakeModules/FindSDL2.cmake diff --git a/CMakeModules/FindSDL2.cmake b/CMakeModules/FindSDL2.cmake deleted file mode 100644 index b039031b4a..0000000000 --- a/CMakeModules/FindSDL2.cmake +++ /dev/null @@ -1,391 +0,0 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project -# SPDX-License-Identifier: GPL-3.0-or-later - -# Distributed under the OSI-approved BSD 3-Clause License. See accompanying -# file Copyright.txt or https://cmake.org/licensing for details. - -# Copyright 2019 Amine Ben Hassouna -# Copyright 2000-2019 Kitware, Inc. and Contributors -# 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 Kitware, Inc. nor the names of 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 -# HOLDER 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. - -#[=======================================================================[.rst: -FindSDL2 --------- - -Locate SDL2 library - -This module defines the following 'IMPORTED' targets: - -:: - - SDL2::Core - The SDL2 library, if found. - Libraries should link to SDL2::Core - - SDL2::Main - The SDL2main library, if found. - Applications should link to SDL2::Main instead of SDL2::Core - - - -This module will set the following variables in your project: - -:: - - SDL2_LIBRARIES, the name of the library to link against - SDL2_INCLUDE_DIRS, where to find SDL.h - SDL2_FOUND, if false, do not try to link to SDL2 - SDL2MAIN_FOUND, if false, do not try to link to SDL2main - SDL2_VERSION_STRING, human-readable string containing the version of SDL2 - - - -This module responds to the following cache variables: - -:: - - SDL2_PATH - Set a custom SDL2 Library path (default: empty) - - SDL2_NO_DEFAULT_PATH - Disable search SDL2 Library in default path. - If SDL2_PATH (default: ON) - Else (default: OFF) - - SDL2_INCLUDE_DIR - SDL2 headers path. - - SDL2_LIBRARY - SDL2 Library (.dll, .so, .a, etc) path. - - SDL2MAIN_LIBRAY - SDL2main Library (.a) path. - - SDL2_BUILDING_LIBRARY - This flag is useful only when linking to SDL2_LIBRARIES insead of - SDL2::Main. It is required only when building a library that links to - SDL2_LIBRARIES, because only applications need main() (No need to also - link to SDL2main). - If this flag is defined, then no SDL2main will be added to SDL2_LIBRARIES - and no SDL2::Main target will be created. - - -Don't forget to include SDLmain.h and SDLmain.m in your project for the -OS X framework based version. (Other versions link to -lSDL2main which -this module will try to find on your behalf.) Also for OS X, this -module will automatically add the -framework Cocoa on your behalf. - - -Additional Note: If you see an empty SDL2_LIBRARY in your project -configuration, it means CMake did not find your SDL2 library -(SDL2.dll, libsdl2.so, SDL2.framework, etc). Set SDL2_LIBRARY to point -to your SDL2 library, and configure again. Similarly, if you see an -empty SDL2MAIN_LIBRARY, you should set this value as appropriate. These -values are used to generate the final SDL2_LIBRARIES variable and the -SDL2::Core and SDL2::Main targets, but when these values are unset, -SDL2_LIBRARIES, SDL2::Core and SDL2::Main does not get created. - - -$SDL2DIR is an environment variable that would correspond to the -./configure --prefix=$SDL2DIR used in building SDL2. l.e.galup 9-20-02 - - - -Created by Amine Ben Hassouna: - Adapt FindSDL.cmake to SDL2 (FindSDL2.cmake). - Add cache variables for more flexibility: - SDL2_PATH, SDL2_NO_DEFAULT_PATH (for details, see doc above). - Mark 'Threads' as a required dependency for non-OSX systems. - Modernize the FindSDL2.cmake module by creating specific targets: - SDL2::Core and SDL2::Main (for details, see doc above). - - -Original FindSDL.cmake module: - Modified by Eric Wing. Added code to assist with automated building - by using environmental variables and providing a more - controlled/consistent search behavior. Added new modifications to - recognize OS X frameworks and additional Unix paths (FreeBSD, etc). - Also corrected the header search path to follow "proper" SDL - guidelines. Added a search for SDLmain which is needed by some - platforms. Added a search for threads which is needed by some - platforms. Added needed compile switches for MinGW. - -On OSX, this will prefer the Framework version (if found) over others. -People will have to manually change the cache value of SDL2_LIBRARY to -override this selection or set the SDL2_PATH variable or the CMake -environment CMAKE_INCLUDE_PATH to modify the search paths. - -Note that the header path has changed from SDL/SDL.h to just SDL.h -This needed to change because "proper" SDL convention is #include -"SDL.h", not . This is done for portability reasons -because not all systems place things in SDL/ (see FreeBSD). -#]=======================================================================] - -# Define options for searching SDL2 Library in a custom path - -set(SDL2_PATH "" CACHE STRING "Custom SDL2 Library path") - -set(_SDL2_NO_DEFAULT_PATH OFF) -if(SDL2_PATH) - set(_SDL2_NO_DEFAULT_PATH ON) -endif() - -set(SDL2_NO_DEFAULT_PATH ${_SDL2_NO_DEFAULT_PATH} - CACHE BOOL "Disable search SDL2 Library in default path") -unset(_SDL2_NO_DEFAULT_PATH) - -set(SDL2_NO_DEFAULT_PATH_CMD) -if(SDL2_NO_DEFAULT_PATH) - set(SDL2_NO_DEFAULT_PATH_CMD NO_DEFAULT_PATH) -endif() - -# Search for the SDL2 include directory -find_path(SDL2_INCLUDE_DIR SDL.h - HINTS - ENV SDL2DIR - ${SDL2_NO_DEFAULT_PATH_CMD} - PATH_SUFFIXES SDL2 - # path suffixes to search inside ENV{SDL2DIR} - include/SDL2 include - PATHS ${SDL2_PATH} - DOC "Where the SDL2 headers can be found" -) - -set(SDL2_INCLUDE_DIRS "${SDL2_INCLUDE_DIR}") - -if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(VC_LIB_PATH_SUFFIX lib/x64) -else() - set(VC_LIB_PATH_SUFFIX lib/x86) -endif() - -# SDL-2.0 is the name used by FreeBSD ports... -# don't confuse it for the version number. -find_library(SDL2_LIBRARY - NAMES SDL2 SDL-2.0 - HINTS - ENV SDL2DIR - ${SDL2_NO_DEFAULT_PATH_CMD} - PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} - PATHS ${SDL2_PATH} - DOC "Where the SDL2 Library can be found" -) - -set(SDL2_LIBRARIES "${SDL2_LIBRARY}") - -if(NOT SDL2_BUILDING_LIBRARY) - if(NOT SDL2_INCLUDE_DIR MATCHES ".framework") - # Non-OS X framework versions expect you to also dynamically link to - # SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms - # seem to provide SDL2main for compatibility even though they don't - # necessarily need it. - - if(SDL2_PATH) - set(SDL2MAIN_LIBRARY_PATHS "${SDL2_PATH}") - endif() - - if(NOT SDL2_NO_DEFAULT_PATH) - set(SDL2MAIN_LIBRARY_PATHS - /sw - /opt/local - /opt/csw - /opt - "${SDL2MAIN_LIBRARY_PATHS}" - ) - endif() - - find_library(SDL2MAIN_LIBRARY - NAMES SDL2main - HINTS - ENV SDL2DIR - ${SDL2_NO_DEFAULT_PATH_CMD} - PATH_SUFFIXES lib ${VC_LIB_PATH_SUFFIX} - PATHS ${SDL2MAIN_LIBRARY_PATHS} - DOC "Where the SDL2main library can be found" - ) - unset(SDL2MAIN_LIBRARY_PATHS) - endif() -endif() - -# SDL2 may require threads on your system. -# The Apple build may not need an explicit flag because one of the -# frameworks may already provide it. -# But for non-OSX systems, I will use the CMake Threads package. -if(NOT APPLE) - find_package(Threads QUIET) - if(NOT Threads_FOUND) - set(SDL2_THREADS_NOT_FOUND "Could NOT find Threads (Threads is required by SDL2).") - if(SDL2_FIND_REQUIRED) - message(FATAL_ERROR ${SDL2_THREADS_NOT_FOUND}) - else() - if(NOT SDL2_FIND_QUIETLY) - message(STATUS ${SDL2_THREADS_NOT_FOUND}) - endif() - return() - endif() - unset(SDL2_THREADS_NOT_FOUND) - endif() -endif() - -# MinGW needs an additional link flag, -mwindows -# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -mwindows -if(MINGW) - set(MINGW32_LIBRARY mingw32 "-mwindows" CACHE STRING "link flags for MinGW") -endif() - -if(SDL2_LIBRARY) - # For SDL2main - if(SDL2MAIN_LIBRARY AND NOT SDL2_BUILDING_LIBRARY) - list(FIND SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" _SDL2_MAIN_INDEX) - if(_SDL2_MAIN_INDEX EQUAL -1) - set(SDL2_LIBRARIES "${SDL2MAIN_LIBRARY}" ${SDL2_LIBRARIES}) - endif() - unset(_SDL2_MAIN_INDEX) - endif() - - # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. - # CMake doesn't display the -framework Cocoa string in the UI even - # though it actually is there if I modify a pre-used variable. - # I think it has something to do with the CACHE STRING. - # So I use a temporary variable until the end so I can set the - # "real" variable in one-shot. - if(APPLE) - set(SDL2_LIBRARIES ${SDL2_LIBRARIES} -framework Cocoa) - endif() - - # For threads, as mentioned Apple doesn't need this. - # In fact, there seems to be a problem if I used the Threads package - # and try using this line, so I'm just skipping it entirely for OS X. - if(NOT APPLE) - set(SDL2_LIBRARIES ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - endif() - - # For MinGW library - if(MINGW) - set(SDL2_LIBRARIES ${MINGW32_LIBRARY} ${SDL2_LIBRARIES}) - endif() - -endif() - -# Read SDL2 version -if(SDL2_INCLUDE_DIR AND EXISTS "${SDL2_INCLUDE_DIR}/SDL_version.h") - file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MAJOR_LINE REGEX "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_MINOR_LINE REGEX "^#define[ \t]+SDL_MINOR_VERSION[ \t]+[0-9]+$") - file(STRINGS "${SDL2_INCLUDE_DIR}/SDL_version.h" SDL2_VERSION_PATCH_LINE REGEX "^#define[ \t]+SDL_PATCHLEVEL[ \t]+[0-9]+$") - string(REGEX REPLACE "^#define[ \t]+SDL_MAJOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MAJOR "${SDL2_VERSION_MAJOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_MINOR_VERSION[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_MINOR "${SDL2_VERSION_MINOR_LINE}") - string(REGEX REPLACE "^#define[ \t]+SDL_PATCHLEVEL[ \t]+([0-9]+)$" "\\1" SDL2_VERSION_PATCH "${SDL2_VERSION_PATCH_LINE}") - set(SDL2_VERSION_STRING ${SDL2_VERSION_MAJOR}.${SDL2_VERSION_MINOR}.${SDL2_VERSION_PATCH}) - unset(SDL2_VERSION_MAJOR_LINE) - unset(SDL2_VERSION_MINOR_LINE) - unset(SDL2_VERSION_PATCH_LINE) - unset(SDL2_VERSION_MAJOR) - unset(SDL2_VERSION_MINOR) - unset(SDL2_VERSION_PATCH) -endif() - -include(FindPackageHandleStandardArgs) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2 - REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR - VERSION_VAR SDL2_VERSION_STRING) - -if(SDL2MAIN_LIBRARY) - FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2main - REQUIRED_VARS SDL2MAIN_LIBRARY SDL2_INCLUDE_DIR - VERSION_VAR SDL2_VERSION_STRING) -endif() - - -mark_as_advanced(SDL2_PATH - SDL2_NO_DEFAULT_PATH - SDL2_LIBRARY - SDL2MAIN_LIBRARY - SDL2_INCLUDE_DIR - SDL2_BUILDING_LIBRARY) - - -# SDL2:: targets (SDL2::Core and SDL2::Main) -if(SDL2_FOUND) - - # SDL2::Core target - if(SDL2_LIBRARY AND NOT TARGET SDL2::Core) - add_library(SDL2::Core UNKNOWN IMPORTED) - set_target_properties(SDL2::Core PROPERTIES - IMPORTED_LOCATION "${SDL2_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIR}") - - if(APPLE) - # For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa. - # For more details, please see above. - set_property(TARGET SDL2::Core APPEND PROPERTY - INTERFACE_LINK_OPTIONS -framework Cocoa) - else() - # For threads, as mentioned Apple doesn't need this. - # For more details, please see above. - set_property(TARGET SDL2::Core APPEND PROPERTY - INTERFACE_LINK_LIBRARIES Threads::Threads) - endif() - endif() - - # SDL2::Main target - # Applications should link to SDL2::Main instead of SDL2::Core - # For more details, please see above. - if(NOT SDL2_BUILDING_LIBRARY AND NOT TARGET SDL2::Main) - - if(SDL2_INCLUDE_DIR MATCHES ".framework" OR NOT SDL2MAIN_LIBRARY) - add_library(SDL2::Main INTERFACE IMPORTED) - set_property(TARGET SDL2::Main PROPERTY - INTERFACE_LINK_LIBRARIES SDL2::Core) - elseif(SDL2MAIN_LIBRARY) - # MinGW requires that the mingw32 library is specified before the - # libSDL2main.a static library when linking. - # The SDL2::MainInternal target is used internally to make sure that - # CMake respects this condition. - add_library(SDL2::MainInternal UNKNOWN IMPORTED) - set_property(TARGET SDL2::MainInternal PROPERTY - IMPORTED_LOCATION "${SDL2MAIN_LIBRARY}") - set_property(TARGET SDL2::MainInternal PROPERTY - INTERFACE_LINK_LIBRARIES SDL2::Core) - - add_library(SDL2::Main INTERFACE IMPORTED) - - if(MINGW) - # MinGW needs an additional link flag '-mwindows' and link to mingw32 - set_property(TARGET SDL2::Main PROPERTY - INTERFACE_LINK_LIBRARIES "mingw32" "-mwindows") - endif() - - set_property(TARGET SDL2::Main APPEND PROPERTY - INTERFACE_LINK_LIBRARIES SDL2::MainInternal) - endif() - - endif() -endif() diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index f3a8e54450..4b20eb441b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -176,13 +176,7 @@ if (NOT ANDROID) AddJsonPackage(sdl2) endif() - if (PLATFORM_PS4) - set(SDL2_LIBRARY ${CMAKE_SYSROOT}/lib/libSDL2.a) - set(SDL2_INCLUDE_DIR ${CMAKE_SYSROOT}/include/SDL2) - find_package(SDL2 REQUIRED) - else() - find_package(SDL2 2.26.4 REQUIRED) - endif() + find_package(SDL2 2.26.4 REQUIRED) endif() set(BUILD_SHARED_LIBS OFF) From d133fc7a5ab25c6cd467141c2a77ca8bb516d8e4 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 24 Jan 2026 20:37:37 +0000 Subject: [PATCH 054/181] fix ps4/orbis --- externals/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 4b20eb441b..1c73f4671f 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -163,8 +163,6 @@ if (NOT ANDROID) set(PS4 ON) set(ORBIS ON) AddJsonPackage("sdl2_ps4") - unset(ORBIS) - unset(PS4) else() AddJsonPackage("sdl2_generic") endif() From a9fc29bedc4fdd9502d4a9ecc49856769946a17a Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 28 Jan 2026 18:04:31 +0000 Subject: [PATCH 055/181] mark codeblocks as noexcept --- docs/Caveats.md | 6 +++++- externals/cpmfile.json | 2 +- .../src/dynarmic/backend/x64/block_of_code.cpp | 12 ++++++------ .../src/dynarmic/backend/x64/block_of_code.h | 4 ++-- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/Caveats.md b/docs/Caveats.md index f07c8e7e66..89a83d468c 100644 --- a/docs/Caveats.md +++ b/docs/Caveats.md @@ -218,10 +218,14 @@ When CMake invokes certain file syscalls - it may sometimes cause crashes or cor ## PlayStation 4 ```sh -export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain" +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 diff --git a/externals/cpmfile.json b/externals/cpmfile.json index e39e47cb3a..f24c69bd40 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -113,7 +113,7 @@ ], "patches": [ "0001-netbsd-fix.patch", - "0002-allow-static-only.patch" + "0002-allow-static-only.patch", "0003-openorbis.patch" ] }, diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 28c821ab59..3388760024 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -239,12 +239,12 @@ static const auto default_cg_mode = Xbyak::DontSetProtectRWE; static const auto default_cg_mode = nullptr; //Allow RWE #endif -BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) - : Xbyak::CodeGenerator(total_code_size, default_cg_mode, &s_allocator) - , cb(std::move(cb)) - , jsi(jsi) - , constant_pool(*this, CONSTANT_POOL_SIZE) - , host_features(GetHostFeatures()) { +BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) noexcept + : Xbyak::CodeGenerator(total_code_size, default_cg_mode, &s_allocator) + , cb(std::move(cb)) + , jsi(jsi) + , constant_pool(*this, CONSTANT_POOL_SIZE) + , host_features(GetHostFeatures()) { EnableWriting(); EnsureMemoryCommitted(PRELUDE_COMMIT_SIZE); GenRunCode(rcp); diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h index 5ccab7a3ed..315833645c 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.h @@ -38,8 +38,8 @@ struct RunCodeCallbacks { class BlockOfCode final : public Xbyak::CodeGenerator { public: - BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp); - BlockOfCode(const BlockOfCode&) = delete; + BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) noexcept; + BlockOfCode(const BlockOfCode&) noexcept = delete; /// Call when external emitters have finished emitting their preludes. void PreludeComplete(); From eb95d38c530a8941ba83fb8eb84c0fb9e6d91c2f Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 28 Jan 2026 19:03:55 +0000 Subject: [PATCH 056/181] use newer sdl2, make bigger stack --- externals/cpmfile.json | 9 ++++++--- src/common/fiber.cpp | 2 +- src/yuzu_cmd/CMakeLists.txt | 4 +--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index f24c69bd40..aa0d06057d 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -191,11 +191,14 @@ }, "sdl2_ps4": { "package": "SDL2", - "repo": "xinitrcn1/SDL", - "sha": "f577141fc4", + "repo": "libsdl-org/SDL", + "sha": "0c7042477a", "key": "ps4", "bundled": true, - "skip_updates": true + "skip_updates": true, + "patches": [ + "0001-ps4.patch" + ] }, "moltenvk": { "repo": "V380-Ori/Ryujinx.MoltenVK", diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 69eca732eb..0c9bd4fb4d 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -16,7 +16,7 @@ namespace Common { #ifdef __OPENORBIS__ -constexpr size_t DEFAULT_STACK_SIZE = 128 * 4096; +constexpr size_t DEFAULT_STACK_SIZE = 256 * 4096; #else constexpr size_t DEFAULT_STACK_SIZE = 512 * 4096; #endif diff --git a/src/yuzu_cmd/CMakeLists.txt b/src/yuzu_cmd/CMakeLists.txt index c153e9fb78..3b85bc1d28 100644 --- a/src/yuzu_cmd/CMakeLists.txt +++ b/src/yuzu_cmd/CMakeLists.txt @@ -39,9 +39,7 @@ target_link_libraries(yuzu-cmd PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) create_resource("../../dist/eden.bmp" "yuzu_cmd/yuzu_icon.h" "yuzu_icon") target_include_directories(yuzu-cmd PRIVATE ${RESOURCES_DIR}) - -target_include_directories(yuzu-cmd PRIVATE ${CMAKE_SYSROOT}/include/SDL2) -target_link_libraries(yuzu-cmd PRIVATE SDL2) +target_link_libraries(yuzu-cmd PRIVATE SDL2::SDL2) if(UNIX AND NOT APPLE) install(TARGETS yuzu-cmd) From a87f44d8092d093494da7705fa87ea9789c44863 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 28 Jan 2026 19:15:51 +0000 Subject: [PATCH 057/181] SDL2 PS4 patch --- .patch/sdl2_ps4/0001-ps4.patch | 359 +++++++++++++++++++++++++++++++++ 1 file changed, 359 insertions(+) create mode 100644 .patch/sdl2_ps4/0001-ps4.patch diff --git a/.patch/sdl2_ps4/0001-ps4.patch b/.patch/sdl2_ps4/0001-ps4.patch new file mode 100644 index 0000000000..cb5ed901cb --- /dev/null +++ b/.patch/sdl2_ps4/0001-ps4.patch @@ -0,0 +1,359 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 7c230473ac..b1275edb61 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -331,6 +331,13 @@ if(CYGWIN) + list(APPEND SDL_CFLAGS "-I/usr/include/mingw") + endif() + ++######### *FIXME* ++if(PS4 OR ORBIS) ++ set(USE_GENERATED_CONFIG Off) ++else() ++ set(USE_GENERATED_CONFIG On) ++endif() ++ + # General includes + target_compile_definitions(sdl-build-options INTERFACE "-DUSING_GENERATED_CONFIG_H") + target_include_directories(sdl-build-options BEFORE INTERFACE "${SDL2_BINARY_DIR}/include" "${SDL2_BINARY_DIR}/include-config-$>") +@@ -359,6 +366,15 @@ if(EMSCRIPTEN) + set(SDL_CPUINFO_ENABLED_BY_DEFAULT OFF) + endif() + ++if(PS4 OR ORBIS) ++ set(SDL_ATOMIC_ENABLED_BY_DEFAULT ON) ++ set(SDL_SHARED_ENABLED_BY_DEFAULT OFF) ++ set(SDL_THREADS_ENABLED_BY_DEFAULT ON) ++ set(SDL_PTHREADS_ENABLED_BY_DEFAULT ON) ++ set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF) ++ set(SDL_DLOPEN_ENABLED_BY_DEFAULT OFF) ++endif() ++ + if(VITA OR PSP OR PS2 OR N3DS) + set(SDL_SHARED_ENABLED_BY_DEFAULT OFF) + set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF) +@@ -1478,7 +1494,42 @@ elseif(EMSCRIPTEN) + + CheckPTHREAD() + CheckLibUnwind() ++elseif(PS4 OR ORBIS) ++ CheckPTHREAD() ++ if(SDL_AUDIO) ++ set(SDL_AUDIO_DRIVER_PS4 1) ++ file(GLOB PS4_AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/ps4/*.c) ++ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_AUDIO_SOURCES}) ++ set(HAVE_SDL_AUDIO TRUE) ++ endif() ++# if(SDL_FILESYSTEM) ++# set(SDL_FILESYSTEM_PS4 1) ++# file(GLOB PS4_FILESYSTEM_SOURCES ${SDL2_SOURCE_DIR}/src/filesystem/ps4/*.c) ++# set(SOURCE_FILES ${SOURCE_FILES} ${PS4_FILESYSTEM_SOURCES}) ++# set(HAVE_SDL_FILESYSTEM TRUE) ++# endif() ++ if(SDL_JOYSTICK) ++ set(SDL_JOYSTICK_PS4 1) ++ file(GLOB PS4_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/ps4/*.c) ++ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_JOYSTICK_SOURCES}) ++ set(HAVE_SDL_JOYSTICK TRUE) ++ endif() ++ if(SDL_TIMERS) ++ set(SDL_TIMER_UNIX 1) ++ file(GLOB TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/unix/*.c) ++ set(SOURCE_FILES ${SOURCE_FILES} ${TIMER_SOURCES}) ++ set(HAVE_SDL_TIMERS TRUE) + ++ if(CLOCK_GETTIME) ++ set(HAVE_CLOCK_GETTIME 1) ++ endif() ++ endif() ++ if(SDL_VIDEO) ++ set(SDL_VIDEO_DRIVER_PS4 1) ++ file(GLOB PS4_VIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/ps4/*.c) ++ set(SOURCE_FILES ${SOURCE_FILES} ${PS4_VIDEO_SOURCES}) ++ set(HAVE_SDL_VIDEO TRUE) ++ endif() + elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU) + if(SDL_AUDIO) + if(SYSV5 OR SOLARIS OR HPUX) +@@ -3039,7 +3090,7 @@ endif() + # We always need to have threads and timers around + if(NOT HAVE_SDL_THREADS) + # The emscripten platform has been carefully vetted to work without threads +- if (EMSCRIPTEN) ++ if (EMSCRIPTEN OR PS4 OR ORBIS) + set(SDL_THREADS_DISABLED 1) + file(GLOB THREADS_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/*.c) + list(APPEND SOURCE_FILES ${THREADS_SOURCES}) +diff --git a/README.md b/README.md +index fa7f7ba0b5..8d5a375694 100644 +--- a/README.md ++++ b/README.md +@@ -1,5 +1,5 @@ + +-# Simple DirectMedia Layer (SDL) Version 2.0 ++# Simple DirectMedia Layer (SDL) Version 2.0 (For OpenOrbis PS4 SDK) + + https://www.libsdl.org/ + +diff --git a/include/SDL_config.h b/include/SDL_config.h +index a628d86252..a101532d16 100644 +--- a/include/SDL_config.h ++++ b/include/SDL_config.h +@@ -41,6 +41,10 @@ + #include "SDL_config_iphoneos.h" + #elif defined(__ANDROID__) + #include "SDL_config_android.h" ++#elif defined(__PSP__) ++#include "SDL_config_psp.h" ++#elif defined(__OPENORBIS__) ++#include "SDL_config_ps4.h" + #elif defined(__OS2__) + #include "SDL_config_os2.h" + #elif defined(__EMSCRIPTEN__) +diff --git a/include/SDL_platform.h b/include/SDL_platform.h +index 36df782a4e..0cc20dc4e2 100644 +--- a/include/SDL_platform.h ++++ b/include/SDL_platform.h +@@ -214,6 +214,10 @@ + #if defined(PS2) + #define __PS2__ 1 + #endif ++#if defined(__OPENORBIS__) ++#undef __PS4__ ++#define __PS4__ 1 ++#endif + + /* The NACL compiler defines __native_client__ and __pnacl__ + * Ref: http://www.chromium.org/nativeclient/pnacl/stability-of-the-pnacl-bitcode-abi +diff --git a/src/SDL.c b/src/SDL.c +index cfeea077e7..33fce965c0 100644 +--- a/src/SDL.c ++++ b/src/SDL.c +@@ -642,6 +642,8 @@ const char *SDL_GetPlatform(void) + return "Nokia N-Gage"; + #elif defined(__3DS__) + return "Nintendo 3DS"; ++#elif defined(__PS4__) ++ return "PlayStation4"; + #else + return "Unknown (see SDL_platform.h)"; + #endif +diff --git a/src/SDL_error.c b/src/SDL_error.c +index 993f5bac55..083ebf3027 100644 +--- a/src/SDL_error.c ++++ b/src/SDL_error.c +@@ -50,11 +50,14 @@ int SDL_SetError(SDL_PRINTF_FORMAT_STRING const char *fmt, ...) + va_end(ap); + } + } +- ++#ifndef __OPENORBIS__ // Yeah this is stupid but whatever + if (SDL_LogGetPriority(SDL_LOG_CATEGORY_ERROR) <= SDL_LOG_PRIORITY_DEBUG) { ++#endif + /* If we are in debug mode, print out the error message */ + SDL_LogDebug(SDL_LOG_CATEGORY_ERROR, "%s", error->str); ++#ifndef __OPENORBIS__ // Yeah this is stupid but whatever + } ++#endif + } + + return -1; +diff --git a/src/SDL_log.c b/src/SDL_log.c +index 7a5f1dbc03..a7f3d85782 100644 +--- a/src/SDL_log.c ++++ b/src/SDL_log.c +@@ -390,10 +390,12 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va + int len; + va_list aq; + ++#ifndef __OPENORBIS__ + /* Nothing to do if we don't have an output function */ + if (!SDL_log_function) { + return; + } ++#endif + + /* Make sure we don't exceed array bounds */ + if ((int)priority < 0 || priority >= SDL_NUM_LOG_PRIORITIES) { +@@ -442,7 +444,11 @@ void SDL_LogMessageV(int category, SDL_LogPriority priority, const char *fmt, va + } + + SDL_LockMutex(log_function_mutex); ++#ifdef __OPENORBIS__ ++ printf("%s\n", message); // just fucking do it ++#else + SDL_log_function(SDL_log_userdata, category, priority, message); ++#endif + SDL_UnlockMutex(log_function_mutex); + + /* Free only if dynamically allocated */ +diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c +index 421adbc76a..82d087a2f8 100644 +--- a/src/audio/SDL_audio.c ++++ b/src/audio/SDL_audio.c +@@ -114,7 +114,10 @@ static const AudioBootStrap *const bootstrap[] = { + #ifdef SDL_AUDIO_DRIVER_N3DS + &N3DSAUDIO_bootstrap, + #endif +-#ifdef SDL_AUDIO_DRIVER_EMSCRIPTEN ++#if SDL_AUDIO_DRIVER_PS4 ++ &PS4AUDIO_bootstrap, ++#endif ++#if SDL_AUDIO_DRIVER_EMSCRIPTEN + &EMSCRIPTENAUDIO_bootstrap, + #endif + #ifdef SDL_AUDIO_DRIVER_JACK +diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h +index 87387692ce..b1c00ba9dc 100644 +--- a/src/audio/SDL_sysaudio.h ++++ b/src/audio/SDL_sysaudio.h +@@ -207,6 +207,7 @@ extern AudioBootStrap PS2AUDIO_bootstrap; + extern AudioBootStrap PSPAUDIO_bootstrap; + extern AudioBootStrap VITAAUD_bootstrap; + extern AudioBootStrap N3DSAUDIO_bootstrap; ++extern AudioBootStrap PS4AUDIO_bootstrap; + extern AudioBootStrap EMSCRIPTENAUDIO_bootstrap; + extern AudioBootStrap OS2AUDIO_bootstrap; + +diff --git a/src/dynapi/SDL_dynapi.h b/src/dynapi/SDL_dynapi.h +index 178218c053..a6e298a9fe 100644 +--- a/src/dynapi/SDL_dynapi.h ++++ b/src/dynapi/SDL_dynapi.h +@@ -69,6 +69,8 @@ + #define SDL_DYNAMIC_API 0 /* devkitARM doesn't support dynamic linking */ + #elif defined(DYNAPI_NEEDS_DLOPEN) && !defined(HAVE_DLOPEN) + #define SDL_DYNAMIC_API 0 /* we need dlopen(), but don't have it.... */ ++#elif defined(__OPENORBIS__) // Apparently __PS4__ getting defined is missed somewhere, I get broken static builds so force the issue ++#define SDL_DYNAMIC_API 0 + #endif + + /* everyone else. This is where we turn on the API if nothing forced it off. */ +diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c +index 60b0daf790..34433166e8 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 d36f784143..6671aff2fd 100644 +--- a/src/joystick/SDL_sysjoystick.h ++++ b/src/joystick/SDL_sysjoystick.h +@@ -243,6 +243,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_render.c b/src/render/SDL_render.c +index 35f80664ab..cd8f9d3615 100644 +--- a/src/render/SDL_render.c ++++ b/src/render/SDL_render.c +@@ -137,6 +137,10 @@ static const SDL_RenderDriver *render_drivers[] = { + #if SDL_VIDEO_RENDER_VITA_GXM + &VITA_GXM_RenderDriver, + #endif ++#if SDL_VIDEO_RENDER_PS4 && 0 // *FIXME* PS4_RenderDriver Disabled, it's software anyhow lets not reinvent... ++#error Use SoftRender for PS4 currently! ++ &PS4_RenderDriver, ++#endif + #if SDL_VIDEO_RENDER_SW + &SW_RenderDriver + #endif +diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h +index ac5426b676..d9b5bfbc39 100644 +--- a/src/render/SDL_sysrender.h ++++ b/src/render/SDL_sysrender.h +@@ -307,6 +307,7 @@ extern SDL_RenderDriver DirectFB_RenderDriver; + extern SDL_RenderDriver METAL_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; + +diff --git a/src/thread/pthread/SDL_systhread.c b/src/thread/pthread/SDL_systhread.c +index 212fe9c000..a920afba0b 100644 +--- a/src/thread/pthread/SDL_systhread.c ++++ b/src/thread/pthread/SDL_systhread.c +@@ -29,8 +29,10 @@ + #include + #endif + ++#ifdef HAVE_SIGNAL_H + #include + #include ++#endif + + #ifdef __LINUX__ + #include +@@ -60,7 +62,7 @@ + #endif + + +-#ifndef __NACL__ ++#if !defined(__NACL__) && !defined(__OPENORBIS__) + /* List of signals to mask in the subthreads */ + static const int sig_list[] = { + SIGHUP, SIGINT, SIGQUIT, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGWINCH, +@@ -162,7 +164,7 @@ void SDL_SYS_SetupThread(const char *name) + } + + /* NativeClient does not yet support signals.*/ +-#if !defined(__NACL__) ++#if !defined(__NACL__) && !defined(__OPENORBIS__) + /* Mask asynchronous signals for this thread */ + sigemptyset(&mask); + for (i = 0; sig_list[i]; ++i) { +diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h +index badb1a3edc..e17beb9f5c 100644 +--- a/src/video/SDL_sysvideo.h ++++ b/src/video/SDL_sysvideo.h +@@ -471,6 +471,7 @@ extern VideoBootStrap PSP_bootstrap; + extern VideoBootStrap VITA_bootstrap; + extern VideoBootStrap RISCOS_bootstrap; + extern VideoBootStrap N3DS_bootstrap; ++extern VideoBootStrap PS4_bootstrap; + extern VideoBootStrap RPI_bootstrap; + extern VideoBootStrap KMSDRM_bootstrap; + extern VideoBootStrap KMSDRM_LEGACY_bootstrap; +diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c +index 134cc05e13..f40d6104e2 100644 +--- a/src/video/SDL_video.c ++++ b/src/video/SDL_video.c +@@ -121,6 +121,9 @@ static VideoBootStrap *bootstrap[] = { + #ifdef SDL_VIDEO_DRIVER_N3DS + &N3DS_bootstrap, + #endif ++#ifdef SDL_VIDEO_DRIVER_PS4 ++ &PS4_bootstrap, ++#endif + #ifdef SDL_VIDEO_DRIVER_KMSDRM + &KMSDRM_bootstrap, + #endif +@@ -241,6 +244,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U + SDL_GetWindowSizeInPixels(window, &w, &h); + + if (!data) { ++ + SDL_Renderer *renderer = NULL; + const char *render_driver = NULL; + const char *hint; +@@ -297,7 +301,7 @@ static int SDL_CreateWindowTexture(SDL_VideoDevice *_this, SDL_Window *window, U + SDL_assert(renderer != NULL); /* should have explicitly checked this above. */ + + /* Create the data after we successfully create the renderer (bug #1116) */ +- data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(*data)); ++ data = (SDL_WindowTextureData *)SDL_calloc(1, sizeof(SDL_WindowTextureData)); + if (!data) { + SDL_DestroyRenderer(renderer); + return SDL_OutOfMemory(); From 9de03b55281f1dacf8e236eae4926041eb7c9785 Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 28 Jan 2026 19:51:50 +0000 Subject: [PATCH 058/181] fixup shit --- externals/CMakeLists.txt | 6 ++++-- src/core/device_memory.h | 16 +++++++++------- src/core/device_memory_manager.inc | 2 +- src/input_common/CMakeLists.txt | 2 +- src/yuzu_cmd/yuzu.cpp | 17 +---------------- 5 files changed, 16 insertions(+), 27 deletions(-) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 1c73f4671f..c324e35f73 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -263,8 +263,10 @@ target_include_directories(tz PUBLIC ./tz) add_library(bc_decoder bc_decoder/bc_decoder.cpp) target_include_directories(bc_decoder PUBLIC ./bc_decoder) -add_library(ps4sup ps4sup/emutls.c ps4sup/stub.cpp) -target_include_directories(ps4sup PUBLIC ./ps4sup) +if (PLATFORM_PS4) + 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) diff --git a/src/core/device_memory.h b/src/core/device_memory.h index 29d2ff7a2b..11bf0e3268 100644 --- a/src/core/device_memory.h +++ b/src/core/device_memory.h @@ -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 @@ -29,22 +26,27 @@ public: template Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const { - return (uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer())) + DramMemoryMap::Base; + return (reinterpret_cast(ptr) - + reinterpret_cast(buffer.BackingBasePointer())) + + DramMemoryMap::Base; } template PAddr GetRawPhysicalAddr(const T* ptr) const { - return PAddr(uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer())); + return static_cast(reinterpret_cast(ptr) - + reinterpret_cast(buffer.BackingBasePointer())); } template T* GetPointer(Common::PhysicalAddress addr) { - return reinterpret_cast(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base)); + return reinterpret_cast(buffer.BackingBasePointer() + + (GetInteger(addr) - DramMemoryMap::Base)); } template const T* GetPointer(Common::PhysicalAddress addr) const { - return reinterpret_cast(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base)); + return reinterpret_cast(buffer.BackingBasePointer() + + (GetInteger(addr) - DramMemoryMap::Base)); } template diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc index 953d32eb01..08fe799174 100644 --- a/src/core/device_memory_manager.inc +++ b/src/core/device_memory_manager.inc @@ -166,7 +166,7 @@ struct DeviceMemoryManagerAllocator { template DeviceMemoryManager::DeviceMemoryManager(const DeviceMemory& device_memory_) - : physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}, + : physical_base{reinterpret_cast(device_memory_.buffer.BackingBasePointer())}, device_inter{nullptr}, compressed_physical_ptr(device_as_size >> Memory::YUZU_PAGEBITS), compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index ef1308b1d0..c7c4b11800 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later # SPDX-FileCopyrightText: 2018 yuzu Emulator Project diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index baba1c1d0a..368123d941 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -51,22 +51,7 @@ #include #endif -#ifdef __OPENORBIS__ -#include -#include -#include <__thread/support.h> -# define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); } -extern "C" void __cxa_thread_atexit_impl() { - //printf("atexit called"); -} -STUB_WEAK(__assert) -STUB_WEAK(ZSTD_trace_compress_begin) -STUB_WEAK(ZSTD_trace_compress_end) -STUB_WEAK(ZSTD_trace_decompress_begin) -STUB_WEAK(ZSTD_trace_decompress_end) -FILE* __stderrp = stdout; -# undef STUB_WEAK -#elif defined(_WIN32) +#if defined(_WIN32) extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable // graphics From 96556566cef82e888b083a0edbbba7cd2f54e314 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 30 Jan 2026 10:01:26 +0000 Subject: [PATCH 059/181] fix --- .ci/ps4/build.sh | 2 ++ src/yuzu_cmd/yuzu.cpp | 4 ---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 2fdcd01c68..60e8359efd 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -3,6 +3,8 @@ # SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project # SPDX-License-Identifier: GPL-3.0-or-later +[ -z ${OO_PS4_TOOLCHAIN+x} ] && exit + [ -f "ps4-toolchain.cmake" ] || cat << EOF >"ps4-toolchain.cmake" set(CMAKE_SYSROOT "$OO_PS4_TOOLCHAIN") set(CMAKE_STAGING_PREFIX "$OO_PS4_TOOLCHAIN") diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 368123d941..4d91a5d13d 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -435,10 +435,6 @@ int main(int argc, char** argv) { }; system.RegisterExitCallback(exit_fn); -#ifdef __linux__ - Common::Linux::StartGamemode(); -#endif - void(system.Run()); if (system.DebuggerEnabled()) { system.InitializeDebugger(); From 342fdedd1e67e9b377bd70175d667f3f653f210f Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 30 Jan 2026 10:19:34 +0000 Subject: [PATCH 060/181] add hash --- externals/cpmfile.json | 1 + 1 file changed, 1 insertion(+) diff --git a/externals/cpmfile.json b/externals/cpmfile.json index aa0d06057d..882edf5217 100644 --- a/externals/cpmfile.json +++ b/externals/cpmfile.json @@ -193,6 +193,7 @@ "package": "SDL2", "repo": "libsdl-org/SDL", "sha": "0c7042477a", + "hash": "91d897257fe1134e65234618a96bc8f4f9b61dd3ba42241a65c293cd406139e308a6c79eadfa7c3969271c88d73149e75c4310fff37c79387c80d9c982c1f322", "key": "ps4", "bundled": true, "skip_updates": true, From 989ac3bd04d4ebd921e9d318ebe84662babb5748 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 31 Jan 2026 12:34:57 +0000 Subject: [PATCH 061/181] force ankerl + fixup for OO with prelude commits --- .patch/xbyak/0001-macro-stl.patch | 21 +++++++++++++ .patch/xbyak_sun/0001-macro-stl.patch | 21 +++++++++++++ src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- .../dynarmic/backend/x64/block_of_code.cpp | 31 ++++++++++++++----- 5 files changed, 68 insertions(+), 9 deletions(-) create mode 100644 .patch/xbyak/0001-macro-stl.patch create mode 100644 .patch/xbyak_sun/0001-macro-stl.patch diff --git a/.patch/xbyak/0001-macro-stl.patch b/.patch/xbyak/0001-macro-stl.patch new file mode 100644 index 0000000000..5cfb9eeec6 --- /dev/null +++ b/.patch/xbyak/0001-macro-stl.patch @@ -0,0 +1,21 @@ +diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h +index ed7706a..51b520d 100644 +--- a/xbyak/xbyak.h ++++ b/xbyak/xbyak.h +@@ -37,6 +37,7 @@ + #define XBYAK_GNUC_PREREQ(major, minor) 0 + #endif + ++#if !defined(XBYAK_STD_UNORDERED_SET) + // This covers -std=(gnu|c)++(0x|11|1y), -stdlib=libc++, and modern Microsoft. + #if ((defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_LIBCPP_VERSION) ||\ + ((__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__))) +@@ -71,6 +72,8 @@ + #define XBYAK_STD_UNORDERED_MAP std::map + #define XBYAK_STD_UNORDERED_MULTIMAP std::multimap + #endif ++#endif ++ + #ifdef _WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN diff --git a/.patch/xbyak_sun/0001-macro-stl.patch b/.patch/xbyak_sun/0001-macro-stl.patch new file mode 100644 index 0000000000..5cfb9eeec6 --- /dev/null +++ b/.patch/xbyak_sun/0001-macro-stl.patch @@ -0,0 +1,21 @@ +diff --git a/xbyak/xbyak.h b/xbyak/xbyak.h +index ed7706a..51b520d 100644 +--- a/xbyak/xbyak.h ++++ b/xbyak/xbyak.h +@@ -37,6 +37,7 @@ + #define XBYAK_GNUC_PREREQ(major, minor) 0 + #endif + ++#if !defined(XBYAK_STD_UNORDERED_SET) + // This covers -std=(gnu|c)++(0x|11|1y), -stdlib=libc++, and modern Microsoft. + #if ((defined(_MSC_VER) && (_MSC_VER >= 1600)) || defined(_LIBCPP_VERSION) ||\ + ((__cplusplus >= 201103) || defined(__GXX_EXPERIMENTAL_CXX0X__))) +@@ -71,6 +72,8 @@ + #define XBYAK_STD_UNORDERED_MAP std::map + #define XBYAK_STD_UNORDERED_MULTIMAP std::multimap + #endif ++#endif ++ + #ifdef _WIN32 + #ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index f41a2be482..a485ba9a78 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -203,7 +203,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(8_MiB); + config.code_cache_size = std::uint32_t(32_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4da2c2b211..bfd531dabc 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -255,7 +255,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(8_MiB); + config.code_cache_size = std::uint32_t(32_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 3388760024..39e39577e9 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -58,8 +58,13 @@ const std::array BlockOfCode::ABI_PARAMS = {Block namespace { +#ifdef __OPENORBIS__ +constexpr size_t CONSTANT_POOL_SIZE = 8 * 4096; +constexpr size_t PRELUDE_COMMIT_SIZE = 8 * 4096; +#else constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024; +#endif class CustomXbyakAllocator : public Xbyak::Allocator { public: @@ -67,8 +72,12 @@ public: uint8_t* alloc(size_t size) override { void* p = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_READWRITE); if (p == nullptr) { +#ifndef XBYAK_NO_EXCEPTION using Xbyak::Error; XBYAK_THROW(Xbyak::ERR_CANT_ALLOC); +#else + std::abort(); +#endif } return static_cast(p); } @@ -106,8 +115,12 @@ public: #endif void* p = mmap(nullptr, size, prot, mode, -1, 0); if (p == MAP_FAILED) { +#ifndef XBYAK_NO_EXCEPTION using Xbyak::Error; XBYAK_THROW(Xbyak::ERR_CANT_ALLOC); +#else + std::abort(); +#endif } std::memcpy(p, &size, sizeof(size_t)); return static_cast(p) + DYNARMIC_PAGE_SIZE; @@ -233,14 +246,14 @@ bool IsUnderRosetta() { } // anonymous namespace -#ifdef DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT -static const auto default_cg_mode = Xbyak::DontSetProtectRWE; -#else -static const auto default_cg_mode = nullptr; //Allow RWE -#endif - BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) noexcept - : Xbyak::CodeGenerator(total_code_size, default_cg_mode, &s_allocator) +#ifdef __OPENORBIS__ + : Xbyak::CodeGenerator(total_code_size, Xbyak::AutoGrow, &s_allocator) +#elif defined(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT) + : Xbyak::CodeGenerator(total_code_size, Xbyak::DontSetProtectRWE, &s_allocator) +#else + : Xbyak::CodeGenerator(total_code_size, nullptr, &s_allocator) +#endif , cb(std::move(cb)) , jsi(jsi) , constant_pool(*this, CONSTANT_POOL_SIZE) @@ -533,8 +546,12 @@ size_t BlockOfCode::GetTotalCodeSize() const { void* BlockOfCode::AllocateFromCodeSpace(size_t alloc_size) { if (size_ + alloc_size >= maxSize_) { +#ifndef XBYAK_NO_EXCEPTION using Xbyak::Error; XBYAK_THROW(Xbyak::ERR_CODE_IS_TOO_BIG); +#else + std::abort(); +#endif } EnsureMemoryCommitted(alloc_size); From 359837e31d50afd762e8d177b5356cca208b0ea5 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 1 Feb 2026 03:39:22 +0000 Subject: [PATCH 062/181] use dmem for swap buffers, restore full jit sizes --- src/common/virtual_buffer.cpp | 12 +++++++++--- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- .../src/dynarmic/backend/x64/block_of_code.cpp | 9 +-------- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 48f26ec298..bd647b0acf 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -16,6 +16,7 @@ #include #include #include +#include typedef void (*SceKernelExceptionHandler)(int32_t, void*); extern "C" int32_t sceKernelInstallExceptionHandler(int32_t signum, SceKernelExceptionHandler handler); #endif @@ -143,8 +144,13 @@ void* AllocateMemoryPages(std::size_t size) noexcept { #elif defined(__OPENORBIS__) void* addr; if (size <= 8192 * 4096) { - addr = malloc(size); - LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", size, addr); + size_t align = 16384; + size_t len = (size + align - 1) / align * align; + off_t offset = 0; + ASSERT(sceKernelAllocateDirectMemory(0, ORBIS_KERNEL_MAIN_DMEM_SIZE, len, align, ORBIS_KERNEL_WB_ONION, &offset) == 0); + ASSERT(sceKernelMapDirectMemory(&addr, len, ORBIS_KERNEL_PROT_CPU_RW, 0, offset, len) == 0); + ASSERT(sceKernelMprotect(addr, len, VM_PROT_ALL) == 0); + LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", len, addr); ASSERT(addr != nullptr); } else { addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_VOID | MAP_PRIVATE, -1, 0); @@ -166,7 +172,7 @@ void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept { VirtualFree(addr, 0, MEM_RELEASE); #elif defined(__OPENORBIS__) if (size <= 8192 * 4096) { - free(addr); + sceKernelCheckedReleaseDirectMemory(off_t(addr), size_t(size)); } else { int rc = munmap(addr, size); ASSERT(rc == 0); diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index a485ba9a78..679b733d77 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -203,7 +203,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(32_MiB); + config.code_cache_size = std::uint32_t(128_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index bfd531dabc..4c3cf62d54 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -255,7 +255,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(32_MiB); + config.code_cache_size = std::uint32_t(128_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp index 39e39577e9..9b0e44b19f 100644 --- a/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp +++ b/src/dynarmic/src/dynarmic/backend/x64/block_of_code.cpp @@ -58,13 +58,8 @@ const std::array BlockOfCode::ABI_PARAMS = {Block namespace { -#ifdef __OPENORBIS__ -constexpr size_t CONSTANT_POOL_SIZE = 8 * 4096; -constexpr size_t PRELUDE_COMMIT_SIZE = 8 * 4096; -#else constexpr size_t CONSTANT_POOL_SIZE = 2 * 1024 * 1024; constexpr size_t PRELUDE_COMMIT_SIZE = 16 * 1024 * 1024; -#endif class CustomXbyakAllocator : public Xbyak::Allocator { public: @@ -247,9 +242,7 @@ bool IsUnderRosetta() { } // anonymous namespace BlockOfCode::BlockOfCode(RunCodeCallbacks cb, JitStateInfo jsi, size_t total_code_size, std::function rcp) noexcept -#ifdef __OPENORBIS__ - : Xbyak::CodeGenerator(total_code_size, Xbyak::AutoGrow, &s_allocator) -#elif defined(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT) +#if defined(DYNARMIC_ENABLE_NO_EXECUTE_SUPPORT) : Xbyak::CodeGenerator(total_code_size, Xbyak::DontSetProtectRWE, &s_allocator) #else : Xbyak::CodeGenerator(total_code_size, nullptr, &s_allocator) From 0f7b6aa41680e4864a9e7909281301386e10cd01 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sun, 1 Feb 2026 03:39:53 +0000 Subject: [PATCH 063/181] fix yuzu cpp --- src/yuzu_cmd/yuzu.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 4d91a5d13d..ff6d36440c 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -51,7 +51,10 @@ #include #endif -#if defined(_WIN32) +#if defined(__OPENORBIS__) +#include +#include +#elif defined(_WIN32) extern "C" { // tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable // graphics From 1bc2588b6807689dae09f94d8cbe61bad2738e95 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 07:30:19 +0000 Subject: [PATCH 064/181] reduce fiber sizes --- src/common/fiber.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 2 +- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/common/fiber.cpp b/src/common/fiber.cpp index 0c9bd4fb4d..4f3dad7e88 100644 --- a/src/common/fiber.cpp +++ b/src/common/fiber.cpp @@ -16,7 +16,7 @@ namespace Common { #ifdef __OPENORBIS__ -constexpr size_t DEFAULT_STACK_SIZE = 256 * 4096; +constexpr size_t DEFAULT_STACK_SIZE = 32 * 4096; #else constexpr size_t DEFAULT_STACK_SIZE = 512 * 4096; #endif diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 679b733d77..f41a2be482 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -203,7 +203,7 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(128_MiB); + config.code_cache_size = std::uint32_t(8_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4c3cf62d54..4da2c2b211 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -255,7 +255,7 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s // Code cache size #if defined(__OPENORBIS__) - config.code_cache_size = std::uint32_t(128_MiB); + config.code_cache_size = std::uint32_t(8_MiB); #elif defined(ARCHITECTURE_arm64) || defined(__sun__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) config.code_cache_size = std::uint32_t(128_MiB); #else From f0d045fd202886d3a744416939d2ed0e3f03d8eb Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 11:43:45 +0000 Subject: [PATCH 065/181] use btver2 --- .ci/ps4/build.sh | 6 ++++-- src/common/host_memory.cpp | 4 +--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index 60e8359efd..cec9876dcd 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -10,8 +10,8 @@ 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=x86-64 -march=x86-64 -fPIC -funwind-tables") -set(CMAKE_CXX_FLAGS " -D__OPENORBIS__ -D_LIBCPP_HAS_MUSL_LIBC=1 -D_GNU_SOURCE=1 --target=x86_64-pc-freebsd12-elf -mtune=x86-64 -march=x86-64 -fPIC -funwind-tables") +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") +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") 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") @@ -59,3 +59,5 @@ cmake -S . -B build -G "Unix Makefiles" \ -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 diff --git a/src/common/host_memory.cpp b/src/common/host_memory.cpp index ce28b36527..6de3e64474 100644 --- a/src/common/host_memory.cpp +++ b/src/common/host_memory.cpp @@ -499,9 +499,7 @@ class HostMemory::Impl { public: explicit Impl(size_t backing_size_, size_t virtual_size_) : backing_size{backing_size_}, virtual_size{virtual_size_} { -#ifdef __OPENORBIS__ - -#else +#if !defined(__OPENORBIS__) && !defined(__APPLE__) long page_size = sysconf(_SC_PAGESIZE); ASSERT_MSG(page_size == 0x1000, "page size {:#x} is incompatible with 4K paging", page_size); #endif From 17da677e20b8d5b70250f5e43a86d32ec4d1defa Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 12:55:01 +0000 Subject: [PATCH 066/181] immediately terminate in OO, use 2MB swap handler --- src/common/virtual_buffer.cpp | 3 +-- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 4 ---- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 4 ---- 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index bd647b0acf..409f3efefa 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -114,7 +114,7 @@ static void SwapHandler(int sig, void* raw_context) { 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 = 4096 * 8; //16K + size_t const page_size = 0x200000; //2M size_t const page_mask = ~(page_size - 1); // should replace the existing mapping... ugh void* aligned_addr = reinterpret_cast(uintptr_t(mctx.mc_addr) & page_mask); @@ -149,7 +149,6 @@ void* AllocateMemoryPages(std::size_t size) noexcept { off_t offset = 0; ASSERT(sceKernelAllocateDirectMemory(0, ORBIS_KERNEL_MAIN_DMEM_SIZE, len, align, ORBIS_KERNEL_WB_ONION, &offset) == 0); ASSERT(sceKernelMapDirectMemory(&addr, len, ORBIS_KERNEL_PROT_CPU_RW, 0, offset, len) == 0); - ASSERT(sceKernelMprotect(addr, len, VM_PROT_ALL) == 0); LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", len, addr); ASSERT(addr != nullptr); } else { diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index f41a2be482..5f082e38bf 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -306,10 +306,6 @@ void ArmDynarmic32::MakeJit(Common::PageTable* page_table) { default: break; } -#ifdef __OPENORBIS__ - config.unsafe_optimizations = false; - config.optimizations = Dynarmic::no_optimizations; -#endif m_jit.emplace(config); } diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index 4da2c2b211..0842f439b8 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -357,10 +357,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s default: break; } -#ifdef __OPENORBIS__ - config.unsafe_optimizations = false; - config.optimizations = Dynarmic::no_optimizations; -#endif m_jit.emplace(config); } From f76bb75c515d7328790297b1ccc9ad6de05cbd5e Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 23:11:31 +0000 Subject: [PATCH 067/181] restore protection --- src/common/virtual_buffer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp index 409f3efefa..cd269cb997 100644 --- a/src/common/virtual_buffer.cpp +++ b/src/common/virtual_buffer.cpp @@ -149,6 +149,7 @@ void* AllocateMemoryPages(std::size_t size) noexcept { off_t offset = 0; ASSERT(sceKernelAllocateDirectMemory(0, ORBIS_KERNEL_MAIN_DMEM_SIZE, len, align, ORBIS_KERNEL_WB_ONION, &offset) == 0); ASSERT(sceKernelMapDirectMemory(&addr, len, ORBIS_KERNEL_PROT_CPU_RW, 0, offset, len) == 0); + ASSERT(sceKernelMprotect(addr, len, VM_PROT_ALL) == 0); LOG_WARNING(HW_Memory, "Using DMem for {} bytes area @ {}", len, addr); ASSERT(addr != nullptr); } else { From 34d4e335991f144d7d67633530d4e4feca21762a Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 23:12:17 +0000 Subject: [PATCH 068/181] leave pending param package stuff --- src/common/param_package.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index 629babb811..972b1c1f5f 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp @@ -75,7 +75,9 @@ std::string ParamPackage::Serialize() const { std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { auto pair = data.find(key); if (pair == data.end()) { +#ifndef __OPENORBIS__ LOG_TRACE(Common, "key '{}' not found", key); +#endif return default_value; } @@ -85,7 +87,9 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default int ParamPackage::Get(const std::string& key, int default_value) const { auto pair = data.find(key); if (pair == data.end()) { +#ifndef __OPENORBIS__ LOG_TRACE(Common, "key '{}' not found", key); +#endif return default_value; } @@ -100,7 +104,9 @@ int ParamPackage::Get(const std::string& key, int default_value) const { float ParamPackage::Get(const std::string& key, float default_value) const { auto pair = data.find(key); if (pair == data.end()) { +#ifndef __OPENORBIS__ LOG_TRACE(Common, "key {} not found", key); +#endif return default_value; } From 75f57ed4ecd7b1eee1efeb2c26a07fd03769efbe Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 2 Feb 2026 23:14:39 +0000 Subject: [PATCH 069/181] let it rip --- src/common/param_package.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index 972b1c1f5f..629babb811 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp @@ -75,9 +75,7 @@ std::string ParamPackage::Serialize() const { std::string ParamPackage::Get(const std::string& key, const std::string& default_value) const { auto pair = data.find(key); if (pair == data.end()) { -#ifndef __OPENORBIS__ LOG_TRACE(Common, "key '{}' not found", key); -#endif return default_value; } @@ -87,9 +85,7 @@ std::string ParamPackage::Get(const std::string& key, const std::string& default int ParamPackage::Get(const std::string& key, int default_value) const { auto pair = data.find(key); if (pair == data.end()) { -#ifndef __OPENORBIS__ LOG_TRACE(Common, "key '{}' not found", key); -#endif return default_value; } @@ -104,9 +100,7 @@ int ParamPackage::Get(const std::string& key, int default_value) const { float ParamPackage::Get(const std::string& key, float default_value) const { auto pair = data.find(key); if (pair == data.end()) { -#ifndef __OPENORBIS__ LOG_TRACE(Common, "key {} not found", key); -#endif return default_value; } From 3bf49a759271ee267e937fe668b200e9d328b93a Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 18 Feb 2026 19:49:28 +0000 Subject: [PATCH 070/181] FX --- src/input_common/drivers/sdl_driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 6fc2f47f6a..81b0a2313a 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -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: 2018 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later From 54f0445a877abe229af70de697abf3d14365114d Mon Sep 17 00:00:00 2001 From: lizzie Date: Wed, 25 Feb 2026 15:25:16 +0000 Subject: [PATCH 071/181] disable stdio buffering --- src/yuzu_cmd/yuzu.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index ff6d36440c..d0bdd1078c 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -185,6 +185,11 @@ int main(int argc, char** argv) { freopen("CONOUT$", "wb", stderr); } #endif +#ifdef __OPENORBIS__ + // May prevent spurious crashes on swap handlers... + setvbuf(stdout, nullptr, _IONBF, 0); + setvbuf(stderr, nullptr, _IONBF, 0); +#endif Common::Log::Initialize(); Common::Log::SetColorConsoleBackendEnabled(true); From a987f520de25c6063bccd1832e5c777fac8e5b44 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 26 Feb 2026 01:07:06 +0000 Subject: [PATCH 072/181] fix openssl --- .ci/ps4/build.sh | 4 ++++ externals/ps4sup/stub.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/.ci/ps4/build.sh b/.ci/ps4/build.sh index cec9876dcd..c7bb54deaa 100755 --- a/.ci/ps4/build.sh +++ b/.ci/ps4/build.sh @@ -52,6 +52,10 @@ cmake -S . -B build -G "Unix Makefiles" \ -DENABLE_WEB_SERVICE=OFF \ -DUSE_DISCORD_PRESENCE=OFF \ -DCPMUTIL_FORCE_BUNDLED=ON \ + -DOPENSSL_ROOT_DIR="$OO_PS4_TOOLCHAIN" \ + -DOPENSSL_SSL_LIBRARY="$OO_PS4_TOOLCHAIN/lib/libssl.a" \ + -DOPENSSL_CRYPTO_LIBRARY="$OO_PS4_TOOLCHAIN/lib/libcrypto.a" \ + -DOPENSSL_INCLUDE_DIR="$OO_PS4_TOOLCHAIN/include/openssl" \ -DYUZU_USE_EXTERNAL_FFMPEG=ON \ -DYUZU_USE_CPM=ON \ -DDYNARMIC_ENABLE_NO_EXECUTE_SUPPORT=OFF \ diff --git a/externals/ps4sup/stub.cpp b/externals/ps4sup/stub.cpp index bee5613486..562fbd4a38 100644 --- a/externals/ps4sup/stub.cpp +++ b/externals/ps4sup/stub.cpp @@ -16,7 +16,17 @@ STUB_WEAK(ZSTD_trace_compress_begin) STUB_WEAK(ZSTD_trace_compress_end) STUB_WEAK(ZSTD_trace_decompress_begin) STUB_WEAK(ZSTD_trace_decompress_end) + FILE* __stderrp = stdout; +FILE* __stdinp = stdin; + +extern "C" { +struct _RuneLocale; +thread_local const _RuneLocale *_ThreadRuneLocale = NULL; +const _RuneLocale *_CurrentRuneLocale = NULL; +int __isthreaded = 0; +int __mb_sb_limit = 0; +} #undef STUB_WEAK From c682306788055c57953aea38fdded95a0c6dfc09 Mon Sep 17 00:00:00 2001 From: wildcard Date: Wed, 4 Mar 2026 22:46:55 +0100 Subject: [PATCH 073/181] [vulkan] Implement push descriptors for compute pipelines (#3666) Implements push descriptor for compute pipelines along with a bug fix, the increment logic was, offset += sizeof(DescriptorUpdateEntry); This only advances the byte offset by a single descriptor slot, regardless of the array's size (descriptorCount).Now suppose if a shader utilized an array of descriptors (eg, layout(binding = 0) uniform sampler2D textures[4]) and if this happened to fit within the MaxPushDescriptors limit, the template would consume 4 * sizeof(DescriptorUpdateEntry) bytes, but the offset for the next binding would only advance by 1 slot. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3666 Reviewed-by: MaranBr Co-authored-by: wildcard Co-committed-by: wildcard --- .../renderer_vulkan/pipeline_helper.h | 8 +++++-- .../renderer_vulkan/vk_compute_pipeline.cpp | 24 ++++++++++++------- .../renderer_vulkan/vk_compute_pipeline.h | 4 ++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/video_core/renderer_vulkan/pipeline_helper.h b/src/video_core/renderer_vulkan/pipeline_helper.h index 910e07a606..e88b27b273 100644 --- a/src/video_core/renderer_vulkan/pipeline_helper.h +++ b/src/video_core/renderer_vulkan/pipeline_helper.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -61,7 +64,8 @@ public: .pDescriptorUpdateEntries = entries.data(), .templateType = type, .descriptorSetLayout = descriptor_set_layout, - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, + .pipelineBindPoint = + is_compute ? VK_PIPELINE_BIND_POINT_COMPUTE : VK_PIPELINE_BIND_POINT_GRAPHICS, .pipelineLayout = pipeline_layout, .set = 0, }); @@ -122,7 +126,7 @@ private: }); ++binding; num_descriptors += descriptors[i].count; - offset += sizeof(DescriptorUpdateEntry); + offset += sizeof(DescriptorUpdateEntry) * descriptors[i].count; } } diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 51b5141a06..6a6fe2b830 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -50,11 +50,14 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel DescriptorLayoutBuilder builder{device}; builder.Add(info, VK_SHADER_STAGE_COMPUTE_BIT); - descriptor_set_layout = builder.CreateDescriptorSetLayout(false); + uses_push_descriptor = builder.CanUsePushDescriptor(); + descriptor_set_layout = builder.CreateDescriptorSetLayout(uses_push_descriptor); pipeline_layout = builder.CreatePipelineLayout(*descriptor_set_layout); descriptor_update_template = - builder.CreateTemplate(*descriptor_set_layout, *pipeline_layout, false); - descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, info); + builder.CreateTemplate(*descriptor_set_layout, *pipeline_layout, uses_push_descriptor); + if (!uses_push_descriptor) { + descriptor_allocator = descriptor_pool.Allocator(*descriptor_set_layout, info); + } const VkPipelineShaderStageRequiredSubgroupSizeCreateInfoEXT subgroup_size_ci{ .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO_EXT, .pNext = nullptr, @@ -241,11 +244,16 @@ void ComputePipeline::Configure(Tegra::Engines::KeplerCompute& kepler_compute, RESCALING_LAYOUT_WORDS_OFFSET, sizeof(rescaling_data), rescaling_data.data()); } - const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; - const vk::Device& dev{device.GetLogical()}; - dev.UpdateDescriptorSet(descriptor_set, *descriptor_update_template, descriptor_data); - cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, - descriptor_set, nullptr); + if (uses_push_descriptor) { + cmdbuf.PushDescriptorSetWithTemplateKHR(*descriptor_update_template, *pipeline_layout, + 0, descriptor_data); + } else { + const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()}; + const vk::Device& dev{device.GetLogical()}; + dev.UpdateDescriptorSet(descriptor_set, *descriptor_update_template, descriptor_data); + cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline_layout, 0, + descriptor_set, nullptr); + } }); } diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.h b/src/video_core/renderer_vulkan/vk_compute_pipeline.h index d1a1e2c46d..aa84c00e12 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.h +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -55,6 +58,7 @@ private: vk::ShaderModule spv_module; vk::DescriptorSetLayout descriptor_set_layout; + bool uses_push_descriptor{false}; DescriptorAllocator descriptor_allocator; vk::PipelineLayout pipeline_layout; vk::DescriptorUpdateTemplate descriptor_update_template; From 7f5de6bcd651f8145e4746c76d0531b6560fd5e4 Mon Sep 17 00:00:00 2001 From: xbzk Date: Wed, 4 Mar 2026 22:51:35 +0100 Subject: [PATCH 074/181] [android/fs] external content loader + nca/xci patches (#3596) Foreword: WHY DON'T EVERYBODY USE ONE FOLDER FOR EACH GAME+CONTENTS? AIN'T THIS THE FORMAT GAMES COME WHEN YOU BUE THEM? DO YOU LIVE WITH ALL YOUR FRIENDS AND HAVE A 2ND HOUSE FOR ALL THE CHILDREN? Nice, i feel better now. This feat extends Maufeat's work on external content loading. It harmonically additions: "...also, if in each game folder X, you find a folder Y, and in this folder Y you detect ONLY a single game, then mount all external content for that game found in that folder Y and its subfolders." Permanent (not toggleable). External Content folders are supported equally. Also: -Reworked several routines for preserving single source of truth between android and other systems; -Fixed the annoying unknown format error for content files, by providing proper format detection. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3596 Reviewed-by: MaranBr Reviewed-by: Lizzie Co-authored-by: xbzk Co-committed-by: xbzk --- .../java/org/yuzu/yuzu_emu/NativeLibrary.kt | 6 + .../org/yuzu/yuzu_emu/model/AddonViewModel.kt | 6 +- .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 4 +- .../org/yuzu/yuzu_emu/utils/GameHelper.kt | 64 ++- .../app/src/main/jni/android_config.cpp | 6 + .../app/src/main/jni/game_metadata.cpp | 5 + src/android/app/src/main/jni/native.cpp | 116 +---- src/android/app/src/main/jni/native.h | 4 + src/common/settings.h | 2 + src/core/file_sys/patch_manager.cpp | 27 +- src/core/file_sys/registered_cache.cpp | 473 +++++++++--------- src/core/file_sys/registered_cache.h | 5 +- src/core/loader/loader.cpp | 70 ++- src/core/loader/loader.h | 22 +- src/core/loader/nsp.cpp | 36 +- src/core/loader/xci.cpp | 14 +- src/yuzu/game/game_list_worker.cpp | 22 +- src/yuzu/main_window.cpp | 19 +- 18 files changed, 477 insertions(+), 424 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 1f0acf2835..397b44c9f9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -607,6 +607,12 @@ object NativeLibrary { */ external fun addFileToFilesystemProvider(path: String) + /** + * Adds a game-folder file to the manual filesystem provider, respecting the internal gate for + * game-folder external-content mounting. + */ + external fun addGameFolderFileToFilesystemProvider(path: String) + /** * Clears all files added to the manual filesystem provider in our EmulationSession instance */ diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt index c682a13cfc..2a0e72be26 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/AddonViewModel.kt @@ -127,10 +127,6 @@ class AddonViewModel : ViewModel() { return } - // Check if there are multiple update versions - val updates = _patchList.value.filter { PatchType.from(it.type) == PatchType.Update } - val hasMultipleUpdates = updates.size > 1 - NativeConfig.setDisabledAddons( game!!.programId, _patchList.value.mapNotNull { @@ -140,7 +136,7 @@ class AddonViewModel : ViewModel() { if (PatchType.from(it.type) == PatchType.Update) { if (it.name.contains("(NAND)") || it.name.contains("(SDMC)")) { it.name - } else if (hasMultipleUpdates) { + } else if (it.numericVersion != 0L) { "Update@${it.numericVersion}" } else { it.name diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 8a4262ebe7..db4cc0f60e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -424,7 +424,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { ) val uriString = result.toString() - val folder = gamesViewModel.folders.value.firstOrNull { it.uriString == uriString } + val folder = gamesViewModel.folders.value.firstOrNull { + it.uriString == uriString && it.type == org.yuzu.yuzu_emu.model.DirectoryType.EXTERNAL_CONTENT + } if (folder != null) { Toast.makeText( applicationContext, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index fff5fdfb9b..4a3cf61daa 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt @@ -51,11 +51,24 @@ object GameHelper { // Scan External Content directories and register all NSP/XCI files val externalContentDirs = NativeConfig.getExternalContentDirs() - for (externalDir in externalContentDirs) { + val uniqueExternalContentDirs = linkedSetOf() + externalContentDirs.forEach { externalDir -> + if (externalDir.isNotEmpty()) { + uniqueExternalContentDirs.add(externalDir) + } + } + + val mountedContainerUris = mutableSetOf() + for (externalDir in uniqueExternalContentDirs) { if (externalDir.isNotEmpty()) { val externalDirUri = externalDir.toUri() if (FileUtil.isTreeUriValid(externalDirUri)) { - scanExternalContentRecursive(FileUtil.listFiles(externalDirUri), 3) + scanContentContainersRecursive(FileUtil.listFiles(externalDirUri), 3) { + val containerUri = it.uri.toString() + if (mountedContainerUris.add(containerUri)) { + NativeLibrary.addFileToFilesystemProvider(containerUri) + } + } } } } @@ -65,10 +78,13 @@ object GameHelper { val gameDirUri = gameDir.uriString.toUri() val isValid = FileUtil.isTreeUriValid(gameDirUri) if (isValid) { + val scanDepth = if (gameDir.deepScan) 3 else 1 + addGamesRecursive( games, FileUtil.listFiles(gameDirUri), - if (gameDir.deepScan) 3 else 1 + scanDepth, + mountedContainerUris ) } else { badDirs.add(index) @@ -103,9 +119,10 @@ object GameHelper { // be done better imo. private val externalContentExtensions = setOf("nsp", "xci") - private fun scanExternalContentRecursive( + private fun scanContentContainersRecursive( files: Array, - depth: Int + depth: Int, + onContainerFound: (MinimalDocumentFile) -> Unit ) { if (depth <= 0) { return @@ -113,14 +130,15 @@ object GameHelper { files.forEach { if (it.isDirectory) { - scanExternalContentRecursive( + scanContentContainersRecursive( FileUtil.listFiles(it.uri), - depth - 1 + depth - 1, + onContainerFound ) } else { val extension = FileUtil.getExtension(it.uri).lowercase() if (externalContentExtensions.contains(extension)) { - NativeLibrary.addFileToFilesystemProvider(it.uri.toString()) + onContainerFound(it) } } } @@ -129,7 +147,8 @@ object GameHelper { private fun addGamesRecursive( games: MutableList, files: Array, - depth: Int + depth: Int, + mountedContainerUris: MutableSet ) { if (depth <= 0) { return @@ -140,11 +159,20 @@ object GameHelper { addGamesRecursive( games, FileUtil.listFiles(it.uri), - depth - 1 + depth - 1, + mountedContainerUris ) } else { - if (Game.extensions.contains(FileUtil.getExtension(it.uri))) { - val game = getGame(it.uri, true) + val extension = FileUtil.getExtension(it.uri).lowercase() + val filePath = it.uri.toString() + + if (externalContentExtensions.contains(extension) && + mountedContainerUris.add(filePath)) { + NativeLibrary.addGameFolderFileToFilesystemProvider(filePath) + } + + if (Game.extensions.contains(extension)) { + val game = getGame(it.uri, true, false) if (game != null) { games.add(game) } @@ -153,14 +181,20 @@ object GameHelper { } } - fun getGame(uri: Uri, addedToLibrary: Boolean): Game? { + fun getGame( + uri: Uri, + addedToLibrary: Boolean, + registerFilesystemProvider: Boolean = true + ): Game? { val filePath = uri.toString() if (!GameMetadata.getIsValid(filePath)) { return null } - // Needed to update installed content information - NativeLibrary.addFileToFilesystemProvider(filePath) + if (registerFilesystemProvider) { + // Needed to update installed content information + NativeLibrary.addFileToFilesystemProvider(filePath) + } var name = GameMetadata.getTitle(filePath) diff --git a/src/android/app/src/main/jni/android_config.cpp b/src/android/app/src/main/jni/android_config.cpp index 0171e2a7b3..0c5696ef3f 100644 --- a/src/android/app/src/main/jni/android_config.cpp +++ b/src/android/app/src/main/jni/android_config.cpp @@ -33,6 +33,12 @@ void AndroidConfig::ReadAndroidValues() { if (global) { ReadAndroidUIValues(); ReadUIValues(); + BeginGroup(Settings::TranslateCategory(Settings::Category::DataStorage)); + Settings::values.ext_content_from_game_dirs = ReadBooleanSetting( + std::string("ext_content_from_game_dirs"), + std::make_optional( + Settings::values.ext_content_from_game_dirs.GetDefault())); + EndGroup(); ReadOverlayValues(); } ReadDriverValues(); diff --git a/src/android/app/src/main/jni/game_metadata.cpp b/src/android/app/src/main/jni/game_metadata.cpp index e9c03b6440..9acba456f1 100644 --- a/src/android/app/src/main/jni/game_metadata.cpp +++ b/src/android/app/src/main/jni/game_metadata.cpp @@ -96,6 +96,11 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj return false; } + if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && + !Loader::IsBootableGameContainer(file, file_type)) { + return false; + } + u64 program_id = 0; Loader::ResultStatus res = loader->ReadProgramId(program_id); if (res != Loader::ResultStatus::Success) { diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index c429f4a1e4..3f0029c78a 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -217,107 +217,8 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) return; } - const auto extension = Common::ToLower(filepath.substr(filepath.find_last_of('.') + 1)); - - if (extension == "nsp") { - auto nsp = std::make_shared(file); - if (nsp->GetStatus() == Loader::ResultStatus::Success) { - std::map nsp_versions; - std::map nsp_version_strings; - - for (const auto& [title_id, nca_map] : nsp->GetNCAs()) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (content_type == FileSys::ContentRecordType::Meta) { - const auto meta_nca = std::make_shared(nca->GetBaseFile()); - if (meta_nca->GetStatus() == Loader::ResultStatus::Success) { - const auto section0 = meta_nca->GetSubdirectories(); - if (!section0.empty()) { - for (const auto& meta_file : section0[0]->GetFiles()) { - if (meta_file->GetExtension() == "cnmt") { - FileSys::CNMT cnmt(meta_file); - nsp_versions[cnmt.GetTitleID()] = cnmt.GetTitleVersion(); - } - } - } - } - } - - if (content_type == FileSys::ContentRecordType::Control && - title_type == FileSys::TitleType::Update) { - auto romfs = nca->GetRomFS(); - if (romfs) { - auto extracted = FileSys::ExtractRomFS(romfs); - if (extracted) { - auto nacp_file = extracted->GetFile("control.nacp"); - if (!nacp_file) { - nacp_file = extracted->GetFile("Control.nacp"); - } - if (nacp_file) { - FileSys::NACP nacp(nacp_file); - auto ver_str = nacp.GetVersionString(); - if (!ver_str.empty()) { - nsp_version_strings[title_id] = ver_str; - } - } - } - } - } - } - } - - for (const auto& [title_id, nca_map] : nsp->GetNCAs()) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (title_type == FileSys::TitleType::Update) { - u32 version = 0; - auto ver_it = nsp_versions.find(title_id); - if (ver_it != nsp_versions.end()) { - version = ver_it->second; - } - - std::string version_string; - auto str_it = nsp_version_strings.find(title_id); - if (str_it != nsp_version_strings.end()) { - version_string = str_it->second; - } - - m_manual_provider->AddEntryWithVersion( - title_type, content_type, title_id, version, version_string, - nca->GetBaseFile()); - - LOG_DEBUG(Frontend, "Added NSP update entry - TitleID: {:016X}, Version: {}, VersionStr: {}", - title_id, version, version_string); - } else { - // Use regular AddEntry for non-updates - m_manual_provider->AddEntry(title_type, content_type, title_id, - nca->GetBaseFile()); - LOG_DEBUG(Frontend, "Added NSP entry - TitleID: {:016X}, TitleType: {}, ContentType: {}", - title_id, static_cast(title_type), static_cast(content_type)); - } - } - } - return; - } - } - - // Handle XCI files - if (extension == "xci") { - FileSys::XCI xci{file}; - if (xci.GetStatus() == Loader::ResultStatus::Success) { - const auto nsp = xci.GetSecurePartitionNSP(); - if (nsp) { - for (const auto& title : nsp->GetNCAs()) { - for (const auto& entry : title.second) { - m_manual_provider->AddEntry(entry.first.first, entry.first.second, title.first, - entry.second->GetBaseFile()); - } - } - } - return; - } + if (m_manual_provider->AddEntriesFromContainer(file)) { + return; } auto loader = Loader::GetLoader(m_system, file); @@ -339,6 +240,13 @@ void EmulationSession::ConfigureFilesystemProvider(const std::string& filepath) } } +void EmulationSession::ConfigureFilesystemProviderFromGameFolder(const std::string& filepath) { + if (!Settings::values.ext_content_from_game_dirs.GetValue()) { + return; + } + ConfigureFilesystemProvider(filepath); +} + void EmulationSession::InitializeSystem(bool reload) { if (!reload) { // Initialize logging system @@ -1609,6 +1517,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_addFileToFilesystemProvider(JNIEnv* e Common::Android::GetJString(env, jpath)); } +void Java_org_yuzu_yuzu_1emu_NativeLibrary_addGameFolderFileToFilesystemProvider( + JNIEnv* env, jobject jobj, jstring jpath) { + EmulationSession::GetInstance().ConfigureFilesystemProviderFromGameFolder( + Common::Android::GetJString(env, jpath)); +} + void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, jobject jobj) { EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); } diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index dfbc8b2943..f2e5c2cfd6 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -46,6 +49,7 @@ public: const Core::PerfStatsResults& PerfStats(); int ShadersBuilding(); void ConfigureFilesystemProvider(const std::string& filepath); + void ConfigureFilesystemProviderFromGameFolder(const std::string& filepath); void InitializeSystem(bool reload); void SetAppletId(int applet_id); Core::SystemResultStatus InitializeEmulation(const std::string& filepath, diff --git a/src/common/settings.h b/src/common/settings.h index 7ea4136576..7c6c0d062f 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -756,6 +756,8 @@ struct Values { Category::DataStorage}; Setting gamecard_path{linkage, std::string(), "gamecard_path", Category::DataStorage}; + Setting ext_content_from_game_dirs{linkage, true, "ext_content_from_game_dirs", + Category::DataStorage}; std::vector external_content_dirs; // Debugging diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 82944ceceb..e9c3bb75c2 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -117,6 +117,12 @@ void AppendCommaIfNotEmpty(std::string& to, std::string_view with) { bool IsDirValidAndNonEmpty(const VirtualDir& dir) { return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty()); } + +bool IsVersionedExternalUpdateDisabled(const std::vector& disabled, u32 version) { + const std::string disabled_key = fmt::format("Update@{}", version); + return std::find(disabled.cbegin(), disabled.cend(), disabled_key) != disabled.cend() || + std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); +} } // Anonymous namespace PatchManager::PatchManager(u64 title_id_, @@ -155,8 +161,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { if (!update_versions.empty()) { checked_external = true; for (const auto& update_entry : update_versions) { - std::string disabled_key = fmt::format("Update@{}", update_entry.version); - if (std::find(disabled.cbegin(), disabled.cend(), disabled_key) == disabled.cend()) { + if (!IsVersionedExternalUpdateDisabled(disabled, update_entry.version)) { update_disabled = false; enabled_version = update_entry.version; break; @@ -175,8 +180,7 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { if (!manual_update_versions.empty()) { checked_manual = true; for (const auto& update_entry : manual_update_versions) { - std::string disabled_key = fmt::format("Update@{}", update_entry.version); - if (std::find(disabled.cbegin(), disabled.cend(), disabled_key) == disabled.cend()) { + if (!IsVersionedExternalUpdateDisabled(disabled, update_entry.version)) { update_disabled = false; enabled_version = update_entry.version; break; @@ -580,8 +584,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs if (!update_versions.empty()) { checked_external = true; for (const auto& update_entry : update_versions) { - std::string disabled_key = fmt::format("Update@{}", update_entry.version); - if (std::find(disabled.cbegin(), disabled.cend(), disabled_key) == disabled.cend()) { + if (!IsVersionedExternalUpdateDisabled(disabled, update_entry.version)) { update_disabled = false; enabled_version = update_entry.version; update_raw = external_provider->GetEntryForVersion(update_tid, type, update_entry.version); @@ -600,8 +603,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs if (!manual_update_versions.empty()) { checked_manual = true; for (const auto& update_entry : manual_update_versions) { - std::string disabled_key = fmt::format("Update@{}", update_entry.version); - if (std::find(disabled.cbegin(), disabled.cend(), disabled_key) == disabled.cend()) { + if (!IsVersionedExternalUpdateDisabled(disabled, update_entry.version)) { update_disabled = false; enabled_version = update_entry.version; update_raw = manual_provider->GetEntryForVersion(update_tid, type, update_entry.version); @@ -704,9 +706,8 @@ std::vector PatchManager::GetPatches(VirtualFile update_raw) const { version_str = FormatTitleVersion(update_entry.version); } - std::string disabled_key = fmt::format("Update@{}", update_entry.version); const auto update_disabled = - std::find(disabled.cbegin(), disabled.cend(), disabled_key) != disabled.cend(); + IsVersionedExternalUpdateDisabled(disabled, update_entry.version); Patch update_patch = {.enabled = !update_disabled, .name = "Update", @@ -732,9 +733,8 @@ std::vector PatchManager::GetPatches(VirtualFile update_raw) const { version_str = FormatTitleVersion(update_entry.version); } - std::string disabled_key = fmt::format("Update@{}", update_entry.version); const auto update_disabled = - std::find(disabled.cbegin(), disabled.cend(), disabled_key) != disabled.cend(); + IsVersionedExternalUpdateDisabled(disabled, update_entry.version); Patch update_patch = {.enabled = !update_disabled, @@ -771,7 +771,8 @@ std::vector PatchManager::GetPatches(VirtualFile update_raw) const { std::nullopt, std::nullopt, ContentRecordType::Program, update_tid); for (const auto& [slot, entry] : all_updates) { - if (slot == ContentProviderUnionSlot::External) { + if (slot == ContentProviderUnionSlot::External || + slot == ContentProviderUnionSlot::FrontendManual) { continue; } diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 7bf2ad8fcd..020d403c95 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -104,6 +104,206 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); } +static std::shared_ptr OpenContainerAsNsp(const VirtualFile& file, Loader::FileType type) { + if (!file) { + return nullptr; + } + + if (type == Loader::FileType::Unknown || type == Loader::FileType::Error) { + type = Loader::IdentifyFile(file); + if (type == Loader::FileType::Unknown) { + type = Loader::GuessFromFilename(file->GetName()); + } + } + + if (type == Loader::FileType::NSP) { + auto nsp = std::make_shared(file); + return nsp->GetStatus() == Loader::ResultStatus::Success ? nsp : nullptr; + } + + if (type == Loader::FileType::XCI) { + XCI xci(file); + if (xci.GetStatus() != Loader::ResultStatus::Success) { + return nullptr; + } + + auto secure_partition = xci.GetSecurePartitionNSP(); + if (secure_partition == nullptr) { + return nullptr; + } + + return secure_partition; + } + + // SAF-backed files can occasionally fail type-guessing despite being valid NSP/XCI. + // As a last resort, probe both container parsers directly. + { + auto nsp = std::make_shared(file); + if (nsp->GetStatus() == Loader::ResultStatus::Success) { + return nsp; + } + } + { + XCI xci(file); + if (xci.GetStatus() == Loader::ResultStatus::Success) { + auto secure_partition = xci.GetSecurePartitionNSP(); + if (secure_partition != nullptr) { + return secure_partition; + } + } + } + + return nullptr; +} + +template +bool ForEachContainerEntry(const std::shared_ptr& nsp, bool only_content, + std::optional base_program_id, Callback&& on_entry) { + if (!nsp) { + return false; + } + + const auto& ncas = nsp->GetNCAs(); + if (ncas.empty()) { + return false; + } + + std::map versions; + std::map version_strings; + + for (const auto& [title_id, nca_map] : ncas) { + for (const auto& [type_pair, nca] : nca_map) { + if (!nca) { + continue; + } + + const auto& [title_type, content_type] = type_pair; + + if (content_type == ContentRecordType::Meta) { + const auto subdirs = nca->GetSubdirectories(); + if (!subdirs.empty()) { + for (const auto& inner_file : subdirs[0]->GetFiles()) { + if (inner_file->GetExtension() == "cnmt") { + const CNMT cnmt(inner_file); + versions[cnmt.GetTitleID()] = cnmt.GetTitleVersion(); + break; + } + } + } + } + + if (title_type == TitleType::Update && content_type == ContentRecordType::Control) { + const auto romfs = nca->GetRomFS(); + if (!romfs) { + continue; + } + + const auto extracted = ExtractRomFS(romfs); + if (!extracted) { + continue; + } + + auto nacp_file = extracted->GetFile("control.nacp"); + if (!nacp_file) { + nacp_file = extracted->GetFile("Control.nacp"); + } + if (!nacp_file) { + continue; + } + + const NACP nacp(nacp_file); + auto version_string = nacp.GetVersionString(); + if (!version_string.empty()) { + version_strings[title_id] = std::move(version_string); + } + } + } + } + + bool added_entries = false; + for (const auto& [title_id, nca_map] : ncas) { + if (base_program_id.has_value() && GetBaseTitleID(title_id) != *base_program_id) { + continue; + } + + for (const auto& [type_pair, nca] : nca_map) { + const auto& [title_type, content_type] = type_pair; + if (only_content && title_type != TitleType::Update && title_type != TitleType::AOC) { + continue; + } + + auto entry_file = nca ? nca->GetBaseFile() : nullptr; + if (!entry_file) { + continue; + } + + u32 version = 0; + std::string version_string; + + if (title_type == TitleType::Update) { + if (const auto version_it = versions.find(title_id); version_it != versions.end()) { + version = version_it->second; + } + + if (const auto version_str_it = version_strings.find(title_id); + version_str_it != version_strings.end()) { + version_string = version_str_it->second; + } + } + + on_entry(title_type, content_type, title_id, entry_file, version, version_string); + added_entries = true; + } + } + + return added_entries; +} + +static void UpsertExternalVersionEntry(std::vector& multi_version_entries, + u64 title_id, u32 version, + const std::string& version_string, + ContentRecordType content_type, const VirtualFile& file) { + auto it = std::find_if(multi_version_entries.begin(), multi_version_entries.end(), + [title_id, version](const ExternalUpdateEntry& entry) { + return entry.title_id == title_id && entry.version == version; + }); + + if (it == multi_version_entries.end()) { + ExternalUpdateEntry update_entry; + update_entry.title_id = title_id; + update_entry.version = version; + update_entry.version_string = version_string; + update_entry.files[static_cast(content_type)] = file; + multi_version_entries.push_back(std::move(update_entry)); + return; + } + + it->files[static_cast(content_type)] = file; + if (it->version_string.empty() && !version_string.empty()) { + it->version_string = version_string; + } +} + +template +static bool AddExternalEntriesFromContainer(const std::shared_ptr& nsp, EntryMap& entries, + VersionMap& versions, + std::vector& multi_version_entries) { + return ForEachContainerEntry( + nsp, true, std::nullopt, + [&entries, &versions, + &multi_version_entries](TitleType title_type, ContentRecordType content_type, u64 title_id, + const VirtualFile& file, u32 version, + const std::string& version_string) { + entries[{title_id, content_type, title_type}] = file; + + if (title_type == TitleType::Update) { + versions[title_id] = version; + UpsertExternalVersionEntry(multi_version_entries, title_id, version, version_string, + content_type, file); + } + }); +} + ContentRecordType GetCRTypeFromNCAType(NCAContentType type) { switch (type) { case NCAContentType::Program: @@ -1008,6 +1208,26 @@ void ManualContentProvider::AddEntryWithVersion(TitleType title_type, ContentRec } } +bool ManualContentProvider::AddEntriesFromContainer(VirtualFile file, bool only_content, + std::optional base_program_id) { + const auto nsp = OpenContainerAsNsp(file, Loader::FileType::Unknown); + if (!nsp) { + return false; + } + + return ForEachContainerEntry( + nsp, only_content, base_program_id, + [this](TitleType title_type, ContentRecordType content_type, u64 title_id, + const VirtualFile& entry_file, u32 version, const std::string& version_string) { + if (title_type == TitleType::Update) { + AddEntryWithVersion(title_type, content_type, title_id, version, version_string, + entry_file); + } else { + AddEntry(title_type, content_type, title_id, entry_file); + } + }); +} + void ManualContentProvider::ClearAllEntries() { entries.clear(); multi_version_entries.clear(); @@ -1091,14 +1311,6 @@ VirtualFile ManualContentProvider::GetEntryForVersion(u64 title_id, ContentRecor return nullptr; } -bool ManualContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const { - size_t count = 0; - for (const auto& entry : multi_version_entries) - if (entry.title_id == title_id && entry.files[size_t(type)]) - ++count; - return count > 0; -} - ExternalContentProvider::ExternalContentProvider(std::vector load_directories) : load_dirs(std::move(load_directories)) { ExternalContentProvider::Refresh(); @@ -1159,247 +1371,22 @@ void ExternalContentProvider::ScanDirectory(const VirtualDir& dir) { } void ExternalContentProvider::ProcessNSP(const VirtualFile& file) { - auto nsp = NSP(file); - if (nsp.GetStatus() != Loader::ResultStatus::Success) { + const auto nsp = OpenContainerAsNsp(file, Loader::FileType::NSP); + if (!nsp) { return; } LOG_DEBUG(Service_FS, "Processing NSP file: {}", file->GetName()); - - const auto ncas = nsp.GetNCAs(); - - std::map nsp_versions; - std::map nsp_version_strings; // title_id -> NACP version string - - for (const auto& [title_id, nca_map] : ncas) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (content_type == ContentRecordType::Meta) { - const auto subdirs = nca->GetSubdirectories(); - if (!subdirs.empty()) { - const auto section0 = subdirs[0]; - const auto files = section0->GetFiles(); - for (const auto& inner_file : files) { - if (inner_file->GetExtension() == "cnmt") { - const CNMT cnmt(inner_file); - const auto cnmt_title_id = cnmt.GetTitleID(); - const auto version = cnmt.GetTitleVersion(); - nsp_versions[cnmt_title_id] = version; - versions[cnmt_title_id] = version; - break; - } - } - } - } - - if (content_type == ContentRecordType::Control && title_type == TitleType::Update) { - auto romfs = nca->GetRomFS(); - if (romfs) { - auto extracted = ExtractRomFS(romfs); - if (extracted) { - auto nacp_file = extracted->GetFile("control.nacp"); - if (!nacp_file) { - nacp_file = extracted->GetFile("Control.nacp"); - } - if (nacp_file) { - NACP nacp(nacp_file); - auto ver_str = nacp.GetVersionString(); - if (!ver_str.empty()) { - nsp_version_strings[title_id] = ver_str; - } - } - } - } - } - } - } - - std::map, std::array> version_files; - - for (const auto& [title_id, nca_map] : ncas) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (title_type != TitleType::AOC && title_type != TitleType::Update) { - continue; - } - - auto nca_file = nsp.GetNCAFile(title_id, content_type, title_type); - if (nca_file != nullptr) { - entries[{title_id, content_type, title_type}] = nca_file; - - if (title_type == TitleType::Update) { - u32 version = 0; - auto ver_it = nsp_versions.find(title_id); - if (ver_it != nsp_versions.end()) { - version = ver_it->second; - } - - version_files[{title_id, version}][size_t(content_type)] = nca_file; - } - - LOG_DEBUG(Service_FS, "Added entry - Title ID: {:016X}, Type: {}, Content: {}", - title_id, static_cast(title_type), static_cast(content_type)); - } - } - } - - for (const auto& [key, files_map] : version_files) { - const auto& [title_id, version] = key; - - std::string ver_str; - auto str_it = nsp_version_strings.find(title_id); - if (str_it != nsp_version_strings.end()) { - ver_str = str_it->second; - } - - bool version_exists = false; - for (auto& existing : multi_version_entries) { - if (existing.title_id == title_id && existing.version == version) { - existing.files = files_map; - if (existing.version_string.empty() && !ver_str.empty()) { - existing.version_string = ver_str; - } - version_exists = true; - break; - } - } - - if (!version_exists && !files_map.empty()) { - ExternalUpdateEntry update_entry{ - .title_id = title_id, - .version = version, - .version_string = ver_str, - .files = files_map - }; - multi_version_entries.push_back(update_entry); - LOG_DEBUG(Service_FS, "Added multi-version update - Title ID: {:016X}, Version: {}, VersionStr: {}, Content types: {}", - title_id, version, ver_str, files_map.size()); - } - } + AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries); } void ExternalContentProvider::ProcessXCI(const VirtualFile& file) { - auto xci = XCI(file); - if (xci.GetStatus() != Loader::ResultStatus::Success) { + const auto nsp = OpenContainerAsNsp(file, Loader::FileType::XCI); + if (!nsp) { return; } - auto nsp = xci.GetSecurePartitionNSP(); - if (nsp == nullptr) { - return; - } - - const auto ncas = nsp->GetNCAs(); - - std::map xci_versions; - std::map xci_version_strings; - - for (const auto& [title_id, nca_map] : ncas) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (content_type == ContentRecordType::Meta) { - const auto subdirs = nca->GetSubdirectories(); - if (!subdirs.empty()) { - const auto section0 = subdirs[0]; - const auto files = section0->GetFiles(); - for (const auto& inner_file : files) { - if (inner_file->GetExtension() == "cnmt") { - const CNMT cnmt(inner_file); - const auto cnmt_title_id = cnmt.GetTitleID(); - const auto version = cnmt.GetTitleVersion(); - xci_versions[cnmt_title_id] = version; - versions[cnmt_title_id] = version; - break; - } - } - } - } - - if (content_type == ContentRecordType::Control && title_type == TitleType::Update) { - auto romfs = nca->GetRomFS(); - if (romfs) { - auto extracted = ExtractRomFS(romfs); - if (extracted) { - auto nacp_file = extracted->GetFile("control.nacp"); - if (!nacp_file) { - nacp_file = extracted->GetFile("Control.nacp"); - } - if (nacp_file) { - NACP nacp(nacp_file); - auto ver_str = nacp.GetVersionString(); - if (!ver_str.empty()) { - xci_version_strings[title_id] = ver_str; - } - } - } - } - } - } - } - - std::map, std::array> version_files; - - for (const auto& [title_id, nca_map] : ncas) { - for (const auto& [type_pair, nca] : nca_map) { - const auto& [title_type, content_type] = type_pair; - - if (title_type != TitleType::AOC && title_type != TitleType::Update) { - continue; - } - - auto nca_file = nsp->GetNCAFile(title_id, content_type, title_type); - if (nca_file != nullptr) { - entries[{title_id, content_type, title_type}] = nca_file; - - if (title_type == TitleType::Update) { - u32 version = 0; - auto ver_it = xci_versions.find(title_id); - if (ver_it != xci_versions.end()) { - version = ver_it->second; - } - - version_files[{title_id, version}][size_t(content_type)] = nca_file; - } - } - } - } - - for (const auto& [key, files_map] : version_files) { - const auto& [title_id, version] = key; - - std::string ver_str; - auto str_it = xci_version_strings.find(title_id); - if (str_it != xci_version_strings.end()) { - ver_str = str_it->second; - } - - bool version_exists = false; - for (auto& existing : multi_version_entries) { - if (existing.title_id == title_id && existing.version == version) { - existing.files = files_map; - if (existing.version_string.empty() && !ver_str.empty()) { - existing.version_string = ver_str; - } - version_exists = true; - break; - } - } - - if (!version_exists && !files_map.empty()) { - ExternalUpdateEntry update_entry{ - .title_id = title_id, - .version = version, - .version_string = ver_str, - .files = files_map - }; - multi_version_entries.push_back(update_entry); - LOG_DEBUG(Service_FS, "Added multi-version update from XCI - Title ID: {:016X}, Version: {}, VersionStr: {}, Content types: {}", - title_id, version, ver_str, files_map.size()); - } - } + AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries); } bool ExternalContentProvider::HasEntry(u64 title_id, ContentRecordType type) const { @@ -1491,12 +1478,4 @@ VirtualFile ExternalContentProvider::GetEntryForVersion(u64 title_id, ContentRec return nullptr; } -bool ExternalContentProvider::HasMultipleVersions(u64 title_id, ContentRecordType type) const { - size_t count = 0; - for (const auto& entry : multi_version_entries) - if (entry.title_id == title_id && entry.files[size_t(type)]) - ++count; - return count > 1; -} - } // namespace FileSys diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 2e39f74db8..32134d1c48 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -262,6 +263,8 @@ public: VirtualFile file); void AddEntryWithVersion(TitleType title_type, ContentRecordType content_type, u64 title_id, u32 version, const std::string& version_string, VirtualFile file); + bool AddEntriesFromContainer(VirtualFile file, bool only_content = false, + std::optional base_program_id = std::nullopt); void ClearAllEntries(); void Refresh() override; @@ -276,7 +279,6 @@ public: std::vector ListUpdateVersions(u64 title_id) const; VirtualFile GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const; - bool HasMultipleVersions(u64 title_id, ContentRecordType type) const; private: std::map, VirtualFile> entries; @@ -303,7 +305,6 @@ public: std::vector ListUpdateVersions(u64 title_id) const; VirtualFile GetEntryForVersion(u64 title_id, ContentRecordType type, u32 version) const; - bool HasMultipleVersions(u64 title_id, ContentRecordType type) const; private: void ScanDirectory(const VirtualDir& dir); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 4379634d03..b4d50227d3 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -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 @@ -9,11 +9,15 @@ #include #include #include +#include #include "common/concepts.h" #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/core.h" +#include "core/file_sys/card_image.h" +#include "core/file_sys/common_funcs.h" +#include "core/file_sys/submission_package.h" #include "core/hle/kernel/k_process.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/kip.h" @@ -37,6 +41,49 @@ std::optional IdentifyFileLoader(FileSys::VirtualFile file) { return std::nullopt; } +std::shared_ptr OpenContainerAsNsp(FileSys::VirtualFile file, FileType type, + u64 program_id = 0, + std::size_t program_index = 0) { + if (!file) { + return nullptr; + } + + if (type == FileType::NSP) { + auto nsp = std::make_shared(file, program_id, program_index); + return nsp->GetStatus() == ResultStatus::Success ? nsp : nullptr; + } + + if (type == FileType::XCI) { + FileSys::XCI xci{file, program_id, program_index}; + if (xci.GetStatus() != ResultStatus::Success) { + return nullptr; + } + + auto secure_nsp = xci.GetSecurePartitionNSP(); + if (secure_nsp == nullptr || secure_nsp->GetStatus() != ResultStatus::Success) { + return nullptr; + } + + return secure_nsp; + } + + return nullptr; +} + +bool HasApplicationProgramContent(const std::shared_ptr& nsp) { + if (!nsp) { + return false; + } + + const auto& ncas = nsp->GetNCAs(); + return std::any_of(ncas.cbegin(), ncas.cend(), [](const auto& title_entry) { + const auto& nca_map = title_entry.second; + return nca_map.find( + {FileSys::TitleType::Application, FileSys::ContentRecordType::Program}) != + nca_map.end(); + }); +} + } // namespace FileType IdentifyFile(FileSys::VirtualFile file) { @@ -62,6 +109,27 @@ FileType IdentifyFile(FileSys::VirtualFile file) { } } +bool IsContainerType(FileType type) { + return type == FileType::NSP || type == FileType::XCI; +} + +bool IsBootableGameContainer(FileSys::VirtualFile file, FileType type, u64 program_id, + std::size_t program_index) { + if (!file) { + return false; + } + + if (type == FileType::Unknown) { + type = IdentifyFile(file); + } + + if (!IsContainerType(type)) { + return false; + } + + return HasApplicationProgramContent(OpenContainerAsNsp(file, type, program_id, program_index)); +} + FileType GuessFromFilename(const std::string& name) { if (name == "main") return FileType::DeconstructedRomDirectory; diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index f4e932cec9..95ce638da0 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h @@ -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 @@ -46,12 +49,29 @@ enum class FileType { }; /** - * Identifies the type of a bootable file based on the magic value in its header. + * Identifies the type of a supported file/container based on its structure. * @param file open file * @return FileType of file */ FileType IdentifyFile(FileSys::VirtualFile file); +/** + * Returns whether the file type represents a container format that can bundle multiple titles + * (currently NSP/XCI). + */ +bool IsContainerType(FileType type); + +/** + * Returns whether a container file is bootable as a game (has Application/Program content). + * + * @param file open file + * @param type optional file type; if Unknown it is auto-detected. + * @param program_id optional program id hint for multi-program containers. + * @param program_index optional program index hint for multi-program containers. + */ +bool IsBootableGameContainer(FileSys::VirtualFile file, FileType type = FileType::Unknown, + u64 program_id = 0, std::size_t program_index = 0); + /** * Guess the type of a bootable file from its name * @param name String name of bootable file diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp index 3016d5f25f..4333acb70c 100644 --- a/src/core/loader/nsp.cpp +++ b/src/core/loader/nsp.cpp @@ -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 @@ -55,19 +58,30 @@ AppLoader_NSP::~AppLoader_NSP() = default; FileType AppLoader_NSP::IdentifyType(const FileSys::VirtualFile& nsp_file) { const FileSys::NSP nsp(nsp_file); - if (nsp.GetStatus() == ResultStatus::Success) { - // Extracted Type case - if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr && - FileSys::IsDirectoryExeFS(nsp.GetExeFS())) { - return FileType::NSP; + if (nsp.GetStatus() != ResultStatus::Success) { + return FileType::Error; + } + + // Extracted Type case + if (nsp.IsExtractedType() && nsp.GetExeFS() != nullptr && + FileSys::IsDirectoryExeFS(nsp.GetExeFS())) { + return FileType::NSP; + } + + // Non-extracted NSPs can legitimately contain only update/DLC content. + // Identify the container format itself; bootability is validated by Load(). + if (!nsp.GetNCAs().empty()) { + return FileType::NSP; + } + + // Fallback when NCAs couldn't be parsed (e.g. missing keys) but the PFS still contains NCAs. + for (const auto& entry : nsp.GetFiles()) { + if (entry == nullptr) { + continue; } - // Non-Extracted Type case - const auto program_id = nsp.GetProgramTitleID(); - if (!nsp.IsExtractedType() && - nsp.GetNCA(program_id, FileSys::ContentRecordType::Program) != nullptr && - AppLoader_NCA::IdentifyType( - nsp.GetNCAFile(program_id, FileSys::ContentRecordType::Program)) == FileType::NCA) { + const auto& name = entry->GetName(); + if (name.size() >= 4 && name.substr(name.size() - 4) == ".nca") { return FileType::NSP; } } diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index e9abb199a1..983184a226 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp @@ -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 @@ -44,10 +47,13 @@ AppLoader_XCI::~AppLoader_XCI() = default; FileType AppLoader_XCI::IdentifyType(const FileSys::VirtualFile& xci_file) { const FileSys::XCI xci(xci_file); - if (xci.GetStatus() == ResultStatus::Success && - xci.GetNCAByType(FileSys::NCAContentType::Program) != nullptr && - AppLoader_NCA::IdentifyType(xci.GetNCAFileByType(FileSys::NCAContentType::Program)) == - FileType::NCA) { + if (xci.GetStatus() != ResultStatus::Success) { + return FileType::Error; + } + + // Identify XCI as a valid container even when it does not include a bootable Program NCA. + // Bootability is handled by AppLoader_XCI::Load(). + if (xci.GetSecurePartitionNSP() != nullptr) { return FileType::XCI; } diff --git a/src/yuzu/game/game_list_worker.cpp b/src/yuzu/game/game_list_worker.cpp index c4504a0d5e..81012e4374 100644 --- a/src/yuzu/game/game_list_worker.cpp +++ b/src/yuzu/game/game_list_worker.cpp @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include #include @@ -16,14 +17,17 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/settings.h" #include "core/core.h" #include "core/file_sys/card_image.h" +#include "core/file_sys/common_funcs.h" #include "core/file_sys/content_archive.h" #include "core/file_sys/control_metadata.h" #include "core/file_sys/fs_filesystem.h" #include "core/file_sys/nca_metadata.h" #include "core/file_sys/patch_manager.h" #include "core/file_sys/registered_cache.h" +#include "core/file_sys/romfs.h" #include "core/file_sys/submission_package.h" #include "core/loader/loader.h" #include "yuzu/compatibility_list.h" @@ -375,6 +379,12 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa return true; } + if (target == ScanTarget::PopulateGameList && + (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP) && + !Loader::IsBootableGameContainer(file, file_type)) { + return true; + } + u64 program_id = 0; const auto res2 = loader->ReadProgramId(program_id); @@ -383,18 +393,10 @@ void GameListWorker::ScanFileSystem(ScanTarget target, const std::string& dir_pa provider->AddEntry(FileSys::TitleType::Application, FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, file); - } else if (res2 == Loader::ResultStatus::Success && + } else if (Settings::values.ext_content_from_game_dirs.GetValue() && (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { - const auto nsp = file_type == Loader::FileType::NSP - ? std::make_shared(file) - : FileSys::XCI{file}.GetSecurePartitionNSP(); - for (const auto& title : nsp->GetNCAs()) { - for (const auto& entry : title.second) { - provider->AddEntry(entry.first.first, entry.first.second, title.first, - entry.second->GetBaseFile()); - } - } + void(provider->AddEntriesFromContainer(file)); } } else { std::vector program_ids; diff --git a/src/yuzu/main_window.cpp b/src/yuzu/main_window.cpp index 6ead3c4130..e02e02b413 100644 --- a/src/yuzu/main_window.cpp +++ b/src/yuzu/main_window.cpp @@ -2019,6 +2019,10 @@ void MainWindow::ConfigureFilesystemProvider(const std::string& filepath) { return; } + if (QtCommon::provider->AddEntriesFromContainer(file)) { + return; + } + auto loader = Loader::GetLoader(*QtCommon::system, file); if (!loader) { return; @@ -2033,19 +2037,8 @@ void MainWindow::ConfigureFilesystemProvider(const std::string& filepath) { const auto res2 = loader->ReadProgramId(program_id); if (res2 == Loader::ResultStatus::Success && file_type == Loader::FileType::NCA) { QtCommon::provider->AddEntry(FileSys::TitleType::Application, - FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), program_id, - file); - } else if (res2 == Loader::ResultStatus::Success && - (file_type == Loader::FileType::XCI || file_type == Loader::FileType::NSP)) { - const auto nsp = file_type == Loader::FileType::NSP - ? std::make_shared(file) - : FileSys::XCI{file}.GetSecurePartitionNSP(); - for (const auto& title : nsp->GetNCAs()) { - for (const auto& entry : title.second) { - QtCommon::provider->AddEntry(entry.first.first, entry.first.second, title.first, - entry.second->GetBaseFile()); - } - } + FileSys::GetCRTypeFromNCAType(FileSys::NCA{file}.GetType()), + program_id, file); } } From cdf9b556b25b33cf558c0ed3085d99e129a2fb1c Mon Sep 17 00:00:00 2001 From: wildcard Date: Thu, 5 Mar 2026 00:54:26 +0100 Subject: [PATCH 075/181] [vulkan]fix vuid 02751 (#3573) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3573 Reviewed-by: CamilleLaVey Reviewed-by: DraVee Co-authored-by: wildcard Co-committed-by: wildcard --- src/video_core/renderer_vulkan/vk_buffer_cache.cpp | 8 ++++++++ src/video_core/vulkan_common/vulkan_device.h | 5 +++++ 2 files changed, 13 insertions(+) diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 6256bc8bd8..f4345262fb 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -108,6 +108,14 @@ VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat // Null buffer not supported, adjust offset and size offset = 0; size = 0; + } else { + // Align offset down to minTexelBufferOffsetAlignment + const u32 alignment = static_cast(device->GetMinTexelBufferOffsetAlignment()); + if (alignment > 1) { + const u32 aligned_offset = offset & ~(alignment - 1); + size += offset - aligned_offset; + offset = aligned_offset; + } } const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) { return offset == view.offset && size == view.size && format == view.format; diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d3623d1186..d29a8cd3f3 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -318,6 +318,11 @@ public: return properties.properties.limits.minStorageBufferOffsetAlignment; } + /// Returns texel buffer offset alignment requirement. + VkDeviceSize GetMinTexelBufferOffsetAlignment() const { + return properties.properties.limits.minTexelBufferOffsetAlignment; + } + /// Returns the maximum range for storage buffers. VkDeviceSize GetMaxStorageBufferRange() const { return properties.properties.limits.maxStorageBufferRange; From 69e47bd2c0c04e0e18c29a23533e8e7724436226 Mon Sep 17 00:00:00 2001 From: wildcard Date: Thu, 5 Mar 2026 00:54:48 +0100 Subject: [PATCH 076/181] [vulkan] Fix wrong stage index in prepare_stage render area check (#3672) The OpenGL correctly uses const auto& info{stage_infos[stage]}; Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3672 Reviewed-by: MaranBr Reviewed-by: DraVee Co-authored-by: wildcard Co-committed-by: wildcard --- src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index d156baa77b..5b11a34232 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -474,7 +474,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) { buffer_cache.BindHostStageBuffers(stage); PushImageDescriptors(texture_cache, guest_descriptor_queue, stage_infos[stage], rescaling, samplers_it, views_it); - const auto& info{stage_infos[0]}; + const auto& info{stage_infos[stage]}; if (info.uses_render_area) { render_area.uses_render_area = true; render_area.words = {static_cast(regs.surface_clip.width), From 70c1e9abed3dc70284c4eece3786922b2fc144ed Mon Sep 17 00:00:00 2001 From: nekle Date: Thu, 5 Mar 2026 00:56:25 +0100 Subject: [PATCH 077/181] [android] Try and fix SD Card storage mount points for external paths (#3436) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3436 Reviewed-by: DraVee Reviewed-by: MaranBr Co-authored-by: nekle Co-committed-by: nekle --- .../java/org/yuzu/yuzu_emu/utils/PathUtil.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PathUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PathUtil.kt index a840b3b846..744e1d149c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PathUtil.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/PathUtil.kt @@ -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 package org.yuzu.yuzu_emu.utils @@ -80,16 +80,14 @@ object PathUtil { } } - // This really shouldn't be necessary, but the Android API seemingly - // doesn't have a way of doing this? - // Apparently, on certain devices the mount location can vary, so add - // extra cases here if we discover any new ones. fun getRemovableStoragePath(idString: String): String? { - var pathFile: File + val possibleMountPaths = listOf("/mnt/media_rw/$idString", "/storage/$idString") - pathFile = File("/mnt/media_rw/$idString"); - if (pathFile.exists()) { - return pathFile.absolutePath + for (mountPath in possibleMountPaths) { + val pathFile = File(mountPath); + if (pathFile.exists()) { + return pathFile.absolutePath + } } return null From 05f6942befe0ab1209ecc5e2ddb9716f49d65574 Mon Sep 17 00:00:00 2001 From: xbzk Date: Thu, 5 Mar 2026 00:58:49 +0100 Subject: [PATCH 078/181] [android, ui] fixed setting reset to defaults infinite loop (#3659) fixed a bug discovered by Pavel in which the settings' "reset to defaults" dialog would get stuck in a infinite loop, due to a recall prior to cleaning state. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3659 Reviewed-by: MaranBr Reviewed-by: DraVee Reviewed-by: CamilleLaVey Co-authored-by: xbzk Co-committed-by: xbzk --- .../settings/ui/SettingsDialogFragment.kt | 42 +++++++------------ .../settings/ui/SettingsFragmentPresenter.kt | 5 ++- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt index f66f4bac7f..4dcb35c010 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsDialogFragment.kt @@ -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: 2023 yuzu Emulator Project @@ -68,7 +68,9 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener MaterialAlertDialogBuilder(requireContext()) .setMessage(R.string.reset_setting_confirmation) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> - when (val item = settingsViewModel.clickedItem) { + val item = settingsViewModel.clickedItem ?: return@setPositiveButton + clearDialogState() + when (item) { is AnalogInputSetting -> { val stickParam = NativeInput.getStickParam( item.playerIndex, @@ -107,12 +109,17 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener } else -> { - settingsViewModel.clickedItem!!.setting.reset() + item.setting.reset() settingsViewModel.setAdapterItemChanged(position) } } } - .setNegativeButton(android.R.string.cancel, null) + .setNegativeButton(android.R.string.cancel) { _: DialogInterface, _: Int -> + clearDialogState() + } + .setOnCancelListener { + clearDialogState() + } .create() } @@ -186,27 +193,6 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener updateButtonState(isValid) } - /* - * xbzk: these two events, along with attachRepeat feature, - * were causing spinbox buttons to respond twice per press - * cutting these out to retain accelerated press functionality - * TODO: clean this out later if no issues arise - * - spinboxBinding.buttonDecrement.setOnClickListener { - val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue - val newValue = current - 1 - spinboxBinding.editValue.setText(newValue.toString()) - updateValidity(newValue) - } - - spinboxBinding.buttonIncrement.setOnClickListener { - val current = spinboxBinding.editValue.text.toString().toIntOrNull() ?: currentValue - val newValue = current + 1 - spinboxBinding.editValue.setText(newValue.toString()) - updateValidity(newValue) - } - */ - fun attachRepeat(button: View, delta: Int) { val handler = Handler(Looper.getMainLooper()) var runnable: Runnable? = null @@ -439,9 +425,13 @@ class SettingsDialogFragment : DialogFragment(), DialogInterface.OnClickListener private fun closeDialog() { settingsViewModel.setAdapterItemChanged(position) + clearDialogState() + dismiss() + } + + private fun clearDialogState() { settingsViewModel.clickedItem = null settingsViewModel.setSliderProgress(-1f) - dismiss() } private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 0fc4fb0b7f..77104e0614 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -1066,7 +1066,10 @@ class SettingsFragmentPresenter( IntSetting.THEME.getValueAsString() override val defaultValue: Int = IntSetting.THEME.defaultValue - override fun reset() = IntSetting.THEME.setInt(defaultValue) + override fun reset() { + IntSetting.THEME.setInt(defaultValue) + settingsViewModel.setShouldRecreate(true) + } } add(HeaderSetting(R.string.app_settings)) From 9a07bd0570ceba262b4a918f4927e5674b6f7269 Mon Sep 17 00:00:00 2001 From: lizzie Date: Thu, 5 Mar 2026 07:32:18 +0100 Subject: [PATCH 079/181] [vk] unify VkSurfaceKHR with Android and the rest of platforms; remove technically incorrect nullptr() ctor for handles (#2971) Removes some odd #ifdef-ing that just can use a shrimple opaque type. Also removes nullptr() ctor'ing for vulkan handles and such; it's not incorrect per se like how `void *p = 0;` isn't incorrect, just that, y'know, any static analyzer will go "woah". Also there isn't any guarantee that handles `sizeof(Handle) == sizeof(void*)` so may as well :) Signed-off-by: lizzie lizzie@eden-emu.dev Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/2971 Reviewed-by: CamilleLaVey Reviewed-by: MaranBr Co-authored-by: lizzie Co-committed-by: lizzie --- src/video_core/renderer_vulkan/blit_image.cpp | 8 +-- .../renderer_vulkan/renderer_vulkan.cpp | 8 +-- .../renderer_vulkan/vk_compute_pass.cpp | 8 +-- .../renderer_vulkan/vk_compute_pipeline.cpp | 36 ++++++------- .../renderer_vulkan/vk_graphics_pipeline.cpp | 44 ++++++++------- .../renderer_vulkan/vk_present_manager.cpp | 20 ++----- .../renderer_vulkan/vk_present_manager.h | 16 ++---- .../renderer_vulkan/vk_query_cache.cpp | 2 +- .../renderer_vulkan/vk_query_cache.h | 5 +- .../renderer_vulkan/vk_scheduler.cpp | 2 +- src/video_core/renderer_vulkan/vk_scheduler.h | 8 +-- .../renderer_vulkan/vk_swapchain.cpp | 54 +++---------------- src/video_core/renderer_vulkan/vk_swapchain.h | 22 ++------ src/video_core/vulkan_common/vulkan.h | 5 +- .../vulkan_common/vulkan_device.cpp | 2 +- .../vulkan_common/vulkan_surface.cpp | 2 +- src/video_core/vulkan_common/vulkan_wrapper.h | 44 +++++++-------- 17 files changed, 104 insertions(+), 182 deletions(-) diff --git a/src/video_core/renderer_vulkan/blit_image.cpp b/src/video_core/renderer_vulkan/blit_image.cpp index 07611ef98c..789f4da2ed 100644 --- a/src/video_core/renderer_vulkan/blit_image.cpp +++ b/src/video_core/renderer_vulkan/blit_image.cpp @@ -1032,7 +1032,7 @@ void BlitImageHelper::ConvertDepthToColorPipeline(vk::Pipeline& pipeline, VkRend VkShaderModule frag_shader = *convert_float_to_depth_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); - pipeline = device.GetLogical().CreateGraphicsPipeline({ + pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -1062,7 +1062,7 @@ void BlitImageHelper::ConvertColorToDepthPipeline(vk::Pipeline& pipeline, VkRend VkShaderModule frag_shader = *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); - pipeline = device.GetLogical().CreateGraphicsPipeline({ + pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -1093,7 +1093,7 @@ void BlitImageHelper::ConvertPipelineEx(vk::Pipeline& pipeline, VkRenderPass ren } const std::array stages = MakeStages(*full_screen_vert, *module); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); - pipeline = device.GetLogical().CreateGraphicsPipeline({ + pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -1135,7 +1135,7 @@ void BlitImageHelper::ConvertPipeline(vk::Pipeline& pipeline, VkRenderPass rende is_target_depth ? *convert_float_to_depth_frag : *convert_depth_to_float_frag; const std::array stages = MakeStages(*full_screen_vert, frag_shader); const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device); - pipeline = device.GetLogical().CreateGraphicsPipeline({ + pipeline = device.GetLogical().CreateGraphicsPipeline(VkGraphicsPipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d1e607e75f..cb1b1a5362 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -137,14 +137,8 @@ try memory_allocator, scheduler, swapchain, -#ifdef ANDROID - surface) - , -#else *surface) - , -#endif - blit_swapchain(device_memory, + , blit_swapchain(device_memory, device, memory_allocator, present_manager, diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 22e646afe9..d45a57f7bb 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -285,7 +285,7 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool, .requiredSubgroupSize = optional_subgroup_size ? *optional_subgroup_size : 32U, }; bool use_setup_size = device.IsExtSubgroupSizeControlSupported() && optional_subgroup_size; - pipeline = device.GetLogical().CreateComputePipeline({ + pipeline = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -299,7 +299,7 @@ ComputePass::ComputePass(const Device& device_, DescriptorPool& descriptor_pool, .pSpecializationInfo = nullptr, }, .layout = *layout, - .basePipelineHandle = nullptr, + .basePipelineHandle = {}, .basePipelineIndex = 0, }); } @@ -944,7 +944,7 @@ MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_, .codeSize = static_cast(code.size_bytes()), .pCode = code.data(), }); - pipelines[i] = device.GetLogical().CreateComputePipeline({ + pipelines[i] = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{ .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -958,7 +958,7 @@ MSAACopyPass::MSAACopyPass(const Device& device_, Scheduler& scheduler_, .pSpecializationInfo = nullptr, }, .layout = *layout, - .basePipelineHandle = nullptr, + .basePipelineHandle = {}, .basePipelineIndex = 0, }); }; diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 6a6fe2b830..1a62324c95 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -67,26 +67,24 @@ ComputePipeline::ComputePipeline(const Device& device_, vk::PipelineCache& pipel if (device.IsKhrPipelineExecutablePropertiesEnabled() && Settings::values.renderer_debug.GetValue()) { flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; } - pipeline = device.GetLogical().CreateComputePipeline( - { - .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .flags = flags, - .stage{ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = - device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, - .flags = 0, - .stage = VK_SHADER_STAGE_COMPUTE_BIT, - .module = *spv_module, - .pName = "main", - .pSpecializationInfo = nullptr, - }, - .layout = *pipeline_layout, - .basePipelineHandle = 0, - .basePipelineIndex = 0, + pipeline = device.GetLogical().CreateComputePipeline(VkComputePipelineCreateInfo{ + .sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = flags, + .stage{ + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = + device.IsExtSubgroupSizeControlSupported() ? &subgroup_size_ci : nullptr, + .flags = 0, + .stage = VK_SHADER_STAGE_COMPUTE_BIT, + .module = *spv_module, + .pName = "main", + .pSpecializationInfo = nullptr, }, - *pipeline_cache); + .layout = *pipeline_layout, + .basePipelineHandle = 0, + .basePipelineIndex = 0, + }, *pipeline_cache); // Log compute pipeline creation if (Settings::values.gpu_logging_enabled.GetValue()) { diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 5b11a34232..e989bf6b31 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp @@ -946,29 +946,27 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) { flags |= VK_PIPELINE_CREATE_CAPTURE_STATISTICS_BIT_KHR; } - pipeline = device.GetLogical().CreateGraphicsPipeline( - { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .flags = flags, - .stageCount = static_cast(shader_stages.size()), - .pStages = shader_stages.data(), - .pVertexInputState = &vertex_input_ci, - .pInputAssemblyState = &input_assembly_ci, - .pTessellationState = &tessellation_ci, - .pViewportState = &viewport_ci, - .pRasterizationState = &rasterization_ci, - .pMultisampleState = &multisample_ci, - .pDepthStencilState = &depth_stencil_ci, - .pColorBlendState = &color_blend_ci, - .pDynamicState = &dynamic_state_ci, - .layout = *pipeline_layout, - .renderPass = render_pass, - .subpass = 0, - .basePipelineHandle = nullptr, - .basePipelineIndex = 0, - }, - *pipeline_cache); + pipeline = device.GetLogical().CreateGraphicsPipeline({ + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = nullptr, + .flags = flags, + .stageCount = static_cast(shader_stages.size()), + .pStages = shader_stages.data(), + .pVertexInputState = &vertex_input_ci, + .pInputAssemblyState = &input_assembly_ci, + .pTessellationState = &tessellation_ci, + .pViewportState = &viewport_ci, + .pRasterizationState = &rasterization_ci, + .pMultisampleState = &multisample_ci, + .pDepthStencilState = &depth_stencil_ci, + .pColorBlendState = &color_blend_ci, + .pDynamicState = &dynamic_state_ci, + .layout = *pipeline_layout, + .renderPass = render_pass, + .subpass = 0, + .basePipelineHandle = nullptr, + .basePipelineIndex = 0, + }, *pipeline_cache); // Log graphics pipeline creation if (Settings::values.gpu_logging_enabled.GetValue()) { diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index 3b5c2e3c01..aa019a4160 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -101,22 +101,14 @@ PresentManager::PresentManager(const vk::Instance& instance_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, Swapchain& swapchain_, -#ifdef ANDROID - vk::SurfaceKHR& surface_) -#else - VkSurfaceKHR_T* surface_handle_) -#endif + VkSurfaceKHR_T* surface_) : instance{instance_} , render_window{render_window_} , device{device_} , memory_allocator{memory_allocator_} , scheduler{scheduler_} , swapchain{swapchain_} -#ifdef ANDROID , surface{surface_} -#else - , surface_handle{surface_handle_} -#endif , blit_supported{CanBlitToSwapchain(device.GetPhysical(), swapchain.GetImageViewFormat())} , use_present_thread{Settings::values.async_presentation.GetValue()} { @@ -299,11 +291,7 @@ void PresentManager::PresentThread(std::stop_token token) { } void PresentManager::RecreateSwapchain(Frame* frame) { -#ifndef ANDROID - swapchain.Create(surface_handle, frame->width, frame->height); // Pass raw pointer -#else - swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer -#endif + swapchain.Create(surface, frame->width, frame->height); // Pass raw pointer SetImageCount(); } @@ -322,7 +310,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) { // Recreate surface and swapchain if needed. if (requires_recreation) { #ifdef ANDROID - surface = CreateSurface(instance, render_window.GetWindowInfo()); + surface = *CreateSurface(instance, render_window.GetWindowInfo()).address(); #endif RecreateSwapchain(frame); } diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index aacc9b025a..3d5cc32102 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -15,8 +15,6 @@ #include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" -struct VkSurfaceKHR_T; - namespace Core::Frontend { class EmuWindow; } // namespace Core::Frontend @@ -46,11 +44,7 @@ public: MemoryAllocator& memory_allocator, Scheduler& scheduler, Swapchain& swapchain, -#ifdef ANDROID - vk::SurfaceKHR& surface); -#else - VkSurfaceKHR_T* surface_handle); -#endif + VkSurfaceKHR_T* surface); ~PresentManager(); /// Returns the last used presentation frame @@ -84,11 +78,7 @@ private: MemoryAllocator& memory_allocator; Scheduler& scheduler; Swapchain& swapchain; -#ifdef ANDROID - vk::SurfaceKHR& surface; -#else - VkSurfaceKHR_T* surface_handle; -#endif + VkSurfaceKHR_T* surface; vk::CommandPool cmdpool; std::vector frames; boost::container::deque present_queue; diff --git a/src/video_core/renderer_vulkan/vk_query_cache.cpp b/src/video_core/renderer_vulkan/vk_query_cache.cpp index 415259c72c..7cdb3acadd 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_query_cache.cpp @@ -1280,7 +1280,7 @@ void QueryCacheRuntime::EndHostConditionalRendering() { PauseHostConditionalRendering(); impl->hcr_is_set = false; impl->is_hcr_running = false; - impl->hcr_buffer = nullptr; + impl->hcr_buffer = VkBuffer{}; impl->hcr_offset = 0; } diff --git a/src/video_core/renderer_vulkan/vk_query_cache.h b/src/video_core/renderer_vulkan/vk_query_cache.h index b8dae9bc2d..e2aa4d991e 100644 --- a/src/video_core/renderer_vulkan/vk_query_cache.h +++ b/src/video_core/renderer_vulkan/vk_query_cache.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -35,7 +38,7 @@ public: ~QueryCacheRuntime(); template - void SyncValues(std::span values, VkBuffer base_src_buffer = nullptr); + void SyncValues(std::span values, VkBuffer base_src_buffer = VkBuffer{}); void Barriers(bool is_prebarrier); diff --git a/src/video_core/renderer_vulkan/vk_scheduler.cpp b/src/video_core/renderer_vulkan/vk_scheduler.cpp index 0a032cdae0..947de6a80e 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.cpp +++ b/src/video_core/renderer_vulkan/vk_scheduler.cpp @@ -377,7 +377,7 @@ void Scheduler::EndRenderPass() VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, nullptr, nullptr, vk::Span(barriers.data(), num_images)); }); - state.renderpass = nullptr; + state.renderpass = VkRenderPass{}; num_renderpass_images = 0; } diff --git a/src/video_core/renderer_vulkan/vk_scheduler.h b/src/video_core/renderer_vulkan/vk_scheduler.h index 667f136ee6..00a912f2cd 100644 --- a/src/video_core/renderer_vulkan/vk_scheduler.h +++ b/src/video_core/renderer_vulkan/vk_scheduler.h @@ -44,10 +44,10 @@ public: ~Scheduler(); /// Sends the current execution context to the GPU. - u64 Flush(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); + u64 Flush(VkSemaphore signal_semaphore = {}, VkSemaphore wait_semaphore = {}); /// Sends the current execution context to the GPU and waits for it to complete. - void Finish(VkSemaphore signal_semaphore = nullptr, VkSemaphore wait_semaphore = nullptr); + void Finish(VkSemaphore signal_semaphore = {}, VkSemaphore wait_semaphore = {}); /// Waits for the worker thread to finish executing everything. After this function returns it's /// safe to touch worker resources. @@ -237,8 +237,8 @@ private: }; struct State { - VkRenderPass renderpass = nullptr; - VkFramebuffer framebuffer = nullptr; + VkRenderPass renderpass{}; + VkFramebuffer framebuffer{}; VkExtent2D render_area = {0, 0}; GraphicsPipeline* graphics_pipeline = nullptr; bool is_rescaling = false; diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp index b89e981444..cd8f948d8b 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.cpp +++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp @@ -109,38 +109,22 @@ VkCompositeAlphaFlagBitsKHR ChooseAlphaFlags(const VkSurfaceCapabilitiesKHR& cap } // Anonymous namespace Swapchain::Swapchain( -#ifdef ANDROID - VkSurfaceKHR surface_, -#else - VkSurfaceKHR_T* surface_handle_, -#endif + VkSurfaceKHR_T* surface_, const Device& device_, Scheduler& scheduler_, u32 width_, u32 height_) -#ifdef ANDROID : surface(surface_) -#else - : surface_handle{surface_handle_} -#endif , device{device_} , scheduler{scheduler_} { -#ifdef ANDROID Create(surface, width_, height_); -#else - Create(surface_handle, width_, height_); -#endif } Swapchain::~Swapchain() = default; void Swapchain::Create( -#ifdef ANDROID - VkSurfaceKHR surface_, -#else - VkSurfaceKHR_T* surface_handle_, -#endif + VkSurfaceKHR_T* surface_, u32 width_, u32 height_) { @@ -148,18 +132,10 @@ void Swapchain::Create( is_suboptimal = false; width = width_; height = height_; -#ifdef ANDROID surface = surface_; -#else - surface_handle = surface_handle_; -#endif const auto physical_device = device.GetPhysical(); -#ifdef ANDROID - const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface)}; -#else - const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(surface_handle)}; -#endif + const auto capabilities{physical_device.GetSurfaceCapabilitiesKHR(VkSurfaceKHR(surface))}; if (capabilities.maxImageExtent.width == 0 || capabilities.maxImageExtent.height == 0) { return; } @@ -254,14 +230,8 @@ void Swapchain::Present(VkSemaphore render_semaphore) { void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { const auto physical_device{device.GetPhysical()}; - -#ifdef ANDROID - const auto formats{physical_device.GetSurfaceFormatsKHR(surface)}; - const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface); -#else - const auto formats{physical_device.GetSurfaceFormatsKHR(surface_handle)}; - const auto present_modes = physical_device.GetSurfacePresentModesKHR(surface_handle); -#endif + const auto formats{physical_device.GetSurfaceFormatsKHR(VkSurfaceKHR(surface))}; + const auto present_modes = physical_device.GetSurfacePresentModesKHR(VkSurfaceKHR(surface)); has_mailbox = std::find(present_modes.begin(), present_modes.end(), VK_PRESENT_MODE_MAILBOX_KHR) != present_modes.end(); @@ -290,11 +260,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, .pNext = nullptr, .flags = 0, -#ifdef ANDROID - .surface = surface, -#else - .surface = surface_handle, -#endif + .surface = VkSurfaceKHR(surface), .minImageCount = requested_image_count, .imageFormat = surface_format.format, .imageColorSpace = surface_format.colorSpace, @@ -313,7 +279,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { .compositeAlpha = alpha_flags, .presentMode = present_mode, .clipped = VK_FALSE, - .oldSwapchain = nullptr, + .oldSwapchain = VkSwapchainKHR{}, }; const u32 graphics_family{device.GetGraphicsFamily()}; const u32 present_family{device.GetPresentFamily()}; @@ -345,11 +311,7 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) { swapchain_ci.flags |= VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR; } // Request the size again to reduce the possibility of a TOCTOU race condition. -#ifdef ANDROID - const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface); -#else - const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(surface_handle); -#endif + const auto updated_capabilities = physical_device.GetSurfaceCapabilitiesKHR(VkSurfaceKHR(surface)); swapchain_ci.imageExtent = ChooseSwapExtent(updated_capabilities, width, height); // Don't add code within this and the swapchain creation. swapchain = device.GetLogical().CreateSwapchainKHR(swapchain_ci); diff --git a/src/video_core/renderer_vulkan/vk_swapchain.h b/src/video_core/renderer_vulkan/vk_swapchain.h index 7e99bf8fa7..d926cc118a 100644 --- a/src/video_core/renderer_vulkan/vk_swapchain.h +++ b/src/video_core/renderer_vulkan/vk_swapchain.h @@ -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 2019 yuzu Emulator Project @@ -11,8 +11,6 @@ #include "common/common_types.h" #include "video_core/vulkan_common/vulkan_wrapper.h" -struct VkSurfaceKHR_T; - namespace Layout { struct FramebufferLayout; } @@ -25,11 +23,7 @@ class Scheduler; class Swapchain { public: explicit Swapchain( -#ifdef ANDROID - VkSurfaceKHR surface, -#else - VkSurfaceKHR_T* surface_handle, -#endif + VkSurfaceKHR_T* surface, const Device& device, Scheduler& scheduler, u32 width, @@ -38,11 +32,7 @@ public: /// Creates (or recreates) the swapchain with a given size. void Create( -#ifdef ANDROID - VkSurfaceKHR surface, -#else - VkSurfaceKHR_T* surface_handle, -#endif + VkSurfaceKHR_T* surface, u32 width, u32 height); @@ -128,11 +118,7 @@ private: bool NeedsPresentModeUpdate() const; -#ifdef ANDROID - VkSurfaceKHR surface; -#else - VkSurfaceKHR_T* surface_handle; -#endif + VkSurfaceKHR_T* surface; const Device& device; Scheduler& scheduler; diff --git a/src/video_core/vulkan_common/vulkan.h b/src/video_core/vulkan_common/vulkan.h index 8d2e8e2a37..2cc0f0d7f0 100644 --- a/src/video_core/vulkan_common/vulkan.h +++ b/src/video_core/vulkan_common/vulkan.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project @@ -40,3 +40,6 @@ #undef False #undef None #undef True + +// "Catch-all" handle for both Android and.. the rest of platforms +struct VkSurfaceKHR_T; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index a2ff3ee6ed..b51c57d380 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -419,7 +419,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR : instance{instance_}, dld{dld_}, physical{physical_}, format_properties(GetFormatProperties(physical)) { // Get suitability and device properties. - const bool is_suitable = GetSuitability(surface != nullptr); + const bool is_suitable = GetSuitability(surface != VkSurfaceKHR{}); const VkDriverId driver_id = properties.driver.driverID; diff --git a/src/video_core/vulkan_common/vulkan_surface.cpp b/src/video_core/vulkan_common/vulkan_surface.cpp index dc65d3960a..761b7759c8 100644 --- a/src/video_core/vulkan_common/vulkan_surface.cpp +++ b/src/video_core/vulkan_common/vulkan_surface.cpp @@ -15,7 +15,7 @@ vk::SurfaceKHR CreateSurface( const vk::Instance& instance, [[maybe_unused]] const Core::Frontend::EmuWindow::WindowSystemInfo& window_info) { [[maybe_unused]] const vk::InstanceDispatch& dld = instance.Dispatch(); - VkSurfaceKHR unsafe_surface = nullptr; + VkSurfaceKHR unsafe_surface = VkSurfaceKHR{}; #ifdef _WIN32 if (window_info.type == Core::Frontend::WindowSystemType::Windows) { diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 5c04132f7b..872fbd858e 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -404,13 +404,13 @@ public: /// Construct a handle transferring the ownership from another handle. Handle(Handle&& rhs) noexcept - : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, dld{rhs.dld} {} + : handle{std::exchange(rhs.handle, Type{})}, owner{rhs.owner}, dld{rhs.dld} {} /// Assign the current handle transferring the ownership from another handle. /// Destroys any previously held object. Handle& operator=(Handle&& rhs) noexcept { Release(); - handle = std::exchange(rhs.handle, nullptr); + handle = std::exchange(rhs.handle, Type{}); owner = rhs.owner; dld = rhs.dld; return *this; @@ -424,7 +424,7 @@ public: /// Destroys any held object. void reset() noexcept { Release(); - handle = nullptr; + handle = Type{}; } /// Returns the address of the held object. @@ -440,7 +440,7 @@ public: /// Returns true when there's a held object. explicit operator bool() const noexcept { - return handle != nullptr; + return handle != Type{}; } #ifndef ANDROID @@ -455,7 +455,7 @@ public: #endif protected: - Type handle = nullptr; + Type handle{}; OwnerType owner = nullptr; const Dispatch* dld = nullptr; @@ -463,7 +463,7 @@ private: /// Destroys the held object if it exists. void Release() noexcept { if (handle) { - Destroy(owner, handle, *dld); + Destroy(OwnerType(owner), Type(handle), *dld); } } }; @@ -506,7 +506,7 @@ public: /// Destroys any held object. void reset() noexcept { Release(); - handle = nullptr; + handle = {}; } /// Returns the address of the held object. @@ -522,7 +522,7 @@ public: /// Returns true when there's a held object. explicit operator bool() const noexcept { - return handle != nullptr; + return handle != Type{}; } #ifndef ANDROID @@ -537,7 +537,7 @@ public: #endif protected: - Type handle = nullptr; + Type handle{}; const Dispatch* dld = nullptr; private: @@ -607,7 +607,7 @@ private: std::unique_ptr allocations; std::size_t num = 0; VkDevice device = nullptr; - PoolType pool = nullptr; + PoolType pool{}; const DeviceDispatch* dld = nullptr; }; @@ -669,12 +669,12 @@ public: Image& operator=(const Image&) = delete; Image(Image&& rhs) noexcept - : handle{std::exchange(rhs.handle, nullptr)}, usage{rhs.usage}, owner{rhs.owner}, + : handle{std::exchange(rhs.handle, VkImage{})}, usage{rhs.usage}, owner{rhs.owner}, allocator{rhs.allocator}, allocation{rhs.allocation}, dld{rhs.dld} {} Image& operator=(Image&& rhs) noexcept { Release(); - handle = std::exchange(rhs.handle, nullptr); + handle = std::exchange(rhs.handle, VkImage{}); usage = rhs.usage; owner = rhs.owner; allocator = rhs.allocator; @@ -693,11 +693,11 @@ public: void reset() noexcept { Release(); - handle = nullptr; + handle = VkImage{}; } explicit operator bool() const noexcept { - return handle != nullptr; + return handle != VkImage{}; } void SetObjectNameEXT(const char* name) const; @@ -709,7 +709,7 @@ public: private: void Release() const noexcept; - VkImage handle = nullptr; + VkImage handle{}; VkImageUsageFlags usage{}; VkDevice owner = nullptr; VmaAllocator allocator = nullptr; @@ -730,13 +730,13 @@ public: Buffer& operator=(const Buffer&) = delete; Buffer(Buffer&& rhs) noexcept - : handle{std::exchange(rhs.handle, nullptr)}, owner{rhs.owner}, allocator{rhs.allocator}, + : handle{std::exchange(rhs.handle, VkBuffer{})}, owner{rhs.owner}, allocator{rhs.allocator}, allocation{rhs.allocation}, mapped{rhs.mapped}, is_coherent{rhs.is_coherent}, dld{rhs.dld} {} Buffer& operator=(Buffer&& rhs) noexcept { Release(); - handle = std::exchange(rhs.handle, nullptr); + handle = std::exchange(rhs.handle, VkBuffer{}); owner = rhs.owner; allocator = rhs.allocator; allocation = rhs.allocation; @@ -756,11 +756,11 @@ public: void reset() noexcept { Release(); - handle = nullptr; + handle = VkBuffer{}; } explicit operator bool() const noexcept { - return handle != nullptr; + return handle != VkBuffer{}; } /// Returns the host mapped memory, an empty span otherwise. @@ -786,7 +786,7 @@ public: private: void Release() const noexcept; - VkBuffer handle = nullptr; + VkBuffer handle{}; VkDevice owner = nullptr; VmaAllocator allocator = nullptr; VmaAllocation allocation = nullptr; @@ -1020,10 +1020,10 @@ public: [[nodiscard]] PipelineLayout CreatePipelineLayout(const VkPipelineLayoutCreateInfo& ci) const; [[nodiscard]] Pipeline CreateGraphicsPipeline(const VkGraphicsPipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + VkPipelineCache cache = {}) const; [[nodiscard]] Pipeline CreateComputePipeline(const VkComputePipelineCreateInfo& ci, - VkPipelineCache cache = nullptr) const; + VkPipelineCache cache = {}) const; [[nodiscard]] Sampler CreateSampler(const VkSamplerCreateInfo& ci) const; From 529b0694995c84c51515022c52a66c67ceacdc65 Mon Sep 17 00:00:00 2001 From: xbzk Date: Thu, 5 Mar 2026 13:58:46 +0100 Subject: [PATCH 080/181] [android,ui] fixed top disalignment between buttons of each column in settings fragment (#3675) this silly little thing tickles obsessive compulsive disturbed fellas a lot hu3 was shipped along PR 3660, which was rediscussed for other reason, hence this tiny lonely PR. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3675 Reviewed-by: DraVee Reviewed-by: MaranBr Co-authored-by: xbzk Co-committed-by: xbzk --- .../features/fetcher/SpacingItemDecoration.kt | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt index f3d000a739..b3ffcc2a35 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/SpacingItemDecoration.kt @@ -1,10 +1,11 @@ -// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later package org.yuzu.yuzu_emu.features.fetcher import android.graphics.Rect import android.view.View +import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecoration() { @@ -15,8 +16,20 @@ class SpacingItemDecoration(private val spacing: Int) : RecyclerView.ItemDecorat state: RecyclerView.State ) { outRect.bottom = spacing - if (parent.getChildAdapterPosition(view) == 0) { + + val position = parent.getChildAdapterPosition(view) + if (position == RecyclerView.NO_POSITION) return + + if (position == 0) { outRect.top = spacing + return + } + + // If the item is in the first row, but NOT in first column add top spacing as well + val layoutManager = parent.layoutManager + if (layoutManager is GridLayoutManager && layoutManager.spanSizeLookup.getSpanGroupIndex(position, layoutManager.spanCount) == 0) { + outRect.top = spacing + return } } } From 23566a1f7dc639946e6d3935f4951d4d2bce8461 Mon Sep 17 00:00:00 2001 From: MaranBr Date: Fri, 6 Mar 2026 15:02:59 +0100 Subject: [PATCH 081/181] [prepo] Add support for missing PlayReport commands (#3674) This fixes: `[ 433.095195] Debug core\hle\service\service.cpp:operator ():69: Assertion Failed! Unknown / unimplemented function '10107': port='prepo:u' cmd_buf={[0]=0x110006, [1]=0x80000014, [2]=0x1, [3]=0x0, [4]=0x0, [5]=0x191080, [6]=0x5A7350F8, [7]=0x112, [8]=0x5A735158}` Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3674 Reviewed-by: CamilleLaVey Reviewed-by: DraVee Reviewed-by: Maufeat Co-authored-by: MaranBr Co-committed-by: MaranBr --- src/core/hle/service/prepo/prepo.cpp | 8 +++++--- src/core/reporter.h | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp index 4fc59d0e10..bfc5539903 100644 --- a/src/core/hle/service/prepo/prepo.cpp +++ b/src/core/hle/service/prepo/prepo.cpp @@ -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 @@ -28,8 +28,10 @@ public: {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUserOld"}, {10102, &PlayReport::SaveReport, "SaveReportOld2"}, {10103, &PlayReport::SaveReportWithUser, "SaveReportWithUserOld2"}, - {10104, &PlayReport::SaveReport, "SaveReport"}, - {10105, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, + {10104, &PlayReport::SaveReport, "SaveReportOld3"}, + {10105, &PlayReport::SaveReportWithUser, "SaveReportWithUserOld3"}, + {10106, &PlayReport::SaveReport, "SaveReport"}, + {10107, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, {10200, &PlayReport::RequestImmediateTransmission, "RequestImmediateTransmission"}, {10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"}, {10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"}, diff --git a/src/core/reporter.h b/src/core/reporter.h index db1ca3ba0c..1eee8da31f 100644 --- a/src/core/reporter.h +++ b/src/core/reporter.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -53,6 +56,7 @@ public: enum class PlayReportType { Old, Old2, + Old3, New, System, }; From c70b857c4f8324621c3d3f7dfe659856c8000878 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 6 Mar 2026 15:04:38 +0100 Subject: [PATCH 082/181] [video_core/engines] Macro HLE inline (#3653) Should slightly boost perf on android, Desktop is mainly unaffected (for now) Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3653 Reviewed-by: CamilleLaVey Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- src/video_core/engines/maxwell_3d.cpp | 21 +- src/video_core/engines/maxwell_3d.h | 2 +- src/video_core/macro.cpp | 1103 ++++++++++--------------- src/video_core/macro.h | 166 +++- 4 files changed, 586 insertions(+), 706 deletions(-) diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 7dbb8f6617..e48f294a5a 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -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 @@ -26,8 +26,15 @@ namespace Tegra::Engines { constexpr u32 MacroRegistersStart = 0xE00; Maxwell3D::Maxwell3D(Core::System& system_, MemoryManager& memory_manager_) - : draw_manager{std::make_unique(this)}, system{system_}, - memory_manager{memory_manager_}, macro_engine{GetMacroEngine(*this)}, upload_state{memory_manager, regs.upload} { + : draw_manager{std::make_unique(this)}, system{system_} + , memory_manager{memory_manager_} +#ifdef ARCHITECTURE_x86_64 + , macro_engine(bool(Settings::values.disable_macro_jit)) +#else + , macro_engine(true) +#endif + , upload_state{memory_manager, regs.upload} +{ dirty.flags.flip(); InitializeRegisterDefaults(); execution_mask.reset(); @@ -328,9 +335,9 @@ void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argume shadow_state.shadow_ram_control = static_cast(nonshadow_argument); return; case MAXWELL3D_REG_INDEX(load_mme.instruction_ptr): - return macro_engine->ClearCode(regs.load_mme.instruction_ptr); + return macro_engine.ClearCode(regs.load_mme.instruction_ptr); case MAXWELL3D_REG_INDEX(load_mme.instruction): - return macro_engine->AddCode(regs.load_mme.instruction_ptr, argument); + return macro_engine.AddCode(regs.load_mme.instruction_ptr, argument); case MAXWELL3D_REG_INDEX(load_mme.start_address): return ProcessMacroBind(argument); case MAXWELL3D_REG_INDEX(falcon[4]): @@ -398,7 +405,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector& parameters) ((method - MacroRegistersStart) >> 1) % static_cast(macro_positions.size()); // Execute the current macro. - macro_engine->Execute(macro_positions[entry], parameters); + macro_engine.Execute(*this, macro_positions[entry], parameters); draw_manager->DrawDeferred(); } @@ -464,7 +471,7 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, } void Maxwell3D::ProcessMacroUpload(u32 data) { - macro_engine->AddCode(regs.load_mme.instruction_ptr++, data); + macro_engine.AddCode(regs.load_mme.instruction_ptr++, data); } void Maxwell3D::ProcessMacroBind(u32 data) { diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 5312c04b6f..52546e4279 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -3203,7 +3203,7 @@ private: std::vector macro_params; /// Interpreter for the macro codes uploaded to the GPU. - std::optional macro_engine; + MacroEngine macro_engine; Upload::State upload_state; diff --git a/src/video_core/macro.cpp b/src/video_core/macro.cpp index 3fe69be4dd..0d1fe0a52b 100644 --- a/src/video_core/macro.cpp +++ b/src/video_core/macro.cpp @@ -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 2020 yuzu Emulator Project @@ -10,6 +10,7 @@ #include #include +#include #ifdef ARCHITECTURE_x86_64 // xbyak hates human beings #ifdef __GNUC__ @@ -73,601 +74,411 @@ bool IsTopologySafe(Maxwell3D::Regs::PrimitiveTopology topology) { } } -class HLEMacroImpl : public CachedMacro { -public: - explicit HLEMacroImpl(Maxwell3D& maxwell3d_) - : CachedMacro(maxwell3d_) - {} -}; +} // Anonymous namespace -/// @note: these macros have two versions, a normal and extended version, with the extended version -/// also assigning the base vertex/instance. -template -class HLE_DrawArraysIndirect final : public HLEMacroImpl { -public: - explicit HLE_DrawArraysIndirect(Maxwell3D& maxwell3d_) - : HLEMacroImpl(maxwell3d_) - {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - auto topology = static_cast(parameters[0]); - if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { - Fallback(parameters); - return; - } - - auto& params = maxwell3d.draw_manager->GetIndirectParams(); - params.is_byte_count = false; - params.is_indexed = false; - params.include_count = false; - params.count_start_address = 0; - params.indirect_start_address = maxwell3d.GetMacroAddress(1); - params.buffer_size = 4 * sizeof(u32); - params.max_draw_counts = 1; - params.stride = 0; - - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - } - - maxwell3d.draw_manager->DrawArrayIndirect(topology); - - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::None; - maxwell3d.replace_table.clear(); - } +void HLE_DrawArraysIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + auto topology = static_cast(parameters[0]); + if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { + Fallback(maxwell3d, parameters); + return; } -private: - void Fallback(const std::vector& parameters) { - SCOPE_EXIT { - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::None; - maxwell3d.replace_table.clear(); - } - }; - maxwell3d.RefreshParameters(); - const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); + auto& params = maxwell3d.draw_manager->GetIndirectParams(); + params.is_byte_count = false; + params.is_indexed = false; + params.include_count = false; + params.count_start_address = 0; + params.indirect_start_address = maxwell3d.GetMacroAddress(1); + params.buffer_size = 4 * sizeof(u32); + params.max_draw_counts = 1; + params.stride = 0; - auto topology = static_cast(parameters[0]); - const u32 vertex_first = parameters[3]; - const u32 vertex_count = parameters[1]; - - if (!IsTopologySafe(topology) && size_t(maxwell3d.GetMaxCurrentVertices()) < size_t(vertex_first) + size_t(vertex_count)) { - ASSERT(false && "Faulty draw!"); - return; - } - - const u32 base_instance = parameters[4]; - if (extended) { - maxwell3d.regs.global_base_instance_index = base_instance; - maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType( - 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - } - - maxwell3d.draw_manager->DrawArray(topology, vertex_first, vertex_count, base_instance, - instance_count); - - if (extended) { - maxwell3d.regs.global_base_instance_index = 0; - maxwell3d.engine_state = Maxwell3D::EngineHint::None; - maxwell3d.replace_table.clear(); - } - } -}; - -/* - * @note: these macros have two versions, a normal and extended version, with the extended version - * also assigning the base vertex/instance. - */ -template -class HLE_DrawIndexedIndirect final : public HLEMacroImpl { -public: - explicit HLE_DrawIndexedIndirect(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - auto topology = static_cast(parameters[0]); - if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { - Fallback(parameters); - return; - } - - const u32 estimate = static_cast(maxwell3d.EstimateIndexBufferSize()); - const u32 element_base = parameters[4]; - const u32 base_instance = parameters[5]; - maxwell3d.regs.vertex_id_base = element_base; - maxwell3d.regs.global_base_vertex_index = element_base; - maxwell3d.regs.global_base_instance_index = base_instance; - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); - maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - } - auto& params = maxwell3d.draw_manager->GetIndirectParams(); - params.is_byte_count = false; - params.is_indexed = true; - params.include_count = false; - params.count_start_address = 0; - params.indirect_start_address = maxwell3d.GetMacroAddress(1); - params.buffer_size = 5 * sizeof(u32); - params.max_draw_counts = 1; - params.stride = 0; - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); - maxwell3d.regs.vertex_id_base = 0x0; - maxwell3d.regs.global_base_vertex_index = 0x0; - maxwell3d.regs.global_base_instance_index = 0x0; - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::None; - maxwell3d.replace_table.clear(); - } - } - -private: - void Fallback(const std::vector& parameters) { - maxwell3d.RefreshParameters(); - const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); - const u32 element_base = parameters[4]; - const u32 base_instance = parameters[5]; - maxwell3d.regs.vertex_id_base = element_base; - maxwell3d.regs.global_base_vertex_index = element_base; - maxwell3d.regs.global_base_instance_index = base_instance; - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); - maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - } - - maxwell3d.draw_manager->DrawIndex(Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); - - maxwell3d.regs.vertex_id_base = 0x0; - maxwell3d.regs.global_base_vertex_index = 0x0; - maxwell3d.regs.global_base_instance_index = 0x0; - if (extended) { - maxwell3d.engine_state = Maxwell3D::EngineHint::None; - maxwell3d.replace_table.clear(); - } - } -}; - -class HLE_MultiLayerClear final : public HLEMacroImpl { -public: - explicit HLE_MultiLayerClear(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - ASSERT(parameters.size() == 1); - - const Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; - const u32 rt_index = clear_params.RT; - const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; - ASSERT(clear_params.layer == 0); - - maxwell3d.regs.clear_surface.raw = clear_params.raw; - maxwell3d.draw_manager->Clear(num_layers); - } -}; - -class HLE_MultiDrawIndexedIndirectCount final : public HLEMacroImpl { -public: - explicit HLE_MultiDrawIndexedIndirectCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]); - if (!IsTopologySafe(topology)) { - Fallback(parameters); - return; - } - - const u32 start_indirect = parameters[0]; - const u32 end_indirect = parameters[1]; - if (start_indirect >= end_indirect) { - // Nothing to do. - return; - } - - const u32 padding = parameters[3]; // padding is in words - - // size of each indirect segment - const u32 indirect_words = 5 + padding; - const u32 stride = indirect_words * sizeof(u32); - const std::size_t draw_count = end_indirect - start_indirect; - const u32 estimate = static_cast(maxwell3d.EstimateIndexBufferSize()); - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - auto& params = maxwell3d.draw_manager->GetIndirectParams(); - params.is_byte_count = false; - params.is_indexed = true; - params.include_count = true; - params.count_start_address = maxwell3d.GetMacroAddress(4); - params.indirect_start_address = maxwell3d.GetMacroAddress(5); - params.buffer_size = stride * draw_count; - params.max_draw_counts = draw_count; - params.stride = stride; - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType( - 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); - maxwell3d.SetHLEReplacementAttributeType( - 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - maxwell3d.SetHLEReplacementAttributeType(0, 0x648, - Maxwell3D::HLEReplacementAttributeType::DrawID); - maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance); + } + + maxwell3d.draw_manager->DrawArrayIndirect(topology); + + if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::None; maxwell3d.replace_table.clear(); } - -private: - void Fallback(const std::vector& parameters) { - SCOPE_EXIT { - // Clean everything. - maxwell3d.regs.vertex_id_base = 0x0; +} +void HLE_DrawArraysIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { + SCOPE_EXIT { + if (extended) { maxwell3d.engine_state = Maxwell3D::EngineHint::None; maxwell3d.replace_table.clear(); - }; - maxwell3d.RefreshParameters(); - const u32 start_indirect = parameters[0]; - const u32 end_indirect = parameters[1]; - if (start_indirect >= end_indirect) { - // Nothing to do. - return; - } - const auto topology = static_cast(parameters[2]); - const u32 padding = parameters[3]; - const std::size_t max_draws = parameters[4]; - - const u32 indirect_words = 5 + padding; - const std::size_t first_draw = start_indirect; - const std::size_t effective_draws = end_indirect - start_indirect; - const std::size_t last_draw = start_indirect + (std::min)(effective_draws, max_draws); - - for (std::size_t index = first_draw; index < last_draw; index++) { - const std::size_t base = index * indirect_words + 5; - const u32 base_vertex = parameters[base + 3]; - const u32 base_instance = parameters[base + 4]; - maxwell3d.regs.vertex_id_base = base_vertex; - maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; - maxwell3d.SetHLEReplacementAttributeType( - 0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); - maxwell3d.SetHLEReplacementAttributeType( - 0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); - maxwell3d.CallMethod(0x8e3, 0x648, true); - maxwell3d.CallMethod(0x8e4, static_cast(index), true); - maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; - maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base], - base_vertex, base_instance, parameters[base + 1]); } + }; + maxwell3d.RefreshParameters(); + const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); + auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0]); + const u32 vertex_first = parameters[3]; + const u32 vertex_count = parameters[1]; + if (!IsTopologySafe(topology) && size_t(maxwell3d.GetMaxCurrentVertices()) < size_t(vertex_first) + size_t(vertex_count)) { + ASSERT(false && "Faulty draw!"); + return; } -}; - -class HLE_DrawIndirectByteCount final : public HLEMacroImpl { -public: - explicit HLE_DrawIndirectByteCount(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback(); - - auto topology = static_cast(parameters[0] & 0xFFFFU); - if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) { - Fallback(parameters); - return; - } - auto& params = maxwell3d.draw_manager->GetIndirectParams(); - params.is_byte_count = true; - params.is_indexed = false; - params.include_count = false; - params.count_start_address = 0; - params.indirect_start_address = maxwell3d.GetMacroAddress(2); - params.buffer_size = 4; - params.max_draw_counts = 1; - params.stride = parameters[1]; - maxwell3d.regs.draw.begin = parameters[0]; - maxwell3d.regs.draw_auto_stride = parameters[1]; - maxwell3d.regs.draw_auto_byte_count = parameters[2]; - - maxwell3d.draw_manager->DrawArrayIndirect(topology); + const u32 base_instance = parameters[4]; + if (extended) { + maxwell3d.regs.global_base_instance_index = base_instance; + maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseInstance); } - -private: - void Fallback(const std::vector& parameters) { - maxwell3d.RefreshParameters(); - - maxwell3d.regs.draw.begin = parameters[0]; - maxwell3d.regs.draw_auto_stride = parameters[1]; - maxwell3d.regs.draw_auto_byte_count = parameters[2]; - - maxwell3d.draw_manager->DrawArray( - maxwell3d.regs.draw.topology, 0, - maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); - } -}; - -class HLE_C713C83D8F63CCF3 final : public HLEMacroImpl { -public: - explicit HLE_C713C83D8F63CCF3(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2; - const u32 address = maxwell3d.regs.shadow_scratch[24]; - auto& const_buffer = maxwell3d.regs.const_buffer; - const_buffer.size = 0x7000; - const_buffer.address_high = (address >> 24) & 0xFF; - const_buffer.address_low = address << 8; - const_buffer.offset = offset; - } -}; - -class HLE_D7333D26E0A93EDE final : public HLEMacroImpl { -public: - explicit HLE_D7333D26E0A93EDE(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - const size_t index = parameters[0]; - const u32 address = maxwell3d.regs.shadow_scratch[42 + index]; - const u32 size = maxwell3d.regs.shadow_scratch[47 + index]; - auto& const_buffer = maxwell3d.regs.const_buffer; - const_buffer.size = size; - const_buffer.address_high = (address >> 24) & 0xFF; - const_buffer.address_low = address << 8; - } -}; - -class HLE_BindShader final : public HLEMacroImpl { -public: - explicit HLE_BindShader(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - auto& regs = maxwell3d.regs; - const u32 index = parameters[0]; - if ((parameters[1] - regs.shadow_scratch[28 + index]) == 0) { - return; - } - - regs.pipelines[index & 0xF].offset = parameters[2]; - maxwell3d.dirty.flags[VideoCommon::Dirty::Shaders] = true; - regs.shadow_scratch[28 + index] = parameters[1]; - regs.shadow_scratch[34 + index] = parameters[2]; - - const u32 address = parameters[4]; - auto& const_buffer = regs.const_buffer; - const_buffer.size = 0x10000; - const_buffer.address_high = (address >> 24) & 0xFF; - const_buffer.address_low = address << 8; - - const size_t bind_group_id = parameters[3] & 0x7F; - auto& bind_group = regs.bind_groups[bind_group_id]; - bind_group.raw_config = 0x11; - maxwell3d.ProcessCBBind(bind_group_id); - } -}; - -class HLE_SetRasterBoundingBox final : public HLEMacroImpl { -public: - explicit HLE_SetRasterBoundingBox(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - const u32 raster_mode = parameters[0]; - auto& regs = maxwell3d.regs; - const u32 raster_enabled = maxwell3d.regs.conservative_raster_enable; - const u32 scratch_data = maxwell3d.regs.shadow_scratch[52]; - regs.raster_bounding_box.raw = raster_mode & 0xFFFFF00F; - regs.raster_bounding_box.pad.Assign(scratch_data & raster_enabled); - } -}; - -template -class HLE_ClearConstBuffer final : public HLEMacroImpl { -public: - explicit HLE_ClearConstBuffer(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - static constexpr std::array zeroes{}; - auto& regs = maxwell3d.regs; - regs.const_buffer.size = u32(base_size); - regs.const_buffer.address_high = parameters[0]; - regs.const_buffer.address_low = parameters[1]; - regs.const_buffer.offset = 0; - maxwell3d.ProcessCBMultiData(zeroes.data(), parameters[2] * 4); - } -}; - -class HLE_ClearMemory final : public HLEMacroImpl { -public: - explicit HLE_ClearMemory(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - - const u32 needed_memory = parameters[2] / sizeof(u32); - if (needed_memory > zero_memory.size()) { - zero_memory.resize(needed_memory, 0); - } - auto& regs = maxwell3d.regs; - regs.upload.line_length_in = parameters[2]; - regs.upload.line_count = 1; - regs.upload.dest.address_high = parameters[0]; - regs.upload.dest.address_low = parameters[1]; - maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); - maxwell3d.CallMultiMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), zero_memory.data(), needed_memory, needed_memory); - } - -private: - std::vector zero_memory; -}; - -class HLE_TransformFeedbackSetup final : public HLEMacroImpl { -public: - explicit HLE_TransformFeedbackSetup(Maxwell3D& maxwell3d_) : HLEMacroImpl(maxwell3d_) {} - - void Execute(const std::vector& parameters, [[maybe_unused]] u32 method) override { - maxwell3d.RefreshParameters(); - - auto& regs = maxwell3d.regs; - regs.transform_feedback_enabled = 1; - regs.transform_feedback.buffers[0].start_offset = 0; - regs.transform_feedback.buffers[1].start_offset = 0; - regs.transform_feedback.buffers[2].start_offset = 0; - regs.transform_feedback.buffers[3].start_offset = 0; - - regs.upload.line_length_in = 4; - regs.upload.line_count = 1; - regs.upload.dest.address_high = parameters[0]; - regs.upload.dest.address_low = parameters[1]; - maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); - maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), regs.transform_feedback.controls[0].stride, true); - - maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address()); - } -}; - -} // Anonymous namespace - -HLEMacro::HLEMacro(Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {} - -HLEMacro::~HLEMacro() = default; - -std::unique_ptr HLEMacro::GetHLEProgram(u64 hash) const { - // Compiler will make you a GREAT job at making an ad-hoc hash table :) - switch (hash) { - case 0x0D61FC9FAAC9FCADULL: return std::make_unique>(maxwell3d); - case 0x8A4D173EB99A8603ULL: return std::make_unique>(maxwell3d); - case 0x771BB18C62444DA0ULL: return std::make_unique>(maxwell3d); - case 0x0217920100488FF7ULL: return std::make_unique>(maxwell3d); - case 0x3F5E74B9C9A50164ULL: return std::make_unique(maxwell3d); - case 0xEAD26C3E2109B06BULL: return std::make_unique(maxwell3d); - case 0xC713C83D8F63CCF3ULL: return std::make_unique(maxwell3d); - case 0xD7333D26E0A93EDEULL: return std::make_unique(maxwell3d); - case 0xEB29B2A09AA06D38ULL: return std::make_unique(maxwell3d); - case 0xDB1341DBEB4C8AF7ULL: return std::make_unique(maxwell3d); - case 0x6C97861D891EDf7EULL: return std::make_unique>(maxwell3d); - case 0xD246FDDF3A6173D7ULL: return std::make_unique>(maxwell3d); - case 0xEE4D0004BEC8ECF4ULL: return std::make_unique(maxwell3d); - case 0xFC0CF27F5FFAA661ULL: return std::make_unique(maxwell3d); - case 0xB5F74EDB717278ECULL: return std::make_unique(maxwell3d); - default: - return nullptr; + maxwell3d.draw_manager->DrawArray(topology, vertex_first, vertex_count, base_instance, instance_count); + if (extended) { + maxwell3d.regs.global_base_instance_index = 0; + maxwell3d.engine_state = Maxwell3D::EngineHint::None; + maxwell3d.replace_table.clear(); } } -namespace { -class MacroInterpreterImpl final : public CachedMacro { -public: - explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, const std::vector& code_) - : CachedMacro(maxwell3d_) - , code{code_} - {} +void HLE_DrawIndexedIndirect::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + auto topology = static_cast(parameters[0]); + if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) { + Fallback(maxwell3d, parameters); + return; + } - void Execute(const std::vector& params, u32 method) override; + const u32 estimate = u32(maxwell3d.EstimateIndexBufferSize()); + const u32 element_base = parameters[4]; + const u32 base_instance = parameters[5]; + maxwell3d.regs.vertex_id_base = element_base; + maxwell3d.regs.global_base_vertex_index = element_base; + maxwell3d.regs.global_base_instance_index = base_instance; + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + if (extended) { + maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); + maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); + } + auto& params = maxwell3d.draw_manager->GetIndirectParams(); + params.is_byte_count = false; + params.is_indexed = true; + params.include_count = false; + params.count_start_address = 0; + params.indirect_start_address = maxwell3d.GetMacroAddress(1); + params.buffer_size = 5 * sizeof(u32); + params.max_draw_counts = 1; + params.stride = 0; + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); + maxwell3d.regs.vertex_id_base = 0x0; + maxwell3d.regs.global_base_vertex_index = 0x0; + maxwell3d.regs.global_base_instance_index = 0x0; + if (extended) { + maxwell3d.engine_state = Maxwell3D::EngineHint::None; + maxwell3d.replace_table.clear(); + } +} +void HLE_DrawIndexedIndirect::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { + maxwell3d.RefreshParameters(); + const u32 instance_count = (maxwell3d.GetRegisterValue(0xD1B) & parameters[2]); + const u32 element_base = parameters[4]; + const u32 base_instance = parameters[5]; + maxwell3d.regs.vertex_id_base = element_base; + maxwell3d.regs.global_base_vertex_index = element_base; + maxwell3d.regs.global_base_instance_index = base_instance; + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + if (extended) { + maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); + maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); + } + maxwell3d.draw_manager->DrawIndex(Tegra::Maxwell3D::Regs::PrimitiveTopology(parameters[0]), parameters[3], parameters[1], element_base, base_instance, instance_count); + maxwell3d.regs.vertex_id_base = 0x0; + maxwell3d.regs.global_base_vertex_index = 0x0; + maxwell3d.regs.global_base_instance_index = 0x0; + if (extended) { + maxwell3d.engine_state = Maxwell3D::EngineHint::None; + maxwell3d.replace_table.clear(); + } +} +void HLE_MultiLayerClear::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + ASSERT(parameters.size() == 1); -private: - /// Resets the execution engine state, zeroing registers, etc. - void Reset(); + const Maxwell3D::Regs::ClearSurface clear_params{parameters[0]}; + const u32 rt_index = clear_params.RT; + const u32 num_layers = maxwell3d.regs.rt[rt_index].depth; + ASSERT(clear_params.layer == 0); - /** - * Executes a single macro instruction located at the current program counter. Returns whether - * the interpreter should keep running. - * - * @param is_delay_slot Whether the current step is being executed due to a delay slot in a - * previous instruction. - */ - bool Step(bool is_delay_slot); + maxwell3d.regs.clear_surface.raw = clear_params.raw; + maxwell3d.draw_manager->Clear(num_layers); +} +void HLE_MultiDrawIndexedIndirectCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]); + if (!IsTopologySafe(topology)) { + Fallback(maxwell3d, parameters); + return; + } - /// Calculates the result of an ALU operation. src_a OP src_b; - u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b); + const u32 start_indirect = parameters[0]; + const u32 end_indirect = parameters[1]; + if (start_indirect >= end_indirect) { + // Nothing to do. + return; + } - /// Performs the result operation on the input result and stores it in the specified register - /// (if necessary). - void ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result); + const u32 padding = parameters[3]; // padding is in words - /// Evaluates the branch condition and returns whether the branch should be taken or not. - bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const; + // size of each indirect segment + const u32 indirect_words = 5 + padding; + const u32 stride = indirect_words * sizeof(u32); + const std::size_t draw_count = end_indirect - start_indirect; + const u32 estimate = static_cast(maxwell3d.EstimateIndexBufferSize()); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + auto& params = maxwell3d.draw_manager->GetIndirectParams(); + params.is_byte_count = false; + params.is_indexed = true; + params.include_count = true; + params.count_start_address = maxwell3d.GetMacroAddress(4); + params.indirect_start_address = maxwell3d.GetMacroAddress(5); + params.buffer_size = stride * draw_count; + params.max_draw_counts = draw_count; + params.stride = stride; + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); + maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); + maxwell3d.SetHLEReplacementAttributeType(0, 0x648, Maxwell3D::HLEReplacementAttributeType::DrawID); + maxwell3d.draw_manager->DrawIndexedIndirect(topology, 0, estimate); + maxwell3d.engine_state = Maxwell3D::EngineHint::None; + maxwell3d.replace_table.clear(); +} +void HLE_MultiDrawIndexedIndirectCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { + SCOPE_EXIT { + // Clean everything. + maxwell3d.regs.vertex_id_base = 0x0; + maxwell3d.engine_state = Maxwell3D::EngineHint::None; + maxwell3d.replace_table.clear(); + }; + maxwell3d.RefreshParameters(); + const u32 start_indirect = parameters[0]; + const u32 end_indirect = parameters[1]; + if (start_indirect >= end_indirect) { + // Nothing to do. + return; + } + const auto topology = static_cast(parameters[2]); + const u32 padding = parameters[3]; + const std::size_t max_draws = parameters[4]; + const u32 indirect_words = 5 + padding; + const std::size_t first_draw = start_indirect; + const std::size_t effective_draws = end_indirect - start_indirect; + const std::size_t last_draw = start_indirect + (std::min)(effective_draws, max_draws); + for (std::size_t index = first_draw; index < last_draw; index++) { + const std::size_t base = index * indirect_words + 5; + const u32 base_vertex = parameters[base + 3]; + const u32 base_instance = parameters[base + 4]; + maxwell3d.regs.vertex_id_base = base_vertex; + maxwell3d.engine_state = Maxwell3D::EngineHint::OnHLEMacro; + maxwell3d.SetHLEReplacementAttributeType(0, 0x640, Maxwell3D::HLEReplacementAttributeType::BaseVertex); + maxwell3d.SetHLEReplacementAttributeType(0, 0x644, Maxwell3D::HLEReplacementAttributeType::BaseInstance); + maxwell3d.CallMethod(0x8e3, 0x648, true); + maxwell3d.CallMethod(0x8e4, static_cast(index), true); + maxwell3d.dirty.flags[VideoCommon::Dirty::IndexBuffer] = true; + maxwell3d.draw_manager->DrawIndex(topology, parameters[base + 2], parameters[base], base_vertex, base_instance, parameters[base + 1]); + } +} +void HLE_DrawIndirectByteCount::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + const bool force = maxwell3d.Rasterizer().HasDrawTransformFeedback(); + auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[0] & 0xFFFFU); + if (!force && (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology))) { + Fallback(maxwell3d, parameters); + return; + } + auto& params = maxwell3d.draw_manager->GetIndirectParams(); + params.is_byte_count = true; + params.is_indexed = false; + params.include_count = false; + params.count_start_address = 0; + params.indirect_start_address = maxwell3d.GetMacroAddress(2); + params.buffer_size = 4; + params.max_draw_counts = 1; + params.stride = parameters[1]; + maxwell3d.regs.draw.begin = parameters[0]; + maxwell3d.regs.draw_auto_stride = parameters[1]; + maxwell3d.regs.draw_auto_byte_count = parameters[2]; + maxwell3d.draw_manager->DrawArrayIndirect(topology); +} +void HLE_DrawIndirectByteCount::Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters) { + maxwell3d.RefreshParameters(); - /// Reads an opcode at the current program counter location. - Macro::Opcode GetOpcode() const; + maxwell3d.regs.draw.begin = parameters[0]; + maxwell3d.regs.draw_auto_stride = parameters[1]; + maxwell3d.regs.draw_auto_byte_count = parameters[2]; - /// Returns the specified register's value. Register 0 is hardcoded to always return 0. - u32 GetRegister(u32 register_id) const; + maxwell3d.draw_manager->DrawArray( + maxwell3d.regs.draw.topology, 0, + maxwell3d.regs.draw_auto_byte_count / maxwell3d.regs.draw_auto_stride, 0, 1); +} +void HLE_C713C83D8F63CCF3::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + const u32 offset = (parameters[0] & 0x3FFFFFFF) << 2; + const u32 address = maxwell3d.regs.shadow_scratch[24]; + auto& const_buffer = maxwell3d.regs.const_buffer; + const_buffer.size = 0x7000; + const_buffer.address_high = (address >> 24) & 0xFF; + const_buffer.address_low = address << 8; + const_buffer.offset = offset; +} +void HLE_D7333D26E0A93EDE::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + const size_t index = parameters[0]; + const u32 address = maxwell3d.regs.shadow_scratch[42 + index]; + const u32 size = maxwell3d.regs.shadow_scratch[47 + index]; + auto& const_buffer = maxwell3d.regs.const_buffer; + const_buffer.size = size; + const_buffer.address_high = (address >> 24) & 0xFF; + const_buffer.address_low = address << 8; +} +void HLE_BindShader::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + auto& regs = maxwell3d.regs; + const u32 index = parameters[0]; + if ((parameters[1] - regs.shadow_scratch[28 + index]) == 0) { + return; + } - /// Sets the register to the input value. - void SetRegister(u32 register_id, u32 value); + regs.pipelines[index & 0xF].offset = parameters[2]; + maxwell3d.dirty.flags[VideoCommon::Dirty::Shaders] = true; + regs.shadow_scratch[28 + index] = parameters[1]; + regs.shadow_scratch[34 + index] = parameters[2]; - /// Sets the method address to use for the next Send instruction. - void SetMethodAddress(u32 address); + const u32 address = parameters[4]; + auto& const_buffer = regs.const_buffer; + const_buffer.size = 0x10000; + const_buffer.address_high = (address >> 24) & 0xFF; + const_buffer.address_low = address << 8; - /// Calls a GPU Engine method with the input parameter. - void Send(u32 value); + const size_t bind_group_id = parameters[3] & 0x7F; + auto& bind_group = regs.bind_groups[bind_group_id]; + bind_group.raw_config = 0x11; + maxwell3d.ProcessCBBind(bind_group_id); +} +void HLE_SetRasterBoundingBox::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + const u32 raster_mode = parameters[0]; + auto& regs = maxwell3d.regs; + const u32 raster_enabled = maxwell3d.regs.conservative_raster_enable; + const u32 scratch_data = maxwell3d.regs.shadow_scratch[52]; + regs.raster_bounding_box.raw = raster_mode & 0xFFFFF00F; + regs.raster_bounding_box.pad.Assign(scratch_data & raster_enabled); +} +void HLE_ClearConstBuffer::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + static constexpr std::array zeroes{}; //must be bigger than either 7000 or 5F00 + maxwell3d.RefreshParameters(); + auto& regs = maxwell3d.regs; + regs.const_buffer.size = u32(base_size); + regs.const_buffer.address_high = parameters[0]; + regs.const_buffer.address_low = parameters[1]; + regs.const_buffer.offset = 0; + maxwell3d.ProcessCBMultiData(zeroes.data(), parameters[2] * 4); +} +void HLE_ClearMemory::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + const u32 needed_memory = parameters[2] / sizeof(u32); + if (needed_memory > zero_memory.size()) { + zero_memory.resize(needed_memory, 0); + } + auto& regs = maxwell3d.regs; + regs.upload.line_length_in = parameters[2]; + regs.upload.line_count = 1; + regs.upload.dest.address_high = parameters[0]; + regs.upload.dest.address_low = parameters[1]; + maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); + maxwell3d.CallMultiMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), zero_memory.data(), needed_memory, needed_memory); +} +void HLE_TransformFeedbackSetup::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method) { + maxwell3d.RefreshParameters(); + auto& regs = maxwell3d.regs; + regs.transform_feedback_enabled = 1; + regs.transform_feedback.buffers[0].start_offset = 0; + regs.transform_feedback.buffers[1].start_offset = 0; + regs.transform_feedback.buffers[2].start_offset = 0; + regs.transform_feedback.buffers[3].start_offset = 0; + regs.upload.line_length_in = 4; + regs.upload.line_count = 1; + regs.upload.dest.address_high = parameters[0]; + regs.upload.dest.address_low = parameters[1]; + maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(launch_dma)), 0x1011, true); + maxwell3d.CallMethod(size_t(MAXWELL3D_REG_INDEX(inline_data)), regs.transform_feedback.controls[0].stride, true); + maxwell3d.Rasterizer().RegisterTransformFeedback(regs.upload.dest.Address()); +} - /// Reads a GPU register located at the method address. - u32 Read(u32 method) const; +#define HLE_MACRO_LIST \ + HLE_MACRO_ELEM(0x0D61FC9FAAC9FCADULL, HLE_DrawArraysIndirect, (false)) \ + HLE_MACRO_ELEM(0x8A4D173EB99A8603ULL, HLE_DrawArraysIndirect, (true)) \ + HLE_MACRO_ELEM(0x771BB18C62444DA0ULL, HLE_DrawIndexedIndirect, (false)) \ + HLE_MACRO_ELEM(0x0217920100488FF7ULL, HLE_DrawIndexedIndirect, (true)) \ + HLE_MACRO_ELEM(0x3F5E74B9C9A50164ULL, HLE_MultiDrawIndexedIndirectCount, ()) \ + HLE_MACRO_ELEM(0xEAD26C3E2109B06BULL, HLE_MultiLayerClear, ()) \ + HLE_MACRO_ELEM(0xC713C83D8F63CCF3ULL, HLE_C713C83D8F63CCF3, ()) \ + HLE_MACRO_ELEM(0xD7333D26E0A93EDEULL, HLE_D7333D26E0A93EDE, ()) \ + HLE_MACRO_ELEM(0xEB29B2A09AA06D38ULL, HLE_BindShader, ()) \ + HLE_MACRO_ELEM(0xDB1341DBEB4C8AF7ULL, HLE_SetRasterBoundingBox, ()) \ + HLE_MACRO_ELEM(0x6C97861D891EDf7EULL, HLE_ClearConstBuffer, (0x5F00)) \ + HLE_MACRO_ELEM(0xD246FDDF3A6173D7ULL, HLE_ClearConstBuffer, (0x7000)) \ + HLE_MACRO_ELEM(0xEE4D0004BEC8ECF4ULL, HLE_ClearMemory, ()) \ + HLE_MACRO_ELEM(0xFC0CF27F5FFAA661ULL, HLE_TransformFeedbackSetup, ()) \ + HLE_MACRO_ELEM(0xB5F74EDB717278ECULL, HLE_DrawIndirectByteCount, ()) \ - /// Returns the next parameter in the parameter queue. - u32 FetchParameter(); +// Allocates and returns a cached macro if the hash matches a known function. +[[nodiscard]] inline AnyCachedMacro GetHLEProgram(u64 hash) noexcept { + // Compiler will make you a GREAT job at making an ad-hoc hash table :) + switch (hash) { +#define HLE_MACRO_ELEM(HASH, TY, VAL) case HASH: return TY VAL; + HLE_MACRO_LIST +#undef HLE_MACRO_ELEM + default: return std::monostate{}; + } +} +[[nodiscard]] inline bool CanBeHLEProgram(u64 hash) noexcept { + switch (hash) { +#define HLE_MACRO_ELEM(HASH, TY, VAL) case HASH: return true; + HLE_MACRO_LIST +#undef HLE_MACRO_ELEM + default: return false; + } +} - /// Current program counter - u32 pc{}; - /// Program counter to execute at after the delay slot is executed. - std::optional delayed_pc; - - /// General purpose macro registers. - std::array registers = {}; - - /// Method address to use for the next Send instruction. - Macro::MethodAddress method_address = {}; - - /// Input parameters of the current macro. - std::unique_ptr parameters; - std::size_t num_parameters = 0; - std::size_t parameters_capacity = 0; - /// Index of the next parameter that will be fetched by the 'parm' instruction. - u32 next_parameter_index = 0; - - bool carry_flag = false; - const std::vector& code; -}; - -void MacroInterpreterImpl::Execute(const std::vector& params, u32 method) { +void MacroInterpreterImpl::Execute(Engines::Maxwell3D& maxwell3d, std::span params, u32 method) { Reset(); registers[1] = params[0]; - num_parameters = params.size(); - - if (num_parameters > parameters_capacity) { - parameters_capacity = num_parameters; - parameters = std::make_unique(num_parameters); - } - std::memcpy(parameters.get(), params.data(), num_parameters * sizeof(u32)); + parameters.resize(params.size()); + std::memcpy(parameters.data(), params.data(), params.size() * sizeof(u32)); // Execute the code until we hit an exit condition. bool keep_executing = true; while (keep_executing) { - keep_executing = Step(false); + keep_executing = Step(maxwell3d, false); } // Assert the the macro used all the input parameters - ASSERT(next_parameter_index == num_parameters); + ASSERT(next_parameter_index == parameters.size()); } +/// Resets the execution engine state, zeroing registers, etc. void MacroInterpreterImpl::Reset() { registers = {}; pc = 0; delayed_pc = {}; method_address.raw = 0; - num_parameters = 0; + // Vector must hold its last indices otherwise wonky shit will happen // The next parameter index starts at 1, because $r1 already has the value of the first // parameter. next_parameter_index = 1; carry_flag = false; } -bool MacroInterpreterImpl::Step(bool is_delay_slot) { +/// @brief Executes a single macro instruction located at the current program counter. Returns whether +/// the interpreter should keep running. +/// @param is_delay_slot Whether the current step is being executed due to a delay slot in a previous instruction. +bool MacroInterpreterImpl::Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slot) { u32 base_address = pc; Macro::Opcode opcode = GetOpcode(); @@ -682,14 +493,12 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { switch (opcode.operation) { case Macro::Operation::ALU: { - u32 result = GetALUResult(opcode.alu_operation, GetRegister(opcode.src_a), - GetRegister(opcode.src_b)); - ProcessResult(opcode.result_operation, opcode.dst, result); + u32 result = GetALUResult(opcode.alu_operation, GetRegister(opcode.src_a), GetRegister(opcode.src_b)); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result); break; } case Macro::Operation::AddImmediate: { - ProcessResult(opcode.result_operation, opcode.dst, - GetRegister(opcode.src_a) + opcode.immediate); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, GetRegister(opcode.src_a) + opcode.immediate); break; } case Macro::Operation::ExtractInsert: { @@ -699,7 +508,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { src = (src >> opcode.bf_src_bit) & opcode.GetBitfieldMask(); dst &= ~(opcode.GetBitfieldMask() << opcode.bf_dst_bit); dst |= src << opcode.bf_dst_bit; - ProcessResult(opcode.result_operation, opcode.dst, dst); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, dst); break; } case Macro::Operation::ExtractShiftLeftImmediate: { @@ -708,7 +517,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { u32 result = ((src >> dst) & opcode.GetBitfieldMask()) << opcode.bf_dst_bit; - ProcessResult(opcode.result_operation, opcode.dst, result); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result); break; } case Macro::Operation::ExtractShiftLeftRegister: { @@ -717,12 +526,12 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { u32 result = ((src >> opcode.bf_src_bit) & opcode.GetBitfieldMask()) << dst; - ProcessResult(opcode.result_operation, opcode.dst, result); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result); break; } case Macro::Operation::Read: { - u32 result = Read(GetRegister(opcode.src_a) + opcode.immediate); - ProcessResult(opcode.result_operation, opcode.dst, result); + u32 result = Read(maxwell3d, GetRegister(opcode.src_a) + opcode.immediate); + ProcessResult(maxwell3d, opcode.result_operation, opcode.dst, result); break; } case Macro::Operation::Branch: { @@ -738,7 +547,7 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { delayed_pc = base_address + opcode.GetBranchTarget(); // Execute one more instruction due to the delay slot. - return Step(true); + return Step(maxwell3d, true); } break; } @@ -751,13 +560,13 @@ bool MacroInterpreterImpl::Step(bool is_delay_slot) { // cause an exit if it's executed inside a delay slot. if (opcode.is_exit && !is_delay_slot) { // Exit has a delay slot, execute the next instruction - Step(true); + Step(maxwell3d, true); return false; } - return true; } +/// Calculates the result of an ALU operation. src_a OP src_b; u32 MacroInterpreterImpl::GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b) { switch (operation) { case Macro::ALUOperation::Add: { @@ -797,7 +606,8 @@ u32 MacroInterpreterImpl::GetALUResult(Macro::ALUOperation operation, u32 src_a, } } -void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result) { +/// Performs the result operation on the input result and stores it in the specified register (if necessary). +void MacroInterpreterImpl::ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result) { switch (operation) { case Macro::ResultOperation::IgnoreAndFetch: // Fetch parameter and ignore result. @@ -815,12 +625,12 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r case Macro::ResultOperation::FetchAndSend: // Fetch parameter and send result. SetRegister(reg, FetchParameter()); - Send(result); + Send(maxwell3d, result); break; case Macro::ResultOperation::MoveAndSend: // Move and send result. SetRegister(reg, result); - Send(result); + Send(maxwell3d, result); break; case Macro::ResultOperation::FetchAndSetMethod: // Fetch parameter and use result as Method Address. @@ -831,13 +641,13 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r // Move result and use as Method Address, then fetch and send parameter. SetRegister(reg, result); SetMethodAddress(result); - Send(FetchParameter()); + Send(maxwell3d, FetchParameter()); break; case Macro::ResultOperation::MoveAndSetMethodSend: // Move result and use as Method Address, then send bits 12:17 of result. SetRegister(reg, result); SetMethodAddress(result); - Send((result >> 12) & 0b111111); + Send(maxwell3d, (result >> 12) & 0b111111); break; default: UNIMPLEMENTED_MSG("Unimplemented result operation {}", operation); @@ -845,6 +655,7 @@ void MacroInterpreterImpl::ProcessResult(Macro::ResultOperation operation, u32 r } } +/// Evaluates the branch condition and returns whether the branch should be taken or not. bool MacroInterpreterImpl::EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const { switch (cond) { case Macro::BranchCondition::Zero: @@ -855,46 +666,44 @@ bool MacroInterpreterImpl::EvaluateBranchCondition(Macro::BranchCondition cond, UNREACHABLE(); } +/// Reads an opcode at the current program counter location. Macro::Opcode MacroInterpreterImpl::GetOpcode() const { ASSERT((pc % sizeof(u32)) == 0); ASSERT(pc < code.size() * sizeof(u32)); return {code[pc / sizeof(u32)]}; } +/// Returns the specified register's value. Register 0 is hardcoded to always return 0. u32 MacroInterpreterImpl::GetRegister(u32 register_id) const { - return registers.at(register_id); + return registers[register_id]; } +/// Sets the register to the input value. void MacroInterpreterImpl::SetRegister(u32 register_id, u32 value) { // Register 0 is hardwired as the zero register. // Ensure no writes to it actually occur. - if (register_id == 0) { + if (register_id == 0) return; - } - - registers.at(register_id) = value; + registers[register_id] = value; } -void MacroInterpreterImpl::SetMethodAddress(u32 address) { - method_address.raw = address; -} - -void MacroInterpreterImpl::Send(u32 value) { +/// Calls a GPU Engine method with the input parameter. +void MacroInterpreterImpl::Send(Engines::Maxwell3D& maxwell3d, u32 value) { maxwell3d.CallMethod(method_address.address, value, true); // Increment the method address by the method increment. - method_address.address.Assign(method_address.address.Value() + - method_address.increment.Value()); + method_address.address.Assign(method_address.address.Value() + method_address.increment.Value()); } -u32 MacroInterpreterImpl::Read(u32 method) const { +/// Reads a GPU register located at the method address. +u32 MacroInterpreterImpl::Read(Engines::Maxwell3D& maxwell3d, u32 method) const { return maxwell3d.GetRegisterValue(method); } +/// Returns the next parameter in the parameter queue. u32 MacroInterpreterImpl::FetchParameter() { - ASSERT(next_parameter_index < num_parameters); + ASSERT(next_parameter_index < parameters.size()); return parameters[next_parameter_index++]; } -} // Anonymous namespace #ifdef ARCHITECTURE_x86_64 namespace { @@ -930,17 +739,15 @@ static const auto default_cg_mode = Xbyak::DontSetProtectRWE; static const auto default_cg_mode = nullptr; //Allow RWE #endif -class MacroJITx64Impl final : public Xbyak::CodeGenerator, public CachedMacro { -public: - explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector& code_) +struct MacroJITx64Impl final : public Xbyak::CodeGenerator, public DynamicCachedMacro { + explicit MacroJITx64Impl(std::span code_) : Xbyak::CodeGenerator(MAX_CODE_SIZE, default_cg_mode) - , CachedMacro(maxwell3d_) , code{code_} { Compile(); } - void Execute(const std::vector& parameters, u32 method) override; + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, u32 method) override; void Compile_ALU(Macro::Opcode opcode); void Compile_AddImmediate(Macro::Opcode opcode); @@ -950,18 +757,13 @@ public: void Compile_Read(Macro::Opcode opcode); void Compile_Branch(Macro::Opcode opcode); -private: void Optimizer_ScanFlags(); - void Compile(); bool Compile_NextInstruction(); - Xbyak::Reg32 Compile_FetchParameter(); Xbyak::Reg32 Compile_GetRegister(u32 index, Xbyak::Reg32 dst); - void Compile_ProcessResult(Macro::ResultOperation operation, u32 reg); void Compile_Send(Xbyak::Reg32 value); - Macro::Opcode GetOpCode() const; struct JITState { @@ -981,21 +783,17 @@ private: bool enable_asserts{}; }; OptimizerState optimizer{}; - std::optional next_opcode{}; ProgramType program{nullptr}; - std::array labels; std::array delay_skip; Xbyak::Label end_of_code{}; - bool is_delay_slot{}; u32 pc{}; - - const std::vector& code; + std::span code; }; -void MacroJITx64Impl::Execute(const std::vector& parameters, u32 method) { +void MacroJITx64Impl::Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, u32 method) { ASSERT_OR_EXECUTE(program != nullptr, { return; }); JITState state{}; state.maxwell3d = &maxwell3d; @@ -1231,7 +1029,7 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) { Compile_ProcessResult(opcode.result_operation, opcode.dst); } -void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { +static void MacroJIT_SendThunk(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { maxwell3d->CallMethod(method_address.address, value, true); } @@ -1240,7 +1038,7 @@ void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { mov(Common::X64::ABI_PARAM1, qword[STATE]); mov(Common::X64::ABI_PARAM2.cvt32(), METHOD_ADDRESS); mov(Common::X64::ABI_PARAM3.cvt32(), value); - Common::X64::CallFarFunction(*this, &Send); + Common::X64::CallFarFunction(*this, &MacroJIT_SendThunk); Common::X64::ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); Xbyak::Label dont_process{}; @@ -1452,10 +1250,8 @@ bool MacroJITx64Impl::Compile_NextInstruction() { return true; } -static void WarnInvalidParameter(uintptr_t parameter, uintptr_t max_parameter) { - LOG_CRITICAL(HW_GPU, - "Macro JIT: invalid parameter access 0x{:x} (0x{:x} is the last parameter)", - parameter, max_parameter - sizeof(u32)); +static void MacroJIT_ErrorThunk(uintptr_t parameter, uintptr_t max_parameter) { + LOG_CRITICAL(HW_GPU, "Macro JIT: invalid parameter access 0x{:x} (0x{:x} is the last parameter)", parameter, max_parameter - sizeof(u32)); } Xbyak::Reg32 MacroJITx64Impl::Compile_FetchParameter() { @@ -1465,7 +1261,7 @@ Xbyak::Reg32 MacroJITx64Impl::Compile_FetchParameter() { Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); mov(Common::X64::ABI_PARAM1, PARAMETERS); mov(Common::X64::ABI_PARAM2, MAX_PARAMETER); - Common::X64::CallFarFunction(*this, &WarnInvalidParameter); + Common::X64::CallFarFunction(*this, &MacroJIT_ErrorThunk); Common::X64::ABI_PopRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); L(parameter_ok); mov(eax, dword[PARAMETERS]); @@ -1574,33 +1370,42 @@ static void Dump(u64 hash, std::span code, bool decompiled = false) { macro_file.write(reinterpret_cast(code.data()), code.size_bytes()); } -MacroEngine::MacroEngine(Engines::Maxwell3D& maxwell3d_, bool is_interpreted_) - : hle_macros{std::make_optional(maxwell3d_)} - , maxwell3d{maxwell3d_} - , is_interpreted{is_interpreted_} -{} - -MacroEngine::~MacroEngine() = default; - -void MacroEngine::AddCode(u32 method, u32 data) { - uploaded_macro_code[method].push_back(data); -} - -void MacroEngine::ClearCode(u32 method) { - macro_cache.erase(method); - uploaded_macro_code.erase(method); -} - -void MacroEngine::Execute(u32 method, const std::vector& parameters) { - auto compiled_macro = macro_cache.find(method); - if (compiled_macro != macro_cache.end()) { - const auto& cache_info = compiled_macro->second; - if (cache_info.has_hle_program) { - cache_info.hle_program->Execute(parameters, method); - } else { - maxwell3d.RefreshParameters(); - cache_info.lle_program->Execute(parameters, method); - } +void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span parameters) { + auto const execute_variant = [&maxwell3d, ¶meters, method](AnyCachedMacro& acm) { + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if(&acm)) + a->Execute(maxwell3d, parameters, method); + if (auto a = std::get_if>(&acm)) + a->get()->Execute(maxwell3d, parameters, method); + }; + if (auto const it = macro_cache.find(method); it != macro_cache.end()) { + auto& ci = it->second; + if (!CanBeHLEProgram(ci.hash) || Settings::values.disable_macro_hle) + maxwell3d.RefreshParameters(); //LLE must reload parameters + execute_variant(ci.program); } else { // Macro not compiled, check if it's uploaded and if so, compile it std::optional mid_method; @@ -1617,51 +1422,37 @@ void MacroEngine::Execute(u32 method, const std::vector& parameters) { return; } } - auto& cache_info = macro_cache[method]; - - if (!mid_method.has_value()) { - cache_info.lle_program = Compile(macro_code->second); - cache_info.hash = Common::HashValue(macro_code->second); - } else { + auto& ci = macro_cache[method]; + if (mid_method) { const auto& macro_cached = uploaded_macro_code[mid_method.value()]; const auto rebased_method = method - mid_method.value(); auto& code = uploaded_macro_code[method]; code.resize(macro_cached.size() - rebased_method); std::memcpy(code.data(), macro_cached.data() + rebased_method, code.size() * sizeof(u32)); - cache_info.hash = Common::HashValue(code); - cache_info.lle_program = Compile(code); - } - - auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); - if (!hle_program || Settings::values.disable_macro_hle) { - maxwell3d.RefreshParameters(); - cache_info.lle_program->Execute(parameters, method); + ci.hash = Common::HashValue(code); + ci.program = Compile(maxwell3d, code); } else { - cache_info.has_hle_program = true; - cache_info.hle_program = std::move(hle_program); - cache_info.hle_program->Execute(parameters, method); + ci.program = Compile(maxwell3d, macro_code->second); + ci.hash = Common::HashValue(macro_code->second); } - + if (CanBeHLEProgram(ci.hash) && !Settings::values.disable_macro_hle) { + ci.program = GetHLEProgram(ci.hash); + } else { + maxwell3d.RefreshParameters(); + } + execute_variant(ci.program); if (Settings::values.dump_macros) { - Dump(cache_info.hash, macro_code->second, cache_info.has_hle_program); + Dump(ci.hash, macro_code->second, !std::holds_alternative(ci.program)); } } } -std::unique_ptr MacroEngine::Compile(const std::vector& code) { +AnyCachedMacro MacroEngine::Compile(Engines::Maxwell3D& maxwell3d, std::span code) { #ifdef ARCHITECTURE_x86_64 if (!is_interpreted) - return std::make_unique(maxwell3d, code); -#endif - return std::make_unique(maxwell3d, code); -} - -std::optional GetMacroEngine(Engines::Maxwell3D& maxwell3d) { -#ifdef ARCHITECTURE_x86_64 - return std::make_optional(maxwell3d, bool(Settings::values.disable_macro_jit)); -#else - return std::make_optional(maxwell3d, true); + return std::make_unique(code); #endif + return MacroInterpreterImpl(code); } } // namespace Tegra diff --git a/src/video_core/macro.h b/src/video_core/macro.h index 9bdb4219ce..a9a8f2de04 100644 --- a/src/video_core/macro.h +++ b/src/video_core/macro.h @@ -7,8 +7,10 @@ #pragma once #include -#include +#include +#include #include +#include #include "common/bit_field.h" #include "common/common_types.h" @@ -98,62 +100,142 @@ union MethodAddress { } // namespace Macro -class CachedMacro { -public: - CachedMacro(Engines::Maxwell3D& maxwell3d_) - : maxwell3d{maxwell3d_} - {} - virtual ~CachedMacro() = default; +struct HLEMacro { +}; +/// @note: these macros have two versions, a normal and extended version, with the extended version +/// also assigning the base vertex/instance. +struct HLE_DrawArraysIndirect final { + HLE_DrawArraysIndirect(bool extended_) noexcept : extended{extended_} {} + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + bool extended; +}; +/// @note: these macros have two versions, a normal and extended version, with the extended version +/// also assigning the base vertex/instance. +struct HLE_DrawIndexedIndirect final { + explicit HLE_DrawIndexedIndirect(bool extended_) noexcept : extended{extended_} {} + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); + bool extended; +}; +struct HLE_MultiLayerClear final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct HLE_MultiDrawIndexedIndirectCount final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); +}; +struct HLE_DrawIndirectByteCount final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + void Fallback(Engines::Maxwell3D& maxwell3d, std::span parameters); +}; +struct HLE_C713C83D8F63CCF3 final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct HLE_D7333D26E0A93EDE final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct HLE_BindShader final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct HLE_SetRasterBoundingBox final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct HLE_ClearConstBuffer final { + HLE_ClearConstBuffer(size_t base_size_) noexcept : base_size{base_size_} {} + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + size_t base_size; +}; +struct HLE_ClearMemory final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); + std::vector zero_memory; +}; +struct HLE_TransformFeedbackSetup final { + void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, [[maybe_unused]] u32 method); +}; +struct MacroInterpreterImpl final { + MacroInterpreterImpl() {} + MacroInterpreterImpl(std::span code_) : code{code_} {} + void Execute(Engines::Maxwell3D& maxwell3d, std::span params, u32 method); + void Reset(); + bool Step(Engines::Maxwell3D& maxwell3d, bool is_delay_slot); + u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b); + void ProcessResult(Engines::Maxwell3D& maxwell3d, Macro::ResultOperation operation, u32 reg, u32 result); + bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const; + Macro::Opcode GetOpcode() const; + u32 GetRegister(u32 register_id) const; + void SetRegister(u32 register_id, u32 value); + /// Sets the method address to use for the next Send instruction. + [[nodiscard]] inline void SetMethodAddress(u32 address) noexcept { + method_address.raw = address; + } + void Send(Engines::Maxwell3D& maxwell3d, u32 value); + u32 Read(Engines::Maxwell3D& maxwell3d, u32 method) const; + u32 FetchParameter(); + /// General purpose macro registers. + std::array registers = {}; + /// Input parameters of the current macro. + std::vector parameters; + std::span code; + /// Program counter to execute at after the delay slot is executed. + std::optional delayed_pc; + /// Method address to use for the next Send instruction. + Macro::MethodAddress method_address = {}; + /// Current program counter + u32 pc{}; + /// Index of the next parameter that will be fetched by the 'parm' instruction. + u32 next_parameter_index = 0; + bool carry_flag = false; +}; +struct DynamicCachedMacro { + virtual ~DynamicCachedMacro() = default; /// Executes the macro code with the specified input parameters. /// @param parameters The parameters of the macro /// @param method The method to execute - virtual void Execute(const std::vector& parameters, u32 method) = 0; - Engines::Maxwell3D& maxwell3d; + virtual void Execute(Engines::Maxwell3D& maxwell3d, std::span parameters, u32 method) = 0; }; -class HLEMacro { -public: - explicit HLEMacro(Engines::Maxwell3D& maxwell3d_); - ~HLEMacro(); - // Allocates and returns a cached macro if the hash matches a known function. - // Returns nullptr otherwise. - [[nodiscard]] std::unique_ptr GetHLEProgram(u64 hash) const; -private: - Engines::Maxwell3D& maxwell3d; -}; - -class MacroEngine { -public: - explicit MacroEngine(Engines::Maxwell3D& maxwell3d, bool is_interpreted); - ~MacroEngine(); +using AnyCachedMacro = std::variant< + std::monostate, + HLEMacro, + HLE_DrawArraysIndirect, + HLE_DrawIndexedIndirect, + HLE_MultiDrawIndexedIndirectCount, + HLE_MultiLayerClear, + HLE_C713C83D8F63CCF3, + HLE_D7333D26E0A93EDE, + HLE_BindShader, + HLE_SetRasterBoundingBox, + HLE_ClearConstBuffer, + HLE_ClearMemory, + HLE_TransformFeedbackSetup, + HLE_DrawIndirectByteCount, + MacroInterpreterImpl, + // Used for JIT x86 macro + std::unique_ptr +>; +struct MacroEngine { + MacroEngine(bool is_interpreted_) noexcept : is_interpreted{is_interpreted_} {} // Store the uploaded macro code to compile them when they're called. - void AddCode(u32 method, u32 data); - + inline void AddCode(u32 method, u32 data) noexcept { + uploaded_macro_code[method].push_back(data); + } // Clear the code associated with a method. - void ClearCode(u32 method); - + inline void ClearCode(u32 method) noexcept { + macro_cache.erase(method); + uploaded_macro_code.erase(method); + } // Compiles the macro if its not in the cache, and executes the compiled macro - void Execute(u32 method, const std::vector& parameters); - -protected: - std::unique_ptr Compile(const std::vector& code); - -private: + void Execute(Engines::Maxwell3D& maxwell3d, u32 method, std::span parameters); + AnyCachedMacro Compile(Engines::Maxwell3D& maxwell3d, std::span code); struct CacheInfo { - std::unique_ptr lle_program{}; - std::unique_ptr hle_program{}; + AnyCachedMacro program; u64 hash{}; - bool has_hle_program{}; }; - ankerl::unordered_dense::map macro_cache; ankerl::unordered_dense::map> uploaded_macro_code; - std::optional hle_macros; - Engines::Maxwell3D& maxwell3d; bool is_interpreted; }; -std::optional GetMacroEngine(Engines::Maxwell3D& maxwell3d); - } // namespace Tegra From 2ed1328c93c4739c069e7a284cb82b0a72762dac Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 6 Mar 2026 15:05:05 +0100 Subject: [PATCH 083/181] [vk] use static_vector instead of small_vector for TFB and other bindings (#3641) MK8D is a big offender, taking up lots of time memcpy'ing and memmov'ing small_vector<> AND to add salt to the wound it doesn't even do heap allocations (no game does I think) - so basically useless waste of compute time in hot path for NO reason :^) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3641 Reviewed-by: CamilleLaVey Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- .../buffer_cache/buffer_cache_base.h | 13 +++-- .../renderer_vulkan/vk_buffer_cache.cpp | 50 +++++++++---------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/src/video_core/buffer_cache/buffer_cache_base.h b/src/video_core/buffer_cache/buffer_cache_base.h index 0596329392..08524bd854 100644 --- a/src/video_core/buffer_cache/buffer_cache_base.h +++ b/src/video_core/buffer_cache/buffer_cache_base.h @@ -14,9 +14,12 @@ #include #include #include -#include #include +#include +#include +#include + #include "common/common_types.h" #include "common/div_ceil.h" #include "common/literals.h" @@ -94,10 +97,10 @@ static constexpr Binding NULL_BINDING{ template struct HostBindings { - boost::container::small_vector buffers; - boost::container::small_vector offsets; - boost::container::small_vector sizes; - boost::container::small_vector strides; + boost::container::static_vector buffers; + boost::container::static_vector offsets; + boost::container::static_vector sizes; + boost::container::static_vector strides; u32 min_index{NUM_VERTEX_BUFFERS}; u32 max_index{0}; }; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index f4345262fb..c842cce709 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -10,6 +10,7 @@ #include #include +#include "video_core/buffer_cache/buffer_cache_base.h" #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" @@ -583,18 +584,18 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset } void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bindings) { - boost::container::small_vector buffer_handles; - for (u32 index = 0; index < bindings.buffers.size(); ++index) { - auto handle = bindings.buffers[index]->Handle(); + boost::container::static_vector buffer_handles(bindings.buffers.size()); + for (u32 i = 0; i < bindings.buffers.size(); ++i) { + auto handle = bindings.buffers[i]->Handle(); if (handle == VK_NULL_HANDLE) { - bindings.offsets[index] = 0; - bindings.sizes[index] = VK_WHOLE_SIZE; + bindings.offsets[i] = 0; + bindings.sizes[i] = VK_WHOLE_SIZE; if (!device.HasNullDescriptor()) { ReserveNullBuffer(); handle = *null_buffer; } } - buffer_handles.push_back(handle); + buffer_handles[i] = handle; } const u32 device_max = device.GetMaxVertexInputBindings(); const u32 min_binding = (std::min)(bindings.min_index, device_max); @@ -604,19 +605,12 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings& bi return; } if (device.IsExtExtendedDynamicStateSupported()) { - scheduler.Record([bindings_ = std::move(bindings), - buffer_handles_ = std::move(buffer_handles), - binding_count](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), - bindings_.offsets.data(), bindings_.sizes.data(), - bindings_.strides.data()); + scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data(), bindings_.strides.data()); }); } else { - scheduler.Record([bindings_ = std::move(bindings), - buffer_handles_ = std::move(buffer_handles), - binding_count](vk::CommandBuffer cmdbuf) { - cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), - bindings_.offsets.data()); + scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles), binding_count](vk::CommandBuffer cmdbuf) { + cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(), bindings_.offsets.data()); }); } } @@ -647,15 +641,21 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings< // Already logged in the rasterizer return; } - boost::container::small_vector buffer_handles; - for (u32 index = 0; index < bindings.buffers.size(); ++index) { - buffer_handles.push_back(bindings.buffers[index]->Handle()); + boost::container::static_vector buffer_handles(bindings.buffers.size()); + for (u32 i = 0; i < bindings.buffers.size(); ++i) { + auto handle = bindings.buffers[i]->Handle(); + if (handle == VK_NULL_HANDLE) { + bindings.offsets[i] = 0; + bindings.sizes[i] = VK_WHOLE_SIZE; + if (!device.HasNullDescriptor()) { + ReserveNullBuffer(); + handle = *null_buffer; + } + } + buffer_handles[i] = handle; } - scheduler.Record([bindings_ = std::move(bindings), - buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { - cmdbuf.BindTransformFeedbackBuffersEXT(0, static_cast(buffer_handles_.size()), - buffer_handles_.data(), bindings_.offsets.data(), - bindings_.sizes.data()); + scheduler.Record([bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles)](vk::CommandBuffer cmdbuf) { + cmdbuf.BindTransformFeedbackBuffersEXT(0, u32(buffer_handles_.size()), buffer_handles_.data(), bindings_.offsets.data(), bindings_.sizes.data()); }); } From b75e81af5e11cb09eae405d51c40489401794912 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 6 Mar 2026 15:05:39 +0100 Subject: [PATCH 084/181] [video_core/engines] implement stub NV01 timer, inline other channel engines (#3640) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3640 Reviewed-by: CamilleLaVey Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- src/video_core/control/channel_state.cpp | 15 ++++--- src/video_core/control/channel_state.h | 44 +++++++++---------- src/video_core/engines/engine_interface.h | 3 +- src/video_core/engines/maxwell_3d.h | 2 +- src/video_core/engines/nv01_timer.h | 52 +++++++++++++++++++++++ src/video_core/engines/puller.cpp | 42 +++++++++--------- src/video_core/engines/puller.h | 4 ++ 7 files changed, 109 insertions(+), 53 deletions(-) create mode 100644 src/video_core/engines/nv01_timer.h diff --git a/src/video_core/control/channel_state.cpp b/src/video_core/control/channel_state.cpp index 2539997d53..d07c7e2a83 100644 --- a/src/video_core/control/channel_state.cpp +++ b/src/video_core/control/channel_state.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -19,12 +22,12 @@ ChannelState::ChannelState(s32 bind_id_) : bind_id{bind_id_}, initialized{} {} void ChannelState::Init(Core::System& system, GPU& gpu, u64 program_id_) { ASSERT(memory_manager); program_id = program_id_; - dma_pusher = std::make_unique(system, gpu, *memory_manager, *this); - maxwell_3d = std::make_unique(system, *memory_manager); - fermi_2d = std::make_unique(*memory_manager); - kepler_compute = std::make_unique(system, *memory_manager); - maxwell_dma = std::make_unique(system, *memory_manager); - kepler_memory = std::make_unique(system, *memory_manager); + dma_pusher.emplace(system, gpu, *memory_manager, *this); + maxwell_3d.emplace(system, *memory_manager); + fermi_2d.emplace(*memory_manager); + kepler_compute.emplace(system, *memory_manager); + maxwell_dma.emplace(system, *memory_manager); + kepler_memory.emplace(system, *memory_manager); initialized = true; } diff --git a/src/video_core/control/channel_state.h b/src/video_core/control/channel_state.h index b385f4939f..2984d2e09e 100644 --- a/src/video_core/control/channel_state.h +++ b/src/video_core/control/channel_state.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -6,6 +9,12 @@ #include #include "common/common_types.h" +#include "video_core/engines/fermi_2d.h" +#include "video_core/engines/kepler_memory.h" +#include "video_core/engines/kepler_compute.h" +#include "video_core/engines/maxwell_3d.h" +#include "video_core/engines/maxwell_dma.h" +#include "video_core/dma_pusher.h" namespace Core { class System; @@ -18,49 +27,34 @@ class RasterizerInterface; namespace Tegra { class GPU; - -namespace Engines { -class Puller; -class Fermi2D; -class Maxwell3D; -class MaxwellDMA; -class KeplerCompute; -class KeplerMemory; -} // namespace Engines - class MemoryManager; -class DmaPusher; namespace Control { struct ChannelState { explicit ChannelState(s32 bind_id); - ChannelState(const ChannelState& state) = delete; - ChannelState& operator=(const ChannelState&) = delete; - ChannelState(ChannelState&& other) noexcept = default; - ChannelState& operator=(ChannelState&& other) noexcept = default; void Init(Core::System& system, GPU& gpu, u64 program_id); void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); - s32 bind_id = -1; - u64 program_id = 0; /// 3D engine - std::unique_ptr maxwell_3d; + std::optional maxwell_3d; /// 2D engine - std::unique_ptr fermi_2d; + std::optional fermi_2d; /// Compute engine - std::unique_ptr kepler_compute; + std::optional kepler_compute; /// DMA engine - std::unique_ptr maxwell_dma; + std::optional maxwell_dma; /// Inline memory engine - std::unique_ptr kepler_memory; - + std::optional kepler_memory; + /// NV01 Timer + std::optional nv01_timer; + std::optional dma_pusher; std::shared_ptr memory_manager; - std::unique_ptr dma_pusher; - + s32 bind_id = -1; + u64 program_id = 0; bool initialized{}; }; diff --git a/src/video_core/engines/engine_interface.h b/src/video_core/engines/engine_interface.h index e271ecab59..bf3bd66aca 100644 --- a/src/video_core/engines/engine_interface.h +++ b/src/video_core/engines/engine_interface.h @@ -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 2020 yuzu Emulator Project @@ -15,6 +15,7 @@ namespace Tegra::Engines { enum class EngineTypes : u32 { + Nv01Timer, KeplerCompute, Maxwell3D, Fermi2D, diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 52546e4279..b73082b7ef 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -2258,7 +2258,7 @@ public: /// Returns whether the vertex array specified by index is supposed to be /// accessed per instance or not. bool IsInstancingEnabled(std::size_t index) const { - return is_instanced[index]; + return bool(is_instanced[index]); //FUCK YOU MSVC } }; diff --git a/src/video_core/engines/nv01_timer.h b/src/video_core/engines/nv01_timer.h new file mode 100644 index 0000000000..a8e60f9f53 --- /dev/null +++ b/src/video_core/engines/nv01_timer.h @@ -0,0 +1,52 @@ +// 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 +#include +#include "common/bit_field.h" +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "video_core/engines/engine_interface.h" +#include "video_core/engines/engine_upload.h" + +namespace Core { +class System; +} + +namespace Tegra { +class MemoryManager; +} + +namespace Tegra::Engines { +class Nv01Timer final : public EngineInterface { +public: + explicit Nv01Timer(Core::System& system_, MemoryManager& memory_manager) + : system{system_} + {} + ~Nv01Timer() override; + + /// Write the value to the register identified by method. + void CallMethod(u32 method, u32 method_argument, bool is_last_call) override { + LOG_DEBUG(HW_GPU, "method={}, argument={}, is_last_call={}", method, method_argument, is_last_call); + } + + /// Write multiple values to the register identified by method. + void CallMultiMethod(u32 method, const u32* base_start, u32 amount, u32 methods_pending) override { + LOG_DEBUG(HW_GPU, "method={}, base_start={}, amount={}, pending={}", method, fmt::ptr(base_start), amount, methods_pending); + } + + struct Regs { + // No fucking idea + INSERT_PADDING_BYTES_NOINIT(0x48); + } regs{}; +private: + void ConsumeSinkImpl() override {} + Core::System& system; +}; +} diff --git a/src/video_core/engines/puller.cpp b/src/video_core/engines/puller.cpp index 8dd34c04ab..b5b4e5d7fa 100644 --- a/src/video_core/engines/puller.cpp +++ b/src/video_core/engines/puller.cpp @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -34,24 +37,22 @@ void Puller::ProcessBindMethod(const MethodCall& method_call) { bound_engines[method_call.subchannel] = engine_id; switch (engine_id) { case EngineID::FERMI_TWOD_A: - dma_pusher.BindSubchannel(channel_state.fermi_2d.get(), method_call.subchannel, - EngineTypes::Fermi2D); + dma_pusher.BindSubchannel(&*channel_state.fermi_2d, method_call.subchannel, EngineTypes::Fermi2D); break; case EngineID::MAXWELL_B: - dma_pusher.BindSubchannel(channel_state.maxwell_3d.get(), method_call.subchannel, - EngineTypes::Maxwell3D); + dma_pusher.BindSubchannel(&*channel_state.maxwell_3d, method_call.subchannel, EngineTypes::Maxwell3D); break; case EngineID::KEPLER_COMPUTE_B: - dma_pusher.BindSubchannel(channel_state.kepler_compute.get(), method_call.subchannel, - EngineTypes::KeplerCompute); + dma_pusher.BindSubchannel(&*channel_state.kepler_compute, method_call.subchannel, EngineTypes::KeplerCompute); break; case EngineID::MAXWELL_DMA_COPY_A: - dma_pusher.BindSubchannel(channel_state.maxwell_dma.get(), method_call.subchannel, - EngineTypes::MaxwellDMA); + dma_pusher.BindSubchannel(&*channel_state.maxwell_dma, method_call.subchannel, EngineTypes::MaxwellDMA); break; case EngineID::KEPLER_INLINE_TO_MEMORY_B: - dma_pusher.BindSubchannel(channel_state.kepler_memory.get(), method_call.subchannel, - EngineTypes::KeplerMemory); + dma_pusher.BindSubchannel(&*channel_state.kepler_memory, method_call.subchannel, EngineTypes::KeplerMemory); + break; + case EngineID::NV01_TIMER: + dma_pusher.BindSubchannel(&*channel_state.nv01_timer, method_call.subchannel, EngineTypes::Nv01Timer); break; default: UNIMPLEMENTED_MSG("Unimplemented engine {:04X}", engine_id); @@ -209,24 +210,22 @@ void Puller::CallEngineMethod(const MethodCall& method_call) { switch (engine) { case EngineID::FERMI_TWOD_A: - channel_state.fermi_2d->CallMethod(method_call.method, method_call.argument, - method_call.IsLastCall()); + channel_state.fermi_2d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); break; case EngineID::MAXWELL_B: - channel_state.maxwell_3d->CallMethod(method_call.method, method_call.argument, - method_call.IsLastCall()); + channel_state.maxwell_3d->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); break; case EngineID::KEPLER_COMPUTE_B: - channel_state.kepler_compute->CallMethod(method_call.method, method_call.argument, - method_call.IsLastCall()); + channel_state.kepler_compute->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); break; case EngineID::MAXWELL_DMA_COPY_A: - channel_state.maxwell_dma->CallMethod(method_call.method, method_call.argument, - method_call.IsLastCall()); + channel_state.maxwell_dma->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); break; case EngineID::KEPLER_INLINE_TO_MEMORY_B: - channel_state.kepler_memory->CallMethod(method_call.method, method_call.argument, - method_call.IsLastCall()); + channel_state.kepler_memory->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); + break; + case EngineID::NV01_TIMER: + channel_state.nv01_timer->CallMethod(method_call.method, method_call.argument, method_call.IsLastCall()); break; default: UNIMPLEMENTED_MSG("Unimplemented engine"); @@ -255,6 +254,9 @@ void Puller::CallEngineMultiMethod(u32 method, u32 subchannel, const u32* base_s case EngineID::KEPLER_INLINE_TO_MEMORY_B: channel_state.kepler_memory->CallMultiMethod(method, base_start, amount, methods_pending); break; + case EngineID::NV01_TIMER: + channel_state.nv01_timer->CallMultiMethod(method, base_start, amount, methods_pending); + break; default: UNIMPLEMENTED_MSG("Unimplemented engine"); break; diff --git a/src/video_core/engines/puller.h b/src/video_core/engines/puller.h index d4175ee945..fe5102e3ed 100644 --- a/src/video_core/engines/puller.h +++ b/src/video_core/engines/puller.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-3.0-or-later @@ -20,6 +23,7 @@ class MemoryManager; class DmaPusher; enum class EngineID { + NV01_TIMER = 0x0004, FERMI_TWOD_A = 0x902D, // 2D Engine MAXWELL_B = 0xB197, // 3D Engine KEPLER_COMPUTE_B = 0xB1C0, From e4122dae1d56a8b358c46e450b3d50ca10ffcc21 Mon Sep 17 00:00:00 2001 From: crueter Date: Fri, 6 Mar 2026 16:38:21 +0100 Subject: [PATCH 085/181] [desktop] addons: open mod folder in rc menu (#3662) also fixed the multiselection being absolutely horrendous Signed-off-by: crueter Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3662 --- .../configure_per_game_addons.cpp | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/yuzu/configuration/configure_per_game_addons.cpp b/src/yuzu/configuration/configure_per_game_addons.cpp index bdff73a040..1d2d358672 100644 --- a/src/yuzu/configuration/configure_per_game_addons.cpp +++ b/src/yuzu/configuration/configure_per_game_addons.cpp @@ -10,13 +10,14 @@ #include +#include #include #include #include +#include #include #include #include -#include #include "common/common_types.h" #include "common/fs/fs.h" @@ -42,7 +43,7 @@ ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* p item_model = new QStandardItemModel(tree_view); tree_view->setModel(item_model); tree_view->setAlternatingRowColors(true); - tree_view->setSelectionMode(QHeaderView::MultiSelection); + tree_view->setSelectionMode(QHeaderView::ExtendedSelection); tree_view->setSelectionBehavior(QHeaderView::SelectRows); tree_view->setVerticalScrollMode(QHeaderView::ScrollPerPixel); tree_view->setHorizontalScrollMode(QHeaderView::ScrollPerPixel); @@ -248,8 +249,11 @@ void ConfigurePerGameAddons::AddonDeleteRequested(QList selected) { void ConfigurePerGameAddons::showContextMenu(const QPoint& pos) { const QModelIndex index = tree_view->indexAt(pos); - auto selected = tree_view->selectionModel()->selectedIndexes(); - if (index.isValid() && selected.empty()) selected = {index}; + auto selected = tree_view->selectionModel()->selectedRows(); + if (index.isValid() && selected.empty()) { + QModelIndex idx = item_model->index(index.row(), 0); + if (idx.isValid()) selected << idx; + } if (selected.empty()) return; @@ -260,6 +264,15 @@ void ConfigurePerGameAddons::showContextMenu(const QPoint& pos) { AddonDeleteRequested(selected); }); + if (selected.length() == 1) { + auto loc = selected.at(0).data(PATCH_LOCATION).toString(); + if (QFileInfo::exists(loc)) { + QAction* open = menu.addAction(tr("&Open in File Manager")); + connect(open, &QAction::triggered, this, + [selected, loc]() { QDesktopServices::openUrl(QUrl::fromLocalFile(loc)); }); + } + } + menu.exec(tree_view->viewport()->mapToGlobal(pos)); } From c062931c9bef18afd5f0cd74329e8c3e32b4b598 Mon Sep 17 00:00:00 2001 From: lizzie Date: Fri, 6 Mar 2026 16:38:39 +0100 Subject: [PATCH 086/181] [qt] add translation table entry for debug_knobs,serial_battery and serial_unit (#3682) trivial qt change Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3682 Reviewed-by: DraVee Co-authored-by: lizzie Co-committed-by: lizzie --- src/qt_common/config/shared_translation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/qt_common/config/shared_translation.cpp b/src/qt_common/config/shared_translation.cpp index f49c43ee2a..d1ed32134c 100644 --- a/src/qt_common/config/shared_translation.cpp +++ b/src/qt_common/config/shared_translation.cpp @@ -425,6 +425,9 @@ std::unique_ptr InitializeTranslations(QObject* parent) "their resolution, details and supported controllers and depending on this setting.\n" "Setting to Handheld can help improve performance for low end systems.")); INSERT(Settings, current_user, QString(), QString()); + INSERT(Settings, serial_unit, tr("Unit Serial"), QString()); + INSERT(Settings, serial_battery, tr("Battery Serial"), QString()); + INSERT(Settings, debug_knobs, tr("Debug knobs"), QString()); // Controls From ddac8c8eb500918bd8c89e0c330587c591206c2c Mon Sep 17 00:00:00 2001 From: xbzk Date: Fri, 6 Mar 2026 19:52:17 +0100 Subject: [PATCH 087/181] [vk] fix crash introduced in 9a07bd0570 (#3685) Fix for current crash on master. Just reverted only the necessary stuff so that PresentManager can hold a reference to khr and resist death upon application hold/restore. @Lizzie shall judge. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3685 Co-authored-by: xbzk Co-committed-by: xbzk --- src/video_core/renderer_vulkan/renderer_vulkan.cpp | 2 +- src/video_core/renderer_vulkan/vk_present_manager.cpp | 6 +++--- src/video_core/renderer_vulkan/vk_present_manager.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index cb1b1a5362..1725bc8ccc 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -137,7 +137,7 @@ try memory_allocator, scheduler, swapchain, - *surface) + surface) , blit_swapchain(device_memory, device, memory_allocator, diff --git a/src/video_core/renderer_vulkan/vk_present_manager.cpp b/src/video_core/renderer_vulkan/vk_present_manager.cpp index aa019a4160..80853362ad 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_present_manager.cpp @@ -101,7 +101,7 @@ PresentManager::PresentManager(const vk::Instance& instance_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_, Swapchain& swapchain_, - VkSurfaceKHR_T* surface_) + vk::SurfaceKHR& surface_) : instance{instance_} , render_window{render_window_} , device{device_} @@ -291,7 +291,7 @@ void PresentManager::PresentThread(std::stop_token token) { } void PresentManager::RecreateSwapchain(Frame* frame) { - swapchain.Create(surface, frame->width, frame->height); // Pass raw pointer + swapchain.Create(*surface, frame->width, frame->height); // Pass raw pointer SetImageCount(); } @@ -310,7 +310,7 @@ void PresentManager::CopyToSwapchain(Frame* frame) { // Recreate surface and swapchain if needed. if (requires_recreation) { #ifdef ANDROID - surface = *CreateSurface(instance, render_window.GetWindowInfo()).address(); + surface = CreateSurface(instance, render_window.GetWindowInfo()); #endif RecreateSwapchain(frame); } diff --git a/src/video_core/renderer_vulkan/vk_present_manager.h b/src/video_core/renderer_vulkan/vk_present_manager.h index 3d5cc32102..c51f8ed77f 100644 --- a/src/video_core/renderer_vulkan/vk_present_manager.h +++ b/src/video_core/renderer_vulkan/vk_present_manager.h @@ -44,7 +44,7 @@ public: MemoryAllocator& memory_allocator, Scheduler& scheduler, Swapchain& swapchain, - VkSurfaceKHR_T* surface); + vk::SurfaceKHR& surface); ~PresentManager(); /// Returns the last used presentation frame @@ -78,7 +78,7 @@ private: MemoryAllocator& memory_allocator; Scheduler& scheduler; Swapchain& swapchain; - VkSurfaceKHR_T* surface; + vk::SurfaceKHR& surface; vk::CommandPool cmdpool; std::vector frames; boost::container::deque present_queue; From 11ad71b1e7db5206f074481d642020d1c30dafb1 Mon Sep 17 00:00:00 2001 From: lizzie Date: Sat, 7 Mar 2026 18:16:05 +0100 Subject: [PATCH 088/181] [docs] Obtanium, installing mods, external ES-DE config, section about CFW and settings (#3678) Signed-off-by: lizzie Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3678 Reviewed-by: DraVee Reviewed-by: CamilleLaVey Co-authored-by: lizzie Co-committed-by: lizzie --- README.md | 8 +- docs/README.md | 3 +- docs/user/AddGamesToSRM.md | 100 ---------- docs/user/CFW.md | 11 ++ docs/user/Graphics.md | 4 +- docs/user/Mods.md | 206 +++++++++++++++++++++ docs/user/README.md | 19 +- docs/user/Settings.md | 54 ++++++ docs/user/{AddEdenToSRM.md => SteamROM.md} | 129 +++++++++++-- docs/user/ThirdParty.md | 59 ++++++ 10 files changed, 473 insertions(+), 120 deletions(-) delete mode 100644 docs/user/AddGamesToSRM.md create mode 100644 docs/user/CFW.md create mode 100644 docs/user/Mods.md create mode 100644 docs/user/Settings.md rename docs/user/{AddEdenToSRM.md => SteamROM.md} (50%) diff --git a/README.md b/README.md index 3ae31151f7..44a2b4c28b 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,10 @@ See the [sign-up instructions](docs/SIGNUP.md) for information on registration. Alternatively, if you wish to add translations, go to the [Eden project on Transifex](https://app.transifex.com/edenemu/eden-emulator) and review [the translations README](./dist/languages). +## Documentation + +We have a user manual! See our [User Handbook](./docs/user/README.md). + ## Building See the [General Build Guide](docs/Build.md) @@ -69,7 +73,9 @@ For information on provided development tooling, see the [Tools directory](./too ## Download -You can download the latest releases from [here](https://github.com/eden-emulator/Releases/releases). +You can download the latest releases from [here](https://git.eden-emu.dev/eden-emu/eden/releases). + +Save us some bandwidth! We have [mirrors available](./docs/user/ThirdParty.md#mirrors) as well. ## Support diff --git a/docs/README.md b/docs/README.md index 01727ae4dc..4ea532be8e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,7 @@ # Eden Build Documentation +Are you just a casual user? Take a look at our [User Handbook](./user) then! + This contains documentation created by developers. This contains build instructions, guidelines, instructions/layouts for [cool stuff we made](./CPMUtil), and more. - **[General Build Instructions](Build.md)** @@ -11,7 +13,6 @@ This contains documentation created by developers. This contains build instructi - **[CPM - CMake Package Manager](./CPMUtil)** - **[Platform-Specific Caveats](Caveats.md)** - **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)** -- **[User Handbook](./user)** - **[Dynarmic](./dynarmic)** - **[Cross compilation](./CrossCompile.md)** - **[Driver Bugs](./DriverBugs.md)** diff --git a/docs/user/AddGamesToSRM.md b/docs/user/AddGamesToSRM.md deleted file mode 100644 index 433999c9b6..0000000000 --- a/docs/user/AddGamesToSRM.md +++ /dev/null @@ -1,100 +0,0 @@ -# Importing Games into Steam with Steam Rom Manager - -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.** - ---- - -### Pre-Requisites - -- Steam Deck Set up and Configured -- Eden set up and Configured -- Internet Access - ---- - -## Steps - -1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode. - -1. Install ***Steam ROM Manager***, there are 2 ways you can accomplish this, either manually or through [*EmuDeck*](https://www.emudeck.com/#downloads). - - --- - - ### Manual Installation - - 1. Open the *Discover Store* and search for *Steam ROM Manager.* - 2. Select the **Install** button to install the program. - - --- - - ### Installing Through *EmuDeck* - - - - 1. Open **EmuDeck**, then navigate to *Manage Emulators.* - 2. Scroll down to the bottom of the page to the *Manage your Tools & Frontends* section. Click **Steam ROM Manager**. - - 3. Click the **Install** button on the right hand side to install it. - - --- - -2. Open the Start Menu and Launch ***Steam ROM Manager*** - -1. The program will now launch and show you a window with parsers. - - - -2. Switch off all Parsers by hitting the *Toggle Parsers* switch. -3. Scroll down the list on the left-hand side and look for a parser called *Nintendo Switch - Eden* and switch it on. This parser may not exist depending on how you installed *Steam ROM Manager* (EmuDeck creates it for you). Follow these steps to create it if it is missing. - - --- - ### Creating the Eden Parser - - 1. Select Create Parser and in the *Community Presets* option look for **Nintendo Switch - Yuzu**. - 2. Change the **Parser title** from *Nintendo Switch - Yuzu* to *Nintendo Switch - Eden.* - 3. Hit the **Browse** option under the *ROMs directory* section. Select the directory containing your Switch ROMs. - 4. Under *Steam collections*, you can add a Steam category name. This just organizes the games under a common category in your Steam Library, this is optional but recommended. - 5. Scroll down slightly to the **Executable Configuration → Executable**, select **Browse** and select the Eden AppImage. - 6. Leave everything else the same and hit **Save** to save the parser. - --- - -4. Click the Eden parser to view the options on the right, select **Test** at the bottom of the screen to ensure that *Steam ROM Manager* detects your games correctly. -1. *Steam ROM Manager* will start to scan the specified ROMs directory and match them to games. Look over the results to ensure they are accurate. If you do not see any entries - check your parsers ROMs directory field. -1. When you are happy with the results, click the **Add Games** → **Parse** to start the actual Parsing. -1. The program will now identify the games and pull artwork from [*SteamGridDB*](https://www.steamgriddb.com/). -2. Review the game matches and ensure everything is there. - - --- - - ### Correcting a Mismatch - - If the game is not identified correctly, you may need to tell *Steam ROM Manager* what the game is manually. - - 1. Hover over the game card and click the magnifying glass icon. - 2. Search for the game on the *Search SteamGridDB* section and scroll through the results, selecting the one you want. - 3. Ensure the *Name* and *Game ID* update in the **Per-App Exceptions** and press **Save and close**. The game should now update. - - --- - - ### Excluding Matches - - You may want to tell Steam ROM Manager to ignore some files (updates/DLC/etc.) that it finds in the directory. This is how you do so. - - 1. Hit the **Exclude Games** button in the bottom right. - 2. Deselect the game you want to exclude, the poster artwork should go dim and the **Number Excluded** number should increment up. Repeat with any other exclusions you want to add. - 3. Hit **Save Excludes** when you are happy with your selections. - --- -3. When you are happy with the results, select **Save to Steam** to save the results. -1. The program will now start writing the entries into the Steam Library. You should get pop up notifications of the progress, but you can monitor the progress by selecting the **Log** on the left-hand side if needed. -2. Restart Steam to have the changes take effect. Check your library to ensure that your games are there, in a category if you defined one in the parser. -3. Try to launch a game and ensure everything is working. You are now good to go. \ No newline at end of file diff --git a/docs/user/CFW.md b/docs/user/CFW.md new file mode 100644 index 0000000000..ea224d3d36 --- /dev/null +++ b/docs/user/CFW.md @@ -0,0 +1,11 @@ +# User Handbook - Custom Firmware (CFW) + +At the moment of writing, we do not support CFW such as Atmosphere, due to: + +- Lacking the required LLE emulation capabilities to properly emulate the full firmware. +- Lack of implementation on some of the key internals. +- Nobody has bothered to do it (PRs always welcome!) + +We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments. + +If they don't run - then that's a bug! diff --git a/docs/user/Graphics.md b/docs/user/Graphics.md index e1e13a777d..ad359b9049 100644 --- a/docs/user/Graphics.md +++ b/docs/user/Graphics.md @@ -1,5 +1,7 @@ # User Handbook - Graphics +Graphical enhancements and visual quality improvments. This doesn't cover texture mods. + ## Visual Enhancements ### Anti-aliasing @@ -89,7 +91,7 @@ The OpenGL backend would invoke behaviour that would result in swarst/LLVMpipe w ### HaikuOS compatibility -HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purpouses `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through. +HaikuOS bundles a Mesa library that doesn't support full core OpenGL 4.6 (required by the emulator). This leads to HaikuOS being one of the few computer platforms where Vulkan is the only available option for users. If OpenGL is desired, Mesa has to be built manually from source. For debugging purposes `lavapipe` is recommended over the GPU driver; there is in-kernel support for NVIDIA cards through. ### Fixes for Windows 10 and above having "Device loss" diff --git a/docs/user/Mods.md b/docs/user/Mods.md new file mode 100644 index 0000000000..11361d628c --- /dev/null +++ b/docs/user/Mods.md @@ -0,0 +1,206 @@ +# User Handbook - Installing Mods + +## General Notes + +**Note:** When installing a mod, always read the mod's installation instructions. + +This is especially important if a mod uses a framework such as **ARCropolis**, **Skyline**, or **Atmosphere plugins**. In those cases, follow the framework's instructions instead of using Eden's normal mod folder. + +For example, **Super Smash Bros. Ultimate** uses such a framework. See the related section below for details. + +--- + +# Installing Mods for Most Games + +1. Right click a game in the game list. +2. Click **"Open Mod Data Location"**. +3. Extract the mod into that folder. + +Each mod should be placed inside **its own subfolder**. + +--- + +# Enabling or Disabling Mods + +1. Right click the game in the game list. +2. Click **Configure Game**. +3. In the **Add-Ons** tab, enable or disable mods, updates, and DLC by ticking or unticking their boxes. + +--- + +# Important Note About SD Card Paths + +Some mods are designed for real Nintendo Switch consoles and refer to the **SD card root**. + +The emulated SD card is located at: + +``` +%AppData%\eden\sdmc +``` + +Example: + +``` +Switch instruction: sd:/ultimate/mods +Eden equivalent: sdmc/ultimate/mods +``` + +--- + +# Framework-Based Mods (Super Smash Bros. Ultimate) + +Some games require external mod frameworks instead of the built-in mod loader. + +The most common example is **Super Smash Bros. Ultimate**. + +These mods are installed directly to the **emulated SD card**, not the normal Eden mod folder. + +--- + +# Installing the ARCropolis Modding Framework + +**Note:** Some mod packs bundle ARCropolis with their installer (for example, Smash Ult-S). + +--- + +## 1. Download ARCropolis + +Download the latest release: + +https://github.com/Raytwo/ARCropolis/releases/ + +--- + +## 2. Install ARCropolis + +Extract the **`atmosphere`** folder into: + +``` +%AppData%\eden\sdmc +``` + +This is the **emulated SD card directory**. + +Verify installation by checking that the following file exists: + +``` +sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins\libarcropolis.nro +``` + +--- + +## 3. Download Skyline + +Download the latest Skyline release: + +https://github.com/skyline-dev/skyline/releases + +Skyline used to be bundled with ARCropolis but is now distributed separately to avoid compatibility issues caused by outdated bundled versions. + +--- + +## 4. Install Skyline + +Extract the **`exefs`** folder into: + +``` +sdmc\atmosphere\contents\01006A800016E000 +``` + +The `exefs` folder should be **next to the `romfs` folder**. + +Verify installation by checking that the following file exists: + +``` +%AppData%\eden\sdmc\atmosphere\contents\01006A800016E000\exefs\subsdk9 +``` + +--- + +## 5. Launch the Game Once + +Start the game and make sure you see the **ARCropolis version text on the title screen**. + +This will also create the folders required for installing mods. + +--- + +## 6. Install Smash Ultimate Mods + +Install mods inside: + +``` +sdmc\ultimate\mods +``` + +Each mod must be placed inside **its own subfolder**. + +Example: + +``` +sdmc\ultimate\mods\ExampleMod +``` + +--- + +# Troubleshooting + +## ARCropolis text does not appear on startup + +Check the following: + +- `libarcropolis.nro` exists in: + +``` +sdmc\atmosphere\contents\01006A800016E000\romfs\skyline\plugins +``` + +- `subsdk9` exists in: + +``` +sdmc\atmosphere\contents\01006A800016E000\exefs +``` + +- Files were extracted to: + +``` +%AppData%\eden\sdmc +``` + +--- + +## Mods are not loading + +Make sure mods are installed inside: + +``` +sdmc\ultimate\mods +``` + +Each mod must have its **own subfolder**. + +Correct example: + +``` +sdmc\ultimate\mods\ExampleMod +``` + +Incorrect example: + +``` +sdmc\ultimate\mods\ExampleMod\ExampleMod +``` + +--- + +## Installing mods in the wrong folder + +ARCropolis mods **do not go in Eden's normal mod folder**. + +Do **not** install Smash mods here: + +``` +user\load\01006A800016E000 +``` + +That folder is only used for traditional **RomFS mods**, not ARCropolis. diff --git a/docs/user/README.md b/docs/user/README.md index 5fd3a17e51..9804f4d62f 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -4,10 +4,14 @@ The "FAQ". This handbook is primarily aimed at the end-user - baking useful knowledge for enhancing their emulation experience. +A copy of this handbook is [available online](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/user/README.md). + ## Basics - **[The Basics](Basics.md)** - **[Quickstart](./QuickStart.md)** +- **[Settings](./Settings.md)** +- **[Installing Mods](./Mods.md)** - **[Run On macOS](./RunOnMacOS.md)** - **[Audio](Audio.md)** - **[Graphics](Graphics.md)** @@ -17,22 +21,29 @@ This handbook is primarily aimed at the end-user - baking useful knowledge for e - **[Using Amiibo](./UsingAmiibo.md)** - **[Using Cheats](./UsingCheats.md)** - **[Importing Saves](./ImportingSaves.md)** -- **[Add Eden to Steam ROM Manager](./AddEdenToSRM.md)** -- **[Add Games to Steam ROM Manager](./AddGamesToSRM.md)** - **[Installing Atmosphere Mods](./InstallingAtmosphereMods.md)** - **[Installing Updates & DLCs](./InstallingUpdatesDLC.md)** - **[Controller Profiles](./ControllerProfiles.md)** - **[Alter Date & Time](./AlterDateTime.md)** +## 3rd-party Integration + +- **[Configuring Steam ROM Manager](./SteamROM.md)** +- **[Server hosting](ServerHosting.md)** +- **[Syncthing Guide](./SyncthingGuide.md)** +- **[Third Party](./ThirdParty.md)** + - **[Obtainium](./ThirdParty.md#configuring-obtainium)** + - **[ES-DE](./ThirdParty.md#configuring-es-de)** + - **[Mirrors](./ThirdParty.md#mirrors)** + ## Advanced +- **[Custom Firmware](./CFW.md)** - **[How To Access Logs](./HowToAccessLogs.md)** - **[Gyro Controls](./GyroControls.md)** - **[Platforms and Architectures](Architectures.md)** -- **[Server hosting](ServerHosting.md)** - **[Command Line](CommandLine.md)** - **[Native Application Development](Native.md)** - **[Adding Boolean Settings Toggles](AddingBooleanToggles.md)** - **[Adding Debug Knobs](./AddingDebugKnobs.md)** -- **[Syncthing Guide](./SyncthingGuide.md)** - **[Testing](Testing.md)** diff --git a/docs/user/Settings.md b/docs/user/Settings.md new file mode 100644 index 0000000000..35fcd0c9ef --- /dev/null +++ b/docs/user/Settings.md @@ -0,0 +1,54 @@ +# User Handbook - Settings + +As the emulator continues to grow, so does the number of settings that come and go. + +Most of the development adds new settings that enhance performance/compatibility, only to be removed later in newer versions due to newfound discoveries or because they were "a hacky workaround". + +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. + +## 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. + +## General + +- `General/Force X11 as Graphics Backend`: Wayland on *NIX has prominent issues that are unlikely to be resolved; the kind that are "not our fault, it's Wayland issue", this "temporary" hack forces X11 as the backend, regardless of the desktop manager's default. +- `General/Enable Gamemode`: This only does anything when you have Feral Interactive's Gamemode library installed somewhere, if you do, this will help boost FPS by telling the OS to explicitly prioritize *this* application for "gaming" - only for *NIX systems. +- `Hotkeys`: Deceptively to remove a hotkey you must right click and a menu will appear to remove that specific hotkey. +- `UI/Language`: Changes language *of the interface* NOT the emulated program! +- `Debug/Enable Auto Stub`: May help to "fix" some games by just lying and saying that everything they do returns "success" instead of outright crashing for any function/service that is NOT implemented. +- `Debug/Show log in console`: Does as said, note that the program may need to be reopened (Windows) for changes to take effect. +- `Debug/Flush log output`: Classically, every write to the log is "buffered", that is, changes aren't written to the disk UNTIL the program has decided it is time to write, until then it keeps data in a buffer which resides on RAM. If the program crashes, the OS will automatically discard said buffer (any RAM associated with a dead process is automatically discarded/reused for some other purpose); this means critical data may not be logged to the disk on time, which may lead to missing log lines. Use this if you're wanting to remove that factor when debugging, sometimes a hard crash may "eat" some of the log lines IF this option isn't enabled. +- `Debug/Disable Macro HLE:` The emulator has HLE emulation of macro programs for Maxwell, this means that some details are purpousefully skipped; this option forces all macro programs to be ran without skipping anything. + +## 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. +- `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 + +- `CPU/Virtual table bouncing`: Some games have the tendency to crash on loading due to an indirect bad jump (Pokemon ZA being the worst offender); this option lies to the game and tells it to just pretend it never executed a given function. This is fine for most casual users, but developers of switch applications **must** disable this. This temporary "hack" should hopefully be gone in 6-7 months from now on. +- `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/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/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. + +It is important to note the majority of precision-reducing instructions do not benefit cases where they are not used, which means the performance gains will vary per game. + +# Graphics + +See also [an extended breakdown of some options](./Graphics.md). + +- `Extras/Extended Dynamic State` and `Extras/Vertex Input Dynamic State`: These Vulkan extensions essentially allow you to reuse the same pipeline but just change the state between calls (so called "dynamic state"); the "extended" levels signifies how much state can be placed on this "dynamic" range, for example the amount of depth culling to use can be placed on the dynamic state, avoiding costly reloads and flushes. While this by itself is a fine option, SOME vendors (notably PowerVR and Mali) have problems with anything related to EDS3. EDS3 contains EDS2, and EDS2 contains EDS1. Essentially this means more extended data the driver has to keep track of, at the benefit of avoiding costly flushes. +- `Advanced/Use persistent cache`: This saves compiled shaders onto the disk, independent of any driver's own disk saved shaders (yes, some drivers, notably NVIDIA, save a secondary shader cache onto disk) - disable this only if you're debugging or working on the GPU backend. This option is meant to massively help to reduce shader stutters (after playing for one session that compiles them). +- `Advanced/Use Vulkan pipeline cache`: This is NOT the same as `Use persistent cache`; it's a separate flag that tells the Vulkan backend to create pipeline caches, which are a detail that can be used to massively improve performance and remove pipeline creation overhead. This is a Vulkan feature. + +## Controls + +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: +- https://github.com/dkosmari/calibrate-joystick diff --git a/docs/user/AddEdenToSRM.md b/docs/user/SteamROM.md similarity index 50% rename from docs/user/AddEdenToSRM.md rename to docs/user/SteamROM.md index 4658bcf7e0..a782b51969 100644 --- a/docs/user/AddEdenToSRM.md +++ b/docs/user/SteamROM.md @@ -1,4 +1,6 @@ -# Importing Eden into Steam with Steam Rom Manager +# User Handbook - Configuring Steam ROM Manager + +## Importing Eden into Steam with Steam Rom Manager Use this when you want to import the Eden AppImage into your Steam Library along with artwork using *Steam ROM Manager.* @@ -6,7 +8,7 @@ Use this when you want to import the Eden AppImage into your Steam Library along --- -### Pre-Requisites +#### Pre-Requisites - Eden set up and configured - Internet Connection @@ -14,9 +16,9 @@ Use this when you want to import the Eden AppImage into your Steam Library along --- -## Steps +### Steps -### Initial Setup +#### Initial Setup 1. Press the **STEAM** button and then go to *Power → Switch to Desktop* to enter the Desktop mode. @@ -24,14 +26,14 @@ Use this when you want to import the Eden AppImage into your Steam Library along --- - ### Manual Installation + #### Manual Installation 1. Open the *Discover Store* and search for *Steam ROM Manager.* 2. Select the **Install** button to install the program. --- - ### Installing Through *EmuDeck* + #### Installing Through *EmuDeck*