Compare commits
36 Commits
dynarmic-d
...
eden-orbis
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13330d9f40 | ||
|
|
83839afee4 | ||
|
|
abf7f9e660 | ||
|
|
2e9b83ec60 | ||
|
|
31bf016581 | ||
|
|
158491ca24 | ||
|
|
94e2dedf26 | ||
|
|
571970c155 | ||
|
|
3813d0cc48 | ||
|
|
dac749063f | ||
|
|
f178cb394c | ||
|
|
07bfa08f99 | ||
|
|
1514146522 | ||
|
|
66143bf7a5 | ||
|
|
0dc71ff89a | ||
|
|
7d5e78b3dc | ||
|
|
9bebc88bcd | ||
|
|
628b1a84b9 | ||
|
|
2aeb14b096 | ||
|
|
891c3aee4b | ||
|
|
70496b0400 | ||
|
|
96c1abcbf7 | ||
|
|
f4d80a0bda | ||
|
|
2ef9cb72c4 | ||
|
|
40b88aaf08 | ||
|
|
da120cd2b4 | ||
|
|
9688243e6c | ||
|
|
9dc1b595e0 | ||
|
|
f9977fb46c | ||
|
|
818ff96fac | ||
|
|
d057db0a86 | ||
|
|
cfae726289 | ||
|
|
bb94cff886 | ||
|
|
370997f42e | ||
|
|
5213cc5689 | ||
|
|
bc9af86269 |
54
.ci/ps4/build.sh
Executable file
54
.ci/ps4/build.sh
Executable file
@@ -0,0 +1,54 @@
|
||||
#!/usr/local/bin/bash -ex
|
||||
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
[ -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 -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 "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||
set(CMAKE_C_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||
set(CMAKE_CXX_LINK_FLAGS "-m elf_x86_64 -pie -T $OO_PS4_TOOLCHAIN/link.x --eh-frame-hdr -L$OO_PS4_TOOLCHAIN/lib")
|
||||
|
||||
set(CMAKE_C_COMPILER clang)
|
||||
set(CMAKE_CXX_COMPILER clang++)
|
||||
set(CMAKE_LINKER ld.lld)
|
||||
set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_C_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <CMAKE_CXX_LINK_FLAGS> <OBJECTS> -o <TARGET> -lc -lkernel -lc++ -lSceUserService -lSceSysmodule -lSceNet $OO_PS4_TOOLCHAIN/lib/crt1.o <LINK_LIBRARIES>")
|
||||
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
|
||||
# TODO: Why does cmake not set this?
|
||||
set(CMAKE_SIZEOF_VOID_P 8)
|
||||
EOF
|
||||
|
||||
# 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 "Unix Makefiles" \
|
||||
-DCMAKE_TOOLCHAIN_FILE="ps4-toolchain.cmake" \
|
||||
-DENABLE_QT_TRANSLATION=OFF \
|
||||
-DENABLE_CUBEB=OFF \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_CXX_FLAGS="$ARCH_FLAGS" \
|
||||
-DCMAKE_C_FLAGS="$ARCH_FLAGS" \
|
||||
-DENABLE_SDL2=ON \
|
||||
-DENABLE_LIBUSB=OFF \
|
||||
-DENABLE_UPDATE_CHECKER=OFF \
|
||||
-DENABLE_QT=OFF \
|
||||
-DENABLE_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
|
||||
cmake --build build -t yuzu-cmd_pkg -- -j8
|
||||
176
.ci/ps4/make-toolchain.sh
Executable file
176
.ci/ps4/make-toolchain.sh
Executable file
@@ -0,0 +1,176 @@
|
||||
#!/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"
|
||||
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
|
||||
[ -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/"
|
||||
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 -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 -ldflags "-linkmode external -extldflags -static" -o create-gp4
|
||||
mv ./create-gp4 $PREFIX/bin/create-gp4
|
||||
cd ../../../
|
||||
|
||||
# Build readoelf
|
||||
cd readoelf/cmd/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
|
||||
}
|
||||
|
||||
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 -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
|
||||
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
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -63,3 +63,6 @@ artifacts
|
||||
*.AppImage*
|
||||
/install*
|
||||
vulkansdk*.exe
|
||||
|
||||
# PS4 toolchain stuff
|
||||
ps4-toolchain.cmake
|
||||
|
||||
17
.patch/boost/0004-openorbis.patch
Normal file
17
.patch/boost/0004-openorbis.patch
Normal file
@@ -0,0 +1,17 @@
|
||||
diff --git a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||
index 0129511c..10fc9b04 100644
|
||||
--- a/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||
+++ b/libs/asio/include/boost/asio/detail/impl/socket_ops.ipp
|
||||
@@ -15,6 +15,12 @@
|
||||
# pragma once
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
||||
|
||||
+// hacky fix for ps4
|
||||
+#if defined(__OPENORBIS__)
|
||||
+# define FIONBIO 0
|
||||
+# define FIONREAD 1
|
||||
+#endif
|
||||
+
|
||||
#include <boost/asio/detail/config.hpp>
|
||||
|
||||
#include <cctype>
|
||||
13
.patch/enet/0001-openorbis.patch
Normal file
13
.patch/enet/0001-openorbis.patch
Normal file
@@ -0,0 +1,13 @@
|
||||
diff --git a/unix.c b/unix.c
|
||||
index 6669216..86a2faa 100644
|
||||
--- a/unix.c
|
||||
+++ b/unix.c
|
||||
@@ -53,7 +53,7 @@
|
||||
#include <poll.h>
|
||||
#endif
|
||||
|
||||
-#if !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||
+#if !defined(__OPENORBIS__) && !defined(HAS_SOCKLEN_T) && !defined(__socklen_t_defined)
|
||||
typedef int socklen_t;
|
||||
#endif
|
||||
|
||||
@@ -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__)
|
||||
+#if (defined(__GNUC__) || defined(__clang__)) && !defined(_LIBCPP_HAS_MUSL_LIBC)
|
||||
#define MBEDTLS_AESNI_HAVE_INTRINSICS
|
||||
#endif
|
||||
/* For 32-bit, we only support intrinsics */
|
||||
@@ -25,7 +25,7 @@ index 2857068..3e104ab 100644
|
||||
#pragma GCC target ("pclmul,sse2,aes")
|
||||
#define MBEDTLS_POP_TARGET_PRAGMA
|
||||
-#elif defined(__clang__) && (__clang_major__ >= 5)
|
||||
+#elif defined(__clang__)
|
||||
+#elif defined(__clang__) && !defined(__OPENORBIS__)
|
||||
#pragma clang attribute push (__attribute__((target("pclmul,sse2,aes"))), apply_to=function)
|
||||
#define MBEDTLS_POP_TARGET_PRAGMA
|
||||
#endif
|
||||
|
||||
13
.patch/mbedtls/0003-openorbis.patch
Normal file
13
.patch/mbedtls/0003-openorbis.patch
Normal file
@@ -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 <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#if defined(KERN_ARND)
|
||||
25
.patch/spirv-tools/0002-openorbis.patch
Normal file
25
.patch/spirv-tools/0002-openorbis.patch
Normal file
@@ -0,0 +1,25 @@
|
||||
diff --git a/source/opt/loop_dependence.cpp b/source/opt/loop_dependence.cpp
|
||||
index e41c044..a51b53b 100644
|
||||
--- a/source/opt/loop_dependence.cpp
|
||||
+++ b/source/opt/loop_dependence.cpp
|
||||
@@ -12,6 +12,12 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
+// PS4: issue?
|
||||
+#ifdef __PS4__
|
||||
+#pragma clang diagnostic ignored "-Wabsolute-value"
|
||||
+#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
||||
+#endif
|
||||
+
|
||||
#include "source/opt/loop_dependence.h"
|
||||
|
||||
#include <functional>
|
||||
@@ -19,6 +25,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
+#include <cstdlib>
|
||||
|
||||
#include "source/opt/instruction.h"
|
||||
#include "source/opt/scalar_analysis_nodes.h"
|
||||
@@ -17,6 +17,7 @@ include(DownloadExternals)
|
||||
include(CMakeDependentOption)
|
||||
include(CTest)
|
||||
include(CPMUtil)
|
||||
include(OpenOrbis)
|
||||
|
||||
DetectArchitecture()
|
||||
|
||||
|
||||
391
CMakeModules/FindSDL2.cmake
Normal file
391
CMakeModules/FindSDL2.cmake
Normal file
@@ -0,0 +1,391 @@
|
||||
# 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.
|
||||
|
||||
# Copyright 2019 Amine Ben Hassouna <amine.benhassouna@gmail.com>
|
||||
# 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 <SDL/SDL.h>. 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()
|
||||
@@ -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()
|
||||
|
||||
set(GIT_DESC ${BUILD_VERSION})
|
||||
|
||||
33
CMakeModules/OpenOrbis.cmake
Normal file
33
CMakeModules/OpenOrbis.cmake
Normal file
@@ -0,0 +1,33 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
function(create_ps4_pkg project target content_id)
|
||||
set(sce_sys_dir sce_sys)
|
||||
set(sce_sys_param ${sce_sys_dir}/param.sfo)
|
||||
add_custom_command(
|
||||
OUTPUT "${target}.pkg"
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/create-fself -in=bin/${target} -out=${target}.oelf --eboot eboot.bin
|
||||
COMMAND mkdir -p ${sce_sys_dir}
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_new ${sce_sys_param}
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_TYPE --type Integer --maxsize 4 --value 1
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} APP_VER --type Utf8 --maxsize 8 --value 1.03
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} ATTRIBUTE --type Integer --maxsize 4 --value 0
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CATEGORY --type Utf8 --maxsize 4 --value gd
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} CONTENT_ID --type Utf8 --maxsize 48 --value ${content_id}
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} DOWNLOAD_DATA_SIZE --type Integer --maxsize 4 --value 0
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} SYSTEM_VER --type Integer --maxsize 4 --value 0
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE --type Utf8 --maxsize 128 --value ${target}
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} TITLE_ID --type Utf8 --maxsize 12 --value BREW00090
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core sfo_setentry ${sce_sys_param} VERSION --type Utf8 --maxsize 8 --value 1.03
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/create-gp4 -out ${target}.gp4 --content-id=${content_id} --files "eboot.bin ${sce_sys_param} sce_module/libc.prx sce_module/libSceFios2.prx"
|
||||
COMMAND ${CMAKE_SYSROOT}/bin/PkgTool.Core pkg_build ${target}.gp4 .
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS ${project}
|
||||
)
|
||||
add_custom_target(${project}_pkg ALL DEPENDS "${target}.pkg")
|
||||
endfunction()
|
||||
|
||||
if (NOT DEFINED ENV{OO_PS4_TOOLCHAIN})
|
||||
set(ENV{OO_PS4_TOOLCHAIN} ${CMAKE_SYSROOT})
|
||||
endif ()
|
||||
@@ -19,7 +19,8 @@
|
||||
"patches": [
|
||||
"0001-clang-cl.patch",
|
||||
"0002-use-marmasm.patch",
|
||||
"0003-armasm-options.patch"
|
||||
"0003-armasm-options.patch",
|
||||
"0004-openorbis.patch"
|
||||
]
|
||||
},
|
||||
"fmt": {
|
||||
@@ -96,8 +97,8 @@
|
||||
"package": "VVL",
|
||||
"repo": "KhronosGroup/Vulkan-ValidationLayers",
|
||||
"tag": "vulkan-sdk-%VERSION%",
|
||||
"git_version": "1.4.328.1",
|
||||
"git_version": "1.4.335.0",
|
||||
"artifact": "android-binaries-%VERSION%.zip",
|
||||
"hash": "5ec895a453cb7c2f156830b9766953a0c2bd44dea99e6a3dac4160305041ccd3e87534b4ce0bd102392178d2a8eca48411856298f9395e60117cdfe89f72137e"
|
||||
"hash": "48167c4a17736301bd08f9290f41830443e1f18cce8ad867fc6f289b49e18b40e93c9850b377951af82f51b5b6d7313aa6a884fc5df79f5ce3df82696c1c1244"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,3 +207,10 @@ Install [Qt6 compatibility libraries](github.com/ANightly/qt6windows7) specifica
|
||||
The package install may randomly hang at times, in which case it has to be restarted. ALWAYS do a `sudo pkg update` or the chances of it hanging will be close to 90%. If "multiple" installs fail at once, try installing 1 by 1 the packages.
|
||||
|
||||
When CMake invokes certain file syscalls - it may sometimes cause crashes or corruptions on the (kernel?) address space - so reboot the system if there is a "hang" in CMake.
|
||||
|
||||
## PlayStation 4 (OpenOrbis cross compile)
|
||||
|
||||
```sh
|
||||
export OO_PS4_TOOLCHAIN="$HOME/OpenOrbis/PS4Toolchain"
|
||||
export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1
|
||||
```
|
||||
|
||||
@@ -13,4 +13,3 @@ This contains documentation created by developers. This contains build instructi
|
||||
- **[The NVIDIA SM86 (Maxwell) GPU](./NvidiaGpu.md)**
|
||||
- **[User Handbook](./user)**
|
||||
- **[Release Policy](./ReleasePolicy.md)**
|
||||
- **[Dynarmic](./dynarmic)**
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
6
externals/CMakeLists.txt
vendored
6
externals/CMakeLists.txt
vendored
@@ -147,7 +147,11 @@ if (ENABLE_SDL2)
|
||||
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)
|
||||
|
||||
2
externals/cmake-modules/DetectPlatform.cmake
vendored
2
externals/cmake-modules/DetectPlatform.cmake
vendored
@@ -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")
|
||||
|
||||
15
externals/cpmfile.json
vendored
15
externals/cpmfile.json
vendored
@@ -104,7 +104,8 @@
|
||||
"skip_updates": true,
|
||||
"patches": [
|
||||
"0001-aesni-fix.patch",
|
||||
"0002-arm64-aes-fix.patch"
|
||||
"0002-arm64-aes-fix.patch",
|
||||
"0003-openorbis.patch"
|
||||
]
|
||||
},
|
||||
"enet": {
|
||||
@@ -113,16 +114,19 @@
|
||||
"hash": "a0d2fa8c957704dd49e00a726284ac5ca034b50b00d2b20a94fa1bbfbb80841467834bfdc84aa0ed0d6aab894608fd6c86c3b94eee46343f0e6d9c22e391dbf9",
|
||||
"version": "1.3",
|
||||
"git_version": "1.3.18",
|
||||
"find_args": "MODULE"
|
||||
"find_args": "MODULE",
|
||||
"patches": [
|
||||
"0001-openorbis.patch"
|
||||
]
|
||||
},
|
||||
"vulkan-utility-headers": {
|
||||
"package": "VulkanUtilityLibraries",
|
||||
"repo": "scripts/VulkanUtilityHeaders",
|
||||
"tag": "%VERSION%",
|
||||
"git_version": "1.4.328",
|
||||
"git_version": "1.4.335",
|
||||
"artifact": "VulkanUtilityHeaders.tar.zst",
|
||||
"git_host": "git.crueter.xyz",
|
||||
"hash": "9922217b39faf73cd4fc1510f2fdba14a49aa5c0d77f9ee24ee0512cef16b234d0cabc83c1fec861fa5df1d43e7f086ca9b6501753899119f39c5ca530cb0dae"
|
||||
"hash": "16dac0e6586702580c4279e4cd37ffe3cf909c93eb31b5069da7af36436d47b270a9cbaac953bb66c22ed12ed67ffa096688599267f307dfb62be1bc09f79833"
|
||||
},
|
||||
"spirv-tools": {
|
||||
"package": "SPIRV-Tools",
|
||||
@@ -134,7 +138,8 @@
|
||||
"SPIRV_SKIP_EXECUTABLES ON"
|
||||
],
|
||||
"patches": [
|
||||
"0001-netbsd-fix.patch"
|
||||
"0001-netbsd-fix.patch",
|
||||
"0002-openorbis.patch"
|
||||
]
|
||||
},
|
||||
"spirv-headers": {
|
||||
|
||||
181
externals/ffmpeg/CMakeLists.txt
vendored
181
externals/ffmpeg/CMakeLists.txt
vendored
@@ -13,63 +13,106 @@ 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)
|
||||
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}"
|
||||
)
|
||||
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 (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 (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)
|
||||
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)
|
||||
@@ -113,6 +156,23 @@ if (UNIX AND NOT ANDROID)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4)
|
||||
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()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
AddJsonPackage(ffmpeg-ci)
|
||||
|
||||
@@ -183,24 +243,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})
|
||||
@@ -217,15 +259,18 @@ else()
|
||||
--disable-ffmpeg
|
||||
--disable-ffprobe
|
||||
--disable-network
|
||||
--disable-postproc
|
||||
--disable-swresample
|
||||
--enable-decoder=h264
|
||||
--enable-decoder=vp8
|
||||
--enable-decoder=vp9
|
||||
--enable-filter=yadif,scale
|
||||
--enable-pic
|
||||
--cc="${FFmpeg_CC}"
|
||||
--cxx="${FFmpeg_CXX}"
|
||||
--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
|
||||
@@ -257,7 +302,7 @@ else()
|
||||
OUTPUT
|
||||
${FFmpeg_BUILD_LIBRARIES}
|
||||
COMMAND
|
||||
make ${FFmpeg_MAKE_ARGS}
|
||||
gmake ${FFmpeg_MAKE_ARGS}
|
||||
WORKING_DIRECTORY
|
||||
${FFmpeg_BUILD_DIR}
|
||||
)
|
||||
|
||||
@@ -39,7 +39,6 @@ android {
|
||||
|
||||
buildFeatures {
|
||||
viewBinding = true
|
||||
buildConfig = true
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
|
||||
@@ -14,6 +14,8 @@ android.useAndroidX=true
|
||||
# Kotlin code style for this project: "official" or "obsolete":
|
||||
kotlin.code.style=official
|
||||
kotlin.parallel.tasks.in.project=true
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
|
||||
# Android Gradle plugin 8.0.2
|
||||
android.suppressUnsupportedCompileSdk=34
|
||||
android.native.buildOutput=verbose
|
||||
@@ -251,8 +251,8 @@ if (ENABLE_SDL2)
|
||||
sink/sdl2_sink.cpp
|
||||
sink/sdl2_sink.h
|
||||
)
|
||||
|
||||
target_link_libraries(audio_core PRIVATE SDL2::SDL2)
|
||||
target_include_directories(audio_core PRIVATE ${CMAKE_SYSROOT}/include/SDL2)
|
||||
target_link_libraries(audio_core PRIVATE SDL2)
|
||||
target_compile_definitions(audio_core PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ struct Member {
|
||||
struct RoomInformation {
|
||||
std::string name; ///< Name of the server
|
||||
std::string description; ///< Server description
|
||||
u32 member_slots; ///< Maximum number of members in this room
|
||||
u16 port; ///< The port of this room
|
||||
u32 member_slots{}; ///< Maximum number of members in this room
|
||||
u16 port{}; ///< The port of this room
|
||||
GameInfo preferred_game; ///< Game to advertise that you want to play
|
||||
std::string host_username; ///< Forum username of the host
|
||||
};
|
||||
@@ -46,8 +46,8 @@ struct Room {
|
||||
std::string id;
|
||||
std::string verify_uid; ///< UID used for verification
|
||||
std::string ip;
|
||||
u32 net_version;
|
||||
bool has_password;
|
||||
u32 net_version{};
|
||||
bool has_password = false;
|
||||
|
||||
std::vector<Member> members;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -171,11 +174,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",
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -30,19 +30,21 @@
|
||||
#include <sys/random.h>
|
||||
#include <mach/vm_map.h>
|
||||
#include <mach/mach.h>
|
||||
#elif defined(__OPENORBIS__)
|
||||
#include <orbis/libkernel.h>
|
||||
#endif
|
||||
|
||||
// FreeBSD
|
||||
#ifndef MAP_NORESERVE
|
||||
#define MAP_NORESERVE 0
|
||||
# define MAP_NORESERVE 0
|
||||
#endif
|
||||
// Solaris 11 and illumos
|
||||
#ifndef MAP_ALIGNED_SUPER
|
||||
#define MAP_ALIGNED_SUPER 0
|
||||
# define MAP_ALIGNED_SUPER 0
|
||||
#endif
|
||||
// macOS
|
||||
#ifndef MAP_ANONYMOUS
|
||||
#define MAP_ANONYMOUS MAP_ANON
|
||||
# define MAP_ANONYMOUS MAP_ANON
|
||||
#endif
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
@@ -68,8 +70,8 @@ static int memfd_create(const char* name, unsigned int flags) {
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr size_t PageAlignment = 0x1000;
|
||||
constexpr size_t HugePageSize = 0x200000;
|
||||
[[maybe_unused]] constexpr size_t PageAlignment = 0x1000;
|
||||
[[maybe_unused]] constexpr size_t HugePageSize = 0x200000;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -438,13 +440,15 @@ static void* ChooseVirtualBase(size_t virtual_size) {
|
||||
|
||||
#else
|
||||
|
||||
static void* ChooseVirtualBase(size_t virtual_size) {
|
||||
static void* ChooseVirtualBase(size_t size) {
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__managarm__) || defined(__AIX__)
|
||||
void* virtual_base = mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
|
||||
void* virtual_base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_ALIGNED_SUPER, -1, 0);
|
||||
if (virtual_base != MAP_FAILED)
|
||||
return virtual_base;
|
||||
return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
#else
|
||||
return mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
#endif
|
||||
return mmap(nullptr, virtual_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -500,9 +504,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);
|
||||
@@ -692,31 +699,25 @@ private:
|
||||
|
||||
#endif // ^^^ POSIX ^^^
|
||||
|
||||
HostMemory::HostMemory(size_t backing_size_, size_t virtual_size_)
|
||||
: backing_size(backing_size_), virtual_size(virtual_size_) {
|
||||
try {
|
||||
// Try to allocate a fastmem arena.
|
||||
// The implementation will fail with std::bad_alloc on errors.
|
||||
impl =
|
||||
std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment),
|
||||
AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
|
||||
if (virtual_base) {
|
||||
// Ensure the virtual base is aligned to the L2 block size.
|
||||
virtual_base = reinterpret_cast<u8*>(
|
||||
Common::AlignUp(reinterpret_cast<uintptr_t>(virtual_base), HugePageSize));
|
||||
virtual_base_offset = virtual_base - impl->virtual_base;
|
||||
}
|
||||
|
||||
} catch (const std::bad_alloc&) {
|
||||
LOG_CRITICAL(HW_Memory,
|
||||
"Fastmem unavailable, falling back to VirtualBuffer for memory allocation");
|
||||
fallback_buffer = std::make_unique<Common::VirtualBuffer<u8>>(backing_size);
|
||||
backing_base = fallback_buffer->data();
|
||||
virtual_base = nullptr;
|
||||
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();
|
||||
virtual_base = nullptr;
|
||||
#else
|
||||
// Try to allocate a fastmem arena.
|
||||
// The implementation will fail with std::bad_alloc on errors.
|
||||
impl = std::make_unique<HostMemory::Impl>(AlignUp(backing_size, PageAlignment), AlignUp(virtual_size, PageAlignment) + HugePageSize);
|
||||
backing_base = impl->backing_base;
|
||||
virtual_base = impl->virtual_base;
|
||||
if (virtual_base) {
|
||||
// Ensure the virtual base is aligned to the L2 block size.
|
||||
virtual_base = reinterpret_cast<u8*>(Common::AlignUp(uintptr_t(virtual_base), HugePageSize));
|
||||
virtual_base_offset = virtual_base - impl->virtual_base;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
HostMemory::~HostMemory() = default;
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
@@ -81,7 +85,7 @@ private:
|
||||
size_t virtual_base_offset{};
|
||||
|
||||
// Fallback if fastmem is not supported on this platform
|
||||
std::unique_ptr<Common::VirtualBuffer<u8>> fallback_buffer;
|
||||
std::optional<Common::VirtualBuffer<u8>> fallback_buffer;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,7 +11,7 @@
|
||||
// clang-format on
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#if defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#if defined(__APPLE__) || (defined(__FreeBSD__) && !defined(__OPENORBIS__))
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__linux__)
|
||||
#include <sys/sysinfo.h>
|
||||
@@ -43,6 +46,8 @@ static MemoryInfo Detect() {
|
||||
sysctlbyname("vm.swapusage", &vmusage, &sizeof_vmusage, nullptr, 0);
|
||||
mem_info.TotalPhysicalMemory = ramsize;
|
||||
mem_info.TotalSwapMemory = vmusage.xsu_total;
|
||||
#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);
|
||||
|
||||
@@ -196,7 +196,14 @@ struct Values {
|
||||
linkage, false, "dump_audio_commands", Category::Audio, Specialization::Default, false};
|
||||
|
||||
// Core
|
||||
SwitchableSetting<bool> use_multi_core{linkage, true, "use_multi_core", Category::Core};
|
||||
SwitchableSetting<bool> use_multi_core{linkage,
|
||||
#ifdef __OPENORBIS__
|
||||
// Re-enable once proper TLS support is added
|
||||
false,
|
||||
#else
|
||||
true,
|
||||
#endif
|
||||
"use_multi_core", Category::Core};
|
||||
SwitchableSetting<MemoryLayout, true> memory_layout_mode{linkage,
|
||||
MemoryLayout::Memory_4Gb,
|
||||
"memory_layout_mode",
|
||||
@@ -318,14 +325,14 @@ struct Values {
|
||||
|
||||
// Renderer
|
||||
SwitchableSetting<RendererBackend, true> renderer_backend{linkage,
|
||||
#if defined(__sun__) || defined(__managarm__)
|
||||
#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__)
|
||||
RendererBackend::OpenGL,
|
||||
#else
|
||||
RendererBackend::Vulkan,
|
||||
#endif
|
||||
"backend", Category::Renderer};
|
||||
SwitchableSetting<ShaderBackend, true> shader_backend{linkage,
|
||||
#if defined(__sun__) || defined(__managarm__)
|
||||
#if defined(__sun__) || defined(__managarm__) || defined(__OPENORBIS__)
|
||||
ShaderBackend::Glsl,
|
||||
#else
|
||||
ShaderBackend::SpirV,
|
||||
|
||||
@@ -10,30 +10,147 @@
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef __OPENORBIS__
|
||||
#include <ranges>
|
||||
#include <csignal>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <orbis/SystemService.h>
|
||||
typedef void (*SceKernelExceptionHandler)(int32_t, void*);
|
||||
extern "C" int32_t sceKernelInstallExceptionHandler(int32_t signum, SceKernelExceptionHandler handler);
|
||||
#endif
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/virtual_buffer.h"
|
||||
#include "common/logging/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
|
||||
// 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 {
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
#ifdef _WIN32
|
||||
void* base = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
|
||||
#else
|
||||
void* base = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
if (base == MAP_FAILED)
|
||||
base = nullptr;
|
||||
#endif
|
||||
ASSERT(base);
|
||||
return base;
|
||||
#ifdef __OPENORBIS__
|
||||
|
||||
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];
|
||||
};
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) noexcept {
|
||||
if (!base)
|
||||
static boost::container::static_vector<std::pair<void*, size_t>, 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) {
|
||||
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<void*>(uintptr_t(mctx.mc_addr) & page_mask);
|
||||
void* res = mmap(aligned_addr, page_size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
ASSERT(res != MAP_FAILED);
|
||||
} else {
|
||||
LOG_ERROR(HW_Memory, "fault in addr {:#x} at {:#x}", mctx.mc_addr, mctx.mc_rip); // print caller address
|
||||
sceKernelRemoveExceptionHandler(SIGSEGV); // to not catch the next signal
|
||||
}
|
||||
}
|
||||
void InitSwap() noexcept {
|
||||
sceKernelInstallExceptionHandler(SIGSEGV, &SwapHandler);
|
||||
}
|
||||
#else
|
||||
void InitSwap() noexcept {}
|
||||
#endif
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept {
|
||||
#ifdef _WIN32
|
||||
void* addr = VirtualAlloc(nullptr, size, MEM_COMMIT, 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);
|
||||
#else
|
||||
void* addr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
|
||||
ASSERT(addr != MAP_FAILED);
|
||||
#endif
|
||||
return addr;
|
||||
}
|
||||
|
||||
void FreeMemoryPages(void* addr, [[maybe_unused]] std::size_t size) noexcept {
|
||||
if (!addr)
|
||||
return;
|
||||
#ifdef _WIN32
|
||||
ASSERT(VirtualFree(base, 0, MEM_RELEASE));
|
||||
VirtualFree(addr, 0, MEM_RELEASE);
|
||||
#else
|
||||
ASSERT(munmap(base, size) == 0);
|
||||
int rc = munmap(addr, size);
|
||||
ASSERT(rc == 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,6 +12,7 @@ namespace Common {
|
||||
|
||||
void* AllocateMemoryPages(std::size_t size) noexcept;
|
||||
void FreeMemoryPages(void* base, std::size_t size) noexcept;
|
||||
void InitSwap() noexcept;
|
||||
|
||||
template <typename T>
|
||||
class VirtualBuffer final {
|
||||
@@ -32,9 +36,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);
|
||||
|
||||
@@ -295,7 +295,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ArmDynarmic32::MakeJit(Common::PageTable* pa
|
||||
// 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -26,27 +29,22 @@ public:
|
||||
|
||||
template <typename T>
|
||||
Common::PhysicalAddress GetPhysicalAddr(const T* ptr) const {
|
||||
return (reinterpret_cast<uintptr_t>(ptr) -
|
||||
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer())) +
|
||||
DramMemoryMap::Base;
|
||||
return (uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer())) + DramMemoryMap::Base;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
PAddr GetRawPhysicalAddr(const T* ptr) const {
|
||||
return static_cast<PAddr>(reinterpret_cast<uintptr_t>(ptr) -
|
||||
reinterpret_cast<uintptr_t>(buffer.BackingBasePointer()));
|
||||
return PAddr(uintptr_t(ptr) - uintptr_t(buffer.BackingBasePointer()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T* GetPointer(Common::PhysicalAddress addr) {
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() +
|
||||
(GetInteger(addr) - DramMemoryMap::Base));
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
const T* GetPointer(Common::PhysicalAddress addr) const {
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() +
|
||||
(GetInteger(addr) - DramMemoryMap::Base));
|
||||
return reinterpret_cast<T*>(buffer.BackingBasePointer() + (GetInteger(addr) - DramMemoryMap::Base));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
||||
@@ -161,7 +161,7 @@ struct DeviceMemoryManagerAllocator {
|
||||
|
||||
template <typename Traits>
|
||||
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
|
||||
: physical_base{reinterpret_cast<const uintptr_t>(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
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Core::Frontend {
|
||||
struct CabinetParameters {
|
||||
Service::NFP::TagInfo tag_info;
|
||||
Service::NFP::RegisterInfo register_info;
|
||||
Service::NFP::CabinetMode mode;
|
||||
Service::NFP::CabinetMode mode{};
|
||||
};
|
||||
|
||||
using CabinetCallback = std::function<void(bool, const std::string&)>;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -20,9 +23,9 @@ struct KeyboardInitializeParameters {
|
||||
std::u16string initial_text;
|
||||
char16_t left_optional_symbol_key;
|
||||
char16_t right_optional_symbol_key;
|
||||
u32 max_text_length;
|
||||
u32 min_text_length;
|
||||
s32 initial_cursor_position;
|
||||
u32 max_text_length{};
|
||||
u32 min_text_length{};
|
||||
s32 initial_cursor_position{};
|
||||
Service::AM::Frontend::SwkbdType type;
|
||||
Service::AM::Frontend::SwkbdPasswordMode password_mode;
|
||||
Service::AM::Frontend::SwkbdTextDrawType text_draw_type;
|
||||
@@ -34,12 +37,12 @@ struct KeyboardInitializeParameters {
|
||||
};
|
||||
|
||||
struct InlineAppearParameters {
|
||||
u32 max_text_length;
|
||||
u32 min_text_length;
|
||||
f32 key_top_scale_x;
|
||||
f32 key_top_scale_y;
|
||||
f32 key_top_translate_x;
|
||||
f32 key_top_translate_y;
|
||||
u32 max_text_length{};
|
||||
u32 min_text_length{};
|
||||
f32 key_top_scale_x{};
|
||||
f32 key_top_scale_y{};
|
||||
f32 key_top_translate_x{};
|
||||
f32 key_top_translate_y{};
|
||||
Service::AM::Frontend::SwkbdType type;
|
||||
Service::AM::Frontend::SwkbdKeyDisableFlags key_disable_flags;
|
||||
bool key_top_as_floating;
|
||||
@@ -50,7 +53,7 @@ struct InlineAppearParameters {
|
||||
|
||||
struct InlineTextParameters {
|
||||
std::u16string input_text;
|
||||
s32 cursor_position;
|
||||
s32 cursor_position{};
|
||||
};
|
||||
|
||||
class SoftwareKeyboardApplet : public Applet {
|
||||
|
||||
@@ -69,7 +69,9 @@ struct KernelCore::Impl {
|
||||
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
|
||||
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
|
||||
|
||||
#ifndef __OPENORBIS__
|
||||
is_phantom_mode_for_singlecore = false;
|
||||
#endif
|
||||
|
||||
// Derive the initial memory layout from the emulated board
|
||||
Init::InitializeSlabResourceCounts(kernel);
|
||||
@@ -356,7 +358,11 @@ struct KernelCore::Impl {
|
||||
application_process->Open();
|
||||
}
|
||||
|
||||
#ifdef __OPENORBIS__
|
||||
static inline u8 host_thread_id = UINT8_MAX;
|
||||
#else
|
||||
static inline thread_local u8 host_thread_id = UINT8_MAX;
|
||||
#endif
|
||||
|
||||
/// Sets the host thread ID for the caller.
|
||||
u32 SetHostThreadId(std::size_t core_id) {
|
||||
@@ -380,8 +386,14 @@ struct KernelCore::Impl {
|
||||
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
|
||||
return thread;
|
||||
}};
|
||||
#ifdef __OPENORBIS__
|
||||
// No proper TLS yet
|
||||
static KThread raw_thread{system.Kernel()};
|
||||
static KThread* thread = existing_thread ? existing_thread : initialize(&raw_thread);
|
||||
#else
|
||||
thread_local KThread raw_thread{system.Kernel()};
|
||||
thread_local KThread* thread = existing_thread ? existing_thread : initialize(&raw_thread);
|
||||
#endif
|
||||
return thread;
|
||||
}
|
||||
|
||||
@@ -407,22 +419,33 @@ struct KernelCore::Impl {
|
||||
return this_id;
|
||||
}
|
||||
|
||||
#ifdef __OPENORBIS__
|
||||
bool IsPhantomModeForSingleCore() const {
|
||||
return true;
|
||||
}
|
||||
void SetIsPhantomModeForSingleCore(bool value) {}
|
||||
#else
|
||||
// Forces singlecore
|
||||
static inline thread_local bool is_phantom_mode_for_singlecore{false};
|
||||
|
||||
bool IsPhantomModeForSingleCore() const {
|
||||
return is_phantom_mode_for_singlecore;
|
||||
}
|
||||
|
||||
void SetIsPhantomModeForSingleCore(bool value) {
|
||||
ASSERT(!is_multicore);
|
||||
is_phantom_mode_for_singlecore = value;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IsShuttingDown() const {
|
||||
return is_shutting_down.load(std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
#ifdef __OPENORBIS__
|
||||
// PS4 doesn't have proper TLS handling
|
||||
static inline KThread* current_thread{nullptr};
|
||||
#else
|
||||
static inline thread_local KThread* current_thread{nullptr};
|
||||
#endif
|
||||
|
||||
KThread* GetCurrentEmuThread() {
|
||||
if (!current_thread) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -79,7 +82,7 @@ using DeviceHandle = u64;
|
||||
|
||||
// This is nn::nfc::TagInfo
|
||||
struct TagInfo {
|
||||
UniqueSerialNumber uuid;
|
||||
UniqueSerialNumber uuid{};
|
||||
u8 uuid_length;
|
||||
INSERT_PADDING_BYTES(0x15);
|
||||
NfcProtocol protocol;
|
||||
|
||||
@@ -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-3.0-or-later
|
||||
|
||||
@@ -315,7 +318,7 @@ static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size");
|
||||
// This is nn::nfp::RegisterInfo
|
||||
struct RegisterInfo {
|
||||
Service::Mii::CharInfo mii_char_info;
|
||||
WriteDate creation_date;
|
||||
WriteDate creation_date{};
|
||||
AmiiboName amiibo_name;
|
||||
u8 font_region;
|
||||
INSERT_PADDING_BYTES(0x7A);
|
||||
|
||||
@@ -164,7 +164,7 @@ IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const ch
|
||||
// Rebuild shared fonts from data ncas or synthesize
|
||||
|
||||
impl->shared_font = std::make_shared<Kernel::PhysicalMemory>(SHARED_FONT_MEM_SIZE);
|
||||
for (auto font : SHARED_FONTS) {
|
||||
for (auto& font : SHARED_FONTS) {
|
||||
FileSys::VirtualFile romfs;
|
||||
const auto nca =
|
||||
nand->GetEntry(static_cast<u64>(font.first), FileSys::ContentRecordType::Data);
|
||||
@@ -261,7 +261,7 @@ Result IPlatformServiceManager::GetSharedFontInOrderOfPriority(
|
||||
out_font_sizes.size(), impl->shared_font_regions.size()});
|
||||
|
||||
for (size_t i = 0; i < max_size; i++) {
|
||||
auto region = impl->GetSharedFontRegion(i);
|
||||
auto& region = impl->GetSharedFontRegion(i);
|
||||
|
||||
out_font_codes[i] = static_cast<u32>(i);
|
||||
out_font_offsets[i] = region.offset;
|
||||
|
||||
@@ -49,7 +49,7 @@ Important API Changes in v6.x Series
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
Design documentation can be found at [./Design.md](./Design.md).
|
||||
Design documentation can be found at [docs/Design.md](docs/Design.md).
|
||||
|
||||
|
||||
Usage Example
|
||||
@@ -343,279 +343,3 @@ SetTerm(IR::Term::If{cond, term_then, term_else})
|
||||
|
||||
This terminal instruction conditionally executes one terminal or another depending
|
||||
on the run-time state of the ARM flags.
|
||||
|
||||
# Register Allocation (x64 Backend)
|
||||
|
||||
`HostLoc`s contain values. A `HostLoc` ("host value location") is either a host CPU register or a host spill location.
|
||||
|
||||
Values once set cannot be changed. Values can however be moved by the register allocator between `HostLoc`s. This is
|
||||
handled by the register allocator itself and code that uses the register allocator need not and should not move values
|
||||
between registers.
|
||||
|
||||
The register allocator is based on three concepts: `Use`, `Def` and `Scratch`.
|
||||
|
||||
* `Use`: The use of a value.
|
||||
* `Define`: The definition of a value, this is the only time when a value is set.
|
||||
* `Scratch`: Allocate a register that can be freely modified as one wishes.
|
||||
|
||||
Note that `Use`ing a value decrements its `use_count` by one. When the `use_count` reaches zero the value is discarded and no longer exists.
|
||||
|
||||
The member functions on `RegAlloc` are just a combination of the above concepts.
|
||||
|
||||
The following registers are reserved for internal use and should NOT participate in register allocation:
|
||||
- `%xmm0`, `%xmm1`, `%xmm2`: Used as scratch in exclusive memory access.
|
||||
- `%rsp`: Stack pointer.
|
||||
- `%r15`: JIT pointer
|
||||
- `%r14`: Page table pointer.
|
||||
- `%r13`: Fastmem pointer.
|
||||
|
||||
The layout convenes `%r15` as the JIT state pointer - while it may be tempting to turn it into a synthetic pointer, keeping an entire register (out of 12 available) is preferable over inlining a directly computed immediate.
|
||||
|
||||
Do NEVER modify `%r15`, we must make it clear that this register is "immutable" for the entirety of the JIT block duration.
|
||||
|
||||
### `Scratch`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr);
|
||||
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm);
|
||||
```
|
||||
|
||||
At runtime, allocate one of the registers in `desired_locations`. You are free to modify the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### Pure `Use`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 UseGpr(Argument& arg);
|
||||
Xbyak::Xmm UseXmm(Argument& arg);
|
||||
OpArg UseOpArg(Argument& arg);
|
||||
void Use(Argument& arg, HostLoc host_loc);
|
||||
```
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseGpr` places it in an unused GPR, `UseXmm` places it
|
||||
in an unused XMM register, `UseOpArg` might be in a register or might be a memory location, and `Use` allows
|
||||
you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
This register **must not** have it's value changed.
|
||||
|
||||
### `UseScratch`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 UseScratchGpr(Argument& arg);
|
||||
Xbyak::Xmm UseScratchXmm(Argument& arg);
|
||||
void UseScratch(Argument& arg, HostLoc host_loc);
|
||||
```
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseScratchGpr` places it in an unused GPR, `UseScratchXmm` places it
|
||||
in an unused XMM register, and `UseScratch` allows you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
The return value is the register allocated to you.
|
||||
|
||||
You are free to modify the value in the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### `Define` as register
|
||||
|
||||
A `Define` is the defintion of a value. This is the only time when a value may be set.
|
||||
|
||||
```c++
|
||||
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
|
||||
```
|
||||
|
||||
By calling `DefineValue`, you are stating that you wish to define the value for `inst`, and you have written the
|
||||
value to the specified register `reg`.
|
||||
|
||||
### `Define`ing as an alias of a different value
|
||||
|
||||
Adding a `Define` to an existing value.
|
||||
|
||||
```c++
|
||||
void DefineValue(IR::Inst* inst, Argument& arg);
|
||||
```
|
||||
|
||||
You are declaring that the value for `inst` is the same as the value for `arg`. No host machine instructions are
|
||||
emitted.
|
||||
|
||||
## When to use each?
|
||||
|
||||
* Prefer `Use` to `UseScratch` where possible.
|
||||
* Prefer the `OpArg` variants where possible.
|
||||
* Prefer to **not** use the specific `HostLoc` variants where possible.
|
||||
|
||||
# Return Stack Buffer Optimization (x64 Backend)
|
||||
|
||||
One of the optimizations that dynarmic does is block-linking. Block-linking is done when
|
||||
the destination address of a jump is available at JIT-time. Instead of returning to the
|
||||
dispatcher at the end of a block we can perform block-linking: just jump directly to the
|
||||
next block. This is beneficial because returning to the dispatcher can often be quite
|
||||
expensive.
|
||||
|
||||
What should we do in cases when we can't predict the destination address? The eponymous
|
||||
example is when executing a return statement at the end of a function; the return address
|
||||
is not statically known at compile time.
|
||||
|
||||
We deal with this by using a return stack buffer: When we execute a call instruction,
|
||||
we push our prediction onto the RSB. When we execute a return instruction, we pop a
|
||||
prediction off the RSB. If the prediction is a hit, we immediately jump to the relevant
|
||||
compiled block. Otherwise, we return to the dispatcher.
|
||||
|
||||
This is the essential idea behind this optimization.
|
||||
|
||||
## `UniqueHash`
|
||||
|
||||
One complication dynarmic has is that a compiled block is not uniquely identifiable by
|
||||
the PC alone, but bits in the FPSCR and CPSR are also relevant. We resolve this by
|
||||
computing a 64-bit `UniqueHash` that is guaranteed to uniquely identify a block.
|
||||
|
||||
```c++
|
||||
u64 LocationDescriptor::UniqueHash() const {
|
||||
// This value MUST BE UNIQUE.
|
||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||
u64 pc_u64 = u64(arm_pc) << 32;
|
||||
u64 fpscr_u64 = u64(fpscr.Value());
|
||||
u64 t_u64 = cpsr.T() ? 1 : 0;
|
||||
u64 e_u64 = cpsr.E() ? 2 : 0;
|
||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||
}
|
||||
```
|
||||
|
||||
## Our implementation isn't actually a stack
|
||||
|
||||
Dynarmic's RSB isn't actually a stack. It was implemented as a ring buffer because
|
||||
that showed better performance in tests.
|
||||
|
||||
### RSB Structure
|
||||
|
||||
The RSB is implemented as a ring buffer. `rsb_ptr` is the index of the insertion
|
||||
point. Each element in `rsb_location_descriptors` is a `UniqueHash` and they
|
||||
each correspond to an element in `rsb_codeptrs`. `rsb_codeptrs` contains the
|
||||
host addresses for the corresponding the compiled blocks.
|
||||
|
||||
`RSBSize` was chosen by performance testing. Note that this is bigger than the
|
||||
size of the real RSB in hardware (which has 3 entries). Larger RSBs than 8
|
||||
showed degraded performance.
|
||||
|
||||
```c++
|
||||
struct JitState {
|
||||
// ...
|
||||
|
||||
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
|
||||
u32 rsb_ptr = 0;
|
||||
std::array<u64, RSBSize> rsb_location_descriptors;
|
||||
std::array<u64, RSBSize> rsb_codeptrs;
|
||||
void ResetRSB();
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### RSB Push
|
||||
|
||||
We insert our prediction at the insertion point iff the RSB doesn't already
|
||||
contain a prediction with the same `UniqueHash`.
|
||||
|
||||
```c++
|
||||
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
ASSERT(inst->GetArg(0).IsImmediate());
|
||||
u64 imm64 = inst->GetArg(0).GetU64();
|
||||
|
||||
Xbyak::Reg64 code_ptr_reg = reg_alloc.ScratchGpr(code, {HostLoc::RCX});
|
||||
Xbyak::Reg64 loc_desc_reg = reg_alloc.ScratchGpr(code);
|
||||
Xbyak::Reg32 index_reg = reg_alloc.ScratchGpr(code).cvt32();
|
||||
u64 code_ptr = unique_hash_to_code_ptr.find(imm64) != unique_hash_to_code_ptr.end()
|
||||
? u64(unique_hash_to_code_ptr[imm64])
|
||||
: u64(code->GetReturnFromRunCodeAddress());
|
||||
|
||||
code->mov(index_reg, dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)]);
|
||||
code->add(index_reg, 1);
|
||||
code->and_(index_reg, u32(JitState::RSBSize - 1));
|
||||
|
||||
code->mov(loc_desc_reg, u64(imm64));
|
||||
CodePtr patch_location = code->getCurr<CodePtr>();
|
||||
patch_unique_hash_locations[imm64].emplace_back(patch_location);
|
||||
code->mov(code_ptr_reg, u64(code_ptr)); // This line has to match up with EmitX64::Patch.
|
||||
code->EnsurePatchLocationSize(patch_location, 10);
|
||||
|
||||
Xbyak::Label label;
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(loc_desc_reg, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->je(label, code->T_SHORT);
|
||||
}
|
||||
|
||||
code->mov(dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)], index_reg);
|
||||
code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_location_descriptors)], loc_desc_reg);
|
||||
code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_codeptrs)], code_ptr_reg);
|
||||
code->L(label);
|
||||
}
|
||||
```
|
||||
|
||||
In pseudocode:
|
||||
|
||||
```c++
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rsb_location_descriptors[i] == imm64)
|
||||
goto label;
|
||||
rsb_ptr++;
|
||||
rsb_ptr %= RSBSize;
|
||||
rsb_location_desciptors[rsb_ptr] = imm64; //< The UniqueHash
|
||||
rsb_codeptr[rsb_ptr] = /* codeptr corresponding to the UniqueHash */;
|
||||
label:
|
||||
```
|
||||
|
||||
## RSB Pop
|
||||
|
||||
To check if a predicition is in the RSB, we linearly scan the RSB.
|
||||
|
||||
```c++
|
||||
void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescriptor initial_location) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
// This calculation has to match up with IREmitter::PushRSB
|
||||
code->mov(ecx, MJitStateReg(Arm::Reg::PC));
|
||||
code->shl(rcx, 32);
|
||||
code->mov(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, FPSCR_mode)]);
|
||||
code->or_(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, CPSR_et)]);
|
||||
code->or_(rbx, rcx);
|
||||
|
||||
code->mov(rax, u64(code->GetReturnFromRunCodeAddress()));
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->cmove(rax, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]);
|
||||
}
|
||||
|
||||
code->jmp(rax);
|
||||
}
|
||||
```
|
||||
|
||||
In pseudocode:
|
||||
|
||||
```c++
|
||||
rbx := ComputeUniqueHash()
|
||||
rax := ReturnToDispatch
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rbx == rsb_location_descriptors[i])
|
||||
rax = rsb_codeptrs[i]
|
||||
goto rax
|
||||
```
|
||||
|
||||
# Fast memory (Fastmem)
|
||||
|
||||
The main way of accessing memory in JITed programs is via an invoked function, say "Read()" and "Write()". On our translator, such functions usually take a sizable amounts of code space (push + call + pop). Trash the i-cache (due to an indirect call) and overall make code emission more bloated.
|
||||
|
||||
The solution? Delegate invalid accesses to a dedicated arena, similar to a swap. The main idea behind such mechanism is to allow the OS to transmit page faults from invalid accesses into the JIT translator directly, bypassing address space calls, while this sacrifices i-cache coherency, it allows for smaller code-size and "faster" throguhput.
|
||||
|
||||
Many kernels however, do not support fast signal dispatching (Solaris, OpenBSD, FreeBSD). Only Linux and Windows support relatively "fast" signal dispatching. Hence this feature is better suited for them only.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
In x86_64 for example, when a page fault occurs, the CPU will transmit via control registers and the stack (see `IRETQ`) the appropriate arguments for a page fault handler, the OS then will transform that into something that can be sent into userspace.
|
||||
|
||||
Most modern OSes implement kernel-page-table-isolation, which means a set of system calls will invoke a context switch (not often used syscalls), whereas others are handled by the same process address space (the smaller kernel portion, often used syscalls) without needing a context switch. This effect can be negated on systems with PCID (up to 4096 unique IDs).
|
||||
|
||||
Signal dispatching takes a performance hit from reloading `%cr3` - but Linux does something more clever to avoid reloads: VDSO will take care of the entire thing in the same address space. Making dispatching as costly as an indirect call - without the hazards of increased code size.
|
||||
|
||||
The main downside from this is the constant i-cache trashing and pipeline hazards introduced by the VDSO signal handlers. However on most benchmarks fastmem does perform faster than without (Linux only). This also abuses the fact of continous address space emulation by using an arena - which can then be potentially transparently mapped into a hugepage, reducing TLB walk times.
|
||||
2474
src/dynarmic/docs/Doxyfile
Normal file
2474
src/dynarmic/docs/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
19
src/dynarmic/docs/FastMemory.md
Normal file
19
src/dynarmic/docs/FastMemory.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Fast memory (Fastmem)
|
||||
|
||||
The main way of accessing memory in JITed programs is via an invoked function, say "Read()" and "Write()". On our translator, such functions usually take a sizable amounts of code space (push + call + pop). Trash the i-cache (due to an indirect call) and overall make code emission more bloated.
|
||||
|
||||
The solution? Delegate invalid accesses to a dedicated arena, similar to a swap. The main idea behind such mechanism is to allow the OS to transmit page faults from invalid accesses into the JIT translator directly, bypassing address space calls, while this sacrifices i-cache coherency, it allows for smaller code-size and "faster" throguhput.
|
||||
|
||||
Many kernels however, do not support fast signal dispatching (Solaris, OpenBSD, FreeBSD). Only Linux and Windows support relatively "fast" signal dispatching. Hence this feature is better suited for them only.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
In x86_64 for example, when a page fault occurs, the CPU will transmit via control registers and the stack (see `IRETQ`) the appropriate arguments for a page fault handler, the OS then will transform that into something that can be sent into userspace.
|
||||
|
||||
Most modern OSes implement kernel-page-table-isolation, which means a set of system calls will invoke a context switch (not often used syscalls), whereas others are handled by the same process address space (the smaller kernel portion, often used syscalls) without needing a context switch. This effect can be negated on systems with PCID (up to 4096 unique IDs).
|
||||
|
||||
Signal dispatching takes a performance hit from reloading `%cr3` - but Linux does something more clever to avoid reloads: VDSO will take care of the entire thing in the same address space. Making dispatching as costly as an indirect call - without the hazards of increased code size.
|
||||
|
||||
The main downside from this is the constant i-cache trashing and pipeline hazards introduced by the VDSO signal handlers. However on most benchmarks fastmem does perform faster than without (Linux only). This also abuses the fact of continous address space emulation by using an arena - which can then be potentially transparently mapped into a hugepage, reducing TLB walk times.
|
||||
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
|
Before Width: | Height: | Size: 98 KiB After Width: | Height: | Size: 98 KiB |
97
src/dynarmic/docs/RegisterAllocator.md
Normal file
97
src/dynarmic/docs/RegisterAllocator.md
Normal file
@@ -0,0 +1,97 @@
|
||||
# Register Allocation (x64 Backend)
|
||||
|
||||
`HostLoc`s contain values. A `HostLoc` ("host value location") is either a host CPU register or a host spill location.
|
||||
|
||||
Values once set cannot be changed. Values can however be moved by the register allocator between `HostLoc`s. This is
|
||||
handled by the register allocator itself and code that uses the register allocator need not and should not move values
|
||||
between registers.
|
||||
|
||||
The register allocator is based on three concepts: `Use`, `Def` and `Scratch`.
|
||||
|
||||
* `Use`: The use of a value.
|
||||
* `Define`: The definition of a value, this is the only time when a value is set.
|
||||
* `Scratch`: Allocate a register that can be freely modified as one wishes.
|
||||
|
||||
Note that `Use`ing a value decrements its `use_count` by one. When the `use_count` reaches zero the value is discarded and no longer exists.
|
||||
|
||||
The member functions on `RegAlloc` are just a combination of the above concepts.
|
||||
|
||||
The following registers are reserved for internal use and should NOT participate in register allocation:
|
||||
- `%xmm0`, `%xmm1`, `%xmm2`: Used as scratch in exclusive memory access.
|
||||
- `%rsp`: Stack pointer.
|
||||
- `%r15`: JIT pointer
|
||||
- `%r14`: Page table pointer.
|
||||
- `%r13`: Fastmem pointer.
|
||||
|
||||
The layout convenes `%r15` as the JIT state pointer - while it may be tempting to turn it into a synthetic pointer, keeping an entire register (out of 12 available) is preferable over inlining a directly computed immediate.
|
||||
|
||||
Do NEVER modify `%r15`, we must make it clear that this register is "immutable" for the entirety of the JIT block duration.
|
||||
|
||||
### `Scratch`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 ScratchGpr(HostLocList desired_locations = any_gpr);
|
||||
Xbyak::Xmm ScratchXmm(HostLocList desired_locations = any_xmm);
|
||||
```
|
||||
|
||||
At runtime, allocate one of the registers in `desired_locations`. You are free to modify the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### Pure `Use`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 UseGpr(Argument& arg);
|
||||
Xbyak::Xmm UseXmm(Argument& arg);
|
||||
OpArg UseOpArg(Argument& arg);
|
||||
void Use(Argument& arg, HostLoc host_loc);
|
||||
```
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseGpr` places it in an unused GPR, `UseXmm` places it
|
||||
in an unused XMM register, `UseOpArg` might be in a register or might be a memory location, and `Use` allows
|
||||
you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
This register **must not** have it's value changed.
|
||||
|
||||
### `UseScratch`
|
||||
|
||||
```c++
|
||||
Xbyak::Reg64 UseScratchGpr(Argument& arg);
|
||||
Xbyak::Xmm UseScratchXmm(Argument& arg);
|
||||
void UseScratch(Argument& arg, HostLoc host_loc);
|
||||
```
|
||||
|
||||
At runtime, the value corresponding to `arg` will be placed a register. The actual register is determined by
|
||||
which one of the above functions is called. `UseScratchGpr` places it in an unused GPR, `UseScratchXmm` places it
|
||||
in an unused XMM register, and `UseScratch` allows you to specify a specific register (GPR or XMM) to use.
|
||||
|
||||
The return value is the register allocated to you.
|
||||
|
||||
You are free to modify the value in the register. The register is discarded at the end of the allocation scope.
|
||||
|
||||
### `Define` as register
|
||||
|
||||
A `Define` is the defintion of a value. This is the only time when a value may be set.
|
||||
|
||||
```c++
|
||||
void DefineValue(IR::Inst* inst, const Xbyak::Reg& reg);
|
||||
```
|
||||
|
||||
By calling `DefineValue`, you are stating that you wish to define the value for `inst`, and you have written the
|
||||
value to the specified register `reg`.
|
||||
|
||||
### `Define`ing as an alias of a different value
|
||||
|
||||
Adding a `Define` to an existing value.
|
||||
|
||||
```c++
|
||||
void DefineValue(IR::Inst* inst, Argument& arg);
|
||||
```
|
||||
|
||||
You are declaring that the value for `inst` is the same as the value for `arg`. No host machine instructions are
|
||||
emitted.
|
||||
|
||||
## When to use each?
|
||||
|
||||
* Prefer `Use` to `UseScratch` where possible.
|
||||
* Prefer the `OpArg` variants where possible.
|
||||
* Prefer to **not** use the specific `HostLoc` variants where possible.
|
||||
157
src/dynarmic/docs/ReturnStackBufferOptimization.md
Normal file
157
src/dynarmic/docs/ReturnStackBufferOptimization.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# Return Stack Buffer Optimization (x64 Backend)
|
||||
|
||||
One of the optimizations that dynarmic does is block-linking. Block-linking is done when
|
||||
the destination address of a jump is available at JIT-time. Instead of returning to the
|
||||
dispatcher at the end of a block we can perform block-linking: just jump directly to the
|
||||
next block. This is beneficial because returning to the dispatcher can often be quite
|
||||
expensive.
|
||||
|
||||
What should we do in cases when we can't predict the destination address? The eponymous
|
||||
example is when executing a return statement at the end of a function; the return address
|
||||
is not statically known at compile time.
|
||||
|
||||
We deal with this by using a return stack buffer: When we execute a call instruction,
|
||||
we push our prediction onto the RSB. When we execute a return instruction, we pop a
|
||||
prediction off the RSB. If the prediction is a hit, we immediately jump to the relevant
|
||||
compiled block. Otherwise, we return to the dispatcher.
|
||||
|
||||
This is the essential idea behind this optimization.
|
||||
|
||||
## `UniqueHash`
|
||||
|
||||
One complication dynarmic has is that a compiled block is not uniquely identifiable by
|
||||
the PC alone, but bits in the FPSCR and CPSR are also relevant. We resolve this by
|
||||
computing a 64-bit `UniqueHash` that is guaranteed to uniquely identify a block.
|
||||
|
||||
```c++
|
||||
u64 LocationDescriptor::UniqueHash() const {
|
||||
// This value MUST BE UNIQUE.
|
||||
// This calculation has to match up with EmitX64::EmitTerminalPopRSBHint
|
||||
u64 pc_u64 = u64(arm_pc) << 32;
|
||||
u64 fpscr_u64 = u64(fpscr.Value());
|
||||
u64 t_u64 = cpsr.T() ? 1 : 0;
|
||||
u64 e_u64 = cpsr.E() ? 2 : 0;
|
||||
return pc_u64 | fpscr_u64 | t_u64 | e_u64;
|
||||
}
|
||||
```
|
||||
|
||||
## Our implementation isn't actually a stack
|
||||
|
||||
Dynarmic's RSB isn't actually a stack. It was implemented as a ring buffer because
|
||||
that showed better performance in tests.
|
||||
|
||||
### RSB Structure
|
||||
|
||||
The RSB is implemented as a ring buffer. `rsb_ptr` is the index of the insertion
|
||||
point. Each element in `rsb_location_descriptors` is a `UniqueHash` and they
|
||||
each correspond to an element in `rsb_codeptrs`. `rsb_codeptrs` contains the
|
||||
host addresses for the corresponding the compiled blocks.
|
||||
|
||||
`RSBSize` was chosen by performance testing. Note that this is bigger than the
|
||||
size of the real RSB in hardware (which has 3 entries). Larger RSBs than 8
|
||||
showed degraded performance.
|
||||
|
||||
```c++
|
||||
struct JitState {
|
||||
// ...
|
||||
|
||||
static constexpr size_t RSBSize = 8; // MUST be a power of 2.
|
||||
u32 rsb_ptr = 0;
|
||||
std::array<u64, RSBSize> rsb_location_descriptors;
|
||||
std::array<u64, RSBSize> rsb_codeptrs;
|
||||
void ResetRSB();
|
||||
|
||||
// ...
|
||||
};
|
||||
```
|
||||
|
||||
### RSB Push
|
||||
|
||||
We insert our prediction at the insertion point iff the RSB doesn't already
|
||||
contain a prediction with the same `UniqueHash`.
|
||||
|
||||
```c++
|
||||
void EmitX64::EmitPushRSB(IR::Block&, IR::Inst* inst) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
ASSERT(inst->GetArg(0).IsImmediate());
|
||||
u64 imm64 = inst->GetArg(0).GetU64();
|
||||
|
||||
Xbyak::Reg64 code_ptr_reg = reg_alloc.ScratchGpr(code, {HostLoc::RCX});
|
||||
Xbyak::Reg64 loc_desc_reg = reg_alloc.ScratchGpr(code);
|
||||
Xbyak::Reg32 index_reg = reg_alloc.ScratchGpr(code).cvt32();
|
||||
u64 code_ptr = unique_hash_to_code_ptr.find(imm64) != unique_hash_to_code_ptr.end()
|
||||
? u64(unique_hash_to_code_ptr[imm64])
|
||||
: u64(code->GetReturnFromRunCodeAddress());
|
||||
|
||||
code->mov(index_reg, dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)]);
|
||||
code->add(index_reg, 1);
|
||||
code->and_(index_reg, u32(JitState::RSBSize - 1));
|
||||
|
||||
code->mov(loc_desc_reg, u64(imm64));
|
||||
CodePtr patch_location = code->getCurr<CodePtr>();
|
||||
patch_unique_hash_locations[imm64].emplace_back(patch_location);
|
||||
code->mov(code_ptr_reg, u64(code_ptr)); // This line has to match up with EmitX64::Patch.
|
||||
code->EnsurePatchLocationSize(patch_location, 10);
|
||||
|
||||
Xbyak::Label label;
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(loc_desc_reg, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->je(label, code->T_SHORT);
|
||||
}
|
||||
|
||||
code->mov(dword[code.ABI_JIT_PTR + offsetof(JitState, rsb_ptr)], index_reg);
|
||||
code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_location_descriptors)], loc_desc_reg);
|
||||
code->mov(qword[code.ABI_JIT_PTR + index_reg.cvt64() * 8 + offsetof(JitState, rsb_codeptrs)], code_ptr_reg);
|
||||
code->L(label);
|
||||
}
|
||||
```
|
||||
|
||||
In pseudocode:
|
||||
|
||||
```c++
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rsb_location_descriptors[i] == imm64)
|
||||
goto label;
|
||||
rsb_ptr++;
|
||||
rsb_ptr %= RSBSize;
|
||||
rsb_location_desciptors[rsb_ptr] = imm64; //< The UniqueHash
|
||||
rsb_codeptr[rsb_ptr] = /* codeptr corresponding to the UniqueHash */;
|
||||
label:
|
||||
```
|
||||
|
||||
## RSB Pop
|
||||
|
||||
To check if a predicition is in the RSB, we linearly scan the RSB.
|
||||
|
||||
```c++
|
||||
void EmitX64::EmitTerminalPopRSBHint(IR::Term::PopRSBHint, IR::LocationDescriptor initial_location) {
|
||||
using namespace Xbyak::util;
|
||||
|
||||
// This calculation has to match up with IREmitter::PushRSB
|
||||
code->mov(ecx, MJitStateReg(Arm::Reg::PC));
|
||||
code->shl(rcx, 32);
|
||||
code->mov(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, FPSCR_mode)]);
|
||||
code->or_(ebx, dword[code.ABI_JIT_PTR + offsetof(JitState, CPSR_et)]);
|
||||
code->or_(rbx, rcx);
|
||||
|
||||
code->mov(rax, u64(code->GetReturnFromRunCodeAddress()));
|
||||
for (size_t i = 0; i < JitState::RSBSize; ++i) {
|
||||
code->cmp(rbx, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_location_descriptors) + i * sizeof(u64)]);
|
||||
code->cmove(rax, qword[code.ABI_JIT_PTR + offsetof(JitState, rsb_codeptrs) + i * sizeof(u64)]);
|
||||
}
|
||||
|
||||
code->jmp(rax);
|
||||
}
|
||||
```
|
||||
|
||||
In pseudocode:
|
||||
|
||||
```c++
|
||||
rbx := ComputeUniqueHash()
|
||||
rax := ReturnToDispatch
|
||||
for (i := 0 .. RSBSize-1)
|
||||
if (rbx == rsb_location_descriptors[i])
|
||||
rax = rsb_codeptrs[i]
|
||||
goto rax
|
||||
```
|
||||
@@ -59,12 +59,16 @@ public:
|
||||
signal_stack_size = std::max<size_t>(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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -48,7 +48,7 @@ private:
|
||||
void Save();
|
||||
|
||||
PlayTimeDatabase database;
|
||||
u64 running_program_id;
|
||||
u64 running_program_id{};
|
||||
std::jthread play_time_thread;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,7 +75,8 @@ if (ENABLE_SDL2)
|
||||
helpers/joycon_protocol/rumble.cpp
|
||||
helpers/joycon_protocol/rumble.h
|
||||
)
|
||||
target_link_libraries(input_common PRIVATE SDL2::SDL2)
|
||||
target_include_directories(input_common PRIVATE ${CMAKE_SYSROOT}/include/SDL2)
|
||||
target_link_libraries(input_common PRIVATE SDL2)
|
||||
target_compile_definitions(input_common PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +9,14 @@
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <thread>
|
||||
#include <SDL_hidapi.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#if SDL_VERSION_ATLEAST(2, 26, 4)
|
||||
# include <SDL_hidapi.h>
|
||||
#else
|
||||
struct SDL_hid_device;
|
||||
struct SDL_hid_device_info;
|
||||
#endif
|
||||
|
||||
#include "input_common/input_engine.h"
|
||||
|
||||
|
||||
@@ -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");
|
||||
@@ -531,6 +535,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;
|
||||
@@ -835,6 +840,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;
|
||||
@@ -843,6 +849,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},
|
||||
@@ -864,7 +871,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
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -38,8 +41,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 +51,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 +144,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<u8> buffer(MaxBufferSize);
|
||||
|
||||
while (!stop_token.stop_requested()) {
|
||||
@@ -150,14 +154,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 +697,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<std::pair<u32, ControllerType>, 6> supported_devices{
|
||||
std::pair<u32, ControllerType>{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<u16>(product_id)) {
|
||||
@@ -710,16 +716,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -15,11 +18,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 +42,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 +67,21 @@ Common::Input::DriverResult JoyconCommonProtocol::SetReportMode(ReportMode repor
|
||||
}
|
||||
|
||||
Common::Input::DriverResult JoyconCommonProtocol::SendRawData(std::span<const u8> 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<u8*>(&output),
|
||||
sizeof(SubCommandResponse), timeout_mili);
|
||||
@@ -88,9 +92,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 +221,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<u8*>(&output),
|
||||
sizeof(MCUCommandResponse), TimeoutMili);
|
||||
@@ -234,9 +236,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +13,14 @@
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <SDL_hidapi.h>
|
||||
|
||||
#include <SDL.h>
|
||||
#if SDL_VERSION_ATLEAST(2, 26, 4)
|
||||
# include <SDL_hidapi.h>
|
||||
#else
|
||||
struct SDL_hid_device;
|
||||
struct SDL_hid_device_info;
|
||||
#endif
|
||||
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.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
|
||||
|
||||
|
||||
@@ -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> mouse;
|
||||
std::shared_ptr<TouchScreen> touch_screen;
|
||||
std::shared_ptr<TasInput::Tas> tas_input;
|
||||
#ifndef __OPENORBIS__
|
||||
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
|
||||
#endif
|
||||
std::shared_ptr<Camera> camera;
|
||||
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
|
||||
std::shared_ptr<VirtualGamepad> 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) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -53,7 +56,7 @@ struct ChatEntry {
|
||||
|
||||
/// Represents a system status message.
|
||||
struct StatusMessageEntry {
|
||||
StatusMessageTypes type; ///< Type of the message
|
||||
StatusMessageTypes type{}; ///< Type of the message
|
||||
/// Subject of the message. i.e. the user who is joining/leaving/being banned, etc.
|
||||
std::string nickname;
|
||||
std::string username;
|
||||
|
||||
@@ -159,7 +159,13 @@ struct Values {
|
||||
Setting<bool> enable_discord_presence{linkage, false, "enable_discord_presence", Category::Ui};
|
||||
|
||||
// logging
|
||||
Setting<bool> show_console{linkage, false, "showConsole", Category::Ui};
|
||||
Setting<bool> show_console{linkage,
|
||||
#ifdef __OPENORBIS__
|
||||
true,
|
||||
#else
|
||||
false,
|
||||
#endif
|
||||
"showConsole", Category::Ui};
|
||||
|
||||
// Screenshots
|
||||
Setting<bool> enable_screenshot_save_as{linkage, true, "enable_screenshot_save_as",
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
|
||||
@@ -16,8 +15,6 @@
|
||||
#include "video_core/guest_memory.h"
|
||||
#include "video_core/host1x/gpu_device_memory_manager.h"
|
||||
#include "video_core/texture_cache/util.h"
|
||||
#include "video_core/polygon_mode_utils.h"
|
||||
#include "video_core/renderer_vulkan/line_loop_utils.h"
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
@@ -356,37 +353,14 @@ void BufferCache<P>::UpdateComputeBuffers() {
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
if (is_indexed) {
|
||||
BindHostIndexBuffer();
|
||||
} else {
|
||||
if constexpr (!P::IS_OPENGL) {
|
||||
const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
|
||||
if (draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
|
||||
polygon_mode == Maxwell::PolygonMode::Line && draw_state.vertex_buffer.count > 1) {
|
||||
const u32 vertex_count = draw_state.vertex_buffer.count;
|
||||
const u32 generated_count = vertex_count + 1;
|
||||
const bool use_u16 = vertex_count <= 0x10000;
|
||||
const u32 element_size = use_u16 ? sizeof(u16) : sizeof(u32);
|
||||
auto staging = runtime.UploadStagingBuffer(
|
||||
static_cast<size_t>(generated_count) * element_size);
|
||||
std::span<u8> dst_span{staging.mapped_span.data(),
|
||||
generated_count * static_cast<size_t>(element_size)};
|
||||
Vulkan::LineLoop::GenerateSequentialWithClosureRaw(dst_span, element_size);
|
||||
const auto synthetic_format = use_u16 ? Maxwell::IndexFormat::UnsignedShort
|
||||
: Maxwell::IndexFormat::UnsignedInt;
|
||||
runtime.BindIndexBuffer(draw_state.topology, synthetic_format,
|
||||
draw_state.vertex_buffer.first, generated_count,
|
||||
staging.buffer, static_cast<u32>(staging.offset),
|
||||
generated_count * element_size);
|
||||
}
|
||||
}
|
||||
if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
|
||||
draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
|
||||
runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first,
|
||||
draw_state.vertex_buffer.count);
|
||||
}
|
||||
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
if (draw_state.topology == Maxwell::PrimitiveTopology::Quads ||
|
||||
draw_state.topology == Maxwell::PrimitiveTopology::QuadStrip) {
|
||||
runtime.BindQuadIndexBuffer(draw_state.topology, draw_state.vertex_buffer.first,
|
||||
draw_state.vertex_buffer.count);
|
||||
}
|
||||
}
|
||||
BindHostVertexBuffers();
|
||||
@@ -715,44 +689,6 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||
const u32 offset = buffer.Offset(channel_state->index_buffer.device_addr);
|
||||
const u32 size = channel_state->index_buffer.size;
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
if constexpr (!P::IS_OPENGL) {
|
||||
const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
|
||||
const bool polygon_line =
|
||||
draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
|
||||
polygon_mode == Maxwell::PolygonMode::Line;
|
||||
if (polygon_line && draw_state.index_buffer.count > 1) {
|
||||
const u32 element_size = draw_state.index_buffer.FormatSizeInBytes();
|
||||
const size_t src_bytes = static_cast<size_t>(draw_state.index_buffer.count) * element_size;
|
||||
const size_t total_bytes = src_bytes + element_size;
|
||||
auto staging = runtime.UploadStagingBuffer(total_bytes);
|
||||
std::span<u8> dst_span{staging.mapped_span.data(), total_bytes};
|
||||
std::span<const u8> src_span;
|
||||
if (!draw_state.inline_index_draw_indexes.empty()) {
|
||||
const u8* const src =
|
||||
draw_state.inline_index_draw_indexes.data() +
|
||||
static_cast<size_t>(draw_state.index_buffer.first) * element_size;
|
||||
src_span = {src, src_bytes};
|
||||
} else if (const u8* const cpu_base =
|
||||
device_memory.GetPointer<u8>(channel_state->index_buffer.device_addr)) {
|
||||
const u8* const src = cpu_base +
|
||||
static_cast<size_t>(draw_state.index_buffer.first) * element_size;
|
||||
src_span = {src, src_bytes};
|
||||
} else {
|
||||
const DAddr src_addr =
|
||||
channel_state->index_buffer.device_addr +
|
||||
static_cast<DAddr>(draw_state.index_buffer.first) * element_size;
|
||||
device_memory.ReadBlockUnsafe(src_addr, dst_span.data(), src_bytes);
|
||||
src_span = {dst_span.data(), src_bytes};
|
||||
}
|
||||
Vulkan::LineLoop::CopyWithClosureRaw(dst_span, src_span, element_size);
|
||||
buffer.MarkUsage(offset, size);
|
||||
runtime.BindIndexBuffer(draw_state.topology, draw_state.index_buffer.format,
|
||||
draw_state.index_buffer.first, draw_state.index_buffer.count + 1,
|
||||
staging.buffer, static_cast<u32>(staging.offset),
|
||||
static_cast<u32>(total_bytes));
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!draw_state.inline_index_draw_indexes.empty()) [[unlikely]] {
|
||||
if constexpr (USE_MEMORY_MAPS_FOR_UPLOADS) {
|
||||
auto upload_staging = runtime.UploadStagingBuffer(size);
|
||||
@@ -1769,21 +1705,26 @@ Binding BufferCache<P>::StorageBufferBinding(GPUVAddr ssbo_addr, u32 cbuf_index,
|
||||
return NULL_BINDING;
|
||||
}
|
||||
|
||||
// xbzk: New size logic. Fixes MCI.
|
||||
// If ever the * comment below prove wrong, the 'if' block may be removed.
|
||||
const auto size = [&]() {
|
||||
const bool is_nvn_cbuf = cbuf_index == 0;
|
||||
// The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size.
|
||||
if (is_nvn_cbuf) {
|
||||
const u32 ssbo_size = gpu_memory->Read<u32>(ssbo_addr + 8);
|
||||
if (ssbo_size != 0) {
|
||||
return ssbo_size;
|
||||
// * The NVN driver buffer (index 0) is known to pack the SSBO address followed by its size.
|
||||
const u64 next_qword = gpu_memory->Read<u64>(ssbo_addr + 8);
|
||||
const u32 upper_32 = static_cast<u32>(next_qword >> 32);
|
||||
// Hardware-based detection: GPU addresses have non-zero upper bits
|
||||
if (upper_32 == 0) {
|
||||
// This is a size field, not a GPU address
|
||||
return static_cast<u32>(next_qword); // Return lower_32
|
||||
}
|
||||
}
|
||||
// Other titles (notably Doom Eternal) may use STG/LDG on buffer addresses in custom defined
|
||||
// cbufs, which do not store the sizes adjacent to the addresses, so use the fully
|
||||
// mapped buffer size for now.
|
||||
// Fall through: either not NVN cbuf (Doom Eternal & +), or NVN but ssbo_addr+8 is a GPU address (MCI)
|
||||
const u32 memory_layout_size = static_cast<u32>(gpu_memory->GetMemoryLayoutSize(gpu_addr));
|
||||
// Cap at 8MB to prevent allocator overflow from misinterpreted addresses
|
||||
return (std::min)(memory_layout_size, static_cast<u32>(8_MiB));
|
||||
}();
|
||||
|
||||
// Alignment only applies to the offset of the buffer
|
||||
const u32 alignment = runtime.GetStorageBufferAlignment();
|
||||
const GPUVAddr aligned_gpu_addr = Common::AlignDown(gpu_addr, alignment);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -17,7 +20,7 @@ void Scheduler::Push(s32 channel, CommandList&& entries) {
|
||||
std::unique_lock lk(scheduling_guard);
|
||||
auto it = channels.find(channel);
|
||||
ASSERT(it != channels.end());
|
||||
auto channel_state = it->second;
|
||||
auto& channel_state = it->second;
|
||||
gpu.BindChannel(channel_state->bind_id);
|
||||
channel_state->dma_pusher->Push(std::move(entries));
|
||||
channel_state->dma_pusher->DispatchCalls();
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
inline Tegra::Engines::Maxwell3D::Regs::PolygonMode EffectivePolygonMode(
|
||||
const Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
const bool cull_enabled = regs.gl_cull_test_enabled != 0;
|
||||
const auto cull_face = regs.gl_cull_face;
|
||||
const bool cull_front = cull_enabled && (cull_face == Maxwell::CullFace::Front ||
|
||||
cull_face == Maxwell::CullFace::FrontAndBack);
|
||||
const bool cull_back = cull_enabled && (cull_face == Maxwell::CullFace::Back ||
|
||||
cull_face == Maxwell::CullFace::FrontAndBack);
|
||||
|
||||
const bool render_front = !cull_front;
|
||||
const bool render_back = !cull_back;
|
||||
|
||||
const auto front_mode = regs.polygon_mode_front;
|
||||
const auto back_mode = regs.polygon_mode_back;
|
||||
|
||||
if (render_front && render_back && front_mode != back_mode) {
|
||||
if (front_mode == Maxwell::PolygonMode::Line || back_mode == Maxwell::PolygonMode::Line) {
|
||||
return Maxwell::PolygonMode::Line;
|
||||
}
|
||||
if (front_mode == Maxwell::PolygonMode::Point || back_mode == Maxwell::PolygonMode::Point) {
|
||||
return Maxwell::PolygonMode::Point;
|
||||
}
|
||||
}
|
||||
|
||||
if (render_front) {
|
||||
return front_mode;
|
||||
}
|
||||
if (render_back) {
|
||||
return back_mode;
|
||||
}
|
||||
return front_mode;
|
||||
}
|
||||
|
||||
} // namespace VideoCore
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "video_core/engines/draw_manager.h"
|
||||
#include "video_core/renderer_vulkan/fixed_pipeline_state.h"
|
||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||
#include "video_core/polygon_mode_utils.h"
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
@@ -66,7 +65,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
|
||||
xfb_enabled.Assign(regs.transform_feedback_enabled != 0);
|
||||
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
|
||||
polygon_mode.Assign(PackPolygonMode(VideoCore::EffectivePolygonMode(regs)));
|
||||
polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front));
|
||||
tessellation_primitive.Assign(static_cast<u32>(regs.tessellation.params.domain_type.Value()));
|
||||
tessellation_spacing.Assign(static_cast<u32>(regs.tessellation.params.spacing.Value()));
|
||||
tessellation_clockwise.Assign(regs.tessellation.params.output_primitives.Value() ==
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <span>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Vulkan::LineLoop {
|
||||
|
||||
inline void CopyWithClosureRaw(std::span<u8> dst, std::span<const u8> src, size_t element_size) {
|
||||
ASSERT_MSG(dst.size() == src.size() + element_size, "Invalid line loop copy sizes");
|
||||
if (src.empty()) {
|
||||
if (!dst.empty()) {
|
||||
std::fill(dst.begin(), dst.end(), u8{0});
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::memcpy(dst.data(), src.data(), src.size());
|
||||
std::memcpy(dst.data() + src.size(), src.data(), element_size);
|
||||
}
|
||||
|
||||
inline void GenerateSequentialWithClosureRaw(std::span<u8> dst, size_t element_size,
|
||||
u64 start_value = 0) {
|
||||
if (dst.empty()) {
|
||||
return;
|
||||
}
|
||||
const size_t last = dst.size() - element_size;
|
||||
size_t offset = 0;
|
||||
u64 value = start_value;
|
||||
while (offset < last) {
|
||||
std::memcpy(dst.data() + offset, &value, element_size);
|
||||
offset += element_size;
|
||||
++value;
|
||||
}
|
||||
std::memcpy(dst.data() + offset, &start_value, element_size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void CopyWithClosure(std::span<T> dst, std::span<const T> src) {
|
||||
ASSERT_MSG(dst.size() == src.size() + 1, "Invalid destination size for line loop copy");
|
||||
if (src.empty()) {
|
||||
if (!dst.empty()) {
|
||||
dst.front() = {};
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::copy(src.begin(), src.end(), dst.begin());
|
||||
dst.back() = src.front();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void GenerateSequentialWithClosure(std::span<T> dst, T start_value = {}) {
|
||||
if (dst.empty()) {
|
||||
return;
|
||||
}
|
||||
const size_t last = dst.size() - 1;
|
||||
for (size_t i = 0; i < last; ++i) {
|
||||
dst[i] = static_cast<T>(start_value + static_cast<T>(i));
|
||||
}
|
||||
dst.back() = start_value;
|
||||
}
|
||||
|
||||
} // namespace Vulkan::LineLoop
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -326,9 +323,44 @@ VkShaderStageFlagBits ShaderStage(Shader::Stage stage) {
|
||||
}
|
||||
|
||||
VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const Device& device,
|
||||
Maxwell::PrimitiveTopology topology,
|
||||
Maxwell::PolygonMode polygon_mode) {
|
||||
return detail::PrimitiveTopologyNoDevice(topology, polygon_mode);
|
||||
Maxwell::PrimitiveTopology topology) {
|
||||
switch (topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
case Maxwell::PrimitiveTopology::Lines:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
case Maxwell::PrimitiveTopology::LineLoop:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::Triangles:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
case Maxwell::PrimitiveTopology::LinesAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::LineStripAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
case Maxwell::PrimitiveTopology::QuadStrip:
|
||||
// TODO: Use VK_PRIMITIVE_TOPOLOGY_QUAD_LIST_EXT/VK_PRIMITIVE_TOPOLOGY_QUAD_STRIP_EXT
|
||||
// whenever it releases
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case Maxwell::PrimitiveTopology::Patches:
|
||||
return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||
case Maxwell::PrimitiveTopology::Polygon:
|
||||
LOG_WARNING(Render_Vulkan, "Draw mode is Polygon with a polygon mode of lines should be a "
|
||||
"single body and not a bunch of triangles.");
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented topology={}", topology);
|
||||
return {};
|
||||
}
|
||||
|
||||
VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type,
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -18,52 +15,6 @@ namespace Vulkan::MaxwellToVK {
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
using PixelFormat = VideoCore::Surface::PixelFormat;
|
||||
|
||||
namespace detail {
|
||||
constexpr VkPrimitiveTopology PrimitiveTopologyNoDevice(Maxwell::PrimitiveTopology topology,
|
||||
Maxwell::PolygonMode polygon_mode) {
|
||||
switch (topology) {
|
||||
case Maxwell::PrimitiveTopology::Points:
|
||||
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
case Maxwell::PrimitiveTopology::Lines:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST;
|
||||
case Maxwell::PrimitiveTopology::LineLoop:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::LineStrip:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::Triangles:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case Maxwell::PrimitiveTopology::TriangleStrip:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
|
||||
case Maxwell::PrimitiveTopology::TriangleFan:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
case Maxwell::PrimitiveTopology::LinesAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::LineStripAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::TrianglesAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::TriangleStripAdjacency:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
|
||||
case Maxwell::PrimitiveTopology::Quads:
|
||||
case Maxwell::PrimitiveTopology::QuadStrip:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
case Maxwell::PrimitiveTopology::Patches:
|
||||
return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||
case Maxwell::PrimitiveTopology::Polygon:
|
||||
switch (polygon_mode) {
|
||||
case Maxwell::PolygonMode::Fill:
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
|
||||
case Maxwell::PolygonMode::Line:
|
||||
return VK_PRIMITIVE_TOPOLOGY_LINE_STRIP;
|
||||
case Maxwell::PolygonMode::Point:
|
||||
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
namespace Sampler {
|
||||
|
||||
VkFilter Filter(Tegra::Texture::TextureFilter filter);
|
||||
@@ -95,8 +46,7 @@ struct FormatInfo {
|
||||
|
||||
VkShaderStageFlagBits ShaderStage(Shader::Stage stage);
|
||||
|
||||
VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology,
|
||||
Maxwell::PolygonMode polygon_mode);
|
||||
VkPrimitiveTopology PrimitiveTopology(const Device& device, Maxwell::PrimitiveTopology topology);
|
||||
|
||||
VkFormat VertexFormat(const Device& device, Maxwell::VertexAttribute::Type type,
|
||||
Maxwell::VertexAttribute::Size size);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
@@ -23,7 +22,6 @@
|
||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
#include "video_core/polygon_mode_utils.h"
|
||||
#include "video_core/shader_notify.h"
|
||||
#include "video_core/texture_cache/texture_cache.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
@@ -616,10 +614,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
vertex_input_ci.pNext = &input_divisor_ci;
|
||||
}
|
||||
const bool has_tess_stages = spv_modules[1] || spv_modules[2];
|
||||
const auto polygon_mode =
|
||||
FixedPipelineState::UnpackPolygonMode(key.state.polygon_mode.Value());
|
||||
auto input_assembly_topology =
|
||||
MaxwellToVK::PrimitiveTopology(device, key.state.topology, polygon_mode);
|
||||
auto input_assembly_topology = MaxwellToVK::PrimitiveTopology(device, key.state.topology);
|
||||
if (input_assembly_topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
|
||||
if (!has_tess_stages) {
|
||||
LOG_WARNING(Render_Vulkan, "Patch topology used without tessellation, using points");
|
||||
@@ -634,33 +629,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
input_assembly_topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||
}
|
||||
}
|
||||
if (key.state.topology == Maxwell::PrimitiveTopology::Polygon) {
|
||||
const auto polygon_mode_name = [polygon_mode]() -> std::string_view {
|
||||
switch (polygon_mode) {
|
||||
case Maxwell::PolygonMode::Fill:
|
||||
return "Fill";
|
||||
case Maxwell::PolygonMode::Line:
|
||||
return "Line";
|
||||
case Maxwell::PolygonMode::Point:
|
||||
return "Point";
|
||||
}
|
||||
return "Unknown";
|
||||
}();
|
||||
const auto vk_topology_name = [input_assembly_topology]() -> std::string_view {
|
||||
switch (input_assembly_topology) {
|
||||
case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
|
||||
return "TriangleFan";
|
||||
case VK_PRIMITIVE_TOPOLOGY_LINE_STRIP:
|
||||
return "LineStrip";
|
||||
case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
|
||||
return "PointList";
|
||||
default:
|
||||
return "Unexpected";
|
||||
}
|
||||
}();
|
||||
LOG_DEBUG(Render_Vulkan, "Polygon primitive in {} mode mapped to {}", polygon_mode_name,
|
||||
vk_topology_name);
|
||||
}
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
||||
@@ -37,7 +37,6 @@
|
||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||
#include "video_core/shader_cache.h"
|
||||
#include "video_core/texture_cache/texture_cache_base.h"
|
||||
#include "video_core/polygon_mode_utils.h"
|
||||
#include "video_core/vulkan_common/vulkan_device.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
|
||||
@@ -109,7 +108,7 @@ VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t in
|
||||
|
||||
VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u32 down_shift = 0) {
|
||||
const auto& src = regs.scissor_test[index];
|
||||
VkRect2D scissor;
|
||||
VkRect2D scissor{};
|
||||
const auto scale_up = [&](s32 value) -> s32 {
|
||||
if (value == 0) {
|
||||
return 0U;
|
||||
@@ -149,8 +148,7 @@ VkRect2D GetScissorState(const Maxwell& regs, size_t index, u32 up_scale = 1, u3
|
||||
return scissor;
|
||||
}
|
||||
|
||||
DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed,
|
||||
Maxwell::PolygonMode polygon_mode) {
|
||||
DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances, bool is_indexed) {
|
||||
DrawParams params{
|
||||
.base_instance = draw_state.base_instance,
|
||||
.num_instances = num_instances,
|
||||
@@ -170,21 +168,6 @@ DrawParams MakeDrawParams(const MaxwellDrawState& draw_state, u32 num_instances,
|
||||
params.base_vertex = 0;
|
||||
params.is_indexed = true;
|
||||
}
|
||||
const bool polygon_line =
|
||||
draw_state.topology == Maxwell::PrimitiveTopology::Polygon &&
|
||||
polygon_mode == Maxwell::PolygonMode::Line;
|
||||
if (polygon_line) {
|
||||
if (params.is_indexed) {
|
||||
if (draw_state.index_buffer.count > 1) {
|
||||
params.num_vertices = draw_state.index_buffer.count + 1;
|
||||
}
|
||||
} else if (draw_state.vertex_buffer.count > 1) {
|
||||
params.num_vertices = draw_state.vertex_buffer.count + 1;
|
||||
params.is_indexed = true;
|
||||
params.first_index = 0;
|
||||
params.base_vertex = draw_state.vertex_buffer.first;
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
@@ -250,8 +233,7 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
||||
PrepareDraw(is_indexed, [this, is_indexed, instance_count] {
|
||||
const auto& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||
const u32 num_instances{instance_count};
|
||||
const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
|
||||
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed, polygon_mode)};
|
||||
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed)};
|
||||
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||
if (draw_params.is_indexed) {
|
||||
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
||||
@@ -392,7 +374,7 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
||||
}
|
||||
UpdateViewportsState(regs);
|
||||
|
||||
VkRect2D default_scissor;
|
||||
VkRect2D default_scissor{};
|
||||
default_scissor.offset.x = 0;
|
||||
default_scissor.offset.y = 0;
|
||||
default_scissor.extent.width = (std::numeric_limits<s32>::max)();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -57,6 +57,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);
|
||||
|
||||
@@ -74,6 +74,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{
|
||||
|
||||
@@ -435,7 +435,8 @@ if (YUZU_USE_BUNDLED_QT)
|
||||
endif()
|
||||
|
||||
if (ENABLE_SDL2)
|
||||
target_link_libraries(yuzu PRIVATE SDL2::SDL2)
|
||||
target_include_directories(yuzu PRIVATE ${CMAKE_SYSROOT}/include/SDL2)
|
||||
target_link_libraries(yuzu PRIVATE SDL2)
|
||||
target_compile_definitions(yuzu PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -71,11 +74,11 @@ private:
|
||||
|
||||
std::unique_ptr<InputProfiles> profiles;
|
||||
|
||||
std::array<ConfigureInputPlayer*, 8> player_controllers;
|
||||
std::array<QWidget*, 8> player_tabs;
|
||||
std::array<ConfigureInputPlayer*, 8> player_controllers{};
|
||||
std::array<QWidget*, 8> player_tabs{};
|
||||
// Checkboxes representing the "Connected Controllers".
|
||||
std::array<QCheckBox*, 8> connected_controller_checkboxes;
|
||||
ConfigureInputAdvanced* advanced;
|
||||
std::array<QCheckBox*, 8> connected_controller_checkboxes{};
|
||||
ConfigureInputAdvanced* advanced = nullptr;
|
||||
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -689,10 +692,10 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen
|
||||
{
|
||||
// Draw joysticks
|
||||
using namespace Settings::NativeAnalog;
|
||||
const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value);
|
||||
const auto l_button = button_values[Settings::NativeButton::LStick];
|
||||
const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value);
|
||||
const auto r_button = button_values[Settings::NativeButton::RStick];
|
||||
const auto& l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value);
|
||||
const auto& l_button = button_values[Settings::NativeButton::LStick];
|
||||
const auto& r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value);
|
||||
const auto& r_button = button_values[Settings::NativeButton::RStick];
|
||||
|
||||
DrawJoystick(p, center + QPointF(-171, -41) + (l_stick * 4), 1.0f, l_button);
|
||||
DrawJoystick(p, center + QPointF(171, 8) + (r_stick * 4), 1.0f, r_button);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -214,7 +217,7 @@ private:
|
||||
|
||||
bool mapping_active{};
|
||||
int blink_counter{};
|
||||
int callback_key;
|
||||
int callback_key{};
|
||||
QColor button_color{};
|
||||
ColorMapping colors{};
|
||||
Core::HID::LedPattern led_pattern{0, 0, 0, 0};
|
||||
|
||||
@@ -1495,7 +1495,7 @@ void MainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
||||
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
||||
auto_paused = true;
|
||||
OnPauseGame();
|
||||
} else if (!emu_thread->IsRunning() && auto_paused && state == Qt::ApplicationActive) {
|
||||
} else if (!emu_thread->IsRunning() && auto_paused && (state & Qt::ApplicationActive)) {
|
||||
auto_paused = false;
|
||||
OnStartGame();
|
||||
}
|
||||
@@ -1505,7 +1505,7 @@ void MainWindow::OnAppFocusStateChanged(Qt::ApplicationState state) {
|
||||
(state & (Qt::ApplicationHidden | Qt::ApplicationInactive))) {
|
||||
Settings::values.audio_muted = true;
|
||||
auto_muted = true;
|
||||
} else if (auto_muted && state == Qt::ApplicationActive) {
|
||||
} else if (auto_muted && (state & Qt::ApplicationActive)) {
|
||||
Settings::values.audio_muted = false;
|
||||
auto_muted = false;
|
||||
}
|
||||
|
||||
@@ -482,13 +482,13 @@ private:
|
||||
|
||||
MultiplayerState* multiplayer_state = nullptr;
|
||||
|
||||
GRenderWindow* render_window;
|
||||
GameList* game_list;
|
||||
LoadingScreen* loading_screen;
|
||||
GRenderWindow* render_window = nullptr;
|
||||
GameList* game_list = nullptr;
|
||||
LoadingScreen* loading_screen = nullptr;
|
||||
QTimer shutdown_timer;
|
||||
OverlayDialog* shutdown_dialog{};
|
||||
|
||||
GameListPlaceholder* game_list_placeholder;
|
||||
GameListPlaceholder* game_list_placeholder = nullptr;
|
||||
|
||||
std::vector<VkDeviceInfo::Record> vk_device_records;
|
||||
|
||||
@@ -531,7 +531,7 @@ private:
|
||||
QString startup_icon_theme;
|
||||
|
||||
// Debugger panes
|
||||
ControllerDialog* controller_dialog;
|
||||
ControllerDialog* controller_dialog = nullptr;
|
||||
|
||||
QAction* actions_recent_files[max_recent_files_item];
|
||||
|
||||
@@ -543,7 +543,7 @@ private:
|
||||
QTranslator translator;
|
||||
|
||||
// Install progress dialog
|
||||
QProgressDialog* install_progress;
|
||||
QProgressDialog* install_progress = nullptr;
|
||||
|
||||
// Last game booted, used for multi-process apps
|
||||
QString last_filename_booted;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2017 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -175,7 +178,7 @@ public:
|
||||
private:
|
||||
QString username;
|
||||
QString nickname;
|
||||
u64 title_id;
|
||||
u64 title_id{};
|
||||
QString game_name;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,13 +34,16 @@ 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)
|
||||
|
||||
create_resource("../../dist/yuzu.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)
|
||||
@@ -65,3 +68,7 @@ if (NOT MSVC)
|
||||
-Wno-unused-parameter
|
||||
-Wno-missing-field-initializers)
|
||||
endif()
|
||||
|
||||
if (PLATFORM_PS4)
|
||||
create_ps4_pkg(yuzu-cmd eden-cli IV0000-BREW00090_00-EDENEMULAT000000)
|
||||
endif()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,6 +77,12 @@ EmuWindow_SDL2_VK::EmuWindow_SDL2_VK(InputCommon::InputSubsystem* input_subsyste
|
||||
window_info.type = Core::Frontend::WindowSystemType::Android;
|
||||
window_info.render_surface = reinterpret_cast<void*>(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<void*>(wm.info.dfb.window);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
LOG_CRITICAL(Frontend, "Window manager subsystem {} not implemented", wm.subsystem);
|
||||
|
||||
@@ -51,7 +51,20 @@
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef __OPENORBIS__
|
||||
#include <orbis/SystemService.h>
|
||||
#include <cxxabi.h>
|
||||
#include <__thread/support.h>
|
||||
# define STUB_WEAK(name) extern "C" void name() { printf("called " #name); asm volatile("ud2"); }
|
||||
void *__cxa_thread_atexit_impl = nullptr;
|
||||
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)
|
||||
extern "C" {
|
||||
// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable
|
||||
// graphics
|
||||
@@ -224,7 +237,11 @@ 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.
|
||||
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) {
|
||||
@@ -419,10 +436,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();
|
||||
@@ -434,6 +461,7 @@ int main(int argc, char** argv) {
|
||||
void(system.Pause());
|
||||
system.ShutdownMainProcess();
|
||||
detached_tasks.WaitForAllTasks();
|
||||
exit_fn();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ try {
|
||||
Exit 1
|
||||
}
|
||||
|
||||
$VulkanSDKVer = "1.4.328.1"
|
||||
$VulkanSDKVer = "1.4.335.0"
|
||||
$VULKAN_SDK = "C:/VulkanSDK/$VulkanSDKVer"
|
||||
$ExeFile = "vulkansdk-windows-X64-$VulkanSDKVer.exe"
|
||||
$Uri = "https://sdk.lunarg.com/sdk/download/$VulkanSDKVer/windows/$ExeFile"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
: "${VULKAN_SDK_VER:=1.4.328.1}"
|
||||
: "${VULKAN_SDK_VER:=1.4.335.0}"
|
||||
: "${VULKAN_ROOT:=C:/VulkanSDK/$VULKAN_SDK_VER}"
|
||||
EXE_FILE="vulkansdk-windows-X64-$VULKAN_SDK_VER.exe"
|
||||
URI="https://sdk.lunarg.com/sdk/download/$VULKAN_SDK_VER/windows/$EXE_FILE"
|
||||
|
||||
Reference in New Issue
Block a user