Compare commits
36 Commits
fs_externa
...
vulkan-thi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3f449e5d77 | ||
|
|
ac4983d48f | ||
|
|
c5da21d064 | ||
|
|
1423619e61 | ||
|
|
312c1cc0f6 | ||
|
|
576c4e5f77 | ||
|
|
84cf3e8c84 | ||
|
|
45a2008aa6 | ||
|
|
8f6e0aa2cb | ||
|
|
ca0bc65531 | ||
|
|
a1930d1063 | ||
|
|
48843306e2 | ||
|
|
159482a7a9 | ||
|
|
0510f0bdbc | ||
|
|
569dbfe8c0 | ||
|
|
8412e64bb0 | ||
|
|
1c4dae066b | ||
|
|
9406438d51 | ||
|
|
612da00d1b | ||
|
|
4b34a5c9fa | ||
|
|
504df4856d | ||
|
|
6abaee94a6 | ||
|
|
4bf2e0a7aa | ||
|
|
82a476d458 | ||
|
|
ac2287f261 | ||
|
|
dd24ef244d | ||
|
|
5cc218084b | ||
|
|
c0663ccd6b | ||
|
|
8a7fe32a2c | ||
|
|
4b0bcfb0f7 | ||
|
|
82eb5a03f4 | ||
|
|
0e6ea2d9d6 | ||
|
|
6a9ad5e1ea | ||
|
|
903106c9b2 | ||
|
|
c70abc8e43 | ||
|
|
8ae7974092 |
@@ -13,6 +13,8 @@ elseif (${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD")
|
||||
set(PLATFORM_OPENBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "NetBSD")
|
||||
set(PLATFORM_NETBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "DragonFly")
|
||||
set(PLATFORM_DRAGONFLYBSD ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Haiku")
|
||||
set(PLATFORM_HAIKU ON)
|
||||
elseif (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
|
||||
@@ -37,17 +39,23 @@ endif()
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||
|
||||
# https://gitlab.kitware.com/cmake/cmake/-/merge_requests/11112
|
||||
# This works totally fine on MinGW64, but not CLANG{,ARM}64
|
||||
if(MINGW AND CXX_CLANG)
|
||||
set(CMAKE_SYSTEM_VERSION 10.0.0)
|
||||
endif()
|
||||
|
||||
# NB: this does not account for SPARC
|
||||
# If you get Eden working on SPARC, please shoot crueter@crueter.xyz multiple emails
|
||||
# and you will be hailed for eternity
|
||||
if (PLATFORM_SUN)
|
||||
# Terrific Solaris pkg shenanigans
|
||||
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SYSROOT}/usr/lib/qt/6.6/lib/amd64/cmake")
|
||||
|
||||
# Amazing - absolutely incredible
|
||||
list(APPEND CMAKE_PREFIX_PATH "/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SYSROOT}/usr/lib/amd64/cmake")
|
||||
|
||||
# For some mighty reason, doing a normal release build sometimes may not trigger
|
||||
# the proper -O3 switch to materialize
|
||||
@@ -63,18 +71,18 @@ endif()
|
||||
|
||||
# Needed for FFmpeg w/ VAAPI and DRM
|
||||
if (PLATFORM_OPENBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R6/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R6/include")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R6/lib")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R6/include")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R6/lib")
|
||||
elseif (PLATFORM_NETBSD)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I/usr/X11R7/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I/usr/X11R7/include")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/X11R7/lib")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_SYSROOT}/usr/X11R7/include")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/X11R7/lib")
|
||||
endif()
|
||||
|
||||
# NetBSD: Fun for the whole family!
|
||||
if (PLATFORM_NETBSD)
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_PATH}:${CMAKE_SYSROOT}/usr/pkg/lib/ffmpeg7/pkgconfig")
|
||||
endif()
|
||||
|
||||
# Detect current compilation architecture and create standard definitions
|
||||
@@ -92,12 +100,14 @@ function(detect_architecture symbol arch)
|
||||
if (ARCHITECTURE_${arch})
|
||||
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
|
||||
set(ARCHITECTURE_${arch} 1 PARENT_SCOPE)
|
||||
add_definitions(-DARCHITECTURE_${arch}=1)
|
||||
add_definitions("-DARCHITECTURE_${arch}=1")
|
||||
endif()
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
if (NOT ENABLE_GENERIC)
|
||||
# https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
# TODO: THIS IS FUCKING FLAWED ONLY THE FIRST SYMBOL THAT APPEARS WILL BE CONSIDERED :(
|
||||
if (MSVC)
|
||||
detect_architecture("_M_AMD64" x86_64)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
@@ -109,6 +119,48 @@ if (NOT ENABLE_GENERIC)
|
||||
detect_architecture("__arm__" arm)
|
||||
detect_architecture("__aarch64__" arm64)
|
||||
endif()
|
||||
detect_architecture("__ARM64__" arm64)
|
||||
detect_architecture("__aarch64__" arm64)
|
||||
detect_architecture("_M_ARM64" arm64)
|
||||
|
||||
detect_architecture("__arm__" arm)
|
||||
detect_architecture("__TARGET_ARCH_ARM" arm)
|
||||
detect_architecture("_M_ARM" arm)
|
||||
|
||||
detect_architecture("__x86_64" x86_64)
|
||||
detect_architecture("__x86_64__" x86_64)
|
||||
detect_architecture("__amd64" x86_64)
|
||||
detect_architecture("_M_X64" x86_64)
|
||||
|
||||
detect_architecture("__i386" x86)
|
||||
detect_architecture("__i386__" x86)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
|
||||
detect_architecture("__ia64" ia64)
|
||||
detect_architecture("__ia64__" ia64)
|
||||
detect_architecture("_M_IA64" ia64)
|
||||
|
||||
detect_architecture("__mips" mips)
|
||||
detect_architecture("__mips__" mips)
|
||||
detect_architecture("_M_MRX000" mips)
|
||||
|
||||
detect_architecture("__powerpc64__" ppc64)
|
||||
detect_architecture("__ppc64__" ppc64)
|
||||
detect_architecture("__PPC64__" ppc64)
|
||||
detect_architecture("_ARCH_PPC64" ppc64)
|
||||
|
||||
detect_architecture("__ppc__" ppc)
|
||||
detect_architecture("__ppc" ppc)
|
||||
detect_architecture("__powerpc__" ppc)
|
||||
detect_architecture("_ARCH_COM" ppc)
|
||||
detect_architecture("_ARCH_PWR" ppc)
|
||||
detect_architecture("_ARCH_PPC" ppc)
|
||||
detect_architecture("_M_MPPC" ppc)
|
||||
detect_architecture("_M_PPC" ppc)
|
||||
|
||||
detect_architecture("__riscv" riscv)
|
||||
|
||||
detect_architecture("__EMSCRIPTEN__" wasm)
|
||||
endif()
|
||||
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
@@ -139,9 +191,9 @@ if (CXX_CLANG_CL)
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:/EHsc> # thanks microsoft
|
||||
)
|
||||
|
||||
# REQUIRED CPU features IN Windows-amd64
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options(
|
||||
# Required CPU features for amd64
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-msse4.1>
|
||||
$<$<COMPILE_LANGUAGE:C,CXX>:-mcx16>
|
||||
)
|
||||
@@ -159,9 +211,8 @@ if (MSVC AND NOT CXX_CLANG)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /WX-")
|
||||
endif()
|
||||
|
||||
if (PLATFORM_FREEBSD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib")
|
||||
|
||||
if (PLATFORM_FREEBSD OR PLATFORM_DRAGONFLYBSD)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${CMAKE_SYSROOT}/usr/local/lib")
|
||||
endif()
|
||||
|
||||
# Set bundled sdl2/qt as dependent options.
|
||||
@@ -221,6 +272,7 @@ if(YUZU_ENABLE_LTO)
|
||||
set(CMAKE_POLICY_DEFAULT_CMP0069 NEW)
|
||||
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ${COMPILER_SUPPORTS_LTO})
|
||||
endif()
|
||||
|
||||
option(USE_CCACHE "Use ccache for compilation" OFF)
|
||||
set(CCACHE_PATH "ccache" CACHE STRING "Path to ccache binary")
|
||||
if(USE_CCACHE)
|
||||
@@ -265,9 +317,11 @@ if (ANDROID OR WIN32 OR APPLE OR PLATFORM_SUN)
|
||||
# your own copy of it.
|
||||
set(DEFAULT_ENABLE_OPENSSL OFF)
|
||||
endif()
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
set(DEFAULT_ENABLE_OPENSSL ON)
|
||||
endif()
|
||||
|
||||
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
||||
if (ENABLE_OPENSSL)
|
||||
set(DEFAULT_YUZU_USE_BUNDLED_OPENSSL OFF)
|
||||
@@ -894,6 +948,14 @@ if(MSVC)
|
||||
)
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
# This saves a truly ridiculous amount of time during linking
|
||||
# In my tests, without this it takes 2 mins, with it takes 3-5 seconds
|
||||
# or on GitHub Actions, 10 minutes -> 3 seconds
|
||||
set(MINGW_FLAGS "-Wl,--strip-all -Wl,--gc-sections")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${MINGW_FLAGS}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(src)
|
||||
|
||||
# Set yuzu project or yuzu-cmd project as default StartUp Project in Visual Studio depending on whether QT is enabled or not
|
||||
|
||||
@@ -594,6 +594,14 @@ function(AddCIPackage)
|
||||
add_ci_package(windows-arm64)
|
||||
endif()
|
||||
|
||||
if ((MINGW AND ARCHITECTURE_x86_64) AND NOT "mingw-amd64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(mingw-amd64)
|
||||
endif()
|
||||
|
||||
if ((MINGW AND ARCHITECTURE_arm64) AND NOT "mingw-arm64" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(mingw-arm64)
|
||||
endif()
|
||||
|
||||
if (ANDROID AND NOT "android" IN_LIST DISABLED_PLATFORMS)
|
||||
add_ci_package(android)
|
||||
endif()
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2020 yuzu Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
function(copy_yuzu_FFmpeg_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
||||
file(READ "${FFmpeg_PATH}/requirements.txt" FFmpeg_REQUIRED_DLLS)
|
||||
string(STRIP "${FFmpeg_REQUIRED_DLLS}" FFmpeg_REQUIRED_DLLS)
|
||||
windows_copy_files(${target_dir} ${FFmpeg_LIBRARY_DIR} ${DLL_DEST} ${FFmpeg_REQUIRED_DLLS})
|
||||
endfunction(copy_yuzu_FFmpeg_deps)
|
||||
@@ -1,8 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2016 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
function(copy_yuzu_SDL_deps target_dir)
|
||||
include(WindowsCopyFiles)
|
||||
set(DLL_DEST "$<TARGET_FILE_DIR:${target_dir}>/")
|
||||
windows_copy_files(${target_dir} ${SDL2_DLL_DIR} ${DLL_DEST} SDL2.dll)
|
||||
endfunction(copy_yuzu_SDL_deps)
|
||||
@@ -1,3 +1,6 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
# SPDX-FileCopyrightText: 2019 Citra Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -75,16 +78,16 @@ function(find_ffmpeg LIBNAME)
|
||||
)
|
||||
else()
|
||||
list(APPEND INCLUDE_PATHS
|
||||
/usr/local/include/ffmpeg
|
||||
/usr/local/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg
|
||||
/usr/include/lib${LIBNAME}
|
||||
/usr/include/ffmpeg/lib${LIBNAME}
|
||||
${CMAKE_SYSROOT}/usr/local/include/ffmpeg
|
||||
${CMAKE_SYSROOT}/usr/local/include/lib${LIBNAME}
|
||||
${CMAKE_SYSROOT}/usr/include/ffmpeg
|
||||
${CMAKE_SYSROOT}/usr/include/lib${LIBNAME}
|
||||
${CMAKE_SYSROOT}/usr/include/ffmpeg/lib${LIBNAME}
|
||||
)
|
||||
|
||||
list(APPEND LIB_PATHS
|
||||
/usr/local/lib
|
||||
/usr/lib
|
||||
${CMAKE_SYSROOT}/usr/local/lib
|
||||
${CMAKE_SYSROOT}/usr/lib
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
"version": "3.6.0",
|
||||
"min_version": "1.1.1",
|
||||
"disabled_platforms": [
|
||||
"macos-universal"
|
||||
"macos-universal",
|
||||
"mingw-amd64",
|
||||
"mingw-arm64"
|
||||
]
|
||||
},
|
||||
"boost": {
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
- `DISABLED_PLATFORMS`: List of platforms that lack artifacts for this package. Options:
|
||||
* `windows-amd64`
|
||||
* `windows-arm64`
|
||||
* `mingw-amd64`
|
||||
* `mingw-arm64`
|
||||
* `android`
|
||||
* `solaris-amd64`
|
||||
* `freebsd-amd64`
|
||||
|
||||
119
docs/Caveats.md
119
docs/Caveats.md
@@ -1,24 +1,28 @@
|
||||
# Caveats
|
||||
|
||||
<!-- TOC -->
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [Gentoo Linux](#gentoo-linux)
|
||||
- [macOS](#macos)
|
||||
- [Solaris](#solaris)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [NetBSD](#netbsd)
|
||||
- [Caveats](#caveats)
|
||||
- [Arch Linux](#arch-linux)
|
||||
- [Gentoo Linux](#gentoo-linux)
|
||||
- [macOS](#macos)
|
||||
- [Solaris](#solaris)
|
||||
- [HaikuOS](#haikuos)
|
||||
- [OpenBSD](#openbsd)
|
||||
- [FreeBSD](#freebsd)
|
||||
- [NetBSD](#netbsd)
|
||||
- [MSYS2](#msys2)
|
||||
- [Windows 8.1 and below](#windows-81-and-below)
|
||||
<!-- /TOC -->
|
||||
|
||||
## Arch Linux
|
||||
|
||||
- httplib AUR package is broken. Set `httplib_FORCE_BUNDLED=ON` if you have it installed.
|
||||
- Eden is also available as an [AUR package](https://aur.archlinux.org/packages/eden-git). If you are unable to build, either use that or compare your process to the PKGBUILD.
|
||||
Eden is also available as an [AUR package](https://aur.archlinux.org/packages/eden-git). If you are unable to build, either use that or compare your process to the PKGBUILD.
|
||||
|
||||
## Gentoo Linux
|
||||
|
||||
Do not use the system sirit or xbyak packages.
|
||||
[`games-emulation/eden`](https://gitweb.gentoo.org/repo/proj/guru.git/tree/games-emulation/eden) is available in the GURU. This repository also contains some additional dependencies, such as mcl, sirit, oaknut, etc.
|
||||
|
||||
If you're having issues with building, always consult that ebuild.
|
||||
|
||||
## macOS
|
||||
|
||||
@@ -26,6 +30,13 @@ macOS is largely untested. Expect crashes, significant Vulkan issues, and other
|
||||
|
||||
## Solaris
|
||||
|
||||
Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability.
|
||||
|
||||
Run the usual update + install of essential toolings: `sudo pkg update && sudo pkg install git cmake`.
|
||||
|
||||
- **gcc**: `sudo pkg install developer/gcc-14`.
|
||||
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
|
||||
|
||||
Qt Widgets appears to be broken. For now, add `-DENABLE_QT=OFF` to your configure command. In the meantime, a Qt Quick frontend is in the works--check back later!
|
||||
|
||||
This is needed for some dependencies that call cc directly (tz):
|
||||
@@ -70,7 +81,7 @@ Still will not run flawlessly until `mesa-24` is available. Modify CMakeCache.tx
|
||||
|
||||
After configuration, you may need to modify `externals/ffmpeg/CMakeFiles/ffmpeg-build/build.make` to use `-j$(nproc)` instead of just `-j`.
|
||||
|
||||
`-lc++-experimental` doesn't exist in OpenBSD but the LLVM driver still tries to link against it, to solve just symlink `ln -s /usr/lib/libc++.a /usr/lib/libc++experimental.a`.
|
||||
`-lc++-experimental` doesn't exist in OpenBSD but the LLVM driver still tries to link against it, to solve just symlink `ln -s /usr/lib/libc++.a /usr/lib/libc++experimental.a`. Builds are currently not working due to lack of `std::jthread` and such, either compile libc++ manually or wait for ports to catch up.
|
||||
|
||||
If clang has errors, try using `g++-11`.
|
||||
|
||||
@@ -102,3 +113,87 @@ cmake -B build -DCMAKE_BUILD_TYPE=Release
|
||||
cmake --build build -- -j`nproc`
|
||||
cmake --install build
|
||||
```
|
||||
|
||||
# DragonFlyBSD
|
||||
|
||||
If `libstdc++.so.6` is not found (`GLIBCXX_3.4.30`) then attempt:
|
||||
```sh
|
||||
rm /usr/local/lib/gcc11/libstdc++.so.6
|
||||
ln -s /usr/local/lib/gcc14/libstdc++.so /usr/local/lib/gcc11/libstdc++.so.6
|
||||
```
|
||||
This may have unforeseen consequences of which we don't need to worry about for now.
|
||||
|
||||
Default `g++` (and the libstdc++) is too outdated - so install `gcc14` and redirect CMake to the new compiler toolchain `-DCMAKE_CXX_COMPILER=gcc14 -DCMAKE_C_COMPILER=g++14`.
|
||||
|
||||
There is also `llvm18` and use `-DCMAKE_CXX_COMPILER=clang++18 -DCMAKE_C_COMPILER=clang18` (note the `18` suffix at the end). NOTE: It doesn't have an updated libcxx so `<span>` will be missing, either build it manually or use gcc.
|
||||
|
||||
If build hangs, use `hammer2 bulkfree`.
|
||||
|
||||
## MSYS2
|
||||
|
||||
`qt6-static` isn't supported yet.
|
||||
|
||||
Only the `MINGW64` environment is tested; however, all of the others should work (in theory) sans `MINGW32`.
|
||||
|
||||
Currently, only FFmpeg can be used as a system dependency; the others will result in linker errors.
|
||||
|
||||
When packaging an MSYS2 build, you will need to copy all dependent DLLs recursively alongside the `windeployqt6`; for example:
|
||||
|
||||
```sh
|
||||
# MSYS_TOOLCHAIN is typically just mingw64
|
||||
# since Windows is case-insensitive, you can set this to $MSYSTEM
|
||||
# or, if cross-compiling from Linux, set it to usr/x86_64-w64-mingw32
|
||||
export PATH="/${MSYS_TOOLCHAIN}/bin:$PATH"
|
||||
|
||||
# grab deps of a dll or exe and place them in the current dir
|
||||
deps() {
|
||||
# string parsing is fun
|
||||
objdump -p "$1" | awk '/DLL Name:/ {print $3}' | while read -r dll; do
|
||||
[ -z "$dll" ] && continue
|
||||
|
||||
# bin directory is used for DLLs, so we can do a quick "hack"
|
||||
# and use command to find the path of the DLL
|
||||
dllpath=$(command -v "$dll" 2>/dev/null || true)
|
||||
|
||||
[ -z "$dllpath" ] && continue
|
||||
|
||||
# explicitly exclude system32/syswow64 deps
|
||||
# these aren't needed to be bundled, as all systems already have them
|
||||
case "$dllpath" in
|
||||
*System32* | *SysWOW64*) continue ;;
|
||||
esac
|
||||
|
||||
# avoid copying deps multiple times
|
||||
if [ ! -f "$dll" ]; then
|
||||
echo "$dllpath"
|
||||
cp "$dllpath" "$dll"
|
||||
|
||||
# also grab the dependencies of the dependent DLL; e.g.
|
||||
# double-conversion is a dep of Qt6Core.dll but NOT eden.exe
|
||||
deps "$dllpath"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# NB: must be done in a directory containing eden.exe
|
||||
deps eden.exe
|
||||
|
||||
# deploy Qt plugins and such
|
||||
windeployqt6 --no-compiler-runtime --no-opengl-sw --no-system-dxc-compiler \
|
||||
--no-system-d3d-compiler eden.exe
|
||||
|
||||
# grab deps for Qt plugins
|
||||
find ./*/ -name "*.dll" | while read -r dll; do deps "$dll"; done
|
||||
```
|
||||
|
||||
## Windows 8.1 and below
|
||||
|
||||
DirectX 12 is not available - simply copy and paste a random DLL and name it `d3d12.dll`.
|
||||
|
||||
Install [Qt6 compatibility libraries](github.com/ANightly/qt6windows7) specifically Qt 6.9.5.
|
||||
|
||||
## RedoxOS
|
||||
|
||||
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.
|
||||
|
||||
@@ -8,6 +8,8 @@ But for new developers you may find that following these guidelines will make ev
|
||||
|
||||
Simply put, types/classes are named as `PascalCase`, same for methods and functions like `AddElement`. Variables are named `like_this_snake_case` and constants are `IN_SCREAMING_CASE`.
|
||||
|
||||
Except for Qt MOC where `functionName` is preferred.
|
||||
|
||||
Template typenames prefer short names like `T`, `I`, `U`, if a longer name is required either `Iterator` or `perform_action` are fine as well.
|
||||
|
||||
Macros must always be in `SCREAMING_CASE`. Do not use short letter macros as systems like Solaris will conflict with them; a good rule of thumb is >5 characters per macro - i.e `THIS_MACRO_IS_GOOD`, `AND_ALSO_THIS_ONE`.
|
||||
|
||||
89
docs/Deps.md
89
docs/Deps.md
@@ -87,6 +87,53 @@ Notes for writers: Include build tools as well, assume user has NOTHING installe
|
||||
|
||||
Click on the arrows to expand.
|
||||
|
||||
<details>
|
||||
<summary>Gentoo Linux</summary>
|
||||
|
||||
GURU must be enabled:
|
||||
|
||||
```
|
||||
sudo emerge -a app-eselect/eselect-repository
|
||||
sudo eselect repository enable guru
|
||||
sudo emaint sync -r guru
|
||||
```
|
||||
|
||||
Now, install all deps:
|
||||
|
||||
```sh
|
||||
sudo emerge -a \
|
||||
app-arch/lz4 app-arch/zstd app-arch/unzip \
|
||||
dev-libs/libfmt dev-libs/libusb dev-libs/mcl dev-libs/sirit \
|
||||
dev-libs/unordered_dense dev-libs/boost dev-libs/openssl dev-libs/discord-rpc \
|
||||
dev-util/spirv-tools dev-util/spirv-headers dev-util/vulkan-headers \
|
||||
dev-util/vulkan-utility-libraries dev-util/glslang \
|
||||
media-gfx/renderdoc media-libs/libva media-libs/opus media-video/ffmpeg \
|
||||
media-libs/VulkanMemoryAllocator media-libs/libsdl2 media-libs/cubeb \
|
||||
net-libs/enet net-libs/mbedtls \
|
||||
sys-libs/zlib \
|
||||
dev-cpp/nlohmann_json dev-cpp/simpleini dev-cpp/cpp-httplib dev-cpp/cpp-jwt \
|
||||
games-util/gamemode \
|
||||
net-wireless/wireless-tools \
|
||||
dev-qt/qtbase:6 dev-libs/quazip \
|
||||
virtual/pkgconfig
|
||||
```
|
||||
|
||||
- On `amd64`, also add `dev-libs/xbyak`
|
||||
- On `riscv64`, also add `dev-libs/biscuit` (currently unavailable)
|
||||
- On `aarch64`, also add `dev-libs/oaknut`
|
||||
- If tests are enabled, also add `dev-libs/oaknut` and `dev-cpp/catch`
|
||||
|
||||
Required USE flags:
|
||||
- `dev-qt/qtbase network concurrent dbus gui widgets`
|
||||
- `dev-libs/quazip qt6`
|
||||
- `net-libs/mbedtls cmac`
|
||||
- `media-libs/libsdl2 haptic joystick sound video`
|
||||
- `dev-cpp/cpp-httplib ssl`
|
||||
|
||||
[Caveats](./Caveats.md#gentoo-linux)
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Arch Linux</summary>
|
||||
|
||||
@@ -149,6 +196,7 @@ apk add g++ git cmake make mbedtls-dev mbedtls-static mesa-dev qt6-qtbase-dev qt
|
||||
`mbedtls-static` has to be specified otherwise `libeverest.a` and `libp256m.a` will fail to be found.
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Void Linux</summary>
|
||||
|
||||
```sh
|
||||
@@ -158,6 +206,7 @@ xbps-install -Su git make cmake clang pkg-config patch mbedtls-devel SPIRV-Tools
|
||||
Yes, `nlohmann-json` is just named `json-c++`. Why?
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>NixOS</summary>
|
||||
|
||||
@@ -186,7 +235,7 @@ brew install molten-vk vulkan-loader
|
||||
<details>
|
||||
<summary>FreeBSD</summary>
|
||||
|
||||
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense`
|
||||
As root run: `pkg install devel/cmake devel/sdl20 devel/boost-libs devel/catch2 devel/libfmt devel/nlohmann-json devel/ninja devel/nasm devel/autoconf devel/pkgconf devel/qt6-base devel/simpleini net/enet multimedia/ffnvcodec-headers multimedia/ffmpeg audio/opus archivers/liblz4 lang/gcc12 graphics/glslang graphics/vulkan-utility-libraries graphics/spirv-tools www/cpp-httplib devel/jwt-cpp devel/unordered-dense mbedtls3 vulkan-headers quazip-qt6`
|
||||
|
||||
If using FreeBSD 12 or prior, use `devel/pkg-config` instead.
|
||||
|
||||
@@ -211,18 +260,23 @@ pkg_add cmake nasm git boost unzip--iconv autoconf-2.72p0 bash ffmpeg glslang gm
|
||||
|
||||
[Caveats](./Caveats.md#openbsd).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>DragonFlyBSD</summary>
|
||||
|
||||
```sh
|
||||
pkg install gcc14 git cmake unzip nasm autoconf bash pkgconf ffmpeg glslang gmake jq nlohmann-json enet spirv-tools sdl2 vulkan-utility-libraries vulkan-headers catch2 libfmt openssl liblz4 boost-libs cpp-httplib qt6-base quazip-qt6 unordered-dense libva-vdpau-driver libva-utils libva-intel-driver
|
||||
```
|
||||
|
||||
[Caveats](./Caveats.md#dragonflybsd).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Solaris / OpenIndiana</summary>
|
||||
|
||||
Always consult [the OpenIndiana package list](https://pkg.openindiana.org/hipster/en/index.shtml) to cross-verify availability.
|
||||
|
||||
Run the usual update + install of essential toolings: `sudo pkg update && sudo pkg install git cmake`.
|
||||
|
||||
- **gcc**: `sudo pkg install developer/gcc-14`.
|
||||
- **clang**: Version 20 is broken, use `sudo pkg install developer/clang-19`.
|
||||
|
||||
Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt`.
|
||||
```sh
|
||||
sudo pkg install qt6 boost glslang libzip library/lz4 libusb-1 nlohmann-json openssl opus sdl2 zlib compress/zstd unzip pkg-config nasm autoconf mesa library/libdrm header-drm developer/fmt
|
||||
```
|
||||
|
||||
[Caveats](./Caveats.md#solaris).
|
||||
|
||||
@@ -234,24 +288,27 @@ Then install the libraries: `sudo pkg install qt6 boost glslang libzip library/l
|
||||
* Download and install all dependencies:
|
||||
```
|
||||
BASE="git make autoconf libtool automake-wrapper jq patch"
|
||||
MINGW="SDL2 cmake python-pip qt6-base toolchain ffmpeg boost catch fmt lz4 nlohmann-json openssl zlib zstd enet opus mbedtls vulkan-devel libusb vulkan-memory-allocator unordered_dense clang ccache"
|
||||
|
||||
MINGW="qt6-base qt6-tools qt6-translations qt6-svg cmake toolchain clang python-pip openssl vulkan-memory-allocator vulkan-devel glslang boost fmt lz4 nlohmann-json zlib zstd enet opus mbedtls libusb unordered_dense"
|
||||
|
||||
packages="$BASE"
|
||||
for pkg in $MINGW; do
|
||||
packages="$packages mingw-w64-x86_64-$pkg"
|
||||
done
|
||||
|
||||
pacman -Syu --needed --noconfirm $packages
|
||||
pacman -Syuu --needed --noconfirm $packages
|
||||
```
|
||||
* Notes:
|
||||
- Using `qt6-static` is possible but currently untested.
|
||||
- Other environments are entirely untested, but should theoretically work provided you install all the necessary packages.
|
||||
- Clang is installed as it generally works better here. You can compile with GCC just fine, however.
|
||||
- GCC is proven to work better with the MinGW environment. If you choose to use Clang, you *may* be better off using the clang64 environment.
|
||||
- Add `qt-creator` to the `MINGW` variable to install Qt Creator. You can then create a Start Menu shortcut to the MinGW Qt Creator by running `powershell "\$s=(New-Object -COM WScript.Shell).CreateShortcut('C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Qt Creator.lnk');\$s.TargetPath='C:\\msys64\\mingw64\\bin\\qtcreator.exe';\$s.Save()"` in Git Bash or MSYS2.
|
||||
* Add MinGW binaries to the PATH if they aren't already:
|
||||
* `echo 'PATH=/mingw64/bin:$PATH' >> ~/.bashrc`
|
||||
* or `echo 'PATH=/mingw64/bin:$PATH' >> ~/.zshrc`
|
||||
|
||||
[Caveats](./Caveats.md#msys2).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>HaikuOS</summary>
|
||||
@@ -263,14 +320,16 @@ pkgman install git cmake patch libfmt_devel nlohmann_json lz4_devel opus_devel b
|
||||
[Caveats](./Caveats.md#haikuos).
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>RedoxOS</summary>
|
||||
|
||||
TODO: Fix syscall crashes (heavy IO stalls and hangup due to net mutexes?)
|
||||
```sh
|
||||
sudo pkg update && sudo pkg install git cmake
|
||||
sudo pkg install ffmpeg6 sdl2 zlib llvm18
|
||||
sudo pkg update
|
||||
sudo pkg install git cmake ffmpeg6 sdl2 zlib llvm18
|
||||
```
|
||||
|
||||
[Caveats](./Caveats.md#redoxos).
|
||||
|
||||
</details>
|
||||
|
||||
## All Done
|
||||
|
||||
6
externals/cpmfile.json
vendored
6
externals/cpmfile.json
vendored
@@ -23,7 +23,11 @@
|
||||
"package": "sirit",
|
||||
"name": "sirit",
|
||||
"repo": "eden-emulator/sirit",
|
||||
"version": "1.0.2"
|
||||
"version": "1.0.2",
|
||||
"disabled_platforms": [
|
||||
"mingw-amd64",
|
||||
"mingw-arm64"
|
||||
]
|
||||
},
|
||||
"httplib": {
|
||||
"repo": "yhirose/cpp-httplib",
|
||||
|
||||
3
externals/ffmpeg/CMakeLists.txt
vendored
3
externals/ffmpeg/CMakeLists.txt
vendored
@@ -107,9 +107,10 @@ endif()
|
||||
|
||||
if (YUZU_USE_BUNDLED_FFMPEG)
|
||||
# MSVC conflicts with ksuser otherwise
|
||||
# MinGW has the funny quirk of requiring avutil after avcodec
|
||||
# Android needs some deps to be compiled with PIC (TODO)
|
||||
# TODO(crueter) fix
|
||||
if (MSVC OR ANDROID)
|
||||
if (ANDROID)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
else()
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
1
externals/ffmpeg/cpmfile.json
vendored
1
externals/ffmpeg/cpmfile.json
vendored
@@ -15,6 +15,7 @@
|
||||
"disabled_platforms": [
|
||||
"freebsd-amd64",
|
||||
"solaris-amd64",
|
||||
"openbsd-amd64",
|
||||
"macos-universal"
|
||||
]
|
||||
}
|
||||
|
||||
16
shell.nix
16
shell.nix
@@ -9,11 +9,15 @@ pkgs.mkShellNoCC {
|
||||
# libraries
|
||||
openssl boost fmt nlohmann_json lz4 zlib zstd
|
||||
enet libopus vulkan-headers vulkan-utility-libraries
|
||||
spirv-tools spirv-headers simpleini vulkan-memory-allocator
|
||||
vulkan-loader unzip mbedtls glslang python3 httplib
|
||||
cpp-jwt ffmpeg-headless libusb1 cubeb
|
||||
qt6.full # eden
|
||||
SDL2 # eden-cli
|
||||
discord-rpc gamemode # optional components
|
||||
spirv-tools spirv-headers vulkan-loader unzip mbedtls
|
||||
glslang python3 httplib cpp-jwt ffmpeg-headless
|
||||
libusb1 cubeb
|
||||
# eden
|
||||
qt6.qtbase qt6.qtmultimedia qt6.qtwayland qt6.qttools
|
||||
qt6.qtwebengine qt6.qt5compat
|
||||
# eden-cli
|
||||
SDL2
|
||||
# optional components
|
||||
discord-rpc gamemode
|
||||
];
|
||||
}
|
||||
@@ -178,8 +178,10 @@ else()
|
||||
|
||||
if (MINGW)
|
||||
add_compile_definitions(MINGW_HAS_SECURE_API)
|
||||
add_compile_options("-msse4.1")
|
||||
|
||||
# Only windows has this requirement, thanks windows
|
||||
if (WIN32)
|
||||
add_compile_options("-msse4.1")
|
||||
endif()
|
||||
if (MINGW_STATIC_BUILD)
|
||||
add_compile_definitions(QT_STATICPLUGIN)
|
||||
add_compile_options("-static")
|
||||
|
||||
@@ -1511,7 +1511,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
emulationState.newSurface(holder.surface)
|
||||
} else {
|
||||
emulationState.newSurface(holder.surface)
|
||||
// Surface changed due to rotation/config change
|
||||
// Only update surface reference, don't trigger state changes
|
||||
emulationState.updateSurfaceReference(holder.surface)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1842,6 +1844,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun updateSurfaceReference(surface: Surface?) {
|
||||
this.surface = surface
|
||||
if (this.surface != null && state == State.RUNNING) {
|
||||
NativeLibrary.surfaceChanged(this.surface)
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
fun clearSurface() {
|
||||
if (surface == null) {
|
||||
|
||||
@@ -84,6 +84,7 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par
|
||||
const auto pow_10 = [](f32 val) -> f32 {
|
||||
return (val >= 0.0f) ? 1.0f : (val <= -5.3f) ? 0.0f : std::pow(10.0f, val);
|
||||
};
|
||||
|
||||
const auto cos = [](f32 degrees) -> f32 {
|
||||
return std::cos(degrees * std::numbers::pi_v<f32> / 180.0f);
|
||||
};
|
||||
@@ -91,26 +92,39 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par
|
||||
static bool unk_initialized{false};
|
||||
static Common::FixedPoint<50, 14> unk_value{};
|
||||
|
||||
const auto sample_rate{Common::FixedPoint<50, 14>::from_base(params.sample_rate)};
|
||||
const auto pre_delay_time{Common::FixedPoint<50, 14>::from_base(params.pre_delay)};
|
||||
auto sample_rate = Common::FixedPoint<50, 14>::from_base(params.sample_rate);
|
||||
if (sample_rate.to_float() < 1.0f) sample_rate = Common::FixedPoint<50, 14>(1.0f);
|
||||
|
||||
auto pre_delay_time = Common::FixedPoint<50, 14>::from_base(params.pre_delay);
|
||||
if (pre_delay_time.to_float() < 0.0f) pre_delay_time = Common::FixedPoint<50, 14>(0.0f);
|
||||
|
||||
for (u32 i = 0; i < ReverbInfo::MaxDelayTaps; i++) {
|
||||
auto early_delay{
|
||||
((pre_delay_time + EarlyDelayTimes[params.early_mode][i]) * sample_rate).to_int()};
|
||||
early_delay = (std::min)(early_delay, state.pre_delay_line.sample_count_max);
|
||||
state.early_delay_times[i] = early_delay + 1;
|
||||
state.early_gains[i] = Common::FixedPoint<50, 14>::from_base(params.early_gain) *
|
||||
EarlyDelayGains[params.early_mode][i];
|
||||
int target_delay = ((pre_delay_time + EarlyDelayTimes[params.early_mode][i]) * sample_rate).to_int();
|
||||
if (target_delay < 0) target_delay = 0;
|
||||
if (target_delay > state.pre_delay_line.sample_count_max) target_delay = state.pre_delay_line.sample_count_max;
|
||||
|
||||
int old_delay = state.early_delay_times[i] - 1;
|
||||
int smooth_delay = old_delay + (target_delay - old_delay) / 4;
|
||||
state.early_delay_times[i] = smooth_delay + 1;
|
||||
|
||||
auto target_gain = Common::FixedPoint<50, 14>::from_base(params.early_gain) * EarlyDelayGains[params.early_mode][i];
|
||||
if (target_gain.to_float() < 0.0f) target_gain = Common::FixedPoint<50, 14>(0.0f);
|
||||
if (target_gain.to_float() > 1.0f) target_gain = Common::FixedPoint<50, 14>(1.0f);
|
||||
|
||||
state.early_gains[i] = state.early_gains[i] + (target_gain - state.early_gains[i]) / 4;
|
||||
}
|
||||
|
||||
if (params.channel_count == 2) {
|
||||
state.early_gains[4] * 0.5f;
|
||||
state.early_gains[5] * 0.5f;
|
||||
state.early_gains[4] *= Common::FixedPoint<50, 14>(0.5f);
|
||||
state.early_gains[5] *= Common::FixedPoint<50, 14>(0.5f);
|
||||
}
|
||||
|
||||
auto pre_time{
|
||||
((pre_delay_time + EarlyDelayTimes[params.early_mode][10]) * sample_rate).to_int()};
|
||||
state.pre_delay_time = (std::min)(pre_time, state.pre_delay_line.sample_count_max);
|
||||
int target_pre_time = ((pre_delay_time + EarlyDelayTimes[params.early_mode][10]) * sample_rate).to_int();
|
||||
if (target_pre_time < 0) target_pre_time = 0;
|
||||
if (target_pre_time > state.pre_delay_line.sample_count_max) target_pre_time = state.pre_delay_line.sample_count_max;
|
||||
|
||||
int old_pre_time = state.pre_delay_time;
|
||||
state.pre_delay_time = old_pre_time + (target_pre_time - old_pre_time) / 4;
|
||||
|
||||
if (!unk_initialized) {
|
||||
unk_value = cos((1280.0f / sample_rate).to_float());
|
||||
@@ -118,45 +132,64 @@ static void UpdateReverbEffectParameter(const ReverbInfo::ParameterVersion2& par
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) {
|
||||
const auto fdn_delay{(FdnDelayTimes[params.late_mode][i] * sample_rate).to_int()};
|
||||
state.fdn_delay_lines[i].sample_count =
|
||||
(std::min)(fdn_delay, state.fdn_delay_lines[i].sample_count_max);
|
||||
state.fdn_delay_lines[i].buffer_end =
|
||||
&state.fdn_delay_lines[i].buffer[state.fdn_delay_lines[i].sample_count - 1];
|
||||
int target_fdn_delay = (FdnDelayTimes[params.late_mode][i] * sample_rate).to_int();
|
||||
if (target_fdn_delay < 0) target_fdn_delay = 0;
|
||||
if (target_fdn_delay > state.fdn_delay_lines[i].sample_count_max) target_fdn_delay = state.fdn_delay_lines[i].sample_count_max;
|
||||
|
||||
const auto decay_delay{(DecayDelayTimes[params.late_mode][i] * sample_rate).to_int()};
|
||||
state.decay_delay_lines[i].sample_count =
|
||||
(std::min)(decay_delay, state.decay_delay_lines[i].sample_count_max);
|
||||
state.decay_delay_lines[i].buffer_end =
|
||||
&state.decay_delay_lines[i].buffer[state.decay_delay_lines[i].sample_count - 1];
|
||||
int old_fdn = state.fdn_delay_lines[i].sample_count;
|
||||
state.fdn_delay_lines[i].sample_count = old_fdn + (target_fdn_delay - old_fdn) / 4;
|
||||
state.fdn_delay_lines[i].buffer_end = &state.fdn_delay_lines[i].buffer[state.fdn_delay_lines[i].sample_count - 1];
|
||||
|
||||
state.decay_delay_lines[i].decay =
|
||||
0.5999755859375f * (1.0f - Common::FixedPoint<50, 14>::from_base(params.colouration));
|
||||
int target_decay_delay = (DecayDelayTimes[params.late_mode][i] * sample_rate).to_int();
|
||||
if (target_decay_delay < 0) target_decay_delay = 0;
|
||||
if (target_decay_delay > state.decay_delay_lines[i].sample_count_max) target_decay_delay = state.decay_delay_lines[i].sample_count_max;
|
||||
|
||||
auto a{(Common::FixedPoint<50, 14>(state.fdn_delay_lines[i].sample_count_max) +
|
||||
state.decay_delay_lines[i].sample_count_max) *
|
||||
-3};
|
||||
auto b{a / (Common::FixedPoint<50, 14>::from_base(params.decay_time) * sample_rate)};
|
||||
Common::FixedPoint<50, 14> c{0.0f};
|
||||
Common::FixedPoint<50, 14> d{0.0f};
|
||||
auto hf_decay_ratio{Common::FixedPoint<50, 14>::from_base(params.high_freq_decay_ratio)};
|
||||
int old_decay = state.decay_delay_lines[i].sample_count;
|
||||
state.decay_delay_lines[i].sample_count = old_decay + (target_decay_delay - old_decay) / 4;
|
||||
state.decay_delay_lines[i].buffer_end = &state.decay_delay_lines[i].buffer[state.decay_delay_lines[i].sample_count - 1];
|
||||
|
||||
if (hf_decay_ratio > 0.99493408203125f) {
|
||||
auto colouration = Common::FixedPoint<50, 14>::from_base(params.colouration);
|
||||
if (colouration.to_float() < 0.0f) colouration = Common::FixedPoint<50, 14>(0.0f);
|
||||
if (colouration.to_float() > 1.0f) colouration = Common::FixedPoint<50, 14>(1.0f);
|
||||
|
||||
state.decay_delay_lines[i].decay = state.decay_delay_lines[i].decay + (0.5999755859375f * (1.0f - colouration) - state.decay_delay_lines[i].decay) / 4;
|
||||
|
||||
auto decay_time_fp = Common::FixedPoint<50, 14>::from_base(params.decay_time);
|
||||
if (decay_time_fp.to_float() <= 0.0f) decay_time_fp = Common::FixedPoint<50, 14>(0.0001f);
|
||||
|
||||
auto a = (Common::FixedPoint<50, 14>(state.fdn_delay_lines[i].sample_count_max) + state.decay_delay_lines[i].sample_count_max) * -3;
|
||||
auto b = a / (decay_time_fp * sample_rate);
|
||||
|
||||
auto hf_decay_ratio = Common::FixedPoint<50, 14>::from_base(params.high_freq_decay_ratio);
|
||||
if (hf_decay_ratio.to_float() < 0.001f) hf_decay_ratio = Common::FixedPoint<50, 14>(0.001f);
|
||||
if (hf_decay_ratio.to_float() > 0.999f) hf_decay_ratio = Common::FixedPoint<50, 14>(0.999f);
|
||||
|
||||
Common::FixedPoint<50, 14> c{0.0f}, d{0.0f};
|
||||
if (hf_decay_ratio.to_float() > 0.9949f) {
|
||||
c = 0.0f;
|
||||
d = 1.0f;
|
||||
} else {
|
||||
const auto e{
|
||||
pow_10(((((1.0f / hf_decay_ratio) - 1.0f) * 2) / 100 * (b / 10)).to_float())};
|
||||
const auto f{1.0f - e};
|
||||
const auto g{2.0f - (unk_value * e * 2)};
|
||||
const auto h{std::sqrt(std::pow(g.to_float(), 2.0f) - (std::pow(f, 2.0f) * 4))};
|
||||
auto e = pow_10(((((1.0f / hf_decay_ratio.to_float()) - 1.0f) * 2) / 100 * (b / 10)).to_float());
|
||||
if (e < 0.0001f) e = 0.0001f;
|
||||
if (e > 1.0f) e = 1.0f;
|
||||
|
||||
auto f = 1.0f - e;
|
||||
if (f < 0.0001f) f = 0.0001f;
|
||||
|
||||
auto g = 2.0f - (unk_value.to_float() * e * 2);
|
||||
|
||||
auto h_sq = g * g - f * f * 4;
|
||||
if (h_sq < 0.0f) h_sq = 0.0f;
|
||||
|
||||
auto h = std::sqrt(h_sq);
|
||||
|
||||
c = (g - h) / (f * 2.0f);
|
||||
d = 1.0f - c;
|
||||
}
|
||||
|
||||
state.hf_decay_prev_gain[i] = c;
|
||||
state.hf_decay_gain[i] = pow_10((b / 1000).to_float()) * d * 0.70709228515625f;
|
||||
state.hf_decay_prev_gain[i] = state.hf_decay_prev_gain[i] + (c - state.hf_decay_prev_gain[i]) / 4;
|
||||
state.hf_decay_gain[i] = state.hf_decay_gain[i] + (pow_10((b / 1000).to_float()) * d * 0.70709228515625f - state.hf_decay_gain[i]) / 4;
|
||||
|
||||
state.prev_feedback_output[i] = 0;
|
||||
}
|
||||
}
|
||||
@@ -191,6 +224,8 @@ static void InitializeReverbEffect(const ReverbInfo::ParameterVersion2& params,
|
||||
const auto center_delay_time{(5 * delay).to_uint_floor()};
|
||||
state.center_delay_line.Initialize(center_delay_time, 1.0f);
|
||||
|
||||
UpdateReverbEffectParameter(params, state);
|
||||
|
||||
for (u32 i = 0; i < ReverbInfo::MaxDelayLines; i++) {
|
||||
std::ranges::fill(state.fdn_delay_lines[i].buffer, 0);
|
||||
std::ranges::fill(state.decay_delay_lines[i].buffer, 0);
|
||||
|
||||
@@ -220,8 +220,8 @@ u64 SinkStream::GetExpectedPlayedSampleCount() {
|
||||
auto time_delta{cur_time - last_sample_count_update_time};
|
||||
auto exp_played_sample_count{min_played_sample_count + (TargetSampleRate * time_delta) / std::chrono::seconds{1}};
|
||||
|
||||
// Add 15ms of latency in sample reporting to allow for some leeway in scheduler timings
|
||||
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 3;
|
||||
// Add 25ms of latency in sample reporting to allow for some leeway in scheduler timings
|
||||
return std::min<u64>(exp_played_sample_count, max_played_sample_count) + TargetSampleCount * 5;
|
||||
}
|
||||
|
||||
void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
|
||||
@@ -231,9 +231,9 @@ void SinkStream::WaitFreeSpace(std::stop_token stop_token) {
|
||||
return paused || queued_buffers < max_queue_size;
|
||||
};
|
||||
|
||||
release_cv.wait_for(lk, std::chrono::milliseconds(10), can_continue);
|
||||
release_cv.wait_for(lk, std::chrono::milliseconds(7), can_continue);
|
||||
|
||||
if (queued_buffers > max_queue_size + 10) {
|
||||
if (queued_buffers > max_queue_size + 3) {
|
||||
release_cv.wait(lk, stop_token, can_continue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
// 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
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/backend.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
void assert_fail_impl() {
|
||||
#ifdef _MSC_VER
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
}
|
||||
#endif
|
||||
void AssertFailSoftImpl() {
|
||||
if (Settings::values.use_debug_asserts) {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
#ifndef _MSC_VER
|
||||
# if defined(ARCHITECTURE_x86_64)
|
||||
__asm__ __volatile__("int $3");
|
||||
# elif defined(ARCHITECTURE_arm64)
|
||||
__asm__ __volatile__("brk #0");
|
||||
# else
|
||||
exit(1);
|
||||
# endif
|
||||
#else // POSIX ^^^ _MSC_VER vvv
|
||||
DebugBreak();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
[[noreturn]] void unreachable_impl() {
|
||||
void AssertFatalImpl() {
|
||||
Common::Log::Stop();
|
||||
Crash();
|
||||
throw std::runtime_error("Unreachable code");
|
||||
std::abort();
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2013 Dolphin Emulator Project
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
@@ -10,8 +13,8 @@
|
||||
// However touching this file yields a global recompilation as this header is included almost
|
||||
// everywhere. So let's just move the handling of the failed assert to a single cpp file.
|
||||
|
||||
void assert_fail_impl();
|
||||
[[noreturn]] void unreachable_impl();
|
||||
void AssertFailSoftImpl();
|
||||
[[noreturn]] void AssertFatalImpl();
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define YUZU_NO_INLINE __declspec(noinline)
|
||||
@@ -22,29 +25,29 @@ void assert_fail_impl();
|
||||
#define ASSERT(_a_) \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
||||
assert_fail_impl(); \
|
||||
LOG_CRITICAL(Debug, "Assert"); \
|
||||
AssertFailSoftImpl(); \
|
||||
} \
|
||||
}())
|
||||
|
||||
#define ASSERT_MSG(_a_, ...) \
|
||||
([&]() YUZU_NO_INLINE { \
|
||||
if (!(_a_)) [[unlikely]] { \
|
||||
LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); \
|
||||
assert_fail_impl(); \
|
||||
LOG_CRITICAL(Debug, "Assert\n" __VA_ARGS__); \
|
||||
AssertFailSoftImpl(); \
|
||||
} \
|
||||
}())
|
||||
|
||||
#define UNREACHABLE() \
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable code!"); \
|
||||
unreachable_impl(); \
|
||||
LOG_CRITICAL(Debug, "Unreachable"); \
|
||||
AssertFatalImpl(); \
|
||||
} while (0)
|
||||
|
||||
#define UNREACHABLE_MSG(...) \
|
||||
do { \
|
||||
LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); \
|
||||
unreachable_impl(); \
|
||||
LOG_CRITICAL(Debug, "Unreachable\n" __VA_ARGS__); \
|
||||
AssertFatalImpl(); \
|
||||
} while (0)
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
@@ -32,27 +32,9 @@
|
||||
#define INSERT_PADDING_WORDS_NOINIT(num_words) \
|
||||
[[maybe_unused]] std::array<u32, num_words> CONCAT2(pad, __LINE__)
|
||||
|
||||
#ifndef _MSC_VER
|
||||
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
#define Crash() __asm__ __volatile__("int $3")
|
||||
#elif defined(ARCHITECTURE_arm64)
|
||||
#define Crash() __asm__ __volatile__("brk #0")
|
||||
#else
|
||||
#define Crash() exit(1)
|
||||
#endif
|
||||
|
||||
#else // _MSC_VER
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
|
||||
extern "C" {
|
||||
__declspec(dllimport) void __stdcall DebugBreak(void);
|
||||
}
|
||||
#define Crash() DebugBreak()
|
||||
|
||||
#endif // _MSC_VER ndef
|
||||
#ifdef _MSC_VER
|
||||
# define locale_t _locale_t // Locale Cross-Compatibility
|
||||
#endif // _MSC_VER
|
||||
|
||||
#define DECLARE_ENUM_FLAG_OPERATORS(type) \
|
||||
[[nodiscard]] constexpr type operator|(type a, type b) noexcept { \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,24 +15,4 @@ namespace Common {
|
||||
template <typename T>
|
||||
concept IsContiguousContainer = std::contiguous_iterator<typename T::iterator>;
|
||||
|
||||
// TODO: Replace with std::derived_from when the <concepts> header
|
||||
// is available on all supported platforms.
|
||||
template <typename Derived, typename Base>
|
||||
concept DerivedFrom = requires {
|
||||
std::is_base_of_v<Base, Derived>;
|
||||
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
};
|
||||
|
||||
// TODO: Replace with std::convertible_to when libc++ implements it.
|
||||
template <typename From, typename To>
|
||||
concept ConvertibleTo = std::is_convertible_v<From, To>;
|
||||
|
||||
// No equivalents in the stdlib
|
||||
|
||||
template <typename T>
|
||||
concept IsArithmetic = std::is_arithmetic_v<T>;
|
||||
|
||||
template <typename T>
|
||||
concept IsIntegral = std::is_integral_v<T>;
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2015 Evan Teran
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
@@ -16,6 +19,10 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
// No equivalent for "std::arithmetic" in the stdlib
|
||||
template <typename T>
|
||||
concept IsArithmetic = std::is_arithmetic_v<T>;
|
||||
|
||||
template <size_t I, size_t F>
|
||||
class FixedPoint;
|
||||
|
||||
@@ -392,13 +399,13 @@ public: // binary math operators, effects underlying bit pattern since these
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <IsIntegral Integer>
|
||||
template <std::integral Integer>
|
||||
constexpr FixedPoint& operator>>=(Integer n) {
|
||||
data_ >>= n;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <IsIntegral Integer>
|
||||
template <std::integral Integer>
|
||||
constexpr FixedPoint& operator<<=(Integer n) {
|
||||
data_ <<= n;
|
||||
return *this;
|
||||
@@ -587,12 +594,12 @@ constexpr FixedPoint<I, F> operator/(Number lhs, FixedPoint<I, F> rhs) {
|
||||
}
|
||||
|
||||
// shift operators
|
||||
template <size_t I, size_t F, IsIntegral Integer>
|
||||
template <size_t I, size_t F, std::integral Integer>
|
||||
constexpr FixedPoint<I, F> operator<<(FixedPoint<I, F> lhs, Integer rhs) {
|
||||
lhs <<= rhs;
|
||||
return lhs;
|
||||
}
|
||||
template <size_t I, size_t F, IsIntegral Integer>
|
||||
template <size_t I, size_t F, std::integral Integer>
|
||||
constexpr FixedPoint<I, F> operator>>(FixedPoint<I, F> lhs, Integer rhs) {
|
||||
lhs >>= rhs;
|
||||
return lhs;
|
||||
|
||||
@@ -521,14 +521,29 @@ public:
|
||||
#else
|
||||
fd = memfd_create("HostMemory", 0);
|
||||
#endif
|
||||
ASSERT_MSG(fd >= 0, "memfd_create failed: {}", strerror(errno));
|
||||
|
||||
// Defined to extend the file with zeros
|
||||
int ret = ftruncate(fd, backing_size);
|
||||
ASSERT_MSG(ret == 0, "ftruncate failed with {}, are you out-of-memory?", strerror(errno));
|
||||
|
||||
backing_base = static_cast<u8*>(
|
||||
mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
bool use_anon = false;
|
||||
if (fd <= 0) {
|
||||
LOG_WARNING(Common_Memory, "memfd_create: {}", strerror(errno));
|
||||
use_anon = true;
|
||||
}
|
||||
if (!use_anon) {
|
||||
// Defined to extend the file with zeros
|
||||
int ret = ftruncate(fd, backing_size);
|
||||
if (ret != 0) {
|
||||
LOG_WARNING(Common_Memory, "ftruncate: {} (likely out-of-emory)", strerror(errno));
|
||||
use_anon = true;
|
||||
}
|
||||
}
|
||||
if (use_anon) {
|
||||
LOG_WARNING(Common_Memory, "Using private mappings instead of shared ones");
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
|
||||
if (fd > 0) {
|
||||
fd = -1;
|
||||
close(fd);
|
||||
}
|
||||
} else {
|
||||
backing_base = static_cast<u8*>(mmap(nullptr, backing_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
|
||||
}
|
||||
ASSERT_MSG(backing_base != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||
|
||||
// Virtual memory initialization
|
||||
@@ -552,22 +567,18 @@ public:
|
||||
free_manager.AllocateBlock(virtual_base + virtual_offset, length);
|
||||
|
||||
// Deduce mapping protection flags.
|
||||
int flags = PROT_NONE;
|
||||
if (True(perms & MemoryPermission::Read)) {
|
||||
flags |= PROT_READ;
|
||||
}
|
||||
if (True(perms & MemoryPermission::Write)) {
|
||||
flags |= PROT_WRITE;
|
||||
}
|
||||
int prot_flags = PROT_NONE;
|
||||
if (True(perms & MemoryPermission::Read))
|
||||
prot_flags |= PROT_READ;
|
||||
if (True(perms & MemoryPermission::Write))
|
||||
prot_flags |= PROT_WRITE;
|
||||
#ifdef ARCHITECTURE_arm64
|
||||
if (True(perms & MemoryPermission::Execute)) {
|
||||
flags |= PROT_EXEC;
|
||||
}
|
||||
if (True(perms & MemoryPermission::Execute))
|
||||
prot_flags |= PROT_EXEC;
|
||||
#endif
|
||||
|
||||
void* ret = mmap(virtual_base + virtual_offset, length, flags, MAP_SHARED | MAP_FIXED, fd,
|
||||
host_offset);
|
||||
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
|
||||
int flags = (fd > 0 ? MAP_SHARED : MAP_PRIVATE) | MAP_FIXED;
|
||||
void* ret = mmap(virtual_base + virtual_offset, length, prot_flags, flags, fd, host_offset);
|
||||
ASSERT_MSG(ret != MAP_FAILED, "mmap: {}", strerror(errno));
|
||||
}
|
||||
|
||||
void Unmap(size_t virtual_offset, size_t length) {
|
||||
|
||||
@@ -169,7 +169,7 @@ bool IsFastmemEnabled() {
|
||||
if (values.cpu_accuracy.GetValue() == CpuAccuracy::Unsafe) {
|
||||
return bool(values.cpuopt_unsafe_host_mmu);
|
||||
}
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
|
||||
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__ANDROID__) && !defined(_WIN32)
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
|
||||
@@ -240,7 +240,7 @@ struct Values {
|
||||
Category::Cpu};
|
||||
SwitchableSetting<CpuAccuracy, true> cpu_accuracy{linkage, CpuAccuracy::Auto,
|
||||
"cpu_accuracy", Category::Cpu};
|
||||
|
||||
SwitchableSetting<bool> vtable_bouncing{linkage, true, "vtable_bouncing", Category::Cpu};
|
||||
SwitchableSetting<bool> use_fast_cpu_time{linkage,
|
||||
false,
|
||||
"use_fast_cpu_time",
|
||||
@@ -296,7 +296,7 @@ struct Values {
|
||||
Category::CpuDebug};
|
||||
|
||||
SwitchableSetting<bool> cpuopt_unsafe_host_mmu{linkage,
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
|
||||
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__ANDROID__) && !defined(_WIN32)
|
||||
false,
|
||||
#else
|
||||
true,
|
||||
|
||||
@@ -81,7 +81,10 @@ void SetCurrentThreadPriority(ThreadPriority new_priority) {
|
||||
|
||||
// Sets the debugger-visible name of the current thread.
|
||||
void SetCurrentThreadName(const char* name) {
|
||||
SetThreadDescription(GetCurrentThread(), UTF8ToUTF16W(name).data());
|
||||
if (auto pf = (decltype(&SetThreadDescription))(void*)GetProcAddress(GetModuleHandle(TEXT("KernelBase.dll")), "SetThreadDescription"); pf)
|
||||
pf(GetCurrentThread(), UTF8ToUTF16W(name).data()); // Windows 10+
|
||||
else
|
||||
; // No-op
|
||||
}
|
||||
|
||||
#else // !MSVC_VER, so must be POSIX threads
|
||||
@@ -109,7 +112,7 @@ void SetCurrentThreadName(const char* name) {
|
||||
buf[len] = '\0';
|
||||
pthread_setname_np(pthread_self(), buf);
|
||||
}
|
||||
#elif !defined(_WIN32) || defined(_MSC_VER)
|
||||
#elif defined(_WIN32)
|
||||
// mingw stub
|
||||
(void)name;
|
||||
#else
|
||||
|
||||
@@ -14,11 +14,33 @@ namespace Core {
|
||||
void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
|
||||
Kernel::Svc::ThreadContext ctx;
|
||||
this->GetContext(ctx);
|
||||
LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", ctx.sp, ctx.pc);
|
||||
LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", "Offset", "Symbol");
|
||||
|
||||
std::array<u64, 32> xreg{
|
||||
ctx.r[0], ctx.r[1], ctx.r[2], ctx.r[3],
|
||||
ctx.r[4], ctx.r[5], ctx.r[6], ctx.r[7],
|
||||
ctx.r[8], ctx.r[9], ctx.r[10], ctx.r[11],
|
||||
ctx.r[12], ctx.r[13], ctx.r[14], ctx.r[15],
|
||||
ctx.r[16], ctx.r[17], ctx.r[18], ctx.r[19],
|
||||
ctx.r[20], ctx.r[21], ctx.r[22], ctx.r[23],
|
||||
ctx.r[24], ctx.r[25], ctx.r[26], ctx.r[27],
|
||||
ctx.r[28], ctx.fp, ctx.lr, ctx.sp,
|
||||
};
|
||||
|
||||
std::string msg = fmt::format("Backtrace @ PC={:016X}\n", ctx.pc);
|
||||
for (size_t i = 0; i < 32; i += 4)
|
||||
msg += fmt::format("R{:02}={:016X} R{:02}={:016X} R{:02}={:016X} R{:02}={:016X}\n",
|
||||
i + 0, xreg[i + 0], i + 1, xreg[i + 1],
|
||||
i + 2, xreg[i + 2], i + 3, xreg[i + 3]);
|
||||
for (size_t i = 0; i < 32; i += 2)
|
||||
msg += fmt::format("V{:02}={:016X}_{:016X} V{:02}={:016X}_{:016X}\n",
|
||||
i + 0, ctx.v[i + 0][0], ctx.v[i + 0][1],
|
||||
i + 1, ctx.v[i + 1][0], ctx.v[i + 1][1]);
|
||||
msg += fmt::format("PSTATE={:08X} FPCR={:08X} FPSR={:08X} TPIDR={:016X}\n", ctx.pstate, ctx.fpcr, ctx.fpsr, ctx.tpidr);
|
||||
msg += fmt::format("{:20}{:20}{:20}{:20}{}\n", "Module", "Address", "Original Address", "Offset", "Symbol");
|
||||
auto const backtrace = GetBacktraceFromContext(process, ctx);
|
||||
for (auto const& entry : backtrace)
|
||||
LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, entry.original_address, entry.offset, entry.name);
|
||||
msg += fmt::format("{:20}{:016X} {:016X} {:016X} {}\n", entry.module, entry.address, entry.original_address, entry.offset, entry.name);
|
||||
LOG_ERROR(Core_ARM, "{}", msg);
|
||||
}
|
||||
|
||||
const Kernel::DebugWatchpoint* ArmInterface::MatchingWatchpoint(
|
||||
|
||||
@@ -292,7 +292,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__)
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__) || defined(__DragonFly__)
|
||||
config.fastmem_pointer = std::nullopt;
|
||||
config.fastmem_exclusive_access = false;
|
||||
#endif
|
||||
|
||||
@@ -351,7 +351,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ArmDynarmic64::MakeJit(Common::PageTable* pa
|
||||
// Safe optimisations
|
||||
case Settings::CpuAccuracy::Auto:
|
||||
config.unsafe_optimizations = true;
|
||||
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__sun__) || defined(__HAIKU__)
|
||||
#if !defined(__APPLE__) && !defined(__linux__) && !defined(__ANDROID__) && !defined(_WIN32)
|
||||
config.fastmem_pointer = std::nullopt;
|
||||
config.fastmem_exclusive_access = false;
|
||||
#endif
|
||||
|
||||
@@ -388,14 +388,6 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
|
||||
const std::size_t CACHE_PAGE_SIZE = 4096;
|
||||
|
||||
void ArmNce::ClearInstructionCache() {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
void* start = (void*)((uintptr_t)__builtin_return_address(0) & ~(CACHE_PAGE_SIZE - 1));
|
||||
void* end =
|
||||
(void*)((uintptr_t)start + CACHE_PAGE_SIZE * 2); // Clear two pages for better coverage
|
||||
// Prefetch next likely pages
|
||||
__builtin_prefetch((void*)((uintptr_t)end), 1, 3);
|
||||
__builtin___clear_cache(static_cast<char*>(start), static_cast<char*>(end));
|
||||
#endif
|
||||
#ifdef __aarch64__
|
||||
// Ensure all previous memory operations complete
|
||||
asm volatile("dmb ish" ::: "memory");
|
||||
@@ -405,20 +397,6 @@ void ArmNce::ClearInstructionCache() {
|
||||
}
|
||||
|
||||
void ArmNce::InvalidateCacheRange(u64 addr, std::size_t size) {
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// Align the start address to cache line boundary for better performance
|
||||
const size_t CACHE_LINE_SIZE = 64;
|
||||
addr &= ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
// Round up size to nearest cache line
|
||||
size = (size + CACHE_LINE_SIZE - 1) & ~(CACHE_LINE_SIZE - 1);
|
||||
|
||||
// Prefetch the range to be invalidated
|
||||
for (size_t offset = 0; offset < size; offset += CACHE_LINE_SIZE) {
|
||||
__builtin_prefetch((void*)(addr + offset), 1, 3);
|
||||
}
|
||||
#endif
|
||||
|
||||
this->ClearInstructionCache();
|
||||
}
|
||||
|
||||
|
||||
@@ -181,14 +181,6 @@ bool InterpreterVisitor::Ordered(size_t size, bool L, bool o0, Reg Rn, Reg Rt) {
|
||||
const size_t dbytes = datasize / 8;
|
||||
|
||||
u64 address = (Rn == Reg::SP) ? this->GetSp() : this->GetReg(Rn);
|
||||
|
||||
// Conservative prefetch for atomic ops
|
||||
if (memop == MemOp::Load) {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address), 0, 1);
|
||||
} else {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address), 1, 1);
|
||||
}
|
||||
|
||||
switch (memop) {
|
||||
case MemOp::Store: {
|
||||
std::atomic_thread_fence(std::memory_order_seq_cst);
|
||||
@@ -435,21 +427,6 @@ bool InterpreterVisitor::RegisterImmediate(bool wback, bool postindex, size_t sc
|
||||
if (!postindex)
|
||||
address += offset;
|
||||
|
||||
// Optimized prefetch for loads
|
||||
if (memop == MemOp::Load) {
|
||||
const size_t access_size = datasize / 8;
|
||||
const bool is_aligned = (address % access_size) == 0;
|
||||
|
||||
if (is_aligned) {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address), 0, 3);
|
||||
if (access_size >= 8 && access_size <= 32) {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address + PREFETCH_STRIDE), 0, 3);
|
||||
}
|
||||
} else {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address), 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
switch (memop) {
|
||||
case MemOp::Store: {
|
||||
u64 data = this->GetReg(Rt);
|
||||
@@ -516,15 +493,6 @@ bool InterpreterVisitor::SIMDImmediate(bool wback, bool postindex, size_t scale,
|
||||
if (!postindex)
|
||||
address += offset;
|
||||
|
||||
// Aggressive prefetch for SIMD
|
||||
if (memop == MemOp::Load) {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address), 0, 3);
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address + CACHE_LINE_SIZE), 0, 3);
|
||||
if (datasize >= SIMD_PREFETCH_THRESHOLD) {
|
||||
__builtin_prefetch(reinterpret_cast<const void*>(address + PREFETCH_STRIDE), 0, 3);
|
||||
}
|
||||
}
|
||||
|
||||
switch (memop) {
|
||||
case MemOp::Store: {
|
||||
u128 data = VectorGetElement(this->GetVec(Vt), datasize);
|
||||
|
||||
@@ -63,12 +63,10 @@ constexpr bool IsInvalidCharacter(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharacters, std::size(InvalidCharacters)>(c);
|
||||
}
|
||||
constexpr bool IsInvalidCharacterForHostName(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName,
|
||||
std::size(InvalidCharactersForHostName)>(c);
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForHostName, std::size(InvalidCharactersForHostName)>(c);
|
||||
}
|
||||
constexpr bool IsInvalidCharacterForMountName(char c) {
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName,
|
||||
std::size(InvalidCharactersForMountName)>(c);
|
||||
return impl::IsInvalidCharacterImpl<InvalidCharactersForMountName, std::size(InvalidCharactersForMountName)>(c);
|
||||
}
|
||||
|
||||
} // namespace StringTraits
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/concepts.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -24,7 +23,7 @@ class KThread;
|
||||
template <typename T>
|
||||
concept KPriorityQueueAffinityMask = !
|
||||
std::is_reference_v<T>&& requires(T& t) {
|
||||
{ t.GetAffinityMask() } -> Common::ConvertibleTo<u64>;
|
||||
{ t.GetAffinityMask() } -> std::convertible_to<u64>;
|
||||
{ t.SetAffinityMask(0) };
|
||||
|
||||
{ t.GetAffinity(0) } -> std::same_as<bool>;
|
||||
@@ -50,9 +49,9 @@ std::is_reference_v<T>&& requires(T& t) {
|
||||
std::remove_cvref_t<decltype(t.GetAffinityMask())>()
|
||||
} -> KPriorityQueueAffinityMask;
|
||||
|
||||
{ t.GetActiveCore() } -> Common::ConvertibleTo<s32>;
|
||||
{ t.GetPriority() } -> Common::ConvertibleTo<s32>;
|
||||
{ t.IsDummyThread() } -> Common::ConvertibleTo<bool>;
|
||||
{ t.GetActiveCore() } -> std::convertible_to<s32>;
|
||||
{ t.GetPriority() } -> std::convertible_to<s32>;
|
||||
{ t.IsDummyThread() } -> std::convertible_to<bool>;
|
||||
};
|
||||
|
||||
template <typename Member, size_t NumCores_, int LowestPriority, int HighestPriority>
|
||||
|
||||
@@ -28,9 +28,6 @@ namespace Kernel {
|
||||
|
||||
namespace {
|
||||
|
||||
// TODO: Remove this workaround when proper ASLR is implemented for all address spaces.
|
||||
constexpr u64 CodeStartOffset = 0x500000UL;
|
||||
|
||||
Result TerminateChildren(KernelCore& kernel, KProcess* process,
|
||||
const KThread* thread_to_not_terminate) {
|
||||
// Request that all children threads terminate.
|
||||
@@ -1157,7 +1154,7 @@ KProcess::KProcess(KernelCore& kernel)
|
||||
KProcess::~KProcess() = default;
|
||||
|
||||
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||
KProcessAddress aslr_space_start, bool is_hbl) {
|
||||
KProcessAddress aslr_space_start, size_t aslr_space_offset, bool is_hbl) {
|
||||
// Create a resource limit for the process.
|
||||
const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
|
||||
const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
|
||||
@@ -1187,25 +1184,24 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||
// Set the address space type and code address.
|
||||
switch (metadata.GetAddressSpaceType()) {
|
||||
case FileSys::ProgramAddressSpaceType::Is39Bit:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace64Bit;
|
||||
|
||||
// For 39-bit processes, the ASLR region starts at 0x800'0000 and is ~512GiB large.
|
||||
// However, some (buggy) programs/libraries like skyline incorrectly depend on the
|
||||
// existence of ASLR pages before the entry point, so we will adjust the load address
|
||||
// to point to about 2GiB into the ASLR region.
|
||||
code_address = 0x8000'0000;
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace64Bit;
|
||||
code_address = 0x8000'0000 + aslr_space_offset;
|
||||
break;
|
||||
case FileSys::ProgramAddressSpaceType::Is36Bit:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace64BitDeprecated;
|
||||
code_address = 0x800'0000;
|
||||
code_address = 0x800'0000 + aslr_space_offset;
|
||||
break;
|
||||
case FileSys::ProgramAddressSpaceType::Is32Bit:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace32Bit;
|
||||
code_address = 0x20'0000 + CodeStartOffset;
|
||||
code_address = 0x20'0000 + aslr_space_offset;
|
||||
break;
|
||||
case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
|
||||
flag |= Svc::CreateProcessFlag::AddressSpace32BitWithoutAlias;
|
||||
code_address = 0x20'0000 + CodeStartOffset;
|
||||
code_address = 0x20'0000 + aslr_space_offset;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
@@ -511,7 +511,7 @@ public:
|
||||
|
||||
public:
|
||||
Result LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
|
||||
KProcessAddress aslr_space_start, bool is_hbl);
|
||||
KProcessAddress aslr_space_start, size_t aslr_space_offset, bool is_hbl);
|
||||
|
||||
void LoadModule(CodeSet code_set, KProcessAddress base_addr);
|
||||
|
||||
|
||||
@@ -103,12 +103,26 @@ void PhysicalCore::RunThread(Kernel::KThread* thread) {
|
||||
const bool data_abort = True(hr & Core::HaltReason::DataAbort);
|
||||
const bool interrupt = True(hr & Core::HaltReason::BreakLoop);
|
||||
|
||||
bool may_abort = true; // Ignore aborting virtual functions (for debugging)
|
||||
if (prefetch_abort && ::Settings::values.vtable_bouncing) {
|
||||
auto& lock = m_kernel.GlobalSchedulerContext().SchedulerLock();
|
||||
lock.Lock();
|
||||
Kernel::Svc::ThreadContext ctx;
|
||||
interface->GetContext(ctx);
|
||||
LOG_WARNING(Core_ARM, "vtable bouncing {:016X}", ctx.lr);
|
||||
ctx.pc = ctx.lr;
|
||||
ctx.r[0] = 0;
|
||||
interface->SetContext(ctx);
|
||||
lock.Unlock();
|
||||
may_abort = false;
|
||||
}
|
||||
|
||||
// Since scheduling may occur here, we cannot use any cached
|
||||
// state after returning from calls we make.
|
||||
|
||||
// Notify the debugger and go to sleep if a breakpoint was hit,
|
||||
// or if the thread is unable to continue for any reason.
|
||||
if (breakpoint || prefetch_abort) {
|
||||
if (breakpoint || (prefetch_abort && may_abort)) {
|
||||
if (breakpoint) {
|
||||
interface->RewindBreakpointInstruction();
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,10 @@
|
||||
// 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-2.0-or-later
|
||||
// SPDX-License-Identifier: GPL-2.0-or-late
|
||||
|
||||
// This file is automatically generated using svc_generator.py.
|
||||
// DO NOT MODIFY IT MANUALLY
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -16,8 +19,6 @@ class System;
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel::Svc {
|
||||
|
||||
// clang-format off
|
||||
Result SetHeapSize(Core::System& system, uint64_t* out_address, uint64_t size);
|
||||
Result SetMemoryPermission(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
|
||||
Result SetMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
|
||||
@@ -506,8 +507,6 @@ enum class SvcId : u32 {
|
||||
MapInsecureMemory = 0x90,
|
||||
UnmapInsecureMemory = 0x91,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Custom ABI.
|
||||
Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
|
||||
Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -30,8 +33,8 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Ap
|
||||
{8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"},
|
||||
{9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"},
|
||||
{10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"},
|
||||
{11, nullptr, "ReleaseSleepLock"},
|
||||
{12, nullptr, "ReleaseSleepLockTransiently"},
|
||||
{11, D<&ICommonStateGetter::ReleaseSleepLock>, "ReleaseSleepLock"},
|
||||
{12, D<&ICommonStateGetter::ReleaseSleepLockTransiently>, "ReleaseSleepLockTransiently"},
|
||||
{13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
|
||||
{14, nullptr, "GetWakeupCount"},
|
||||
{20, nullptr, "PushToGeneralChannel"},
|
||||
@@ -112,6 +115,20 @@ Result ICommonStateGetter::RequestToAcquireSleepLock() {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::ReleaseSleepLock() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
m_applet->sleep_lock_event.Clear();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::ReleaseSleepLockTransiently() {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
m_applet->sleep_lock_event.Clear();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICommonStateGetter::GetAcquiredSleepLockEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_WARNING(Service_AM, "called");
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -29,6 +32,8 @@ private:
|
||||
Result ReceiveMessage(Out<AppletMessage> out_applet_message);
|
||||
Result GetCurrentFocusState(Out<FocusState> out_focus_state);
|
||||
Result RequestToAcquireSleepLock();
|
||||
Result ReleaseSleepLock();
|
||||
Result ReleaseSleepLockTransiently();
|
||||
Result GetAcquiredSleepLockEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetReaderLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor,
|
||||
u32 button_type);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,8 +11,8 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <concepts>
|
||||
|
||||
#include "common/concepts.h"
|
||||
#include "core/hle/kernel/k_port.h"
|
||||
#include "core/hle/kernel/svc.h"
|
||||
#include "core/hle/result.h"
|
||||
@@ -63,7 +66,7 @@ public:
|
||||
Result UnregisterService(const std::string& name);
|
||||
Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
|
||||
|
||||
template <Common::DerivedFrom<SessionRequestHandler> T>
|
||||
template <std::derived_from<SessionRequestHandler> T>
|
||||
std::shared_ptr<T> GetService(const std::string& service_name, bool block = false) const {
|
||||
auto service = registered_services.find(service_name);
|
||||
if (service == registered_services.end() && !block) {
|
||||
|
||||
@@ -19,6 +19,10 @@
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/internal_network/sockets.h"
|
||||
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
#include <openssl/cert.h>
|
||||
#endif
|
||||
|
||||
using namespace Common::FS;
|
||||
|
||||
namespace Service::SSL {
|
||||
@@ -41,11 +45,85 @@ void OneTimeInit();
|
||||
void OneTimeInitLogFile();
|
||||
bool OneTimeInitBIO();
|
||||
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
// This is ported from httplib
|
||||
struct scope_exit {
|
||||
explicit scope_exit(std::function<void(void)> &&f)
|
||||
: exit_function(std::move(f)), execute_on_destruction{true} {}
|
||||
|
||||
scope_exit(scope_exit &&rhs) noexcept
|
||||
: exit_function(std::move(rhs.exit_function)),
|
||||
execute_on_destruction{rhs.execute_on_destruction} {
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
~scope_exit() {
|
||||
if (execute_on_destruction) { this->exit_function(); }
|
||||
}
|
||||
|
||||
void release() { this->execute_on_destruction = false; }
|
||||
|
||||
private:
|
||||
scope_exit(const scope_exit &) = delete;
|
||||
void operator=(const scope_exit &) = delete;
|
||||
scope_exit &operator=(scope_exit &&) = delete;
|
||||
|
||||
std::function<void(void)> exit_function;
|
||||
bool execute_on_destruction;
|
||||
};
|
||||
|
||||
inline X509_STORE *CreateCaCertStore(const char *ca_cert,
|
||||
std::size_t size) {
|
||||
auto mem = BIO_new_mem_buf(ca_cert, static_cast<int>(size));
|
||||
auto se = scope_exit([&] { BIO_free_all(mem); });
|
||||
if (!mem) { return nullptr; }
|
||||
|
||||
auto inf = PEM_X509_INFO_read_bio(mem, nullptr, nullptr, nullptr);
|
||||
if (!inf) { return nullptr; }
|
||||
|
||||
auto cts = X509_STORE_new();
|
||||
if (cts) {
|
||||
for (auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
|
||||
auto itmp = sk_X509_INFO_value(inf, i);
|
||||
if (!itmp) { continue; }
|
||||
|
||||
if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
|
||||
if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
|
||||
}
|
||||
}
|
||||
|
||||
sk_X509_INFO_pop_free(inf, X509_INFO_free);
|
||||
return cts;
|
||||
}
|
||||
|
||||
inline void SetCaCertStore(SSL_CTX *ctx, X509_STORE *ca_cert_store) {
|
||||
if (ca_cert_store) {
|
||||
if (ctx) {
|
||||
if (SSL_CTX_get_cert_store(ctx) != ca_cert_store) {
|
||||
// Free memory allocated for old cert and use new store `ca_cert_store`
|
||||
SSL_CTX_set_cert_store(ctx, ca_cert_store);
|
||||
}
|
||||
} else {
|
||||
X509_STORE_free(ca_cert_store);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void LoadCaCertStore(SSL_CTX* ctx, const char* ca_cert, std::size_t size)
|
||||
{
|
||||
SetCaCertStore(ctx, CreateCaCertStore(ca_cert, size));
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace
|
||||
|
||||
class SSLConnectionBackendOpenSSL final : public SSLConnectionBackend {
|
||||
public:
|
||||
Result Init() {
|
||||
// on bundled OpenSSL, load ca cert store
|
||||
#ifdef YUZU_BUNDLED_OPENSSL
|
||||
LoadCaCertStore(ssl_ctx, kCert, sizeof(kCert));
|
||||
#endif
|
||||
std::call_once(one_time_init_flag, OneTimeInit);
|
||||
|
||||
if (!one_time_init_success) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -223,8 +226,13 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
// Add patch size to the total module size
|
||||
code_size += patch_ctx.GetTotalPatchSize();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, is_hbl).IsError()) {
|
||||
if (process.LoadFromMetadata(metadata, code_size, fastmem_base, aslr_offset, is_hbl).IsError()) {
|
||||
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstring>
|
||||
#include "common/settings.h"
|
||||
#include "core/file_sys/kernel_executable.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/code_set.h"
|
||||
@@ -76,11 +77,10 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
Kernel::CodeSet codeset;
|
||||
Kernel::PhysicalMemory program_image;
|
||||
|
||||
const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment,
|
||||
const std::vector<u8>& data, u32 offset) {
|
||||
const auto load_segment = [&program_image](Kernel::CodeSet::Segment& segment, const std::vector<u8>& data, u32 offset) {
|
||||
segment.addr = offset;
|
||||
segment.offset = offset;
|
||||
segment.size = PageAlignSize(static_cast<u32>(data.size()));
|
||||
segment.size = PageAlignSize(u32(data.size()));
|
||||
program_image.resize(offset + data.size());
|
||||
std::memcpy(program_image.data() + offset, data.data(), data.size());
|
||||
};
|
||||
@@ -92,10 +92,14 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
|
||||
program_image.resize(PageAlignSize(kip->GetBSSOffset()) + kip->GetBSSSize());
|
||||
codeset.DataSegment().size += kip->GetBSSSize();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), 0,
|
||||
false)
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), 0, aslr_offset, false)
|
||||
.IsError()) {
|
||||
return {ResultStatus::ErrorNotInitialized, {}};
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <concepts>
|
||||
#include "common/concepts.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -27,7 +28,7 @@ namespace Loader {
|
||||
|
||||
namespace {
|
||||
|
||||
template <Common::DerivedFrom<AppLoader> T>
|
||||
template <std::derived_from<AppLoader> T>
|
||||
std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
|
||||
const auto file_type = T::IdentifyType(file);
|
||||
if (file_type != FileType::Error) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -237,10 +240,14 @@ static bool LoadNroImpl(Core::System& system, Kernel::KProcess& process,
|
||||
return 0;
|
||||
}();
|
||||
|
||||
// TODO: this is bad form of ASLR, it sucks
|
||||
size_t aslr_offset = ((::Settings::values.rng_seed_enabled.GetValue()
|
||||
? ::Settings::values.rng_seed.GetValue()
|
||||
: std::rand()) * 0x734287f27) & 0xfff000;
|
||||
|
||||
// Setup the process code layout
|
||||
if (process
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base,
|
||||
false)
|
||||
.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), image_size, fastmem_base, aslr_offset, false)
|
||||
.IsError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ endif()
|
||||
list(APPEND CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/CMakeModules")
|
||||
|
||||
# Arch detection
|
||||
include(DetectArchitecture)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
message(FATAL_ERROR "Unsupported architecture encountered. Ending CMake generation.")
|
||||
endif()
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(DYNARMIC_MULTIARCH_BUILD 1)
|
||||
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
function(detect_architecture symbol arch)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
set(CMAKE_REQUIRED_QUIET YES)
|
||||
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
|
||||
unset(CMAKE_REQUIRED_QUIET)
|
||||
|
||||
if (DETECT_ARCHITECTURE_${arch})
|
||||
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
unset(DETECT_ARCHITECTURE_${arch} CACHE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
detect_architecture("__ARM64__" arm64)
|
||||
detect_architecture("__aarch64__" arm64)
|
||||
detect_architecture("_M_ARM64" arm64)
|
||||
|
||||
detect_architecture("__arm__" arm)
|
||||
detect_architecture("__TARGET_ARCH_ARM" arm)
|
||||
detect_architecture("_M_ARM" arm)
|
||||
|
||||
detect_architecture("__x86_64" x86_64)
|
||||
detect_architecture("__x86_64__" x86_64)
|
||||
detect_architecture("__amd64" x86_64)
|
||||
detect_architecture("_M_X64" x86_64)
|
||||
|
||||
detect_architecture("__i386" x86)
|
||||
detect_architecture("__i386__" x86)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
|
||||
detect_architecture("__ia64" ia64)
|
||||
detect_architecture("__ia64__" ia64)
|
||||
detect_architecture("_M_IA64" ia64)
|
||||
|
||||
detect_architecture("__mips" mips)
|
||||
detect_architecture("__mips__" mips)
|
||||
detect_architecture("_M_MRX000" mips)
|
||||
|
||||
detect_architecture("__ppc64__" ppc64)
|
||||
detect_architecture("__powerpc64__" ppc64)
|
||||
|
||||
detect_architecture("__ppc__" ppc)
|
||||
detect_architecture("__ppc" ppc)
|
||||
detect_architecture("__powerpc__" ppc)
|
||||
detect_architecture("_ARCH_COM" ppc)
|
||||
detect_architecture("_ARCH_PWR" ppc)
|
||||
detect_architecture("_ARCH_PPC" ppc)
|
||||
detect_architecture("_M_MPPC" ppc)
|
||||
detect_architecture("_M_PPC" ppc)
|
||||
|
||||
detect_architecture("__riscv" riscv)
|
||||
|
||||
detect_architecture("__EMSCRIPTEN__" wasm)
|
||||
@@ -468,8 +468,9 @@ void EmitIR<IR::Opcode::FPRoundInt32>(oaknut::CodeGenerator& code, EmitContext&
|
||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
||||
code.FRINTA(Sresult, Soperand);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1668,8 +1668,9 @@ void EmitIR<IR::Opcode::VectorTableLookup64>(oaknut::CodeGenerator& code, EmitCo
|
||||
code.TBX(Dresult->B8(), oaknut::List{V0.B16(), V1.B16()}, Dindices->B8());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
@@ -1731,8 +1732,9 @@ void EmitIR<IR::Opcode::VectorTableLookup128>(oaknut::CodeGenerator& code, EmitC
|
||||
code.TBX(Qresult->B16(), oaknut::List{V0.B16(), V1.B16(), V2.B16(), V3.B16()}, Qindices->B16());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@@ -645,8 +645,9 @@ void EmitIR<IR::Opcode::FPVectorRoundInt32>(oaknut::CodeGenerator& code, EmitCon
|
||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
||||
code.FRINTA(Qresult->S4(), Qoperand->S4());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -684,8 +685,9 @@ void EmitIR<IR::Opcode::FPVectorRoundInt64>(oaknut::CodeGenerator& code, EmitCon
|
||||
case FP::RoundingMode::ToNearest_TieAwayFromZero:
|
||||
code.FRINTA(Qresult->D2(), Qoperand->D2());
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -371,8 +371,9 @@ void RAReg<T>::Realize() {
|
||||
case RWType::ReadWrite:
|
||||
reg = T{reg_alloc.RealizeReadWriteImpl<kind>(read_value, write_value)};
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::Backend::Arm64
|
||||
|
||||
@@ -188,15 +188,15 @@ private:
|
||||
ExceptionHandler::ExceptionHandler() = default;
|
||||
ExceptionHandler::~ExceptionHandler() = default;
|
||||
|
||||
#if defined(MCL_ARCHITECTURE_X86_64)
|
||||
#if defined(ARCHITECTURE_x86_64)
|
||||
void ExceptionHandler::Register(X64::BlockOfCode& code) {
|
||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(code.getCode()), code.GetTotalCodeSize());
|
||||
}
|
||||
#elif defined(MCL_ARCHITECTURE_ARM64)
|
||||
#elif defined(ARCHITECTURE_arm64)
|
||||
void ExceptionHandler::Register(oaknut::CodeBlock& mem, std::size_t size) {
|
||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr()), size);
|
||||
}
|
||||
#elif defined(MCL_ARCHITECTURE_RISCV)
|
||||
#elif defined(ARCHITECTURE_riscv64)
|
||||
void ExceptionHandler::Register(RV64::CodeBlock& mem, std::size_t size) {
|
||||
impl = std::make_unique<Impl>(std::bit_cast<u64>(mem.ptr<u64>()), size);
|
||||
}
|
||||
|
||||
@@ -36,22 +36,8 @@
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
|
||||
#define FCODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (fsize == 32) { \
|
||||
code.NAME##s(args...); \
|
||||
} else { \
|
||||
code.NAME##d(args...); \
|
||||
} \
|
||||
}
|
||||
#define ICODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (fsize == 32) { \
|
||||
code.NAME##d(args...); \
|
||||
} else { \
|
||||
code.NAME##q(args...); \
|
||||
} \
|
||||
}
|
||||
#define FCODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
|
||||
#define ICODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -36,22 +36,8 @@
|
||||
#include "dynarmic/ir/basic_block.h"
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
|
||||
#define FCODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (fsize == 32) { \
|
||||
code.NAME##s(args...); \
|
||||
} else { \
|
||||
code.NAME##d(args...); \
|
||||
} \
|
||||
}
|
||||
#define ICODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (fsize == 32) { \
|
||||
code.NAME##d(args...); \
|
||||
} else { \
|
||||
code.NAME##q(args...); \
|
||||
} \
|
||||
}
|
||||
#define FCODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
|
||||
#define ICODE(NAME) [&](auto... args) { if (fsize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -14,23 +14,8 @@
|
||||
#include "dynarmic/ir/microinstruction.h"
|
||||
#include "dynarmic/ir/opcodes.h"
|
||||
|
||||
#define FCODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (esize == 32) { \
|
||||
code.NAME##s(args...); \
|
||||
} else { \
|
||||
code.NAME##d(args...); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ICODE(NAME) \
|
||||
[&code](auto... args) { \
|
||||
if constexpr (esize == 32) { \
|
||||
code.NAME##d(args...); \
|
||||
} else { \
|
||||
code.NAME##q(args...); \
|
||||
} \
|
||||
}
|
||||
#define FCODE(NAME) [&](auto... args) { if (esize == 32) code.NAME##s(args...); else code.NAME##d(args...); }
|
||||
#define ICODE(NAME) [&](auto... args) { if (esize == 32) code.NAME##d(args...); else code.NAME##q(args...); }
|
||||
|
||||
namespace Dynarmic::Backend::X64 {
|
||||
|
||||
|
||||
@@ -72,6 +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)
|
||||
# else
|
||||
# error "Unknown platform"
|
||||
# endif
|
||||
|
||||
@@ -44,13 +44,13 @@ Block::iterator Block::PrependNewInst(iterator insertion_point, Opcode opcode, s
|
||||
// hugely benefit from the coherency of faster allocations...
|
||||
IR::Inst* inst;
|
||||
if (inlined_inst.size() < inlined_inst.max_size()) {
|
||||
inst = &inlined_inst[inlined_inst.size()];
|
||||
inlined_inst.emplace_back(opcode);
|
||||
inst = &inlined_inst[inlined_inst.size() - 1];
|
||||
} else {
|
||||
if (pooled_inst.empty() || pooled_inst.back().size() == pooled_inst.back().max_size())
|
||||
pooled_inst.emplace_back();
|
||||
inst = &pooled_inst.back()[pooled_inst.back().size()];
|
||||
pooled_inst.back().emplace_back(opcode);
|
||||
inst = &pooled_inst.back()[pooled_inst.back().size() - 1];
|
||||
}
|
||||
DEBUG_ASSERT(args.size() == inst->NumArgs());
|
||||
std::for_each(args.begin(), args.end(), [&inst, index = size_t(0)](const auto& arg) mutable {
|
||||
|
||||
@@ -654,3 +654,11 @@ constexpr bool MayGetNZCVFromOp(const Opcode op) noexcept {
|
||||
}
|
||||
|
||||
} // namespace Dynarmic::IR
|
||||
|
||||
template<>
|
||||
struct fmt::formatter<Dynarmic::IR::Opcode> : fmt::formatter<std::string_view> {
|
||||
template<typename FormatContext>
|
||||
auto format(Dynarmic::IR::Opcode op, FormatContext& ctx) const {
|
||||
return formatter<std::string_view>::format(GetNameOf(op), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,7 +29,6 @@ target_link_libraries(dynarmic_tests PRIVATE merry::oaknut)
|
||||
|
||||
if (DYNARMIC_TESTS_USE_UNICORN)
|
||||
target_link_libraries(dynarmic_tests PRIVATE Unicorn::Unicorn)
|
||||
|
||||
target_sources(dynarmic_tests PRIVATE
|
||||
fuzz_util.cpp
|
||||
fuzz_util.h
|
||||
|
||||
@@ -109,6 +109,10 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QObject* parent)
|
||||
"cause deadlocks. A range of 77-21000 is recommended."));
|
||||
INSERT(Settings, cpu_backend, tr("Backend:"), QString());
|
||||
|
||||
INSERT(Settings, vtable_bouncing,
|
||||
tr("Virtual Table Bouncing"),
|
||||
tr("Bounces (by emulating a 0-valued return) any functions that triggers a prefetch abort"));
|
||||
|
||||
// Cpu Debug
|
||||
|
||||
// Cpu Unsafe
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -313,6 +316,7 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, ScalarU32 a, ScalarU32 b);
|
||||
void EmitINeg32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value);
|
||||
void EmitINeg64(EmitContext& ctx, IR::Inst& inst, Register value);
|
||||
void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value);
|
||||
void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, ScalarS32 value);
|
||||
void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift);
|
||||
void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, ScalarRegister base, ScalarU32 shift);
|
||||
void EmitShiftRightLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -113,6 +116,10 @@ void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
|
||||
ctx.Add("ABS.S {},{};", inst, value);
|
||||
}
|
||||
|
||||
void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, ScalarS32 value) {
|
||||
ctx.Add("ABS.S64 {},{};", inst, value);
|
||||
}
|
||||
|
||||
void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, ScalarU32 base, ScalarU32 shift) {
|
||||
ctx.Add("SHL.U {}.x,{},{};", inst, base, shift);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -373,6 +376,7 @@ void EmitUDiv32(EmitContext& ctx, IR::Inst& inst, std::string_view a, std::strin
|
||||
void EmitINeg32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
|
||||
void EmitINeg64(EmitContext& ctx, IR::Inst& inst, std::string_view value);
|
||||
void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value);
|
||||
void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value);
|
||||
void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
|
||||
std::string_view shift);
|
||||
void EmitShiftLeftLogical64(EmitContext& ctx, IR::Inst& inst, std::string_view base,
|
||||
|
||||
@@ -98,6 +98,11 @@ void EmitIAbs32(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
|
||||
ctx.AddU32("{}=abs(int({}));", inst, value);
|
||||
}
|
||||
|
||||
void EmitIAbs64(EmitContext& ctx, IR::Inst& inst, std::string_view value) {
|
||||
// TODO: Uhm, are you sure? This may crash on some drivers!
|
||||
ctx.AddU32("{}=abs(int64_t({}));", inst, value);
|
||||
}
|
||||
|
||||
void EmitShiftLeftLogical32(EmitContext& ctx, IR::Inst& inst, std::string_view base,
|
||||
std::string_view shift) {
|
||||
ctx.AddU32("{}={}<<{};", inst, base, shift);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -293,6 +296,7 @@ Id EmitUDiv32(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitINeg32(EmitContext& ctx, Id value);
|
||||
Id EmitINeg64(EmitContext& ctx, Id value);
|
||||
Id EmitIAbs32(EmitContext& ctx, Id value);
|
||||
Id EmitIAbs64(EmitContext& ctx, Id value);
|
||||
Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift);
|
||||
Id EmitShiftLeftLogical64(EmitContext& ctx, Id base, Id shift);
|
||||
Id EmitShiftRightLogical32(EmitContext& ctx, Id base, Id shift);
|
||||
|
||||
@@ -94,6 +94,10 @@ Id EmitIAbs32(EmitContext& ctx, Id value) {
|
||||
return ctx.OpSAbs(ctx.U32[1], value);
|
||||
}
|
||||
|
||||
Id EmitIAbs64(EmitContext& ctx, Id value) {
|
||||
return ctx.OpSAbs(ctx.U64, value);
|
||||
}
|
||||
|
||||
Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) {
|
||||
return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift);
|
||||
}
|
||||
|
||||
@@ -1190,8 +1190,15 @@ U32U64 IREmitter::INeg(const U32U64& value) {
|
||||
}
|
||||
}
|
||||
|
||||
U32 IREmitter::IAbs(const U32& value) {
|
||||
return Inst<U32>(Opcode::IAbs32, value);
|
||||
U32U64 IREmitter::IAbs(const U32U64& value) {
|
||||
switch (value.Type()) {
|
||||
case Type::U32:
|
||||
return Inst<U32>(Opcode::IAbs32, value);
|
||||
case Type::U64:
|
||||
return Inst<U64>(Opcode::IAbs64, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
}
|
||||
|
||||
U32U64 IREmitter::ShiftLeftLogical(const U32U64& base, const U32& shift) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -218,7 +221,7 @@ public:
|
||||
[[nodiscard]] U32 IMul(const U32& a, const U32& b);
|
||||
[[nodiscard]] U32 IDiv(const U32& a, const U32& b, bool is_signed = false);
|
||||
[[nodiscard]] U32U64 INeg(const U32U64& value);
|
||||
[[nodiscard]] U32 IAbs(const U32& value);
|
||||
[[nodiscard]] U32U64 IAbs(const U32U64& value);
|
||||
[[nodiscard]] U32U64 ShiftLeftLogical(const U32U64& base, const U32& shift);
|
||||
[[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift);
|
||||
[[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift);
|
||||
|
||||
@@ -296,6 +296,7 @@ OPCODE(UDiv32, U32, U32,
|
||||
OPCODE(INeg32, U32, U32, )
|
||||
OPCODE(INeg64, U64, U64, )
|
||||
OPCODE(IAbs32, U32, U32, )
|
||||
OPCODE(IAbs64, U64, U64, )
|
||||
OPCODE(ShiftLeftLogical32, U32, U32, U32, )
|
||||
OPCODE(ShiftLeftLogical64, U64, U64, U32, )
|
||||
OPCODE(ShiftRightLogical32, U32, U32, U32, )
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <ranges>
|
||||
#include <string_view>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "shader_recompiler/exception.h"
|
||||
#include "shader_recompiler/frontend/maxwell/decode.h"
|
||||
@@ -45,7 +46,8 @@ Opcode Decode(u64 insn) {
|
||||
return Opcode::name;
|
||||
#include "maxwell.inc"
|
||||
#undef INST
|
||||
throw NotImplementedException("Invalid insn 0x{:016x}", insn);
|
||||
ASSERT_MSG(false, "Invalid insn 0x{:016x}", insn);
|
||||
return Opcode::NOP;
|
||||
}
|
||||
|
||||
} // namespace Shader::Maxwell
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,7 +32,7 @@ void TranslatorVisitor::MEMBAR(u64 inst) {
|
||||
}
|
||||
}
|
||||
|
||||
void TranslatorVisitor::DEPBAR() {
|
||||
void TranslatorVisitor::DEPBAR(u64) {
|
||||
// DEPBAR is a no-op
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -32,7 +35,7 @@ void ExitFragment(TranslatorVisitor& v) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void TranslatorVisitor::EXIT() {
|
||||
void TranslatorVisitor::EXIT(u64) {
|
||||
switch (env.ShaderStage()) {
|
||||
case Stage::Fragment:
|
||||
ExitFragment(*this);
|
||||
|
||||
@@ -56,293 +56,14 @@ enum class FPCompareOp : u64 {
|
||||
T,
|
||||
};
|
||||
|
||||
class TranslatorVisitor {
|
||||
public:
|
||||
struct TranslatorVisitor {
|
||||
explicit TranslatorVisitor(Environment& env_, IR::Block& block) : env{env_}, ir(block) {}
|
||||
|
||||
Environment& env;
|
||||
IR::IREmitter ir;
|
||||
|
||||
void AL2P(u64 insn);
|
||||
void ALD(u64 insn);
|
||||
void AST(u64 insn);
|
||||
void ATOM_cas(u64 insn);
|
||||
void ATOM(u64 insn);
|
||||
void ATOMS_cas(u64 insn);
|
||||
void ATOMS(u64 insn);
|
||||
void B2R(u64 insn);
|
||||
void BAR(u64 insn);
|
||||
void BFE_reg(u64 insn);
|
||||
void BFE_cbuf(u64 insn);
|
||||
void BFE_imm(u64 insn);
|
||||
void BFI_reg(u64 insn);
|
||||
void BFI_rc(u64 insn);
|
||||
void BFI_cr(u64 insn);
|
||||
void BFI_imm(u64 insn);
|
||||
void BPT(u64 insn);
|
||||
void BRA(u64 insn);
|
||||
void BRK(u64 insn);
|
||||
void BRX(u64 insn);
|
||||
void CAL();
|
||||
void CCTL(u64 insn);
|
||||
void CCTLL(u64 insn);
|
||||
void CCTLT(u64 insn);
|
||||
void CONT(u64 insn);
|
||||
void CS2R(u64 insn);
|
||||
void CSET(u64 insn);
|
||||
void CSETP(u64 insn);
|
||||
void DADD_reg(u64 insn);
|
||||
void DADD_cbuf(u64 insn);
|
||||
void DADD_imm(u64 insn);
|
||||
void DEPBAR();
|
||||
void DFMA_reg(u64 insn);
|
||||
void DFMA_rc(u64 insn);
|
||||
void DFMA_cr(u64 insn);
|
||||
void DFMA_imm(u64 insn);
|
||||
void DMNMX_reg(u64 insn);
|
||||
void DMNMX_cbuf(u64 insn);
|
||||
void DMNMX_imm(u64 insn);
|
||||
void DMUL_reg(u64 insn);
|
||||
void DMUL_cbuf(u64 insn);
|
||||
void DMUL_imm(u64 insn);
|
||||
void DSET_reg(u64 insn);
|
||||
void DSET_cbuf(u64 insn);
|
||||
void DSET_imm(u64 insn);
|
||||
void DSETP_reg(u64 insn);
|
||||
void DSETP_cbuf(u64 insn);
|
||||
void DSETP_imm(u64 insn);
|
||||
void EXIT();
|
||||
void F2F_reg(u64 insn);
|
||||
void F2F_cbuf(u64 insn);
|
||||
void F2F_imm(u64 insn);
|
||||
void F2I_reg(u64 insn);
|
||||
void F2I_cbuf(u64 insn);
|
||||
void F2I_imm(u64 insn);
|
||||
void FADD_reg(u64 insn);
|
||||
void FADD_cbuf(u64 insn);
|
||||
void FADD_imm(u64 insn);
|
||||
void FADD32I(u64 insn);
|
||||
void FCHK_reg(u64 insn);
|
||||
void FCHK_cbuf(u64 insn);
|
||||
void FCHK_imm(u64 insn);
|
||||
void FCMP_reg(u64 insn);
|
||||
void FCMP_rc(u64 insn);
|
||||
void FCMP_cr(u64 insn);
|
||||
void FCMP_imm(u64 insn);
|
||||
void FFMA_reg(u64 insn);
|
||||
void FFMA_rc(u64 insn);
|
||||
void FFMA_cr(u64 insn);
|
||||
void FFMA_imm(u64 insn);
|
||||
void FFMA32I(u64 insn);
|
||||
void FLO_reg(u64 insn);
|
||||
void FLO_cbuf(u64 insn);
|
||||
void FLO_imm(u64 insn);
|
||||
void FMNMX_reg(u64 insn);
|
||||
void FMNMX_cbuf(u64 insn);
|
||||
void FMNMX_imm(u64 insn);
|
||||
void FMUL_reg(u64 insn);
|
||||
void FMUL_cbuf(u64 insn);
|
||||
void FMUL_imm(u64 insn);
|
||||
void FMUL32I(u64 insn);
|
||||
void FSET_reg(u64 insn);
|
||||
void FSET_cbuf(u64 insn);
|
||||
void FSET_imm(u64 insn);
|
||||
void FSETP_reg(u64 insn);
|
||||
void FSETP_cbuf(u64 insn);
|
||||
void FSETP_imm(u64 insn);
|
||||
void FSWZADD(u64 insn);
|
||||
void GETCRSPTR(u64 insn);
|
||||
void GETLMEMBASE(u64 insn);
|
||||
void HADD2_reg(u64 insn);
|
||||
void HADD2_cbuf(u64 insn);
|
||||
void HADD2_imm(u64 insn);
|
||||
void HADD2_32I(u64 insn);
|
||||
void HFMA2_reg(u64 insn);
|
||||
void HFMA2_rc(u64 insn);
|
||||
void HFMA2_cr(u64 insn);
|
||||
void HFMA2_imm(u64 insn);
|
||||
void HFMA2_32I(u64 insn);
|
||||
void HMUL2_reg(u64 insn);
|
||||
void HMUL2_cbuf(u64 insn);
|
||||
void HMUL2_imm(u64 insn);
|
||||
void HMUL2_32I(u64 insn);
|
||||
void HSET2_reg(u64 insn);
|
||||
void HSET2_cbuf(u64 insn);
|
||||
void HSET2_imm(u64 insn);
|
||||
void HSETP2_reg(u64 insn);
|
||||
void HSETP2_cbuf(u64 insn);
|
||||
void HSETP2_imm(u64 insn);
|
||||
void I2F_reg(u64 insn);
|
||||
void I2F_cbuf(u64 insn);
|
||||
void I2F_imm(u64 insn);
|
||||
void I2I_reg(u64 insn);
|
||||
void I2I_cbuf(u64 insn);
|
||||
void I2I_imm(u64 insn);
|
||||
void IADD_reg(u64 insn);
|
||||
void IADD_cbuf(u64 insn);
|
||||
void IADD_imm(u64 insn);
|
||||
void IADD3_reg(u64 insn);
|
||||
void IADD3_cbuf(u64 insn);
|
||||
void IADD3_imm(u64 insn);
|
||||
void IADD32I(u64 insn);
|
||||
void ICMP_reg(u64 insn);
|
||||
void ICMP_rc(u64 insn);
|
||||
void ICMP_cr(u64 insn);
|
||||
void ICMP_imm(u64 insn);
|
||||
void IDE(u64 insn);
|
||||
void IDP_reg(u64 insn);
|
||||
void IDP_imm(u64 insn);
|
||||
void IMAD_reg(u64 insn);
|
||||
void IMAD_rc(u64 insn);
|
||||
void IMAD_cr(u64 insn);
|
||||
void IMAD_imm(u64 insn);
|
||||
void IMAD32I(u64 insn);
|
||||
void IMADSP_reg(u64 insn);
|
||||
void IMADSP_rc(u64 insn);
|
||||
void IMADSP_cr(u64 insn);
|
||||
void IMADSP_imm(u64 insn);
|
||||
void IMNMX_reg(u64 insn);
|
||||
void IMNMX_cbuf(u64 insn);
|
||||
void IMNMX_imm(u64 insn);
|
||||
void IMUL_reg(u64 insn);
|
||||
void IMUL_cbuf(u64 insn);
|
||||
void IMUL_imm(u64 insn);
|
||||
void IMUL32I(u64 insn);
|
||||
void IPA(u64 insn);
|
||||
void ISBERD(u64 insn);
|
||||
void ISCADD_reg(u64 insn);
|
||||
void ISCADD_cbuf(u64 insn);
|
||||
void ISCADD_imm(u64 insn);
|
||||
void ISCADD32I(u64 insn);
|
||||
void ISET_reg(u64 insn);
|
||||
void ISET_cbuf(u64 insn);
|
||||
void ISET_imm(u64 insn);
|
||||
void ISETP_reg(u64 insn);
|
||||
void ISETP_cbuf(u64 insn);
|
||||
void ISETP_imm(u64 insn);
|
||||
void JCAL(u64 insn);
|
||||
void JMP(u64 insn);
|
||||
void JMX(u64 insn);
|
||||
void KIL();
|
||||
void LD(u64 insn);
|
||||
void LDC(u64 insn);
|
||||
void LDG(u64 insn);
|
||||
void LDL(u64 insn);
|
||||
void LDS(u64 insn);
|
||||
void LEA_hi_reg(u64 insn);
|
||||
void LEA_hi_cbuf(u64 insn);
|
||||
void LEA_lo_reg(u64 insn);
|
||||
void LEA_lo_cbuf(u64 insn);
|
||||
void LEA_lo_imm(u64 insn);
|
||||
void LEPC(u64 insn);
|
||||
void LONGJMP(u64 insn);
|
||||
void LOP_reg(u64 insn);
|
||||
void LOP_cbuf(u64 insn);
|
||||
void LOP_imm(u64 insn);
|
||||
void LOP3_reg(u64 insn);
|
||||
void LOP3_cbuf(u64 insn);
|
||||
void LOP3_imm(u64 insn);
|
||||
void LOP32I(u64 insn);
|
||||
void MEMBAR(u64 insn);
|
||||
void MOV_reg(u64 insn);
|
||||
void MOV_cbuf(u64 insn);
|
||||
void MOV_imm(u64 insn);
|
||||
void MOV32I(u64 insn);
|
||||
void MUFU(u64 insn);
|
||||
void NOP(u64 insn);
|
||||
void OUT_reg(u64 insn);
|
||||
void OUT_cbuf(u64 insn);
|
||||
void OUT_imm(u64 insn);
|
||||
void P2R_reg(u64 insn);
|
||||
void P2R_cbuf(u64 insn);
|
||||
void P2R_imm(u64 insn);
|
||||
void PBK();
|
||||
void PCNT();
|
||||
void PEXIT(u64 insn);
|
||||
void PIXLD(u64 insn);
|
||||
void PLONGJMP(u64 insn);
|
||||
void POPC_reg(u64 insn);
|
||||
void POPC_cbuf(u64 insn);
|
||||
void POPC_imm(u64 insn);
|
||||
void PRET(u64 insn);
|
||||
void PRMT_reg(u64 insn);
|
||||
void PRMT_rc(u64 insn);
|
||||
void PRMT_cr(u64 insn);
|
||||
void PRMT_imm(u64 insn);
|
||||
void PSET(u64 insn);
|
||||
void PSETP(u64 insn);
|
||||
void R2B(u64 insn);
|
||||
void R2P_reg(u64 insn);
|
||||
void R2P_cbuf(u64 insn);
|
||||
void R2P_imm(u64 insn);
|
||||
void RAM(u64 insn);
|
||||
void RED(u64 insn);
|
||||
void RET(u64 insn);
|
||||
void RRO_reg(u64 insn);
|
||||
void RRO_cbuf(u64 insn);
|
||||
void RRO_imm(u64 insn);
|
||||
void RTT(u64 insn);
|
||||
void S2R(u64 insn);
|
||||
void SAM(u64 insn);
|
||||
void SEL_reg(u64 insn);
|
||||
void SEL_cbuf(u64 insn);
|
||||
void SEL_imm(u64 insn);
|
||||
void SETCRSPTR(u64 insn);
|
||||
void SETLMEMBASE(u64 insn);
|
||||
void SHF_l_reg(u64 insn);
|
||||
void SHF_l_imm(u64 insn);
|
||||
void SHF_r_reg(u64 insn);
|
||||
void SHF_r_imm(u64 insn);
|
||||
void SHFL(u64 insn);
|
||||
void SHL_reg(u64 insn);
|
||||
void SHL_cbuf(u64 insn);
|
||||
void SHL_imm(u64 insn);
|
||||
void SHR_reg(u64 insn);
|
||||
void SHR_cbuf(u64 insn);
|
||||
void SHR_imm(u64 insn);
|
||||
void SSY();
|
||||
void ST(u64 insn);
|
||||
void STG(u64 insn);
|
||||
void STL(u64 insn);
|
||||
void STP(u64 insn);
|
||||
void STS(u64 insn);
|
||||
void SUATOM(u64 insn);
|
||||
void SUATOM_cas(u64 insn);
|
||||
void SULD(u64 insn);
|
||||
void SURED(u64 insn);
|
||||
void SUST(u64 insn);
|
||||
void SYNC(u64 insn);
|
||||
void TEX(u64 insn);
|
||||
void TEX_b(u64 insn);
|
||||
void TEXS(u64 insn);
|
||||
void TLD(u64 insn);
|
||||
void TLD_b(u64 insn);
|
||||
void TLD4(u64 insn);
|
||||
void TLD4_b(u64 insn);
|
||||
void TLD4S(u64 insn);
|
||||
void TLDS(u64 insn);
|
||||
void TMML(u64 insn);
|
||||
void TMML_b(u64 insn);
|
||||
void TXA(u64 insn);
|
||||
void TXD(u64 insn);
|
||||
void TXD_b(u64 insn);
|
||||
void TXQ(u64 insn);
|
||||
void TXQ_b(u64 insn);
|
||||
void VABSDIFF(u64 insn);
|
||||
void VABSDIFF4(u64 insn);
|
||||
void VADD(u64 insn);
|
||||
void VMAD(u64 insn);
|
||||
void VMNMX(u64 insn);
|
||||
void VOTE(u64 insn);
|
||||
void VOTE_vtg(u64 insn);
|
||||
void VSET(u64 insn);
|
||||
void VSETP(u64 insn);
|
||||
void VSHL(u64 insn);
|
||||
void VSHR(u64 insn);
|
||||
void XMAD_reg(u64 insn);
|
||||
void XMAD_rc(u64 insn);
|
||||
void XMAD_cr(u64 insn);
|
||||
void XMAD_imm(u64 insn);
|
||||
#define INST(name, cute, encode) void name(u64 insn);
|
||||
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
|
||||
#undef INST
|
||||
|
||||
[[nodiscard]] IR::U32 X(IR::Reg reg);
|
||||
[[nodiscard]] IR::U64 L(IR::Reg reg);
|
||||
|
||||
@@ -70,32 +70,25 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
||||
int src_bitsize{};
|
||||
switch (i2f.int_format) {
|
||||
case IntFormat::U8:
|
||||
src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8),
|
||||
v.ir.Imm32(8), is_signed);
|
||||
if (i2f.abs != 0) {
|
||||
src = v.ir.BitFieldExtract(src, v.ir.Imm32(u32(i2f.selector) * 8), v.ir.Imm32(8), is_signed);
|
||||
if (i2f.abs != 0)
|
||||
src = SmallAbs(v, src, 8);
|
||||
}
|
||||
src_bitsize = 8;
|
||||
break;
|
||||
case IntFormat::U16:
|
||||
if (i2f.selector == 1 || i2f.selector == 3) {
|
||||
if (i2f.selector == 1 || i2f.selector == 3)
|
||||
throw NotImplementedException("Invalid U16 selector {}", i2f.selector.Value());
|
||||
}
|
||||
src = v.ir.BitFieldExtract(src, v.ir.Imm32(static_cast<u32>(i2f.selector) * 8),
|
||||
v.ir.Imm32(16), is_signed);
|
||||
if (i2f.abs != 0) {
|
||||
src = v.ir.BitFieldExtract(src, v.ir.Imm32(u32(i2f.selector) * 8), v.ir.Imm32(16), is_signed);
|
||||
if (i2f.abs != 0)
|
||||
src = SmallAbs(v, src, 16);
|
||||
}
|
||||
src_bitsize = 16;
|
||||
break;
|
||||
case IntFormat::U32:
|
||||
case IntFormat::U64:
|
||||
if (i2f.selector != 0) {
|
||||
if (i2f.selector != 0)
|
||||
throw NotImplementedException("Unexpected selector {}", i2f.selector.Value());
|
||||
}
|
||||
if (i2f.abs != 0 && is_signed) {
|
||||
if (i2f.abs != 0 && is_signed)
|
||||
src = v.ir.IAbs(src);
|
||||
}
|
||||
src_bitsize = i2f.int_format == IntFormat::U64 ? 64 : 32;
|
||||
break;
|
||||
}
|
||||
@@ -106,9 +99,7 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
||||
.rounding = CastFpRounding(i2f.fp_rounding),
|
||||
.fmz_mode = IR::FmzMode::DontCare,
|
||||
};
|
||||
auto value{v.ir.ConvertIToF(static_cast<size_t>(dst_bitsize),
|
||||
static_cast<size_t>(conversion_src_bitsize), is_signed, src,
|
||||
fp_control)};
|
||||
auto value{v.ir.ConvertIToF(size_t(dst_bitsize), size_t(conversion_src_bitsize), is_signed, src, fp_control)};
|
||||
if (i2f.neg != 0) {
|
||||
if (i2f.abs != 0 || !is_signed) {
|
||||
// We know the value is positive
|
||||
@@ -141,9 +132,8 @@ void I2F(TranslatorVisitor& v, u64 insn, IR::U32U64 src) {
|
||||
throw NotImplementedException("Unaligned destination {}", i2f.dest_reg.Value());
|
||||
}
|
||||
const IR::Value vector{v.ir.UnpackDouble2x32(value)};
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, static_cast<size_t>(i))});
|
||||
}
|
||||
for (int i = 0; i < 2; ++i)
|
||||
v.X(i2f.dest_reg + i, IR::U32{v.ir.CompositeExtract(vector, size_t(i))});
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -39,7 +39,7 @@ void TranslatorVisitor::BRK(u64) {
|
||||
ThrowNotImplemented(Opcode::BRK);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::CAL() {
|
||||
void TranslatorVisitor::CAL(u64) {
|
||||
// CAL is a no-op
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ void TranslatorVisitor::JMP(u64) {
|
||||
ThrowNotImplemented(Opcode::JMP);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::KIL() {
|
||||
void TranslatorVisitor::KIL(u64) {
|
||||
// KIL is a no-op
|
||||
}
|
||||
|
||||
@@ -172,14 +172,14 @@ void TranslatorVisitor::LONGJMP(u64) {
|
||||
}
|
||||
|
||||
void TranslatorVisitor::NOP(u64) {
|
||||
// NOP is No-Op.
|
||||
// NOP is a no-op
|
||||
}
|
||||
|
||||
void TranslatorVisitor::PBK() {
|
||||
void TranslatorVisitor::PBK(u64) {
|
||||
// PBK is a no-op
|
||||
}
|
||||
|
||||
void TranslatorVisitor::PCNT() {
|
||||
void TranslatorVisitor::PCNT(u64) {
|
||||
// PCNT is a no-op
|
||||
}
|
||||
|
||||
@@ -239,7 +239,7 @@ void TranslatorVisitor::SETLMEMBASE(u64) {
|
||||
ThrowNotImplemented(Opcode::SETLMEMBASE);
|
||||
}
|
||||
|
||||
void TranslatorVisitor::SSY() {
|
||||
void TranslatorVisitor::SSY(u64) {
|
||||
// SSY is a no-op
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,40 +13,17 @@
|
||||
|
||||
namespace Shader::Maxwell {
|
||||
|
||||
template <auto method>
|
||||
static void Invoke(TranslatorVisitor& visitor, Location pc, u64 insn) {
|
||||
using MethodType = decltype(method);
|
||||
if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, Location, u64>) {
|
||||
(visitor.*method)(pc, insn);
|
||||
} else if constexpr (std::is_invocable_r_v<void, MethodType, TranslatorVisitor&, u64>) {
|
||||
(visitor.*method)(insn);
|
||||
} else {
|
||||
(visitor.*method)();
|
||||
}
|
||||
}
|
||||
|
||||
void Translate(Environment& env, IR::Block* block, u32 location_begin, u32 location_end) {
|
||||
if (location_begin == location_end) {
|
||||
return;
|
||||
}
|
||||
TranslatorVisitor visitor{env, *block};
|
||||
for (Location pc = location_begin; pc != location_end; ++pc) {
|
||||
const u64 insn{env.ReadInstruction(pc.Offset())};
|
||||
try {
|
||||
const Opcode opcode{Decode(insn)};
|
||||
if (location_begin != location_end) {
|
||||
TranslatorVisitor visitor{env, *block};
|
||||
for (Location pc = location_begin; pc != location_end; ++pc) {
|
||||
u64 const insn = env.ReadInstruction(pc.Offset());
|
||||
Opcode const opcode = Decode(insn);
|
||||
switch (opcode) {
|
||||
#define INST(name, cute, mask) \
|
||||
case Opcode::name: \
|
||||
Invoke<&TranslatorVisitor::name>(visitor, pc, insn); \
|
||||
break;
|
||||
#define INST(name, cute, mask) case Opcode::name: visitor.name(insn); break;
|
||||
#include "shader_recompiler/frontend/maxwell/maxwell.inc"
|
||||
#undef OPCODE
|
||||
default:
|
||||
throw LogicError("Invalid opcode {}", opcode);
|
||||
}
|
||||
} catch (Exception& exception) {
|
||||
exception.Prepend(fmt::format("Translate {}: ", Decode(insn)));
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -384,10 +384,6 @@ if (ARCHITECTURE_x86_64)
|
||||
macro/macro_jit_x64.h
|
||||
)
|
||||
target_link_libraries(video_core PUBLIC xbyak::xbyak)
|
||||
|
||||
if (NOT MSVC)
|
||||
target_compile_options(video_core PRIVATE -msse4.1)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
|
||||
@@ -23,9 +23,7 @@ namespace VideoCommon::GPUThread {
|
||||
static void RunThread(std::stop_token stop_token, Core::System& system,
|
||||
VideoCore::RendererBase& renderer, Core::Frontend::GraphicsContext& context,
|
||||
Tegra::Control::Scheduler& scheduler, SynchState& state) {
|
||||
std::string name = "GPU";
|
||||
|
||||
Common::SetCurrentThreadName(name.c_str());
|
||||
Common::SetCurrentThreadName("GPU");
|
||||
Common::SetCurrentThreadPriority(Common::ThreadPriority::Critical);
|
||||
system.RegisterHostThread();
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// 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
|
||||
|
||||
@@ -10,7 +13,7 @@
|
||||
namespace VideoCommon {
|
||||
|
||||
constexpr size_t NUM_RT = 8;
|
||||
constexpr size_t MAX_MIP_LEVELS = 14;
|
||||
constexpr size_t MAX_MIP_LEVELS = 16;
|
||||
|
||||
constexpr Common::SlotId CORRUPT_ID{0xfffffffe};
|
||||
|
||||
|
||||
@@ -646,9 +646,10 @@ LevelArray CalculateMipLevelOffsets(const ImageInfo& info) noexcept {
|
||||
if (info.type == ImageType::Linear) {
|
||||
return {};
|
||||
}
|
||||
ASSERT(info.resources.levels <= static_cast<s32>(MAX_MIP_LEVELS));
|
||||
if (info.resources.levels > static_cast<s32>(MAX_MIP_LEVELS))
|
||||
if (info.resources.levels > static_cast<s32>(MAX_MIP_LEVELS)) {
|
||||
LOG_ERROR(HW_GPU, "Image has too many mip levels={}, maximum supported is={}", info.resources.levels, MAX_MIP_LEVELS);
|
||||
return {};
|
||||
}
|
||||
const LevelInfo level_info = MakeLevelInfo(info);
|
||||
LevelArray offsets{};
|
||||
u32 offset = 0;
|
||||
|
||||
@@ -775,20 +775,65 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
if (extensions.memory_budget) {
|
||||
flags |= VMA_ALLOCATOR_CREATE_EXT_MEMORY_BUDGET_BIT;
|
||||
}
|
||||
|
||||
// Runtime sanity check: some drivers (notably Qualcomm and Turnip) advertise
|
||||
// VK_EXT_custom_border_color but mis-implement it. Try creating a sampler
|
||||
// with a formatless custom border color and disable the feature if it fails.
|
||||
if (extensions.custom_border_color) {
|
||||
VkSamplerCustomBorderColorCreateInfoEXT border_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.customBorderColor = VkClearColorValue{{1.0f, 0.0f, 0.0f, 1.0f}},
|
||||
.format = VK_FORMAT_UNDEFINED,
|
||||
};
|
||||
VkSamplerCreateInfo sampler_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
||||
.pNext = &border_ci,
|
||||
.flags = 0,
|
||||
.magFilter = VK_FILTER_NEAREST,
|
||||
.minFilter = VK_FILTER_NEAREST,
|
||||
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST,
|
||||
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
|
||||
.mipLodBias = 0.0f,
|
||||
.anisotropyEnable = VK_FALSE,
|
||||
.maxAnisotropy = 1.0f,
|
||||
.compareEnable = VK_FALSE,
|
||||
.compareOp = VK_COMPARE_OP_ALWAYS,
|
||||
.minLod = 0.0f,
|
||||
.maxLod = 0.0f,
|
||||
.borderColor = VK_BORDER_COLOR_FLOAT_CUSTOM_EXT,
|
||||
.unnormalizedCoordinates = VK_FALSE,
|
||||
};
|
||||
try {
|
||||
const auto test_sampler = logical.CreateSampler(sampler_ci);
|
||||
// dson't allow to optimize away
|
||||
(void)test_sampler;
|
||||
// Destroy immediately; this is just a capability test.
|
||||
test_sampler.~Handle();
|
||||
LOG_INFO(Render_Vulkan, "VK_EXT_custom_border_color runtime test passed");
|
||||
} catch (const vk::Exception& e) {
|
||||
LOG_WARNING(Render_Vulkan, "VK_EXT_custom_border_color advertised but sampler create failed: {}. Disabling feature.", e.what());
|
||||
// Disable the extension feature so the runtime falls back to fixed border colors.
|
||||
RemoveExtensionFeature(extensions.custom_border_color, features.custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
const VmaAllocatorCreateInfo allocator_info{
|
||||
.flags = flags,
|
||||
.physicalDevice = physical,
|
||||
.device = *logical,
|
||||
.preferredLargeHeapBlockSize = is_integrated
|
||||
? (64u * 1024u * 1024u)
|
||||
: (256u * 1024u * 1024u),
|
||||
.pAllocationCallbacks = nullptr,
|
||||
.pDeviceMemoryCallbacks = nullptr,
|
||||
.pHeapSizeLimit = nullptr,
|
||||
.pVulkanFunctions = &functions,
|
||||
.instance = instance,
|
||||
.vulkanApiVersion = ApiVersion(),
|
||||
.pTypeExternalMemoryHandleTypes = nullptr,
|
||||
.flags = flags,
|
||||
.physicalDevice = physical,
|
||||
.device = *logical,
|
||||
.preferredLargeHeapBlockSize = is_integrated
|
||||
? (64u * 1024u * 1024u)
|
||||
: (256u * 1024u * 1024u),
|
||||
.pAllocationCallbacks = nullptr,
|
||||
.pDeviceMemoryCallbacks = nullptr,
|
||||
.pHeapSizeLimit = nullptr,
|
||||
.pVulkanFunctions = &functions,
|
||||
.instance = instance,
|
||||
.vulkanApiVersion = ApiVersion(),
|
||||
.pTypeExternalMemoryHandleTypes = nullptr,
|
||||
};
|
||||
|
||||
vk::Check(vmaCreateAllocator(&allocator_info, &allocator));
|
||||
|
||||
@@ -437,13 +437,6 @@ if (ENABLE_SDL2)
|
||||
target_compile_definitions(yuzu PRIVATE HAVE_SDL2)
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
include(CopyYuzuSDLDeps)
|
||||
include(CopyYuzuFFmpegDeps)
|
||||
copy_yuzu_SDL_deps(yuzu)
|
||||
copy_yuzu_FFmpeg_deps(yuzu)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
|
||||
target_link_libraries(yuzu PRIVATE dynarmic::dynarmic)
|
||||
endif()
|
||||
|
||||
@@ -55,9 +55,4 @@ if(WIN32)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (MSVC)
|
||||
include(CopyYuzuSDLDeps)
|
||||
copy_yuzu_SDL_deps(yuzu-cmd)
|
||||
endif()
|
||||
|
||||
create_target_directory_groups(yuzu-cmd)
|
||||
|
||||
@@ -8,7 +8,8 @@ Tools for Eden and other subprojects.
|
||||
|
||||
## Eden
|
||||
|
||||
- `find-unused-strings.pl`: Find unused strings (for Android XML files).
|
||||
- `generate_converters.py`: Generates converters for given formats of textures (C++ helper).
|
||||
- `svc_generator.py`: Generates the files `src/core/hle/kernel/svc.cpp` and `src/core/hle/kernel/svc.h` based off prototypes.
|
||||
- `shellcheck.sh`: Ensure POSIX compliance (and syntax sanity) for all tools in this directory and subdirectories.
|
||||
- `llvmpipe-run.sh`: Sets environment variables needed to run any command (or Eden) with llvmpipe.
|
||||
- `optimize-assets.sh`: Optimizes PNG assets with OptiPng.
|
||||
|
||||
@@ -37,11 +37,20 @@ EOF
|
||||
|
||||
while true; do
|
||||
case "$1" in
|
||||
(-uf|--force) UPDATE=true; FORCE=true; continue ;;
|
||||
(-u|--update) UPDATE=true; continue ;;
|
||||
(-h) usage ;;
|
||||
("$0") break ;;
|
||||
("") break ;;
|
||||
-f | --force)
|
||||
UPDATE=true
|
||||
FORCE=true
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
-u | --update)
|
||||
UPDATE=true
|
||||
shift
|
||||
continue
|
||||
;;
|
||||
-h) usage ;;
|
||||
"$0") break ;;
|
||||
"") break ;;
|
||||
esac
|
||||
|
||||
PACKAGE="$1"
|
||||
@@ -52,68 +61,72 @@ while true; do
|
||||
# shellcheck disable=SC1091
|
||||
. tools/cpm/package.sh
|
||||
|
||||
SKIP=$(value "skip_updates")
|
||||
SKIP=$(value "skip_updates")
|
||||
|
||||
[ "$SKIP" = "true" ] && continue
|
||||
[ "$SKIP" = "true" ] && continue
|
||||
|
||||
[ "$REPO" = null ] && continue
|
||||
[ "$GIT_HOST" != "github.com" ] && continue # TODO
|
||||
# shellcheck disable=SC2153
|
||||
[ "$TAG" = null ] && continue
|
||||
[ "$REPO" = null ] && continue
|
||||
[ "$GIT_HOST" != "github.com" ] && continue # TODO
|
||||
# shellcheck disable=SC2153
|
||||
[ "$TAG" = null ] && continue
|
||||
|
||||
echo "-- Package $PACKAGE"
|
||||
echo "-- Package $PACKAGE"
|
||||
|
||||
# TODO(crueter): Support for Forgejo updates w/ forgejo_token
|
||||
# Use gh-cli to avoid ratelimits lmao
|
||||
TAGS=$(gh api --method GET "/repos/$REPO/tags")
|
||||
# Use gh-cli to avoid ratelimits lmao
|
||||
TAGS=$(gh api --method GET "/repos/$REPO/tags")
|
||||
|
||||
# filter out some commonly known annoyances
|
||||
# filter out some commonly known annoyances
|
||||
# TODO add more
|
||||
|
||||
filter vulkan-sdk # vulkan
|
||||
filter yotta # mbedtls
|
||||
filter vulkan-sdk # vulkan
|
||||
filter yotta # mbedtls
|
||||
|
||||
# ignore betas/alphas (remove if needed)
|
||||
# ignore betas/alphas (remove if needed)
|
||||
filter alpha
|
||||
filter beta
|
||||
filter rc
|
||||
|
||||
# Add package-specific overrides here, e.g. here for fmt:
|
||||
[ "$PACKAGE" = fmt ] && filter v0.11
|
||||
[ "$PACKAGE" = fmt ] && filter v0.11
|
||||
|
||||
LATEST=$(echo "$TAGS" | jq -r '.[0].name')
|
||||
LATEST=$(echo "$TAGS" | jq -r '.[0].name')
|
||||
|
||||
[ "$LATEST" = "$TAG" ] && [ "$FORCE" != "true" ] && echo "-- * Up-to-date" && continue
|
||||
[ "$LATEST" = "$TAG" ] && [ "$FORCE" != "true" ] && echo "-- * Up-to-date" && continue
|
||||
|
||||
RETURN=1
|
||||
|
||||
if [ "$HAS_REPLACE" = "true" ]; then
|
||||
# this just extracts the tag prefix
|
||||
VERSION_PREFIX=$(echo "$ORIGINAL_TAG" | cut -d"%" -f1)
|
||||
if [ "$HAS_REPLACE" = "true" ]; then
|
||||
# this just extracts the tag prefix
|
||||
VERSION_PREFIX=$(echo "$ORIGINAL_TAG" | cut -d"%" -f1)
|
||||
|
||||
# then we strip out the prefix from the new tag, and make that our new git_version
|
||||
NEW_GIT_VERSION=$(echo "$LATEST" | sed "s/$VERSION_PREFIX//g")
|
||||
fi
|
||||
# then we strip out the prefix from the new tag, and make that our new git_version
|
||||
if [ -z "$VERSION_PREFIX" ]; then
|
||||
NEW_GIT_VERSION="$LATEST"
|
||||
else
|
||||
NEW_GIT_VERSION=$(echo "$LATEST" | sed "s/$VERSION_PREFIX//g")
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "-- * Version $LATEST available, current is $TAG"
|
||||
echo "-- * Version $LATEST available, current is $TAG"
|
||||
|
||||
HASH=$(tools/cpm/hash.sh "$REPO" "$LATEST")
|
||||
HASH=$(tools/cpm/hash.sh "$REPO" "$LATEST")
|
||||
|
||||
echo "-- * New hash: $HASH"
|
||||
echo "-- * New hash: $HASH"
|
||||
|
||||
if [ "$UPDATE" = "true" ]; then
|
||||
if [ "$UPDATE" = "true" ]; then
|
||||
RETURN=0
|
||||
|
||||
if [ "$HAS_REPLACE" = "true" ]; then
|
||||
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$HASH\" | .git_version = \"$NEW_GIT_VERSION\"")
|
||||
else
|
||||
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$HASH\" | .tag = \"$LATEST\"")
|
||||
fi
|
||||
if [ "$HAS_REPLACE" = "true" ]; then
|
||||
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$HASH\" | .git_version = \"$NEW_GIT_VERSION\"")
|
||||
else
|
||||
NEW_JSON=$(echo "$JSON" | jq ".hash = \"$HASH\" | .tag = \"$LATEST\"")
|
||||
fi
|
||||
|
||||
export NEW_JSON
|
||||
|
||||
tools/cpm/replace.sh
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
exit $RETURN
|
||||
exit $RETURN
|
||||
|
||||
@@ -65,7 +65,7 @@ ci_package() {
|
||||
|
||||
echo "-- CI package $PACKAGE_NAME"
|
||||
|
||||
for platform in windows-amd64 windows-arm64 android solaris-amd64 freebsd-amd64 linux-amd64 linux-aarch64 macos-universal; do
|
||||
for platform in windows-amd64 windows-arm64 mingw-amd64 mingw-arm64 android solaris-amd64 freebsd-amd64 openbsd-amd64 linux-amd64 linux-aarch64 macos-universal; do
|
||||
echo "-- * platform $platform"
|
||||
|
||||
case $DISABLED in
|
||||
|
||||
90
src/core/hle/kernel/svc_generator.py → tools/svc_generator.py
Normal file → Executable file
90
src/core/hle/kernel/svc_generator.py → tools/svc_generator.py
Normal file → Executable file
@@ -1,3 +1,6 @@
|
||||
#!/usr/bin/python3
|
||||
# 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-2.0-or-later
|
||||
|
||||
@@ -378,7 +381,7 @@ def emit_gather(sources, name, type_name, reg_size):
|
||||
|
||||
if len(sources) == 1:
|
||||
s, = sources
|
||||
line = f"{name} = Convert<{type_name}>({get_fn}(args, {s}));"
|
||||
line = f"{type_name} {name} = Convert<{type_name}>({get_fn}(args, {s}));"
|
||||
return [line]
|
||||
|
||||
var_type = f"std::array<uint{reg_size*8}_t, {len(sources)}>"
|
||||
@@ -386,10 +389,9 @@ def emit_gather(sources, name, type_name, reg_size):
|
||||
f"{var_type} {name}_gather{{}};"
|
||||
]
|
||||
for i in range(0, len(sources)):
|
||||
lines.append(
|
||||
f"{name}_gather[{i}] = {get_fn}(args, {sources[i]});")
|
||||
lines.append(f"{name}_gather[{i}] = {get_fn}(args, {sources[i]});")
|
||||
|
||||
lines.append(f"{name} = Convert<{type_name}>({name}_gather);")
|
||||
lines.append(f"{type_name} {name} = Convert<{type_name}>({name}_gather);")
|
||||
return lines
|
||||
|
||||
|
||||
@@ -405,14 +407,9 @@ def emit_scatter(destinations, name, reg_size):
|
||||
return [line]
|
||||
|
||||
var_type = f"std::array<{reg_type}, {len(destinations)}>"
|
||||
lines = [
|
||||
f"auto {name}_scatter = Convert<{var_type}>({name});"
|
||||
]
|
||||
|
||||
lines = [f"auto {name}_scatter = Convert<{var_type}>({name});"]
|
||||
for i in range(0, len(destinations)):
|
||||
lines.append(
|
||||
f"{set_fn}(args, {destinations[i]}, {name}_scatter[{i}]);")
|
||||
|
||||
lines.append(f"{set_fn}(args, {destinations[i]}, {name}_scatter[{i}]);")
|
||||
return lines
|
||||
|
||||
|
||||
@@ -436,25 +433,8 @@ def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
|
||||
f"static void SvcWrap_{wrapped_fn}{suffix}(Core::System& system, std::span<uint64_t, 8> args) {{"
|
||||
]
|
||||
|
||||
# Get everything ready.
|
||||
for return_type, _ in return_write:
|
||||
lines.append(f"{return_type} ret{{}};")
|
||||
if return_write:
|
||||
lines.append("")
|
||||
|
||||
for output_type, var_name, _, is_address in output_writes:
|
||||
output_type = "uint64_t" if is_address else output_type
|
||||
lines.append(f"{output_type} {var_name}{{}};")
|
||||
for input_type, var_name, _ in input_reads:
|
||||
lines.append(f"{input_type} {var_name}{{}};")
|
||||
|
||||
if output_writes or input_reads:
|
||||
lines.append("")
|
||||
|
||||
for input_type, var_name, sources in input_reads:
|
||||
lines += emit_gather(sources, var_name, input_type, byte_size)
|
||||
if input_reads:
|
||||
lines.append("")
|
||||
|
||||
# Build the call.
|
||||
call_arguments = ["system"]
|
||||
@@ -464,16 +444,18 @@ def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
|
||||
else:
|
||||
call_arguments.append(arg.var_name)
|
||||
|
||||
# Get everything ready.
|
||||
for output_type, var_name, _, is_address in output_writes:
|
||||
output_type = "uint64_t" if is_address else output_type
|
||||
lines.append(f"{output_type} {var_name}{{}};")
|
||||
|
||||
line = ""
|
||||
if return_write:
|
||||
line += "ret = "
|
||||
for return_type, _ in return_write:
|
||||
line += f"{return_type} ret = "
|
||||
|
||||
line += f"{wrapped_fn}{suffix}({', '.join(call_arguments)});"
|
||||
lines.append(line)
|
||||
|
||||
if return_write or output_writes:
|
||||
lines.append("")
|
||||
|
||||
# Write back the return value and outputs.
|
||||
for _, destinations in return_write:
|
||||
lines += emit_scatter(destinations, "ret", byte_size)
|
||||
@@ -485,10 +467,13 @@ def emit_wrapper(wrapped_fn, suffix, register_info, arguments, byte_size):
|
||||
|
||||
|
||||
COPYRIGHT = """\
|
||||
// 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-2.0-or-later
|
||||
// SPDX-License-Identifier: GPL-2.0-or-late
|
||||
|
||||
// This file is automatically generated using svc_generator.py.
|
||||
// DO NOT MODIFY IT MANUALLY
|
||||
"""
|
||||
|
||||
PROLOGUE_H = """
|
||||
@@ -505,13 +490,9 @@ class System;
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel::Svc {
|
||||
|
||||
// clang-format off
|
||||
"""
|
||||
|
||||
EPILOGUE_H = """
|
||||
// clang-format on
|
||||
|
||||
// Custom ABI.
|
||||
Result ReplyAndReceiveLight(Core::System& system, Handle handle, uint32_t* args);
|
||||
Result ReplyAndReceiveLight64From32(Core::System& system, Handle handle, uint32_t* args);
|
||||
@@ -553,7 +534,7 @@ PROLOGUE_CPP = """
|
||||
namespace Kernel::Svc {
|
||||
|
||||
static uint32_t GetArg32(std::span<uint64_t, 8> args, int n) {
|
||||
return static_cast<uint32_t>(args[n]);
|
||||
return uint32_t(args[n]);
|
||||
}
|
||||
|
||||
static void SetArg32(std::span<uint64_t, 8> args, int n, uint32_t result) {
|
||||
@@ -574,37 +555,27 @@ template <typename To, typename From>
|
||||
requires(std::is_trivial_v<To> && std::is_trivially_copyable_v<From>)
|
||||
static To Convert(const From& from) {
|
||||
To to{};
|
||||
|
||||
if constexpr (sizeof(To) >= sizeof(From)) {
|
||||
if constexpr (sizeof(To) >= sizeof(From))
|
||||
std::memcpy(std::addressof(to), std::addressof(from), sizeof(From));
|
||||
} else {
|
||||
else
|
||||
std::memcpy(std::addressof(to), std::addressof(from), sizeof(To));
|
||||
}
|
||||
|
||||
return to;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
"""
|
||||
|
||||
EPILOGUE_CPP = """
|
||||
// clang-format on
|
||||
|
||||
void Call(Core::System& system, u32 imm) {
|
||||
auto& kernel = system.Kernel();
|
||||
auto& process = GetCurrentProcess(kernel);
|
||||
|
||||
std::array<uint64_t, 8> args;
|
||||
kernel.CurrentPhysicalCore().SaveSvcArguments(process, args);
|
||||
kernel.EnterSVCProfile();
|
||||
|
||||
if (process.Is64Bit()) {
|
||||
//kernel.EnterSVCProfile();
|
||||
if (process.Is64Bit())
|
||||
Call64(system, imm, args);
|
||||
} else {
|
||||
else
|
||||
Call32(system, imm, args);
|
||||
}
|
||||
|
||||
kernel.ExitSVCProfile();
|
||||
//kernel.ExitSVCProfile();
|
||||
kernel.CurrentPhysicalCore().LoadSvcArguments(process, args);
|
||||
}
|
||||
|
||||
@@ -617,12 +588,11 @@ def emit_call(bitness, names, suffix):
|
||||
indent = " "
|
||||
lines = [
|
||||
f"static void Call{bit_size}(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {{",
|
||||
f"{indent}switch (static_cast<SvcId>(imm)) {{"
|
||||
f"{indent}switch (SvcId(imm)) {{"
|
||||
]
|
||||
|
||||
for _, name in names:
|
||||
lines.append(f"{indent}case SvcId::{name}:")
|
||||
lines.append(f"{indent*2}return SvcWrap_{name}{suffix}(system, args);")
|
||||
lines.append(f"{indent}case SvcId::{name}: return SvcWrap_{name}{suffix}(system, args);")
|
||||
|
||||
lines.append(f"{indent}default:")
|
||||
lines.append(
|
||||
@@ -692,7 +662,7 @@ def main():
|
||||
call_64 = emit_call(BIT_64, names, SUFFIX_NAMES[BIT_64])
|
||||
enum_decls = build_enum_declarations()
|
||||
|
||||
with open("svc.h", "w") as f:
|
||||
with open("src/core/hle/kernel/svc.h", "w") as f:
|
||||
f.write(COPYRIGHT)
|
||||
f.write(PROLOGUE_H)
|
||||
f.write("\n".join(svc_fw_declarations))
|
||||
@@ -704,7 +674,7 @@ def main():
|
||||
f.write(enum_decls)
|
||||
f.write(EPILOGUE_H)
|
||||
|
||||
with open("svc.cpp", "w") as f:
|
||||
with open("src/core/hle/kernel/svc.cpp", "w") as f:
|
||||
f.write(COPYRIGHT)
|
||||
f.write(PROLOGUE_CPP)
|
||||
f.write(emit_size_check())
|
||||
Reference in New Issue
Block a user