Compare commits

..

No commits in common. "master" and "v0.0.38" have entirely different histories.

349 changed files with 4442 additions and 8227 deletions

View file

@ -6,13 +6,12 @@ export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_ENV_HINTS=1 export HOMEBREW_NO_ENV_HINTS=1
export HOMEBREW_NO_INSTALL_CLEANUP=1 export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install -f --overwrite --quiet pipenv googletest opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers brew install -f --overwrite --quiet ccache pipenv googletest ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative
brew link -f --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5 brew link -f --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5
# moltenvk based on commit for 1.4.0 release # moltenvk based on commit for 1.3.0 release
export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb wget https://raw.githubusercontent.com/Homebrew/homebrew-core/7255441cbcafabaa8950f67c7ec55ff499dbb2d3/Formula/m/molten-vk.rb
/opt/homebrew/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb /opt/homebrew/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb
export HOMEBREW_DEVELOPER=0 export HOMEBREW_DEVELOPER=0
@ -28,25 +27,23 @@ export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
export WORKDIR; export WORKDIR;
WORKDIR="$(pwd)" WORKDIR="$(pwd)"
# Setup ccache
if [ ! -d "$CCACHE_DIR" ]; then
mkdir -p "$CCACHE_DIR"
fi
# Get Qt # Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt" mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597 git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader # nested Qt 6.9.3 URL workaround
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader # sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
# archived Qt 6.7.3 URL workaround
sed -i '' "s/official_releases/archive/g" qt-downloader
cd "/tmp/Qt" cd "/tmp/Qt"
"$BREW_PATH/bin/pipenv" run pip3 uninstall py7zr requests semantic_version lxml "$BREW_PATH/bin/pipenv" run pip3 uninstall py7zr requests semantic_version lxml
"$BREW_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml --no-cache "$BREW_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml --no-cache
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64" mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.3 workaround
"$BREW_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64" "$BREW_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi fi
cd "$WORKDIR" cd "$WORKDIR"

View file

@ -8,17 +8,13 @@ export HOMEBREW_NO_INSTALL_CLEANUP=1
brew install -f --overwrite --quiet ccache pipenv "llvm@$LLVM_COMPILER_VER" brew install -f --overwrite --quiet ccache pipenv "llvm@$LLVM_COMPILER_VER"
brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER"
# shellcheck disable=SC3009
rm /usr/local/bin/{idle3.14,pip3.14,pydoc3.14,python3.14,python3.14-config} && \
rm /usr/local/bin/{idle3,pip3,pydoc3,python3,python3-config}
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet ffmpeg@5 "llvm@$LLVM_COMPILER_VER" glew sdl3 vulkan-headers
arch -x86_64 /usr/local/bin/brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative
arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5 arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5
# moltenvk based on commit for 1.4.0 release # moltenvk based on commit for 1.3.0 release
export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb wget https://raw.githubusercontent.com/Homebrew/homebrew-core/7255441cbcafabaa8950f67c7ec55ff499dbb2d3/Formula/m/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb arch -x86_64 /usr/local/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb
export HOMEBREW_DEVELOPER=0 export HOMEBREW_DEVELOPER=0
export CXX=clang++ export CXX=clang++
@ -39,13 +35,16 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
git clone https://github.com/engnr/qt-downloader.git git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597 git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader # nested Qt 6.9.3 URL workaround
sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader # sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
# archived Qt 6.7.3 URL workaround
sed -i '' "s/official_releases/archive/g" qt-downloader
cd "/tmp/Qt" cd "/tmp/Qt"
"/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run pip3 install py7zr requests semantic_version lxml "/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64" mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.9.3 workaround
"/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64" "/opt/homebrew/bin/pipenv" --python "/opt/homebrew/bin/python3" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi fi
cd "$WORKDIR" cd "$WORKDIR"
@ -55,8 +54,7 @@ export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN
export SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3" export SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3"
export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH" export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
# shellcheck disable=SC2155 export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib,-L$(brew --prefix llvm)/lib/c++"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib" export LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib"

View file

@ -14,7 +14,7 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh chmod +x ./linuxdeploy-plugin-checkrt.sh
export EXTRA_PLATFORM_PLUGINS="libqwayland.so" export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor" export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt
@ -32,25 +32,6 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
# Remove git directory containing local commit history file # Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git rm -rf ./AppDir/usr/share/rpcs3/git
# Download translations
mkdir -p "./AppDir/usr/translations"
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
unzip -o translations.zip -d "./AppDir/usr/translations" >/dev/null 2>&1 || \
echo "Failed to extract translations.zip. Continuing without translations."
rm -f translations.zip
fi
curl -fsSLo /uruntime "https://github.com/VHSgunzo/uruntime/releases/download/v0.3.4/uruntime-appimage-dwarfs-$CPU_ARCH" curl -fsSLo /uruntime "https://github.com/VHSgunzo/uruntime/releases/download/v0.3.4/uruntime-appimage-dwarfs-$CPU_ARCH"
chmod +x /uruntime chmod +x /uruntime
/uruntime --appimage-mkdwarfs -f --set-owner 0 --set-group 0 --no-history --no-create-timestamp \ /uruntime --appimage-mkdwarfs -f --set-owner 0 --set-group 0 --no-history --no-create-timestamp \

View file

@ -17,7 +17,6 @@ cd bin
mkdir "rpcs3.app/Contents/lib/" || true mkdir "rpcs3.app/Contents/lib/" || true
cp "$(realpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib" cp "$(realpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "$(realpath /opt/homebrew/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib"
cp "$(realpath /opt/homebrew/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib" cp "$(realpath /opt/homebrew/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /opt/homebrew/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib" cp "$(realpath /opt/homebrew/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
@ -32,28 +31,11 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
../../.ci/optimize-mac.sh rpcs3.app ../../.ci/optimize-mac.sh rpcs3.app
# Download translations
mkdir -p "rpcs3.app/Contents/translations"
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1 || \
echo "Failed to extract translations.zip. Continuing without translations."
rm -f translations.zip
fi
# Hack # Hack
install_name_tool -delete_rpath /opt/homebrew/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/lib not needed" install_name_tool \
install_name_tool -delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib not needed" -delete_rpath /opt/homebrew/lib \
-delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /opt/homebrew1/Cellar/sdl3/3.2.8/lib
# Need to do this rename hack due to case insensitive filesystem # Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app mv rpcs3.app RPCS3_.app

View file

@ -16,9 +16,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin cd bin
mkdir "rpcs3.app/Contents/lib/" mkdir "rpcs3.app/Contents/lib/"
cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib" cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib)" "rpcs3.app/Contents/Frameworks/libunwind.1.dylib"
cp "$(realpath /usr/local/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib"
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib" cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib" cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
@ -33,25 +31,6 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
../../.ci/optimize-mac.sh rpcs3.app ../../.ci/optimize-mac.sh rpcs3.app
# Download translations
mkdir -p "rpcs3.app/Contents/translations"
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1 || \
echo "Failed to extract translations.zip. Continuing without translations."
rm -f translations.zip
fi
# Need to do this rename hack due to case insensitive filesystem # Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app mv RPCS3_.app RPCS3.app

View file

@ -24,25 +24,6 @@ mkdir ./bin/config/input_configs
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt
curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat
# Download translations
mkdir -p ./bin/share/qt6/translations
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
unzip -o translations.zip -d "./bin/share/qt6/translations" >/dev/null 2>&1 || \
echo "Failed to extract translations.zip. Continuing without translations."
rm -f translations.zip
fi
# Package artifacts # Package artifacts
7z a -m0=LZMA2 -mx9 "$BUILD" ./bin/* 7z a -m0=LZMA2 -mx9 "$BUILD" ./bin/*

View file

@ -15,25 +15,6 @@ mkdir ./bin/config/input_configs
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./bin/config/input_configs/gamecontrollerdb.txt
curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat curl -fsSL 'https://rpcs3.net/compatibility?api=v1&export' | iconv -t UTF-8 1> ./bin/GuiConfigs/compat_database.dat
# Download translations
mkdir -p ./bin/qt6/translations
ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \
| grep "browser_download_url" \
| grep "RPCS3-languages.zip" \
| cut -d '"' -f 4)
if [ -z "$ZIP_URL" ]; then
echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations."
else
echo "Downloading translations from: $ZIP_URL"
curl -L -o translations.zip "$ZIP_URL" || {
echo "Failed to download translations.zip. Continuing without translations."
exit 0
}
unzip -o translations.zip -d "./bin/qt6/translations" >/dev/null 2>&1 || \
echo "Failed to extract translations.zip. Continuing without translations."
rm -f translations.zip
fi
# Download SSL certificate (not needed with CURLSSLOPT_NATIVE_CA) # Download SSL certificate (not needed with CURLSSLOPT_NATIVE_CA)
#curl -fsSL 'https://curl.haxx.se/ca/cacert.pem' 1> ./bin/cacert.pem #curl -fsSL 'https://curl.haxx.se/ca/cacert.pem' 1> ./bin/cacert.pem

View file

@ -12,7 +12,7 @@ pkg info # debug
pkg install "llvm$LLVM_COMPILER_VER" pkg install "llvm$LLVM_COMPILER_VER"
# Mandatory dependencies (qtX-base is pulled via qtX-multimedia) # Mandatory dependencies (qtX-base is pulled via qtX-multimedia)
pkg install git ccache cmake ninja "qt$QT_VER_MAIN-multimedia" "qt$QT_VER_MAIN-svg" glew openal-soft ffmpeg pcre2 pkg install git ccache cmake ninja "qt$QT_VER_MAIN-multimedia" "qt$QT_VER_MAIN-svg" glew openal-soft ffmpeg
# Optional dependencies (libevdev is pulled by qtX-base) # Optional dependencies (libevdev is pulled by qtX-base)
pkg install pkgconf alsa-lib pulseaudio sdl3 evdev-proto vulkan-headers vulkan-loader opencv pkg install pkgconf alsa-lib pulseaudio sdl3 evdev-proto vulkan-headers vulkan-loader opencv

View file

@ -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_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="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_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_11_24H2-${QT_VER_MSVC_UP}-Windows-Windows_11_24H2-X86_64.7z" QT_SUFFIX="-Windows-Windows_11_23H2-${QT_VER_MSVC_UP}-Windows-Windows_11_23H2-X86_64.7z"
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}" 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_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}" QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"

View file

@ -30,23 +30,23 @@ jobs:
matrix: matrix:
include: include:
- os: ubuntu-24.04 - os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.7" docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
build_sh: "/rpcs3/.ci/build-linux.sh" build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang compiler: clang
UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux" UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
- os: ubuntu-24.04 - os: ubuntu-24.04
docker_img: "rpcs3/rpcs3-ci-jammy:1.7" docker_img: "rpcs3/rpcs3-ci-jammy:1.6"
build_sh: "/rpcs3/.ci/build-linux.sh" build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc compiler: gcc
- os: ubuntu-24.04-arm - os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7" docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh" build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang compiler: clang
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1 UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64" UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
- os: ubuntu-24.04-arm - os: ubuntu-24.04-arm
docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.7" docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.6"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh" build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: gcc compiler: gcc
name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
@ -134,9 +134,9 @@ jobs:
runs-on: macos-14 runs-on: macos-14
env: env:
CCACHE_DIR: /tmp/ccache_dir CCACHE_DIR: /tmp/ccache_dir
QT_VER: '6.10.1' QT_VER: '6.7.3'
QT_VER_MAIN: '6' QT_VER_MAIN: '6'
LLVM_COMPILER_VER: '21' LLVM_COMPILER_VER: '19'
RELEASE_MESSAGE: ../GitHubReleaseMessage.txt RELEASE_MESSAGE: ../GitHubReleaseMessage.txt
UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }} UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }}
UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }} UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }}
@ -212,9 +212,9 @@ jobs:
env: env:
COMPILER: msvc COMPILER: msvc
QT_VER_MAIN: '6' QT_VER_MAIN: '6'
QT_VER: '6.10.1' QT_VER: '6.9.3'
QT_VER_MSVC: 'msvc2022' QT_VER_MSVC: 'msvc2022'
QT_DATE: '202511161843' QT_DATE: '202509261208'
LLVM_VER: '19.1.7' LLVM_VER: '19.1.7'
VULKAN_VER: '1.3.268.0' VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5' VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'

2
.gitmodules vendored
View file

@ -21,7 +21,7 @@
ignore = dirty ignore = dirty
[submodule "3rdparty/hidapi"] [submodule "3rdparty/hidapi"]
path = 3rdparty/hidapi/hidapi path = 3rdparty/hidapi/hidapi
url = ../../libusb/hidapi.git url = ../../RPCS3/hidapi.git
branch = master branch = master
ignore = dirty ignore = dirty
[submodule "3rdparty/pugixml"] [submodule "3rdparty/pugixml"]

View file

@ -278,7 +278,7 @@ if(USE_FAUDIO)
target_compile_definitions(FAudio-static INTERFACE -DHAVE_FAUDIO) target_compile_definitions(FAudio-static INTERFACE -DHAVE_FAUDIO)
set(FAUDIO_TARGET FAudio-static) set(FAUDIO_TARGET FAudio-static)
else() else()
message(WARNING message(FATAL_ERROR
"-- RPCS3: 3rdparty FAudio requires SDL 3.2.0 or newer. Since a valid SDL3" "-- RPCS3: 3rdparty FAudio requires SDL 3.2.0 or newer. Since a valid SDL3"
">=3.2.0 version cannot be found, building with FAudio will be skipped.") ">=3.2.0 version cannot be found, building with FAudio will be skipped.")
set(USE_FAUDIO OFF CACHE BOOL "Disabled FAudio with SDL < 3.2.0" FORCE) set(USE_FAUDIO OFF CACHE BOOL "Disabled FAudio with SDL < 3.2.0" FORCE)

2
3rdparty/FAudio vendored

@ -1 +1 @@
Subproject commit 4ea8afea6ba857c24e40877f487d000d559b196d Subproject commit 8a87fdc9242a7b507cf5c96c539334a1760c1ec7

View file

@ -3,7 +3,7 @@ include(ExternalProject)
ExternalProject_Add(moltenvk ExternalProject_Add(moltenvk
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
GIT_TAG 4588705 GIT_TAG 49b97f2
BUILD_IN_SOURCE 1 BUILD_IN_SOURCE 1
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos

@ -1 +1 @@
Subproject commit 0e5e98e4ac8adae92e4f7653dd6eee17aa9c8791 Subproject commit dc7d7054a5b4f3bec1dc23a42fd616a0847af948

View file

@ -49,11 +49,11 @@
<PropertyGroup Label="UserMacros"> <PropertyGroup Label="UserMacros">
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64 <CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft" cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Release" -DCMAKE_INSTALL_PREFIX="./Release" -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DFORCE_STATIC_VCRT=true -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
</CmakeReleaseCLI> </CmakeReleaseCLI>
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64 <CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)" cd "$(SolutionDir)build\tmp\$(ProjectName)-$(Configuration)-$(Platform)"
cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDebug -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft" cmake -G Ninja -DCMAKE_CXX_COMPILER="cl.exe" -DCMAKE_C_COMPILER="cl.exe" -DCMAKE_BUILD_TYPE="Debug" -DCMAKE_INSTALL_PREFIX="./Debug" -DCMAKE_SYSTEM_VERSION=10.0 -DLIBTYPE=STATIC -DALSOFT_UTILS=false -DALSOFT_EXAMPLES=false -DALSOFT_INSTALL=false -DALSOFT_INSTALL_CONFIG=false -DALSOFT_INSTALL_HRTF_DATA=false -DALSOFT_INSTALL_AMBDEC_PRESETS=false -DALSOFT_INSTALL_EXAMPLES=false -DALSOFT_INSTALL_UTILS=false "$(SolutionDir)3rdparty\OpenAL\openal-soft"
</CmakeDebugCLI> </CmakeDebugCLI>
<CmakeCopyCLI> <CmakeCopyCLI>
echo Copying.. echo Copying..
@ -106,4 +106,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets"> <ImportGroup Label="ExtensionTargets">
</ImportGroup> </ImportGroup>
</Project> </Project>

2
3rdparty/curl/curl vendored

@ -1 +1 @@
Subproject commit 400fffa90f30c7a2dc762fa33009d24851bd2016 Subproject commit 11b991232fbcaa88e2b1faecac224416b0001e35

View file

@ -80,12 +80,10 @@
<ClCompile Include="curl\lib\cshutdn.c" /> <ClCompile Include="curl\lib\cshutdn.c" />
<ClCompile Include="curl\lib\curlx\base64.c" /> <ClCompile Include="curl\lib\curlx\base64.c" />
<ClCompile Include="curl\lib\curlx\dynbuf.c" /> <ClCompile Include="curl\lib\curlx\dynbuf.c" />
<ClCompile Include="curl\lib\curlx\fopen.c" />
<ClCompile Include="curl\lib\curlx\inet_ntop.c" /> <ClCompile Include="curl\lib\curlx\inet_ntop.c" />
<ClCompile Include="curl\lib\curlx\inet_pton.c" /> <ClCompile Include="curl\lib\curlx\inet_pton.c" />
<ClCompile Include="curl\lib\curlx\multibyte.c" /> <ClCompile Include="curl\lib\curlx\multibyte.c" />
<ClCompile Include="curl\lib\curlx\nonblock.c" /> <ClCompile Include="curl\lib\curlx\nonblock.c" />
<ClCompile Include="curl\lib\curlx\strerr.c" />
<ClCompile Include="curl\lib\curlx\strparse.c" /> <ClCompile Include="curl\lib\curlx\strparse.c" />
<ClCompile Include="curl\lib\curlx\timediff.c" /> <ClCompile Include="curl\lib\curlx\timediff.c" />
<ClCompile Include="curl\lib\curlx\timeval.c" /> <ClCompile Include="curl\lib\curlx\timeval.c" />
@ -94,9 +92,9 @@
<ClCompile Include="curl\lib\curlx\warnless.c" /> <ClCompile Include="curl\lib\curlx\warnless.c" />
<ClCompile Include="curl\lib\curlx\winapi.c" /> <ClCompile Include="curl\lib\curlx\winapi.c" />
<ClCompile Include="curl\lib\curl_addrinfo.c" /> <ClCompile Include="curl\lib\curl_addrinfo.c" />
<ClCompile Include="curl\lib\curl_des.c" />
<ClCompile Include="curl\lib\curl_endian.c" /> <ClCompile Include="curl\lib\curl_endian.c" />
<ClCompile Include="curl\lib\curl_fnmatch.c" /> <ClCompile Include="curl\lib\curl_fnmatch.c" />
<ClCompile Include="curl\lib\curl_fopen.c" />
<ClCompile Include="curl\lib\curl_gethostname.c" /> <ClCompile Include="curl\lib\curl_gethostname.c" />
<ClCompile Include="curl\lib\curl_get_line.c" /> <ClCompile Include="curl\lib\curl_get_line.c" />
<ClCompile Include="curl\lib\curl_gssapi.c" /> <ClCompile Include="curl\lib\curl_gssapi.c" />
@ -122,6 +120,7 @@
<ClCompile Include="curl\lib\fake_addrinfo.c" /> <ClCompile Include="curl\lib\fake_addrinfo.c" />
<ClCompile Include="curl\lib\file.c" /> <ClCompile Include="curl\lib\file.c" />
<ClCompile Include="curl\lib\fileinfo.c" /> <ClCompile Include="curl\lib\fileinfo.c" />
<ClCompile Include="curl\lib\fopen.c" />
<ClCompile Include="curl\lib\formdata.c" /> <ClCompile Include="curl\lib\formdata.c" />
<ClCompile Include="curl\lib\ftp.c" /> <ClCompile Include="curl\lib\ftp.c" />
<ClCompile Include="curl\lib\ftplistparser.c" /> <ClCompile Include="curl\lib\ftplistparser.c" />
@ -148,6 +147,7 @@
<ClCompile Include="curl\lib\idn.c" /> <ClCompile Include="curl\lib\idn.c" />
<ClCompile Include="curl\lib\if2ip.c" /> <ClCompile Include="curl\lib\if2ip.c" />
<ClCompile Include="curl\lib\imap.c" /> <ClCompile Include="curl\lib\imap.c" />
<ClCompile Include="curl\lib\krb5.c" />
<ClCompile Include="curl\lib\ldap.c" /> <ClCompile Include="curl\lib\ldap.c" />
<ClCompile Include="curl\lib\llist.c" /> <ClCompile Include="curl\lib\llist.c" />
<ClCompile Include="curl\lib\macos.c" /> <ClCompile Include="curl\lib\macos.c" />
@ -159,7 +159,6 @@
<ClCompile Include="curl\lib\mqtt.c" /> <ClCompile Include="curl\lib\mqtt.c" />
<ClCompile Include="curl\lib\multi.c" /> <ClCompile Include="curl\lib\multi.c" />
<ClCompile Include="curl\lib\multi_ev.c" /> <ClCompile Include="curl\lib\multi_ev.c" />
<ClCompile Include="curl\lib\multi_ntfy.c" />
<ClCompile Include="curl\lib\netrc.c" /> <ClCompile Include="curl\lib\netrc.c" />
<ClCompile Include="curl\lib\noproxy.c" /> <ClCompile Include="curl\lib\noproxy.c" />
<ClCompile Include="curl\lib\openldap.c" /> <ClCompile Include="curl\lib\openldap.c" />
@ -204,7 +203,6 @@
<ClCompile Include="curl\lib\version.c" /> <ClCompile Include="curl\lib\version.c" />
<ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" /> <ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" />
<ClCompile Include="curl\lib\vquic\curl_quiche.c" /> <ClCompile Include="curl\lib\vquic\curl_quiche.c" />
<ClCompile Include="curl\lib\vtls\apple.c" />
<ClCompile Include="curl\lib\vtls\cipher_suite.c" /> <ClCompile Include="curl\lib\vtls\cipher_suite.c" />
<ClCompile Include="curl\lib\vtls\hostcheck.c" /> <ClCompile Include="curl\lib\vtls\hostcheck.c" />
<ClCompile Include="curl\lib\vtls\rustls.c" /> <ClCompile Include="curl\lib\vtls\rustls.c" />
@ -227,6 +225,7 @@
<ClCompile Include="curl\lib\vssh\curl_path.c" /> <ClCompile Include="curl\lib\vssh\curl_path.c" />
<ClCompile Include="curl\lib\vssh\libssh.c" /> <ClCompile Include="curl\lib\vssh\libssh.c" />
<ClCompile Include="curl\lib\vssh\libssh2.c" /> <ClCompile Include="curl\lib\vssh\libssh2.c" />
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
<ClCompile Include="curl\lib\vtls\gtls.c" /> <ClCompile Include="curl\lib\vtls\gtls.c" />
<ClCompile Include="curl\lib\vtls\keylog.c" /> <ClCompile Include="curl\lib\vtls\keylog.c" />
<ClCompile Include="curl\lib\vtls\mbedtls.c" /> <ClCompile Include="curl\lib\vtls\mbedtls.c" />
@ -275,12 +274,10 @@
<ClInclude Include="curl\lib\curlx\binmode.h" /> <ClInclude Include="curl\lib\curlx\binmode.h" />
<ClInclude Include="curl\lib\curlx\curlx.h" /> <ClInclude Include="curl\lib\curlx\curlx.h" />
<ClInclude Include="curl\lib\curlx\dynbuf.h" /> <ClInclude Include="curl\lib\curlx\dynbuf.h" />
<ClInclude Include="curl\lib\curlx\fopen.h" />
<ClInclude Include="curl\lib\curlx\inet_ntop.h" /> <ClInclude Include="curl\lib\curlx\inet_ntop.h" />
<ClInclude Include="curl\lib\curlx\inet_pton.h" /> <ClInclude Include="curl\lib\curlx\inet_pton.h" />
<ClInclude Include="curl\lib\curlx\multibyte.h" /> <ClInclude Include="curl\lib\curlx\multibyte.h" />
<ClInclude Include="curl\lib\curlx\nonblock.h" /> <ClInclude Include="curl\lib\curlx\nonblock.h" />
<ClInclude Include="curl\lib\curlx\strerr.h" />
<ClInclude Include="curl\lib\curlx\strparse.h" /> <ClInclude Include="curl\lib\curlx\strparse.h" />
<ClInclude Include="curl\lib\curlx\timediff.h" /> <ClInclude Include="curl\lib\curlx\timediff.h" />
<ClInclude Include="curl\lib\curlx\timeval.h" /> <ClInclude Include="curl\lib\curlx\timeval.h" />
@ -290,13 +287,14 @@
<ClInclude Include="curl\lib\curlx\winapi.h" /> <ClInclude Include="curl\lib\curlx\winapi.h" />
<ClInclude Include="curl\lib\curl_addrinfo.h" /> <ClInclude Include="curl\lib\curl_addrinfo.h" />
<ClInclude Include="curl\lib\curl_ctype.h" /> <ClInclude Include="curl\lib\curl_ctype.h" />
<ClInclude Include="curl\lib\curl_des.h" />
<ClInclude Include="curl\lib\curl_endian.h" /> <ClInclude Include="curl\lib\curl_endian.h" />
<ClInclude Include="curl\lib\curl_fnmatch.h" /> <ClInclude Include="curl\lib\curl_fnmatch.h" />
<ClInclude Include="curl\lib\curl_fopen.h" />
<ClInclude Include="curl\lib\curl_gethostname.h" /> <ClInclude Include="curl\lib\curl_gethostname.h" />
<ClInclude Include="curl\lib\curl_get_line.h" /> <ClInclude Include="curl\lib\curl_get_line.h" />
<ClInclude Include="curl\lib\curl_gssapi.h" /> <ClInclude Include="curl\lib\curl_gssapi.h" />
<ClInclude Include="curl\lib\curl_hmac.h" /> <ClInclude Include="curl\lib\curl_hmac.h" />
<ClInclude Include="curl\lib\curl_krb5.h" />
<ClInclude Include="curl\lib\curl_ldap.h" /> <ClInclude Include="curl\lib\curl_ldap.h" />
<ClInclude Include="curl\lib\curl_md4.h" /> <ClInclude Include="curl\lib\curl_md4.h" />
<ClInclude Include="curl\lib\curl_md5.h" /> <ClInclude Include="curl\lib\curl_md5.h" />
@ -327,6 +325,7 @@
<ClInclude Include="curl\lib\fake_addrinfo.h" /> <ClInclude Include="curl\lib\fake_addrinfo.h" />
<ClInclude Include="curl\lib\file.h" /> <ClInclude Include="curl\lib\file.h" />
<ClInclude Include="curl\lib\fileinfo.h" /> <ClInclude Include="curl\lib\fileinfo.h" />
<ClInclude Include="curl\lib\fopen.h" />
<ClInclude Include="curl\lib\formdata.h" /> <ClInclude Include="curl\lib\formdata.h" />
<ClInclude Include="curl\lib\ftp.h" /> <ClInclude Include="curl\lib\ftp.h" />
<ClInclude Include="curl\lib\ftplistparser.h" /> <ClInclude Include="curl\lib\ftplistparser.h" />
@ -358,7 +357,6 @@
<ClInclude Include="curl\lib\multihandle.h" /> <ClInclude Include="curl\lib\multihandle.h" />
<ClInclude Include="curl\lib\multiif.h" /> <ClInclude Include="curl\lib\multiif.h" />
<ClInclude Include="curl\lib\multi_ev.h" /> <ClInclude Include="curl\lib\multi_ev.h" />
<ClInclude Include="curl\lib\multi_ntfy.h" />
<ClInclude Include="curl\lib\netrc.h" /> <ClInclude Include="curl\lib\netrc.h" />
<ClInclude Include="curl\lib\noproxy.h" /> <ClInclude Include="curl\lib\noproxy.h" />
<ClInclude Include="curl\lib\parsedate.h" /> <ClInclude Include="curl\lib\parsedate.h" />
@ -405,7 +403,6 @@
<ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" /> <ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" />
<ClInclude Include="curl\lib\vquic\curl_quiche.h" /> <ClInclude Include="curl\lib\vquic\curl_quiche.h" />
<ClInclude Include="curl\lib\vquic\vquic_int.h" /> <ClInclude Include="curl\lib\vquic\vquic_int.h" />
<ClInclude Include="curl\lib\vtls\apple.h" />
<ClInclude Include="curl\lib\vtls\cipher_suite.h" /> <ClInclude Include="curl\lib\vtls\cipher_suite.h" />
<ClInclude Include="curl\lib\vtls\hostcheck.h" /> <ClInclude Include="curl\lib\vtls\hostcheck.h" />
<ClInclude Include="curl\lib\vtls\rustls.h" /> <ClInclude Include="curl\lib\vtls\rustls.h" />

View file

@ -42,6 +42,9 @@
<ClCompile Include="curl\lib\curl_addrinfo.c"> <ClCompile Include="curl\lib\curl_addrinfo.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="curl\lib\curl_des.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\curl_endian.c"> <ClCompile Include="curl\lib\curl_endian.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -156,6 +159,9 @@
<ClCompile Include="curl\lib\imap.c"> <ClCompile Include="curl\lib\imap.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="curl\lib\krb5.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\ldap.c"> <ClCompile Include="curl\lib\ldap.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -327,6 +333,9 @@
<ClCompile Include="curl\lib\vssh\libssh2.c"> <ClCompile Include="curl\lib\vssh\libssh2.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="curl\lib\vssh\wolfssh.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\vtls\gtls.c"> <ClCompile Include="curl\lib\vtls\gtls.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -387,6 +396,9 @@
<ClCompile Include="curl\lib\headers.c"> <ClCompile Include="curl\lib\headers.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="curl\lib\fopen.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\noproxy.c"> <ClCompile Include="curl\lib\noproxy.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@ -534,21 +546,6 @@
<ClCompile Include="curl\lib\cf-ip-happy.c"> <ClCompile Include="curl\lib\cf-ip-happy.c">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="curl\lib\curl_fopen.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\multi_ntfy.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\vtls\apple.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\curlx\fopen.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="curl\lib\curlx\strerr.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="curl\include\curl\curl.h"> <ClInclude Include="curl\include\curl\curl.h">
@ -626,6 +623,9 @@
<ClInclude Include="curl\lib\curl_ctype.h"> <ClInclude Include="curl\lib\curl_ctype.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="curl\lib\curl_des.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\curl_endian.h"> <ClInclude Include="curl\lib\curl_endian.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -926,6 +926,9 @@
<ClInclude Include="curl\lib\vtls\keylog.h"> <ClInclude Include="curl\lib\vtls\keylog.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="curl\lib\curl_krb5.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\easyoptions.h"> <ClInclude Include="curl\lib\easyoptions.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -950,6 +953,9 @@
<ClInclude Include="curl\lib\easy_lock.h"> <ClInclude Include="curl\lib\easy_lock.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="curl\lib\fopen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\functypes.h"> <ClInclude Include="curl\lib\functypes.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -1106,21 +1112,6 @@
<ClInclude Include="curl\lib\curl_mem_undef.h"> <ClInclude Include="curl\lib\curl_mem_undef.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="curl\lib\curl_fopen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\multi_ntfy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\vtls\apple.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\curlx\fopen.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="curl\lib\curlx\strerr.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="curl\lib\libcurl.rc"> <ResourceCompile Include="curl\lib\libcurl.rc">

@ -1 +1 @@
Subproject commit 759ac5d698baefca53f1975a0bb1d2dcbdb9f836 Subproject commit 066d4a63b2c714b20b0a8073a01fda7c5c6763f6

@ -1 +1 @@
Subproject commit d6b2a974608dec3b76fb1e36c189f22b9cf3650c Subproject commit f42423643ec9011c98cccc0bb790722bbbd3f30b

@ -1 +1 @@
Subproject commit 49363adcfaf098748d7a4c8c624ad8c45a8c3a86 Subproject commit 2b978915d82377df13fcbb1fb56660195ded868a

@ -1 +1 @@
Subproject commit 7f3ae3d57459e59943a4ecfefc8f6277ec6bf540 Subproject commit a96677bdf6b4acb84af4ec294e5f60a4e8cbbe03

View file

@ -384,6 +384,7 @@
<ClCompile Include="SDL\src\render\opengl\SDL_shaders_gl.c" /> <ClCompile Include="SDL\src\render\opengl\SDL_shaders_gl.c" />
<ClCompile Include="SDL\src\render\opengles2\SDL_render_gles2.c" /> <ClCompile Include="SDL\src\render\opengles2\SDL_render_gles2.c" />
<ClCompile Include="SDL\src\render\opengles2\SDL_shaders_gles2.c" /> <ClCompile Include="SDL\src\render\opengles2\SDL_shaders_gles2.c" />
<ClCompile Include="SDL\src\render\SDL_d3dmath.c" />
<ClCompile Include="SDL\src\render\SDL_render.c" /> <ClCompile Include="SDL\src\render\SDL_render.c" />
<ClCompile Include="SDL\src\render\SDL_render_unsupported.c" /> <ClCompile Include="SDL\src\render\SDL_render_unsupported.c" />
<ClCompile Include="SDL\src\render\SDL_yuv_sw.c" /> <ClCompile Include="SDL\src\render\SDL_yuv_sw.c" />

View file

@ -172,6 +172,9 @@
<Filter Include="render\direct3d12"> <Filter Include="render\direct3d12">
<UniqueIdentifier>{f48c2b17-1bee-4fec-a7c8-24cf619abe08}</UniqueIdentifier> <UniqueIdentifier>{f48c2b17-1bee-4fec-a7c8-24cf619abe08}</UniqueIdentifier>
</Filter> </Filter>
<Filter Include="video\intrin">
<UniqueIdentifier>{653672cc-90ae-4eba-a256-6479f2c31804}</UniqueIdentifier>
</Filter>
<Filter Include="main"> <Filter Include="main">
<UniqueIdentifier>{00001967ea2801028a046a722a070000}</UniqueIdentifier> <UniqueIdentifier>{00001967ea2801028a046a722a070000}</UniqueIdentifier>
</Filter> </Filter>
@ -1457,6 +1460,9 @@
<ClCompile Include="SDL\src\sensor\windows\SDL_windowssensor.c"> <ClCompile Include="SDL\src\sensor\windows\SDL_windowssensor.c">
<Filter>sensor\windows</Filter> <Filter>sensor\windows</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="SDL\src\render\SDL_d3dmath.c">
<Filter>render</Filter>
</ClCompile>
<ClCompile Include="SDL\src\render\SDL_render.c"> <ClCompile Include="SDL\src\render\SDL_render.c">
<Filter>render</Filter> <Filter>render</Filter>
</ClCompile> </ClCompile>

5
3rdparty/qt6.cmake vendored
View file

@ -6,15 +6,14 @@ find_package(Qt6 ${QT_MIN_VER} CONFIG COMPONENTS Widgets Concurrent Multimedia M
if(WIN32) if(WIN32)
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
else() else()
set(QT_NO_PRIVATE_MODULE_WARNING ON) find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui)
find_package(Qt6 ${QT_MIN_VER} COMPONENTS DBus Gui GuiPrivate)
if(Qt6DBus_FOUND) if(Qt6DBus_FOUND)
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::DBus Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS) target_compile_definitions(3rdparty_qt6 INTERFACE -DHAVE_QTDBUS)
else() else()
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets) target_link_libraries(3rdparty_qt6 INTERFACE Qt6::Widgets Qt6::Concurrent Qt6::Multimedia Qt6::MultimediaWidgets Qt6::Svg Qt6::SvgWidgets)
endif() endif()
target_link_libraries(3rdparty_qt6 INTERFACE Qt6::GuiPrivate) target_include_directories(3rdparty_qt6 INTERFACE ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
endif() endif()
if(Qt6Widgets_FOUND) if(Qt6Widgets_FOUND)

View file

@ -10,7 +10,7 @@ else()
option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON) option(ZSTD_BUILD_STATIC "BUILD STATIC LIBRARIES" ON)
option(ZSTD_BUILD_TESTS "BUILD TESTS" OFF) option(ZSTD_BUILD_TESTS "BUILD TESTS" OFF)
add_subdirectory(zstd/build/cmake EXCLUDE_FROM_ALL) add_subdirectory(zstd/build/cmake EXLUDE_FROM_ALL)
add_library(3rdparty_zstd INTERFACE) add_library(3rdparty_zstd INTERFACE)
target_link_libraries(3rdparty_zstd INTERFACE libzstd_static) target_link_libraries(3rdparty_zstd INTERFACE libzstd_static)
endif() endif()

View file

@ -8,38 +8,37 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
### Windows 10 or later ### Windows 10 or later
The following tools are required to build RPCS3 on Windows 10 or later: The following tools are required to build RPCS3 on Windows 10 or later:
- [Visual Studio 2022/2026](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) - [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community)
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH) - **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
**NOTES:** **NOTES:**
- **Visual Studio 2026** needs at least **CMake 4.2.0+**. - **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
- **Visual Studio 2022/2026** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution) See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
on how to build the project with **Visual Studio**. on how to build the project with **Visual Studio**.
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project - Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
with standalone **CMake** tool. with standalone **CMake** tool.
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH) - [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
- [Qt 6.10.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.9.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. - [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. 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: 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. `<QtInstallFolder>\6.10.1\msvc2022_64\` - add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.9.3\msvc2022_64\`
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022) - 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. **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): 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. `<QtInstallFolder>\6.10.1\msvc2022_64\` - add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.9.3\msvc2022_64\`
### Linux ### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager: 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+ - Clang 17+ or GCC 13+
- [CMake 3.28.0+](https://www.cmake.org/download/) - [CMake 3.28.0+](https://www.cmake.org/download/)
- [Qt 6.10.1](https://www.qt.io/download-qt-installer) - [Qt 6.9.3](https://www.qt.io/download-qt-installer)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0. - [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) - [SDL3](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
@ -122,7 +121,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
##### Configuring the Qt Plugin (if used) ##### Configuring the Qt Plugin (if used)
1) go to `Extensions->Qt VS Tools->Qt Versions` 1) go to `Extensions->Qt VS Tools->Qt Versions`
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.10.1\msvc2022_64`, version will fill in automatically 2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.9.3\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**) 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**) 4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)

View file

@ -133,7 +133,7 @@ if(MSVC)
endif() endif()
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8) if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
message(FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms.") message( FATAL_ERROR "RPCS3 can only be compiled on 64-bit platforms." )
endif() endif()
if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64") if(APPLE AND CMAKE_OSX_ARCHITECTURES STREQUAL "arm64")

View file

@ -166,55 +166,6 @@ bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max)
return true; 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<usz>(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<std::string> cfg::make_float_range(f64 min, f64 max) std::vector<std::string> cfg::make_float_range(f64 min, f64 max)
{ {
return {std::to_string(min), std::to_string(max)}; return {std::to_string(min), std::to_string(max)};
@ -327,19 +278,6 @@ bool cfg::try_to_enum_value(u64* out, decltype(&fmt_class_string<int>::format) f
return true; 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<u64>(value >> (i * 4)) % 16];
}
return result;
}
std::vector<std::string> cfg::try_to_enum_list(decltype(&fmt_class_string<int>::format) func) std::vector<std::string> cfg::try_to_enum_list(decltype(&fmt_class_string<int>::format) func)
{ {
std::vector<std::string> result; std::vector<std::string> result;

View file

@ -38,7 +38,6 @@ namespace cfg
_enum, // cfg::_enum type _enum, // cfg::_enum type
_int, // cfg::_int type _int, // cfg::_int type
uint, // cfg::uint type uint, // cfg::uint type
uint128, // cfg::uint128 type
string, // cfg::string type string, // cfg::string type
set, // cfg::set_entry type set, // cfg::set_entry type
map, // cfg::map_entry type map, // cfg::map_entry type
@ -579,86 +578,6 @@ namespace cfg
// Alias for 64 bit int // Alias for 64 bit int
using uint64 = uint<0, u64{umax}>; using uint64 = uint<0, u64{umax}>;
// Unsigned 128-bit integer entry.
class uint128 final : public _base
{
using int_type = u128;
atomic_t<int_type> 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<ullong>(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<std::string> to_list() const override
{
// Should not be used
return make_uint_range(0, 1);
}
};
// Simple string entry with mutex // Simple string entry with mutex
class string : public _base class string : public _base
{ {

View file

@ -658,11 +658,7 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
std::string result; std::string result;
auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context); auto null_mod = std::make_unique<llvm::Module> ("null_", *m_context);
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple1()));
#else
null_mod->setTargetTriple(jit_compiler::triple1()); null_mod->setTargetTriple(jit_compiler::triple1());
#endif
std::unique_ptr<llvm::RTDyldMemoryManager> mem; std::unique_ptr<llvm::RTDyldMemoryManager> mem;
@ -676,11 +672,7 @@ jit_compiler::jit_compiler(const std::unordered_map<std::string, u64>& _link, co
else else
{ {
mem = std::make_unique<MemoryManager2>(std::move(symbols_cement)); mem = std::make_unique<MemoryManager2>(std::move(symbols_cement));
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
null_mod->setTargetTriple(llvm::Triple(jit_compiler::triple2()));
#else
null_mod->setTargetTriple(jit_compiler::triple2()); null_mod->setTargetTriple(jit_compiler::triple2());
#endif
} }
} }
else else

View file

@ -394,7 +394,7 @@ namespace fmt
} }
#if !defined(_MSC_VER) || defined(__clang__) #if !defined(_MSC_VER) || defined(__clang__)
[[noreturn]] ~throw_exception() = default; [[noreturn]] ~throw_exception();
#endif #endif
}; };

View file

@ -28,9 +28,6 @@ bool try_to_int64(s64* out, std::string_view value, s64 min, s64 max);
// Convert string to unsigned integer // Convert string to unsigned integer
bool try_to_uint64(u64* out, std::string_view value, u64 min, u64 max); 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 // Convert string to float
bool try_to_float(f64* out, std::string_view value, f64 min, f64 max); bool try_to_float(f64* out, std::string_view value, f64 min, f64 max);

View file

@ -106,11 +106,6 @@ thread_local u64 g_tls_wait_fail = 0;
thread_local bool g_tls_access_violation_recovered = false; thread_local bool g_tls_access_violation_recovered = false;
extern thread_local std::string(*g_tls_log_prefix)(); extern thread_local std::string(*g_tls_log_prefix)();
namespace stx
{
atomic_t<u32> g_launch_retainer{0};
}
// Report error and call std::abort(), defined in main.cpp // Report error and call std::abort(), defined in main.cpp
[[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true); [[noreturn]] void report_fatal_error(std::string_view text, bool is_html = false, bool include_help_text = true);

View file

@ -465,8 +465,6 @@ public:
namespace stx namespace stx
{ {
struct launch_retainer; struct launch_retainer;
extern atomic_t<u32> g_launch_retainer;
} }
// Derived from the callable object Context, possibly a lambda // Derived from the callable object Context, possibly a lambda
@ -483,11 +481,6 @@ class named_thread final : public Context, result_storage<Context>, thread_base
u64 entry_point2() u64 entry_point2()
{ {
while (u32 value = stx::g_launch_retainer)
{
stx::g_launch_retainer.wait(value);
}
thread::initialize([]() thread::initialize([]()
{ {
if constexpr (!result::empty) if constexpr (!result::empty)

View file

@ -1,27 +0,0 @@
#pragma once
// Generic deferred routine wrapper
// Use-case is similar to "defer" statement in other languages, just invokes a callback when the object goes out of scope
#include <functional>
namespace utils
{
template <typename F>
requires std::is_invocable_v<F>
class deferred_op
{
public:
deferred_op(F&& callback)
: m_callback(callback)
{}
~deferred_op()
{
m_callback();
}
private:
F m_callback;
};
}

View file

@ -201,7 +201,7 @@ QPushButton::disabled {
/* QSpinBox (Settings -> Emulator -> width/height) */ /* QSpinBox (Settings -> Emulator -> width/height) */
/* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */ /* QDoubleSpinBox (Pads -> Mouse Acceleration -> x/y) */
QSpinBox, QDoubleSpinBox { QSpinBox, QDoubleSpinBox {
height: 1.50em; height: 0.1em;
background-color: #b3ac98; background-color: #b3ac98;
} }
QSpinBox::disabled, QDoubleSpinBox::disabled { QSpinBox::disabled, QDoubleSpinBox::disabled {

View file

@ -5,6 +5,7 @@ if(MSVC)
add_compile_definitions( add_compile_definitions(
_CRT_SECURE_NO_DEPRECATE=1 _CRT_NON_CONFORMING_SWPRINTFS=1 _SCL_SECURE_NO_WARNINGS=1 _CRT_SECURE_NO_DEPRECATE=1 _CRT_NON_CONFORMING_SWPRINTFS=1 _SCL_SECURE_NO_WARNINGS=1
NOMINMAX _ENABLE_EXTENDED_ALIGNED_STORAGE=1 _HAS_EXCEPTIONS=0) NOMINMAX _ENABLE_EXTENDED_ALIGNED_STORAGE=1 _HAS_EXCEPTIONS=0)
add_link_options(/DYNAMICBASE)
#TODO: Some of these could be cleaned up #TODO: Some of these could be cleaned up
add_compile_options(/wd4805) # Comparing boolean and int add_compile_options(/wd4805) # Comparing boolean and int

View file

@ -66,7 +66,7 @@ else ()
find_package_handle_standard_args(FFMPEG find_package_handle_standard_args(FFMPEG
DEFAULT_MSG DEFAULT_MSG
FFMPEG_LIBAVCODEC FFMPEG_LIBAVFORMAT FFMPEG_LIBAVUTIL FFMPEG_LIBSWSCALE FFMPEG_LIBSWRESAMPLE FFMPEG_LIBAVCODEC FFMPEG_LIBAVFORMAT FFMPEG_LIBSWSCALE FFMPEG_LIBSWRESAMPLE
) )
if (FFMPEG_FOUND) if (FFMPEG_FOUND)

View file

@ -25,7 +25,6 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <charconv> #include <charconv>
#include <string_view>
std::string to_hex(std::uint64_t value, bool prfx = true) std::string to_hex(std::uint64_t value, bool prfx = true)
{ {
@ -86,7 +85,7 @@ int main(int argc, char* argv[])
// Decode address and try to find the object // Decode address and try to find the object
std::uint64_t addr = -1; std::uint64_t addr = -1;
std::from_chars(arg.data() + ("--start-address=0x"sv).size(), arg.data() + arg.size(), addr, 16); std::from_chars(arg.data() + strlen("--start-address=0x"), arg.data() + arg.size(), addr, 16);
for (int j = 0; j < 0x100'0000; j++) for (int j = 0; j < 0x100'0000; j++)
{ {

View file

@ -10,6 +10,16 @@ include(CheckFunctionExists)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(ADDITIONAL_LIBS "")
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
#on some Linux distros shm_unlink and similar functions are in librt only
list(APPEND ADDITIONAL_LIBS "rt")
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
#it seems like glibc includes the iconv functions we use but other libc
#implementations like the one on OSX don't seem implement them
list(APPEND ADDITIONAL_LIBS "iconv")
endif()
if(UNIX AND NOT APPLE AND NOT ANDROID) if(UNIX AND NOT APPLE AND NOT ANDROID)
add_compile_definitions(DATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3") add_compile_definitions(DATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
# Optionally enable X11 for window management # Optionally enable X11 for window management
@ -68,16 +78,8 @@ if (NOT ANDROID)
3rdparty::libcurl 3rdparty::libcurl
3rdparty::zlib 3rdparty::zlib
3rdparty::opencv 3rdparty::opencv
3rdparty::fusion) 3rdparty::fusion
${ADDITIONAL_LIBS})
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
#on some Linux distros shm_unlink and similar functions are in librt only
target_link_libraries(rpcs3_lib PRIVATE rt)
elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
#it seems like glibc includes the iconv functions we use but other libc
#implementations like the one on OSX don't seem implement them
target_link_libraries(rpcs3_lib PRIVATE iconv)
endif()
# Unix display manager # Unix display manager
if(X11_FOUND) if(X11_FOUND)
@ -104,16 +106,19 @@ if (NOT ANDROID)
endif() endif()
# Build rpcs3 executable # Build rpcs3 executable
add_executable(rpcs3 WIN32 MACOSX_BUNDLE)
if(WIN32) if(WIN32)
add_executable(rpcs3 WIN32)
target_sources(rpcs3 PRIVATE rpcs3.rc) target_sources(rpcs3 PRIVATE rpcs3.rc)
target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE) target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE)
elseif(APPLE) elseif(APPLE)
add_executable(rpcs3 MACOSX_BUNDLE)
target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh) target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh)
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set_target_properties(rpcs3 set_target_properties(rpcs3
PROPERTIES PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in") MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
else()
add_executable(rpcs3)
endif() endif()
target_sources(rpcs3 target_sources(rpcs3
@ -132,12 +137,17 @@ if (NOT ANDROID)
# Copy icons to executable directory # Copy icons to executable directory
if(APPLE) if(APPLE)
if (CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
set(QT_DEPLOY_FLAGS "-no-strip")
else()
set(QT_DEPLOY_FLAGS "")
endif()
qt_finalize_target(rpcs3) qt_finalize_target(rpcs3)
add_custom_command(TARGET rpcs3 POST_BUILD add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "$<$<CONFIG:Debug,RelWithDebInfo>:-no-strip>") COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
elseif(UNIX) elseif(UNIX)
add_custom_command(TARGET rpcs3 POST_BUILD add_custom_command(TARGET rpcs3 POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
@ -188,11 +198,8 @@ if(BUILD_RPCS3_TESTS)
PRIVATE PRIVATE
tests/test.cpp tests/test.cpp
tests/test_fmt.cpp tests/test_fmt.cpp
tests/test_pair.cpp
tests/test_tuple.cpp
tests/test_simple_array.cpp tests/test_simple_array.cpp
tests/test_address_range.cpp tests/test_address_range.cpp
tests/test_rsx_cfg.cpp
) )
target_link_libraries(rpcs3_test target_link_libraries(rpcs3_test

View file

@ -11,10 +11,10 @@ SELF_KEY::SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::str
version_end = ver_end; version_end = ver_end;
revision = rev; revision = rev;
self_type = type; self_type = type;
hex_to_bytes(erk, e, 0); hex_to_bytes(erk, e.c_str(), 0);
hex_to_bytes(riv, r, 0); hex_to_bytes(riv, r.c_str(), 0);
hex_to_bytes(pub, pb, 0); hex_to_bytes(pub, pb.c_str(), 0);
hex_to_bytes(priv, pr, 0); hex_to_bytes(priv, pr.c_str(), 0);
curve_type = ct; curve_type = ct;
} }

View file

@ -7,11 +7,9 @@
#include "sha1.h" #include "sha1.h"
#include "sha256.h" #include "sha256.h"
#include "key_vault.h" #include "key_vault.h"
#include <charconv>
#include <cstdlib>
#include <cstring> #include <cstring>
#include <cstdio> #include <stdio.h>
#include <ctime> #include <time.h>
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
#include "Utilities/File.h" #include "Utilities/File.h"
@ -23,24 +21,50 @@
// Auxiliary functions (endian swap, xor). // Auxiliary functions (endian swap, xor).
// Hex string conversion auxiliary functions. // Hex string conversion auxiliary functions.
void hex_to_bytes(unsigned char* data, std::string_view hex_str, unsigned int str_length) u64 hex_to_u64(const char* hex_str)
{ {
const auto strn_length = (str_length > 0) ? str_length : hex_str.size(); auto length = std::strlen(hex_str);
u64 tmp = 0;
u64 result = 0;
char c;
while (length--)
{
c = *hex_str++;
if((c >= '0') && (c <= '9'))
tmp = c - '0';
else if((c >= 'a') && (c <= 'f'))
tmp = c - 'a' + 10;
else if((c >= 'A') && (c <= 'F'))
tmp = c - 'A' + 10;
else
tmp = 0;
result |= (tmp << (length * 4));
}
return result;
}
void hex_to_bytes(unsigned char* data, const char* hex_str, unsigned int str_length)
{
const auto strn_length = (str_length > 0) ? str_length : std::strlen(hex_str);
auto data_length = strn_length / 2;
char tmp_buf[3] = {0, 0, 0};
// Don't convert if the string length is odd. // Don't convert if the string length is odd.
if ((strn_length % 2) == 0) if ((strn_length % 2) == 0)
{ {
for (size_t i = 0; i < strn_length; i += 2) while (data_length--)
{ {
const auto [ptr, err] = std::from_chars(hex_str.data() + i, hex_str.data() + i + 2, *data++, 16); tmp_buf[0] = *hex_str++;
if (err != std::errc()) tmp_buf[1] = *hex_str++;
{
fmt::throw_exception("Failed to read hex string: %s", std::make_error_code(err).message()); *data++ = static_cast<u8>(hex_to_u64(tmp_buf) & 0xFF);
}
} }
} }
} }
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC). // Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len) void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len)
{ {
@ -157,7 +181,7 @@ std::array<u8, PASSPHRASE_KEY_LEN> sc_combine_laid_paid(s64 laid, s64 paid)
{ {
const std::string paid_laid = fmt::format("%016llx%016llx", laid, paid); const std::string paid_laid = fmt::format("%016llx%016llx", laid, paid);
std::array<u8, PASSPHRASE_KEY_LEN> out{}; std::array<u8, PASSPHRASE_KEY_LEN> out{};
hex_to_bytes(out.data(), paid_laid, PASSPHRASE_KEY_LEN * 2); hex_to_bytes(out.data(), paid_laid.c_str(), PASSPHRASE_KEY_LEN * 2);
return out; return out;
} }

View file

@ -6,8 +6,7 @@
#include "util/types.hpp" #include "util/types.hpp"
#include <cstdlib> #include <stdlib.h>
#include <string_view>
enum { CRYPTO_MAX_PATH = 4096 }; enum { CRYPTO_MAX_PATH = 4096 };
@ -16,7 +15,8 @@ char* extract_file_name(const char* file_path, char real_file_name[CRYPTO_MAX_PA
std::string sha256_get_hash(const char* data, usz size, bool lower_case); std::string sha256_get_hash(const char* data, usz size, bool lower_case);
// Hex string conversion auxiliary functions. // Hex string conversion auxiliary functions.
void hex_to_bytes(unsigned char* data, std::string_view hex_str, unsigned int str_length); u64 hex_to_u64(const char* hex_str);
void hex_to_bytes(unsigned char *data, const char *hex_str, unsigned int str_length);
// Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC). // Crypto functions (AES128-CBC, AES128-ECB, SHA1-HMAC and AES-CMAC).
void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len); void aescbc128_decrypt(unsigned char *key, unsigned char *iv, unsigned char *in, unsigned char *out, usz len);

View file

@ -52,6 +52,6 @@ namespace audio
g_cfg.audio.volume.set(std::clamp<s32>(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max)); g_cfg.audio.volume.set(std::clamp<s32>(new_volume, g_cfg.audio.volume.min, g_cfg.audio.volume.max));
Emu.GetCallbacks().update_emu_settings(); Emu.GetCallbacks().update_emu_settings();
rsx::overlays::queue_message(localized_string(localized_string_id::AUDIO_CHANGED, "%d%%", g_cfg.audio.volume.get()), 3'000'000, {}, rsx::overlays::message_pin_location::top_left, {}, true, true); 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 } // namespace audio

View file

@ -402,7 +402,6 @@ target_sources(rpcs3_emu PRIVATE
Io/GunCon3.cpp Io/GunCon3.cpp
Io/Infinity.cpp Io/Infinity.cpp
Io/interception.cpp Io/interception.cpp
Io/KamenRider.cpp
Io/KeyboardHandler.cpp Io/KeyboardHandler.cpp
Io/midi_config_types.cpp Io/midi_config_types.cpp
Io/mouse_config.cpp Io/mouse_config.cpp
@ -516,7 +515,6 @@ target_sources(rpcs3_emu PRIVATE
RSX/Overlays/overlay_video.cpp RSX/Overlays/overlay_video.cpp
RSX/Overlays/Shaders/shader_loading_dialog.cpp RSX/Overlays/Shaders/shader_loading_dialog.cpp
RSX/Overlays/Shaders/shader_loading_dialog_native.cpp RSX/Overlays/Shaders/shader_loading_dialog_native.cpp
RSX/Program/Assembler/FPToCFG.cpp
RSX/Program/CgBinaryProgram.cpp RSX/Program/CgBinaryProgram.cpp
RSX/Program/CgBinaryFragmentProgram.cpp RSX/Program/CgBinaryFragmentProgram.cpp
RSX/Program/CgBinaryVertexProgram.cpp RSX/Program/CgBinaryVertexProgram.cpp
@ -579,7 +577,6 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/vkutils/buffer_object.cpp RSX/VK/vkutils/buffer_object.cpp
RSX/VK/vkutils/chip_class.cpp RSX/VK/vkutils/chip_class.cpp
RSX/VK/vkutils/commands.cpp RSX/VK/vkutils/commands.cpp
RSX/VK/vkutils/ex.cpp
RSX/VK/vkutils/data_heap.cpp RSX/VK/vkutils/data_heap.cpp
RSX/VK/vkutils/descriptors.cpp RSX/VK/vkutils/descriptors.cpp
RSX/VK/vkutils/image.cpp RSX/VK/vkutils/image.cpp
@ -592,7 +589,6 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/vkutils/device.cpp RSX/VK/vkutils/device.cpp
RSX/VK/vkutils/sampler.cpp RSX/VK/vkutils/sampler.cpp
RSX/VK/vkutils/shared.cpp RSX/VK/vkutils/shared.cpp
RSX/VK/vkutils/unique_resource.cpp
RSX/VK/VKAsyncScheduler.cpp RSX/VK/VKAsyncScheduler.cpp
RSX/VK/VKCommandStream.cpp RSX/VK/VKCommandStream.cpp
RSX/VK/VKCommonDecompiler.cpp RSX/VK/VKCommonDecompiler.cpp

View file

@ -190,7 +190,7 @@ struct cpu_prof
reservation_samples = 0; reservation_samples = 0;
} }
static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, u32 type_id, bool extended_print = false) static std::string format(const std::multimap<u64, u64, std::greater<u64>>& chart, u64 samples, u64 idle, bool extended_print = false)
{ {
// Print results // Print results
std::string results; std::string results;
@ -204,18 +204,11 @@ struct cpu_prof
const f64 _frac = count / busy / samples; const f64 _frac = count / busy / samples;
// Print only 7 hash characters out of 11 (which covers roughly 48 bits) // Print only 7 hash characters out of 11 (which covers roughly 48 bits)
if (type_id == 2) fmt::append(results, "\n\t[%s", fmt::base57(be_t<u64>{name}));
{ results.resize(results.size() - 4);
fmt::append(results, "\n\t[%s", fmt::base57(be_t<u64>{name}));
results.resize(results.size() - 4);
// Print chunk address from lowest 16 bits // Print chunk address from lowest 16 bits
fmt::append(results, "...chunk-0x%05x]: %.4f%% (%u)", (name & 0xffff) * 4, _frac * 100., count); fmt::append(results, "...chunk-0x%05x]: %.4f%% (%u)", (name & 0xffff) * 4, _frac * 100., count);
}
else
{
fmt::append(results, "\n\t[0x%07x]: %.4f%% (%u)", name, _frac * 100., count);
}
if (results.size() >= (extended_print ? 10000 : 5000)) if (results.size() >= (extended_print ? 10000 : 5000))
{ {
@ -264,37 +257,27 @@ struct cpu_prof
} }
// Print results // Print results
const std::string results = format(chart, samples, idle, ptr->id_type()); const std::string results = format(chart, samples, idle);
profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):\n%s", ptr->get_name(), ptr->id, samples, get_percent(idle, samples), new_samples, reservation_samples, get_percent(reservation_samples, samples - idle), results); profiler.notice("Thread \"%s\" [0x%08x]: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):\n%s", ptr->get_name(), ptr->id, samples, get_percent(idle, samples), new_samples, reservation_samples, get_percent(reservation_samples, samples - idle), results);
new_samples = 0; new_samples = 0;
} }
static void print_all(std::unordered_map<shared_ptr<cpu_thread>, sample_info>& threads, sample_info& all_info, u32 type_id) static void print_all(std::unordered_map<shared_ptr<cpu_thread>, sample_info>& threads, sample_info& all_info)
{ {
u64 new_samples = 0; u64 new_samples = 0;
// Print all results and cleanup // Print all results and cleanup
for (auto& [ptr, info] : threads) for (auto& [ptr, info] : threads)
{ {
if (ptr->id_type() != type_id)
{
continue;
}
new_samples += info.new_samples; new_samples += info.new_samples;
info.print(ptr); info.print(ptr);
} }
std::multimap<u64, u64, std::greater<u64>> chart; std::multimap<u64, u64, std::greater<u64>> chart;
for (auto& [ptr, info] : threads) for (auto& [_, info] : threads)
{ {
if (ptr->id_type() != type_id)
{
continue;
}
// This function collects thread information regardless of 'new_samples' member state // This function collects thread information regardless of 'new_samples' member state
for (auto& [name, count] : info.freq) for (auto& [name, count] : info.freq)
{ {
@ -318,7 +301,7 @@ struct cpu_prof
if (new_samples < min_print_all_samples && thread_ctrl::state() != thread_state::aborting) if (new_samples < min_print_all_samples && thread_ctrl::state() != thread_state::aborting)
{ {
profiler.notice("All %s Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", type_id == 1 ? "PPU" : "SPU", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle)); profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%): Not enough new samples have been collected since the last print.", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle));
return; return;
} }
@ -327,13 +310,12 @@ struct cpu_prof
chart.emplace(count, name); chart.emplace(count, name);
} }
const std::string results = format(chart, samples, idle, type_id, true); const std::string results = format(chart, samples, idle, true);
profiler.notice("All %s Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", type_id == 1 ? "PPU" : "SPU", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle), results); profiler.notice("All Threads: %u samples (%.4f%% idle), %u new, %u reservation (%.4f%%):%s", samples, get_percent(idle, samples), new_samples, reservation, get_percent(reservation, samples - idle), results);
} }
}; };
sample_info all_spu_threads_info{}; sample_info all_threads_info{};
sample_info all_ppu_threads_info{};
void operator()() void operator()()
{ {
@ -394,11 +376,8 @@ struct cpu_prof
{ {
if (auto state = +ptr->state; cpu_flag::exit - state) if (auto state = +ptr->state; cpu_flag::exit - state)
{ {
const auto spu = ptr->try_get<spu_thread>();
const auto ppu = ptr->try_get<ppu_thread>();
// Get short function hash // Get short function hash
const u64 name = ppu ? atomic_storage<u32>::load(ppu->cia) : atomic_storage<u64>::load(ptr->block_hash); const u64 name = atomic_storage<u64>::load(ptr->block_hash);
// Append occurrence // Append occurrence
info.samples++; info.samples++;
@ -408,17 +387,17 @@ struct cpu_prof
info.freq[name]++; info.freq[name]++;
info.new_samples++; info.new_samples++;
if (spu) if (auto spu = ptr->try_get<spu_thread>())
{ {
if (spu->raddr) if (spu->raddr)
{ {
info.reservation_samples++; info.reservation_samples++;
} }
// Append verification time to fixed common name 0000000...chunk-0x3fffc
if (name >> 16 && (name & 0xffff) == 0)
info.freq[0xffff]++;
} }
// Append verification time to fixed common name 0000000...chunk-0x3fffc
if (name >> 16 && (name & 0xffff) == 0)
info.freq[0xffff]++;
} }
else else
{ {
@ -441,10 +420,8 @@ struct cpu_prof
{ {
profiler.success("Flushing profiling results..."); profiler.success("Flushing profiling results...");
all_ppu_threads_info = {}; all_threads_info = {};
all_spu_threads_info = {}; sample_info::print_all(threads, all_threads_info);
sample_info::print_all(threads, all_ppu_threads_info, 1);
sample_info::print_all(threads, all_spu_threads_info, 2);
} }
if (Emu.IsPaused()) if (Emu.IsPaused())
@ -465,8 +442,7 @@ struct cpu_prof
} }
// Print all remaining results // Print all remaining results
sample_info::print_all(threads, all_ppu_threads_info, 1); sample_info::print_all(threads, all_threads_info);
sample_info::print_all(threads, all_spu_threads_info, 2);
} }
static constexpr auto thread_name = "CPU Profiler"sv; static constexpr auto thread_name = "CPU Profiler"sv;
@ -483,7 +459,7 @@ extern f64 get_cpu_program_usage_percent(u64 hash)
{ {
u64 total = 0; u64 total = 0;
for (auto [name, count] : prof->all_spu_threads_info.freq) for (auto [name, count] : prof->all_threads_info.freq)
{ {
if ((name & -65536) == hash) if ((name & -65536) == hash)
{ {
@ -496,7 +472,7 @@ extern f64 get_cpu_program_usage_percent(u64 hash)
return 0; return 0;
} }
return std::max<f64>(0.0001, static_cast<f64>(total) * 100 / (prof->all_spu_threads_info.samples - prof->all_spu_threads_info.idle)); return std::max<f64>(0.0001, static_cast<f64>(total) * 100 / (prof->all_threads_info.samples - prof->all_threads_info.idle));
} }
} }
@ -663,22 +639,27 @@ void cpu_thread::operator()()
thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(get_class())); thread_ctrl::set_thread_affinity_mask(thread_ctrl::get_affinity_mask(get_class()));
} }
ensure(g_fxo->is_init<cpu_profiler>()); while (!g_fxo->is_init<cpu_profiler>())
{
if (Emu.IsStopped())
{
return;
}
// Can we have a little race, right? First thread is started concurrently with g_fxo->init()
thread_ctrl::wait_for(1000);
}
switch (get_class()) switch (get_class())
{ {
case thread_class::ppu: case thread_class::ppu:
{ {
if (g_cfg.core.ppu_prof) //g_fxo->get<cpu_profiler>().registered.push(id);
{
g_fxo->get<cpu_profiler>().registered.push(id);
}
break; break;
} }
case thread_class::spu: case thread_class::spu:
{ {
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) if (g_cfg.core.spu_prof)
{ {
g_fxo->get<cpu_profiler>().registered.push(id); g_fxo->get<cpu_profiler>().registered.push(id);
} }
@ -1565,7 +1546,7 @@ void cpu_thread::flush_profilers() noexcept
return; return;
} }
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug || g_cfg.core.ppu_prof) if (g_cfg.core.spu_prof)
{ {
g_fxo->get<cpu_profiler>().registered.push(0); g_fxo->get<cpu_profiler>().registered.push(0);
} }
@ -1604,30 +1585,22 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu) idm::select<named_thread<spu_thread>>([&](u32 id, spu_thread& spu)
{ {
if (give_up) spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
{
return;
}
if (spu.current_func && spu.unsavable && !force_collect) if (spu.current_func && spu.unsavable)
{ {
const u64 start = spu.start_time; const u64 start = spu.start_time;
// Automatically give up if it is asleep 5 seconds or more // Automatically give up if it is asleep 15 seconds or more
if (start && current > start && current - start >= 5'000'000) if (start && current > start && current - start >= 15'000'000)
{ {
give_up = true; give_up = true;
return;
} }
} }
spu_list.emplace_back(ensure(idm::get_unlocked<named_thread<spu_thread>>(id)));
}); });
if (give_up) if (!force_collect && give_up)
{ {
spu_list.clear();
old_counter = umax;
return decltype(&spu_list){}; return decltype(&spu_list){};
} }
@ -1652,7 +1625,6 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
} }
else if (get_system_time() - start >= 150'000) else if (get_system_time() - start >= 150'000)
{ {
std::this_thread::sleep_for(1ms);
passed_count++; passed_count++;
start = 0; start = 0;
continue; continue;
@ -1664,29 +1636,37 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
if (!spu_list) if (!spu_list)
{ {
// Give up for now // Give up for now
std::this_thread::sleep_for(50ms); std::this_thread::sleep_for(10ms);
passed_count++; passed_count++;
start = 0; start = 0;
continue; continue;
} }
// Avoid using suspend_all when more than 2 threads known to be unsavable // Avoid using suspend_all when more than 2 threads known to be unsavable
u32 savable_threads = 0; u32 unsavable_threads = 0;
for (auto& spu : *spu_list) for (auto& spu : *spu_list)
{ {
if (!spu->unsavable) if (spu->unsavable)
{ {
savable_threads++; unsavable_threads++;
if (unsavable_threads >= 3)
{
break;
}
} }
} }
if (!savable_threads) if (unsavable_threads >= 3)
{ {
std::this_thread::yield(); std::this_thread::yield();
continue; continue;
} }
// Flag for optimization
bool paused_anyone = false;
if (cpu_thread::suspend_all(nullptr, {}, [&]() if (cpu_thread::suspend_all(nullptr, {}, [&]()
{ {
if (!get_spus(false, true)) if (!get_spus(false, true))
@ -1715,13 +1695,19 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
break; break;
} }
} }
else
{
paused_anyone = true;
ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause));
}
} }
for (auto& spu : *spu_list) if (failed && paused_anyone)
{ {
if (!failed && !is_emu_paused) // For faster signalling, first remove state flags then batch notifications
for (auto& spu : *spu_list)
{ {
ensure(!spu->state.test_and_set(cpu_flag::dbg_global_pause)); spu->state -= cpu_flag::dbg_global_pause;
} }
} }
@ -1733,6 +1719,13 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
return false; return false;
} }
if (!paused_anyone)
{
// Need not do anything
std::this_thread::yield();
continue;
}
for (auto& spu : *spu_list) for (auto& spu : *spu_list)
{ {
if (spu->state & cpu_flag::wait) if (spu->state & cpu_flag::wait)
@ -1762,7 +1755,7 @@ extern bool try_lock_spu_threads_in_a_state_compatible_with_savestates(bool reve
{ {
spu->state.notify_one(); spu->state.notify_one();
} }
} };
return false; return false;
} }

View file

@ -4007,7 +4007,7 @@ llvm::CallInst* llvm_asm(
const std::string& constraints, const std::string& constraints,
llvm::LLVMContext& context) llvm::LLVMContext& context)
{ {
llvm::ArrayRef<llvm::Type*> types_ref {}; llvm::ArrayRef<llvm::Type*> types_ref = std::nullopt;
std::vector<llvm::Type*> types; std::vector<llvm::Type*> types;
types.reserve(args.size()); types.reserve(args.size());

View file

@ -111,41 +111,7 @@ void AtracXdecDecoder::alloc_avcodec()
fmt::throw_exception("avcodec_find_decoder() failed"); fmt::throw_exception("avcodec_find_decoder() failed");
} }
packet = av_packet_alloc(); ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES));
if (!packet)
{
fmt::throw_exception("av_packet_alloc() failed");
}
frame = av_frame_alloc();
if (!frame)
{
fmt::throw_exception("av_frame_alloc() failed");
}
}
void AtracXdecDecoder::free_avcodec()
{
if (packet)
{
av_packet_free(&packet);
}
if (frame)
{
av_frame_free(&frame);
}
if (ctx)
{
avcodec_free_context(&ctx);
}
}
void AtracXdecDecoder::init_avcodec()
{
if (ctx)
{
avcodec_free_context(&ctx);
}
ctx = avcodec_alloc_context3(codec); ctx = avcodec_alloc_context3(codec);
if (!ctx) if (!ctx)
@ -167,6 +133,34 @@ void AtracXdecDecoder::init_avcodec()
frame->buf[0] = av_buffer_create(frame->data[0], ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * frame->ch_layout.nb_channels, [](void*, uint8_t*){}, nullptr, 0); frame->buf[0] = av_buffer_create(frame->data[0], ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * frame->ch_layout.nb_channels, [](void*, uint8_t*){}, nullptr, 0);
return 0; return 0;
}; };
packet = av_packet_alloc();
if (!packet)
{
fmt::throw_exception("av_packet_alloc() failed");
}
frame = av_frame_alloc();
if (!frame)
{
fmt::throw_exception("av_frame_alloc() failed");
}
}
void AtracXdecDecoder::free_avcodec()
{
av_packet_free(&packet);
av_frame_free(&frame);
avcodec_free_context(&ctx);
}
void AtracXdecDecoder::init_avcodec()
{
if (int err = avcodec_close(ctx); err)
{
fmt::throw_exception("avcodec_close() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
}
ctx->block_align = nbytes; ctx->block_align = nbytes;
ctx->ch_layout.nb_channels = nch_in; ctx->ch_layout.nb_channels = nch_in;
ctx->sample_rate = sampling_freq; ctx->sample_rate = sampling_freq;

View file

@ -192,10 +192,10 @@ struct AtracXdecDecoder
// HLE exclusive // HLE exclusive
b8 config_is_set = false; // For savestates b8 config_is_set = false; // For savestates
const AVCodec* codec = nullptr; const AVCodec* codec;
AVCodecContext* ctx = nullptr; AVCodecContext* ctx;
AVPacket* packet = nullptr; AVPacket* packet;
AVFrame* frame = nullptr; AVFrame* frame;
u8 spurs_stuff[84]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc. u8 spurs_stuff[84]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.

View file

@ -1139,10 +1139,8 @@ error_code cellCameraGetBufferInfo(s32 dev_num, vm::ptr<CellCameraInfo> info)
return CELL_OK; return CELL_OK;
} }
error_code cellCameraGetBufferInfoEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellCameraInfoEx> info) error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info)
{ {
ppu.state += cpu_flag::wait;
cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info); cellCamera.notice("cellCameraGetBufferInfoEx(dev_num=%d, info=0x%x)", dev_num, info);
// calls cellCameraGetBufferInfo // calls cellCameraGetBufferInfo
@ -1153,16 +1151,10 @@ error_code cellCameraGetBufferInfoEx(ppu_thread& ppu, s32 dev_num, vm::ptr<CellC
} }
auto& g_camera = g_fxo->get<camera_thread>(); auto& g_camera = g_fxo->get<camera_thread>();
std::lock_guard lock(g_camera.mutex);
CellCameraInfoEx info_out; *info = g_camera.info;
{
std::lock_guard lock(g_camera.mutex);
info_out = g_camera.info;
}
*info = info_out;
return CELL_OK; return CELL_OK;
} }

View file

@ -464,8 +464,6 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
{ {
get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR; get->isNewData = CELL_HDDGAME_ISNEWDATA_NODIR;
get->getParam = {}; get->getParam = {};
cellGame.warning("cellHddGameCheck(): New data.");
} }
else else
{ {
@ -478,22 +476,13 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
if (psf.contains("RESOLUTION")) get->getParam.resolution = ::at32(psf, "RESOLUTION").as_integer(); if (psf.contains("RESOLUTION")) get->getParam.resolution = ::at32(psf, "RESOLUTION").as_integer();
if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = ::at32(psf, "SOUND_FORMAT").as_integer(); if (psf.contains("SOUND_FORMAT")) get->getParam.soundFormat = ::at32(psf, "SOUND_FORMAT").as_integer();
if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, ::at32(psf, "TITLE").as_string()); if (psf.contains("TITLE")) strcpy_trunc(get->getParam.title, ::at32(psf, "TITLE").as_string());
if (psf.contains("APP_VER")) strcpy_trunc(get->getParam.dataVersion, ::at32(psf, "APP_VER").as_string());
// Old games do not have APP_VER key if (psf.contains("TITLE_ID")) strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
strcpy_trunc(get->getParam.dataVersion, psf::get_string(psf, "APP_VER", psf::get_string(sfo, "VERSION", "")));
if (psf.contains("TITLE_ID"))
{
strcpy_trunc(get->getParam.titleId, ::at32(psf, "TITLE_ID").as_string());
}
for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++) for (u32 i = 0; i < CELL_HDDGAME_SYSP_LANGUAGE_NUM; i++)
{ {
strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i))); strcpy_trunc(get->getParam.titleLang[i], psf::get_string(psf, fmt::format("TITLE_%02d", i)));
} }
cellGame.warning("cellHddGameCheck(): Data exists:\nATTRIBUTE: 0x%x, RESOLUTION: 0x%x, RESOLUTION: 0x%x, SOUND_FORMAT: 0x%x, dataVersion: %s"
, get->getParam.attribute, get->getParam.resolution, get->getParam.soundFormat, get->getParam.soundFormat, std::span<const u8>(reinterpret_cast<const u8*>(get->getParam.dataVersion), 6));
} }
// TODO ? // TODO ?
@ -561,7 +550,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
case CELL_HDDGAME_CBRESULT_ERR_NOSPACE: case CELL_HDDGAME_CBRESULT_ERR_NOSPACE:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB); cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", result->errNeedSizeKB);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, "%d", result->errNeedSizeKB); error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_NOSPACE, fmt::format("%d", result->errNeedSizeKB).c_str());
break; break;
case CELL_HDDGAME_CBRESULT_ERR_BROKEN: case CELL_HDDGAME_CBRESULT_ERR_BROKEN:
@ -576,12 +565,12 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
case CELL_HDDGAME_CBRESULT_ERR_INVALID: case CELL_HDDGAME_CBRESULT_ERR_INVALID:
cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg); cellGame.error("cellHddGameCheck(): callback returned CELL_HDDGAME_CBRESULT_ERR_INVALID. Error message: %s", result->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg); error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str());
break; break;
default: default:
cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg); cellGame.error("cellHddGameCheck(): callback returned unknown error (code=0x%x). Error message: %s", result->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, "%s", result->invalidMsg); error_msg = get_localized_string(localized_string_id::CELL_HDD_GAME_CHECK_INVALID, fmt::format("%s", result->invalidMsg).c_str());
break; break;
} }
@ -1180,7 +1169,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
} }
case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE: case CELL_GAMEDATA_CBRESULT_ERR_NOSPACE:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", cbResult->errNeedSizeKB); cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_NOSPACE. Space Needed: %d KB", cbResult->errNeedSizeKB);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, "%d", cbResult->errNeedSizeKB); error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_NOSPACE, fmt::format("%d", cbResult->errNeedSizeKB).c_str());
break; break;
case CELL_GAMEDATA_CBRESULT_ERR_BROKEN: case CELL_GAMEDATA_CBRESULT_ERR_BROKEN:
@ -1195,12 +1184,12 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
case CELL_GAMEDATA_CBRESULT_ERR_INVALID: case CELL_GAMEDATA_CBRESULT_ERR_INVALID:
cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID. Error message: %s", cbResult->invalidMsg); cellGame.error("cellGameDataCheckCreate2(): callback returned CELL_GAMEDATA_CBRESULT_ERR_INVALID. Error message: %s", cbResult->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg); error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str());
break; break;
default: default:
cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg); cellGame.error("cellGameDataCheckCreate2(): callback returned unknown error (code=0x%x). Error message: %s", cbResult->invalidMsg);
error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, "%s", cbResult->invalidMsg); error_msg = get_localized_string(localized_string_id::CELL_GAMEDATA_CHECK_INVALID, fmt::format("%s", cbResult->invalidMsg).c_str());
break; break;
} }
@ -1697,7 +1686,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
break; break;
case CELL_GAME_ERRDIALOG_NOSPACE: case CELL_GAME_ERRDIALOG_NOSPACE:
// Not enough available space. The application will continue. // Not enough available space. The application will continue.
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE, "%d", errNeedSizeKB); error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE, fmt::format("%d", errNeedSizeKB).c_str());
break; break;
case CELL_GAME_ERRDIALOG_BROKEN_EXIT_GAMEDATA: case CELL_GAME_ERRDIALOG_BROKEN_EXIT_GAMEDATA:
// Game data is corrupted. The application will be terminated. // Game data is corrupted. The application will be terminated.
@ -1709,7 +1698,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
break; break;
case CELL_GAME_ERRDIALOG_NOSPACE_EXIT: case CELL_GAME_ERRDIALOG_NOSPACE_EXIT:
// Not enough available space. The application will be terminated. // Not enough available space. The application will be terminated.
error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE_EXIT, "%d", errNeedSizeKB); error_msg = get_localized_string(localized_string_id::CELL_GAME_ERROR_NOSPACE_EXIT, fmt::format("%d", errNeedSizeKB).c_str());
break; break;
default: default:
return CELL_GAME_ERROR_PARAM; return CELL_GAME_ERROR_PARAM;
@ -1723,7 +1712,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
} }
error_msg += '\n'; error_msg += '\n';
error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, "%s", dirName); error_msg += get_localized_string(localized_string_id::CELL_GAME_ERROR_DIR_NAME, fmt::format("%s", dirName).c_str());
} }
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame); return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame);

View file

@ -224,8 +224,8 @@ enum
struct CellGameDataSystemFileParam struct CellGameDataSystemFileParam
{ {
char title[CELL_GAMEDATA_SYSP_TITLE_SIZE]; char title[CELL_GAMEDATA_SYSP_TITLE_SIZE];
char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE]; // 0x80 char titleLang[CELL_GAMEDATA_SYSP_LANGUAGE_NUM][CELL_GAMEDATA_SYSP_TITLE_SIZE];
char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE]; // 0xA80 char titleId[CELL_GAMEDATA_SYSP_TITLEID_SIZE];
char reserved0[2]; char reserved0[2];
char dataVersion[CELL_GAMEDATA_SYSP_VERSION_SIZE]; char dataVersion[CELL_GAMEDATA_SYSP_VERSION_SIZE];
char reserved1[2]; char reserved1[2];
@ -248,13 +248,13 @@ struct CellGameDataStatGet
{ {
be_t<s32> hddFreeSizeKB; be_t<s32> hddFreeSizeKB;
be_t<u32> isNewData; be_t<u32> isNewData;
char contentInfoPath[CELL_GAMEDATA_PATH_MAX]; // 0x8 char contentInfoPath[CELL_GAMEDATA_PATH_MAX];
char gameDataPath[CELL_GAMEDATA_PATH_MAX]; // 0x427 char gameDataPath[CELL_GAMEDATA_PATH_MAX];
char reserved0[2]; // 0x846 char reserved0[2];
be_t<s64> st_atime_; // 0x848 be_t<s64> st_atime_;
be_t<s64> st_mtime_; // 0x850 be_t<s64> st_mtime_;
be_t<s64> st_ctime_; // 0x858 be_t<s64> st_ctime_;
CellGameDataSystemFileParam getParam; // 0x860 CellGameDataSystemFileParam getParam;
be_t<s32> sizeKB; be_t<s32> sizeKB;
be_t<s32> sysSizeKB; be_t<s32> sysSizeKB;
char reserved1[68]; char reserved1[68];

View file

@ -361,7 +361,7 @@ public:
case move_handler::mouse: case move_handler::mouse:
case move_handler::raw_mouse: case move_handler::raw_mouse:
{ {
auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>()); auto& handler = g_fxo->get<MouseHandlerBase>();
std::lock_guard mouse_lock(handler.mutex); std::lock_guard mouse_lock(handler.mutex);
const MouseInfo& info = handler.GetInfo(); const MouseInfo& info = handler.GetInfo();
@ -374,7 +374,7 @@ public:
#ifdef HAVE_LIBEVDEV #ifdef HAVE_LIBEVDEV
case move_handler::gun: case move_handler::gun:
{ {
gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>()); gun_thread& gun = g_fxo->get<gun_thread>();
std::scoped_lock lock(gun.handler.mutex); std::scoped_lock lock(gun.handler.mutex);
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
@ -505,7 +505,7 @@ public:
case move_handler::mouse: case move_handler::mouse:
case move_handler::raw_mouse: case move_handler::raw_mouse:
{ {
auto& handler = *ensure(g_fxo->try_get<MouseHandlerBase>()); auto& handler = g_fxo->get<MouseHandlerBase>();
std::lock_guard mouse_lock(handler.mutex); std::lock_guard mouse_lock(handler.mutex);
// Make sure that the mouse handler is initialized // Make sure that the mouse handler is initialized
@ -522,7 +522,7 @@ public:
#ifdef HAVE_LIBEVDEV #ifdef HAVE_LIBEVDEV
case move_handler::gun: case move_handler::gun:
{ {
gun_thread& gun = *ensure(g_fxo->try_get<gun_thread>()); gun_thread& gun = g_fxo->get<gun_thread>();
std::scoped_lock lock(gun.handler.mutex); std::scoped_lock lock(gun.handler.mutex);
gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0; gun.num_devices = gun.handler.init() ? gun.handler.get_num_guns() : 0;
connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices); connected_controllers = std::min<u32>(std::min<u32>(attribute.max_connect, CELL_GEM_MAX_NUM), gun.num_devices);
@ -2284,8 +2284,6 @@ error_code cellGemClearStatusFlags(u32 gem_num, u64 mask)
error_code cellGemConvertVideoFinish(ppu_thread& ppu) error_code cellGemConvertVideoFinish(ppu_thread& ppu)
{ {
ppu.state += cpu_flag::wait;
cellGem.warning("cellGemConvertVideoFinish()"); cellGem.warning("cellGemConvertVideoFinish()");
auto& gem = g_fxo->get<gem_config>(); auto& gem = g_fxo->get<gem_config>();
@ -2308,10 +2306,8 @@ error_code cellGemConvertVideoFinish(ppu_thread& ppu)
return CELL_OK; return CELL_OK;
} }
error_code cellGemConvertVideoStart(ppu_thread& ppu, vm::cptr<void> video_frame) error_code cellGemConvertVideoStart(vm::cptr<void> video_frame)
{ {
ppu.state += cpu_flag::wait;
cellGem.warning("cellGemConvertVideoStart(video_frame=*0x%x)", video_frame); cellGem.warning("cellGemConvertVideoStart(video_frame=*0x%x)", video_frame);
auto& gem = g_fxo->get<gem_config>(); auto& gem = g_fxo->get<gem_config>();
@ -2463,8 +2459,6 @@ error_code cellGemEnableMagnetometer2(u32 gem_num, u32 enable)
error_code cellGemEnd(ppu_thread& ppu) error_code cellGemEnd(ppu_thread& ppu)
{ {
ppu.state += cpu_flag::wait;
cellGem.warning("cellGemEnd()"); cellGem.warning("cellGemEnd()");
auto& gem = g_fxo->get<gem_config>(); auto& gem = g_fxo->get<gem_config>();
@ -3269,7 +3263,7 @@ error_code cellGemPrepareCamera(s32 max_exposure, f32 image_quality)
extern error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2); extern error_code cellCameraGetAttribute(s32 dev_num, s32 attrib, vm::ptr<u32> arg1, vm::ptr<u32> arg2);
extern error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2); extern error_code cellCameraSetAttribute(s32 dev_num, s32 attrib, u32 arg1, u32 arg2);
extern error_code cellCameraGetBufferInfoEx(ppu_thread&, s32 dev_num, vm::ptr<CellCameraInfoEx> info); extern error_code cellCameraGetBufferInfoEx(s32 dev_num, vm::ptr<CellCameraInfoEx> info);
vm::var<CellCameraInfoEx> info = vm::make_var<CellCameraInfoEx>({}); vm::var<CellCameraInfoEx> info = vm::make_var<CellCameraInfoEx>({});
vm::var<u32> arg1 = vm::make_var<u32>({}); vm::var<u32> arg1 = vm::make_var<u32>({});
@ -3277,7 +3271,7 @@ error_code cellGemPrepareCamera(s32 max_exposure, f32 image_quality)
cellCameraGetAttribute(0, 0x3e6, arg1, arg2); cellCameraGetAttribute(0, 0x3e6, arg1, arg2);
cellCameraSetAttribute(0, 0x3e6, 0x3e, *arg2 | 0x80); cellCameraSetAttribute(0, 0x3e6, 0x3e, *arg2 | 0x80);
cellCameraGetBufferInfoEx(*cpu_thread::get_current<ppu_thread>(), 0, info); cellCameraGetBufferInfoEx(0, info);
if (info->width == 640) if (info->width == 640)
{ {
@ -3609,8 +3603,6 @@ error_code cellGemTrackHues(vm::cptr<u32> req_hues, vm::ptr<u32> res_hues)
error_code cellGemUpdateFinish(ppu_thread& ppu) error_code cellGemUpdateFinish(ppu_thread& ppu)
{ {
ppu.state += cpu_flag::wait;
cellGem.warning("cellGemUpdateFinish()"); cellGem.warning("cellGemUpdateFinish()");
auto& gem = g_fxo->get<gem_config>(); auto& gem = g_fxo->get<gem_config>();

View file

@ -2498,7 +2498,7 @@ s32 UCS2stoSBCSs(vm::cptr<u16> src, vm::ptr<u32> src_len, vm::ptr<u8> dst, vm::p
for (u32 src_pos = 0; src_pos < *src_len; src_pos++) for (u32 src_pos = 0; src_pos < *src_len; src_pos++)
{ {
const u16 ucs2 = src[src_pos]; const s16 ucs2 = src[src_pos];
if (ucs2 >= 0xfffe) if (ucs2 >= 0xfffe)
{ {

View file

@ -506,7 +506,7 @@ error_code cellMsgDialogOpenErrorCode(u32 errorCode, vm::ptr<CellMsgDialogCallba
default: string_id = localized_string_id::CELL_MSG_DIALOG_ERROR_DEFAULT; break; // An error has occurred. default: string_id = localized_string_id::CELL_MSG_DIALOG_ERROR_DEFAULT; break; // An error has occurred.
} }
const std::string error = get_localized_string(string_id, "%08x", errorCode); const std::string error = get_localized_string(string_id, fmt::format("%08x", errorCode).c_str());
return cellMsgDialogOpen2(CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(error), callback, userData, extParam); return cellMsgDialogOpen2(CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(error), callback, userData, extParam);
} }

View file

@ -575,12 +575,12 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
if (setting & CELL_PAD_SETTING_PRESS_ON) if (setting & CELL_PAD_SETTING_PRESS_ON)
{ {
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_PRESS_ON) - static_cast<u32>(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16); constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_PRESS_ON - 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); std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_DIGITAL1], &output.button[CELL_PAD_BTN_OFFSET_DIGITAL1], copy_size);
} }
else else
{ {
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_DEFAULT) - static_cast<u32>(CELL_PAD_BTN_OFFSET_DIGITAL1)) * sizeof(u16); constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_DEFAULT - 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); 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 // Clear area if setting is not used
@ -590,7 +590,7 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON) if (data->len == CELL_PAD_LEN_CHANGE_SENSOR_ON)
{ {
constexpr u32 copy_size = (static_cast<u32>(CELL_PAD_LEN_CHANGE_SENSOR_ON) - static_cast<u32>(CELL_PAD_BTN_OFFSET_SENSOR_X)) * sizeof(u16); constexpr u32 copy_size = (CELL_PAD_LEN_CHANGE_SENSOR_ON - 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); std::memcpy(&data->button[CELL_PAD_BTN_OFFSET_SENSOR_X], &output.button[CELL_PAD_BTN_OFFSET_SENSOR_X], copy_size);
} }
} }
@ -1051,15 +1051,7 @@ error_code cellPadSetPortSetting(u32 port_no, u32 port_setting)
if (port_no >= CELL_PAD_MAX_PORT_NUM) if (port_no >= CELL_PAD_MAX_PORT_NUM)
return CELL_OK; return CELL_OK;
if (port_setting & CELL_PAD_SETTING_PRESS_ON) config.port_setting[port_no] = port_setting;
config.port_setting[port_no] |= CELL_PAD_SETTING_PRESS_ON;
else
config.port_setting[port_no] &= ~CELL_PAD_SETTING_PRESS_ON;
if (port_setting & CELL_PAD_SETTING_SENSOR_ON)
config.port_setting[port_no] |= CELL_PAD_SETTING_SENSOR_ON;
else
config.port_setting[port_no] &= ~CELL_PAD_SETTING_SENSOR_ON;
// can also return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD <- Update: seems to be just internal and ignored // can also return CELL_PAD_ERROR_UNSUPPORTED_GAMEPAD <- Update: seems to be just internal and ignored
@ -1131,7 +1123,7 @@ error_code cellPadSetPressMode(u32 port_no, u32 mode)
if (!config.max_connect) if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
if (port_no >= CELL_MAX_PADS || mode > 1) if (port_no >= CELL_PAD_MAX_PORT_NUM)
return CELL_PAD_ERROR_INVALID_PARAMETER; return CELL_PAD_ERROR_INVALID_PARAMETER;
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case. // CELL_PAD_ERROR_NO_DEVICE is not returned in this case.
@ -1165,7 +1157,7 @@ error_code cellPadSetSensorMode(u32 port_no, u32 mode)
if (!config.max_connect) if (!config.max_connect)
return CELL_PAD_ERROR_UNINITIALIZED; return CELL_PAD_ERROR_UNINITIALIZED;
if (port_no >= CELL_MAX_PADS || mode > 1) if (port_no >= CELL_MAX_PADS)
return CELL_PAD_ERROR_INVALID_PARAMETER; return CELL_PAD_ERROR_INVALID_PARAMETER;
// CELL_PAD_ERROR_NO_DEVICE is not returned in this case. // CELL_PAD_ERROR_NO_DEVICE is not returned in this case.

View file

@ -396,7 +396,7 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
switch (result.result) switch (result.result)
{ {
case CELL_SAVEDATA_CBRESULT_ERR_NOSPACE: case CELL_SAVEDATA_CBRESULT_ERR_NOSPACE:
msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_NO_SPACE, "%d", result.errNeedSizeKB); msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_NO_SPACE, fmt::format("%d", result.errNeedSizeKB).c_str());
break; break;
case CELL_SAVEDATA_CBRESULT_ERR_FAILURE: case CELL_SAVEDATA_CBRESULT_ERR_FAILURE:
msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_FAILURE); msg = get_localized_string(localized_string_id::CELL_SAVEDATA_CB_FAILURE);

View file

@ -1230,7 +1230,7 @@ s32 _spurs::initialize(ppu_thread& ppu, vm::ptr<CellSpurs> spurs, u32 revision,
if (flags & SAF_UNKNOWN_FLAG_9) spuTgAttr->type |= 0x0800; if (flags & SAF_UNKNOWN_FLAG_9) spuTgAttr->type |= 0x0800;
if (flags & SAF_SYSTEM_WORKLOAD_ENABLED) spuTgAttr->type |= SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM; if (flags & SAF_SYSTEM_WORKLOAD_ENABLED) spuTgAttr->type |= SYS_SPU_THREAD_GROUP_TYPE_COOPERATE_WITH_SYSTEM;
if (s32 rc = sys_spu_thread_group_create(ppu, spurs.ptr(&CellSpurs::spuTG), nSpus, spuPriority, vm::unsafe_ptr_cast<reduced_sys_spu_thread_group_attribute>(spuTgAttr))) if (s32 rc = sys_spu_thread_group_create(ppu, spurs.ptr(&CellSpurs::spuTG), nSpus, spuPriority, spuTgAttr))
{ {
ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg)); ppu_execute<&sys_spu_image_close>(ppu, spurs.ptr(&CellSpurs::spuImg));
return rollback(), rc; return rollback(), rc;

View file

@ -3198,7 +3198,7 @@ error_code sceNpLookupTerm()
error_code sceNpLookupCreateTitleCtx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> selfNpId) error_code sceNpLookupCreateTitleCtx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> selfNpId)
{ {
sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? std::string_view(communicationId->data, 9) : "", selfNpId); sceNp.warning("sceNpLookupCreateTitleCtx(communicationId=*0x%x(%s), selfNpId=0x%x)", communicationId, communicationId ? communicationId->data : "", selfNpId);
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();
@ -3930,8 +3930,8 @@ error_code sceNpManagerGetMyLanguages(vm::ptr<SceNpMyLanguages> myLanguages)
return SCE_NP_ERROR_INVALID_STATE; return SCE_NP_ERROR_INVALID_STATE;
} }
myLanguages->language1 = g_cfg.sys.language; myLanguages->language1 = SCE_NP_LANG_ENGLISH_US;
myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? CELL_SYSUTIL_LANG_ENGLISH_US : -1; myLanguages->language2 = g_cfg.sys.language != CELL_SYSUTIL_LANG_ENGLISH_US ? g_cfg.sys.language : -1;
myLanguages->language3 = -1; myLanguages->language3 = -1;
return CELL_OK; return CELL_OK;
@ -3968,7 +3968,7 @@ error_code sceNpManagerGetAccountRegion(vm::ptr<SceNpCountryCode> countryCode, v
ensure(ccode.size() == sizeof(SceNpCountryCode::data)); ensure(ccode.size() == sizeof(SceNpCountryCode::data));
std::memcpy(countryCode->data, ccode.data(), sizeof(SceNpCountryCode::data)); std::memcpy(countryCode->data, ccode.data(), sizeof(SceNpCountryCode::data));
*language = g_cfg.sys.language; *language = CELL_SYSUTIL_LANG_ENGLISH_US;
return CELL_OK; return CELL_OK;
} }
@ -6962,7 +6962,7 @@ error_code sceNpSignalingGetConnectionFromPeerAddress(u32 ctx_id, np_in_addr_t p
return CELL_OK; return CELL_OK;
} }
error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetInfoDeprecated> info) error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetInfo> info)
{ {
sceNp.warning("sceNpSignalingGetLocalNetInfo(ctx_id=%d, info=*0x%x)", ctx_id, info); sceNp.warning("sceNpSignalingGetLocalNetInfo(ctx_id=%d, info=*0x%x)", ctx_id, info);
@ -6973,8 +6973,7 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetIn
return SCE_NP_SIGNALING_ERROR_NOT_INITIALIZED; return SCE_NP_SIGNALING_ERROR_NOT_INITIALIZED;
} }
// Library has backward support for a version of SceNpSignalingNetInfo without npport if (!info || info->size != sizeof(SceNpSignalingNetInfo))
if (!info || (info->size != sizeof(SceNpSignalingNetInfo) && info->size != sizeof(SceNpSignalingNetInfoDeprecated)))
{ {
return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT; return SCE_NP_SIGNALING_ERROR_INVALID_ARGUMENT;
} }
@ -6986,12 +6985,7 @@ error_code sceNpSignalingGetLocalNetInfo(u32 ctx_id, vm::ptr<SceNpSignalingNetIn
info->nat_status = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2; info->nat_status = SCE_NP_SIGNALING_NETINFO_NAT_STATUS_TYPE2;
info->upnp_status = nph.get_upnp_status(); info->upnp_status = nph.get_upnp_status();
info->npport_status = SCE_NP_SIGNALING_NETINFO_NPPORT_STATUS_OPEN; info->npport_status = SCE_NP_SIGNALING_NETINFO_NPPORT_STATUS_OPEN;
info->npport = SCE_NP_PORT;
if (info->size == sizeof(SceNpSignalingNetInfo))
{
auto new_info = vm::unsafe_ptr_cast<SceNpSignalingNetInfo>(info);
new_info->npport = SCE_NP_PORT;
}
return CELL_OK; return CELL_OK;
} }

View file

@ -1584,16 +1584,6 @@ struct SceNpSignalingNetInfo
be_t<u16> npport; be_t<u16> npport;
}; };
struct SceNpSignalingNetInfoDeprecated
{
be_t<u32> size;
be_t<u32> local_addr; // in_addr
be_t<u32> mapped_addr; // in_addr
be_t<s32> nat_status;
be_t<s32> upnp_status;
be_t<s32> npport_status;
};
struct SceNpCustomMenuAction struct SceNpCustomMenuAction
{ {
be_t<u32> options; be_t<u32> options;

View file

@ -1300,7 +1300,7 @@ error_code sceNpMatching2GrantRoomOwner(
error_code sceNpMatching2CreateContext( error_code sceNpMatching2CreateContext(
vm::cptr<SceNpId> npId, vm::cptr<SceNpCommunicationId> commId, vm::cptr<SceNpCommunicationPassphrase> passPhrase, vm::ptr<SceNpMatching2ContextId> ctxId, s32 option) vm::cptr<SceNpId> npId, vm::cptr<SceNpCommunicationId> commId, vm::cptr<SceNpCommunicationPassphrase> passPhrase, vm::ptr<SceNpMatching2ContextId> ctxId, s32 option)
{ {
sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? std::string_view(commId->data, 9) : "", passPhrase, ctxId, option); sceNp2.warning("sceNpMatching2CreateContext(npId=*0x%x, commId=*0x%x(%s), passPhrase=*0x%x, ctxId=*0x%x, option=%d)", npId, commId, commId ? commId->data : "", passPhrase, ctxId, option);
auto& nph = g_fxo->get<named_thread<np::np_handler>>(); auto& nph = g_fxo->get<named_thread<np::np_handler>>();

View file

@ -3,6 +3,7 @@
#include "util/types.hpp" #include "util/types.hpp"
#include "Emu/Memory/vm_ptr.h" #include "Emu/Memory/vm_ptr.h"
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include <mutex>
#include <vector> #include <vector>
#include <mutex> #include <mutex>

View file

@ -221,7 +221,7 @@ std::pair<PPUDisAsm::const_op, u64> PPUDisAsm::try_get_const_op_gpr_value(u32 re
GET_CONST_REG(reg_rs, op.rs); GET_CONST_REG(reg_rs, op.rs);
return {form, std::rotl<u64>(reg_rs, op.sh64) & (~0ull << (op.mbe64 ^ 63))}; return { form, utils::rol64(reg_rs, op.sh64) & (~0ull << (op.mbe64 ^ 63)) };
} }
case ppu_itype::OR: case ppu_itype::OR:
{ {

View file

@ -3483,7 +3483,7 @@ auto RLWIMI()
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32); const u64 mask = ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & mask); ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & mask);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3497,7 +3497,7 @@ auto RLWINM()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); ppu.gpr[op.ra] = dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), op.sh32)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3511,7 +3511,7 @@ auto RLWNM()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = dup32(std::rotl<u32>(static_cast<u32>(ppu.gpr[op.rs]), ppu.gpr[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32); ppu.gpr[op.ra] = dup32(utils::rol32(static_cast<u32>(ppu.gpr[op.rs]), ppu.gpr[op.rb] & 0x1f)) & ppu_rotate_mask(32 + op.mb32, 32 + op.me32);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3599,7 +3599,7 @@ auto RLDICL()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64); ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull >> op.mbe64);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3613,7 +3613,7 @@ auto RLDICR()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63)); ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & (~0ull << (op.mbe64 ^ 63));
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3627,7 +3627,7 @@ auto RLDIC()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], op.sh64) & ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3642,7 +3642,7 @@ auto RLDIMI()
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63); const u64 mask = ppu_rotate_mask(op.mbe64, op.sh64 ^ 63);
ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (std::rotl<u64>(ppu.gpr[op.rs], op.sh64) & mask); ppu.gpr[op.ra] = (ppu.gpr[op.ra] & ~mask) | (utils::rol64(ppu.gpr[op.rs], op.sh64) & mask);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3656,7 +3656,7 @@ auto RLDCL()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64); ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull >> op.mbe64);
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };
@ -3670,7 +3670,7 @@ auto RLDCR()
return ppu_exec_select<Flags...>::template select<>(); return ppu_exec_select<Flags...>::template select<>();
static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) { static const auto exec = [](ppu_thread& ppu, ppu_opcode_t op) {
ppu.gpr[op.ra] = std::rotl<u64>(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63)); ppu.gpr[op.ra] = utils::rol64(ppu.gpr[op.rs], ppu.gpr[op.rb] & 0x3f) & (~0ull << (op.mbe64 ^ 63));
if constexpr (((Flags == has_rc) || ...)) if constexpr (((Flags == has_rc) || ...))
ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0); ppu_cr_set<s64>(ppu, 0, ppu.gpr[op.ra], 0);
}; };

View file

@ -832,9 +832,6 @@ extern void ppu_register_function_at(u32 addr, u32 size, ppu_intrp_func_t ptr =
return; return;
} }
size = utils::align<u32>(size + addr % 4, 4);
addr &= -4;
// Initialize interpreter cache // Initialize interpreter cache
while (size) while (size)
{ {
@ -2311,7 +2308,7 @@ void ppu_thread::cpu_sleep()
raddr = 0; raddr = 0;
// Setup wait flag and memory flags to relock itself // Setup wait flag and memory flags to relock itself
state += cpu_flag::wait + cpu_flag::memory; state += g_use_rtm ? cpu_flag::wait : cpu_flag::wait + cpu_flag::memory;
if (auto ptr = vm::g_tls_locked) if (auto ptr = vm::g_tls_locked)
{ {
@ -2457,8 +2454,10 @@ ppu_thread::ppu_thread(const ppu_thread_params& param, std::string_view name, u3
// Trigger the scheduler // Trigger the scheduler
state += cpu_flag::suspend; state += cpu_flag::suspend;
// Acquire memory passive lock if (!g_use_rtm)
state += cpu_flag::memory; {
state += cpu_flag::memory;
}
call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1); call_history.data.resize(g_cfg.core.ppu_call_history ? call_history_max_size : 1);
syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1); syscall_history.data.resize(g_cfg.core.ppu_call_history ? syscall_history_max_size : 1);
@ -2704,7 +2703,11 @@ ppu_thread::ppu_thread(utils::serial& ar)
// Trigger the scheduler // Trigger the scheduler
state += cpu_flag::suspend; state += cpu_flag::suspend;
state += cpu_flag::memory;
if (!g_use_rtm)
{
state += cpu_flag::memory;
}
ppu_tname = make_single<std::string>(ar.pop<std::string>()); ppu_tname = make_single<std::string>(ar.pop<std::string>());
@ -3188,6 +3191,221 @@ extern u64 ppu_ldarx(ppu_thread& ppu, u32 addr)
return ppu_load_acquire_reservation<u64>(ppu, addr); return ppu_load_acquire_reservation<u64>(ppu, addr);
} }
const auto ppu_stcx_accurate_tx = build_function_asm<u64(*)(u32 raddr, u64 rtime, const void* _old, u64 _new)>("ppu_stcx_accurate_tx", [](native_asm& c, auto& args)
{
using namespace asmjit;
#if defined(ARCH_X64)
Label fall = c.newLabel();
Label fail = c.newLabel();
Label _ret = c.newLabel();
Label load = c.newLabel();
//if (utils::has_avx() && !s_tsx_avx)
//{
// c.vzeroupper();
//}
// Create stack frame if necessary (Windows ABI has only 6 volatile vector registers)
c.push(x86::rbp);
c.push(x86::r13);
c.push(x86::r14);
c.sub(x86::rsp, 48);
#ifdef _WIN32
if (!s_tsx_avx)
{
c.movups(x86::oword_ptr(x86::rsp, 0), x86::xmm6);
c.movups(x86::oword_ptr(x86::rsp, 16), x86::xmm7);
}
#endif
// Prepare registers
build_swap_rdx_with(c, args, x86::r10);
c.movabs(x86::rbp, reinterpret_cast<u64>(&vm::g_sudo_addr));
c.mov(x86::rbp, x86::qword_ptr(x86::rbp));
c.lea(x86::rbp, x86::qword_ptr(x86::rbp, args[0]));
c.and_(x86::rbp, -128);
c.prefetchw(x86::byte_ptr(x86::rbp, 0));
c.prefetchw(x86::byte_ptr(x86::rbp, 64));
c.movzx(args[0].r32(), args[0].r16());
c.shr(args[0].r32(), 1);
c.movabs(x86::r11, reinterpret_cast<u64>(+vm::g_reservations));
c.lea(x86::r11, x86::qword_ptr(x86::r11, args[0]));
c.and_(x86::r11, -128 / 2);
c.and_(args[0].r32(), 63);
// Prepare data
if (s_tsx_avx)
{
c.vmovups(x86::ymm0, x86::ymmword_ptr(args[2], 0));
c.vmovups(x86::ymm1, x86::ymmword_ptr(args[2], 32));
c.vmovups(x86::ymm2, x86::ymmword_ptr(args[2], 64));
c.vmovups(x86::ymm3, x86::ymmword_ptr(args[2], 96));
}
else
{
c.movaps(x86::xmm0, x86::oword_ptr(args[2], 0));
c.movaps(x86::xmm1, x86::oword_ptr(args[2], 16));
c.movaps(x86::xmm2, x86::oword_ptr(args[2], 32));
c.movaps(x86::xmm3, x86::oword_ptr(args[2], 48));
c.movaps(x86::xmm4, x86::oword_ptr(args[2], 64));
c.movaps(x86::xmm5, x86::oword_ptr(args[2], 80));
c.movaps(x86::xmm6, x86::oword_ptr(args[2], 96));
c.movaps(x86::xmm7, x86::oword_ptr(args[2], 112));
}
// Alloc r14 to stamp0
const auto stamp0 = x86::r14;
build_get_tsc(c, stamp0);
Label fail2 = c.newLabel();
Label tx1 = build_transaction_enter(c, fall, [&]()
{
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.movabs(x86::r13, reinterpret_cast<u64>(&g_rtm_tx_limit2));
c.cmp(x86::rax, x86::qword_ptr(x86::r13));
c.jae(fall);
});
// Check pause flag
c.bt(x86::dword_ptr(args[2], ::offset32(&ppu_thread::state) - ::offset32(&ppu_thread::rdata)), static_cast<u32>(cpu_flag::pause));
c.jc(fall);
c.xbegin(tx1);
if (s_tsx_avx)
{
c.vxorps(x86::ymm0, x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
c.vxorps(x86::ymm1, x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
c.vxorps(x86::ymm2, x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
c.vxorps(x86::ymm3, x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
c.vorps(x86::ymm0, x86::ymm0, x86::ymm1);
c.vorps(x86::ymm1, x86::ymm2, x86::ymm3);
c.vorps(x86::ymm0, x86::ymm1, x86::ymm0);
c.vptest(x86::ymm0, x86::ymm0);
}
else
{
c.xorps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
c.xorps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
c.xorps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
c.xorps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
c.xorps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
c.xorps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
c.xorps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
c.xorps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
c.orps(x86::xmm0, x86::xmm1);
c.orps(x86::xmm2, x86::xmm3);
c.orps(x86::xmm4, x86::xmm5);
c.orps(x86::xmm6, x86::xmm7);
c.orps(x86::xmm0, x86::xmm2);
c.orps(x86::xmm4, x86::xmm6);
c.orps(x86::xmm0, x86::xmm4);
c.ptest(x86::xmm0, x86::xmm0);
}
c.jnz(fail);
// Store 8 bytes
c.mov(x86::qword_ptr(x86::rbp, args[0], 1, 0), args[3]);
c.xend();
c.lock().add(x86::qword_ptr(x86::r11), 64);
build_get_tsc(c);
c.sub(x86::rax, stamp0);
c.jmp(_ret);
// XABORT is expensive so try to finish with xend instead
c.bind(fail);
// Load old data to store back in rdata
if (s_tsx_avx)
{
c.vmovaps(x86::ymm0, x86::ymmword_ptr(x86::rbp, 0));
c.vmovaps(x86::ymm1, x86::ymmword_ptr(x86::rbp, 32));
c.vmovaps(x86::ymm2, x86::ymmword_ptr(x86::rbp, 64));
c.vmovaps(x86::ymm3, x86::ymmword_ptr(x86::rbp, 96));
}
else
{
c.movaps(x86::xmm0, x86::oword_ptr(x86::rbp, 0));
c.movaps(x86::xmm1, x86::oword_ptr(x86::rbp, 16));
c.movaps(x86::xmm2, x86::oword_ptr(x86::rbp, 32));
c.movaps(x86::xmm3, x86::oword_ptr(x86::rbp, 48));
c.movaps(x86::xmm4, x86::oword_ptr(x86::rbp, 64));
c.movaps(x86::xmm5, x86::oword_ptr(x86::rbp, 80));
c.movaps(x86::xmm6, x86::oword_ptr(x86::rbp, 96));
c.movaps(x86::xmm7, x86::oword_ptr(x86::rbp, 112));
}
c.xend();
c.jmp(fail2);
c.bind(fall);
c.mov(x86::rax, -1);
c.jmp(_ret);
c.bind(fail2);
c.lock().sub(x86::qword_ptr(x86::r11), 64);
c.bind(load);
// Store previous data back to rdata
if (s_tsx_avx)
{
c.vmovaps(x86::ymmword_ptr(args[2], 0), x86::ymm0);
c.vmovaps(x86::ymmword_ptr(args[2], 32), x86::ymm1);
c.vmovaps(x86::ymmword_ptr(args[2], 64), x86::ymm2);
c.vmovaps(x86::ymmword_ptr(args[2], 96), x86::ymm3);
}
else
{
c.movaps(x86::oword_ptr(args[2], 0), x86::xmm0);
c.movaps(x86::oword_ptr(args[2], 16), x86::xmm1);
c.movaps(x86::oword_ptr(args[2], 32), x86::xmm2);
c.movaps(x86::oword_ptr(args[2], 48), x86::xmm3);
c.movaps(x86::oword_ptr(args[2], 64), x86::xmm4);
c.movaps(x86::oword_ptr(args[2], 80), x86::xmm5);
c.movaps(x86::oword_ptr(args[2], 96), x86::xmm6);
c.movaps(x86::oword_ptr(args[2], 112), x86::xmm7);
}
c.mov(x86::rax, -1);
c.mov(x86::qword_ptr(args[2], ::offset32(&ppu_thread::last_ftime) - ::offset32(&ppu_thread::rdata)), x86::rax);
c.xor_(x86::eax, x86::eax);
//c.jmp(_ret);
c.bind(_ret);
#ifdef _WIN32
if (!s_tsx_avx)
{
c.vmovups(x86::xmm6, x86::oword_ptr(x86::rsp, 0));
c.vmovups(x86::xmm7, x86::oword_ptr(x86::rsp, 16));
}
#endif
if (s_tsx_avx)
{
c.vzeroupper();
}
c.add(x86::rsp, 48);
c.pop(x86::r14);
c.pop(x86::r13);
c.pop(x86::rbp);
maybe_flush_lbr(c);
c.ret();
#else
UNUSED(args);
// Unimplemented should fail.
c.brk(Imm(0x42));
c.ret(a64::x30);
#endif
});
template <typename T> template <typename T>
static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value) static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
{ {
@ -3268,6 +3486,77 @@ static bool ppu_store_reservation(ppu_thread& ppu, u32 addr, u64 reg_value)
return false; return false;
} }
if (g_use_rtm) [[likely]]
{
switch (u64 count = ppu_stcx_accurate_tx(addr & -8, rtime, ppu.rdata, std::bit_cast<u64>(new_data)))
{
case umax:
{
auto& all_data = *vm::get_super_ptr<spu_rdata_t>(addr & -128);
auto& sdata = *vm::get_super_ptr<atomic_be_t<u64>>(addr & -8);
const bool ok = cpu_thread::suspend_all<+3>(&ppu, {all_data, all_data + 64, &res}, [&]
{
if ((res & -128) == rtime && cmp_rdata(ppu.rdata, all_data))
{
sdata.release(new_data);
res += 64;
return true;
}
mov_rdata_nt(ppu.rdata, all_data);
res -= 64;
return false;
});
if (ok)
{
break;
}
ppu.last_ftime = -1;
[[fallthrough]];
}
case 0:
{
if (ppu.last_faddr == addr)
{
ppu.last_fail++;
}
if (ppu.last_ftime != umax)
{
ppu.last_faddr = 0;
return false;
}
utils::prefetch_read(ppu.rdata);
utils::prefetch_read(ppu.rdata + 64);
ppu.last_faddr = addr;
ppu.last_ftime = res.load() & -128;
ppu.last_ftsc = utils::get_tsc();
return false;
}
default:
{
if (count > 20000 && g_cfg.core.perf_report) [[unlikely]]
{
perf_log.warning("STCX: took too long: %.3fus (%u c)", count / (utils::get_tsc_freq() / 1000'000.), count);
}
break;
}
}
if (ppu.last_faddr == addr)
{
ppu.last_succ++;
}
ppu.last_faddr = 0;
return true;
}
// Align address: we do not need the lower 7 bits anymore // Align address: we do not need the lower 7 bits anymore
addr &= -128; addr &= -128;
@ -3718,7 +4007,7 @@ extern void ppu_finalize(const ppu_module<lv2_obj>& info, bool force_mem_release
#endif #endif
} }
extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_modules, bool is_fast_compilation) extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_module<lv2_obj>*>* loaded_modules)
{ {
if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm) if (g_cfg.core.ppu_decoder != ppu_decoder_type::llvm)
{ {
@ -4166,12 +4455,6 @@ extern void ppu_precompile(std::vector<std::string>& dir_queue, std::vector<ppu_
break; break;
} }
if (is_fast_compilation)
{
// Skip overlays in fast mode
break;
}
if (!wait_for_memory()) if (!wait_for_memory())
{ {
// Emulation stopped // Emulation stopped
@ -4466,7 +4749,7 @@ extern void ppu_initialize()
progress_dialog.reset(); progress_dialog.reset();
ppu_precompile(dir_queue, &module_list, false); ppu_precompile(dir_queue, &module_list);
if (Emu.IsStopped()) if (Emu.IsStopped())
{ {
@ -5520,11 +5803,7 @@ static void ppu_initialize2(jit_compiler& jit, const ppu_module<lv2_obj>& module
std::unique_ptr<Module> _module = std::make_unique<Module>(obj_name, jit.get_context()); std::unique_ptr<Module> _module = std::make_unique<Module>(obj_name, jit.get_context());
// Initialize target // Initialize target
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
_module->setTargetTriple(Triple(jit_compiler::triple1()));
#else
_module->setTargetTriple(jit_compiler::triple1()); _module->setTargetTriple(jit_compiler::triple1());
#endif
_module->setDataLayout(jit.get_engine().getTargetMachine()->createDataLayout()); _module->setDataLayout(jit.get_engine().getTargetMachine()->createDataLayout());
// Initialize translator // Initialize translator

View file

@ -416,6 +416,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
assert(ptr_inst->getResultElementType() == m_ir->getPtrTy()); assert(ptr_inst->getResultElementType() == m_ir->getPtrTy());
const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst); const auto faddr = m_ir->CreateLoad(ptr_inst->getResultElementType(), ptr_inst);
const auto faddr_int = m_ir->CreatePtrToInt(faddr, get_type<uptr>());
const auto pos_32 = m_reloc ? m_ir->CreateAdd(func_pc, m_seg0) : func_pc; 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 pos = m_ir->CreateShl(pos_32, 1);
const auto ptr = m_ir->CreatePtrAdd(m_exec, pos); const auto ptr = m_ir->CreatePtrAdd(m_exec, pos);
@ -426,7 +427,7 @@ Function* PPUTranslator::GetSymbolResolver(const ppu_module<lv2_obj>& info)
const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>()); const auto seg_val = m_ir->CreateTrunc(m_ir->CreateLShr(m_seg0, 13), get_type<u16>());
// Store to jumptable // Store to jumptable
m_ir->CreateStore(faddr, ptr); m_ir->CreateStore(faddr_int, ptr);
m_ir->CreateStore(seg_val, seg_ptr); m_ir->CreateStore(seg_val, seg_ptr);
// Increment index and branch back to loop // Increment index and branch back to loop
@ -592,11 +593,6 @@ void PPUTranslator::CallFunction(u64 target, Value* indirect)
{ {
callee = m_module->getOrInsertFunction(fmt::format("__0x%x", target_last - base), type); callee = m_module->getOrInsertFunction(fmt::format("__0x%x", target_last - base), type);
cast<Function>(callee.getCallee())->setCallingConv(CallingConv::GHC); cast<Function>(callee.getCallee())->setCallingConv(CallingConv::GHC);
if (g_cfg.core.ppu_prof)
{
m_ir->CreateStore(GetAddr(target_last - m_addr), m_ir->CreateStructGEP(m_thread_type, m_thread, static_cast<uint>(&m_cia - m_locals)));
}
} }
} }
else else
@ -1119,24 +1115,7 @@ void PPUTranslator::VCFSX(ppu_opcode_t op)
void PPUTranslator::VCFUX(ppu_opcode_t op) void PPUTranslator::VCFUX(ppu_opcode_t op)
{ {
const auto b = get_vr<u32[4]>(op.vb); const auto b = get_vr<u32[4]>(op.vb);
set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
#ifdef ARCH_ARM64
return set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
#else
if (m_use_avx512)
{
return set_vr(op.vd, fpcast<f32[4]>(b) * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
}
constexpr int bit_shift = 9;
const auto shifted = (b >> bit_shift);
const auto cleared = shifted << bit_shift;
const auto low_bits = b - cleared;
const auto high_part = fpcast<f32[4]>(noncast<s32[4]>(shifted)) * fsplat<f32[4]>(static_cast<f32>(1u << bit_shift));
const auto low_part = fpcast<f32[4]>(noncast<s32[4]>(low_bits));
const auto temp = high_part + low_part;
set_vr(op.vd, temp * fsplat<f32[4]>(std::pow(2, -static_cast<int>(op.vuimm))));
#endif
} }
void PPUTranslator::VCMPBFP(ppu_opcode_t op) void PPUTranslator::VCMPBFP(ppu_opcode_t op)

View file

@ -186,7 +186,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
c->cmp(SPU_OFF_32(state), 0); c->cmp(SPU_OFF_32(state), 0);
c->jnz(label_stop); c->jnz(label_stop);
if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification) if (g_cfg.core.spu_prof && g_cfg.core.spu_verification)
{ {
c->mov(x86::rax, m_hash_start & -0xffff); c->mov(x86::rax, m_hash_start & -0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);
@ -755,7 +755,7 @@ spu_function_t spu_recompiler::compile(spu_program&& _func)
c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4)); c->add(SPU_OFF_64(block_counter), ::size32(words) / (words_align / 4));
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) if (g_cfg.core.spu_prof)
{ {
c->mov(x86::rax, m_hash_start | 0xffff); c->mov(x86::rax, m_hash_start | 0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);
@ -1199,7 +1199,7 @@ void spu_recompiler::branch_set_link(u32 target)
c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0); c->movdqa(x86::dqword_ptr(*cpu, *qw1, 0, ::offset32(&spu_thread::stack_mirror)), x86::xmm0);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) if (g_cfg.core.spu_prof)
{ {
c->mov(x86::rax, m_hash_start | 0xffff); c->mov(x86::rax, m_hash_start | 0xffff);
c->mov(SPU_OFF_64(block_hash), x86::rax); c->mov(SPU_OFF_64(block_hash), x86::rax);
@ -3212,7 +3212,7 @@ void spu_recompiler::ROTQBYI(spu_opcode_t op)
} }
else if (s == 4 || s == 8 || s == 12) else if (s == 4 || s == 8 || s == 12)
{ {
c->pshufd(va, va, std::rotl<u8>(0xE4, s / 2)); c->pshufd(va, va, utils::rol8(0xE4, s / 2));
} }
else if (utils::has_ssse3()) else if (utils::has_ssse3())
{ {

View file

@ -38,9 +38,26 @@ constexpr u32 s_reg_max = spu_recompiler_base::s_reg_max;
template<typename T> template<typename T>
struct span_less struct span_less
{ {
static auto compare(const std::span<T>& lhs, const std::span<T>& rhs) noexcept static int compare(const std::span<T>& lhs, const std::span<T>& rhs) noexcept
{ {
return std::lexicographical_compare_three_way(lhs.begin(), lhs.end(), rhs.begin(), rhs.end()); // TODO: Replace with std::lexicographical_compare_three_way when it becomes available to all compilers
for (usz i = 0, last = std::min(lhs.size(), rhs.size()); i != last; i++)
{
const T vl = lhs[i];
const T vr = rhs[i];
if (vl != vr)
{
return vl < vr ? -1 : 1;
}
}
if (lhs.size() != rhs.size())
{
return lhs.size() < rhs.size() ? -1 : 1;
}
return 0;
} }
bool operator()(const std::span<T>& lhs, const std::span<T>& rhs) const noexcept bool operator()(const std::span<T>& lhs, const std::span<T>& rhs) const noexcept
@ -720,19 +737,9 @@ void spu_cache::initialize(bool build_existing_cache)
} }
// SPU cache file (version + block size type) // SPU cache file (version + block size type)
const std::string filename = "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat"; const std::string loc = ppu_cache + "spu-" + fmt::to_lower(g_cfg.core.spu_block_size.to_string()) + "-v1-tane.dat";
const std::string loc = ppu_cache + filename;
const std::string loc_debug = fs::get_cache_dir() + "DEBUG/" + filename;
bool is_debug = false; spu_cache cache(loc);
if (fs::is_file(loc_debug))
{
spu_log.success("SPU Cache override applied!");
is_debug = true;
}
spu_cache cache(is_debug ? loc_debug : loc);
if (!cache) if (!cache)
{ {
@ -1302,7 +1309,7 @@ bool spu_program::operator<(const spu_program& rhs) const noexcept
std::span<const u32> lhs_data(data.data() + lhs_offs, data.size() - lhs_offs); std::span<const u32> lhs_data(data.data() + lhs_offs, data.size() - lhs_offs);
std::span<const u32> rhs_data(rhs.data.data() + rhs_offs, rhs.data.size() - rhs_offs); std::span<const u32> rhs_data(rhs.data.data() + rhs_offs, rhs.data.size() - rhs_offs);
const auto cmp0 = span_less<const u32>::compare(lhs_data, rhs_data); const int cmp0 = span_less<const u32>::compare(lhs_data, rhs_data);
if (cmp0 < 0) if (cmp0 < 0)
return true; return true;
@ -1313,7 +1320,7 @@ bool spu_program::operator<(const spu_program& rhs) const noexcept
lhs_data = {data.data(), lhs_offs}; lhs_data = {data.data(), lhs_offs};
rhs_data = {rhs.data.data(), rhs_offs}; rhs_data = {rhs.data.data(), rhs_offs};
const auto cmp1 = span_less<const u32>::compare(lhs_data, rhs_data); const int cmp1 = span_less<const u32>::compare(lhs_data, rhs_data);
if (cmp1 < 0) if (cmp1 < 0)
return true; return true;
@ -2326,7 +2333,7 @@ std::vector<u32> spu_thread::discover_functions(u32 base_addr, std::span<const u
// Search for BRSL LR and BRASL LR or BR // Search for BRSL LR and BRASL LR or BR
// TODO: BISL // TODO: BISL
const v128 inst = read_from_ptr<be_t<v128>>(ls.data(), i - base_addr); const v128 inst = read_from_ptr<be_t<v128>>(ls.data(), i - base_addr);
const v128 cleared_i16 = gv_and32(inst, v128::from32p(std::rotl<u32>(~0xffff, 7))); const v128 cleared_i16 = gv_and32(inst, v128::from32p(utils::rol32(~0xffff, 7)));
const v128 eq_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23)); const v128 eq_brsl = gv_eq32(cleared_i16, v128::from32p(0x66u << 23));
const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask); const v128 eq_brasl = gv_eq32(cleared_i16, brasl_mask);
const v128 eq_br = gv_eq32(cleared_i16, v128::from32p(0x64u << 23)); const v128 eq_br = gv_eq32(cleared_i16, v128::from32p(0x64u << 23));
@ -3079,39 +3086,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
values[op.rt] = pos + 4; values[op.rt] = pos + 4;
} }
const u32 pos_next = wa;
bool is_no_return = false;
if (pos_next >= lsa && pos_next < limit)
{
const u32 data_next = ls[pos_next / 4];
const auto type_next = g_spu_itype.decode(data_next);
const auto flag_next = g_spu_iflag.decode(data_next);
const auto op_next = spu_opcode_t{data_next};
if (!(type_next & spu_itype::zregmod) && !(type_next & spu_itype::branch))
{
if (auto iflags = g_spu_iflag.decode(data_next))
{
if (+flag_next & +spu_iflag::use_ra)
{
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.ra < 10);
}
if (+flag_next & +spu_iflag::use_rb)
{
is_no_return = is_no_return || (op_next.rb >= 4 && op_next.rb < 10);
}
if (type_next & spu_itype::_quadrop && +iflags & +spu_iflag::use_rc)
{
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.rb < 10);
}
}
}
}
if (af & vf::is_const) if (af & vf::is_const)
{ {
const u32 target = spu_branch_target(av); const u32 target = spu_branch_target(av);
@ -3148,7 +3122,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
limit = std::min<u32>(limit, target); limit = std::min<u32>(limit, target);
} }
if (!is_no_return && sl && g_cfg.core.spu_block_size != spu_block_size_type::safe) if (sl && g_cfg.core.spu_block_size != spu_block_size_type::safe)
{ {
m_ret_info[pos / 4 + 1] = true; m_ret_info[pos / 4 + 1] = true;
m_entry_info[pos / 4 + 1] = true; m_entry_info[pos / 4 + 1] = true;
@ -3165,7 +3139,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
u64 dabs = 0; u64 dabs = 0;
u64 drel = 0; u64 drel = 0;
for (u32 i = start, abs_fail = 0, rel_fail = 0; i < limit; i += 4) for (u32 i = start; i < limit; i += 4)
{ {
const u32 target = ls[i / 4]; const u32 target = ls[i / 4];
@ -3175,39 +3149,16 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
break; break;
} }
if (target >= SPU_LS_SIZE && target <= 0u - SPU_LS_SIZE)
{
if (g_spu_itype.decode(target) != spu_itype::UNK)
{
// End of jumptable: valid instruction
break;
}
}
if (target >= lsa && target < SPU_LS_SIZE) if (target >= lsa && target < SPU_LS_SIZE)
{ {
// Possible jump table entry (absolute) // Possible jump table entry (absolute)
if (!abs_fail) jt_abs.push_back(target);
{
jt_abs.push_back(target);
}
}
else
{
abs_fail++;
} }
if (target + start >= lsa && target + start < SPU_LS_SIZE) if (target + start >= lsa && target + start < SPU_LS_SIZE)
{ {
// Possible jump table entry (relative) // Possible jump table entry (relative)
if (!rel_fail) jt_rel.push_back(target + start);
{
jt_rel.push_back(target + start);
}
}
else
{
rel_fail++;
} }
if (std::max(jt_abs.size(), jt_rel.size()) * 4 + start <= i) if (std::max(jt_abs.size(), jt_rel.size()) * 4 + start <= i)
@ -3219,35 +3170,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
} }
} }
for (usz i = 0; i < jt_abs.size(); i++)
{
if (jt_abs[i] == start + jt_abs.size() * 4)
{
// If jumptable contains absolute address of code start after the jumptable itself
// It is likely an absolute-type jumptable
bool is_good_conclusion = true;
// For verification: make sure there is none like this in relative table
for (u32 target : jt_rel)
{
if (target == start + jt_rel.size() * 4)
{
is_good_conclusion = false;
break;
}
}
if (is_good_conclusion)
{
jt_rel.clear();
}
break;
}
}
// Choose position after the jt as an anchor and compute the average distance // Choose position after the jt as an anchor and compute the average distance
for (u32 target : jt_abs) for (u32 target : jt_abs)
{ {
@ -3346,9 +3268,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
spu_log.notice("[0x%x] At 0x%x: ignoring indirect branch (SYNC)", entry_point, pos); spu_log.notice("[0x%x] At 0x%x: ignoring indirect branch (SYNC)", entry_point, pos);
} }
if (type == spu_itype::BI || sl || is_no_return) if (type == spu_itype::BI || sl)
{ {
if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe || is_no_return) if (type == spu_itype::BI || g_cfg.core.spu_block_size == spu_block_size_type::safe)
{ {
m_targets[pos]; m_targets[pos];
} }
@ -3385,42 +3307,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
break; break;
} }
const u32 pos_next = wa;
bool is_no_return = false;
if (pos_next >= lsa && pos_next < limit)
{
const u32 data_next = ls[pos_next / 4];
const auto type_next = g_spu_itype.decode(data_next);
const auto flag_next = g_spu_iflag.decode(data_next);
const auto op_next = spu_opcode_t{data_next};
if (!(type_next & spu_itype::zregmod) && !(type_next & spu_itype::branch))
{
if (auto iflags = g_spu_iflag.decode(data_next))
{
if (+flag_next & +spu_iflag::use_ra)
{
is_no_return = is_no_return || (op_next.ra >= 4 && op_next.ra < 10);
}
if (+flag_next & +spu_iflag::use_rb)
{
is_no_return = is_no_return || (op_next.rb >= 4 && op_next.rb < 10);
}
if (type_next & spu_itype::_quadrop && +iflags & +spu_iflag::use_rc)
{
is_no_return = is_no_return || (op_next.rc >= 4 && op_next.rc < 10);
}
}
}
}
m_targets[pos].push_back(target); m_targets[pos].push_back(target);
if (!is_no_return && g_cfg.core.spu_block_size != spu_block_size_type::safe) if (g_cfg.core.spu_block_size != spu_block_size_type::safe)
{ {
m_ret_info[pos / 4 + 1] = true; m_ret_info[pos / 4 + 1] = true;
m_entry_info[pos / 4 + 1] = true; m_entry_info[pos / 4 + 1] = true;
@ -3428,7 +3317,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
add_block(pos + 4); add_block(pos + 4);
} }
if (!is_no_return && g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync) if (g_cfg.core.spu_block_size == spu_block_size_type::giga && !sync)
{ {
m_entry_info[target / 4] = true; m_entry_info[target / 4] = true;
add_block(target); add_block(target);
@ -4973,7 +4862,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write u32 lsa_last_pc = SPU_LS_SIZE; // PC of first LSA write
u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR u32 get_pc = SPU_LS_SIZE; // PC of GETLLAR
u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC u32 put_pc = SPU_LS_SIZE; // PC of PUTLLC
u32 rdatomic_pc = SPU_LS_SIZE; // PC of last RdAtomcStat read
reg_state_t ls{}; // state of LS load/store address register reg_state_t ls{}; // state of LS load/store address register
reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls reg_state_t ls_offs = reg_state_t::from_value(0); // Added value to ls
reg_state_t lsa{}; // state of LSA register on GETLLAR reg_state_t lsa{}; // state of LSA register on GETLLAR
@ -4989,27 +4877,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
bool select_16_or_0_at_runtime = false; bool select_16_or_0_at_runtime = false;
bool put_active = false; // PUTLLC happened bool put_active = false; // PUTLLC happened
bool get_rdatomic = false; // True if MFC_RdAtomicStat was read after GETLLAR bool get_rdatomic = false; // True if MFC_RdAtomicStat was read after GETLLAR
u32 required_pc = SPU_LS_SIZE; // Require program to be location specific for this optimization (SPU_LS_SIZE - no requirement)
u32 mem_count = 0; u32 mem_count = 0;
u32 break_cause = 100;
u32 break_pc = SPU_LS_SIZE;
// Return old state for error reporting // Return old state for error reporting
atomic16_t discard() atomic16_t discard()
{ {
const u32 pc = lsa_pc; const u32 pc = lsa_pc;
const u32 last_pc = lsa_last_pc; const u32 last_pc = lsa_last_pc;
const u32 cause = break_cause;
const u32 break_pos = break_pc;
const atomic16_t old = *this; const atomic16_t old = *this;
*this = atomic16_t{}; *this = atomic16_t{};
// Keep some members // Keep some members
this->lsa_pc = pc; lsa_pc = pc;
this->lsa_last_pc = last_pc; lsa_last_pc = last_pc;
this->break_cause = cause;
this->break_pc = break_pos;
return old; return old;
} }
@ -5019,7 +4900,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
ls_invalid = true; ls_invalid = true;
ls_write |= write; ls_write |= write;
if (ls_write) if (write)
{ {
return discard(); return discard();
} }
@ -5216,17 +5097,15 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{ {
if (previous.active && likely_putllc_loop && getllar_starts.contains(previous.lsa_pc)) if (previous.active && likely_putllc_loop && getllar_starts.contains(previous.lsa_pc))
{ {
had_putllc_evaluation = true; const bool is_first = !std::exchange(getllar_starts[previous.lsa_pc], true);
if (cause != 24) if (!is_first)
{ {
atomic16->break_cause = cause;
atomic16->break_pc = pos;
return; return;
} }
cause = atomic16->break_cause; had_putllc_evaluation = true;
getllar_starts[previous.lsa_pc] = true;
g_fxo->get<putllc16_statistics_t>().breaking_reason[cause]++; g_fxo->get<putllc16_statistics_t>().breaking_reason[cause]++;
if (!spu_log.notice) if (!spu_log.notice)
@ -5234,7 +5113,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
return; return;
} }
std::string break_error = fmt::format("PUTLLC pattern breakage [%x mem=%d lsa_const=%d cause=%u] (lsa_pc=0x%x)", atomic16->break_pc, previous.mem_count, u32{!previous.ls_offs.is_const()} * 2 + previous.lsa.is_const(), cause, previous.lsa_pc); std::string break_error = fmt::format("PUTLLC pattern breakage [%x mem=%d lsa_const=%d cause=%u] (lsa_pc=0x%x)", pos, previous.mem_count, u32{!previous.ls_offs.is_const()} * 2 + previous.lsa.is_const(), cause, previous.lsa_pc);
const auto values = sort_breakig_reasons(g_fxo->get<putllc16_statistics_t>().breaking_reason); const auto values = sort_breakig_reasons(g_fxo->get<putllc16_statistics_t>().breaking_reason);
@ -5517,7 +5396,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
const usz block_tail = duplicate_positions[it_begin - it_tail]; const usz block_tail = duplicate_positions[it_begin - it_tail];
// Check if the distance is precisely two times from the end // Check if the distance is precisely two times from the end
if (reg_state_it.size() - block_start != std::rotl<u64>(reg_state_it.size() - block_tail, 1)) if (reg_state_it.size() - block_start != utils::rol64(reg_state_it.size() - block_tail, 1))
{ {
continue; continue;
} }
@ -6334,8 +6213,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
break; break;
} }
atomic16->rdatomic_pc = pos;
const auto it = atomic16_all.find(pos); const auto it = atomic16_all.find(pos);
if (it == atomic16_all.end()) if (it == atomic16_all.end())
@ -6398,7 +6275,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
existing.ls_invalid |= atomic16->ls_invalid; existing.ls_invalid |= atomic16->ls_invalid;
existing.ls_access |= atomic16->ls_access; existing.ls_access |= atomic16->ls_access;
existing.mem_count = std::max<u32>(existing.mem_count, atomic16->mem_count); existing.mem_count = std::max<u32>(existing.mem_count, atomic16->mem_count);
existing.required_pc = std::min<u32>(existing.required_pc, atomic16->required_pc);
existing.select_16_or_0_at_runtime |= atomic16->select_16_or_0_at_runtime; existing.select_16_or_0_at_runtime |= atomic16->select_16_or_0_at_runtime;
} }
@ -6413,24 +6289,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
invalidate = false; invalidate = false;
} }
} }
else if (atomic16->break_cause != 100 && atomic16->lsa_pc != SPU_LS_SIZE)
{
const auto it = atomic16_all.find(pos);
if (it == atomic16_all.end())
{
// Ensure future failure
atomic16_all.emplace(pos, *atomic16);
break_putllc16(24, FN(x.active = true, x)(as_rvalue(*atomic16)));
}
else if (it->second.active && atomic16->break_cause != 100)
{
it->second = *atomic16;
break_putllc16(24, FN(x.active = true, x)(as_rvalue(*atomic16)));
}
atomic16->break_cause = 100;
}
break; break;
} }
@ -6501,10 +6359,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
// Do not clear lower 16 bytes addressing because the program can move on 4-byte basis // Do not clear lower 16 bytes addressing because the program can move on 4-byte basis
const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16); const u32 offs = spu_branch_target(pos - result.lower_bound, op.si16);
const u32 true_offs = spu_branch_target(pos, op.si16);
// Make this optimization depend on the location of the program
atomic16->required_pc = result.lower_bound;
if (atomic16->lsa.is_const() && [&]() if (atomic16->lsa.is_const() && [&]()
{ {
@ -6529,10 +6383,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
{ {
// Ignore memory access in this case // Ignore memory access in this case
} }
else if (atomic16->lsa.is_const() && !atomic16->lsa.compare_with_mask_indifference(true_offs, SPU_LS_MASK_128))
{
// Same
}
else if (atomic16->ls_invalid && is_store) else if (atomic16->ls_invalid && is_store)
{ {
break_putllc16(35, atomic16->set_invalid_ls(is_store)); break_putllc16(35, atomic16->set_invalid_ls(is_store));
@ -7276,7 +7126,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
for (const auto& [pc_commited, pattern] : atomic16_all) for (const auto& [pc_commited, pattern] : atomic16_all)
{ {
if (!pattern.active || pattern.lsa_pc >= pattern.rdatomic_pc) if (!pattern.active)
{ {
continue; continue;
} }
@ -7286,44 +7136,27 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
continue; continue;
} }
std::string pattern_hash;
{
sha1_context ctx;
u8 output[20]{};
sha1_starts(&ctx);
sha1_update(&ctx, reinterpret_cast<const u8*>(result.data.data()) + (pattern.lsa_pc - result.lower_bound), pattern.rdatomic_pc - pattern.lsa_pc);
sha1_finish(&ctx, output);
fmt::append(pattern_hash, "%s", fmt::base57(output));
}
union putllc16_or_0_info
{
u64 data;
bf_t<u64, 32, 18> required_pc;
bf_t<u64, 30, 2> type;
bf_t<u64, 29, 1> runtime16_select;
bf_t<u64, 28, 1> no_notify;
bf_t<u64, 18, 8> reg;
bf_t<u64, 0, 18> off18;
bf_t<u64, 0, 8> reg2;
} value{};
auto& stats = g_fxo->get<putllc16_statistics_t>(); auto& stats = g_fxo->get<putllc16_statistics_t>();
had_putllc_evaluation = true; had_putllc_evaluation = true;
if (!pattern.ls_write) if (!pattern.ls_write)
{ {
if (pattern.required_pc != SPU_LS_SIZE) spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
{ add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa);
value.required_pc = pattern.required_pc;
}
// spu_log.success("PUTLLC0 Pattern Detected! (put_pc=0x%x, %s) (putllc0=%d, putllc16+0=%d, all=%d)", pattern.put_pc, func_hash, ++stats.nowrite, ++stats.single, +stats.all);
// add_pattern(false, inst_attr::putllc0, pattern.put_pc - lsa, value.data);
continue; continue;
} }
union putllc16_info
{
u32 data;
bf_t<u32, 30, 2> type;
bf_t<u32, 29, 1> runtime16_select;
bf_t<u32, 28, 1> no_notify;
bf_t<u32, 18, 8> reg;
bf_t<u32, 0, 18> off18;
bf_t<u32, 0, 8> reg2;
} value{};
enum : u32 enum : u32
{ {
v_const = 0, v_const = 0,
@ -7354,11 +7187,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
value.runtime16_select = pattern.select_16_or_0_at_runtime; value.runtime16_select = pattern.select_16_or_0_at_runtime;
value.reg = s_reg_max; value.reg = s_reg_max;
if (pattern.required_pc != SPU_LS_SIZE)
{
value.required_pc = pattern.required_pc;
}
if (pattern.ls.is_const()) if (pattern.ls.is_const())
{ {
ensure(pattern.reg == s_reg_max && pattern.reg2 == s_reg_max && pattern.ls_offs.is_const(), "Unexpected register usage"); ensure(pattern.reg == s_reg_max && pattern.reg2 == s_reg_max && pattern.ls_offs.is_const(), "Unexpected register usage");
@ -7387,35 +7215,16 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
value.reg2 = pattern.reg2; value.reg2 = pattern.reg2;
} }
bool allow_pattern = true;
if (g_cfg.core.spu_accurate_reservations) if (g_cfg.core.spu_accurate_reservations)
{ {
// The problem with PUTLLC16 optimization, that it is in theory correct at the bounds of the spu function. // Because enabling it is a hack, as it turns out
// But if the SPU code reuses the cache line data observed, it is not truly atomic. continue;
// So we may enable it only for known cases where SPU atomic data is not used after the function leaves.
// So the two options are:
// 1. Atomic compare exchange 16 bytes operation. (rest of data is not read) -> good for RPCS3 to optimize.
// 2. Fetch 128 bytes (read them later), modify only 16 bytes. -> Bad for RPCS3 to optimize.
// This difference cannot be known at analyzer time but from observing callers.
static constexpr std::initializer_list<std::string_view> allowed_patterns =
{
"620oYSe8uQqq9eTkhWfMqoEXX0us"sv, // CellSpurs JobChain acquire pattern
};
allow_pattern = std::any_of(allowed_patterns.begin(), allowed_patterns.end(), FN(pattern_hash == x));
} }
if (allow_pattern) add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
{
add_pattern(false, inst_attr::putllc16, pattern.put_pc - result.entry_point, value.data);
}
spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s, pattern-hash=%s) (putllc0=%d, putllc16+0=%d, all=%d)" spu_log.success("PUTLLC16 Pattern Detected! (mem_count=%d, put_pc=0x%x, pc_rel=%d, offset=0x%x, const=%u, two_regs=%d, reg=%u, runtime=%d, 0x%x-%s) (putllc0=%d, putllc16+0=%d, all=%d)"
, pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, pattern_hash, +stats.nowrite, ++stats.single, +stats.all); , pattern.mem_count, pattern.put_pc, value.type == v_relative, value.off18, value.type == v_const, value.type == v_reg2, value.reg, value.runtime16_select, entry_point, func_hash, +stats.nowrite, ++stats.single, +stats.all);
} }
for (const auto& [read_pc, pattern] : rchcnt_loop_all) for (const auto& [read_pc, pattern] : rchcnt_loop_all)
@ -7433,7 +7242,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
if (inst_attr attr = m_inst_attrs[(read_pc - entry_point) / 4]; attr == inst_attr::none) if (inst_attr attr = m_inst_attrs[(read_pc - entry_point) / 4]; attr == inst_attr::none)
{ {
add_pattern(false, inst_attr::rchcnt_loop, read_pc - result.entry_point, 0); add_pattern(false, inst_attr::rchcnt_loop, read_pc - result.entry_point);
spu_log.error("Channel Loop Pattern Detected! Report to developers! (read_pc=0x%x, branch_pc=0x%x, branch_target=0x%x, 0x%x-%s)", read_pc, pattern.branch_pc, pattern.branch_target, entry_point, func_hash); spu_log.error("Channel Loop Pattern Detected! Report to developers! (read_pc=0x%x, branch_pc=0x%x, branch_target=0x%x, 0x%x-%s)", read_pc, pattern.branch_pc, pattern.branch_target, entry_point, func_hash);
} }
@ -7449,26 +7258,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
// Blocks starting from 0x0 or invalid instruction won't be compiled, may need special interpreter fallback // Blocks starting from 0x0 or invalid instruction won't be compiled, may need special interpreter fallback
} }
if (!m_patterns.empty())
{
std::string out_dump;
dump(result, out_dump);
spu_log.notice("Dump SPU Function with pattern(s):\n%s", out_dump);
}
for (u32 i = 0; i < result.data.size(); i++)
{
const be_t<u32> ls_val = ls[result.lower_bound / 4 + i];
if (result.data[i] && std::bit_cast<u32>(ls_val) != result.data[i])
{
std::string out_dump;
dump(result, out_dump);
spu_log.error("SPU Function Dump:\n%s", out_dump);
fmt::throw_exception("SPU Analyzer failed: Instruction mismatch at 0x%x [read: 0x%x vs LS: 0x%x] (i=0x%x)", result.lower_bound + i * 4, std::bit_cast<be_t<u32>>(result.data[i]), ls_val, i);
}
}
return result; return result;
} }
@ -8478,9 +8267,8 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
{ {
// TODO: The true maximum occurence count need to depend on the amount of branching-outs passed through // TODO: The true maximum occurence count need to depend on the amount of branching-outs passed through
// Currently allow 2 for short-term code and 1 for long-term code // Currently allow 2 for short-term code and 1 for long-term code
// Ignore large jumptables as well
const bool loop_terminator_detected = std::count(been_there.begin(), been_there.end(), prev_pc) >= (qi < 20 ? 2u : 1u); const bool loop_terminator_detected = std::count(been_there.begin(), been_there.end(), prev_pc) >= (qi < 20 ? 2u : 1u);
const bool avoid_extensive_analysis = qi >= (extensive_evaluation ? 22 : 16) || it->state_prev.size() >= 8; const bool avoid_extensive_analysis = qi >= (extensive_evaluation ? 22 : 16);
if (!loop_terminator_detected && !avoid_extensive_analysis) if (!loop_terminator_detected && !avoid_extensive_analysis)
{ {
@ -8519,10 +8307,19 @@ std::array<reg_state_t, s_reg_max>& block_reg_info::evaluate_start_state(const s
return walkby_state; return walkby_state;
} }
void spu_recompiler_base::add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info) void spu_recompiler_base::add_pattern(bool fill_all, inst_attr attr, u32 start, u32 end)
{ {
m_patterns[start] = pattern_info{info}; if (end == umax)
m_inst_attrs[start / 4] = attr; {
end = start;
}
m_patterns[start] = pattern_info{utils::address_range32::start_end(start, end)};
for (u32 i = start; i <= (fill_all ? end : start); i += 4)
{
m_inst_attrs[i / 4] = attr;
}
} }
extern std::string format_spu_func_info(u32 addr, cpu_thread* spu) extern std::string format_spu_func_info(u32 addr, cpu_thread* spu)

View file

@ -291,7 +291,7 @@ bool ROT(spu_thread& spu, spu_opcode_t op)
for (u32 i = 0; i < 4; i++) for (u32 i = 0; i < 4; i++)
{ {
spu.gpr[op.rt]._u32[i] = std::rotl<u32>(a._u32[i], b._u32[i]); spu.gpr[op.rt]._u32[i] = utils::rol32(a._u32[i], b._u32[i]);
} }
return true; return true;
} }
@ -346,7 +346,7 @@ bool ROTH(spu_thread& spu, spu_opcode_t op)
for (u32 i = 0; i < 8; i++) for (u32 i = 0; i < 8; i++)
{ {
spu.gpr[op.rt]._u16[i] = std::rotl<u16>(a._u16[i], b._u16[i]); spu.gpr[op.rt]._u16[i] = utils::rol16(a._u16[i], b._u16[i]);
} }
return true; return true;
} }

View file

@ -1080,7 +1080,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
m_ir->SetInsertPoint(_body); m_ir->SetInsertPoint(_body);
} }
void putllc16_pattern(const spu_program& /*prog*/, u64 pattern_info) void putllc16_pattern(const spu_program& /*prog*/, utils::address_range32 range)
{ {
// Prevent store elimination // Prevent store elimination
m_block->store_context_ctr[s_reg_mfc_eal]++; m_block->store_context_ctr[s_reg_mfc_eal]++;
@ -1109,17 +1109,16 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
} }
}; };
const union putllc16_or_0_info const union putllc16_info
{ {
u64 data; u32 data;
bf_t<u64, 32, 18> required_pc; bf_t<u32, 30, 2> type;
bf_t<u64, 30, 2> type; bf_t<u32, 29, 1> runtime16_select;
bf_t<u64, 29, 1> runtime16_select; bf_t<u32, 28, 1> no_notify;
bf_t<u64, 28, 1> no_notify; bf_t<u32, 18, 8> reg;
bf_t<u64, 18, 8> reg; bf_t<u32, 0, 18> off18;
bf_t<u64, 0, 18> off18; bf_t<u32, 0, 8> reg2;
bf_t<u64, 0, 8> reg2; } info = std::bit_cast<putllc16_info>(range.end);
} info = std::bit_cast<putllc16_or_0_info>(pattern_info);
enum : u32 enum : u32
{ {
@ -1151,10 +1150,8 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
value_t<u32> eal_val; value_t<u32> eal_val;
eal_val.value = _eal; eal_val.value = _eal;
auto get_reg32 = [&](u64 reg_) auto get_reg32 = [&](u32 reg)
{ {
const u32 reg = static_cast<u32>(reg_);
if (get_reg_type(reg) != get_type<u32[4]>()) if (get_reg_type(reg) != get_type<u32[4]>())
{ {
return get_reg_fixed(reg, get_type<u32>()); return get_reg_fixed(reg, get_type<u32>());
@ -1173,19 +1170,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
} }
else if (info.type == v_relative) else if (info.type == v_relative)
{ {
if (info.required_pc && info.required_pc != SPU_LS_SIZE)
{
const auto short_op = llvm::BasicBlock::Create(m_context, "__putllc16_short_op", m_function);
const auto heavy_op = llvm::BasicBlock::Create(m_context, "__putllc16_heavy_op", m_function);
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->getInt32(info.required_pc), m_base_pc), heavy_op, short_op);
m_ir->SetInsertPoint(heavy_op);
update_pc();
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
m_ir->CreateBr(_final);
m_ir->SetInsertPoint(short_op);
}
dest = m_ir->CreateAnd(get_pc(spu_branch_target(info.off18 + m_base)), 0x3fff0); dest = m_ir->CreateAnd(get_pc(spu_branch_target(info.off18 + m_base)), 0x3fff0);
} }
else if (info.type == v_reg_offs) else if (info.type == v_reg_offs)
@ -1284,18 +1268,17 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
const auto _new = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(m_lsptr, dest), llvm::MaybeAlign{16}); const auto _new = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(m_lsptr, dest), llvm::MaybeAlign{16});
const auto _rdata = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(spu_ptr(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16}); const auto _rdata = m_ir->CreateAlignedLoad(get_type<u128>(), _ptr(spu_ptr(&spu_thread::rdata), m_ir->CreateAnd(diff, 0x70)), llvm::MaybeAlign{16});
const bool is_accurate_op = true || !!g_cfg.core.spu_accurate_reservations; const bool is_accurate_op = !!g_cfg.core.spu_accurate_reservations;
const auto compare_data_change_res = m_ir->CreateICmpNE(_new, _rdata); const auto compare_data_change_res = is_accurate_op ? m_ir->getTrue() : m_ir->CreateICmpNE(_new, _rdata);
const auto second_test_for_complete_op = is_accurate_op ? m_ir->getTrue() : compare_data_change_res;
if (info.runtime16_select) if (info.runtime16_select)
{ {
m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpULT(diff, m_ir->getInt64(128)), second_test_for_complete_op), _begin_op, _inc_res, m_md_likely); m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpULT(diff, m_ir->getInt64(128)), compare_data_change_res), _begin_op, _inc_res, m_md_likely);
} }
else else
{ {
m_ir->CreateCondBr(second_test_for_complete_op, _begin_op, _inc_res, m_md_unlikely); m_ir->CreateCondBr(compare_data_change_res, _begin_op, _inc_res, m_md_unlikely);
} }
m_ir->SetInsertPoint(_begin_op); m_ir->SetInsertPoint(_begin_op);
@ -1340,14 +1323,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
if (!info.no_notify) if (!info.no_notify)
{ {
const auto notify_block = llvm::BasicBlock::Create(m_context, "__putllc16_block_notify", m_function);
const auto notify_next = llvm::BasicBlock::Create(m_context, "__putllc16_block_notify_next", m_function);
m_ir->CreateCondBr(compare_data_change_res, notify_block, notify_next);
m_ir->SetInsertPoint(notify_block);
call("atomic_wait_engine::notify_all", static_cast<void(*)(const void*)>(atomic_wait_engine::notify_all), rptr); call("atomic_wait_engine::notify_all", static_cast<void(*)(const void*)>(atomic_wait_engine::notify_all), rptr);
m_ir->CreateBr(notify_next);
m_ir->SetInsertPoint(notify_next);
} }
m_ir->CreateBr(_success); m_ir->CreateBr(_success);
@ -1397,7 +1373,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
m_ir->SetInsertPoint(_final); m_ir->SetInsertPoint(_final);
} }
void putllc0_pattern(const spu_program& /*prog*/, u64 pattern_info) void putllc0_pattern(const spu_program& /*prog*/, utils::address_range32 /*range*/)
{ {
// Prevent store elimination // Prevent store elimination
m_block->store_context_ctr[s_reg_mfc_eal]++; m_block->store_context_ctr[s_reg_mfc_eal]++;
@ -1425,18 +1401,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
} }
}; };
const union putllc16_or_0_info
{
u64 data;
bf_t<u64, 32, 18> required_pc;
bf_t<u64, 30, 2> type;
bf_t<u64, 29, 1> runtime16_select;
bf_t<u64, 28, 1> no_notify;
bf_t<u64, 18, 8> reg;
bf_t<u64, 0, 18> off18;
bf_t<u64, 0, 8> reg2;
} info = std::bit_cast<putllc16_or_0_info>(pattern_info);
const auto _next = llvm::BasicBlock::Create(m_context, "", m_function); const auto _next = llvm::BasicBlock::Create(m_context, "", m_function);
const auto _next0 = llvm::BasicBlock::Create(m_context, "", m_function); const auto _next0 = llvm::BasicBlock::Create(m_context, "", m_function);
const auto _fail = llvm::BasicBlock::Create(m_context, "", m_function); const auto _fail = llvm::BasicBlock::Create(m_context, "", m_function);
@ -1445,19 +1409,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
const auto _eal = (get_reg_fixed<u32>(s_reg_mfc_eal) & -128).eval(m_ir); const auto _eal = (get_reg_fixed<u32>(s_reg_mfc_eal) & -128).eval(m_ir);
const auto _raddr = m_ir->CreateLoad(get_type<u32>(), spu_ptr(&spu_thread::raddr)); const auto _raddr = m_ir->CreateLoad(get_type<u32>(), spu_ptr(&spu_thread::raddr));
if (info.required_pc && info.required_pc != SPU_LS_SIZE)
{
const auto short_op = llvm::BasicBlock::Create(m_context, "__putllc0_short_op", m_function);
const auto heavy_op = llvm::BasicBlock::Create(m_context, "__putllc0_heavy_op", m_function);
m_ir->CreateCondBr(m_ir->CreateICmpNE(m_ir->getInt32(info.required_pc), m_base_pc), heavy_op, short_op);
m_ir->SetInsertPoint(heavy_op);
update_pc();
call("spu_exec_mfc_cmd", &exec_mfc_cmd<false>, m_thread);
m_ir->CreateBr(_final);
m_ir->SetInsertPoint(short_op);
}
m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpEQ(_eal, _raddr), m_ir->CreateIsNotNull(_raddr)), _next, _fail, m_md_likely); m_ir->CreateCondBr(m_ir->CreateAnd(m_ir->CreateICmpEQ(_eal, _raddr), m_ir->CreateIsNotNull(_raddr)), _next, _fail, m_md_likely);
m_ir->SetInsertPoint(_next); m_ir->SetInsertPoint(_next);
@ -1647,11 +1598,7 @@ public:
// Create LLVM module // Create LLVM module
std::unique_ptr<Module> _module = std::make_unique<Module>(m_hash + ".obj", m_context); std::unique_ptr<Module> _module = std::make_unique<Module>(m_hash + ".obj", m_context);
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
_module->setTargetTriple(Triple(jit_compiler::triple2()));
#else
_module->setTargetTriple(jit_compiler::triple2()); _module->setTargetTriple(jit_compiler::triple2());
#endif
_module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout()); _module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout());
m_module = _module.get(); m_module = _module.get();
@ -1685,7 +1632,7 @@ public:
m_ir->SetInsertPoint(label_test); m_ir->SetInsertPoint(label_test);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if ((g_cfg.core.spu_prof || g_cfg.core.spu_debug) && g_cfg.core.spu_verification) 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) if (!g_cfg.core.spu_verification)
@ -2042,7 +1989,7 @@ public:
set_function(m_functions[m_entry].chunk); set_function(m_functions[m_entry].chunk);
// Set block hash for profiling (if enabled) // Set block hash for profiling (if enabled)
if (g_cfg.core.spu_prof || g_cfg.core.spu_debug) 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_finfo = &m_functions[m_entry];
@ -2192,12 +2139,12 @@ public:
{ {
case inst_attr::putllc0: case inst_attr::putllc0:
{ {
putllc0_pattern(func, m_patterns.at(m_pos - start).info); putllc0_pattern(func, m_patterns.at(m_pos - start).range);
continue; continue;
} }
case inst_attr::putllc16: case inst_attr::putllc16:
{ {
putllc16_pattern(func, m_patterns.at(m_pos - start).info); putllc16_pattern(func, m_patterns.at(m_pos - start).range);
continue; continue;
} }
case inst_attr::omit: case inst_attr::omit:
@ -2280,12 +2227,6 @@ public:
{ {
for (auto& [a, b] : m_blocks) for (auto& [a, b] : m_blocks)
{ {
if (has_gpr_memory_barriers)
{
// Dive deeper and inspect GPR store barriers
break;
}
// Check if the store occurs before any barrier in the block // Check if the store occurs before any barrier in the block
if (b.store[i] && b.store[i] != bs && b.store_context_first_id[i] == 1) if (b.store[i] && b.store[i] != bs && b.store_context_first_id[i] == 1)
{ {
@ -2932,11 +2873,7 @@ public:
// Create LLVM module // Create LLVM module
std::unique_ptr<Module> _module = std::make_unique<Module>("spu_interpreter.obj", m_context); std::unique_ptr<Module> _module = std::make_unique<Module>("spu_interpreter.obj", m_context);
#if LLVM_VERSION_MAJOR >= 21 && (LLVM_VERSION_MINOR >= 1 || LLVM_VERSION_MAJOR >= 22)
_module->setTargetTriple(Triple(jit_compiler::triple2()));
#else
_module->setTargetTriple(jit_compiler::triple2()); _module->setTargetTriple(jit_compiler::triple2());
#endif
_module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout()); _module->setDataLayout(m_jit.get_engine().getTargetMachine()->createDataLayout());
m_module = _module.get(); m_module = _module.get();
@ -4040,7 +3977,7 @@ public:
bool must_use_cpp_functions = !!g_cfg.core.spu_accurate_dma; bool must_use_cpp_functions = !!g_cfg.core.spu_accurate_dma;
if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || g_cfg.video.strict_rendering_mode || /*!g_use_rtm*/ true) if (u64 cmdh = ci->getZExtValue() & ~(MFC_BARRIER_MASK | MFC_FENCE_MASK | MFC_RESULT_MASK); g_cfg.core.rsx_fifo_accuracy || g_cfg.video.strict_rendering_mode || !g_use_rtm)
{ {
// TODO: don't require TSX (current implementation is TSX-only) // TODO: don't require TSX (current implementation is TSX-only)
if (cmdh == MFC_PUT_CMD || cmdh == MFC_SNDSIG_CMD) if (cmdh == MFC_PUT_CMD || cmdh == MFC_SNDSIG_CMD)

View file

@ -397,12 +397,12 @@ protected:
struct pattern_info struct pattern_info
{ {
u64 info; utils::address_range32 range;
}; };
std::unordered_map<u32, pattern_info> m_patterns; std::unordered_map<u32, pattern_info> m_patterns;
void add_pattern(bool fill_all, inst_attr attr, u32 start, u64 info); void add_pattern(bool fill_all, inst_attr attr, u32 start, u32 end = -1);
private: private:
// For private use // For private use

File diff suppressed because it is too large Load diff

View file

@ -901,8 +901,7 @@ public:
// Returns true if reservation existed but was just discovered to be lost // Returns true if reservation existed but was just discovered to be lost
// It is safe to use on any address, even if not directly accessed by SPU (so it's slower) // It is safe to use on any address, even if not directly accessed by SPU (so it's slower)
// Optionally pass a known allocated address for internal optimization (the current Effective-Address of the MFC command) bool reservation_check(u32 addr, const decltype(rdata)& data) const;
bool reservation_check(u32 addr, const decltype(rdata)& data, u32 current_eal = 0) const;
static bool reservation_check(u32 addr, u32 hash, atomic_t<u64, 64>* range_lock); static bool reservation_check(u32 addr, u32 hash, atomic_t<u64, 64>* range_lock);
usz register_cache_line_waiter(u32 addr); usz register_cache_line_waiter(u32 addr);
void deregister_cache_line_waiter(usz index); void deregister_cache_line_waiter(usz index);

View file

@ -1036,6 +1036,7 @@ lv2_file::open_result_t lv2_file::open(std::string_view vpath, s32 flags, s32 mo
error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size) error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, s32 mode, vm::cptr<void> arg, u64 size)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size); sys_fs.warning("sys_fs_open(path=%s, flags=%#o, fd=*0x%x, mode=%#o, arg=*0x%x, size=0x%llx)", path, flags, fd, mode, arg, size);
@ -1084,6 +1085,7 @@ error_code sys_fs_open(ppu_thread& ppu, vm::cptr<char> path, s32 flags, vm::ptr<
error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread) error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, vm::ptr<u64> nread)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread); sys_fs.trace("sys_fs_read(fd=%d, buf=*0x%x, nbytes=0x%llx, nread=*0x%x)", fd, buf, nbytes, nread);
@ -1120,11 +1122,6 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
return CELL_OK; return CELL_OK;
} }
if (nbytes >= 0x100000 && file->type != lv2_file_type::regular)
{
lv2_obj::sleep(ppu);
}
std::unique_lock lock(file->mp->mutex); std::unique_lock lock(file->mp->mutex);
if (!file->file) if (!file->file)
@ -1157,6 +1154,7 @@ error_code sys_fs_read(ppu_thread& ppu, u32 fd, vm::ptr<void> buf, u64 nbytes, v
error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite) error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes, vm::ptr<u64> nwrite)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite); sys_fs.trace("sys_fs_write(fd=%d, buf=*0x%x, nbytes=0x%llx, nwrite=*0x%x)", fd, buf, nbytes, nwrite);
@ -1239,6 +1237,7 @@ error_code sys_fs_write(ppu_thread& ppu, u32 fd, vm::cptr<void> buf, u64 nbytes,
error_code sys_fs_close(ppu_thread& ppu, u32 fd) error_code sys_fs_close(ppu_thread& ppu, u32 fd)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd); const auto file = idm::get_unlocked<lv2_fs_object, lv2_file>(fd);
@ -1315,6 +1314,7 @@ error_code sys_fs_close(ppu_thread& ppu, u32 fd)
error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd) error_code sys_fs_opendir(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u32> fd)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_opendir(path=%s, fd=*0x%x)", path, fd); sys_fs.warning("sys_fs_opendir(path=%s, fd=*0x%x)", path, fd);
@ -1491,6 +1491,7 @@ error_code sys_fs_readdir(ppu_thread& ppu, u32 fd, vm::ptr<CellFsDirent> dir, vm
error_code sys_fs_closedir(ppu_thread& ppu, u32 fd) error_code sys_fs_closedir(ppu_thread& ppu, u32 fd)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_closedir(fd=%d)", fd); sys_fs.warning("sys_fs_closedir(fd=%d)", fd);
@ -1505,6 +1506,7 @@ error_code sys_fs_closedir(ppu_thread& ppu, u32 fd)
error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat> sb) error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat> sb)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_stat(path=%s, sb=*0x%x)", path, sb); sys_fs.warning("sys_fs_stat(path=%s, sb=*0x%x)", path, sb);
@ -1608,6 +1610,7 @@ error_code sys_fs_stat(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<CellFsStat>
error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb) error_code sys_fs_fstat(ppu_thread& ppu, u32 fd, vm::ptr<CellFsStat> sb)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb); sys_fs.warning("sys_fs_fstat(fd=%d, sb=*0x%x)", fd, sb);
@ -1663,6 +1666,7 @@ error_code sys_fs_link(ppu_thread&, vm::cptr<char> from, vm::cptr<char> to)
error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode) error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_mkdir(path=%s, mode=%#o)", path, mode); sys_fs.warning("sys_fs_mkdir(path=%s, mode=%#o)", path, mode);
@ -1724,6 +1728,7 @@ error_code sys_fs_mkdir(ppu_thread& ppu, vm::cptr<char> path, s32 mode)
error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to) error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to); sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to);
@ -1789,6 +1794,7 @@ error_code sys_fs_rename(ppu_thread& ppu, vm::cptr<char> from, vm::cptr<char> to
error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path) error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_rmdir(path=%s)", path); sys_fs.warning("sys_fs_rmdir(path=%s)", path);
@ -1844,6 +1850,7 @@ error_code sys_fs_rmdir(ppu_thread& ppu, vm::cptr<char> path)
error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path) error_code sys_fs_unlink(ppu_thread& ppu, vm::cptr<char> path)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_unlink(path=%s)", path); sys_fs.warning("sys_fs_unlink(path=%s)", path);
@ -1944,6 +1951,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0x8000000a: // cellFsReadWithOffset case 0x8000000a: // cellFsReadWithOffset
case 0x8000000b: // cellFsWriteWithOffset case 0x8000000b: // cellFsWriteWithOffset
{ {
lv2_obj::sleep(ppu);
const auto arg = vm::static_ptr_cast<lv2_file_op_rw>(_arg); const auto arg = vm::static_ptr_cast<lv2_file_op_rw>(_arg);
if (_size < arg.size()) if (_size < arg.size())
@ -1983,11 +1992,6 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
sys_fs.error("%s type: Writing %u bytes to FD=%d (path=%s)", file->type, arg->size, file->name.data()); sys_fs.error("%s type: Writing %u bytes to FD=%d (path=%s)", file->type, arg->size, file->name.data());
} }
if (op == 0x8000000a && file->type != lv2_file_type::regular && arg->size >= 0x100000)
{
lv2_obj::sleep(ppu);
}
std::unique_lock wlock(file->mp->mutex, std::defer_lock); std::unique_lock wlock(file->mp->mutex, std::defer_lock);
std::shared_lock rlock(file->mp->mutex, std::defer_lock); std::shared_lock rlock(file->mp->mutex, std::defer_lock);
@ -2043,6 +2047,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0x80000009: // cellFsSdataOpenByFd case 0x80000009: // cellFsSdataOpenByFd
{ {
lv2_obj::sleep(ppu);
const auto arg = vm::static_ptr_cast<lv2_file_op_09>(_arg); const auto arg = vm::static_ptr_cast<lv2_file_op_09>(_arg);
if (_size < arg.size()) if (_size < arg.size())
@ -2096,6 +2102,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0xc0000002: // cellFsGetFreeSize (TODO) case 0xc0000002: // cellFsGetFreeSize (TODO)
{ {
lv2_obj::sleep(ppu);
const auto arg = vm::static_ptr_cast<lv2_file_c0000002>(_arg); const auto arg = vm::static_ptr_cast<lv2_file_c0000002>(_arg);
const auto& mp = g_fxo->get<lv2_fs_mount_info_map>().lookup("/dev_hdd0"); const auto& mp = g_fxo->get<lv2_fs_mount_info_map>().lookup("/dev_hdd0");
@ -2410,6 +2418,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
case 0xe0000012: // cellFsGetDirectoryEntries case 0xe0000012: // cellFsGetDirectoryEntries
{ {
lv2_obj::sleep(ppu);
const auto arg = vm::static_ptr_cast<lv2_file_op_dir::dir_info>(_arg); const auto arg = vm::static_ptr_cast<lv2_file_op_dir::dir_info>(_arg);
if (_size < arg.size()) if (_size < arg.size())
@ -2424,6 +2434,8 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
return CELL_EBADF; return CELL_EBADF;
} }
ppu.check_state();
u32 read_count = 0; u32 read_count = 0;
// NOTE: This function is actually capable of reading only one entry at a time // NOTE: This function is actually capable of reading only one entry at a time
@ -2581,6 +2593,7 @@ error_code sys_fs_fcntl(ppu_thread& ppu, u32 fd, u32 op, vm::ptr<void> _arg, u32
error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos) error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr<u64> pos)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos); sys_fs.trace("sys_fs_lseek(fd=%d, offset=0x%llx, whence=0x%x, pos=*0x%x)", fd, offset, whence, pos);
@ -2626,6 +2639,7 @@ error_code sys_fs_lseek(ppu_thread& ppu, u32 fd, s64 offset, s32 whence, vm::ptr
error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd) error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.trace("sys_fs_fdadasync(fd=%d)", fd); sys_fs.trace("sys_fs_fdadasync(fd=%d)", fd);
@ -2636,8 +2650,6 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
return CELL_EBADF; return CELL_EBADF;
} }
lv2_obj::sleep(ppu);
std::lock_guard lock(file->mp->mutex); std::lock_guard lock(file->mp->mutex);
if (!file->file) if (!file->file)
@ -2652,6 +2664,7 @@ error_code sys_fs_fdatasync(ppu_thread& ppu, u32 fd)
error_code sys_fs_fsync(ppu_thread& ppu, u32 fd) error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.trace("sys_fs_fsync(fd=%d)", fd); sys_fs.trace("sys_fs_fsync(fd=%d)", fd);
@ -2662,8 +2675,6 @@ error_code sys_fs_fsync(ppu_thread& ppu, u32 fd)
return CELL_EBADF; return CELL_EBADF;
} }
lv2_obj::sleep(ppu);
std::lock_guard lock(file->mp->mutex); std::lock_guard lock(file->mp->mutex);
if (!file->file) if (!file->file)
@ -2752,6 +2763,7 @@ error_code sys_fs_get_block_size(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u
error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size) error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_truncate(path=%s, size=0x%llx)", path, size); sys_fs.warning("sys_fs_truncate(path=%s, size=0x%llx)", path, size);
@ -2803,6 +2815,7 @@ error_code sys_fs_truncate(ppu_thread& ppu, vm::cptr<char> path, u64 size)
error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size) error_code sys_fs_ftruncate(ppu_thread& ppu, u32 fd, u64 size)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size); sys_fs.warning("sys_fs_ftruncate(fd=%d, size=0x%llx)", fd, size);
@ -3008,6 +3021,7 @@ error_code sys_fs_disk_free(ppu_thread& ppu, vm::cptr<char> path, vm::ptr<u64> t
error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUtimbuf> timep) error_code sys_fs_utime(ppu_thread& ppu, vm::cptr<char> path, vm::cptr<CellFsUtimbuf> timep)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
lv2_obj::sleep(ppu);
sys_fs.warning("sys_fs_utime(path=%s, timep=*0x%x)", path, timep); sys_fs.warning("sys_fs_utime(path=%s, timep=*0x%x)", path, timep);
sys_fs.warning("** actime=%u, modtime=%u", timep->actime, timep->modtime); sys_fs.warning("** actime=%u, modtime=%u", timep->actime, timep->modtime);

View file

@ -5,7 +5,6 @@
#include "Emu/CPU/CPUThread.h" #include "Emu/CPU/CPUThread.h"
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
#include "Emu/Cell/SPUThread.h" #include "Emu/Cell/SPUThread.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "util/asm.hpp" #include "util/asm.hpp"
@ -214,8 +213,6 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid
if (alloc_addr) if (alloc_addr)
{ {
sys_memory.notice("sys_memory_allocate_from_container(): Allocated 0x%x address (size=0x%x)", addr, size);
vm::lock_sudo(addr, static_cast<u32>(size)); vm::lock_sudo(addr, static_cast<u32>(size));
cpu.check_state(); cpu.check_state();
*alloc_addr = addr; *alloc_addr = addr;
@ -250,37 +247,17 @@ error_code sys_memory_free(cpu_thread& cpu, u32 addr)
return CELL_OK; return CELL_OK;
} }
error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr<sys_page_attr_t> attr) error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr)
{ {
ppu.state += cpu_flag::wait; cpu.state += cpu_flag::wait;
sys_memory.trace("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr); sys_memory.trace("sys_memory_get_page_attribute(addr=0x%x, attr=*0x%x)", addr, attr);
if ((addr >> 28) == (ppu.stack_addr >> 28)) vm::writer_lock rlock;
if (!vm::check_addr(addr) || addr >= SPU_FAKE_BASE_ADDR)
{ {
// Stack address: fast path return CELL_EINVAL;
if (!(addr >= ppu.stack_addr && addr < ppu.stack_addr + ppu.stack_size) && !vm::check_addr(addr))
{
return { CELL_EINVAL, addr };
}
if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
{
return CELL_EFAULT;
}
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE
attr->access_right = SYS_MEMORY_ACCESS_RIGHT_PPU_THR;
attr->page_size = 4096;
attr->pad = 0; // Always write 0
return CELL_OK;
}
const auto [ok, vm_flags] = vm::get_addr_flags(addr);
if (!ok || addr >= SPU_FAKE_BASE_ADDR)
{
return { CELL_EINVAL, addr };
} }
if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size())) if (!vm::check_addr(attr.addr(), vm::page_readable, attr.size()))
@ -289,20 +266,19 @@ error_code sys_memory_get_page_attribute(ppu_thread& ppu, u32 addr, vm::ptr<sys_
} }
attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE (TODO) attr->attribute = 0x40000ull; // SYS_MEMORY_PROT_READ_WRITE (TODO)
attr->access_right = SYS_MEMORY_ACCESS_RIGHT_ANY; // TODO: Report accurately attr->access_right = addr >> 28 == 0xdu ? SYS_MEMORY_ACCESS_RIGHT_PPU_THR : SYS_MEMORY_ACCESS_RIGHT_ANY;// (TODO)
if (vm_flags & vm::page_1m_size) if (vm::check_addr(addr, vm::page_1m_size))
{ {
attr->page_size = 0x100000; attr->page_size = 0x100000;
} }
else if (vm_flags & vm::page_64k_size) else if (vm::check_addr(addr, vm::page_64k_size))
{ {
attr->page_size = 0x10000; attr->page_size = 0x10000;
} }
else else
{ {
//attr->page_size = 4096; attr->page_size = 4096;
fmt::throw_exception("Unreachable");
} }
attr->pad = 0; // Always write 0 attr->pad = 0; // Always write 0

View file

@ -4,7 +4,6 @@
#include "Emu/Cell/ErrorCodes.h" #include "Emu/Cell/ErrorCodes.h"
class cpu_thread; class cpu_thread;
class ppu_thread;
enum lv2_mem_container_id : u32 enum lv2_mem_container_id : u32
{ {
@ -132,7 +131,7 @@ struct sys_memory_user_memory_stat_t
error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr); error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr); error_code sys_memory_allocate_from_container(cpu_thread& cpu, u64 size, u32 cid, u64 flags, vm::ptr<u32> alloc_addr);
error_code sys_memory_free(cpu_thread& cpu, u32 start_addr); error_code sys_memory_free(cpu_thread& cpu, u32 start_addr);
error_code sys_memory_get_page_attribute(ppu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr); error_code sys_memory_get_page_attribute(cpu_thread& cpu, u32 addr, vm::ptr<sys_page_attr_t> attr);
error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info); error_code sys_memory_get_user_memory_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info);
error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_user_memory_stat_t> mem_stat); error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_user_memory_stat_t> mem_stat);
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size); error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size);

View file

@ -468,11 +468,11 @@ error_code sys_ppu_thread_restart(ppu_thread& ppu)
return CELL_OK; return CELL_OK;
} }
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u64 _stacksz, u64 flags, vm::cptr<char> threadname) error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 unk, s32 prio, u32 _stacksz, u64 flags, vm::cptr<char> threadname)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
sys_ppu_thread.warning("_sys_ppu_thread_create(thread_id=*0x%x, param=*0x%x, arg=0x%llx, unk=0x%llx, prio=%d, stacksize=0x%llx, flags=0x%llx, threadname=*0x%x)", sys_ppu_thread.warning("_sys_ppu_thread_create(thread_id=*0x%x, param=*0x%x, arg=0x%llx, unk=0x%llx, prio=%d, stacksize=0x%x, flags=0x%llx, threadname=*0x%x)",
thread_id, param, arg, unk, prio, _stacksz, flags, threadname); thread_id, param, arg, unk, prio, _stacksz, flags, threadname);
// thread_id is checked for null in stub -> CELL_ENOMEM // thread_id is checked for null in stub -> CELL_ENOMEM
@ -497,8 +497,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
const u32 tls = param->tls; const u32 tls = param->tls;
// Compute actual stack size and allocate // Compute actual stack size and allocate
// 0 and UINT64_MAX both convert to 4096 const u32 stack_size = utils::align<u32>(std::max<u32>(_stacksz, 4096), 4096);
const u64 stack_size = FN(x ? x : 4096)(utils::align<u64>(_stacksz, 4096));
auto& dct = g_fxo->get<lv2_memory_container>(); auto& dct = g_fxo->get<lv2_memory_container>();
@ -508,7 +507,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
return {CELL_ENOMEM, dct.size - dct.used}; return {CELL_ENOMEM, dct.size - dct.used};
} }
const vm::addr_t stack_base{vm::alloc(static_cast<u32>(stack_size), vm::stack, 4096)}; const vm::addr_t stack_base{vm::alloc(stack_size, vm::stack, 4096)};
if (!stack_base) if (!stack_base)
{ {
@ -533,7 +532,7 @@ error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::p
{ {
ppu_thread_params p; ppu_thread_params p;
p.stack_addr = stack_base; p.stack_addr = stack_base;
p.stack_size = static_cast<u32>(stack_size); p.stack_size = stack_size;
p.tls_addr = tls; p.tls_addr = tls;
p.entry = entry; p.entry = entry;
p.arg0 = arg; p.arg0 = arg;

View file

@ -53,7 +53,7 @@ error_code sys_ppu_thread_get_priority(ppu_thread& ppu, u32 thread_id, vm::ptr<s
error_code sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp); error_code sys_ppu_thread_get_stack_information(ppu_thread& ppu, vm::ptr<sys_ppu_thread_stack_t> sp);
error_code sys_ppu_thread_stop(ppu_thread& ppu, u32 thread_id); error_code sys_ppu_thread_stop(ppu_thread& ppu, u32 thread_id);
error_code sys_ppu_thread_restart(ppu_thread& ppu); error_code sys_ppu_thread_restart(ppu_thread& ppu);
error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 arg4, s32 prio, u64 stacksize, u64 flags, vm::cptr<char> threadname); error_code _sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, vm::ptr<ppu_thread_param_t> param, u64 arg, u64 arg4, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname);
error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id); error_code sys_ppu_thread_start(ppu_thread& ppu, u32 thread_id);
error_code sys_ppu_thread_rename(ppu_thread& ppu, u32 thread_id, vm::cptr<char> name); error_code sys_ppu_thread_rename(ppu_thread& ppu, u32 thread_id, vm::cptr<char> name);
error_code sys_ppu_thread_recover_page_fault(ppu_thread& ppu, u32 thread_id); error_code sys_ppu_thread_recover_page_fault(ppu_thread& ppu, u32 thread_id);

View file

@ -767,12 +767,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
} }
// Read thread name // Read thread name
std::string thread_name; const std::string thread_name(attr_data.name.get_ptr(), std::max<u32>(attr_data.name_len, 1) - 1);
if (attr_data.name_len && !vm::read_string(attr_data.name.addr(), attr_data.name_len - 1, thread_name, true))
{
return { CELL_EFAULT, attr_data.name.addr() };
}
const auto group = idm::get_unlocked<lv2_spu_group>(group_id); const auto group = idm::get_unlocked<lv2_spu_group>(group_id);
@ -911,7 +906,7 @@ error_code sys_spu_thread_get_exit_status(ppu_thread& ppu, u32 id, vm::ptr<s32>
return CELL_ESTAT; return CELL_ESTAT;
} }
error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<reduced_sys_spu_thread_group_attribute> attr) error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr)
{ {
ppu.state += cpu_flag::wait; ppu.state += cpu_flag::wait;
@ -919,32 +914,13 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16; const s32 min_prio = g_ps3_process_info.has_root_perm() ? 0 : 16;
sys_spu_thread_group_attribute attr_data{}; const sys_spu_thread_group_attribute attr_data = *attr;
{
const reduced_sys_spu_thread_group_attribute attr_reduced = *attr;
attr_data.name = attr_reduced.name;
attr_data.nsize = attr_reduced.nsize;
attr_data.type = attr_reduced.type;
// Read container-id member at offset 12 bytes conditionally (that's what LV2 does)
if (attr_data.type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER)
{
attr_data.ct = vm::unsafe_ptr_cast<sys_spu_thread_group_attribute>(attr)->ct;
}
}
if (attr_data.nsize > 0x80 || !num) if (attr_data.nsize > 0x80 || !num)
{ {
return CELL_EINVAL; return CELL_EINVAL;
} }
std::string group_name;
if (attr_data.nsize && !vm::read_string(attr_data.name.addr(), attr_data.nsize - 1, group_name, true))
{
return { CELL_EFAULT, attr_data.name.addr() };
}
const s32 type = attr_data.type; const s32 type = attr_data.type;
bool use_scheduler = true; bool use_scheduler = true;
@ -1099,7 +1075,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
return CELL_EBUSY; return CELL_EBUSY;
} }
const auto group = idm::make_ptr<lv2_spu_group>(std::move(group_name), num, prio, type, ct, use_scheduler, mem_size); const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr_data.name.get_ptr(), std::max<u32>(attr_data.nsize, 1) - 1), num, prio, type, ct, use_scheduler, mem_size);
if (!group) if (!group)
{ {

View file

@ -82,16 +82,9 @@ enum spu_stop_syscall : u32
SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE = 0x0120, SYS_SPU_THREAD_STOP_SWITCH_SYSTEM_MODULE = 0x0120,
}; };
struct reduced_sys_spu_thread_group_attribute
{
be_t<u32> nsize; // name length including NULL terminator
vm::bcptr<char> name;
be_t<s32> type;
};
struct sys_spu_thread_group_attribute struct sys_spu_thread_group_attribute
{ {
be_t<u32> nsize; be_t<u32> nsize; // name length including NULL terminator
vm::bcptr<char> name; vm::bcptr<char> name;
be_t<s32> type; be_t<s32> type;
be_t<u32> ct; // memory container id be_t<u32> ct; // memory container id
@ -367,7 +360,7 @@ error_code _sys_spu_image_close(ppu_thread&, vm::ptr<sys_spu_image> img);
error_code _sys_spu_image_get_segments(ppu_thread&, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg); error_code _sys_spu_image_get_segments(ppu_thread&, vm::ptr<sys_spu_image> img, vm::ptr<sys_spu_segment> segments, s32 nseg);
error_code sys_spu_thread_initialize(ppu_thread&, vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image>, vm::ptr<sys_spu_thread_attribute>, vm::ptr<sys_spu_thread_argument>); error_code sys_spu_thread_initialize(ppu_thread&, vm::ptr<u32> thread, u32 group, u32 spu_num, vm::ptr<sys_spu_image>, vm::ptr<sys_spu_thread_attribute>, vm::ptr<sys_spu_thread_argument>);
error_code sys_spu_thread_set_argument(ppu_thread&, u32 id, vm::ptr<sys_spu_thread_argument> arg); error_code sys_spu_thread_set_argument(ppu_thread&, u32 id, vm::ptr<sys_spu_thread_argument> arg);
error_code sys_spu_thread_group_create(ppu_thread&, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<reduced_sys_spu_thread_group_attribute> attr); error_code sys_spu_thread_group_create(ppu_thread&, vm::ptr<u32> id, u32 num, s32 prio, vm::ptr<sys_spu_thread_group_attribute> attr);
error_code sys_spu_thread_group_destroy(ppu_thread&, u32 id); error_code sys_spu_thread_group_destroy(ppu_thread&, u32 id);
error_code sys_spu_thread_group_start(ppu_thread&, u32 id); error_code sys_spu_thread_group_start(ppu_thread&, u32 id);
error_code sys_spu_thread_group_suspend(ppu_thread&, u32 id); error_code sys_spu_thread_group_suspend(ppu_thread&, u32 id);

View file

@ -210,10 +210,8 @@ error_code sys_ss_get_open_psid(vm::ptr<CellSsOpenPSID> psid)
{ {
sys_ss.notice("sys_ss_get_open_psid(psid=*0x%x)", psid); sys_ss.notice("sys_ss_get_open_psid(psid=*0x%x)", psid);
const u128 configured_psid = g_cfg.sys.console_psid.get(); psid->high = g_cfg.sys.console_psid_high;
psid->low = g_cfg.sys.console_psid_low;
psid->high = static_cast<u64>(configured_psid >> 64);
psid->low = static_cast<u64>(configured_psid);
return CELL_OK; return CELL_OK;
} }
@ -261,8 +259,8 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr<u8> buffer)
case 0x19005: case 0x19005:
{ {
// AIM_get_open_ps_id // AIM_get_open_ps_id
const be_t<u128> psid = g_cfg.sys.console_psid.get(); be_t<u64> psid[2] = { +g_cfg.sys.console_psid_high, +g_cfg.sys.console_psid_low };
std::memcpy(buffer.get_ptr(), &psid, 16); std::memcpy(buffer.get_ptr(), psid, 16);
break; break;
} }
case 0x19006: case 0x19006:
@ -270,11 +268,7 @@ error_code sys_ss_appliance_info_manager(u32 code, vm::ptr<u8> buffer)
// qa values (dex only) ?? // qa values (dex only) ??
[[fallthrough]]; [[fallthrough]];
} }
default: default: sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer);
{
sys_ss.todo("sys_ss_appliance_info_manager(code=0x%x, buffer=*0x%x)", code, buffer);
break;
}
} }
return CELL_OK; return CELL_OK;

View file

@ -18,7 +18,6 @@
#include "Emu/Io/Skylander.h" #include "Emu/Io/Skylander.h"
#include "Emu/Io/Infinity.h" #include "Emu/Io/Infinity.h"
#include "Emu/Io/Dimensions.h" #include "Emu/Io/Dimensions.h"
#include "Emu/Io/KamenRider.h"
#include "Emu/Io/GHLtar.h" #include "Emu/Io/GHLtar.h"
#include "Emu/Io/ghltar_config.h" #include "Emu/Io/ghltar_config.h"
#include "Emu/Io/guncon3_config.h" #include "Emu/Io/guncon3_config.h"
@ -176,7 +175,7 @@ private:
{0x1430, 0x0150, 0x0150, "Skylanders Portal", &usb_device_skylander::get_num_emu_devices, &usb_device_skylander::make_instance}, {0x1430, 0x0150, 0x0150, "Skylanders Portal", &usb_device_skylander::get_num_emu_devices, &usb_device_skylander::make_instance},
{0x0E6F, 0x0129, 0x0129, "Disney Infinity Base", &usb_device_infinity::get_num_emu_devices, &usb_device_infinity::make_instance}, {0x0E6F, 0x0129, 0x0129, "Disney Infinity Base", &usb_device_infinity::get_num_emu_devices, &usb_device_infinity::make_instance},
{0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal", &usb_device_dimensions::get_num_emu_devices, &usb_device_dimensions::make_instance}, {0x0E6F, 0x0241, 0x0241, "Lego Dimensions Portal", &usb_device_dimensions::get_num_emu_devices, &usb_device_dimensions::make_instance},
{0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal", &usb_device_kamen_rider::get_num_emu_devices, &usb_device_kamen_rider::make_instance}, {0x0E6F, 0x200A, 0x200A, "Kamen Rider Summonride Portal", nullptr, nullptr},
// Cameras // Cameras
// {0x1415, 0x0020, 0x2000, "Sony Playstation Eye", nullptr, nullptr}, // TODO: verifiy // {0x1415, 0x0020, 0x2000, "Sony Playstation Eye", nullptr, nullptr}, // TODO: verifiy

View file

@ -544,7 +544,9 @@ std::optional<std::array<u8, 32>> dimensions_toypad::pop_added_removed_response(
std::lock_guard lock(m_dimensions_mutex); std::lock_guard lock(m_dimensions_mutex);
if (m_figure_added_removed_responses.empty()) if (m_figure_added_removed_responses.empty())
{
return std::nullopt; return std::nullopt;
}
std::array<u8, 32> response = m_figure_added_removed_responses.front(); std::array<u8, 32> response = m_figure_added_removed_responses.front();
m_figure_added_removed_responses.pop(); m_figure_added_removed_responses.pop();
@ -595,6 +597,7 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi
{ {
// Read Endpoint, if a request has not been sent via the write endpoint, set expected result as // Read Endpoint, if a request has not been sent via the write endpoint, set expected result as
// EHCI_CC_HALTED so the game doesn't report the Toypad as being disconnected. // EHCI_CC_HALTED so the game doesn't report the Toypad as being disconnected.
std::lock_guard lock(m_query_mutex);
std::optional<std::array<u8, 32>> response = g_dimensionstoypad.pop_added_removed_response(); std::optional<std::array<u8, 32>> response = g_dimensionstoypad.pop_added_removed_response();
if (response) if (response)
{ {
@ -693,6 +696,7 @@ void usb_device_dimensions::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoi
break; break;
} }
} }
std::lock_guard lock(m_query_mutex);
m_queries.push(q_result); m_queries.push(q_result);
break; break;
} }

View file

@ -79,5 +79,6 @@ public:
void isochronous_transfer(UsbTransfer* transfer) override; void isochronous_transfer(UsbTransfer* transfer) override;
protected: protected:
shared_mutex m_query_mutex;
std::queue<std::array<u8, 32>> m_queries; std::queue<std::array<u8, 32>> m_queries;
}; };

View file

@ -258,13 +258,13 @@ void infinity_base::get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8
reply_buf[11] = generate_checksum(reply_buf, 11); reply_buf[11] = generate_checksum(reply_buf, 11);
} }
std::optional<std::array<u8, 32>> infinity_base::pop_added_removed_response() bool infinity_base::has_figure_been_added_removed() const
{ {
std::lock_guard lock(infinity_mutex); return !m_figure_added_removed_responses.empty();
}
if (m_figure_added_removed_responses.empty())
return std::nullopt;
std::array<u8, 32> infinity_base::pop_added_removed_response()
{
std::array<u8, 32> response = m_figure_added_removed_responses.front(); std::array<u8, 32> response = m_figure_added_removed_responses.front();
m_figure_added_removed_responses.pop(); m_figure_added_removed_responses.pop();
return response; return response;
@ -399,10 +399,9 @@ void usb_device_infinity::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint
{ {
// Respond after FF command // Respond after FF command
transfer->expected_time = get_timestamp() + 1000; transfer->expected_time = get_timestamp() + 1000;
std::optional<std::array<u8, 32>> response = g_infinitybase.pop_added_removed_response(); if (g_infinitybase.has_figure_been_added_removed())
if (response)
{ {
memcpy(buf, response.value().data(), 0x20); memcpy(buf, g_infinitybase.pop_added_removed_response().data(), 0x20);
} }
else if (!m_queries.empty()) else if (!m_queries.empty())
{ {

View file

@ -3,7 +3,6 @@
#include "Emu/Io/usb_device.h" #include "Emu/Io/usb_device.h"
#include "Utilities/mutex.h" #include "Utilities/mutex.h"
#include <array> #include <array>
#include <optional>
#include <queue> #include <queue>
struct infinity_figure struct infinity_figure
@ -25,7 +24,8 @@ public:
void query_block(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence); void query_block(u8 fig_num, u8 block, std::array<u8, 32>& reply_buf, u8 sequence);
void write_block(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf, u8 sequence); void write_block(u8 fig_num, u8 block, const u8* to_write_buf, std::array<u8, 32>& reply_buf, u8 sequence);
void get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf); void get_figure_identifier(u8 fig_num, u8 sequence, std::array<u8, 32>& reply_buf);
std::optional<std::array<u8, 32>> pop_added_removed_response(); bool has_figure_been_added_removed() const;
std::array<u8, 32> pop_added_removed_response();
bool remove_figure(u8 position); bool remove_figure(u8 position);
u32 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file, u8 position); u32 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file, u8 position);

View file

@ -1,291 +0,0 @@
#include "stdafx.h"
#include "KamenRider.h"
LOG_CHANNEL(kamen_rider_log, "kamen_rider");
rider_gate g_ridergate;
void kamen_rider_figure::save()
{
if (!kamen_file)
{
kamen_rider_log.error("Tried to save kamen rider figure to file but no kamen rider figure is active!");
return;
}
kamen_file.seek(0, fs::seek_set);
kamen_file.write(data.data(), 0x14 * 0x10);
}
u8 rider_gate::generate_checksum(const std::array<u8, 64>& data, u32 num_of_bytes) const
{
ensure(num_of_bytes <= data.size());
int checksum = 0;
for (u32 i = 0; i < num_of_bytes; i++)
{
checksum += data[i];
}
return (checksum & 0xFF);
}
kamen_rider_figure& rider_gate::get_figure_by_uid(const std::array<u8, 7> uid)
{
for (kamen_rider_figure& figure : figures)
{
if (figure.uid == uid)
{
return figure;
}
}
return figures[7];
}
void rider_gate::get_blank_response(u8 command, u8 sequence, std::array<u8, 64>& reply_buf)
{
reply_buf = {0x55, 0x02, command, sequence};
reply_buf[4] = generate_checksum(reply_buf, 4);
}
void rider_gate::wake_rider_gate(std::array<u8, 64>& reply_buf, u8 command, u8 sequence)
{
std::lock_guard lock(kamen_mutex);
m_is_awake = true;
reply_buf = {0x55, 0x1a, command, sequence, 0x00, 0x07, 0x00, 0x03, 0x02,
0x09, 0x20, 0x03, 0xf5, 0x00, 0x19, 0x42, 0x52, 0xb7,
0xb9, 0xa1, 0xae, 0x2b, 0x88, 0x42, 0x05, 0xfe, 0xe0, 0x1c, 0xac};
}
void rider_gate::get_list_tags(std::array<u8, 64>& reply_buf, u8 command, u8 sequence)
{
std::lock_guard lock(kamen_mutex);
reply_buf = {0x55, 0x02, command, sequence};
u8 index = 4;
for (const kamen_rider_figure& figure : figures)
{
if (figure.present)
{
reply_buf[index] = 0x09;
memcpy(&reply_buf[index + 1], figure.data.data(), 7);
index += 8;
reply_buf[1] += 8;
}
}
reply_buf[index] = generate_checksum(reply_buf, index);
}
void rider_gate::query_block(std::array<u8, 64>& reply_buf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block)
{
std::lock_guard lock(kamen_mutex);
reply_buf = {0x55, 0x13, command, sequence, 0x00};
const std::array<u8, 7> uid_array = {uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
const kamen_rider_figure& figure = get_figure_by_uid(uid_array);
if (figure.present)
{
if (sector < 5 && block < 4)
{
memcpy(&reply_buf[5], &figure.data[(sector * 4 * 16) + (block * 16)], 16);
}
}
reply_buf[21] = generate_checksum(reply_buf, 21);
}
void rider_gate::write_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block, const u8* to_write_buf)
{
std::lock_guard lock(kamen_mutex);
const std::array<u8, 7> uid_array = {uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6]};
kamen_rider_figure& figure = get_figure_by_uid(uid_array);
if (figure.present)
{
if (sector < 5 && block < 4)
{
memcpy(&figure.data[(sector * 4 * 16) + (block * 16)], to_write_buf, 16);
}
}
get_blank_response(command, sequence, replyBuf);
}
std::optional<std::array<u8, 64>> rider_gate::pop_added_removed_response()
{
std::lock_guard lock(kamen_mutex);
if (m_figure_added_removed_responses.empty())
{
return std::nullopt;
}
std::array<u8, 64> response = m_figure_added_removed_responses.front();
m_figure_added_removed_responses.pop();
return response;
}
bool rider_gate::remove_figure(u8 index)
{
std::lock_guard lock(kamen_mutex);
auto& figure = figures[index];
if (figure.present)
{
figure.present = false;
figure.save();
figure.kamen_file.close();
if (m_is_awake)
{
std::array<u8, 64> figure_removed_response = {0x56, 0x09, 0x09, 0x00};
memcpy(&figure_removed_response[4], figure.uid.data(), figure.uid.size());
figure_removed_response[11] = generate_checksum(figure_removed_response, 11);
m_figure_added_removed_responses.push(std::move(figure_removed_response));
}
figure.uid = {};
return true;
}
return false;
}
u8 rider_gate::load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file)
{
std::lock_guard lock(kamen_mutex);
u8 found_slot = 0xFF;
// mimics spot retaining on the portal
for (auto i = 0; i < 7; i++)
{
if (!figures[i].present)
{
if (i < found_slot)
{
found_slot = i;
}
}
}
if (found_slot != 0xFF)
{
auto& figure = figures[found_slot];
memcpy(figure.data.data(), buf.data(), buf.size());
figure.kamen_file = std::move(in_file);
figure.uid = {buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]};
figure.present = true;
if (m_is_awake)
{
std::array<u8, 64> figure_added_response = {0x56, 0x09, 0x09, 0x01};
memcpy(&figure_added_response[4], figure.uid.data(), figure.uid.size());
figure_added_response[11] = generate_checksum(figure_added_response, 11);
m_figure_added_removed_responses.push(std::move(figure_added_response));
}
}
return found_slot;
}
usb_device_kamen_rider::usb_device_kamen_rider(const std::array<u8, 7>& location)
: usb_device_emulated(location)
{
device = UsbDescriptorNode(USB_DESCRIPTOR_DEVICE, UsbDeviceDescriptor{0x200, 0x0, 0x0, 0x0, 0x40, 0x0E6F, 0x200A, 0x100, 0x1, 0x2, 0x3, 0x1});
auto& config0 = device.add_node(UsbDescriptorNode(USB_DESCRIPTOR_CONFIG, UsbDeviceConfiguration{0x29, 0x1, 0x1, 0x0, 0x80, 0xFA}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_INTERFACE, UsbDeviceInterface{0x0, 0x0, 0x2, 0x3, 0x0, 0x0, 0x0}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x81, 0x3, 0x40, 0x1}));
config0.add_node(UsbDescriptorNode(USB_DESCRIPTOR_ENDPOINT, UsbDeviceEndpoint{0x1, 0x3, 0x40, 0x1}));
}
usb_device_kamen_rider::~usb_device_kamen_rider()
{
}
std::shared_ptr<usb_device> usb_device_kamen_rider::make_instance(u32, const std::array<u8, 7>& location)
{
return std::make_shared<usb_device_kamen_rider>(location);
}
u16 usb_device_kamen_rider::get_num_emu_devices()
{
return 1;
}
void usb_device_kamen_rider::control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer)
{
usb_device_emulated::control_transfer(bmRequestType, bRequest, wValue, wIndex, wLength, buf_size, buf, transfer);
}
void usb_device_kamen_rider::interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer)
{
ensure(buf_size == 0x40);
transfer->fake = true;
transfer->expected_count = buf_size;
transfer->expected_result = HC_CC_NOERR;
if (endpoint == 0x81)
{
// Respond after FF command
transfer->expected_time = get_timestamp() + 1000;
std::optional<std::array<u8, 64>> response = g_ridergate.pop_added_removed_response();
if (response)
{
memcpy(buf, response.value().data(), 0x40);
}
else if (!m_queries.empty())
{
memcpy(buf, m_queries.front().data(), 0x20);
m_queries.pop();
}
else
{
transfer->expected_count = 0;
transfer->expected_result = EHCI_CC_HALTED;
}
}
else if (endpoint == 0x01)
{
const u8 command = buf[2];
const u8 sequence = buf[3];
std::array<u8, 64> q_result{};
switch (command)
{
case 0xB0: // Wake
{
g_ridergate.wake_rider_gate(q_result, command, sequence);
break;
}
case 0xC0:
case 0xC3: // Color Commands
{
g_ridergate.get_blank_response(command, sequence, q_result);
break;
}
case 0xD0: // Tag List
{
// Return list of figure UIDs, separated by an 09
g_ridergate.get_list_tags(q_result, command, sequence);
break;
}
case 0xD2: // Read
{
// Read 16 bytes from figure with UID buf[4] - buf[10]
g_ridergate.query_block(q_result, command, sequence, &buf[4], buf[11], buf[12]);
break;
}
case 0xD3:
{
// Write 16 bytes to figure with UID buf[4] - buf[10]
g_ridergate.write_block(q_result, command, sequence, &buf[4], buf[11], buf[12], &buf[13]);
break;
}
default:
kamen_rider_log.error("Unhandled Query Type: 0x%02X", command);
break;
}
m_queries.push(std::move(q_result));
}
}

View file

@ -1,60 +0,0 @@
#pragma once
#include "Emu/Io/usb_device.h"
#include "Utilities/mutex.h"
#include <array>
#include <optional>
#include <queue>
struct kamen_rider_figure
{
fs::file kamen_file;
std::array<u8, 0x14 * 0x10> data{};
std::array<u8, 7> uid{};
bool present = false;
void save();
};
class rider_gate
{
public:
void get_blank_response(u8 command, u8 sequence, std::array<u8, 64>& reply_buf);
void wake_rider_gate(std::array<u8, 64>& replyBuf, u8 command, u8 sequence);
void get_list_tags(std::array<u8, 64>& replyBuf, u8 command, u8 sequence);
void query_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block);
void write_block(std::array<u8, 64>& replyBuf, u8 command, u8 sequence, const u8* uid, u8 sector, u8 block, const u8* to_write_buf);
std::optional<std::array<u8, 64>> pop_added_removed_response();
bool remove_figure(u8 position);
u8 load_figure(const std::array<u8, 0x14 * 0x10>& buf, fs::file in_file);
protected:
shared_mutex kamen_mutex;
std::array<kamen_rider_figure, 8> figures{};
private:
u8 generate_checksum(const std::array<u8, 64>& data, u32 num_of_bytes) const;
kamen_rider_figure& get_figure_by_uid(const std::array<u8, 7> uid);
std::queue<std::array<u8, 64>> m_figure_added_removed_responses;
bool m_is_awake = false;
};
extern rider_gate g_ridergate;
class usb_device_kamen_rider : public usb_device_emulated
{
public:
usb_device_kamen_rider(const std::array<u8, 7>& location);
~usb_device_kamen_rider();
static std::shared_ptr<usb_device> make_instance(u32 controller_index, const std::array<u8, 7>& location);
static u16 get_num_emu_devices();
void control_transfer(u8 bmRequestType, u8 bRequest, u16 wValue, u16 wIndex, u16 wLength, u32 buf_size, u8* buf, UsbTransfer* transfer) override;
void interrupt_transfer(u32 buf_size, u8* buf, u32 endpoint, UsbTransfer* transfer) override;
protected:
std::queue<std::array<u8, 64>> m_queries;
};

View file

@ -170,7 +170,7 @@ u16 PadHandlerBase::ConvertAxis(f32 value)
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle // The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange // using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of ~4000 // this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255 // This function assumes inX and inY is already in 0-255
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor) void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
{ {
@ -208,21 +208,6 @@ void PadHandlerBase::init_configs()
} }
} }
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) cfg_pad* PadHandlerBase::get_config(const std::string& pad_id)
{ {
int index = 0; int index = 0;
@ -346,13 +331,12 @@ PadHandlerBase::connection PadHandlerBase::get_next_button_press(const std::stri
if (callback) if (callback)
{ {
pad_preview_values preview_values = get_preview_values(data); 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); const u32 battery_level = get_battery_level(pad_id);
if (pressed_button.value > 0) if (pressed_button.value > 0)
callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values), std::move(capabilities)); callback(pressed_button.value, pressed_button.name, pad_id, battery_level, std::move(preview_values));
else else
callback(0, "", pad_id, battery_level, std::move(preview_values), std::move(capabilities)); callback(0, "", pad_id, battery_level, std::move(preview_values));
} }
return status; return status;

View file

@ -81,20 +81,8 @@ 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<int, 6>; using pad_preview_values = std::array<int, 6>;
using pad_callback = std::function<void(u16 /*button_value*/, std::string /*button_name*/, std::string /*pad_name*/, u32 /*battery_level*/, pad_preview_values, pad_capabilities)>; using pad_callback = std::function<void(u16 /*button_value*/, std::string /*button_name*/, std::string /*pad_name*/, u32 /*battery_level*/, pad_preview_values /*preview_values*/)>;
using pad_fail_callback = std::function<void(std::string /*pad_name*/)>; using pad_fail_callback = std::function<void(std::string /*pad_name*/)>;
using motion_preview_values = std::array<u16, 4>; using motion_preview_values = std::array<u16, 4>;
@ -338,8 +326,6 @@ public:
bool has_analog_limiter_button() const { return b_has_analog_limiter_button; } bool has_analog_limiter_button() const { return b_has_analog_limiter_button; }
bool has_orientation() const { return b_has_orientation; } 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; 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 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; } void set_trigger_recognition_mode(trigger_recognition_mode mode) { m_trigger_recognition_mode = mode; }

View file

@ -88,8 +88,8 @@ struct cfg_pad final : cfg::node
cfg::uint<0, 1000000> rstick_anti_deadzone{ this, "Right Stick Anti-Deadzone", 0 }; cfg::uint<0, 1000000> rstick_anti_deadzone{ this, "Right Stick Anti-Deadzone", 0 };
cfg::uint<0, 1000000> ltriggerthreshold{ this, "Left Trigger Threshold", 0 }; cfg::uint<0, 1000000> ltriggerthreshold{ this, "Left Trigger Threshold", 0 };
cfg::uint<0, 1000000> rtriggerthreshold{ this, "Right Trigger Threshold", 0 }; cfg::uint<0, 1000000> rtriggerthreshold{ this, "Right Trigger Threshold", 0 };
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 4000 }; cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 8000 };
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 4000 }; cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 8000 };
cfg::uint<0, 255> colorR{ this, "Color Value R", 0 }; cfg::uint<0, 255> colorR{ this, "Color Value R", 0 };
cfg::uint<0, 255> colorG{ this, "Color Value G", 0 }; cfg::uint<0, 255> colorG{ this, "Color Value G", 0 };

View file

@ -217,12 +217,6 @@ bool Pad::get_analog_limiter_button_active(bool is_toggle_mode, u32 player_id)
const Button& analog_limiter_button = m_buttons[m_analog_limiter_button_index]; const Button& analog_limiter_button = m_buttons[m_analog_limiter_button_index];
if (analog_limiter_button.m_key_codes.empty())
{
// Active by default if no button was assigned
return true;
}
if (is_toggle_mode) if (is_toggle_mode)
{ {
const bool pressed = analog_limiter_button.m_pressed; const bool pressed = analog_limiter_button.m_pressed;

View file

@ -98,6 +98,7 @@ namespace vm
void reservation_update(u32 addr) void reservation_update(u32 addr)
{ {
u64 old = -1;
const auto cpu = get_current_cpu_thread(); const auto cpu = get_current_cpu_thread();
const bool had_wait = cpu && cpu->state & cpu_flag::wait; const bool had_wait = cpu && cpu->state & cpu_flag::wait;
@ -125,6 +126,8 @@ namespace vm
return; return;
} }
old = rtime;
} }
} }
@ -547,13 +550,6 @@ namespace vm
{ {
to_clear = for_all_range_locks(to_clear & ~get_range_lock_bits(true), [&](u64 addr2, u32 size2) to_clear = for_all_range_locks(to_clear & ~get_range_lock_bits(true), [&](u64 addr2, u32 size2)
{ {
constexpr u32 range_size_loc = vm::range_pos - 32;
if ((size2 >> range_size_loc) == (vm::range_readable >> vm::range_pos))
{
return 0;
}
// Split and check every 64K page separately // Split and check every 64K page separately
for (u64 hi = addr2 >> 16, max = (addr2 + size2 - 1) >> 16; hi <= max; hi++) for (u64 hi = addr2 >> 16, max = (addr2 + size2 - 1) >> 16; hi <= max; hi++)
{ {
@ -957,7 +953,7 @@ namespace vm
return true; return true;
} }
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm, std::vector<std::pair<u64, u64>>& unmap_events, bool is_block_termination = false) static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm, std::vector<std::pair<u64, u64>>& unmap_events)
{ {
perf_meter<"PAGE_UNm"_u64> perf0; perf_meter<"PAGE_UNm"_u64> perf0;
@ -1028,11 +1024,7 @@ namespace vm
ppu_remove_hle_instructions(addr, size); ppu_remove_hle_instructions(addr, size);
// Actually unmap memory // Actually unmap memory
if (is_block_termination && (!shm || is_noop)) if (is_noop)
{
// We can skip it if the block is freed
}
else if (is_noop)
{ {
std::memset(g_sudo_addr + addr, 0, size); std::memset(g_sudo_addr + addr, 0, size);
} }
@ -1338,17 +1330,7 @@ namespace vm
const auto size = it->second.first; const auto size = it->second.first;
std::vector<std::pair<u64, u64>> event_data; std::vector<std::pair<u64, u64>> event_data;
ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data, true)); ensure(size == _page_unmap(it->first, size, this->flags, it->second.second.get(), unmapped ? *unmapped : event_data));
if (it->second.second && addr < 0xE0000000)
{
if (it->second.second.use_count() != 1)
{
fmt::throw_exception("External memory usage at block 0x%x (addr=0x%x, size=0x%x)", this->addr, it->first, size);
}
it->second.second.reset();
}
it = next; it = next;
} }
@ -1359,8 +1341,6 @@ namespace vm
#ifdef _WIN32 #ifdef _WIN32
m_common->unmap_critical(vm::get_super_ptr(addr)); m_common->unmap_critical(vm::get_super_ptr(addr));
#endif #endif
ensure(m_common.use_count() == 1);
m_common.reset();
} }
return true; return true;
@ -1372,7 +1352,6 @@ namespace vm
block_t::~block_t() block_t::~block_t()
{ {
ensure(!is_valid()); ensure(!is_valid());
ensure(!m_common || m_common.use_count() == 1);
} }
u32 block_t::alloc(const u32 orig_size, const std::shared_ptr<utils::shm>* src, u32 align, u64 flags) u32 block_t::alloc(const u32 orig_size, const std::shared_ptr<utils::shm>* src, u32 align, u64 flags)
@ -2268,11 +2247,7 @@ namespace vm
for (auto& block : g_locations) for (auto& block : g_locations)
{ {
if (block) if (block) _unmap_block(block);
{
_unmap_block(block);
ensure(block.use_count() == 1);
}
} }
g_locations.clear(); g_locations.clear();

View file

@ -81,7 +81,7 @@ namespace vm
bool check_addr(u32 addr, u8 flags, u32 size); bool check_addr(u32 addr, u8 flags, u32 size);
template <u32 Size = 1> template <u32 Size = 1>
inline bool check_addr(u32 addr, u8 flags = page_readable) bool check_addr(u32 addr, u8 flags = page_readable)
{ {
extern std::array<memory_page, 0x100000000 / 4096> g_pages; extern std::array<memory_page, 0x100000000 / 4096> g_pages;
@ -94,16 +94,6 @@ namespace vm
return !(~g_pages[addr / 4096] & (flags | page_allocated)); return !(~g_pages[addr / 4096] & (flags | page_allocated));
} }
// Like check_addr but should only be used in lock-free context with care
inline std::pair<bool, u8> get_addr_flags(u32 addr) noexcept
{
extern std::array<memory_page, 0x100000000 / 4096> g_pages;
const u8 flags = g_pages[addr / 4096].load();
return std::make_pair(!!(flags & page_allocated), flags);
}
// Read string in a safe manner (page aware) (bool true = if null-termination) // Read string in a safe manner (page aware) (bool true = if null-termination)
bool read_string(u32 addr, u32 max_size, std::string& out_string, bool check_pages = true) noexcept; bool read_string(u32 addr, u32 max_size, std::string& out_string, bool check_pages = true) noexcept;

View file

@ -6,6 +6,9 @@
#include "util/tsc.hpp" #include "util/tsc.hpp"
#include <functional> #include <functional>
extern bool g_use_rtm;
extern u64 g_rtm_tx_limit2;
#ifdef _MSC_VER #ifdef _MSC_VER
extern "C" extern "C"
{ {
@ -140,7 +143,7 @@ namespace vm
void reservation_op_internal(u32 addr, std::function<bool()> func); void reservation_op_internal(u32 addr, std::function<bool()> func);
template <bool Ack = false, typename CPU, typename T, typename AT = u32, typename F> template <bool Ack = false, typename CPU, typename T, typename AT = u32, typename F>
inline SAFE_BUFFERS(auto) reservation_op(CPU& /*cpu*/, _ptr_base<T, AT> ptr, F op) inline SAFE_BUFFERS(auto) reservation_op(CPU& cpu, _ptr_base<T, AT> ptr, F op)
{ {
// Atomic operation will be performed on aligned 128 bytes of data, so the data size and alignment must comply // Atomic operation will be performed on aligned 128 bytes of data, so the data size and alignment must comply
static_assert(sizeof(T) <= 128 && alignof(T) == sizeof(T), "vm::reservation_op: unsupported type"); static_assert(sizeof(T) <= 128 && alignof(T) == sizeof(T), "vm::reservation_op: unsupported type");
@ -159,6 +162,188 @@ namespace vm
auto& res = vm::reservation_acquire(addr); auto& res = vm::reservation_acquire(addr);
//_m_prefetchw(&res); //_m_prefetchw(&res);
#if defined(ARCH_X64)
if (g_use_rtm)
{
// Stage 1: single optimistic transaction attempt
unsigned status = -1;
u64 _old = 0;
auto stamp0 = utils::get_tsc(), stamp1 = stamp0, stamp2 = stamp0;
#ifndef _MSC_VER
__asm__ goto ("xbegin %l[stage2];" ::: "memory" : stage2);
#else
status = _xbegin();
if (status == umax)
#endif
{
if (res & rsrv_unique_lock)
{
#ifndef _MSC_VER
__asm__ volatile ("xend; mov $-1, %%eax;" ::: "memory");
#else
_xend();
#endif
goto stage2;
}
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
{
std::invoke(op, *sptr);
const u64 old_time = res.fetch_add(128);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
if constexpr (Ack)
reservation_notifier_notify(addr, old_time);
return;
}
else
{
if (auto result = std::invoke(op, *sptr))
{
const u64 old_time = res.fetch_add(128);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
if constexpr (Ack)
reservation_notifier_notify(addr, old_time);
return result;
}
else
{
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return result;
}
}
}
stage2:
#ifndef _MSC_VER
__asm__ volatile ("mov %%eax, %0;" : "=r" (status) :: "memory");
#endif
stamp1 = utils::get_tsc();
// Stage 2: try to lock reservation first
_old = res.fetch_add(1);
// Compute stamps excluding memory touch
stamp2 = utils::get_tsc() - (stamp1 - stamp0);
// Start lightened transaction
for (; !(_old & vm::rsrv_unique_lock) && stamp2 - stamp0 <= g_rtm_tx_limit2; stamp2 = utils::get_tsc())
{
if (cpu.has_pause_flag())
{
break;
}
#ifndef _MSC_VER
__asm__ goto ("xbegin %l[retry];" ::: "memory" : retry);
#else
status = _xbegin();
if (status != umax) [[unlikely]]
{
goto retry;
}
#endif
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
{
std::invoke(op, *sptr);
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
res += 127;
if (Ack)
reservation_notifier_notify(addr, _old);
return;
}
else
{
if (auto result = std::invoke(op, *sptr))
{
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
res += 127;
if (Ack)
reservation_notifier_notify(addr, _old);
return result;
}
else
{
#ifndef _MSC_VER
__asm__ volatile ("xend;" ::: "memory");
#else
_xend();
#endif
return result;
}
}
retry:
#ifndef _MSC_VER
__asm__ volatile ("mov %%eax, %0;" : "=r" (status) :: "memory");
#endif
if (!status)
{
break;
}
}
// Stage 3: all failed, heavyweight fallback (see comments at the bottom)
if constexpr (std::is_void_v<std::invoke_result_t<F, T&>>)
{
vm::reservation_op_internal(addr, [&]
{
std::invoke(op, *sptr);
return true;
});
if constexpr (Ack)
reservation_notifier_notify(addr, _old);
return;
}
else
{
auto result = std::invoke_result_t<F, T&>();
vm::reservation_op_internal(addr, [&]
{
if ((result = std::invoke(op, *sptr)))
{
return true;
}
else
{
return false;
}
});
if (Ack && result)
reservation_notifier_notify(addr, _old);
return result;
}
}
#else
static_cast<void>(cpu);
#endif /* ARCH_X64 */
// Lock reservation and perform heavyweight lock // Lock reservation and perform heavyweight lock
reservation_shared_lock_internal(res); reservation_shared_lock_internal(res);

View file

@ -4,7 +4,6 @@
#include "Emu/Cell/PPUCallback.h" #include "Emu/Cell/PPUCallback.h"
#include "Emu/IdManager.h" #include "Emu/IdManager.h"
#include "Emu/Cell/Modules/cellSysutil.h" #include "Emu/Cell/Modules/cellSysutil.h"
#include "np_helpers.h"
LOG_CHANNEL(sceNp2); LOG_CHANNEL(sceNp2);
@ -54,7 +53,7 @@ void generic_async_transaction_context::set_result_and_wake(error_code err)
tus_ctx::tus_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase) tus_ctx::tus_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase)
{ {
ensure(communicationId && np::validate_communication_id(*communicationId), "tus_ctx::tus_ctx: Invalid SceNpCommunicationId"); ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
} }
@ -97,7 +96,7 @@ bool destroy_tus_transaction_context(s32 ctx_id)
score_ctx::score_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase) score_ctx::score_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase)
{ {
ensure(communicationId && np::validate_communication_id(*communicationId), "score_ctx::score_ctx: Invalid SceNpCommunicationId"); ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
} }
@ -141,7 +140,7 @@ bool destroy_score_transaction_context(s32 ctx_id)
match2_ctx::match2_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option) match2_ctx::match2_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option)
{ {
ensure(communicationId && np::validate_communication_id(*communicationId), "match2_ctx::match2_ctx: Invalid SceNpCommunicationId"); ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase)); memcpy(&this->passphrase, passphrase.get_ptr(), sizeof(SceNpCommunicationPassphrase));
@ -150,7 +149,7 @@ match2_ctx::match2_ctx(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<
} }
u16 create_match2_context(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option) u16 create_match2_context(vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpCommunicationPassphrase> passphrase, s32 option)
{ {
sceNp2.notice("Creating match2 context with communicationId: <%s>", std::string_view(communicationId->data, 9)); sceNp2.notice("Creating match2 context with communicationId: <%s>", static_cast<const char*>(communicationId->data));
return static_cast<u16>(idm::make<match2_ctx>(communicationId, passphrase, option)); return static_cast<u16>(idm::make<match2_ctx>(communicationId, passphrase, option));
} }
bool destroy_match2_context(u16 ctx_id) bool destroy_match2_context(u16 ctx_id)
@ -168,7 +167,7 @@ shared_ptr<match2_ctx> get_match2_context(u16 ctx_id)
lookup_title_ctx::lookup_title_ctx(vm::cptr<SceNpCommunicationId> communicationId) lookup_title_ctx::lookup_title_ctx(vm::cptr<SceNpCommunicationId> communicationId)
{ {
ensure(communicationId && np::validate_communication_id(*communicationId), "lookup_title_ctx::lookup_title_ctx: Invalid SceNpCommunicationId"); ensure(!communicationId->data[9] && strlen(communicationId->data) == 9);
memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId)); memcpy(&this->communicationId, communicationId.get_ptr(), sizeof(SceNpCommunicationId));
} }
s32 create_lookup_title_context(vm::cptr<SceNpCommunicationId> communicationId) s32 create_lookup_title_context(vm::cptr<SceNpCommunicationId> communicationId)

View file

@ -646,7 +646,7 @@ namespace np
for (; it != end; ++it) for (; it != end; ++it)
{ {
strcpy_trunc(ifr.ifr_name, it->ifr_name); strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0)
{ {
if (!(ifr.ifr_flags & IFF_LOOPBACK)) if (!(ifr.ifr_flags & IFF_LOOPBACK))

View file

@ -1,4 +1,3 @@
#include "Emu/Cell/Modules/sceNp.h"
#include "stdafx.h" #include "stdafx.h"
#include "util/types.hpp" #include "util/types.hpp"
#include "Utilities/StrUtil.h" #include "Utilities/StrUtil.h"
@ -23,15 +22,9 @@ namespace np
return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]); return fmt::format("%02X:%02X:%02X:%02X:%02X:%02X", ether[0], ether[1], ether[2], ether[3], ether[4], ether[5]);
} }
bool validate_communication_id(const SceNpCommunicationId& com_id)
{
return std::all_of(com_id.data, com_id.data + 9, [](char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z'); }) && com_id.num <= 99;
}
std::string communication_id_to_string(const SceNpCommunicationId& communicationId) std::string communication_id_to_string(const SceNpCommunicationId& communicationId)
{ {
std::string_view com_id_data(communicationId.data, 9); return fmt::format("%s_%02d", communicationId.data, communicationId.num);
return fmt::format("%s_%02d", com_id_data, communicationId.num);
} }
void strings_to_userinfo(std::string_view npid, std::string_view online_name, std::string_view avatar_url, SceNpUserInfo& user_info) void strings_to_userinfo(std::string_view npid, std::string_view online_name, std::string_view avatar_url, SceNpUserInfo& user_info)

Some files were not shown because too many files have changed in this diff Show more