Compare commits
197 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17e78a9e6f | |||
| 42751cc8fb | |||
| e67d090c35 | |||
| ddd0494cf4 | |||
| 2222807624 | |||
| 488814bb2d | |||
| 4206b022b6 | |||
| b87c891ec4 | |||
| 5eb4691cd6 | |||
| bfcbc13b8a | |||
| 5c5edb4785 | |||
| edfe940543 | |||
| 8b8396b945 | |||
| 97f2b6b701 | |||
| 92bf6ed0a7 | |||
| 29c1c3df1f | |||
| cd8954db14 | |||
| 431221f172 | |||
| 3ecb14dcda | |||
| a325eb52bd | |||
| 84217917d5 | |||
| af052b0627 | |||
| c70c08bb07 | |||
| 2e8029a45b | |||
| a9a454faf7 | |||
| 3378b03c1f | |||
| 8d9911e383 | |||
| 60ae4c1121 | |||
| 5ed7d043c4 | |||
| c28ec457fd | |||
| a79ef1efb2 | |||
| 1299aa68b3 | |||
| 681debd8f6 | |||
| 0db06964dc | |||
| 6ce1816e3f | |||
| 7fdfbe3c52 | |||
| 3e516df214 | |||
| 899b4aaeec | |||
| d2612bed3a | |||
| 42b255a4a2 | |||
| 18c01f7151 | |||
| 4cd1d639ed | |||
| 2732d6c3dc | |||
| 8e4f5cc7b3 | |||
| e58a3ab7e0 | |||
| e0e1c729cd | |||
| 7c6b558647 | |||
| 217c924d42 | |||
| 7b92cbcb9a | |||
| c882f0baf0 | |||
| f1f124dcbf | |||
| d4ce5b86ec | |||
| 16c1b9ed73 | |||
| 42ee2463c7 | |||
| 2fc9ae5d28 | |||
| 28dc7356a8 | |||
| f6c585902a | |||
| 693cf9950f | |||
| cef3ee2d80 | |||
| 8fac136056 | |||
| fa707047e6 | |||
| c009215983 | |||
| d51d5ce86d | |||
| 36da83592a | |||
| 0a57c459b6 | |||
| 73fe420d09 | |||
| a85cdb5947 | |||
| 511f8a91f1 | |||
| 2d1da95bc1 | |||
| 967adaf9db | |||
| 8ca60df1ab | |||
| 4832267307 | |||
| 6bb01066fb | |||
| 522124d695 | |||
| d9c4e14c40 | |||
| 00944a5d71 | |||
| e9bc99253d | |||
| e9a45a6d06 | |||
| 497b9ba55b | |||
| d1d04b1b32 | |||
| 826f805902 | |||
| b1b0ac4433 | |||
| 3f28f88a35 | |||
| 938306a7bc | |||
| 1568366d9c | |||
| 79614562b9 | |||
| 96e495c61d | |||
| e4dd957bbc | |||
| aace685202 | |||
| fa6f999754 | |||
| f18649567f | |||
| ae580c7749 | |||
| c711764850 | |||
| 7d5dc101fa | |||
| 252e69a6ba | |||
| c4be603279 | |||
| 90bf35bb1e | |||
| 47fb653044 | |||
| 4fe306c9ad | |||
| 03a58d36da | |||
| d379dd4c8d | |||
| 7fc31e20b3 | |||
| d11fe09419 | |||
| c49ff490bc | |||
| 3f66297593 | |||
| 37d2317b68 | |||
| a1d55e5a54 | |||
| 0ba0f11c4a | |||
| f0c60b42c2 | |||
| 88adaa9d2d | |||
| 56099e79da | |||
| 4ba4268282 | |||
| 2661b6a71c | |||
| e58a89af2d | |||
| ad3d8675e7 | |||
| 18d9ca5928 | |||
| 5ab955d9c4 | |||
| 2b4a90781a | |||
| 10dece1c80 | |||
| 9dd0b055d0 | |||
| 9e460ebe0a | |||
| 7106bfcfb9 | |||
| c936de7c20 | |||
| 60b5adab63 | |||
| e3c8b3d524 | |||
| 8b79fd3da1 | |||
| feedc183a4 | |||
| c4282e63fb | |||
| 82f97d33d1 | |||
| c1d43aff05 | |||
| a14c166aab | |||
| 7d39ac4e1e | |||
| f40d8b669c | |||
| 4b0a5bd1b8 | |||
| 6995467ff6 | |||
| ad42a2b89a | |||
| c4334f5142 | |||
| 4c3d243672 | |||
| 340c17f422 | |||
| 18a99a7d8f | |||
| 31b133b012 | |||
| eb9acd9b56 | |||
| 02362a4807 | |||
| 466a93dca5 | |||
| c89e30b3d9 | |||
| d88b7f6fde | |||
| d0a13c1a5a | |||
| df9275819e | |||
| 5b5bfaf696 | |||
| 3d9c8a670e | |||
| cf65571be7 | |||
| 66eae05e75 | |||
| d1648dd707 | |||
| 7f2534819e | |||
| e678931cee | |||
| 965dbf2c12 | |||
| 624f34ae13 | |||
| d60eced317 | |||
| c813c5e953 | |||
| 5ce9c5b09f | |||
| 7df33bc8c0 | |||
| 0abaac90a8 | |||
| e5a526e4d6 | |||
| 8131f40269 | |||
| 743f9a9f51 | |||
| 0a54e34a9b | |||
| 53c84577c0 | |||
| 00e5d54be7 | |||
| d13acdb484 | |||
| 92c1a8c45d | |||
| 939479f55e | |||
| d19d0cb70d | |||
| 31ce32709e | |||
| 4f27af9949 | |||
| b31280e387 | |||
| 03980304cf | |||
| c852ae1a22 | |||
| 58f3841383 | |||
| 9385f0673b | |||
| 2bc0d19c9d | |||
| fe1fa45956 | |||
| 6fa993645e | |||
| 144ff82402 | |||
| f285b0c053 | |||
| 7e9cf297ac | |||
| d780355784 | |||
| b0194ba6af | |||
| deba582353 | |||
| 303c6715dd | |||
| b4ff988bd8 | |||
| 7e3b8b5cdb | |||
| 7353696014 | |||
| a60eab6e36 | |||
| 23f9eb57e5 | |||
| ad1eb93a05 | |||
| 2fb0c499ea | |||
| fbebdc09b7 |
@@ -3,7 +3,7 @@
|
||||
# Pull all the submodules except llvm
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
|
||||
# Prefer newer Clang than in base system (see also .ci/install-freebsd.sh)
|
||||
# libc++ isn't in llvm* packages, so download manually
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
if [ -z "$CIRRUS_CI" ]; then
|
||||
cd rpcs3 || exit 1
|
||||
fi
|
||||
|
||||
git config --global --add safe.directory '*'
|
||||
|
||||
# Pull all the submodules except llvm
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
|
||||
mkdir build && cd build || exit 1
|
||||
|
||||
export CC="${CLANG_BINARY}"
|
||||
export CXX="${CLANGXX_BINARY}"
|
||||
|
||||
cmake .. \
|
||||
-DCMAKE_INSTALL_PREFIX=/usr \
|
||||
-DUSE_NATIVE_INSTRUCTIONS=OFF \
|
||||
-DUSE_PRECOMPILED_HEADERS=OFF \
|
||||
-DCMAKE_C_FLAGS="$CFLAGS" \
|
||||
-DCMAKE_CXX_FLAGS="$CFLAGS" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_SYSTEM_SDL=ON \
|
||||
-DUSE_SYSTEM_FFMPEG=OFF \
|
||||
-DUSE_DISCORD_RPC=ON \
|
||||
-DOpenGL_GL_PREFERENCE=LEGACY \
|
||||
-DLLVM_DIR=/opt/llvm/lib/cmake/llvm \
|
||||
-DSTATIC_LINK_LLVM=ON \
|
||||
-G Ninja
|
||||
|
||||
ninja; build_status=$?;
|
||||
|
||||
cd ..
|
||||
|
||||
shellcheck .ci/*.sh
|
||||
|
||||
# If it compiled succesfully let's deploy.
|
||||
# Azure and Cirrus publish PRs as artifacts only.
|
||||
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
|
||||
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
|
||||
|
||||
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
|
||||
.ci/deploy-linux.sh "aarch64"
|
||||
fi
|
||||
+3
-2
@@ -9,7 +9,7 @@ git config --global --add safe.directory '*'
|
||||
# Pull all the submodules except llvm
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init $(awk '/path/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init $(awk '/path/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
|
||||
mkdir build && cd build || exit 1
|
||||
|
||||
@@ -42,6 +42,7 @@ cmake .. \
|
||||
-DCMAKE_RANLIB="$RANLIB" \
|
||||
-DUSE_SYSTEM_CURL=ON \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_SYSTEM_SDL=ON \
|
||||
-DUSE_SYSTEM_FFMPEG=OFF \
|
||||
-DUSE_DISCORD_RPC=ON \
|
||||
-DOpenGL_GL_PREFERENCE=LEGACY \
|
||||
@@ -61,5 +62,5 @@ shellcheck .ci/*.sh
|
||||
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
|
||||
|
||||
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
|
||||
.ci/deploy-linux.sh
|
||||
.ci/deploy-linux.sh "x86_64"
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
brew_arm64_install_packages() {
|
||||
for pkg in "$@"; do
|
||||
echo "Fetching bottle for $pkg (arm64)..."
|
||||
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
|
||||
if [ ! -f "$bottle_path" ]; then
|
||||
if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_ventura "$pkg"; then
|
||||
echo "Failed to fetch bottle for $pkg"
|
||||
return 1
|
||||
fi
|
||||
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_ventura "$pkg")"
|
||||
fi
|
||||
|
||||
echo "Installing $pkg (arm64)..."
|
||||
"$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true
|
||||
done
|
||||
}
|
||||
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
|
||||
/usr/local/bin/brew update
|
||||
sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl
|
||||
/usr/local/bin/brew install -f --overwrite curl
|
||||
/usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
|
||||
/usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true
|
||||
/usr/local/bin/brew install -f --overwrite python || true
|
||||
/usr/local/bin/brew link --overwrite python || true
|
||||
/usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
|
||||
/usr/local/bin/brew link -f curl || true
|
||||
/usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
|
||||
/usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true
|
||||
|
||||
export BREW_ARM64_PATH="/opt/homebrew1"
|
||||
sudo mkdir -p "$BREW_ARM64_PATH"
|
||||
sudo chmod 777 "$BREW_ARM64_PATH"
|
||||
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH"
|
||||
|
||||
#"$BREW_ARM64_PATH/bin/brew" update
|
||||
# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary
|
||||
brew_arm64_install_packages curl
|
||||
mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak
|
||||
ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl
|
||||
|
||||
brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl2 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd
|
||||
"$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.2.11 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
|
||||
/usr/local/bin/brew install -f --overwrite ./molten-vk.rb
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
|
||||
export BREW_PATH;
|
||||
BREW_PATH="$(brew --prefix)"
|
||||
export BREW_X64_PATH;
|
||||
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
|
||||
export BREW_BIN="/usr/local/bin"
|
||||
export BREW_SBIN="/usr/local/sbin"
|
||||
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
|
||||
|
||||
export WORKDIR;
|
||||
WORKDIR="$(pwd)"
|
||||
|
||||
# Get Qt
|
||||
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
||||
mkdir -p "/tmp/Qt"
|
||||
git clone https://github.com/engnr/qt-downloader.git
|
||||
cd qt-downloader
|
||||
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
|
||||
cd "/tmp/Qt"
|
||||
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
|
||||
fi
|
||||
|
||||
cd "$WORKDIR"
|
||||
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
|
||||
|
||||
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
|
||||
export SDL2_DIR="$BREW_ARM64_PATH/opt/sdl2/lib/cmake/SDL2"
|
||||
|
||||
export PATH="$BREW_X64_PATH/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 LDFLAGS="-L$BREW_ARM64_PATH/lib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavcodec.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavformat.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavutil.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswscale.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswresample.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++.1.dylib $BREW_ARM64_PATH/lib/libSDL2.dylib $BREW_ARM64_PATH/lib/libGLEW.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/libunwind.1.dylib -Wl,-rpath,$BREW_ARM64_PATH/lib"
|
||||
export CPPFLAGS="-I$BREW_ARM64_PATH/include -I$BREW_X64_PATH/include -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
|
||||
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
|
||||
export LIBRARY_PATH="$BREW_ARM64_PATH/lib"
|
||||
export LD_LIBRARY_PATH="$BREW_ARM64_PATH/lib"
|
||||
|
||||
export VULKAN_SDK
|
||||
VULKAN_SDK="$BREW_ARM64_PATH/opt/molten-vk"
|
||||
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" || true
|
||||
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||
|
||||
export LLVM_DIR
|
||||
LLVM_DIR="$BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER"
|
||||
# exclude ffmpeg, LLVM, and sdl from submodule update
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
|
||||
|
||||
# 3rdparty fixes
|
||||
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
|
||||
|
||||
rm -rf build
|
||||
mkdir build && cd build || exit 1
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=13.0
|
||||
|
||||
"$BREW_X64_PATH/bin/cmake" .. \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_DISCORD_RPC=OFF \
|
||||
-DUSE_VULKAN=ON \
|
||||
-DUSE_ALSA=OFF \
|
||||
-DUSE_PULSE=OFF \
|
||||
-DUSE_AUDIOUNIT=ON \
|
||||
-DUSE_SYSTEM_FFMPEG=ON \
|
||||
-DLLVM_CCACHE_BUILD=OFF \
|
||||
-DLLVM_BUILD_RUNTIME=OFF \
|
||||
-DLLVM_BUILD_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_DOCS=OFF \
|
||||
-DLLVM_INCLUDE_EXAMPLES=OFF \
|
||||
-DLLVM_INCLUDE_TESTS=OFF \
|
||||
-DLLVM_INCLUDE_TOOLS=OFF \
|
||||
-DLLVM_INCLUDE_UTILS=OFF \
|
||||
-DLLVM_USE_PERF=OFF \
|
||||
-DLLVM_ENABLE_Z3_SOLVER=OFF \
|
||||
-DUSE_NATIVE_INSTRUCTIONS=OFF \
|
||||
-DUSE_SYSTEM_MVK=ON \
|
||||
-DUSE_SYSTEM_FAUDIO=OFF \
|
||||
-DUSE_SYSTEM_SDL=ON \
|
||||
$CMAKE_EXTRA_OPTS \
|
||||
-DLLVM_TARGET_ARCH=arm64 \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \
|
||||
-DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \
|
||||
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
|
||||
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
|
||||
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
|
||||
-G Ninja
|
||||
|
||||
"$BREW_PATH/bin/ninja"; build_status=$?;
|
||||
|
||||
cd ..
|
||||
|
||||
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
|
||||
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
|
||||
|
||||
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
|
||||
.ci/deploy-mac-arm64.sh
|
||||
fi
|
||||
Executable → Regular
+16
-12
@@ -1,5 +1,6 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
brew unlink certifi
|
||||
@@ -7,18 +8,17 @@ brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
|
||||
|
||||
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
|
||||
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite python@3.12 || arch -x86_64 /usr/local/bin/brew link --overwrite python@3.12
|
||||
arch -x86_64 /usr/local/bin/brew update
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite python || arch -x86_64 /usr/local/bin/brew link --overwrite python
|
||||
arch -x86_64 /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
|
||||
arch -x86_64 /usr/local/bin/brew install -f --build-from-source ffmpeg@5
|
||||
arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetype
|
||||
arch -x86_64 /usr/local/bin/brew install llvm@16 glew cmake sdl2 vulkan-headers coreutils
|
||||
arch -x86_64 /usr/local/bin/brew link -f llvm@16 ffmpeg@5
|
||||
arch -x86_64 /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl2 vulkan-headers coreutils
|
||||
arch -x86_64 /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5
|
||||
|
||||
# moltenvk based on commit for 1.2.10 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/0d9f25fbd1658e975d00bd0e8cccd20a0c2cb74b/Formula/m/molten-vk.rb
|
||||
# moltenvk based on commit for 1.2.11 release
|
||||
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
|
||||
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
|
||||
#export MACOSX_DEPLOYMENT_TARGET=12.0
|
||||
export CXX=clang++
|
||||
export CC=clang
|
||||
|
||||
@@ -42,7 +42,7 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
|
||||
cd "/tmp/Qt"
|
||||
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
|
||||
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
|
||||
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia
|
||||
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats
|
||||
fi
|
||||
|
||||
cd "$WORKDIR"
|
||||
@@ -51,9 +51,10 @@ ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
|
||||
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
|
||||
export SDL2_DIR="$BREW_X64_PATH/opt/sdl2/lib/cmake/SDL2"
|
||||
|
||||
export PATH="$BREW_X64_PATH/opt/llvm@16/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="$BREW_X64_PATH/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 LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
|
||||
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie"
|
||||
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
|
||||
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000"
|
||||
export LIBRARY_PATH="$BREW_X64_PATH/lib"
|
||||
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
|
||||
|
||||
@@ -63,16 +64,18 @@ ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
|
||||
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
|
||||
|
||||
export LLVM_DIR
|
||||
LLVM_DIR="BREW_X64_PATH/opt/llvm@16"
|
||||
# exclude ffmpeg, SPIRV and LLVM, and sdl from submodule update
|
||||
LLVM_DIR="BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER"
|
||||
# exclude ffmpeg, LLVM, and sdl from submodule update
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SPIRV/ && !/SDL/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
|
||||
|
||||
# 3rdparty fixes
|
||||
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
|
||||
|
||||
mkdir build && cd build || exit 1
|
||||
|
||||
export MACOSX_DEPLOYMENT_TARGET=13.0
|
||||
|
||||
"$BREW_X64_PATH/bin/cmake" .. \
|
||||
-DUSE_SDL=ON \
|
||||
-DUSE_DISCORD_RPC=ON \
|
||||
@@ -99,6 +102,7 @@ mkdir build && cd build || exit 1
|
||||
-DLLVM_TARGET_ARCH=X86_64 \
|
||||
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
|
||||
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
|
||||
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=130000" \
|
||||
-G Ninja
|
||||
|
||||
"$BREW_PATH/bin/ninja"; build_status=$?;
|
||||
|
||||
+15
-8
@@ -2,19 +2,22 @@
|
||||
|
||||
cd build || exit 1
|
||||
|
||||
CPU_ARCH="${1:-x86_64}"
|
||||
|
||||
if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
DESTDIR=AppDir ninja install
|
||||
|
||||
curl -fsSLo /usr/bin/linuxdeploy https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||
curl -fsSLo /usr/bin/linuxdeploy "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$CPU_ARCH.AppImage"
|
||||
chmod +x /usr/bin/linuxdeploy
|
||||
curl -fsSLo /usr/bin/linuxdeploy-plugin-qt https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
curl -fsSLo /usr/bin/linuxdeploy-plugin-qt "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-$CPU_ARCH.AppImage"
|
||||
chmod +x /usr/bin/linuxdeploy-plugin-qt
|
||||
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
|
||||
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
|
||||
|
||||
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
|
||||
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration"
|
||||
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt
|
||||
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
|
||||
|
||||
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
|
||||
rm -f ./AppDir/usr/lib/libwayland-client.so*
|
||||
@@ -25,15 +28,19 @@ if [ "$DEPLOY_APPIMAGE" = "true" ]; then
|
||||
# Remove git directory containing local commit history file
|
||||
rm -rf ./AppDir/usr/share/rpcs3/git
|
||||
|
||||
./linuxdeploy-plugin-checkrt.sh --appdir AppDir
|
||||
|
||||
linuxdeploy --appimage-extract
|
||||
./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g
|
||||
|
||||
APPIMAGE_SUFFIX="linux_${CPU_ARCH}"
|
||||
if [ "$CPU_ARCH" = "x86_64" ]; then
|
||||
# Preserve back compat. Previous versions never included the full arch.
|
||||
APPIMAGE_SUFFIX="linux64"
|
||||
fi
|
||||
|
||||
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
|
||||
COMM_COUNT="$(git rev-list --count HEAD)"
|
||||
COMM_HASH="$(git rev-parse --short=8 HEAD)"
|
||||
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_linux64.AppImage"
|
||||
RPCS3_APPIMAGE="rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_${APPIMAGE_SUFFIX}.AppImage"
|
||||
|
||||
mv ./RPCS3*.AppImage "$RPCS3_APPIMAGE"
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
cd build || exit 1
|
||||
|
||||
# Gather explicit version number and number of commits
|
||||
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
|
||||
COMM_COUNT=$(git rev-list --count HEAD)
|
||||
COMM_HASH=$(git rev-parse --short=8 HEAD)
|
||||
|
||||
AVVER="${COMM_TAG}-${COMM_COUNT}"
|
||||
|
||||
# AVVER is used for GitHub releases, it is the version number.
|
||||
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
|
||||
|
||||
cd bin
|
||||
mkdir "rpcs3.app/Contents/lib/" || true
|
||||
|
||||
cp "$(realpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
|
||||
cp "$(realpath /opt/homebrew1/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
|
||||
cp "$(realpath /opt/homebrew1/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
|
||||
|
||||
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
|
||||
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
|
||||
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
|
||||
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
|
||||
"rpcs3.app/Contents/Resources/git"
|
||||
|
||||
../../.ci/optimize-mac.sh rpcs3.app
|
||||
|
||||
# Hack
|
||||
install_name_tool \
|
||||
-delete_rpath /opt/homebrew1/lib \
|
||||
-delete_rpath /opt/homebrew/lib \
|
||||
-delete_rpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib \
|
||||
-delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3
|
||||
#-delete_rpath /opt/homebrew1/Cellar/sdl2/2.30.7/lib
|
||||
|
||||
# Need to do this rename hack due to case insensitive filesystem
|
||||
mv rpcs3.app RPCS3_.app
|
||||
mv RPCS3_.app RPCS3.app
|
||||
|
||||
# NOTE: "--deep" is deprecated
|
||||
codesign --deep -fs - RPCS3.app
|
||||
|
||||
echo "[InternetShortcut]" > Quickstart.url
|
||||
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
|
||||
echo "IconIndex=0" >> Quickstart.url
|
||||
|
||||
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.dmg"
|
||||
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
|
||||
#--window-size 800 400 \
|
||||
#--icon-size 100 \
|
||||
#--icon rpcs3.app 200 190 \
|
||||
#--add-file Quickstart.url Quickstart.url 400 20 \
|
||||
#--hide-extension rpcs3.app \
|
||||
#--hide-extension Quickstart.url \
|
||||
#--app-drop-link 600 185 \
|
||||
#--skip-jenkins \
|
||||
#--format ULMO \
|
||||
#"$DMG_FILEPATH" \
|
||||
#RPCS3.app
|
||||
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
|
||||
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
|
||||
|
||||
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z"
|
||||
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
|
||||
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
|
||||
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
|
||||
|
||||
cd ..
|
||||
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
|
||||
cd bin
|
||||
Executable → Regular
+13
-1
@@ -1,5 +1,6 @@
|
||||
#!/bin/sh -ex
|
||||
|
||||
# shellcheck disable=SC2086
|
||||
cd build || exit 1
|
||||
|
||||
# Gather explicit version number and number of commits
|
||||
@@ -15,7 +16,7 @@ echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
|
||||
cd bin
|
||||
mkdir "rpcs3.app/Contents/lib/"
|
||||
|
||||
cp "/usr/local/opt/llvm@16/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/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/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"
|
||||
|
||||
@@ -28,10 +29,21 @@ rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
|
||||
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
|
||||
"rpcs3.app/Contents/Resources/git"
|
||||
|
||||
../../.ci/optimize-mac.sh rpcs3.app
|
||||
|
||||
# Need to do this rename hack due to case insensitive filesystem
|
||||
mv rpcs3.app RPCS3_.app
|
||||
mv RPCS3_.app RPCS3.app
|
||||
|
||||
# Hack
|
||||
install_name_tool \
|
||||
-delete_rpath /usr/local/lib \
|
||||
-delete_rpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
|
||||
#-delete_rpath /usr/local/Cellar/sdl2/2.30.3/lib
|
||||
|
||||
# NOTE: "--deep" is deprecated
|
||||
codesign --deep -fs - RPCS3.app
|
||||
|
||||
echo "[InternetShortcut]" > Quickstart.url
|
||||
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
|
||||
echo "IconIndex=0" >> Quickstart.url
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
file_path=$(find "$1/Contents/MacOS" -type f -print0 | head -n 1)
|
||||
|
||||
if [ -z "$file_path" ]; then
|
||||
echo "No executable file found in $1/Contents/MacOS" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
target_architecture="$(lipo "$file_path" -archs)"
|
||||
|
||||
if [ -z "$target_architecture" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC3045
|
||||
find "$1" -type f -print0 | while IFS= read -r -d '' file; do
|
||||
echo Thinning "$file" -> "$target_architecture"
|
||||
lipo "$file" -thin "$target_architecture" -output "$file" || true
|
||||
done
|
||||
@@ -39,7 +39,7 @@ DEP_URLS=" \
|
||||
# Pull all the submodules except llvm, since it is built separately and we just download that build
|
||||
# Note: Tried to use git submodule status, but it takes over 20 seconds
|
||||
# shellcheck disable=SC2046
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ && !/SPIRV/ { print $3 }' .gitmodules)
|
||||
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ && !/llvm/ { print $3 }' .gitmodules)
|
||||
|
||||
# Git bash doesn't have rev, so here it is
|
||||
rev()
|
||||
|
||||
+38
-37
@@ -5,9 +5,9 @@ env:
|
||||
SYSTEM_PULLREQUEST_PULLREQUESTID: $CIRRUS_PR
|
||||
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
|
||||
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
|
||||
RPCS3_TOKEN: ENCRYPTED[!a4c3850e29ab150692286a74bec29819d25971a7ec431b86de2a35f7ed90c5b2ab3c93469f9298e30924d843599110e9!]
|
||||
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.6.3'
|
||||
QT_VER: '6.7.3'
|
||||
|
||||
# windows_task:
|
||||
# matrix:
|
||||
@@ -21,7 +21,7 @@ env:
|
||||
# COMPILER: msvc
|
||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
|
||||
# QT_VER_MSVC: 'msvc2019'
|
||||
# QT_DATE: '202403191840'
|
||||
# QT_DATE: '202409200836'
|
||||
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
|
||||
# VULKAN_VER: '1.3.268.0'
|
||||
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
@@ -114,37 +114,38 @@ freebsd_task:
|
||||
install_script: "sh -ex ./.ci/install-freebsd.sh"
|
||||
script: "./.ci/build-freebsd.sh"
|
||||
|
||||
# macos_task:
|
||||
# timeout_in: 12000m
|
||||
# homebrew_cache:
|
||||
# folder: /Users/admin/Library/Caches/Homebrew
|
||||
# qt_cache:
|
||||
# folder: /tmp/Qt
|
||||
# ccache_cache:
|
||||
# folder: /tmp/ccache_dir
|
||||
# matrix:
|
||||
# - name: Cirrus macOS
|
||||
# macos_instance:
|
||||
# image: ghcr.io/cirruslabs/macos-monterey-xcode:latest
|
||||
# mac_script:
|
||||
# - mkdir artifacts
|
||||
# - chmod +x ".ci/build-mac.sh"
|
||||
# - chmod +x ".ci/deploy-mac.sh"
|
||||
# - ".ci/build-mac.sh"
|
||||
# env:
|
||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
|
||||
# ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
|
||||
# CCACHE_DIR: "/tmp/ccache_dir"
|
||||
# CCACHE_MAXSIZE: 300M
|
||||
# CI_HAS_ARTIFACTS: true
|
||||
# UPLOAD_COMMIT_HASH: 51ae32f468089a8169aaf1567de355ff4a3e0842
|
||||
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-mac"
|
||||
# RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
||||
# artifacts:
|
||||
# name: Artifact
|
||||
# path: "artifacts/*"
|
||||
# push_script: |
|
||||
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
|
||||
# source './.ci/export-cirrus-vars.sh'
|
||||
# .ci/github-upload.sh
|
||||
# fi;
|
||||
linux_aarch64_task:
|
||||
env:
|
||||
BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
|
||||
ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
|
||||
CCACHE_DIR: "/tmp/ccache_dir"
|
||||
CCACHE_MAXSIZE: 300M
|
||||
CI_HAS_ARTIFACTS: true
|
||||
UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
||||
UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
|
||||
DEPLOY_APPIMAGE: true
|
||||
APPDIR: "./appdir"
|
||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
||||
COMPILER: clang
|
||||
ccache_cache:
|
||||
folder: "/tmp/ccache_dir"
|
||||
matrix:
|
||||
- name: Cirrus Linux AArch64 Clang
|
||||
arm_container:
|
||||
image: 'docker.io/rpcs3/rpcs3-ci-focal-aarch64:1.0'
|
||||
cpu: 8
|
||||
memory: 8G
|
||||
clang_script:
|
||||
- mkdir artifacts
|
||||
- "sh -ex ./.ci/build-linux-aarch64.sh"
|
||||
artifacts:
|
||||
name: Artifact
|
||||
path: "artifacts/*"
|
||||
push_script: |
|
||||
if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
|
||||
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
|
||||
COMM_COUNT=$(git rev-list --count HEAD)
|
||||
COMM_HASH=$(git rev-parse --short=8 HEAD)
|
||||
export AVVER="${COMM_TAG}-${COMM_COUNT}"
|
||||
.ci/github-upload.sh
|
||||
fi;
|
||||
|
||||
@@ -15,14 +15,6 @@
|
||||
path = 3rdparty/glslang/glslang
|
||||
url = ../../KhronosGroup/glslang.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/SPIRV-Tools"]
|
||||
path = 3rdparty/SPIRV/SPIRV-Tools
|
||||
url = ../../KhronosGroup/SPIRV-Tools.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/SPIRV-Headers"]
|
||||
path = 3rdparty/SPIRV/SPIRV-Headers
|
||||
url = ../../KhronosGroup/SPIRV-Headers.git
|
||||
ignore = dirty
|
||||
[submodule "3rdparty/zlib"]
|
||||
path = 3rdparty/zlib/zlib
|
||||
url = ../../madler/zlib
|
||||
|
||||
Vendored
+26
-32
@@ -4,6 +4,9 @@ include(CMakeDependentOption)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Defines the ARCHITECTURE variable
|
||||
include("DetectArchitecture.cmake")
|
||||
|
||||
# Warnings are silenced for 3rdparty code
|
||||
if(NOT MSVC)
|
||||
add_compile_options("$<$<COMPILE_LANGUAGE:CXX,C>:-w>")
|
||||
@@ -86,7 +89,6 @@ add_subdirectory(hidapi)
|
||||
|
||||
# Vulkan
|
||||
add_subdirectory(glslang EXCLUDE_FROM_ALL)
|
||||
#add_subdirectory(SPIRV EXCLUDE_FROM_ALL)
|
||||
|
||||
|
||||
# yaml-cpp
|
||||
@@ -247,8 +249,8 @@ if(USE_FAUDIO)
|
||||
message(STATUS "RPCS3: Using builtin FAudio")
|
||||
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared library")
|
||||
add_subdirectory(FAudio EXCLUDE_FROM_ALL)
|
||||
target_compile_definitions(FAudio INTERFACE -DHAVE_FAUDIO)
|
||||
set(FAUDIO_TARGET FAudio)
|
||||
target_compile_definitions(FAudio-static INTERFACE -DHAVE_FAUDIO)
|
||||
set(FAUDIO_TARGET FAudio-static)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -267,38 +269,30 @@ if(USE_SYSTEM_FFMPEG)
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE ${FFMPEG_INCLUDE_DIR})
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE ${FFMPEG_LIBRARIES})
|
||||
else()
|
||||
if (NOT MSVC AND WIN32)
|
||||
message(FATAL_ERROR "-- RPCS3: building ffmpeg submodule is currently not supported")
|
||||
else()
|
||||
message(STATUS "RPCS3: using builtin ffmpeg")
|
||||
message(STATUS "RPCS3: using builtin ffmpeg")
|
||||
add_subdirectory(ffmpeg EXCLUDE_FROM_ALL)
|
||||
# ffmpeg-core libraries are extracted to CMAKE_BINARY_DIR
|
||||
set(FFMPEG_LIB_DIR "${CMAKE_BINARY_DIR}/3rdparty/ffmpeg/lib")
|
||||
|
||||
if (WIN32)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/lib/windows/x86_64")
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
|
||||
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/lib/linux/ubuntu-20.04/x86_64")
|
||||
elseif(APPLE)
|
||||
set(FFMPEG_LIB_DIR "ffmpeg/lib/macos/x86_64")
|
||||
else()
|
||||
message(FATAL_ERROR "Prebuilt ffmpeg is not available on this platform! Try USE_SYSTEM_FFMPEG=ON.")
|
||||
endif()
|
||||
|
||||
find_library(FFMPEG_LIB_AVFORMAT avformat PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVCODEC avcodec PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
target_link_libraries(3rdparty_ffmpeg
|
||||
INTERFACE
|
||||
${FFMPEG_LIB_AVFORMAT}
|
||||
${FFMPEG_LIB_AVCODEC}
|
||||
${FFMPEG_LIB_AVUTIL}
|
||||
${FFMPEG_LIB_SWSCALE}
|
||||
${FFMPEG_LIB_SWRESAMPLE}
|
||||
)
|
||||
if (WIN32)
|
||||
target_link_libraries(3rdparty_ffmpeg INTERFACE "Bcrypt.lib")
|
||||
endif()
|
||||
|
||||
find_library(FFMPEG_LIB_AVFORMAT avformat PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVCODEC avcodec PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_AVUTIL avutil PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWSCALE swscale PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
find_library(FFMPEG_LIB_SWRESAMPLE swresample PATHS ${FFMPEG_LIB_DIR} NO_DEFAULT_PATH)
|
||||
|
||||
target_link_libraries(3rdparty_ffmpeg
|
||||
INTERFACE
|
||||
${FFMPEG_LIB_AVFORMAT}
|
||||
${FFMPEG_LIB_AVCODEC}
|
||||
${FFMPEG_LIB_AVUTIL}
|
||||
${FFMPEG_LIB_SWSCALE}
|
||||
${FFMPEG_LIB_SWRESAMPLE}
|
||||
)
|
||||
|
||||
target_include_directories(3rdparty_ffmpeg INTERFACE "ffmpeg/include")
|
||||
endif()
|
||||
|
||||
|
||||
Vendored
+63
@@ -0,0 +1,63 @@
|
||||
# From https://github.com/merryhime/dynarmic
|
||||
include(CheckSymbolExists)
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES)
|
||||
set(DYNARMIC_MULTIARCH_BUILD 1)
|
||||
set(ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
return()
|
||||
endif()
|
||||
|
||||
function(detect_architecture symbol arch)
|
||||
if (NOT DEFINED ARCHITECTURE)
|
||||
set(CMAKE_REQUIRED_QUIET YES)
|
||||
check_symbol_exists("${symbol}" "" DETECT_ARCHITECTURE_${arch})
|
||||
unset(CMAKE_REQUIRED_QUIET)
|
||||
|
||||
if (DETECT_ARCHITECTURE_${arch})
|
||||
set(ARCHITECTURE "${arch}" PARENT_SCOPE)
|
||||
endif()
|
||||
|
||||
unset(DETECT_ARCHITECTURE_${arch} CACHE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
detect_architecture("__ARM64__" arm64)
|
||||
detect_architecture("__aarch64__" arm64)
|
||||
detect_architecture("_M_ARM64" arm64)
|
||||
|
||||
detect_architecture("__arm__" arm)
|
||||
detect_architecture("__TARGET_ARCH_ARM" arm)
|
||||
detect_architecture("_M_ARM" arm)
|
||||
|
||||
detect_architecture("__x86_64" x86_64)
|
||||
detect_architecture("__x86_64__" x86_64)
|
||||
detect_architecture("__amd64" x86_64)
|
||||
detect_architecture("_M_X64" x86_64)
|
||||
|
||||
detect_architecture("__i386" x86)
|
||||
detect_architecture("__i386__" x86)
|
||||
detect_architecture("_M_IX86" x86)
|
||||
|
||||
detect_architecture("__ia64" ia64)
|
||||
detect_architecture("__ia64__" ia64)
|
||||
detect_architecture("_M_IA64" ia64)
|
||||
|
||||
detect_architecture("__mips" mips)
|
||||
detect_architecture("__mips__" mips)
|
||||
detect_architecture("_M_MRX000" mips)
|
||||
|
||||
detect_architecture("__ppc64__" ppc64)
|
||||
detect_architecture("__powerpc64__" ppc64)
|
||||
|
||||
detect_architecture("__ppc__" ppc)
|
||||
detect_architecture("__ppc" ppc)
|
||||
detect_architecture("__powerpc__" ppc)
|
||||
detect_architecture("_ARCH_COM" ppc)
|
||||
detect_architecture("_ARCH_PWR" ppc)
|
||||
detect_architecture("_ARCH_PPC" ppc)
|
||||
detect_architecture("_M_MPPC" ppc)
|
||||
detect_architecture("_M_PPC" ppc)
|
||||
|
||||
detect_architecture("__riscv" riscv)
|
||||
|
||||
detect_architecture("__EMSCRIPTEN__" wasm)
|
||||
Vendored
+1
-1
Submodule 3rdparty/FAudio updated: d8db582124...54bff04461
Vendored
+1
-1
@@ -4,7 +4,7 @@ include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(moltenvk
|
||||
GIT_REPOSITORY https://github.com/KhronosGroup/MoltenVK.git
|
||||
GIT_TAG edbdcf0
|
||||
GIT_TAG 81541f6
|
||||
BUILD_IN_SOURCE 1
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||
CONFIGURE_COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/fetchDependencies" --macos
|
||||
|
||||
Vendored
+2
-2
@@ -5,8 +5,8 @@ if(USE_SYSTEM_OPENAL)
|
||||
target_include_directories(3rdparty_openal INTERFACE ${OPENAL_INCLUDE_DIR})
|
||||
target_link_libraries(3rdparty_openal INTERFACE ${OPENAL_LIBRARY})
|
||||
else()
|
||||
option(ALSOFT_UTILS "Build utility programs" OFF)
|
||||
option(ALSOFT_EXAMPLES "Build example programs" OFF)
|
||||
option(ALSOFT_UTILS "Build utility programs" OFF)
|
||||
option(ALSOFT_EXAMPLES "Build example programs" OFF)
|
||||
add_subdirectory(openal-soft EXCLUDE_FROM_ALL)
|
||||
add_library(3rdparty_openal INTERFACE)
|
||||
target_link_libraries(3rdparty_openal INTERFACE OpenAL::OpenAL)
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
/build
|
||||
/x64
|
||||
Vendored
-3
@@ -1,3 +0,0 @@
|
||||
set(SKIP_SPIRV_TOOLS_INSTALL ON CACHE BOOL "Skip spirv-tools install" FORCE)
|
||||
set(SPIRV-Headers_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/SPIRV-Headers" CACHE STRING "SPIRV-Headers path" FORCE)
|
||||
add_subdirectory(SPIRV-Tools)
|
||||
Vendored
-1
Submodule 3rdparty/SPIRV/SPIRV-Headers deleted from e867c06631
Vendored
-1
Submodule 3rdparty/SPIRV/SPIRV-Tools deleted from 360d469b9e
Vendored
-71
@@ -1,71 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}</ProjectGuid>
|
||||
<Keyword>MakeFileProj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="..\..\buildfiles\msvc\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="..\..\buildfiles\msvc\common_default_macros.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Makefile</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros">
|
||||
<CmakeGenerator>"Visual Studio $(VisualStudioVersion.Substring(0,2))"</CmakeGenerator>
|
||||
<CmakeReleaseCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Release" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" SPIRV-Tools -B build</CmakeReleaseCLI>
|
||||
<CmakeDebugCLI>call vsdevcmd.bat -arch=amd64
|
||||
cmake -G $(CmakeGenerator) -A x64 -DCMAKE_BUILD_TYPE="Debug" -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)/SPIRV-Headers').Replace('\', '/'))" -S SPIRV-Tools -B build</CmakeDebugCLI>
|
||||
<PropsAbsPath>$([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\..\buildfiles\msvc\common_default.props'))</PropsAbsPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<NMakeBuildCommandLine>$(CmakeReleaseCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>$(CmakeReleaseCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>$(CmakeReleaseCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Release /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<NMakeBuildCommandLine>$(CmakeDebugCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:build /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
|
||||
</NMakeBuildCommandLine>
|
||||
<NMakeReBuildCommandLine>$(CmakeDebugCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:rebuild /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
|
||||
</NMakeReBuildCommandLine>
|
||||
<NMakeCleanCommandLine>$(CmakeDebugCLI)
|
||||
msbuild.exe build\ALL_BUILD.vcxproj /t:clean /p:Configuration=Debug /p:ForceImportBeforeCppTargets="$(PropsAbsPath)" /m
|
||||
</NMakeCleanCommandLine>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
Vendored
-2
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" />
|
||||
Vendored
+1
-1
Submodule 3rdparty/curl/curl updated: 83bedbd730...7eb8c04847
Vendored
+1
-1
Submodule 3rdparty/ffmpeg updated: 10d0ebc0b8...ec6367d3ba
Vendored
+1
-1
Submodule 3rdparty/flatbuffers updated: 0100f6a577...595bf0007a
Vendored
+11
@@ -101,6 +101,17 @@
|
||||
<ItemGroup>
|
||||
<ClInclude Include="hidapi\hidapi\hidapi.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="hidapi\linux\hid.c" />
|
||||
<None Include="hidapi\mac\hid.c" />
|
||||
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.c" />
|
||||
<None Include="hidapi\mac\hidapi_darwin.h" />
|
||||
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.h" />
|
||||
<None Include="hidapi\windows\hidapi_hidclass.h" />
|
||||
<None Include="hidapi\windows\hidapi_hidpi.h" />
|
||||
<None Include="hidapi\windows\hidapi_hidsdi.h" />
|
||||
<None Include="hidapi\windows\hidapi_winapi.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
||||
+29
@@ -24,4 +24,33 @@
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\linux\hid.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\mac\hid.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\windows\hidapi_descriptor_reconstruct.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\windows\hidapi_hidclass.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\windows\hidapi_hidpi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\windows\hidapi_hidsdi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\windows\hidapi_winapi.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="hidapi\mac\hidapi_darwin.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Vendored
+1
-1
Submodule 3rdparty/libpng/libpng updated: ed217e3e60...f5e92d7697
Vendored
+1
-1
Submodule 3rdparty/libsdl-org/SDL updated: ba2f78a006...79ec168f3c
Vendored
+14
-3
@@ -17,12 +17,17 @@ if(WITH_LLVM)
|
||||
option(LLVM_CCACHE_BUILD OFF)
|
||||
set(LLVM_ENABLE_WARNINGS OFF CACHE BOOL "Enable compiler warnings.")
|
||||
|
||||
if(WIN32)
|
||||
# For Windows x86 (not Windows AArch64).
|
||||
# Check on MSVC is needed due to COMPILER_X86, COMPILER_ARM etc. are not set/supported by the MSVC compiler, if used.
|
||||
# Furthermore, the MSVC compiler is not available/supported on Windows AArch64
|
||||
if(WIN32 AND (COMPILER_X86 OR MSVC))
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
if(COMPILER_X86)
|
||||
set(LLVM_USE_INTEL_JITEVENTS ON)
|
||||
endif()
|
||||
set(LLVM_USE_PERF ON)
|
||||
endif()
|
||||
|
||||
@@ -68,12 +73,18 @@ if(WITH_LLVM)
|
||||
set(LLVM_TARGETS_TO_BUILD "X86" CACHE STRING "Semicolon-separated list of targets to build, or \"all\".")
|
||||
endif()
|
||||
endif()
|
||||
if((WIN32 AND BUILD_LLVM) OR CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
||||
# For Windows x86 (not Windows AArch64) only when BUILD_LLVM is enabled and
|
||||
# for Linux x86 (not Linux AArch64) even if BUILD_LLVM is disabled (precompiled llvm used)
|
||||
if(LLVM_USE_INTEL_JITEVENTS OR (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND COMPILER_X86))
|
||||
list (APPEND LLVM_ADDITIONAL_LIBS IntelJITEvents)
|
||||
endif()
|
||||
|
||||
# For Linux even if BUILD_LLVM is disabled (precompiled llvm used)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
list (APPEND LLVM_ADDITIONAL_LIBS PerfJITEvents)
|
||||
endif()
|
||||
|
||||
llvm_map_components_to_libnames(LLVM_LIBS
|
||||
${LLVM_TARGETS_TO_BUILD}
|
||||
${LLVM_ADDITIONAL_LIBS}
|
||||
|
||||
Vendored
+2
-2
@@ -200,7 +200,7 @@ namespace pine
|
||||
if (!SafetyChecks(buf_cnt, 4, ret_cnt, 1, buf_size))
|
||||
return error();
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
if (!Impl::template check_addr(a))
|
||||
if (!Impl::template check_addr<1>(a))
|
||||
return error();
|
||||
const u8 res = Impl::read8(a);
|
||||
ToArray(ret_buffer, res, ret_cnt);
|
||||
@@ -252,7 +252,7 @@ namespace pine
|
||||
if (!SafetyChecks(buf_cnt, 1 + 4, ret_cnt, 0, buf_size))
|
||||
return error();
|
||||
const u32 a = FromArray<u32>(&buf[buf_cnt], 0);
|
||||
if (!Impl::template check_addr(a, vm::page_writable))
|
||||
if (!Impl::template check_addr<1>(a, vm::page_writable))
|
||||
return error();
|
||||
Impl::write8(a, FromArray<u8>(&buf[buf_cnt], 4));
|
||||
buf_cnt += 5;
|
||||
|
||||
Vendored
+5
-1
@@ -109,12 +109,13 @@
|
||||
<OutDir>$(SolutionDir)lib\$(Configuration)-$(Platform)\</OutDir>
|
||||
<IntDir>$(SolutionDir)tmp\$(ProjectName)-$(Configuration)-$(Platform)\</IntDir>
|
||||
<InstructionSet>NotSet</InstructionSet>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default.props" />
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<Import Project="$(SolutionDir)\buildfiles\msvc\common_default_macros.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<ConfigurationType>StaticLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
@@ -152,10 +153,13 @@
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level4</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<AdditionalOptions>/DZSTD_MULTITHREAD %(AdditionalOptions)</AdditionalOptions>
|
||||
<PreprocessorDefinitions>ZSTD_MULTITHREAD=1;ZSTD_LEGACY_SUPPORT=5;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<EnablePREfast>false</EnablePREfast>
|
||||
<EnableEnhancedInstructionSet>$(InstructionSet)</EnableEnhancedInstructionSet>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
|
||||
+85
-29
@@ -7,25 +7,40 @@ Other instructions may be found [here](https://wiki.rpcs3.net/index.php?title=Bu
|
||||
|
||||
### Windows 10 or later
|
||||
|
||||
* [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
||||
* [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
|
||||
* [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
|
||||
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
The following tools are required to build RPCS3 on Windows 10 or later:
|
||||
- [Visual Studio 2022](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=Community) (or at least Visual Studio 2019 16.11.xx+ as C++20 is not included in previous versions)
|
||||
- **Optional** - [CMake 3.28.0+](https://www.cmake.org/download/) (add to PATH)
|
||||
|
||||
**Either add the** `QTDIR` **environment variable, e.g.** `<QtInstallFolder>\6.6.3\msvc2019_64\` **, or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)**
|
||||
**NOTES:**
|
||||
- **Visual Studio 2022** integrates **CMake 3.29+** and it also supports both the `sln` solution (`.sln`, `.vcxproj`) and `CMake` solution (`CMakeLists.txt`, `CMakePresets.json`).
|
||||
See sections [Building with Visual Studio sln solution](#building-with-visual-studio-sln-solution) and [Building with Visual Studio CMake solution](#building-with-visual-studio-cmake-solution)
|
||||
on how to build the project with **Visual Studio**.
|
||||
- Install and use this standalone **CMake** tool just in case of your preference. See section [Building with standalone CMake tool](#building-with-standalone-cmake-tool) on how to build the project
|
||||
with standalone **CMake** tool.
|
||||
|
||||
**NOTE: If you have issues with the Qt plugin, you may want to uninstall the Qt Plugin and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.**
|
||||
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
- [Qt 6.7.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
|
||||
|
||||
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
|
||||
- add and set the `QTDIR` environment variable, e.g. `<QtInstallFolder>\6.7.3\msvc2019_64\`
|
||||
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2019)
|
||||
|
||||
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2019) instead.
|
||||
|
||||
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
|
||||
- add and set the `CMAKE_PREFIX_PATH` environment variable to the **Qt** libs path, e.g. `<QtInstallFolder>\6.7.3\msvc2019_64\`
|
||||
|
||||
### Linux
|
||||
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager.
|
||||
|
||||
* Clang 17+ or GCC 13+
|
||||
* [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
* [Qt 6.6.3](https://www.qt.io/download-qt-installer)
|
||||
* [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
* [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
|
||||
- Clang 17+ or GCC 13+
|
||||
- [CMake 3.28.0+](https://www.cmake.org/download/)
|
||||
- [Qt 6.7.3](https://www.qt.io/download-qt-installer)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (See "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/linux/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
- [SDL2](https://github.com/libsdl-org/SDL/releases) (for the FAudio backend)
|
||||
|
||||
**If you have an NVIDIA GPU, you may need to install the libglvnd package.**
|
||||
|
||||
@@ -38,6 +53,7 @@ These are the essentials tools to build RPCS3 on Linux. Some of them can be inst
|
||||
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev
|
||||
|
||||
Ubuntu is usually horrendously out of date, and some packages need to be downloaded by hand. This part is for Qt, GCC, Vulkan, and CMake
|
||||
|
||||
##### Qt PPA
|
||||
|
||||
Ubuntu usually does not have a new enough Qt package to suit rpcs3's needs. There is currently no PPA available to work around this.
|
||||
@@ -65,6 +81,7 @@ sudo apt install vulkan-sdk
|
||||
```
|
||||
|
||||
##### CMake
|
||||
|
||||
```
|
||||
. /etc/os-release
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | sudo apt-key add -
|
||||
@@ -95,27 +112,64 @@ git submodule update --init
|
||||
|
||||
### Windows
|
||||
|
||||
#### Configuring the Qt plugin (if used)
|
||||
#### Building with Visual Studio sln solution
|
||||
|
||||
1) Go to `Extensions->Qt VS Tools->Qt Versions`.
|
||||
2) Add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.6.3\msvc2019_64`, version will fill in automatically.
|
||||
3) Go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the legacy Qt plugin)
|
||||
4) Set `Build: Run pre-build setup` to `true`. (Only available in the legacy Qt plugin)
|
||||
Start **Visual Studio**, click on `Open a project or solution` and select the `rpcs3.sln` file inside the RPCS3's root folder
|
||||
|
||||
#### Building the projects
|
||||
##### Configuring the Qt Plugin (if used)
|
||||
|
||||
Open `rpcs3.sln`. The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`)
|
||||
1) go to `Extensions->Qt VS Tools->Qt Versions`
|
||||
2) add the path to your Qt installation with compiler e.g. `<QtInstallFolder>\6.7.3\msvc2019_64`, version will fill in automatically
|
||||
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
|
||||
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
|
||||
|
||||
You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`, as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation time (unoptimised/debug libs are currently not available precompiled).
|
||||
##### Building the projects
|
||||
|
||||
If you're not using the precompiled libs, build the following projects in *__BUILD_BEFORE* folder by right-clicking on a project > *Build*.:
|
||||
* glslang
|
||||
* **Either** llvm_build **or** llvm_build_clang_cl
|
||||
* spirv
|
||||
**NOTE:** The recommended build configuration is `Release`. (On older revisions: `Release - LLVM`)
|
||||
|
||||
Afterwards:
|
||||
You may want to download the precompiled [LLVM libs](https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-16.0.1/llvmlibs_mt.7z) and extract them to `3rdparty\llvm\`,
|
||||
as well as download and extract the [additional libs](https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z) to `lib\%CONFIGURATION%-x64\` to speed up compilation
|
||||
time (unoptimised/debug libs are currently not available precompiled).
|
||||
|
||||
`Build > Build Solution`
|
||||
If you're not using the precompiled libs, those dependency libs need to be compiled first. From the `Solution Explorer` panel:
|
||||
1) expand `__BUILD_BEFORE`
|
||||
2) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode)
|
||||
3) one after another, right-click on the following projects and then click on `Build` to build the selected lib:
|
||||
- `glslang`
|
||||
- either `llvm_build`
|
||||
- or `llvm_build_clang_cl` (if you installed **clang** on VS)
|
||||
|
||||
In order to build the **RPCS3** application:
|
||||
1) from the `Solution Configurations` drop-down menu, select `Release` (select `Debug` if you want to build in `Debug` mode)
|
||||
|
||||
**NOTE:** In case you previously compiled the dependency libs under `__BUILD_BEFORE`, you have also to select the same build configuration (e.g. `Release`, if you compiled the dependency libs in `Release` mode)
|
||||
|
||||
2) click on `Build` menu and then on `Build Solution`
|
||||
3) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\bin` folder
|
||||
|
||||
#### Building with Visual Studio CMake solution
|
||||
|
||||
Start **Visual Studio**, click on `Open a local folder` and select the RPCS3's root folder
|
||||
|
||||
Once the project is open on VS, from the `Solution Explorer` panel:
|
||||
1) right-click on `rpcs3` and then click on `Switch to CMake Targets View`
|
||||
2) from the `Configuration` drop-down menu, select `msvc-release` (select `msvc-debug` if you want to build in `Debug` mode)
|
||||
3) right-click on `CMakeLists.txt Project` and then click on `Configure Cache`
|
||||
4) once the cache is created, the `rpcs3 project` will be available
|
||||
5) right-click on `rpcs3 Project` and then click on `Build All`, or click on `Build` menu and then on `Build All`
|
||||
6) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\build-msvc\bin` folder
|
||||
|
||||
#### Building with standalone CMake tool
|
||||
|
||||
In case you preferred to install and use the standalone **CMake** tool:
|
||||
1) move on the RPCS3's root folder
|
||||
2) execute the following commands to create the cache and to build the application (for the build, use `--preset msvc-debug` if you want to build in `Debug` mode), respectively:
|
||||
|
||||
```
|
||||
cmake --preset msvc
|
||||
cmake --build --preset msvc-release
|
||||
```
|
||||
3) once the build is completed, the **RPCS3** application will be available under the `<rpcs3_root>\build-msvc\bin` folder
|
||||
|
||||
### Linux
|
||||
|
||||
@@ -123,7 +177,9 @@ While still in the project root:
|
||||
|
||||
1) `cd .. && mkdir --parents rpcs3_build && cd rpcs3_build`
|
||||
2) `cmake ../rpcs3/ && make` or `CXX=g++-13 CC=gcc-13 cmake ../rpcs3/ && make` to force these compilers
|
||||
3) Run RPCS3 with `./bin/rpcs3`
|
||||
3) run RPCS3 with `./bin/rpcs3`
|
||||
|
||||
If compiling for ARM, pass the flag `-DUSE_NATIVE_INSTRUCTIONS=OFF` to the cmake command. This resolves some Neon errors when compiling our SIMD headers.
|
||||
|
||||
When using GDB, configure it to ignore SIGSEGV signal (`handle SIGSEGV nostop noprint`).
|
||||
If desired, use the various build options in [CMakeLists](https://github.com/RPCS3/rpcs3/blob/master/CMakeLists.txt).
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ option(USE_SYSTEM_ZLIB "Prefer system ZLIB instead of the builtin one" ON)
|
||||
option(USE_VULKAN "Vulkan render backend" ON)
|
||||
option(USE_PRECOMPILED_HEADERS "Use precompiled headers" OFF)
|
||||
option(USE_SDL "Enables SDL input handler" OFF)
|
||||
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" OFF)
|
||||
option(USE_SYSTEM_SDL "Prefer system SDL instead of the builtin one" ON)
|
||||
option(USE_SYSTEM_FFMPEG "Prefer system ffmpeg instead of the prebuild one" OFF)
|
||||
option(USE_SYSTEM_OPENAL "Prefer system OpenAL instead of the prebuild one" ON)
|
||||
option(USE_SYSTEM_CURL "Prefer system Curl instead of the prebuild one" ON)
|
||||
|
||||
+22
-7
@@ -7,12 +7,12 @@
|
||||
"binaryDir": "build-gcc",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_SYSTEM_CURL": "OFF",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_SYSTEM_LIBPNG": "OFF",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"BUILD_LLVM": "OFF",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
}
|
||||
@@ -23,13 +23,13 @@
|
||||
"binaryDir": "build-clang64",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_SYSTEM_CURL": "OFF",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_SYSTEM_LIBPNG": "OFF",
|
||||
"LLVM_ENABLE_LIBCXX": "ON",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"BUILD_LLVM": "OFF",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
},
|
||||
@@ -48,11 +48,14 @@
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_CONFIGURATION_TYPES": "Debug;Release",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_NATIVE_INSTRUCTIONS": "ON",
|
||||
"USE_PRECOMPILED_HEADERS": "ON",
|
||||
"USE_FAUDIO": "OFF",
|
||||
"USE_SYSTEM_CURL": "OFF",
|
||||
"USE_SYSTEM_ZLIB": "OFF",
|
||||
"USE_SYSTEM_OPENAL": "OFF",
|
||||
"BUILD_LLVM": "ON",
|
||||
"STATIC_LINK_LLVM": "ON"
|
||||
},
|
||||
@@ -64,5 +67,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "msvc-debug",
|
||||
"configurePreset": "msvc",
|
||||
"configuration": "Debug"
|
||||
},
|
||||
{
|
||||
"name": "msvc-release",
|
||||
"configurePreset": "msvc",
|
||||
"configuration": "Release"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+85
-3
@@ -2475,7 +2475,6 @@ bool fs::pending_file::commit(bool overwrite)
|
||||
{
|
||||
file.sync();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
@@ -2486,15 +2485,98 @@ bool fs::pending_file::commit(bool overwrite)
|
||||
disp.DeleteFileW = false;
|
||||
ensure(SetFileInformationByHandle(file.get_handle(), FileDispositionInfo, &disp, sizeof(disp)));
|
||||
}
|
||||
|
||||
std::vector<std::wstring> hardlink_paths;
|
||||
|
||||
const auto ws1 = to_wchar(m_path);
|
||||
|
||||
const HANDLE file_handle = !overwrite ? INVALID_HANDLE_VALUE
|
||||
: CreateFileW(ws1.get(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
|
||||
while (file_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Get file ID (used to check for hardlinks)
|
||||
BY_HANDLE_FILE_INFORMATION file_info;
|
||||
|
||||
if (!GetFileInformationByHandle(file_handle, &file_info) || file_info.nNumberOfLinks == 1)
|
||||
{
|
||||
CloseHandle(file_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
// Buffer for holding link name
|
||||
std::wstring link_name_buffer(MAX_PATH, wchar_t{});
|
||||
DWORD buffer_size{};
|
||||
HANDLE find_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
while (true)
|
||||
{
|
||||
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
|
||||
find_handle = FindFirstFileNameW(ws1.get(), 0, &buffer_size, link_name_buffer.data());
|
||||
|
||||
if (find_handle != INVALID_HANDLE_VALUE || GetLastError() != ERROR_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
link_name_buffer.resize(buffer_size + 1);
|
||||
}
|
||||
|
||||
if (find_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const std::wstring_view ws1_sv = ws1.get();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (link_name_buffer.c_str() != ws1_sv)
|
||||
{
|
||||
// Note: link_name_buffer is a buffer which may contain zeroes so truncate it
|
||||
hardlink_paths.push_back(link_name_buffer.c_str());
|
||||
}
|
||||
|
||||
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
|
||||
if (!FindNextFileNameW(find_handle, &buffer_size, link_name_buffer.data()))
|
||||
{
|
||||
if (GetLastError() != ERROR_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
link_name_buffer.resize(buffer_size + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
FindClose(find_handle);
|
||||
CloseHandle(file_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hardlink_paths.empty())
|
||||
{
|
||||
// REPLACEFILE_WRITE_THROUGH is not supported
|
||||
file.sync();
|
||||
}
|
||||
#endif
|
||||
|
||||
file.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto ws1 = to_wchar(m_path);
|
||||
const auto ws2 = to_wchar(m_dest);
|
||||
|
||||
if (MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH))
|
||||
bool ok = false;
|
||||
|
||||
if (hardlink_paths.empty())
|
||||
{
|
||||
ok = MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = ReplaceFileW(ws1.get(), ws2.get(), nullptr, 0, nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
// Disable the destructor
|
||||
m_path.clear();
|
||||
|
||||
+19
-13
@@ -110,18 +110,21 @@ static u64 make_null_function(const std::string& name)
|
||||
c.align(AlignMode::kData, 16);
|
||||
#else
|
||||
// AArch64 implementation
|
||||
Label jmp_address = c.newLabel();
|
||||
Label data = c.newLabel();
|
||||
// Force absolute jump to prevent out of bounds PC-rel jmp
|
||||
c.ldr(args[0], arm::ptr(jmp_address));
|
||||
c.br(args[0]);
|
||||
c.align(AlignMode::kCode, 16);
|
||||
Label jump_address = c.newLabel();
|
||||
c.ldr(args[0], arm::ptr(data, 0));
|
||||
c.ldr(a64::x14, arm::ptr(jump_address, 0));
|
||||
c.br(a64::x14);
|
||||
|
||||
// Data frame
|
||||
c.align(AlignMode::kCode, 16);
|
||||
c.bind(jump_address);
|
||||
c.embedUInt64(reinterpret_cast<u64>(&null));
|
||||
|
||||
c.align(AlignMode::kData, 16);
|
||||
c.bind(data);
|
||||
c.embed(name.c_str(), name.size());
|
||||
c.embedUInt8(0U);
|
||||
c.bind(jmp_address);
|
||||
c.embedUInt64(reinterpret_cast<u64>(&null));
|
||||
c.align(AlignMode::kData, 16);
|
||||
#endif
|
||||
});
|
||||
@@ -731,11 +734,14 @@ llvm::StringRef fallback_cpu_detection()
|
||||
const auto family = utils::get_cpu_family();
|
||||
const auto model = utils::get_cpu_model();
|
||||
|
||||
jit_log.error("CPU wasn't identified by LLVM, brand = %s, family = 0x%x, model = 0x%x", brand, family, model);
|
||||
|
||||
if (brand.starts_with("AMD"))
|
||||
{
|
||||
switch (family)
|
||||
{
|
||||
case 0x10:
|
||||
case 0x12: // Unimplemented in LLVM
|
||||
return "amdfam10";
|
||||
case 0x15:
|
||||
// Bulldozer class, includes piledriver, excavator, steamroller, etc
|
||||
@@ -746,17 +752,17 @@ llvm::StringRef fallback_cpu_detection()
|
||||
return "znver1";
|
||||
case 0x19:
|
||||
// Models 0-Fh are zen3 as are 20h-60h. The rest we can assume are zen4
|
||||
return ((model >= 0x20 && model <= 0x60) || model < 0x10)
|
||||
? "znver3"
|
||||
: "znver4";
|
||||
return ((model >= 0x20 && model <= 0x60) || model < 0x10) ? "znver3" : "znver4";
|
||||
case 0x1a:
|
||||
// Only one generation in family 1a so far, zen5, which we do not support yet.
|
||||
// Return zen4 as a workaround until the next LLVM upgrade.
|
||||
return "znver4";
|
||||
default:
|
||||
return utils::has_avx512()
|
||||
? "znver4"
|
||||
: "znver3";
|
||||
// Safest guesses
|
||||
return utils::has_avx512() ? "znver4" :
|
||||
utils::has_avx2() ? "znver1" :
|
||||
utils::has_avx() ? "bdver1" :
|
||||
"nehalem";
|
||||
}
|
||||
}
|
||||
else if (brand.find("Intel") != std::string::npos)
|
||||
|
||||
+11
-3
@@ -1840,10 +1840,18 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
|
||||
}
|
||||
}
|
||||
|
||||
fmt::append(msg, "Instruction address: %p.\n", pExp->ContextRecord->Rip);
|
||||
#if defined(ARCH_X64)
|
||||
const auto exec_addr = pExp->ContextRecord->Rip;
|
||||
#elif defined(ARCH_ARM64)
|
||||
const auto exec_addr = pExp->ContextRecord->Pc;
|
||||
#else
|
||||
#error "Unimplemented exception handling for this architecture"
|
||||
#endif
|
||||
|
||||
fmt::append(msg, "Instruction address: %p.\n", exec_addr);
|
||||
|
||||
DWORD64 unwind_base;
|
||||
if (const auto rtf = RtlLookupFunctionEntry(pExp->ContextRecord->Rip, &unwind_base, nullptr))
|
||||
if (const auto rtf = RtlLookupFunctionEntry(exec_addr, &unwind_base, nullptr))
|
||||
{
|
||||
// Get function address
|
||||
const DWORD64 func_addr = rtf->BeginAddress + unwind_base;
|
||||
@@ -1860,7 +1868,7 @@ static LONG exception_filter(PEXCEPTION_POINTERS pExp) noexcept
|
||||
{
|
||||
const DWORD64 base = reinterpret_cast<DWORD64>(info.lpBaseOfDll);
|
||||
|
||||
if (pExp->ContextRecord->Rip >= base && pExp->ContextRecord->Rip < base + info.SizeOfImage)
|
||||
if (exec_addr >= base && exec_addr < base + info.SizeOfImage)
|
||||
{
|
||||
std::string module_name;
|
||||
for (DWORD size = 15; module_name.size() != size;)
|
||||
|
||||
+5
-1
@@ -510,15 +510,19 @@ class named_thread final : public Context, result_storage<Context>, thread_base
|
||||
|
||||
#if defined(ARCH_X64)
|
||||
static inline thread::native_entry trampoline = thread::make_trampoline(entry_point);
|
||||
#else
|
||||
#ifdef _WIN32
|
||||
static uint trampoline(void* arg)
|
||||
#else
|
||||
static void* trampoline(void* arg)
|
||||
#endif
|
||||
{
|
||||
if (const auto next = thread_base::finalize(entry_point(static_cast<thread_base*>(arg))))
|
||||
{
|
||||
return next(thread_ctrl::get_current());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -41,12 +41,18 @@ namespace utils
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
STACKFRAME64 stack = {};
|
||||
stack.AddrPC.Offset = context.Rip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = context.Rsp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = context.Rbp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#if defined(ARCH_X64)
|
||||
stack.AddrPC.Offset = context.Rip;
|
||||
stack.AddrStack.Offset = context.Rsp;
|
||||
stack.AddrFrame.Offset = context.Rbp;
|
||||
#elif defined(ARCH_ARM64)
|
||||
stack.AddrPC.Offset = context.Pc;
|
||||
stack.AddrStack.Offset = context.Sp;
|
||||
stack.AddrFrame.Offset = context.Fp;
|
||||
#endif
|
||||
|
||||
while (max_depth--)
|
||||
{
|
||||
|
||||
+81
-18
@@ -38,13 +38,13 @@ jobs:
|
||||
displayName: ccache
|
||||
|
||||
- bash: |
|
||||
docker pull --quiet rpcs3/rpcs3-ci-focal:1.7
|
||||
docker pull --quiet rpcs3/rpcs3-ci-focal:1.9
|
||||
docker run \
|
||||
-v $(pwd):/rpcs3 \
|
||||
--env-file .ci/docker.env \
|
||||
-v $CCACHE_DIR:/root/.ccache \
|
||||
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
||||
rpcs3/rpcs3-ci-focal:1.7 \
|
||||
rpcs3/rpcs3-ci-focal:1.9 \
|
||||
/rpcs3/.ci/build-linux.sh
|
||||
displayName: Docker setup and build
|
||||
|
||||
@@ -69,9 +69,9 @@ jobs:
|
||||
variables:
|
||||
COMPILER: msvc
|
||||
QT_VER_MAIN: '6'
|
||||
QT_VER: '6.6.3'
|
||||
QT_VER: '6.7.3'
|
||||
QT_VER_MSVC: 'msvc2019'
|
||||
QT_DATE: '202403191840'
|
||||
QT_DATE: '202409200836'
|
||||
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
||||
VULKAN_VER: '1.3.268.0'
|
||||
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
||||
@@ -122,7 +122,7 @@ jobs:
|
||||
env:
|
||||
RPCS3_TOKEN: $(RPCS3-Token)
|
||||
|
||||
- job: Mac_Build
|
||||
- job: Mac_Build_x86_64
|
||||
timeoutInMinutes: 180
|
||||
variables:
|
||||
CCACHE_DIR: "/tmp/ccache_dir"
|
||||
@@ -132,11 +132,12 @@ jobs:
|
||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
|
||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
||||
ARTDIR: $(Build.ArtifactStagingDirectory)
|
||||
QT_VER: '6.6.3'
|
||||
QT_VER: '6.7.3'
|
||||
QT_VER_MAIN: '6'
|
||||
LLVM_COMPILER_VER: '16'
|
||||
|
||||
pool:
|
||||
vmImage: "macOS-12"
|
||||
vmImage: "macOS-13"
|
||||
|
||||
steps:
|
||||
- task: Cache@2
|
||||
@@ -149,29 +150,91 @@ jobs:
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: qt | "$(Agent.OS)" | "$(QT_VER)"
|
||||
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
||||
path: /tmp/Qt
|
||||
restoreKeys: |
|
||||
qt | "$(Agent.OS)" | "$(QT_VER)"
|
||||
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
||||
displayName: Qt cache
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: brew | "$(Agent.OS)"
|
||||
path: /Users/runner/Library/Caches/Homebrew
|
||||
restoreKeys: |
|
||||
brew | "$(Agent.OS)"
|
||||
displayName: Homebrew cache
|
||||
# - task: Cache@2
|
||||
# inputs:
|
||||
# key: brew | "$(Agent.OS)"
|
||||
# path: /Users/runner/Library/Caches/Homebrew
|
||||
# restoreKeys: |
|
||||
# brew | "$(Agent.OS)"
|
||||
# displayName: Homebrew cache
|
||||
|
||||
- bash: |
|
||||
chmod +x ".ci/build-mac.sh"
|
||||
chmod +x ".ci/deploy-mac.sh"
|
||||
chmod +x ".ci/optimize-mac.sh"
|
||||
".ci/build-mac.sh"
|
||||
displayName: Build MacOS
|
||||
displayName: Build macOS (x86_64)
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
condition: succeeded()
|
||||
artifact: RPCS3 for Mac
|
||||
artifact: RPCS3 for Mac (Intel)
|
||||
|
||||
- bash: |
|
||||
source './.ci/export-cirrus-vars.sh'
|
||||
.ci/github-upload.sh
|
||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
displayName: Push build to GitHub
|
||||
env:
|
||||
RPCS3_TOKEN: $(RPCS3-Token)
|
||||
|
||||
- job: Mac_Build_arm64
|
||||
timeoutInMinutes: 180
|
||||
variables:
|
||||
CCACHE_DIR: "/tmp/ccache_dir"
|
||||
CCACHE_MAXSIZE: 300M
|
||||
CI_HAS_ARTIFACTS: true
|
||||
UPLOAD_COMMIT_HASH: 8e21bdbc40711a3fccd18fbf17b742348b0f4281
|
||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac-arm64"
|
||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
||||
ARTDIR: $(Build.ArtifactStagingDirectory)
|
||||
QT_VER: '6.7.3'
|
||||
QT_VER_MAIN: '6'
|
||||
LLVM_COMPILER_VER: '16'
|
||||
|
||||
pool:
|
||||
vmImage: "macOS-13"
|
||||
|
||||
steps:
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: ccache | "$(Agent.OS)"
|
||||
path: $(CCACHE_DIR)
|
||||
restoreKeys: |
|
||||
ccache | "$(Agent.OS)"
|
||||
displayName: Ccache cache
|
||||
|
||||
- task: Cache@2
|
||||
inputs:
|
||||
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
||||
path: /tmp/Qt
|
||||
restoreKeys: |
|
||||
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
||||
displayName: Qt cache
|
||||
|
||||
# - task: Cache@2
|
||||
# inputs:
|
||||
# key: brew | "$(Agent.OS)"
|
||||
# path: /Users/runner/Library/Caches/Homebrew
|
||||
# restoreKeys: |
|
||||
# brew | "$(Agent.OS)"
|
||||
# displayName: Homebrew cache
|
||||
|
||||
- bash: |
|
||||
chmod +x ".ci/build-mac-arm64.sh"
|
||||
chmod +x ".ci/deploy-mac-arm64.sh"
|
||||
chmod +x ".ci/optimize-mac.sh"
|
||||
".ci/build-mac-arm64.sh"
|
||||
displayName: Build macOS (arm64)
|
||||
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
condition: succeeded()
|
||||
artifact: RPCS3 for Mac (Apple Silicon)
|
||||
|
||||
- bash: |
|
||||
source './.ci/export-cirrus-vars.sh'
|
||||
|
||||
@@ -20,6 +20,9 @@ QToolBar#mw_toolbar::separator {
|
||||
margin-top:2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
QToolButton:disabled {
|
||||
color: #787878;
|
||||
}
|
||||
QSlider#sizeSlider::groove:horizontal {
|
||||
border: 0em solid transparent;
|
||||
height: .3em;
|
||||
@@ -147,3 +150,16 @@ QLabel#l_controller {
|
||||
#game_list_grid_item[focus="true"] #game_list_grid_item_title_label {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Top menu bar (Workaround for transparent menus in Qt 6.7.3) */
|
||||
QMenu {
|
||||
color: #000;
|
||||
background-color: #F0F0F0;
|
||||
alternate-background-color: #f2f2f2;
|
||||
}
|
||||
QMenu::item:selected {
|
||||
background: #90C8F6;
|
||||
}
|
||||
QMenu::item:disabled {
|
||||
color: #787878;
|
||||
}
|
||||
|
||||
@@ -88,6 +88,7 @@ else()
|
||||
add_compile_options(-Wno-unused-lambda-capture)
|
||||
add_compile_options(-Wno-unused-private-field)
|
||||
add_compile_options(-Wno-unused-command-line-argument)
|
||||
add_compile_options(-Wno-elaborated-enum-base)
|
||||
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
add_compile_options(-Wno-class-memaccess)
|
||||
endif()
|
||||
@@ -100,10 +101,6 @@ else()
|
||||
add_link_options(-no-pie)
|
||||
endif()
|
||||
elseif(APPLE)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
add_compile_options(-stdlib=libc++)
|
||||
endif()
|
||||
|
||||
if (CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
|
||||
add_link_options(-Wl,-image_base,0x10000 -Wl,-pagezero_size,0x10000)
|
||||
add_link_options(-Wl,-no_pie)
|
||||
@@ -117,6 +114,14 @@ else()
|
||||
# Increase stack limit to 8 MB
|
||||
add_link_options(-Wl,--stack -Wl,8388608)
|
||||
|
||||
add_link_options(-Wl,--image-base,0x10000)
|
||||
# For arm64 windows, the image base cannot be below 4GB or the OS rejects the binary without much explanation.
|
||||
if(COMPILER_X86)
|
||||
add_link_options(-Wl,--image-base,0x10000)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Specify C++ library to use as standard C++ when using clang (not required on linux due to GNU)
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND (APPLE OR WIN32))
|
||||
add_compile_options(-stdlib=libc++)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
set(CMAKE_SYSTEM_NAME Darwin)
|
||||
set(CMAKE_SYSTEM_PROCESSOR arm64)
|
||||
@@ -76,8 +76,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcurl", "3rdparty\curl\li
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {73973223-5EE8-41CA-8E88-1D60E89A237B}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "spirv", "3rdparty\SPIRV\spirv.vcxproj", "{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "llvm_build_clang_cl", "3rdparty\llvm\llvm_build\llvm_build_clang_cl.vcxproj", "{A37E4273-85DB-4217-B775-CE971B87D9DF}"
|
||||
@@ -175,8 +173,6 @@ Global
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Debug|x64.Build.0 = Debug|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.ActiveCfg = Release|x64
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB}.Release|x64.Build.0 = Release|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1}.Release|x64.ActiveCfg = Release|x64
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF}.Release|x64.ActiveCfg = Release|x64
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -236,7 +232,6 @@ Global
|
||||
{349EE8F9-7D25-4909-AAF5-FF3FADE72187} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{73973223-5EE8-41CA-8E88-1D60E89A237B} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{DA6F56B4-06A4-441D-AD70-AC5A7D51FADB} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
{4CBD3DDD-5555-49A4-A44D-DD3D8CB516A1} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
|
||||
{A37E4273-85DB-4217-B775-CE971B87D9DF} = {B0AC29FD-7B01-4B5E-9C8D-0A081E4C5668}
|
||||
{9610627D-20FE-4B07-8CE3-9FF68A5F1EC2} = {10FBF193-D532-4CCF-B875-4C7091A7F6C2}
|
||||
{FDA7B080-03B0-48C8-B24F-88118981422A} = {6C3B64A0-8F8A-4DC4-8C0B-D71EBEED7FA8}
|
||||
|
||||
+21
-20
@@ -114,7 +114,7 @@ if(UNIX)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(rpcs3 PRIVATE ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
|
||||
target_link_libraries(rpcs3 PRIVATE bcrypt ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
|
||||
else()
|
||||
target_link_libraries(rpcs3 PRIVATE ${CMAKE_DL_LIBS})
|
||||
endif()
|
||||
@@ -130,30 +130,31 @@ if(APPLE)
|
||||
else()
|
||||
set(QT_DEPLOY_FLAGS "")
|
||||
endif()
|
||||
qt_finalize_target(rpcs3)
|
||||
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_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/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<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/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
|
||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
|
||||
elseif(UNIX)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
|
||||
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/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
|
||||
elseif(WIN32)
|
||||
if(MSVC)
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_BINARY_DIR}/3rdparty/OpenAL/openal-soft/$<CONFIG>/OpenAL32.dll $<TARGET_FILE_DIR:rpcs3>)
|
||||
endif()
|
||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
||||
COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_SOURCE_DIR}/bin" "$<TARGET_FILE_DIR:rpcs3>"
|
||||
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt --no-translations --no-quick --no-system-d3d-compiler --no-quick-import --plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>" --verbose 0 "$<TARGET_FILE:rpcs3>")
|
||||
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/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git
|
||||
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
|
||||
--no-translations --no-quick --no-system-d3d-compiler --no-quick-import
|
||||
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
|
||||
--verbose 0 "$<TARGET_FILE:rpcs3>")
|
||||
endif()
|
||||
|
||||
# Unix installation
|
||||
|
||||
@@ -239,6 +239,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
Cell/Modules/cellAdec.cpp
|
||||
Cell/Modules/cellAtrac.cpp
|
||||
Cell/Modules/cellAtracMulti.cpp
|
||||
Cell/Modules/cellAtracXdec.cpp
|
||||
Cell/Modules/cellAudio.cpp
|
||||
Cell/Modules/cellAudioOut.cpp
|
||||
Cell/Modules/cellAuthDialog.cpp
|
||||
@@ -389,7 +390,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
CPU/CPUTranslator.cpp
|
||||
)
|
||||
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "arm64|aarch64")
|
||||
if(CMAKE_SYSTEM_PROCESSOR MATCHES "ARM64|arm64|aarch64")
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
CPU/Backends/AArch64/AArch64ASM.cpp
|
||||
CPU/Backends/AArch64/AArch64Common.cpp
|
||||
@@ -442,8 +443,10 @@ target_link_libraries(rpcs3_emu PRIVATE
|
||||
target_sources(rpcs3_emu PRIVATE
|
||||
NP/fb_helpers.cpp
|
||||
NP/np_cache.cpp
|
||||
NP/np_gui_cache.cpp
|
||||
NP/np_contexts.cpp
|
||||
NP/np_dnshook.cpp
|
||||
NP/np_requests_gui.cpp
|
||||
NP/np_handler.cpp
|
||||
NP/np_helpers.cpp
|
||||
NP/np_notifications.cpp
|
||||
@@ -475,6 +478,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/gcm_printing.cpp
|
||||
RSX/GL/GLCommonDecompiler.cpp
|
||||
RSX/GL/GLCompute.cpp
|
||||
RSX/GL/GLDMA.cpp
|
||||
RSX/GL/GLDraw.cpp
|
||||
RSX/GL/GLFragmentProgram.cpp
|
||||
RSX/GL/GLGSRender.cpp
|
||||
@@ -500,6 +504,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/GL/OpenGL.cpp
|
||||
RSX/GL/upscalers/fsr1/fsr_pass.cpp
|
||||
RSX/GSRender.cpp
|
||||
RSX/Host/RSXDMAWriter.cpp
|
||||
RSX/Null/NullGSRender.cpp
|
||||
RSX/NV47/FW/draw_call.cpp
|
||||
RSX/NV47/FW/reg_context.cpp
|
||||
@@ -509,6 +514,7 @@ target_sources(rpcs3_emu PRIVATE
|
||||
RSX/NV47/HW/nv308a.cpp
|
||||
RSX/NV47/HW/nv406e.cpp
|
||||
RSX/NV47/HW/nv4097.cpp
|
||||
RSX/Overlays/FriendsList/overlay_friends_list_dialog.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_components.cpp
|
||||
RSX/Overlays/HomeMenu/overlay_home_menu_main_menu.cpp
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
|
||||
namespace aarch64
|
||||
{
|
||||
constexpr u32 ESR_CTX_MAGIC = 0x45535201;
|
||||
|
||||
// Some of the EC codes we care about
|
||||
enum class EL1_exception_class
|
||||
{
|
||||
@@ -23,6 +21,8 @@ namespace aarch64
|
||||
};
|
||||
|
||||
#ifdef __linux__
|
||||
constexpr u32 ESR_CTX_MAGIC = 0x45535201;
|
||||
|
||||
const aarch64_esr_ctx* find_EL1_esr_context(const ucontext_t* ctx)
|
||||
{
|
||||
u32 offset = 0;
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <util/types.hpp>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/ucontext.h>
|
||||
#else
|
||||
using ucontext_t = void;
|
||||
#endif
|
||||
|
||||
namespace aarch64
|
||||
{
|
||||
|
||||
@@ -3729,6 +3729,22 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
value_t<f32[4]> vfixupimmps(T1 a, T2 b, T3 c, u8 d, u8 e)
|
||||
{
|
||||
value_t<f32[4]> result;
|
||||
|
||||
const auto data0 = a.eval(m_ir);
|
||||
const auto data1 = b.eval(m_ir);
|
||||
const auto data2 = c.eval(m_ir);
|
||||
const auto immediate = (llvm_const_int<u32>{d});
|
||||
const auto imm32 = immediate.eval(m_ir);
|
||||
const auto immediate2 = (llvm_const_int<u8>{e});
|
||||
const auto imm8 = immediate2.eval(m_ir);
|
||||
result.value = m_ir->CreateCall(get_intrinsic(llvm::Intrinsic::x86_avx512_mask_fixupimm_ps_128), {data0, data1, data2, imm32, imm8});
|
||||
return result;
|
||||
}
|
||||
|
||||
llvm::Value* load_const(llvm::GlobalVariable* g, llvm::Value* i, llvm::Type* type = nullptr)
|
||||
{
|
||||
return m_ir->CreateLoad(type ? type : g->getValueType(), m_ir->CreateGEP(g->getValueType(), g, {m_ir->getInt64(0), m_ir->CreateZExtOrTrunc(i, get_type<u64>())}));
|
||||
|
||||
@@ -132,6 +132,27 @@
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/* RPCS3 additions */
|
||||
#if defined(_WIN32)
|
||||
static inline int posix_memalign(void** memptr, size_t alignment, size_t size)
|
||||
{
|
||||
// Check for valid alignment (must be a power of two and multiple of sizeof(void*))
|
||||
if (alignment == 0 || (alignment & (alignment - 1)) != 0 || alignment % sizeof(void*) != 0)
|
||||
return EINVAL;
|
||||
|
||||
// Allocate memory using _aligned_malloc
|
||||
void* ptr = _aligned_malloc(size, alignment);
|
||||
if (!ptr)
|
||||
// NOTE: _aligned_malloc sets errno, ideally we should use that to generate the return code
|
||||
return ENOMEM;
|
||||
|
||||
// Success
|
||||
*memptr = ptr;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
/* End RPCS3 additions */
|
||||
|
||||
/* "__has_builtin" can be used to query support for built-in functions
|
||||
* provided by gcc/clang and other compilers that support it.
|
||||
*/
|
||||
|
||||
@@ -28,6 +28,7 @@ extern "C"
|
||||
#endif
|
||||
|
||||
#include "cellPamf.h"
|
||||
#include "cellAtracXdec.h"
|
||||
#include "cellAdec.h"
|
||||
|
||||
#include <mutex>
|
||||
@@ -136,63 +137,6 @@ void fmt_class_string<CellAdecError>::format(std::string& out, u64 arg)
|
||||
STR_CASE(CELL_ADEC_ERROR_AT3_BUSY);
|
||||
STR_CASE(CELL_ADEC_ERROR_AT3_EMPTY);
|
||||
STR_CASE(CELL_ADEC_ERROR_AT3_ERROR);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_OK); // CELL_ADEC_ERROR_ATX_OFFSET, CELL_ADEC_ERROR_ATX_NONE
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_BUSY);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_EMPTY);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ATSHDR);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_NON_FATAL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_NOT_IMPLE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ENC_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL_HANDLE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NBYTES);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_POSCFG_PRESENT);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SYNCWORD);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL);
|
||||
STR_CASE(CELL_ADEC_ERROR_LPCM_FATAL);
|
||||
STR_CASE(CELL_ADEC_ERROR_LPCM_SEQ);
|
||||
STR_CASE(CELL_ADEC_ERROR_LPCM_ARG);
|
||||
@@ -910,7 +854,7 @@ error_code cellAdecDecodeAu(u32 handle, vm::ptr<CellAdecAuInfo> auInfo)
|
||||
|
||||
AdecTask task(adecDecodeAu);
|
||||
task.au.auInfo_addr = auInfo.addr();
|
||||
task.au.addr = auInfo->startAddr;
|
||||
task.au.addr = auInfo->startAddr.addr();
|
||||
task.au.size = auInfo->size;
|
||||
task.au.pts = (u64{auInfo->pts.upper} << 32) | u64{auInfo->pts.lower};
|
||||
task.au.userdata = auInfo->userData;
|
||||
@@ -1072,7 +1016,7 @@ error_code cellAdecGetPcmItem(u32 handle, vm::pptr<CellAdecPcmItem> pcmItem)
|
||||
pcm->auInfo.pts.lower = static_cast<u32>(af.pts);
|
||||
pcm->auInfo.pts.upper = static_cast<u32>(af.pts >> 32);
|
||||
pcm->auInfo.size = af.auSize;
|
||||
pcm->auInfo.startAddr = af.auAddr;
|
||||
pcm->auInfo.startAddr.set(af.auAddr);
|
||||
pcm->auInfo.userData = af.userdata;
|
||||
|
||||
if (adecIsAtracX(adec->type))
|
||||
@@ -1119,7 +1063,6 @@ DECLARE(ppu_module_manager::cellAdec)("cellAdec", []()
|
||||
{
|
||||
static ppu_static_module cell_libac3dec("cell_libac3dec");
|
||||
static ppu_static_module cellAtrac3dec("cellAtrac3dec");
|
||||
static ppu_static_module cellAtracXdec("cellAtracXdec");
|
||||
static ppu_static_module cellCelpDec("cellCelpDec");
|
||||
static ppu_static_module cellDTSdec("cellDTSdec");
|
||||
static ppu_static_module cellM2AACdec("cellM2AACdec");
|
||||
|
||||
+160
-129
@@ -111,68 +111,6 @@ enum CellAdecError : u32
|
||||
CELL_ADEC_ERROR_AT3_ERROR = 0x80612180,
|
||||
|
||||
|
||||
CELL_ADEC_ERROR_ATX_OFFSET = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_NONE = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_OK = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_BUSY = 0x80612264,
|
||||
CELL_ADEC_ERROR_ATX_EMPTY = 0x80612265,
|
||||
CELL_ADEC_ERROR_ATX_ATSHDR = 0x80612266,
|
||||
CELL_ADEC_ERROR_ATX_NON_FATAL = 0x80612281,
|
||||
CELL_ADEC_ERROR_ATX_NOT_IMPLE = 0x80612282,
|
||||
CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW = 0x80612283,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS = 0x80612284,
|
||||
CELL_ADEC_ERROR_ATX_FATAL = 0x8061228c,
|
||||
CELL_ADEC_ERROR_ATX_ENC_OVERFLOW = 0x8061228d,
|
||||
CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW = 0x8061228e,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT = 0x8061228f,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ = 0x80612290,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF = 0x80612291,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA = 0x80612292,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL = 0x80612293,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE = 0x80612294,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER = 0x80612295,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A = 0x80612296,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B = 0x80612297,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C = 0x80612298,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D = 0x80612299,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E = 0x8061229a,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A = 0x8061229b,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B = 0x8061229c,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C = 0x8061229d,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D = 0x8061229e,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A = 0x8061229f,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC = 0x806122a0,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A = 0x806122a1,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A = 0x806122a2,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B = 0x806122a3,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B = 0x806122a4,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS = 0x806122a5,
|
||||
CELL_ADEC_ERROR_ATX_FATAL_HANDLE = 0x806122aa,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ = 0x806122ab,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX = 0x806122ac,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_NBYTES = 0x806122ad,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM = 0x806122ae,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID = 0x806122af,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS = 0x806122b0,
|
||||
CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED = 0x806122b1,
|
||||
CELL_ADEC_ERROR_ATX_POSCFG_PRESENT = 0x806122b2,
|
||||
CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW = 0x806122b3,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID = 0x806122b4,
|
||||
CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED = 0x806122b5,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1 = 0x806122b6,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2 = 0x806122b7,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING = 0x806122b8,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING = 0x806122b9,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES = 0x806122ba,
|
||||
|
||||
CELL_ADEC_ERROR_ATX_ILL_SYNCWORD = 0x806122bb,
|
||||
CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ = 0x806122bc,
|
||||
CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX = 0x806122bd,
|
||||
CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER = 0x806122be,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER = 0x806122bf,
|
||||
CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL = 0x806122c8,
|
||||
|
||||
|
||||
CELL_ADEC_ERROR_LPCM_FATAL = 0x80612001,
|
||||
CELL_ADEC_ERROR_LPCM_SEQ = 0x80612002,
|
||||
CELL_ADEC_ERROR_LPCM_ARG = 0x80612003,
|
||||
@@ -250,38 +188,38 @@ enum CellAdecError : u32
|
||||
// Audio Codec Type
|
||||
enum AudioCodecType : s32
|
||||
{
|
||||
CELL_ADEC_TYPE_RESERVED1,
|
||||
CELL_ADEC_TYPE_INVALID1,
|
||||
CELL_ADEC_TYPE_LPCM_PAMF,
|
||||
CELL_ADEC_TYPE_AC3,
|
||||
CELL_ADEC_TYPE_ATRACX,
|
||||
CELL_ADEC_TYPE_MP3,
|
||||
CELL_ADEC_TYPE_ATRAC3,
|
||||
CELL_ADEC_TYPE_MPEG_L2,
|
||||
CELL_ADEC_TYPE_RESERVED5,
|
||||
CELL_ADEC_TYPE_RESERVED6,
|
||||
CELL_ADEC_TYPE_RESERVED7,
|
||||
CELL_ADEC_TYPE_RESERVED8,
|
||||
CELL_ADEC_TYPE_M2AAC,
|
||||
CELL_ADEC_TYPE_EAC3,
|
||||
CELL_ADEC_TYPE_TRUEHD,
|
||||
CELL_ADEC_TYPE_DTS, // Removed in firmware 4.00, integrated into DTSHD
|
||||
CELL_ADEC_TYPE_CELP,
|
||||
CELL_ADEC_TYPE_RESERVED10,
|
||||
CELL_ADEC_TYPE_LPCM_BLURAY,
|
||||
CELL_ADEC_TYPE_ATRACX_2CH,
|
||||
CELL_ADEC_TYPE_ATRACX_6CH,
|
||||
CELL_ADEC_TYPE_ATRACX_8CH,
|
||||
CELL_ADEC_TYPE_M4AAC,
|
||||
CELL_ADEC_TYPE_RESERVED12,
|
||||
CELL_ADEC_TYPE_RESERVED13,
|
||||
CELL_ADEC_TYPE_RESERVED14,
|
||||
CELL_ADEC_TYPE_RESERVED15,
|
||||
CELL_ADEC_TYPE_RESERVED16,
|
||||
CELL_ADEC_TYPE_RESERVED17,
|
||||
CELL_ADEC_TYPE_RESERVED18,
|
||||
CELL_ADEC_TYPE_RESERVED19,
|
||||
CELL_ADEC_TYPE_LPCM_DVD,
|
||||
CELL_ADEC_TYPE_WMA,
|
||||
CELL_ADEC_TYPE_DTSLBR,
|
||||
CELL_ADEC_TYPE_M4AAC_2CH,
|
||||
CELL_ADEC_TYPE_DTSHD,
|
||||
CELL_ADEC_TYPE_MPEG_L1,
|
||||
CELL_ADEC_TYPE_MP3S,
|
||||
CELL_ADEC_TYPE_M4AAC_2CH_MOD,
|
||||
CELL_ADEC_TYPE_CELP8,
|
||||
CELL_ADEC_TYPE_RESERVED20,
|
||||
CELL_ADEC_TYPE_RESERVED21,
|
||||
CELL_ADEC_TYPE_RESERVED22,
|
||||
CELL_ADEC_TYPE_RESERVED23,
|
||||
CELL_ADEC_TYPE_RESERVED24,
|
||||
CELL_ADEC_TYPE_RESERVED25,
|
||||
CELL_ADEC_TYPE_INVALID2,
|
||||
CELL_ADEC_TYPE_INVALID3,
|
||||
CELL_ADEC_TYPE_RESERVED22, // Either WMA Pro or WMA Lossless, was never released
|
||||
CELL_ADEC_TYPE_RESERVED23, // Either WMA Pro or WMA Lossless, was never released
|
||||
CELL_ADEC_TYPE_DTSHDCORE, // Removed in firmware 4.00, integrated into DTSHD
|
||||
CELL_ADEC_TYPE_ATRAC3MULTI,
|
||||
};
|
||||
|
||||
inline bool adecIsAtracX(s32 type)
|
||||
@@ -313,10 +251,12 @@ enum CellAdecChannel : s32
|
||||
// Sampling Rate
|
||||
enum CellAdecSampleRate : s32
|
||||
{
|
||||
CELL_ADEC_FS_RESERVED1 = 0,
|
||||
CELL_ADEC_FS_48kHz = 1,
|
||||
CELL_ADEC_FS_16kHz = 2,
|
||||
CELL_ADEC_FS_8kHz = 5,
|
||||
CELL_ADEC_FS_RESERVED1,
|
||||
CELL_ADEC_FS_48kHz,
|
||||
CELL_ADEC_FS_16kHz,
|
||||
CELL_ADEC_FS_96kHz,
|
||||
CELL_ADEC_FS_192kHz,
|
||||
CELL_ADEC_FS_8kHz,
|
||||
};
|
||||
|
||||
enum CellAdecBitLength : s32
|
||||
@@ -359,6 +299,13 @@ struct CellAdecResourceEx
|
||||
be_t<u32> maxContention;
|
||||
};
|
||||
|
||||
struct CellAdecResourceSpurs
|
||||
{
|
||||
be_t<u32> spurs_addr; // CellSpurs*
|
||||
u8 priority[8];
|
||||
be_t<u32> maxContention;
|
||||
};
|
||||
|
||||
// Callback Messages
|
||||
enum CellAdecMsgType : s32
|
||||
{
|
||||
@@ -370,16 +317,20 @@ enum CellAdecMsgType : s32
|
||||
|
||||
using CellAdecCbMsg = s32(u32 handle, CellAdecMsgType msgType, s32 msgData, u32 cbArg);
|
||||
|
||||
struct CellAdecCb
|
||||
// Used for internal callbacks as well
|
||||
template <typename F>
|
||||
struct AdecCb
|
||||
{
|
||||
vm::bptr<CellAdecCbMsg> cbFunc;
|
||||
be_t<u32> cbArg;
|
||||
vm::bptr<F> cbFunc;
|
||||
vm::bptr<void> cbArg;
|
||||
};
|
||||
|
||||
using CellAdecCb = AdecCb<CellAdecCbMsg>;
|
||||
|
||||
// AU Info
|
||||
struct CellAdecAuInfo
|
||||
{
|
||||
be_t<u32> startAddr;
|
||||
vm::bcptr<u8> startAddr;
|
||||
be_t<u32> size;
|
||||
CellCodecTimeStamp pts;
|
||||
be_t<u64> userData;
|
||||
@@ -401,6 +352,125 @@ struct CellAdecPcmItem
|
||||
CellAdecAuInfo auInfo;
|
||||
};
|
||||
|
||||
// Controls how much is added to the presentation time stamp of the previous frame if the game didn't set a pts itself in CellAdecAuInfo when calling cellAdecDecodeAu()
|
||||
enum AdecCorrectPtsValueType : s8
|
||||
{
|
||||
ADEC_CORRECT_PTS_VALUE_TYPE_UNSPECIFIED = -1,
|
||||
|
||||
// Adds a fixed amount
|
||||
ADEC_CORRECT_PTS_VALUE_TYPE_LPCM = 0,
|
||||
// 1
|
||||
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz = 2,
|
||||
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz = 3,
|
||||
ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz = 4,
|
||||
// 5: Dolby Digital
|
||||
// 6: ATRAC3
|
||||
// 7: MP3
|
||||
// 8: MP3
|
||||
// 9: MP3
|
||||
// 39: ATRAC3 multi-track
|
||||
|
||||
// Calls a decoder function (_SceAdecCorrectPtsValue_codec())
|
||||
// 17: Dolby Digital Plus
|
||||
// 18
|
||||
// 19
|
||||
// 20
|
||||
// 21: DTS HD
|
||||
// 22
|
||||
// 23
|
||||
// 24: CELP
|
||||
// 25: MPEG-2 AAC
|
||||
// 26: MPEG-2 BC
|
||||
// 27: Dolby TrueHD
|
||||
// 28: DTS
|
||||
// 29: MPEG-4 AAC
|
||||
// 30: Windows Media Audio
|
||||
// 31: DTS Express
|
||||
// 32: MP1
|
||||
// 33: MP3 Surround
|
||||
// 34: CELP8
|
||||
// 35: Windows Media Audio Professional
|
||||
// 36: Windows Media Audio Lossless
|
||||
// 37: DTS HD Core
|
||||
// 38: DTS HD Core
|
||||
};
|
||||
|
||||
// Internal callbacks
|
||||
using AdecNotifyAuDone = error_code(s32 pcmHandle, vm::ptr<void> cbArg);
|
||||
using AdecNotifyPcmOut = error_code(s32 pcmHandle, vm::ptr<void> pcmAddr, u32 pcmSize, vm::ptr<void> cbArg, vm::cpptr<void> bsiInfo, AdecCorrectPtsValueType correctPtsValueType, s32 errorCode);
|
||||
using AdecNotifyError = error_code(s32 errorCode, vm::ptr<void> cbArg);
|
||||
using AdecNotifySeqDone = error_code(vm::ptr<void> cbArg);
|
||||
|
||||
// Decoder functions
|
||||
using CellAdecCoreOpGetMemSize = error_code(vm::ptr<CellAdecAttr> attr);
|
||||
using CellAdecCoreOpOpen = error_code(vm::ptr<void> coreHandle, vm::ptr<AdecNotifyAuDone> cbFuncAuDone, vm::ptr<void> cbArgAuDone, vm::ptr<AdecNotifyPcmOut> cbFuncPcmOut, vm::ptr<void> cbArgPcmOut,
|
||||
vm::ptr<AdecNotifyError> cbFuncError, vm::ptr<void> cbArgError, vm::ptr<AdecNotifySeqDone> cbFuncSeqDone, vm::ptr<void> cbArgSeqDone, vm::cptr<CellAdecResource> res);
|
||||
using CellAdecCoreOpClose = error_code(vm::ptr<void> coreHandle);
|
||||
using CellAdecCoreOpStartSeq = error_code(vm::ptr<void> coreHandle, vm::cptr<void> param);
|
||||
using CellAdecCoreOpEndSeq = error_code(vm::ptr<void> coreHandle);
|
||||
using CellAdecCoreOpDecodeAu = error_code(vm::ptr<void> coreHandle, s32 pcmHandle, vm::cptr<CellAdecAuInfo> auInfo);
|
||||
using CellAdecCoreOpGetVersion = void(vm::ptr<be_t<u32, 1>> version);
|
||||
using CellAdecCoreOpRealign = error_code(vm::ptr<void> coreHandle, vm::ptr<void> outBuffer, vm::cptr<void> pcmStartAddr);
|
||||
using CellAdecCoreOpReleasePcm = error_code(vm::ptr<void> coreHandle, s32 pcmHandle, vm::cptr<void> outBuffer);
|
||||
using CellAdecCoreOpGetPcmHandleNum = s32();
|
||||
using CellAdecCoreOpGetBsiInfoSize = u32();
|
||||
using CellAdecCoreOpOpenExt = error_code(vm::ptr<void> coreHandle, vm::ptr<AdecNotifyAuDone> cbFuncAuDone, vm::ptr<void> cbArgAuDone, vm::ptr<AdecNotifyPcmOut> cbFuncPcmOut, vm::ptr<void> cbArgPcmOut,
|
||||
vm::ptr<AdecNotifyError> cbFuncError, vm::ptr<void> cbArgError, vm::ptr<AdecNotifySeqDone> cbFuncSeqDone, vm::ptr<void> cbArgSeqDone, vm::cptr<CellAdecResource> res, vm::cptr<CellAdecResourceSpurs> spursRes);
|
||||
|
||||
// Decoders export a pointer to this struct
|
||||
struct CellAdecCoreOps
|
||||
{
|
||||
vm::bptr<CellAdecCoreOpGetMemSize> getMemSize;
|
||||
vm::bptr<CellAdecCoreOpOpen> open;
|
||||
vm::bptr<CellAdecCoreOpClose> close;
|
||||
vm::bptr<CellAdecCoreOpStartSeq> startSeq;
|
||||
vm::bptr<CellAdecCoreOpEndSeq> endSeq;
|
||||
vm::bptr<CellAdecCoreOpDecodeAu> decodeAu;
|
||||
vm::bptr<CellAdecCoreOpGetVersion> getVersion;
|
||||
vm::bptr<CellAdecCoreOpRealign> realign;
|
||||
vm::bptr<CellAdecCoreOpReleasePcm> releasePcm;
|
||||
vm::bptr<CellAdecCoreOpGetPcmHandleNum> getPcmHandleNum;
|
||||
vm::bptr<CellAdecCoreOpGetBsiInfoSize> getBsiInfoSize;
|
||||
vm::bptr<CellAdecCoreOpOpenExt> openExt;
|
||||
};
|
||||
|
||||
// Used by several decoders as command queue
|
||||
template <typename T>
|
||||
struct AdecCmdQueue
|
||||
{
|
||||
T elements[4];
|
||||
|
||||
be_t<s32> front = 0;
|
||||
be_t<s32> back = 0;
|
||||
be_t<s32> size = 0;
|
||||
|
||||
template <bool is_peek = false>
|
||||
void pop(T& cmd)
|
||||
{
|
||||
// LLE returns uninitialized stack memory if the queue is empty
|
||||
cmd = elements[front];
|
||||
|
||||
if constexpr (!is_peek)
|
||||
{
|
||||
elements[front].pcm_handle = 0xff;
|
||||
front = (front + 1) & 3;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
|
||||
void emplace(auto&&... args)
|
||||
{
|
||||
new (&elements[back]) T(std::forward<decltype(args)>(args)...);
|
||||
|
||||
back = (back + 1) & 3;
|
||||
size++;
|
||||
}
|
||||
|
||||
void peek(T& cmd) const { return pop<true>(cmd); }
|
||||
bool empty() const { return size == 0; }
|
||||
bool full() const { return size >= 4; }
|
||||
};
|
||||
|
||||
struct CellAdecParamLpcm
|
||||
{
|
||||
be_t<u32> channelNumber;
|
||||
@@ -771,45 +841,6 @@ struct CellAdecAtrac3Info
|
||||
be_t<s32> nbytes;
|
||||
};
|
||||
|
||||
enum ATRACX_WordSize : s32
|
||||
{
|
||||
CELL_ADEC_ATRACX_WORD_SZ_16BIT = 0x02,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_24BIT = 0x03,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_32BIT = 0x04,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_FLOAT = 0x84,
|
||||
};
|
||||
|
||||
enum ATRACX_ATSHeaderInclude : u8
|
||||
{
|
||||
CELL_ADEC_ATRACX_ATS_HDR_NOTINC = 0,
|
||||
CELL_ADEC_ATRACX_ATS_HDR_INC = 1,
|
||||
};
|
||||
|
||||
enum ATRACX_DownmixFlag : u8
|
||||
{
|
||||
ATRACX_DOWNMIX_OFF = 0,
|
||||
ATRACX_DOWNMIX_ON = 1,
|
||||
};
|
||||
|
||||
struct CellAdecParamAtracX
|
||||
{
|
||||
be_t<s32> sampling_freq;
|
||||
be_t<s32> ch_config_idx;
|
||||
be_t<s32> nch_out;
|
||||
be_t<s32> nbytes;
|
||||
std::array<u8, 4> extra_config_data; // downmix coefficients
|
||||
be_t<s32> bw_pcm; // ATRACX_WordSize
|
||||
ATRACX_DownmixFlag downmix_flag;
|
||||
ATRACX_ATSHeaderInclude au_includes_ats_hdr_flg;
|
||||
};
|
||||
|
||||
struct CellAdecAtracXInfo
|
||||
{
|
||||
be_t<u32> samplingFreq; // [Hz]
|
||||
be_t<u32> channelConfigIndex;
|
||||
be_t<u32> nbytes;
|
||||
};
|
||||
|
||||
enum MP3_WordSize : s32
|
||||
{
|
||||
CELL_ADEC_MP3_WORD_SZ_16BIT = 3,
|
||||
|
||||
@@ -0,0 +1,892 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/perf_meter.hpp"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "Emu/Cell/lv2/sys_ppu_thread.h"
|
||||
#include "Emu/savestate_utils.hpp"
|
||||
#include "sysPrxForUser.h"
|
||||
#include "util/asm.hpp"
|
||||
#include "util/media_utils.h"
|
||||
|
||||
#include "cellAtracXdec.h"
|
||||
|
||||
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx2ch;
|
||||
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx6ch;
|
||||
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx8ch;
|
||||
vm::gvar<CellAdecCoreOps> g_cell_adec_core_ops_atracx;
|
||||
|
||||
LOG_CHANNEL(cellAtracXdec);
|
||||
|
||||
template <>
|
||||
void fmt_class_string<CellAtracXdecError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](CellAtracXdecError value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_OK); // CELL_ADEC_ERROR_ATX_OFFSET, CELL_ADEC_ERROR_ATX_NONE
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_BUSY);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_EMPTY);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ATSHDR);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_NON_FATAL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_NOT_IMPLE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ENC_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_FATAL_HANDLE);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NBYTES);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_POSCFG_PRESENT);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SYNCWORD);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER);
|
||||
STR_CASE(CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
constexpr u32 atracXdecGetSpursMemSize(u32 nch_in)
|
||||
{
|
||||
switch (nch_in)
|
||||
{
|
||||
case 1: return 0x6000;
|
||||
case 2: return 0x6000;
|
||||
case 3: return 0x12880;
|
||||
case 4: return 0x19c80;
|
||||
case 5: return -1;
|
||||
case 6: return 0x23080;
|
||||
case 7: return 0x2a480;
|
||||
case 8: return 0x2c480;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void AtracXdecDecoder::alloc_avcodec()
|
||||
{
|
||||
codec = avcodec_find_decoder(AV_CODEC_ID_ATRAC3P);
|
||||
if (!codec)
|
||||
{
|
||||
fmt::throw_exception("avcodec_find_decoder() failed");
|
||||
}
|
||||
|
||||
ensure(!(codec->capabilities & AV_CODEC_CAP_SUBFRAMES));
|
||||
|
||||
ctx = avcodec_alloc_context3(codec);
|
||||
if (!ctx)
|
||||
{
|
||||
fmt::throw_exception("avcodec_alloc_context3() failed");
|
||||
}
|
||||
|
||||
// Allows FFmpeg to output directly into guest memory
|
||||
ctx->opaque = this;
|
||||
ctx->thread_type = FF_THREAD_SLICE; // Silences a warning by FFmpeg about requesting frame threading with a custom get_buffer2(). Default is FF_THREAD_FRAME & FF_THREAD_SLICE
|
||||
ctx->get_buffer2 = [](AVCodecContext* s, AVFrame* frame, int /*flags*/) -> int
|
||||
{
|
||||
for (s32 i = 0; i < frame->ch_layout.nb_channels; i++)
|
||||
{
|
||||
frame->data[i] = static_cast<AtracXdecDecoder*>(s->opaque)->work_mem.get_ptr() + ATXDEC_MAX_FRAME_LENGTH + ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * i;
|
||||
frame->linesize[i] = ATXDEC_SAMPLES_PER_FRAME * sizeof(f32);
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
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->ch_layout.nb_channels = nch_in;
|
||||
ctx->sample_rate = sampling_freq;
|
||||
|
||||
if (int err = avcodec_open2(ctx, codec, nullptr); err)
|
||||
{
|
||||
fmt::throw_exception("avcodec_open2() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
|
||||
}
|
||||
|
||||
packet->data = work_mem.get_ptr();
|
||||
packet->size = nbytes;
|
||||
packet->buf = av_buffer_create(work_mem.get_ptr(), nbytes, [](void*, uint8_t*){}, nullptr, 0);
|
||||
}
|
||||
|
||||
error_code AtracXdecDecoder::set_config_info(u32 sampling_freq, u32 ch_config_idx, u32 nbytes)
|
||||
{
|
||||
cellAtracXdec.notice("AtracXdecDecoder::set_config_info(sampling_freq=%d, ch_config_idx=%d, nbytes=0x%x)", sampling_freq, ch_config_idx, nbytes);
|
||||
|
||||
this->sampling_freq = sampling_freq;
|
||||
this->ch_config_idx = ch_config_idx;
|
||||
this->nbytes = nbytes;
|
||||
this->nbytes_128_aligned = utils::align(nbytes, 0x80);
|
||||
this->nch_in = ch_config_idx <= 4 ? ch_config_idx : ch_config_idx + 1;
|
||||
|
||||
if (ch_config_idx > 7u)
|
||||
{
|
||||
this->config_is_set = false;
|
||||
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid channel configuration: %d", ch_config_idx };
|
||||
}
|
||||
|
||||
this->nch_blocks = ATXDEC_NCH_BLOCKS_MAP[ch_config_idx];
|
||||
|
||||
// These checks are performed on the LLE SPU thread
|
||||
if (ch_config_idx == 0u)
|
||||
{
|
||||
this->config_is_set = false;
|
||||
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid channel configuration: %d", ch_config_idx };
|
||||
}
|
||||
|
||||
if (sampling_freq != 48000u && sampling_freq != 44100u) // 32kHz is not supported, even though official docs claim it is
|
||||
{
|
||||
this->config_is_set = false;
|
||||
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid sample rate: %d", sampling_freq };
|
||||
}
|
||||
|
||||
if (nbytes == 0u || nbytes > ATXDEC_MAX_FRAME_LENGTH)
|
||||
{
|
||||
this->config_is_set = false;
|
||||
return { 0x80004005, "AtracXdecDecoder::set_config_info() failed: Invalid frame length: 0x%x", nbytes };
|
||||
}
|
||||
|
||||
this->config_is_set = true;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code AtracXdecDecoder::init_decode(u32 bw_pcm, u32 nch_out)
|
||||
{
|
||||
if (bw_pcm < CELL_ADEC_ATRACX_WORD_SZ_16BIT || (bw_pcm > CELL_ADEC_ATRACX_WORD_SZ_32BIT && bw_pcm != CELL_ADEC_ATRACX_WORD_SZ_FLOAT))
|
||||
{
|
||||
return { 0x80004005, "AtracXdecDecoder::init_decode() failed: Invalid PCM output format" };
|
||||
}
|
||||
|
||||
this->bw_pcm = bw_pcm;
|
||||
this->nch_out = nch_out; // Not checked for invalid values on LLE
|
||||
this->pcm_output_size = (bw_pcm == CELL_ADEC_ATRACX_WORD_SZ_16BIT ? sizeof(s16) : sizeof(f32)) * nch_in * ATXDEC_SAMPLES_PER_FRAME;
|
||||
|
||||
init_avcodec();
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code AtracXdecDecoder::parse_ats_header(vm::cptr<u8> au_start_addr)
|
||||
{
|
||||
const auto ats = std::bit_cast<AtracXdecAtsHeader>(vm::read64(au_start_addr.addr()));
|
||||
|
||||
if (ats.sync_word != 0x0fd0)
|
||||
{
|
||||
return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid sync word: 0x%x", ats.sync_word };
|
||||
}
|
||||
|
||||
const u8 sample_rate_idx = ats.params >> 13;
|
||||
const u8 ch_config_idx = ats.params >> 10 & 7;
|
||||
const u16 nbytes = ((ats.params & 0x3ff) + 1) * 8;
|
||||
|
||||
if (ch_config_idx == 0u)
|
||||
{
|
||||
return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid channel configuration: %d", ch_config_idx };
|
||||
}
|
||||
|
||||
u32 sampling_freq;
|
||||
switch (sample_rate_idx)
|
||||
{
|
||||
case 1: sampling_freq = 44100; break;
|
||||
case 2: sampling_freq = 48000; break;
|
||||
default: return { CELL_ADEC_ERROR_ATX_ATSHDR, "AtracXdecDecoder::parse_ats_header() failed: Invalid sample rate index: %d", sample_rate_idx };
|
||||
}
|
||||
|
||||
return set_config_info(sampling_freq, ch_config_idx, nbytes); // Cannot return error here, values were already checked
|
||||
}
|
||||
|
||||
void AtracXdecContext::exec(ppu_thread& ppu)
|
||||
{
|
||||
perf_meter<"ATXDEC"_u64> perf0;
|
||||
|
||||
// Savestates
|
||||
if (decoder.config_is_set)
|
||||
{
|
||||
decoder.init_avcodec();
|
||||
}
|
||||
|
||||
for (;;cmd_counter++)
|
||||
{
|
||||
cellAtracXdec.trace("Command counter: %llu, waiting for next command...", cmd_counter);
|
||||
|
||||
if (!skip_getting_command)
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
std::lock_guard lock{queue_mutex};
|
||||
|
||||
while (cmd_queue.empty() && !ppu.is_stopped())
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
queue_not_empty.wait(queue_mutex, 20000);
|
||||
}
|
||||
|
||||
if (ppu.is_stopped())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
cmd_queue.pop(cmd);
|
||||
|
||||
if (!run_thread)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cellAtracXdec.trace("Command type: %d", static_cast<u32>(cmd.type.get()));
|
||||
|
||||
switch (cmd.type)
|
||||
{
|
||||
case AtracXdecCmdType::start_seq:
|
||||
{
|
||||
first_decode = true;
|
||||
skip_next_frame = true;
|
||||
|
||||
// Skip if access units contain an ATS header, the parameters are included in the header and we need to wait for the first decode command to parse them
|
||||
if (cmd.atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_NOTINC)
|
||||
{
|
||||
if (decoder.set_config_info(cmd.atracx_param.sampling_freq, cmd.atracx_param.ch_config_idx, cmd.atracx_param.nbytes) == static_cast<s32>(0x80004005))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (decoder.init_decode(cmd.atracx_param.bw_pcm, cmd.atracx_param.nch_out) == static_cast<s32>(0x80004005))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
atracx_param = cmd.atracx_param;
|
||||
break;
|
||||
}
|
||||
case AtracXdecCmdType::end_seq:
|
||||
{
|
||||
skip_getting_command = true;
|
||||
|
||||
// Block savestate creation during callbacks
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
skip_getting_command = false;
|
||||
|
||||
// Doesn't do anything else
|
||||
notify_seq_done.cbFunc(ppu, notify_seq_done.cbArg);
|
||||
break;
|
||||
}
|
||||
case AtracXdecCmdType::decode_au:
|
||||
{
|
||||
skip_getting_command = true;
|
||||
|
||||
ensure(!!cmd.au_start_addr); // Not checked on LLE
|
||||
|
||||
cellAtracXdec.trace("Waiting for output to be consumed...");
|
||||
|
||||
lv2_obj::sleep(ppu);
|
||||
std::unique_lock output_mutex_lock{output_mutex};
|
||||
|
||||
while (output_locked && !ppu.is_stopped())
|
||||
{
|
||||
lv2_obj::sleep(ppu);
|
||||
output_consumed.wait(output_mutex, 20000);
|
||||
}
|
||||
|
||||
if (ppu.is_stopped())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!run_thread)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cellAtracXdec.trace("Output consumed");
|
||||
|
||||
u32 error = CELL_OK;
|
||||
|
||||
// Only the first valid ATS header after starting a sequence is parsed. It is ignored on all subsequent access units
|
||||
if (first_decode && atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_INC)
|
||||
{
|
||||
// Block savestate creation during callbacks
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
if (error = decoder.parse_ats_header(cmd.au_start_addr); error != CELL_OK)
|
||||
{
|
||||
notify_error.cbFunc(ppu, error, notify_error.cbArg);
|
||||
}
|
||||
else if (decoder.init_decode(atracx_param.bw_pcm, atracx_param.nch_out) != CELL_OK)
|
||||
{
|
||||
notify_error.cbFunc(ppu, CELL_ADEC_ERROR_ATX_FATAL, notify_error.cbArg);
|
||||
}
|
||||
}
|
||||
|
||||
// LLE does not initialize the output address if parsing the ATS header fails
|
||||
vm::ptr<void> output = vm::null;
|
||||
u32 decoded_samples_num = 0;
|
||||
|
||||
if (error != CELL_ADEC_ERROR_ATX_ATSHDR)
|
||||
{
|
||||
// The LLE SPU thread would crash if you attempt to decode without a valid configuration
|
||||
ensure(decoder.config_is_set, "Attempted to decode with invalid configuration");
|
||||
|
||||
output.set(work_mem.addr() + atracXdecGetSpursMemSize(decoder.nch_in));
|
||||
|
||||
const auto au_start_addr = atracx_param.au_includes_ats_hdr_flg == CELL_ADEC_ATRACX_ATS_HDR_INC ? cmd.au_start_addr.get_ptr() + sizeof(AtracXdecAtsHeader) : cmd.au_start_addr.get_ptr();
|
||||
std::memcpy(work_mem.get_ptr(), au_start_addr, decoder.nbytes);
|
||||
|
||||
if (int err = avcodec_send_packet(decoder.ctx, decoder.packet); err)
|
||||
{
|
||||
// These errors should never occur
|
||||
if (err == AVERROR(EAGAIN) || err == averror_eof || err == AVERROR(EINVAL) || err == AVERROR(ENOMEM))
|
||||
{
|
||||
fmt::throw_exception("avcodec_send_packet() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
|
||||
}
|
||||
|
||||
// Game sent invalid data
|
||||
cellAtracXdec.error("avcodec_send_packet() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
|
||||
error = CELL_ADEC_ERROR_ATX_NON_FATAL; // Not accurate, FFmpeg doesn't provide detailed errors like LLE
|
||||
|
||||
av_frame_unref(decoder.frame);
|
||||
}
|
||||
else if ((err = avcodec_receive_frame(decoder.ctx, decoder.frame)))
|
||||
{
|
||||
fmt::throw_exception("avcodec_receive_frame() failed (err=0x%x='%s')", err, utils::av_error_to_string(err));
|
||||
}
|
||||
|
||||
decoded_samples_num = decoder.frame->nb_samples;
|
||||
ensure(decoded_samples_num == 0u || decoded_samples_num == ATXDEC_SAMPLES_PER_FRAME);
|
||||
|
||||
// The first frame after starting a new sequence or after an error is replaced with silence
|
||||
if (skip_next_frame && error == CELL_OK)
|
||||
{
|
||||
skip_next_frame = false;
|
||||
decoded_samples_num = 0;
|
||||
std::memset(output.get_ptr(), 0, ATXDEC_SAMPLES_PER_FRAME * (decoder.bw_pcm & 0x7full) * decoder.nch_out);
|
||||
}
|
||||
|
||||
// Convert FFmpeg output to LLE output
|
||||
const auto output_f32 = vm::static_ptr_cast<f32>(output).get_ptr();
|
||||
const auto output_s16 = vm::static_ptr_cast<s16>(output).get_ptr();
|
||||
const auto output_s32 = vm::static_ptr_cast<s32>(output).get_ptr();
|
||||
const u8* const ch_map = ATXDEC_AVCODEC_CH_MAP[decoder.ch_config_idx - 1];
|
||||
const u32 nch_in = decoder.nch_in;
|
||||
|
||||
switch (decoder.bw_pcm)
|
||||
{
|
||||
case CELL_ADEC_ATRACX_WORD_SZ_FLOAT:
|
||||
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
|
||||
{
|
||||
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
|
||||
|
||||
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
|
||||
{
|
||||
const f32 sample = samples[in_sample_idx];
|
||||
|
||||
if (sample >= std::bit_cast<f32>(std::bit_cast<u32>(1.f) - 1))
|
||||
{
|
||||
output_f32[out_sample_idx] = std::bit_cast<be_t<f32>>("\x3f\x7f\xff\xff"_u32); // Prevents an unnecessary endian swap
|
||||
}
|
||||
else if (sample <= -1.f)
|
||||
{
|
||||
output_f32[out_sample_idx] = -1.f;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_f32[out_sample_idx] = sample;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CELL_ADEC_ATRACX_WORD_SZ_16BIT:
|
||||
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
|
||||
{
|
||||
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
|
||||
|
||||
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
|
||||
{
|
||||
const f32 sample = samples[in_sample_idx];
|
||||
|
||||
if (sample >= 1.f)
|
||||
{
|
||||
output_s16[out_sample_idx] = INT16_MAX;
|
||||
}
|
||||
else if (sample <= -1.f)
|
||||
{
|
||||
output_s16[out_sample_idx] = INT16_MIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_s16[out_sample_idx] = static_cast<s16>(std::floor(sample * 0x8000u));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CELL_ADEC_ATRACX_WORD_SZ_24BIT:
|
||||
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
|
||||
{
|
||||
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
|
||||
|
||||
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
|
||||
{
|
||||
const f32 sample = samples[in_sample_idx];
|
||||
|
||||
if (sample >= 1.f)
|
||||
{
|
||||
output_s32[out_sample_idx] = 0x007fffff;
|
||||
}
|
||||
else if (sample <= -1.f)
|
||||
{
|
||||
output_s32[out_sample_idx] = 0x00800000;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_s32[out_sample_idx] = static_cast<s32>(std::floor(sample * 0x00800000u)) & 0x00ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CELL_ADEC_ATRACX_WORD_SZ_32BIT:
|
||||
for (u32 channel_idx = 0; channel_idx < nch_in; channel_idx++)
|
||||
{
|
||||
const f32* samples = reinterpret_cast<f32*>(decoder.frame->data[channel_idx]);
|
||||
|
||||
for (u32 in_sample_idx = 0, out_sample_idx = ch_map[channel_idx]; in_sample_idx < decoded_samples_num; in_sample_idx++, out_sample_idx += nch_in)
|
||||
{
|
||||
const f32 sample = samples[in_sample_idx];
|
||||
|
||||
if (sample >= 1.f)
|
||||
{
|
||||
output_s32[out_sample_idx] = INT32_MAX;
|
||||
}
|
||||
else if (sample <= -1.f)
|
||||
{
|
||||
output_s32[out_sample_idx] = INT32_MIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
output_s32[out_sample_idx] = static_cast<s32>(std::floor(sample * 0x80000000u));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
first_decode = false;
|
||||
|
||||
if (error != CELL_OK)
|
||||
{
|
||||
// Block savestate creation during callbacks
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
skip_next_frame = true;
|
||||
notify_error.cbFunc(ppu, error, notify_error.cbArg);
|
||||
}
|
||||
}
|
||||
|
||||
// Block savestate creation during callbacks
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return;
|
||||
}
|
||||
|
||||
skip_getting_command = false;
|
||||
|
||||
// au_done and pcm_out callbacks are always called after a decode command, even if an error occurred
|
||||
// The output always has to be consumed as well
|
||||
notify_au_done.cbFunc(ppu, cmd.pcm_handle, notify_au_done.cbArg);
|
||||
|
||||
output_locked = true;
|
||||
output_mutex_lock.unlock();
|
||||
|
||||
const u32 output_size = decoded_samples_num * (decoder.bw_pcm & 0x7fu) * decoder.nch_out;
|
||||
|
||||
const vm::var<CellAdecAtracXInfo> bsi_info{{ decoder.sampling_freq, decoder.ch_config_idx, decoder.nbytes }};
|
||||
|
||||
const AdecCorrectPtsValueType correct_pts_type = [&]
|
||||
{
|
||||
switch (decoder.sampling_freq)
|
||||
{
|
||||
case 32000u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_32000Hz;
|
||||
case 44100u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_44100Hz;
|
||||
case 48000u: return ADEC_CORRECT_PTS_VALUE_TYPE_ATRACX_48000Hz;
|
||||
default: return ADEC_CORRECT_PTS_VALUE_TYPE_UNSPECIFIED;
|
||||
}
|
||||
}();
|
||||
|
||||
notify_pcm_out.cbFunc(ppu, cmd.pcm_handle, output, output_size, notify_pcm_out.cbArg, vm::make_var<vm::bcptr<void>>(bsi_info), correct_pts_type, error);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fmt::throw_exception("Invalid command");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <AtracXdecCmdType type>
|
||||
error_code AtracXdecContext::send_command(ppu_thread& ppu, auto&&... args)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
{
|
||||
std::lock_guard lock{queue_mutex};
|
||||
|
||||
if constexpr (type == AtracXdecCmdType::close)
|
||||
{
|
||||
// Close command is only sent if the queue is empty on LLE
|
||||
if (!cmd_queue.empty())
|
||||
{
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
if (cmd_queue.full())
|
||||
{
|
||||
return CELL_ADEC_ERROR_ATX_BUSY;
|
||||
}
|
||||
|
||||
cmd_queue.emplace(std::forward<AtracXdecCmdType>(type), std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
|
||||
queue_not_empty.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
void atracXdecEntry(ppu_thread& ppu, vm::ptr<AtracXdecContext> atxdec)
|
||||
{
|
||||
atxdec->decoder.alloc_avcodec();
|
||||
|
||||
atxdec->exec(ppu);
|
||||
|
||||
atxdec->decoder.free_avcodec();
|
||||
|
||||
if (ppu.state & cpu_flag::again)
|
||||
{
|
||||
// For savestates, save argument
|
||||
ppu.syscall_args[0] = atxdec.addr();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ppu_execute<&sys_ppu_thread_exit>(ppu, CELL_OK);
|
||||
}
|
||||
|
||||
template <u32 nch_in>
|
||||
error_code _CellAdecCoreOpGetMemSize_atracx(vm::ptr<CellAdecAttr> attr)
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpGetMemSize_atracx<nch_in=%d>(attr=*0x%x)", nch_in, attr);
|
||||
|
||||
ensure(!!attr); // Not checked on LLE
|
||||
|
||||
constexpr u32 mem_size =
|
||||
sizeof(AtracXdecContext) + 0x7f
|
||||
+ ATXDEC_SPURS_STRUCTS_SIZE + 0x1d8
|
||||
+ atracXdecGetSpursMemSize(nch_in)
|
||||
+ ATXDEC_SAMPLES_PER_FRAME * sizeof(f32) * nch_in;
|
||||
|
||||
attr->workMemSize = utils::align(mem_size, 0x80);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpOpenExt_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
|
||||
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::cptr<CellAdecResource> res, vm::cptr<CellAdecResourceSpurs> spursRes)
|
||||
{
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return {};
|
||||
}
|
||||
|
||||
cellAtracXdec.notice("_CellAdecCoreOpOpenExt_atracx(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x, spursRes=*0x%x)",
|
||||
handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, spursRes);
|
||||
|
||||
ensure(!!handle && !!res); // Not checked on LLE
|
||||
ensure(handle.aligned(0x80)); // On LLE, this functions doesn't check the alignment or aligns the address itself. The address should already be aligned to 128 bytes by cellAdec
|
||||
ensure(!!notifyAuDone && !!notifyAuDoneArg && !!notifyPcmOut && !!notifyPcmOutArg && !!notifyError && !!notifyErrorArg && !!notifySeqDone && !!notifySeqDoneArg); // These should always be set by cellAdec
|
||||
|
||||
write_to_ptr(handle.get_ptr(), AtracXdecContext(notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg,
|
||||
vm::bptr<u8>::make(handle.addr() + utils::align(static_cast<u32>(sizeof(AtracXdecContext)), 0x80) + ATXDEC_SPURS_STRUCTS_SIZE)));
|
||||
|
||||
const vm::var<char[]> _name = vm::make_str("HLE ATRAC3plus decoder");
|
||||
const auto entry = g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(atracXdecEntry));
|
||||
ppu_execute<&sys_ppu_thread_create>(ppu, handle.ptr(&AtracXdecContext::thread_id), entry, handle.addr(), +res->ppuThreadPriority, +res->ppuThreadStackSize, SYS_PPU_THREAD_CREATE_JOINABLE, +_name);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpOpen_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
|
||||
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::cptr<CellAdecResource> res)
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpOpen_atracx(handle=*0x%x, notifyAuDone=*0x%x, notifyAuDoneArg=*0x%x, notifyPcmOut=*0x%x, notifyPcmOutArg=*0x%x, notifyError=*0x%x, notifyErrorArg=*0x%x, notifySeqDone=*0x%x, notifySeqDoneArg=*0x%x, res=*0x%x)",
|
||||
handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res);
|
||||
|
||||
return _CellAdecCoreOpOpenExt_atracx(ppu, handle, notifyAuDone, notifyAuDoneArg, notifyPcmOut, notifyPcmOutArg, notifyError, notifyErrorArg, notifySeqDone, notifySeqDoneArg, res, vm::null);
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpClose_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle)
|
||||
{
|
||||
std::unique_lock savestate_lock{g_fxo->get<hle_locks_t>(), std::try_to_lock};
|
||||
|
||||
if (!savestate_lock.owns_lock())
|
||||
{
|
||||
ppu.state += cpu_flag::again;
|
||||
return {};
|
||||
}
|
||||
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellAtracXdec.notice("_CellAdecCoreOpClose_atracx(handle=*0x%x)", handle);
|
||||
|
||||
ensure(!!handle); // Not checked on LLE
|
||||
|
||||
handle->run_thread = false;
|
||||
handle->send_command<AtracXdecCmdType::close>(ppu);
|
||||
|
||||
{
|
||||
std::lock_guard lock{handle->output_mutex};
|
||||
handle->output_locked = false;
|
||||
}
|
||||
|
||||
handle->output_consumed.notify_one();
|
||||
|
||||
if (vm::var<u64> ret; sys_ppu_thread_join(ppu, static_cast<u32>(handle->thread_id), +ret) != CELL_OK)
|
||||
{
|
||||
// Other thread already closed the decoder
|
||||
return CELL_ADEC_ERROR_FATAL;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpStartSeq_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, vm::cptr<CellAdecParamAtracX> atracxParam)
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpStartSeq_atracx(handle=*0x%x, atracxParam=*0x%x)", handle, atracxParam);
|
||||
|
||||
ensure(!!handle && !!atracxParam); // Not checked on LLE
|
||||
|
||||
cellAtracXdec.notice("_CellAdecCoreOpStartSeq_atracx(): sampling_freq=%d, ch_config_idx=%d, nch_out=%d, nbytes=0x%x, extra_config_data=0x%08x, bw_pcm=0x%x, downmix_flag=%d, au_includes_ats_hdr_flg=%d",
|
||||
atracxParam->sampling_freq, atracxParam->ch_config_idx, atracxParam->nch_out, atracxParam->nbytes, std::bit_cast<u32>(atracxParam->extra_config_data), atracxParam->bw_pcm, atracxParam->downmix_flag, atracxParam->au_includes_ats_hdr_flg);
|
||||
|
||||
return handle->send_command<AtracXdecCmdType::start_seq>(ppu, *atracxParam);
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpEndSeq_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle)
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpEndSeq_atracx(handle=*0x%x)", handle);
|
||||
|
||||
ensure(!!handle); // Not checked on LLE
|
||||
|
||||
return handle->send_command<AtracXdecCmdType::end_seq>(ppu);
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpDecodeAu_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, s32 pcmHandle, vm::cptr<CellAdecAuInfo> auInfo)
|
||||
{
|
||||
cellAtracXdec.trace("_CellAdecCoreOpDecodeAu_atracx(handle=*0x%x, pcmHandle=%d, auInfo=*0x%x)", handle, pcmHandle, auInfo);
|
||||
|
||||
ensure(!!handle && !!auInfo); // Not checked on LLE
|
||||
|
||||
cellAtracXdec.trace("_CellAdecCoreOpDecodeAu_atracx(): startAddr=*0x%x, size=0x%x, pts=%lld, userData=0x%llx", auInfo->startAddr, auInfo->size, std::bit_cast<be_t<u64>>(auInfo->pts), auInfo->userData);
|
||||
|
||||
return handle->send_command<AtracXdecCmdType::decode_au>(ppu, pcmHandle, *auInfo);
|
||||
}
|
||||
|
||||
void _CellAdecCoreOpGetVersion_atracx(vm::ptr<be_t<u32, 1>> version)
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpGetVersion_atracx(version=*0x%x)", version);
|
||||
|
||||
ensure(!!version); // Not checked on LLE
|
||||
|
||||
*version = 0x01020000;
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpRealign_atracx(vm::ptr<AtracXdecContext> handle, vm::ptr<void> outBuffer, vm::cptr<void> pcmStartAddr)
|
||||
{
|
||||
cellAtracXdec.trace("_CellAdecCoreOpRealign_atracx(handle=*0x%x, outBuffer=*0x%x, pcmStartAddr=*0x%x)", handle, outBuffer, pcmStartAddr);
|
||||
|
||||
if (outBuffer)
|
||||
{
|
||||
ensure(!!handle && !!pcmStartAddr); // Not checked on LLE
|
||||
ensure(vm::check_addr(outBuffer.addr(), vm::page_info_t::page_writable, handle->decoder.pcm_output_size));
|
||||
|
||||
std::memcpy(outBuffer.get_ptr(), pcmStartAddr.get_ptr(), handle->decoder.pcm_output_size);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code _CellAdecCoreOpReleasePcm_atracx(ppu_thread& ppu, vm::ptr<AtracXdecContext> handle, s32 pcmHandle, vm::cptr<void> outBuffer)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
cellAtracXdec.trace("_CellAdecCoreOpReleasePcm_atracx(handle=*0x%x, pcmHandle=%d, outBuffer=*0x%x)", handle, pcmHandle, outBuffer);
|
||||
|
||||
ensure(!!handle); // Not checked on LLE
|
||||
|
||||
std::lock_guard lock{handle->output_mutex};
|
||||
handle->output_locked = false;
|
||||
handle->output_consumed.notify_one();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
s32 _CellAdecCoreOpGetPcmHandleNum_atracx()
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpGetPcmHandleNum_atracx()");
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
u32 _CellAdecCoreOpGetBsiInfoSize_atracx()
|
||||
{
|
||||
cellAtracXdec.notice("_CellAdecCoreOpGetBsiInfoSize_atracx()");
|
||||
|
||||
return sizeof(CellAdecAtracXInfo);
|
||||
}
|
||||
|
||||
static void init_gvar(vm::gvar<CellAdecCoreOps>& var)
|
||||
{
|
||||
var->open.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpOpen_atracx)));
|
||||
var->close.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpClose_atracx)));
|
||||
var->startSeq.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpStartSeq_atracx)));
|
||||
var->endSeq.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpEndSeq_atracx)));
|
||||
var->decodeAu.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpDecodeAu_atracx)));
|
||||
var->getVersion.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetVersion_atracx)));
|
||||
var->realign.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpRealign_atracx)));
|
||||
var->releasePcm.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpReleasePcm_atracx)));
|
||||
var->getPcmHandleNum.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetPcmHandleNum_atracx)));
|
||||
var->getBsiInfoSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetBsiInfoSize_atracx)));
|
||||
var->openExt.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpOpenExt_atracx)));
|
||||
}
|
||||
|
||||
DECLARE(ppu_module_manager::cellAtracXdec)("cellAtracXdec", []()
|
||||
{
|
||||
REG_VNID(cellAtracXdec, 0x076b33ab, g_cell_adec_core_ops_atracx2ch).init = []()
|
||||
{
|
||||
g_cell_adec_core_ops_atracx2ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<2>)));
|
||||
init_gvar(g_cell_adec_core_ops_atracx2ch);
|
||||
};
|
||||
REG_VNID(cellAtracXdec, 0x1d210eaa, g_cell_adec_core_ops_atracx6ch).init = []()
|
||||
{
|
||||
g_cell_adec_core_ops_atracx6ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<6>)));
|
||||
init_gvar(g_cell_adec_core_ops_atracx6ch);
|
||||
};
|
||||
REG_VNID(cellAtracXdec, 0xe9a86e54, g_cell_adec_core_ops_atracx8ch).init = []()
|
||||
{
|
||||
g_cell_adec_core_ops_atracx8ch->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>)));
|
||||
init_gvar(g_cell_adec_core_ops_atracx8ch);
|
||||
};
|
||||
REG_VNID(cellAtracXdec, 0x4944af9a, g_cell_adec_core_ops_atracx).init = []()
|
||||
{
|
||||
g_cell_adec_core_ops_atracx->getMemSize.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>)));
|
||||
init_gvar(g_cell_adec_core_ops_atracx);
|
||||
};
|
||||
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<2>);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<6>);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetMemSize_atracx<8>);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpOpen_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpClose_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpStartSeq_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpEndSeq_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpDecodeAu_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetVersion_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpRealign_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpReleasePcm_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetPcmHandleNum_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpGetBsiInfoSize_atracx);
|
||||
REG_HIDDEN_FUNC(_CellAdecCoreOpOpenExt_atracx);
|
||||
|
||||
REG_HIDDEN_FUNC(atracXdecEntry);
|
||||
});
|
||||
@@ -0,0 +1,302 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wall"
|
||||
#pragma GCC diagnostic ignored "-Wextra"
|
||||
#pragma GCC diagnostic ignored "-Wold-style-cast"
|
||||
#endif
|
||||
extern "C"
|
||||
{
|
||||
#include "libavcodec/avcodec.h"
|
||||
}
|
||||
|
||||
constexpr int averror_eof = AVERROR_EOF; // Workaround for old-style-cast error
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "Utilities/cond.h"
|
||||
#include "cellPamf.h"
|
||||
#include "cellAdec.h"
|
||||
|
||||
enum CellAtracXdecError : u32
|
||||
{
|
||||
CELL_ADEC_ERROR_ATX_OFFSET = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_NONE = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_OK = 0x80612200,
|
||||
CELL_ADEC_ERROR_ATX_BUSY = 0x80612264,
|
||||
CELL_ADEC_ERROR_ATX_EMPTY = 0x80612265,
|
||||
CELL_ADEC_ERROR_ATX_ATSHDR = 0x80612266,
|
||||
CELL_ADEC_ERROR_ATX_NON_FATAL = 0x80612281,
|
||||
CELL_ADEC_ERROR_ATX_NOT_IMPLE = 0x80612282,
|
||||
CELL_ADEC_ERROR_ATX_PACK_CE_OVERFLOW = 0x80612283,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_NPROCQUS = 0x80612284,
|
||||
CELL_ADEC_ERROR_ATX_FATAL = 0x8061228c,
|
||||
CELL_ADEC_ERROR_ATX_ENC_OVERFLOW = 0x8061228d,
|
||||
CELL_ADEC_ERROR_ATX_PACK_CE_UNDERFLOW = 0x8061228e,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT = 0x8061228f,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GAINADJ = 0x80612290,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF = 0x80612291,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SPECTRA = 0x80612292,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL = 0x80612293,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GHWAVE = 0x80612294,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SHEADER = 0x80612295,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_A = 0x80612296,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_B = 0x80612297,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_C = 0x80612298,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_D = 0x80612299,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDWL_E = 0x8061229a,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_A = 0x8061229b,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_B = 0x8061229c,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_C = 0x8061229d,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDSF_D = 0x8061229e,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_IDCT_A = 0x8061229f,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_NGC = 0x806122a0,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_A = 0x806122a1,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_A = 0x806122a2,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLEV_B = 0x806122a3,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_GC_IDLOC_B = 0x806122a4,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_SN_NWVS = 0x806122a5,
|
||||
CELL_ADEC_ERROR_ATX_FATAL_HANDLE = 0x806122aa,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_SAMPLING_FREQ = 0x806122ab,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_CH_CONFIG_INDEX = 0x806122ac,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_NBYTES = 0x806122ad,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_NUM = 0x806122ae,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_BLOCK_ID = 0x806122af,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_CHANNELS = 0x806122b0,
|
||||
CELL_ADEC_ERROR_ATX_UNINIT_BLOCK_SPECIFIED = 0x806122b1,
|
||||
CELL_ADEC_ERROR_ATX_POSCFG_PRESENT = 0x806122b2,
|
||||
CELL_ADEC_ERROR_ATX_BUFFER_OVERFLOW = 0x806122b3,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_TYPE_ID = 0x806122b4,
|
||||
CELL_ADEC_ERROR_ATX_UNPACK_CHANNEL_BLK_FAILED = 0x806122b5,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_1 = 0x806122b6,
|
||||
CELL_ADEC_ERROR_ATX_ILL_BLK_ID_USED_2 = 0x806122b7,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_ENC_SETTING = 0x806122b8,
|
||||
CELL_ADEC_ERROR_ATX_ILLEGAL_DEC_SETTING = 0x806122b9,
|
||||
CELL_ADEC_ERROR_ATX_ASSERT_NSAMPLES = 0x806122ba,
|
||||
CELL_ADEC_ERROR_ATX_ILL_SYNCWORD = 0x806122bb,
|
||||
CELL_ADEC_ERROR_ATX_ILL_SAMPLING_FREQ = 0x806122bc,
|
||||
CELL_ADEC_ERROR_ATX_ILL_CH_CONFIG_INDEX = 0x806122bd,
|
||||
CELL_ADEC_ERROR_ATX_RAW_DATA_FRAME_SIZE_OVER = 0x806122be,
|
||||
CELL_ADEC_ERROR_ATX_SYNTAX_ENHANCE_LENGTH_OVER = 0x806122bf,
|
||||
CELL_ADEC_ERROR_ATX_SPU_INTERNAL_FAIL = 0x806122c8,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_ADEC_ATRACX_WORD_SZ_16BIT = 0x02,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_24BIT = 0x03,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_32BIT = 0x04,
|
||||
CELL_ADEC_ATRACX_WORD_SZ_FLOAT = 0x84,
|
||||
};
|
||||
|
||||
enum : u8
|
||||
{
|
||||
CELL_ADEC_ATRACX_ATS_HDR_NOTINC = 0,
|
||||
CELL_ADEC_ATRACX_ATS_HDR_INC = 1,
|
||||
};
|
||||
|
||||
enum : u8
|
||||
{
|
||||
ATRACX_DOWNMIX_OFF = 0,
|
||||
ATRACX_DOWNMIX_ON = 1,
|
||||
};
|
||||
|
||||
struct CellAdecParamAtracX
|
||||
{
|
||||
be_t<u32> sampling_freq;
|
||||
be_t<u32> ch_config_idx;
|
||||
be_t<u32> nch_out;
|
||||
be_t<u32> nbytes;
|
||||
std::array<u8, 4> extra_config_data;
|
||||
be_t<u32> bw_pcm;
|
||||
u8 downmix_flag;
|
||||
u8 au_includes_ats_hdr_flg;
|
||||
};
|
||||
|
||||
struct CellAdecAtracXInfo
|
||||
{
|
||||
be_t<u32> samplingFreq;
|
||||
be_t<u32> channelConfigIndex;
|
||||
be_t<u32> nbytes;
|
||||
};
|
||||
|
||||
CHECK_SIZE(CellAdecAtracXInfo, 12);
|
||||
|
||||
struct AtracXdecAtsHeader
|
||||
{
|
||||
be_t<u16> sync_word; // 0x0fd0
|
||||
be_t<u16> params; // 3 bits: sample rate, 3 bits: channel config, 10 bits: (nbytes / 8) - 1
|
||||
u8 extra_config_data[4];
|
||||
};
|
||||
|
||||
CHECK_SIZE(AtracXdecAtsHeader, 8);
|
||||
|
||||
enum class AtracXdecCmdType : u32
|
||||
{
|
||||
invalid,
|
||||
start_seq,
|
||||
decode_au,
|
||||
end_seq,
|
||||
close,
|
||||
};
|
||||
|
||||
struct AtracXdecCmd
|
||||
{
|
||||
be_t<AtracXdecCmdType> type;
|
||||
be_t<s32> pcm_handle;
|
||||
vm::bcptr<u8> au_start_addr;
|
||||
be_t<u32> au_size;
|
||||
vm::bptr<void> pcm_start_addr; // Unused
|
||||
be_t<u32> pcm_size; // Unused
|
||||
CellAdecParamAtracX atracx_param;
|
||||
|
||||
AtracXdecCmd() = default; // cellAdecOpen()
|
||||
|
||||
AtracXdecCmd(AtracXdecCmdType&& type) // cellAdecEndSeq(), cellAdecClose()
|
||||
: type(type)
|
||||
{
|
||||
}
|
||||
|
||||
AtracXdecCmd(AtracXdecCmdType&& type, const CellAdecParamAtracX& atracx_param) // cellAdecStartSeq()
|
||||
: type(type), atracx_param(atracx_param)
|
||||
{
|
||||
}
|
||||
|
||||
AtracXdecCmd(AtracXdecCmdType&& type, const s32& pcm_handle, const CellAdecAuInfo& au_info) // cellAdecDecodeAu()
|
||||
: type(type), pcm_handle(pcm_handle), au_start_addr(au_info.startAddr), au_size(au_info.size)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
CHECK_SIZE(AtracXdecCmd, 0x34);
|
||||
|
||||
struct AtracXdecDecoder
|
||||
{
|
||||
be_t<u32> sampling_freq;
|
||||
be_t<u32> ch_config_idx;
|
||||
be_t<u32> nch_in;
|
||||
be_t<u32> nch_blocks;
|
||||
be_t<u32> nbytes;
|
||||
be_t<u32> nch_out;
|
||||
be_t<u32> bw_pcm;
|
||||
be_t<u32> nbytes_128_aligned;
|
||||
be_t<u32> status;
|
||||
be_t<u32> pcm_output_size;
|
||||
|
||||
const vm::bptr<u8> work_mem;
|
||||
|
||||
// HLE exclusive
|
||||
b8 config_is_set = false; // For savestates
|
||||
const AVCodec* codec;
|
||||
AVCodecContext* ctx;
|
||||
AVPacket* packet;
|
||||
AVFrame* frame;
|
||||
|
||||
u8 spurs_stuff[84]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.
|
||||
|
||||
be_t<u32> spurs_task_id; // CellSpursTaskId
|
||||
|
||||
AtracXdecDecoder(vm::ptr<u8> work_mem) : work_mem(work_mem) {}
|
||||
|
||||
void alloc_avcodec();
|
||||
void free_avcodec();
|
||||
void init_avcodec();
|
||||
|
||||
error_code set_config_info(u32 sampling_freq, u32 ch_config_idx, u32 nbytes);
|
||||
error_code init_decode(u32 bw_pcm, u32 nch_out);
|
||||
error_code parse_ats_header(vm::cptr<u8> au_start_addr);
|
||||
};
|
||||
|
||||
CHECK_SIZE(AtracXdecDecoder, 0xa8);
|
||||
|
||||
struct AtracXdecContext
|
||||
{
|
||||
be_t<u64> thread_id; // sys_ppu_thread_t
|
||||
|
||||
shared_mutex queue_mutex; // sys_mutex_t
|
||||
cond_variable queue_not_empty; // sys_cond_t
|
||||
AdecCmdQueue<AtracXdecCmd> cmd_queue;
|
||||
|
||||
shared_mutex output_mutex; // sys_mutex_t
|
||||
cond_variable output_consumed; // sys_cond_t
|
||||
be_t<u32> output_locked = false;
|
||||
|
||||
be_t<u32> run_thread_mutex; // sys_mutex_t
|
||||
be_t<u32> run_thread_cond; // sys_cond_t
|
||||
be_t<u32> run_thread = true;
|
||||
|
||||
const AdecCb<AdecNotifyAuDone> notify_au_done;
|
||||
const AdecCb<AdecNotifyPcmOut> notify_pcm_out;
|
||||
const AdecCb<AdecNotifyError> notify_error;
|
||||
const AdecCb<AdecNotifySeqDone> notify_seq_done;
|
||||
|
||||
const vm::bptr<u8> work_mem;
|
||||
|
||||
// HLE exclusive
|
||||
u64 cmd_counter = 0; // For debugging
|
||||
AtracXdecCmd cmd; // For savestates; if savestate was created while processing a decode command, we need to save the current command
|
||||
b8 skip_getting_command = false; // For savestates; skips getting a new command from the queue
|
||||
b8 skip_next_frame; // Needed to emulate behavior of LLE SPU program, it doesn't output the first frame after a sequence reset or error
|
||||
|
||||
u8 spurs_stuff[58]; // 120 bytes on LLE, pointers to CellSpurs, CellSpursTaskset, etc.
|
||||
|
||||
CellAdecParamAtracX atracx_param;
|
||||
|
||||
u8 reserved;
|
||||
b8 first_decode;
|
||||
|
||||
AtracXdecDecoder decoder;
|
||||
|
||||
AtracXdecContext(vm::ptr<AdecNotifyAuDone> notifyAuDone, vm::ptr<void> notifyAuDoneArg, vm::ptr<AdecNotifyPcmOut> notifyPcmOut, vm::ptr<void> notifyPcmOutArg,
|
||||
vm::ptr<AdecNotifyError> notifyError, vm::ptr<void> notifyErrorArg, vm::ptr<AdecNotifySeqDone> notifySeqDone, vm::ptr<void> notifySeqDoneArg, vm::bptr<u8> work_mem)
|
||||
: notify_au_done{ notifyAuDone, notifyAuDoneArg }
|
||||
, notify_pcm_out{ notifyPcmOut, notifyPcmOutArg }
|
||||
, notify_error{ notifyError, notifyErrorArg }
|
||||
, notify_seq_done{ notifySeqDone, notifySeqDoneArg }
|
||||
, work_mem(work_mem)
|
||||
, decoder(work_mem)
|
||||
{
|
||||
}
|
||||
|
||||
void exec(ppu_thread& ppu);
|
||||
|
||||
template <AtracXdecCmdType type>
|
||||
error_code send_command(ppu_thread& ppu, auto&&... args);
|
||||
};
|
||||
|
||||
static_assert(std::is_standard_layout_v<AtracXdecContext>);
|
||||
CHECK_SIZE_ALIGN(AtracXdecContext, 0x268, 8);
|
||||
|
||||
constexpr u32 ATXDEC_SPURS_STRUCTS_SIZE = 0x1cf00; // CellSpurs, CellSpursTaskset, context, etc.
|
||||
constexpr u16 ATXDEC_SAMPLES_PER_FRAME = 0x800;
|
||||
constexpr u16 ATXDEC_MAX_FRAME_LENGTH = 0x2000;
|
||||
constexpr std::array<u8, 8> ATXDEC_NCH_BLOCKS_MAP = { 0, 1, 1, 2, 3, 4, 5, 5 };
|
||||
|
||||
// Expected output channel order
|
||||
// - for 1 to 7 channels: Front Left, Center, Front Right, Rear Left, Rear Right, Rear Center, LFE
|
||||
// - for 8 channels: Front Left, Front Right, Center, LFE, Rear Left, Rear Right, Side Left, Side Right
|
||||
// FFmpeg output
|
||||
// - ver <= 5.1.2: Front Left, Front Right, Center, Rear Left, Rear Right, Rear Center, Side Left, Side Right, LFE
|
||||
// - ver >= 5.1.3: Front Left, Front Right, Center, LFE, Rear Left, Rear Right, Rear Center, Side Left, Side Right
|
||||
constexpr u8 ATXDEC_AVCODEC_CH_MAP[7][8] =
|
||||
{
|
||||
{ 0 },
|
||||
{ 0, 1 },
|
||||
{ 0, 2, 1 },
|
||||
{ 0, 2, 1, 3 },
|
||||
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 51, 101)
|
||||
{ 0, 2, 1, 3, 4, 5 },
|
||||
{ 0, 2, 1, 3, 4, 5, 6 },
|
||||
{ 0, 1, 2, 4, 5, 6, 7, 3 }
|
||||
#else
|
||||
{ 0, 2, 1, 4, 5, 3 },
|
||||
{ 0, 2, 1, 4, 5, 6, 3 },
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }
|
||||
#endif
|
||||
};
|
||||
@@ -813,7 +813,7 @@ void cell_audio_thread::operator()()
|
||||
|
||||
if (time_left > cfg.period_comparison_margin)
|
||||
{
|
||||
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
||||
thread_ctrl::wait_for(time_left - cfg.period_comparison_margin);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -886,7 +886,7 @@ void cell_audio_thread::operator()()
|
||||
const s64 time_left = m_dynamic_period - time_since_last_period;
|
||||
if (time_left > cfg.period_comparison_margin)
|
||||
{
|
||||
thread_ctrl::wait_for(get_thread_wait_delay(time_left));
|
||||
thread_ctrl::wait_for(time_left - cfg.period_comparison_margin);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -251,7 +251,12 @@ struct cell_audio_config
|
||||
|
||||
static constexpr f32 period_average_alpha = 0.02f; // alpha factor for the m_average_period rolling average
|
||||
|
||||
static constexpr s64 period_comparison_margin = 250; // when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer
|
||||
// when comparing the current period time with the desired period, if it is below this number of usecs we do not wait any longer(quantum dependent)
|
||||
#ifdef _WIN32
|
||||
static constexpr s64 period_comparison_margin = 250;
|
||||
#else
|
||||
static constexpr s64 period_comparison_margin = 5;
|
||||
#endif
|
||||
|
||||
u64 fully_untouched_timeout = 0; // timeout if the game has not touched any audio buffer yet
|
||||
u64 partially_untouched_timeout = 0; // timeout if the game has not touched all audio buffers yet
|
||||
@@ -373,11 +378,6 @@ private:
|
||||
void mix(float* out_buffer, s32 offset = 0);
|
||||
void finish_port_volume_stepping();
|
||||
|
||||
constexpr static u64 get_thread_wait_delay(u64 time_left)
|
||||
{
|
||||
return (time_left > 350) ? time_left - 250 : 100;
|
||||
}
|
||||
|
||||
void update_config(bool backend_changed);
|
||||
void reset_counters();
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ struct cross_controller
|
||||
msg_dialog_callback.set(g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(finish_callback)));
|
||||
|
||||
// TODO: Show icons from comboplay_plugin.rco in dialog. Maybe use a new dialog or add an optional icon to this one.
|
||||
error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_callback, userdata);
|
||||
error_code res = open_msg_dialog(false, CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_OFF, vm::make_str(msg), msg_dialog_source::_cellCrossController, msg_dialog_callback, userdata);
|
||||
|
||||
sysutil_register_cb([this, res](ppu_thread& ppu) -> s32
|
||||
{
|
||||
|
||||
@@ -579,7 +579,7 @@ error_code cellHddGameCheck(ppu_thread& ppu, u32 version, vm::cptr<char> dirName
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg), msg_dialog_source::_cellGame);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -664,7 +664,7 @@ error_code cellHddGameSetSystemVer(vm::cptr<char> systemVersion)
|
||||
error_code cellHddGameExitBroken()
|
||||
{
|
||||
cellGame.warning("cellHddGameExitBroken()");
|
||||
return open_exit_dialog(get_localized_string(localized_string_id::CELL_HDD_GAME_EXIT_BROKEN), true);
|
||||
return open_exit_dialog(get_localized_string(localized_string_id::CELL_HDD_GAME_EXIT_BROKEN), true, msg_dialog_source::_cellGame);
|
||||
}
|
||||
|
||||
error_code cellGameDataGetSizeKB(ppu_thread& ppu, vm::ptr<u32> size)
|
||||
@@ -723,7 +723,7 @@ error_code cellGameDataSetSystemVer(vm::cptr<char> systemVersion)
|
||||
error_code cellGameDataExitBroken()
|
||||
{
|
||||
cellGame.warning("cellGameDataExitBroken()");
|
||||
return open_exit_dialog(get_localized_string(localized_string_id::CELL_GAME_DATA_EXIT_BROKEN), true);
|
||||
return open_exit_dialog(get_localized_string(localized_string_id::CELL_GAME_DATA_EXIT_BROKEN), true, msg_dialog_source::_cellGame);
|
||||
}
|
||||
|
||||
error_code cellGameBootCheck(vm::ptr<u32> type, vm::ptr<u32> attributes, vm::ptr<CellGameContentSize> size, vm::ptr<char[CELL_GAME_DIRNAME_SIZE]> dirName)
|
||||
@@ -1198,7 +1198,7 @@ error_code cellGameDataCheckCreate2(ppu_thread& ppu, u32 version, vm::cptr<char>
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg));
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON, vm::make_str(error_msg), msg_dialog_source::_cellGame);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -1714,7 +1714,7 @@ error_code cellGameContentErrorDialog(s32 type, s32 errNeedSizeKB, vm::cptr<char
|
||||
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);
|
||||
return open_exit_dialog(error_msg, type > CELL_GAME_ERRDIALOG_NOSPACE, msg_dialog_source::_cellGame);
|
||||
}
|
||||
|
||||
error_code cellGameThemeInstall(vm::cptr<char> usrdirPath, vm::cptr<char> fileName, u32 option)
|
||||
|
||||
@@ -258,6 +258,29 @@ inline void microphone_device::variable_byteswap(const void* src, void* dst)
|
||||
}
|
||||
}
|
||||
|
||||
inline u32 microphone_device::convert_16_bit_pcm_to_float(const std::vector<u8>& buffer, u32 num_bytes)
|
||||
{
|
||||
static_assert((float_buf_size % sizeof(f32)) == 0);
|
||||
|
||||
float_buf.resize(float_buf_size, 0);
|
||||
const u32 bytes_to_write = static_cast<u32>(num_bytes * (sizeof(f32) / sizeof(s16)));
|
||||
ensure(bytes_to_write <= float_buf.size());
|
||||
|
||||
const be_t<s16>* src = utils::bless<const be_t<s16>>(buffer.data());
|
||||
be_t<f32>* dst = reinterpret_cast<be_t<f32>*>(float_buf.data());
|
||||
|
||||
for (usz i = 0; i < num_bytes / sizeof(s16); i++)
|
||||
{
|
||||
const be_t<s16> sample = *src++;
|
||||
|
||||
const be_t<f32> normalized_sample_be = std::clamp(static_cast<f32>(sample) / std::numeric_limits<s16>::max(), -1.0f, 1.0f);
|
||||
|
||||
*dst++ = normalized_sample_be;
|
||||
}
|
||||
|
||||
return bytes_to_write;
|
||||
}
|
||||
|
||||
// Public functions
|
||||
|
||||
microphone_device::microphone_device(microphone_handler type)
|
||||
@@ -696,7 +719,17 @@ void microphone_device::get_dsp(const u32 num_samples)
|
||||
const u32 bufsize = num_samples * sample_size;
|
||||
ensure(bufsize <= buf.size());
|
||||
|
||||
rbuf_dsp.write_bytes(buf.data(), bufsize);
|
||||
if (attr_dsptype != 0x01)
|
||||
{
|
||||
// Convert 16-bit PCM audio data to 32-bit float (DSP format)
|
||||
const u32 bufsize_float = convert_16_bit_pcm_to_float(buf, bufsize);
|
||||
rbuf_dsp.write_bytes(float_buf.data(), bufsize_float);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The same as device RAW stream format, except that the data byte is always big-endian
|
||||
rbuf_dsp.write_bytes(buf.data(), bufsize);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialization/Shutdown Functions
|
||||
|
||||
@@ -323,6 +323,7 @@ public:
|
||||
private:
|
||||
template <u32 bytesize>
|
||||
static inline void variable_byteswap(const void* src, void* dst);
|
||||
inline u32 convert_16_bit_pcm_to_float(const std::vector<u8>& buffer, u32 num_bytes);
|
||||
|
||||
u32 capture_audio();
|
||||
|
||||
@@ -345,6 +346,7 @@ private:
|
||||
|
||||
std::vector<mic_device> devices;
|
||||
std::vector<u8> temp_buf;
|
||||
std::vector<u8> float_buf;
|
||||
|
||||
// Sampling information provided at opening of mic
|
||||
u32 raw_samplingrate = 48000;
|
||||
@@ -358,9 +360,10 @@ private:
|
||||
|
||||
static constexpr u8 bit_resolution = 16;
|
||||
static constexpr usz inbuf_size = 400000; // Default value unknown
|
||||
static constexpr usz float_buf_size = inbuf_size * (sizeof(f32) / sizeof(s16));
|
||||
|
||||
simple_ringbuf<inbuf_size> rbuf_raw;
|
||||
simple_ringbuf<inbuf_size> rbuf_dsp;
|
||||
simple_ringbuf<float_buf_size> rbuf_dsp;
|
||||
simple_ringbuf<inbuf_size> rbuf_aux;
|
||||
};
|
||||
|
||||
|
||||
@@ -33,6 +33,27 @@ void fmt_class_string<CellMsgDialogError>::format(std::string& out, u64 arg)
|
||||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<msg_dialog_source>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](auto src)
|
||||
{
|
||||
switch (src)
|
||||
{
|
||||
case msg_dialog_source::_cellMsgDialog: return "cellMsgDialog";
|
||||
case msg_dialog_source::_cellSaveData: return "cellSaveData";
|
||||
case msg_dialog_source::_cellGame: return "cellGame";
|
||||
case msg_dialog_source::_cellCrossController: return "cellCrossController";
|
||||
case msg_dialog_source::_sceNp: return "sceNp";
|
||||
case msg_dialog_source::_sceNpTrophy: return "sceNpTrophy";
|
||||
case msg_dialog_source::sys_progress: return "sys_progress";
|
||||
case msg_dialog_source::shader_loading: return "shader_loading";
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
MsgDialogBase::~MsgDialogBase()
|
||||
{
|
||||
}
|
||||
@@ -141,9 +162,9 @@ using msg_dlg_thread = named_thread<msg_dlg_thread_info>;
|
||||
error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam);
|
||||
|
||||
// wrapper to call for other hle dialogs
|
||||
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
|
||||
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam, s32* return_code)
|
||||
{
|
||||
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msgString, callback, userData, extParam, return_code);
|
||||
cellSysutil.notice("open_msg_dialog(is_blocking=%d, type=0x%x, msgString=%s, source=%s, callback=*0x%x, userData=*0x%x, extParam=*0x%x, return_code=*0x%x)", is_blocking, type, msgString, source, callback, userData, extParam, return_code);
|
||||
|
||||
const MsgDialogType _type{ type };
|
||||
|
||||
@@ -166,7 +187,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
|
||||
|
||||
const auto notify = std::make_shared<atomic_t<u32>>(0);
|
||||
|
||||
const auto res = manager->create<rsx::overlays::message_dialog>()->show(is_blocking, msgString.get_ptr(), _type, [callback, userData, &return_code, is_blocking, notify](s32 status)
|
||||
const auto res = manager->create<rsx::overlays::message_dialog>()->show(is_blocking, msgString.get_ptr(), _type, source, [callback, userData, &return_code, is_blocking, notify](s32 status)
|
||||
{
|
||||
if (is_blocking && return_code)
|
||||
{
|
||||
@@ -213,6 +234,7 @@ error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString,
|
||||
}
|
||||
|
||||
dlg->type = _type;
|
||||
dlg->source = source;
|
||||
|
||||
dlg->on_close = [callback, userData, is_blocking, &return_code, wptr = std::weak_ptr<MsgDialogBase>(dlg)](s32 status)
|
||||
{
|
||||
@@ -318,9 +340,9 @@ void exit_game(s32/* buttonType*/, vm::ptr<void>/* userData*/)
|
||||
sysutil_send_system_cmd(CELL_SYSUTIL_REQUEST_EXITGAME, 0);
|
||||
}
|
||||
|
||||
error_code open_exit_dialog(const std::string& message, bool is_exit_requested)
|
||||
error_code open_exit_dialog(const std::string& message, bool is_exit_requested, msg_dialog_source source)
|
||||
{
|
||||
cellSysutil.notice("open_exit_dialog(message=%s, is_exit_requested=%d)", message, is_exit_requested);
|
||||
cellSysutil.notice("open_exit_dialog(message=%s, is_exit_requested=%d, source=%s)", message, is_exit_requested, source);
|
||||
|
||||
vm::bptr<CellMsgDialogCallback> callback = vm::null;
|
||||
|
||||
@@ -334,6 +356,7 @@ error_code open_exit_dialog(const std::string& message, bool is_exit_requested)
|
||||
true,
|
||||
CELL_MSGDIALOG_TYPE_SE_TYPE_ERROR | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK | CELL_MSGDIALOG_TYPE_DISABLE_CANCEL_ON,
|
||||
vm::make_str(message),
|
||||
source,
|
||||
callback
|
||||
);
|
||||
|
||||
@@ -401,7 +424,7 @@ error_code cellMsgDialogOpen2(u32 type, vm::cptr<char> msgString, vm::ptr<CellMs
|
||||
cellSysutil.error("Opening error message dialog with message: %s", msgString);
|
||||
}
|
||||
|
||||
return open_msg_dialog(false, type, msgString, callback, userData, extParam);
|
||||
return open_msg_dialog(false, type, msgString, msg_dialog_source::_cellMsgDialog, callback, userData, extParam);
|
||||
}
|
||||
|
||||
error_code cellMsgDialogOpen(u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback, vm::ptr<void> userData, vm::ptr<void> extParam)
|
||||
@@ -496,7 +519,8 @@ error_code cellMsgDialogClose(f32 delay)
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
|
||||
if (auto dlg = manager->get<rsx::overlays::message_dialog>();
|
||||
dlg && dlg->source() == msg_dialog_source::_cellMsgDialog)
|
||||
{
|
||||
auto& thr = g_fxo->get<msg_dlg_thread>();
|
||||
thr.wait_until = wait_until;
|
||||
@@ -509,7 +533,7 @@ error_code cellMsgDialogClose(f32 delay)
|
||||
|
||||
const auto dlg = g_fxo->get<msg_info>().get();
|
||||
|
||||
if (!dlg)
|
||||
if (!dlg || dlg->source != msg_dialog_source::_cellMsgDialog)
|
||||
{
|
||||
return CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED;
|
||||
}
|
||||
@@ -526,7 +550,8 @@ error_code cellMsgDialogAbort()
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (auto dlg = manager->get<rsx::overlays::message_dialog>())
|
||||
if (auto dlg = manager->get<rsx::overlays::message_dialog>();
|
||||
dlg && dlg->source() == msg_dialog_source::_cellMsgDialog)
|
||||
{
|
||||
g_fxo->get<msg_dlg_thread>().wait_until = 0;
|
||||
dlg->close(false, true); // this doesn't call on_close
|
||||
@@ -539,7 +564,7 @@ error_code cellMsgDialogAbort()
|
||||
|
||||
const auto dlg = g_fxo->get<msg_info>().get();
|
||||
|
||||
if (!dlg)
|
||||
if (!dlg || dlg->source != msg_dialog_source::_cellMsgDialog)
|
||||
{
|
||||
return CELL_OK; // Not CELL_MSGDIALOG_ERROR_DIALOG_NOT_OPENED, tested on HW.
|
||||
}
|
||||
|
||||
@@ -89,9 +89,21 @@ enum class MsgDialogState
|
||||
Close,
|
||||
};
|
||||
|
||||
enum class msg_dialog_source
|
||||
{
|
||||
_cellMsgDialog,
|
||||
_cellSaveData,
|
||||
_cellGame,
|
||||
_cellCrossController,
|
||||
_sceNp,
|
||||
_sceNpTrophy,
|
||||
sys_progress,
|
||||
shader_loading,
|
||||
};
|
||||
|
||||
void close_msg_dialog();
|
||||
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, vm::ptr<CellMsgDialogCallback> callback = vm::null, vm::ptr<void> userData = vm::null, vm::ptr<void> extParam = vm::null, s32* return_code = nullptr);
|
||||
error_code open_exit_dialog(const std::string& message, bool is_exit_requested);
|
||||
error_code open_msg_dialog(bool is_blocking, u32 type, vm::cptr<char> msgString, msg_dialog_source source, vm::ptr<CellMsgDialogCallback> callback = vm::null, vm::ptr<void> userData = vm::null, vm::ptr<void> extParam = vm::null, s32* return_code = nullptr);
|
||||
error_code open_exit_dialog(const std::string& message, bool is_exit_requested, msg_dialog_source source);
|
||||
|
||||
class MsgDialogBase
|
||||
{
|
||||
@@ -103,6 +115,7 @@ public:
|
||||
atomic_t<MsgDialogState> state{ MsgDialogState::Close };
|
||||
|
||||
MsgDialogType type{};
|
||||
msg_dialog_source source = msg_dialog_source::_cellMsgDialog;
|
||||
|
||||
std::function<void(s32 status)> on_close = nullptr;
|
||||
|
||||
|
||||
@@ -224,14 +224,27 @@ error_code cellNetCtlGetInfo(s32 code, vm::ptr<CellNetCtlInfo> info)
|
||||
case CELL_NET_CTL_INFO_MTU: info->mtu = 1500; break;
|
||||
case CELL_NET_CTL_INFO_LINK: info->link = CELL_NET_CTL_LINK_CONNECTED; break;
|
||||
case CELL_NET_CTL_INFO_LINK_TYPE: info->link_type = CELL_NET_CTL_LINK_TYPE_100BASE_FULL; break;
|
||||
// case CELL_NET_CTL_INFO_BSSID: break;
|
||||
// case CELL_NET_CTL_INFO_SSID: break;
|
||||
// case CELL_NET_CTL_INFO_WLAN_SECURITY: break;
|
||||
// case CELL_NET_CTL_INFO_8021X_TYPE: break;
|
||||
// case CELL_NET_CTL_INFO_8021X_AUTH_NAME: break;
|
||||
case CELL_NET_CTL_INFO_RSSI: info->rssi = 100; break; // wireless: value ranges from 0-100 indicating wireless connection strength
|
||||
case CELL_NET_CTL_INFO_CHANNEL: info->channel = 1; break; // wireless: channel used to connect to the AP?
|
||||
case CELL_NET_CTL_INFO_IP_CONFIG: info->ip_config = CELL_NET_CTL_IP_STATIC; break;
|
||||
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
|
||||
// case CELL_NET_CTL_INFO_PPPOE_AUTH_NAME: break;
|
||||
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break; // verified on HW
|
||||
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.0"); break;
|
||||
case CELL_NET_CTL_INFO_DEFAULT_ROUTE: strcpy_trunc(info->default_route, "192.168.1.1"); break;
|
||||
case CELL_NET_CTL_INFO_PRIMARY_DNS: strcpy_trunc(info->primary_dns, np::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_SECONDARY_DNS: strcpy_trunc(info->secondary_dns, np::ip_to_string(nph.get_dns_ip())); break;
|
||||
case CELL_NET_CTL_INFO_IP_ADDRESS: strcpy_trunc(info->ip_address, np::ip_to_string(nph.get_local_ip_addr())); break; // verified on HW
|
||||
case CELL_NET_CTL_INFO_NETMASK: strcpy_trunc(info->netmask, "255.255.255.0"); break;
|
||||
case CELL_NET_CTL_INFO_HTTP_PROXY_CONFIG: info->http_proxy_config = 0; break;
|
||||
case CELL_NET_CTL_INFO_DHCP_HOSTNAME: strcpy_trunc(info->dhcp_hostname, nph.get_hostname()); break;
|
||||
// case CELL_NET_CTL_INFO_HTTP_PROXY_SERVER: break;
|
||||
// case CELL_NET_CTL_INFO_HTTP_PROXY_PORT: break;
|
||||
case CELL_NET_CTL_INFO_UPNP_CONFIG: info->upnp_config = (nph.get_upnp_status() == SCE_NP_SIGNALING_NETINFO_UPNP_STATUS_VALID) ? CELL_NET_CTL_UPNP_ON : CELL_NET_CTL_UPNP_OFF; break;
|
||||
// case CELL_NET_CTL_INFO_RESERVED1: break;
|
||||
// case CELL_NET_CTL_INFO_RESERVED2: break;
|
||||
default: cellNetCtl.error("Unsupported request: %s", InfoCodeToName(code)); break;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Emu/Cell/lv2/sys_process.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
#include "Emu/Io/pad_types.h"
|
||||
#include "Emu/RSX/Overlays/overlay_debug_overlay.h"
|
||||
#include "Input/pad_thread.h"
|
||||
#include "Input/product_info.h"
|
||||
#include "cellPad.h"
|
||||
@@ -73,6 +74,95 @@ void pad_info::save(utils::serial& ar)
|
||||
sys_io_serialize(ar);
|
||||
}
|
||||
|
||||
void show_debug_overlay(const CellPadData& data, const Pad& pad, const pad_info& config)
|
||||
{
|
||||
const u32 setting = config.port_setting[pad.m_player_id];
|
||||
const u16 d1 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL1];
|
||||
const u16 d2 = data.button[CELL_PAD_BTN_OFFSET_DIGITAL2];
|
||||
|
||||
std::string text = fmt::format(
|
||||
"> Name: Raw Value Pressure\n"
|
||||
">\n"
|
||||
"> Len: %13d\n"
|
||||
"> Digital: %5s %5s\n"
|
||||
"> Press: %5s %5s\n"
|
||||
"> Sensor: %5s %5s\n"
|
||||
">\n"
|
||||
"> Digital 1: 0x%04x 0x%04x\n"
|
||||
"> Digital 2: 0x%04x 0x%04x\n"
|
||||
">\n"
|
||||
"> D-Pad Up: %5d %5d %5d\n"
|
||||
"> D-Pad Down: %5d %5d %5d\n"
|
||||
"> D-Pad Left: %5d %5d %5d\n"
|
||||
"> D-Pad Right: %5d %5d %5d\n"
|
||||
"> Cross: %5d %5d %5d\n"
|
||||
"> Square: %5d %5d %5d\n"
|
||||
"> Circle: %5d %5d %5d\n"
|
||||
"> Triangle: %5d %5d %5d\n"
|
||||
"> Start: %5d %5d\n"
|
||||
"> Select: %5d %5d\n"
|
||||
"> PS: %5d %5d\n"
|
||||
"> L1: %5d %5d %5d\n"
|
||||
"> L2: %5d %5d %5d\n"
|
||||
"> L3: %5d %5d\n"
|
||||
"> R1: %5d %5d %5d\n"
|
||||
"> R2: %5d %5d %5d\n"
|
||||
"> R3: %5d %5d\n"
|
||||
"> LS X: %5d %5d\n"
|
||||
"> LS Y: %5d %5d\n"
|
||||
"> RS X: %5d %5d\n"
|
||||
"> RS Y: %5d %5d\n"
|
||||
">\n"
|
||||
"> Sensor X: %5d %5d\n"
|
||||
"> Sensor Y: %5d %5d\n"
|
||||
"> Sensor Z: %5d %5d\n"
|
||||
"> Sensor G: %5d %5d\n"
|
||||
">\n"
|
||||
"> PID: 0x%04x\n"
|
||||
"> VID: 0x%04x\n"
|
||||
"> Device Type: 0x%08x\n"
|
||||
"> Class Type: 0x%08x\n"
|
||||
,
|
||||
data.len,
|
||||
"on", data.len >= CELL_PAD_LEN_CHANGE_DEFAULT ? "on" : "off",
|
||||
(setting & CELL_PAD_SETTING_PRESS_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_PRESS_ON ? "on" : "off",
|
||||
(setting & CELL_PAD_SETTING_SENSOR_ON) ? "on" : "off", data.len >= CELL_PAD_LEN_CHANGE_SENSOR_ON ? "on" : "off",
|
||||
pad.m_digital_1, d1,
|
||||
pad.m_digital_2, d2,
|
||||
pad.m_press_up, !!(d1 & CELL_PAD_CTRL_UP), data.button[CELL_PAD_BTN_OFFSET_PRESS_UP],
|
||||
pad.m_press_down, !!(d1 & CELL_PAD_CTRL_DOWN), data.button[CELL_PAD_BTN_OFFSET_PRESS_DOWN],
|
||||
pad.m_press_left, !!(d1 & CELL_PAD_CTRL_LEFT), data.button[CELL_PAD_BTN_OFFSET_PRESS_LEFT],
|
||||
pad.m_press_right, !!(d1 & CELL_PAD_CTRL_RIGHT), data.button[CELL_PAD_BTN_OFFSET_PRESS_RIGHT],
|
||||
pad.m_press_cross, !!(d2 & CELL_PAD_CTRL_CROSS), data.button[CELL_PAD_BTN_OFFSET_PRESS_CROSS],
|
||||
pad.m_press_square, !!(d2 & CELL_PAD_CTRL_SQUARE), data.button[CELL_PAD_BTN_OFFSET_PRESS_SQUARE],
|
||||
pad.m_press_circle, !!(d2 & CELL_PAD_CTRL_CIRCLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_CIRCLE],
|
||||
pad.m_press_triangle, !!(d2 & CELL_PAD_CTRL_TRIANGLE), data.button[CELL_PAD_BTN_OFFSET_PRESS_TRIANGLE],
|
||||
!!(pad.m_digital_1 & CELL_PAD_CTRL_START), !!(d1 & CELL_PAD_CTRL_START),
|
||||
!!(pad.m_digital_1 & CELL_PAD_CTRL_SELECT), !!(d1 & CELL_PAD_CTRL_SELECT),
|
||||
!!(pad.m_digital_1 & CELL_PAD_CTRL_PS), !!(d1 & CELL_PAD_CTRL_PS),
|
||||
pad.m_press_L1, !!(d2 & CELL_PAD_CTRL_L1), data.button[CELL_PAD_BTN_OFFSET_PRESS_L1],
|
||||
pad.m_press_L2, !!(d2 & CELL_PAD_CTRL_L2), data.button[CELL_PAD_BTN_OFFSET_PRESS_L2],
|
||||
!!(pad.m_digital_1 & CELL_PAD_CTRL_L3), !!(d1 & CELL_PAD_CTRL_L3),
|
||||
pad.m_press_R1, !!(d2 & CELL_PAD_CTRL_R1), data.button[CELL_PAD_BTN_OFFSET_PRESS_R1],
|
||||
pad.m_press_R2, !!(d2 & CELL_PAD_CTRL_R2), data.button[CELL_PAD_BTN_OFFSET_PRESS_R2],
|
||||
!!(pad.m_digital_1 & CELL_PAD_CTRL_R3), !!(d1 & CELL_PAD_CTRL_R3),
|
||||
pad.m_analog_left_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X],
|
||||
pad.m_analog_left_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y],
|
||||
pad.m_analog_right_x, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X],
|
||||
pad.m_analog_right_y, data.button[CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y],
|
||||
pad.m_sensor_x, data.button[CELL_PAD_BTN_OFFSET_SENSOR_X],
|
||||
pad.m_sensor_y, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Y],
|
||||
pad.m_sensor_z, data.button[CELL_PAD_BTN_OFFSET_SENSOR_Z],
|
||||
pad.m_sensor_g, data.button[CELL_PAD_BTN_OFFSET_SENSOR_G],
|
||||
pad.m_product_id,
|
||||
pad.m_vendor_id,
|
||||
pad.m_device_type,
|
||||
pad.m_class_type
|
||||
);
|
||||
|
||||
rsx::overlays::set_debug_overlay_text(std::move(text));
|
||||
}
|
||||
|
||||
extern void send_sys_io_connect_event(usz index, u32 state);
|
||||
|
||||
bool cellPad_NotifyStateChange(usz index, u64 /*state*/, bool locked, bool is_blocking = true)
|
||||
@@ -297,10 +387,22 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
|
||||
// Curiously it maps infrared on the press value of the face buttons for some reason.
|
||||
const bool use_piggyback = pad->m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD;
|
||||
|
||||
const auto set_value = [&btnChanged, use_piggyback](u16& value, u16 new_value, bool is_piggyback = false)
|
||||
const auto set_value = [&btnChanged, use_piggyback, &pad](u16& value, u16 new_value, bool force_processing = false, u16 old_max_value = 255, u16 new_max_value = 255)
|
||||
{
|
||||
if (use_piggyback && !is_piggyback)
|
||||
return;
|
||||
if (use_piggyback)
|
||||
{
|
||||
if (!force_processing)
|
||||
return;
|
||||
|
||||
// Some piggyback values need to be scaled down on emulated devices
|
||||
if (old_max_value != new_max_value)
|
||||
{
|
||||
if (pad->m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD && pad->m_pad_handler != pad_handler::skateboard)
|
||||
{
|
||||
new_value = static_cast<u16>(new_max_value * std::clamp(new_value / static_cast<f32>(old_max_value), 0.0f, 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (value != new_value)
|
||||
{
|
||||
@@ -367,10 +469,10 @@ void pad_get_data(u32 port_no, CellPadData* data, bool get_periph_data = false)
|
||||
case CELL_PAD_CTRL_PRESS_LEFT: set_value(pad->m_press_left, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_UP: set_value(pad->m_press_up, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_DOWN: set_value(pad->m_press_down, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_TRIANGLE: set_value(pad->m_press_triangle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
|
||||
case CELL_PAD_CTRL_PRESS_CIRCLE: set_value(pad->m_press_circle, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
|
||||
case CELL_PAD_CTRL_PRESS_CROSS: set_value(pad->m_press_cross, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
|
||||
case CELL_PAD_CTRL_PRESS_SQUARE: set_value(pad->m_press_square, button.m_value, true, 255, 63); break; // Infrared on RIDE Skateboard
|
||||
case CELL_PAD_CTRL_PRESS_L1: set_value(pad->m_press_L1, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_R1: set_value(pad->m_press_R1, button.m_value, true); break;
|
||||
case CELL_PAD_CTRL_PRESS_L2: set_value(pad->m_press_L2, button.m_value, true); break;
|
||||
@@ -614,6 +716,12 @@ error_code cellPadGetData(u32 port_no, vm::ptr<CellPadData> data)
|
||||
return not_an_error(CELL_PAD_ERROR_NO_DEVICE);
|
||||
|
||||
pad_get_data(port_no, data.get_ptr());
|
||||
|
||||
if (g_cfg.io.debug_overlay && !g_cfg.video.overlay && port_no == 0)
|
||||
{
|
||||
show_debug_overlay(*data, *pad, config);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ static error_code select_and_delete(ppu_thread& ppu)
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(msg), vm::null, vm::null, vm::null, &return_code);
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(msg), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -370,7 +370,7 @@ static error_code select_and_delete(ppu_thread& ppu)
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Display success message by opening a blocking dialog (return value should be irrelevant here)
|
||||
res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(msg));
|
||||
res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, vm::make_str(msg), msg_dialog_source::_cellSaveData);
|
||||
|
||||
// Reschedule after blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -423,7 +423,7 @@ static error_code display_callback_result_error_message(ppu_thread& ppu, const C
|
||||
lv2_obj::sleep(ppu);
|
||||
|
||||
// Get user confirmation by opening a blocking dialog (return value should be irrelevant here)
|
||||
[[maybe_unused]] error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, use_invalid_message ? result.invalidMsg : vm::make_str(msg));
|
||||
[[maybe_unused]] error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_OK, use_invalid_message ? result.invalidMsg : vm::make_str(msg), msg_dialog_source::_cellSaveData);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -1219,7 +1219,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), vm::null, vm::null, vm::null, &return_code);
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
@@ -1350,7 +1350,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
||||
|
||||
// Get user confirmation by opening a blocking dialog
|
||||
s32 return_code = CELL_MSGDIALOG_BUTTON_NONE;
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), vm::null, vm::null, vm::null, &return_code);
|
||||
error_code res = open_msg_dialog(true, CELL_MSGDIALOG_TYPE_SE_TYPE_NORMAL | CELL_MSGDIALOG_TYPE_BUTTON_TYPE_YESNO, vm::make_str(message), msg_dialog_source::_cellSaveData, vm::null, vm::null, vm::null, &return_code);
|
||||
|
||||
// Reschedule after a blocking dialog returns
|
||||
if (ppu.check_state())
|
||||
|
||||
@@ -1,65 +1,221 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/Modules/cellSysutilAvc.h"
|
||||
#include "Emu/Cell/Modules/cellSysutil.h"
|
||||
#include "Emu/IdManager.h"
|
||||
|
||||
LOG_CHANNEL(cellSysutil);
|
||||
|
||||
error_code cellSysutilAvcByeRequest()
|
||||
template<>
|
||||
void fmt_class_string<CellAvcError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcByeRequest()");
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_AVC_ERROR_UNKNOWN);
|
||||
STR_CASE(CELL_AVC_ERROR_NOT_SUPPORTED);
|
||||
STR_CASE(CELL_AVC_ERROR_NOT_INITIALIZED);
|
||||
STR_CASE(CELL_AVC_ERROR_ALREADY_INITIALIZED);
|
||||
STR_CASE(CELL_AVC_ERROR_INVALID_ARGUMENT);
|
||||
STR_CASE(CELL_AVC_ERROR_OUT_OF_MEMORY);
|
||||
STR_CASE(CELL_AVC_ERROR_BAD_ID);
|
||||
STR_CASE(CELL_AVC_ERROR_INVALID_STATUS);
|
||||
STR_CASE(CELL_AVC_ERROR_TIMEOUT);
|
||||
STR_CASE(CELL_AVC_ERROR_NO_SESSION);
|
||||
STR_CASE(CELL_AVC_ERROR_INCOMPATIBLE_PROTOCOL);
|
||||
STR_CASE(CELL_AVC_ERROR_PEER_UNREACHABLE);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
// Callback handle tag type
|
||||
struct avc_cb_handle_t{};
|
||||
|
||||
struct avc_settings
|
||||
{
|
||||
avc_settings() = default;
|
||||
|
||||
avc_settings(const avc_settings&) = delete;
|
||||
avc_settings& operator=(const avc_settings&) = delete;
|
||||
|
||||
SAVESTATE_INIT_POS(53);
|
||||
|
||||
shared_mutex mutex_cb;
|
||||
vm::ptr<CellSysutilAvcCallback> avc_cb{};
|
||||
vm::ptr<void> avc_cb_arg{};
|
||||
|
||||
atomic_t<u32> req_id_cnt = 0;
|
||||
|
||||
static bool saveable(bool /*is_writing*/) noexcept
|
||||
{
|
||||
return GET_SERIALIZATION_VERSION(cellSysutil) != 0;
|
||||
}
|
||||
|
||||
avc_settings(utils::serial& ar) noexcept
|
||||
{
|
||||
[[maybe_unused]] const s32 version = GET_SERIALIZATION_VERSION(cellSysutil);
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
save(ar);
|
||||
}
|
||||
|
||||
void save(utils::serial& ar)
|
||||
{
|
||||
[[maybe_unused]] const s32 version = GET_OR_USE_SERIALIZATION_VERSION(ar.is_writing(), cellSysutil);
|
||||
ar(avc_cb, avc_cb_arg);
|
||||
}
|
||||
|
||||
void register_cb_call(CellSysutilAvcRequestId req_id, CellSysutilAvcEvent event_id, CellSysUtilAvcEventParam param)
|
||||
{
|
||||
// This is equivalent to the dispatcher code
|
||||
sysutil_register_cb_with_id<avc_cb_handle_t>([=, this](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
vm::ptr<CellSysutilAvcCallback> avc_cb{};
|
||||
vm::ptr<void> avc_cb_arg{};
|
||||
|
||||
{
|
||||
std::lock_guard lock(this->mutex_cb);
|
||||
avc_cb = this->avc_cb;
|
||||
avc_cb_arg = this->avc_cb_arg;
|
||||
}
|
||||
|
||||
if (avc_cb)
|
||||
{
|
||||
// TODO: lots of checks before calling the cb
|
||||
if (event_id == CELL_AVC_EVENT_UNLOAD_SUCCEEDED)
|
||||
{
|
||||
std::lock_guard lock(this->mutex_cb);
|
||||
this->avc_cb = {};
|
||||
this->avc_cb_arg = {};
|
||||
}
|
||||
|
||||
avc_cb(cb_ppu, req_id, event_id, param, avc_cb_arg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
error_code cellSysutilAvcByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcByeRequest(request_id=*0x%x)", request_id);
|
||||
|
||||
if (!request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
auto& settings = g_fxo->get<avc_settings>();
|
||||
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
|
||||
*request_id = req_id;
|
||||
settings.register_cb_call(req_id, CELL_AVC_EVENT_BYE_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcCancelByeRequest()
|
||||
error_code cellSysutilAvcCancelByeRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcCancelByeRequest()");
|
||||
cellSysutil.todo("cellSysutilAvcCancelByeRequest(request_id=*0x%x)", request_id);
|
||||
|
||||
if (!request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcCancelJoinRequest()
|
||||
error_code cellSysutilAvcCancelJoinRequest(vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcCancelJoinRequest()");
|
||||
cellSysutil.todo("cellSysutilAvcCancelJoinRequest(request_id=*0x%x)", request_id);
|
||||
|
||||
if (!request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcEnumPlayers()
|
||||
error_code cellSysutilAvcEnumPlayers(vm::ptr<SceNpId> players_id, vm::ptr<s32> players_num)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcEnumPlayers()");
|
||||
cellSysutil.todo("cellSysutilAvcEnumPlayers(players_id=*0x%x, players_num=*0x%x)", players_id, players_num);
|
||||
|
||||
if (!players_num)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (players_id)
|
||||
{
|
||||
// Fill players_id with players_num participants
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return number of participants
|
||||
*players_num = 0;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetAttribute()
|
||||
error_code cellSysutilAvcGetAttribute(CellSysUtilAvcAttribute attr_id, vm::pptr<void> param)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetAttribute()");
|
||||
cellSysutil.todo("cellSysutilAvcGetAttribute(attr_id=0x%x, param=*0x%x)", +attr_id, param);
|
||||
|
||||
if (!param)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetLayoutMode()
|
||||
error_code cellSysutilAvcGetLayoutMode(vm::ptr<CellSysutilAvcLayoutMode> layout)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetLayoutMode()");
|
||||
cellSysutil.todo("cellSysutilAvcGetLayoutMode(layout=*0x%x)", layout);
|
||||
|
||||
if (!layout)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetShowStatus()
|
||||
error_code cellSysutilAvcGetShowStatus(vm::ptr<b8> is_visible)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetShowStatus()");
|
||||
cellSysutil.todo("cellSysutilAvcGetShowStatus(is_visible=*0x%x)", is_visible);
|
||||
|
||||
if (!is_visible)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetSpeakerVolumeLevel()
|
||||
error_code cellSysutilAvcGetSpeakerVolumeLevel(vm::ptr<s32> volumeLevel)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetSpeakerVolumeLevel()");
|
||||
cellSysutil.todo("cellSysutilAvcGetSpeakerVolumeLevel(volumeLevel=*0x%x)", volumeLevel);
|
||||
|
||||
if (!volumeLevel)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetVideoMuting()
|
||||
error_code cellSysutilAvcGetVideoMuting(vm::ptr<b8> is_muting)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetVideoMuting()");
|
||||
cellSysutil.todo("cellSysutilAvcGetVideoMuting(is_muting=*0x%x)", is_muting);
|
||||
|
||||
if (!is_muting)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcGetVoiceMuting()
|
||||
error_code cellSysutilAvcGetVoiceMuting(vm::ptr<b8> is_muting)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcGetVoiceMuting()");
|
||||
cellSysutil.todo("cellSysutilAvcGetVoiceMuting(is_muting=*0x%x)", is_muting);
|
||||
|
||||
if (!is_muting)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -69,45 +225,105 @@ error_code cellSysutilAvcHidePanel()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcJoinRequest()
|
||||
error_code cellSysutilAvcJoinRequest(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcJoinRequest()");
|
||||
cellSysutil.todo("cellSysutilAvcJoinRequest(ctx_id=*0x%x, room_id=*0x%x, request_id=*0x%x)", ctx_id, room_id, request_id);
|
||||
|
||||
if (!room_id || !request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
auto& settings = g_fxo->get<avc_settings>();
|
||||
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
|
||||
*request_id = req_id;
|
||||
settings.register_cb_call(req_id, CELL_AVC_EVENT_JOIN_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcLoadAsync()
|
||||
error_code cellSysutilAvcLoadAsync(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container,
|
||||
CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcLoadAsync()");
|
||||
cellSysutil.todo("cellSysutilAvcLoadAsync(func=*0x%x, userdata=*0x%x, container=0x%x, media=0x%x, videoQuality=0x%x, voiceQuality=0x%x, request_id=*0x%x)",
|
||||
func, userdata, container, +media, +videoQuality, +voiceQuality, request_id);
|
||||
|
||||
//if (sys_memory_container_get_size(.., container) != CELL_OK)
|
||||
// return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
switch (media)
|
||||
{
|
||||
case CELL_SYSUTIL_AVC_VOICE_CHAT:
|
||||
case CELL_SYSUTIL_AVC_VIDEO_CHAT:
|
||||
// TODO: return CELL_AVC_ERROR_OUT_OF_MEMORY
|
||||
// TODO: return CELL_AVC_ERROR_INVALID_ARGUMENT
|
||||
break;
|
||||
default:
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!func || !request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
if (videoQuality != CELL_SYSUTIL_AVC_VIDEO_QUALITY_DEFAULT || voiceQuality != CELL_SYSUTIL_AVC_VOICE_QUALITY_DEFAULT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
auto& settings = g_fxo->get<avc_settings>();
|
||||
|
||||
{
|
||||
std::lock_guard lock(settings.mutex_cb);
|
||||
|
||||
if (settings.avc_cb)
|
||||
return CELL_AVC_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
settings.avc_cb = func;
|
||||
settings.avc_cb_arg = userdata;
|
||||
}
|
||||
|
||||
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
|
||||
*request_id = req_id;
|
||||
settings.register_cb_call(req_id, CELL_AVC_EVENT_LOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcSetAttribute()
|
||||
error_code cellSysutilAvcSetAttribute(CellSysUtilAvcAttribute attr_id, vm::ptr<void> param)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcSetAttribute()");
|
||||
cellSysutil.todo("cellSysutilAvcSetAttribute(attr_id=0x%x, param=*0x%x)", +attr_id, param);
|
||||
|
||||
if (!param)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcSetLayoutMode()
|
||||
error_code cellSysutilAvcSetLayoutMode(CellSysutilAvcLayoutMode layout)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcSetLayoutMode()");
|
||||
cellSysutil.todo("cellSysutilAvcSetLayoutMode(layout=0x%x)", +layout);
|
||||
|
||||
if (layout > CELL_SYSUTIL_AVC_LAYOUT_BOTTOM)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcSetSpeakerVolumeLevel()
|
||||
error_code cellSysutilAvcSetSpeakerVolumeLevel(s32 volumeLevel)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcSetSpeakerVolumeLevel()");
|
||||
cellSysutil.todo("cellSysutilAvcSetSpeakerVolumeLevel(volumeLevel=%d)", volumeLevel);
|
||||
|
||||
if (volumeLevel < 0 || volumeLevel > 10)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcSetVideoMuting()
|
||||
error_code cellSysutilAvcSetVideoMuting(b8 is_muting)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcSetVideoMuting()");
|
||||
cellSysutil.todo("cellSysutilAvcSetVideoMuting(is_muting=%d)", is_muting);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcSetVoiceMuting()
|
||||
error_code cellSysutilAvcSetVoiceMuting(b8 is_muting)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcSetVoiceMuting()");
|
||||
cellSysutil.todo("cellSysutilAvcSetVoiceMuting(is_muting=%d)", is_muting);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -117,9 +333,18 @@ error_code cellSysutilAvcShowPanel()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcUnloadAsync()
|
||||
error_code cellSysutilAvcUnloadAsync(vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
cellSysutil.todo("cellSysutilAvcUnloadAsync()");
|
||||
cellSysutil.todo("cellSysutilAvcUnloadAsync(request_id=*0x%x)", request_id);
|
||||
|
||||
if (!request_id)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
auto& settings = g_fxo->get<avc_settings>();
|
||||
const CellSysutilAvcRequestId req_id = settings.req_id_cnt.fetch_add(1);
|
||||
*request_id = req_id;
|
||||
settings.register_cb_call(req_id, CELL_AVC_EVENT_UNLOAD_SUCCEEDED, static_cast<CellSysUtilAvcEventParam>(0));
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
#pragma once
|
||||
|
||||
#include "Emu/Cell/Modules/sceNp.h"
|
||||
|
||||
enum CellAvcError : u32
|
||||
{
|
||||
CELL_AVC_ERROR_UNKNOWN = 0x8002b701,
|
||||
CELL_AVC_ERROR_NOT_SUPPORTED = 0x8002b702,
|
||||
CELL_AVC_ERROR_NOT_INITIALIZED = 0x8002b703,
|
||||
CELL_AVC_ERROR_ALREADY_INITIALIZED = 0x8002b704,
|
||||
CELL_AVC_ERROR_INVALID_ARGUMENT = 0x8002b705,
|
||||
CELL_AVC_ERROR_OUT_OF_MEMORY = 0x8002b706,
|
||||
CELL_AVC_ERROR_BAD_ID = 0x8002b707,
|
||||
CELL_AVC_ERROR_INVALID_STATUS = 0x8002b70a,
|
||||
CELL_AVC_ERROR_TIMEOUT = 0x8002b70b,
|
||||
CELL_AVC_ERROR_NO_SESSION = 0x8002b70d,
|
||||
CELL_AVC_ERROR_INCOMPATIBLE_PROTOCOL = 0x8002b70e,
|
||||
CELL_AVC_ERROR_PEER_UNREACHABLE = 0x8002b710,
|
||||
};
|
||||
|
||||
enum CellSysutilAvcTransitionType : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_TRANSITION_LINEAR = 0x00000000,
|
||||
CELL_SYSUTIL_AVC_TRANSITION_SLOWDOWN = 0x00000001,
|
||||
CELL_SYSUTIL_AVC_TRANSITION_FASTUP = 0x00000002,
|
||||
CELL_SYSUTIL_AVC_TRANSITION_ANGULAR = 0x00000003,
|
||||
CELL_SYSUTIL_AVC_TRANSITION_EXPONENT = 0x00000004,
|
||||
CELL_SYSUTIL_AVC_TRANSITION_NONE = 0xffffffff
|
||||
};
|
||||
|
||||
enum CellSysutilAvcWindowZorderMode : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_ZORDER_FORWARD_MOST = 0x00000002,
|
||||
CELL_SYSUTIL_AVC_ZORDER_BEHIND_MOST = 0x00000003,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_AVC_REQUEST_ID_SYSTEM_EVENT = 0x00000000,
|
||||
|
||||
CELL_SYSUTIL_AVC_VIDEO_MEMORY_SIZE = 26 * 1024 * 1024,
|
||||
CELL_SYSUTIL_AVC_VOICE_MEMORY_SIZE = 8 * 1024 * 1024,
|
||||
CELL_SYSUTIL_AVC_EXTRA_MEMORY_SIZE_FOR_SHARING_VIDEO_BUFFER = 2 * 1024 * 1024,
|
||||
|
||||
CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION = 100,
|
||||
};
|
||||
|
||||
enum CellSysutilAvcEvent : u32
|
||||
{
|
||||
CELL_AVC_EVENT_LOAD_SUCCEEDED = 0x00000001,
|
||||
CELL_AVC_EVENT_LOAD_FAILED = 0x00000002,
|
||||
CELL_AVC_EVENT_UNLOAD_SUCCEEDED = 0x00000003,
|
||||
CELL_AVC_EVENT_UNLOAD_FAILED = 0x00000004,
|
||||
CELL_AVC_EVENT_JOIN_SUCCEEDED = 0x00000005,
|
||||
CELL_AVC_EVENT_JOIN_FAILED = 0x00000006,
|
||||
CELL_AVC_EVENT_BYE_SUCCEEDED = 0x00000007,
|
||||
CELL_AVC_EVENT_BYE_FAILED = 0x00000008,
|
||||
|
||||
CELL_AVC_EVENT_SYSTEM_NEW_MEMBER_JOINED = 0x10000001,
|
||||
CELL_AVC_EVENT_SYSTEM_MEMBER_LEFT = 0x10000002,
|
||||
CELL_AVC_EVENT_SYSTEM_SESSION_ESTABLISHED = 0x10000003,
|
||||
CELL_AVC_EVENT_SYSTEM_SESSION_CANNOT_ESTABLISHED = 0x10000004,
|
||||
CELL_AVC_EVENT_SYSTEM_SESSION_DISCONNECTED = 0x10000005,
|
||||
CELL_AVC_EVENT_SYSTEM_VOICE_DETECTED = 0x10000006,
|
||||
CELL_AVC_EVENT_SYSTEM_MIC_DETECTED = 0x10000007,
|
||||
CELL_AVC_EVENT_SYSTEM_CAMERA_DETECTED = 0x10000008,
|
||||
};
|
||||
|
||||
enum CellSysUtilAvcEventParam : u64
|
||||
{
|
||||
CELL_AVC_EVENT_PARAM_ERROR_UNKNOWN = 0x00000001,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_NOT_SUPPORTED = 0x00000002,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_INVALID_ARGUMENT = 0x00000003,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_OUT_OF_MEMORY = 0x00000004,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_INVALID_STATUS = 0x00000005,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_TIMEOUT = 0x00000006,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_CONTEXT_DOES_NOT_EXIST = 0x00000007,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_ROOM_DOES_NOT_EXIST = 0x00000008,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_MEDIA_MISMATCHED = 0x00000009,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_MEMBER_EXCEEDED = 0x0000000A,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_MASTER_LEFT = 0x0000000B,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_NETWORK_ERROR = 0x0000000C,
|
||||
CELL_AVC_EVENT_PARAM_ERROR_INCOMPATIBLE_PROTOCOL = 0x0000000D,
|
||||
};
|
||||
|
||||
enum CellSysUtilAvcAttribute : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_TRANSITION_TYPE = 0x00000001,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_TRANSITION_DURATION = 0x00000002,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_DEFAULT_INITIAL_SHOW_STATUS = 0x00000003,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_EVENT_TYPE = 0x00000004,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_INTERVAL_TIME = 0x00000005,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_VOICE_DETECT_SIGNAL_LEVEL = 0x00000006,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_ROOM_PRIVILEGE_TYPE = 0x00000007,
|
||||
CELL_SYSUTIL_AVC_ATTRIBUTE_VIDEO_MAX_BITRATE = 0x00000008,
|
||||
};
|
||||
|
||||
enum CellSysutilAvcLayoutMode : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_LAYOUT_LEFT = 0x00000000,
|
||||
CELL_SYSUTIL_AVC_LAYOUT_RIGHT = 0x00000001,
|
||||
CELL_SYSUTIL_AVC_LAYOUT_TOP = 0x00000002,
|
||||
CELL_SYSUTIL_AVC_LAYOUT_BOTTOM = 0x00000003,
|
||||
};
|
||||
|
||||
enum CellSysUtilAvcMediaType : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_VOICE_CHAT = 0x00000001,
|
||||
CELL_SYSUTIL_AVC_VIDEO_CHAT = 0x00000002,
|
||||
};
|
||||
|
||||
enum CellSysutilAvcRoomPrivilegeType : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_ROOM_PRIVILEGE_TYPE_NO_AUTO_GRANT = 0x00000000,
|
||||
CELL_SYSUTIL_AVC_ROOM_PRIVILEGE_TYPE_AUTO_GRANT = 0x00000001
|
||||
};
|
||||
|
||||
enum CellSysUtilAvcVideoQuality : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_VIDEO_QUALITY_DEFAULT = 0x00000001
|
||||
};
|
||||
|
||||
enum CellSysutilAvcVoiceDetectEventType : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_VOICE_DETECT_EVENT_TYPE_SIGNAL = 0x00000001,
|
||||
CELL_SYSUTIL_AVC_VOICE_DETECT_EVENT_TYPE_SPEAK = 0x00000002
|
||||
};
|
||||
|
||||
enum CellSysutilAvcVoiceDetectSpeakData : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_VOICE_DETECT_DATA_SPEAK_STOP = 0x00000000,
|
||||
CELL_SYSUTIL_AVC_VOICE_DETECT_DATA_SPEAK_START = 0x00000001
|
||||
};
|
||||
|
||||
enum CellSysUtilAvcVoiceQuality : u32
|
||||
{
|
||||
CELL_SYSUTIL_AVC_VOICE_QUALITY_DEFAULT = 0x00000001
|
||||
};
|
||||
|
||||
struct CellSysutilAvcOptionParam
|
||||
{
|
||||
be_t<s32> avcOptionParamVersion;
|
||||
b8 sharingVideoBuffer;
|
||||
be_t<s32> maxPlayers; // Not in FW 1.70
|
||||
};
|
||||
|
||||
struct CellSysutilAvcVoiceDetectData
|
||||
{
|
||||
SceNpId npid;
|
||||
be_t<s32> data;
|
||||
};
|
||||
|
||||
typedef u32 CellSysutilAvcRequestId;
|
||||
|
||||
using CellSysutilAvcCallback = void(CellSysutilAvcRequestId request_id, CellSysutilAvcEvent event_id, CellSysUtilAvcEventParam event_param, vm::ptr<void> userdata);
|
||||
@@ -1,185 +1,287 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/Cell/Modules/cellSysutilAvc.h"
|
||||
|
||||
LOG_CHANNEL(cellSysutilAvcExt);
|
||||
|
||||
error_code cellSysutilAvcExtIsMicAttached()
|
||||
error_code cellSysutilAvcSetAttribute(CellSysUtilAvcAttribute attr_id, vm::ptr<void> param);
|
||||
error_code cellSysutilAvcLoadAsync(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container, CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcRequestId> request_id);
|
||||
|
||||
error_code cellSysutilAvcExtIsMicAttached(vm::ptr<s32> status)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtIsMicAttached(status=*0x%x)", status);
|
||||
|
||||
ensure(!!status); // Not actually checked
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStopCameraDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStopCameraDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetWindowRotation()
|
||||
error_code cellSysutilAvcExtSetWindowRotation(vm::ptr<SceNpId> player_id, f32 rotation_x, f32 rotation_y, f32 rotation_z, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowRotation(player_id=*0x%x, rotation_x=%f, rotation_y=%f, rotation_z=%f, transition_type=0x%x)", player_id, rotation_x, rotation_y, rotation_z, +transition_type);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetWindowPosition()
|
||||
error_code cellSysutilAvcExtGetWindowPosition(vm::ptr<SceNpId> player_id, vm::ptr<f32> position_x, vm::ptr<f32> position_y, vm::ptr<f32> position_z)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowPosition(player_id=*0x%x, position_x=*0x%x, position_y=*0x%x, position_z=*0x%x)", player_id, position_x, position_y, position_z);
|
||||
|
||||
if (!player_id || !position_x || !position_y || !position_z)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetHideNamePlate()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetHideNamePlate()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetWindowPosition()
|
||||
error_code cellSysutilAvcExtSetWindowPosition(vm::ptr<SceNpId> player_id, f32 position_x, f32 position_y, f32 position_z, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowPosition(player_id=*0x%x, position_x=%f, position_y=%f, position_z=%f, transition_type=0x%x)", player_id, position_x, position_y, position_z, +transition_type);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetWindowSize()
|
||||
error_code cellSysutilAvcExtGetWindowSize(vm::ptr<SceNpId> player_id, vm::ptr<f32> size_x, vm::ptr<f32> size_y)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowSize(player_id=*0x%x, size_x=*0x%x, size_y=*0x%x)", player_id, size_x, size_y);
|
||||
|
||||
if (!player_id || !size_x || !size_y)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStartCameraDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStartCameraDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetWindowShowStatus()
|
||||
error_code cellSysutilAvcExtGetWindowShowStatus(vm::ptr<SceNpId> player_id, vm::ptr<b8> is_visible)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowShowStatus(player_id=*0x%x, is_visible=*0x%x)", player_id, is_visible);
|
||||
|
||||
if (!player_id || !is_visible)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetChatMode()
|
||||
error_code cellSysutilAvcExtSetChatMode(u32 mode)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetChatMode(mode=0x%x)", mode);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetNamePlateShowStatus()
|
||||
error_code cellSysutilAvcExtGetNamePlateShowStatus(vm::ptr<b8> is_visible)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetNamePlateShowStatus(is_visible=*0x%x)", is_visible);
|
||||
|
||||
if (!is_visible)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetWindowAlpha()
|
||||
error_code cellSysutilAvcExtSetWindowAlpha(vm::ptr<SceNpId> player_id, f32 alpha, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowAlpha(player_id=*0x%x, alpha=%f, transition_type=0x%x)", player_id, alpha, +transition_type);
|
||||
|
||||
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetWindowSize()
|
||||
error_code cellSysutilAvcExtSetWindowSize(vm::ptr<SceNpId> player_id, f32 size_x, f32 size_y, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowSize(player_id=*0x%x, size_x=%f, size_y=%f, transition_type=0x%x)", player_id, size_x, size_y, +transition_type);
|
||||
|
||||
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtShowPanelEx()
|
||||
error_code cellSysutilAvcExtShowPanelEx(CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtShowPanelEx(transition_type=0x%x)", +transition_type);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtLoadAsyncEx()
|
||||
error_code cellSysutilAvcExtLoadAsyncEx(vm::ptr<CellSysutilAvcCallback> func, vm::ptr<void> userdata, sys_memory_container_t container,
|
||||
CellSysUtilAvcMediaType media, CellSysUtilAvcVideoQuality videoQuality, CellSysUtilAvcVoiceQuality voiceQuality, vm::ptr<CellSysutilAvcOptionParam> option, vm::ptr<CellSysutilAvcRequestId> request_id)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
return CELL_OK;
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtLoadAsyncEx(func=*0x%x, userdata=*0x%x, container=0x%x, media=0x%x, videoQuality=0x%x, voiceQuality=0x%x, option=*0x%x, request_id=*0x%x)",
|
||||
func, userdata, container, +media, +videoQuality, +voiceQuality, option, request_id);
|
||||
|
||||
if (!option)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
switch (option->avcOptionParamVersion)
|
||||
{
|
||||
case CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION:
|
||||
if (option->sharingVideoBuffer && media == CELL_SYSUTIL_AVC_VOICE_CHAT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
//cellSysutilAvcSetAttribute(0x10000100, &option->sharingVideoBuffer);
|
||||
break;
|
||||
case 180:
|
||||
if (option->sharingVideoBuffer && media == CELL_SYSUTIL_AVC_VOICE_CHAT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
//cellSysutilAvcSetAttribute(0x10000100, &option->sharingVideoBuffer);
|
||||
//cellSysutilAvcSetAttribute(0x10000102, &option->maxPlayers);
|
||||
break;
|
||||
default:
|
||||
return CELL_AVC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
return cellSysutilAvcLoadAsync(func, userdata, container, media, videoQuality, voiceQuality, request_id);
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetShowNamePlate()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetShowNamePlate()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStopVoiceDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStopVoiceDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtShowWindow()
|
||||
error_code cellSysutilAvcExtShowWindow(vm::ptr<SceNpId> player_id, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStopVoiceDetection(player_id=*0x%x, transition_type=0x%x)", player_id, +transition_type);
|
||||
|
||||
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtIsCameraAttached()
|
||||
error_code cellSysutilAvcExtIsCameraAttached(vm::ptr<s32> status)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtIsCameraAttached(status=*0x%x)", status);
|
||||
|
||||
ensure(!!status); // Not actually checked
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtHidePanelEx()
|
||||
error_code cellSysutilAvcExtHidePanelEx(CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtHidePanelEx(transition_type=0x%x)", +transition_type);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtHideWindow()
|
||||
error_code cellSysutilAvcExtHideWindow(vm::ptr<SceNpId> player_id, CellSysutilAvcTransitionType transition_type)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtHideWindow(player_id=*0x%x, transition_type=0x%x)", player_id, +transition_type);
|
||||
|
||||
if (!player_id || transition_type > CELL_SYSUTIL_AVC_TRANSITION_EXPONENT)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetChatGroup()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetChatGroup()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetWindowRotation()
|
||||
error_code cellSysutilAvcExtGetWindowRotation(vm::ptr<SceNpId> player_id, vm::ptr<f32> rotation_x, vm::ptr<f32> rotation_y, vm::ptr<f32> rotation_z)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowRotation(player_id=*0x%x, rotation_x=*0x%x, rotation_y=*0x%x, rotation_z=*0x%x)", player_id, rotation_x, rotation_y, rotation_z);
|
||||
|
||||
if (!player_id || !rotation_x || !rotation_y || !rotation_z)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStartMicDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStartMicDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetWindowAlpha()
|
||||
error_code cellSysutilAvcExtGetWindowAlpha(vm::ptr<SceNpId> player_id, vm::ptr<f32> alpha)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetWindowAlpha(player_id=*0x%x, alpha=*0x%x)", player_id, alpha);
|
||||
|
||||
if (!player_id || !alpha)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStartVoiceDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStartVoiceDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtGetSurfacePointer()
|
||||
error_code cellSysutilAvcExtGetSurfacePointer(vm::ptr<SceNpId> player_id, vm::pptr<void> surface_ptr, vm::ptr<s32> surface_size, vm::ptr<s32> surface_size_x, vm::ptr<s32> surface_size_y)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtGetSurfacePointer(player_id=*0x%x, surface_ptr=*0x%x, surface_size=*0x%x, surface_size_x=*0x%x, surface_size_y=*0x%x)", player_id, surface_ptr, surface_size, surface_size_x, surface_size_y);
|
||||
|
||||
if (!player_id || !surface_ptr || !surface_size || !surface_size_x || !surface_size_y)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtStopMicDetection()
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtStopMicDetection()");
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtInitOptionParam()
|
||||
error_code cellSysutilAvcExtInitOptionParam(s32 avcOptionParamVersion, vm::ptr<CellSysutilAvcOptionParam> option)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.notice("cellSysutilAvcExtInitOptionParam(avcOptionParamVersion=0x%x, option=*0x%x)", avcOptionParamVersion, option);
|
||||
|
||||
if (!option)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
option->avcOptionParamVersion = avcOptionParamVersion;
|
||||
|
||||
switch (option->avcOptionParamVersion)
|
||||
{
|
||||
case CELL_SYSUTIL_AVC_OPTION_PARAM_VERSION:
|
||||
break;
|
||||
case 180:
|
||||
option->maxPlayers = 16;
|
||||
break;
|
||||
default:
|
||||
return CELL_AVC_ERROR_UNKNOWN;
|
||||
}
|
||||
|
||||
option->sharingVideoBuffer = false;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code cellSysutilAvcExtSetWindowZorder()
|
||||
error_code cellSysutilAvcExtSetWindowZorder(vm::ptr<SceNpId> player_id, u32 zorder)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(cellSysutilAvcExt);
|
||||
cellSysutilAvcExt.todo("cellSysutilAvcExtSetWindowZorder(player_id=*0x%x, zorder=0x%x)", player_id, zorder);
|
||||
|
||||
if (!player_id || zorder < CELL_SYSUTIL_AVC_ZORDER_FORWARD_MOST || zorder > CELL_SYSUTIL_AVC_ZORDER_BEHIND_MOST)
|
||||
return CELL_AVC_ERROR_INVALID_ARGUMENT;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
|
||||
+213
-235
@@ -1946,7 +1946,7 @@ error_code sceNpBasicAddPlayersHistoryAsync(vm::cptr<SceNpId> npids, u32 count,
|
||||
|
||||
error_code sceNpBasicGetPlayersHistoryEntryCount(u32 options, vm::ptr<u32> count)
|
||||
{
|
||||
sceNp.todo("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
|
||||
sceNp.warning("sceNpBasicGetPlayersHistoryEntryCount(options=%d, count=*0x%x)", options, count);
|
||||
|
||||
if (options > SCE_NP_BASIC_PLAYERS_HISTORY_OPTIONS_ALL)
|
||||
{
|
||||
@@ -3176,7 +3176,7 @@ error_code sceNpLookupInit()
|
||||
|
||||
error_code sceNpLookupTerm()
|
||||
{
|
||||
sceNp.todo("sceNpLookupTerm()");
|
||||
sceNp.warning("sceNpLookupTerm()");
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
@@ -4450,141 +4450,166 @@ error_code check_text(vm::cptr<char> text)
|
||||
|
||||
error_code sceNpMatchingCreateCtx(vm::ptr<SceNpId> npId, vm::ptr<SceNpMatchingHandler> handler, vm::ptr<void> arg, vm::ptr<u32> ctx_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
|
||||
sceNp.warning("sceNpMatchingCreateCtx(npId=*0x%x, handler=*0x%x, arg=*0x%x, ctx_id=*0x%x)", npId, handler, arg, ctx_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
{
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (false) // TODO
|
||||
// assumed checks done on vsh
|
||||
if (!npId || !handler || !ctx_id)
|
||||
{
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
const s32 id = create_matching_context(npId, handler, arg);
|
||||
|
||||
if (!id)
|
||||
{
|
||||
return SCE_NP_MATCHING_ERROR_CTX_MAX;
|
||||
}
|
||||
|
||||
nph.set_current_gui_ctx_id(id);
|
||||
|
||||
*ctx_id = static_cast<u32>(id);
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingDestroyCtx(u32 ctx_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
|
||||
sceNp.warning("sceNpMatchingDestroyCtx(ctx_id=%d)", ctx_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (false) // TODO
|
||||
if (!destroy_matching_context(ctx_id))
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
|
||||
nph.set_current_gui_ctx_id(0);
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetResult(u32 ctx_id, u32 req_id, vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
|
||||
sceNp.warning("sceNpMatchingGetResult(ctx_id=%d, req_id=%d, buf=*0x%x, size=*0x%x, event=*0x%x)", ctx_id, req_id, buf, size, event);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!size)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
return nph.get_matching_result(ctx_id, req_id, buf, size, event);
|
||||
|
||||
const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
|
||||
if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
|
||||
|
||||
if (buf)
|
||||
{
|
||||
// TODO: copy data to buf
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr u32 required_size = 0; // TODO
|
||||
*size = required_size;
|
||||
}
|
||||
|
||||
if (event)
|
||||
{
|
||||
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
// const u64 id_check = static_cast<s64>(static_cast<s32>(req_id)) >> 0x17 & 0x3f;
|
||||
// if (id_check > 32 || (1ULL << id_check & 0x1f89ad040U) == 0)
|
||||
// return SCE_NP_MATCHING_ERROR_INVALID_REQ_ID;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetResultGUI(vm::ptr<void> buf, vm::ptr<u32> size, vm::ptr<s32> event)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
|
||||
sceNp.warning("sceNpMatchingGetResultGUI(buf=*0x%x, size=*0x%x, event=*0x%x)", buf, size, event);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!size)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (buf)
|
||||
return nph.get_result_gui(buf, size, event);
|
||||
}
|
||||
|
||||
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
|
||||
{
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (limit)
|
||||
{
|
||||
// TODO: copy data to buf
|
||||
}
|
||||
else
|
||||
{
|
||||
constexpr u32 required_size = 0; // TODO
|
||||
*size = required_size;
|
||||
static u64 last_call = 0;
|
||||
|
||||
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
last_call = get_system_time();
|
||||
}
|
||||
|
||||
if (event)
|
||||
{
|
||||
//*event = some_event; // TODO: example: SCE_NP_MATCHING_GUI_EVENT_CREATE_ROOM
|
||||
}
|
||||
if (!lobby_id || !room_id || !req_id || !attr)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
error_code err = check_attr_id_and_duplicate(attr);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
auto res = nph.set_room_info_gui(ctx_id, lobby_id, room_id, attr);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
*req_id = res;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
sceNp.warning("sceNpMatchingSetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (false) // TODO: some timeout with 30000000 us ?
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
if (!lobby_id || !room_id || !req_id || !attr)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
error_code err = check_attr_id_and_duplicate(attr);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
|
||||
return CELL_OK;
|
||||
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
sceNp.warning("sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
|
||||
}
|
||||
|
||||
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit)
|
||||
{
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (limit)
|
||||
{
|
||||
static u64 last_call = 0;
|
||||
|
||||
if (last_call != 0 && (get_system_time() - last_call) < 30'000'000)
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
last_call = get_system_time();
|
||||
}
|
||||
|
||||
if (!lobby_id || !room_id || !req_id || !attr)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
@@ -4592,131 +4617,98 @@ error_code sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lob
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
auto res = nph.get_room_info_gui(ctx_id, lobby_id, room_id, attr);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
*req_id = res;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomInfo(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
sceNp.warning("sceNpMatchingGetRoomInfo(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (false) // TODO: some timeout with 30000000 us ?
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
if (!lobby_id || !room_id || !req_id || !attr)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
error_code err = check_attr_id_and_duplicate(attr);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
|
||||
return CELL_OK;
|
||||
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, true);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
sceNp.warning("sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!lobby_id || !room_id || !req_id || !attr)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
error_code err = check_attr_id_and_duplicate(attr);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
|
||||
return CELL_OK;
|
||||
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, s32 flag, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
|
||||
sceNp.warning("sceNpMatchingSetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, flag=%d, req_id=*0x%x)", ctx_id, lobby_id, room_id, flag, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!lobby_id || !room_id || !req_id || (flag < SCE_NP_MATCHING_ROOM_SEARCH_FLAG_OPEN || flag > SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH))
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
auto res = nph.set_room_search_flag_gui(ctx_id, lobby_id, room_id, flag);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
*req_id = res;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomSearchFlag(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
|
||||
sceNp.warning("sceNpMatchingGetRoomSearchFlag(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!lobby_id || !room_id || !req_id)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
auto res = nph.get_room_search_flag_gui(ctx_id, lobby_id, room_id);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
*req_id = res;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
|
||||
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (false) // TODO
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!buflen)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
return nph.get_room_member_list_local_gui(ctx_id, room_id, buflen, buf);
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
error_code sceNpMatchingGetRoomMemberListLocal(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
|
||||
{
|
||||
sceNp.warning("sceNpMatchingGetRoomMemberListLocal(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
|
||||
|
||||
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
|
||||
}
|
||||
|
||||
// FUN_00014bdc
|
||||
@@ -4788,41 +4780,42 @@ error_code check_room_list_params([[maybe_unused]] u32 ctx_id, vm::ptr<SceNpComm
|
||||
return check_attr_id_and_duplicate(attribute);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (false) // TODO
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
// TODO: add limiter
|
||||
|
||||
// This check is used in all sceNpMatchingGetRoomList functions
|
||||
error_code err = check_room_list_params(ctx_id, communicationId, range, cond, attr, handler, 1, 0);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
return nph.get_room_list_gui(ctx_id, communicationId, range, cond, attr, handler, arg, limit);
|
||||
}
|
||||
|
||||
// TODO: set callback: handler + arg
|
||||
error_code sceNpMatchingGetRoomListLimitGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.warning("sceNpMatchingGetRoomListLimitGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
|
||||
|
||||
err = CELL_OK; // GetRoomListLimit
|
||||
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, true);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingKickRoomMember(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingKickRoomMember(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!room_id || !user_id || !req_id)
|
||||
@@ -4841,10 +4834,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
|
||||
{
|
||||
sceNp.todo("sceNpMatchingKickRoomMemberWithOpt(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, opt=*0x%x, opt_len=%d, req_id=*0x%x)", ctx_id, room_id, user_id, opt, opt_len, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!room_id || !user_id || !req_id)
|
||||
@@ -4865,10 +4860,12 @@ error_code sceNpMatchingKickRoomMemberWithOpt(u32 ctx_id, vm::cptr<SceNpRoomId>
|
||||
error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, s32 available_num, s32 timeout,
|
||||
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
|
||||
sceNp.warning("sceNpMatchingQuickMatchGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, available_num=%d, timeout=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, available_num, timeout,
|
||||
handler, arg);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!communicationId || !handler || available_num < 2 || timeout < 1)
|
||||
@@ -4908,15 +4905,7 @@ error_code sceNpMatchingQuickMatchGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: set callback: handler + arg
|
||||
|
||||
error_code err = CELL_OK; // QuickMatch
|
||||
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
return err;
|
||||
return nph.quickmatch_gui(ctx_id, communicationId, cond, available_num, timeout, handler, arg);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpId> dsts, s32 num, s32 slot_type,
|
||||
@@ -4925,7 +4914,9 @@ error_code sceNpMatchingSendInvitationGUI(u32 ctx_id, vm::cptr<SceNpRoomId> room
|
||||
sceNp.todo("sceNpMatchingSendInvitationGUI(ctx_id=%d, room_id=*0x%x, communicationId=*0x%x, dsts=*0x%x, num=%d, slot_type=%d, subject=%s, body=%s, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id,
|
||||
room_id, communicationId, dsts, num, slot_type, subject, body, container, handler, arg);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!room_id || !communicationId || !subject || !body) // TODO: || (in_stack_0000007c != 0)
|
||||
@@ -4969,7 +4960,9 @@ error_code sceNpMatchingAcceptInvitationGUI(u32 ctx_id, vm::cptr<SceNpCommunicat
|
||||
{
|
||||
sceNp.todo("sceNpMatchingAcceptInvitationGUI(ctx_id=%d, communicationId=*0x%x, container=%d, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, container, handler, arg);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!communicationId || !handler)
|
||||
@@ -5058,12 +5051,14 @@ error_code check_attr_create_room(vm::cptr<SceNpMatchingAttr> attribute)
|
||||
return SCE_NP_MATCHING_ERROR_ATTR_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (false) // TODO
|
||||
if (nph.is_NP2_Match2_init)
|
||||
{
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (!communicationId || !handler)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
@@ -5073,69 +5068,66 @@ error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId>
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
// TODO: set callback: handler + arg
|
||||
|
||||
err = CELL_OK; // create_room
|
||||
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
return err;
|
||||
return nph.create_room_gui(ctx_id, communicationId, attr, handler, arg);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
error_code sceNpMatchingCreateRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
|
||||
sceNp.warning("sceNpMatchingCreateRoomGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
|
||||
|
||||
if (false) // TODO
|
||||
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
|
||||
}
|
||||
|
||||
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!room_id || !handler)
|
||||
return SCE_NP_MATCHING_ERROR_INVALID_ARG;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
return nph.join_room_gui(ctx_id, room_id, handler, arg);
|
||||
}
|
||||
|
||||
// TODO: set callback: handler + arg
|
||||
error_code sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.warning("sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
|
||||
|
||||
error_code err = CELL_OK; // join_room
|
||||
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
return err;
|
||||
return matching_join_room(ctx_id, room_id, handler, arg);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingLeaveRoom(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
|
||||
sceNp.warning("sceNpMatchingLeaveRoom(ctx_id=%d, room_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
auto res = nph.leave_room_gui(ctx_id, room_id);
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_CTX_NOT_FOUND;
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
*req_id = res;
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attribute,
|
||||
error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingSearchCondition> cond, vm::cptr<SceNpMatchingAttr> attr,
|
||||
vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attribute, handler, arg);
|
||||
sceNp.warning("sceNpMatchingSearchJoinRoomGUI(ctx_id=%d, communicationId=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, cond, attr, handler, arg);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (!communicationId || !handler)
|
||||
@@ -5183,32 +5175,23 @@ error_code sceNpMatchingSearchJoinRoomGUI(u32 ctx_id, vm::cptr<SceNpCommunicatio
|
||||
}
|
||||
}
|
||||
|
||||
error_code err = check_attr_id_and_duplicate(attribute);
|
||||
error_code err = check_attr_id_and_duplicate(attr);
|
||||
if (err != CELL_OK)
|
||||
return err;
|
||||
|
||||
if (false) // TODO
|
||||
return SCE_NP_MATCHING_ERROR_BUSY;
|
||||
|
||||
// TODO: set callback: handler + arg
|
||||
|
||||
//err = search_join_room
|
||||
if (err != CELL_OK && static_cast<u32>(err) != SCE_NP_MATCHING_ERROR_BUSY)
|
||||
{
|
||||
// TODO ?
|
||||
}
|
||||
|
||||
return err;
|
||||
return nph.searchjoin_gui(ctx_id, communicationId, cond, attr, handler, arg);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGrantOwnership(u32 ctx_id, vm::cptr<SceNpRoomId> room_id, vm::cptr<SceNpId> user_id, vm::ptr<u32> req_id)
|
||||
{
|
||||
sceNp.todo("sceNpMatchingGrantOwnership(ctx_id=%d, room_id=*0x%x, user_id=*0x%x, req_id=*0x%x)", ctx_id, room_id, user_id, req_id);
|
||||
|
||||
if (false) // TODO
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
if (nph.is_NP2_Match2_init)
|
||||
return SCE_NP_MATCHING_ERROR_UTILITY_UNAVAILABLE;
|
||||
|
||||
if (false) // TODO
|
||||
if (!nph.is_NP_init)
|
||||
return SCE_NP_MATCHING_ERROR_NOT_INITIALIZED;
|
||||
|
||||
if (!room_id || !user_id || !req_id)
|
||||
@@ -5658,11 +5641,6 @@ error_code scenp_score_record_score(s32 transId, SceNpScoreBoardId boardId, SceN
|
||||
data_size = 64;
|
||||
}
|
||||
|
||||
if (option)
|
||||
{
|
||||
return SCE_NP_COMMUNITY_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
nph.record_score(trans_ctx, boardId, score, scoreComment, data, data_size, tmpRank, async);
|
||||
|
||||
if (async)
|
||||
@@ -6230,7 +6208,7 @@ error_code sceNpScoreGetRankingByNpIdPcIdAsync(s32 transId, SceNpScoreBoardId bo
|
||||
|
||||
error_code sceNpScoreAbortTransaction(s32 transId)
|
||||
{
|
||||
sceNp.todo("sceNpScoreAbortTransaction(transId=%d)", transId);
|
||||
sceNp.warning("sceNpScoreAbortTransaction(transId=%d)", transId);
|
||||
|
||||
auto& nph = g_fxo->get<named_thread<np::np_handler>>();
|
||||
|
||||
|
||||
@@ -677,6 +677,17 @@ enum
|
||||
SCE_NP_MATCHING_ATTR_TYPE_GAME_NUM = 4,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_ATTR_ID_MIN = 1,
|
||||
SCE_NP_MATCHING_ATTR_ID_MAX = 16,
|
||||
SCE_NP_MATCHING_ATTR_ID_FOR_SEARCH_CONDITION_MAX = 8,
|
||||
SCE_NP_MATCHING_ATTR_ID_FOR_GRLGLIMIT_SRCH_COND_MAX = 8,
|
||||
SCE_NP_MATCHING_ATTR_BIN_BIG_SIZE_ID_MAX = 2,
|
||||
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_SMALL = 64,
|
||||
SCE_NP_MATCHING_ATTR_BIN_MAX_SIZE_BIG = 256,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_ROOM_ATTR_ID_TOTAL_SLOT = 1,
|
||||
@@ -686,6 +697,7 @@ enum
|
||||
SCE_NP_MATCHING_ROOM_ATTR_ID_CUR_PRIVATE_NUM = 5,
|
||||
SCE_NP_MATCHING_ROOM_ATTR_ID_PRIVILEGE_TYPE = 6,
|
||||
SCE_NP_MATCHING_ROOM_ATTR_ID_ROOM_SEARCH_FLAG = 7,
|
||||
SCE_NP_MATCHING_ROOM_ATTR_ID_MAX = 8,
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -706,6 +718,13 @@ enum
|
||||
SCE_NP_MATCHING_ROOM_SEARCH_FLAG_STEALTH = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_COND_MAX = 9,
|
||||
SCE_NP_MATCHING_GRLG_LIMIT_COND_MAX = 9,
|
||||
SCE_NP_MATCHING_COMP_OP_INEQUALITY_MAX = 9,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_CONDITION_SEARCH_EQ = 0,
|
||||
@@ -714,6 +733,7 @@ enum
|
||||
SCE_NP_MATCHING_CONDITION_SEARCH_LE = 3,
|
||||
SCE_NP_MATCHING_CONDITION_SEARCH_GT = 4,
|
||||
SCE_NP_MATCHING_CONDITION_SEARCH_GE = 5,
|
||||
SCE_NP_MATCHING_CONDITION_SEARCH_MAX = 6,
|
||||
};
|
||||
|
||||
enum
|
||||
@@ -724,6 +744,19 @@ enum
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_INVITATION_DESTINATION_MAX = 12,
|
||||
SCE_NP_MATCHING_INVITATION_SUBJECT_MAX_CHARS = 16,
|
||||
SCE_NP_MATCHING_INVITATION_BODY_MAX_CHARS = 128,
|
||||
|
||||
SCE_NP_MATCHING_KICK_OPT_MAX_LENGTH = 16,
|
||||
|
||||
SCE_NP_MATCHING_ROOM_MAX_SLOT = 16,
|
||||
SCE_NP_MATCHING_CTX_MAX = 8,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SCE_NP_MATCHING_SEND_INVITATION_MEMSIZE = 16 * 1024 * 1024,
|
||||
SCE_NP_MATCHING_ACCEPT_INVITATION_MEMSIZE = 16 * 1024 * 1024,
|
||||
};
|
||||
|
||||
// Basic presence options
|
||||
@@ -1170,7 +1203,7 @@ enum
|
||||
SCE_NP_MATCHING_GUI_EVENT_ACCEPT_INVITATION = 0x0007,
|
||||
SCE_NP_MATCHING_GUI_EVENT_COMMON_LOAD = 0x0008,
|
||||
SCE_NP_MATCHING_GUI_EVENT_COMMON_UNLOAD = 0x0009,
|
||||
SCE_NP_MATCHING_GUI_EVENT_RESERVED3 = 0x000a,
|
||||
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST = 0x000a,
|
||||
SCE_NP_MATCHING_GUI_EVENT_GET_ROOM_LIST_LIMIT = 0x000b
|
||||
};
|
||||
|
||||
@@ -1697,6 +1730,59 @@ struct SceNpScoreRecordOptParam
|
||||
vm::bptr<CellRtcTick> reserved;
|
||||
};
|
||||
|
||||
// Old GUI API structures
|
||||
|
||||
struct SceNpMatchingRoomMember
|
||||
{
|
||||
vm::bptr<SceNpMatchingRoomMember> next;
|
||||
SceNpUserInfo user_info;
|
||||
be_t<s32> owner;
|
||||
};
|
||||
|
||||
struct SceNpMatchingRoomStatus
|
||||
{
|
||||
SceNpRoomId id;
|
||||
vm::bptr<SceNpMatchingRoomMember> members;
|
||||
be_t<s32> num;
|
||||
vm::bptr<SceNpId> kick_actor;
|
||||
vm::bptr<void> opt;
|
||||
be_t<s32> opt_len;
|
||||
};
|
||||
|
||||
struct SceNpMatchingJoinedRoomInfo
|
||||
{
|
||||
SceNpLobbyId lobbyid;
|
||||
SceNpMatchingRoomStatus room_status;
|
||||
};
|
||||
|
||||
struct SceNpMatchingRange
|
||||
{
|
||||
be_t<u32> start;
|
||||
be_t<u32> results;
|
||||
be_t<u32> total;
|
||||
};
|
||||
|
||||
struct SceNpMatchingRoom
|
||||
{
|
||||
vm::bptr<SceNpMatchingRoom> next;
|
||||
SceNpRoomId id;
|
||||
vm::bptr<SceNpMatchingAttr> attr;
|
||||
};
|
||||
|
||||
struct SceNpMatchingRoomList
|
||||
{
|
||||
SceNpLobbyId lobbyid;
|
||||
SceNpMatchingRange range;
|
||||
vm::bptr<SceNpMatchingRoom> head;
|
||||
};
|
||||
|
||||
struct SceNpMatchingSearchJoinRoomInfo
|
||||
{
|
||||
SceNpLobbyId lobbyid;
|
||||
SceNpMatchingRoomStatus room_status;
|
||||
vm::bptr<SceNpMatchingAttr> attr;
|
||||
};
|
||||
|
||||
// NP callback functions
|
||||
using SceNpCustomMenuEventHandler = s32(s32 retCode, u32 index, vm::cptr<SceNpId> npid, SceNpCustomMenuSelectedType type, vm::ptr<void> arg);
|
||||
using SceNpBasicEventHandler = s32(s32 event, s32 retCode, u32 reqId, vm::ptr<void> arg);
|
||||
@@ -1756,3 +1842,12 @@ public:
|
||||
protected:
|
||||
std::shared_ptr<rpcn::rpcn_client> m_rpcn;
|
||||
};
|
||||
|
||||
// Generic functions, also used in SceNpMatchingInt.cpp
|
||||
error_code matching_create_room(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
|
||||
error_code matching_join_room(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg);
|
||||
error_code matching_get_room_list(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg, bool limit);
|
||||
error_code matching_set_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
|
||||
error_code matching_get_room_info(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id, bool limit);
|
||||
error_code matching_get_room_member_list(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf);
|
||||
|
||||
@@ -576,9 +576,9 @@ error_code sceNpMatching2ContextStart(SceNpMatching2ContextId ctxId)
|
||||
|
||||
if (ctx->context_callback)
|
||||
{
|
||||
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
@@ -1106,9 +1106,9 @@ error_code sceNpMatching2ContextStartAsync(SceNpMatching2ContextId ctxId, u32 ti
|
||||
|
||||
if (ctx->context_callback)
|
||||
{
|
||||
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Start, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
@@ -1656,6 +1656,13 @@ error_code sceNpMatching2GetLobbyInfoList(
|
||||
return res;
|
||||
}
|
||||
|
||||
const u32 request_id = nph.get_lobby_info_list(ctxId, optParam, reqParam.get_ptr());
|
||||
|
||||
if (assignedReqId)
|
||||
{
|
||||
*assignedReqId = request_id;
|
||||
}
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
@@ -1709,9 +1716,9 @@ error_code sceNpMatching2ContextStop(SceNpMatching2ContextId ctxId)
|
||||
|
||||
if (ctx->context_callback)
|
||||
{
|
||||
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
ctx->context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctxId, SCE_NP_MATCHING2_CONTEXT_EVENT_Stop, SCE_NP_MATCHING2_EVENT_CAUSE_CONTEXT_ACTION, 0, context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -220,9 +220,9 @@ error_code sceNpCommerce2EmptyStoreCheckStart(u32 ctx_id, s32 store_check_type,
|
||||
|
||||
if (ctx->context_callback)
|
||||
{
|
||||
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_EMPTY_STORE_CHECK_DONE, 0, context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
@@ -276,9 +276,9 @@ error_code sceNpCommerce2CreateSessionStart(u32 ctx_id)
|
||||
|
||||
if (ctx->context_callback)
|
||||
{
|
||||
sysutil_register_cb([=](ppu_thread& cb_ppu) -> s32
|
||||
sysutil_register_cb([=, context_callback = ctx->context_callback, context_callback_param = ctx->context_callback_param](ppu_thread& cb_ppu) -> s32
|
||||
{
|
||||
ctx->context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, ctx->context_callback_param);
|
||||
context_callback(cb_ppu, ctx_id, 0, SCE_NP_COMMERCE2_EVENT_CREATE_SESSION_DONE, 0, context_callback_param);
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#include "stdafx.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
|
||||
// Temporarily
|
||||
#ifndef _MSC_VER
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
#endif
|
||||
#include "sceNp.h"
|
||||
|
||||
LOG_CHANNEL(sceNpMatchingInt);
|
||||
|
||||
@@ -14,48 +10,55 @@ error_code sceNpMatchingCancelRequest()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomMemberList()
|
||||
error_code sceNpMatchingGetRoomMemberList(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<u32> buflen, vm::ptr<void> buf)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("sceNpMatchingGetRoomMemberList(ctx_id=%d, room_id=*0x%x, buflen=*0x%x, buf=*0x%x)", ctx_id, room_id, buflen, buf);
|
||||
|
||||
return matching_get_room_member_list(ctx_id, room_id, buflen, buf);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingJoinRoomWithoutGUI()
|
||||
error_code sceNpMatchingJoinRoomWithoutGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("sceNpMatchingJoinRoomWithoutGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
|
||||
|
||||
return matching_join_room(ctx_id, room_id, handler, arg);
|
||||
}
|
||||
|
||||
// Parameter "unknown" added to distinguish this function
|
||||
// from the one in sceNp.cpp which has the same name
|
||||
error_code sceNpMatchingJoinRoomGUI(vm::ptr<void> unknown)
|
||||
error_code OLD_sceNpMatchingJoinRoomGUI(u32 ctx_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("OLD_sceNpMatchingJoinRoomGUI(ctx_id=%d, room_id=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, room_id, handler, arg);
|
||||
|
||||
return matching_join_room(ctx_id, room_id, handler, arg);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingSetRoomInfoNoLimit(vm::ptr<void> unknown)
|
||||
error_code OLD_sceNpMatchingSetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("OLD_sceNpMatchingSetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
return matching_set_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomListWithoutGUI()
|
||||
error_code sceNpMatchingGetRoomListWithoutGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("sceNpMatchingGetRoomListWithoutGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
|
||||
|
||||
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomListGUI()
|
||||
error_code sceNpMatchingGetRoomListGUI(u32 ctx_id, vm::ptr<SceNpCommunicationId> communicationId, vm::ptr<SceNpMatchingReqRange> range, vm::ptr<SceNpMatchingSearchCondition> cond,
|
||||
vm::ptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("sceNpMatchingGetRoomListGUI(ctx_id=%d, communicationId=*0x%x, range=*0x%x, cond=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, range, cond, attr, handler, arg);
|
||||
|
||||
return matching_get_room_list(ctx_id, communicationId, range, cond, attr, handler, arg, false);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingGetRoomInfoNoLimit(vm::ptr<void> unknown)
|
||||
error_code OLD_sceNpMatchingGetRoomInfoNoLimit(u32 ctx_id, vm::ptr<SceNpLobbyId> lobby_id, vm::ptr<SceNpRoomId> room_id, vm::ptr<SceNpMatchingAttr> attr, vm::ptr<u32> req_id)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("OLD_sceNpMatchingGetRoomInfoNoLimit(ctx_id=%d, lobby_id=*0x%x, room_id=*0x%x, attr=*0x%x, req_id=*0x%x)", ctx_id, lobby_id, room_id, attr, req_id);
|
||||
|
||||
return matching_get_room_info(ctx_id, lobby_id, room_id, attr, req_id, false);
|
||||
}
|
||||
|
||||
error_code sceNpMatchingCancelRequestGUI()
|
||||
@@ -70,22 +73,27 @@ error_code sceNpMatchingSendRoomMessage()
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sceNpMatchingCreateRoomWithoutGUI()
|
||||
error_code sceNpMatchingCreateRoomWithoutGUI(u32 ctx_id, vm::cptr<SceNpCommunicationId> communicationId, vm::cptr<SceNpMatchingAttr> attr, vm::ptr<SceNpMatchingGUIHandler> handler, vm::ptr<void> arg)
|
||||
{
|
||||
UNIMPLEMENTED_FUNC(sceNpMatchingInt);
|
||||
return CELL_OK;
|
||||
sceNpMatchingInt.warning("sceNpMatchingCreateRoomWithoutGUI(ctx_id=%d, communicationId=*0x%x, attr=*0x%x, handler=*0x%x, arg=*0x%x)", ctx_id, communicationId, attr, handler, arg);
|
||||
|
||||
return matching_create_room(ctx_id, communicationId, attr, handler, arg);
|
||||
}
|
||||
|
||||
// This module has some conflicting function names with sceNp module, hence the REG_FNID
|
||||
DECLARE(ppu_module_manager::sceNpMatchingInt)("sceNpMatchingInt", []()
|
||||
{
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequest);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomMemberList);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomWithoutGUI);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
|
||||
// REG_FUNC(sceNpMatchingInt, sceNpMatchingJoinRoomGUI);
|
||||
REG_FNID(sceNpMatchingInt, "sceNpMatchingJoinRoomGUI", OLD_sceNpMatchingJoinRoomGUI);
|
||||
// REG_FUNC(sceNpMatchingInt, sceNpMatchingSetRoomInfoNoLimit);
|
||||
REG_FNID(sceNpMatchingInt, "sceNpMatchingSetRoomInfoNoLimit", OLD_sceNpMatchingSetRoomInfoNoLimit);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListWithoutGUI);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomListGUI);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
|
||||
// REG_FUNC(sceNpMatchingInt, sceNpMatchingGetRoomInfoNoLimit);
|
||||
REG_FNID(sceNpMatchingInt, "sceNpMatchingGetRoomInfoNoLimit", OLD_sceNpMatchingGetRoomInfoNoLimit);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingCancelRequestGUI);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingSendRoomMessage);
|
||||
REG_FUNC(sceNpMatchingInt, sceNpMatchingCreateRoomWithoutGUI);
|
||||
|
||||
@@ -572,7 +572,7 @@ error_code sceNpTrophyRegisterContext(ppu_thread& ppu, u32 context, u32 handle,
|
||||
{
|
||||
if (!!(options & SCE_NP_TROPHY_OPTIONS_REGISTER_CONTEXT_SHOW_ERROR_EXIT))
|
||||
{
|
||||
static_cast<void>(open_exit_dialog("Error during trophy registration! The game will now be terminated.", true));
|
||||
static_cast<void>(open_exit_dialog("Error during trophy registration! The game will now be terminated.", true, msg_dialog_source::_sceNpTrophy));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -184,6 +184,7 @@ static void ppu_initialize_modules(ppu_linkage_info* link, utils::serial* ar = n
|
||||
&ppu_module_manager::cellAdec,
|
||||
&ppu_module_manager::cellAtrac,
|
||||
&ppu_module_manager::cellAtracMulti,
|
||||
&ppu_module_manager::cellAtracXdec,
|
||||
&ppu_module_manager::cellAudio,
|
||||
&ppu_module_manager::cellAvconfExt,
|
||||
&ppu_module_manager::cellAuthDialogUtility,
|
||||
|
||||
@@ -168,6 +168,7 @@ public:
|
||||
static const ppu_static_module cellAdec;
|
||||
static const ppu_static_module cellAtrac;
|
||||
static const ppu_static_module cellAtracMulti;
|
||||
static const ppu_static_module cellAtracXdec;
|
||||
static const ppu_static_module cellAudio;
|
||||
static const ppu_static_module cellAvconfExt;
|
||||
static const ppu_static_module cellAuthDialogUtility;
|
||||
|
||||
@@ -7,20 +7,30 @@
|
||||
|
||||
inline void try_start(spu_thread& spu)
|
||||
{
|
||||
reader_lock lock(spu.run_ctrl_mtx);
|
||||
bool notify = false;
|
||||
|
||||
if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value)
|
||||
if (~spu.status_npc.load().status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
if (value.status & SPU_STATUS_RUNNING)
|
||||
reader_lock lock(spu.run_ctrl_mtx);
|
||||
|
||||
if (spu.status_npc.fetch_op([](spu_thread::status_npc_sync_var& value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (value.status & SPU_STATUS_RUNNING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED);
|
||||
return true;
|
||||
}).second)
|
||||
value.status = SPU_STATUS_RUNNING | (value.status & SPU_STATUS_IS_ISOLATED);
|
||||
return true;
|
||||
}).second)
|
||||
{
|
||||
spu.state -= cpu_flag::stop;
|
||||
notify = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (notify)
|
||||
{
|
||||
spu.state -= cpu_flag::stop;
|
||||
spu.state.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5028,8 +5028,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
|
||||
auto& vregs = is_form_block ? infos[bpc]->local_state : *true_state_walkby;
|
||||
auto& atomic16 = is_pattern_match ? ::at32(reg_state_it, wi).atomic16 : dummy16;
|
||||
auto& rchcnt_loop = is_pattern_match ? ::at32(reg_state_it, wi).rchcnt_loop : dummy_loop;
|
||||
const auto atomic16 = is_pattern_match ? &::at32(reg_state_it, wi).atomic16 : &dummy16;
|
||||
const auto rchcnt_loop = is_pattern_match ? &::at32(reg_state_it, wi).rchcnt_loop : &dummy_loop;
|
||||
|
||||
const u32 pos = wa;
|
||||
|
||||
@@ -5153,8 +5153,8 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
const auto break_all_patterns = [&](u32 cause)
|
||||
{
|
||||
break_putllc16(cause, atomic16.discard());
|
||||
break_channel_pattern(cause, rchcnt_loop.discard());
|
||||
break_putllc16(cause, atomic16->discard());
|
||||
break_channel_pattern(cause, rchcnt_loop->discard());
|
||||
};
|
||||
|
||||
const auto calculate_absolute_ls_difference = [](u32 addr1, u32 addr2)
|
||||
@@ -5188,7 +5188,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
auto& block = infos[bpc];
|
||||
|
||||
if (g_cfg.core.spu_block_size != spu_block_size_type::safe && (m_ret_info[bpc / 4] || m_entry_info[bpc / 4] || pos == entry_point))
|
||||
if (pos == entry_point || (g_cfg.core.spu_block_size != spu_block_size_type::safe && (m_ret_info[bpc / 4] || m_entry_info[bpc / 4])))
|
||||
{
|
||||
// Do not allow value passthrough
|
||||
for (reg_state_t& f : block->start_reg_state)
|
||||
@@ -5429,6 +5429,18 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
}
|
||||
|
||||
if (wi != stackframe_it || may_return || !insert_entry)
|
||||
{
|
||||
// Possible function end
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
// Does not post-dominates channel reads
|
||||
auto& pair = rchcnt_loop_all[rchcnt_loop->read_pc];
|
||||
pair.failed = true;
|
||||
pair.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Backup analyser information
|
||||
const auto atomic16_info = reg_state_it[stackframe_it].atomic16;
|
||||
const auto rchcnt_loop_info = reg_state_it[stackframe_it].rchcnt_loop;
|
||||
@@ -5450,18 +5462,6 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
}
|
||||
|
||||
if (wi != stackframe_it || may_return || !insert_entry)
|
||||
{
|
||||
// Possible function end
|
||||
if (rchcnt_loop.active)
|
||||
{
|
||||
// Does not post-dominates channel reads
|
||||
auto& pair = rchcnt_loop_all[rchcnt_loop.read_pc];
|
||||
pair.failed = true;
|
||||
pair.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_entry)
|
||||
{
|
||||
const usz target_size = get_block_targets(stackframe_pc).size();
|
||||
@@ -5484,10 +5484,10 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break_putllc16(39, atomic16_info);
|
||||
}
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop_info.active)
|
||||
{
|
||||
// Does not post-dominates channel read
|
||||
auto& pair = rchcnt_loop_all[rchcnt_loop.read_pc];
|
||||
auto& pair = rchcnt_loop_all[rchcnt_loop_info.read_pc];
|
||||
pair.failed = true;
|
||||
pair.active = false;
|
||||
}
|
||||
@@ -5648,20 +5648,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
for (auto state : {&atomic16.lsa, &atomic16.ls, &atomic16.ls_offs})
|
||||
for (auto state : {&atomic16->lsa, &atomic16->ls, &atomic16->ls_offs})
|
||||
{
|
||||
state->invalidate_if_created(pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
if (rchcnt_loop.origins.find_first_of(pos) != umax)
|
||||
if (rchcnt_loop->origins.find_first_of(pos) != umax)
|
||||
{
|
||||
rchcnt_loop.failed = true;
|
||||
rchcnt_loop.active = false;
|
||||
rchcnt_loop->failed = true;
|
||||
rchcnt_loop->active = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5719,7 +5719,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
dis_asm.last_opcode.pop_back();
|
||||
}
|
||||
|
||||
spu_log.always()("[SPU=0%x, it=%d] %s%s [%d]", pos, reg_state_it[wi].iterator_id, dis_asm.last_opcode, consts, atomic16.active);
|
||||
spu_log.always()("[SPU=0%x, it=%d] %s%s [%d]", pos, reg_state_it[wi].iterator_id, dis_asm.last_opcode, consts, atomic16->active);
|
||||
}
|
||||
|
||||
// Analyse instruction
|
||||
@@ -5798,22 +5798,22 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
const u32 next_pc = spu_branch_target(pos, 1);
|
||||
const u32 target = spu_branch_target(pos, op.i16);
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
const reg_state_t& rt = vregs[op.rt];
|
||||
|
||||
if (rt.is_instruction && (rchcnt_loop.ch_state.origin == rt.origin || rchcnt_loop.ch_product.origin == rt.origin))
|
||||
if (rt.is_instruction && (rchcnt_loop->ch_state.origin == rt.origin || rchcnt_loop->ch_product.origin == rt.origin))
|
||||
{
|
||||
if (rchcnt_loop.conditioned)
|
||||
if (rchcnt_loop->conditioned)
|
||||
{
|
||||
// Let's not make it complicated, have a single branch determining the condition
|
||||
break_channel_pattern(54, rchcnt_loop.discard());
|
||||
break_channel_pattern(54, rchcnt_loop->discard());
|
||||
break;
|
||||
}
|
||||
|
||||
rchcnt_loop.conditioned = true;
|
||||
rchcnt_loop.branch_pc = pos;
|
||||
rchcnt_loop.branch_target = rchcnt_loop.product_test_negate != (type == spu_itype::BRZ) ? target : next_pc;
|
||||
rchcnt_loop->conditioned = true;
|
||||
rchcnt_loop->branch_pc = pos;
|
||||
rchcnt_loop->branch_target = rchcnt_loop->product_test_negate != (type == spu_itype::BRZ) ? target : next_pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -5845,7 +5845,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
case spu_itype::WRCH:
|
||||
{
|
||||
break_channel_pattern(56, rchcnt_loop.discard());
|
||||
break_channel_pattern(56, rchcnt_loop->discard());
|
||||
|
||||
switch (op.ra)
|
||||
{
|
||||
@@ -5861,7 +5861,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (is_pattern_match)
|
||||
{
|
||||
atomic16.lsa_last_pc = pos;
|
||||
atomic16->lsa_last_pc = pos;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -5897,27 +5897,27 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
auto lsa = get_reg(s_reg_mfc_lsa);
|
||||
vregs[s_reg_mfc_lsa] = old_lsa;
|
||||
|
||||
const u32 lsa_pc = atomic16.lsa_last_pc == SPU_LS_SIZE ? bpc : atomic16.lsa_last_pc;
|
||||
const u32 lsa_pc = atomic16->lsa_last_pc == SPU_LS_SIZE ? bpc : atomic16->lsa_last_pc;
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
if (atomic16.lsa_pc != lsa_pc || atomic16.get_pc != pos || atomic16.lsa != lsa)
|
||||
if (atomic16->lsa_pc != lsa_pc || atomic16->get_pc != pos || atomic16->lsa != lsa)
|
||||
{
|
||||
break_putllc16(30, atomic16.discard());
|
||||
break_putllc16(30, atomic16->discard());
|
||||
}
|
||||
}
|
||||
|
||||
// If LSA write has not happened, use block start
|
||||
atomic16.lsa_pc = lsa_pc;
|
||||
atomic16.get_pc = pos;
|
||||
atomic16.active = true;
|
||||
atomic16->lsa_pc = lsa_pc;
|
||||
atomic16->get_pc = pos;
|
||||
atomic16->active = true;
|
||||
|
||||
atomic16.lsa = lsa;
|
||||
atomic16->lsa = lsa;
|
||||
|
||||
if (likely_putllc_loop)
|
||||
{
|
||||
// Register loop entry
|
||||
if (getllar_starts.emplace(atomic16.lsa_pc, false).second)
|
||||
if (getllar_starts.emplace(atomic16->lsa_pc, false).second)
|
||||
{
|
||||
g_fxo->get<putllc16_statistics_t>().all++;
|
||||
spu_log.notice("[0x%05x] GETLLAR pattern entry point", pos);
|
||||
@@ -5928,17 +5928,17 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
}
|
||||
case MFC_PUTLLC_CMD:
|
||||
{
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
const auto _lsa = get_reg(s_reg_mfc_lsa);
|
||||
|
||||
// Search the value of LS address stoire/load in latest register file
|
||||
if (atomic16.ls_access && atomic16.ls_write && !atomic16.ls_pc_rel && !atomic16.ls.is_const())
|
||||
if (atomic16->ls_access && atomic16->ls_write && !atomic16->ls_pc_rel && !atomic16->ls.is_const())
|
||||
{
|
||||
usz reg_it = umax;
|
||||
u32 regs[2]{s_reg_max, s_reg_max};
|
||||
|
||||
for (auto val : {&atomic16.ls, &atomic16.ls_offs})
|
||||
for (auto val : {&atomic16->ls, &atomic16->ls_offs})
|
||||
{
|
||||
reg_it++;
|
||||
|
||||
@@ -5968,68 +5968,68 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (regs[0] == s_reg_max || regs[1] == s_reg_max)
|
||||
{
|
||||
break_putllc16(3, atomic16.discard());
|
||||
break_putllc16(3, atomic16->discard());
|
||||
break;
|
||||
}
|
||||
|
||||
atomic16.reg = regs[0];
|
||||
atomic16->reg = regs[0];
|
||||
|
||||
if (!atomic16.ls_offs.is_const())
|
||||
if (!atomic16->ls_offs.is_const())
|
||||
{
|
||||
atomic16.reg2 = regs[1];
|
||||
atomic16->reg2 = regs[1];
|
||||
}
|
||||
}
|
||||
|
||||
if (atomic16.ls_access && atomic16.ls_write && !atomic16.lsa.compare_with_mask_indifference(_lsa, SPU_LS_MASK_128))
|
||||
if (atomic16->ls_access && atomic16->ls_write && !atomic16->lsa.compare_with_mask_indifference(_lsa, SPU_LS_MASK_128))
|
||||
{
|
||||
// LSA latest value mismatches with the one written with GETLLAR
|
||||
|
||||
if (atomic16.lsa.flag != _lsa.flag)
|
||||
if (atomic16->lsa.flag != _lsa.flag)
|
||||
{
|
||||
break_putllc16(1, atomic16.discard());
|
||||
break_putllc16(1, atomic16->discard());
|
||||
}
|
||||
else
|
||||
{
|
||||
break_putllc16(2, atomic16.discard());
|
||||
break_putllc16(2, atomic16->discard());
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (atomic16.ls_access && atomic16.ls_write)
|
||||
if (atomic16->ls_access && atomic16->ls_write)
|
||||
{
|
||||
atomic16.select_16_or_0_at_runtime = false;
|
||||
atomic16->select_16_or_0_at_runtime = false;
|
||||
|
||||
bool ok = false;
|
||||
|
||||
if (atomic16.ls_pc_rel || !atomic16.ls_offs.is_const())
|
||||
if (atomic16->ls_pc_rel || !atomic16->ls_offs.is_const())
|
||||
{
|
||||
//
|
||||
}
|
||||
else if (atomic16.lsa.is_const())
|
||||
else if (atomic16->lsa.is_const())
|
||||
{
|
||||
if (atomic16.ls.is_const())
|
||||
if (atomic16->ls.is_const())
|
||||
{
|
||||
if (atomic16.ls_offs.value != 0)
|
||||
if (atomic16->ls_offs.value != 0)
|
||||
{
|
||||
// Rebase constant so we can get rid of ls_offs
|
||||
atomic16.ls.value = spu_ls_target(atomic16.ls_offs.value + atomic16.ls.value);
|
||||
atomic16.ls_offs = reg_state_t::from_value(0);
|
||||
atomic16->ls.value = spu_ls_target(atomic16->ls_offs.value + atomic16->ls.value);
|
||||
atomic16->ls_offs = reg_state_t::from_value(0);
|
||||
}
|
||||
|
||||
if (atomic16.ls.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128))
|
||||
if (atomic16->ls.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128))
|
||||
{
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
else if (atomic16.ls_offs.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128) && atomic16.ls.is_less_than(128 - (atomic16.ls_offs.value & 127)))
|
||||
else if (atomic16->ls_offs.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128) && atomic16->ls.is_less_than(128 - (atomic16->ls_offs.value & 127)))
|
||||
{
|
||||
// Relative memory access with offset less than 128 bytes
|
||||
// Common around SPU utilities which have less strict restrictions about memory alignment
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
else if (atomic16.lsa.compare_with_mask_indifference(atomic16.ls, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
|
||||
else if (atomic16->lsa.compare_with_mask_indifference(atomic16->ls, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
|
||||
{
|
||||
// Unknown value with known offset of less than 128 bytes
|
||||
ok = true;
|
||||
@@ -6039,37 +6039,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
// This is quite common.. let's try to select between putllc16 and putllc0 at runtime!
|
||||
// break_putllc16(100);
|
||||
// atomic16.discard();
|
||||
// atomic16->discard();
|
||||
// break;
|
||||
atomic16.select_16_or_0_at_runtime = true;
|
||||
atomic16->select_16_or_0_at_runtime = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!atomic16.get_rdatomic)
|
||||
if (!atomic16->get_rdatomic)
|
||||
{
|
||||
// MFC_RdAtomicStat must have been read, otherwise GETLLAR may not be executed (according to HW tests)
|
||||
break_putllc16(21, atomic16.discard());
|
||||
break_putllc16(21, atomic16->discard());
|
||||
}
|
||||
|
||||
atomic16.put_pc = pos;
|
||||
atomic16.put_active = true;
|
||||
atomic16->put_pc = pos;
|
||||
atomic16->put_active = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break_putllc16(4, atomic16.discard());
|
||||
break_putllc16(4, atomic16->discard());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break_putllc16(5, atomic16.discard());
|
||||
break_putllc16(5, atomic16->discard());
|
||||
}
|
||||
|
||||
if (!atomic16.active)
|
||||
if (!atomic16->active)
|
||||
{
|
||||
// Propagate failure
|
||||
for (auto& atm : atomic16_all)
|
||||
@@ -6113,7 +6113,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
if (it != rchcnt_loop_all.end())
|
||||
{
|
||||
if (rchcnt_loop.failed || !rchcnt_loop.conditioned || rchcnt_loop.read_pc != pos)
|
||||
if (rchcnt_loop->failed || !rchcnt_loop->conditioned || rchcnt_loop->read_pc != pos)
|
||||
{
|
||||
// Propagate faiure
|
||||
it->second.failed = true;
|
||||
@@ -6125,14 +6125,14 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
it->second.active = false;
|
||||
}
|
||||
|
||||
rchcnt_loop.active = false;
|
||||
rchcnt_loop->active = false;
|
||||
}
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
if (rchcnt_loop.read_pc != pos)
|
||||
if (rchcnt_loop->read_pc != pos)
|
||||
{
|
||||
break_channel_pattern(53, rchcnt_loop.discard());
|
||||
break_channel_pattern(53, rchcnt_loop->discard());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6145,13 +6145,13 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
break;
|
||||
}
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
if (atomic16.put_active)
|
||||
if (atomic16->put_active)
|
||||
{
|
||||
if (getllar_starts.contains(atomic16.lsa_pc) && getllar_starts[atomic16.lsa_pc])
|
||||
if (getllar_starts.contains(atomic16->lsa_pc) && getllar_starts[atomic16->lsa_pc])
|
||||
{
|
||||
break_putllc16(24, atomic16.discard());
|
||||
break_putllc16(24, atomic16->discard());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -6160,7 +6160,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
if (it == atomic16_all.end())
|
||||
{
|
||||
// Fresh new pattern detected in a single code path
|
||||
atomic16_all.emplace(pos, atomic16);
|
||||
atomic16_all.emplace(pos, *atomic16);
|
||||
}
|
||||
else if (it->second.active)
|
||||
{
|
||||
@@ -6178,53 +6178,53 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
return a.second == b.second;
|
||||
};
|
||||
|
||||
if (existing.lsa_pc != atomic16.lsa_pc || existing.put_pc != atomic16.put_pc || !existing.lsa.compare_with_mask_indifference(atomic16.lsa, SPU_LS_MASK_128))
|
||||
if (existing.lsa_pc != atomic16->lsa_pc || existing.put_pc != atomic16->put_pc || !existing.lsa.compare_with_mask_indifference(atomic16->lsa, SPU_LS_MASK_128))
|
||||
{
|
||||
// Register twice
|
||||
break_putllc16(22, atomic16.discard());
|
||||
break_putllc16(22, atomic16->discard());
|
||||
break_putllc16(22, existing.discard());
|
||||
}
|
||||
|
||||
if (existing.active && existing.ls_access && atomic16.ls_access && (!compare_tag_and_reg({&existing.ls, existing.reg}, {&atomic16.ls, atomic16.reg}) || existing.ls_offs != atomic16.ls_offs || existing.reg2 != atomic16.reg2))
|
||||
if (existing.active && existing.ls_access && atomic16->ls_access && (!compare_tag_and_reg({&existing.ls, existing.reg}, {&atomic16->ls, atomic16->reg}) || existing.ls_offs != atomic16->ls_offs || existing.reg2 != atomic16->reg2))
|
||||
{
|
||||
// Conflicting loads with stores in more than one code path
|
||||
break_putllc16(27, atomic16.set_invalid_ls(existing.ls_write || atomic16.ls_write));
|
||||
break_putllc16(27, atomic16->set_invalid_ls(existing.ls_write || atomic16->ls_write));
|
||||
|
||||
if (!atomic16.active)
|
||||
if (!atomic16->active)
|
||||
{
|
||||
existing.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (existing.active && (existing.ls_write || atomic16.ls_write) && (existing.ls_invalid || atomic16.ls_invalid))
|
||||
if (existing.active && (existing.ls_write || atomic16->ls_write) && (existing.ls_invalid || atomic16->ls_invalid))
|
||||
{
|
||||
// Conflicting loads with stores in more than one code path
|
||||
break_putllc16(33, atomic16.discard());
|
||||
break_putllc16(33, atomic16->discard());
|
||||
existing.active = false;
|
||||
existing.ls_invalid = true;
|
||||
}
|
||||
|
||||
if (existing.active && !existing.ls_access && atomic16.ls_access)
|
||||
if (existing.active && !existing.ls_access && atomic16->ls_access)
|
||||
{
|
||||
// Propagate LS access
|
||||
existing.ls = atomic16.ls;
|
||||
existing.reg = atomic16.reg;
|
||||
existing.reg2 = atomic16.reg2;
|
||||
existing.ls_offs = atomic16.ls_offs;
|
||||
existing.ls = atomic16->ls;
|
||||
existing.reg = atomic16->reg;
|
||||
existing.reg2 = atomic16->reg2;
|
||||
existing.ls_offs = atomic16->ls_offs;
|
||||
}
|
||||
|
||||
existing.ls_write |= atomic16.ls_write;
|
||||
existing.ls_invalid |= atomic16.ls_invalid;
|
||||
existing.ls_access |= atomic16.ls_access;
|
||||
existing.mem_count = std::max<u32>(existing.mem_count, atomic16.mem_count);
|
||||
existing.select_16_or_0_at_runtime |= atomic16.select_16_or_0_at_runtime;
|
||||
existing.ls_write |= atomic16->ls_write;
|
||||
existing.ls_invalid |= atomic16->ls_invalid;
|
||||
existing.ls_access |= atomic16->ls_access;
|
||||
existing.mem_count = std::max<u32>(existing.mem_count, atomic16->mem_count);
|
||||
existing.select_16_or_0_at_runtime |= atomic16->select_16_or_0_at_runtime;
|
||||
}
|
||||
|
||||
atomic16.discard();
|
||||
atomic16->discard();
|
||||
}
|
||||
else if (!atomic16.get_rdatomic)
|
||||
else if (!atomic16->get_rdatomic)
|
||||
{
|
||||
atomic16.get_rdatomic = true;
|
||||
atomic16->get_rdatomic = true;
|
||||
|
||||
// Go above and beyond and also set the constant for it
|
||||
set_const_value(op.rt, MFC_GETLLAR_SUCCESS);
|
||||
@@ -6244,34 +6244,34 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
if (is_read)
|
||||
{
|
||||
break_putllc16(28, atomic16.discard());
|
||||
break_putllc16(28, atomic16->discard());
|
||||
}
|
||||
else
|
||||
{
|
||||
break_putllc16(29, atomic16.discard());
|
||||
break_putllc16(29, atomic16->discard());
|
||||
}
|
||||
|
||||
if (!is_pattern_match || is_read)
|
||||
{
|
||||
//
|
||||
}
|
||||
else if (!rchcnt_loop.active && it == rchcnt_loop_all.end())
|
||||
else if (!rchcnt_loop->active && it == rchcnt_loop_all.end())
|
||||
{
|
||||
rchcnt_loop.read_pc = pos;
|
||||
rchcnt_loop.channel = op.ra;
|
||||
rchcnt_loop.active = true;
|
||||
rchcnt_loop->read_pc = pos;
|
||||
rchcnt_loop->channel = op.ra;
|
||||
rchcnt_loop->active = true;
|
||||
unconst(op.rt, pos);
|
||||
rchcnt_loop.ch_state = vregs[op.rt];
|
||||
rchcnt_loop->ch_state = vregs[op.rt];
|
||||
invalidate = false;
|
||||
}
|
||||
else if (rchcnt_loop.active)
|
||||
else if (rchcnt_loop->active)
|
||||
{
|
||||
// Success
|
||||
rchcnt_loop.active = false;
|
||||
rchcnt_loop->active = false;
|
||||
|
||||
if (it == rchcnt_loop_all.end())
|
||||
{
|
||||
rchcnt_loop_all.emplace(pos, rchcnt_loop);
|
||||
rchcnt_loop_all.emplace(pos, *rchcnt_loop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6295,20 +6295,20 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const bool is_store = type == spu_itype::STQR;
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
atomic16.mem_count++;
|
||||
atomic16->mem_count++;
|
||||
|
||||
// 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);
|
||||
|
||||
if (atomic16.lsa.is_const() && [&]()
|
||||
if (atomic16->lsa.is_const() && [&]()
|
||||
{
|
||||
bool hack = false;
|
||||
|
||||
if (offs % 16 == 0 && (pos - result.lower_bound + op.si16 * 4) == offs)
|
||||
{
|
||||
const u32 reservation_bound = (atomic16.lsa.value | 127);
|
||||
const u32 reservation_bound = (atomic16->lsa.value | 127);
|
||||
const u32 min_offs = offs;
|
||||
|
||||
// Hack: assume there is no overflow in relative instruction offset
|
||||
@@ -6325,37 +6325,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
// Ignore memory access in this case
|
||||
}
|
||||
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));
|
||||
}
|
||||
else if (atomic16.ls_access && atomic16.ls != start_program_count)
|
||||
else if (atomic16->ls_access && atomic16->ls != start_program_count)
|
||||
{
|
||||
break_putllc16(7, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(7, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else if (atomic16.ls_access && offs != atomic16.ls_offs)
|
||||
else if (atomic16->ls_access && offs != atomic16->ls_offs)
|
||||
{
|
||||
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
{
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16->ls_write |= is_store;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(8, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(8, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = start_program_count;
|
||||
atomic16.ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16.ls_pc_rel = true;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = start_program_count;
|
||||
atomic16->ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16->ls_pc_rel = true;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
|
||||
// atomic16.ls_reg[offs % 128 / 16] = start_program_count;
|
||||
// atomic16.ls_offs[offs % 128 / 16] = offs;
|
||||
// atomic16->ls_reg[offs % 128 / 16] = start_program_count;
|
||||
// atomic16->ls_offs[offs % 128 / 16] = offs;
|
||||
}
|
||||
|
||||
if (is_store)
|
||||
@@ -6373,9 +6373,9 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const bool is_store = type == spu_itype::STQX;
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
atomic16.mem_count++;
|
||||
atomic16->mem_count++;
|
||||
|
||||
auto ra = get_reg(op.ra);
|
||||
ra.value &= SPU_LS_MASK_1;
|
||||
@@ -6393,37 +6393,37 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
add_res.value &= SPU_LS_MASK_16;
|
||||
add_res.tag = umax;
|
||||
|
||||
if (atomic16.lsa.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128))
|
||||
if (atomic16->lsa.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128))
|
||||
{
|
||||
// Unrelated, ignore
|
||||
}
|
||||
else if (atomic16.ls_invalid && is_store)
|
||||
else if (atomic16->ls_invalid && is_store)
|
||||
{
|
||||
break_putllc16(20, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(20, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else if (atomic16.ls_access && add_res != atomic16.ls)
|
||||
else if (atomic16->ls_access && add_res != atomic16->ls)
|
||||
{
|
||||
if (atomic16.ls.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
|
||||
if (atomic16->ls.unequal_with_mask_indifference(add_res, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
|
||||
{
|
||||
// Ok
|
||||
}
|
||||
else if (atomic16.ls_pc_rel)
|
||||
else if (atomic16->ls_pc_rel)
|
||||
{
|
||||
break_putllc16(8, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(8, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(9, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(9, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = reg_state_t::from_value(add_res.value);
|
||||
atomic16.ls_offs = reg_state_t::from_value(0);
|
||||
atomic16.ls_pc_rel = false;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = reg_state_t::from_value(add_res.value);
|
||||
atomic16->ls_offs = reg_state_t::from_value(0);
|
||||
atomic16->ls_pc_rel = false;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -6431,7 +6431,7 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
case 1:
|
||||
{
|
||||
const auto& state = ra.is_const() ? rb : ra;
|
||||
const auto& _lsa = atomic16.lsa;
|
||||
const auto& _lsa = atomic16->lsa;
|
||||
const u32 offs = (ra.is_const() ? ra.value : rb.value) & SPU_LS_MASK_1;
|
||||
const u32 abs_diff = calculate_absolute_ls_difference(offs, 0);
|
||||
|
||||
@@ -6443,82 +6443,82 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
// We already know it's an unrelated load/store
|
||||
// The reason for SPU_LS_SIZE - 128 check is that in case LSA is not aligned, it detects the possible wraparound
|
||||
}
|
||||
else if (atomic16.ls_invalid && is_store)
|
||||
else if (atomic16->ls_invalid && is_store)
|
||||
{
|
||||
break_putllc16(23, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(23, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else if (atomic16.ls_access && atomic16.ls != state)
|
||||
else if (atomic16->ls_access && atomic16->ls != state)
|
||||
{
|
||||
if (atomic16.ls.unequal_with_mask_indifference(state, SPU_LS_MASK_128) && offs == 0)
|
||||
if (atomic16->ls.unequal_with_mask_indifference(state, SPU_LS_MASK_128) && offs == 0)
|
||||
{
|
||||
// Ok
|
||||
}
|
||||
else if (atomic16.ls_pc_rel)
|
||||
else if (atomic16->ls_pc_rel)
|
||||
{
|
||||
break_putllc16(36, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(36, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(11, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(11, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else if (atomic16.ls_access)
|
||||
else if (atomic16->ls_access)
|
||||
{
|
||||
ensure(!atomic16.ls.is_const());
|
||||
ensure(!atomic16->ls.is_const());
|
||||
|
||||
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
{
|
||||
// Ok
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16->ls_write |= is_store;
|
||||
}
|
||||
else if (atomic16.ls_offs.is_const() && atomic16.ls_offs.value / 16 == offs / 16 && state.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16.ls_offs.value % 16))
|
||||
else if (atomic16->ls_offs.is_const() && atomic16->ls_offs.value / 16 == offs / 16 && state.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16->ls_offs.value % 16))
|
||||
{
|
||||
// For special case observed in games (offset cannot cause the address to roll over the next 16 bytes)
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16->ls_write |= is_store;
|
||||
}
|
||||
else
|
||||
{
|
||||
break_putllc16(12, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(12, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = state;
|
||||
atomic16.ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16.ls_pc_rel = false;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = state;
|
||||
atomic16->ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16->ls_pc_rel = false;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
const bool is_ra_first = atomic16.ls_access ? ra == atomic16.ls : op.ra <= op.rb;
|
||||
const bool is_ra_first = atomic16->ls_access ? ra == atomic16->ls : op.ra <= op.rb;
|
||||
|
||||
const auto& state1 = is_ra_first ? ra : rb;
|
||||
const auto& state2 = is_ra_first ? rb : ra;
|
||||
|
||||
if (atomic16.ls_access && (atomic16.ls != state1 || atomic16.ls_offs != state2))
|
||||
if (atomic16->ls_access && (atomic16->ls != state1 || atomic16->ls_offs != state2))
|
||||
{
|
||||
if (atomic16.ls_pc_rel)
|
||||
if (atomic16->ls_pc_rel)
|
||||
{
|
||||
break_putllc16(32, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(32, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(13, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(13, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = state1;
|
||||
atomic16.ls_offs = state2;
|
||||
atomic16.ls_pc_rel = false;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = state1;
|
||||
atomic16->ls_offs = state2;
|
||||
atomic16->ls_pc_rel = false;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -6541,43 +6541,43 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const bool is_store = type == spu_itype::STQA;
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
atomic16.mem_count++;
|
||||
atomic16->mem_count++;
|
||||
|
||||
const reg_state_t ca = reg_state_t::from_value(spu_ls_target(0, op.i16));
|
||||
|
||||
if (atomic16.lsa.unequal_with_mask_indifference(ca, SPU_LS_MASK_128))
|
||||
if (atomic16->lsa.unequal_with_mask_indifference(ca, SPU_LS_MASK_128))
|
||||
{
|
||||
// We already know it's an unrelated load/store
|
||||
}
|
||||
else if (atomic16.ls_invalid && is_store)
|
||||
else if (atomic16->ls_invalid && is_store)
|
||||
{
|
||||
break_putllc16(37, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(37, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else if (atomic16.ls_access && ca != atomic16.ls)
|
||||
else if (atomic16->ls_access && ca != atomic16->ls)
|
||||
{
|
||||
if (atomic16.ls.unequal_with_mask_indifference(ca, SPU_LS_MASK_128) && atomic16.ls_offs == 0)
|
||||
if (atomic16->ls.unequal_with_mask_indifference(ca, SPU_LS_MASK_128) && atomic16->ls_offs == 0)
|
||||
{
|
||||
// Ok
|
||||
}
|
||||
else if (atomic16.ls_pc_rel)
|
||||
else if (atomic16->ls_pc_rel)
|
||||
{
|
||||
break_putllc16(14, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(14, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(15, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(15, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = ca;
|
||||
atomic16.ls_offs = reg_state_t::from_value(0);
|
||||
atomic16.ls_pc_rel = false;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = ca;
|
||||
atomic16->ls_offs = reg_state_t::from_value(0);
|
||||
atomic16->ls_pc_rel = false;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6596,12 +6596,12 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
{
|
||||
const bool is_store = type == spu_itype::STQD;
|
||||
|
||||
if (atomic16.active)
|
||||
if (atomic16->active)
|
||||
{
|
||||
atomic16.mem_count++;
|
||||
atomic16->mem_count++;
|
||||
|
||||
auto ra = get_reg(op.ra);
|
||||
const auto& _lsa = atomic16.lsa;
|
||||
const auto& _lsa = atomic16->lsa;
|
||||
|
||||
ra.value = ra.is_const() ? spu_ls_target(ra.value, op.si10 * 4) : 0;
|
||||
const u32 offs = ra.is_const() ? 0 : spu_ls_target(0, op.si10 * 4);
|
||||
@@ -6615,49 +6615,49 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
// We already know it's an unrelated load/store
|
||||
// The reason for SPU_LS_SIZE - 128 check is that in case LSA is not aligned, it detects the possible wraparound
|
||||
}
|
||||
else if (atomic16.ls_invalid && is_store)
|
||||
else if (atomic16->ls_invalid && is_store)
|
||||
{
|
||||
break_putllc16(34, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(34, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else if (atomic16.ls_access && atomic16.ls != ra)
|
||||
else if (atomic16->ls_access && atomic16->ls != ra)
|
||||
{
|
||||
if (atomic16.ls.unequal_with_mask_indifference(ra, SPU_LS_MASK_128) && (offs == 0 && atomic16.ls_offs == 0))
|
||||
if (atomic16->ls.unequal_with_mask_indifference(ra, SPU_LS_MASK_128) && (offs == 0 && atomic16->ls_offs == 0))
|
||||
{
|
||||
// Ok
|
||||
}
|
||||
else if (atomic16.ls_pc_rel)
|
||||
else if (atomic16->ls_pc_rel)
|
||||
{
|
||||
break_putllc16(16, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(16, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Sad
|
||||
break_putllc16(17, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(17, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else if (atomic16.ls_access)
|
||||
else if (atomic16->ls_access)
|
||||
{
|
||||
if (atomic16.ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
if (atomic16->ls_offs.compare_with_mask_indifference(offs, SPU_LS_MASK_1))
|
||||
{
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16->ls_write |= is_store;
|
||||
}
|
||||
else if (atomic16.ls_offs.is_const() && atomic16.ls_offs.value / 16 == offs / 16 && ra.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16.ls_offs.value % 16))
|
||||
else if (atomic16->ls_offs.is_const() && atomic16->ls_offs.value / 16 == offs / 16 && ra.get_known_zeroes() % 16 >= std::max<u32>(offs % 16, atomic16->ls_offs.value % 16))
|
||||
{
|
||||
// For special case observed in games (offset cannot cause the address to roll over the next 16 bytes)
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16->ls_write |= is_store;
|
||||
}
|
||||
else
|
||||
{
|
||||
break_putllc16(18, atomic16.set_invalid_ls(is_store));
|
||||
break_putllc16(18, atomic16->set_invalid_ls(is_store));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
atomic16.ls = ra;
|
||||
atomic16.ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16.ls_pc_rel = false;
|
||||
atomic16.ls_write |= is_store;
|
||||
atomic16.ls_access = true;
|
||||
atomic16->ls = ra;
|
||||
atomic16->ls_offs = reg_state_t::from_value(offs);
|
||||
atomic16->ls_pc_rel = false;
|
||||
atomic16->ls_write |= is_store;
|
||||
atomic16->ls_access = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6947,18 +6947,18 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
inherit_const_value(op.rt, ra, ra, av == op.si10 + 0u, pos);
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
if (ra.is_instruction && ra.origin == rchcnt_loop.ch_state.origin)
|
||||
if (ra.is_instruction && ra.origin == rchcnt_loop->ch_state.origin)
|
||||
{
|
||||
if (op.si10 != 0 && op.si10 != 1)
|
||||
{
|
||||
break_channel_pattern(55, rchcnt_loop.discard());
|
||||
break_channel_pattern(55, rchcnt_loop->discard());
|
||||
break;
|
||||
}
|
||||
|
||||
rchcnt_loop.ch_product = vregs[op.rt];
|
||||
rchcnt_loop.product_test_negate = op.si10 == 1;
|
||||
rchcnt_loop->ch_product = vregs[op.rt];
|
||||
rchcnt_loop->product_test_negate = op.si10 == 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7030,11 +7030,11 @@ spu_program spu_recompiler_base::analyse(const be_t<u32>* ls, u32 entry_point, s
|
||||
|
||||
unconst(op_rt, reg_pos == SPU_LS_SIZE ? pos : reg_pos);
|
||||
|
||||
if (rchcnt_loop.active)
|
||||
if (rchcnt_loop->active)
|
||||
{
|
||||
if (rchcnt_loop.origins.find_first_of(vregs[op_rt].origin) == umax)
|
||||
if (rchcnt_loop->origins.find_first_of(vregs[op_rt].origin) == umax)
|
||||
{
|
||||
rchcnt_loop.origins.push_back(vregs[op_rt].origin);
|
||||
rchcnt_loop->origins.push_back(vregs[op_rt].origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +124,6 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
|
||||
// Global LUTs
|
||||
llvm::GlobalVariable* m_spu_frest_fraction_lut{};
|
||||
llvm::GlobalVariable* m_spu_frest_exponent_lut{};
|
||||
llvm::GlobalVariable* m_spu_frsqest_fraction_lut{};
|
||||
llvm::GlobalVariable* m_spu_frsqest_exponent_lut{};
|
||||
|
||||
@@ -544,9 +543,7 @@ class spu_llvm_recompiler : public spu_recompiler_base, public cpu_translator
|
||||
template <typename T = u8>
|
||||
llvm::Value* _ptr(llvm::Value* base, llvm::Value* offset)
|
||||
{
|
||||
const auto off = m_ir->CreateGEP(get_type<u8>(), base, offset);
|
||||
const auto ptr = m_ir->CreateBitCast(off, get_type<T*>());
|
||||
return ptr;
|
||||
return m_ir->CreateGEP(get_type<u8>(), base, offset);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
@@ -1507,7 +1504,6 @@ public:
|
||||
{
|
||||
// LUTs for some instructions
|
||||
m_spu_frest_fraction_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 32), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frest_fraction_lut));
|
||||
m_spu_frest_exponent_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 256), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frest_exponent_lut));
|
||||
m_spu_frsqest_fraction_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 64), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frsqest_fraction_lut));
|
||||
m_spu_frsqest_exponent_lut = new llvm::GlobalVariable(*m_module, llvm::ArrayType::get(GetType<u32>(), 256), true, llvm::GlobalValue::PrivateLinkage, llvm::ConstantDataArray::get(m_context, spu_frsqest_exponent_lut));
|
||||
}
|
||||
@@ -6040,23 +6036,22 @@ public:
|
||||
const auto a = bitcast<u32[4]>(value<f32[4]>(ci->getOperand(0)));
|
||||
|
||||
const auto a_fraction = (a >> splat<u32[4]>(18)) & splat<u32[4]>(0x1F);
|
||||
const auto a_exponent = (a >> splat<u32[4]>(23)) & splat<u32[4]>(0xFF);
|
||||
const auto a_exponent = (a & splat<u32[4]>(0x7F800000u));
|
||||
const auto r_exponent = sub_sat(build<u16[8]>(0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80), bitcast<u16[8]>(a_exponent));
|
||||
const auto fix_exponent = select((a_exponent > 0), bitcast<u32[4]>(r_exponent), splat<u32[4]>(0x7F800000u));
|
||||
const auto a_sign = (a & splat<u32[4]>(0x80000000));
|
||||
value_t<u32[4]> final_result = eval(splat<u32[4]>(0));
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
const auto eval_fraction = eval(extract(a_fraction, i));
|
||||
const auto eval_exponent = eval(extract(a_exponent, i));
|
||||
const auto eval_sign = eval(extract(a_sign, i));
|
||||
|
||||
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
|
||||
value_t<u32> r_exponent = load_const<u32>(m_spu_frest_exponent_lut, eval_exponent);
|
||||
|
||||
final_result = eval(insert(final_result, i, eval(r_fraction | eval_sign | r_exponent)));
|
||||
final_result = eval(insert(final_result, i, r_fraction));
|
||||
}
|
||||
|
||||
return bitcast<f32[4]>(final_result);
|
||||
return bitcast<f32[4]>(bitcast<u32[4]>(final_result | bitcast<u32[4]>(fix_exponent) | a_sign));
|
||||
});
|
||||
|
||||
set_vr(op.rt, frest(get_vr<f32[4]>(op.ra)));
|
||||
@@ -6704,24 +6699,39 @@ public:
|
||||
}
|
||||
});
|
||||
|
||||
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
|
||||
if (m_use_avx512)
|
||||
{
|
||||
const auto div = value<f32[4]>(ci->getOperand(0));
|
||||
const auto the_one = value<f32[4]>(ci->getOperand(1));
|
||||
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
|
||||
{
|
||||
const auto div = value<f32[4]>(ci->getOperand(0));
|
||||
const auto the_one = value<f32[4]>(ci->getOperand(1));
|
||||
|
||||
const auto div_result = the_one / div;
|
||||
const auto div_result = the_one / div;
|
||||
|
||||
// from ps3 hardware testing: Inf => NaN and NaN => Zero
|
||||
const auto result_and = bitcast<u32[4]>(div_result) & 0x7fffffffu;
|
||||
const auto result_cmp_inf = sext<s32[4]>(result_and == splat<u32[4]>(0x7F800000u));
|
||||
const auto result_cmp_nan = sext<s32[4]>(result_and <= splat<u32[4]>(0x7F800000u));
|
||||
return vfixupimmps(bitcast<f32[4]>(splat<u32[4]>(0xFFFFFFFFu)), div_result, splat<u32[4]>(0x11001188u), 0, 0xff);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
register_intrinsic("spu_re_acc", [&](llvm::CallInst* ci)
|
||||
{
|
||||
const auto div = value<f32[4]>(ci->getOperand(0));
|
||||
const auto the_one = value<f32[4]>(ci->getOperand(1));
|
||||
|
||||
const auto and_mask = bitcast<u32[4]>(result_cmp_nan) & splat<u32[4]>(0xFFFFFFFFu);
|
||||
const auto or_mask = bitcast<u32[4]>(result_cmp_inf) & splat<u32[4]>(0xFFFFFFFu);
|
||||
const auto div_result = the_one / div;
|
||||
|
||||
return bitcast<f32[4]>((bitcast<u32[4]>(div_result) & and_mask) | or_mask);
|
||||
});
|
||||
// from ps3 hardware testing: Inf => NaN and NaN => Zero
|
||||
const auto result_and = bitcast<u32[4]>(div_result) & 0x7fffffffu;
|
||||
const auto result_cmp_inf = sext<s32[4]>(result_and == splat<u32[4]>(0x7F800000u));
|
||||
const auto result_cmp_nan = sext<s32[4]>(result_and <= splat<u32[4]>(0x7F800000u));
|
||||
|
||||
const auto and_mask = bitcast<u32[4]>(result_cmp_nan) & splat<u32[4]>(0xFFFFFFFFu);
|
||||
const auto or_mask = bitcast<u32[4]>(result_cmp_inf) & splat<u32[4]>(0xFFFFFFFu);
|
||||
return bitcast<f32[4]>((bitcast<u32[4]>(div_result) & and_mask) | or_mask);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const auto [a, b, c] = get_vrs<f32[4]>(op.ra, op.rb, op.rc);
|
||||
static const auto MT = match<f32[4]>();
|
||||
|
||||
@@ -7004,20 +7014,23 @@ public:
|
||||
{
|
||||
const auto a = bitcast<u32[4]>(value<f32[4]>(ci->getOperand(0)));
|
||||
const auto a_fraction = (a >> splat<u32[4]>(18)) & splat<u32[4]>(0x1F);
|
||||
const auto a_exponent = (a >> splat<u32[4]>(23)) & splat<u32[4]>(0xFF);
|
||||
const auto a_exponent = (a & splat<u32[4]>(0x7F800000u));
|
||||
const auto r_exponent = sub_sat(build<u16[8]>(0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80, 0000, 0x7E80), bitcast<u16[8]>(a_exponent));
|
||||
const auto fix_exponent = select((a_exponent > 0), bitcast<u32[4]>(r_exponent), splat<u32[4]>(0x7F800000u));
|
||||
const auto a_sign = (a & splat<u32[4]>(0x80000000));
|
||||
value_t<u32[4]> b = eval(splat<u32[4]>(0));
|
||||
|
||||
for (u32 i = 0; i < 4; i++)
|
||||
{
|
||||
const auto eval_fraction = eval(extract(a_fraction, i));
|
||||
const auto eval_exponent = eval(extract(a_exponent, i));
|
||||
const auto eval_sign = eval(extract(a_sign, i));
|
||||
|
||||
value_t<u32> r_fraction = load_const<u32>(m_spu_frest_fraction_lut, eval_fraction);
|
||||
value_t<u32> r_exponent = load_const<u32>(m_spu_frest_exponent_lut, eval_exponent);
|
||||
b = eval(insert(b, i, eval(r_fraction | eval_sign | r_exponent)));
|
||||
|
||||
b = eval(insert(b, i, r_fraction));
|
||||
}
|
||||
|
||||
b = eval(b | fix_exponent | a_sign);
|
||||
|
||||
const auto base = (b & 0x007ffc00u) << 9; // Base fraction
|
||||
const auto ymul = (b & 0x3ff) * (a & 0x7ffff); // Step fraction * Y fraction (fixed point at 2^-32)
|
||||
const auto comparison = (ymul > base); // Should exponent be adjusted?
|
||||
|
||||
@@ -1673,6 +1673,12 @@ void spu_thread::cpu_init()
|
||||
status_npc.raw() = {get_type() == spu_type::isolated ? SPU_STATUS_IS_ISOLATED : 0, 0};
|
||||
run_ctrl.raw() = 0;
|
||||
|
||||
spurs_last_task_timestamp = 0;
|
||||
spurs_wait_duration_last = 0;
|
||||
spurs_average_task_duration = 0;
|
||||
spurs_waited = false;
|
||||
spurs_entered_wait = false;
|
||||
|
||||
int_ctrl[0].clear();
|
||||
int_ctrl[1].clear();
|
||||
int_ctrl[2].clear();
|
||||
@@ -1823,17 +1829,28 @@ void spu_thread::cpu_task()
|
||||
return fmt::format("%sSPU[0x%07x] Thread (%s) [0x%05x]", type >= spu_type::raw ? type == spu_type::isolated ? "Iso" : "Raw" : "", cpu->lv2_id, *name_cache.get(), cpu->pc);
|
||||
};
|
||||
|
||||
if (!spurs_addr)
|
||||
constexpr u32 invalid_spurs = 0u - 0x80;
|
||||
|
||||
if (spurs_addr == 0)
|
||||
{
|
||||
// Evaluate it
|
||||
if (!group)
|
||||
{
|
||||
spurs_addr = -0x80; // Some invalid non-0 address
|
||||
spurs_addr = invalid_spurs; // Some invalid non-0 address
|
||||
}
|
||||
else
|
||||
{
|
||||
const u32 arg = static_cast<u32>(group->args[index][1]);
|
||||
spurs_addr = group->name.ends_with("CellSpursKernelGroup"sv) && vm::check_addr(arg) ? arg : 0u - 0x80;
|
||||
|
||||
if (group->name.ends_with("CellSpursKernelGroup"sv) && vm::check_addr(arg))
|
||||
{
|
||||
spurs_addr = arg;
|
||||
group->spurs_running++;
|
||||
}
|
||||
else
|
||||
{
|
||||
spurs_addr = invalid_spurs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1884,6 +1901,14 @@ void spu_thread::cpu_task()
|
||||
|
||||
allow_interrupts_in_cpu_work = false;
|
||||
}
|
||||
|
||||
if (spurs_addr != invalid_spurs)
|
||||
{
|
||||
if (group->spurs_running.exchange(0))
|
||||
{
|
||||
group->spurs_running.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void spu_thread::cpu_work()
|
||||
@@ -4765,7 +4790,7 @@ bool spu_thread::process_mfc_cmd()
|
||||
getllar_spin_count = 0;
|
||||
getllar_busy_waiting_switch = umax;
|
||||
|
||||
u64 ntime;
|
||||
u64 ntime = 0;
|
||||
rsx::reservation_lock rsx_lock(addr, 128);
|
||||
|
||||
for (u64 i = 0; i != umax; [&]()
|
||||
@@ -4871,9 +4896,163 @@ bool spu_thread::process_mfc_cmd()
|
||||
// Avoid logging useless commands if there is no reservation
|
||||
const bool dump = g_cfg.core.mfc_debug && raddr;
|
||||
|
||||
const bool is_spurs_task_wait = pc == 0x11e4 && spurs_addr != 0u - 0x80u;
|
||||
|
||||
if (!is_spurs_task_wait || spurs_addr != raddr || spurs_waited)
|
||||
{
|
||||
//
|
||||
}
|
||||
else if ((_ref<u8>(0x100 + 0x73) & (1u << index)) == 0 && (static_cast<u8>(rdata[0x73]) & (1u << index)) != 0)
|
||||
{
|
||||
// Wait for other threads to complete their tasks (temporarily)
|
||||
u32 max_run = group->max_run;
|
||||
|
||||
auto [prev_running, ok] = spurs_entered_wait ? std::make_pair(+group->spurs_running, false) :
|
||||
group->spurs_running.fetch_op([max_run, num = group->max_num](u32& x)
|
||||
{
|
||||
if (x >= max_run && max_run < num)
|
||||
{
|
||||
x--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
if (ok || spurs_entered_wait)
|
||||
{
|
||||
lv2_obj::prepare_for_sleep(*this);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
if (prev_running == max_run)
|
||||
{
|
||||
group->spurs_running.notify_one();
|
||||
|
||||
if (group->spurs_running == max_run - 1)
|
||||
{
|
||||
// Try to let another thread slip in and take over execution
|
||||
thread_ctrl::wait_for(300);
|
||||
|
||||
// Update value
|
||||
prev_running = group->spurs_running + 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Restore state
|
||||
prev_running--;
|
||||
}
|
||||
|
||||
const u64 before = get_system_time();
|
||||
u64 current = before;
|
||||
|
||||
spurs_waited = true;
|
||||
spurs_entered_wait = true;
|
||||
|
||||
// Wait the duration of one and a half tasks
|
||||
const u64 spurs_wait_time = std::clamp<u64>(spurs_average_task_duration / spurs_task_count_to_calculate * 3 / 2, 10'000, 100'000);
|
||||
spurs_wait_duration_last = spurs_wait_time;
|
||||
|
||||
if (spurs_last_task_timestamp)
|
||||
{
|
||||
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
|
||||
spurs_average_task_duration -= avg_entry;
|
||||
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
|
||||
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
|
||||
spurs_last_task_timestamp = 0;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (is_stopped() || current - before >= spurs_wait_time)
|
||||
{
|
||||
// Timed-out
|
||||
group->spurs_running++;
|
||||
break;
|
||||
}
|
||||
|
||||
if (prev_running >= max_run)
|
||||
{
|
||||
thread_ctrl::wait_on(group->spurs_running, prev_running, spurs_wait_time - (current - before));
|
||||
}
|
||||
|
||||
max_run = group->max_run;
|
||||
|
||||
prev_running = group->spurs_running.fetch_op([max_run](u32& x)
|
||||
{
|
||||
if (x < max_run)
|
||||
{
|
||||
x++;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}).first;
|
||||
|
||||
if (prev_running < max_run)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
current = get_system_time();
|
||||
}
|
||||
|
||||
state += cpu_flag::temp;
|
||||
static_cast<void>(test_stopped());
|
||||
}
|
||||
}
|
||||
|
||||
if (do_putllc(ch_mfc_cmd))
|
||||
{
|
||||
ch_atomic_stat.set_value(MFC_PUTLLC_SUCCESS);
|
||||
|
||||
if (is_spurs_task_wait)
|
||||
{
|
||||
const bool is_idle = (_ref<u8>(0x100 + 0x73) & (1u << index)) != 0;
|
||||
const bool was_idle = (static_cast<u8>(rdata[0x73]) & (1u << index)) != 0;
|
||||
|
||||
if (!was_idle && is_idle)
|
||||
{
|
||||
const u32 prev_running = group->spurs_running.fetch_op([](u32& x)
|
||||
{
|
||||
if (x)
|
||||
{
|
||||
x--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}).first;
|
||||
|
||||
if (prev_running)
|
||||
{
|
||||
spurs_entered_wait = true;
|
||||
}
|
||||
|
||||
if (prev_running == group->max_run && prev_running < group->max_num)
|
||||
{
|
||||
group->spurs_running.notify_one();
|
||||
}
|
||||
}
|
||||
else if (was_idle && !is_idle)
|
||||
{
|
||||
// Cleanup
|
||||
const u64 current = get_system_time();
|
||||
|
||||
if (spurs_last_task_timestamp)
|
||||
{
|
||||
const u64 avg_entry = spurs_average_task_duration / spurs_task_count_to_calculate;
|
||||
spurs_average_task_duration -= avg_entry;
|
||||
spurs_average_task_duration += std::min<u64>(45'000, current - spurs_last_task_timestamp);
|
||||
spu_log.trace("duration: %d, avg=%d", current - spurs_last_task_timestamp, spurs_average_task_duration / spurs_task_count_to_calculate);
|
||||
spurs_last_task_timestamp = 0;
|
||||
}
|
||||
|
||||
spurs_last_task_timestamp = current;
|
||||
spurs_waited = false;
|
||||
spurs_entered_wait = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5391,6 +5570,8 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
|
||||
thread_ctrl::wait_on(state, old);
|
||||
}
|
||||
|
||||
fmt::throw_exception("Unreachable"); // Fix unannotated fallthrough warning
|
||||
}
|
||||
|
||||
case MFC_RdTagStat:
|
||||
@@ -5490,7 +5671,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
const u32 old_raddr = raddr;
|
||||
|
||||
// Does not need to safe-access reservation if LR is the only event masked
|
||||
// Because it's either an access violation or a livelock if an invalid memory is passed
|
||||
// Because it's either an access violation or a live-lock if an invalid memory is passed
|
||||
if (raddr && mask1 > SPU_EVENT_LR)
|
||||
{
|
||||
auto area = vm::get(vm::any, raddr);
|
||||
@@ -5504,7 +5685,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
}
|
||||
else if (area)
|
||||
{
|
||||
// Ensure possesion over reservation memory so it won't be deallocated
|
||||
// Ensure possession over reservation memory so it won't be de-allocated
|
||||
auto [base_addr, shm_] = area->peek(raddr);
|
||||
|
||||
if (shm_)
|
||||
@@ -5571,6 +5752,24 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
|
||||
if (raddr && (mask1 & ~SPU_EVENT_TM) == SPU_EVENT_LR)
|
||||
{
|
||||
if (u32 max_threads = std::min<u32>(g_cfg.core.max_spurs_threads, group ? group->max_num : u32{umax}); group && group->max_run != max_threads)
|
||||
{
|
||||
constexpr std::string_view spurs_suffix = "CellSpursKernelGroup"sv;
|
||||
|
||||
if (group->name.ends_with(spurs_suffix) && !group->name.substr(0, group->name.size() - spurs_suffix.size()).ends_with("_libsail"))
|
||||
{
|
||||
// Hack: don't run more SPURS threads than specified.
|
||||
if (u32 old = atomic_storage<u32>::exchange(group->max_run, max_threads); old > max_threads)
|
||||
{
|
||||
spu_log.success("HACK: '%s' (0x%x) limited to %u threads.", group->name, group->id, max_threads);
|
||||
}
|
||||
else if (u32 running = group->spurs_running; old < max_threads && running >= old && running < max_threads)
|
||||
{
|
||||
group->spurs_running.notify_all();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Don't busy-wait with TSX - memory is sensitive
|
||||
if (g_use_rtm || !reservation_busy_waiting)
|
||||
{
|
||||
@@ -5616,7 +5815,7 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
static thread_local bool s_tls_try_notify = false;
|
||||
s_tls_try_notify = false;
|
||||
|
||||
atomic_wait_engine::set_one_time_use_wait_callback(mask1 != SPU_EVENT_LR ? nullptr : +[](u64 attempts) -> bool
|
||||
const auto wait_cb = mask1 != SPU_EVENT_LR ? nullptr : +[](u64 attempts) -> bool
|
||||
{
|
||||
const auto _this = static_cast<spu_thread*>(cpu_thread::get_current());
|
||||
AUDIT(_this->get_class() == thread_class::spu);
|
||||
@@ -5665,10 +5864,11 @@ s64 spu_thread::get_ch_value(u32 ch)
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
if (auto wait_var = vm::reservation_notifier_begin_wait(_raddr, rtime))
|
||||
{
|
||||
atomic_wait_engine::set_one_time_use_wait_callback(wait_cb);
|
||||
utils::bless<atomic_t<u32>>(&wait_var->raw().wait_flag)->wait(1, atomic_wait_timeout{80'000});
|
||||
vm::reservation_notifier_end_wait(*wait_var);
|
||||
}
|
||||
|
||||
+24
-18
@@ -188,10 +188,10 @@ struct spu_channel_op_state
|
||||
struct alignas(16) spu_channel
|
||||
{
|
||||
// Low 32 bits contain value
|
||||
atomic_t<u64> data;
|
||||
atomic_t<u64> data{};
|
||||
|
||||
// Pending value to be inserted when it is possible in pop() or pop_wait()
|
||||
atomic_t<u64> jostling_value;
|
||||
atomic_t<u64> jostling_value{};
|
||||
|
||||
public:
|
||||
static constexpr u32 off_wait = 32;
|
||||
@@ -667,11 +667,11 @@ public:
|
||||
u8* reserv_base_addr = vm::g_reservations;
|
||||
|
||||
// General-Purpose Registers
|
||||
std::array<v128, 128> gpr;
|
||||
SPU_FPSCR fpscr;
|
||||
std::array<v128, 128> gpr{};
|
||||
SPU_FPSCR fpscr{};
|
||||
|
||||
// MFC command data
|
||||
spu_mfc_cmd ch_mfc_cmd;
|
||||
spu_mfc_cmd ch_mfc_cmd{};
|
||||
|
||||
// MFC command queue
|
||||
spu_mfc_cmd mfc_queue[16]{};
|
||||
@@ -683,9 +683,9 @@ public:
|
||||
u64 mfc_last_timestamp = 0;
|
||||
|
||||
// MFC proxy command data
|
||||
spu_mfc_cmd mfc_prxy_cmd;
|
||||
spu_mfc_cmd mfc_prxy_cmd{};
|
||||
shared_mutex mfc_prxy_mtx;
|
||||
atomic_t<u32> mfc_prxy_mask;
|
||||
atomic_t<u32> mfc_prxy_mask = 0;
|
||||
|
||||
// Tracks writes to MFC proxy command data
|
||||
union
|
||||
@@ -707,11 +707,11 @@ public:
|
||||
// Range Lock pointer
|
||||
atomic_t<u64, 64>* range_lock{};
|
||||
|
||||
u32 srr0;
|
||||
u32 ch_tag_upd;
|
||||
u32 ch_tag_mask;
|
||||
u32 srr0 = 0;
|
||||
u32 ch_tag_upd = 0;
|
||||
u32 ch_tag_mask = 0;
|
||||
spu_channel ch_tag_stat;
|
||||
u32 ch_stall_mask;
|
||||
u32 ch_stall_mask = 0;
|
||||
spu_channel ch_stall_stat;
|
||||
spu_channel ch_atomic_stat;
|
||||
|
||||
@@ -736,14 +736,14 @@ public:
|
||||
};
|
||||
|
||||
atomic_t<ch_events_t> ch_events;
|
||||
bool interrupts_enabled;
|
||||
bool interrupts_enabled = false;
|
||||
|
||||
u64 ch_dec_start_timestamp; // timestamp of writing decrementer value
|
||||
u32 ch_dec_value; // written decrementer value
|
||||
u64 ch_dec_start_timestamp = 0; // timestamp of writing decrementer value
|
||||
u32 ch_dec_value = 0; // written decrementer value
|
||||
bool is_dec_frozen = false;
|
||||
std::pair<u32, u32> read_dec() const; // Read decrementer
|
||||
|
||||
atomic_t<u32> run_ctrl; // SPU Run Control register (only provided to get latest data written)
|
||||
atomic_t<u32> run_ctrl = 0; // SPU Run Control register (only provided to get latest data written)
|
||||
shared_mutex run_ctrl_mtx;
|
||||
|
||||
struct alignas(8) status_npc_sync_var
|
||||
@@ -752,10 +752,10 @@ public:
|
||||
u32 npc; // SPU Next Program Counter register
|
||||
};
|
||||
|
||||
atomic_t<status_npc_sync_var> status_npc;
|
||||
std::array<spu_int_ctrl_t, 3> int_ctrl; // SPU Class 0, 1, 2 Interrupt Management
|
||||
atomic_t<status_npc_sync_var> status_npc{};
|
||||
std::array<spu_int_ctrl_t, 3> int_ctrl{}; // SPU Class 0, 1, 2 Interrupt Management
|
||||
|
||||
std::array<std::pair<u32, std::shared_ptr<lv2_event_queue>>, 32> spuq; // Event Queue Keys for SPU Thread
|
||||
std::array<std::pair<u32, std::shared_ptr<lv2_event_queue>>, 32> spuq{}; // Event Queue Keys for SPU Thread
|
||||
std::shared_ptr<lv2_event_queue> spup[64]; // SPU Ports
|
||||
spu_channel exit_status{}; // Threaded SPU exit status (not a channel, but the interface fits)
|
||||
atomic_t<u32> last_exit_status; // Value to be written in exit_status after checking group termination
|
||||
@@ -767,6 +767,12 @@ public:
|
||||
const u32 option; // sys_spu_thread_initialize option
|
||||
const u32 lv2_id; // The actual id that is used by syscalls
|
||||
u32 spurs_addr = 0;
|
||||
bool spurs_waited = false;
|
||||
bool spurs_entered_wait = false;
|
||||
u64 spurs_wait_duration_last = 0;
|
||||
u64 spurs_average_task_duration = 0;
|
||||
u64 spurs_last_task_timestamp = 0;
|
||||
static constexpr u64 spurs_task_count_to_calculate = 10;
|
||||
|
||||
spu_thread* next_cpu{}; // LV2 thread queues' node link
|
||||
|
||||
|
||||
@@ -119,8 +119,13 @@ std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
|
||||
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
|
||||
|
||||
CellError lv2_event_queue::send(lv2_event event)
|
||||
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
|
||||
{
|
||||
if (notified_thread)
|
||||
{
|
||||
*notified_thread = false;
|
||||
}
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!exists)
|
||||
@@ -162,6 +167,15 @@ CellError lv2_event_queue::send(lv2_event event)
|
||||
std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = event;
|
||||
|
||||
awake(&ppu);
|
||||
|
||||
if (port && ppu.prio.load().prio < ensure(cpu_thread::get_current<ppu_thread>())->prio.load().prio)
|
||||
{
|
||||
// Block event port disconnection for the time being of sending events
|
||||
// PPU -> lower prio PPU is the only case that can cause thread blocking
|
||||
port->is_busy++;
|
||||
ensure(notified_thread);
|
||||
*notified_thread = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -709,7 +723,10 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
|
||||
return CELL_ENOTCONN;
|
||||
}
|
||||
|
||||
// TODO: return CELL_EBUSY if necessary (can't detect the condition)
|
||||
if (port->is_busy)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
port->queue.reset();
|
||||
|
||||
@@ -718,20 +735,32 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
|
||||
|
||||
error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
if (auto cpu = get_current_cpu_thread())
|
||||
const auto cpu = cpu_thread::get_current();
|
||||
const auto ppu = cpu ? cpu->try_get<ppu_thread>() : nullptr;
|
||||
|
||||
if (cpu)
|
||||
{
|
||||
cpu->state += cpu_flag::wait;
|
||||
}
|
||||
|
||||
sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
|
||||
|
||||
bool notified_thread = false;
|
||||
|
||||
const auto port = idm::check<lv2_obj, lv2_event_port>(eport_id, [&, notify = lv2_obj::notify_all_t()](lv2_event_port& port) -> CellError
|
||||
{
|
||||
if (ppu && ppu->loaded_from_savestate)
|
||||
{
|
||||
port.is_busy++;
|
||||
notified_thread = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (lv2_obj::check(port.queue))
|
||||
{
|
||||
const u64 source = port.name ? port.name : (u64{process_getpid() + 0u} << 32) | u64{eport_id};
|
||||
|
||||
return port.queue->send(source, data1, data2, data3);
|
||||
return port.queue->send(source, data1, data2, data3, ¬ified_thread, ppu && port.queue->type == SYS_PPU_QUEUE ? &port : nullptr);
|
||||
}
|
||||
|
||||
return CELL_ENOTCONN;
|
||||
@@ -742,6 +771,19 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (ppu && notified_thread)
|
||||
{
|
||||
// Wait to be requeued
|
||||
if (ppu->test_stopped())
|
||||
{
|
||||
// Wait again on savestate load
|
||||
ppu->state += cpu_flag::again;
|
||||
}
|
||||
|
||||
port->is_busy--;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (port.ret)
|
||||
{
|
||||
if (port.ret == CELL_EAGAIN)
|
||||
|
||||
@@ -79,6 +79,8 @@ struct sys_event_t
|
||||
// Source, data1, data2, data3
|
||||
using lv2_event = std::tuple<u64, u64, u64, u64>;
|
||||
|
||||
struct lv2_event_port;
|
||||
|
||||
struct lv2_event_queue final : public lv2_obj
|
||||
{
|
||||
static const u32 id_base = 0x8d000000;
|
||||
@@ -103,11 +105,11 @@ struct lv2_event_queue final : public lv2_obj
|
||||
static void save_ptr(utils::serial&, lv2_event_queue*);
|
||||
static std::shared_ptr<lv2_event_queue> load_ptr(utils::serial& ar, std::shared_ptr<lv2_event_queue>& queue, std::string_view msg = {});
|
||||
|
||||
CellError send(lv2_event event);
|
||||
CellError send(lv2_event event, bool* notified_thread = nullptr, lv2_event_port* port = nullptr);
|
||||
|
||||
CellError send(u64 source, u64 d1, u64 d2, u64 d3)
|
||||
CellError send(u64 source, u64 d1, u64 d2, u64 d3, bool* notified_thread = nullptr, lv2_event_port* port = nullptr)
|
||||
{
|
||||
return send(std::make_tuple(source, d1, d2, d3));
|
||||
return send(std::make_tuple(source, d1, d2, d3), notified_thread, port);
|
||||
}
|
||||
|
||||
// Get event queue by its global key
|
||||
@@ -121,6 +123,7 @@ struct lv2_event_port final : lv2_obj
|
||||
const s32 type; // Port type, either IPC or local
|
||||
const u64 name; // Event source (generated from id and process id if not set)
|
||||
|
||||
atomic_t<usz> is_busy = 0; // Counts threads waiting on event sending
|
||||
std::shared_ptr<lv2_event_queue> queue; // Event queue this port is connected to
|
||||
|
||||
lv2_event_port(s32 type, u64 name)
|
||||
|
||||
@@ -357,16 +357,14 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
|
||||
}
|
||||
}
|
||||
|
||||
// Process all waiters in single atomic op
|
||||
const u32 count = flag->pattern.atomic_op([&](u64& value)
|
||||
{
|
||||
value |= bitptn;
|
||||
u32 count = 0;
|
||||
u32 count = 0;
|
||||
|
||||
if (!flag->sq)
|
||||
{
|
||||
return count;
|
||||
}
|
||||
// Process all waiters in single atomic op
|
||||
for (u64 pattern = flag->pattern, to_write = pattern, dependant_mask = 0;; to_write = pattern, dependant_mask = 0)
|
||||
{
|
||||
count = 0;
|
||||
to_write |= bitptn;
|
||||
dependant_mask = 0;
|
||||
|
||||
for (auto ppu = +flag->sq; ppu; ppu = ppu->next_cpu)
|
||||
{
|
||||
@@ -405,10 +403,20 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
|
||||
const u64 pattern = ppu.gpr[4];
|
||||
const u64 mode = ppu.gpr[5];
|
||||
|
||||
if (lv2_event_flag::check_pattern(value, pattern, mode, &ppu.gpr[6]))
|
||||
// If it's OR mode, set bits must have waken up the thread therefore no
|
||||
// dependency on old value
|
||||
const u64 dependant_mask_or = ((mode & 0xf) == SYS_EVENT_FLAG_WAIT_OR || (bitptn & pattern & to_write) == pattern ? 0 : pattern);
|
||||
|
||||
if (lv2_event_flag::check_pattern(to_write, pattern, mode, &ppu.gpr[6]))
|
||||
{
|
||||
dependant_mask |= dependant_mask_or;
|
||||
ppu.gpr[3] = CELL_OK;
|
||||
count++;
|
||||
|
||||
if (!to_write)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -416,8 +424,29 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
});
|
||||
dependant_mask &= ~bitptn;
|
||||
|
||||
auto [new_val, ok] = flag->pattern.fetch_op([&](u64& x)
|
||||
{
|
||||
if ((x ^ pattern) & dependant_mask)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
x |= bitptn;
|
||||
|
||||
// Clear the bit-wise difference
|
||||
x &= ~((pattern | bitptn) & ~to_write);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (ok)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
pattern = new_val;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
|
||||
@@ -93,7 +93,7 @@ std::shared_ptr<vm::block_t> reserve_map(u32 alloc_size, u32 align)
|
||||
|
||||
// Todo: fix order of error checks
|
||||
|
||||
error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32> alloc_addr)
|
||||
error_code sys_memory_allocate(cpu_thread& cpu, u64 size, u64 flags, vm::ptr<u32> alloc_addr)
|
||||
{
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
@@ -129,9 +129,9 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
|
||||
return {CELL_ENOMEM, dct.size - dct.used};
|
||||
}
|
||||
|
||||
if (const auto area = reserve_map(size, align))
|
||||
if (const auto area = reserve_map(static_cast<u32>(size), align))
|
||||
{
|
||||
if (const u32 addr = area->alloc(size, nullptr, align))
|
||||
if (const u32 addr = area->alloc(static_cast<u32>(size), nullptr, align))
|
||||
{
|
||||
ensure(!g_fxo->get<sys_memory_address_table>().addrs[addr >> 16].exchange(&dct));
|
||||
|
||||
@@ -139,7 +139,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
|
||||
{
|
||||
sys_memory.notice("sys_memory_allocate(): Allocated 0x%x address (size=0x%x)", addr, size);
|
||||
|
||||
vm::lock_sudo(addr, size);
|
||||
vm::lock_sudo(addr, static_cast<u32>(size));
|
||||
cpu.check_state();
|
||||
*alloc_addr = addr;
|
||||
return CELL_OK;
|
||||
@@ -155,7 +155,7 @@ error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 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)
|
||||
{
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
@@ -203,15 +203,15 @@ error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid
|
||||
return {ct.ret, ct->size - ct->used};
|
||||
}
|
||||
|
||||
if (const auto area = reserve_map(size, align))
|
||||
if (const auto area = reserve_map(static_cast<u32>(size), align))
|
||||
{
|
||||
if (const u32 addr = area->alloc(size))
|
||||
if (const u32 addr = area->alloc(static_cast<u32>(size)))
|
||||
{
|
||||
ensure(!g_fxo->get<sys_memory_address_table>().addrs[addr >> 16].exchange(ct.ptr.get()));
|
||||
|
||||
if (alloc_addr)
|
||||
{
|
||||
vm::lock_sudo(addr, size);
|
||||
vm::lock_sudo(addr, static_cast<u32>(size));
|
||||
cpu.check_state();
|
||||
*alloc_addr = addr;
|
||||
return CELL_OK;
|
||||
@@ -320,7 +320,7 @@ error_code sys_memory_get_user_memory_stat(cpu_thread& cpu, vm::ptr<sys_memory_u
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 size)
|
||||
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size)
|
||||
{
|
||||
cpu.state += cpu_flag::wait;
|
||||
|
||||
@@ -345,7 +345,7 @@ error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u32 si
|
||||
}
|
||||
|
||||
// Create the memory container
|
||||
if (const u32 id = idm::make<lv2_memory_container>(size, true))
|
||||
if (const u32 id = idm::make<lv2_memory_container>(static_cast<u32>(size), true))
|
||||
{
|
||||
cpu.check_state();
|
||||
*cid = id;
|
||||
|
||||
@@ -128,13 +128,13 @@ struct sys_memory_user_memory_stat_t
|
||||
};
|
||||
|
||||
// SysCalls
|
||||
error_code sys_memory_allocate(cpu_thread& cpu, u32 size, u64 flags, vm::ptr<u32> alloc_addr);
|
||||
error_code sys_memory_allocate_from_container(cpu_thread& cpu, u32 size, u32 cid, 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_free(cpu_thread& cpu, u32 start_addr);
|
||||
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_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, u32 size);
|
||||
error_code sys_memory_container_create(cpu_thread& cpu, vm::ptr<u32> cid, u64 size);
|
||||
error_code sys_memory_container_destroy(cpu_thread& cpu, u32 cid);
|
||||
error_code sys_memory_container_get_size(cpu_thread& cpu, vm::ptr<sys_memory_info_t> mem_info, u32 cid);
|
||||
error_code sys_memory_container_destroy_parent_with_childs(cpu_thread& cpu, u32 cid, u32 must_0, vm::ptr<u32> mc_child);
|
||||
|
||||
@@ -47,7 +47,7 @@ extern const std::map<std::string_view, int> g_prx_list
|
||||
{ "libat3multidec.sprx", 0 },
|
||||
{ "libatrac3multi.sprx", 0 },
|
||||
{ "libatrac3plus.sprx", 0 },
|
||||
{ "libatxdec.sprx", 0 },
|
||||
{ "libatxdec.sprx", 1 },
|
||||
{ "libatxdec2.sprx", 0 },
|
||||
{ "libaudio.sprx", 1 },
|
||||
{ "libavcdec.sprx", 0 },
|
||||
|
||||
@@ -562,20 +562,48 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
||||
|
||||
sys_spu.warning("sys_spu_thread_initialize(thread=*0x%x, group=0x%x, spu_num=%d, img=*0x%x, attr=*0x%x, arg=*0x%x)", thread, group_id, spu_num, img, attr, arg);
|
||||
|
||||
const u32 option = attr->option;
|
||||
|
||||
if (attr->name_len > 0x80 || option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE))
|
||||
if (spu_num >= std::size(decltype(lv2_spu_group::threads_map){}))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
sys_spu_image image;
|
||||
if (!attr)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
switch (img->type)
|
||||
const sys_spu_thread_attribute attr_data = *attr;
|
||||
|
||||
if (attr_data.name_len > 0x80)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!arg)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
const sys_spu_thread_argument args = *arg;
|
||||
const u32 option = attr_data.option;
|
||||
|
||||
if (option & ~(SYS_SPU_THREAD_OPTION_DEC_SYNC_TB_ENABLE | SYS_SPU_THREAD_OPTION_ASYNC_INTR_ENABLE))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (!img)
|
||||
{
|
||||
return CELL_EFAULT;
|
||||
}
|
||||
|
||||
sys_spu_image image = *img;
|
||||
|
||||
switch (image.type)
|
||||
{
|
||||
case SYS_SPU_IMAGE_TYPE_KERNEL:
|
||||
{
|
||||
const auto handle = idm::get<lv2_obj, lv2_spu_image>(img->entry_point);
|
||||
const auto handle = idm::get<lv2_obj, lv2_spu_image>(image.entry_point);
|
||||
|
||||
if (!handle)
|
||||
{
|
||||
@@ -591,12 +619,11 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
||||
}
|
||||
case SYS_SPU_IMAGE_TYPE_USER:
|
||||
{
|
||||
if (img->entry_point > 0x3fffc || img->nsegs <= 0 || img->nsegs > 0x20)
|
||||
if (image.entry_point > 0x3fffc || image.nsegs <= 0 || image.nsegs > 0x20)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
image = *img;
|
||||
break;
|
||||
}
|
||||
default: return CELL_EINVAL;
|
||||
@@ -672,7 +699,7 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
||||
}
|
||||
|
||||
// Read thread name
|
||||
const std::string thread_name(attr->name.get_ptr(), std::max<u32>(attr->name_len, 1) - 1);
|
||||
const std::string thread_name(attr_data.name.get_ptr(), std::max<u32>(attr_data.name_len, 1) - 1);
|
||||
|
||||
const auto group = idm::get<lv2_spu_group>(group_id);
|
||||
|
||||
@@ -681,11 +708,6 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (spu_num >= group->threads_map.size())
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::unique_lock lock(group->mutex);
|
||||
|
||||
if (auto state = +group->run_state; state != SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED)
|
||||
@@ -725,23 +747,12 @@ error_code sys_spu_thread_initialize(ppu_thread& ppu, vm::ptr<u32> thread, u32 g
|
||||
ensure(vm::get(vm::spu)->falloc(spu->vm_offset(), SPU_LS_SIZE, &spu->shm, static_cast<u64>(vm::page_size_64k) | static_cast<u64>(vm::alloc_hidden)));
|
||||
spu->map_ls(*spu->shm, spu->ls);
|
||||
|
||||
group->args[inited] = {arg->arg1, arg->arg2, arg->arg3, arg->arg4};
|
||||
group->args[inited] = {args.arg1, args.arg2, args.arg3, args.arg4};
|
||||
group->imgs[inited].first = image.entry_point;
|
||||
group->imgs[inited].second = std::move(spu_segs);
|
||||
|
||||
if (++group->init == group->max_num)
|
||||
{
|
||||
if (g_cfg.core.max_spurs_threads < 6 && group->max_num > 0u + g_cfg.core.max_spurs_threads)
|
||||
{
|
||||
if (group->name.ends_with("CellSpursKernelGroup"))
|
||||
{
|
||||
// Hack: don't run more SPURS threads than specified.
|
||||
group->max_run = g_cfg.core.max_spurs_threads;
|
||||
|
||||
spu_log.success("HACK: '%s' (0x%x) limited to %u threads.", group->name, group_id, +g_cfg.core.max_spurs_threads);
|
||||
}
|
||||
}
|
||||
|
||||
const auto old = group->run_state.compare_and_swap(SPU_THREAD_GROUP_STATUS_NOT_INITIALIZED, SPU_THREAD_GROUP_STATUS_INITIALIZED);
|
||||
|
||||
if (old == SPU_THREAD_GROUP_STATUS_DESTROYED)
|
||||
@@ -811,12 +822,14 @@ 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;
|
||||
|
||||
if (attr->nsize > 0x80 || !num)
|
||||
const sys_spu_thread_group_attribute attr_data = *attr;
|
||||
|
||||
if (attr_data.nsize > 0x80 || !num)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const s32 type = attr->type;
|
||||
const s32 type = attr_data.type;
|
||||
|
||||
bool use_scheduler = true;
|
||||
bool use_memct = !!(type & SYS_SPU_THREAD_GROUP_TYPE_MEMORY_FROM_CONTAINER);
|
||||
@@ -913,7 +926,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
||||
|
||||
if (use_memct && mem_size)
|
||||
{
|
||||
const auto sct = idm::get<lv2_memory_container>(attr->ct);
|
||||
const auto sct = idm::get<lv2_memory_container>(attr_data.ct);
|
||||
|
||||
if (!sct)
|
||||
{
|
||||
@@ -947,7 +960,7 @@ error_code sys_spu_thread_group_create(ppu_thread& ppu, vm::ptr<u32> id, u32 num
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
const auto group = idm::make_ptr<lv2_spu_group>(std::string(attr->name.get_ptr(), std::max<u32>(attr->nsize, 1) - 1), 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)
|
||||
{
|
||||
@@ -1057,7 +1070,7 @@ error_code sys_spu_thread_group_start(ppu_thread& ppu, u32 id)
|
||||
default: return CELL_ESTAT;
|
||||
}
|
||||
|
||||
const u32 max_threads = group->max_run;
|
||||
const u32 max_threads = group->max_num;
|
||||
|
||||
group->join_state = 0;
|
||||
group->exit_status = 0;
|
||||
@@ -1818,6 +1831,11 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val
|
||||
|
||||
sys_spu.trace("sys_spu_thread_write_snr(id=0x%x, number=%d, value=0x%x)", id, number, value);
|
||||
|
||||
if (number > 1)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto [thread, group] = lv2_spu_group::get_thread(id);
|
||||
|
||||
if (!thread) [[unlikely]]
|
||||
@@ -1825,11 +1843,6 @@ error_code sys_spu_thread_write_snr(ppu_thread& ppu, u32 id, u32 number, u32 val
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (number > 1)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
thread->push_snr(number, value);
|
||||
|
||||
return CELL_OK;
|
||||
@@ -1906,21 +1919,19 @@ error_code sys_spu_thread_group_disconnect_event(ppu_thread& ppu, u32 id, u32 et
|
||||
if (!ep)
|
||||
{
|
||||
sys_spu.error("sys_spu_thread_group_disconnect_event(): unknown event type (%d)", et);
|
||||
return CELL_EINVAL;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// No error checking is performed
|
||||
|
||||
std::lock_guard lock(group->mutex);
|
||||
|
||||
if (!lv2_obj::check(*ep))
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
ep->reset();
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u8 spup)
|
||||
error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et, u32 spup)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
@@ -1954,7 +1965,7 @@ error_code sys_spu_thread_connect_event(ppu_thread& ppu, u32 id, u32 eq, u32 et,
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u8 spup)
|
||||
error_code sys_spu_thread_disconnect_event(ppu_thread& ppu, u32 id, u32 et, u32 spup)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
@@ -2079,6 +2090,11 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
|
||||
|
||||
sys_spu.warning("sys_spu_thread_group_connect_event_all_threads(id=0x%x, eq=0x%x, req=0x%llx, spup=*0x%x)", id, eq, req, spup);
|
||||
|
||||
if (!req)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto group = idm::get<lv2_spu_group>(id);
|
||||
const auto queue = idm::get<lv2_obj, lv2_event_queue>(eq);
|
||||
|
||||
@@ -2087,11 +2103,6 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!req)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::unique_lock lock(group->mutex);
|
||||
|
||||
if (auto state = +group->run_state;
|
||||
@@ -2155,12 +2166,17 @@ error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread& ppu, u32 i
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u8 spup)
|
||||
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u32 id, u32 spup)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_spu.warning("sys_spu_thread_group_disconnect_event_all_threads(id=0x%x, spup=%d)", id, spup);
|
||||
|
||||
if (spup > 63)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
const auto group = idm::get<lv2_spu_group>(id);
|
||||
|
||||
if (!group)
|
||||
@@ -2168,11 +2184,6 @@ error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread& ppu, u3
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (spup > 63)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
std::lock_guard lock(group->mutex);
|
||||
|
||||
for (auto& t : group->threads)
|
||||
|
||||
@@ -289,6 +289,7 @@ struct lv2_spu_group
|
||||
atomic_t<s32> exit_status; // SPU Thread Group Exit Status
|
||||
atomic_t<u32> join_state; // flags used to detect exit cause and signal
|
||||
atomic_t<u32> running = 0; // Number of running threads
|
||||
atomic_t<u32> spurs_running = 0;
|
||||
atomic_t<u32> stop_count = 0;
|
||||
atomic_t<u32> wait_term_count = 0;
|
||||
u32 waiter_spu_index = -1; // Index of SPU executing a waiting syscall
|
||||
@@ -371,7 +372,7 @@ error_code sys_spu_thread_group_get_priority(ppu_thread&, u32 id, vm::ptr<s32> p
|
||||
error_code sys_spu_thread_group_connect_event(ppu_thread&, u32 id, u32 eq, u32 et);
|
||||
error_code sys_spu_thread_group_disconnect_event(ppu_thread&, u32 id, u32 et);
|
||||
error_code sys_spu_thread_group_connect_event_all_threads(ppu_thread&, u32 id, u32 eq_id, u64 req, vm::ptr<u8> spup);
|
||||
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u8 spup);
|
||||
error_code sys_spu_thread_group_disconnect_event_all_threads(ppu_thread&, u32 id, u32 spup);
|
||||
error_code sys_spu_thread_group_set_cooperative_victims(ppu_thread&, u32 id, u32 threads_mask);
|
||||
error_code sys_spu_thread_group_syscall_253(ppu_thread& ppu, u32 id, vm::ptr<sys_spu_thread_group_syscall_253_info> info);
|
||||
error_code sys_spu_thread_group_log(ppu_thread&, s32 command, vm::ptr<s32> stat);
|
||||
@@ -381,8 +382,8 @@ error_code sys_spu_thread_write_spu_mb(ppu_thread&, u32 id, u32 value);
|
||||
error_code sys_spu_thread_set_spu_cfg(ppu_thread&, u32 id, u64 value);
|
||||
error_code sys_spu_thread_get_spu_cfg(ppu_thread&, u32 id, vm::ptr<u64> value);
|
||||
error_code sys_spu_thread_write_snr(ppu_thread&, u32 id, u32 number, u32 value);
|
||||
error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u8 spup);
|
||||
error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u8 spup);
|
||||
error_code sys_spu_thread_connect_event(ppu_thread&, u32 id, u32 eq, u32 et, u32 spup);
|
||||
error_code sys_spu_thread_disconnect_event(ppu_thread&, u32 id, u32 et, u32 spup);
|
||||
error_code sys_spu_thread_bind_queue(ppu_thread&, u32 id, u32 spuq, u32 spuq_num);
|
||||
error_code sys_spu_thread_unbind_queue(ppu_thread&, u32 id, u32 spuq_num);
|
||||
error_code sys_spu_thread_get_exit_status(ppu_thread&, u32 id, vm::ptr<s32> status);
|
||||
|
||||
@@ -156,7 +156,7 @@ error_code sys_ss_random_number_generator(u64 pkg_id, vm::ptr<void> buf, u64 siz
|
||||
|
||||
error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3)
|
||||
{
|
||||
sys_ss.todo("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3);
|
||||
sys_ss.success("sys_ss_access_control_engine(pkg_id=0x%llx, a2=0x%llx, a3=0x%llx)", pkg_id, a2, a3);
|
||||
|
||||
const u64 authid = g_ps3_process_info.self_info.valid ?
|
||||
g_ps3_process_info.self_info.prog_id_hdr.program_authority_id : 0;
|
||||
@@ -167,7 +167,7 @@ error_code sys_ss_access_control_engine(u64 pkg_id, u64 a2, u64 a3)
|
||||
{
|
||||
if (!g_ps3_process_info.debug_or_root())
|
||||
{
|
||||
return CELL_ENOSYS;
|
||||
return not_an_error(CELL_ENOSYS);
|
||||
}
|
||||
|
||||
if (!a2)
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/sysinfo.hpp"
|
||||
|
||||
static u64 timebase_offset;
|
||||
static u64 systemtime_offset;
|
||||
@@ -146,6 +147,18 @@ u64 convert_to_timebased_time(u64 time)
|
||||
|
||||
u64 get_timebased_time()
|
||||
{
|
||||
if (u64 freq = utils::get_tsc_freq())
|
||||
{
|
||||
const u64 tsc = utils::get_tsc();
|
||||
|
||||
#if _MSC_VER
|
||||
const u64 result = static_cast<u64>(u128_from_mul(tsc, g_timebase_freq) / freq) * g_cfg.core.clocks_scale / 100u;
|
||||
#else
|
||||
const u64 result = (tsc / freq * g_timebase_freq + tsc % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u;
|
||||
#endif
|
||||
return result - timebase_offset;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -155,7 +168,11 @@ u64 get_timebased_time()
|
||||
const u64 time = count.QuadPart;
|
||||
const u64 freq = s_time_aux_info.perf_freq;
|
||||
|
||||
#if _MSC_VER
|
||||
const u64 result = static_cast<u64>(u128_from_mul(time * g_cfg.core.clocks_scale, g_timebase_freq) / freq / 100u);
|
||||
#else
|
||||
const u64 result = (time / freq * g_timebase_freq + time % freq * g_timebase_freq / freq) * g_cfg.core.clocks_scale / 100u;
|
||||
#endif
|
||||
#else
|
||||
struct timespec ts;
|
||||
ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
|
||||
@@ -190,6 +207,18 @@ void initialize_timebased_time(u64 timebased_init, bool reset)
|
||||
// Returns some relative time in microseconds, don't change this fact
|
||||
u64 get_system_time()
|
||||
{
|
||||
if (u64 freq = utils::get_tsc_freq())
|
||||
{
|
||||
const u64 tsc = utils::get_tsc();
|
||||
|
||||
#if _MSC_VER
|
||||
const u64 result = static_cast<u64>(u128_from_mul(tsc, 1000000ull) / freq);
|
||||
#else
|
||||
const u64 result = (tsc / freq * 1000000ull + tsc % freq * 1000000ull / freq);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
@@ -199,7 +228,11 @@ u64 get_system_time()
|
||||
const u64 time = count.QuadPart;
|
||||
const u64 freq = s_time_aux_info.perf_freq;
|
||||
|
||||
#if _MSC_VER
|
||||
const u64 result = static_cast<u64>(u128_from_mul(time, 1000000ull) / freq);
|
||||
#else
|
||||
const u64 result = time / freq * 1000000ull + (time % freq) * 1000000ull / freq;
|
||||
#endif
|
||||
#else
|
||||
struct timespec ts;
|
||||
ensure(::clock_gettime(CLOCK_MONOTONIC, &ts) == 0);
|
||||
|
||||
@@ -48,13 +48,18 @@ sys_vm_t::sys_vm_t(utils::serial& ar)
|
||||
g_fxo->get<sys_vm_global_t>().total_vsize += size;
|
||||
}
|
||||
|
||||
error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
|
||||
error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
sys_vm.warning("sys_vm_memory_map(vsize=0x%x, psize=0x%x, cid=0x%x, flags=0x%x, policy=0x%x, addr=*0x%x)", vsize, psize, cid, flag, policy, addr);
|
||||
|
||||
if (!vsize || !psize || vsize % 0x2000000 || vsize > 0x10000000 || psize > 0x10000000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED)
|
||||
if (!vsize || !psize || vsize % 0x200'0000 || vsize > 0x1000'0000 || psize % 0x1'0000 || policy != SYS_VM_POLICY_AUTO_RECOMMENDED)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
|
||||
if (ppu.gpr[11] == 300 && psize < 0x10'0000)
|
||||
{
|
||||
return CELL_EINVAL;
|
||||
}
|
||||
@@ -68,16 +73,16 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
|
||||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (!g_fxo->get<sys_vm_global_t>().total_vsize.fetch_op([vsize](u32& size)
|
||||
if (!g_fxo->get<sys_vm_global_t>().total_vsize.fetch_op([vsize, has_root = g_ps3_process_info.has_root_perm()](u32& size)
|
||||
{
|
||||
// A single process can hold up to 256MB of virtual memory, even on DECR
|
||||
// VSH can hold more
|
||||
if ((g_ps3_process_info.has_root_perm() ? 0x1E000000 : 0x10000000) - size < vsize)
|
||||
if ((has_root ? 0x1E000000 : 0x10000000) - size < vsize)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
size += vsize;
|
||||
size += static_cast<u32>(vsize);
|
||||
return true;
|
||||
}).second)
|
||||
{
|
||||
@@ -86,7 +91,7 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
|
||||
|
||||
if (!ct->take(psize))
|
||||
{
|
||||
g_fxo->get<sys_vm_global_t>().total_vsize -= vsize;
|
||||
g_fxo->get<sys_vm_global_t>().total_vsize -= static_cast<u32>(vsize);
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
@@ -96,10 +101,10 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
|
||||
sys_vm.warning("sys_vm_memory_map(): Found VM 0x%x area (vsize=0x%x)", addr, vsize);
|
||||
|
||||
// Alloc all memory (shall not fail)
|
||||
ensure(area->alloc(vsize));
|
||||
vm::lock_sudo(area->addr, vsize);
|
||||
ensure(area->alloc(static_cast<u32>(vsize)));
|
||||
vm::lock_sudo(area->addr, static_cast<u32>(vsize));
|
||||
|
||||
idm::make<sys_vm_t>(area->addr, vsize, ct, psize);
|
||||
idm::make<sys_vm_t>(area->addr, static_cast<u32>(vsize), ct, static_cast<u32>(psize));
|
||||
|
||||
// Write a pointer for the allocated memory
|
||||
ppu.check_state();
|
||||
@@ -108,11 +113,11 @@ error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64
|
||||
}
|
||||
|
||||
ct->free(psize);
|
||||
g_fxo->get<sys_vm_global_t>().total_vsize -= vsize;
|
||||
g_fxo->get<sys_vm_global_t>().total_vsize -= static_cast<u32>(vsize);
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
|
||||
error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
@@ -153,7 +158,7 @@ error_code sys_vm_unmap(ppu_thread& ppu, u32 addr)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
|
||||
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
@@ -176,7 +181,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
|
||||
return CELL_ENOMEM;
|
||||
}
|
||||
|
||||
vmo.psize += size;
|
||||
vmo.psize += static_cast<u32>(size);
|
||||
return {};
|
||||
});
|
||||
|
||||
@@ -193,7 +198,7 @@ error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size)
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size)
|
||||
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size)
|
||||
{
|
||||
ppu.state += cpu_flag::wait;
|
||||
|
||||
@@ -213,12 +218,12 @@ error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size)
|
||||
|
||||
auto [_, ok] = vmo.psize.fetch_op([&](u32& value)
|
||||
{
|
||||
if (value < 0x100000ull + size)
|
||||
if (value <= size || value - size < 0x100000ull)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value -= size;
|
||||
value -= static_cast<u32>(size);
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
@@ -58,11 +58,11 @@ struct sys_vm_t
|
||||
class ppu_thread;
|
||||
|
||||
// SysCalls
|
||||
error_code sys_vm_memory_map(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
|
||||
error_code sys_vm_memory_map_different(ppu_thread& ppu, u32 vsize, u32 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
|
||||
error_code sys_vm_memory_map(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
|
||||
error_code sys_vm_memory_map_different(ppu_thread& ppu, u64 vsize, u64 psize, u32 cid, u64 flag, u64 policy, vm::ptr<u32> addr);
|
||||
error_code sys_vm_unmap(ppu_thread& ppu, u32 addr);
|
||||
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u32 size);
|
||||
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u32 size);
|
||||
error_code sys_vm_append_memory(ppu_thread& ppu, u32 addr, u64 size);
|
||||
error_code sys_vm_return_memory(ppu_thread& ppu, u32 addr, u64 size);
|
||||
error_code sys_vm_lock(ppu_thread& ppu, u32 addr, u32 size);
|
||||
error_code sys_vm_unlock(ppu_thread& ppu, u32 addr, u32 size);
|
||||
error_code sys_vm_touch(ppu_thread& ppu, u32 addr, u32 size);
|
||||
|
||||
+25
-22
@@ -172,24 +172,28 @@ u16 PadHandlerBase::ConvertAxis(f32 value)
|
||||
// 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 8000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
std::tuple<u16, u16> PadHandlerBase::ConvertToSquirclePoint(u16 inX, u16 inY, u32 squircle_factor)
|
||||
void PadHandlerBase::ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor)
|
||||
{
|
||||
// convert inX and Y to a (-1, 1) vector;
|
||||
const f32 x = (inX - 127.5f) / 127.5f;
|
||||
const f32 y = (inY - 127.5f) / 127.5f;
|
||||
if (!squircle_factor)
|
||||
return;
|
||||
|
||||
// compute angle and len of given point to be used for squircle radius
|
||||
constexpr f32 radius = 127.5f;
|
||||
|
||||
// convert inX and Y to a (-1, 1) vector;
|
||||
const f32 x = (inX - radius) / radius;
|
||||
const f32 y = (inY - radius) / radius;
|
||||
|
||||
// compute angle and len of given point to be used for squircle radius. Clamp to circle, we don't want to exceed the squircle.
|
||||
const f32 angle = std::atan2(y, x);
|
||||
const f32 r = std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f));
|
||||
const f32 distance_to_center = std::min(1.0f, std::sqrt(std::pow(x, 2.f) + std::pow(y, 2.f)));
|
||||
|
||||
// now find len/point on the given squircle from our current angle and radius in polar coords
|
||||
// https://thatsmaths.com/2016/07/14/squircles/
|
||||
const f32 newLen = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * r;
|
||||
const f32 new_len = (1 + std::pow(std::sin(2 * angle), 2.f) / (squircle_factor / 1000.f)) * distance_to_center;
|
||||
|
||||
// we now have len and angle, convert to cartesian
|
||||
const int newX = Clamp0To255(std::round(((newLen * std::cos(angle)) + 1) * 127.5f));
|
||||
const int newY = Clamp0To255(std::round(((newLen * std::sin(angle)) + 1) * 127.5f));
|
||||
return std::tuple<u16, u16>(newX, newY);
|
||||
inX = Clamp0To255(std::round(((new_len * std::cos(angle)) + 1) * radius));
|
||||
inY = Clamp0To255(std::round(((new_len * std::sin(angle)) + 1) * radius));
|
||||
}
|
||||
|
||||
void PadHandlerBase::init_configs()
|
||||
@@ -346,7 +350,6 @@ void PadHandlerBase::get_motion_sensors(const std::string& pad_id, const motion_
|
||||
|
||||
// Get the current motion values
|
||||
std::shared_ptr<Pad> pad = std::make_shared<Pad>(m_type, 0, 0, 0, 0);
|
||||
pad->m_sensors.resize(preview_values.size(), AnalogSensor(0, 0, 0, 0, 0));
|
||||
pad_ensemble binding{pad, device, nullptr};
|
||||
get_extended_info(binding);
|
||||
|
||||
@@ -366,7 +369,7 @@ void PadHandlerBase::convert_stick_values(u16& x_out, u16& y_out, s32 x_in, s32
|
||||
// Apply pad squircling if necessary
|
||||
if (padsquircling != 0)
|
||||
{
|
||||
std::tie(x_out, y_out) = ConvertToSquirclePoint(x_out, y_out, padsquircling);
|
||||
ConvertToSquirclePoint(x_out, y_out, padsquircling);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -501,18 +504,18 @@ bool PadHandlerBase::bindPadToDevice(std::shared_ptr<Pad> pad)
|
||||
pad->m_buttons.emplace_back(CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK, mapping[button::skateboard_tilt_right], CELL_PAD_CTRL_PRESS_R1);
|
||||
}
|
||||
|
||||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]);
|
||||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]);
|
||||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]);
|
||||
pad->m_sticks.emplace_back(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]);
|
||||
pad->m_sticks[0] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X, mapping[button::ls_left], mapping[button::ls_right]);
|
||||
pad->m_sticks[1] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y, mapping[button::ls_down], mapping[button::ls_up]);
|
||||
pad->m_sticks[2] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X, mapping[button::rs_left], mapping[button::rs_right]);
|
||||
pad->m_sticks[3] = AnalogStick(CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y, mapping[button::rs_down], mapping[button::rs_up]);
|
||||
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z);
|
||||
pad->m_sensors.emplace_back(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G);
|
||||
pad->m_sensors[0] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_X, 0, 0, 0, DEFAULT_MOTION_X);
|
||||
pad->m_sensors[1] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Y, 0, 0, 0, DEFAULT_MOTION_Y);
|
||||
pad->m_sensors[2] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_Z, 0, 0, 0, DEFAULT_MOTION_Z);
|
||||
pad->m_sensors[3] = AnalogSensor(CELL_PAD_BTN_OFFSET_SENSOR_G, 0, 0, 0, DEFAULT_MOTION_G);
|
||||
|
||||
pad->m_vibrateMotors.emplace_back(true, 0);
|
||||
pad->m_vibrateMotors.emplace_back(false, 0);
|
||||
pad->m_vibrateMotors[0] = VibrateMotor(true, 0);
|
||||
pad->m_vibrateMotors[1] = VibrateMotor(false, 0);
|
||||
|
||||
m_bindings.emplace_back(pad, pad_device, nullptr);
|
||||
|
||||
|
||||
@@ -245,6 +245,7 @@ protected:
|
||||
|
||||
// get clamped value between 0 and 255
|
||||
static u16 Clamp0To255(f32 input);
|
||||
|
||||
// get clamped value between 0 and 1023
|
||||
static u16 Clamp0To1023(f32 input);
|
||||
|
||||
@@ -255,7 +256,7 @@ protected:
|
||||
// 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 8000
|
||||
// This function assumes inX and inY is already in 0-255
|
||||
static std::tuple<u16, u16> ConvertToSquirclePoint(u16 inX, u16 inY, u32 squircle_factor);
|
||||
static void ConvertToSquirclePoint(u16& inX, u16& inY, u32 squircle_factor);
|
||||
|
||||
public:
|
||||
// u32 thumb_min = 0; // Unused. Make sure all handlers report 0+ values for sticks in get_button_values.
|
||||
|
||||
@@ -81,8 +81,8 @@ struct cfg_pad final : cfg::node
|
||||
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> rtriggerthreshold{ this, "Right Trigger Threshold", 0 };
|
||||
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 0 };
|
||||
cfg::uint<0, 1000000> rpadsquircling{ this, "Right Pad Squircling Factor", 0 };
|
||||
cfg::uint<0, 1000000> lpadsquircling{ this, "Left Pad Squircling Factor", 8000 };
|
||||
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> colorG{ this, "Color Value G", 0 };
|
||||
|
||||
@@ -417,6 +417,7 @@ struct AnalogStick
|
||||
std::map<u32, u16> m_pressed_keys_min{}; // only used in keyboard_pad_handler
|
||||
std::map<u32, u16> m_pressed_keys_max{}; // only used in keyboard_pad_handler
|
||||
|
||||
AnalogStick() {}
|
||||
AnalogStick(u32 offset, std::set<u32> key_codes_min, std::set<u32> key_codes_max)
|
||||
: m_offset(offset)
|
||||
, m_key_codes_min(std::move(key_codes_min))
|
||||
@@ -447,6 +448,7 @@ struct VibrateMotor
|
||||
bool m_is_large_motor = false;
|
||||
u8 m_value = 0;
|
||||
|
||||
VibrateMotor() {}
|
||||
VibrateMotor(bool is_large_motor, u8 value)
|
||||
: m_is_large_motor(is_large_motor)
|
||||
, m_value(value)
|
||||
@@ -489,9 +491,9 @@ struct Pad
|
||||
u8 m_battery_level{0};
|
||||
|
||||
std::vector<Button> m_buttons;
|
||||
std::vector<AnalogStick> m_sticks;
|
||||
std::vector<AnalogSensor> m_sensors;
|
||||
std::vector<VibrateMotor> m_vibrateMotors;
|
||||
std::array<AnalogStick, 4> m_sticks{};
|
||||
std::array<AnalogSensor, 4> m_sensors{};
|
||||
std::array<VibrateMotor, 2> m_vibrateMotors{};
|
||||
|
||||
// These hold bits for their respective buttons
|
||||
u16 m_digital_1{0};
|
||||
|
||||
+43
-8
@@ -945,7 +945,7 @@ namespace vm
|
||||
return true;
|
||||
}
|
||||
|
||||
static u32 _page_unmap(u32 addr, u32 max_size, u64 bflags, utils::shm* shm)
|
||||
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;
|
||||
|
||||
@@ -1009,7 +1009,7 @@ namespace vm
|
||||
// the RSX might try to call VirtualProtect on memory that is already unmapped
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
rsxthr->on_notify_memory_unmapped(addr, size);
|
||||
rsxthr->on_notify_pre_memory_unmapped(addr, size, unmap_events);
|
||||
}
|
||||
|
||||
// Deregister PPU related data
|
||||
@@ -1309,7 +1309,7 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
bool block_t::unmap()
|
||||
bool block_t::unmap(std::vector<std::pair<u64, u64>>* unmapped)
|
||||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
|
||||
@@ -1320,7 +1320,10 @@ namespace vm
|
||||
{
|
||||
const auto next = std::next(it);
|
||||
const auto size = it->second.first;
|
||||
_page_unmap(it->first, size, this->flags, it->second.second.get());
|
||||
|
||||
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));
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
||||
@@ -1480,6 +1483,22 @@ namespace vm
|
||||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
{
|
||||
struct notify_t
|
||||
{
|
||||
std::vector<std::pair<u64, u64>> event_data;
|
||||
|
||||
~notify_t() noexcept
|
||||
{
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
for (const auto [event_data1, event_data2] : event_data)
|
||||
{
|
||||
rsxthr->on_notify_post_memory_unmapped(event_data1, event_data2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} unmap_notification;
|
||||
|
||||
vm::writer_lock lock;
|
||||
|
||||
const auto found = m_map.find(addr - (flags & stack_guarded ? 0x1000 : 0));
|
||||
@@ -1505,7 +1524,7 @@ namespace vm
|
||||
}
|
||||
|
||||
// Unmap "real" memory pages
|
||||
ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get()));
|
||||
ensure(size == _page_unmap(addr, size, this->flags, found->second.second.get(), unmap_notification.event_data));
|
||||
|
||||
// Clear stack guards
|
||||
if (flags & stack_guarded)
|
||||
@@ -1815,9 +1834,9 @@ namespace vm
|
||||
}
|
||||
}
|
||||
|
||||
bool _unmap_block(const std::shared_ptr<block_t>& block)
|
||||
bool _unmap_block(const std::shared_ptr<block_t>& block, std::vector<std::pair<u64, u64>>* unmapped = nullptr)
|
||||
{
|
||||
return block->unmap();
|
||||
return block->unmap(unmapped);
|
||||
}
|
||||
|
||||
static bool _test_map(u32 addr, u32 size)
|
||||
@@ -1964,6 +1983,22 @@ namespace vm
|
||||
|
||||
std::pair<std::shared_ptr<block_t>, bool> result{};
|
||||
|
||||
struct notify_t
|
||||
{
|
||||
std::vector<std::pair<u64, u64>> unmap_data;
|
||||
|
||||
~notify_t() noexcept
|
||||
{
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
for (const auto [event_data1, event_data2] : unmap_data)
|
||||
{
|
||||
rsxthr->on_notify_post_memory_unmapped(event_data1, event_data2);
|
||||
}
|
||||
}
|
||||
}
|
||||
} unmap_notifications;
|
||||
|
||||
vm::writer_lock lock;
|
||||
|
||||
for (auto it = g_locations.begin() + memory_location_max; it != g_locations.end(); it++)
|
||||
@@ -1993,7 +2028,7 @@ namespace vm
|
||||
|
||||
result.first = std::move(*it);
|
||||
g_locations.erase(it);
|
||||
ensure(_unmap_block(result.first));
|
||||
ensure(_unmap_block(result.first, &unmap_notifications.unmap_data));
|
||||
result.second = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user