From e65755d68de345d14f8a4c0e8a71cfc63248fe7e Mon Sep 17 00:00:00 2001 From: schm1dtmac Date: Sat, 3 Jan 2026 00:53:39 +0000 Subject: [PATCH 1/6] Unify & optimise Mac build script --- .ci/build-mac-arm64.sh | 121 ----------------------------------------- .ci/build-mac.sh | 116 ++++++++++++++++++++------------------- 2 files changed, 59 insertions(+), 178 deletions(-) delete mode 100755 .ci/build-mac-arm64.sh diff --git a/.ci/build-mac-arm64.sh b/.ci/build-mac-arm64.sh deleted file mode 100755 index 043e421d80..0000000000 --- a/.ci/build-mac-arm64.sh +++ /dev/null @@ -1,121 +0,0 @@ -#!/bin/sh -ex - -# shellcheck disable=SC2086 -export HOMEBREW_NO_AUTO_UPDATE=1 -export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 -export HOMEBREW_NO_ENV_HINTS=1 -export HOMEBREW_NO_INSTALL_CLEANUP=1 - -brew install -f --overwrite --quiet googletest opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader -brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative - -brew link -f --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5 - -# moltenvk based on commit for 1.4.0 release -export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae -wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb -/opt/homebrew/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb -export HOMEBREW_DEVELOPER=0 - -export CXX=clang++ -export CC=clang - -export BREW_PATH; -BREW_PATH="$(brew --prefix)" -export BREW_BIN="/opt/homebrew/bin" -export BREW_SBIN="/opt/homebrew/sbin" -export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64' - -export WORKDIR; -WORKDIR="$(pwd)" - -# Setup ccache -if [ ! -d "$CCACHE_DIR" ]; then - mkdir -p "$CCACHE_DIR" -fi - -# 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 - sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader - sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader - cd "/tmp/Qt" - pip3 install py7zr requests semantic_version lxml --no-cache --break-system-packages - mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64" - sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" - python3 "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats -o "$QT_VER/clang_64" -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 SDL3_DIR="$BREW_PATH/opt/sdl3/lib/cmake/SDL3" - -export PATH="$BREW_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_PATH/lib $BREW_PATH/opt/ffmpeg@5/lib/libavcodec.dylib $BREW_PATH/opt/ffmpeg@5/lib/libavformat.dylib $BREW_PATH/opt/ffmpeg@5/lib/libavutil.dylib $BREW_PATH/opt/ffmpeg@5/lib/libswscale.dylib $BREW_PATH/opt/ffmpeg@5/lib/libswresample.dylib $BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++.1.dylib $BREW_PATH/lib/libSDL3.dylib $BREW_PATH/lib/libGLEW.dylib $BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib -Wl,-rpath,$BREW_PATH/lib" -export CPPFLAGS="-I$BREW_PATH/include -D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" -export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" -export LIBRARY_PATH="$BREW_PATH/lib" -export LD_LIBRARY_PATH="$BREW_PATH/lib" - -export VULKAN_SDK -VULKAN_SDK="$BREW_PATH/opt/molten-vk" -ln -s "$BREW_PATH/opt/vulkan-loader/lib/libvulkan.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" || true - -export LLVM_DIR -LLVM_DIR="$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER" -# exclude ffmpeg, LLVM, opencv, and sdl from submodule update -# shellcheck disable=SC2046 -git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/opencv/ && !/SDL/ && !/feralinteractive/ { print $3 }' .gitmodules) - -mkdir build && cd build || exit 1 - -export MACOSX_DEPLOYMENT_TARGET=14.4 - -"$BREW_PATH/bin/cmake" .. \ - -DBUILD_RPCS3_TESTS="${RUN_UNIT_TESTS}" \ - -DRUN_RPCS3_TESTS="${RUN_UNIT_TESTS}" \ - -DUSE_SDL=ON \ - -DUSE_DISCORD_RPC=ON \ - -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 \ - -DUSE_SYSTEM_OPENCV=ON \ - "$CMAKE_EXTRA_OPTS" \ - -DLLVM_TARGET_ARCH=arm64 \ - -DCMAKE_OSX_ARCHITECTURES=arm64 \ - -DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \ - -DCMAKE_IGNORE_PREFIX_PATH=/opt/homebrew/opt \ - -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" \ - -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ - -DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \ - -G Ninja - -"$BREW_PATH/bin/ninja"; build_status=$?; - -cd .. - -# If it compiled succesfully let's deploy. -if [ "$build_status" -eq 0 ]; then - .ci/deploy-mac-arm64.sh -fi diff --git a/.ci/build-mac.sh b/.ci/build-mac.sh index e391e3e575..7c62fdc631 100755 --- a/.ci/build-mac.sh +++ b/.ci/build-mac.sh @@ -1,36 +1,43 @@ #!/bin/sh -ex -# shellcheck disable=SC2086 export HOMEBREW_NO_AUTO_UPDATE=1 export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 export HOMEBREW_NO_ENV_HINTS=1 export HOMEBREW_NO_INSTALL_CLEANUP=1 - brew install -f --overwrite --quiet ccache "llvm@$LLVM_COMPILER_VER" brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" -# shellcheck disable=SC3009 -arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" -arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet python@3.14 opencv@4 ffmpeg@5 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader -arch -x86_64 /usr/local/bin/brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative -arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" ffmpeg@5 +if [ "$AARCH64" -eq 1 ]; then + brew install -f --overwrite --quiet googletest opencv@4 sdl3 vulkan-headers vulkan-loader molten-vk + brew unlink --quiet ffmpeg fmt qtbase qtsvg qtdeclarative +else + arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + arch -x86_64 /usr/local/bin/brew install -f --overwrite --quiet python@3.14 opencv@4 "llvm@$LLVM_COMPILER_VER" sdl3 vulkan-headers vulkan-loader molten-vk + arch -x86_64 /usr/local/bin/brew unlink --quiet ffmpeg qtbase qtsvg qtdeclarative + arch -x86_64 /usr/local/bin/brew link -f --overwrite --quiet "llvm@$LLVM_COMPILER_VER" +fi -# moltenvk based on commit for 1.4.0 release -export HOMEBREW_DEVELOPER=1 # Prevents blocking of local formulae -wget https://raw.githubusercontent.com/Homebrew/homebrew-core/ea2bec5f1f4384e188d7fc0702ab21a20a2ced08/Formula/m/molten-vk.rb -arch -x86_64 /usr/local/bin/brew install -f --overwrite --formula --quiet ./molten-vk.rb -export HOMEBREW_DEVELOPER=0 export CXX=clang++ export CC=clang -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=X86' +export BREW_PATH; +if [ "$AARCH64" -eq 1 ]; then + BREW_PATH="$(brew --prefix)" + export BREW_BIN="/opt/homebrew/bin" + export BREW_SBIN="/opt/homebrew/sbin" +else + BREW_PATH="$("/usr/local/bin/brew" --prefix)" + export BREW_BIN="/usr/local/bin" + export BREW_SBIN="/usr/local/sbin" +fi export WORKDIR; WORKDIR="$(pwd)" +# Setup ccache +if [ ! -d "$CCACHE_DIR" ]; then + mkdir -p "$CCACHE_DIR" +fi + # Get Qt if [ ! -d "/tmp/Qt/$QT_VER" ]; then mkdir -p "/tmp/Qt" @@ -50,68 +57,63 @@ 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 SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3" +export SDL3_DIR="$BREW_PATH/opt/sdl3/lib/cmake/SDL3" -export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH" -# shellcheck disable=SC2155 -export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib,-L$(brew --prefix llvm)/lib/c++" -export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" -export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" -export LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib" -export LD_LIBRARY_PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib:$BREW_X64_PATH/lib" +export PATH="/opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/bin:$PATH" +export LDFLAGS="-L$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++ -L$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/unwind -lunwind" export VULKAN_SDK -VULKAN_SDK="$BREW_X64_PATH/opt/molten-vk" -ln -s "$BREW_X64_PATH/opt/vulkan-loader/lib/libvulkan.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" +VULKAN_SDK="$BREW_PATH/opt/molten-vk" +ln -s "$BREW_PATH/opt/vulkan-loader/lib/libvulkan.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" export LLVM_DIR -LLVM_DIR="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER" -# exclude ffmpeg, LLVM, opencv, and sdl from submodule update +LLVM_DIR="$BREW_PATH/opt/llvm@$LLVM_COMPILER_VER" +# Pull all the submodules except some # shellcheck disable=SC2046 -git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/opencv/ && !/SDL/ && !/feralinteractive/ { print $3 }' .gitmodules) +git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/llvm/ && !/opencv/ && !/SDL/ && !/feralinteractive/ { print $3 }' .gitmodules) mkdir build && cd build || exit 1 -export MACOSX_DEPLOYMENT_TARGET=14.4 - -"/opt/homebrew/bin/cmake" .. \ - -DBUILD_RPCS3_TESTS=OFF \ - -DRUN_RPCS3_TESTS=OFF \ +if [ "$AARCH64" -eq 1 ]; then +cmake .. \ + -DBUILD_RPCS3_TESTS="${RUN_UNIT_TESTS}" \ + -DRUN_RPCS3_TESTS="${RUN_UNIT_TESTS}" \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14.4 \ + -DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \ + -DSTATIC_LINK_LLVM=ON \ -DUSE_SDL=ON \ -DUSE_DISCORD_RPC=ON \ - -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_SYSTEM_FFMPEG=OFF \ -DUSE_NATIVE_INSTRUCTIONS=OFF \ + -DUSE_PRECOMPILED_HEADERS=OFF \ -DUSE_SYSTEM_MVK=ON \ - -DUSE_SYSTEM_FAUDIO=OFF \ -DUSE_SYSTEM_SDL=ON \ -DUSE_SYSTEM_OPENCV=ON \ - "$CMAKE_EXTRA_OPTS" \ - -DLLVM_TARGET_ARCH=X86_64 \ + -G Ninja +else +cmake .. \ + -DBUILD_RPCS3_TESTS=OFF \ + -DRUN_RPCS3_TESTS=OFF \ -DCMAKE_OSX_ARCHITECTURES=x86_64 \ -DCMAKE_SYSTEM_PROCESSOR=x86_64 \ -DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinX86_64.cmake \ - -DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \ - -DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \ - -DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=144000" \ - -DCMAKE_POLICY_VERSION_MINIMUM=3.5 \ + -DCMAKE_OSX_DEPLOYMENT_TARGET=14.4 \ -DCMAKE_OSX_SYSROOT="$(xcrun --sdk macosx --show-sdk-path)" \ + -DSTATIC_LINK_LLVM=ON \ + -DUSE_SDL=ON \ + -DUSE_DISCORD_RPC=ON \ + -DUSE_AUDIOUNIT=ON \ + -DUSE_SYSTEM_FFMPEG=OFF \ + -DUSE_NATIVE_INSTRUCTIONS=OFF \ + -DUSE_PRECOMPILED_HEADERS=OFF \ + -DUSE_SYSTEM_MVK=ON \ + -DUSE_SYSTEM_SDL=ON \ + -DUSE_SYSTEM_OPENCV=ON \ -G Ninja +fi -"/opt/homebrew/bin/ninja"; build_status=$?; +ninja; build_status=$?; cd .. From c83769e79e8bfcd92538aa5b73dccb70b5f8cf9c Mon Sep 17 00:00:00 2001 From: schm1dtmac Date: Sat, 3 Jan 2026 00:53:54 +0000 Subject: [PATCH 2/6] Unify & cleanup Mac deploy script --- .ci/deploy-mac-arm64.sh | 86 ----------------------------------------- .ci/deploy-mac.sh | 14 +++---- 2 files changed, 5 insertions(+), 95 deletions(-) delete mode 100755 .ci/deploy-mac-arm64.sh diff --git a/.ci/deploy-mac-arm64.sh b/.ci/deploy-mac-arm64.sh deleted file mode 100755 index a4661dc0dd..0000000000 --- a/.ci/deploy-mac-arm64.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/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 -mkdir -p "rpcs3.app/Contents/Resources/vulkan/icd.d" || true -wget https://github.com/KhronosGroup/MoltenVK/releases/download/v1.4.1/MoltenVK-macos-privateapi.tar -tar -xvf MoltenVK-macos-privateapi.tar -cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib" "rpcs3.app/Contents/Frameworks/libMoltenVK.dylib" -cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/MoltenVK_icd.json" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json" -sed -i '' "s/.\//..\/..\/..\/Frameworks\//g" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json" - -cp "$(realpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib" -cp "$(realpath /opt/homebrew/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib" -cp "$(realpath /opt/homebrew/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib" -cp "$(realpath /opt/homebrew/lib/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 - -# Download translations -mkdir -p "rpcs3.app/Contents/translations" -ZIP_URL=$(curl -fsSL "https://api.github.com/repos/RPCS3/rpcs3_translations/releases/latest" \ - | grep "browser_download_url" \ - | grep "RPCS3-languages.zip" \ - | cut -d '"' -f 4) -if [ -z "$ZIP_URL" ]; then - echo "Failed to find RPCS3-languages.zip in the latest release. Continuing without translations." -else - echo "Downloading translations from: $ZIP_URL" - curl -L -o translations.zip "$ZIP_URL" || { - echo "Failed to download translations.zip. Continuing without translations." - exit 0 - } - unzip -o translations.zip -d "rpcs3.app/Contents/translations" >/dev/null 2>&1 || \ - echo "Failed to extract translations.zip. Continuing without translations." - rm -f translations.zip -fi - -# Copy Qt translations manually -QT_TRANS="$WORKDIR/qt-downloader/$QT_VER/clang_64/translations" -cp $QT_TRANS/qt*.qm rpcs3.app/Contents/translations - -# Hack -install_name_tool -delete_rpath /opt/homebrew/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/lib not needed" -install_name_tool -delete_rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3 || echo "Hack for deleting rpath /opt/homebrew/opt/llvm@$LLVM_COMPILER_VER/lib not needed" - -# 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 - -ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z" -"/opt/homebrew/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url -FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH") -SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }') - -cd .. -echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE" -cd bin diff --git a/.ci/deploy-mac.sh b/.ci/deploy-mac.sh index b0bfb4b455..b144003fb9 100755 --- a/.ci/deploy-mac.sh +++ b/.ci/deploy-mac.sh @@ -14,7 +14,6 @@ AVVER="${COMM_TAG}-${COMM_COUNT}" echo "AVVER=$AVVER" >> ../.ci/ci-vars.env cd bin -mkdir "rpcs3.app/Contents/lib/" || true mkdir -p "rpcs3.app/Contents/Resources/vulkan/icd.d" || true wget https://github.com/KhronosGroup/MoltenVK/releases/download/v1.4.1/MoltenVK-macos-privateapi.tar tar -xvf MoltenVK-macos-privateapi.tar @@ -22,11 +21,8 @@ cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/libMoltenVK.dylib" "rpcs3.app/Contents cp "MoltenVK/MoltenVK/dynamic/dylib/macOS/MoltenVK_icd.json" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json" sed -i '' "s/.\//..\/..\/..\/Frameworks\//g" "rpcs3.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json" -cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib" -cp "$(realpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib)" "rpcs3.app/Contents/Frameworks/libunwind.1.dylib" -cp "$(realpath /usr/local/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib" -cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib" -cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib" +cp "$(realpath $BREW_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib" +cp "$(realpath $BREW_PATH/opt/gcc/lib/gcc/current/libgcc_s.1.1.dylib)" "rpcs3.app/Contents/Frameworks/libgcc_s.1.1.dylib" rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \ "rpcs3.app/Contents/Frameworks/QtQml.framework" \ @@ -67,8 +63,8 @@ mv rpcs3.app RPCS3_.app mv RPCS3_.app RPCS3.app # Hack -install_name_tool -delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3 -#-delete_rpath /usr/local/Cellar/sdl3/3.2.8/lib +install_name_tool -delete_rpath /opt/homebrew/lib RPCS3.app/Contents/MacOS/rpcs3 || true +install_name_tool -delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3 || true # NOTE: "--deep" is deprecated codesign --deep -fs - RPCS3.app @@ -78,7 +74,7 @@ echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url echo "IconIndex=0" >> Quickstart.url ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.7z" -"/opt/homebrew/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url +7z a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH") SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }') From 44bd0568e78acba2a691ed8f33073aee944cd931 Mon Sep 17 00:00:00 2001 From: schm1dtmac Date: Sat, 3 Jan 2026 00:53:59 +0000 Subject: [PATCH 3/6] Unify Mac CI action --- .github/workflows/rpcs3.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rpcs3.yml b/.github/workflows/rpcs3.yml index a4a99fd015..77cbf0f7d9 100644 --- a/.github/workflows/rpcs3.yml +++ b/.github/workflows/rpcs3.yml @@ -123,11 +123,11 @@ jobs: matrix: include: - name: Intel - build_sh: .ci/build-mac.sh + AARCH64: 0 UPLOAD_COMMIT_HASH: 51ae32f468089a8169aaf1567de355ff4a3e0842 UPLOAD_REPO_FULL_NAME: rpcs3/rpcs3-binaries-mac - name: Apple Silicon - build_sh: .ci/build-mac-arm64.sh + AARCH64: 1 UPLOAD_COMMIT_HASH: 8e21bdbc40711a3fccd18fbf17b742348b0f4281 UPLOAD_REPO_FULL_NAME: rpcs3/rpcs3-binaries-mac-arm64 name: RPCS3 Mac ${{ matrix.name }} @@ -140,6 +140,7 @@ jobs: RELEASE_MESSAGE: ../GitHubReleaseMessage.txt UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }} UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }} + AARCH64: ${{ matrix.AARCH64 }} RUN_UNIT_TESTS: github.event_name == 'pull_request' && 'ON' || 'OFF' steps: - name: Checkout repository @@ -164,7 +165,7 @@ jobs: restore-keys: ${{ runner.os }}-qt-${{ matrix.name }}-${{ env.QT_VER }} - name: Build - run: ${{ matrix.build_sh }} + run: .ci/build-mac.sh - name: Upload artifacts uses: actions/upload-artifact@main From aab40bd26948ace182ce471121e23bd0a5c9f1ce Mon Sep 17 00:00:00 2001 From: schm1dtmac Date: Sat, 3 Jan 2026 02:21:56 +0000 Subject: [PATCH 4/6] Try and cut down unnecessary Qt translations --- .ci/deploy-mac.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.ci/deploy-mac.sh b/.ci/deploy-mac.sh index b144003fb9..8b6301f8b9 100755 --- a/.ci/deploy-mac.sh +++ b/.ci/deploy-mac.sh @@ -56,7 +56,10 @@ fi # Copy Qt translations manually QT_TRANS="$WORKDIR/qt-downloader/$QT_VER/clang_64/translations" -cp $QT_TRANS/qt*.qm rpcs3.app/Contents/translations +cp $QT_TRANS/qt_*.qm rpcs3.app/Contents/translations +cp $QT_TRANS/qtbase_*.qm rpcs3.app/Contents/translations +cp $QT_TRANS/qtmultimedia_*.qm rpcs3.app/Contents/translations +rm -f rpcs3.app/Contents/translations/qt_help_*.qm # Need to do this rename hack due to case insensitive filesystem mv rpcs3.app RPCS3_.app From cc37a40f400edc048b72cb74726f5a8154dfbc04 Mon Sep 17 00:00:00 2001 From: kd-11 Date: Sun, 4 Jan 2026 14:01:18 +0300 Subject: [PATCH 5/6] rsx/fp: Harden the FP decompiler a bit when bogus inputs are passed in. --- rpcs3/Emu/RSX/Program/Assembler/CFG.h | 2 +- rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp | 42 +++++++++++++++++-- rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.h | 9 ++++ .../Passes/FP/RegisterAnnotationPass.cpp | 38 +++++++++++++++-- .../Passes/FP/RegisterAnnotationPass.h | 2 +- .../Passes/FP/RegisterDependencyPass.cpp | 4 +- .../Passes/FP/RegisterDependencyPass.h | 2 +- .../RSX/Program/FragmentProgramDecompiler.cpp | 8 ++-- 8 files changed, 92 insertions(+), 15 deletions(-) diff --git a/rpcs3/Emu/RSX/Program/Assembler/CFG.h b/rpcs3/Emu/RSX/Program/Assembler/CFG.h index 818bc2a018..4f2357f2de 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/CFG.h +++ b/rpcs3/Emu/RSX/Program/Assembler/CFG.h @@ -36,7 +36,7 @@ namespace rsx::assembler struct CFGPass { - virtual void run(FlowGraph& graph) = 0; + virtual bool run(FlowGraph& graph) = 0; }; FlowGraph deconstruct_fragment_program(const RSXFragmentProgram& prog); diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp index 3ab4f3d893..c195b4a75b 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.cpp @@ -8,6 +8,42 @@ namespace rsx::assembler::FP { + static const char* s_opcode_names[RSX_FP_OPCODE_ENUM_MAX + 1] = + { + "NOP", "MOV", "MUL", "ADD", "MAD", "DP3", "DP4", "DST", "MIN", "MAX", "SLT", "SGE", "SLE", "SGT", "SNE", "SEQ", // 0x00 - 0x0F + "FRC", "FLR", "KIL", "PK4", "UP4", "DDX", "DDY", "TEX", "TXP", "TXD", "RCP", "RSQ", "EX2", "LG2", "LIT", "LRP", // 0x10 - 0x1F + "STR", "SFL", "COS", "SIN", "PK2", "UP2", "POW", "PKB", "UPB", "PK16", "UP16", "BEM", "PKG", "UPG", "DP2A", "TXL", // 0x20 - 0x2F + "UNK_30", "TXB", "UNK_32", "TEXBEM", "TXPBEM", "BEMLUM", "REFL", "TIMESWTEX", "DP2", "NRM", "DIV", "DIVSQ", "LIF", "FENCT", "FENCB", "UNK_3F", // 0x30 - 0x3F + "BRK", "CAL", "IFE", "LOOP", "REP", "RET", // 0x40 - 0x45 (Flow control) + "OR16_LO", "OR16_HI" // Custom instructions for RPCS3 use + }; + + const char* get_opcode_name(FP_opcode opcode) + { + if (opcode > RSX_FP_OPCODE_ENUM_MAX) + { + return "invalid"; + } + return s_opcode_names[opcode]; + } + + bool is_instruction_valid(FP_opcode opcode) + { + switch (opcode) + { + case RSX_FP_OPCODE_POW: + case RSX_FP_OPCODE_BEM: + case RSX_FP_OPCODE_TEXBEM: + case RSX_FP_OPCODE_TXPBEM: + case RSX_FP_OPCODE_BEMLUM: + case RSX_FP_OPCODE_TIMESWTEX: + return false; + default: + // This isn't necessarily true + return opcode <= RSX_FP_OPCODE_ENUM_MAX; + } + } + u8 get_operand_count(FP_opcode opcode) { switch (opcode) @@ -90,6 +126,8 @@ namespace rsx::assembler::FP return 2; case RSX_FP_OPCODE_LIF: return 1; + case RSX_FP_OPCODE_REFL: + return 2; case RSX_FP_OPCODE_FENCT: case RSX_FP_OPCODE_FENCB: case RSX_FP_OPCODE_BRK: @@ -110,8 +148,6 @@ namespace rsx::assembler::FP case RSX_FP_OPCODE_TXPBEM: case RSX_FP_OPCODE_BEMLUM: fmt::throw_exception("Unimplemented BEM class instruction"); // Unused - case RSX_FP_OPCODE_REFL: - return 2; case RSX_FP_OPCODE_TIMESWTEX: fmt::throw_exception("Unimplemented TIMESWTEX instruction"); // Unused default: @@ -397,7 +433,7 @@ namespace rsx::assembler::FP // Convert vector mask to file range rsx::simple_array get_register_file_range(const RegisterRef& reg) { - if (!reg.mask) + if (!reg.mask || reg.reg.id >= 48) { return {}; } diff --git a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.h b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.h index 1de0985a35..a29b22c842 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.h +++ b/rpcs3/Emu/RSX/Program/Assembler/FPOpcodes.h @@ -81,6 +81,9 @@ namespace rsx::assembler // Custom opcodes for dependency injection RSX_FP_OPCODE_OR16_LO = 0x46, // Performs a 16-bit OR, taking one register channel as input and overwriting low 16 bits of the output RSX_FP_OPCODE_OR16_HI = 0x47, // Same as the lo variant but now overwrites the high 16-bit block + + // Meta + RSX_FP_OPCODE_ENUM_MAX = RSX_FP_OPCODE_OR16_HI }; namespace FP @@ -100,6 +103,12 @@ namespace rsx::assembler using register_file_t = std::array; + // Convert opcode to human-readable string + const char* get_opcode_name(FP_opcode opcode); + + // Returns true if the instruction is implemented by RSX HW + bool is_instruction_valid(FP_opcode opcode); + // Returns number of operands consumed by an instruction u8 get_operand_count(FP_opcode opcode); diff --git a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.cpp b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.cpp index 1b34f53091..622deefe7c 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.cpp @@ -126,8 +126,9 @@ namespace rsx::assembler::FP } // Decay instructions into register references - void annotate_instructions(BasicBlock* block, const RSXFragmentProgram& prog, bool skip_delay_slots) + bool annotate_instructions(BasicBlock* block, const RSXFragmentProgram& prog, bool skip_delay_slots) { + bool result = true; for (auto& instruction : block->instructions) { if (skip_delay_slots && is_delay_slot(instruction)) @@ -135,7 +136,15 @@ namespace rsx::assembler::FP continue; } - const u32 operand_count = get_operand_count(static_cast(instruction.opcode)); + const auto opcode = static_cast(instruction.opcode); + if (!is_instruction_valid(opcode)) + { + rsx_log.error("[CFG] Annotation: Unexpected instruction '%s'", get_opcode_name(opcode)); + result = false; + continue; + } + + const u32 operand_count = get_operand_count(opcode); for (u32 i = 0; i < operand_count; i++) { RegisterRef reg = get_src_register(prog, &instruction, i); @@ -145,15 +154,29 @@ namespace rsx::assembler::FP continue; } + if (reg.reg.id >= 48) + { + rsx_log.error("[CFG] Annotation: Instruction references invalid register %s", reg.reg.to_string()); + result = false; + } + instruction.srcs.push_back(std::move(reg)); } RegisterRef dst = get_dst_register(&instruction); if (dst) { + if (dst.reg.id >= 48) + { + rsx_log.error("[CFG] Annotation: Instruction references invalid register %s", dst.reg.to_string()); + result = false; + } + instruction.dsts.push_back(std::move(dst)); } } + + return result; } // Annotate each block with input and output lanes (read and clobber list) @@ -215,12 +238,19 @@ namespace rsx::assembler::FP block->input_list = compile_register_file(input_register_file); } - void RegisterAnnotationPass::run(FlowGraph& graph) + bool RegisterAnnotationPass::run(FlowGraph& graph) { + bool result = true; for (auto& block : graph.blocks) { - annotate_instructions(&block, m_prog, m_config.skip_delay_slots); + if (!annotate_instructions(&block, m_prog, m_config.skip_delay_slots)) + { + result = false; + } + annotate_block_io(&block); } + + return result; } } diff --git a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.h b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.h index b5cab3da85..2b1ada7f9d 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.h +++ b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterAnnotationPass.h @@ -25,7 +25,7 @@ namespace rsx::assembler::FP : m_prog(prog), m_config(options) {} - void run(FlowGraph& graph) override; + bool run(FlowGraph& graph) override; private: const RSXFragmentProgram& m_prog; diff --git a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.cpp b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.cpp index 27fcd488a7..de9f978f51 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.cpp +++ b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.cpp @@ -464,7 +464,7 @@ namespace rsx::assembler::FP } } - void RegisterDependencyPass::run(FlowGraph& graph) + bool RegisterDependencyPass::run(FlowGraph& graph) { DependencyPassContext ctx{}; @@ -480,5 +480,7 @@ namespace rsx::assembler::FP { insert_block_dependencies(ctx, &(*it)); } + + return true; } } diff --git a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.h b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.h index 48068691e1..8a46b6d65e 100644 --- a/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.h +++ b/rpcs3/Emu/RSX/Program/Assembler/Passes/FP/RegisterDependencyPass.h @@ -10,6 +10,6 @@ namespace rsx::assembler::FP class RegisterDependencyPass : public CFGPass { public: - void run(FlowGraph& graph) override; + bool run(FlowGraph& graph) override; }; } diff --git a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp index 8c5c163f06..ef2029c652 100644 --- a/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp +++ b/rpcs3/Emu/RSX/Program/FragmentProgramDecompiler.cpp @@ -761,7 +761,7 @@ template std::string FragmentProgramDecompiler::GetSRC(T src) break; case RSX_FP_REGISTER_TYPE_UNKNOWN: // ??? Used by a few games, what is it? - rsx_log.error("Src type 3 used, opcode=0x%X, dst=0x%X s0=0x%X s1=0x%X s2=0x%X", + rsx_log.error("[FP] Invalid Src type 3 used, opcode=0x%X, dst=0x%X s0=0x%X s1=0x%X s2=0x%X", dst.opcode, dst.HEX, src0.HEX, src1.HEX, src2.HEX); // This is not some special type, it is a bug indicating memory corruption @@ -1289,6 +1289,7 @@ bool FragmentProgramDecompiler::handle_tex_srb(u32 opcode) std::string FragmentProgramDecompiler::Decompile() { auto graph = deconstruct_fragment_program(m_prog); + m_is_valid_ucode = true; if (!graph.blocks.empty()) { @@ -1315,15 +1316,14 @@ std::string FragmentProgramDecompiler::Decompile() FP::RegisterAnnotationPass annotation_pass{ m_prog, { .skip_delay_slots = true } }; FP::RegisterDependencyPass dependency_pass{}; - annotation_pass.run(graph); - dependency_pass.run(graph); + m_is_valid_ucode = m_is_valid_ucode && annotation_pass.run(graph); + m_is_valid_ucode = m_is_valid_ucode && dependency_pass.run(graph); } m_size = 0; m_location = 0; m_loop_count = 0; m_code_level = 1; - m_is_valid_ucode = true; m_constant_offsets.clear(); // For GLSL scope wind/unwind. We store the min scope depth and loop count for each block and "unwind" to it. From a0e0a6c6a6b1b51b51fe58dc356d33916f3ef3f3 Mon Sep 17 00:00:00 2001 From: schm1dtmac Date: Sun, 4 Jan 2026 15:19:28 +0000 Subject: [PATCH 6/6] [macOS Updater] Cleanup remnants of the old app bundle post-update --- rpcs3/update_helper.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/rpcs3/update_helper.sh b/rpcs3/update_helper.sh index bc51edebe6..380d845980 100755 --- a/rpcs3/update_helper.sh +++ b/rpcs3/update_helper.sh @@ -10,5 +10,6 @@ fi new_app="$1/" old_app="$2/" -cp -Rf -p "$new_app" "$old_app" +rm -rf "$old_app" +mv "$new_app" "$old_app" open -n -a "$2" --args --updating