diff --git a/.ci/deploy-mac-arm64.sh b/.ci/deploy-mac-arm64.sh index e7de472378..d556a9442b 100755 --- a/.ci/deploy-mac-arm64.sh +++ b/.ci/deploy-mac-arm64.sh @@ -48,24 +48,8 @@ echo "[InternetShortcut]" > Quickstart.url echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url echo "IconIndex=0" >> Quickstart.url -#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.dmg" -#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \ -#--window-size 800 400 \ -#--icon-size 100 \ -#--icon rpcs3.app 200 190 \ -#--add-file Quickstart.url Quickstart.url 400 20 \ -#--hide-extension rpcs3.app \ -#--hide-extension Quickstart.url \ -#--app-drop-link 600 185 \ -#--skip-jenkins \ -#--format ULMO \ -#"$DMG_FILEPATH" \ -#RPCS3.app -#FILESIZE=$(stat -f %z "$DMG_FILEPATH") -#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }') - ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z" -"$BREW_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url +"/opt/homebrew/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH") SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }') diff --git a/.ci/setup-windows.sh b/.ci/setup-windows.sh index 0924023228..f637cec9ad 100755 --- a/.ci/setup-windows.sh +++ b/.ci/setup-windows.sh @@ -8,7 +8,7 @@ QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g") QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]') QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}." QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}" -QT_SUFFIX="-Windows-Windows_11_23H2-${QT_VER_MSVC_UP}-Windows-Windows_11_23H2-X86_64.7z" +QT_SUFFIX="-Windows-Windows_11_24H2-${QT_VER_MSVC_UP}-Windows-Windows_11_24H2-X86_64.7z" QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}" QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}" QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}" diff --git a/.github/workflows/rpcs3.yml b/.github/workflows/rpcs3.yml index 6457334be8..2d5b29acf1 100644 --- a/.github/workflows/rpcs3.yml +++ b/.github/workflows/rpcs3.yml @@ -212,9 +212,9 @@ jobs: env: COMPILER: msvc QT_VER_MAIN: '6' - QT_VER: '6.9.3' + QT_VER: '6.10.0' QT_VER_MSVC: 'msvc2022' - QT_DATE: '202509261208' + QT_DATE: '202510021201' LLVM_VER: '19.1.7' VULKAN_VER: '1.3.268.0' VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5' diff --git a/3rdparty/7zip/7zip b/3rdparty/7zip/7zip index 395149956d..5e96a82794 160000 --- a/3rdparty/7zip/7zip +++ b/3rdparty/7zip/7zip @@ -1 +1 @@ -Subproject commit 395149956d696e6e3099d8b76d797437f94a6942 +Subproject commit 5e96a8279489832924056b1fa82f29d5837c9469 diff --git a/3rdparty/CMakeLists.txt b/3rdparty/CMakeLists.txt index 94c6069271..46307746a3 100644 --- a/3rdparty/CMakeLists.txt +++ b/3rdparty/CMakeLists.txt @@ -51,6 +51,14 @@ else() add_subdirectory(pugixml EXCLUDE_FROM_ALL) endif() +if (USE_SYSTEM_VULKAN_MEMORY_ALLOCATOR) + find_package(VulkanMemoryAllocator REQUIRED GLOBAL) + add_library(3rdparty::vulkanmemoryallocator ALIAS GPUOpen::VulkanMemoryAllocator) +else() + add_library(3rdparty_vulkanmemoryallocator INTERFACE) + target_include_directories(3rdparty_vulkanmemoryallocator INTERFACE GPUOpen/VulkanMemoryAllocator/include) + add_library(3rdparty::vulkanmemoryallocator ALIAS 3rdparty_vulkanmemoryallocator) +endif() # libusb if(CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD") @@ -92,9 +100,6 @@ add_subdirectory(hidapi) # glslang add_subdirectory(glslang EXCLUDE_FROM_ALL) -add_library(3rdparty_glslang INTERFACE) -target_link_libraries(3rdparty_glslang INTERFACE SPIRV) - # yaml-cpp add_subdirectory(yaml-cpp) @@ -388,7 +393,7 @@ add_library(3rdparty::wolfssl ALIAS wolfssl) add_library(3rdparty::libcurl ALIAS 3rdparty_libcurl) add_library(3rdparty::soundtouch ALIAS soundtouch) add_library(3rdparty::sdl3 ALIAS ${SDL3_TARGET}) -add_library(3rdparty::miniupnpc ALIAS libminiupnpc-static) +add_library(3rdparty::miniupnpc ALIAS 3rdparty_miniupnpc) add_library(3rdparty::rtmidi ALIAS rtmidi) add_library(3rdparty::opencv ALIAS ${OPENCV_TARGET}) add_library(3rdparty::fusion ALIAS Fusion) diff --git a/3rdparty/FAudio b/3rdparty/FAudio index e6ddfabab2..ba876ce3be 160000 --- a/3rdparty/FAudio +++ b/3rdparty/FAudio @@ -1 +1 @@ -Subproject commit e6ddfabab2efbc8765750039634fe5e24ac31205 +Subproject commit ba876ce3be73eabd7094fa276a751ede8328b608 diff --git a/3rdparty/cubeb/cubeb b/3rdparty/cubeb/cubeb index 70b4e3db78..e495bee4cd 160000 --- a/3rdparty/cubeb/cubeb +++ b/3rdparty/cubeb/cubeb @@ -1 +1 @@ -Subproject commit 70b4e3db7822de4d534959885cda109d6edbee36 +Subproject commit e495bee4cd630c9f99907a764e16edba37a4b564 diff --git a/3rdparty/curl/curl b/3rdparty/curl/curl index fdb8a789d2..11b991232f 160000 --- a/3rdparty/curl/curl +++ b/3rdparty/curl/curl @@ -1 +1 @@ -Subproject commit fdb8a789d2b446b77bd7cdd2eff95f6cbc814cf4 +Subproject commit 11b991232fbcaa88e2b1faecac224416b0001e35 diff --git a/3rdparty/curl/libcurl.vcxproj b/3rdparty/curl/libcurl.vcxproj index c4a96abdc4..e39805855d 100644 --- a/3rdparty/curl/libcurl.vcxproj +++ b/3rdparty/curl/libcurl.vcxproj @@ -70,6 +70,7 @@ + @@ -79,6 +80,7 @@ + @@ -86,6 +88,7 @@ + @@ -144,7 +147,6 @@ - @@ -199,7 +201,6 @@ - @@ -225,7 +226,6 @@ - @@ -233,7 +233,6 @@ - @@ -258,6 +257,7 @@ + @@ -271,8 +271,10 @@ + + @@ -280,6 +282,7 @@ + @@ -297,6 +300,7 @@ + @@ -345,7 +349,6 @@ - @@ -397,7 +400,6 @@ - @@ -415,14 +417,12 @@ - - diff --git a/3rdparty/curl/libcurl.vcxproj.filters b/3rdparty/curl/libcurl.vcxproj.filters index 32eb05f40e..4bd52daddf 100644 --- a/3rdparty/curl/libcurl.vcxproj.filters +++ b/3rdparty/curl/libcurl.vcxproj.filters @@ -159,9 +159,6 @@ Source Files - - Source Files - Source Files @@ -339,9 +336,6 @@ Source Files - - Source Files - Source Files @@ -360,9 +354,6 @@ Source Files - - Source Files - Source Files @@ -426,9 +417,6 @@ Source Files - - Source Files - Source Files @@ -549,6 +537,15 @@ Source Files + + Source Files + + + Source Files + + + Source Files + @@ -758,9 +755,6 @@ Header Files - - Header Files - Header Files @@ -899,9 +893,6 @@ Header Files - - Header Files - Header Files @@ -917,9 +908,6 @@ Header Files - - Header Files - Header Files @@ -989,9 +977,6 @@ Header Files - - Header Files - Header Files @@ -1112,6 +1097,21 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + diff --git a/3rdparty/glslang/CMakeLists.txt b/3rdparty/glslang/CMakeLists.txt index 5b6aa8e962..c86d0b384c 100644 --- a/3rdparty/glslang/CMakeLists.txt +++ b/3rdparty/glslang/CMakeLists.txt @@ -1,11 +1,23 @@ #glslang -set(ENABLE_PCH OFF CACHE BOOL "Enables Precompiled header" FORCE) -set(BUILD_EXTERNAL OFF CACHE BOOL "Build external dependencies in /External" FORCE) -set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "Skip installation" FORCE) -set(ENABLE_SPVREMAPPER OFF CACHE BOOL "Enables building of SPVRemapper" FORCE) -set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "Builds glslangValidator and spirv-remap" FORCE) -set(ENABLE_HLSL OFF CACHE BOOL "Enables HLSL input support" FORCE) -set(ENABLE_OPT OFF CACHE BOOL "Enables spirv-opt capability if present" FORCE) -set(ENABLE_CTEST OFF CACHE BOOL "Enables testing" FORCE) -add_subdirectory(glslang) +if(USE_SYSTEM_GLSLANG) + message(STATUS "RPCS3: using shared glslang") + find_package(glslang REQUIRED GLOBAL) + add_library(3rdparty_glslang INTERFACE) + target_link_libraries(3rdparty_glslang INTERFACE glslang::SPIRV) + get_target_property(SPIRV_INCLUDE_DIRS glslang::SPIRV INTERFACE_INCLUDE_DIRECTORIES) + list(TRANSFORM SPIRV_INCLUDE_DIRS APPEND "/glslang") + target_include_directories(3rdparty_glslang INTERFACE ${SPIRV_INCLUDE_DIRS}) +else() + set(ENABLE_PCH OFF CACHE BOOL "Enables Precompiled header" FORCE) + set(BUILD_EXTERNAL OFF CACHE BOOL "Build external dependencies in /External" FORCE) + set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "Skip installation" FORCE) + set(ENABLE_SPVREMAPPER OFF CACHE BOOL "Enables building of SPVRemapper" FORCE) + set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "Builds glslangValidator and spirv-remap" FORCE) + set(ENABLE_HLSL OFF CACHE BOOL "Enables HLSL input support" FORCE) + set(ENABLE_OPT OFF CACHE BOOL "Enables spirv-opt capability if present" FORCE) + set(ENABLE_CTEST OFF CACHE BOOL "Enables testing" FORCE) + add_subdirectory(glslang) + add_library(3rdparty_glslang INTERFACE) + target_link_libraries(3rdparty_glslang INTERFACE SPIRV) +endif() diff --git a/3rdparty/hidapi/CMakeLists.txt b/3rdparty/hidapi/CMakeLists.txt index e1e36ac13e..2d043d6936 100644 --- a/3rdparty/hidapi/CMakeLists.txt +++ b/3rdparty/hidapi/CMakeLists.txt @@ -1,22 +1,30 @@ # hidapi -set(BUILD_SHARED_LIBS FALSE CACHE BOOL "Don't build shared libs") -set(HIDAPI_INSTALL_TARGETS FALSE CACHE BOOL "Don't install anything") - -if(CMAKE_SYSTEM MATCHES "Linux") - set(HIDAPI_WITH_LIBUSB FALSE CACHE BOOL "Don't build with libusb for linux") -endif() - -add_library(3rdparty_hidapi INTERFACE) -add_subdirectory(hidapi EXCLUDE_FROM_ALL) - -if(APPLE) - target_link_libraries(3rdparty_hidapi INTERFACE hidapi_darwin "-framework CoreFoundation" "-framework IOKit") -elseif(CMAKE_SYSTEM MATCHES "Linux") - target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hidraw udev) -elseif(WIN32) - target_link_libraries(3rdparty_hidapi INTERFACE hidapi::hidapi hidapi::include Shlwapi.lib) -elseif(ANDROID) - target_link_libraries(3rdparty_hidapi INTERFACE hidapi::libusb) +if(USE_SYSTEM_HIDAPI) + message(STATUS "RPCS3: using shared hidapi") + pkg_check_modules(hidapi-hidraw REQUIRED IMPORTED_TARGET hidapi-hidraw) + add_library(3rdparty_hidapi INTERFACE) + target_link_libraries(3rdparty_hidapi INTERFACE PkgConfig::hidapi-hidraw) + target_include_directories(3rdparty_hidapi INTERFACE PkgConfig::hidapi-hidraw) else() - target_link_libraries(3rdparty_hidapi INTERFACE hidapi-libusb usb) + set(BUILD_SHARED_LIBS FALSE CACHE BOOL "Don't build shared libs") + set(HIDAPI_INSTALL_TARGETS FALSE CACHE BOOL "Don't install anything") + + if(CMAKE_SYSTEM MATCHES "Linux") + set(HIDAPI_WITH_LIBUSB FALSE CACHE BOOL "Don't build with libusb for linux") + endif() + + add_library(3rdparty_hidapi INTERFACE) + add_subdirectory(hidapi EXCLUDE_FROM_ALL) + + if(APPLE) + target_link_libraries(3rdparty_hidapi INTERFACE hidapi_darwin "-framework CoreFoundation" "-framework IOKit") + elseif(CMAKE_SYSTEM MATCHES "Linux") + target_link_libraries(3rdparty_hidapi INTERFACE hidapi-hidraw udev) + elseif(WIN32) + target_link_libraries(3rdparty_hidapi INTERFACE hidapi::hidapi hidapi::include Shlwapi.lib) + elseif(ANDROID) + target_link_libraries(3rdparty_hidapi INTERFACE hidapi::libusb) + else() + target_link_libraries(3rdparty_hidapi INTERFACE hidapi-libusb usb) + endif() endif() diff --git a/3rdparty/libsdl-org/SDL b/3rdparty/libsdl-org/SDL index c9a6709bd2..a8589a8422 160000 --- a/3rdparty/libsdl-org/SDL +++ b/3rdparty/libsdl-org/SDL @@ -1 +1 @@ -Subproject commit c9a6709bd21750f1ad9597be21abace78c6378c9 +Subproject commit a8589a84226a6202831a3d49ff4edda4acab9acd diff --git a/3rdparty/libsdl-org/SDL.vcxproj.filters b/3rdparty/libsdl-org/SDL.vcxproj.filters index 44d4e4ec9f..d6a29f2faf 100644 --- a/3rdparty/libsdl-org/SDL.vcxproj.filters +++ b/3rdparty/libsdl-org/SDL.vcxproj.filters @@ -172,9 +172,6 @@ {f48c2b17-1bee-4fec-a7c8-24cf619abe08} - - {653672cc-90ae-4eba-a256-6479f2c31804} - {00001967ea2801028a046a722a070000} diff --git a/3rdparty/miniupnp/CMakeLists.txt b/3rdparty/miniupnp/CMakeLists.txt index 93c3dc55cd..c40d4a5ebd 100644 --- a/3rdparty/miniupnp/CMakeLists.txt +++ b/3rdparty/miniupnp/CMakeLists.txt @@ -1,8 +1,21 @@ -option (UPNPC_BUILD_STATIC "Build static library" TRUE) -option (UPNPC_BUILD_SHARED "Build shared library" FALSE) -option (UPNPC_BUILD_TESTS "Build test executables" FALSE) -option (UPNPC_BUILD_SAMPLE "Build sample executables" FALSE) -option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) -option (UPNPC_NO_INSTALL "Disable installation" TRUE) +if(USE_SYSTEM_MINIUPNPC) + message(STATUS "RPCS3: using shared MiniUPnPc") + pkg_check_modules(MiniUPnPc REQUIRED IMPORTED_TARGET miniupnpc>=2.3.3) + add_library(3rdparty_miniupnpc INTERFACE) + target_link_libraries(3rdparty_miniupnpc INTERFACE PkgConfig::MiniUPnPc) + target_include_directories(3rdparty_miniupnpc INTERFACE PkgConfig::MiniUPnPc) + list(TRANSFORM MiniUPnPc_INCLUDE_DIRS APPEND "/miniupnpc") + target_include_directories(3rdparty_miniupnpc INTERFACE ${MiniUPnPc_INCLUDE_DIRS}) +else() + option (UPNPC_BUILD_STATIC "Build static library" TRUE) + option (UPNPC_BUILD_SHARED "Build shared library" FALSE) + option (UPNPC_BUILD_TESTS "Build test executables" FALSE) + option (UPNPC_BUILD_SAMPLE "Build sample executables" FALSE) + option (NO_GETADDRINFO "Define NO_GETADDRINFO" FALSE) + option (UPNPC_NO_INSTALL "Disable installation" TRUE) -add_subdirectory(miniupnp/miniupnpc EXCLUDE_FROM_ALL) + add_subdirectory(miniupnp/miniupnpc EXCLUDE_FROM_ALL) + add_library(3rdparty_miniupnpc INTERFACE) + target_link_libraries(3rdparty_miniupnpc INTERFACE libminiupnpc-static) + target_include_directories(3rdparty_miniupnpc INTERFACE libminiupnpc-static) +endif() diff --git a/3rdparty/opencv/opencv b/3rdparty/opencv/opencv index 50fb5e701d..67f53c26a7 160000 --- a/3rdparty/opencv/opencv +++ b/3rdparty/opencv/opencv @@ -1 +1 @@ -Subproject commit 50fb5e701d8b0d3fe8262ed84668a94cc8cbf0b1 +Subproject commit 67f53c26a701c2aeefd8033ec2f2079e04c438ca diff --git a/3rdparty/rtmidi/CMakeLists.txt b/3rdparty/rtmidi/CMakeLists.txt index 610f858c6d..b9dd286ce0 100644 --- a/3rdparty/rtmidi/CMakeLists.txt +++ b/3rdparty/rtmidi/CMakeLists.txt @@ -1,4 +1,12 @@ -option(RTMIDI_API_JACK "Compile with JACK support." OFF) -option(RTMIDI_BUILD_TESTING "Build test programs" OFF) -set(RTMIDI_TARGETNAME_UNINSTALL "uninstall-rpcs3-rtmidi") -add_subdirectory(rtmidi EXCLUDE_FROM_ALL) +if(USE_SYSTEM_RTMIDI) + message(STATUS "RPCS3: using shared RtMidi") + pkg_check_modules(RtMidi REQUIRED IMPORTED_TARGET rtmidi>=6.0.0) + add_library(rtmidi INTERFACE) + target_link_libraries(rtmidi INTERFACE PkgConfig::RtMidi) + target_include_directories(rtmidi INTERFACE PkgConfig::RtMidi) +else() + option(RTMIDI_API_JACK "Compile with JACK support." OFF) + option(RTMIDI_BUILD_TESTING "Build test programs" OFF) + set(RTMIDI_TARGETNAME_UNINSTALL "uninstall-rpcs3-rtmidi") + add_subdirectory(rtmidi EXCLUDE_FROM_ALL) +endif() diff --git a/BUILDING.md b/BUILDING.md index 311bbddeee..2de1dc1c50 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -19,26 +19,26 @@ The following tools are required to build RPCS3 on Windows 10 or later: with standalone **CMake** tool. - [Python 3.6+](https://www.python.org/downloads/) (add to PATH) -- [Qt 6.9.1](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) +- [Qt 6.10.0](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.9.1\msvc2022_64\` +- add and set the `QTDIR` environment variable, e.g. `\6.10.0\msvc2022_64\` - or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022) **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.LEGACYQtVisualStudioTools2022) instead. In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool): -- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `\6.9.1\msvc2022_64\` +- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `\6.10.0\msvc2022_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.9.1](https://www.qt.io/download-qt-installer) +- [Qt 6.10.0](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. - [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend) @@ -121,7 +121,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r ##### Configuring the Qt Plugin (if used) 1) go to `Extensions->Qt VS Tools->Qt Versions` -2) add the path to your Qt installation with compiler e.g. `\6.9.1\msvc2022_64`, version will fill in automatically +2) add the path to your Qt installation with compiler e.g. `\6.10.0\msvc2022_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**) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb3ea2e435..92be9ce329 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,12 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() endif() +if(APPLE OR WIN32) + set(USE_SYSTEM_OPENAL_DEFAULT OFF) +else() + set(USE_SYSTEM_OPENAL_DEFAULT ON) +endif() + option(USE_NATIVE_INSTRUCTIONS "USE_NATIVE_INSTRUCTIONS makes rpcs3 compile with -march=native, which is useful for local builds, but not good for packages." ON) option(WITH_LLVM "Enable usage of LLVM library" ON) option(BUILD_LLVM "Build LLVM from git submodule" OFF) @@ -37,20 +43,26 @@ option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON) option(USE_SYSTEM_FAUDIO "Prefer system FAudio instead of the builtin one" OFF) option(USE_SYSTEM_FFMPEG "Prefer system ffmpeg instead of the prebuild one" OFF) option(USE_SYSTEM_FLATBUFFERS "Prefer system flatbuffers instead of the builtin one" OFF) +option(USE_SYSTEM_GLSLANG "Prefer system glslang instead of the builtin one" OFF) +option(USE_SYSTEM_HIDAPI "Prefer system hidapi instead of the builtin one" OFF) option(USE_SYSTEM_LIBPNG "Prefer system libpng instead of the builtin one" OFF) option(USE_SYSTEM_LIBUSB "Prefer system libusb instead of the builtin one" OFF) +option(USE_SYSTEM_MINIUPNPC "Prefer system MiniUPnPc instead of the builtin one" OFF) option(USE_SYSTEM_MVK "Prefer system MoltenVK instead of the builtin one" OFF) -option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON) +option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ${USE_SYSTEM_OPENAL_DEFAULT}) option(USE_SYSTEM_OPENCV "Prefer system OpenCV instead of the builtin one" ON) option(USE_SYSTEM_PUGIXML "Prefer system pugixml instead of the builtin one" OFF) +option(USE_SYSTEM_RTMIDI "Prefer system RtMidi instead of the builtin one" OFF) option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" ON) -option(USE_SYSTEM_WOLFSSL "Prefer system MoltenVK instead of the builtin one" OFF) +option(USE_SYSTEM_VULKAN_MEMORY_ALLOCATOR "Prefer system Vulkan Memory Allocator instead of the builtin one" OFF) +option(USE_SYSTEM_WOLFSSL "Prefer system wolfSSL instead of the builtin one" OFF) option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON) -option(USE_SYSTEM_ZSTD "Prefer system zstd instead of the prebuild one" OFF) +option(USE_SYSTEM_ZSTD "Prefer system zstd instead of the builtin one" OFF) option(HAS_MEMORY_BREAKPOINTS "Add support for memory breakpoints to the interpreter" OFF) option(USE_LTO "Use LTO for building" ON) option(BUILD_RPCS3_TESTS "Build RPCS3 unit tests." OFF) option(RUN_RPCS3_TESTS "Run RPCS3 unit tests. Requires BUILD_RPCS3_TESTS" OFF) +option(USE_GAMEMODE "Choose whether to enable GameMode features or not." ON) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake") @@ -157,11 +169,10 @@ endif() ## Look for Gamemode if its installed on Linux if(LINUX) - find_program(GAMEMODE_FOUND gamemoded) ## Only works if gamemode is installed on system (might include lib32 case) - if(GAMEMODE_FOUND) + ## User chooses whether to Enable GameMode features or not + if(USE_GAMEMODE) add_compile_definitions(GAMEMODE_AVAILABLE) endif() - message(GAMEMODE_AVAILABLE="${GAMEMODE_AVAILABLE}") endif() # TODO: do real installation, including copying directory structure diff --git a/Utilities/Config.cpp b/Utilities/Config.cpp index 0c2a1fa2aa..cee928def7 100644 --- a/Utilities/Config.cpp +++ b/Utilities/Config.cpp @@ -166,6 +166,55 @@ bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max) return true; } +bool try_to_uint128(u128* out, std::string_view value) +{ + if (value.empty()) + { + if (out) cfg_log.error("cfg::try_to_uint128(): called with an empty string"); + return false; + } + + u64 result_low = 0, result_high = 0; + const char* start_high64 = value.data(); + const char* end = value.data() + value.size(); + + if (start_high64[0] == '0' && value.size() >= 2 && (start_high64[1] == 'x' || start_high64[1] == 'X')) + { + // Hex support + start_high64 += 2; + } + + const char* start_low64 = end - std::min(end - start_high64, 16); + + // Hexadecimal-only + constexpr int base = 16; + + auto ret = std::from_chars(start_low64, end, result_low, base); + + if (ret.ec != std::errc() || ret.ptr != end) + { + if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value); + return false; + } + + if (start_high64 == start_low64) + { + if (out) *out = result_low; + return true; + } + + ret = std::from_chars(start_high64, start_low64, result_high, base); + + if (ret.ec != std::errc() || ret.ptr != start_low64) + { + if (out) cfg_log.error("cfg::try_to_uint128('%s'): invalid integer", value); + return false; + } + + if (out) *out = result_low + (u128{result_high} << 64); + return true; +} + std::vector cfg::make_float_range(f64 min, f64 max) { return {std::to_string(min), std::to_string(max)}; @@ -278,6 +327,19 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string::format) f return true; } +std::string cfg::uint128::to_string(u128 value) noexcept +{ + std::string result = "0x"; + result.resize(result.size() + 32); + + for (u32 i = 0; i < 32; i++) + { + result[result.size() - 1 - i] = "0123456789ABCDEF"[static_cast(value >> (i * 4)) % 16]; + } + + return result; +} + std::vector cfg::try_to_enum_list(decltype(&fmt_class_string::format) func) { std::vector result; @@ -553,19 +615,12 @@ void cfg::node::from_default() } } -void cfg::_bool::from_default() +void cfg::node::restore_defaults() { - m_value = def; -} - -void cfg::string::from_default() -{ - m_value = def; -} - -void cfg::set_entry::from_default() -{ - m_set = {}; + for (auto& node : m_nodes) + { + node->restore_defaults(); + } } std::string cfg::map_entry::get_value(std::string_view key) diff --git a/Utilities/Config.h b/Utilities/Config.h index bd05c25220..35dcddc1a6 100644 --- a/Utilities/Config.h +++ b/Utilities/Config.h @@ -38,6 +38,7 @@ namespace cfg _enum, // cfg::_enum type _int, // cfg::_int type uint, // cfg::uint type + uint128, // cfg::uint128 type string, // cfg::string type set, // cfg::set_entry type map, // cfg::map_entry type @@ -90,6 +91,9 @@ namespace cfg // Reset defaults virtual void from_default() = 0; + // Restore default members + virtual void restore_defaults() = 0; + // Convert to string (optional) virtual std::string to_string() const { @@ -151,11 +155,15 @@ namespace cfg // Set default values void from_default() override; + + // Restore default members + void restore_defaults() override; }; class _bool final : public _base { atomic_t m_value; + bool original_def; public: bool def; @@ -163,6 +171,7 @@ namespace cfg _bool(node* owner, std::string name, bool def = false, bool dynamic = false) : _base(type::_bool, owner, std::move(name), dynamic) , m_value(def) + , original_def(def) , def(def) { } @@ -177,7 +186,15 @@ namespace cfg return m_value; } - void from_default() override; + void from_default() override + { + m_value = def; + } + + void restore_defaults() override + { + def = original_def; + } std::string to_string() const override { @@ -220,14 +237,16 @@ namespace cfg class _enum : public _base { atomic_t m_value; + T original_def; public: - const T def; + T def; - _enum(node* owner, const std::string& name, T value = {}, bool dynamic = false) + _enum(node* owner, const std::string& name, T def = {}, bool dynamic = false) : _base(type::_enum, owner, name, dynamic) - , m_value(value) - , def(value) + , m_value(def) + , original_def(def) + , def(def) { } @@ -256,6 +275,11 @@ namespace cfg m_value = def; } + void restore_defaults() override + { + def = original_def; + } + std::string to_string() const override { std::string result; @@ -300,6 +324,7 @@ namespace cfg using int_type = std::conditional_t= s32{smin} && Max <= s32{smax}, s32, s64>; atomic_t m_value; + int_type original_def; public: int_type def; @@ -311,6 +336,7 @@ namespace cfg _int(node* owner, const std::string& name, int_type def = std::min(Max, std::max(Min, 0)), bool dynamic = false) : _base(type::_int, owner, name, dynamic) , m_value(def) + , original_def(def) , def(def) { } @@ -330,6 +356,11 @@ namespace cfg m_value = def; } + void restore_defaults() override + { + def = original_def; + } + std::string to_string() const override { return std::to_string(m_value); @@ -372,6 +403,7 @@ namespace cfg using float_type = f64; atomic_t m_value; + float_type original_def; public: float_type def; @@ -383,6 +415,7 @@ namespace cfg _float(node* owner, const std::string& name, float_type def = std::min(Max, std::max(Min, 0)), bool dynamic = false) : _base(type::_int, owner, name, dynamic) , m_value(def) + , original_def(def) , def(def) { } @@ -402,6 +435,11 @@ namespace cfg m_value = def; } + void restore_defaults() override + { + def = original_def; + } + std::string to_string() const override { std::string result; @@ -464,6 +502,7 @@ namespace cfg using int_type = std::conditional_t; atomic_t m_value; + int_type original_def; public: int_type def; @@ -475,6 +514,7 @@ namespace cfg uint(node* owner, const std::string& name, int_type def = std::max(Min, 0), bool dynamic = false) : _base(type::uint, owner, name, dynamic) , m_value(def) + , original_def(def) , def(def) { } @@ -494,6 +534,11 @@ namespace cfg m_value = def; } + void restore_defaults() override + { + def = original_def; + } + std::string to_string() const override { return std::to_string(m_value); @@ -534,10 +579,91 @@ namespace cfg // Alias for 64 bit int using uint64 = uint<0, u64{umax}>; + // Unsigned 128-bit integer entry. + class uint128 final : public _base + { + using int_type = u128; + + atomic_t m_value{}; + int_type original_def = 0; + + public: + int_type def; + + uint128(node* owner, const std::string& name, int_type def = 0, bool dynamic = false) + : _base(type::uint128, owner, name, dynamic) + , m_value(def) + , original_def(def) + , def(def) + { + } + + operator int_type() const + { + return m_value; + } + + operator ullong() const + { + return static_cast(m_value.load()); + } + + int_type get() const + { + return m_value; + } + + void from_default() override + { + m_value = def; + } + + void restore_defaults() override + { + def = original_def; + } + + static std::string to_string(u128 value) noexcept; + + std::string to_string() const override + { + return to_string(m_value.load()); + } + + std::string def_to_string() const override + { + return to_string(def); + } + + bool from_string(std::string_view value, bool /*dynamic*/ = false) override + { + u128 result; + if (try_to_uint128(&result, value)) + { + m_value = result; + return true; + } + + return false; + } + + void set(u128 value) + { + m_value = value; + } + + std::vector to_list() const override + { + // Should not be used + return make_uint_range(0, 1); + } + }; + // Simple string entry with mutex class string : public _base { atomic_ptr m_value; + std::string original_def; public: std::string def; @@ -545,6 +671,7 @@ namespace cfg string(node* owner, std::string name, std::string def = {}, bool dynamic = false) : _base(type::string, owner, std::move(name), dynamic) , m_value(def) + , original_def(def) , def(std::move(def)) { } @@ -554,7 +681,15 @@ namespace cfg return *m_value.load().get(); } - void from_default() override; + void from_default() override + { + m_value = def; + } + + void restore_defaults() override + { + def = original_def; + } std::string to_string() const override { @@ -595,7 +730,14 @@ namespace cfg m_set = std::move(set); } - void from_default() override; + void from_default() override + { + m_set = {}; + } + + void restore_defaults() override + { + } std::vector to_list() const override { @@ -636,6 +778,10 @@ namespace cfg void erase(std::string_view key); void from_default() override; + + void restore_defaults() override + { + } }; class node_map_entry final : public map_entry @@ -665,6 +811,10 @@ namespace cfg void set_map(map_of_type&& map); void from_default() override; + + void restore_defaults() override + { + } }; struct device_info @@ -702,5 +852,9 @@ namespace cfg void set_map(map_of_type&& map); void from_default() override; + + void restore_defaults() override + { + } }; } diff --git a/Utilities/StrUtil.h b/Utilities/StrUtil.h index c28efda863..285718ac21 100644 --- a/Utilities/StrUtil.h +++ b/Utilities/StrUtil.h @@ -28,6 +28,9 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max); // Convert string to unsigned integer bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max); +// Convert string to unsigned int128_t +bool try_to_uint128(u128* out, std::string_view value); + // Convert string to float bool try_to_float(f64* out, std::string_view value, f64 min, f64 max); diff --git a/bin/GuiConfigs/Windows 11 (Dark Mode) by GustavoGraziano.qss b/bin/GuiConfigs/Windows 11 (Dark Mode) by GustavoGraziano.qss new file mode 100644 index 0000000000..20b8638862 --- /dev/null +++ b/bin/GuiConfigs/Windows 11 (Dark Mode) by GustavoGraziano.qss @@ -0,0 +1,1090 @@ +/* + Windows 11 (Dark Mode) + by GustavoGraziano + GitHub: "https://github.com/GustavoGraziano" + (2025/09/18) +*/ + + + + + +/* ----- GLOBAL QWIDGET ----- */ + +/* RESET */ +QWidget { + font-family: "Segoe UI"; + color: #FFFFFF; + background-color: transparent; + alternate-background-color: #2B2B2B; + border: none; +} + +QDockWidget QWidget, QTabWidget::pane { + border: none; +} + +QMainWindow { + background-color: #191919; +} + +QDialog { + background-color: #191919; +} + + +QWidget#cg_disasm, QWidget#trophy_manager { + background-color: #222222; +} + +QWidget#trophy_notification_frame { + background-color: #191919; + color: #FFFFFF; +} + + +/* TOOLTIP */ +QToolTip { + background-color: #2C2C2C; + color: #FFFFFF; + border: 1px solid #1C1C1C; + padding: 2px 6px; +} + + +/* DOCK */ +QDockWidget { + color: #FFFFFF; + titlebar-normal-icon: url("GuiConfigs/dark/window-undock.svg"); + titlebar-close-icon: url("GuiConfigs/dark/window-close.svg"); +} + +QDockWidget::title { + background-color: #222222; + border-width: 1px 0px; + border-style: solid; + border-color: #3A3A3A; + padding: 6px 0px; +} + +QDockWidget::float-button, QDockWidget::close-button { + background-color: transparent; +} + +QDockWidget::float-button:hover { + background-color: #424242; + border: none; + border-radius: 4px; +} + +QDockWidget::close-button:hover { + background-color: #E81123; + border: none; + border-radius: 4px; +} + + +/* TAB BAR */ +QTabBar::tab { + color: #FFFFFF; + padding: 8px 16px; + border: none; + border-radius: 6px; + margin: 0 8px 16px 0; + min-width: 65px; +} + +QTabBar::tab:hover { + background-color: #2D2D2D; +} + +QTabBar::tab:selected { + font-weight: bold; + color: #4CC2FF; + background-color: #2D2D2D; +} + +QTabBar::tab:selected:hover { + background-color: #292929; +} + + +/* SCROOL BAR */ +QScrollBar:vertical { + background-color: transparent; + width: 6px; + margin: 0px; +} + +QScrollBar::groove:vertical { + background-color: transparent; + border-radius: 3px; + margin: 0px; + width: 6px; +} + +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; + width: 0px; + background: none; + border: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: transparent; +} + +QScrollBar::handle:vertical { + background-color: #959595; + min-height: 20px; + border-radius: 2px; + border: none; + margin: 0px 1px; +} + +QScrollBar::handle:vertical:hover { + background-color: #959595; + border-radius: 3px; + min-width: 12px; + margin: 0px; +} + + +QScrollBar:horizontal { + background-color: transparent; + height: 6px; + margin: 0px; +} + +QScrollBar::groove:horizontal { + background-color: transparent; + border-radius: 3px; + margin: 0px; + height: 6px; +} + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + height: 0px; + width: 0px; + background: none; + border: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background-color: transparent; +} + +QScrollBar::handle:horizontal { + background-color: #959595; + min-width: 20px; + border-radius: 2px; + border: none; + margin: 1px 0px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #959595; + border-radius: 3px; + min-height: 12px; + margin: 0px; +} + + +/* PROGRESS BAR */ +QProgressBar { + font-size: 10px; + font-weight: bold; + color: #FFFFFF; + background-color: #373737; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #4CAF50; + border-radius: 4px; +} + +QProgressBar:disabled { + background-color: #3F3F3F; + border: 1px solid transparent; + color: #7E7E7E; +} + +QProgressBar::chunk:disabled { + background-color: #555555; +} + +QProgressBar:indeterminate { + background-color: #373737; +} + +QProgressBar::chunk:indeterminate { + background-color: #4CAF50; +} + + +/* CALENDAR */ +QCalendarWidget QWidget#qt_calendar_navigationbar { + background: #222222; + border-bottom: 1px solid #3A3A3A; +} + +QCalendarWidget QToolButton { + background-color: transparent; + border: none; + border-radius: 4px; +} + +QCalendarWidget QToolButton:hover { + color: #FFFFFF; + background-color: #383838; +} + +QCalendarWidget QToolButton#qt_calendar_prevmonth, QCalendarWidget QToolButton#qt_calendar_nextmonth { + width: 6px; + height: 6px; + padding: 0px 10px; +} + +QCalendarWidget QToolButton#qt_calendar_prevmonth { + qproperty-icon: url("GuiConfigs/dark/arrow-prev.svg"); +} + +QCalendarWidget QToolButton#qt_calendar_nextmonth { + qproperty-icon: url("GuiConfigs/dark/arrow-next.svg"); +} + +QCalendarWidget QAbstractItemView { + color: #FFFFFF; + background-color: #222222; + alternate-background-color: #222222; +} + +QCalendarWidget QAbstractItemView::item:selected { + color: #4CC2FF; + background-color: #383838; +} + +QCalendarWidget QAbstractItemView::item:hover { + color: #4CC2FF; +} + +QCalendarWidget QAbstractItemView:focus { + outline: none; +} + +QCalendarWidget QToolButton#qt_calendar_monthbutton::menu-indicator, QCalendarWidget QToolButton#qt_calendar_yearbutton::menu-indicator { + image: none; +} + + +/* TABLE / TABLE HEADER */ +QTableView { + color: #FFFFFF; + background-color: #191919; + border: none; + border-radius: 6px; + selection-background-color: #4D4D4D; +} + +QTableView::item:selected { + color: #FFFFFF; + background-color: #4D4D4D; +} + + +QHeaderView::section { + color: #DEDEDE; + background-color: #191919; + border: none; + padding: 6px 8px 0px; + border-left: 1px solid #636363; +} + +QHeaderView::section:first { + border-left: none; + border-top-left-radius: 6px; +} + +QHeaderView::section:hover { + background-color: #4D4D4D; +} + +QHeaderView::section:last { + border-top-right-radius: 6px; +} + + + + + +/* ----- GLOBAL FORM ----- */ + +/* BUTTONS */ +QPushButton { + color: #FFFFFF; + background-color: #373737; + border: 2px solid #3F3F3F; + border-radius: 4px; + min-width: 120px; + padding: 4px 8px; +} + +QPushButton:hover { + background-color: #3C3C3C; + border-color: #3F3F3F; +} + +QPushButton:pressed { + color: #D0D0D0; + background-color: #323232; + border-color: #3A3A3A; +} + +QPushButton:disabled { + color: #7E7E7E; + background-color: #343434; + border-color: #3A3A3A; +} + + +QDialog QDialogButtonBox QPushButton { + color: #000000; + background-color: #4CC2FF; + border-color: #5AC7FF; +} + +QDialog QDialogButtonBox QPushButton:hover { + background-color: #48B2E9; + border-color: #56B8EB; +} + +QDialog QDialogButtonBox QPushButton:pressed { + color: #22526A; + background-color: #45A4D5; + border-color: #45A4D5; +} + +QDialog QDialogButtonBox QPushButton:disabled { + color: #ABABAB; + background-color: #4C4C4C; + border-color: #4C4C4C; +} + + +/* RADIO BUTTON / CHECKBOX / LIST / TREE VIEW */ +QRadioButton, +QCheckBox, +QListWidget { + spacing: 6px; +} + + +QRadioButton::indicator, +QCheckBox::indicator, +QListWidget::indicator { + width: 14px; + height: 14px; +} + + +QListWidget, +QTreeView { + background-color: #222222; + border: 1px solid #555555; + border-radius: 4px; + padding: 4px; + outline: none; +} + +QListWidget::item, +QTreeWidget::item { + color: #FFFFFF; + border-radius: 4px; + padding: 4px; +} + +QListWidget::item:selected, QListWidget::item:selected:hover, +QTreeWidget::item:selected, QTreeWidget::item:selected:hover { + color: #FFFFFF; + background-color: #555555; +} + +QListWidget::item:hover, +QTreeWidget::item:hover { + background-color: #333333; +} + +QListWidget::item:disabled, +QTreeWidget::item:disabled { + color: #7E7E7E; +} + +QListWidget::item:alternate, +QTreeWidget::item:alternate { + background-color: #2A2A2A; +} + + +QTreeView::branch { + background: #222222; +} + + +QRadioButton::indicator:unchecked { + image: url("GuiConfigs/dark/radio-unchecked.svg"); +} + +QRadioButton::indicator:unchecked:hover { + image: url("GuiConfigs/dark/radio-unchecked-hover.svg"); +} + +QRadioButton::indicator:unchecked:pressed { + image: url("GuiConfigs/dark/radio-unchecked-pressed.svg"); +} + +QRadioButton::indicator:checked { + image: url("GuiConfigs/dark/radio-checked.svg"); +} + +QRadioButton::indicator:checked:hover { + image: url("GuiConfigs/dark/radio-checked-hover.svg"); +} + +QRadioButton::indicator:checked:pressed { + image: url("GuiConfigs/dark/radio-checked-pressed.svg"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url("GuiConfigs/dark/radio-disabled.svg"); +} + +QRadioButton::indicator:checked:disabled { + image: url("GuiConfigs/dark/radio-checked-disabled.svg"); +} + + +QCheckBox::indicator:unchecked, +QListWidget::indicator:unchecked { + image: url("GuiConfigs/dark/checkbox-unchecked.svg"); +} + +QCheckBox::indicator:unchecked:hover, +QListWidget::indicator:unchecked:hover { + image: url("GuiConfigs/dark/checkbox-unchecked-hover.svg"); +} + +QCheckBox::indicator:unchecked:pressed, +QListWidget::indicator:unchecked:pressed { + image: url("GuiConfigs/dark/checkbox-unchecked-pressed.svg"); +} + +QCheckBox::indicator:checked, +QListWidget::indicator:checked { + image: url("GuiConfigs/dark/checkbox-checked.svg"); +} + +QCheckBox::indicator:checked:hover, +QListWidget::indicator:checked:hover { + image: url("GuiConfigs/dark/checkbox-checked-hover.svg"); +} + +QCheckBox::indicator:checked:pressed, +QListWidget::indicator:checked:pressed { + image: url("GuiConfigs/dark/checkbox-checked-pressed.svg"); +} + +QCheckBox::indicator:indeterminate, +QListWidget::indicator:indeterminate { + image: url("GuiConfigs/dark/checkbox-indeterminate.svg"); +} + +QCheckBox::indicator:indeterminate:hover, +QListWidget::indicator:indeterminate:hover { + image: url("GuiConfigs/dark/checkbox-indeterminate-hover.svg"); +} + +QCheckBox::indicator:indeterminate:pressed, +QListWidget::indicator:indeterminate:pressed { + image: url("GuiConfigs/dark/checkbox-indeterminate-pressed.svg"); +} + +QCheckBox::indicator:unchecked:disabled, +QListWidget::indicator:unchecked:disabled { + image: url("GuiConfigs/dark/checkbox-disabled.svg"); +} + +QCheckBox::indicator:checked:disabled, +QListWidget::indicator:checked:disabled { + image: url("GuiConfigs/dark/checkbox-checked-disabled.svg"); +} + +QCheckBox::indicator:indeterminate:disabled, +QListWidget::indicator:indeterminate:disabled { + image: url("GuiConfigs/dark/checkbox-indeterminate-disabled.svg"); +} + + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url("GuiConfigs/dark/list-arrow-closed.svg"); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url("GuiConfigs/dark/list-arrow-open.svg"); +} + +QTreeView:disabled::branch:has-children:!has-siblings:closed, +QTreeView:disabled::branch:closed:has-children:has-siblings { + image: url("GuiConfigs/dark/list-arrow-closed-disabled.svg"); +} + +QTreeView:disabled::branch:open:has-children:!has-siblings, +QTreeView:disabled::branch:open:has-children:has-siblings { + image: url("GuiConfigs/dark/list-arrow-open-disabled.svg"); +} + + +/* COMBO BOX / DATE TIME */ +QComboBox, +QDateTimeEdit { + color: #FFFFFF; + background-color: #3E3E3E; + border: 1px solid #454545; + border-radius: 4px; + padding: 4px 8px; +} + +QComboBox:hover, +QDateTimeEdit:hover { + background-color: #434343; + border: 1px solid #454545; +} + +QComboBox:pressed, +QDateTimeEdit:pressed { + color: #D2D2D2; + background-color: #383838; + border: 1px solid #404040; + border-bottom: none; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +QComboBox:disabled, +QDateTimeEdit:disabled { + color: #7E7E7E; + background-color: #343434; + border: 1px solid #3A3A3A; +} + +QComboBox::drop-down, +QDateTimeEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: center right; + width: 10px; + height: 10px; + background: none; + border: none; + padding-right: 8px; + image: url("GuiConfigs/dark/arrow-down.svg"); +} + +QComboBox::drop-down:on, +QDateTimeEdit::drop-down:on { + image: url("GuiConfigs/dark/arrow-up.svg"); +} + +QComboBox::drop-down:disabled, +QDateTimeEdit::drop-down:disabled { + image: url("GuiConfigs/dark/arrow-down-disabled.svg"); +} + + +QComboBox QAbstractItemView { + color: #FFFFFF; + background-color: #222222; + border: 1px solid #3A3A3A; + border-radius: 4px; + padding: 4px; +} + +QComboBox QAbstractItemView::item { + color: #FFFFFF; + padding: 4px 6px; + background-color: transparent; + border-radius: 4px; +} + +QComboBox QAbstractItemView::item:selected { + background-color: #383838; +} + +QComboBox QAbstractItemView:focus { + outline: none; +} + + +/* SPIN BOX / DOUBLE SPIN BOX */ +QSpinBox, +QDoubleSpinBox { + color: #FFFFFF; + background-color: #3E3E3E; + border: 1px solid #454545; + border-radius: 4px; + padding: 5px 8px; +} + +QSpinBox::up-button, QSpinBox::down-button, +QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { + border-radius: 4px; + width: 8px; + height: 8px; + padding: 3px 4px; +} + +QSpinBox::up-button:hover, QSpinBox::down-button:hover, +QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { + background-color: #383838; +} + +QSpinBox:disabled, +QDoubleSpinBox:disabled { + color: #7E7E7E; + background-color: #343434; + border: 1px solid #3A3A3A; +} + +QSpinBox::up-button, +QDoubleSpinBox::up-button { + image: url("GuiConfigs/dark/arrow-up.svg"); +} + +QSpinBox::down-button, +QDoubleSpinBox::down-button { + image: url("GuiConfigs/dark/arrow-down.svg"); +} + +QSpinBox::up-button:disabled, +QDoubleSpinBox::up-button:disabled { + image: url("GuiConfigs/dark/arrow-up-disabled.svg"); +} + +QSpinBox::down-button:disabled, +QDoubleSpinBox::down-button:disabled { + image: url("GuiConfigs/dark/arrow-down-disabled.svg"); +} + + +/* SLIDER */ +QSlider::groove:horizontal { + background-color: #9F9F9F; + border-radius: 2px; + height: 4px; +} + +QSlider::groove:horizontal:disabled { + background-color: #5F5F5F; +} + +QSlider::handle:horizontal { + border-radius: 9px; + width: 18px; + height: 18px; + margin: -7px 0px; + image: url("GuiConfigs/dark/slider-handle.svg"); +} + +QSlider::handle:horizontal:hover { + image: url("GuiConfigs/dark/slider-handle-hover.svg"); +} + +QSlider::handle:horizontal:pressed { + image: url("GuiConfigs/dark/slider-handle-pressed.svg"); +} + +QSlider::handle:horizontal:disabled { + image: url("GuiConfigs/dark/slider-handle-disabled.svg"); +} + + +/* LINE EDIT */ +QLineEdit { + color: #FFFFFF; + background-color: #383838; + border: 1px solid transparent; + border-radius: 4px; + padding: 5px 8px; +} + +QLineEdit:hover { + background-color: #3D3D3D; + border-color: transparent; +} + +QLineEdit:focus { + background-color: #222222; + border: 1px solid #3A3A3A; + border-bottom: 2px solid #4CC2FF; +} + + +QDockWidget QLineEdit { + border: 1px solid transparent; + border-radius: 0; +} + +QDockWidget QLineEdit:focus { + background: #383838; + border: none; +} + + +/* GROUP BOX */ +QGroupBox { + background-color: #2B2B2B; + border: 1px solid #1D1D1D; + border-radius: 6px; + padding-top: 32px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + background-color: transparent; + border-bottom: 1px solid #1D1D1D; + padding: 8px 16px; + min-width: 9999px; +} + +QGroupBox QGroupBox::title { + border: none; +} + + + + + +/* ----- MAIN WINDOW ----- */ + +/* MENU BAR / MENU*/ +QMenuBar { + background-color: #2C2C2C; +} + +QMenuBar::item { + color: #FFFFFF; + background-color: transparent; + padding: 4px 8px; +} + +QMenuBar::item:selected { + background-color: #383838; +} + +QMenuBar::item:pressed { + background-color: #343434; +} + + +QMenu { + background-color: #2C2C2C; + border: 1px solid #131313; + padding: 4px 0px; +} + +QMenu::item { + color: #FFFFFF; + background-color: transparent; + border-radius: 4px; + padding: 8px 20px; + margin: 0px 4px; +} + +QMenu::item:selected { + background-color: #383838; +} + +QMenu::item:disabled { + color: #666666; + background-color: transparent; +} + +QMenu::separator { + height: 1px; + background: #131313; + margin: 4px 0px; +} + +QMenu::indicator, QMenu::right-arrow { + width: 8px; + height: 8px; +} + +QMenu::indicator { + padding-left: 6px; +} + +QMenu::indicator:checked { + image: url("GuiConfigs/dark/check-mark.svg"); +} + +QMenu::indicator:unchecked { + image: url("GuiConfigs/dark/empty.svg"); +} + +QMenu::right-arrow { + image: url("GuiConfigs/dark/arrow-right.svg"); + padding-right: 6px; +} + + +/* TOOLBAR */ +QToolBar { + background-color: #2C2C2C; + border-width: 1px 0px; + border-style: solid; + border-color: #3A3A3A; +} + + +/* TOOLBAR BUTTON */ +QToolButton { + color: #FFFFFF; + background-color: transparent; + border: none; + border-radius: 6px; + padding: 4px 0px; + margin: 4px; +} + +QToolButton:hover { + background-color: #383838; +} + +QToolButton:pressed { + background-color: #343434; +} + +QToolButton:disabled { + color: #666666; +} + + +/* TOOLBAR SLIDER */ +QToolBar#mw_toolbar QSlider { + border: 1px solid transparent; + border-radius: 6px; + margin: 16px 0px; + padding: 0px 16px; +} + +QToolBar#mw_toolbar QSlider:hover { + background-color: #383838; + border-color: transparent; +} + +QToolBar#mw_toolbar QSlider:pressed { + background-color: #343434; + border-color: transparent; +} + +QSlider#sizeSlider::groove:horizontal { + background-color: #9F9F9F; + border-radius: 2px; + height: 4px; +} + +QSlider#sizeSlider::handle:horizontal { + image: url("GuiConfigs/dark/slider-handle.svg"); + border-radius: 9px; + width: 18px; + height: 18px; + margin: -7px 0px; +} + +QSlider#sizeSlider::handle:horizontal:hover { + image: url("GuiConfigs/dark/slider-handle-hover.svg"); +} + +QSlider#sizeSlider::handle:horizontal:pressed { + image: url("GuiConfigs/dark/slider-handle-pressed.svg"); +} + + +/* TOOLBAR SEARCH */ +QLineEdit#mw_searchbar { + color: #FFFFFF; + background-color: #383838; + border: 1px solid transparent; + border-radius: 6px; + padding: 6px 12px; + margin: 16px 0px; +} + +QLineEdit#mw_searchbar:hover { + background-color: #3D3D3D; + border-color: transparent; +} + +QLineEdit#mw_searchbar:focus { + background-color: #222222; + border-color: #3A3A3A; + border-bottom: 2px solid #4CC2FF; +} + + +/* GAME LIST TABLE */ +QMainWindow QTableView, +QMainWindow QHeaderView::section:first, +QMainWindow QHeaderView::section:last { + border-radius: 0px; +} + + +/* GAME GRID BODY */ +#game_list_grid_item { + background-color: transparent; + border-radius: 6px; +} + +#game_list_grid_item:hover { + background-color: #4D4D4D; +} + +#game_list_grid_item:focus { + background-color: #292929; +} + +#game_list_grid_item_title_label { + background-color: transparent; +} + + +/* LOG TAB */ +QTabBar#tab_bar_log::tab { + text-transform: uppercase; + color: #FFFFFF; + background-color: transparent; + border: none; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + min-width: 80px; + padding: 8px 16px; + margin: 0; + margin-top: 8px; +} + +QTabBar#tab_bar_log::tab:selected, QTabBar#tab_bar_log::tab:selected:hover { + font-weight: normal; + color: #FFFFFF; + background-color: #0C0C0C; +} + +QTabBar#tab_bar_log::tab:hover { + background-color: #252525; +} + + +/* LOG CONSOLE / TTY CONSOLE */ +QPlainTextEdit#log_frame, QPlainTextEdit#tty_frame { + background-color: #0C0C0C; + border: none; + padding: 8px; +} + + +/* LOG CONSOLE TEXT */ +QLabel#log_level_fatal { + color: #D61A1B; +} + +QLabel#log_level_error { + color: #FF6D7E; +} + +QLabel#log_level_warning { + color: #FFED72; +} + +QLabel#log_level_todo { + color: #FFB270; +} + +QLabel#log_level_notice { + color: #BAA0F8; +} + +QLabel#log_level_success { + color: #A2E57B; +} + +QLabel#log_level_always { + color: #7CD5F1; +} + +QLabel#log_level_trace { + color: #576265; +} + +QLabel#log_stack { + color: #F2FFFC; +} + + + + + +/* ----- SETTINGS DIALOG ----- */ +QDialog#settings_dialog QTabWidget::pane { + margin-left: -8px; +} + + + + + +/* ----- PAD SETTINGS DIALOG ----- */ +QDialog#pad_settings_dialog QTabWidget::pane { + margin-left: -4px; +} + + +/* SOME CONTROLLER BUTTONS GROUP BOX */ +QGroupBox#gb_l1, QGroupBox#gb_select, QGroupBox#gb_start, QGroupBox#gb_r1, QGroupBox#gb_l3, QGroupBox#gb_r3, QGroupBox#gb_choose_class, QGroupBox#gb_battery { + margin-bottom: 6px; +} + + +/* CONTROLLER ICON */ +#l_controller { + color: #FFFFFF; + padding: 20px 0; +} + + + + + +/* PATCH MANAGER DIALOG */ +QGroupBox#gb_patch_info QGroupBox { + background-color: #202020; + border: none; + border-radius: 6px; + padding-top: 0; + margin-top: 32px; +} + +QGroupBox#gb_patch_info QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + background-color: transparent; + border: none; + padding: 0; + min-width: 0; + margin-top: 12px; +} diff --git a/bin/GuiConfigs/Windows 11 (Light Mode) by GustavoGraziano.qss b/bin/GuiConfigs/Windows 11 (Light Mode) by GustavoGraziano.qss new file mode 100644 index 0000000000..692691856f --- /dev/null +++ b/bin/GuiConfigs/Windows 11 (Light Mode) by GustavoGraziano.qss @@ -0,0 +1,1090 @@ +/* + Windows 11 (Light Mode) + by GustavoGraziano + GitHub: "https://github.com/GustavoGraziano" + (2025/09/18) +*/ + + + + + +/* ----- GLOBAL QWIDGET ----- */ + +/* RESET */ +QWidget { + font-family: "Segoe UI"; + color: #1B1B1B; + background-color: transparent; + alternate-background-color: #EDEDED; + border: none; +} + +QDockWidget QWidget, QTabWidget::pane { + border: none; +} + +QMainWindow { + background-color: #FFFFFF; +} + +QDialog { + background-color: #F3F3F3; +} + + +QWidget#cg_disasm, QWidget#trophy_manager { + background-color: #F3F3F3; +} + +QWidget#trophy_notification_frame { + background-color: #F3F3F3; + color: #1B1B1B; +} + + +/* TOOLTIP */ +QToolTip { + background-color: #F9F9F9; + color: #1A1A1A; + border: 1px solid #DEDEDE; + padding: 2px 6px; +} + + +/* DOCK */ +QDockWidget { + color: #1B1B1B; + titlebar-normal-icon: url("GuiConfigs/light/window-undock.svg"); + titlebar-close-icon: url("GuiConfigs/light/window-close.svg"); +} + +QDockWidget::title { + background-color: #EEEEEE; + border-width: 1px 0px; + border-style: solid; + border-color: #DEDEDE; + padding: 6px 0px; +} + +QDockWidget::float-button, QDockWidget::close-button { + background-color: transparent; +} + +QDockWidget::float-button:hover { + background-color: #DDDDDD; + border: none; + border-radius: 4px; +} + +QDockWidget::close-button:hover { + background-color: #FF4B3A; + border: none; + border-radius: 4px; +} + + +/* TAB BAR */ +QTabBar::tab { + color: #1A1A1A; + padding: 8px 16px; + border: none; + border-radius: 6px; + margin: 0 8px 16px 0; + min-width: 65px; +} + +QTabBar::tab:hover { + background-color: #EAEAEA; +} + +QTabBar::tab:selected { + font-weight: bold; + color: #0067C0; + background-color: #EAEAEA; +} + +QTabBar::tab:selected:hover { + background-color: #EDEDED; +} + + +/* SCROOL BAR */ +QScrollBar:vertical { + background-color: transparent; + width: 6px; + margin: 0px; +} + +QScrollBar::groove:vertical { + background-color: transparent; + border-radius: 3px; + margin: 0px; + width: 6px; +} + +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { + height: 0px; + width: 0px; + background: none; + border: none; +} + +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background-color: transparent; +} + +QScrollBar::handle:vertical { + background-color: #858585; + min-height: 20px; + border-radius: 2px; + border: none; + margin: 0px 1px; +} + +QScrollBar::handle:vertical:hover { + background-color: #858585; + border-radius: 3px; + min-width: 12px; + margin: 0px; +} + + +QScrollBar:horizontal { + background-color: transparent; + height: 6px; + margin: 0px; +} + +QScrollBar::groove:horizontal { + background-color: transparent; + border-radius: 3px; + margin: 0px; + height: 6px; +} + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { + height: 0px; + width: 0px; + background: none; + border: none; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal { + background-color: transparent; +} + +QScrollBar::handle:horizontal { + background-color: #858585; + min-width: 20px; + border-radius: 2px; + border: none; + margin: 1px 0px; +} + +QScrollBar::handle:horizontal:hover { + background-color: #858585; + border-radius: 3px; + min-height: 12px; + margin: 0px; +} + + +/* PROGRESS BAR */ +QProgressBar { + font-size: 10px; + font-weight: bold; + color: #1B1B1B; + background-color: #EDEDED; + border-radius: 4px; + text-align: center; +} + +QProgressBar::chunk { + background-color: #4CAF50; + border-radius: 4px; +} + +QProgressBar:disabled { + background-color: #FAFAFA; + border: 1px solid #ECECEC; + color: #A0A0A0; +} + +QProgressBar::chunk:disabled { + background-color: #579c7e; +} + +QProgressBar:indeterminate { + background-color: #373737; +} + +QProgressBar::chunk:indeterminate { + background-color: #4CAF50; +} + + +/* CALENDAR */ +QCalendarWidget QWidget#qt_calendar_navigationbar { + background-color: #F9F9F9; + border-bottom: 1px solid #E5E5E5; +} + +QCalendarWidget QToolButton { + background-color: transparent; + border: none; + border-radius: 4px; +} + +QCalendarWidget QToolButton:hover { + color: #1B1B1B; + background-color: #F0F0F0; +} + +QCalendarWidget QToolButton#qt_calendar_prevmonth, QCalendarWidget QToolButton#qt_calendar_nextmonth { + width: 6px; + height: 6px; + padding: 0px 10px; +} + +QCalendarWidget QToolButton#qt_calendar_prevmonth { + qproperty-icon: url("GuiConfigs/light/arrow-prev.svg"); +} + +QCalendarWidget QToolButton#qt_calendar_nextmonth { + qproperty-icon: url("GuiConfigs/light/arrow-next.svg"); +} + +QCalendarWidget QAbstractItemView { + color: #1B1B1B; + background-color: #F9F9F9; + alternate-background-color: #F9F9F9; +} + +QCalendarWidget QAbstractItemView::item:selected { + color: #0067C0; + background-color: #F0F0F0; +} + +QCalendarWidget QAbstractItemView::item:hover { + color: #0067C0; +} + +QCalendarWidget QAbstractItemView:focus { + outline: none; +} + +QCalendarWidget QToolButton#qt_calendar_monthbutton::menu-indicator, QCalendarWidget QToolButton#qt_calendar_yearbutton::menu-indicator { + image: none; +} + + +/* TABLE / TABLE HEADER */ +QTableView { + color: #1B1B1B; + background-color: #FFFFFF; + border: none; + border-radius: 6px; + selection-background-color: #CCE8FF; +} + +QTableView::item:selected { + color: #1B1B1B; + background-color: #CCE8FF; +} + + +QHeaderView::section { + background-color: #FFFFFF; + color: #4C607A; + padding: 6px 8px 0px; + border: none; + border-left: 1px solid #E5E5E5; +} + +QHeaderView::section:hover { + background-color: #D9EBF9; +} + +QHeaderView::section:first { + border-left: none; + border-top-left-radius: 6px; +} + +QHeaderView::section:last { + border-top-right-radius: 6px; +} + + + + + +/* ----- GLOBAL FORM ----- */ + +/* BUTTONS */ +QPushButton { + color: #1B1B1B; + background-color: #FEFEFE; + border: 2px solid #ECECEC; + border-radius: 4px; + min-width: 120px; + padding: 4px 8px; +} + +QPushButton:hover { + background-color: #FAFAFA; + border-color: #ECECEC; +} + +QPushButton:pressed { + color: #5F5F5F; + background-color: #FAFAFA; + border-color: #ECECEC; +} + +QPushButton:disabled { + color: #A0A0A0; + background-color: #FAFAFA; + border-color: #ECECEC; +} + + +QDialog QDialogButtonBox QPushButton { + color: #FFFFFF; + background-color: #0067C0; + border-color: #1473C5; +} + +QDialog QDialogButtonBox QPushButton:hover { + background-color: #1A76C6; + border-color: #2C80CA; +} + +QDialog QDialogButtonBox QPushButton:pressed { + color: #C2DAEF; + background-color: #3284CB; + border-color: #3284CB; +} + +QDialog QDialogButtonBox QPushButton:disabled { + color: #FFFFFF; + background-color: #C5C5C5; + border-color: #C5C5C5; +} + + +/* RADIO BUTTON / CHECKBOX / LIST / TREE VIEW */ +QRadioButton, +QCheckBox, +QListWidget { + spacing: 6px; +} + + +QRadioButton::indicator, +QCheckBox::indicator, +QListWidget::indicator { + width: 14px; + height: 14px; +} + + +QListWidget, +QTreeView { + background-color: #F9F9F9; + border: 1px solid #EEEEEE; + border-radius: 4px; + padding: 4px; + outline: none; +} + +QListWidget::item, +QTreeWidget::item { + color: #1B1B1B; + border-radius: 4px; + padding: 4px; +} + +QListWidget::item:selected, QListWidget::item:selected:hover, +QTreeWidget::item:selected, QTreeWidget::item:selected:hover { + color: #1B1B1B; + background-color: #CCE8FF; +} + +QListWidget::item:hover, +QTreeWidget::item:hover { + background-color: #E5F3FF; +} + +QListWidget::item:disabled, +QTreeWidget::item:disabled { + color: #A0A0A0; +} + +QListWidget::item:alternate, +QTreeWidget::item:alternate { + background-color: #F5F5F5; +} + + +QTreeView::branch { + background: #F9F9F9; +} + + +QRadioButton::indicator:unchecked { + image: url("GuiConfigs/light/radio-unchecked.svg"); +} + +QRadioButton::indicator:unchecked:hover { + image: url("GuiConfigs/light/radio-unchecked-hover.svg"); +} + +QRadioButton::indicator:unchecked:pressed { + image: url("GuiConfigs/light/radio-unchecked-pressed.svg"); +} + +QRadioButton::indicator:checked { + image: url("GuiConfigs/light/radio-checked.svg"); +} + +QRadioButton::indicator:checked:hover { + image: url("GuiConfigs/light/radio-checked-hover.svg"); +} + +QRadioButton::indicator:checked:pressed { + image: url("GuiConfigs/light/radio-checked-pressed.svg"); +} + +QRadioButton::indicator:unchecked:disabled { + image: url("GuiConfigs/light/radio-disabled.svg"); +} + +QRadioButton::indicator:checked:disabled { + image: url("GuiConfigs/light/radio-checked-disabled.svg"); +} + + +QCheckBox::indicator:unchecked, +QListWidget::indicator:unchecked { + image: url("GuiConfigs/light/checkbox-unchecked.svg"); +} + +QCheckBox::indicator:unchecked:hover, +QListWidget::indicator:unchecked:hover { + image: url("GuiConfigs/light/checkbox-unchecked-hover.svg"); +} + +QCheckBox::indicator:unchecked:pressed, +QListWidget::indicator:unchecked:pressed { + image: url("GuiConfigs/light/checkbox-unchecked-pressed.svg"); +} + +QCheckBox::indicator:checked, +QListWidget::indicator:checked { + image: url("GuiConfigs/light/checkbox-checked.svg"); +} + +QCheckBox::indicator:checked:hover, +QListWidget::indicator:checked:hover { + image: url("GuiConfigs/light/checkbox-checked-hover.svg"); +} + +QCheckBox::indicator:checked:pressed, +QListWidget::indicator:checked:pressed { + image: url("GuiConfigs/light/checkbox-checked-pressed.svg"); +} + +QCheckBox::indicator:indeterminate, +QListWidget::indicator:indeterminate { + image: url("GuiConfigs/light/checkbox-indeterminate.svg"); +} + +QCheckBox::indicator:indeterminate:hover, +QListWidget::indicator:indeterminate:hover { + image: url("GuiConfigs/light/checkbox-indeterminate-hover.svg"); +} + +QCheckBox::indicator:indeterminate:pressed, +QListWidget::indicator:indeterminate:pressed { + image: url("GuiConfigs/light/checkbox-indeterminate-pressed.svg"); +} + +QCheckBox::indicator:unchecked:disabled, +QListWidget::indicator:unchecked:disabled { + image: url("GuiConfigs/light/checkbox-disabled.svg"); +} + +QCheckBox::indicator:checked:disabled, +QListWidget::indicator:checked:disabled { + image: url("GuiConfigs/light/checkbox-checked-disabled.svg"); +} + +QCheckBox::indicator:indeterminate:disabled, +QListWidget::indicator:indeterminate:disabled { + image: url("GuiConfigs/light/checkbox-indeterminate-disabled.svg"); +} + + +QTreeView::branch:has-children:!has-siblings:closed, +QTreeView::branch:closed:has-children:has-siblings { + image: url("GuiConfigs/light/list-arrow-closed.svg"); +} + +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings { + image: url("GuiConfigs/light/list-arrow-open.svg"); +} + +QTreeView:disabled::branch:has-children:!has-siblings:closed, +QTreeView:disabled::branch:closed:has-children:has-siblings { + image: url("GuiConfigs/light/list-arrow-closed-disabled.svg"); +} + +QTreeView:disabled::branch:open:has-children:!has-siblings, +QTreeView:disabled::branch:open:has-children:has-siblings { + image: url("GuiConfigs/light/list-arrow-open-disabled.svg"); +} + + +/* COMBO BOX / DATE TIME */ +QComboBox, +QDateTimeEdit { + color: #1B1B1B; + background-color: #FEFEFE; + border: 1px solid #E5E5E5; + border-radius: 4px; + padding: 4px 8px; +} + +QComboBox:hover, +QDateTimeEdit:hover { + background-color: #F8F8F8; + border: 1px solid #E8E8E8; +} + +QComboBox:pressed, +QDateTimeEdit:pressed { + color: #5E5E5E; + background-color: #F7F7F7; + border: 1px solid #E8E8E8; + border-bottom: none; + border-bottom-left-radius: 0px; + border-bottom-right-radius: 0px; +} + +QComboBox:disabled, +QDateTimeEdit:disabled { + color: #A0A0A0; + background-color: #FAFAFA; + border: 1px solid #ECECEC; +} + +QComboBox::drop-down, +QDateTimeEdit::drop-down { + subcontrol-origin: padding; + subcontrol-position: center right; + width: 10px; + height: 10px; + background: none; + border: none; + padding-right: 8px; + image: url("GuiConfigs/light/arrow-down.svg"); +} + +QComboBox::drop-down:on, +QDateTimeEdit::drop-down:on { + image: url("GuiConfigs/light/arrow-up.svg"); +} + +QComboBox::drop-down:disabled, +QDateTimeEdit::drop-down:disabled { + image: url("GuiConfigs/light/arrow-down-disabled.svg"); +} + + +QComboBox QAbstractItemView { + color: #1B1B1B; + background-color: #F9F9F9; + border: 1px solid #E5E5E5; + border-radius: 4px; + padding: 4px; +} + +QComboBox QAbstractItemView::item { + color: #1B1B1B; + padding: 4px 6px; + background-color: transparent; + border-radius: 4px; +} + +QComboBox QAbstractItemView::item:selected { + background-color: #F0F0F0; +} + +QComboBox QAbstractItemView:focus { + outline: none; +} + + +/* SPIN BOX / DOUBLE SPIN BOX */ +QSpinBox, +QDoubleSpinBox { + color: #1B1B1B; + background-color: #FEFEFE; + border: 1px solid #ECECEC; + border-radius: 4px; + padding: 5px 8px; +} + +QSpinBox::up-button, QSpinBox::down-button, +QDoubleSpinBox::up-button, QDoubleSpinBox::down-button { + border-radius: 4px; + width: 8px; + height: 8px; + padding: 3px 4px; +} + +QSpinBox::up-button:hover, QSpinBox::down-button:hover, +QDoubleSpinBox::up-button:hover, QDoubleSpinBox::down-button:hover { + background-color: #ECECEC; +} + +QSpinBox:disabled, +QDoubleSpinBox:disabled { + color: #A0A0A0; + background-color: #FAFAFA; + border: 1px solid #ECECEC; +} + +QSpinBox::up-button, +QDoubleSpinBox::up-button { + image: url("GuiConfigs/light/arrow-up.svg"); +} + +QSpinBox::down-button, +QDoubleSpinBox::down-button { + image: url("GuiConfigs/light/arrow-down.svg"); +} + +QSpinBox::up-button:disabled, +QDoubleSpinBox::up-button:disabled { + image: url("GuiConfigs/light/arrow-up-disabled.svg"); +} + +QSpinBox::down-button:disabled, +QDoubleSpinBox::down-button:disabled { + image: url("GuiConfigs/light/arrow-down-disabled.svg"); +} + + +/* SLIDER */ +QSlider::groove:horizontal { + background-color: #8B8B8B; + border-radius: 2px; + height: 4px; +} + +QSlider::groove:horizontal:disabled { + background-color: #ABABAB; +} + +QSlider::handle:horizontal { + image: url("GuiConfigs/light/slider-handle.svg"); + border-radius: 9px; + width: 18px; + height: 18px; + margin: -7px 0px; +} + +QSlider::handle:horizontal:hover { + image: url("GuiConfigs/light/slider-handle-hover.svg"); +} + +QSlider::handle:horizontal:pressed { + image: url("GuiConfigs/light/slider-handle-pressed.svg"); +} + +QSlider::handle:horizontal:disabled { + image: url("GuiConfigs/light/slider-handle-disabled.svg"); +} + + +/* LINE EDIT */ +QLineEdit { + color: #1B1B1B; + background-color: #FDFDFD; + border: 1px solid #EAEAEA; + border-radius: 4px; + padding: 5px 8px; +} + +QLineEdit:hover { + background-color: #F9F9F9; + border-color: #EAEAEA; +} + +QLineEdit:focus { + background-color: #FFFFFF; + border-color: #EAEAEA; + border-bottom: 2px solid #0067C0; +} + + +QDockWidget QLineEdit { + border: 1px solid transparent; + border-radius: 0; +} + +QDockWidget QLineEdit:focus { + background: #FDFDFD; + border: none; +} + + +/* GROUP BOX */ +QGroupBox { + background-color: #FBFBFB; + border: 1px solid #E5E5E5; + border-radius: 6px; + padding-top: 32px; +} + +QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top center; + background-color: transparent; + border-bottom: 1px solid #E5E5E5; + padding: 8px 16px; + min-width: 9999px; +} + +QGroupBox QGroupBox::title { + border: none; +} + + + + + +/* ----- MAIN WINDOW ----- */ + +/* MENU BAR / MENU */ +QMenuBar { + background-color: #F8F8F8; +} + +QMenuBar::item { + color: #1B1B1B; + background-color: transparent; + padding: 4px 8px; +} + +QMenuBar::item:selected { + background-color: #EFEFEF; +} + +QMenuBar::item:pressed { + background-color: #F2F2F2; +} + + +QMenu { + background-color: #F9F9F9; + border: 1px solid #EEEEEE; + padding: 4px 0px; +} + +QMenu::item { + color: #1B1B1B; + background-color: transparent; + border-radius: 4px; + padding: 8px 20px; + margin: 0px 4px; +} + +QMenu::item:selected { + background-color: #F0F0F0; +} + +QMenu::item:disabled { + color: #A0A0A0; + background-color: transparent; +} + +QMenu::separator { + height: 1px; + background: #EEEEEE; + margin: 4px 0px; +} + +QMenu::indicator, QMenu::right-arrow { + width: 8px; + height: 8px; +} + +QMenu::indicator { + padding-left: 6px; +} + +QMenu::indicator:checked { + image: url("GuiConfigs/light/check-mark.svg"); +} + +QMenu::indicator:unchecked { + image: url("GuiConfigs/light/empty.svg"); +} + +QMenu::right-arrow { + image: url("GuiConfigs/light/arrow-right.svg"); + padding-right: 6px; +} + + +/* TOOLBAR */ +QToolBar { + background-color: #F8F8F8; + border-width: 1px 0px; + border-style: solid; + border-color: #DEDEDE; +} + + +/* TOOLBAR BUTTON */ +QToolButton { + color: #1B1B1B; + background-color: transparent; + border: none; + border-radius: 6px; + padding: 4px 0px; + margin: 4px; +} + +QToolButton:hover { + background-color: #EFEFEF; +} + +QToolButton:pressed { + background-color: #F2F2F2; +} + +QToolButton:disabled { + color: #A0A0A0; +} + + +/* TOOLBAR SLIDER */ +QToolBar#mw_toolbar QSlider { + border: 1px solid transparent; + border-radius: 6px; + margin: 16px 0px; + padding: 0px 16px; +} + +QToolBar#mw_toolbar QSlider:hover { + background-color: #FDFDFD; + border-color: #EAEAEA; +} + +QToolBar#mw_toolbar QSlider:pressed { + background-color: #F9F9F9; + border-color: #EAEAEA; +} + +QSlider#sizeSlider::groove:horizontal { + background-color: #8B8B8B; + border-radius: 2px; + height: 4px; +} + +QSlider#sizeSlider::handle:horizontal { + image: url("GuiConfigs/light/slider-handle.svg"); + border-radius: 9px; + width: 18px; + height: 18px; + margin: -7px 0px; +} + +QSlider#sizeSlider::handle:horizontal:hover { + image: url("GuiConfigs/light/slider-handle-hover.svg"); +} + +QSlider#sizeSlider::handle:horizontal:pressed { + image: url("GuiConfigs/light/slider-handle-pressed.svg"); +} + + +/* TOOLBAR SEARCH */ +QLineEdit#mw_searchbar { + color: #1B1B1B; + background-color: #FDFDFD; + border: 1px solid transparent; + border-radius: 6px; + padding: 6px 12px; + margin: 16px 0px; +} + +QLineEdit#mw_searchbar:hover { + background-color: #F9F9F9; + border-color: #EAEAEA; +} + +QLineEdit#mw_searchbar:focus { + background-color: #FFFFFF; + border-color: #EAEAEA; + border-bottom: 2px solid #0067C0; +} + + +/* GAME LIST TABLE */ +QMainWindow QTableView, +QMainWindow QHeaderView::section:first, +QMainWindow QHeaderView::section:last { + border-radius: 0px; +} + + +/* GAME GRID BODY */ +#game_list_grid_item { + background-color: transparent; + border-radius: 6px; +} + +#game_list_grid_item:hover { + background-color: #E5F3FF; +} + +#game_list_grid_item:focus { + background-color: #CCE8FF; +} + +#game_list_grid_item_title_label { + background-color: transparent; +} + + +/* LOG TAB */ +QTabBar#tab_bar_log::tab { + text-transform: uppercase; + color: #1B1B1B; + background-color: transparent; + border: none; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + min-width: 80px; + padding: 8px 16px; + margin: 0; + margin-top: 8px; +} + +QTabBar#tab_bar_log::tab:selected, QTabBar#tab_bar_log::tab:selected:hover { + font-weight: normal; + color: #1B1B1B; + background-color: #FAF4F2; +} + +QTabBar#tab_bar_log::tab:hover { + background-color: #ede5e7; +} + + +/* LOG CONSOLE / TTY CONSOLE */ +QPlainTextEdit#log_frame, QPlainTextEdit#tty_frame { + background-color: #FAF4F2; + border: none; + padding: 8px; +} + + +/* LOG CONSOLE TEXT */ +QLabel#log_level_fatal { + color: #FC3D3C; +} + +QLabel#log_level_error { + color: #E14775; +} + +QLabel#log_level_warning { + color: #CC7A0A; +} + +QLabel#log_level_todo { + color: #E16032; +} + +QLabel#log_level_notice { + color: #7058BE; +} + +QLabel#log_level_success { + color: #269D69; +} + +QLabel#log_level_always { + color: #1C8CA8; +} + +QLabel#log_level_trace { + color: #A59FA0; +} + +QLabel#log_stack { + color: #29242A; +} + + + + + +/* ----- SETTINGS DIALOG ----- */ +QDialog#settings_dialog QTabWidget::pane { + margin-left: -8px; +} + + + + + +/* ----- PAD SETTINGS DIALOG ----- */ +QDialog#pad_settings_dialog QTabWidget::pane { + margin-left: -4px; +} + + +/* SOME CONTROLLER BUTTONS GROUP BOX */ +QGroupBox#gb_l1, QGroupBox#gb_select, QGroupBox#gb_start, QGroupBox#gb_r1, QGroupBox#gb_l3, QGroupBox#gb_r3, QGroupBox#gb_choose_class, QGroupBox#gb_battery { + margin-bottom: 6px; +} + + +/* CONTROLLER ICON */ +#l_controller { + color: #1B1B1B; + padding: 20px 0; +} + + + + + +/* PATCH MANAGER DIALOG */ +QGroupBox#gb_patch_info QGroupBox { + background-color: #F3F3F3; + border: none; + border-radius: 6px; + padding-top: 0; + margin-top: 32px; +} + +QGroupBox#gb_patch_info QGroupBox::title { + subcontrol-origin: margin; + subcontrol-position: top left; + background-color: transparent; + border: none; + padding: 0; + min-width: 0; + margin-top: 12px; +} diff --git a/bin/GuiConfigs/YoRHa by Ani.qss b/bin/GuiConfigs/YoRHa by Ani.qss index c3345d4cd9..bcfd059c2e 100644 --- a/bin/GuiConfigs/YoRHa by Ani.qss +++ b/bin/GuiConfigs/YoRHa by Ani.qss @@ -4,24 +4,28 @@ by Ani @ https://github.com/AniLeo r1 (2018.02.27) r2 (2021.08.28) r3 (2022.08.20) +r4 (2025.09.14) */ /* Color Scheme - Pod Programs -8c806a -bd9d86 -c1b398 -eadfb1 -ebe4d2 +#8c806a +#bd9d86 +#c1b398 +#eadfb1 +#ebe4d2 - Light -b3ac98 -aea993 +#b3ac98 +#aea993 - Dark -4d4940 +#4d4940 + +- Disabled +#828790 */ @@ -55,31 +59,6 @@ QTextEdit, QPlainTextEdit { font-size: 8.50pt; } -/* - QListWidget, QTreeWidget: Style checkboxes and rows - - RPCS3: LLE/HLE Selector, Debugger -*/ -QListWidget::item { - margin-top: 0.05em; - margin-bottom: 0.05em; -} -QListWidget::indicator, QTreeWidget::indicator { - border: 0.05em solid #4d4940; -} -QListWidget::indicator::unchecked, QTreeWidget::indicator::unchecked { - background-color: #b3ac98; -} -QListWidget::indicator::checked, QTreeWidget::indicator::checked { - background-color: #4d4940; -} -QListWidget::indicator::disabled, QTreeWidget::indicator::disabled { - background-color: #828790; -} -QListWidget::item::selected, QTreeWidget::item::selected { - background-color: #4d4940; -} - /* QTableView: Style selected row @@ -141,31 +120,38 @@ QTabBar::tab::selected { color: #aea993; } -/* Checkboxes */ -QCheckBox::indicator { +/* Checkboxes + Radio Buttons + + QListWidget, QTreeWidget: Style indicators (checkboxes) and selected rows + + RPCS3: LLE/HLE Selector, Debugger, Game Patches +*/ +QCheckBox::indicator, QListWidget::indicator, QTreeWidget::indicator { border-radius: 0.1em; } -/* Radio Buttons */ QRadioButton::indicator { border-radius: 0.4em; } -/* Checkboxes and Radio Buttons */ -QCheckBox::indicator, QRadioButton::indicator { +QCheckBox::indicator, QRadioButton::indicator, QListWidget::indicator, QTreeWidget::indicator { border: 0.05em solid #4d4940; margin-top: 0.05em; margin-bottom: 0.05em; width: 0.8em; height: 0.8em; } -QCheckBox::indicator:checked, QRadioButton::indicator:checked { +QCheckBox::indicator:checked, QRadioButton::indicator:checked, QListWidget::indicator::checked, QTreeWidget::indicator::checked{ background-color: #4d4940; /* Dark */ } -QCheckBox::indicator:unchecked, QRadioButton::indicator:unchecked { +QCheckBox::indicator:unchecked, QRadioButton::indicator:unchecked, QListWidget::indicator::unchecked, QTreeWidget::indicator::unchecked { background-color: #b3ac98; /* Light */ } -QCheckBox::indicator::disabled, QRadioButton::indicator::disabled { +QCheckBox::indicator::disabled, QRadioButton::indicator::disabled, QListWidget::indicator::disabled, QTreeWidget::indicator::disabled { background-color: #828790; /* Gray */ } +QListWidget::item::selected, QTreeWidget::item::selected { + background-color: #4d4940; +} /* Combo Boxes, Datetime dropdown */ QComboBox, QDateTimeEdit, QLineEdit { @@ -215,6 +201,7 @@ QPushButton::disabled { /* QSpinBox (Settings -> Emulator -> width/height) */ /* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */ QSpinBox, QDoubleSpinBox { + height: 0.1em; background-color: #b3ac98; } QSpinBox::disabled, QDoubleSpinBox::disabled { @@ -247,6 +234,7 @@ QDockWidget { QDockWidget::title { background: #4d4940; padding-top: 0.2em; + padding-left: 0.2em; } QDockWidget::close-button, QDockWidget::float-button { background-color: #b3ac98; @@ -262,7 +250,7 @@ QTabWidget::tab-bar { } /* Top menu bar */ -QMenuBar { +QMenuBar#menuBar { height:1.50em; text-transform: uppercase; } @@ -314,12 +302,27 @@ QCalendarWidget QWidget{ color: #4d4940; } +/* Scrollbars */ +QScrollBar::handle, QTableView QScrollBar::handle { + background: #4d4940; +} +QScrollBar::handle:disabled { + background: #828790; +} +QScrollBar::add-page, QScrollBar::sub-page { + background: #8c806a; +} +QScrollBar::up-arrow, QScrollBar::down-arrow, QScrollBar::up-button:vertical, QScrollBar::down-button, QScrollBar::sub-line, QScrollBar::add-line { + background: transparent; + color: transparent; +} + /*** RPCS3 Specifics ***/ /* Main Window, Dialogs and some Dialogs that are actually widgets */ -QWidget#trophy_manager, QWidget#cg_disasm, QWidget#log_viewer, QMainWindow#main_window { +QWidget#trophy_manager, QWidget#cg_disasm, QWidget#log_viewer, QWidget#savestate_manager, QMainWindow#main_window { border-image: url("GuiConfigs/YoRHa-background.jpg"); } diff --git a/bin/GuiConfigs/dark/arrow-down-disabled.svg b/bin/GuiConfigs/dark/arrow-down-disabled.svg new file mode 100644 index 0000000000..c057e16738 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-down-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-down.svg b/bin/GuiConfigs/dark/arrow-down.svg new file mode 100644 index 0000000000..10ce5497fd --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-left-disabled.svg b/bin/GuiConfigs/dark/arrow-left-disabled.svg new file mode 100644 index 0000000000..0303633436 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-left-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-left.svg b/bin/GuiConfigs/dark/arrow-left.svg new file mode 100644 index 0000000000..6d85039905 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-next.svg b/bin/GuiConfigs/dark/arrow-next.svg new file mode 100644 index 0000000000..d70f87f999 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-next.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/arrow-prev.svg b/bin/GuiConfigs/dark/arrow-prev.svg new file mode 100644 index 0000000000..afa3358313 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-prev.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/arrow-right-disabled.svg b/bin/GuiConfigs/dark/arrow-right-disabled.svg new file mode 100644 index 0000000000..eaa0f2487c --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-right-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-right.svg b/bin/GuiConfigs/dark/arrow-right.svg new file mode 100644 index 0000000000..b6e2fac21e --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-up-disabled.svg b/bin/GuiConfigs/dark/arrow-up-disabled.svg new file mode 100644 index 0000000000..05e0ab2406 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-up-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/arrow-up.svg b/bin/GuiConfigs/dark/arrow-up.svg new file mode 100644 index 0000000000..95657aa0d0 --- /dev/null +++ b/bin/GuiConfigs/dark/arrow-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/check-mark-disabled.svg b/bin/GuiConfigs/dark/check-mark-disabled.svg new file mode 100644 index 0000000000..dbe8f7e724 --- /dev/null +++ b/bin/GuiConfigs/dark/check-mark-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/check-mark.svg b/bin/GuiConfigs/dark/check-mark.svg new file mode 100644 index 0000000000..3768cda4c1 --- /dev/null +++ b/bin/GuiConfigs/dark/check-mark.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/checkbox-checked-disabled.svg b/bin/GuiConfigs/dark/checkbox-checked-disabled.svg new file mode 100644 index 0000000000..a6323d57d0 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-checked-disabled.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-checked-hover.svg b/bin/GuiConfigs/dark/checkbox-checked-hover.svg new file mode 100644 index 0000000000..9279168411 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-checked-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-checked-pressed.svg b/bin/GuiConfigs/dark/checkbox-checked-pressed.svg new file mode 100644 index 0000000000..4ad4e0f10c --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-checked-pressed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-checked.svg b/bin/GuiConfigs/dark/checkbox-checked.svg new file mode 100644 index 0000000000..860b73323e --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-checked.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-disabled.svg b/bin/GuiConfigs/dark/checkbox-disabled.svg new file mode 100644 index 0000000000..4c0e28af8d --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/checkbox-indeterminate-disabled.svg b/bin/GuiConfigs/dark/checkbox-indeterminate-disabled.svg new file mode 100644 index 0000000000..28ffa34410 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-indeterminate-disabled.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-indeterminate-hover.svg b/bin/GuiConfigs/dark/checkbox-indeterminate-hover.svg new file mode 100644 index 0000000000..b43d5384b0 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-indeterminate-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-indeterminate-pressed.svg b/bin/GuiConfigs/dark/checkbox-indeterminate-pressed.svg new file mode 100644 index 0000000000..e46ae55ddc --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-indeterminate-pressed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-indeterminate.svg b/bin/GuiConfigs/dark/checkbox-indeterminate.svg new file mode 100644 index 0000000000..55a4824043 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-indeterminate.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/dark/checkbox-unchecked-hover.svg b/bin/GuiConfigs/dark/checkbox-unchecked-hover.svg new file mode 100644 index 0000000000..5159b70312 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/checkbox-unchecked-pressed.svg b/bin/GuiConfigs/dark/checkbox-unchecked-pressed.svg new file mode 100644 index 0000000000..4b1b2a3639 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-unchecked-pressed.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/checkbox-unchecked.svg b/bin/GuiConfigs/dark/checkbox-unchecked.svg new file mode 100644 index 0000000000..24b1b1b211 --- /dev/null +++ b/bin/GuiConfigs/dark/checkbox-unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/empty.svg b/bin/GuiConfigs/dark/empty.svg new file mode 100644 index 0000000000..d216ff7f65 --- /dev/null +++ b/bin/GuiConfigs/dark/empty.svg @@ -0,0 +1,2 @@ + + diff --git a/bin/GuiConfigs/dark/list-arrow-closed-disabled.svg b/bin/GuiConfigs/dark/list-arrow-closed-disabled.svg new file mode 100644 index 0000000000..60843e0801 --- /dev/null +++ b/bin/GuiConfigs/dark/list-arrow-closed-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/list-arrow-closed.svg b/bin/GuiConfigs/dark/list-arrow-closed.svg new file mode 100644 index 0000000000..674c19e989 --- /dev/null +++ b/bin/GuiConfigs/dark/list-arrow-closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/list-arrow-open-disabled.svg b/bin/GuiConfigs/dark/list-arrow-open-disabled.svg new file mode 100644 index 0000000000..af22abdb93 --- /dev/null +++ b/bin/GuiConfigs/dark/list-arrow-open-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/list-arrow-open.svg b/bin/GuiConfigs/dark/list-arrow-open.svg new file mode 100644 index 0000000000..3f8652412c --- /dev/null +++ b/bin/GuiConfigs/dark/list-arrow-open.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/radio-checked-disabled.svg b/bin/GuiConfigs/dark/radio-checked-disabled.svg new file mode 100644 index 0000000000..7314ca7e58 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-checked-disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/radio-checked-hover.svg b/bin/GuiConfigs/dark/radio-checked-hover.svg new file mode 100644 index 0000000000..4a1a733688 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-checked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/radio-checked-pressed.svg b/bin/GuiConfigs/dark/radio-checked-pressed.svg new file mode 100644 index 0000000000..6c08461297 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-checked-pressed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/dark/radio-checked.svg b/bin/GuiConfigs/dark/radio-checked.svg new file mode 100644 index 0000000000..40226c2ec9 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-checked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/radio-disabled.svg b/bin/GuiConfigs/dark/radio-disabled.svg new file mode 100644 index 0000000000..d9b45f6275 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/radio-unchecked-hover.svg b/bin/GuiConfigs/dark/radio-unchecked-hover.svg new file mode 100644 index 0000000000..301d8c3414 --- /dev/null +++ b/bin/GuiConfigs/dark/radio-unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/radio-unchecked-pressed.svg b/bin/GuiConfigs/dark/radio-unchecked-pressed.svg new file mode 100644 index 0000000000..a8334fde9e --- /dev/null +++ b/bin/GuiConfigs/dark/radio-unchecked-pressed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/dark/radio-unchecked.svg b/bin/GuiConfigs/dark/radio-unchecked.svg new file mode 100644 index 0000000000..334ce6ca2c --- /dev/null +++ b/bin/GuiConfigs/dark/radio-unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/dark/slider-handle-disabled.svg b/bin/GuiConfigs/dark/slider-handle-disabled.svg new file mode 100644 index 0000000000..2d3d865bb4 --- /dev/null +++ b/bin/GuiConfigs/dark/slider-handle-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/slider-handle-hover.svg b/bin/GuiConfigs/dark/slider-handle-hover.svg new file mode 100644 index 0000000000..2f0f8abb98 --- /dev/null +++ b/bin/GuiConfigs/dark/slider-handle-hover.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/slider-handle-pressed.svg b/bin/GuiConfigs/dark/slider-handle-pressed.svg new file mode 100644 index 0000000000..9ca2a54ad6 --- /dev/null +++ b/bin/GuiConfigs/dark/slider-handle-pressed.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/slider-handle.svg b/bin/GuiConfigs/dark/slider-handle.svg new file mode 100644 index 0000000000..c49e8e25aa --- /dev/null +++ b/bin/GuiConfigs/dark/slider-handle.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/window-close.svg b/bin/GuiConfigs/dark/window-close.svg new file mode 100644 index 0000000000..337b067f44 --- /dev/null +++ b/bin/GuiConfigs/dark/window-close.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/dark/window-undock.svg b/bin/GuiConfigs/dark/window-undock.svg new file mode 100644 index 0000000000..684a8f87fe --- /dev/null +++ b/bin/GuiConfigs/dark/window-undock.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-down-disabled.svg b/bin/GuiConfigs/light/arrow-down-disabled.svg new file mode 100644 index 0000000000..6a35cff63b --- /dev/null +++ b/bin/GuiConfigs/light/arrow-down-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-down.svg b/bin/GuiConfigs/light/arrow-down.svg new file mode 100644 index 0000000000..0820bdb8c9 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-left-disabled.svg b/bin/GuiConfigs/light/arrow-left-disabled.svg new file mode 100644 index 0000000000..02e5395fbf --- /dev/null +++ b/bin/GuiConfigs/light/arrow-left-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-left.svg b/bin/GuiConfigs/light/arrow-left.svg new file mode 100644 index 0000000000..6502056f9f --- /dev/null +++ b/bin/GuiConfigs/light/arrow-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-next.svg b/bin/GuiConfigs/light/arrow-next.svg new file mode 100644 index 0000000000..58a8176040 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-next.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/arrow-prev.svg b/bin/GuiConfigs/light/arrow-prev.svg new file mode 100644 index 0000000000..233a70c3f5 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-prev.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/arrow-right-disabled.svg b/bin/GuiConfigs/light/arrow-right-disabled.svg new file mode 100644 index 0000000000..486e6c0691 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-right-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-right.svg b/bin/GuiConfigs/light/arrow-right.svg new file mode 100644 index 0000000000..651e7adf4f --- /dev/null +++ b/bin/GuiConfigs/light/arrow-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-up-disabled.svg b/bin/GuiConfigs/light/arrow-up-disabled.svg new file mode 100644 index 0000000000..1651415127 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-up-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/arrow-up.svg b/bin/GuiConfigs/light/arrow-up.svg new file mode 100644 index 0000000000..8b1065f702 --- /dev/null +++ b/bin/GuiConfigs/light/arrow-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/check-mark-disabled.svg b/bin/GuiConfigs/light/check-mark-disabled.svg new file mode 100644 index 0000000000..5d42a7aa9e --- /dev/null +++ b/bin/GuiConfigs/light/check-mark-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/check-mark.svg b/bin/GuiConfigs/light/check-mark.svg new file mode 100644 index 0000000000..f0dd920b06 --- /dev/null +++ b/bin/GuiConfigs/light/check-mark.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/checkbox-checked-disabled.svg b/bin/GuiConfigs/light/checkbox-checked-disabled.svg new file mode 100644 index 0000000000..49dd8ce5e7 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-checked-disabled.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-checked-hover.svg b/bin/GuiConfigs/light/checkbox-checked-hover.svg new file mode 100644 index 0000000000..183bf80fc7 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-checked-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-checked-pressed.svg b/bin/GuiConfigs/light/checkbox-checked-pressed.svg new file mode 100644 index 0000000000..e71a14b93a --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-checked-pressed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-checked.svg b/bin/GuiConfigs/light/checkbox-checked.svg new file mode 100644 index 0000000000..7a2acc4fb7 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-checked.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-disabled.svg b/bin/GuiConfigs/light/checkbox-disabled.svg new file mode 100644 index 0000000000..700da26462 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/checkbox-indeterminate-disabled.svg b/bin/GuiConfigs/light/checkbox-indeterminate-disabled.svg new file mode 100644 index 0000000000..a430d6a8c0 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-indeterminate-disabled.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-indeterminate-hover.svg b/bin/GuiConfigs/light/checkbox-indeterminate-hover.svg new file mode 100644 index 0000000000..c4fbf20574 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-indeterminate-hover.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-indeterminate-pressed.svg b/bin/GuiConfigs/light/checkbox-indeterminate-pressed.svg new file mode 100644 index 0000000000..b8c4d2644a --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-indeterminate-pressed.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-indeterminate.svg b/bin/GuiConfigs/light/checkbox-indeterminate.svg new file mode 100644 index 0000000000..0a89706c5e --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-indeterminate.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/bin/GuiConfigs/light/checkbox-unchecked-hover.svg b/bin/GuiConfigs/light/checkbox-unchecked-hover.svg new file mode 100644 index 0000000000..4789c03a08 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/checkbox-unchecked-pressed.svg b/bin/GuiConfigs/light/checkbox-unchecked-pressed.svg new file mode 100644 index 0000000000..709e2686c5 --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-unchecked-pressed.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/checkbox-unchecked.svg b/bin/GuiConfigs/light/checkbox-unchecked.svg new file mode 100644 index 0000000000..2a4cfd581e --- /dev/null +++ b/bin/GuiConfigs/light/checkbox-unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/empty.svg b/bin/GuiConfigs/light/empty.svg new file mode 100644 index 0000000000..d216ff7f65 --- /dev/null +++ b/bin/GuiConfigs/light/empty.svg @@ -0,0 +1,2 @@ + + diff --git a/bin/GuiConfigs/light/list-arrow-closed-disabled.svg b/bin/GuiConfigs/light/list-arrow-closed-disabled.svg new file mode 100644 index 0000000000..d4fbdf3b40 --- /dev/null +++ b/bin/GuiConfigs/light/list-arrow-closed-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/list-arrow-closed.svg b/bin/GuiConfigs/light/list-arrow-closed.svg new file mode 100644 index 0000000000..94f388d3e3 --- /dev/null +++ b/bin/GuiConfigs/light/list-arrow-closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/list-arrow-open-disabled.svg b/bin/GuiConfigs/light/list-arrow-open-disabled.svg new file mode 100644 index 0000000000..243df7618d --- /dev/null +++ b/bin/GuiConfigs/light/list-arrow-open-disabled.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/list-arrow-open.svg b/bin/GuiConfigs/light/list-arrow-open.svg new file mode 100644 index 0000000000..9ee4cfb85b --- /dev/null +++ b/bin/GuiConfigs/light/list-arrow-open.svg @@ -0,0 +1,3 @@ + + + diff --git a/bin/GuiConfigs/light/radio-checked-disabled.svg b/bin/GuiConfigs/light/radio-checked-disabled.svg new file mode 100644 index 0000000000..13084c94a7 --- /dev/null +++ b/bin/GuiConfigs/light/radio-checked-disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/radio-checked-hover.svg b/bin/GuiConfigs/light/radio-checked-hover.svg new file mode 100644 index 0000000000..abfd016a75 --- /dev/null +++ b/bin/GuiConfigs/light/radio-checked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/radio-checked-pressed.svg b/bin/GuiConfigs/light/radio-checked-pressed.svg new file mode 100644 index 0000000000..f842bd4701 --- /dev/null +++ b/bin/GuiConfigs/light/radio-checked-pressed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/radio-checked.svg b/bin/GuiConfigs/light/radio-checked.svg new file mode 100644 index 0000000000..18e8c3bfc4 --- /dev/null +++ b/bin/GuiConfigs/light/radio-checked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/radio-disabled.svg b/bin/GuiConfigs/light/radio-disabled.svg new file mode 100644 index 0000000000..c7a50333c9 --- /dev/null +++ b/bin/GuiConfigs/light/radio-disabled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/radio-unchecked-hover.svg b/bin/GuiConfigs/light/radio-unchecked-hover.svg new file mode 100644 index 0000000000..61ac41e26c --- /dev/null +++ b/bin/GuiConfigs/light/radio-unchecked-hover.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/radio-unchecked-pressed.svg b/bin/GuiConfigs/light/radio-unchecked-pressed.svg new file mode 100644 index 0000000000..909797e62d --- /dev/null +++ b/bin/GuiConfigs/light/radio-unchecked-pressed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/radio-unchecked.svg b/bin/GuiConfigs/light/radio-unchecked.svg new file mode 100644 index 0000000000..41a5f5a1d7 --- /dev/null +++ b/bin/GuiConfigs/light/radio-unchecked.svg @@ -0,0 +1,4 @@ + + + + diff --git a/bin/GuiConfigs/light/slider-handle-disabled.svg b/bin/GuiConfigs/light/slider-handle-disabled.svg new file mode 100644 index 0000000000..0d2ddb8d7b --- /dev/null +++ b/bin/GuiConfigs/light/slider-handle-disabled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/slider-handle-hover.svg b/bin/GuiConfigs/light/slider-handle-hover.svg new file mode 100644 index 0000000000..9eea790adf --- /dev/null +++ b/bin/GuiConfigs/light/slider-handle-hover.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/slider-handle-pressed.svg b/bin/GuiConfigs/light/slider-handle-pressed.svg new file mode 100644 index 0000000000..7989e9d376 --- /dev/null +++ b/bin/GuiConfigs/light/slider-handle-pressed.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/slider-handle.svg b/bin/GuiConfigs/light/slider-handle.svg new file mode 100644 index 0000000000..2c5df2c491 --- /dev/null +++ b/bin/GuiConfigs/light/slider-handle.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/bin/GuiConfigs/light/window-close.svg b/bin/GuiConfigs/light/window-close.svg new file mode 100644 index 0000000000..5a1ef8d6e9 --- /dev/null +++ b/bin/GuiConfigs/light/window-close.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/bin/GuiConfigs/light/window-undock.svg b/bin/GuiConfigs/light/window-undock.svg new file mode 100644 index 0000000000..df9a297b96 --- /dev/null +++ b/bin/GuiConfigs/light/window-undock.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/rpcs3/Emu/Audio/AudioBackend.cpp b/rpcs3/Emu/Audio/AudioBackend.cpp index e0d96c8c2b..80af260414 100644 --- a/rpcs3/Emu/Audio/AudioBackend.cpp +++ b/rpcs3/Emu/Audio/AudioBackend.cpp @@ -2,6 +2,8 @@ #include "AudioBackend.h" #include "Emu/IdManager.h" #include "Emu//Cell/Modules/cellAudioOut.h" +#include +#include AudioBackend::AudioBackend() {} @@ -57,15 +59,25 @@ f32 AudioBackend::apply_volume(const VolumeParam& param, u32 sample_cnt, const f { ensure(param.ch_cnt > 1 && param.ch_cnt % 2 == 0); // Tends to produce faster code + // Fast path when no volume change is needed + if (param.current_volume == param.target_volume) + { + apply_volume_static(param.target_volume, sample_cnt, src, dst); + return param.target_volume; + } + const f32 vol_incr = (param.target_volume - param.initial_volume) / (VOLUME_CHANGE_DURATION * param.freq); f32 crnt_vol = param.current_volume; u32 sample_idx = 0; + // Use epsilon for float comparison to avoid infinite loops + constexpr f32 epsilon = 1e-6f; + if (vol_incr >= 0) { - for (sample_idx = 0; sample_idx < sample_cnt && crnt_vol != param.target_volume; sample_idx += param.ch_cnt) + for (sample_idx = 0; sample_idx < sample_cnt && (param.target_volume - crnt_vol) > epsilon; sample_idx += param.ch_cnt) { - crnt_vol = std::min(param.current_volume + (sample_idx + 1) / param.ch_cnt * vol_incr, param.target_volume); + crnt_vol = std::min(crnt_vol + vol_incr, param.target_volume); for (u32 i = 0; i < param.ch_cnt; i++) { @@ -75,9 +87,9 @@ f32 AudioBackend::apply_volume(const VolumeParam& param, u32 sample_cnt, const f } else { - for (sample_idx = 0; sample_idx < sample_cnt && crnt_vol != param.target_volume; sample_idx += param.ch_cnt) + for (sample_idx = 0; sample_idx < sample_cnt && (crnt_vol - param.target_volume) > epsilon; sample_idx += param.ch_cnt) { - crnt_vol = std::max(param.current_volume + (sample_idx + 1) / param.ch_cnt * vol_incr, param.target_volume); + crnt_vol = std::max(crnt_vol + vol_incr, param.target_volume); for (u32 i = 0; i < param.ch_cnt; i++) { @@ -96,6 +108,25 @@ f32 AudioBackend::apply_volume(const VolumeParam& param, u32 sample_cnt, const f void AudioBackend::apply_volume_static(f32 vol, u32 sample_cnt, const f32* src, f32* dst) { + // Improved volume application with better precision + if (vol == 1.0f) + { + // Fast path for unity gain - no multiplication needed + if (src != dst) + { + std::memcpy(dst, src, sample_cnt * sizeof(f32)); + } + return; + } + + if (vol == 0.0f) + { + // Fast path for mute + std::memset(dst, 0, sample_cnt * sizeof(f32)); + return; + } + + // Process samples with improved precision for (u32 i = 0; i < sample_cnt; i++) { dst[i] = src[i] * vol; @@ -104,9 +135,37 @@ void AudioBackend::apply_volume_static(f32 vol, u32 sample_cnt, const f32* src, void AudioBackend::normalize(u32 sample_cnt, const f32* src, f32* dst) { + // Improved normalization with soft clipping and better dynamic range handling + constexpr f32 soft_clip_threshold = 0.95f; + constexpr f32 hard_clip_limit = 1.0f; + for (u32 i = 0; i < sample_cnt; i++) { - dst[i] = std::clamp(src[i], -1.0f, 1.0f); + f32 sample = src[i]; + f32 abs_sample = std::abs(sample); + + if (abs_sample > soft_clip_threshold) + { + // Apply soft clipping for smoother distortion + f32 sign = std::copysign(1.0f, sample); + if (abs_sample > hard_clip_limit) + { + // Hard limit to prevent overflow + dst[i] = sign * hard_clip_limit; + } + else + { + // Soft clipping using tanh-like curve + f32 excess = (abs_sample - soft_clip_threshold) / (hard_clip_limit - soft_clip_threshold); + f32 soft_factor = soft_clip_threshold + (hard_clip_limit - soft_clip_threshold) * std::tanh(excess); + dst[i] = sign * soft_factor; + } + } + else + { + // No clipping needed + dst[i] = sample; + } } } diff --git a/rpcs3/Emu/Audio/AudioBackend.h b/rpcs3/Emu/Audio/AudioBackend.h index cbd8e045c9..bc07a1e46f 100644 --- a/rpcs3/Emu/Audio/AudioBackend.h +++ b/rpcs3/Emu/Audio/AudioBackend.h @@ -17,11 +17,11 @@ enum : u32 enum class AudioFreq : u32 { - FREQ_32K = 32000, - FREQ_44K = 44100, - FREQ_48K = 48000, - FREQ_88K = 88200, - FREQ_96K = 96000, + FREQ_32K = 32000, + FREQ_44K = 44100, + FREQ_48K = 48000, + FREQ_88K = 88200, + FREQ_96K = 96000, FREQ_176K = 176400, FREQ_192K = 192000, }; @@ -35,7 +35,7 @@ enum class AudioSampleSize : u32 // This enum is only used for emulation enum class AudioChannelCnt : u32 { - STEREO = 2, + STEREO = 2, SURROUND_5_1 = 6, SURROUND_7_1 = 8, }; @@ -49,7 +49,6 @@ enum class AudioStateEvent : u32 class AudioBackend { public: - struct VolumeParam { f32 initial_volume = 1.0f; @@ -93,7 +92,10 @@ public: virtual f64 GetCallbackFrameLen() = 0; // Returns true if audio is currently being played, false otherwise. Reflects end result of Play() and Pause() calls. - virtual bool IsPlaying() { return m_playing; } + virtual bool IsPlaying() + { + return m_playing; + } // Start playing enqueued data. virtual void Play() = 0; @@ -105,17 +107,26 @@ public: * This virtual method should be reimplemented if backend can fail to be initialized under non-error conditions * eg. when there is no audio devices attached */ - virtual bool Initialized() { return true; } + virtual bool Initialized() + { + return true; + } /* * This virtual method should be reimplemented if backend can fail during normal operation */ - virtual bool Operational() { return true; } + virtual bool Operational() + { + return true; + } /* * This virtual method should be reimplemented if backend can report device changes */ - virtual bool DefaultDeviceChanged() { return false; } + virtual bool DefaultDeviceChanged() + { + return false; + } /* * Helper methods @@ -180,20 +191,21 @@ public: /* * Downmix audio stream. */ - template + template static void downmix(u32 sample_cnt, const f32* src, f32* dst) { const u32 dst_ch_cnt = default_layout_channel_count(dst_layout); - if (static_cast(src_ch_cnt) <= dst_ch_cnt) fmt::throw_exception("src channel count must be bigger than dst channel count"); + if (static_cast(src_ch_cnt) <= dst_ch_cnt) + fmt::throw_exception("src channel count must be bigger than dst channel count"); static constexpr f32 center_coef = std::numbers::sqrt2_v / 2; static constexpr f32 surround_coef = std::numbers::sqrt2_v / 2; for (u32 src_sample = 0, dst_sample = 0; src_sample < sample_cnt; src_sample += static_cast(src_ch_cnt), dst_sample += dst_ch_cnt) { - const f32 left = src[src_sample + 0]; + const f32 left = src[src_sample + 0]; const f32 right = src[src_sample + 1]; - + if constexpr (src_ch_cnt == AudioChannelCnt::STEREO) { if constexpr (dst_layout == audio_channel_layout::mono) @@ -203,9 +215,9 @@ public: } else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_5_1) { - const f32 center = src[src_sample + 2]; - const f32 low_freq = src[src_sample + 3]; - const f32 side_left = src[src_sample + 4]; + const f32 center = src[src_sample + 2]; + const f32 low_freq = src[src_sample + 3]; + const f32 side_left = src[src_sample + 4]; const f32 side_right = src[src_sample + 5]; if constexpr (dst_layout == audio_channel_layout::quadraphonic || dst_layout == audio_channel_layout::quadraphonic_lfe) @@ -239,11 +251,11 @@ public: } else if constexpr (src_ch_cnt == AudioChannelCnt::SURROUND_7_1) { - const f32 center = src[src_sample + 2]; - const f32 low_freq = src[src_sample + 3]; - const f32 rear_left = src[src_sample + 4]; + const f32 center = src[src_sample + 2]; + const f32 low_freq = src[src_sample + 3]; + const f32 rear_left = src[src_sample + 4]; const f32 rear_right = src[src_sample + 5]; - const f32 side_left = src[src_sample + 6]; + const f32 side_left = src[src_sample + 6]; const f32 side_right = src[src_sample + 7]; if constexpr (dst_layout == audio_channel_layout::surround_5_1) @@ -372,12 +384,12 @@ protected: void setup_channel_layout(u32 input_channel_count, u32 output_channel_count, audio_channel_layout layout, logs::channel& log); AudioSampleSize m_sample_size = AudioSampleSize::FLOAT; - AudioFreq m_sampling_rate = AudioFreq::FREQ_48K; - u32 m_channels = 2; + AudioFreq m_sampling_rate = AudioFreq::FREQ_48K; + u32 m_channels = 2; audio_channel_layout m_layout = audio_channel_layout::automatic; std::timed_mutex m_cb_mutex{}; - std::function m_write_callback{}; + std::function m_write_callback{}; shared_mutex m_state_cb_mutex{}; std::function m_state_callback{}; @@ -385,6 +397,5 @@ protected: bool m_playing = false; private: - - static constexpr f32 VOLUME_CHANGE_DURATION = 0.016f; // sec + static constexpr f32 VOLUME_CHANGE_DURATION = 0.032f; // sec - Increased for smoother transitions }; diff --git a/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp b/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp index dbaf4aa8db..fc5b24da45 100644 --- a/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp +++ b/rpcs3/Emu/Audio/Cubeb/CubebBackend.cpp @@ -90,11 +90,6 @@ bool CubebBackend::DefaultDeviceChanged() } device_handle device = GetDevice(); - if (!device.handle) - { - Cubeb.error("Selected device not found. Trying alternative approach..."); - device = GetDefaultDeviceAlt(m_sampling_rate, m_sample_size, m_channels); - } return !device.handle || device.id != m_default_device; } @@ -119,20 +114,9 @@ bool CubebBackend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSize if (!device.handle) { - if (use_default_device) - { - device = GetDefaultDeviceAlt(freq, sample_size, static_cast(ch_cnt)); - - if (!device.handle) - { - Cubeb.error("Cannot detect default device. Channel count detection unavailable."); - } - } - else - { - Cubeb.error("Device with id=%s not found", dev_id); - return false; - } + if (use_default_device) Cubeb.error("Opening default device failed"); + else Cubeb.error("Device with id=%s not found", dev_id); + return false; } if (device.ch_cnt == 0) @@ -358,68 +342,6 @@ CubebBackend::device_handle CubebBackend::GetDevice(std::string_view dev_id) return result; }; -CubebBackend::device_handle CubebBackend::GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt) -{ - Cubeb.notice("Starting alternative search for default device with freq=%d, sample_size=%d and ch_cnt=%d", static_cast(freq), static_cast(sample_size), static_cast(ch_cnt)); - - cubeb_stream_params param = - { - .format = sample_size == AudioSampleSize::S16 ? CUBEB_SAMPLE_S16NE : CUBEB_SAMPLE_FLOAT32NE, - .rate = static_cast(freq), - .channels = static_cast(ch_cnt), - .layout = CUBEB_LAYOUT_UNDEFINED, - .prefs = CUBEB_STREAM_PREF_DISABLE_DEVICE_SWITCHING - }; - - u32 min_latency{}; - if (int err = cubeb_get_min_latency(m_ctx, ¶m, &min_latency)) - { - Cubeb.error("cubeb_get_min_latency() failed: %i", err); - min_latency = 100; - } - - cubeb_stream* tmp_stream{}; - static auto dummy_data_cb = [](cubeb_stream*, void*, void const*, void*, long) -> long { return 0; }; - static auto dummy_state_cb = [](cubeb_stream*, void*, cubeb_state) {}; - - if (int err = cubeb_stream_init(m_ctx, &tmp_stream, "Default device detector", nullptr, nullptr, nullptr, ¶m, min_latency, dummy_data_cb, dummy_state_cb, nullptr)) - { - Cubeb.error("cubeb_stream_init() failed: %i", err); - return {}; - } - - cubeb_device* crnt_dev{}; - - if (int err = cubeb_stream_get_current_device(tmp_stream, &crnt_dev); err != CUBEB_OK || !crnt_dev) - { - Cubeb.error("cubeb_stream_get_current_device() failed: err=%i, crnt_dev=%d", err, !!crnt_dev); - cubeb_stream_destroy(tmp_stream); - return {}; - } - - std::string out_dev_name; - - if (crnt_dev->output_name) - { - out_dev_name = crnt_dev->output_name; - } - - if (int err = cubeb_stream_device_destroy(tmp_stream, crnt_dev)) - { - Cubeb.error("cubeb_stream_device_destroy() failed: %i", err); - } - - cubeb_stream_destroy(tmp_stream); - - if (out_dev_name.empty()) - { - Cubeb.notice("No default device available"); - return {}; - } - - return GetDevice(out_dev_name); -} - long CubebBackend::data_cb(cubeb_stream* stream, void* user_ptr, void const* /* input_buffer */, void* output_buffer, long nframes) { if (nframes <= 0) diff --git a/rpcs3/Emu/Audio/Cubeb/CubebBackend.h b/rpcs3/Emu/Audio/Cubeb/CubebBackend.h index 1f230ec238..9641b46006 100644 --- a/rpcs3/Emu/Audio/Cubeb/CubebBackend.h +++ b/rpcs3/Emu/Audio/Cubeb/CubebBackend.h @@ -61,5 +61,4 @@ private: }; device_handle GetDevice(std::string_view dev_id = ""); - device_handle GetDefaultDeviceAlt(AudioFreq freq, AudioSampleSize sample_size, u32 ch_cnt); }; diff --git a/rpcs3/Emu/Audio/audio_resampler.cpp b/rpcs3/Emu/Audio/audio_resampler.cpp index 32c7109b4c..108c63e66d 100644 --- a/rpcs3/Emu/Audio/audio_resampler.cpp +++ b/rpcs3/Emu/Audio/audio_resampler.cpp @@ -4,8 +4,12 @@ audio_resampler::audio_resampler() { - resampler.setSetting(SETTING_SEQUENCE_MS, 20); // Resampler frame size (reduce latency at cost of slight sound quality degradation) - resampler.setSetting(SETTING_USE_QUICKSEEK, 1); // Use fast quick seeking algorithm (substantally reduces computation time) + // Improved quality settings for better audio output + resampler.setSetting(SETTING_SEQUENCE_MS, 40); // Increased sequence length for better quality (was 20) + resampler.setSetting(SETTING_SEEKWINDOW_MS, 15); // Better seeking window for smoother transitions + resampler.setSetting(SETTING_OVERLAP_MS, 8); // Improved overlap for better quality + resampler.setSetting(SETTING_USE_QUICKSEEK, 0); // Disable quick seek for higher quality (was 1) + resampler.setSetting(SETTING_USE_AA_FILTER, 1); // Enable anti-aliasing filter for cleaner sound } audio_resampler::~audio_resampler() @@ -35,7 +39,7 @@ std::pair audio_resampler::get_samples(u32 { // NOTE: Make sure to get the buffer first because receiveSamples advances its position internally // and std::make_pair evaluates the second parameter first... - f32 *const buf = resampler.bufBegin(); + f32* const buf = resampler.bufBegin(); return std::make_pair(buf, resampler.receiveSamples(sample_cnt)); } diff --git a/rpcs3/Emu/Audio/audio_utils.cpp b/rpcs3/Emu/Audio/audio_utils.cpp index bcff7bf947..2db2e1a0ed 100644 --- a/rpcs3/Emu/Audio/audio_utils.cpp +++ b/rpcs3/Emu/Audio/audio_utils.cpp @@ -4,6 +4,7 @@ #include "Emu/System.h" #include "Emu/IdManager.h" #include "Emu/RSX/Overlays/overlay_message.h" +#include namespace audio { @@ -24,16 +25,33 @@ namespace audio void change_volume(s32 delta) { // Ignore if muted - if (g_fxo->get().audio_muted) return; + if (g_fxo->get().audio_muted) + return; const s32 old_volume = g_cfg.audio.volume; - const s32 new_volume = old_volume + delta; - if (old_volume == new_volume) return; + // Apply non-linear volume scaling for better perceived volume control + // Use smaller steps at lower volumes for finer control + s32 adjusted_delta = delta; + if (old_volume < 25 && abs(delta) > 1) + { + // Smaller steps at low volume for better control + adjusted_delta = delta > 0 ? 1 : -1; + } + else if (old_volume > 75 && abs(delta) < 5) + { + // Larger steps at high volume for faster adjustment + adjusted_delta = delta > 0 ? std::min(delta * 2, 5) : std::max(delta * 2, -5); + } + + const s32 new_volume = old_volume + adjusted_delta; + + if (old_volume == new_volume) + return; g_cfg.audio.volume.set(std::clamp(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max)); Emu.GetCallbacks().update_emu_settings(); rsx::overlays::queue_message(get_localized_string(localized_string_id::AUDIO_CHANGED, fmt::format("%d%%", g_cfg.audio.volume.get()).c_str()), 3'000'000); } -} +} // namespace audio diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt index 1a9e95a44d..ad310ba1e0 100644 --- a/rpcs3/Emu/CMakeLists.txt +++ b/rpcs3/Emu/CMakeLists.txt @@ -578,6 +578,7 @@ if(TARGET 3rdparty_vulkan) RSX/VK/vkutils/buffer_object.cpp RSX/VK/vkutils/chip_class.cpp RSX/VK/vkutils/commands.cpp + RSX/VK/vkutils/ex.cpp RSX/VK/vkutils/data_heap.cpp RSX/VK/vkutils/descriptors.cpp RSX/VK/vkutils/image.cpp @@ -643,6 +644,7 @@ target_link_libraries(rpcs3_emu 3rdparty::libevdev 3rdparty::flatbuffers 3rdparty::pugixml + 3rdparty::vulkanmemoryallocator Threads::Threads PRIVATE 3rdparty::glslang diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp index 242dcb9d9f..9710af94f5 100644 --- a/rpcs3/Emu/CPU/CPUThread.cpp +++ b/rpcs3/Emu/CPU/CPUThread.cpp @@ -1158,7 +1158,7 @@ cpu_thread& cpu_thread::operator=(thread_state) { if (u32 resv = atomic_storage::load(thread->raddr)) { - vm::reservation_notifier_notify(resv); + vm::reservation_notifier_notify(resv, thread->rtime); } } } diff --git a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp index b4508ada5b..4851895537 100644 --- a/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp +++ b/rpcs3/Emu/Cell/Modules/cellAvconfExt.cpp @@ -520,7 +520,7 @@ error_code cellVideoOutGetScreenSize(u32 videoOut, vm::ptr screenSize) return CELL_VIDEO_OUT_ERROR_UNSUPPORTED_VIDEO_OUT; } - if (g_cfg.video.stereo_render_mode != stereo_render_mode_options::disabled) + if (g_cfg.video.stereo_enabled) { // Return Playstation 3D display value // Some games call this function when 3D is enabled diff --git a/rpcs3/Emu/Cell/Modules/cellGem.cpp b/rpcs3/Emu/Cell/Modules/cellGem.cpp index ba796be28e..9d39b3c7eb 100644 --- a/rpcs3/Emu/Cell/Modules/cellGem.cpp +++ b/rpcs3/Emu/Cell/Modules/cellGem.cpp @@ -3482,7 +3482,7 @@ error_code cellGemSetRumble(u32 gem_num, u8 rumble) { if (!binding.device || binding.device->player_id != pad_index) continue; - handler->SetRumble(pad_index, rumble, rumble > 0); + handler->SetRumble(pad_index, rumble, rumble); break; } } diff --git a/rpcs3/Emu/Cell/Modules/cellL10n.cpp b/rpcs3/Emu/Cell/Modules/cellL10n.cpp index 6b3ffc4448..0f47c682e6 100644 --- a/rpcs3/Emu/Cell/Modules/cellL10n.cpp +++ b/rpcs3/Emu/Cell/Modules/cellL10n.cpp @@ -2498,7 +2498,7 @@ s32 UCS2stoSBCSs(vm::cptr src, vm::ptr src_len, vm::ptr dst, vm::p for (u32 src_pos = 0; src_pos < *src_len; src_pos++) { - const s16 ucs2 = src[src_pos]; + const u16 ucs2 = src[src_pos]; if (ucs2 >= 0xfffe) { diff --git a/rpcs3/Emu/Cell/Modules/cellMic.cpp b/rpcs3/Emu/Cell/Modules/cellMic.cpp index a5ece1be59..0724b48927 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMic.cpp @@ -11,7 +11,7 @@ #include #ifndef WITHOUT_OPENAL -#include "3rdparty/OpenAL/openal-soft/include/AL/alext.h" +#include "alext.h" #endif LOG_CHANNEL(cellMic); diff --git a/rpcs3/Emu/Cell/Modules/cellMic.h b/rpcs3/Emu/Cell/Modules/cellMic.h index e4b416fa6a..88a2f4d937 100644 --- a/rpcs3/Emu/Cell/Modules/cellMic.h +++ b/rpcs3/Emu/Cell/Modules/cellMic.h @@ -1,9 +1,10 @@ #pragma once #include "Utilities/Thread.h" -#include "3rdparty/OpenAL/openal-soft/include/AL/alc.h" #include "Utilities/mutex.h" +#include "alc.h" + // Error Codes enum CellMicInError : u32 { diff --git a/rpcs3/Emu/Cell/Modules/cellMouse.cpp b/rpcs3/Emu/Cell/Modules/cellMouse.cpp index 8bf550a633..750b463c0c 100644 --- a/rpcs3/Emu/Cell/Modules/cellMouse.cpp +++ b/rpcs3/Emu/Cell/Modules/cellMouse.cpp @@ -1,8 +1,9 @@ #include "stdafx.h" #include "Emu/IdManager.h" +#include "Emu/system_config.h" #include "Emu/Cell/PPUModule.h" - #include "Emu/Io/MouseHandler.h" +#include "Emu/RSX/Overlays/overlay_debug_overlay.h" #include "cellMouse.h" @@ -13,6 +14,54 @@ extern bool is_input_allowed(); LOG_CHANNEL(cellMouse); +void show_debug_overlay(const CellMouseData& data, const MouseData* _mouse) +{ + // The cell mouse can be set empty without any new mouse input. + // Only update our mouse input if there is new data. + static MouseData mouse {}; + if (_mouse) + { + mouse = *_mouse; + } + + std::string text = fmt::format( + "> Name: Raw Value Pixel\n" + ">\n" + "> Update: %5d %5d\n" + "> Wheel: %5d %5d\n" + "> Tilt: %5d %5d\n" + "> X: %5d %5d %5d\n" + "> Y: %5d %5d %5d\n" + ">\n" + "> Buttons: 0x%04x 0x%04x\n" + "> Button 1: %5d %5d\n" + "> Button 2: %5d %5d\n" + "> Button 3: %5d %5d\n" + "> Button 4: %5d %5d\n" + "> Button 5: %5d %5d\n" + "> Button 6: %5d %5d\n" + "> Button 7: %5d %5d\n" + "> Button 8: %5d %5d\n" + , + mouse.update, data.update, + mouse.wheel, data.wheel, + mouse.tilt, data.tilt, + mouse.x_axis, data.x_axis, mouse.pixel_x, + mouse.y_axis, data.y_axis, mouse.pixel_y, + mouse.buttons, data.buttons, + !!(mouse.buttons & CELL_MOUSE_BUTTON_1), !!(data.buttons & CELL_MOUSE_BUTTON_1), + !!(mouse.buttons & CELL_MOUSE_BUTTON_2), !!(data.buttons & CELL_MOUSE_BUTTON_2), + !!(mouse.buttons & CELL_MOUSE_BUTTON_3), !!(data.buttons & CELL_MOUSE_BUTTON_3), + !!(mouse.buttons & CELL_MOUSE_BUTTON_4), !!(data.buttons & CELL_MOUSE_BUTTON_4), + !!(mouse.buttons & CELL_MOUSE_BUTTON_5), !!(data.buttons & CELL_MOUSE_BUTTON_5), + !!(mouse.buttons & CELL_MOUSE_BUTTON_6), !!(data.buttons & CELL_MOUSE_BUTTON_6), + !!(mouse.buttons & CELL_MOUSE_BUTTON_7), !!(data.buttons & CELL_MOUSE_BUTTON_7), + !!(mouse.buttons & CELL_MOUSE_BUTTON_8), !!(data.buttons & CELL_MOUSE_BUTTON_8) + ); + + rsx::overlays::set_debug_overlay_text(std::move(text)); +} + template<> void fmt_class_string::format(std::string& out, u64 arg) { @@ -214,10 +263,16 @@ error_code cellMouseGetData(u32 port_no, vm::ptr data) if (data_list.empty() || current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed()) { data_list.clear(); + + if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay) + { + show_debug_overlay(*data, nullptr); + } + return CELL_OK; } - const MouseData current_data = data_list.front(); + const MouseData& current_data = data_list.front(); data->update = current_data.update; data->buttons = current_data.buttons; data->x_axis = current_data.x_axis; @@ -225,6 +280,11 @@ error_code cellMouseGetData(u32 port_no, vm::ptr data) data->wheel = current_data.wheel; data->tilt = current_data.tilt; + if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay) + { + show_debug_overlay(*data, ¤t_data); + } + data_list.pop_front(); return CELL_OK; @@ -264,20 +324,31 @@ error_code cellMouseGetDataList(u32 port_no, vm::ptr data) if (list.empty() || current_info.is_null_handler || (current_info.info & CELL_MOUSE_INFO_INTERCEPTED) || !is_input_allowed()) { list.clear(); + + if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay) + { + show_debug_overlay(data->list[0], nullptr); + } + return CELL_OK; } data->list_num = std::min(CELL_MOUSE_MAX_DATA_LIST_NUM, static_cast(list.size())); - int i = 0; - for (auto it = list.begin(); it != list.end() && i < CELL_MOUSE_MAX_DATA_LIST_NUM; ++it, ++i) + for (size_t i = 0; i < list.size() && i < CELL_MOUSE_MAX_DATA_LIST_NUM; ++i) { - data->list[i].update = it->update; - data->list[i].buttons = it->buttons; - data->list[i].x_axis = it->x_axis; - data->list[i].y_axis = it->y_axis; - data->list[i].wheel = it->wheel; - data->list[i].tilt = it->tilt; + const MouseData& current_data = list[i]; + data->list[i].update = current_data.update; + data->list[i].buttons = current_data.buttons; + data->list[i].x_axis = current_data.x_axis; + data->list[i].y_axis = current_data.y_axis; + data->list[i].wheel = current_data.wheel; + data->list[i].tilt = current_data.tilt; + + if (port_no == 0 && g_cfg.io.mouse_debug_overlay && !g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay) + { + show_debug_overlay(data->list[i], ¤t_data); + } } list.clear(); diff --git a/rpcs3/Emu/Cell/Modules/cellPad.cpp b/rpcs3/Emu/Cell/Modules/cellPad.cpp index 086a341854..a217a37313 100644 --- a/rpcs3/Emu/Cell/Modules/cellPad.cpp +++ b/rpcs3/Emu/Cell/Modules/cellPad.cpp @@ -76,6 +76,9 @@ void pad_info::save(utils::serial& ar) void show_debug_overlay(const CellPadData& data, const Pad& pad, const pad_info& config) { const u32 setting = config.port_setting[pad.m_player_id]; + const CellPadData& raw = pad.data; + const u16 raw_d1 = raw.button[CELL_PAD_BTN_OFFSET_DIGITAL1]; + const u16 raw_d2 = raw.button[CELL_PAD_BTN_OFFSET_DIGITAL2]; const u16 d1 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL1]; const u16 d2 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL2]; @@ -86,6 +89,8 @@ void show_debug_overlay(const CellPadData& data, const Pad& pad, const pad_info& "> Digital: %5s %5s\n" "> Press: %5s %5s\n" "> Sensor: %5s %5s\n" + "> Large Motor: %5d %5d\n" + "> Small Motor: %5d %5d\n" ">\n" "> Digital 1: 0x%04x 0x%04x\n" "> Digital 2: 0x%04x 0x%04x\n" @@ -126,33 +131,35 @@ void show_debug_overlay(const CellPadData& data, const Pad& pad, const pad_info& "on", data.len >= CELL_PAD_LEN_CHANGE_DEFAULT ? "on" : "off", (setting & CELL_PAD_SETTING_PRESS_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_PRESS_ON ? "on" : "off", (setting & CELL_PAD_SETTING_SENSOR_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_SENSOR_ON ? "on" : "off", - pad.m_digital_1, d1, - pad.m_digital_2, d2, - pad.m_press_up, !!(d1 & CELL_PAD_CTRL_UP), data.button[CELL_PAD_BTN_OFFSET_PRESS_UP], - pad.m_press_down, !!(d1 & CELL_PAD_CTRL_DOWN), data.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN], - pad.m_press_left, !!(d1 & CELL_PAD_CTRL_LEFT), data.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT], - pad.m_press_right, !!(d1 & CELL_PAD_CTRL_RIGHT), data.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT], - pad.m_press_cross, !!(d2 & CELL_PAD_CTRL_CROSS), data.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS], - pad.m_press_square, !!(d2 & CELL_PAD_CTRL_SQUARE), data.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE], - pad.m_press_circle, !!(d2 & CELL_PAD_CTRL_CIRCLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE], - pad.m_press_triangle, !!(d2 & CELL_PAD_CTRL_TRIANGLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE], - !!(pad.m_digital_1 & CELL_PAD_CTRL_START), !!(d1 & CELL_PAD_CTRL_START), - !!(pad.m_digital_1 & CELL_PAD_CTRL_SELECT), !!(d1 & CELL_PAD_CTRL_SELECT), - !!(pad.m_digital_1 & CELL_PAD_CTRL_PS), !!(d1 & CELL_PAD_CTRL_PS), - pad.m_press_L1, !!(d2 & CELL_PAD_CTRL_L1), data.button[CELL_PAD_BTN_OFFSET_PRESS_L1], - pad.m_press_L2, !!(d2 & CELL_PAD_CTRL_L2), data.button[CELL_PAD_BTN_OFFSET_PRESS_L2], - !!(pad.m_digital_1 & CELL_PAD_CTRL_L3), !!(d1 & CELL_PAD_CTRL_L3), - pad.m_press_R1, !!(d2 & CELL_PAD_CTRL_R1), data.button[CELL_PAD_BTN_OFFSET_PRESS_R1], - pad.m_press_R2, !!(d2 & CELL_PAD_CTRL_R2), data.button[CELL_PAD_BTN_OFFSET_PRESS_R2], - !!(pad.m_digital_1 & CELL_PAD_CTRL_R3), !!(d1 & CELL_PAD_CTRL_R3), - pad.m_analog_left_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X], - pad.m_analog_left_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y], - pad.m_analog_right_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X], - pad.m_analog_right_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y], - pad.m_sensor_x, data.button[CELL_PAD_BTN_OFFSET_SENSOR_X], - pad.m_sensor_y, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y], - pad.m_sensor_z, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z], - pad.m_sensor_g, data.button[CELL_PAD_BTN_OFFSET_SENSOR_G], + pad.m_vibrate_motors[0].value, pad.m_vibrate_motors[0].adjusted_value, + pad.m_vibrate_motors[1].value, pad.m_vibrate_motors[1].adjusted_value, + raw_d1, d1, + raw_d2, d2, + raw.button[CELL_PAD_BTN_OFFSET_PRESS_UP], !!(d1 & CELL_PAD_CTRL_UP), data.button[CELL_PAD_BTN_OFFSET_PRESS_UP], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN], !!(d1 & CELL_PAD_CTRL_DOWN), data.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT], !!(d1 & CELL_PAD_CTRL_LEFT), data.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT], !!(d1 & CELL_PAD_CTRL_RIGHT), data.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS], !!(d2 & CELL_PAD_CTRL_CROSS), data.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE], !!(d2 & CELL_PAD_CTRL_SQUARE), data.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE], !!(d2 & CELL_PAD_CTRL_CIRCLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE], !!(d2 & CELL_PAD_CTRL_TRIANGLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE], + !!(raw_d1 & CELL_PAD_CTRL_START), !!(d1 & CELL_PAD_CTRL_START), + !!(raw_d1 & CELL_PAD_CTRL_SELECT), !!(d1 & CELL_PAD_CTRL_SELECT), + !!(raw_d1 & CELL_PAD_CTRL_PS), !!(d1 & CELL_PAD_CTRL_PS), + raw.button[CELL_PAD_BTN_OFFSET_PRESS_L1], !!(d2 & CELL_PAD_CTRL_L1), data.button[CELL_PAD_BTN_OFFSET_PRESS_L1], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_L2], !!(d2 & CELL_PAD_CTRL_L2), data.button[CELL_PAD_BTN_OFFSET_PRESS_L2], + !!(raw_d1 & CELL_PAD_CTRL_L3), !!(d1 & CELL_PAD_CTRL_L3), + raw.button[CELL_PAD_BTN_OFFSET_PRESS_R1], !!(d2 & CELL_PAD_CTRL_R1), data.button[CELL_PAD_BTN_OFFSET_PRESS_R1], + raw.button[CELL_PAD_BTN_OFFSET_PRESS_R2], !!(d2 & CELL_PAD_CTRL_R2), data.button[CELL_PAD_BTN_OFFSET_PRESS_R2], + !!(raw_d1 & CELL_PAD_CTRL_R3), !!(d1 & CELL_PAD_CTRL_R3), + raw.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X], data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X], + raw.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y], data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y], + raw.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X], data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X], + raw.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y], data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y], + raw.button[CELL_PAD_BTN_OFFSET_SENSOR_X], data.button[CELL_PAD_BTN_OFFSET_SENSOR_X], + raw.button[CELL_PAD_BTN_OFFSET_SENSOR_Y], data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y], + raw.button[CELL_PAD_BTN_OFFSET_SENSOR_Z], data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z], + raw.button[CELL_PAD_BTN_OFFSET_SENSOR_G], data.button[CELL_PAD_BTN_OFFSET_SENSOR_G], pad.m_product_id, pad.m_vendor_id, pad.m_device_type, @@ -305,17 +312,15 @@ void clear_pad_buffer(const std::shared_ptr& pad) // might as well also reset everything in our pad 'buffer' to nothing as well pad->m_buffer_cleared = true; - pad->m_analog_left_x = pad->m_analog_left_y = pad->m_analog_right_x = pad->m_analog_right_y = 128; - - pad->m_digital_1 = pad->m_digital_2 = 0; - pad->m_press_right = pad->m_press_left = pad->m_press_up = pad->m_press_down = 0; - pad->m_press_triangle = pad->m_press_circle = pad->m_press_cross = pad->m_press_square = 0; - pad->m_press_L1 = pad->m_press_L2 = pad->m_press_R1 = pad->m_press_R2 = 0; - - pad->m_sensor_x = DEFAULT_MOTION_X; - pad->m_sensor_y = DEFAULT_MOTION_Y; - pad->m_sensor_z = DEFAULT_MOTION_Z; - pad->m_sensor_g = DEFAULT_MOTION_G; + pad->data = {}; + pad->data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = 128; + pad->data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = 128; + pad->data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = 128; + pad->data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = 128; + pad->data.button[CELL_PAD_BTN_OFFSET_SENSOR_X] = DEFAULT_MOTION_X; + pad->data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = DEFAULT_MOTION_Y; + pad->data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = DEFAULT_MOTION_Z; + pad->data.button[CELL_PAD_BTN_OFFSET_SENSOR_G] = DEFAULT_MOTION_G; } error_code cellPadClearBuf(u32 port_no) @@ -363,6 +368,8 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) const u32 setting = config.port_setting[port_no]; bool btnChanged = false; + CellPadData& output = pad->data; + if (rinfo.ignore_input || !is_input_allowed()) { // Needed for Hotline Miami and Ninja Gaiden Sigma after dialogs were closed and buttons are still pressed. @@ -380,14 +387,14 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) } else { - const u16 d1Initial = pad->m_digital_1; - const u16 d2Initial = pad->m_digital_2; + const u16 d1_initial = output.button[CELL_PAD_BTN_OFFSET_DIGITAL1]; + const u16 d2_initial = output.button[CELL_PAD_BTN_OFFSET_DIGITAL2]; // Check if this pad is configured as a skateboard which ignores sticks and pressure button values. // Curiously it maps infrared on the press value of the face buttons for some reason. const bool use_piggyback = pad->m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD; - const auto set_value = [&btnChanged, use_piggyback, &pad](u16& value, u16 new_value, bool force_processing = false, u16 old_max_value = 255, u16 new_max_value = 255) + const auto set_value = [&btnChanged, use_piggyback, &pad](auto& value, u16 new_value, bool force_processing = false, u16 old_max_value = 255, u16 new_max_value = 255) { if (use_piggyback) { @@ -421,16 +428,16 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) case CELL_PAD_BTN_OFFSET_DIGITAL1: { if (button.m_pressed) - pad->m_digital_1 |= button.m_outKeyCode; + output.button[CELL_PAD_BTN_OFFSET_DIGITAL1] |= button.m_outKeyCode; else - pad->m_digital_1 &= ~button.m_outKeyCode; + output.button[CELL_PAD_BTN_OFFSET_DIGITAL1] &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_LEFT: set_value(pad->m_press_left, button.m_value); break; - case CELL_PAD_CTRL_DOWN: set_value(pad->m_press_down, button.m_value); break; - case CELL_PAD_CTRL_RIGHT: set_value(pad->m_press_right, button.m_value); break; - case CELL_PAD_CTRL_UP: set_value(pad->m_press_up, button.m_value); break; + case CELL_PAD_CTRL_LEFT: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT], button.m_value); break; + case CELL_PAD_CTRL_DOWN: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN], button.m_value); break; + case CELL_PAD_CTRL_RIGHT: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT], button.m_value); break; + case CELL_PAD_CTRL_UP: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_UP], button.m_value); break; // These aren't pressure btns case CELL_PAD_CTRL_R3: case CELL_PAD_CTRL_L3: @@ -443,20 +450,20 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) case CELL_PAD_BTN_OFFSET_DIGITAL2: { if (button.m_pressed) - pad->m_digital_2 |= button.m_outKeyCode; + output.button[CELL_PAD_BTN_OFFSET_DIGITAL2] |= button.m_outKeyCode; else - pad->m_digital_2 &= ~button.m_outKeyCode; + output.button[CELL_PAD_BTN_OFFSET_DIGITAL2] &= ~button.m_outKeyCode; switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_SQUARE: set_value(pad->m_press_square, button.m_value); break; - case CELL_PAD_CTRL_CROSS: set_value(pad->m_press_cross, button.m_value); break; - case CELL_PAD_CTRL_CIRCLE: set_value(pad->m_press_circle, button.m_value); break; - case CELL_PAD_CTRL_TRIANGLE: set_value(pad->m_press_triangle, button.m_value); break; - case CELL_PAD_CTRL_R1: set_value(pad->m_press_R1, button.m_value); break; - case CELL_PAD_CTRL_L1: set_value(pad->m_press_L1, button.m_value); break; - case CELL_PAD_CTRL_R2: set_value(pad->m_press_R2, button.m_value); break; - case CELL_PAD_CTRL_L2: set_value(pad->m_press_L2, button.m_value); break; + case CELL_PAD_CTRL_SQUARE: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE], button.m_value); break; + case CELL_PAD_CTRL_CROSS: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS], button.m_value); break; + case CELL_PAD_CTRL_CIRCLE: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE], button.m_value); break; + case CELL_PAD_CTRL_TRIANGLE: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE], button.m_value); break; + case CELL_PAD_CTRL_R1: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_R1], button.m_value); break; + case CELL_PAD_CTRL_L1: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_L1], button.m_value); break; + case CELL_PAD_CTRL_R2: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_R2], button.m_value); break; + case CELL_PAD_CTRL_L2: set_value(output.button[CELL_PAD_BTN_OFFSET_PRESS_L2], button.m_value); break; default: break; } break; @@ -465,18 +472,22 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) { switch (button.m_outKeyCode) { - case CELL_PAD_CTRL_PRESS_RIGHT: set_value(pad->m_press_right, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_LEFT: set_value(pad->m_press_left, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_UP: set_value(pad->m_press_up, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_DOWN: set_value(pad->m_press_down, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard - case CELL_PAD_CTRL_PRESS_L1: set_value(pad->m_press_L1, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_R1: set_value(pad->m_press_R1, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_L2: set_value(pad->m_press_L2, button.m_value, true); break; - case CELL_PAD_CTRL_PRESS_R2: set_value(pad->m_press_R2, button.m_value, true); break; + case CELL_PAD_CTRL_PRESS_RIGHT: + case CELL_PAD_CTRL_PRESS_LEFT: + case CELL_PAD_CTRL_PRESS_UP: + case CELL_PAD_CTRL_PRESS_DOWN: + case CELL_PAD_CTRL_PRESS_L1: + case CELL_PAD_CTRL_PRESS_R1: + case CELL_PAD_CTRL_PRESS_L2: + case CELL_PAD_CTRL_PRESS_R2: + set_value(output.button[button.m_outKeyCode], button.m_value, true); + break; + case CELL_PAD_CTRL_PRESS_TRIANGLE: + case CELL_PAD_CTRL_PRESS_CIRCLE: + case CELL_PAD_CTRL_PRESS_CROSS: + case CELL_PAD_CTRL_PRESS_SQUARE: + set_value(output.button[button.m_outKeyCode], button.m_value, true, 255, 63); // Infrared on RIDE Skateboard + break; default: break; } break; @@ -490,11 +501,14 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) { switch (stick.m_offset) { - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: set_value(pad->m_analog_left_x, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: set_value(pad->m_analog_left_y, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: set_value(pad->m_analog_right_x, stick.m_value); break; - case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: set_value(pad->m_analog_right_y, stick.m_value); break; - default: break; + case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X: + case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y: + case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X: + case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y: + set_value(output.button[stick.m_offset], stick.m_value); + break; + default: + break; } } @@ -504,16 +518,19 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) { switch (sensor.m_offset) { - case CELL_PAD_BTN_OFFSET_SENSOR_X: set_value(pad->m_sensor_x, sensor.m_value, true); break; - case CELL_PAD_BTN_OFFSET_SENSOR_Y: set_value(pad->m_sensor_y, sensor.m_value, true); break; - case CELL_PAD_BTN_OFFSET_SENSOR_Z: set_value(pad->m_sensor_z, sensor.m_value, true); break; - case CELL_PAD_BTN_OFFSET_SENSOR_G: set_value(pad->m_sensor_g, sensor.m_value, true); break; - default: break; + case CELL_PAD_BTN_OFFSET_SENSOR_X: + case CELL_PAD_BTN_OFFSET_SENSOR_Y: + case CELL_PAD_BTN_OFFSET_SENSOR_Z: + case CELL_PAD_BTN_OFFSET_SENSOR_G: + set_value(output.button[sensor.m_offset], sensor.m_value, true); + break; + default: + break; } } } - if (d1Initial != pad->m_digital_1 || d2Initial != pad->m_digital_2) + if (d1_initial != output.button[CELL_PAD_BTN_OFFSET_DIGITAL1] || d2_initial != output.button[CELL_PAD_BTN_OFFSET_DIGITAL2]) { btnChanged = true; } @@ -556,41 +573,25 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false) // bits 15-8 reserved, 7-4 = 0x7, 3-0: data->len/2; data->button[1] = (0x7 << 4) | std::min(data->len / 2, 15); - data->button[CELL_PAD_BTN_OFFSET_DIGITAL1] = pad->m_digital_1; - data->button[CELL_PAD_BTN_OFFSET_DIGITAL2] = pad->m_digital_2; - data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X] = pad->m_analog_right_x; - data->button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y] = pad->m_analog_right_y; - data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X] = pad->m_analog_left_x; - data->button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y] = pad->m_analog_left_y; - if (setting & CELL_PAD_SETTING_PRESS_ON) { - data->button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT] = pad->m_press_right; - data->button[CELL_PAD_BTN_OFFSET_PRESS_LEFT] = pad->m_press_left; - data->button[CELL_PAD_BTN_OFFSET_PRESS_UP] = pad->m_press_up; - data->button[CELL_PAD_BTN_OFFSET_PRESS_DOWN] = pad->m_press_down; - data->button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE] = pad->m_press_triangle; - data->button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE] = pad->m_press_circle; - data->button[CELL_PAD_BTN_OFFSET_PRESS_CROSS] = pad->m_press_cross; - data->button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE] = pad->m_press_square; - data->button[CELL_PAD_BTN_OFFSET_PRESS_L1] = pad->m_press_L1; - data->button[CELL_PAD_BTN_OFFSET_PRESS_R1] = pad->m_press_R1; - data->button[CELL_PAD_BTN_OFFSET_PRESS_L2] = pad->m_press_L2; - data->button[CELL_PAD_BTN_OFFSET_PRESS_R2] = pad->m_press_R2; + constexpr u32 copy_size = (static_cast(CELL_PAD_LEN_CHANGE_PRESS_ON) - static_cast(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16); + std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_DIGITAL1], &output.button[CELL_PAD_BTN_OFFSET_DIGITAL1], copy_size); } else { + constexpr u32 copy_size = (static_cast(CELL_PAD_LEN_CHANGE_DEFAULT) - static_cast(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16); + std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_DIGITAL1], &output.button[CELL_PAD_BTN_OFFSET_DIGITAL1], copy_size); + // Clear area if setting is not used - constexpr u32 area_lengh = (CELL_PAD_LEN_CHANGE_PRESS_ON - CELL_PAD_LEN_CHANGE_DEFAULT) * sizeof(u16); - std::memset(&data->button[CELL_PAD_LEN_CHANGE_DEFAULT], 0, area_lengh); + constexpr u32 area_size = (CELL_PAD_LEN_CHANGE_PRESS_ON - CELL_PAD_LEN_CHANGE_DEFAULT) * sizeof(u16); + std::memset(&data->button[CELL_PAD_LEN_CHANGE_DEFAULT], 0, area_size); } if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON) { - data->button[CELL_PAD_BTN_OFFSET_SENSOR_X] = pad->m_sensor_x; - data->button[CELL_PAD_BTN_OFFSET_SENSOR_Y] = pad->m_sensor_y; - data->button[CELL_PAD_BTN_OFFSET_SENSOR_Z] = pad->m_sensor_z; - data->button[CELL_PAD_BTN_OFFSET_SENSOR_G] = pad->m_sensor_g; + constexpr u32 copy_size = (static_cast(CELL_PAD_LEN_CHANGE_SENSOR_ON) - static_cast(CELL_PAD_BTN_OFFSET_SENSOR_X)) * sizeof(u16); + std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_SENSOR_X], &output.button[CELL_PAD_BTN_OFFSET_SENSOR_X], copy_size); } } @@ -717,7 +718,7 @@ error_code cellPadGetData(u32 port_no, vm::ptr data) pad_get_data(port_no, data.get_ptr()); - if (g_cfg.io.debug_overlay && !g_cfg.video.debug_overlay && port_no == 0) + if (g_cfg.io.pad_debug_overlay && !g_cfg.video.debug_overlay && port_no == 0) { show_debug_overlay(*data, *pad, config); } @@ -834,6 +835,7 @@ error_code cellPadGetRawData(u32 port_no, vm::ptr data) return not_an_error(CELL_PAD_ERROR_NO_DEVICE); // ? + // std::memcpy(data.get_ptr(), &pad->data, sizeof(CellPadData)); return CELL_OK; } @@ -901,7 +903,7 @@ error_code cellPadSetActDirect(u32 port_no, vm::ptr param) if (!(pad->m_device_capability & CELL_PAD_CAPABILITY_ACTUATOR)) return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD; - handler->SetRumble(port_no, param->motor[1], param->motor[0] > 0); + handler->SetRumble(port_no, param->motor[1], param->motor[0]); return CELL_OK; } diff --git a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp index a7d15af2d5..13e4b0dd83 100644 --- a/rpcs3/Emu/Cell/Modules/cellSysutil.cpp +++ b/rpcs3/Emu/Cell/Modules/cellSysutil.cpp @@ -426,11 +426,11 @@ error_code cellSysutilGetSystemParamInt(CellSysutilParamId id, vm::ptr valu break; case CELL_SYSUTIL_SYSTEMPARAM_ID_DATE_FORMAT: - *value = CELL_SYSUTIL_DATE_FMT_DDMMYYYY; + *value = static_cast(g_cfg.sys.date_fmt.get()); break; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIME_FORMAT: - *value = CELL_SYSUTIL_TIME_FMT_CLOCK24; + *value = static_cast(g_cfg.sys.time_fmt.get()); break; case CELL_SYSUTIL_SYSTEMPARAM_ID_TIMEZONE: diff --git a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp index e0db365933..a51ffbf756 100644 --- a/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp +++ b/rpcs3/Emu/Cell/Modules/cellVideoOut.cpp @@ -202,7 +202,7 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptrresolutionId, &res) != CELL_OK || - (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING && g_cfg.video.stereo_render_mode == stereo_render_mode_options::disabled)) + (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING && !g_cfg.video.stereo_enabled)) { // Resolution not supported cellSysutil.error("Unusual resolution requested: 0x%x", config->resolutionId); @@ -211,7 +211,7 @@ error_code cellVideoOutConfigure(u32 videoOut, vm::ptrget(); conf.resolution_id = config->resolutionId; - conf.stereo_mode = (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING) ? g_cfg.video.stereo_render_mode.get() : stereo_render_mode_options::disabled; + conf.stereo_enabled = (config->resolutionId >= CELL_VIDEO_OUT_RESOLUTION_720_3D_FRAME_PACKING) && g_cfg.video.stereo_enabled; conf.aspect = config->aspect; conf.format = config->format; conf.scanline_pitch = config->pitch; @@ -393,7 +393,7 @@ error_code cellVideoOutGetDeviceInfo(u32 videoOut, u32 deviceIndex, vm::ptr myLanguages) return SCE_NP_ERROR_INVALID_STATE; } - myLanguages->language1 = SCE_NP_LANG_ENGLISH_US; - myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? g_cfg.sys.language : -1; + myLanguages->language1 = g_cfg.sys.language; + myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? CELL_SYSUTIL_LANG_ENGLISH_US : -1; myLanguages->language3 = -1; return CELL_OK; @@ -3968,7 +3968,7 @@ error_code sceNpManagerGetAccountRegion(vm::ptr countryCode, v ensure(ccode.size() == sizeof(SceNpCountryCode::data)); std::memcpy(countryCode->data, ccode.data(), sizeof(SceNpCountryCode::data)); - *language = CELL_SYSUTIL_LANG_ENGLISH_US; + *language = g_cfg.sys.language; return CELL_OK; } diff --git a/rpcs3/Emu/Cell/PPUAnalyser.h b/rpcs3/Emu/Cell/PPUAnalyser.h index 693ad8c7ea..8d6486c9a4 100644 --- a/rpcs3/Emu/Cell/PPUAnalyser.h +++ b/rpcs3/Emu/Cell/PPUAnalyser.h @@ -145,6 +145,7 @@ struct ppu_module : public Type std::shared_ptr> jit_bounds; // JIT instance modules addresses range std::unordered_map imports; // Imports information for release upon unload (TODO: OVL implementation!) std::map>> stub_addr_to_constant_state_of_registers; // Tells possible constant states of registers of functions + std::vector excluded_funcs; // Function code not be overwritten bool is_relocatable = false; // Is code relocatable(?) template diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 69d11864d1..cc39eadadd 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -7659,8 +7659,8 @@ ppu_interpreter_rt_base::ppu_interpreter_rt_base() noexcept INIT(LBZUX); INIT_RC(NOR); INIT(STVEBX); - INIT_OV(SUBFE); - INIT_OV(ADDE); + INIT_RC_OV(SUBFE); + INIT_RC_OV(ADDE); INIT(MTOCRF); INIT(STDX); INIT(STWCX); diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index 312cfad783..64a989a9bf 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -195,17 +195,17 @@ const auto ppu_gateway = build_function_asm("ppu_gateway", c.push(x86::rdi); c.push(x86::rbp); c.push(x86::rbx); - c.sub(x86::rsp, 0xa8); - c.movaps(x86::oword_ptr(x86::rsp, 0x90), x86::xmm15); - c.movaps(x86::oword_ptr(x86::rsp, 0x80), x86::xmm14); - c.movaps(x86::oword_ptr(x86::rsp, 0x70), x86::xmm13); - c.movaps(x86::oword_ptr(x86::rsp, 0x60), x86::xmm12); - c.movaps(x86::oword_ptr(x86::rsp, 0x50), x86::xmm11); - c.movaps(x86::oword_ptr(x86::rsp, 0x40), x86::xmm10); - c.movaps(x86::oword_ptr(x86::rsp, 0x30), x86::xmm9); - c.movaps(x86::oword_ptr(x86::rsp, 0x20), x86::xmm8); - c.movaps(x86::oword_ptr(x86::rsp, 0x10), x86::xmm7); - c.movaps(x86::oword_ptr(x86::rsp, 0), x86::xmm6); + c.sub(x86::rsp, 0xc8); + c.movaps(x86::oword_ptr(x86::rsp, 0xb0), x86::xmm15); + c.movaps(x86::oword_ptr(x86::rsp, 0xa0), x86::xmm14); + c.movaps(x86::oword_ptr(x86::rsp, 0x90), x86::xmm13); + c.movaps(x86::oword_ptr(x86::rsp, 0x80), x86::xmm12); + c.movaps(x86::oword_ptr(x86::rsp, 0x70), x86::xmm11); + c.movaps(x86::oword_ptr(x86::rsp, 0x60), x86::xmm10); + c.movaps(x86::oword_ptr(x86::rsp, 0x50), x86::xmm9); + c.movaps(x86::oword_ptr(x86::rsp, 0x40), x86::xmm8); + c.movaps(x86::oword_ptr(x86::rsp, 0x30), x86::xmm7); + c.movaps(x86::oword_ptr(x86::rsp, 0x20), x86::xmm6); #else c.push(x86::rbp); c.push(x86::r15); @@ -252,17 +252,17 @@ const auto ppu_gateway = build_function_asm("ppu_gateway", } #ifdef _WIN32 - c.movaps(x86::xmm6, x86::oword_ptr(x86::rsp, 0)); - c.movaps(x86::xmm7, x86::oword_ptr(x86::rsp, 0x10)); - c.movaps(x86::xmm8, x86::oword_ptr(x86::rsp, 0x20)); - c.movaps(x86::xmm9, x86::oword_ptr(x86::rsp, 0x30)); - c.movaps(x86::xmm10, x86::oword_ptr(x86::rsp, 0x40)); - c.movaps(x86::xmm11, x86::oword_ptr(x86::rsp, 0x50)); - c.movaps(x86::xmm12, x86::oword_ptr(x86::rsp, 0x60)); - c.movaps(x86::xmm13, x86::oword_ptr(x86::rsp, 0x70)); - c.movaps(x86::xmm14, x86::oword_ptr(x86::rsp, 0x80)); - c.movaps(x86::xmm15, x86::oword_ptr(x86::rsp, 0x90)); - c.add(x86::rsp, 0xa8); + c.movaps(x86::xmm6, x86::oword_ptr(x86::rsp, 0x20)); + c.movaps(x86::xmm7, x86::oword_ptr(x86::rsp, 0x30)); + c.movaps(x86::xmm8, x86::oword_ptr(x86::rsp, 0x40)); + c.movaps(x86::xmm9, x86::oword_ptr(x86::rsp, 0x50)); + c.movaps(x86::xmm10, x86::oword_ptr(x86::rsp, 0x60)); + c.movaps(x86::xmm11, x86::oword_ptr(x86::rsp, 0x70)); + c.movaps(x86::xmm12, x86::oword_ptr(x86::rsp, 0x80)); + c.movaps(x86::xmm13, x86::oword_ptr(x86::rsp, 0x90)); + c.movaps(x86::xmm14, x86::oword_ptr(x86::rsp, 0xa0)); + c.movaps(x86::xmm15, x86::oword_ptr(x86::rsp, 0xb0)); + c.add(x86::rsp, 0xc8); c.pop(x86::rbx); c.pop(x86::rbp); c.pop(x86::rdi); @@ -934,13 +934,40 @@ struct ppu_far_jumps_t ppu_far_jumps_t(int) noexcept {} std::map vals; + std::pair vals_range{0, 0}; ::jit_runtime rt; mutable shared_mutex mutex; + void add_value(u32 addr, all_info_t info) + { + vals.insert_or_assign(addr, std::move(info)); + + if (vals.size() == 1) + { + vals_range.first = addr; + vals_range.second = addr; + } + else + { + vals_range.first = std::min(vals_range.first, addr); + vals_range.second = std::max(vals_range.second, addr); + } + } + // Get target address, 'ppu' is used in ppu_far_jump in order to modify registers u32 get_target(u32 pc, ppu_thread* ppu = nullptr) { + if (vals_range.first > pc) + { + return 0; + } + + if (vals_range.second < pc) + { + return 0; + } + reader_lock lock(mutex); if (auto it = vals.find(pc); it != vals.end()) @@ -949,7 +976,7 @@ struct ppu_far_jumps_t return all_info.get_target(pc, ppu); } - return {}; + return 0; } // Get function patches in range (entry -> target) @@ -957,6 +984,16 @@ struct ppu_far_jumps_t { std::vector> targets; + if (vals_range.first >= pc + size) + { + return targets; + } + + if (vals_range.second < pc) + { + return targets; + } + reader_lock lock(mutex); auto it = vals.lower_bound(pc); @@ -1005,22 +1042,21 @@ struct ppu_far_jumps_t #ifdef ARCH_X64 c.mov(args[0], x86::rbp); - c.mov(x86::dword_ptr(args[0], ::offset32(&ppu_thread::cia)), pc); + c.mov(args[2], vm::g_base_addr + pc); c.jmp(ppu_far_jump); #else Label jmp_address = c.newLabel(); - Label imm_address = c.newLabel(); + Label this_op_address = c.newLabel(); - c.ldr(args[1].w(), arm::ptr(imm_address)); - c.str(args[1].w(), arm::Mem(args[0], ::offset32(&ppu_thread::cia))); + c.ldr(args[2], arm::ptr(this_op_address)); c.ldr(args[1], arm::ptr(jmp_address)); c.br(args[1]); c.align(AlignMode::kCode, 16); c.bind(jmp_address); c.embedUInt64(reinterpret_cast(ppu_far_jump)); - c.bind(imm_address); - c.embedUInt32(pc); + c.bind(this_op_address); + c.embedUInt64(reinterpret_cast(vm::g_base_addr) + pc); #endif }, &rt); } @@ -1039,9 +1075,9 @@ u32 ppu_get_far_jump(u32 pc) return g_fxo->get().get_target(pc); } -static void ppu_far_jump(ppu_thread& ppu, ppu_opcode_t, be_t*, ppu_intrp_func*) +static void ppu_far_jump(ppu_thread& ppu, ppu_opcode_t, be_t* this_op, ppu_intrp_func*) { - const u32 cia = g_fxo->get().get_target(ppu.cia, &ppu); + const u32 cia = g_fxo->get().get_target(vm::get_addr(this_op), &ppu); if (!vm::check_addr(cia, vm::page_executable)) { @@ -1110,7 +1146,7 @@ bool ppu_form_branch_to_code(u32 entry, u32 target, bool link, bool with_toc, st auto& jumps = g_fxo->get(); std::lock_guard lock(jumps.mutex); - jumps.vals.insert_or_assign(entry, ppu_far_jumps_t::all_info_t{target, link, with_toc, std::move(module_name)}); + jumps.add_value(entry, ppu_far_jumps_t::all_info_t{target, link, with_toc, std::move(module_name)}); ppu_register_function_at(entry, 4, g_cfg.core.ppu_decoder == ppu_decoder_type::_static ? &ppu_far_jump : ensure(g_fxo->get().gen_jump(entry))); return true; @@ -2326,10 +2362,11 @@ void ppu_thread::cpu_wait(bs_t old) if (u32 addr = res_notify) { res_notify = 0; + res_notify_postpone_streak = 0; - if (res_notify_time == vm::reservation_notifier_count_index(addr).second) + if (res_notify_time + 128 == (vm::reservation_acquire(addr) & -128)) { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, res_notify_time); } } @@ -3117,7 +3154,6 @@ static T ppu_load_acquire_reservation(ppu_thread& ppu, u32 addr) { // Reload "cached" reservation of previous succeeded conditional store // This seems like a hardware feature according to cellSpursAddUrgentCommand function - ppu.rtime -= 128; } else { @@ -3614,67 +3650,70 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value) { extern atomic_t liblv2_begin, liblv2_end; + u32 notify = ppu.res_notify; + // Avoid notifications from lwmutex or sys_spinlock - if (new_data != old_data && (ppu.cia < liblv2_begin || ppu.cia >= liblv2_end)) + const bool is_liblv2_or_null = (ppu.cia >= liblv2_begin && ppu.cia < liblv2_end); + + if (!is_liblv2_or_null) { - u32 notify = ppu.res_notify; + // Try to postpone notification to when PPU is asleep or join notifications on the same address + // This also optimizes a mutex - won't notify after lock is aqcuired (prolonging the critical section duration), only notifies on unlock + const u32 count = vm::reservation_notifier_count(addr, rtime); - if (notify) + switch (count) { - if (ppu.res_notify_time == vm::reservation_notifier_count_index(notify).second) - { - ppu.state += cpu_flag::wait; - vm::reservation_notifier_notify(notify); - } - else - { - notify = 0; - } - - ppu.res_notify = 0; + case 0: + { + // Nothing to do + break; } - - if ((addr ^ notify) & -128) + case 1: { - // Try to postpone notification to when PPU is asleep or join notifications on the same address - // This also optimizes a mutex - won't notify after lock is aqcuired (prolonging the critical section duration), only notifies on unlock - const auto [count, index] = vm::reservation_notifier_count_index(addr); - - switch (count) + // Postpone notifications if there is no pending one OR if there is likely a complex operation on reservation going on + // Which consists of multiple used addresses + if (ppu.res_notify_postpone_streak <= 4) { - case 0: - { - // Nothing to do - break; - } - case 1: - { - if (!notify) + if (!notify || ((notify & -128) == (addr & -128) && new_data != old_data)) { ppu.res_notify = addr; - ppu.res_notify_time = index; + ppu.res_notify_time = rtime; + ppu.res_notify_postpone_streak++; + notify = 0; break; } - - // Notify both - [[fallthrough]]; } - default: + + // Notify both + [[fallthrough]]; + } + default: + { + if (cpu_flag::wait - ppu.state) { - if (!notify) - { - ppu.state += cpu_flag::wait; - } + ppu.state += cpu_flag::wait; + } - vm::reservation_notifier_notify(addr); - break; - } - } + vm::reservation_notifier_notify(addr, rtime); + break; + } + } + } + + if (notify) + { + if (auto waiter = vm::reservation_notifier_notify(notify, ppu.res_notify_time, true)) + { + ppu.state += cpu_flag::wait; + waiter->notify_all(); } - static_cast(ppu.test_stopped()); + ppu.res_notify = 0; + ppu.res_notify_postpone_streak = 0; } + static_cast(ppu.test_stopped()); + if (addr == ppu.last_faddr) { ppu.last_succ++; @@ -3682,7 +3721,6 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value) ppu.last_faddr = 0; ppu.res_cached = ppu.raddr; - ppu.rtime += 128; ppu.raddr = 0; return true; } @@ -3693,14 +3731,15 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value) // And on failure it has some time to do something else if (notify && ((addr ^ notify) & -128)) { - if (ppu.res_notify_time == vm::reservation_notifier_count_index(notify).second) + if (auto waiter = vm::reservation_notifier_notify(notify, ppu.res_notify_time, true)) { ppu.state += cpu_flag::wait; - vm::reservation_notifier_notify(notify); + waiter->notify_all(); static_cast(ppu.test_stopped()); } ppu.res_notify = 0; + ppu.res_notify_postpone_streak = 0; } ppu.raddr = 0; @@ -5211,6 +5250,7 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s { // Replace the function with ppu_far_jump fpos++; + part.excluded_funcs.emplace_back(func.addr); continue; } } @@ -5243,6 +5283,11 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s continue; } + if (std::count(part.excluded_funcs.begin(), part.excluded_funcs.end(), func.addr)) + { + continue; + } + const be_t addr = func.addr - reloc; const be_t size = func.size; sha1_update(&ctx, reinterpret_cast(&addr), sizeof(addr)); @@ -5340,6 +5385,13 @@ bool ppu_initialize(const ppu_module& info, bool check_only, u64 file_s continue; } + if (g_fxo->is_init() && !g_fxo->get().get_targets(func.addr, func.size).empty()) + { + // Filter out functions with patches + part.excluded_funcs.emplace_back(func.addr); + continue; + } + addrs.emplace_back(func.addr - reloc); } @@ -5780,6 +5832,11 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module { if (func.size) { + if (std::count(module_part.excluded_funcs.begin(), module_part.excluded_funcs.end(), func.addr)) + { + continue; + } + const auto f = cast(_module->getOrInsertFunction(fmt::format("__0x%x", func.addr - reloc), _func).getCallee()); f->setCallingConv(CallingConv::GHC); f->addParamAttr(1, llvm::Attribute::NoAlias); @@ -5835,6 +5892,11 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module& module if (mod_func.size) { + if (std::count(module_part.excluded_funcs.begin(), module_part.excluded_funcs.end(), mod_func.addr)) + { + continue; + } + num_func++; guest_code_size += mod_func.size; max_addr = std::max(max_addr, mod_func.addr + mod_func.size); diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index 322cc13ebe..97c705aed5 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -267,6 +267,7 @@ public: u32 res_cached{0}; // Reservation "cached" addresss u32 res_notify{0}; u64 res_notify_time{0}; + u32 res_notify_postpone_streak{0}; union ppu_prio_t { diff --git a/rpcs3/Emu/Cell/PPUTranslator.cpp b/rpcs3/Emu/Cell/PPUTranslator.cpp index 7380d8123f..0a17de2d0f 100644 --- a/rpcs3/Emu/Cell/PPUTranslator.cpp +++ b/rpcs3/Emu/Cell/PPUTranslator.cpp @@ -364,6 +364,12 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) continue; } + if (std::count(info.excluded_funcs.begin(), info.excluded_funcs.end(), f.addr)) + { + // Excluded function (possibly patched) + continue; + } + vec_addrs.push_back(static_cast(f.addr - base)); functions.push_back(cast(m_module->getOrInsertFunction(fmt::format("__0x%x", f.addr - base), ftype).getCallee())); } @@ -413,12 +419,11 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module& info) const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type()); const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc; const auto pos = m_ir->CreateShl(pos_32, 1); - const auto ptr = dyn_cast(m_ir->CreateGEP(get_type(), m_exec, pos)); + const auto ptr = m_ir->CreatePtrAdd(m_exec, pos); - const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd( - m_ir->CreatePtrToInt(m_exec, get_type()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType()); + const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset)); const auto seg_pos = m_ir->CreateLShr(pos_32, 1); - const auto seg_ptr = dyn_cast(m_ir->CreateGEP(get_type(), seg_base_ptr, seg_pos)); + const auto seg_ptr = m_ir->CreatePtrAdd(seg_base_ptr, seg_pos); const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type()); // Store to jumptable @@ -610,15 +615,14 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect) } const auto pos = m_ir->CreateShl(indirect, 1); - const auto ptr = dyn_cast(m_ir->CreateGEP(get_type(), m_exec, pos)); + const auto ptr = m_ir->CreatePtrAdd(m_exec, pos); const auto val = m_ir->CreateLoad(get_type(), ptr); callee = FunctionCallee(type, m_ir->CreateIntToPtr(val, m_ir->getPtrTy())); // Load new segment address - const auto seg_base_ptr = m_ir->CreateIntToPtr(m_ir->CreateAdd( - m_ir->CreatePtrToInt(m_exec, get_type()), m_ir->getInt64(vm::g_exec_addr_seg_offset)), m_exec->getType()); + const auto seg_base_ptr = m_ir->CreatePtrAdd(m_exec, m_ir->getInt64(vm::g_exec_addr_seg_offset)); const auto seg_pos = m_ir->CreateLShr(indirect, 1); - const auto seg_ptr = dyn_cast(m_ir->CreateGEP(get_type(), seg_base_ptr, seg_pos)); + const auto seg_ptr = m_ir->CreatePtrAdd(seg_base_ptr, seg_pos); const auto seg_val = m_ir->CreateZExt(m_ir->CreateLoad(get_type(), seg_ptr), get_type()); seg0 = m_ir->CreateShl(seg_val, 13); } @@ -824,7 +828,7 @@ void PPUTranslator::UseCondition(MDNode* hint, Value* cond) llvm::Value* PPUTranslator::GetMemory(llvm::Value* addr) { - return m_ir->CreateGEP(get_type(), m_base, addr); + return m_ir->CreatePtrAdd(m_base, addr); } void PPUTranslator::TestAborted() @@ -2794,8 +2798,8 @@ void PPUTranslator::MFOCRF(ppu_opcode_t op) else if (std::none_of(m_cr + 0, m_cr + 32, [](auto* p) { return p; })) { // MFCR (optimized) - Value* ln0 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 99), GetType()), m_ir->getPtrTy()); - Value* ln1 = m_ir->CreateIntToPtr(m_ir->CreatePtrToInt(m_ir->CreateStructGEP(m_thread_type, m_thread, 115), GetType()), m_ir->getPtrTy()); + Value* ln0 = m_ir->CreateStructGEP(m_thread_type, m_thread, 99); + Value* ln1 = m_ir->CreateStructGEP(m_thread_type, m_thread, 115); ln0 = m_ir->CreateLoad(GetType(), ln0); ln1 = m_ir->CreateLoad(GetType(), ln1); diff --git a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp index 41e81ac4e2..3531285042 100644 --- a/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPUCommonRecompiler.cpp @@ -305,17 +305,17 @@ DECLARE(spu_runtime::g_gateway) = build_function_asm("spu_gatewa c.push(x86::rdi); c.push(x86::rbp); c.push(x86::rbx); - c.sub(x86::rsp, 0xa8); - c.movaps(x86::oword_ptr(x86::rsp, 0x90), x86::xmm15); - c.movaps(x86::oword_ptr(x86::rsp, 0x80), x86::xmm14); - c.movaps(x86::oword_ptr(x86::rsp, 0x70), x86::xmm13); - c.movaps(x86::oword_ptr(x86::rsp, 0x60), x86::xmm12); - c.movaps(x86::oword_ptr(x86::rsp, 0x50), x86::xmm11); - c.movaps(x86::oword_ptr(x86::rsp, 0x40), x86::xmm10); - c.movaps(x86::oword_ptr(x86::rsp, 0x30), x86::xmm9); - c.movaps(x86::oword_ptr(x86::rsp, 0x20), x86::xmm8); - c.movaps(x86::oword_ptr(x86::rsp, 0x10), x86::xmm7); - c.movaps(x86::oword_ptr(x86::rsp, 0), x86::xmm6); + c.sub(x86::rsp, 0xc8); + c.movaps(x86::oword_ptr(x86::rsp, 0xb0), x86::xmm15); + c.movaps(x86::oword_ptr(x86::rsp, 0xa0), x86::xmm14); + c.movaps(x86::oword_ptr(x86::rsp, 0x90), x86::xmm13); + c.movaps(x86::oword_ptr(x86::rsp, 0x80), x86::xmm12); + c.movaps(x86::oword_ptr(x86::rsp, 0x70), x86::xmm11); + c.movaps(x86::oword_ptr(x86::rsp, 0x60), x86::xmm10); + c.movaps(x86::oword_ptr(x86::rsp, 0x50), x86::xmm9); + c.movaps(x86::oword_ptr(x86::rsp, 0x40), x86::xmm8); + c.movaps(x86::oword_ptr(x86::rsp, 0x30), x86::xmm7); + c.movaps(x86::oword_ptr(x86::rsp, 0x20), x86::xmm6); #else c.push(x86::rbp); c.push(x86::r15); @@ -348,17 +348,17 @@ DECLARE(spu_runtime::g_gateway) = build_function_asm("spu_gatewa } #ifdef _WIN32 - c.movaps(x86::xmm6, x86::oword_ptr(x86::rsp, 0)); - c.movaps(x86::xmm7, x86::oword_ptr(x86::rsp, 0x10)); - c.movaps(x86::xmm8, x86::oword_ptr(x86::rsp, 0x20)); - c.movaps(x86::xmm9, x86::oword_ptr(x86::rsp, 0x30)); - c.movaps(x86::xmm10, x86::oword_ptr(x86::rsp, 0x40)); - c.movaps(x86::xmm11, x86::oword_ptr(x86::rsp, 0x50)); - c.movaps(x86::xmm12, x86::oword_ptr(x86::rsp, 0x60)); - c.movaps(x86::xmm13, x86::oword_ptr(x86::rsp, 0x70)); - c.movaps(x86::xmm14, x86::oword_ptr(x86::rsp, 0x80)); - c.movaps(x86::xmm15, x86::oword_ptr(x86::rsp, 0x90)); - c.add(x86::rsp, 0xa8); + c.movaps(x86::xmm6, x86::oword_ptr(x86::rsp, 0x20)); + c.movaps(x86::xmm7, x86::oword_ptr(x86::rsp, 0x30)); + c.movaps(x86::xmm8, x86::oword_ptr(x86::rsp, 0x40)); + c.movaps(x86::xmm9, x86::oword_ptr(x86::rsp, 0x50)); + c.movaps(x86::xmm10, x86::oword_ptr(x86::rsp, 0x60)); + c.movaps(x86::xmm11, x86::oword_ptr(x86::rsp, 0x70)); + c.movaps(x86::xmm12, x86::oword_ptr(x86::rsp, 0x80)); + c.movaps(x86::xmm13, x86::oword_ptr(x86::rsp, 0x90)); + c.movaps(x86::xmm14, x86::oword_ptr(x86::rsp, 0xa0)); + c.movaps(x86::xmm15, x86::oword_ptr(x86::rsp, 0xb0)); + c.add(x86::rsp, 0xc8); c.pop(x86::rbx); c.pop(x86::rbp); c.pop(x86::rdi); diff --git a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp index 9bc50f7ea2..169d01a09d 100644 --- a/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/SPULLVMRecompiler.cpp @@ -329,9 +329,9 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator if (!m_finfo->fn && !m_block) { - lr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, +s_reg_lr, &v128::_u32, 3)); - sp = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, +s_reg_sp)); - r3 = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, 3)); + lr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, +s_reg_lr, &v128::_u32, 3)); + sp = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, +s_reg_sp)); + r3 = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, 3)); } else { @@ -348,8 +348,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator if (!m_finfo->fn) { lr = m_ir->CreateAnd(lr, 0x3fffc); - m_ir->CreateStore(lr, spu_ptr(&spu_thread::pc)); - m_ir->CreateStore(_call, spu_ptr(&spu_thread::gpr, 3)); + m_ir->CreateStore(lr, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(_call, spu_ptr(&spu_thread::gpr, 3)); m_ir->CreateBr(add_block_indirect({}, value(lr))); } else if (tail) @@ -392,7 +392,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_blocks.clear(); m_block_queue.clear(); m_ir->SetInsertPoint(llvm::BasicBlock::Create(m_context, "", m_function)); - m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); + m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); } // Add block with current block as a predecessor @@ -415,7 +415,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_lsptr = fn->getArg(1); m_base_pc = fn->getArg(2); m_ir->SetInsertPoint(llvm::BasicBlock::Create(m_context, "", fn)); - m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); + m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); // Load registers at the entry chunk for (u32 i = 0; i < s_reg_max; i++) @@ -452,7 +452,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto fail = llvm::BasicBlock::Create(m_context, "", m_function); m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_base_pc, m_ir->getInt32(m_base)), next, fail); m_ir->SetInsertPoint(fail); - m_ir->CreateStore(m_ir->getInt32(target), spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_ir->getInt32(target), spu_ptr(&spu_thread::pc)); tail_chunk(nullptr); m_ir->SetInsertPoint(next); } @@ -490,7 +490,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator { ensure(!m_finfo->fn); - m_ir->CreateStore(m_ir->getInt32(target), spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_ir->getInt32(target), spu_ptr(&spu_thread::pc)); } else { @@ -527,29 +527,26 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator return result; } - template llvm::Value* _ptr(llvm::Value* base, u32 offset) { - return m_ir->CreateGEP(get_type(), base, m_ir->getInt64(offset)); + return m_ir->CreatePtrAdd(base, m_ir->getInt64(offset)); } - template llvm::Value* _ptr(llvm::Value* base, llvm::Value* offset) { - return m_ir->CreateGEP(get_type(), base, offset); + return m_ir->CreatePtrAdd(base, offset); } - template + template + llvm::Value* _ptr(llvm::Value* base, Args... offset_args) + { + return m_ir->CreatePtrAdd(base, m_ir->getInt64(::offset32(offset_args...))); + } + + template llvm::Value* spu_ptr(Args... offset_args) { - return _ptr(m_thread, ::offset32(offset_args...)); - } - - template - llvm::Value* spu_ptr(value_t add, Args... offset_args) - { - const auto off = m_ir->CreateGEP(get_type(), m_thread, m_ir->getInt64(::offset32(offset_args...))); - return m_ir->CreateAdd(off, add.value); + return _ptr(m_thread, ::offset32(offset_args...)); } // Return default register type @@ -596,7 +593,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator { if (!m_block) { - return _ptr(m_thread, get_reg_offset(index)); + return _ptr(m_thread, get_reg_offset(index)); } auto& ptr = ::at32(m_reg_addr, index); @@ -608,7 +605,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator // Emit register pointer at the beginning of the function chunk m_ir->SetInsertPoint(m_function->getEntryBlock().getTerminator()); - ptr = _ptr(m_thread, get_reg_offset(index)); + ptr = _ptr(m_thread, get_reg_offset(index)); m_ir->SetInsertPoint(block_cur); } @@ -616,7 +613,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator } // Get pointer to the vector register (interpreter only) - template + template llvm::Value* init_vr(const bf_t&) { if (!m_interp_magn) @@ -631,7 +628,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto idx = m_ir->CreateAnd(I > 4 ? isr : isl, m_interp_7f0); // Pointer to the register - return m_ir->CreateGEP(get_type(), m_interp_regs, m_ir->CreateZExt(idx, get_type())); + return _ptr(m_interp_regs, m_ir->CreateZExt(idx, get_type())); } llvm::Value* double_as_uint64(llvm::Value* val) @@ -758,11 +755,11 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator // Load reg if (get_type() == get_type()) { - r.value = xfloat_to_double(m_ir->CreateLoad(get_type(), init_vr(index))); + r.value = xfloat_to_double(m_ir->CreateLoad(get_type(), init_vr(index))); } else { - r.value = m_ir->CreateLoad(get_type(), init_vr(index)); + r.value = m_ir->CreateLoad(get_type(), init_vr(index)); } } else @@ -962,7 +959,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto saved_value = is_xfloat && fixup ? xfloat_in_double(value) : value; // Store value - m_ir->CreateStore(is_xfloat ? double_to_xfloat(saved_value) : m_ir->CreateBitCast(value, get_type()), init_vr(index)); + m_ir->CreateStore(is_xfloat ? double_to_xfloat(saved_value) : m_ir->CreateBitCast(value, get_type()), init_vr(index)); return; } @@ -1049,13 +1046,13 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator // Update PC for current or explicitly specified instruction address void update_pc(u32 target = -1) { - m_ir->CreateStore(m_ir->CreateAnd(get_pc(target + 1 ? target : m_pos), 0x3fffc), spu_ptr(&spu_thread::pc))->setVolatile(true); + m_ir->CreateStore(m_ir->CreateAnd(get_pc(target + 1 ? target : m_pos), 0x3fffc), spu_ptr(&spu_thread::pc))->setVolatile(true); } // Call cpu_thread::check_state if necessary and return or continue (full check) void check_state(u32 addr, bool may_be_unsafe_for_savestate = true) { - const auto pstate = spu_ptr(&spu_thread::state); + const auto pstate = spu_ptr(&spu_thread::state); const auto _body = llvm::BasicBlock::Create(m_context, "", m_function); const auto check = llvm::BasicBlock::Create(m_context, "", m_function); m_ir->CreateCondBr(m_ir->CreateICmpEQ(m_ir->CreateLoad(get_type(), pstate, true), m_ir->getInt32(0)), _body, check, m_md_likely); @@ -1069,14 +1066,14 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator if (may_be_unsafe_for_savestate) { - m_ir->CreateStore(m_ir->getInt8(1), spu_ptr(&spu_thread::unsavable))->setVolatile(true); + m_ir->CreateStore(m_ir->getInt8(1), spu_ptr(&spu_thread::unsavable))->setVolatile(true); } m_ir->CreateCall(m_test_state, {m_thread}); if (may_be_unsafe_for_savestate) { - m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::unsavable))->setVolatile(true); + m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::unsavable))->setVolatile(true); } m_ir->CreateBr(_body); @@ -1145,7 +1142,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto _final = llvm::BasicBlock::Create(m_context, "__putllc16_final", m_function); const auto _eal = (get_reg_fixed(s_reg_mfc_eal) & -128).eval(m_ir); - const auto _raddr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::raddr)); + const auto _raddr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::raddr)); m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpEQ(_eal, _raddr), m_ir->CreateIsNotNull(_raddr)), _raddr_match, _fail, m_md_likely); m_ir->SetInsertPoint(_raddr_match); @@ -1259,7 +1256,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_ir->SetInsertPoint(_fail); call("PUTLLC16_fail", +on_fail, m_thread, _eal); - m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); + m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); m_ir->CreateBr(_final); m_ir->SetInsertPoint(_final); @@ -1268,8 +1265,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto diff = m_ir->CreateZExt(m_ir->CreateSub(dest, _lsa), get_type()); - const auto _new = m_ir->CreateAlignedLoad(get_type(), _ptr(m_lsptr, dest), llvm::MaybeAlign{16}); - const auto _rdata = m_ir->CreateAlignedLoad(get_type(), _ptr(spu_ptr(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16}); + const auto _new = m_ir->CreateAlignedLoad(get_type(), _ptr(m_lsptr, dest), llvm::MaybeAlign{16}); + const auto _rdata = m_ir->CreateAlignedLoad(get_type(), _ptr(spu_ptr(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16}); const bool is_accurate_op = !!g_cfg.core.spu_accurate_reservations; @@ -1287,10 +1284,10 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_ir->SetInsertPoint(_begin_op); // Touch memory (on the opposite side of the page) - m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Or, _ptr(m_memptr, m_ir->CreateXor(_eal, 4096 / 2)), m_ir->getInt8(0), llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent); + m_ir->CreateAtomicRMW(llvm::AtomicRMWInst::Or, _ptr(m_memptr, m_ir->CreateXor(_eal, 4096 / 2)), m_ir->getInt8(0), llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent); - const auto rptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); - const auto rtime = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); + const auto rptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); + const auto rtime = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); m_ir->CreateBr(_repeat_lock); m_ir->SetInsertPoint(_repeat_lock); @@ -1313,10 +1310,10 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_ir->SetInsertPoint(_lock_success); // Commit 16 bytes compare-exchange - const auto sudo_ptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_sudo_addr)), _eal); + const auto sudo_ptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_sudo_addr)), _eal); m_ir->CreateCondBr( - m_ir->CreateExtractValue(m_ir->CreateAtomicCmpXchg(_ptr(sudo_ptr, diff), _rdata, _new, llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering::SequentiallyConsistent), 1) + m_ir->CreateExtractValue(m_ir->CreateAtomicCmpXchg(_ptr(sudo_ptr, diff), _rdata, _new, llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering::SequentiallyConsistent), 1) , _success_and_unlock , _fail_and_unlock); @@ -1333,13 +1330,13 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator // Perform unlocked vm::reservation_update if no physical memory changes needed m_ir->SetInsertPoint(_inc_res); - const auto rptr2 = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); + const auto rptr2 = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); llvm::Value* old_val{}; if (true || is_accurate_op) { - old_val = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); + old_val = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); } else { @@ -1360,8 +1357,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator } m_ir->SetInsertPoint(_success); - m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_SUCCESS), spu_ptr(&spu_thread::ch_atomic_stat)); - m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::raddr)); + m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_SUCCESS), spu_ptr(&spu_thread::ch_atomic_stat)); + m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::raddr)); m_ir->CreateBr(_final); m_ir->SetInsertPoint(_fail_and_unlock); @@ -1370,7 +1367,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_ir->SetInsertPoint(_fail); call("PUTLLC16_fail", +on_fail, m_thread, _eal); - m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); + m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); m_ir->CreateBr(_final); m_ir->SetInsertPoint(_final); @@ -1410,7 +1407,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator const auto _final = llvm::BasicBlock::Create(m_context, "", m_function); const auto _eal = (get_reg_fixed(s_reg_mfc_eal) & -128).eval(m_ir); - const auto _raddr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::raddr)); + const auto _raddr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::raddr)); m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpEQ(_eal, _raddr), m_ir->CreateIsNotNull(_raddr)), _next, _fail, m_md_likely); m_ir->SetInsertPoint(_next); @@ -1418,8 +1415,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator value_t eal_val; eal_val.value = _eal; - const auto rptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); - const auto rval = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); + const auto rptr = _ptr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::reserv_base_addr)), ((eal_val & 0xff80) >> 1).eval(m_ir)); + const auto rval = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::rtime)); m_ir->CreateCondBr( m_ir->CreateExtractValue(m_ir->CreateAtomicCmpXchg(rptr, rval, m_ir->CreateAdd(rval, m_ir->getInt64(128)), llvm::MaybeAlign{16}, llvm::AtomicOrdering::SequentiallyConsistent, llvm::AtomicOrdering::SequentiallyConsistent), 1) , _next0 @@ -1427,16 +1424,16 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator m_ir->SetInsertPoint(_next0); //call("atomic_wait_engine::notify_all", static_cast(atomic_wait_engine::notify_all), rptr); - m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_SUCCESS), spu_ptr(&spu_thread::ch_atomic_stat)); + m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_SUCCESS), spu_ptr(&spu_thread::ch_atomic_stat)); m_ir->CreateBr(_final); m_ir->SetInsertPoint(_fail); call("PUTLLC0_fail", +on_fail, m_thread, _eal); - m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); + m_ir->CreateStore(m_ir->getInt64(spu_channel::bit_count | MFC_PUTLLC_FAILURE), spu_ptr(&spu_thread::ch_atomic_stat)); m_ir->CreateBr(_final); m_ir->SetInsertPoint(_final); - m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::raddr)); + m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::raddr)); } public: @@ -1628,10 +1625,10 @@ public: const auto label_stop = BasicBlock::Create(m_context, "", m_function); // Load PC, which will be the actual value of 'm_base' - m_base_pc = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::pc)); + m_base_pc = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::pc)); // Emit state check - const auto pstate = spu_ptr(&spu_thread::state); + const auto pstate = spu_ptr(&spu_thread::state); m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->CreateLoad(get_type(), pstate), m_ir->getInt32(0)), label_stop, label_test, m_md_unlikely); // Emit code check @@ -1640,7 +1637,7 @@ public: // Set block hash for profiling (if enabled) if (g_cfg.core.spu_prof && g_cfg.core.spu_verification) - m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash)); + m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536)), spu_ptr(&spu_thread::block_hash)); if (!g_cfg.core.spu_verification) { @@ -1649,13 +1646,13 @@ public: } else if (func.data.size() == 1) { - const auto pu32 = m_ir->CreateGEP(get_type(), m_lsptr, m_base_pc); + const auto pu32 = _ptr(m_lsptr, m_base_pc); const auto cond = m_ir->CreateICmpNE(m_ir->CreateLoad(get_type(), pu32), m_ir->getInt32(func.data[0])); m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely); } else if (func.data.size() == 2) { - const auto pu64 = m_ir->CreateGEP(get_type(), m_lsptr, m_base_pc); + const auto pu64 = _ptr(m_lsptr, m_base_pc); const auto cond = m_ir->CreateICmpNE(m_ir->CreateLoad(get_type(), pu64), m_ir->getInt64(static_cast(func.data[1]) << 32 | func.data[0])); m_ir->CreateCondBr(cond, label_diff, label_body, m_md_unlikely); } @@ -1701,7 +1698,7 @@ public: // Get actual pc corresponding to the found beginning of the data llvm::Value* starta_pc = m_ir->CreateAnd(get_pc(starta), 0x3fffc); - llvm::Value* data_addr = m_ir->CreateGEP(get_type(), m_lsptr, starta_pc); + llvm::Value* data_addr = _ptr(m_lsptr, starta_pc); llvm::Value* acc0 = nullptr; llvm::Value* acc1 = nullptr; @@ -1743,7 +1740,7 @@ public: llvm::Value* vls = nullptr; // Load unaligned code block from LS - vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); + vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); // Mask if necessary if (holes) @@ -1832,15 +1829,15 @@ public: // Load unaligned code block from LS if (m_use_avx512) { - vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); + vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); } else if (m_use_avx) { - vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); + vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); } else { - vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); + vls = m_ir->CreateAlignedLoad(get_type(), _ptr(data_addr, j - starta), llvm::MaybeAlign{4}); } // Mask if necessary @@ -1859,7 +1856,7 @@ public: } vls = m_ir->CreateXor(vls, ConstantDataVector::get(m_context, llvm::ArrayRef(words, elements))); - + // Interleave accumulators for more performance if (toggle) { @@ -1903,7 +1900,7 @@ public: // Increase block counter with statistics m_ir->SetInsertPoint(label_body); - const auto pbcount = spu_ptr(&spu_thread::block_counter); + const auto pbcount = spu_ptr(&spu_thread::block_counter); m_ir->CreateStore(m_ir->CreateAdd(m_ir->CreateLoad(get_type(), pbcount), m_ir->getInt64(check_iterations)), pbcount); // Call the entry function chunk @@ -1937,7 +1934,7 @@ public: if (g_cfg.core.spu_verification) { - const auto pbfail = spu_ptr(&spu_thread::block_failure); + const auto pbfail = spu_ptr(&spu_thread::block_failure); m_ir->CreateStore(m_ir->CreateAdd(m_ir->CreateLoad(get_type(), pbfail), m_ir->getInt64(1)), pbfail); const auto dispci = call("spu_dispatch", spu_runtime::tr_dispatch, m_thread, m_lsptr, main_arg2); dispci->setCallingConv(CallingConv::GHC); @@ -1997,7 +1994,7 @@ public: // Set block hash for profiling (if enabled) if (g_cfg.core.spu_prof) - m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash)); + m_ir->CreateStore(m_ir->getInt64((m_hash_start & -65536) | (m_entry >> 2)), spu_ptr(&spu_thread::block_hash)); m_finfo = &m_functions[m_entry]; m_ir->CreateBr(add_block(m_entry)); @@ -2402,7 +2399,7 @@ public: worked_on[p] = true; work2_list.push_back(std::make_pair(p, found_user)); } - // Enqueue a second iteration for found_user=true if only found with found_user=false + // Enqueue a second iteration for found_user=true if only found with found_user=false else if (found_user && !std::find_if(work2_list.rbegin(), work2_list.rend(), [&](auto& it){ return it.first == p; })->second) { work2_list.push_back(std::make_pair(p, true)); @@ -2547,7 +2544,7 @@ public: worked_on[target] = true; work_list.emplace_back(target, found_barrier); } - // Enqueue a second iteration for found_barrier=true if only found with found_barrier=false + // Enqueue a second iteration for found_barrier=true if only found with found_barrier=false else if (found_barrier && !std::find_if(work_list.rbegin(), work_list.rend(), [&](auto& it){ return it.first == target; })->second) { work_list.emplace_back(target, true); @@ -2915,8 +2912,8 @@ public: set_function(main_func); // Load pc and opcode - m_interp_pc = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::pc)); - m_interp_op = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_lsptr, m_ir->CreateZExt(m_interp_pc, get_type()))); + m_interp_pc = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::pc)); + m_interp_op = m_ir->CreateLoad(get_type(), _ptr(m_lsptr, m_ir->CreateZExt(m_interp_pc, get_type()))); m_interp_op = m_ir->CreateCall(get_intrinsic(Intrinsic::bswap), {m_interp_op}); // Pinned constant, address of interpreter table @@ -2929,7 +2926,7 @@ public: m_interp_regs = _ptr(m_thread, get_reg_offset(0)); // Save host thread's stack pointer - const auto native_sp = spu_ptr(&spu_thread::hv_ctx, &rpcs3::hypervisor_context_t::regs); + const auto native_sp = spu_ptr(&spu_thread::hv_ctx, &rpcs3::hypervisor_context_t::regs); #if defined(ARCH_X64) const auto rsp_name = MetadataAsValue::get(m_context, MDNode::get(m_context, {MDString::get(m_context, "rsp")})); #elif defined(ARCH_ARM64) @@ -3015,7 +3012,7 @@ public: m_interp_regs = f->getArg(6); m_ir->SetInsertPoint(BasicBlock::Create(m_context, "", f)); - m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); + m_memptr = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::memory_base_addr)); switch (itype) { @@ -3031,7 +3028,7 @@ public: case spu_itype::WRCH: { // Invalid or abortable instruction. Save current address. - m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); [[fallthrough]]; } default: @@ -3075,12 +3072,12 @@ public: { if (check) { - m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); } // Decode next instruction. const auto next_pc = itype & spu_itype::branch ? m_interp_pc : m_interp_pc_next; - const auto be32_op = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_lsptr, m_ir->CreateZExt(next_pc, get_type()))); + const auto be32_op = m_ir->CreateLoad(get_type(), _ptr(m_lsptr, m_ir->CreateZExt(next_pc, get_type()))); const auto next_op = m_ir->CreateCall(get_intrinsic(Intrinsic::bswap), {be32_op}); const auto next_if = m_ir->CreateLoad(m_ir->getPtrTy(), m_ir->CreateGEP(m_ir->getPtrTy(), m_interp_table, m_ir->CreateLShr(next_op, 32u - m_interp_magn))); llvm::cast(next_if)->setVolatile(true); @@ -3112,9 +3109,9 @@ public: { const auto _stop = BasicBlock::Create(m_context, "", f); const auto _next = BasicBlock::Create(m_context, "", f); - m_ir->CreateCondBr(m_ir->CreateIsNotNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::state))), _stop, _next, m_md_unlikely); + m_ir->CreateCondBr(m_ir->CreateIsNotNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::state))), _stop, _next, m_md_unlikely); m_ir->SetInsertPoint(_stop); - m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); const auto escape_yes = BasicBlock::Create(m_context, "", f); const auto escape_no = BasicBlock::Create(m_context, "", f); @@ -3168,7 +3165,7 @@ public: // Call next instruction. const auto _stop = BasicBlock::Create(m_context, "", f); const auto _next = BasicBlock::Create(m_context, "", f); - m_ir->CreateCondBr(m_ir->CreateIsNotNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::state))), _stop, _next, m_md_unlikely); + m_ir->CreateCondBr(m_ir->CreateIsNotNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::state))), _stop, _next, m_md_unlikely); m_ir->SetInsertPoint(_next); if (itype == spu_itype::WRCH || @@ -3186,7 +3183,7 @@ public: ncall->setTailCall(); m_ir->CreateRetVoid(); m_ir->SetInsertPoint(_stop); - m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); call("spu_escape", spu_runtime::g_escape, m_thread)->setTailCall(); m_ir->CreateRetVoid(); } @@ -3311,7 +3308,7 @@ public: { if (m_interp_magn) { - m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_interp_pc, spu_ptr(&spu_thread::pc)); call("spu_unknown", &exec_unk, m_thread, m_ir->getInt32(op_unk.opcode)); return; } @@ -3418,7 +3415,7 @@ public: llvm::Value* get_rdch(spu_opcode_t op, u32 off, bool atomic) { - const auto ptr = _ptr(m_thread, off); + const auto ptr = _ptr(m_thread, off); llvm::Value* val0; if (atomic) @@ -3466,7 +3463,7 @@ public: { case SPU_RdSRR0: { - res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::srr0)); + res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::srr0)); break; } case SPU_RdInMbox: @@ -3483,7 +3480,7 @@ public: } case MFC_RdTagMask: { - res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_mask)); + res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_mask)); break; } case SPU_RdSigNotify1: @@ -3516,13 +3513,13 @@ public: if (utils::get_tsc_freq() && !(g_cfg.core.spu_loop_detection) && (g_cfg.core.clocks_scale == 100)) { const auto timebase_offs = m_ir->CreateLoad(get_type(), m_ir->CreateIntToPtr(m_ir->getInt64(reinterpret_cast(&g_timebase_offs)), get_type())); - const auto timestamp = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_dec_start_timestamp)); - const auto dec_value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_dec_value)); + const auto timestamp = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_dec_start_timestamp)); + const auto dec_value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_dec_value)); const auto tsc = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_rdtsc)); const auto tscx = m_ir->CreateMul(m_ir->CreateUDiv(tsc, m_ir->getInt64(utils::get_tsc_freq())), m_ir->getInt64(80000000)); const auto tscm = m_ir->CreateUDiv(m_ir->CreateMul(m_ir->CreateURem(tsc, m_ir->getInt64(utils::get_tsc_freq())), m_ir->getInt64(80000000)), m_ir->getInt64(utils::get_tsc_freq())); const auto tsctb = m_ir->CreateSub(m_ir->CreateAdd(tscx, tscm), timebase_offs); - const auto frz = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::is_dec_frozen)); + const auto frz = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::is_dec_frozen)); const auto frzev = m_ir->CreateICmpEQ(frz, m_ir->getInt8(0)); const auto delta = m_ir->CreateTrunc(m_ir->CreateSub(tsctb, timestamp), get_type()); @@ -3536,7 +3533,7 @@ public: } case SPU_RdEventMask: { - const auto value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events)); + const auto value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events)); value->setAtomic(llvm::AtomicOrdering::Acquire); res.value = m_ir->CreateTrunc(m_ir->CreateLShr(value, 32), get_type()); break; @@ -3551,22 +3548,22 @@ public: } else { - m_ir->CreateStore(m_ir->getInt8(1), spu_ptr(&spu_thread::unsavable)); + m_ir->CreateStore(m_ir->getInt8(1), spu_ptr(&spu_thread::unsavable)); } res.value = call("spu_read_events", &exec_read_events, m_thread); if (!g_cfg.savestate.compatible_mode) { - m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::unsavable)); + m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::unsavable)); } break; } case SPU_RdMachStat: { - res.value = m_ir->CreateZExt(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::interrupts_enabled)), get_type()); - res.value = m_ir->CreateOr(res.value, m_ir->CreateAnd(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::thread_type)), m_ir->getInt32(2))); + res.value = m_ir->CreateZExt(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::interrupts_enabled)), get_type()); + res.value = m_ir->CreateOr(res.value, m_ir->CreateAnd(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::thread_type)), m_ir->getInt32(2))); break; } @@ -3594,7 +3591,7 @@ public: llvm::Value* get_rchcnt(u32 off, u64 inv = 0) { - const auto val = m_ir->CreateLoad(get_type(), _ptr(m_thread, off)); + const auto val = m_ir->CreateLoad(get_type(), _ptr(m_thread, off)); val->setAtomic(llvm::AtomicOrdering::Acquire); const auto shv = m_ir->CreateLShr(val, spu_channel::off_count); return m_ir->CreateTrunc(m_ir->CreateXor(shv, inv), get_type()); @@ -3616,7 +3613,7 @@ public: return ch->get_count(); }; - return m_ir->CreateXor(call("wait_on_spu_channel", +wait_on_channel, m_thread, _ptr(m_thread, off), m_ir->getInt32(inv == 0u)), m_ir->getInt32(inv)); + return m_ir->CreateXor(call("wait_on_spu_channel", +wait_on_channel, m_thread, _ptr(m_thread, off), m_ir->getInt32(inv == 0u)), m_ir->getInt32(inv)); } void RCHCNT(spu_opcode_t op) // @@ -3695,7 +3692,7 @@ public: return ch->pop_wait(*_spu, false), ch->get_count(); }; - res.value = call("wait_spu_inbox", +wait_inbox, m_thread, spu_ptr(&spu_thread::ch_in_mbox)); + res.value = call("wait_spu_inbox", +wait_inbox, m_thread, spu_ptr(&spu_thread::ch_in_mbox)); break; } default: break; @@ -3752,13 +3749,13 @@ public: } case MFC_Cmd: { - res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size)); + res.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size)); res.value = m_ir->CreateSub(m_ir->getInt32(16), res.value); break; } case SPU_RdInMbox: { - const auto value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_in_mbox)); + const auto value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_in_mbox)); value->setAtomic(llvm::AtomicOrdering::Acquire); res.value = value; res.value = m_ir->CreateLShr(res.value, 8); @@ -3767,7 +3764,7 @@ public: } case SPU_RdEventStat: { - const auto mask = m_ir->CreateTrunc(m_ir->CreateLShr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events)), 32), get_type()); + const auto mask = m_ir->CreateTrunc(m_ir->CreateLShr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events)), 32), get_type()); res.value = call("spu_get_events", &exec_get_events, m_thread, mask); break; } @@ -3865,7 +3862,7 @@ public: { case SPU_WrSRR0: { - m_ir->CreateStore(eval(val & 0x3fffc).value, spu_ptr(&spu_thread::srr0)); + m_ir->CreateStore(eval(val & 0x3fffc).value, spu_ptr(&spu_thread::srr0)); return; } case SPU_WrOutIntrMbox: @@ -3881,10 +3878,10 @@ public: case MFC_WrTagMask: { // TODO - m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_tag_mask)); + m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_tag_mask)); const auto next = llvm::BasicBlock::Create(m_context, "", m_function); const auto _mfc = llvm::BasicBlock::Create(m_context, "", m_function); - m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_upd)), m_ir->getInt32(MFC_TAG_UPDATE_IMMEDIATE)), _mfc, next); + m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_upd)), m_ir->getInt32(MFC_TAG_UPDATE_IMMEDIATE)), _mfc, next); m_ir->SetInsertPoint(_mfc); update_pc(); call("spu_write_channel", &exec_wrch, m_thread, m_ir->getInt32(op.ra), val.value); @@ -3896,11 +3893,11 @@ public: { if (true) { - const auto tag_mask = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_mask)); - const auto mfc_fence = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_fence)); + const auto tag_mask = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_tag_mask)); + const auto mfc_fence = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_fence)); const auto completed = m_ir->CreateAnd(tag_mask, m_ir->CreateNot(mfc_fence)); - const auto upd_ptr = spu_ptr(&spu_thread::ch_tag_upd); - const auto stat_ptr = spu_ptr(&spu_thread::ch_tag_stat); + const auto upd_ptr = spu_ptr(&spu_thread::ch_tag_upd); + const auto stat_ptr = spu_ptr(&spu_thread::ch_tag_stat); const auto stat_val = m_ir->CreateOr(m_ir->CreateZExt(completed, get_type()), s64{smin}); const auto next = llvm::BasicBlock::Create(m_context, "", m_function); @@ -3920,7 +3917,7 @@ public: // Illegal update, access violate with special address m_ir->SetInsertPoint(fail); - const auto ptr = _ptr(m_memptr, 0xffdead04); + const auto ptr = _ptr(m_memptr, 0xffdead04); m_ir->CreateStore(m_ir->getInt32("TAG\0"_u32), ptr); m_ir->CreateBr(next); @@ -3953,7 +3950,7 @@ public: } spu_log.warning("[0x%x] MFC_EAH: $%u is not a zero constant", m_pos, +op.rt); - //m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::eah)); + //m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::eah)); return; } case MFC_EAL: @@ -4007,8 +4004,8 @@ public: const auto fail = llvm::BasicBlock::Create(m_context, "", m_function); const auto next = llvm::BasicBlock::Create(m_context, "", m_function); - const auto pf = spu_ptr(&spu_thread::mfc_fence); - const auto pb = spu_ptr(&spu_thread::mfc_barrier); + const auto pf = spu_ptr(&spu_thread::mfc_fence); + const auto pb = spu_ptr(&spu_thread::mfc_barrier); switch (u64 cmd = ci->getZExtValue()) { @@ -4033,7 +4030,7 @@ public: m_ir->SetInsertPoint(fail); m_ir->CreateUnreachable(); m_ir->SetInsertPoint(next); - m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); + m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); update_pc(); ensure_gpr_stores(); call("spu_exec_mfc_cmd_saveable", &exec_mfc_cmd, m_thread); @@ -4052,7 +4049,7 @@ public: m_ir->SetInsertPoint(fail); m_ir->CreateUnreachable(); m_ir->SetInsertPoint(next); - m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); + m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); update_pc(); call("spu_exec_mfc_cmd", &exec_mfc_cmd, m_thread); return; @@ -4083,8 +4080,8 @@ public: csize = -1; } - llvm::Value* src = m_ir->CreateGEP(get_type(), m_lsptr, zext(lsa).eval(m_ir)); - llvm::Value* dst = m_ir->CreateGEP(get_type(), m_memptr, zext(eal).eval(m_ir)); + llvm::Value* src = _ptr(m_lsptr, zext(lsa).eval(m_ir)); + llvm::Value* dst = _ptr(m_memptr, zext(eal).eval(m_ir)); if (cmd & MFC_GET_CMD) { @@ -4112,7 +4109,7 @@ public: m_ir->SetInsertPoint(mmio); } - m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); + m_ir->CreateStore(ci, spu_ptr(&spu_thread::ch_mfc_cmd, &spu_mfc_cmd::cmd)); call("spu_exec_mfc_cmd", &exec_mfc_cmd, m_thread); m_ir->CreateBr(next); m_ir->SetInsertPoint(copy); @@ -4181,8 +4178,8 @@ public: // Generate fixed sequence of copy operations for (u32 i = 0; i < csize; i += stride) { - const auto _src = m_ir->CreateGEP(get_type(), src, m_ir->getInt32(i)); - const auto _dst = m_ir->CreateGEP(get_type(), dst, m_ir->getInt32(i)); + const auto _src = _ptr(src, i); + const auto _dst = _ptr(dst, i); if (csize - i < stride) { m_ir->CreateStore(m_ir->CreateLoad(get_type(), _src), _dst); @@ -4204,7 +4201,7 @@ public: } // Disable certain thing - m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::last_faddr)); + m_ir->CreateStore(m_ir->getInt32(0), spu_ptr(&spu_thread::last_faddr)); m_ir->CreateBr(next); break; } @@ -4212,7 +4209,7 @@ public: case MFC_EIEIO_CMD: case MFC_SYNC_CMD: { - const auto cond = m_ir->CreateIsNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size))); + const auto cond = m_ir->CreateIsNull(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size))); m_ir->CreateCondBr(cond, exec, fail, m_md_likely); m_ir->SetInsertPoint(exec); m_ir->CreateFence(llvm::AtomicOrdering::SequentiallyConsistent); @@ -4234,12 +4231,12 @@ public: m_ir->SetInsertPoint(fail); // Get MFC slot, redirect to invalid memory address - const auto slot = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size)); + const auto slot = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::mfc_size)); const auto off0 = m_ir->CreateAdd(m_ir->CreateMul(slot, m_ir->getInt32(sizeof(spu_mfc_cmd))), m_ir->getInt32(::offset32(&spu_thread::mfc_queue))); - const auto ptr0 = m_ir->CreateGEP(get_type(), m_thread, m_ir->CreateZExt(off0, get_type())); - const auto ptr1 = m_ir->CreateGEP(get_type(), m_memptr, m_ir->getInt64(0xffdeadf0)); + const auto ptr0 = _ptr(m_thread, m_ir->CreateZExt(off0, get_type())); + const auto ptr1 = _ptr(m_memptr, 0xffdeadf0); const auto pmfc = m_ir->CreateSelect(m_ir->CreateICmpULT(slot, m_ir->getInt32(16)), ptr0, ptr1); - m_ir->CreateStore(ci, _ptr(pmfc, ::offset32(&spu_mfc_cmd::cmd))); + m_ir->CreateStore(ci, _ptr(pmfc, &spu_mfc_cmd::cmd)); switch (u64 cmd = ci->getZExtValue()) { @@ -4279,10 +4276,10 @@ public: case MFC_GETB_CMD: case MFC_GETF_CMD: { - m_ir->CreateStore(tag.value, _ptr(pmfc, ::offset32(&spu_mfc_cmd::tag))); - m_ir->CreateStore(size.value, _ptr(pmfc, ::offset32(&spu_mfc_cmd::size))); - m_ir->CreateStore(lsa.value, _ptr(pmfc, ::offset32(&spu_mfc_cmd::lsa))); - m_ir->CreateStore(eal.value, _ptr(pmfc, ::offset32(&spu_mfc_cmd::eal))); + m_ir->CreateStore(tag.value, _ptr(pmfc, &spu_mfc_cmd::tag)); + m_ir->CreateStore(size.value, _ptr(pmfc, &spu_mfc_cmd::size)); + m_ir->CreateStore(lsa.value, _ptr(pmfc, &spu_mfc_cmd::lsa)); + m_ir->CreateStore(eal.value, _ptr(pmfc, &spu_mfc_cmd::eal)); m_ir->CreateStore(m_ir->CreateOr(m_ir->CreateLoad(get_type(), pf), mask), pf); if (cmd & MFC_BARRIER_MASK) m_ir->CreateStore(m_ir->CreateOr(m_ir->CreateLoad(get_type(), pb), mask), pb); @@ -4303,7 +4300,7 @@ public: } } - m_ir->CreateStore(m_ir->CreateAdd(slot, m_ir->getInt32(1)), spu_ptr(&spu_thread::mfc_size)); + m_ir->CreateStore(m_ir->CreateAdd(slot, m_ir->getInt32(1)), spu_ptr(&spu_thread::mfc_size)); m_ir->CreateBr(next); m_ir->SetInsertPoint(next); return; @@ -4316,7 +4313,7 @@ public: case MFC_WrListStallAck: { const auto mask = eval(splat(1) << (val & 0x1f)); - const auto _ptr = spu_ptr(&spu_thread::ch_stall_mask); + const auto _ptr = spu_ptr(&spu_thread::ch_stall_mask); const auto _old = m_ir->CreateLoad(get_type(), _ptr); const auto _new = m_ir->CreateAnd(_old, m_ir->CreateNot(mask.value)); m_ir->CreateStore(_new, _ptr); @@ -4343,16 +4340,16 @@ public: const auto tscx = m_ir->CreateMul(m_ir->CreateUDiv(tsc, m_ir->getInt64(utils::get_tsc_freq())), m_ir->getInt64(80000000)); const auto tscm = m_ir->CreateUDiv(m_ir->CreateMul(m_ir->CreateURem(tsc, m_ir->getInt64(utils::get_tsc_freq())), m_ir->getInt64(80000000)), m_ir->getInt64(utils::get_tsc_freq())); const auto tsctb = m_ir->CreateSub(m_ir->CreateAdd(tscx, tscm), timebase_offs); - m_ir->CreateStore(tsctb, spu_ptr(&spu_thread::ch_dec_start_timestamp)); + m_ir->CreateStore(tsctb, spu_ptr(&spu_thread::ch_dec_start_timestamp)); } else #endif { - m_ir->CreateStore(call("get_timebased_time", &get_timebased_time), spu_ptr(&spu_thread::ch_dec_start_timestamp)); + m_ir->CreateStore(call("get_timebased_time", &get_timebased_time), spu_ptr(&spu_thread::ch_dec_start_timestamp)); } - m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_dec_value)); - m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::is_dec_frozen)); + m_ir->CreateStore(val.value, spu_ptr(&spu_thread::ch_dec_value)); + m_ir->CreateStore(m_ir->getInt8(0), spu_ptr(&spu_thread::is_dec_frozen)); return; } case SPU_Set_Bkmk_Tag: @@ -4982,7 +4979,7 @@ public: { minusb = eval(x); } - + const auto bx = splat_scalar(minusb) & 0x7; set_vr(op.rt, fshr(zshuffle(a, 1, 2, 3, 4), a, bx)); } @@ -6868,12 +6865,12 @@ public: const auto div_result = the_one / div; return vfixupimmps(div_result, div_result, splat(0x00220088u), 0, 0xff); - }); + }); } else { register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci) - { + { const auto div = value(ci->getOperand(0)); const auto the_one = value(ci->getOperand(1)); @@ -6890,7 +6887,7 @@ public: }); } - + const auto [a, b, c] = get_vrs(op.ra, op.rb, op.rc); static const auto MT = match(); @@ -6936,7 +6933,7 @@ public: erase_stores(a, b, c, a3); set_vr(op.rt4, fsqrt(fabs(src))); return true; - } + } } else if (auto [ok_fm1, a3, b3] = match_expr(c, fm(MT, MT)); ok_fm1 && b3.eq(a1)) { @@ -6945,7 +6942,7 @@ public: erase_stores(a, b, c, b3); set_vr(op.rt4, fsqrt(fabs(src))); return true; - } + } } } else if (fm_half_mul.eq(a1)) @@ -6957,7 +6954,7 @@ public: erase_stores(a, b, c, a3); set_vr(op.rt4, fsqrt(fabs(src))); return true; - } + } } else if (auto [ok_fm1, a3, b3] = match_expr(c, fm(MT, MT)); ok_fm1 && b3.eq(b1)) { @@ -6966,7 +6963,7 @@ public: erase_stores(a, b, c, b3); set_vr(op.rt4, fsqrt(fabs(src))); return true; - } + } } } } @@ -7512,13 +7509,13 @@ public: void make_store_ls(value_t addr, value_t data) { const auto bswapped = byteswap(data); - m_ir->CreateStore(bswapped.eval(m_ir), m_ir->CreateGEP(get_type(), m_lsptr, addr.value)); + m_ir->CreateStore(bswapped.eval(m_ir), _ptr(m_lsptr, addr.value)); } auto make_load_ls(value_t addr) { value_t data; - data.value = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_lsptr, addr.value)); + data.value = m_ir->CreateLoad(get_type(), _ptr(m_lsptr, addr.value)); return byteswap(data); } @@ -7633,10 +7630,10 @@ public: m_ir->CreateCondBr(cond.value, halt, next, m_md_unlikely); m_ir->SetInsertPoint(halt); if (m_interp_magn) - m_ir->CreateStore(m_function->getArg(2), spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(m_function->getArg(2), spu_ptr(&spu_thread::pc)); else update_pc(); - const auto ptr = _ptr(m_memptr, 0xffdead00); + const auto ptr = _ptr(m_memptr, 0xffdead00); m_ir->CreateStore(m_ir->getInt32("HALT"_u32), ptr); m_ir->CreateBr(next); m_ir->SetInsertPoint(next); @@ -7740,7 +7737,7 @@ public: target->addIncoming(e_addr, e_exec); m_ir->CreateCondBr(get_imm(op.d).value, d_exec, d_done, m_md_unlikely); m_ir->SetInsertPoint(d_exec); - m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); + m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); m_ir->CreateBr(d_done); m_ir->SetInsertPoint(d_done); m_ir->CreateBr(m_interp_bblock); @@ -7776,7 +7773,7 @@ public: } else { - sp.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, 1, &v128::_u32, 3)); + sp.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::gpr, 1, &v128::_u32, 3)); } } @@ -7791,32 +7788,31 @@ public: if (op.d) { - m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); + m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); } - m_ir->CreateStore(addr.value, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(addr.value, spu_ptr(&spu_thread::pc)); if (ret && g_cfg.core.spu_block_size >= spu_block_size_type::mega) { // Compare address stored in stack mirror with addr const auto stack0 = eval(zext(sp) + ::offset32(&spu_thread::stack_mirror)); const auto stack1 = eval(stack0 + 8); - const auto _ret = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_thread, stack0.value)); - const auto link = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_thread, stack1.value)); + const auto _ret = m_ir->CreateLoad(get_type(), _ptr(m_thread, stack0.value)); + const auto link = m_ir->CreateLoad(get_type(), _ptr(m_thread, stack1.value)); const auto fail = llvm::BasicBlock::Create(m_context, "", m_function); const auto done = llvm::BasicBlock::Create(m_context, "", m_function); const auto next = llvm::BasicBlock::Create(m_context, "", m_function); m_ir->CreateCondBr(m_ir->CreateICmpEQ(addr.value, m_ir->CreateTrunc(link, get_type())), next, fail, m_md_likely); m_ir->SetInsertPoint(next); - const auto cmp2 = m_ir->CreateLoad(get_type(), m_ir->CreateGEP(get_type(), m_lsptr, addr.value)); + const auto cmp2 = m_ir->CreateLoad(get_type(), _ptr(m_lsptr, addr.value)); m_ir->CreateCondBr(m_ir->CreateICmpEQ(cmp2, m_ir->CreateTrunc(_ret, get_type())), done, fail, m_md_likely); m_ir->SetInsertPoint(done); // Clear stack mirror and return by tail call to the provided return address - m_ir->CreateStore(splat(-1).eval(m_ir), m_ir->CreateGEP(get_type(), m_thread, stack0.value)); - const auto targ = m_ir->CreateAdd(m_ir->CreateLShr(_ret, 32), get_segment_base()); + m_ir->CreateStore(splat(-1).eval(m_ir), _ptr(m_thread, stack0.value)); const auto type = m_finfo->chunk->getFunctionType(); - const auto fval = m_ir->CreateIntToPtr(targ, m_ir->getPtrTy()); + const auto fval = _ptr(get_segment_base(), m_ir->CreateLShr(_ret, 32)); tail_chunk({type, fval}, m_ir->CreateTrunc(m_ir->CreateLShr(link, 32), get_type())); m_ir->SetInsertPoint(fail); } @@ -8059,7 +8055,7 @@ public: if (op.d && tfound != m_targets.end() && tfound->second.size() == 1 && tfound->second[0] == spu_branch_target(m_pos, 1)) { // Interrupts-disable pattern - m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); + m_ir->CreateStore(m_ir->getFalse(), spu_ptr(&spu_thread::interrupts_enabled)); return; } @@ -8119,12 +8115,12 @@ public: // Exit function on unexpected target m_ir->SetInsertPoint(sw->getDefaultDest()); - m_ir->CreateStore(addr.value, spu_ptr(&spu_thread::pc)); + m_ir->CreateStore(addr.value, spu_ptr(&spu_thread::pc)); if (m_finfo && m_finfo->fn) { // Can't afford external tail call in true functions - m_ir->CreateStore(m_ir->getInt32("BIJT"_u32), _ptr(m_memptr, 0xffdead20)); + m_ir->CreateStore(m_ir->getInt32("BIJT"_u32), _ptr(m_memptr, 0xffdead20)); m_ir->CreateCall(m_test_state, {m_thread}); m_ir->CreateBr(sw->getDefaultDest()); } @@ -8152,7 +8148,7 @@ public: { if (m_block) m_block->block_end = m_ir->GetInsertBlock(); value_t srr0; - srr0.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::srr0)); + srr0.value = m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::srr0)); m_ir->CreateBr(add_block_indirect(op, srr0)); } @@ -8161,7 +8157,7 @@ public: if (m_block) m_block->block_end = m_ir->GetInsertBlock(); const auto addr = eval(extract(get_vr(op.ra), 3) & 0x3fffc); set_link(op); - const auto mask = m_ir->CreateTrunc(m_ir->CreateLShr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events), true), 32), get_type()); + const auto mask = m_ir->CreateTrunc(m_ir->CreateLShr(m_ir->CreateLoad(get_type(), spu_ptr(&spu_thread::ch_events), true), 32), get_type()); const auto res = call("spu_get_events", &exec_get_events, m_thread, mask); const auto target = add_block_indirect(op, addr); m_ir->CreateCondBr(m_ir->CreateICmpNE(res, m_ir->getInt32(0)), target, add_block_next()); @@ -8496,11 +8492,11 @@ public: const auto pfunc = add_function(m_pos + 4); const auto stack0 = eval(zext(extract(get_reg_fixed(1), 3) & 0x3fff0) + ::offset32(&spu_thread::stack_mirror)); const auto stack1 = eval(stack0 + 8); - const auto rel_ptr = m_ir->CreateSub(m_ir->CreatePtrToInt(pfunc->chunk, get_type()), get_segment_base()); + const auto rel_ptr = m_ir->CreateSub(m_ir->CreatePtrToInt(pfunc->chunk, get_type()), m_ir->CreatePtrToInt(get_segment_base(), get_type())); const auto ptr_plus_op = m_ir->CreateOr(m_ir->CreateShl(rel_ptr, 32), m_ir->getInt64(m_next_op)); const auto base_plus_pc = m_ir->CreateOr(m_ir->CreateShl(m_ir->CreateZExt(m_base_pc, get_type()), 32), m_ir->getInt64(m_pos + 4)); - m_ir->CreateStore(ptr_plus_op, m_ir->CreateGEP(get_type(), m_thread, stack0.value)); - m_ir->CreateStore(base_plus_pc, m_ir->CreateGEP(get_type(), m_thread, stack1.value)); + m_ir->CreateStore(ptr_plus_op, _ptr(m_thread, stack0.value)); + m_ir->CreateStore(base_plus_pc, _ptr(m_thread, stack1.value)); } } @@ -8509,7 +8505,7 @@ public: const auto type = llvm::FunctionType::get(get_type(), {}, false); const auto func = llvm::cast(m_module->getOrInsertFunction("spu_segment_base", type).getCallee()); m_engine->updateGlobalMapping("spu_segment_base", reinterpret_cast(jit_runtime::alloc(0, 0))); - return m_ir->CreatePtrToInt(func, get_type()); + return func; } static decltype(&spu_llvm_recompiler::UNK) decode(u32 op); diff --git a/rpcs3/Emu/Cell/SPUThread.cpp b/rpcs3/Emu/Cell/SPUThread.cpp index dbf3b695f4..cc21e2ebb8 100644 --- a/rpcs3/Emu/Cell/SPUThread.cpp +++ b/rpcs3/Emu/Cell/SPUThread.cpp @@ -461,7 +461,7 @@ waitpkg_func static void __tpause(u32 cycles, u32 cstate) namespace vm { - std::array, 1024> g_resrv_waiters_count{}; + std::array, 2048> g_resrv_waiters_count{}; } void do_cell_atomic_128_store(u32 addr, const void* to_write); @@ -1899,6 +1899,12 @@ void spu_thread::cpu_task() return fmt::format("%sSPU[0x%07x] Thread (%s) [0x%05x]", type >= spu_type::raw ? type == spu_type::isolated ? "Iso" : "Raw" : "", cpu->lv2_id, *name_cache.get(), cpu->pc); }; + if (get_type() == spu_type::threaded) + { + // Update thread name (spu_thread::lv2_id update) + thread_ctrl::set_name(*group->threads[group->threads_map[index]], thread_name); + } + constexpr u32 invalid_spurs = 0u - 0x80; if (spurs_addr == 0) @@ -1910,7 +1916,7 @@ void spu_thread::cpu_task() } else { - const u32 arg = static_cast(group->args[index][1]); + const u32 arg = static_cast(group->args[group->threads_map[index]][1]); if (group->name.ends_with("CellSpursKernelGroup"sv) && vm::check_addr(arg)) { @@ -3979,7 +3985,7 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) { if (raddr != spurs_addr || pc != 0x11e4) { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, rtime); } else { @@ -3990,7 +3996,7 @@ bool spu_thread::do_putllc(const spu_mfc_cmd& args) if (switched_from_running_to_idle) { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, rtime); } } @@ -4199,7 +4205,11 @@ void spu_thread::do_putlluc(const spu_mfc_cmd& args) } do_cell_atomic_128_store(addr, _ptr(args.lsa & 0x3ff80)); - vm::reservation_notifier_notify(addr); + + // Cover all waiters (TODO: Get reservation time atomically) + const u64 rtime = vm::reservation_acquire(addr); + vm::reservation_notifier_notify(addr, rtime - 128); + vm::reservation_notifier_notify(addr, rtime - 256); } bool spu_thread::do_mfc(bool can_escape, bool must_finish) @@ -4652,7 +4662,7 @@ u32 evaluate_spin_optimization(std::span stats, u64 evaluate_time, const cfg add_count = 0; } - if (inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2) + if (stats.size() == 16 && inclined_for_responsiveness && std::count(old_stats.data(), old_stats.data() + 3, 0) >= 2) { add_count = 0; } @@ -4914,10 +4924,10 @@ bool spu_thread::process_mfc_cmd() usz cache_line_waiter_index = umax; - if (auto wait_var = vm::reservation_notifier_begin_wait(addr, rtime)) + if (auto [wait_var, flag_val] = vm::reservation_notifier_begin_wait(addr, rtime); wait_var) { cache_line_waiter_index = register_cache_line_waiter(addr); - utils::bless>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{100'000}); + utils::bless>(&wait_var->raw().wait_flag)->wait(flag_val, atomic_wait_timeout{100'000}); vm::reservation_notifier_end_wait(*wait_var); } @@ -4964,9 +4974,9 @@ bool spu_thread::process_mfc_cmd() g_unchanged++; // Notify threads manually, memory data has likely changed and broke the reservation for others - if (vm::reservation_notifier_count(addr) && res == new_time) + if (vm::reservation_notifier_count(addr, new_time) && res == new_time) { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, new_time); } } else @@ -4984,9 +4994,9 @@ bool spu_thread::process_mfc_cmd() if (this_time == rtime) { // Notify threads manually, memory data has likely changed and broke the reservation for others - if (vm::reservation_notifier_count(addr) && res == this_time) + if (vm::reservation_notifier_count(addr, this_time) && res == this_time) { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, this_time); } } @@ -5645,28 +5655,46 @@ usz spu_thread::register_cache_line_waiter(u32 addr) { const u64 value = u64{compute_rdata_hash32(rdata)} << 32 | addr; - for (usz i = 0; i < std::size(g_spu_waiters_by_value); i++) + for (usz attempts = 0; attempts < 2; attempts++) { - auto [old, ok] = g_spu_waiters_by_value[i].fetch_op([value](u64& x) + // First, scan for a matching address waiter + // Remembering a potentially empty spot + usz empty_it = umax; + + for (usz i = 0; i < std::size(g_spu_waiters_by_value); i++) { - if (x == 0) + auto [old, ok] = g_spu_waiters_by_value[i].fetch_op([&](u64& x) { - x = value + 1; - return true; - } + if (x == 0) + { + empty_it = i; + return false; + } - if ((x & -128) == value) + if ((x & -128) == value) + { + x++; + return true; + } + + return false; + }); + + if (ok) { - x++; - return true; + return i; } + } - return false; - }); - - if (ok) + if (empty_it == umax) { - return i; + continue; + } + + // If we did not find existing an waiter, try to occupy an empty spot + if (g_spu_waiters_by_value[empty_it].compare_and_swap_test(0, value + 1)) + { + return empty_it; } } @@ -5681,7 +5709,7 @@ void spu_thread::deregister_cache_line_waiter(usz index) return; } - g_spu_waiters_by_value[index].fetch_op([](u64& x) + g_spu_waiters_by_value[index].atomic_op([](u64& x) { x--; @@ -5689,8 +5717,6 @@ void spu_thread::deregister_cache_line_waiter(usz index) { x = 0; } - - return false; }); } @@ -6056,11 +6082,6 @@ s64 spu_thread::get_ch_value(u32 ch) const usz seed = (utils::get_tsc() >> 8) % 100; -#ifdef __linux__ - const bool reservation_busy_waiting = false; -#else - const bool reservation_busy_waiting = (seed + ((raddr == spurs_addr) ? 50u : 0u)) < g_cfg.core.spu_reservation_busy_waiting_percentage; -#endif usz cache_line_waiter_index = umax; auto check_cache_line_waiter = [&]() @@ -6080,6 +6101,9 @@ s64 spu_thread::get_ch_value(u32 ch) return true; }; + static atomic_t s_is_reservation_data_checking_thread = false; + bool is_reservation_data_checking_thread = false; + const bool is_LR_wait = raddr && mask1 & SPU_EVENT_LR; auto& history = eventstat_wait_time[(raddr % SPU_LS_SIZE) / 128]; @@ -6104,6 +6128,19 @@ s64 spu_thread::get_ch_value(u32 ch) u8& val = history.front(); val = static_cast(std::min(val + 1, u8{umax})); } + + if (!s_is_reservation_data_checking_thread && utils::get_thread_count() >= 12)// && std::find(raddr_busy_wait_addr.begin(), raddr_busy_wait_addr.end(), raddr) != raddr_busy_wait_addr.end()) + { + if (s_is_reservation_data_checking_thread.compare_and_swap_test(0, 1)) + { + eventstat_busy_waiting_switch = 1; + is_reservation_data_checking_thread = true; + eventstat_raddr = 1; + eventstat_spin_count = 0; + } + } + + lv2_obj::notify_all(); } else { @@ -6131,11 +6168,15 @@ s64 spu_thread::get_ch_value(u32 ch) if (is_stopped(old)) { - if (cache_line_waiter_index != umax) + if (is_reservation_data_checking_thread) { - g_spu_waiters_by_value[cache_line_waiter_index].release(0); + s_is_reservation_data_checking_thread = 0; + + // Check again other reservations in other threads + lv2_obj::notify_all(); } + deregister_cache_line_waiter(cache_line_waiter_index); return -1; } @@ -6155,10 +6196,22 @@ s64 spu_thread::get_ch_value(u32 ch) } else if (!cmp_rdata(rdata, *resrv_mem)) { - // Notify threads manually, memory data has likely changed and broke the reservation for others - if (vm::reservation_notifier_count(raddr) && vm::reservation_acquire(raddr) == rtime) + if (vm::reservation_acquire(raddr) == rtime) { - vm::reservation_notifier_notify(raddr); + // Confirm change in data only, register address for busy waiting + if (std::find(raddr_busy_wait_addr.begin(), raddr_busy_wait_addr.end(), raddr) == raddr_busy_wait_addr.end()) + { + std::rotate(raddr_busy_wait_addr.rbegin(), raddr_busy_wait_addr.rbegin() + 1, raddr_busy_wait_addr.rend()); + raddr_busy_wait_addr[0] = raddr; + } + + vm::reservation_update(raddr); + } + + // Notify threads manually, memory data has likely changed and broke the reservation for others + if (vm::reservation_notifier_count(raddr, rtime) && vm::reservation_acquire(raddr) == rtime) + { + vm::reservation_notifier_notify(raddr, rtime); } set_lr = true; @@ -6184,7 +6237,7 @@ s64 spu_thread::get_ch_value(u32 ch) // Don't be stubborn, force operating sleep if too much time has passed const u64 time_since = get_system_time() - eventstat_evaluate_time; - if (time_since >= (utils::get_thread_count() >= 9 ? 50'000 : 3000)) + if (!is_reservation_data_checking_thread && time_since >= (utils::get_thread_count() >= 9 ? 50'000 : 3000)) { spu_log.trace("SPU RdEventStat wait for 0x%x failed", raddr); history.front() = 2; @@ -6246,8 +6299,7 @@ s64 spu_thread::get_ch_value(u32 ch) } } - // Don't busy-wait with TSX - memory is sensitive - if (g_use_rtm || !reservation_busy_waiting) + if (true) { if (u32 work_count = g_spu_work_count) { @@ -6274,11 +6326,16 @@ s64 spu_thread::get_ch_value(u32 ch) { // Wait with extended timeout, in this situation we have notifications for nearly all writes making it possible // Abort notifications are handled specially for performance reasons - if (auto wait_var = vm::reservation_notifier_begin_wait(raddr, rtime)) + if (auto [wait_var, flag_val] = vm::reservation_notifier_begin_wait(raddr, rtime); wait_var) { - if (check_cache_line_waiter()) + if (!cmp_rdata(rdata, *resrv_mem)) { - utils::bless>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{300'000}); + raddr = 0; + set_events(SPU_EVENT_LR); + } + else if (check_cache_line_waiter()) + { + utils::bless>(&wait_var->raw().wait_flag)->wait(flag_val, atomic_wait_timeout{200'000}); } vm::reservation_notifier_end_wait(*wait_var); @@ -6289,12 +6346,16 @@ s64 spu_thread::get_ch_value(u32 ch) const u32 _raddr = this->raddr; #ifdef __linux__ - - if (auto wait_var = vm::reservation_notifier_begin_wait(_raddr, rtime)) + if (auto [wait_var, flag_val] = vm::reservation_notifier_begin_wait(_raddr, rtime); wait_var) { - if (check_cache_line_waiter()) + if (!cmp_rdata(rdata, *resrv_mem)) { - utils::bless>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{50'000}); + raddr = 0; + set_events(SPU_EVENT_LR); + } + else if (check_cache_line_waiter()) + { + utils::bless>(&wait_var->raw().wait_flag)->wait(flag_val, atomic_wait_timeout{50'000}); } vm::reservation_notifier_end_wait(*wait_var); @@ -6335,8 +6396,16 @@ s64 spu_thread::get_ch_value(u32 ch) } else if (!cmp_rdata(_this->rdata, *_this->resrv_mem)) { + auto& wait_addrs = _this->raddr_busy_wait_addr; + + if (vm::reservation_acquire(raddr) == _this->rtime && std::find(wait_addrs.begin(), wait_addrs.end(), raddr) == wait_addrs.end()) + { + std::rotate(wait_addrs.rbegin(), wait_addrs.rbegin() + 1, wait_addrs.rend()); + wait_addrs[0] = raddr; + } + // Notify threads manually, memory data has likely changed and broke the reservation for others - if (vm::reservation_notifier_count(raddr) >= 2 && vm::reservation_acquire(raddr) == _this->rtime) + if (vm::reservation_notifier_count(raddr, _this->rtime) >= 2 && vm::reservation_acquire(raddr) == _this->rtime) { s_tls_try_notify = true; } @@ -6357,27 +6426,28 @@ s64 spu_thread::get_ch_value(u32 ch) return true; }; - if (auto wait_var = vm::reservation_notifier_begin_wait(_raddr, rtime)) + if (auto [wait_var, flag_val] = vm::reservation_notifier_begin_wait(_raddr, rtime); wait_var) { - if (check_cache_line_waiter()) + if (!cmp_rdata(rdata, *resrv_mem)) + { + raddr = 0; + set_events(SPU_EVENT_LR); + } + else if (check_cache_line_waiter()) { atomic_wait_engine::set_one_time_use_wait_callback(wait_cb); - utils::bless>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{80'000}); + utils::bless>(&wait_var->raw().wait_flag)->wait(flag_val, atomic_wait_timeout{100'000}); } vm::reservation_notifier_end_wait(*wait_var); } - if (s_tls_try_notify && vm::reservation_notifier_count(_raddr) && vm::reservation_acquire(_raddr) == rtime) + if (s_tls_try_notify && vm::reservation_notifier_count(_raddr, rtime) && vm::reservation_acquire(_raddr) == rtime) { - vm::reservation_notifier_notify(_raddr); + vm::reservation_notifier_notify(_raddr, rtime); } #endif } - else - { - busy_wait(); - } continue; } @@ -6385,11 +6455,19 @@ s64 spu_thread::get_ch_value(u32 ch) thread_ctrl::wait_on(state, old, 100); } + if (is_reservation_data_checking_thread) + { + s_is_reservation_data_checking_thread = 0; + + // Check again other reservations in other threads + lv2_obj::notify_all(); + } + deregister_cache_line_waiter(cache_line_waiter_index); - wakeup_delay(); + const auto old = +state; - if (is_paused(state - cpu_flag::suspend)) + if (is_paused(old - cpu_flag::suspend)) { if (!raddr && old_raddr) { @@ -6399,6 +6477,10 @@ s64 spu_thread::get_ch_value(u32 ch) raddr = 0; } } + else if (!is_stopped(old)) + { + wakeup_delay(); + } check_state(); return events.events & mask1; @@ -6883,7 +6965,7 @@ extern void resume_spu_thread_group_from_waiting(spu_thread& spu, std::arraystate -= cpu_flag::suspend; } - notify_spus[thread->index] = thread; + notify_spus[group->threads_map[thread->index]] = thread; } } } @@ -7283,6 +7365,7 @@ bool spu_thread::stop_and_signal(u32 code) } u32 prev_resv = 0; + u64 prev_rtime = 0; for (auto& thread : group->threads) { @@ -7295,13 +7378,14 @@ bool spu_thread::stop_and_signal(u32 code) if (u32 resv = atomic_storage::load(thread->raddr)) { - if (prev_resv && prev_resv != resv) + if (prev_resv && (prev_resv != resv || thread->rtime != prev_rtime)) { // Batch reservation notifications if possible - vm::reservation_notifier_notify(prev_resv); + vm::reservation_notifier_notify(prev_resv, thread->rtime); } prev_resv = resv; + prev_rtime = thread->rtime; } } } @@ -7309,7 +7393,7 @@ bool spu_thread::stop_and_signal(u32 code) if (prev_resv) { - vm::reservation_notifier_notify(prev_resv); + vm::reservation_notifier_notify(prev_resv, prev_rtime); } check_state(); diff --git a/rpcs3/Emu/Cell/SPUThread.h b/rpcs3/Emu/Cell/SPUThread.h index 5a0d9bab31..36d24ff55e 100644 --- a/rpcs3/Emu/Cell/SPUThread.h +++ b/rpcs3/Emu/Cell/SPUThread.h @@ -768,7 +768,7 @@ public: std::shared_ptr shm; // SPU memory const std::add_pointer_t ls; // SPU LS pointer const u32 option; // sys_spu_thread_initialize option - const u32 lv2_id; // The actual id that is used by syscalls + u32 lv2_id; // The actual id that is used by syscalls u32 spurs_addr = 0; bool spurs_waited = false; bool spurs_entered_wait = false; @@ -824,6 +824,7 @@ public: u8 cpu_work_iteration_count = 0; std::array stack_mirror; // Return address information + std::array raddr_busy_wait_addr{}; // Return address information const char* current_func{}; // Current STOP or RDCH blocking function u64 start_time{}; // Starting time of STOP or RDCH bloking function diff --git a/rpcs3/Emu/Cell/lv2/lv2.cpp b/rpcs3/Emu/Cell/lv2/lv2.cpp index 8d4db2bc91..c405b98a2c 100644 --- a/rpcs3/Emu/Cell/lv2/lv2.cpp +++ b/rpcs3/Emu/Cell/lv2/lv2.cpp @@ -1336,27 +1336,27 @@ bool lv2_obj::sleep(cpu_thread& cpu, const u64 timeout) if (cpu.get_class() == thread_class::ppu) { - if (u32 addr = static_cast(cpu).res_notify) + ppu_thread& ppu = static_cast(cpu); + + if (u32 addr = ppu.res_notify) { - static_cast(cpu).res_notify = 0; + ppu.res_notify = 0; + ppu.res_notify_postpone_streak = 0; - if (static_cast(cpu).res_notify_time != vm::reservation_notifier_count_index(addr).second) + if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t{}); it != std::end(g_to_notify)) { - // Ignore outdated notification request - } - else if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t{}); it != std::end(g_to_notify)) - { - *it++ = vm::reservation_notifier_notify(addr, true); - - if (it < std::end(g_to_notify)) + if ((*it++ = vm::reservation_notifier_notify(addr, ppu.res_notify_time, true))) { - // Null-terminate the list if it ends before last slot - *it = nullptr; + if (it < std::end(g_to_notify)) + { + // Null-terminate the list if it ends before last slot + *it = nullptr; + } } } else { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, ppu.res_notify_time); } } } @@ -1392,24 +1392,22 @@ bool lv2_obj::awake(cpu_thread* thread, s32 prio) if (u32 addr = ppu->res_notify) { ppu->res_notify = 0; + ppu->res_notify_postpone_streak = 0; - if (ppu->res_notify_time != vm::reservation_notifier_count_index(addr).second) + if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t{}); it != std::end(g_to_notify)) { - // Ignore outdated notification request - } - else if (auto it = std::find(g_to_notify, std::end(g_to_notify), std::add_pointer_t{}); it != std::end(g_to_notify)) - { - *it++ = vm::reservation_notifier_notify(addr, true); - - if (it < std::end(g_to_notify)) + if ((*it++ = vm::reservation_notifier_notify(addr, ppu->res_notify_time, true))) { - // Null-terminate the list if it ends before last slot - *it = nullptr; + if (it < std::end(g_to_notify)) + { + // Null-terminate the list if it ends before last slot + *it = nullptr; + } } } else { - vm::reservation_notifier_notify(addr); + vm::reservation_notifier_notify(addr, ppu->res_notify_time); } } } @@ -2232,18 +2230,8 @@ void lv2_obj::notify_all() noexcept if (cpu != &g_to_notify) { - const auto res_start = vm::reservation_notifier(0).second; - const auto res_end = vm::reservation_notifier(umax).second; - - if (cpu >= res_start && cpu <= res_end) - { - atomic_wait_engine::notify_all(cpu); - } - else - { - // Note: by the time of notification the thread could have been deallocated which is why the direct function is used - atomic_wait_engine::notify_one(cpu); - } + // Note: by the time of notification the thread could have been deallocated which is why the direct function is used + atomic_wait_engine::notify_all(cpu); } } @@ -2267,13 +2255,19 @@ void lv2_obj::notify_all() noexcept constexpr usz total_waiters = std::size(spu_thread::g_spu_waiters_by_value); u32 notifies[total_waiters]{}; + u64 notifies_time[total_waiters]{}; // There may be 6 waiters, but checking them all may be performance expensive // Instead, check 2 at max, but use the CPU ID index to tell which index to start checking so the work would be distributed across all threads atomic_t* range_lock = nullptr; - for (usz i = 0, checked = 0; checked < 3 && i < total_waiters; i++) + if (cpu->get_class() == thread_class::spu) + { + range_lock = static_cast(cpu)->range_lock; + } + + for (usz i = 0, checked = 0; checked < 4 && i < total_waiters; i++) { auto& waiter = spu_thread::g_spu_waiters_by_value[(i + cpu->id) % total_waiters]; const u64 value = waiter.load(); @@ -2300,6 +2294,7 @@ void lv2_obj::notify_all() noexcept }).second) { notifies[i] = raddr; + notifies_time[i] = vm::reservation_acquire(raddr); } } @@ -2328,21 +2323,24 @@ void lv2_obj::notify_all() noexcept }).second) { notifies[i] = raddr; + notifies_time[i] = vm::reservation_acquire(raddr); } } } } - if (range_lock) + if (range_lock && cpu->get_class() != thread_class::spu) { vm::free_range_lock(range_lock); } - for (u32 addr : notifies) + for (u32 i = 0; i < total_waiters; i++) { - if (addr) + if (notifies[i]) { - vm::reservation_notifier_notify(addr); + // Cover all waiters for an address + vm::reservation_notifier_notify(notifies[i], notifies_time[i]); + vm::reservation_notifier_notify(notifies[i], notifies_time[i] - 128); } } } diff --git a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp index 92bf877a8a..63c0c16af9 100644 --- a/rpcs3/Emu/Cell/lv2/sys_mutex.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_mutex.cpp @@ -4,6 +4,7 @@ #include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/PPUThread.h" +#include "Emu/Memory/vm_reservation.h" #include "util/asm.hpp" @@ -345,6 +346,9 @@ error_code sys_mutex_unlock(ppu_thread& ppu, u32 mutex_id) const auto mutex = idm::check(mutex_id, [&, notify = lv2_obj::notify_all_t()](lv2_mutex& mutex) -> CellError { + // At unlock, we have some time to do other jobs when the thread is unlikely to be in other critical sections + notify.enqueue_on_top(vm::reservation_notifier_notify(ppu.res_notify, ppu.res_notify_time)); + auto result = mutex.try_unlock(ppu); if (result == CELL_EBUSY) diff --git a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp index 377da5bf31..18a1c2a935 100644 --- a/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_net/network_context.cpp @@ -295,7 +295,8 @@ void p2p_thread::operator()() } #ifdef _WIN32 - const auto ret_p2p = WSAPoll(p2p_fd.data(), num_p2p_sockets, 1); + // WSAPoll seems to consume a lot of CPU time relative to its waiting duration, upping the timeout solves it + const auto ret_p2p = WSAPoll(p2p_fd.data(), num_p2p_sockets, 5); #else const auto ret_p2p = ::poll(p2p_fd.data(), num_p2p_sockets, 1); #endif diff --git a/rpcs3/Emu/Cell/lv2/sys_spu.cpp b/rpcs3/Emu/Cell/lv2/sys_spu.cpp index 77fbcb8505..c3328eb604 100644 --- a/rpcs3/Emu/Cell/lv2/sys_spu.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_spu.cpp @@ -776,8 +776,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g return CELL_ESRCH; } - std::unique_lock lock(group->mutex); - if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) { if (state == SPU_THREAD_GROUP_STATUS_DESTROYED) @@ -793,6 +791,34 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g return CELL_EBUSY; } + const u32 inited_before_lock = group->init; + + u32 tid = (inited_before_lock << 24) | (group_id & 0xffffff); + + const auto spu_ptr = ensure(idm::make_ptr>(group.get(), spu_num, thread_name, tid, false, option)); + + std::unique_lock lock(group->mutex); + + if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED) + { + lock.unlock(); + idm::remove>(idm::last_id()); + + if (state == SPU_THREAD_GROUP_STATUS_DESTROYED) + { + return CELL_ESRCH; + } + + return CELL_EBUSY; + } + + if (group->threads_map[spu_num] != -1) + { + lock.unlock(); + idm::remove>(idm::last_id()); + return CELL_EBUSY; + } + if (option & SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE) { sys_spu.warning("Unimplemented SPU Thread options (0x%x)", option); @@ -800,15 +826,13 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr thread, u32 g const u32 inited = group->init; - const u32 tid = (inited << 24) | (group_id & 0xffffff); + tid = (inited << 24) | (group_id & 0xffffff); - ensure(idm::import>([&]() - { - const auto spu = stx::make_shared>(group.get(), spu_num, thread_name, tid, false, option); - group->threads[inited] = spu; - group->threads_map[spu_num] = static_cast(inited); - return spu; - })); + // Update lv2_id (potentially changed after locking) + spu_ptr->lv2_id = tid; + + group->threads[inited] = spu_ptr; + group->threads_map[spu_num] = static_cast(inited); // alloc_hidden indicates falloc to allocate page with no access rights in base memory auto& spu = group->threads[inited]; @@ -1501,6 +1525,7 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) } u32 prev_resv = 0; + u64 prev_time = 0; for (auto& thread : group->threads) { @@ -1510,20 +1535,21 @@ error_code sys_spu_thread_group_terminate(ppu_thread& ppu, u32 id, s32 value) if (u32 resv = atomic_storage::load(thread->raddr)) { - if (prev_resv && prev_resv != resv) + if (prev_resv && (prev_resv != resv || prev_time != thread->rtime)) { // Batch reservation notifications if possible - vm::reservation_notifier_notify(prev_resv); + vm::reservation_notifier_notify(prev_resv, prev_time); } prev_resv = resv; + prev_time = thread->rtime; } } } if (prev_resv) { - vm::reservation_notifier_notify(prev_resv); + vm::reservation_notifier_notify(prev_resv, prev_time); } group->exit_status = value; diff --git a/rpcs3/Emu/Cell/lv2/sys_ss.cpp b/rpcs3/Emu/Cell/lv2/sys_ss.cpp index 0315c3f152..2c4b1282fd 100644 --- a/rpcs3/Emu/Cell/lv2/sys_ss.cpp +++ b/rpcs3/Emu/Cell/lv2/sys_ss.cpp @@ -210,8 +210,10 @@ error_code sys_ss_get_open_psid(vm::ptr psid) { sys_ss.notice("sys_ss_get_open_psid(psid=*0x%x)", psid); - psid->high = g_cfg.sys.console_psid_high; - psid->low = g_cfg.sys.console_psid_low; + const u128 configured_psid = g_cfg.sys.console_psid.get(); + + psid->high = static_cast(configured_psid >> 64); + psid->low = static_cast(configured_psid); return CELL_OK; } @@ -259,8 +261,8 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr buffer) case 0x19005: { // AIM_get_open_ps_id - be_t psid[2] = { +g_cfg.sys.console_psid_high, +g_cfg.sys.console_psid_low }; - std::memcpy(buffer.get_ptr(), psid, 16); + const be_t psid = g_cfg.sys.console_psid.get(); + std::memcpy(buffer.get_ptr(), &psid, 16); break; } case 0x19006: @@ -268,7 +270,11 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr buffer) // qa values (dex only) ?? [[fallthrough]]; } - default: sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer); + default: + { + sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer); + break; + } } return CELL_OK; diff --git a/rpcs3/Emu/Cell/lv2/sys_sync.h b/rpcs3/Emu/Cell/lv2/sys_sync.h index bf99bcb056..0aff5e1e7a 100644 --- a/rpcs3/Emu/Cell/lv2/sys_sync.h +++ b/rpcs3/Emu/Cell/lv2/sys_sync.h @@ -483,6 +483,12 @@ public: } } + static void enqueue_on_top(const void* waiter) + { + g_to_notify[0] = waiter; + g_to_notify[1] = nullptr; + } + ~notify_all_t() noexcept { lv2_obj::notify_all(); diff --git a/rpcs3/Emu/Io/MouseHandler.cpp b/rpcs3/Emu/Io/MouseHandler.cpp index c80d7556dc..9fd37463cd 100644 --- a/rpcs3/Emu/Io/MouseHandler.cpp +++ b/rpcs3/Emu/Io/MouseHandler.cpp @@ -71,6 +71,8 @@ void MouseHandlerBase::Button(u32 index, u8 button, bool pressed) MouseData new_data{}; new_data.update = CELL_MOUSE_DATA_UPDATE; new_data.buttons = mouse.buttons; + new_data.pixel_x = mouse.x_pos; + new_data.pixel_y = mouse.y_pos; datalist.push_back(std::move(new_data)); } @@ -100,6 +102,8 @@ void MouseHandlerBase::Scroll(u32 index, s8 x, s8 y) new_data.buttons = mouse.buttons; new_data.wheel = y; new_data.tilt = x; + new_data.pixel_x = mouse.x_pos; + new_data.pixel_y = mouse.y_pos; datalist.push_back(std::move(new_data)); } @@ -137,6 +141,8 @@ void MouseHandlerBase::Move(u32 index, s32 x_pos_new, s32 y_pos_new, s32 x_max, new_data.x_axis = static_cast(std::clamp(x_delta, -127, 128)); new_data.y_axis = static_cast(std::clamp(y_delta, -127, 128)); + new_data.pixel_x = x_pos_new; + new_data.pixel_y = y_pos_new; mouse.x_max = x_max; mouse.y_max = y_max; diff --git a/rpcs3/Emu/Io/MouseHandler.h b/rpcs3/Emu/Io/MouseHandler.h index 8a88241523..6a77f44d0e 100644 --- a/rpcs3/Emu/Io/MouseHandler.h +++ b/rpcs3/Emu/Io/MouseHandler.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include "Utilities/StrFmt.h" #include "Utilities/mutex.h" @@ -96,6 +96,9 @@ struct MouseData s8 y_axis = 0; s8 wheel = 0; s8 tilt = 0; + + s32 pixel_x = 0; + s32 pixel_y = 0; }; struct MouseTabletData @@ -104,8 +107,8 @@ struct MouseTabletData u8 data[MOUSE_MAX_CODES]{}; }; -using MouseTabletDataList = std::list; -using MouseDataList = std::list; +using MouseTabletDataList = std::deque; +using MouseDataList = std::deque; struct Mouse { diff --git a/rpcs3/Emu/Io/PadHandler.cpp b/rpcs3/Emu/Io/PadHandler.cpp index 19b9347da6..bc61efc895 100644 --- a/rpcs3/Emu/Io/PadHandler.cpp +++ b/rpcs3/Emu/Io/PadHandler.cpp @@ -40,7 +40,7 @@ f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 dea } // convert [min, max] to [0, 1] - const f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (maximum - minimum); + const f32 val = static_cast(std::max(minimum, std::min(raw_value, maximum)) - minimum) / (maximum - minimum); // convert [0, 1] to [0, range] return range * val; @@ -50,7 +50,7 @@ f32 PadHandlerBase::ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 dea f32 PadHandlerBase::ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range) { // convert [min, max] to [0, 1] - f32 val = static_cast(std::clamp(raw_value, minimum, maximum) - minimum) / (maximum - minimum); + f32 val = static_cast(std::max(minimum, std::min(raw_value, maximum)) - minimum) / (maximum - minimum); if (deadzone > 0) { @@ -200,10 +200,29 @@ void PadHandlerBase::init_configs() { for (u32 i = 0; i < MAX_GAMEPADS; i++) { + // We need to restore the original defaults first. + m_pad_configs[i].restore_defaults(); + + // Set and apply actual defaults depending on pad handler init_config(&m_pad_configs[i]); } } +pad_capabilities PadHandlerBase::get_capabilities(const std::string& /*pad_id*/) +{ + return pad_capabilities + { + .has_led = b_has_rgb, + .has_mono_led = b_has_led, + .has_player_led = b_has_player_led, + .has_battery_led = b_has_battery_led, + .has_rumble = b_has_rumble, + .has_accel = b_has_motion, + .has_gyro = b_has_motion, + .has_pressure_sensitivity = b_has_pressure_intensity_button + }; +} + cfg_pad* PadHandlerBase::get_config(const std::string& pad_id) { int index = 0; @@ -327,12 +346,13 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri if (callback) { pad_preview_values preview_values = get_preview_values(data); + pad_capabilities capabilities = get_capabilities(pad_id); const u32 battery_level = get_battery_level(pad_id); if (pressed_button.value > 0) - callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values)); + callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values), std::move(capabilities)); else - callback(0, "", pad_id, battery_level, std::move(preview_values)); + callback(0, "", pad_id, battery_level, std::move(preview_values), std::move(capabilities)); } return status; @@ -538,8 +558,8 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr pad) 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[0] = VibrateMotor(true, 0); - pad->m_vibrateMotors[1] = VibrateMotor(false, 0); + pad->m_vibrate_motors[0] = VibrateMotor(true); + pad->m_vibrate_motors[1] = VibrateMotor(false); m_bindings.emplace_back(pad, pad_device, nullptr); @@ -759,9 +779,10 @@ void PadHandlerBase::process() if ((get_system_time() - pad->m_last_rumble_time_us) > 3'000'000) { - for (VibrateMotor& motor : pad->m_vibrateMotors) + for (VibrateMotor& motor : pad->m_vibrate_motors) { - motor.m_value = 0; + motor.value = 0; + motor.adjusted_value = 0; } pad->m_last_rumble_time_us = 0; diff --git a/rpcs3/Emu/Io/PadHandler.h b/rpcs3/Emu/Io/PadHandler.h index 99c085b015..e9fc166d93 100644 --- a/rpcs3/Emu/Io/PadHandler.h +++ b/rpcs3/Emu/Io/PadHandler.h @@ -81,8 +81,20 @@ struct pad_list_entry {} }; +struct pad_capabilities +{ + bool has_led = false; + bool has_mono_led = false; + bool has_player_led = false; + bool has_battery_led = false; + bool has_rumble = false; + bool has_accel = false; + bool has_gyro = false; + bool has_pressure_sensitivity = false; +}; + using pad_preview_values = std::array; -using pad_callback = std::function; +using pad_callback = std::function; using pad_fail_callback = std::function; using motion_preview_values = std::array; @@ -255,15 +267,6 @@ protected: return {}; } - // Get new multiplied value based on the multiplier - static s32 MultipliedInput(s32 raw_value, s32 multiplier); - - // Get new scaled value between 0 and 255 based on its minimum and maximum - static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); - - // Get new scaled value between -255 and 255 based on its minimum and maximum - static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); - // Get normalized trigger value based on the range defined by a threshold u16 NormalizeTriggerInput(u16 value, u32 threshold) const; @@ -276,6 +279,17 @@ protected: // return is new x and y values in 0-255 range std::tuple NormalizeStickDeadzone(s32 inX, s32 inY, u32 deadzone, u32 anti_deadzone) const; +public: + + // Get new multiplied value based on the multiplier + static s32 MultipliedInput(s32 raw_value, s32 multiplier); + + // Get new scaled value between 0 and 255 based on its minimum and maximum + static f32 ScaledInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); + + // Get new scaled value between -255 and 255 based on its minimum and maximum + static f32 ScaledAxisInput(f32 raw_value, f32 minimum, f32 maximum, f32 deadzone, f32 range = 255.0f); + // get clamped value between 0 and 255 static u16 Clamp0To255(f32 input); @@ -291,7 +305,6 @@ protected: // This function assumes inX and inY is already in 0-255 static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor); -public: // u32 thumb_min = 0; // Unused. Make sure all handlers report 0+ values for sticks in get_button_values. u32 thumb_max = 255; u32 trigger_min = 0; @@ -325,6 +338,8 @@ public: bool has_analog_limiter_button() const { return b_has_analog_limiter_button; } bool has_orientation() const { return b_has_orientation; } + virtual pad_capabilities get_capabilities(const std::string& /*pad_id*/); + u16 NormalizeStickInput(u16 raw_value, s32 threshold, s32 multiplier, bool ignore_threshold = false) const; void convert_stick_values(u16& x_out, u16& y_out, s32 x_in, s32 y_in, u32 deadzone, u32 anti_deadzone, u32 padsquircling) const; void set_trigger_recognition_mode(trigger_recognition_mode mode) { m_trigger_recognition_mode = mode; } diff --git a/rpcs3/Emu/Io/pad_config.cpp b/rpcs3/Emu/Io/pad_config.cpp index fb0b140aeb..614d972716 100644 --- a/rpcs3/Emu/Io/pad_config.cpp +++ b/rpcs3/Emu/Io/pad_config.cpp @@ -1,8 +1,7 @@ #include "stdafx.h" #include "pad_config.h" #include "Emu/system_utils.hpp" - -LOG_CHANNEL(input_log, "Input"); +#include "Emu/Io/PadHandler.h" extern std::string g_input_config_override; @@ -32,18 +31,27 @@ std::string cfg_pad::get_buttons(std::vector vec) return fmt::merge(vec, ","); } -u8 cfg_pad::get_large_motor_speed(const std::array& motor_speed) const +u8 cfg_pad::get_motor_speed(VibrateMotor& motor, f32 multiplier) const { - const u8 idx = switch_vibration_motors ? 1 : 0; - const f32 multiplier = multiplier_vibration_motor_large / 100.0f; - return static_cast(std::clamp(motor_speed[idx].m_value * multiplier, 0.0f, 255.0f)); + // If motor is small, use either 0 or 255. + const u8 value = motor.is_large_motor ? motor.value : (motor.value > 0 ? 255 : 0); + + // Ignore lower range. Scale remaining range to full range. + const f32 adjusted = PadHandlerBase::ScaledInput(value, static_cast(vibration_threshold.get()), 255.0f, 0.0f, 255.0f); + + // Apply multiplier + motor.adjusted_value = static_cast(std::clamp(adjusted * multiplier, 0.0f, 255.0f)); + return motor.adjusted_value; } -u8 cfg_pad::get_small_motor_speed(const std::array& motor_speed) const +u8 cfg_pad::get_large_motor_speed(std::array& motors) const { - const u8 idx = switch_vibration_motors ? 0 : 1; - const f32 multiplier = multiplier_vibration_motor_small / 100.0f; - return static_cast(std::clamp(motor_speed[idx].m_value * multiplier, 0.0f, 255.0f)); + return get_motor_speed(motors[switch_vibration_motors ? 1 : 0], multiplier_vibration_motor_large / 100.0f); +} + +u8 cfg_pad::get_small_motor_speed(std::array& motors) const +{ + return get_motor_speed(motors[switch_vibration_motors ? 0 : 1], multiplier_vibration_motor_small / 100.0f); } bool cfg_input::load(const std::string& title_id, const std::string& config_file, bool strict) diff --git a/rpcs3/Emu/Io/pad_config.h b/rpcs3/Emu/Io/pad_config.h index 7c39a79411..5f8ea18a74 100644 --- a/rpcs3/Emu/Io/pad_config.h +++ b/rpcs3/Emu/Io/pad_config.h @@ -28,8 +28,9 @@ struct cfg_pad final : cfg::node static std::vector get_buttons(const std::string& str); static std::string get_buttons(std::vector vec); - u8 get_large_motor_speed(const std::array& motor_speed) const; - u8 get_small_motor_speed(const std::array& motor_speed) const; + u8 get_motor_speed(VibrateMotor& motor, f32 multiplier) const; + u8 get_large_motor_speed(std::array& motors) const; + u8 get_small_motor_speed(std::array& motors) const; cfg::string ls_left{ this, "Left Stick Left", "" }; cfg::string ls_down{ this, "Left Stick Down", "" }; @@ -102,6 +103,7 @@ struct cfg_pad final : cfg::node cfg::uint<0, 200> multiplier_vibration_motor_large{ this, "Large Vibration Motor Multiplier", 100 }; cfg::uint<0, 200> multiplier_vibration_motor_small{ this, "Small Vibration Motor Multiplier", 100 }; cfg::_bool switch_vibration_motors{ this, "Switch Vibration Motors", false }; + cfg::uint<0, 255> vibration_threshold{ this, "Vibration Threshold", MOTOR_THRESHOLD }; cfg::_enum mouse_move_mode{ this, "Mouse Movement Mode", mouse_movement_mode::relative }; cfg::uint<0, 255> mouse_deadzone_x{ this, "Mouse Deadzone X Axis", 60 }; diff --git a/rpcs3/Emu/Io/pad_types.cpp b/rpcs3/Emu/Io/pad_types.cpp index 428e0d6cea..9c67cc20f5 100644 --- a/rpcs3/Emu/Io/pad_types.cpp +++ b/rpcs3/Emu/Io/pad_types.cpp @@ -195,14 +195,9 @@ bool Pad::get_pressure_intensity_button_active(bool is_toggle_mode, u32 player_i if (g_cfg.misc.show_pressure_intensity_toggle_hint) { const std::string player_id_string = std::to_string(player_id + 1); - if (m_pressure_intensity_toggled) - { - rsx::overlays::queue_message(get_localized_string(localized_string_id::RSX_OVERLAYS_PRESSURE_INTENSITY_TOGGLED_ON, player_id_string.c_str()), 3'000'000); - } - else - { - rsx::overlays::queue_message(get_localized_string(localized_string_id::RSX_OVERLAYS_PRESSURE_INTENSITY_TOGGLED_OFF, player_id_string.c_str()), 3'000'000); - } + rsx::overlays::queue_message(get_localized_string( + m_pressure_intensity_toggled ? localized_string_id::RSX_OVERLAYS_PRESSURE_INTENSITY_TOGGLED_ON : localized_string_id::RSX_OVERLAYS_PRESSURE_INTENSITY_TOGGLED_OFF, + player_id_string.c_str()), 3'000'000); } } } @@ -235,14 +230,9 @@ bool Pad::get_analog_limiter_button_active(bool is_toggle_mode, u32 player_id) if (g_cfg.misc.show_analog_limiter_toggle_hint) { const std::string player_id_string = std::to_string(player_id + 1); - if (m_analog_limiter_toggled) - { - rsx::overlays::queue_message(get_localized_string(localized_string_id::RSX_OVERLAYS_ANALOG_LIMITER_TOGGLED_ON, player_id_string.c_str()), 3'000'000); - } - else - { - rsx::overlays::queue_message(get_localized_string(localized_string_id::RSX_OVERLAYS_ANALOG_LIMITER_TOGGLED_OFF, player_id_string.c_str()), 3'000'000); - } + rsx::overlays::queue_message(get_localized_string( + m_analog_limiter_toggled ? localized_string_id::RSX_OVERLAYS_ANALOG_LIMITER_TOGGLED_ON : localized_string_id::RSX_OVERLAYS_ANALOG_LIMITER_TOGGLED_OFF, + player_id_string.c_str()), 3'000'000); } } } diff --git a/rpcs3/Emu/Io/pad_types.h b/rpcs3/Emu/Io/pad_types.h index ecbadff3bf..8c669a9413 100644 --- a/rpcs3/Emu/Io/pad_types.h +++ b/rpcs3/Emu/Io/pad_types.h @@ -344,6 +344,8 @@ struct CellPadData be_t button[CELL_PAD_MAX_CODES]; }; +static constexpr u8 MOTOR_THRESHOLD = 63; // The DS3 does not seem to respond to values <= 63. So we should ignore those in other handlers as well. + static constexpr u16 MOTION_ONE_G = 113; static constexpr u16 DEFAULT_MOTION_X = 512; static constexpr u16 DEFAULT_MOTION_Y = 399; // 512 - 113 (113 is 1G gravity) @@ -457,13 +459,13 @@ struct AnalogSensor struct VibrateMotor { - bool m_is_large_motor = false; - u8 m_value = 0; + bool is_large_motor = false; + u8 value = 0; + u8 adjusted_value = 0; VibrateMotor() {} - VibrateMotor(bool is_large_motor, u8 value) - : m_is_large_motor(is_large_motor) - , m_value(value) + VibrateMotor(bool is_large_motor) + : is_large_motor(is_large_motor) {} }; @@ -544,41 +546,14 @@ struct Pad std::vector