diff --git a/.ci/build-mac-arm64.sh b/.ci/build-mac-arm64.sh
index 3c89fd3e5a..23a16f4319 100644
--- a/.ci/build-mac-arm64.sh
+++ b/.ci/build-mac-arm64.sh
@@ -72,13 +72,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
- # nested Qt 6.8.1 URL workaround
+ # nested Qt 6.8.2 URL workaround
# 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"
"$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"
- # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround
+ # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.2 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
diff --git a/.ci/build-mac.sh b/.ci/build-mac.sh
index e6ef1a0178..cdc175c200 100644
--- a/.ci/build-mac.sh
+++ b/.ci/build-mac.sh
@@ -39,13 +39,13 @@ if [ ! -d "/tmp/Qt/$QT_VER" ]; then
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
- # nested Qt 6.8.1 URL workaround
+ # nested Qt 6.8.2 URL workaround
# 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"
"$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"
- # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.1 workaround
+ # sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.2 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
diff --git a/.ci/deploy-windows.sh b/.ci/deploy-windows.sh
index 7a7522f8d4..e109dee9e1 100755
--- a/.ci/deploy-windows.sh
+++ b/.ci/deploy-windows.sh
@@ -1,5 +1,8 @@
#!/bin/sh -ex
+# First let's see print some info about our caches
+"$(cygpath -u "$CCACHE_BIN_DIR")"/ccache.exe --show-stats -v
+
# BUILD_blablabla is Azure specific, so we wrap it for portability
ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
diff --git a/.ci/setup-windows.sh b/.ci/setup-windows.sh
index a8fcec17d4..789253d9d5 100755
--- a/.ci/setup-windows.sh
+++ b/.ci/setup-windows.sh
@@ -22,6 +22,7 @@ QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
LLVMLIBS_URL='https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-19.1.7/llvmlibs_mt.7z'
GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-1.3.268.0-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
+CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.10.2/ccache-4.10.2-windows-x86_64.zip"
DEP_URLS=" \
$QT_BASE_URL \
@@ -31,10 +32,11 @@ DEP_URLS=" \
$QT_SVG_URL \
$LLVMLIBS_URL \
$GLSLANG_URL \
- $VULKAN_SDK_URL"
+ $VULKAN_SDK_URL\
+ $CCACHE_URL"
# Azure pipelines doesn't make a cache dir if it doesn't exist, so we do it manually
-[ -d "$CACHE_DIR" ] || mkdir "$CACHE_DIR"
+[ -d "$DEPS_CACHE_DIR" ] || mkdir "$DEPS_CACHE_DIR"
# 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
@@ -58,10 +60,9 @@ download_and_verify()
fileName="$4"
for _ in 1 2 3; do
- [ -e "$CACHE_DIR/$fileName" ] || curl -fLo "$CACHE_DIR/$fileName" "$url"
- fileChecksum=$("${algo}sum" "$CACHE_DIR/$fileName" | awk '{ print $1 }')
+ [ -e "$DEPS_CACHE_DIR/$fileName" ] || curl -fLo "$DEPS_CACHE_DIR/$fileName" "$url"
+ fileChecksum=$("${algo}sum" "$DEPS_CACHE_DIR/$fileName" | awk '{ print $1 }')
[ "$fileChecksum" = "$correctChecksum" ] && return 0
- rm "$CACHE_DIR/$fileName"
done
return 1;
@@ -80,11 +81,12 @@ for url in $DEP_URLS; do
*qt*) checksum=$(curl -fL "${url}.sha1"); algo="sha1"; outDir="$QTDIR/" ;;
*llvm*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./build/lib_ext/Release-x64" ;;
*glslang*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./build/lib_ext/Release-x64" ;;
+ *ccache*) checksum=$CCACHE_SHA; algo="sha256"; outDir="$CCACHE_BIN_DIR" ;;
*Vulkan*)
# Vulkan setup needs to be run in batch environment
# Need to subshell this or else it doesn't wait
download_and_verify "$url" "$VULKAN_SDK_SHA" "sha256" "$fileName"
- cp "$CACHE_DIR/$fileName" .
+ cp "$DEPS_CACHE_DIR/$fileName" .
_=$(echo "$fileName --accept-licenses --default-answer --confirm-command install" | cmd)
continue
;;
@@ -92,9 +94,15 @@ for url in $DEP_URLS; do
esac
download_and_verify "$url" "$checksum" "$algo" "$fileName"
- 7z x -y "$CACHE_DIR/$fileName" -aos -o"$outDir"
+ 7z x -y "$DEPS_CACHE_DIR/$fileName" -aos -o"$outDir"
done
+# Setup ccache tool
+[ -d "$CCACHE_DIR" ] || mkdir -p "$(cygpath -u "$CCACHE_DIR")"
+CCACHE_SH_DIR=$(cygpath -u "$CCACHE_BIN_DIR")
+mv "$CCACHE_SH_DIR"/ccache-*/* "$CCACHE_SH_DIR"
+cp "$CCACHE_SH_DIR"/ccache.exe "$CCACHE_SH_DIR"/cl.exe
+
# 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)
diff --git a/.cirrus.yml b/.cirrus.yml
index bc00884a48..2ef3e9d7ed 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -7,7 +7,7 @@ env:
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
QT_VER_MAIN: '6'
- QT_VER: '6.8.1'
+ QT_VER: '6.8.2'
# windows_task:
# matrix:
@@ -21,7 +21,7 @@ env:
# COMPILER: msvc
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
# QT_VER_MSVC: 'msvc2022'
-# QT_DATE: '202411221531'
+# QT_DATE: '202501260838'
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
# VULKAN_VER: '1.3.268.0'
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
@@ -56,7 +56,7 @@ env:
# linux_task:
# container:
-# image: rpcs3/rpcs3-ci-jammy:1.0
+# image: rpcs3/rpcs3-ci-jammy:1.1
# cpu: 4
# memory: 16G
# env:
@@ -114,38 +114,38 @@ freebsd_task:
install_script: "sh -ex ./.ci/install-freebsd.sh"
script: "./.ci/build-freebsd.sh"
-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-jammy-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;
+# 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-jammy-aarch64:1.1'
+# 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;
diff --git a/.github/workflows/rpcs3.yml b/.github/workflows/rpcs3.yml
index 76619d766b..789e923075 100644
--- a/.github/workflows/rpcs3.yml
+++ b/.github/workflows/rpcs3.yml
@@ -20,7 +20,8 @@ concurrency:
env:
BUILD_REPOSITORY_NAME: ${{ github.repository }}
BUILD_SOURCEBRANCHNAME: ${{ github.ref_name }}
- BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/build
+ BUILD_SOURCEVERSION: ${{ github.sha }}
+ BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts/
jobs:
Linux_Build:
@@ -29,17 +30,20 @@ jobs:
matrix:
include:
- os: ubuntu-24.04
- docker_img: "rpcs3/rpcs3-ci-jammy:1.0"
+ docker_img: "rpcs3/rpcs3-ci-jammy:1.1"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: clang
- os: ubuntu-24.04
- docker_img: "rpcs3/rpcs3-ci-jammy:1.0"
+ docker_img: "rpcs3/rpcs3-ci-jammy:1.1"
build_sh: "/rpcs3/.ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
- docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.0"
+ docker_img: "rpcs3/rpcs3-ci-jammy-aarch64:1.1"
build_sh: "/rpcs3/.ci/build-linux-aarch64.sh"
compiler: clang
+ UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
+ UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
+ name: RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }}
runs-on: ${{ matrix.os }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
@@ -49,7 +53,8 @@ jobs:
ARTDIR: "/root/artifacts"
RELEASE_MESSAGE: "/rpcs3/GitHubReleaseMessage.txt"
COMPILER: ${{ matrix.compiler }}
-
+ UPLOAD_COMMIT_HASH: ${{ matrix.UPLOAD_COMMIT_HASH }}
+ UPLOAD_REPO_FULL_NAME: ${{ matrix.UPLOAD_REPO_FULL_NAME }}
steps:
- name: Checkout repository
uses: actions/checkout@main
@@ -60,7 +65,9 @@ jobs:
uses: actions/cache@main
with:
path: ${{ env.CCACHE_DIR }}
- key: ${{ runner.os }}-ccache-${{ matrix.compiler }}
+ key: ${{ runner.os }}-ccache-${{ matrix.compiler }}-${{ runner.arch }}-${{github.run_id}}
+ restore-keys: |
+ ${{ runner.os }}-ccache-${{ matrix.compiler }}-${{ runner.arch }}-
- name: Docker setup and build
run: |
@@ -74,30 +81,45 @@ jobs:
${{ matrix.build_sh }}
- name: Upload artifacts
- #TODO: Upload artifact to release repository
- #condition for release
- #if: |
- # github.event_name != 'pull_request' &&
- # github.repository == 'RPCS3/rpcs3' &&
- # github.ref == 'refs/heads/master' &&
- # matrix.compiler == 'clang'
uses: actions/upload-artifact@main
with:
name: RPCS3 for Linux (${{ runner.arch }}, ${{ matrix.compiler }})
path: ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/*.AppImage
compression-level: 0
+
+ - name: Deploy master build to GitHub Releases
+ if: |
+ github.event_name != 'pull_request' &&
+ github.repository == 'RPCS3/rpcs3' &&
+ github.ref == 'refs/heads/master' &&
+ matrix.compiler == 'clang' &&
+ runner.arch == 'ARM64'
+ env:
+ RPCS3_TOKEN: ${{ secrets.RPCS3_TOKEN }}
+ run: |
+ 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
Windows_Build:
+ name: RPCS3 Windows
runs-on: windows-2025
env:
COMPILER: msvc
QT_VER_MAIN: '6'
- QT_VER: '6.8.1'
+ QT_VER: '6.8.2'
QT_VER_MSVC: 'msvc2022'
- QT_DATE: '202411221531'
+ QT_DATE: '202501260838'
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
- CACHE_DIR: ./cache
+ CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9'
+ CCACHE_BIN_DIR: 'C:\ccache_bin'
+ CCACHE_DIR: 'C:\ccache'
+ CCACHE_INODECACHE: 'true'
+ CCACHE_SLOPPINESS: 'time_macros'
+ DEPS_CACHE_DIR: ./dependency_cache
steps:
- name: Checkout repository
@@ -114,12 +136,19 @@ jobs:
shell: bash
run: .ci/get_keys-windows.sh
- - name: Setup Cache
+ - name: Setup Build Ccache
uses: actions/cache@main
with:
- path: ${{ env.CACHE_DIR }}
- key: "${{ runner.os }}-${{ env.COMPILER }}-${{ env.QT_VER }}-${{ env.VULKAN_SDK_SHA }}-${{ hashFiles('llvm.lock') }}-${{ hashFiles('glslang.lock') }}"
- restore-keys: ${{ runner.os }}-${{ env.COMPILER }}
+ path: ${{ env.CCACHE_DIR }}
+ key: "${{ runner.os }}-ccache-${{ env.COMPILER }}-${{github.run_id}}"
+ restore-keys: ${{ runner.os }}-ccache-${{ env.COMPILER }}-
+
+ - name: Setup Dependencies Cache
+ uses: actions/cache@main
+ with:
+ path: ${{ env.DEPS_CACHE_DIR }}
+ key: "${{ runner.os }}-${{ env.COMPILER }}-${{ env.QT_VER }}-${{ env.VULKAN_SDK_SHA }}-${{ env.CCACHE_SHA }}-${{ hashFiles('llvm.lock') }}-${{ hashFiles('glslang.lock') }}"
+ restore-keys: ${{ runner.os }}-${{ env.COMPILER }}-
- name: Download and unpack dependencies
shell: bash
@@ -138,12 +167,12 @@ jobs:
uses: microsoft/setup-msbuild@main
- name: Compile RPCS3
- run: msbuild rpcs3.sln /p:Configuration=Release /p:Platform=x64
+ run: msbuild rpcs3.sln /p:Configuration=Release /p:Platform=x64 /p:CLToolPath=${{ env.CCACHE_BIN_DIR }} /p:UseMultiToolTask=true /p:CustomAfterMicrosoftCommonTargets="${{ github.workspace }}\buildfiles\msvc\ci_no_debug_info.targets"
- name: Pack up build artifacts
shell: bash
run: |
- mkdir -p ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}
+ mkdir -p "${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}"
.ci/deploy-windows.sh
- name: Upload artifacts (7z)
@@ -156,10 +185,6 @@ jobs:
uses: actions/upload-artifact@main
with:
name: RPCS3 for Windows (MSVC)
- # 7z
- # 7z.sha256
- path: |
- ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/${{ env.BUILD }}
- ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}/${{ env.BUILD }}.sha256
+ path: ${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}
compression-level: 0
if-no-files-found: error
diff --git a/3rdparty/curl/curl b/3rdparty/curl/curl
index 34cf9d54a4..57495c6487 160000
--- a/3rdparty/curl/curl
+++ b/3rdparty/curl/curl
@@ -1 +1 @@
-Subproject commit 34cf9d54a46598c44938aa7598820484d7af7133
+Subproject commit 57495c64871d18905a0941db9196ef90bafe9a29
diff --git a/3rdparty/libpng/libpng b/3rdparty/libpng/libpng
index 0024abd279..872555f4ba 160000
--- a/3rdparty/libpng/libpng
+++ b/3rdparty/libpng/libpng
@@ -1 +1 @@
-Subproject commit 0024abd279d3a06435c0309a3f4172eed7c7a19a
+Subproject commit 872555f4ba910252783af1507f9e7fe1653be252
diff --git a/3rdparty/libpng/libpng.vcxproj b/3rdparty/libpng/libpng.vcxproj
index 189db8e307..7e781065a6 100644
--- a/3rdparty/libpng/libpng.vcxproj
+++ b/3rdparty/libpng/libpng.vcxproj
@@ -68,7 +68,6 @@
false
false
pngpriv.h
- true
CompileAsC
true
$(DisableSpecificWarnings)
@@ -91,7 +90,6 @@
false
false
pngpriv.h
- true
CompileAsC
true
false
diff --git a/3rdparty/libsdl-org/SDL b/3rdparty/libsdl-org/SDL
index 8236e01a9f..7a44b1ab00 160000
--- a/3rdparty/libsdl-org/SDL
+++ b/3rdparty/libsdl-org/SDL
@@ -1 +1 @@
-Subproject commit 8236e01a9f758d15927624925c6043f84d8a261f
+Subproject commit 7a44b1ab002cee6efa56d3b4c0e146b7fbaed80b
diff --git a/3rdparty/opencv/CMakeLists.txt b/3rdparty/opencv/CMakeLists.txt
index 2071caa5b6..1103f3be94 100644
--- a/3rdparty/opencv/CMakeLists.txt
+++ b/3rdparty/opencv/CMakeLists.txt
@@ -4,7 +4,7 @@ set(OPENCV_TARGET 3rdparty_dummy_lib PARENT_SCOPE)
if (USE_SYSTEM_OPENCV)
message(STATUS "RPCS3: using system OpenCV")
- find_package(OpenCV)
+ find_package(OpenCV COMPONENTS core photo)
if(OPENCV_FOUND)
message(STATUS "RPCS3: found system OpenCV")
diff --git a/3rdparty/zlib/zlib.vcxproj b/3rdparty/zlib/zlib.vcxproj
index f0daafdd14..dbc63d51a2 100644
--- a/3rdparty/zlib/zlib.vcxproj
+++ b/3rdparty/zlib/zlib.vcxproj
@@ -84,7 +84,6 @@
$(WarningLevel)
ProgramDatabase
Disabled
- true
true
$(DisableSpecificWarnings);4127;4131;4242;4244
$(TreatWarningAsError)
@@ -102,7 +101,6 @@
true
true
false
- true
true
$(DisableSpecificWarnings);4127;4131;4242;4244
$(TreatWarningAsError)
diff --git a/3rdparty/zstd/zstd b/3rdparty/zstd/zstd
index 97291fc502..f8745da6ff 160000
--- a/3rdparty/zstd/zstd
+++ b/3rdparty/zstd/zstd
@@ -1 +1 @@
-Subproject commit 97291fc5020a8994019ab76cf0cda83a9824374c
+Subproject commit f8745da6ff1ad1e7bab384bd1f9d742439278e99
diff --git a/3rdparty/zstd/zstd.vcxproj b/3rdparty/zstd/zstd.vcxproj
index 8527d72ca1..720fabe962 100644
--- a/3rdparty/zstd/zstd.vcxproj
+++ b/3rdparty/zstd/zstd.vcxproj
@@ -58,6 +58,7 @@
+
@@ -97,6 +98,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/BUILDING.md b/BUILDING.md
index 48289878ad..7cad89f8c5 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -19,26 +19,26 @@ The following tools are required to build RPCS3 on Windows 10 or later:
with standalone **CMake** tool.
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
-- [Qt 6.8.1](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
+- [Qt 6.8.2](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
In order to build **RPCS3** with the `sln` solution (with **Visual Studio**), **Qt** libs need to be detected. To detect the libs:
-- add and set the `QTDIR` environment variable, e.g. `\6.8.1\msvc2022_64\`
+- add and set the `QTDIR` environment variable, e.g. `\6.8.2\msvc2022_64\`
- or use the [Visual Studio Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
**NOTE:** If you have issues with the **Visual Studio Qt Plugin**, you may want to uninstall it and install the [Legacy Qt Plugin](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.LEGACYQtVisualStudioTools2022) instead.
In order to build **RPCS3** with the `CMake` solution (with both **Visual Studio** and standalone **CMake** tool):
-- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `\6.8.1\msvc2022_64\`
+- add and set the `Qt6_ROOT` environment variable to the **Qt** libs path, e.g. `\6.8.2\msvc2022_64\`
### Linux
These are the essentials tools to build RPCS3 on Linux. Some of them can be installed through your favorite package manager:
- Clang 17+ or GCC 13+
- [CMake 3.28.0+](https://www.cmake.org/download/)
-- [Qt 6.8.1](https://www.qt.io/download-qt-installer)
+- [Qt 6.8.2](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)
@@ -119,7 +119,7 @@ Start **Visual Studio**, click on `Open a project or solution` and select the `r
##### Configuring the Qt Plugin (if used)
1) go to `Extensions->Qt VS Tools->Qt Versions`
-2) add the path to your Qt installation with compiler e.g. `\6.8.1\msvc2022_64`, version will fill in automatically
+2) add the path to your Qt installation with compiler e.g. `\6.8.2\msvc2022_64`, version will fill in automatically
3) go to `Extensions->Qt VS Tools->Options->Legacy Project Format`. (Only available in the **Legacy Qt Plugin**)
4) set `Build: Run pre-build setup` to `true`. (Only available in the **Legacy Qt Plugin**)
diff --git a/Utilities/BitField.h b/Utilities/BitField.h
index 32785e5e7e..b2243dbe1e 100644
--- a/Utilities/BitField.h
+++ b/Utilities/BitField.h
@@ -256,7 +256,7 @@ struct ff_t : bf_base
#endif
template
-struct fmt_unveil, void>
+struct fmt_unveil>
{
using type = typename fmt_unveil>::type;
@@ -267,7 +267,7 @@ struct fmt_unveil, void>
};
template
-struct fmt_unveil, void>
+struct fmt_unveil>
{
using type = typename fmt_unveil>::type;
@@ -278,7 +278,7 @@ struct fmt_unveil, void>
};
template
-struct fmt_unveil, void>
+struct fmt_unveil>
{
using type = typename fmt_unveil>::type;
diff --git a/Utilities/File.h b/Utilities/File.h
index f3adaa15d4..828a0384b6 100644
--- a/Utilities/File.h
+++ b/Utilities/File.h
@@ -1,5 +1,6 @@
#pragma once // No BOM and only basic ASCII in this header, or a neko will die
+#include "util/serialization.hpp"
#include "util/types.hpp"
#include "util/shared_ptr.hpp"
#include "bit_set.h"
@@ -78,6 +79,8 @@ namespace fs
constexpr bool operator==(const stat_t&) const = default;
};
+ static_assert(utils::Bitcopy);
+
// Helper, layout is equal to iovec struct
struct iovec_clone
{
@@ -126,6 +129,8 @@ namespace fs
using enable_bitcopy = std::false_type;
};
+ static_assert(!utils::Bitcopy);
+
// Directory handle base
struct dir_base
{
diff --git a/Utilities/StrFmt.h b/Utilities/StrFmt.h
index f83cbe49fe..05d98fdfab 100644
--- a/Utilities/StrFmt.h
+++ b/Utilities/StrFmt.h
@@ -22,7 +22,7 @@ namespace fmt
#endif
}
-template
+template
struct fmt_unveil
{
static_assert(sizeof(T) > 0, "fmt_unveil<> error: incomplete type");
@@ -54,7 +54,8 @@ struct fmt_unveil
};
template
-struct fmt_unveil && sizeof(T) <= 8 && alignof(T) <= 8>>
+ requires(std::is_integral_v && sizeof(T) <= 8 && alignof(T) <= 8)
+struct fmt_unveil
{
using type = T;
@@ -65,7 +66,8 @@ struct fmt_unveil && sizeof(T) <= 8 &&
};
template
-struct fmt_unveil && sizeof(T) <= 8 && alignof(T) <= 8>>
+ requires(std::is_floating_point_v && sizeof(T) <= 8 && alignof(T) <= 8)
+struct fmt_unveil
{
using type = T;
@@ -77,7 +79,8 @@ struct fmt_unveil && sizeof(T) <
};
template
-struct fmt_unveil>>
+ requires std::is_enum_v
+struct fmt_unveil
{
using type = T;
@@ -88,7 +91,7 @@ struct fmt_unveil>>
};
template
-struct fmt_unveil
+struct fmt_unveil
{
using type = std::add_const_t*;
@@ -105,7 +108,7 @@ namespace fmt
}
template
-struct fmt_unveil
+struct fmt_unveil
{
using type = std::add_const_t*;
@@ -116,7 +119,7 @@ struct fmt_unveil
};
template
-struct fmt_unveil, void>
+struct fmt_unveil>
{
using type = typename fmt_unveil::type;
@@ -127,7 +130,7 @@ struct fmt_unveil, void>
};
// String type format provider, also type classifier (format() called if an argument is formatted as "%s")
-template
+template
struct fmt_class_string
{
// Formatting function (must be explicitly specialized)
@@ -200,47 +203,47 @@ struct fmt_class_string
};
template <>
-struct fmt_class_string
+struct fmt_class_string
{
static void format(std::string& out, u64 arg);
};
template
-struct fmt_class_string : fmt_class_string
+struct fmt_class_string : fmt_class_string
{
// Classify all pointers as const void*
};
template <>
-struct fmt_class_string
+struct fmt_class_string
{
static void format(std::string& out, u64 arg);
};
template <>
-struct fmt_class_string : fmt_class_string
+struct fmt_class_string : fmt_class_string
{
// Classify char* as const char*
};
template <>
-struct fmt_class_string : fmt_class_string
+struct fmt_class_string : fmt_class_string
{
};
template <>
-struct fmt_class_string : fmt_class_string
+struct fmt_class_string : fmt_class_string
{
};
template <>
-struct fmt_class_string
+struct fmt_class_string
{
static void format(std::string& out, u64 arg);
};
template <>
-struct fmt_class_string : fmt_class_string
+struct fmt_class_string : fmt_class_string
{
};
@@ -254,7 +257,7 @@ namespace fmt
}
template
-struct fmt_class_string
+struct fmt_class_string
{
static FORCE_INLINE SAFE_BUFFERS(const T&) get_object(u64 arg)
{
@@ -275,7 +278,7 @@ namespace fmt
}
template
-struct fmt_class_string
+struct fmt_class_string
{
static FORCE_INLINE SAFE_BUFFERS(const T&) get_object(u64 arg)
{
diff --git a/Utilities/bit_set.h b/Utilities/bit_set.h
index f418fde13e..8b98ae0fd4 100644
--- a/Utilities/bit_set.h
+++ b/Utilities/bit_set.h
@@ -385,7 +385,7 @@ public:
};
template
-struct fmt_unveil, void>
+struct fmt_unveil>
{
// Format as is
using type = bs_t;
diff --git a/Utilities/cheat_info.cpp b/Utilities/cheat_info.cpp
index c46f2089e9..a16be2767f 100644
--- a/Utilities/cheat_info.cpp
+++ b/Utilities/cheat_info.cpp
@@ -4,6 +4,29 @@
LOG_CHANNEL(log_cheat, "Cheat");
+template <>
+void fmt_class_string::format(std::string& out, u64 arg)
+{
+ format_enum(out, arg, [](cheat_type value)
+ {
+ switch (value)
+ {
+ case cheat_type::unsigned_8_cheat: return "Unsigned 8 bits";
+ case cheat_type::unsigned_16_cheat: return "Unsigned 16 bits";
+ case cheat_type::unsigned_32_cheat: return "Unsigned 32 bits";
+ case cheat_type::unsigned_64_cheat: return "Unsigned 64 bits";
+ case cheat_type::signed_8_cheat: return "Signed 8 bits";
+ case cheat_type::signed_16_cheat: return "Signed 16 bits";
+ case cheat_type::signed_32_cheat: return "Signed 32 bits";
+ case cheat_type::signed_64_cheat: return "Signed 64 bits";
+ case cheat_type::float_32_cheat: return "Float 32 bits";
+ case cheat_type::max: break;
+ }
+
+ return unknown;
+ });
+}
+
bool cheat_info::from_str(const std::string& cheat_line)
{
auto cheat_vec = fmt::split(cheat_line, {"@@@"}, false);
diff --git a/Utilities/date_time.cpp b/Utilities/date_time.cpp
new file mode 100644
index 0000000000..6aef060318
--- /dev/null
+++ b/Utilities/date_time.cpp
@@ -0,0 +1,11 @@
+#include "stdafx.h"
+#include "date_time.h"
+
+#include
+
+template <>
+void fmt_class_string>::format(std::string& out, u64 arg)
+{
+ const std::time_t dateTime = std::chrono::system_clock::to_time_t(get_object(arg));
+ out += date_time::fmt_time("%Y-%m-%dT%H:%M:%S", dateTime);
+}
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 082ffa3ea8..2907949c9f 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -33,18 +33,20 @@ jobs:
steps:
- task: Cache@2
inputs:
- key: ccache | $(Agent.OS) | $(COMPILER)
+ key: ccache | $(Agent.OS) | $(COMPILER) | $(Build.SourceVersion)
+ restoreKeys: |
+ ccache | $(Agent.OS) | $(COMPILER)
path: $(CCACHE_DIR)
displayName: ccache
- bash: |
- docker pull --quiet rpcs3/rpcs3-ci-jammy:1.0
+ docker pull --quiet rpcs3/rpcs3-ci-jammy:1.1
docker run \
-v $(pwd):/rpcs3 \
--env-file .ci/docker.env \
-v $CCACHE_DIR:/root/.ccache \
-v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
- rpcs3/rpcs3-ci-jammy:1.0 \
+ rpcs3/rpcs3-ci-jammy:1.1 \
/rpcs3/.ci/build-linux.sh
displayName: Docker setup and build
@@ -69,14 +71,19 @@ jobs:
variables:
COMPILER: msvc
QT_VER_MAIN: '6'
- QT_VER: '6.8.1'
+ QT_VER: '6.8.2'
QT_VER_MSVC: 'msvc2022'
- QT_DATE: '202411221531'
+ QT_DATE: '202501260838'
QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
VULKAN_SDK: C:\VulkanSDK\$(VULKAN_VER)
- CACHE_DIR: ./cache
+ CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9'
+ CCACHE_BIN_DIR: 'C:\ccache_bin'
+ CCACHE_DIR: 'C:\ccache'
+ CCACHE_INODECACHE: 'true'
+ CCACHE_SLOPPINESS: 'time_macros'
+ DEPS_CACHE_DIR: ./dependency_cache
UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
@@ -89,11 +96,17 @@ jobs:
- task: Cache@2
inputs:
- key: $(Agent.OS) | $(COMPILER) | "$(QT_VER)" | $(VULKAN_SDK_SHA) | llvm.lock | glslang.lock
- path: $(CACHE_DIR)
- restoreKeys: |
- $(Agent.OS) | $(COMPILER)
- displayName: Cache
+ key: ccache | $(Agent.OS) | $(COMPILER) | "$(Build.SourceVersion)"
+ path: $(CCACHE_DIR)
+ restoreKeys:
+ ccache | $(Agent.OS) | $(COMPILER)
+ displayName: Build Ccache
+
+ - task: Cache@2
+ inputs:
+ key: $(Agent.OS) | $(COMPILER) | "$(QT_VER)" | $(VULKAN_SDK_SHA) | $(CCACHE_SHA) | llvm.lock | glslang.lock
+ path: $(DEPS_CACHE_DIR)
+ displayName: Dependencies Cache
- bash: .ci/setup-windows.sh
displayName: Download and unpack dependencies
@@ -107,6 +120,7 @@ jobs:
maximumCpuCount: true
platform: x64
configuration: 'Release'
+ msbuildArgs: /p:CLToolPath=$(CCACHE_BIN_DIR) /p:UseMultiToolTask=true /p:CustomAfterMicrosoftCommonTargets="$(Build.SourcesDirectory)\buildfiles\msvc\ci_no_debug_info.targets"
displayName: Compile RPCS3
- bash: .ci/deploy-windows.sh
@@ -142,10 +156,10 @@ jobs:
steps:
- task: Cache@2
inputs:
- key: ccache | "$(Agent.OS)"
+ key: ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(Build.SourceVersion)"
path: $(CCACHE_DIR)
restoreKeys: |
- ccache | "$(Agent.OS)"
+ ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)"
displayName: Ccache cache
- task: Cache@2
@@ -203,10 +217,10 @@ jobs:
steps:
- task: Cache@2
inputs:
- key: ccache | "$(Agent.OS)"
+ key: ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(Build.SourceVersion)"
path: $(CCACHE_DIR)
restoreKeys: |
- ccache | "$(Agent.OS)"
+ ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)"
displayName: Ccache cache
- task: Cache@2
diff --git a/buildfiles/msvc/ci_no_debug_info.targets b/buildfiles/msvc/ci_no_debug_info.targets
new file mode 100644
index 0000000000..147806ac97
--- /dev/null
+++ b/buildfiles/msvc/ci_no_debug_info.targets
@@ -0,0 +1,8 @@
+
+
+
+
+ None
+
+
+
\ No newline at end of file
diff --git a/rpcs3/Crypto/decrypt_binaries.cpp b/rpcs3/Crypto/decrypt_binaries.cpp
index a87db5c0ec..6205ac6d4f 100644
--- a/rpcs3/Crypto/decrypt_binaries.cpp
+++ b/rpcs3/Crypto/decrypt_binaries.cpp
@@ -96,7 +96,7 @@ usz decrypt_binaries_t::decrypt(std::string_view klic_input)
case "SCE\0"_u32:
{
// First KLIC is no KLIC
- elf_file = decrypt_self(std::move(elf_file), key_it != 0 ? reinterpret_cast(&m_klics[key_it]) : nullptr);
+ elf_file = decrypt_self(elf_file, key_it != 0 ? reinterpret_cast(&m_klics[key_it]) : nullptr);
if (!elf_file)
{
diff --git a/rpcs3/Crypto/key_vault.cpp b/rpcs3/Crypto/key_vault.cpp
index ab99514b27..b9222cd63e 100644
--- a/rpcs3/Crypto/key_vault.cpp
+++ b/rpcs3/Crypto/key_vault.cpp
@@ -20,6 +20,7 @@ SELF_KEY::SELF_KEY(u64 ver_start, u64 ver_end, u16 rev, u32 type, const std::str
KeyVault::KeyVault()
{
+ std::memcpy(klicensee_key, NP_KLIC_FREE, sizeof(klicensee_key));
}
void KeyVault::LoadSelfLV0Keys()
@@ -751,15 +752,14 @@ SELF_KEY KeyVault::FindSelfKey(u32 type, u16 revision, u64 version)
return key;
}
-void KeyVault::SetKlicenseeKey(u8* key)
+void KeyVault::SetKlicenseeKey(const u8* key)
{
- klicensee_key = std::make_unique(0x10);
- memcpy(klicensee_key.get(), key, 0x10);
+ std::memcpy(klicensee_key, key, 0x10);
}
-u8* KeyVault::GetKlicenseeKey() const
+const u8* KeyVault::GetKlicenseeKey() const
{
- return klicensee_key.get();
+ return klicensee_key;
}
void rap_to_rif(unsigned char* rap, unsigned char* rif)
diff --git a/rpcs3/Crypto/key_vault.h b/rpcs3/Crypto/key_vault.h
index 5fc19d1659..ac5ba084b9 100644
--- a/rpcs3/Crypto/key_vault.h
+++ b/rpcs3/Crypto/key_vault.h
@@ -319,13 +319,13 @@ class KeyVault
std::vector sk_LDR_arr{};
std::vector sk_UNK7_arr{};
std::vector sk_NPDRM_arr{};
- std::unique_ptr klicensee_key{};
+ u8 klicensee_key[16]{};
public:
KeyVault();
SELF_KEY FindSelfKey(u32 type, u16 revision, u64 version);
- void SetKlicenseeKey(u8* key);
- u8* GetKlicenseeKey() const;
+ void SetKlicenseeKey(const u8* key);
+ const u8* GetKlicenseeKey() const;
private:
void LoadSelfLV0Keys();
diff --git a/rpcs3/Crypto/unpkg.cpp b/rpcs3/Crypto/unpkg.cpp
index baf612657d..4ca103c78b 100644
--- a/rpcs3/Crypto/unpkg.cpp
+++ b/rpcs3/Crypto/unpkg.cpp
@@ -39,6 +39,13 @@ package_reader::package_reader(const std::string& path)
return;
}
+ m_is_valid = set_decryption_key();
+
+ if (!m_is_valid)
+ {
+ return;
+ }
+
const bool param_sfo_found = read_param_sfo();
if (!param_sfo_found)
@@ -66,7 +73,7 @@ bool package_reader::read_header()
}
pkg_log.notice("Path: '%s'", m_path);
- pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string_view(reinterpret_cast(&m_header.pkg_magic + 1), 3)); // Skip 0x7F
+ pkg_log.notice("Header: pkg_magic = 0x%x = \"%s\"", +m_header.pkg_magic, std::string_view(reinterpret_cast(&m_header.pkg_magic), 4).substr(1)); // Skip 0x7F
pkg_log.notice("Header: pkg_type = 0x%x = %d", m_header.pkg_type, m_header.pkg_type);
pkg_log.notice("Header: pkg_platform = 0x%x = %d", m_header.pkg_platform, m_header.pkg_platform);
pkg_log.notice("Header: meta_offset = 0x%x = %d", m_header.meta_offset, m_header.meta_offset);
@@ -93,7 +100,7 @@ bool package_reader::read_header()
return false;
}
- pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string_view(reinterpret_cast(&ext_header.magic + 1), 3));
+ pkg_log.notice("Extended header: magic = 0x%x = \"%s\"", +ext_header.magic, std::string_view(reinterpret_cast(&ext_header.magic), 4).substr(1));
pkg_log.notice("Extended header: unknown_1 = 0x%x = %d", ext_header.unknown_1, ext_header.unknown_1);
pkg_log.notice("Extended header: ext_hdr_size = 0x%x = %d", ext_header.ext_hdr_size, ext_header.ext_hdr_size);
pkg_log.notice("Extended header: ext_data_size = 0x%x = %d", ext_header.ext_data_size, ext_header.ext_data_size);
@@ -112,6 +119,12 @@ bool package_reader::read_header()
return false;
}
+ if (u64{umax} / sizeof(PKGEntry) < m_header.file_count)
+ {
+ pkg_log.error("PKG file count is too large! (0x%x)", m_header.file_count);
+ return false;
+ }
+
switch (const u16 type = m_header.pkg_type)
{
case PKG_RELEASE_TYPE_DEBUG: break;
@@ -187,11 +200,6 @@ bool package_reader::read_header()
bool package_reader::read_metadata()
{
- if (!decrypt_data())
- {
- return false;
- }
-
// Read title ID and use it as an installation directory
m_install_dir.resize(9);
archive_read_block(55, &m_install_dir.front(), m_install_dir.size());
@@ -306,7 +314,7 @@ bool package_reader::read_metadata()
if (packet.size == sizeof(m_metadata.qa_digest))
{
archive_read(&m_metadata.qa_digest, sizeof(m_metadata.qa_digest));
- pkg_log.notice("Metadata: QA Digest = 0x%x", m_metadata.qa_digest);
+ pkg_log.notice("Metadata: QA Digest = %s", std::span(m_metadata.qa_digest, sizeof(m_metadata.qa_digest)));
continue;
}
else
@@ -478,7 +486,7 @@ bool package_reader::read_metadata()
return true;
}
-bool package_reader::decrypt_data()
+bool package_reader::set_decryption_key()
{
if (!m_is_valid)
{
@@ -493,12 +501,76 @@ bool package_reader::decrypt_data()
aes_context ctx;
aes_setkey_enc(&ctx, m_metadata.content_type == 0x15u ? PKG_AES_KEY_VITA_1 : m_metadata.content_type == 0x16u ? PKG_AES_KEY_VITA_2 : PKG_AES_KEY_VITA_3, 128);
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast(&m_header.klicensee), m_dec_key.data());
- decrypt(0, m_header.file_count * sizeof(PKGEntry), m_dec_key.data());
+ return true;
}
- else
+
+ std::memcpy(m_dec_key.data(), PKG_AES_KEY, m_dec_key.size());
+
+ if (std::vector entries; !read_entries(entries))
{
- std::memcpy(m_dec_key.data(), PKG_AES_KEY, m_dec_key.size());
- decrypt(0, m_header.file_count * sizeof(PKGEntry), m_header.pkg_platform == PKG_PLATFORM_TYPE_PSP_PSVITA ? PKG_AES_KEY2 : m_dec_key.data());
+ pkg_log.notice("PKG may be IDU, retrying with IDU key.");
+
+ std::memcpy(m_dec_key.data(), PKG_AES_KEY_IDU, m_dec_key.size());
+
+ if (!read_entries(entries))
+ {
+ pkg_log.error("PKG decryption failed!");
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool package_reader::read_entries(std::vector& entries)
+{
+ entries.clear();
+ entries.resize(m_header.file_count + BUF_PADDING / sizeof(PKGEntry) + 1);
+
+ const usz read_size = decrypt(0, m_header.file_count * sizeof(PKGEntry), m_dec_key.data(), entries.data());
+
+ if (read_size < m_header.file_count * sizeof(PKGEntry))
+ {
+ return false;
+ }
+
+ entries.resize(m_header.file_count);
+
+ const usz fsz = m_file.size() - m_header.data_offset;
+
+ // Data integrity validation
+ for (const PKGEntry& entry : entries)
+ {
+ if (!entry.name_size)
+ {
+ continue;
+ }
+
+ if (entry.name_size > PKG_MAX_FILENAME_SIZE)
+ {
+ return false;
+ }
+
+ if (fsz < entry.name_size || fsz - entry.name_size < entry.name_offset)
+ {
+ // Name exceeds file(s)
+ return false;
+ }
+
+ if (entry.file_size)
+ {
+ if (fsz < entry.file_size || fsz - entry.file_size < entry.file_offset)
+ {
+ // Data exceeds file(s)
+ return false;
+ }
+
+ if (entry.name_offset == entry.file_offset)
+ {
+ // Repeated value: odd
+ return false;
+ }
+ }
}
return true;
@@ -506,28 +578,34 @@ bool package_reader::decrypt_data()
bool package_reader::read_param_sfo()
{
- if (!decrypt_data())
+ std::vector entries;
+
+ if (!read_entries(entries))
{
return false;
}
- std::vector entries(m_header.file_count);
-
- std::memcpy(entries.data(), m_bufs.back().get(), entries.size() * sizeof(PKGEntry));
+ std::vector data_buf;
for (const PKGEntry& entry : entries)
{
- if (entry.name_size > 256)
+ if (entry.name_size > PKG_MAX_FILENAME_SIZE)
{
- pkg_log.error("PKG name size is too big (0x%x)", entry.name_size);
+ pkg_log.error("PKG name size is too big (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
continue;
}
const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
- decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
+ std::string name(entry.name_size + BUF_PADDING, '\0');
- const std::string_view name{reinterpret_cast(m_bufs.back().get()), entry.name_size};
+ if (usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name.data()); read_size < entry.name_size)
+ {
+ pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
+ continue;
+ }
+
+ fmt::trim_back(name, "\0"sv);
// We're looking for the PARAM.SFO file, if there is any
if (usz ndelim = name.find_first_not_of('/'); ndelim == umax || name.substr(ndelim) != "PARAM.SFO")
@@ -536,19 +614,21 @@ bool package_reader::read_param_sfo()
}
// Read the package's PARAM.SFO
- if (fs::file tmp = fs::make_stream>())
+ fs::file tmp = fs::make_stream>();
{
for (u64 pos = 0; pos < entry.file_size; pos += BUF_SIZE)
{
const u64 block_size = std::min(BUF_SIZE, entry.file_size - pos);
- if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data()).size() != block_size)
+ data_buf.resize(block_size + BUF_PADDING);
+
+ if (decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), data_buf.data()) != block_size)
{
pkg_log.error("Failed to decrypt PARAM.SFO file");
return false;
}
- if (tmp.write(m_bufs.back().get(), block_size) != block_size)
+ if (tmp.write(data_buf.data(), block_size) != block_size)
{
pkg_log.error("Failed to write to temporary PARAM.SFO file");
return false;
@@ -567,9 +647,6 @@ bool package_reader::read_param_sfo()
return true;
}
-
- pkg_log.error("Failed to create temporary PARAM.SFO file");
- return false;
}
return false;
@@ -757,31 +834,38 @@ bool package_reader::fill_data(std::map& all_instal
m_entry_indexer = 0;
m_written_bytes = 0;
- if (!decrypt_data())
+ usz num_failures = 0;
+
+ std::vector entries;
+
+ if (!read_entries(entries))
{
return false;
}
- usz num_failures = 0;
-
- std::vector entries(m_header.file_count);
-
- std::memcpy(entries.data(), m_bufs.back().get(), entries.size() * sizeof(PKGEntry));
-
// Create directories first
for (const auto& entry : entries)
{
if (entry.name_size > PKG_MAX_FILENAME_SIZE)
{
num_failures++;
- pkg_log.error("PKG name size is too big (0x%x)", entry.name_size);
+ pkg_log.error("PKG name size is too big (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
break;
}
- const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
- decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data());
+ std::string name(entry.name_size + BUF_PADDING, '\0');
+
+ const bool is_psp = (entry.type & PKG_FILE_ENTRY_PSP) != 0u;
+
+ if (const usz read_size = decrypt(entry.name_offset, entry.name_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), name.data()); read_size < entry.name_size)
+ {
+ num_failures++;
+ pkg_log.error("PKG name could not be read (size=0x%x, offset=0x%x)", entry.name_size, entry.name_offset);
+ break;
+ }
+
+ fmt::trim_back(name, "\0"sv);
- const std::string_view name{reinterpret_cast(m_bufs.back().get()), entry.name_size};
std::string path = m_install_path + vfs::escape(name);
if (entry.pad || (entry.type & ~PKG_FILE_ENTRY_KNOWN_BITS))
@@ -863,7 +947,7 @@ bool package_reader::fill_data(std::map& all_instal
fs::file DecryptEDAT(const fs::file& input, const std::string& input_file_name, int mode, u8 *custom_klic);
-void package_reader::extract_worker(thread_key thread_data_key)
+void package_reader::extract_worker()
{
std::vector read_cache;
@@ -1059,23 +1143,21 @@ void package_reader::extract_worker(thread_key thread_data_key)
{
const u64 block_size = std::min({BUF_SIZE, std::max(size * 5 / 3, 65536), entry.file_size - pos});
- read_cache.resize(block_size);
+ read_cache.resize(block_size + BUF_PADDING);
cache_off = pos;
- const std::span data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
+ const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), read_cache.data());
- if (data_span.empty())
+ if (!advance_size)
{
cache_off = umax;
- read_cache.clear();
return 0;
}
- read_cache.resize(data_span.size());
- std::memcpy(read_cache.data(), data_span.data(), data_span.size());
+ read_cache.resize(advance_size);
- size = std::min(data_span.size(), size);
- std::memcpy(ptr, data_span.data(), size);
+ size = std::min(advance_size, size);
+ std::memcpy(ptr, read_cache.data(), size);
return size;
}
@@ -1083,17 +1165,15 @@ void package_reader::extract_worker(thread_key thread_data_key)
{
const u64 block_size = std::min(BUF_SIZE, size - read_size);
- const std::span data_span = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), thread_data_key);
+ const usz advance_size = decrypt(entry.file_offset + pos, block_size, is_psp ? PKG_AES_KEY2 : m_dec_key.data(), static_cast(ptr) + read_size);
- if (data_span.empty())
+ if (!advance_size)
{
break;
}
- std::memcpy(static_cast(ptr) + read_size, data_span.data(), data_span.size());
-
- read_size += data_span.size();
- pos += data_span.size();
+ read_size += advance_size;
+ pos += advance_size;
}
return read_size + size_cache_end;
@@ -1121,9 +1201,9 @@ void package_reader::extract_worker(thread_key thread_data_key)
}
// 16MB buffer
- std::vector buffer(std::min(entry.file_size, 1u << 24));
+ std::vector buffer(std::min(entry.file_size, 1u << 24) + BUF_PADDING);
- while (usz read_size = final_data.read(buffer.data(), buffer.size()))
+ while (usz read_size = final_data.read(buffer.data(), buffer.size() - BUF_PADDING))
{
out.write(buffer.data(), read_size);
m_written_bytes += read_size;
@@ -1224,20 +1304,15 @@ package_install_result package_reader::extract_data(std::deque&
if (reader.m_num_failures == 0)
{
- reader.m_bufs.resize(std::min(utils::get_thread_count(), reader.m_install_entries.size()));
+ const usz thread_count = std::min(utils::get_thread_count(), reader.m_install_entries.size());
- atomic_t thread_indexer = 0;
-
- named_thread_group workers("PKG Installer "sv, std::max(::narrow(reader.m_bufs.size()), 1) - 1, [&]()
+ named_thread_group workers("PKG Installer "sv, std::max(::narrow(thread_count), 1) - 1, [&]()
{
- reader.extract_worker(thread_key{thread_indexer++});
+ reader.extract_worker();
});
- reader.extract_worker(thread_key{thread_indexer++});
+ reader.extract_worker();
workers.join();
-
- reader.m_bufs.clear();
- reader.m_bufs.shrink_to_fit();
}
num_failures += reader.m_num_failures;
@@ -1312,33 +1387,25 @@ std::span package_reader::archive_read_block(u64 offset, void* data_
return {static_cast(data_ptr), read_n};
}
-std::span package_reader::decrypt(u64 offset, u64 size, const uchar* key, thread_key thread_data_key)
+usz package_reader::decrypt(u64 offset, u64 size, const uchar* key, void* local_buf)
{
if (!m_is_valid)
{
- return {};
+ return 0;
}
- if (m_bufs.empty())
+ if (m_header.data_offset > ~offset)
{
- // Assume in single-threaded mode still
- m_bufs.resize(1);
- }
-
- auto& local_buf = ::at32(m_bufs, thread_data_key.unique_num);
-
- if (!local_buf)
- {
- // Allocate buffer with BUF_SIZE size or more if required
- local_buf.reset(new u128[std::max(BUF_SIZE, sizeof(PKGEntry) * m_header.file_count) / sizeof(u128)]);
+ return 0;
}
// Read the data and set available size
- const auto data_span = archive_read_block(m_header.data_offset + offset, local_buf.get(), size);
- ensure(data_span.data() == static_cast(local_buf.get()));
+ const auto data_span = archive_read_block(m_header.data_offset + offset, local_buf, size);
+ ensure(data_span.data() == static_cast(local_buf));
// Get block count
const u64 blocks = (data_span.size() + 15) / 16;
+ const auto out_data = reinterpret_cast(local_buf);
if (m_header.pkg_type == PKG_RELEASE_TYPE_DEBUG)
{
@@ -1356,15 +1423,15 @@ std::span package_reader::decrypt(u64 offset, u64 size, const uchar*
// Initialize stream cipher for current position
input[7] = offset / 16 + i;
- union sha1_hash
+ struct sha1_hash
{
u8 data[20];
- u128 _v128;
- } hash;
+ } hash{};
sha1(reinterpret_cast(input), sizeof(input), hash.data);
- local_buf[i] ^= hash._v128;
+ const u128 v = read_from_ptr(out_data, i * 16);
+ write_to_ptr(out_data, i * 16, v ^ read_from_ptr(hash.data));
}
}
else if (m_header.pkg_type == PKG_RELEASE_TYPE_RELEASE)
@@ -1384,7 +1451,8 @@ std::span package_reader::decrypt(u64 offset, u64 size, const uchar*
aes_crypt_ecb(&ctx, AES_ENCRYPT, reinterpret_cast(&input), reinterpret_cast(&key));
- local_buf[i] ^= key;
+ const u128 v = read_from_ptr(out_data, i * 16);
+ write_to_ptr(out_data, i * 16, v ^ key);
}
}
else
@@ -1392,8 +1460,14 @@ std::span package_reader::decrypt(u64 offset, u64 size, const uchar*
pkg_log.error("Unknown release type (0x%x)", m_header.pkg_type);
}
+ if (blocks * 16 != size)
+ {
+ // Put NTS and other zeroes on unaligned reads
+ std::memset(out_data + size, 0, blocks * 16 - size);
+ }
+
// Return the amount of data written in buf
- return data_span;
+ return std::min(size, data_span.size());
}
int package_reader::get_progress(int maximum) const
diff --git a/rpcs3/Crypto/unpkg.h b/rpcs3/Crypto/unpkg.h
index 0f5c8faba1..8a7c482f16 100644
--- a/rpcs3/Crypto/unpkg.h
+++ b/rpcs3/Crypto/unpkg.h
@@ -314,11 +314,6 @@ struct package_install_result
class package_reader
{
- struct thread_key
- {
- const usz unique_num = umax;
- };
-
struct install_entry
{
typename std::map::value_type* weak_reference{};
@@ -354,7 +349,7 @@ public:
bool is_valid() const { return m_is_valid; }
package_install_result check_target_app_version() const;
static package_install_result extract_data(std::deque& readers, std::deque& bootable_paths);
- psf::registry get_psf() const { return m_psf; }
+ const psf::registry& get_psf() const { return m_psf; }
result get_result() const { return m_result; };
int get_progress(int maximum = 100) const;
@@ -365,14 +360,15 @@ private:
bool read_header();
bool read_metadata();
bool read_param_sfo();
- bool decrypt_data();
+ bool set_decryption_key();
+ bool read_entries(std::vector& entries);
void archive_seek(s64 new_offset, const fs::seek_mode damode = fs::seek_set);
u64 archive_read(void* data_ptr, u64 num_bytes);
bool set_install_path();
bool fill_data(std::map& all_install_entries);
std::span archive_read_block(u64 offset, void* data_ptr, u64 num_bytes);
- std::span decrypt(u64 offset, u64 size, const uchar* key, thread_key thread_data_key = {0});
- void extract_worker(thread_key thread_data_key);
+ usz decrypt(u64 offset, u64 size, const uchar* key, void* local_buf);
+ void extract_worker();
std::deque m_install_entries;
std::string m_install_path;
@@ -383,6 +379,7 @@ private:
bool m_was_null = false;
static constexpr usz BUF_SIZE = 8192 * 1024; // 8 MB
+ static constexpr usz BUF_PADDING = 32;
bool m_is_valid = false;
result m_result = result::not_started;
@@ -390,7 +387,6 @@ private:
std::string m_path{};
std::string m_install_dir{};
fs::file m_file{};
- std::vector> m_bufs{};
std::array m_dec_key{};
PKGHeader m_header{};
diff --git a/rpcs3/Crypto/unself.cpp b/rpcs3/Crypto/unself.cpp
index 66000c4f12..3855dcd62f 100644
--- a/rpcs3/Crypto/unself.cpp
+++ b/rpcs3/Crypto/unself.cpp
@@ -1045,11 +1045,8 @@ bool SELFDecrypter::DecryptNPDRM(u8 *metadata, u32 metadata_size)
}
else if (npd->license == 3) // Free license.
{
- // Use klicensee if available.
- if (key_v.GetKlicenseeKey())
- memcpy(npdrm_key, key_v.GetKlicenseeKey(), 0x10);
- else
- memcpy(npdrm_key, NP_KLIC_FREE, 0x10);
+ // Use klicensee if available. (may be set to NP_KLIC_FREE if none is set)
+ std::memcpy(npdrm_key, key_v.GetKlicenseeKey(), 0x10);
}
else
{
@@ -1085,7 +1082,7 @@ const NPD_HEADER* SELFDecrypter::GetNPDHeader() const
return nullptr;
}
-bool SELFDecrypter::LoadMetadata(u8* klic_key)
+bool SELFDecrypter::LoadMetadata(const u8* klic_key)
{
aes_context aes;
const auto metadata_info = std::make_unique(sizeof(meta_info));
@@ -1319,11 +1316,11 @@ static bool IsDebugSelf(const fs::file& f)
return false;
}
-static bool CheckDebugSelf(fs::file& s)
+static fs::file CheckDebugSelf(const fs::file& s)
{
if (s.size() < 0x18)
{
- return false;
+ return {};
}
// Get the key version.
@@ -1352,15 +1349,14 @@ static bool CheckDebugSelf(fs::file& s)
e.write(buf, size);
}
- s = std::move(e);
- return true;
+ return e;
}
// Leave the file untouched.
- return false;
+ return {};
}
-fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* out_info, bool require_encrypted)
+fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key, SelfAdditionalInfo* out_info)
{
if (out_info)
{
@@ -1377,10 +1373,10 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
// Check SELF header first. Check for a debug SELF.
if (elf_or_self.size() >= 4 && elf_or_self.read() == "SCE\0"_u32)
{
- if (CheckDebugSelf(elf_or_self))
+ if (fs::file res = CheckDebugSelf(elf_or_self))
{
// TODO: Decrypt
- return elf_or_self;
+ return res;
}
// Check the ELF file class (32 or 64 bit).
@@ -1399,14 +1395,14 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
// Load and decrypt the SELF file metadata.
if (!self_dec.LoadMetadata(klic_key))
{
- self_log.error("Failed to load SELF file metadata!");
+ (klic_key ? self_log.notice : self_log.error)("Failed to load SELF file metadata!");
return fs::file{};
}
// Decrypt the SELF file data.
if (!self_dec.DecryptData())
{
- self_log.error("Failed to decrypt SELF file data!");
+ (klic_key ? self_log.notice : self_log.error)("Failed to decrypt SELF file data!");
return fs::file{};
}
@@ -1414,12 +1410,7 @@ fs::file decrypt_self(fs::file elf_or_self, u8* klic_key, SelfAdditionalInfo* ou
return self_dec.MakeElf(isElf32);
}
- if (require_encrypted)
- {
- return {};
- }
-
- return elf_or_self;
+ return {};
}
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key, NPD_HEADER* npd_out)
diff --git a/rpcs3/Crypto/unself.h b/rpcs3/Crypto/unself.h
index afa3416095..1279bc961d 100644
--- a/rpcs3/Crypto/unself.h
+++ b/rpcs3/Crypto/unself.h
@@ -476,7 +476,7 @@ public:
fs::file MakeElf(bool isElf32);
bool LoadHeaders(bool isElf32, SelfAdditionalInfo* out_info = nullptr);
void ShowHeaders(bool isElf32);
- bool LoadMetadata(u8* klic_key);
+ bool LoadMetadata(const u8* klic_key);
bool DecryptData();
bool DecryptNPDRM(u8 *metadata, u32 metadata_size);
const NPD_HEADER* GetNPDHeader() const;
@@ -559,7 +559,7 @@ private:
}
};
-fs::file decrypt_self(fs::file elf_or_self, u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr, bool require_encrypted = false);
+fs::file decrypt_self(const fs::file& elf_or_self, const u8* klic_key = nullptr, SelfAdditionalInfo* additional_info = nullptr);
bool verify_npdrm_self_headers(const fs::file& self, u8* klic_key = nullptr, NPD_HEADER* npd_out = nullptr);
bool get_npdrm_self_header(const fs::file& self, NPD_HEADER& npd);
diff --git a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp
index 3931638c69..0a84d747bf 100644
--- a/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp
+++ b/rpcs3/Emu/Audio/XAudio2/XAudio2Backend.cpp
@@ -65,7 +65,7 @@ XAudio2Backend::XAudio2Backend()
m_com_init_success = true;
}
- if (HRESULT hr = XAudio2Create(instance.GetAddressOf(), 0, XAUDIO2_USE_DEFAULT_PROCESSOR); FAILED(hr))
+ if (HRESULT hr = XAudio2Create(&instance, 0, XAUDIO2_USE_DEFAULT_PROCESSOR); FAILED(hr))
{
XAudio.error("XAudio2Create() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
return;
@@ -78,7 +78,7 @@ XAudio2Backend::XAudio2Backend()
}
// Try to register a listener for device changes
- if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(enumerator.GetAddressOf())); FAILED(hr))
+ if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&enumerator)); FAILED(hr))
{
XAudio.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
return;
@@ -215,7 +215,7 @@ bool XAudio2Backend::Open(std::string_view dev_id, AudioFreq freq, AudioSampleSi
if (use_default_device)
{
Microsoft::WRL::ComPtr default_dev{};
- if (HRESULT hr = m_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, default_dev.GetAddressOf()); FAILED(hr))
+ if (HRESULT hr = m_device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &default_dev); FAILED(hr))
{
XAudio.error("GetDefaultAudioEndpoint() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
return false;
@@ -319,7 +319,7 @@ f64 XAudio2Backend::GetCallbackFrameLen()
Microsoft::WRL::ComPtr xaudio_ext{};
f64 min_latency{};
- if (HRESULT hr = m_xaudio2_instance->QueryInterface(IID_IXAudio2Extension, std::bit_cast(xaudio_ext.GetAddressOf())); FAILED(hr))
+ if (HRESULT hr = m_xaudio2_instance.As(&xaudio_ext); FAILED(hr))
{
XAudio.error("QueryInterface() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
}
diff --git a/rpcs3/Emu/Audio/XAudio2/xaudio2_enumerator.cpp b/rpcs3/Emu/Audio/XAudio2/xaudio2_enumerator.cpp
index 5f1fd1f44c..0655f29dca 100644
--- a/rpcs3/Emu/Audio/XAudio2/xaudio2_enumerator.cpp
+++ b/rpcs3/Emu/Audio/XAudio2/xaudio2_enumerator.cpp
@@ -26,7 +26,7 @@ xaudio2_enumerator::~xaudio2_enumerator()
std::vector xaudio2_enumerator::get_output_devices()
{
Microsoft::WRL::ComPtr devEnum{};
- if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(devEnum.GetAddressOf())); FAILED(hr))
+ if (HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&devEnum)); FAILED(hr))
{
xaudio_dev_enum.error("CoCreateInstance() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
return {};
@@ -57,7 +57,7 @@ std::vector xaudio2_enumerator::get_outpu
for (UINT dev_idx = 0; dev_idx < count; dev_idx++)
{
Microsoft::WRL::ComPtr endpoint{};
- if (HRESULT hr = devices->Item(dev_idx, endpoint.GetAddressOf()); FAILED(hr))
+ if (HRESULT hr = devices->Item(dev_idx, &endpoint); FAILED(hr))
{
xaudio_dev_enum.error("devices->Item() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
continue;
@@ -83,7 +83,7 @@ std::vector xaudio2_enumerator::get_outpu
CoTaskMemFree(id);
Microsoft::WRL::ComPtr props{};
- if (HRESULT hr = endpoint->OpenPropertyStore(STGM_READ, props.GetAddressOf()); FAILED(hr))
+ if (HRESULT hr = endpoint->OpenPropertyStore(STGM_READ, &props); FAILED(hr))
{
xaudio_dev_enum.error("endpoint->OpenPropertyStore() failed: %s (0x%08x)", std::system_category().message(hr), static_cast(hr));
continue;
diff --git a/rpcs3/Emu/CMakeLists.txt b/rpcs3/Emu/CMakeLists.txt
index cd4cdb2a46..562dd29476 100644
--- a/rpcs3/Emu/CMakeLists.txt
+++ b/rpcs3/Emu/CMakeLists.txt
@@ -48,6 +48,7 @@ target_include_directories(rpcs3_emu
target_sources(rpcs3_emu PRIVATE
../util/atomic.cpp
../util/console.cpp
+ ../util/emu_utils.cpp
../util/media_utils.cpp
../util/video_provider.cpp
../util/logs.cpp
@@ -61,6 +62,7 @@ target_sources(rpcs3_emu PRIVATE
../../Utilities/cheat_info.cpp
../../Utilities/cond.cpp
../../Utilities/Config.cpp
+ ../../Utilities/date_time.cpp
../../Utilities/File.cpp
../../Utilities/JITASM.cpp
../../Utilities/JITLLVM.cpp
@@ -482,6 +484,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Common/surface_store.cpp
RSX/Common/TextureUtils.cpp
RSX/Common/texture_cache.cpp
+ RSX/Common/texture_cache_types.cpp
RSX/Core/RSXContext.cpp
RSX/Core/RSXDisplay.cpp
RSX/Core/RSXDrawCommands.cpp
@@ -571,6 +574,7 @@ target_sources(rpcs3_emu PRIVATE
RSX/Program/program_util.cpp
RSX/Program/SPIRVCommon.cpp
RSX/Program/VertexProgramDecompiler.cpp
+ RSX/GSFrameBase.cpp
RSX/RSXDisAsm.cpp
RSX/RSXFIFO.cpp
RSX/RSXOffload.cpp
@@ -593,8 +597,10 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/vkutils/descriptors.cpp
RSX/VK/vkutils/image.cpp
RSX/VK/vkutils/image_helpers.cpp
+ RSX/VK/vkutils/instance.cpp
RSX/VK/vkutils/scratch.cpp
RSX/VK/vkutils/sync.cpp
+ RSX/VK/vkutils/swapchain.cpp
RSX/VK/vkutils/memory.cpp
RSX/VK/vkutils/device.cpp
RSX/VK/vkutils/sampler.cpp
@@ -627,11 +633,6 @@ if(TARGET 3rdparty_vulkan)
RSX/VK/VKVertexProgram.cpp
RSX/VK/VKTextureCache.cpp
)
- if(MSVC)
- set_source_files_properties(RSX/VK/vkutils/shared.cpp PROPERTIES
- COMPILE_FLAGS /EHs-
- SKIP_PRECOMPILE_HEADERS ON)
- endif()
endif()
target_link_libraries(rpcs3_emu
diff --git a/rpcs3/Emu/CPU/CPUDisAsm.h b/rpcs3/Emu/CPU/CPUDisAsm.h
index 1b4fc5515b..9e9054d62b 100644
--- a/rpcs3/Emu/CPU/CPUDisAsm.h
+++ b/rpcs3/Emu/CPU/CPUDisAsm.h
@@ -110,7 +110,8 @@ protected:
virtual u32 DisAsmBranchTarget(s32 /*imm*/);
// TODO: Add builtin fmt helpper for best performance
- template , int> = 0>
+ template
+ requires std::is_integral_v
static std::string SignedHex(T value)
{
const auto v = static_cast>(value);
diff --git a/rpcs3/Emu/CPU/CPUThread.cpp b/rpcs3/Emu/CPU/CPUThread.cpp
index 520446e991..242dcb9d9f 100644
--- a/rpcs3/Emu/CPU/CPUThread.cpp
+++ b/rpcs3/Emu/CPU/CPUThread.cpp
@@ -1302,7 +1302,7 @@ cpu_thread* cpu_thread::get_next_cpu()
return nullptr;
}
-std::shared_ptr make_disasm(const cpu_thread* cpu, shared_ptr handle);
+extern std::shared_ptr make_disasm(const cpu_thread* cpu, shared_ptr handle);
void cpu_thread::dump_all(std::string& ret) const
{
diff --git a/rpcs3/Emu/CPU/CPUTranslator.h b/rpcs3/Emu/CPU/CPUTranslator.h
index 7bab6b335a..088bd0801b 100644
--- a/rpcs3/Emu/CPU/CPUTranslator.h
+++ b/rpcs3/Emu/CPU/CPUTranslator.h
@@ -2,6 +2,12 @@
#ifdef LLVM_AVAILABLE
+#include "util/types.hpp"
+#include "util/sysinfo.hpp"
+#include "Utilities/StrFmt.h"
+#include "Utilities/JIT.h"
+#include "util/v128.hpp"
+
#ifdef _MSC_VER
#pragma warning(push, 0)
#else
@@ -24,7 +30,9 @@
#include "llvm/Analysis/ConstantFolding.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/IntrinsicsX86.h"
+#ifdef ARCH_ARM64
#include "llvm/IR/IntrinsicsAArch64.h"
+#endif
#include "llvm/IR/InlineAsm.h"
#ifdef _MSC_VER
@@ -33,12 +41,6 @@
#pragma GCC diagnostic pop
#endif
-#include "util/types.hpp"
-#include "util/sysinfo.hpp"
-#include "Utilities/StrFmt.h"
-#include "Utilities/JIT.h"
-
-#include "util/v128.hpp"
#include
#include
@@ -60,9 +62,8 @@ template
concept LLVMValue = (std::is_pointer_v) && (std::is_base_of_v>);
template
-concept DSLValue = requires (T& v)
-{
- { v.eval(std::declval*>()) } -> LLVMValue;
+concept DSLValue = requires(T& v, llvm::IRBuilder<>* ir) {
+ { v.eval(ir) } -> LLVMValue;
};
template
@@ -476,31 +477,33 @@ struct llvm_value_t : llvm_value_t >
template
using llvm_expr_t = std::decay_t;
-template
+template
struct is_llvm_expr
{
};
-template
-struct is_llvm_expr().eval(std::declval*>()))>>
+template
+struct is_llvm_expr
{
using type = typename std::decay_t::type;
};
-template
+template
struct is_llvm_expr_of
{
static constexpr bool ok = false;
};
template
-struct is_llvm_expr_of::type, typename is_llvm_expr::type>>
+ requires(requires { typename is_llvm_expr::type; } && requires { typename is_llvm_expr::type; })
+struct is_llvm_expr_of
{
static constexpr bool ok = std::is_same_v::type, typename is_llvm_expr::type>;
};
template
-using llvm_common_t = std::enable_if_t<(is_llvm_expr_of::ok && ...), typename is_llvm_expr::type>;
+ requires(is_llvm_expr_of::ok && ...)
+using llvm_common_t = typename is_llvm_expr::type;
template
using llvm_match_tuple = decltype(std::tuple_cat(std::declval&>().match(std::declval(), nullptr)...));
@@ -1606,7 +1609,8 @@ struct llvm_ord
};
template
-llvm_ord(T&&) -> llvm_ord>::value, T&&>>;
+ requires is_llvm_cmp>::value
+llvm_ord(T&&) -> llvm_ord;
template >
struct llvm_uno
@@ -1659,7 +1663,8 @@ struct llvm_uno
};
template
-llvm_uno(T&&) -> llvm_uno>::value, T&&>>;
+ requires is_llvm_cmp>::value
+llvm_uno(T&&) -> llvm_uno;
template
inline llvm_cmp operator ==(T1&& a1, T2&& a2)
@@ -3020,7 +3025,7 @@ struct llvm_calli
if (((std::get(r) = std::get(a).match(v[I], _m), v[I]) && ...))
{
return std::tuple_cat(std::get(r)...);
- }
+ }
}
}
}
@@ -3194,14 +3199,16 @@ public:
return {};
}
- template >
+ template