diff --git a/.ci/build-linux-aarch64.sh b/.ci/build-linux-aarch64.sh index b18f307606..4dca82ffb9 100644 --- a/.ci/build-linux-aarch64.sh +++ b/.ci/build-linux-aarch64.sh @@ -12,8 +12,8 @@ git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodule mkdir build && cd build || exit 1 -export CC=clang -export CXX=clang++ +export CC="${CLANG_BINARY}" +export CXX="${CLANGXX_BINARY}" cmake .. \ -DCMAKE_INSTALL_PREFIX=/usr \ @@ -27,8 +27,8 @@ cmake .. \ -DUSE_SYSTEM_FFMPEG=OFF \ -DUSE_DISCORD_RPC=ON \ -DOpenGL_GL_PREFERENCE=LEGACY \ + -DLLVM_DIR=/opt/llvm/lib/cmake/llvm \ -DSTATIC_LINK_LLVM=ON \ - -DBUILD_LLVM=OFF \ -G Ninja ninja; build_status=$?; diff --git a/.ci/build-linux.sh b/.ci/build-linux.sh index 35aabf85d9..ff061cd7e3 100755 --- a/.ci/build-linux.sh +++ b/.ci/build-linux.sh @@ -42,6 +42,7 @@ cmake .. \ -DCMAKE_RANLIB="$RANLIB" \ -DUSE_SYSTEM_CURL=ON \ -DUSE_SDL=ON \ + -DUSE_SYSTEM_SDL=ON \ -DUSE_SYSTEM_FFMPEG=OFF \ -DUSE_DISCORD_RPC=ON \ -DOpenGL_GL_PREFERENCE=LEGACY \ @@ -61,5 +62,5 @@ shellcheck .ci/*.sh } && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false" if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then - .ci/deploy-linux-legacy.sh "x86_64" + .ci/deploy-linux.sh "x86_64" fi diff --git a/.ci/build-mac-arm64.sh b/.ci/build-mac-arm64.sh index 8292329a05..a1aefd2b4f 100644 --- a/.ci/build-mac-arm64.sh +++ b/.ci/build-mac-arm64.sh @@ -3,18 +3,18 @@ # shellcheck disable=SC2086 brew_arm64_install_packages() { for pkg in "$@"; do - echo "Fetching bottle for $pkg..." - bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")" + echo "Fetching bottle for $pkg (arm64)..." + bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")" if [ ! -f "$bottle_path" ]; then - if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --bottle-tag=arm64_sonoma "$pkg"; then + if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_ventura "$pkg"; then echo "Failed to fetch bottle for $pkg" return 1 fi - bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")" + bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")" fi - echo "Installing $pkg..." - "$BREW_ARM64_PATH/bin/brew" install --ignore-dependencies "$bottle_path" || true + echo "Installing $pkg (arm64)..." + "$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true done } @@ -23,9 +23,14 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 export HOMEBREW_NO_INSTALL_CLEANUP=1 /usr/local/bin/brew update +sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl +/usr/local/bin/brew install -f --overwrite curl /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg /usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true +/usr/local/bin/brew install -f --overwrite python || true +/usr/local/bin/brew link --overwrite python || true /usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg +/usr/local/bin/brew link -f curl || true /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true @@ -34,12 +39,17 @@ sudo mkdir -p "$BREW_ARM64_PATH" sudo chmod 777 "$BREW_ARM64_PATH" curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH" -"$BREW_ARM64_PATH/bin/brew" update -brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson curl dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd +#"$BREW_ARM64_PATH/bin/brew" update +# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary +brew_arm64_install_packages curl +mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak +ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl + +brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd "$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5 -# moltenvk based on commit for 1.2.10 release -wget https://raw.githubusercontent.com/Homebrew/homebrew-core/0d9f25fbd1658e975d00bd0e8cccd20a0c2cb74b/Formula/m/molten-vk.rb +# moltenvk based on commit for 1.2.11 release +wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb /usr/local/bin/brew install -f --overwrite ./molten-vk.rb export CXX=clang++ export CC=clang @@ -125,6 +135,7 @@ export MACOSX_DEPLOYMENT_TARGET=13.0 -DLLVM_TARGET_ARCH=arm64 \ -DCMAKE_OSX_ARCHITECTURES=arm64 \ -DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \ + -DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \ -DCMAKE_SYSTEM_PROCESSOR=arm64 \ -DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \ -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \ diff --git a/.ci/build-mac.sh b/.ci/build-mac.sh index 23d5a943d4..85011afcb2 100644 --- a/.ci/build-mac.sh +++ b/.ci/build-mac.sh @@ -9,15 +9,15 @@ brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg #/usr/sbin/softwareupdate --install-rosetta --agree-to-license arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" arch -x86_64 /usr/local/bin/brew update -arch -x86_64 /usr/local/bin/brew install -f --overwrite python@3.12 || arch -x86_64 /usr/local/bin/brew link --overwrite python@3.12 +arch -x86_64 /usr/local/bin/brew install -f --overwrite python || arch -x86_64 /usr/local/bin/brew link --overwrite python arch -x86_64 /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg arch -x86_64 /usr/local/bin/brew install -f --build-from-source ffmpeg@5 arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetype arch -x86_64 /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils arch -x86_64 /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 -# moltenvk based on commit for 1.2.10 release -wget https://raw.githubusercontent.com/Homebrew/homebrew-core/0d9f25fbd1658e975d00bd0e8cccd20a0c2cb74b/Formula/m/molten-vk.rb +# moltenvk based on commit for 1.2.11 release +wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb export CXX=clang++ export CC=clang diff --git a/.ci/deploy-linux-legacy.sh b/.ci/deploy-linux-legacy.sh deleted file mode 100755 index 1e22c5ffc9..0000000000 --- a/.ci/deploy-linux-legacy.sh +++ /dev/null @@ -1,48 +0,0 @@ -#!/bin/sh -ex - -cd build || exit 1 - -if [ "$DEPLOY_APPIMAGE" = "true" ]; then - DESTDIR=AppDir ninja install - - curl -fsSLo /usr/bin/linuxdeploy https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage - chmod +x /usr/bin/linuxdeploy - curl -fsSLo /usr/bin/linuxdeploy-plugin-qt https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage - chmod +x /usr/bin/linuxdeploy-plugin-qt - curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh - chmod +x ./linuxdeploy-plugin-checkrt.sh - - export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" - export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration" - APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt - - # Remove libwayland-client because it has platform-dependent exports and breaks other OSes - rm -f ./AppDir/usr/lib/libwayland-client.so* - - # Remove libvulkan because it causes issues with gamescope - rm -f ./AppDir/usr/lib/libvulkan.so* - - # Remove git directory containing local commit history file - rm -rf ./AppDir/usr/share/rpcs3/git - - ./linuxdeploy-plugin-checkrt.sh --appdir AppDir - - linuxdeploy --appimage-extract - ./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g - - COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp) - COMM_COUNT="$(git rev-list --count HEAD)" - COMM_HASH="$(git rev-parse --short=8 HEAD)" - RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_linux64.AppImage" - - mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE" - - # If we're building using a CI, let's copy over the AppImage artifact - if [ -n "$BUILD_ARTIFACTSTAGINGDIRECTORY" ]; then - cp "$RPCS3_APPIMAGE" "$ARTDIR" - fi - - FILESIZE=$(stat -c %s ./rpcs3*.AppImage) - SHA256SUM=$(sha256sum ./rpcs3*.AppImage | awk '{ print $1 }') - echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE" -fi diff --git a/.ci/deploy-linux.sh b/.ci/deploy-linux.sh index df5950061c..38a1d3e05c 100755 --- a/.ci/deploy-linux.sh +++ b/.ci/deploy-linux.sh @@ -17,7 +17,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor" - APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt + APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt # Remove libwayland-client because it has platform-dependent exports and breaks other OSes rm -f ./AppDir/usr/lib/libwayland-client.so* @@ -28,8 +28,6 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then # Remove git directory containing local commit history file rm -rf ./AppDir/usr/share/rpcs3/git - ./linuxdeploy-plugin-checkrt.sh --appdir AppDir - linuxdeploy --appimage-extract ./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g diff --git a/.cirrus.yml b/.cirrus.yml index 209d7179d9..4dce31a4e9 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -132,7 +132,7 @@ linux_aarch64_task: matrix: - name: Cirrus Linux AArch64 Clang arm_container: - image: 'docker.io/kd117/rpcs3-ci-aarch64:latest' + image: 'docker.io/rpcs3/rpcs3-ci-focal-aarch64:1.0' cpu: 8 memory: 8G clang_script: diff --git a/3rdparty/MoltenVK/CMakeLists.txt b/3rdparty/MoltenVK/CMakeLists.txt index 590779c168..fc1b93074c 100644 --- a/3rdparty/MoltenVK/CMakeLists.txt +++ b/3rdparty/MoltenVK/CMakeLists.txt @@ -4,7 +4,7 @@ include(ExternalProject) ExternalProject_Add(moltenvk GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git - GIT_TAG edbdcf0 + GIT_TAG 81541f6 BUILD_IN_SOURCE 1 SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos diff --git a/3rdparty/OpenAL/CMakeLists.txt b/3rdparty/OpenAL/CMakeLists.txt index ffeeee2bdc..2100de3b4f 100644 --- a/3rdparty/OpenAL/CMakeLists.txt +++ b/3rdparty/OpenAL/CMakeLists.txt @@ -5,8 +5,8 @@ if(USE_SYSTEM_OPENAL) target_include_directories(3rdparty_openal INTERFACE ${OPENAL_INCLUDE_DIR}) target_link_libraries(3rdparty_openal INTERFACE ${OPENAL_LIBRARY}) else() - option(ALSOFT_UTILS "Build utility programs" OFF) - option(ALSOFT_EXAMPLES "Build example programs" OFF) + option(ALSOFT_UTILS "Build utility programs" OFF) + option(ALSOFT_EXAMPLES "Build example programs" OFF) add_subdirectory(openal-soft EXCLUDE_FROM_ALL) add_library(3rdparty_openal INTERFACE) target_link_libraries(3rdparty_openal INTERFACE OpenAL::OpenAL) diff --git a/3rdparty/llvm/CMakeLists.txt b/3rdparty/llvm/CMakeLists.txt index 780d3412c4..e2eb18f129 100644 --- a/3rdparty/llvm/CMakeLists.txt +++ b/3rdparty/llvm/CMakeLists.txt @@ -17,7 +17,10 @@ if(WITH_LLVM) option(LLVM_CCACHE_BUILD OFF) set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "Enable compiler warnings.") - if(WIN32 AND COMPILER_X86) + # For Windows x86 (not Windows AArch64). + # Check on MSVC is needed due to COMPILER_X86, COMPILER_ARM etc. are not set/supported by the MSVC compiler, if used. + # Furthermore, the MSVC compiler is not available/supported on Windows AArch64 + if(WIN32 AND (COMPILER_X86 OR MSVC)) set(LLVM_USE_INTEL_JITEVENTS ON) endif() @@ -70,12 +73,18 @@ if(WITH_LLVM) set(LLVM_TARGETS_TO_BUILD "X86" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".") endif() endif() - if((WIN32 AND BUILD_LLVM) OR (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_X86)) + + # For Windows x86 (not Windows AArch64) only when BUILD_LLVM is enabled and + # for Linux x86 (not Linux AArch64) even if BUILD_LLVM is disabled (precompiled llvm used) + if(LLVM_USE_INTEL_JITEVENTS OR (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_X86)) list (APPEND LLVM_ADDITIONAL_LIBS IntelJITEvents) endif() + + # For Linux even if BUILD_LLVM is disabled (precompiled llvm used) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") list (APPEND LLVM_ADDITIONAL_LIBS PerfJITEvents) endif() + llvm_map_components_to_libnames(LLVM_LIBS ${LLVM_TARGETS_TO_BUILD} ${LLVM_ADDITIONAL_LIBS} diff --git a/BUILDING.md b/BUILDING.md index 1067a3d501..9133596547 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -7,25 +7,40 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu ### Windows 10 or later -* [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH) -* [Python 3.6+](https://www.python.org/downloads/) (add to PATH) -* [Qt 6.7.3](https://www.qt.io/download-qt-installer) -* [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions) -* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. +The following tools are required to build RPCS3 on Windows 10 or later: +- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions) +- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH) -**Either add the** `QTDIR` **environment variable, e.g.** `\6.7.3\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)** + **NOTES:** + - **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`). + See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution) + on how to build the project with **Visual Studio**. + - Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project + with standalone **CMake** tool. -**NOTE: If you have issues with the Qt plugin, you may want to uninstall the Qt Plugin and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.** +- [Python 3.6+](https://www.python.org/downloads/) (add to PATH) +- [Qt 6.7.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt) +- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. + +The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode. + +In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs: +- add and set the `QTDIR` environment variable, e.g. `\6.7.3\msvc2019_64\` +- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019) + + **NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead. + +In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool): +- add and set the `CMAKE_PREFIX_PATH` environment variable to the **Qt** libs path, e.g. `\6.7.3\msvc2019_64\` ### Linux -These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager. - -* Clang 17+ or GCC 13+ -* [CMake 3.28.0+](https://www.cmake.org/download/) -* [Qt 6.7.3](https://www.qt.io/download-qt-installer) -* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. -* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend) +These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager: +- Clang 17+ or GCC 13+ +- [CMake 3.28.0+](https://www.cmake.org/download/) +- [Qt 6.7.3](https://www.qt.io/download-qt-installer) +- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. +- [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend) **If you have an NVIDIA GPU, you may need to install the libglvnd package.** @@ -38,6 +53,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake + ##### Qt PPA Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is currently no PPA available to work around this. @@ -65,6 +81,7 @@ sudo apt install vulkan-sdk ``` ##### CMake + ``` . /etc/os-release wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add - @@ -95,26 +112,64 @@ git submodule update --init ### Windows -#### Configuring the Qt plugin (if used) +#### Building with Visual Studio sln solution -1) Go to `Extensions->Qt VS Tools->Qt Versions`. -2) Add the path to your Qt installation with compiler e.g. `\6.7.3\msvc2019_64`, version will fill in automatically. -3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the legacy Qt plugin) -4) Set `Build: Run pre-build setup` to `true`. (Only available in the legacy Qt plugin) +Start **Visual Studio**, click on `Open a project or solution` and select the `rpcs3.sln` file inside the RPCS3's root folder -#### Building the projects +##### Configuring the Qt Plugin (if used) -Open `rpcs3.sln`. The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`) +1) go to `Extensions->Qt VS Tools->Qt Versions` +2) add the path to your Qt installation with compiler e.g. `\6.7.3\msvc2019_64`, version will fill in automatically +3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**) +4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**) -You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`, as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation time (unoptimised/debug libs are currently not available precompiled). +##### Building the projects -If you're not using the precompiled libs, build the following projects in *__BUILD_BEFORE* folder by right-clicking on a project > *Build*.: -* glslang -* **Either** llvm_build **or** llvm_build_clang_cl +**NOTE:** The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`) -Afterwards: +You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`, +as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation +time (unoptimised/debug libs are currently not available precompiled). -`Build > Build Solution` +If you're not using the precompiled libs, those dependency libs need to be compiled first. From the `Solution Explorer` panel: +1) expand `__BUILD_BEFORE` +2) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode) +3) one after another, right-click on the following projects and then click on `Build` to build the selected lib: + - `glslang` + - either `llvm_build` + - or `llvm_build_clang_cl` (if you installed **clang** on VS) + +In order to build the **RPCS3** application: +1) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode) + + **NOTE:** In case you previously compiled the dependency libs under `__BUILD_BEFORE`, you have also to select the same build configuration (e.g. `Release`, if you compiled the dependency libs in `Release` mode) + +2) click on `Build` menu and then on `Build Solution` +3) once the build is completed, the **RPCS3** application will be available under the `\bin` folder + +#### Building with Visual Studio CMake solution + +Start **Visual Studio**, click on `Open a local folder` and select the RPCS3's root folder + +Once the project is open on VS, from the `Solution Explorer` panel: +1) right-click on `rpcs3` and then click on `Switch to CMake Targets View` +2) from the `Configuration` drop-down menu, select `msvc-release` (select `msvc-debug` if you want to build in `Debug` mode) +3) right-click on `CMakeLists.txt Project` and then click on `Configure Cache` +4) once the cache is created, the `rpcs3 project` will be available +5) right-click on `rpcs3 Project` and then click on `Build All`, or click on `Build` menu and then on `Build All` +6) once the build is completed, the **RPCS3** application will be available under the `\build-msvc\bin` folder + +#### Building with standalone CMake tool + +In case you preferred to install and use the standalone **CMake** tool: +1) move on the RPCS3's root folder +2) execute the following commands to create the cache and to build the application (for the build, use `--preset msvc-debug` if you want to build in `Debug` mode), respectively: + + ``` + cmake --preset msvc + cmake --build --preset msvc-release + ``` +3) once the build is completed, the **RPCS3** application will be available under the `\build-msvc\bin` folder ### Linux @@ -122,7 +177,7 @@ While still in the project root: 1) `cd .. && mkdir --parents rpcs3_build && cd rpcs3_build` 2) `cmake ../rpcs3/ && make` or `CXX=g++-13 CC=gcc-13 cmake ../rpcs3/ && make` to force these compilers -3) Run RPCS3 with `./bin/rpcs3` +3) run RPCS3 with `./bin/rpcs3` If compiling for ARM, pass the flag `-DUSE_NATIVE_INSTRUCTIONS=OFF` to the cmake command. This resolves some Neon errors when compiling our SIMD headers. diff --git a/CMakeLists.txt b/CMakeLists.txt index a399501734..8b95d4a838 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,7 +25,7 @@ option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON) option(USE_VULKAN "Vulkan render backend" ON) option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF) option(USE_SDL "Enables SDL input handler" OFF) -option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" OFF) +option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" ON) option(USE_SYSTEM_FFMPEG "Prefer system ffmpeg instead of the prebuild one" OFF) option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON) option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON) diff --git a/CMakePresets.json b/CMakePresets.json index 82dc88e1a6..f2ad04077c 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -7,12 +7,12 @@ "binaryDir": "build-gcc", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", + "USE_NATIVE_INSTRUCTIONS": "ON", + "USE_PRECOMPILED_HEADERS": "ON", "USE_FAUDIO": "OFF", "USE_SYSTEM_CURL": "OFF", "USE_SYSTEM_ZLIB": "OFF", "USE_SYSTEM_LIBPNG": "OFF", - "USE_NATIVE_INSTRUCTIONS": "ON", - "USE_PRECOMPILED_HEADERS": "ON", "BUILD_LLVM": "OFF", "STATIC_LINK_LLVM": "ON" } @@ -23,13 +23,13 @@ "binaryDir": "build-clang64", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", + "USE_NATIVE_INSTRUCTIONS": "ON", + "USE_PRECOMPILED_HEADERS": "ON", "USE_FAUDIO": "OFF", "USE_SYSTEM_CURL": "OFF", "USE_SYSTEM_ZLIB": "OFF", "USE_SYSTEM_LIBPNG": "OFF", "LLVM_ENABLE_LIBCXX": "ON", - "USE_NATIVE_INSTRUCTIONS": "ON", - "USE_PRECOMPILED_HEADERS": "ON", "BUILD_LLVM": "OFF", "STATIC_LINK_LLVM": "ON" }, @@ -48,11 +48,14 @@ "strategy": "external" }, "cacheVariables": { + "CMAKE_CONFIGURATION_TYPES": "Debug;Release", "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", - "USE_FAUDIO": "OFF", - "USE_PRECOMPILED_HEADERS": "ON", - "USE_SYSTEM_ZLIB": "OFF", "USE_NATIVE_INSTRUCTIONS": "ON", + "USE_PRECOMPILED_HEADERS": "ON", + "USE_FAUDIO": "OFF", + "USE_SYSTEM_CURL": "OFF", + "USE_SYSTEM_ZLIB": "OFF", + "USE_SYSTEM_OPENAL": "OFF", "BUILD_LLVM": "ON", "STATIC_LINK_LLVM": "ON" }, @@ -64,5 +67,17 @@ } } } + ], + "buildPresets": [ + { + "name": "msvc-debug", + "configurePreset": "msvc", + "configuration": "Debug" + }, + { + "name": "msvc-release", + "configurePreset": "msvc", + "configuration": "Release" + } ] } diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 85e6c1cddf..6d58077ba8 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -2412,6 +2412,13 @@ fs::file fs::make_gather(std::vector files) return result; } +std::string fs::generate_neighboring_path(std::string_view source, [[maybe_unused]] u64 seed) +{ + // Seed is currently not used + + return fmt::format(u8"%s/$%s.%s.tmp", get_parent_dir(source), source.substr(source.find_last_of(fs::delim) + 1), fmt::base57(utils::get_unique_tsc())); +} + bool fs::pending_file::open(std::string_view path) { file.close(); @@ -2430,7 +2437,7 @@ bool fs::pending_file::open(std::string_view path) do { - m_path = fmt::format(u8"%s/$%s.%s.tmp", get_parent_dir(path), path.substr(path.find_last_of(fs::delim) + 1), fmt::base57(utils::get_unique_tsc())); + m_path = fs::generate_neighboring_path(path, 0); if (file.open(m_path, fs::create + fs::write + fs::read + fs::excl)) { @@ -2475,7 +2482,6 @@ bool fs::pending_file::commit(bool overwrite) { file.sync(); } - #endif #ifdef _WIN32 @@ -2486,16 +2492,130 @@ bool fs::pending_file::commit(bool overwrite) disp.DeleteFileW = false; ensure(SetFileInformationByHandle(file.get_handle(), FileDispositionInfo, &disp, sizeof(disp))); } + + std::vector hardlink_paths; + + const auto ws1 = to_wchar(m_path); + + const HANDLE file_handle = !overwrite ? INVALID_HANDLE_VALUE + : CreateFileW(ws1.get(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); + + while (file_handle != INVALID_HANDLE_VALUE) + { + // Get file ID (used to check for hardlinks) + BY_HANDLE_FILE_INFORMATION file_info; + + if (!GetFileInformationByHandle(file_handle, &file_info) || file_info.nNumberOfLinks == 1) + { + CloseHandle(file_handle); + break; + } + + // Buffer for holding link name + std::wstring link_name_buffer(MAX_PATH, wchar_t{}); + DWORD buffer_size{}; + HANDLE find_handle = INVALID_HANDLE_VALUE; + + while (true) + { + buffer_size = static_cast(link_name_buffer.size() - 1); + find_handle = FindFirstFileNameW(ws1.get(), 0, &buffer_size, link_name_buffer.data()); + + if (find_handle != INVALID_HANDLE_VALUE || GetLastError() != ERROR_MORE_DATA) + { + break; + } + + link_name_buffer.resize(buffer_size + 1); + } + + if (find_handle != INVALID_HANDLE_VALUE) + { + const std::wstring_view ws1_sv = ws1.get(); + + while (true) + { + if (link_name_buffer.c_str() != ws1_sv) + { + // Note: link_name_buffer is a buffer which may contain zeroes so truncate it + hardlink_paths.push_back(link_name_buffer.c_str()); + } + + buffer_size = static_cast(link_name_buffer.size() - 1); + if (!FindNextFileNameW(find_handle, &buffer_size, link_name_buffer.data())) + { + if (GetLastError() != ERROR_MORE_DATA) + { + break; + } + + link_name_buffer.resize(buffer_size + 1); + } + } + } + + // Clean up + FindClose(find_handle); + CloseHandle(file_handle); + break; + } + + if (!hardlink_paths.empty()) + { + // REPLACEFILE_WRITE_THROUGH is not supported + file.sync(); + } #endif file.close(); #ifdef _WIN32 - const auto ws1 = to_wchar(m_path); - const auto ws2 = to_wchar(m_dest); + const auto wdest = to_wchar(m_dest); - if (MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH)) + bool ok = false; + + if (hardlink_paths.empty()) { + ok = MoveFileExW(ws1.get(), wdest.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH); + } + else + { + ok = ReplaceFileW(ws1.get(), wdest.get(), nullptr, 0, nullptr, nullptr); + } + + if (ok) + { + for (const std::wstring& link_name : hardlink_paths) + { + std::unique_ptr write_temp_path; + + do + { + write_temp_path = to_wchar(fs::generate_neighboring_path(m_dest, 0)); + + // Generate a temporary hard linke + if (CreateHardLinkW(wdest.get(), write_temp_path.get(), nullptr)) + { + if (MoveFileExW(write_temp_path.get(), link_name.data(), MOVEFILE_REPLACE_EXISTING)) + { + // Success + write_temp_path.reset(); + break; + } + + break; + } + } + while (fs::g_tls_error == fs::error::exist); // Only retry if failed due to existing file + + if (write_temp_path) + { + // Failure + g_tls_error = to_error(GetLastError()); + return false; + } + } + // Disable the destructor m_path.clear(); return true; @@ -2557,6 +2677,17 @@ void fmt_class_string::format(std::string& out, u64 arg) template<> void fmt_class_string::format(std::string& out, u64 arg) { + if (arg == static_cast(fs::error::unknown)) + { + // Note: may not be the correct error code because it only prints the last +#ifdef _WIN32 + fmt::append(out, "Unknown error [errno=%d]", GetLastError()); +#else + fmt::append(out, "Unknown error [errno=%d]", errno); +#endif + return; + } + format_enum(out, arg, [](auto arg) { switch (arg) diff --git a/Utilities/File.h b/Utilities/File.h index c95bcbfc02..4c8a085131 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -601,6 +601,8 @@ namespace fs // Temporary directory const std::string& get_temp_dir(); + std::string generate_neighboring_path(std::string_view source, u64 seed); + // Unique pending file creation destined to be renamed to the destination file struct pending_file { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9b4ac02402..8c6c8f36b5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -38,13 +38,13 @@ jobs: displayName: ccache - bash: | - docker pull --quiet rpcs3/rpcs3-ci-focal:1.7.1 + docker pull --quiet rpcs3/rpcs3-ci-focal:1.9 docker run \ -v $(pwd):/rpcs3 \ --env-file .ci/docker.env \ -v $CCACHE_DIR:/root/.ccache \ -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \ - rpcs3/rpcs3-ci-focal:1.7.1 \ + rpcs3/rpcs3-ci-focal:1.9 \ /rpcs3/.ci/build-linux.sh displayName: Docker setup and build diff --git a/rpcs3/CMakeLists.txt b/rpcs3/CMakeLists.txt index a32dbc41a4..edd9dcf59d 100644 --- a/rpcs3/CMakeLists.txt +++ b/rpcs3/CMakeLists.txt @@ -132,29 +132,29 @@ if(APPLE) endif() qt_finalize_target(rpcs3) add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $/../Resources/rpcs3.icns - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/Icons $/../Resources/Icons - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/../Resources/GuiConfigs - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/git $/../Resources/git - COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}") + COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $/../Resources/rpcs3.icns + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $/../Resources/Icons + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/../Resources/GuiConfigs + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $/../Resources/git + COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}") elseif(UNIX) add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/Icons $/Icons) - add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/GuiConfigs) - add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_directory - ${CMAKE_SOURCE_DIR}/bin/git $/git) + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $/Icons + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/GuiConfigs + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $/git) elseif(WIN32) + if(MSVC) + add_custom_command(TARGET rpcs3 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/3rdparty/OpenAL/openal-soft/$/OpenAL32.dll $) + endif() add_custom_command(TARGET rpcs3 POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$" - COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --no-system-d3d-compiler --no-quick-import --plugindir "$,$/plugins,$/share/qt6/plugins>" --verbose 0 "$") + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $/Icons + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $/GuiConfigs + COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $/git + COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt + --no-translations --no-quick --no-system-d3d-compiler --no-quick-import + --plugindir "$,$/plugins,$/share/qt6/plugins>" + --verbose 0 "$") endif() # Unix installation diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 3bd62e9ed6..2d151341c3 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -478,6 +478,7 @@ target_sources(rpcs3_emu PRIVATE RSX/gcm_printing.cpp RSX/GL/GLCommonDecompiler.cpp RSX/GL/GLCompute.cpp + RSX/GL/GLDMA.cpp RSX/GL/GLDraw.cpp RSX/GL/GLFragmentProgram.cpp RSX/GL/GLGSRender.cpp @@ -503,6 +504,7 @@ target_sources(rpcs3_emu PRIVATE RSX/GL/OpenGL.cpp RSX/GL/upscalers/fsr1/fsr_pass.cpp RSX/GSRender.cpp + RSX/Host/RSXDMAWriter.cpp RSX/Null/NullGSRender.cpp RSX/NV47/FW/draw_call.cpp RSX/NV47/FW/reg_context.cpp diff --git a/rpcs3/Emu/Cell/Modules/cellSync.cpp b/rpcs3/Emu/Cell/Modules/cellSync.cpp index 5f281e3fed..99adf97c02 100644 --- a/rpcs3/Emu/Cell/Modules/cellSync.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSync.cpp @@ -472,7 +472,7 @@ error_code cellSyncQueuePush(ppu_thread& ppu, vm::ptr queue, vm:: u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_push_begin(ctrl, depth, &position); })) @@ -509,7 +509,7 @@ error_code cellSyncQueueTryPush(vm::ptr queue, vm::cptr buf u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_push_begin(ctrl, depth, &position); })) @@ -543,7 +543,7 @@ error_code cellSyncQueuePop(ppu_thread& ppu, vm::ptr queue, vm::p u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_pop_begin(ctrl, depth, &position); })) @@ -580,7 +580,7 @@ error_code cellSyncQueueTryPop(vm::ptr queue, vm::ptr buffe u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_pop_begin(ctrl, depth, &position); })) @@ -614,7 +614,7 @@ error_code cellSyncQueuePeek(ppu_thread& ppu, vm::ptr queue, vm:: u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_peek_begin(ctrl, depth, &position); })) @@ -651,7 +651,7 @@ error_code cellSyncQueueTryPeek(vm::ptr queue, vm::ptr buff u32 position; - while (!queue->ctrl.atomic_op([&](auto& ctrl) + while (!queue->ctrl.atomic_op([&](CellSyncQueue::ctrl_t& ctrl) { return CellSyncQueue::try_peek_begin(ctrl, depth, &position); })) diff --git a/rpcs3/Emu/Cell/RawSPUThread.cpp b/rpcs3/Emu/Cell/RawSPUThread.cpp index 91a1166eaa..dd621ae088 100644 --- a/rpcs3/Emu/Cell/RawSPUThread.cpp +++ b/rpcs3/Emu/Cell/RawSPUThread.cpp @@ -7,20 +7,30 @@ inline void try_start(spu_thread& spu) { - reader_lock lock(spu.run_ctrl_mtx); + bool notify = false; - if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value) + if (~spu.status_npc.load().status & SPU_STATUS_RUNNING) { - if (value.status & SPU_STATUS_RUNNING) + reader_lock lock(spu.run_ctrl_mtx); + + if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value) { - return false; - } + if (value.status & SPU_STATUS_RUNNING) + { + return false; + } - value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED); - return true; - }).second) + value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED); + return true; + }).second) + { + spu.state -= cpu_flag::stop; + notify = true; + } + } + + if (notify) { - spu.state -= cpu_flag::stop; spu.state.notify_one(); } }; diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 5c385c2238..0472acdf44 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -543,9 +543,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator template llvm::Value* _ptr(llvm::Value* base, llvm::Value* offset) { - const auto off = m_ir->CreateGEP(get_type(), base, offset); - const auto ptr = m_ir->CreateBitCast(off, get_type()); - return ptr; + return m_ir->CreateGEP(get_type(), base, offset); } template diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index 3f3a7ad6ae..af7b4644bc 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -1678,7 +1678,6 @@ void spu_thread::cpu_init() spurs_average_task_duration = 0; spurs_waited = false; spurs_entered_wait = false; - spurs_read_events = false; int_ctrl[0].clear(); int_ctrl[1].clear(); @@ -2699,7 +2698,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* bool ok = false; - std::tie(old, ok) = bits->fetch_op([&](auto& v) + std::tie(old, ok) = bits->fetch_op([&](u128& v) { if (v & wmask) { @@ -2797,7 +2796,7 @@ void spu_thread::do_dma_transfer(spu_thread* _this, const spu_mfc_cmd& args, u8* res += 127; // Release bits and notify - bits->atomic_op([&](auto& v) + bits->atomic_op([&](u128& v) { v &= ~wmask; }); @@ -4807,7 +4806,7 @@ bool spu_thread::process_mfc_cmd() getllar_spin_count = 0; getllar_busy_waiting_switch = umax; - u64 ntime; + u64 ntime = 0; rsx::reservation_lock rsx_lock(addr, 128); for (u64 i = 0; i != umax; [&]() @@ -4913,21 +4912,14 @@ bool spu_thread::process_mfc_cmd() // Avoid logging useless commands if there is no reservation const bool dump = g_cfg.core.mfc_debug && raddr; - const bool is_spurs_task_wait = pc == 0x11e4; + const bool is_spurs_task_wait = pc == 0x11e4 && spurs_addr != 0u - 0x80u; - do + if (!is_spurs_task_wait || spurs_addr != raddr || spurs_waited) + { + // + } + else if ((_ref(0x100 + 0x73) & (1u << index)) == 0 && (static_cast(rdata[0x73]) & (1u << index)) != 0) { - if (!is_spurs_task_wait) - { - break; - } - - if (spurs_addr != raddr || g_cfg.core.max_spurs_threads == g_cfg.core.max_spurs_threads.def || spurs_waited || spurs_read_events) - { - spurs_read_events = false; - break; - } - // Wait for other threads to complete their tasks (temporarily) u32 max_run = group->max_run; @@ -4973,14 +4965,25 @@ bool spu_thread::process_mfc_cmd() spurs_waited = true; spurs_entered_wait = true; - // Wait the duration of 4 tasks - const u64 spurs_wait_time = std::clamp(spurs_average_task_duration / spurs_task_count_to_calculate * 4, 3000, 100'000); + // Wait the duration of one and a half tasks + const u64 spurs_wait_time = std::clamp(spurs_average_task_duration / spurs_task_count_to_calculate * 3 / 2, 10'000, 100'000); spurs_wait_duration_last = spurs_wait_time; + if (spurs_last_task_timestamp) + { + const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; + spurs_average_task_duration -= avg_entry; + spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); + spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); + spurs_last_task_timestamp = 0; + } + while (true) { - if (is_stopped()) + if (is_stopped() || current - before >= spurs_wait_time) { + // Timed-out + group->spurs_running++; break; } @@ -5008,20 +5011,12 @@ bool spu_thread::process_mfc_cmd() } current = get_system_time(); - - if (current - before >= spurs_wait_time) - { - // Timed-out - group->spurs_running++; - break; - } } state += cpu_flag::temp; static_cast(test_stopped()); } } - while (false); if (do_putllc(ch_mfc_cmd)) { @@ -5029,19 +5024,50 @@ bool spu_thread::process_mfc_cmd() if (is_spurs_task_wait) { - const u64 current = get_system_time(); + const bool is_idle = (_ref(0x100 + 0x73) & (1u << index)) != 0; + const bool was_idle = (static_cast(rdata[0x73]) & (1u << index)) != 0; - if (spurs_last_task_timestamp) + if (!was_idle && is_idle) { - const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; - spurs_average_task_duration -= spurs_waited && !is_stopped() ? spurs_wait_duration_last + avg_entry : avg_entry; - spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); - } + const u32 prev_running = group->spurs_running.fetch_op([](u32& x) + { + if (x) + { + x--; + return true; + } - spurs_last_task_timestamp = current; - spurs_read_events = false; - spurs_waited = false; - spurs_entered_wait = false; + return false; + }).first; + + if (prev_running) + { + spurs_entered_wait = true; + } + + if (prev_running == group->max_run && prev_running < group->max_num) + { + group->spurs_running.notify_one(); + } + } + else if (was_idle && !is_idle) + { + // Cleanup + const u64 current = get_system_time(); + + if (spurs_last_task_timestamp) + { + const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate; + spurs_average_task_duration -= avg_entry; + spurs_average_task_duration += std::min(45'000, current - spurs_last_task_timestamp); + spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate); + spurs_last_task_timestamp = 0; + } + + spurs_last_task_timestamp = current; + spurs_waited = false; + spurs_entered_wait = false; + } } } else @@ -5560,6 +5586,8 @@ s64 spu_thread::get_ch_value(u32 ch) thread_ctrl::wait_on(state, old); } + + fmt::throw_exception("Unreachable"); // Fix unannotated fallthrough warning } case MFC_RdTagStat: @@ -5642,53 +5670,11 @@ s64 spu_thread::get_ch_value(u32 ch) auto events = get_events(mask1, false, true); - const bool is_spurs_task_wait = pc == 0x11a8 && spurs_addr == raddr; - if (events.count) { - if (is_spurs_task_wait) - { - spurs_read_events = true; - } - return events.events & mask1; } - if (is_spurs_task_wait) - { - spurs_read_events = true; - - if (g_cfg.core.max_spurs_threads != g_cfg.core.max_spurs_threads.def && !spurs_entered_wait) - { - const u32 prev_running = group->spurs_running.fetch_op([](u32& x) - { - if (x) - { - x--; - return true; - } - - return false; - }).first; - - if (prev_running) - { - spurs_entered_wait = true; - } - - if (prev_running == group->max_run && prev_running < group->max_num) - { - group->spurs_running.notify_one(); - - if (group->spurs_running == prev_running - 1) - { - // Try to let another thread slip in and take over execution - thread_ctrl::wait_for(300); - } - } - } - } - spu_function_logger logger(*this, "MFC Events read"); lv2_obj::prepare_for_sleep(*this); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index ecbab05389..2d91563a14 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -188,10 +188,10 @@ struct spu_channel_op_state struct alignas(16) spu_channel { // Low 32 bits contain value - atomic_t data; + atomic_t data{}; // Pending value to be inserted when it is possible in pop() or pop_wait() - atomic_t jostling_value; + atomic_t jostling_value{}; public: static constexpr u32 off_wait = 32; @@ -667,11 +667,11 @@ public: u8* reserv_base_addr = vm::g_reservations; // General-Purpose Registers - std::array gpr; - SPU_FPSCR fpscr; + std::array gpr{}; + SPU_FPSCR fpscr{}; // MFC command data - spu_mfc_cmd ch_mfc_cmd; + spu_mfc_cmd ch_mfc_cmd{}; // MFC command queue spu_mfc_cmd mfc_queue[16]{}; @@ -683,9 +683,9 @@ public: u64 mfc_last_timestamp = 0; // MFC proxy command data - spu_mfc_cmd mfc_prxy_cmd; + spu_mfc_cmd mfc_prxy_cmd{}; shared_mutex mfc_prxy_mtx; - atomic_t mfc_prxy_mask; + atomic_t mfc_prxy_mask = 0; // Tracks writes to MFC proxy command data union @@ -707,11 +707,11 @@ public: // Range Lock pointer atomic_t* range_lock{}; - u32 srr0; - u32 ch_tag_upd; - u32 ch_tag_mask; + u32 srr0 = 0; + u32 ch_tag_upd = 0; + u32 ch_tag_mask = 0; spu_channel ch_tag_stat; - u32 ch_stall_mask; + u32 ch_stall_mask = 0; spu_channel ch_stall_stat; spu_channel ch_atomic_stat; @@ -736,14 +736,14 @@ public: }; atomic_t ch_events; - bool interrupts_enabled; + bool interrupts_enabled = false; - u64 ch_dec_start_timestamp; // timestamp of writing decrementer value - u32 ch_dec_value; // written decrementer value + u64 ch_dec_start_timestamp = 0; // timestamp of writing decrementer value + u32 ch_dec_value = 0; // written decrementer value bool is_dec_frozen = false; std::pair read_dec() const; // Read decrementer - atomic_t run_ctrl; // SPU Run Control register (only provided to get latest data written) + atomic_t run_ctrl = 0; // SPU Run Control register (only provided to get latest data written) shared_mutex run_ctrl_mtx; struct alignas(8) status_npc_sync_var @@ -752,10 +752,10 @@ public: u32 npc; // SPU Next Program Counter register }; - atomic_t status_npc; - std::array int_ctrl; // SPU Class 0, 1, 2 Interrupt Management + atomic_t status_npc{}; + std::array int_ctrl{}; // SPU Class 0, 1, 2 Interrupt Management - std::array>, 32> spuq; // Event Queue Keys for SPU Thread + std::array>, 32> spuq{}; // Event Queue Keys for SPU Thread std::shared_ptr spup[64]; // SPU Ports spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits) atomic_t last_exit_status; // Value to be written in exit_status after checking group termination @@ -769,7 +769,6 @@ public: u32 spurs_addr = 0; bool spurs_waited = false; bool spurs_entered_wait = false; - bool spurs_read_events = false; u64 spurs_wait_duration_last = 0; u64 spurs_average_task_duration = 0; u64 spurs_last_task_timestamp = 0; diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index e4ed28fbcd..d30a516607 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1852,7 +1852,7 @@ void lv2_obj::schedule_all(u64 current_time) target->start_time = 0; - if ((target->state.fetch_op(FN(x += cpu_flag::signal, x -= cpu_flag::suspend, x-= remove_yield, void())) & (cpu_flag::wait + cpu_flag::signal)) != cpu_flag::wait) + if ((target->state.fetch_op(AOFN(x += cpu_flag::signal, x -= cpu_flag::suspend, x-= remove_yield, void())) & (cpu_flag::wait + cpu_flag::signal)) != cpu_flag::wait) { continue; } diff --git a/rpcs3/Emu/Cell/lv2/sys_event.cpp b/rpcs3/Emu/Cell/lv2/sys_event.cpp index 3047f87fa6..81f4ff65b0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event.cpp @@ -119,8 +119,13 @@ std::shared_ptr lv2_event_queue::find(u64 ipc_key) extern void resume_spu_thread_group_from_waiting(spu_thread& spu); -CellError lv2_event_queue::send(lv2_event event) +CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port) { + if (notified_thread) + { + *notified_thread = false; + } + std::lock_guard lock(mutex); if (!exists) @@ -162,6 +167,15 @@ CellError lv2_event_queue::send(lv2_event event) std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = event; awake(&ppu); + + if (port && ppu.prio.load().prio < ensure(cpu_thread::get_current())->prio.load().prio) + { + // Block event port disconnection for the time being of sending events + // PPU -> lower prio PPU is the only case that can cause thread blocking + port->is_busy++; + ensure(notified_thread); + *notified_thread = true; + } } else { @@ -709,7 +723,10 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id) return CELL_ENOTCONN; } - // TODO: return CELL_EBUSY if necessary (can't detect the condition) + if (port->is_busy) + { + return CELL_EBUSY; + } port->queue.reset(); @@ -718,20 +735,32 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id) error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) { - if (auto cpu = get_current_cpu_thread()) + const auto cpu = cpu_thread::get_current(); + const auto ppu = cpu ? cpu->try_get() : nullptr; + + if (cpu) { cpu->state += cpu_flag::wait; } sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3); + bool notified_thread = false; + const auto port = idm::check(eport_id, [&, notify = lv2_obj::notify_all_t()](lv2_event_port& port) -> CellError { + if (ppu && ppu->loaded_from_savestate) + { + port.is_busy++; + notified_thread = true; + return {}; + } + if (lv2_obj::check(port.queue)) { const u64 source = port.name ? port.name : (u64{process_getpid() + 0u} << 32) | u64{eport_id}; - return port.queue->send(source, data1, data2, data3); + return port.queue->send(source, data1, data2, data3, ¬ified_thread, ppu && port.queue->type == SYS_PPU_QUEUE ? &port : nullptr); } return CELL_ENOTCONN; @@ -742,6 +771,19 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3) return CELL_ESRCH; } + if (ppu && notified_thread) + { + // Wait to be requeued + if (ppu->test_stopped()) + { + // Wait again on savestate load + ppu->state += cpu_flag::again; + } + + port->is_busy--; + return CELL_OK; + } + if (port.ret) { if (port.ret == CELL_EAGAIN) diff --git a/rpcs3/Emu/Cell/lv2/sys_event.h b/rpcs3/Emu/Cell/lv2/sys_event.h index bf872cc4ba..506a45e7a0 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event.h +++ b/rpcs3/Emu/Cell/lv2/sys_event.h @@ -79,6 +79,8 @@ struct sys_event_t // Source, data1, data2, data3 using lv2_event = std::tuple; +struct lv2_event_port; + struct lv2_event_queue final : public lv2_obj { static const u32 id_base = 0x8d000000; @@ -103,11 +105,11 @@ struct lv2_event_queue final : public lv2_obj static void save_ptr(utils::serial&, lv2_event_queue*); static std::shared_ptr load_ptr(utils::serial& ar, std::shared_ptr& queue, std::string_view msg = {}); - CellError send(lv2_event event); + CellError send(lv2_event event, bool* notified_thread = nullptr, lv2_event_port* port = nullptr); - CellError send(u64 source, u64 d1, u64 d2, u64 d3) + CellError send(u64 source, u64 d1, u64 d2, u64 d3, bool* notified_thread = nullptr, lv2_event_port* port = nullptr) { - return send(std::make_tuple(source, d1, d2, d3)); + return send(std::make_tuple(source, d1, d2, d3), notified_thread, port); } // Get event queue by its global key @@ -121,6 +123,7 @@ struct lv2_event_port final : lv2_obj const s32 type; // Port type, either IPC or local const u64 name; // Event source (generated from id and process id if not set) + atomic_t is_busy = 0; // Counts threads waiting on event sending std::shared_ptr queue; // Event queue this port is connected to lv2_event_port(s32 type, u64 name) diff --git a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp index 7da6563517..c5e3ee9781 100644 --- a/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_event_flag.cpp @@ -357,16 +357,14 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn) } } - // Process all waiters in single atomic op - const u32 count = flag->pattern.atomic_op([&](u64& value) - { - value |= bitptn; - u32 count = 0; + u32 count = 0; - if (!flag->sq) - { - return count; - } + // Process all waiters in single atomic op + for (u64 pattern = flag->pattern, to_write = pattern, dependant_mask = 0;; to_write = pattern, dependant_mask = 0) + { + count = 0; + to_write |= bitptn; + dependant_mask = 0; for (auto ppu = +flag->sq; ppu; ppu = ppu->next_cpu) { @@ -405,10 +403,20 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn) const u64 pattern = ppu.gpr[4]; const u64 mode = ppu.gpr[5]; - if (lv2_event_flag::check_pattern(value, pattern, mode, &ppu.gpr[6])) + // If it's OR mode, set bits must have waken up the thread therefore no + // dependency on old value + const u64 dependant_mask_or = ((mode & 0xf) == SYS_EVENT_FLAG_WAIT_OR || (bitptn & pattern & to_write) == pattern ? 0 : pattern); + + if (lv2_event_flag::check_pattern(to_write, pattern, mode, &ppu.gpr[6])) { + dependant_mask |= dependant_mask_or; ppu.gpr[3] = CELL_OK; count++; + + if (!to_write) + { + break; + } } else { @@ -416,8 +424,29 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn) } } - return count; - }); + dependant_mask &= ~bitptn; + + auto [new_val, ok] = flag->pattern.fetch_op([&](u64& x) + { + if ((x ^ pattern) & dependant_mask) + { + return false; + } + + x |= bitptn; + + // Clear the bit-wise difference + x &= ~((pattern | bitptn) & ~to_write); + return true; + }); + + if (ok) + { + break; + } + + pattern = new_val; + } if (!count) { diff --git a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp index 20a210cbcb..7df939b738 100644 --- a/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_lwmutex.cpp @@ -142,7 +142,7 @@ error_code _sys_lwmutex_lock(ppu_thread& ppu, u32 lwmutex_id, u64 timeout) const auto mutex = idm::get(lwmutex_id, [&, notify = lv2_obj::notify_all_t()](lv2_lwmutex& mutex) { - if (s32 signal = mutex.lv2_control.fetch_op([](auto& data) + if (s32 signal = mutex.lv2_control.fetch_op([](lv2_lwmutex::control_data_t& data) { if (data.signaled) { @@ -297,7 +297,7 @@ error_code _sys_lwmutex_trylock(ppu_thread& ppu, u32 lwmutex_id) const auto mutex = idm::check(lwmutex_id, [&](lv2_lwmutex& mutex) { - auto [_, ok] = mutex.lv2_control.fetch_op([](auto& data) + auto [_, ok] = mutex.lv2_control.fetch_op([](lv2_lwmutex::control_data_t& data) { if (data.signaled & 1) { diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.cpp b/rpcs3/Emu/Cell/lv2/sys_memory.cpp index 6f519c0f69..41b24d79f8 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_memory.cpp @@ -93,7 +93,7 @@ std::shared_ptr reserve_map(u32 alloc_size, u32 align) // Todo: fix order of error checks -error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr) +error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr alloc_addr) { cpu.state += cpu_flag::wait; @@ -129,9 +129,9 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr(size), align)) { - if (const u32 addr = area->alloc(size, nullptr, align)) + if (const u32 addr = area->alloc(static_cast(size), nullptr, align)) { ensure(!g_fxo->get().addrs[addr >> 16].exchange(&dct)); @@ -139,7 +139,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr(size)); cpu.check_state(); *alloc_addr = addr; return CELL_OK; @@ -155,7 +155,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr) +error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr alloc_addr) { cpu.state += cpu_flag::wait; @@ -203,15 +203,15 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid return {ct.ret, ct->size - ct->used}; } - if (const auto area = reserve_map(size, align)) + if (const auto area = reserve_map(static_cast(size), align)) { - if (const u32 addr = area->alloc(size)) + if (const u32 addr = area->alloc(static_cast(size))) { ensure(!g_fxo->get().addrs[addr >> 16].exchange(ct.ptr.get())); if (alloc_addr) { - vm::lock_sudo(addr, size); + vm::lock_sudo(addr, static_cast(size)); cpu.check_state(); *alloc_addr = addr; return CELL_OK; @@ -320,7 +320,7 @@ error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr cid, u32 size) +error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u64 size) { cpu.state += cpu_flag::wait; @@ -345,7 +345,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u32 si } // Create the memory container - if (const u32 id = idm::make(size, true)) + if (const u32 id = idm::make(static_cast(size), true)) { cpu.check_state(); *cid = id; diff --git a/rpcs3/Emu/Cell/lv2/sys_memory.h b/rpcs3/Emu/Cell/lv2/sys_memory.h index 6143edc6df..5184aeed43 100644 --- a/rpcs3/Emu/Cell/lv2/sys_memory.h +++ b/rpcs3/Emu/Cell/lv2/sys_memory.h @@ -128,13 +128,13 @@ struct sys_memory_user_memory_stat_t }; // SysCalls -error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr alloc_addr); -error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid, u64 flags, vm::ptr alloc_addr); +error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr alloc_addr); +error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr alloc_addr); error_code sys_memory_free(cpu_thread& cpu, u32 start_addr); error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr attr); error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr mem_info); error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr mem_stat); -error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u32 size); +error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr cid, u64 size); error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid); error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr mem_info, u32 cid); error_code sys_memory_container_destroy_parent_with_childs(cpu_thread& cpu, u32 cid, u32 must_0, vm::ptr mc_child); diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 86f82c8d01..51b6721048 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -562,20 +562,48 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg); - const u32 option = attr->option; - - if (attr->name_len > 0x80 || option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE)) + if (spu_num >= std::size(decltype(lv2_spu_group::threads_map){})) { return CELL_EINVAL; } - sys_spu_image image; + if (!attr) + { + return CELL_EFAULT; + } - switch (img->type) + const sys_spu_thread_attribute attr_data = *attr; + + if (attr_data.name_len > 0x80) + { + return CELL_EINVAL; + } + + if (!arg) + { + return CELL_EFAULT; + } + + const sys_spu_thread_argument args = *arg; + const u32 option = attr_data.option; + + if (option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE)) + { + return CELL_EINVAL; + } + + if (!img) + { + return CELL_EFAULT; + } + + sys_spu_image image = *img; + + switch (image.type) { case SYS_SPU_IMAGE_TYPE_KERNEL: { - const auto handle = idm::get(img->entry_point); + const auto handle = idm::get(image.entry_point); if (!handle) { @@ -591,12 +619,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g } case SYS_SPU_IMAGE_TYPE_USER: { - if (img->entry_point > 0x3fffc || img->nsegs <= 0 || img->nsegs > 0x20) + if (image.entry_point > 0x3fffc || image.nsegs <= 0 || image.nsegs > 0x20) { return CELL_EINVAL; } - image = *img; break; } default: return CELL_EINVAL; @@ -672,7 +699,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g } // Read thread name - const std::string thread_name(attr->name.get_ptr(), std::max(attr->name_len, 1) - 1); + const std::string thread_name(attr_data.name.get_ptr(), std::max(attr_data.name_len, 1) - 1); const auto group = idm::get(group_id); @@ -681,11 +708,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g return CELL_ESRCH; } - if (spu_num >= group->threads_map.size()) - { - return CELL_EINVAL; - } - std::unique_lock lock(group->mutex); if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) @@ -725,7 +747,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, static_cast(vm::page_size_64k) | static_cast(vm::alloc_hidden))); spu->map_ls(*spu->shm, spu->ls); - group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4}; + group->args[inited] = {args.arg1, args.arg2, args.arg3, args.arg4}; group->imgs[inited].first = image.entry_point; group->imgs[inited].second = std::move(spu_segs); @@ -800,12 +822,14 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16; - if (attr->nsize > 0x80 || !num) + const sys_spu_thread_group_attribute attr_data = *attr; + + if (attr_data.nsize > 0x80 || !num) { return CELL_EINVAL; } - const s32 type = attr->type; + const s32 type = attr_data.type; bool use_scheduler = true; bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER); @@ -902,7 +926,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num if (use_memct && mem_size) { - const auto sct = idm::get(attr->ct); + const auto sct = idm::get(attr_data.ct); if (!sct) { @@ -936,7 +960,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr id, u32 num return CELL_EBUSY; } - const auto group = idm::make_ptr(std::string(attr->name.get_ptr(), std::max(attr->nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size); + const auto group = idm::make_ptr(std::string(attr_data.name.get_ptr(), std::max(attr_data.nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size); if (!group) { @@ -1807,6 +1831,11 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val sys_spu.trace("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value); + if (number > 1) + { + return CELL_EINVAL; + } + const auto [thread, group] = lv2_spu_group::get_thread(id); if (!thread) [[unlikely]] @@ -1814,11 +1843,6 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val return CELL_ESRCH; } - if (number > 1) - { - return CELL_EINVAL; - } - thread->push_snr(number, value); return CELL_OK; @@ -1895,21 +1919,19 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et if (!ep) { sys_spu.error("sys_spu_thread_group_disconnect_event(): unknown event type (%d)", et); - return CELL_EINVAL; + return CELL_OK; } + // No error checking is performed + std::lock_guard lock(group->mutex); - if (!lv2_obj::check(*ep)) - { - return CELL_EINVAL; - } - ep->reset(); + return CELL_OK; } -error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u8 spup) +error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u32 spup) { ppu.state += cpu_flag::wait; @@ -1943,7 +1965,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, return CELL_OK; } -error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 spup) +error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u32 spup) { ppu.state += cpu_flag::wait; @@ -2068,6 +2090,11 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i sys_spu.warning("sys_spu_thread_group_connect_event_all_threads(id=0x%x, eq=0x%x, req=0x%llx, spup=*0x%x)", id, eq, req, spup); + if (!req) + { + return CELL_EINVAL; + } + const auto group = idm::get(id); const auto queue = idm::get(eq); @@ -2076,11 +2103,6 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i return CELL_ESRCH; } - if (!req) - { - return CELL_EINVAL; - } - std::unique_lock lock(group->mutex); if (auto state = +group->run_state; @@ -2144,12 +2166,17 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i return CELL_OK; } -error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u8 spup) +error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u32 spup) { ppu.state += cpu_flag::wait; sys_spu.warning("sys_spu_thread_group_disconnect_event_all_threads(id=0x%x, spup=%d)", id, spup); + if (spup > 63) + { + return CELL_EINVAL; + } + const auto group = idm::get(id); if (!group) @@ -2157,11 +2184,6 @@ error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u3 return CELL_ESRCH; } - if (spup > 63) - { - return CELL_EINVAL; - } - std::lock_guard lock(group->mutex); for (auto& t : group->threads) diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.h b/rpcs3/Emu/Cell/lv2/sys_spu.h index 8b0b890b39..7ce2c8b2ef 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.h +++ b/rpcs3/Emu/Cell/lv2/sys_spu.h @@ -372,7 +372,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread&, u32 id, vm::ptr p error_code sys_spu_thread_group_connect_event(ppu_thread&, u32 id, u32 eq, u32 et); error_code sys_spu_thread_group_disconnect_event(ppu_thread&, u32 id, u32 et); error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread&, u32 id, u32 eq_id, u64 req, vm::ptr spup); -error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u8 spup); +error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u32 spup); error_code sys_spu_thread_group_set_cooperative_victims(ppu_thread&, u32 id, u32 threads_mask); error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr info); error_code sys_spu_thread_group_log(ppu_thread&, s32 command, vm::ptr stat); @@ -382,8 +382,8 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread&, u32 id, u32 value); error_code sys_spu_thread_set_spu_cfg(ppu_thread&, u32 id, u64 value); error_code sys_spu_thread_get_spu_cfg(ppu_thread&, u32 id, vm::ptr value); error_code sys_spu_thread_write_snr(ppu_thread&, u32 id, u32 number, u32 value); -error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8 spup); -error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u8 spup); +error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u32 spup); +error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u32 spup); error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num); error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num); error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr status); diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.cpp b/rpcs3/Emu/Cell/lv2/sys_ss.cpp index e0e23ab234..67f4e70148 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ss.cpp @@ -156,7 +156,7 @@ error_code sys_ss_random_number_generator(u64 pkg_id, vm::ptr buf, u64 siz error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3) { - sys_ss.todo("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3); + sys_ss.success("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3); const u64 authid = g_ps3_process_info.self_info.valid ? g_ps3_process_info.self_info.prog_id_hdr.program_authority_id : 0; @@ -167,7 +167,7 @@ error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3) { if (!g_ps3_process_info.debug_or_root()) { - return CELL_ENOSYS; + return not_an_error(CELL_ENOSYS); } if (!a2) diff --git a/rpcs3/Emu/Cell/lv2/sys_time.cpp b/rpcs3/Emu/Cell/lv2/sys_time.cpp index 389300bbf6..b04be640bc 100644 --- a/rpcs3/Emu/Cell/lv2/sys_time.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_time.cpp @@ -7,6 +7,7 @@ #include "Emu/Cell/timers.hpp" #include "util/asm.hpp" +#include "util/sysinfo.hpp" static u64 timebase_offset; static u64 systemtime_offset; @@ -146,6 +147,18 @@ u64 convert_to_timebased_time(u64 time) u64 get_timebased_time() { + if (u64 freq = utils::get_tsc_freq()) + { + const u64 tsc = utils::get_tsc(); + +#if _MSC_VER + const u64 result = static_cast(u128_from_mul(tsc, g_timebase_freq) / freq) * g_cfg.core.clocks_scale / 100u; +#else + const u64 result = (tsc / freq * g_timebase_freq + tsc % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u; +#endif + return result - timebase_offset; + } + while (true) { #ifdef _WIN32 @@ -155,7 +168,11 @@ u64 get_timebased_time() const u64 time = count.QuadPart; const u64 freq = s_time_aux_info.perf_freq; +#if _MSC_VER + const u64 result = static_cast(u128_from_mul(time * g_cfg.core.clocks_scale, g_timebase_freq) / freq / 100u); +#else const u64 result = (time / freq * g_timebase_freq + time % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u; +#endif #else struct timespec ts; ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0); @@ -190,6 +207,18 @@ void initialize_timebased_time(u64 timebased_init, bool reset) // Returns some relative time in microseconds, don't change this fact u64 get_system_time() { + if (u64 freq = utils::get_tsc_freq()) + { + const u64 tsc = utils::get_tsc(); + +#if _MSC_VER + const u64 result = static_cast(u128_from_mul(tsc, 1000000ull) / freq); +#else + const u64 result = (tsc / freq * 1000000ull + tsc % freq * 1000000ull / freq); +#endif + return result; + } + while (true) { #ifdef _WIN32 @@ -199,7 +228,11 @@ u64 get_system_time() const u64 time = count.QuadPart; const u64 freq = s_time_aux_info.perf_freq; +#if _MSC_VER + const u64 result = static_cast(u128_from_mul(time, 1000000ull) / freq); +#else const u64 result = time / freq * 1000000ull + (time % freq) * 1000000ull / freq; +#endif #else struct timespec ts; ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0); diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.cpp b/rpcs3/Emu/Cell/lv2/sys_vm.cpp index c520882341..273787e6c2 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_vm.cpp @@ -48,13 +48,18 @@ sys_vm_t::sys_vm_t(utils::serial& ar) g_fxo->get().total_vsize += size; } -error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) +error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { ppu.state += cpu_flag::wait; sys_vm.warning("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%x, policy=0x%x, addr=*0x%x)", vsize, psize, cid, flag, policy, addr); - if (!vsize || !psize || vsize % 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED) + if (!vsize || !psize || vsize % 0x200'0000 || vsize > 0x1000'0000 || psize % 0x1'0000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED) + { + return CELL_EINVAL; + } + + if (ppu.gpr[11] == 300 && psize < 0x10'0000) { return CELL_EINVAL; } @@ -68,16 +73,16 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 return CELL_ESRCH; } - if (!g_fxo->get().total_vsize.fetch_op([vsize](u32& size) + if (!g_fxo->get().total_vsize.fetch_op([vsize, has_root = g_ps3_process_info.has_root_perm()](u32& size) { // A single process can hold up to 256MB of virtual memory, even on DECR // VSH can hold more - if ((g_ps3_process_info.has_root_perm() ? 0x1E000000 : 0x10000000) - size < vsize) + if ((has_root ? 0x1E000000 : 0x10000000) - size < vsize) { return false; } - size += vsize; + size += static_cast(vsize); return true; }).second) { @@ -86,7 +91,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 if (!ct->take(psize)) { - g_fxo->get().total_vsize -= vsize; + g_fxo->get().total_vsize -= static_cast(vsize); return CELL_ENOMEM; } @@ -96,10 +101,10 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", addr, vsize); // Alloc all memory (shall not fail) - ensure(area->alloc(vsize)); - vm::lock_sudo(area->addr, vsize); + ensure(area->alloc(static_cast(vsize))); + vm::lock_sudo(area->addr, static_cast(vsize)); - idm::make(area->addr, vsize, ct, psize); + idm::make(area->addr, static_cast(vsize), ct, static_cast(psize)); // Write a pointer for the allocated memory ppu.check_state(); @@ -108,11 +113,11 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 } ct->free(psize); - g_fxo->get().total_vsize -= vsize; + g_fxo->get().total_vsize -= static_cast(vsize); return CELL_ENOMEM; } -error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) +error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr) { ppu.state += cpu_flag::wait; @@ -153,7 +158,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr) return CELL_OK; } -error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) +error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size) { ppu.state += cpu_flag::wait; @@ -176,7 +181,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) return CELL_ENOMEM; } - vmo.psize += size; + vmo.psize += static_cast(size); return {}; }); @@ -193,7 +198,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size) return CELL_OK; } -error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size) +error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size) { ppu.state += cpu_flag::wait; @@ -213,12 +218,12 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size) auto [_, ok] = vmo.psize.fetch_op([&](u32& value) { - if (value < 0x100000ull + size) + if (value <= size || value - size < 0x100000ull) { return false; } - value -= size; + value -= static_cast(size); return true; }); diff --git a/rpcs3/Emu/Cell/lv2/sys_vm.h b/rpcs3/Emu/Cell/lv2/sys_vm.h index f92c44564c..4d588b9200 100644 --- a/rpcs3/Emu/Cell/lv2/sys_vm.h +++ b/rpcs3/Emu/Cell/lv2/sys_vm.h @@ -58,11 +58,11 @@ struct sys_vm_t class ppu_thread; // SysCalls -error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); -error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); +error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); +error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr addr); error_code sys_vm_unmap(ppu_thread& ppu, u32 addr); -error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size); -error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size); +error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size); +error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size); error_code sys_vm_lock(ppu_thread& ppu, u32 addr, u32 size); error_code sys_vm_unlock(ppu_thread& ppu, u32 addr, u32 size); error_code sys_vm_touch(ppu_thread& ppu, u32 addr, u32 size); diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 1667aa3b1d..cc8734b10c 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -350,7 +350,6 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_ // Get the current motion values std::shared_ptr pad = std::make_shared(m_type, 0, 0, 0, 0); - pad->m_sensors.resize(preview_values.size(), AnalogSensor(0, 0, 0, 0, 0)); pad_ensemble binding{pad, device, nullptr}; get_extended_info(binding); @@ -505,18 +504,18 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad) pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK, mapping[button::skateboard_tilt_right], CELL_PAD_CTRL_PRESS_R1); } - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]); - pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]); + pad->m_sticks[0] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]); + pad->m_sticks[1] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]); + pad->m_sticks[2] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]); + pad->m_sticks[3] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z); - pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G); + pad->m_sensors[0] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X); + pad->m_sensors[1] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y); + pad->m_sensors[2] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z); + pad->m_sensors[3] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G); - pad->m_vibrateMotors.emplace_back(true, 0); - pad->m_vibrateMotors.emplace_back(false, 0); + pad->m_vibrateMotors[0] = VibrateMotor(true, 0); + pad->m_vibrateMotors[1] = VibrateMotor(false, 0); m_bindings.emplace_back(pad, pad_device, nullptr); diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index 75b9122137..e99b2edda3 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -417,6 +417,7 @@ struct AnalogStick std::map m_pressed_keys_min{}; // only used in keyboard_pad_handler std::map m_pressed_keys_max{}; // only used in keyboard_pad_handler + AnalogStick() {} AnalogStick(u32 offset, std::set key_codes_min, std::set key_codes_max) : m_offset(offset) , m_key_codes_min(std::move(key_codes_min)) @@ -447,6 +448,7 @@ struct VibrateMotor bool m_is_large_motor = false; u8 m_value = 0; + VibrateMotor() {} VibrateMotor(bool is_large_motor, u8 value) : m_is_large_motor(is_large_motor) , m_value(value) @@ -489,9 +491,9 @@ struct Pad u8 m_battery_level{0}; std::vector