Merge branch 'main' into refactor

This commit is contained in:
georgemoralis 2024-10-18 10:56:00 +03:00 committed by GitHub
commit 2206ca129b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
491 changed files with 95919 additions and 9135 deletions

1
.github/FUNDING.yml vendored Normal file
View File

@ -0,0 +1 @@
ko_fi: shadps4

View File

@ -9,6 +9,8 @@ fi
export Qt6_DIR="/usr/lib/qt6" export Qt6_DIR="/usr/lib/qt6"
export PATH="$Qt6_DIR/bin:$PATH" export PATH="$Qt6_DIR/bin:$PATH"
export EXTRA_QT_PLUGINS="waylandcompositor"
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
# Prepare Tools for building the AppImage # Prepare Tools for building the AppImage
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
@ -22,5 +24,10 @@ chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
# Build AppImage # Build AppImage
./linuxdeploy-x86_64.AppImage --appdir AppDir ./linuxdeploy-x86_64.AppImage --appdir AppDir
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir ./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt --output appimage
cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/.github/shadps4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/.github/shadps4.png --plugin qt
rm AppDir/usr/plugins/multimedia/libgstreamermediaplugin.so
./linuxdeploy-x86_64.AppImage --appdir AppDir --output appimage
mv Shadps4-x86_64.AppImage Shadps4-qt.AppImage mv Shadps4-x86_64.AppImage Shadps4-qt.AppImage

481
.github/workflows/build.yml vendored Normal file
View File

@ -0,0 +1,481 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Build and Release
on: [push, pull_request]
concurrency:
group: ci-${{ github.event_name }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'push' }}
env:
BUILD_TYPE: Release
jobs:
reuse:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: fsfe/reuse-action@v4
clang-format:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main'
sudo apt update
sudo apt install clang-format-17
- name: Build
env:
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
run: ./.ci/clang-format.sh
get-info:
runs-on: ubuntu-latest
outputs:
date: ${{ steps.vars.outputs.date }}
shorthash: ${{ steps.vars.outputs.shorthash }}
steps:
- uses: actions/checkout@v4
- name: Get date and git hash
id: vars
run: |
echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
echo "shorthash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
echo "shorthash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
windows-sdl:
runs-on: windows-latest
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-sdl-ninja-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Setup VS Environment
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: amd64
- name: Configure CMake
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload Windows SDL artifact
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: ${{github.workspace}}/build/shadPS4.exe
windows-qt:
runs-on: windows-latest
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Qt
uses: jurplel/install-qt-action@v4
with:
version: 6.7.3
host: windows
target: desktop
arch: win64_msvc2019_64
archives: qtbase qttools
modules: qtmultimedia
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-ninja-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Setup VS Environment
uses: ilammy/msvc-dev-cmd@v1.13.0
with:
arch: amd64
- name: Configure CMake
run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Deploy and Package
run: |
mkdir upload
move build/shadPS4.exe upload
windeployqt --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --dir upload upload/shadPS4.exe
Compress-Archive -Path upload/* -DestinationPath shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}.zip
- name: Upload Windows Qt artifact
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: upload/
macos-sdl:
runs-on: macos-latest
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup latest Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Install MoltenVK
run: |
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 molten-vk
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{runner.os}}-sdl-cache-cmake-build
with:
append-timestamp: false
create-symlink: true
key: ${{env.cache-name}}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
variant: sccache
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)
- name: Package and Upload macOS SDL artifact
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4 upload
cp $(arch -x86_64 /usr/local/bin/brew --prefix)/opt/molten-vk/lib/libMoltenVK.dylib upload
tar cf shadps4-macos-sdl.tar.gz -C upload .
- uses: actions/upload-artifact@v4
with:
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: shadps4-macos-sdl.tar.gz
macos-qt:
runs-on: macos-latest
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup latest Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Install MoltenVK and Setup Qt
run: |
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 molten-vk
- uses: jurplel/install-qt-action@v4
with:
version: 6.7.3
host: mac
target: desktop
arch: clang_64
archives: qtbase qttools
modules: qtmultimedia
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{runner.os}}-qt-cache-cmake-build
with:
append-timestamp: false
create-symlink: true
key: ${{env.cache-name}}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
variant: sccache
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)
- name: Package and Upload macOS Qt artifact
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4.app upload
macdeployqt upload/shadps4.app
tar cf shadps4-macos-qt.tar.gz -C upload .
- uses: actions/upload-artifact@v4
with:
name: shadps4-macos-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: shadps4-macos-qt.tar.gz
linux-sdl:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Package and Upload Linux(ubuntu64) SDL artifact
run: |
ls -la ${{ github.workspace }}/build/shadps4
- uses: actions/upload-artifact@v4
with:
name: shadps4-ubuntu64-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: ${{ github.workspace }}/build/shadps4
- name: Run AppImage packaging script
run: ./.github/linux-appimage-sdl.sh
- name: Package and Upload Linux SDL artifact
run: |
tar cf shadps4-linux-sdl.tar.gz -C ${{github.workspace}}/build shadps4
- uses: actions/upload-artifact@v4
with:
name: shadps4-linux-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: Shadps4-sdl.AppImage
linux-qt:
runs-on: ubuntu-24.04
needs: get-info
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev
- name: Cache CMake Configuration
uses: actions/cache@v4
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
with:
path: |
${{github.workspace}}/build
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
restore-keys: |
${{ env.cache-name }}-
- name: Cache CMake Build
uses: hendrikmuhs/ccache-action@v1.2.14
env:
cache-name: ${{ runner.os }}-qt-cache-cmake-build
with:
append-timestamp: false
key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
- name: Configure CMake
run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel3
- name: Run AppImage packaging script
run: ./.github/linux-appimage-qt.sh
- name: Package and Upload Linux Qt artifact
run: |
tar cf shadps4-linux-qt.tar.gz -C ${{github.workspace}}/build shadps4
- uses: actions/upload-artifact@v4
with:
name: shadps4-linux-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
path: Shadps4-qt.AppImage
pre-release:
if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: ./artifacts
- name: Compress individual directories (without parent directory)
run: |
cd ./artifacts
for dir in */; do
if [ -d "$dir" ]; then
dir_name=${dir%/}
echo "Creating zip for $dir_name"
(cd "$dir_name" && zip -r "../${dir_name}.zip" .)
fi
done
- name: Get latest release information
id: get_latest_release
env:
GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
run: |
api_url="https://api.github.com/repos/${{ github.repository }}"
latest_release_info=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url/releases/latest")
echo "last_release_tag=$(echo "$latest_release_info" | jq -r '.tag_name')" >> $GITHUB_ENV
- name: Create Pre-Release on GitHub
id: create_release
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.SHADPS4_TOKEN_REPO }}
name: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
draft: false
prerelease: true
body: "Full Changelog: [${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }}](https://github.com/shadps4-emu/shadPS4/compare/${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }})"
artifacts: ./artifacts/*.zip
- name: Get current pre-release information
env:
GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
run: |
api_url="https://api.github.com/repos/${{ github.repository }}/releases"
# Get all releases (sorted by date)
releases=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url")
# Capture the most recent pre-release (assuming the first one is the latest)
current_release=$(echo "$releases" | jq -c '.[] | select(.prerelease == true) | .published_at' | sort -r | head -n 1)
# Remove extra quotes from captured date
current_release=$(echo $current_release | tr -d '"')
# Export the current published_at to be available for the next step
echo "CURRENT_PUBLISHED_AT=$current_release" >> $GITHUB_ENV
- name: Delete old pre-releases and tags
env:
GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
run: |
api_url="https://api.github.com/repos/${{ github.repository }}/releases"
# Get current pre-releases
releases=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url")
# Remove extra quotes from captured date
CURRENT_PUBLISHED_AT=$(echo $CURRENT_PUBLISHED_AT | tr -d '"')
# Convert CURRENT_PUBLISHED_AT para timestamp Unix
current_published_ts=$(date -d "$CURRENT_PUBLISHED_AT" +%s)
# Identify pre-releases
echo "$releases" | jq -c '.[] | select(.prerelease == true)' | while read -r release; do
release_date=$(echo "$release" | jq -r '.published_at')
release_id=$(echo "$release" | jq -r '.id')
release_tag=$(echo "$release" | jq -r '.tag_name')
# Remove extra quotes from captured date
release_date=$(echo $release_date | tr -d '"')
# Convert release_date para timestamp Unix
release_date_ts=$(date -d "$release_date" +%s)
# Compare timestamps and delete old pre-releases
if [[ "$release_date_ts" -lt "$current_published_ts" ]]; then
echo "Deleting old pre-release: $release_id from $release_date with tag: $release_tag"
# Delete the pre-release
curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" "$api_url/$release_id"
# Delete the tag
curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$release_tag"
else
echo "Skipping pre-release: $release_id (newer or same date)"
fi
done

View File

@ -1,17 +0,0 @@
# SPDX-FileCopyrightText: 2021 yuzu Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Reuse
on:
push:
branches: [ main ]
tags: [ "*" ]
pull_request:
branches: [ main ]
jobs:
reuse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: fsfe/reuse-action@v4

View File

@ -1,28 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Clang Format
on:
push:
branches: [ "*" ]
pull_request:
branches: [ main ]
jobs:
clang-format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install
run: |
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main'
sudo apt update
sudo apt install clang-format-17
- name: Build
env:
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
run: ./.ci/clang-format.sh

View File

@ -1,41 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Linux-Qt
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install misc packages
run: >
sudo apt-get update && sudo apt install libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential qt6-base-dev
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Run AppImage packaging script
run: ./.github/linux-appimage-qt.sh
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-linux-qt
path: Shadps4-qt.AppImage

View File

@ -1,48 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Linux
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install misc packages
run: >
sudo apt-get update && sudo apt install libx11-dev libxext-dev libwayland-dev libfuse2 clang build-essential
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-ubuntu64
path: |
${{github.workspace}}/build/shadps4
- name: Run AppImage packaging script
run: ./.github/linux-appimage-sdl.sh
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-sdl-appimage
path: Shadps4-sdl.AppImage

View File

@ -1,60 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: macOS-Qt
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup latest Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Install MoltenVK
run: |
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 molten-vk
- name: Setup Qt
uses: jurplel/install-qt-action@v4
with:
version: 6.7.2
host: mac
target: desktop
arch: clang_64
archives: qtbase
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DENABLE_QT_GUI=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)
- name: Package
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4.app upload
macdeployqt upload/shadps4.app
tar cf shadps4-macos-qt.tar.gz -C upload .
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-macos-qt
path: shadps4-macos-qt.tar.gz

View File

@ -1,52 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: macOS
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup latest Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: latest
- name: Install MoltenVK
run: |
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 molten-vk
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)
- name: Package
run: |
mkdir upload
mv ${{github.workspace}}/build/shadps4 upload
cp $(arch -x86_64 /usr/local/bin/brew --prefix)/opt/molten-vk/lib/libMoltenVK.dylib upload
install_name_tool -add_rpath "@loader_path" upload/shadps4
tar cf shadps4-macos-sdl.tar.gz -C upload .
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-macos-sdl
path: shadps4-macos-sdl.tar.gz

View File

@ -1,49 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Windows-Qt
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Qt
uses: jurplel/install-qt-action@v4
with:
version: 6.7.2
host: windows
target: desktop
arch: win64_msvc2019_64
archives: qtbase
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T ClangCL -DENABLE_QT_GUI=ON
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Deploy
run: |
mkdir upload
move build/Release/shadPS4.exe upload
windeployqt --dir upload upload/shadPS4.exe
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-qt
path: upload

View File

@ -1,34 +0,0 @@
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
name: Windows
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
env:
BUILD_TYPE: Release
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -T ClangCL
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel
- name: Upload executable
uses: actions/upload-artifact@v4
with:
name: shadps4-win64-sdl
path: |
${{github.workspace}}/build/Release/shadPS4.exe

5
.gitignore vendored
View File

@ -387,6 +387,8 @@ FodyWeavers.xsd
!.vscode/launch.json !.vscode/launch.json
!.vscode/extensions.json !.vscode/extensions.json
*.code-workspace *.code-workspace
/CMakeUserPresets.json
/compile_commands.json
# Local History for Visual Studio Code # Local History for Visual Studio Code
.history/ .history/
@ -409,3 +411,6 @@ FodyWeavers.xsd
/out/* /out/*
/third-party/out/* /third-party/out/*
/src/common/scm_rev.cpp /src/common/scm_rev.cpp
# for macOS
**/.DS_Store

17
.gitmodules vendored
View File

@ -81,4 +81,21 @@
[submodule "externals/ffmpeg-core"] [submodule "externals/ffmpeg-core"]
path = externals/ffmpeg-core path = externals/ffmpeg-core
url = https://github.com/shadps4-emu/ext-ffmpeg-core.git url = https://github.com/shadps4-emu/ext-ffmpeg-core.git
shallow = true
[submodule "externals/half"]
path = externals/half
url = https://github.com/ROCm/half.git
shallow = true
[submodule "externals/dear_imgui"]
path = externals/dear_imgui
url = https://github.com/shadps4-emu/ext-imgui.git
shallow = true
branch = docking
[submodule "externals/pugixml"]
path = externals/pugixml
url = https://github.com/zeux/pugixml.git
shallow = true
[submodule "externals/discord-rpc"]
path = externals/discord-rpc
url = https://github.com/shadps4-emu/ext-discord-rpc.git
shallow = true shallow = true

View File

@ -1,60 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Comment: It is best to use this file to record copyright information about
generated, binary and third party files
Files: CMakeSettings.json
.github/shadps4.desktop
.github/shadps4.png
.gitmodules
documents/changelog.txt
documents/readme.txt
documents/Quickstart/1.png
documents/Quickstart/2.png
documents/Screenshots/Bloodborne.png
documents/Screenshots/Sonic Mania.png
documents/Screenshots/Undertale.png
documents/Screenshots/We are DOOMED.png
scripts/ps4_names.txt
src/images/about_icon.png
src/images/controller_icon.png
src/images/exit_icon.png
src/images/file_icon.png
src/images/flag_china.png
src/images/flag_eu.png
src/images/flag_jp.png
src/images/flag_unk.png
src/images/flag_us.png
src/images/flag_world.png
src/images/folder_icon.png
src/images/grid_icon.png
src/images/iconsize_icon.png
src/images/list_icon.png
src/images/list_mode_icon.png
src/images/pause_icon.png
src/images/play_icon.png
src/images/refresh_icon.png
src/images/settings_icon.png
src/images/stop_icon.png
src/images/shadPS4.icns
src/images/shadps4.ico
src/images/themes_icon.png
src/shadps4.qrc
src/shadps4.rc
Copyright: shadPS4 Emulator Project
License: GPL-2.0-or-later
Files: externals/cmake-modules/*
Copyright: 2009-2010 Iowa State University
License: BSL-1.0
Files: externals/renderdoc/*
Copyright: 2019-2024 Baldur Karlsson
License: MIT
Files: externals/stb_image.h
Copyright: 2017 Sean Barrett
License: MIT
Files: externals/tracy/*
Copyright: 2017-2024 Bartosz Taudul <wolf@nereid.pl>
License: BSD-3-Clause

267
CMakeLists.txt Normal file → Executable file
View File

@ -8,7 +8,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
if(APPLE) if(APPLE)
enable_language(OBJC) enable_language(OBJC)
set(CMAKE_OSX_DEPLOYMENT_TARGET 11) set(CMAKE_OSX_DEPLOYMENT_TARGET 14)
endif() endif()
if (NOT CMAKE_BUILD_TYPE) if (NOT CMAKE_BUILD_TYPE)
@ -17,8 +17,47 @@ endif()
project(shadPS4) project(shadPS4)
# Forcing PIE makes sure that the base address is high enough so that it doesn't clash with the PS4 memory.
if(UNIX AND NOT APPLE)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
# check PIE support at link time
include(CheckPIESupported)
check_pie_supported(OUTPUT_VARIABLE pie_check LANGUAGES C CXX)
if(NOT CMAKE_C_LINK_PIE_SUPPORTED OR NOT CMAKE_CXX_LINK_PIE_SUPPORTED)
message(WARNING "PIE is not supported at link time: ${pie_check}")
endif()
endif()
option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF) option(ENABLE_QT_GUI "Enable the Qt GUI. If not selected then the emulator uses a minimal SDL-based UI instead" OFF)
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
else()
set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
endif()
# Next, match common architecture strings down to a known common value.
if (BASE_ARCHITECTURE MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
set(ARCHITECTURE "x86_64")
elseif (BASE_ARCHITECTURE MATCHES "(aarch64)|(AARCH64)|(arm64)|(ARM64)")
set(ARCHITECTURE "arm64")
else()
message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}")
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
# Exclude ARM homebrew path to avoid conflicts when cross compiling.
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
# Need to reconfigure pkg-config to use the right architecture library paths.
# It's not ideal to override these but otherwise the build breaks just by having pkg-config installed.
set(ENV{PKG_CONFIG_DIR} "")
set(ENV{PKG_CONFIG_LIBDIR} "${CMAKE_SYSROOT}/usr/lib/pkgconfig:${CMAKE_SYSROOT}/usr/share/pkgconfig:${CMAKE_SYSROOT}/usr/local/lib/pkgconfig:${CMAKE_SYSROOT}/usr/local/share/pkgconfig")
set(ENV{PKG_CONFIG_SYSROOT_DIR} ${CMAKE_SYSROOT})
endif()
# This function should be passed a list of all files in a target. It will automatically generate file groups # This function should be passed a list of all files in a target. It will automatically generate file groups
# following the directory hierarchy, so that the layout of the files in IDEs matches the one in the filesystem. # following the directory hierarchy, so that the layout of the files in IDEs matches the one in the filesystem.
function(create_target_directory_groups target_name) function(create_target_directory_groups target_name)
@ -62,14 +101,15 @@ include(GetGitRevisionDescription)
get_git_head_revision(GIT_REF_SPEC GIT_REV) get_git_head_revision(GIT_REF_SPEC GIT_REV)
git_describe(GIT_DESC --always --long --dirty) git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH) git_branch_name(GIT_BRANCH)
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp" @ONLY) configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp" @ONLY)
find_package(Boost 1.84.0 CONFIG) find_package(Boost 1.84.0 CONFIG)
find_package(cryptopp 8.9.0 MODULE)
find_package(FFmpeg 5.1.2 MODULE) find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.1 CONFIG) find_package(fmt 10.2.0 CONFIG)
find_package(glslang 14.2.0 CONFIG) find_package(glslang 14.2.0 CONFIG)
find_package(half 1.12.0 MODULE)
find_package(magic_enum 0.9.6 CONFIG) find_package(magic_enum 0.9.6 CONFIG)
find_package(RenderDoc 1.6.0 MODULE) find_package(RenderDoc 1.6.0 MODULE)
find_package(SDL3 3.1.2 CONFIG) find_package(SDL3 3.1.2 CONFIG)
@ -79,8 +119,13 @@ find_package(VulkanHeaders 1.3.289 CONFIG)
find_package(VulkanMemoryAllocator 3.1.0 CONFIG) find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
find_package(xbyak 7.07 CONFIG) find_package(xbyak 7.07 CONFIG)
find_package(xxHash 0.8.2 MODULE) find_package(xxHash 0.8.2 MODULE)
find_package(zlib-ng 2.2.0 MODULE) find_package(zlib-ng 2.1.7 MODULE)
find_package(Zydis 4.1.0 CONFIG) find_package(Zydis 5.0.0 CONFIG)
find_package(pugixml 1.14 CONFIG)
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
find_package(cryptopp 8.9.0 MODULE)
endif()
if (APPLE) if (APPLE)
find_package(date 3.0.1 CONFIG) find_package(date 3.0.1 CONFIG)
@ -92,10 +137,6 @@ check_symbol_exists(pthread_mutex_timedlock "pthread.h" HAVE_PTHREAD_MUTEX_TIMED
if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32) if(HAVE_PTHREAD_MUTEX_TIMEDLOCK OR WIN32)
add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK) add_compile_options(-DHAVE_PTHREAD_MUTEX_TIMEDLOCK)
endif() endif()
check_symbol_exists(sem_timedwait "semaphore.h" HAVE_SEM_TIMEDWAIT)
if(HAVE_SEM_TIMEDWAIT OR WIN32)
add_compile_options(-DHAVE_SEM_TIMEDWAIT)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
# libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support. # libc++ requires -fexperimental-library to enable std::jthread and std::stop_token support.
@ -110,11 +151,27 @@ add_subdirectory(externals)
include_directories(src) include_directories(src)
if(ENABLE_QT_GUI) if(ENABLE_QT_GUI)
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent) find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
qt_standard_project_setup() qt_standard_project_setup()
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
set(QT_TRANSLATIONS "${PROJECT_SOURCE_DIR}/src/qt_gui/translations")
file(GLOB_RECURSE TRANSLATIONS_TS ${QT_TRANSLATIONS}/*.ts)
set_source_files_properties(${TRANSLATIONS_TS} PROPERTIES OUTPUT_LOCATION "${CMAKE_CURRENT_BINARY_DIR}/translations")
qt_add_translation(TRANSLATIONS_QM ${TRANSLATIONS_TS})
set(TRANSLATIONS_QRC ${CMAKE_CURRENT_BINARY_DIR}/translations/translations.qrc)
file(WRITE ${TRANSLATIONS_QRC} "<RCC><qresource prefix=\"translations\">\n")
foreach (QM ${TRANSLATIONS_QM})
get_filename_component(QM_FILE ${QM} NAME)
file(APPEND ${TRANSLATIONS_QRC} "<file>${QM_FILE}</file>\n")
endforeach (QM)
file(APPEND ${TRANSLATIONS_QRC} "</qresource></RCC>")
qt_add_resources(TRANSLATIONS ${TRANSLATIONS_QRC})
endif() endif()
set(AUDIO_CORE src/audio_core/sdl_audio.cpp set(AUDIO_CORE src/audio_core/sdl_audio.cpp
@ -133,9 +190,10 @@ set(AUDIO_LIB src/core/libraries/audio/audioin.cpp
set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp
src/core/libraries/gnmdriver/gnmdriver.h src/core/libraries/gnmdriver/gnmdriver.h
src/core/libraries/gnmdriver/gnm_error.h
) )
set(KERNEL_LIB set(KERNEL_LIB
src/core/libraries/kernel/event_flag/event_flag.cpp src/core/libraries/kernel/event_flag/event_flag.cpp
src/core/libraries/kernel/event_flag/event_flag.h src/core/libraries/kernel/event_flag/event_flag.h
src/core/libraries/kernel/event_flag/event_flag_obj.cpp src/core/libraries/kernel/event_flag/event_flag_obj.cpp
@ -167,6 +225,9 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/net.cpp src/core/libraries/network/net.cpp
src/core/libraries/network/netctl.cpp src/core/libraries/network/netctl.cpp
src/core/libraries/network/netctl.h src/core/libraries/network/netctl.h
src/core/libraries/network/net_ctl_obj.cpp
src/core/libraries/network/net_ctl_obj.h
src/core/libraries/network/net_ctl_codes.h
src/core/libraries/network/net.h src/core/libraries/network/net.h
src/core/libraries/network/ssl.cpp src/core/libraries/network/ssl.cpp
src/core/libraries/network/ssl.h src/core/libraries/network/ssl.h
@ -176,13 +237,21 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/system/commondialog.h src/core/libraries/system/commondialog.h
src/core/libraries/system/msgdialog.cpp src/core/libraries/system/msgdialog.cpp
src/core/libraries/system/msgdialog.h src/core/libraries/system/msgdialog.h
src/core/libraries/system/msgdialog_ui.cpp
src/core/libraries/system/posix.cpp src/core/libraries/system/posix.cpp
src/core/libraries/system/posix.h src/core/libraries/system/posix.h
src/core/libraries/save_data/error_codes.h src/core/libraries/save_data/save_backup.cpp
src/core/libraries/save_data/save_backup.h
src/core/libraries/save_data/save_instance.cpp
src/core/libraries/save_data/save_instance.h
src/core/libraries/save_data/save_memory.cpp
src/core/libraries/save_data/save_memory.h
src/core/libraries/save_data/savedata.cpp src/core/libraries/save_data/savedata.cpp
src/core/libraries/save_data/savedata.h src/core/libraries/save_data/savedata.h
src/core/libraries/system/savedatadialog.cpp src/core/libraries/save_data/dialog/savedatadialog.cpp
src/core/libraries/system/savedatadialog.h src/core/libraries/save_data/dialog/savedatadialog.h
src/core/libraries/save_data/dialog/savedatadialog_ui.cpp
src/core/libraries/save_data/dialog/savedatadialog_ui.h
src/core/libraries/system/sysmodule.cpp src/core/libraries/system/sysmodule.cpp
src/core/libraries/system/sysmodule.h src/core/libraries/system/sysmodule.h
src/core/libraries/system/systemservice.cpp src/core/libraries/system/systemservice.cpp
@ -214,6 +283,20 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/ngs2/ngs2_error.h src/core/libraries/ngs2/ngs2_error.h
src/core/libraries/ngs2/ngs2_impl.cpp src/core/libraries/ngs2/ngs2_impl.cpp
src/core/libraries/ngs2/ngs2_impl.h src/core/libraries/ngs2/ngs2_impl.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.h
src/core/libraries/audio3d/audio3d_error.h
src/core/libraries/audio3d/audio3d_impl.cpp
src/core/libraries/audio3d/audio3d_impl.h
src/core/libraries/ime/ime.cpp
src/core/libraries/ime/ime.h
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
src/core/libraries/game_live_streaming/gamelivestreaming.h
src/core/libraries/remote_play/remoteplay.cpp
src/core/libraries/remote_play/remoteplay.h
src/core/libraries/share_play/shareplay.cpp
src/core/libraries/share_play/shareplay.h
) )
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
@ -229,6 +312,8 @@ set(LIBC_SOURCES src/core/libraries/libc_internal/libc_internal.cpp
set(DIALOGS_LIB src/core/libraries/dialogs/error_dialog.cpp set(DIALOGS_LIB src/core/libraries/dialogs/error_dialog.cpp
src/core/libraries/dialogs/error_dialog.h src/core/libraries/dialogs/error_dialog.h
src/core/libraries/dialogs/ime_dialog_ui.cpp
src/core/libraries/dialogs/ime_dialog_ui.h
src/core/libraries/dialogs/ime_dialog.cpp src/core/libraries/dialogs/ime_dialog.cpp
src/core/libraries/dialogs/ime_dialog.h src/core/libraries/dialogs/ime_dialog.h
src/core/libraries/dialogs/error_codes.h src/core/libraries/dialogs/error_codes.h
@ -249,24 +334,54 @@ set(PLAYGO_LIB src/core/libraries/playgo/playgo.cpp
set(RANDOM_LIB src/core/libraries/random/random.cpp set(RANDOM_LIB src/core/libraries/random/random.cpp
src/core/libraries/random/random.h src/core/libraries/random/random.h
src/core/libraries/random/random_error.h
) )
set(USBD_LIB src/core/libraries/usbd/usbd.cpp set(USBD_LIB src/core/libraries/usbd/usbd.cpp
src/core/libraries/usbd/usbd.h src/core/libraries/usbd/usbd.h
) )
set(FIBER_LIB src/core/libraries/fiber/fiber.cpp
src/core/libraries/fiber/fiber.h
)
set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp set(NP_LIBS src/core/libraries/np_manager/np_manager.cpp
src/core/libraries/np_manager/np_manager.h src/core/libraries/np_manager/np_manager.h
src/core/libraries/np_score/np_score.cpp src/core/libraries/np_score/np_score.cpp
src/core/libraries/np_score/np_score.h src/core/libraries/np_score/np_score.h
src/core/libraries/np_trophy/np_trophy.cpp src/core/libraries/np_trophy/np_trophy.cpp
src/core/libraries/np_trophy/np_trophy.h src/core/libraries/np_trophy/np_trophy.h
src/core/libraries/np_trophy/trophy_ui.cpp
src/core/libraries/np_trophy/trophy_ui.h
) )
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
src/core/libraries/screenshot/screenshot.h src/core/libraries/screenshot/screenshot.h
) )
set(DEV_TOOLS src/core/devtools/layer.cpp
src/core/devtools/layer.h
src/core/devtools/options.cpp
src/core/devtools/options.h
src/core/devtools/gcn/gcn_context_regs.cpp
src/core/devtools/gcn/gcn_op_names.cpp
src/core/devtools/gcn/gcn_shader_regs.cpp
src/core/devtools/widget/cmd_list.cpp
src/core/devtools/widget/cmd_list.h
src/core/devtools/widget/common.h
src/core/devtools/widget/frame_dump.cpp
src/core/devtools/widget/frame_dump.h
src/core/devtools/widget/frame_graph.cpp
src/core/devtools/widget/frame_graph.h
src/core/devtools/widget/imgui_memory_editor.h
src/core/devtools/widget/reg_popup.cpp
src/core/devtools/widget/reg_popup.h
src/core/devtools/widget/reg_view.cpp
src/core/devtools/widget/reg_view.h
src/core/devtools/widget/text_editor.cpp
src/core/devtools/widget/text_editor.h
)
set(COMMON src/common/logging/backend.cpp set(COMMON src/common/logging/backend.cpp
src/common/logging/backend.h src/common/logging/backend.h
src/common/logging/filter.cpp src/common/logging/filter.cpp
@ -278,6 +393,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/logging/text_formatter.h src/common/logging/text_formatter.h
src/common/logging/types.h src/common/logging/types.h
src/common/alignment.h src/common/alignment.h
src/common/arch.h
src/common/assert.cpp src/common/assert.cpp
src/common/assert.h src/common/assert.h
src/common/bit_field.h src/common/bit_field.h
@ -285,9 +401,13 @@ set(COMMON src/common/logging/backend.cpp
src/common/concepts.h src/common/concepts.h
src/common/config.cpp src/common/config.cpp
src/common/config.h src/common/config.h
src/common/cstring.h
src/common/debug.h src/common/debug.h
src/common/disassembler.cpp src/common/decoder.cpp
src/common/disassembler.h src/common/decoder.h
src/common/discord_rpc_handler.cpp
src/common/discord_rpc_handler.h
src/common/elf_info.h
src/common/endian.h src/common/endian.h
src/common/enum.h src/common/enum.h
src/common/io_file.cpp src/common/io_file.cpp
@ -295,6 +415,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/error.cpp src/common/error.cpp
src/common/error.h src/common/error.h
src/common/scope_exit.h src/common/scope_exit.h
src/common/fixed_value.h
src/common/func_traits.h src/common/func_traits.h
src/common/native_clock.cpp src/common/native_clock.cpp
src/common/native_clock.h src/common/native_clock.h
@ -304,6 +425,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/polyfill_thread.h src/common/polyfill_thread.h
src/common/rdtsc.cpp src/common/rdtsc.cpp
src/common/rdtsc.h src/common/rdtsc.h
src/common/signal_context.h
src/common/signal_context.cpp
src/common/singleton.h src/common/singleton.h
src/common/slot_vector.h src/common/slot_vector.h
src/common/string_util.cpp src/common/string_util.cpp
@ -316,6 +439,10 @@ set(COMMON src/common/logging/backend.cpp
src/common/version.h src/common/version.h
src/common/ntapi.h src/common/ntapi.h
src/common/ntapi.cpp src/common/ntapi.cpp
src/common/number_utils.h
src/common/number_utils.cpp
src/common/memory_patcher.h
src/common/memory_patcher.cpp
src/common/scm_rev.cpp src/common/scm_rev.cpp
src/common/scm_rev.h src/common/scm_rev.h
) )
@ -326,10 +453,8 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/aerolib.h src/core/aerolib/aerolib.h
src/core/address_space.cpp src/core/address_space.cpp
src/core/address_space.h src/core/address_space.h
src/core/cpu_patches.cpp
src/core/cpu_patches.h
src/core/crypto/crypto.cpp src/core/crypto/crypto.cpp
src/core/crypto/crypto.h src/core/crypto/crypto.h
src/core/crypto/keys.h src/core/crypto/keys.h
src/core/file_format/pfs.h src/core/file_format/pfs.h
src/core/file_format/pkg.cpp src/core/file_format/pkg.cpp
@ -354,7 +479,7 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/loader/elf.h src/core/loader/elf.h
src/core/loader/symbols_resolver.h src/core/loader/symbols_resolver.h
src/core/loader/symbols_resolver.cpp src/core/loader/symbols_resolver.cpp
src/core/libraries/error_codes.h src/core/libraries/error_codes.h
src/core/libraries/libs.h src/core/libraries/libs.h
src/core/libraries/libs.cpp src/core/libraries/libs.cpp
${AUDIO_LIB} ${AUDIO_LIB}
@ -372,6 +497,10 @@ set(CORE src/core/aerolib/stubs.cpp
${USBD_LIB} ${USBD_LIB}
${MISC_LIBS} ${MISC_LIBS}
${DIALOGS_LIB} ${DIALOGS_LIB}
${FIBER_LIB}
${DEV_TOOLS}
src/core/debug_state.cpp
src/core/debug_state.h
src/core/linker.cpp src/core/linker.cpp
src/core/linker.h src/core/linker.h
src/core/memory.cpp src/core/memory.cpp
@ -379,17 +508,29 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/module.cpp src/core/module.cpp
src/core/module.h src/core/module.h
src/core/platform.h src/core/platform.h
src/core/signals.cpp
src/core/signals.h
src/core/tls.cpp src/core/tls.cpp
src/core/tls.h src/core/tls.h
src/core/virtual_memory.cpp src/core/virtual_memory.cpp
src/core/virtual_memory.h src/core/virtual_memory.h
) )
if (ARCHITECTURE STREQUAL "x86_64")
set(CORE ${CORE}
src/core/cpu_patches.cpp
src/core/cpu_patches.h)
endif()
set(SHADER_RECOMPILER src/shader_recompiler/exception.h set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/profile.h src/shader_recompiler/profile.h
src/shader_recompiler/recompiler.cpp src/shader_recompiler/recompiler.cpp
src/shader_recompiler/recompiler.h src/shader_recompiler/recompiler.h
src/shader_recompiler/info.h
src/shader_recompiler/params.h
src/shader_recompiler/runtime_info.h src/shader_recompiler/runtime_info.h
src/shader_recompiler/specialization.h
src/shader_recompiler/backend/bindings.h
src/shader_recompiler/backend/spirv/emit_spirv.cpp src/shader_recompiler/backend/spirv/emit_spirv.cpp
src/shader_recompiler/backend/spirv/emit_spirv.h src/shader_recompiler/backend/spirv/emit_spirv.h
src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp
@ -413,6 +554,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/frontend/translate/data_share.cpp src/shader_recompiler/frontend/translate/data_share.cpp
src/shader_recompiler/frontend/translate/export.cpp src/shader_recompiler/frontend/translate/export.cpp
src/shader_recompiler/frontend/translate/scalar_alu.cpp src/shader_recompiler/frontend/translate/scalar_alu.cpp
src/shader_recompiler/frontend/translate/scalar_flow.cpp
src/shader_recompiler/frontend/translate/scalar_memory.cpp src/shader_recompiler/frontend/translate/scalar_memory.cpp
src/shader_recompiler/frontend/translate/translate.cpp src/shader_recompiler/frontend/translate/translate.cpp
src/shader_recompiler/frontend/translate/translate.h src/shader_recompiler/frontend/translate/translate.h
@ -421,6 +563,8 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/frontend/translate/vector_memory.cpp src/shader_recompiler/frontend/translate/vector_memory.cpp
src/shader_recompiler/frontend/control_flow_graph.cpp src/shader_recompiler/frontend/control_flow_graph.cpp
src/shader_recompiler/frontend/control_flow_graph.h src/shader_recompiler/frontend/control_flow_graph.h
src/shader_recompiler/frontend/copy_shader.cpp
src/shader_recompiler/frontend/copy_shader.h
src/shader_recompiler/frontend/decode.cpp src/shader_recompiler/frontend/decode.cpp
src/shader_recompiler/frontend/decode.h src/shader_recompiler/frontend/decode.h
src/shader_recompiler/frontend/fetch_shader.cpp src/shader_recompiler/frontend/fetch_shader.cpp
@ -431,12 +575,13 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/frontend/opcodes.h src/shader_recompiler/frontend/opcodes.h
src/shader_recompiler/frontend/structured_control_flow.cpp src/shader_recompiler/frontend/structured_control_flow.cpp
src/shader_recompiler/frontend/structured_control_flow.h src/shader_recompiler/frontend/structured_control_flow.h
src/shader_recompiler/ir/passes/constant_propogation_pass.cpp src/shader_recompiler/ir/passes/constant_propagation_pass.cpp
src/shader_recompiler/ir/passes/dead_code_elimination_pass.cpp src/shader_recompiler/ir/passes/dead_code_elimination_pass.cpp
src/shader_recompiler/ir/passes/identity_removal_pass.cpp src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h src/shader_recompiler/ir/passes/ir_passes.h
src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
src/shader_recompiler/ir/abstract_syntax_list.h src/shader_recompiler/ir/abstract_syntax_list.h
@ -469,6 +614,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/amdgpu/pm4_cmds.h src/video_core/amdgpu/pm4_cmds.h
src/video_core/amdgpu/pm4_opcodes.h src/video_core/amdgpu/pm4_opcodes.h
src/video_core/amdgpu/resource.h src/video_core/amdgpu/resource.h
src/video_core/amdgpu/types.h
src/video_core/amdgpu/default_context.cpp
src/video_core/buffer_cache/buffer.cpp src/video_core/buffer_cache/buffer.cpp
src/video_core/buffer_cache/buffer.h src/video_core/buffer_cache/buffer.h
src/video_core/buffer_cache/buffer_cache.cpp src/video_core/buffer_cache/buffer_cache.cpp
@ -494,6 +641,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/vk_master_semaphore.h src/video_core/renderer_vulkan/vk_master_semaphore.h
src/video_core/renderer_vulkan/vk_pipeline_cache.cpp src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
src/video_core/renderer_vulkan/vk_pipeline_cache.h src/video_core/renderer_vulkan/vk_pipeline_cache.h
src/video_core/renderer_vulkan/vk_pipeline_common.cpp
src/video_core/renderer_vulkan/vk_pipeline_common.h
src/video_core/renderer_vulkan/vk_platform.cpp src/video_core/renderer_vulkan/vk_platform.cpp
src/video_core/renderer_vulkan/vk_platform.h src/video_core/renderer_vulkan/vk_platform.h
src/video_core/renderer_vulkan/vk_rasterizer.cpp src/video_core/renderer_vulkan/vk_rasterizer.cpp
@ -519,6 +668,7 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/texture_cache/tile_manager.cpp src/video_core/texture_cache/tile_manager.cpp
src/video_core/texture_cache/tile_manager.h src/video_core/texture_cache/tile_manager.h
src/video_core/texture_cache/types.h src/video_core/texture_cache/types.h
src/video_core/texture_cache/host_compatibility.h
src/video_core/page_manager.cpp src/video_core/page_manager.cpp
src/video_core/page_manager.h src/video_core/page_manager.h
src/video_core/multi_level_page_table.h src/video_core/multi_level_page_table.h
@ -526,6 +676,20 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderdoc.h src/video_core/renderdoc.h
) )
set(IMGUI src/imgui/imgui_config.h
src/imgui/imgui_layer.h
src/imgui/imgui_std.h
src/imgui/imgui_texture.h
src/imgui/renderer/imgui_core.cpp
src/imgui/renderer/imgui_core.h
src/imgui/renderer/imgui_impl_sdl3.cpp
src/imgui/renderer/imgui_impl_sdl3.h
src/imgui/renderer/imgui_impl_vulkan.cpp
src/imgui/renderer/imgui_impl_vulkan.h
src/imgui/renderer/texture_manager.cpp
src/imgui/renderer/texture_manager.h
)
set(INPUT src/input/controller.cpp set(INPUT src/input/controller.cpp
src/input/controller.h src/input/controller.h
) )
@ -544,6 +708,12 @@ qt_add_resources(RESOURCE_FILES src/shadps4.qrc)
set(QT_GUI src/qt_gui/about_dialog.cpp set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/about_dialog.h src/qt_gui/about_dialog.h
src/qt_gui/about_dialog.ui src/qt_gui/about_dialog.ui
src/qt_gui/background_music_player.cpp
src/qt_gui/background_music_player.h
src/qt_gui/cheats_patches.cpp
src/qt_gui/cheats_patches.h
src/qt_gui/check_update.cpp
src/qt_gui/check_update.h
src/qt_gui/main_window_ui.h src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp src/qt_gui/main_window.cpp
src/qt_gui/main_window.h src/qt_gui/main_window.h
@ -557,6 +727,8 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/game_grid_frame.h src/qt_gui/game_grid_frame.h
src/qt_gui/game_install_dialog.cpp src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h src/qt_gui/game_install_dialog.h
src/qt_gui/install_dir_select.cpp
src/qt_gui/install_dir_select.h
src/qt_gui/pkg_viewer.cpp src/qt_gui/pkg_viewer.cpp
src/qt_gui/pkg_viewer.h src/qt_gui/pkg_viewer.h
src/qt_gui/trophy_viewer.cpp src/qt_gui/trophy_viewer.cpp
@ -571,12 +743,14 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/main.cpp src/qt_gui/main.cpp
${EMULATOR} ${EMULATOR}
${RESOURCE_FILES} ${RESOURCE_FILES}
${TRANSLATIONS}
) )
endif() endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
qt_add_executable(shadps4 qt_add_executable(shadps4
${AUDIO_CORE} ${AUDIO_CORE}
${IMGUI}
${INPUT} ${INPUT}
${QT_GUI} ${QT_GUI}
${COMMON} ${COMMON}
@ -589,6 +763,7 @@ if (ENABLE_QT_GUI)
else() else()
add_executable(shadps4 add_executable(shadps4
${AUDIO_CORE} ${AUDIO_CORE}
${IMGUI}
${INPUT} ${INPUT}
${COMMON} ${COMMON}
${CORE} ${CORE}
@ -605,16 +780,26 @@ endif()
create_target_directory_groups(shadps4) create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3) target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::SPIRV glslang::glslang SDL3::SDL3 pugixml::pugixml)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
if (APPLE) if (APPLE)
# Reserve system-managed memory space. option(USE_SYSTEM_VULKAN_LOADER "Enables using the system Vulkan loader instead of directly linking with MoltenVK. Useful for loading validation layers." OFF)
target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x400000,-segaddr,GUEST_SYSTEM,0x400000,-image_base,0x10000000000) if (USE_SYSTEM_VULKAN_LOADER)
target_compile_definitions(shadps4 PRIVATE USE_SYSTEM_VULKAN_LOADER=1)
else()
# Link MoltenVK for Vulkan support
find_library(MOLTENVK MoltenVK REQUIRED)
target_link_libraries(shadps4 PRIVATE ${MOLTENVK})
endif()
# Link MoltenVK for Vulkan support if (ARCHITECTURE STREQUAL "x86_64")
find_library(MOLTENVK MoltenVK REQUIRED) # Reserve system-managed memory space.
target_link_libraries(shadps4 PRIVATE ${MOLTENVK}) target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,GUEST_SYSTEM,0x400000,-image_base,0x20000000000)
endif()
# Replacement for std::chrono::time_zone # Replacement for std::chrono::time_zone
target_link_libraries(shadps4 PRIVATE date::date-tz) target_link_libraries(shadps4 PRIVATE date::date-tz)
@ -631,7 +816,8 @@ else()
endif() endif()
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent) target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI)
endif() endif()
if (WIN32) if (WIN32)
@ -686,6 +872,11 @@ add_subdirectory(${HOST_SHADERS_INCLUDE})
add_dependencies(shadps4 host_shaders) add_dependencies(shadps4 host_shaders)
target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE}) target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
# ImGui resources
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/imgui/renderer)
add_dependencies(shadps4 ImGui_Resources)
target_include_directories(shadps4 PRIVATE ${IMGUI_RESOURCES_INCLUDE})
if (ENABLE_QT_GUI) if (ENABLE_QT_GUI)
set_target_properties(shadps4 PROPERTIES set_target_properties(shadps4 PROPERTIES
# WIN32_EXECUTABLE ON # WIN32_EXECUTABLE ON
@ -695,3 +886,21 @@ if (ENABLE_QT_GUI)
set_source_files_properties(src/images/shadPS4.icns PROPERTIES set_source_files_properties(src/images/shadPS4.icns PROPERTIES
MACOSX_PACKAGE_LOCATION Resources) MACOSX_PACKAGE_LOCATION Resources)
endif() endif()
if (UNIX AND NOT APPLE)
if (ENABLE_QT_GUI)
find_package(OpenSSL REQUIRED)
target_link_libraries(shadps4 PRIVATE ${OPENSSL_LIBRARIES})
endif()
endif()
# Discord RPC
target_link_libraries(shadps4 PRIVATE discord-rpc)
# Install rules
install(TARGETS shadps4 BUNDLE DESTINATION .)
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
install(FILES ".github/shadps4.desktop" DESTINATION "share/applications")
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps")
endif()

View File

@ -9,7 +9,8 @@
"cmakeCommandArgs": "", "cmakeCommandArgs": "",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ] "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
}, },
{ {
"name": "x64-Clang-Debug", "name": "x64-Clang-Debug",
@ -20,7 +21,8 @@
"cmakeCommandArgs": "", "cmakeCommandArgs": "",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ] "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
}, },
{ {
"name": "x64-Clang-RelWithDebInfo", "name": "x64-Clang-RelWithDebInfo",
@ -31,7 +33,8 @@
"cmakeCommandArgs": "", "cmakeCommandArgs": "",
"buildCommandArgs": "", "buildCommandArgs": "",
"ctestCommandArgs": "", "ctestCommandArgs": "",
"inheritEnvironments": [ "clang_cl_x64_x64" ] "inheritEnvironments": [ "clang_cl_x64_x64" ],
"intelliSenseMode": "windows-clang-x64"
} }
] ]
} }

View File

@ -69,7 +69,7 @@ enum class SomeEnum {
* Note that the asterisks are indented by one space to align to the first line. * Note that the asterisks are indented by one space to align to the first line.
*/ */
struct Position { struct Position {
// Always intitialize member variables! // Always initialize member variables!
int x{}; int x{};
int y{}; int y{};
}; };

43
LICENSES/OFL-1.1.txt Normal file
View File

@ -0,0 +1,43 @@
SIL OPEN FONT LICENSE
Version 1.1 - 26 February 2007
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the copyright statement(s).
"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting, or substituting — in part or in whole — any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.

View File

@ -12,7 +12,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
</h1> </h1>
<h1 align="center"> <h1 align="center">
<a href="https://discord.gg/MyZRaBngxA"> <a href="https://discord.gg/bFJxfftGW6">
<img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4 Discord&logo=Discord&logoColor=white" width="240"> <img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4 Discord&logo=Discord&logoColor=white" width="240">
<a href="https://github.com/shadps4-emu/shadPS4/releases/latest"> <a href="https://github.com/shadps4-emu/shadPS4/releases/latest">
<img src="https://img.shields.io/github/downloads/shadps4-emu/shadPS4/total.svg" width="140"> <img src="https://img.shields.io/github/downloads/shadps4-emu/shadPS4/total.svg" width="140">
@ -26,33 +26,34 @@ SPDX-License-Identifier: GPL-2.0-or-later
<p align="center"> <p align="center">
<a href="https://shadps4.net/"> <a href="https://shadps4.net/">
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/Sonic Mania.png" width="400"> <img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/1.png" width="400">
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/Bloodborne.png" width="400"> <img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/2.png" width="400">
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/Undertale.png" width="400"> <img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/3.png" width="400">
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/We are DOOMED.png" width="400"> <img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Screenshots/4.png" width="400">
</p> </p>
# shadPS4 # General information
shadPS4 is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++ **shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md). If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/Quickstart.md).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility).\
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-emu/shadps4-game-compatibility). To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
To get the latest news, go to our [**X (Twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).\
To discuss shadPS4 development or suggest ideas, join the [**Discord server**](https://discord.gg/MyZRaBngxA). For those who'd like to donate to the project, we now have a [**Kofi page**](https://ko-fi.com/shadps4)!
To get the latest news, go to our [**X (twitter)**](https://x.com/shadps4) or our [**website**](https://shadps4.net/).
# Status # Status
In development, small games are working like [**Sonic Mania**](https://www.youtube.com/watch?v=AAHoNzhHyCU), [**Undertale**](https://youtu.be/5zIvdy65Ro4), [**Dysmantle**](https://youtu.be/b9xzhLBdESE) and others... > [!IMPORTANT]
> shadPS4 is early in development, don't expect a flawless experience.
Currently, the emulator can successfully run games like [**Bloodborne**](https://www.youtube.com/watch?v=wC6s0avpQRE), [**Dark Souls Remastered**](https://www.youtube.com/watch?v=-3PA-Xwszts), [**Red Dead Redemption**](https://www.youtube.com/watch?v=Al7yz_5nLag) and many other games.
# Why # Why
The project started as a fun project. Due to limited free time, it will probably take a while before shadPS4 is able to run anything decent, but we're trying to make small, regular commits. This project began as a fun project. Given our limited free time, it may take some time before shadPS4 can run more complex games, but we're committed to making small, regular updates.
# Build # Building
## Windows ## Windows
@ -62,42 +63,23 @@ Check the build instructions for [**Windows**](https://github.com/shadps4-emu/sh
Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-linux.md). Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-linux.md).
## Build status ## macOS
<details> Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
<summary><b>Windows</b></summary>
| Windows | Build status | > [!IMPORTANT]
|--------|--------| > macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices.
|Windows SDL Build|[![Windows-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml)
|Windows Qt Build|[![Windows-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows-qt.yml)
</details>
<details>
<summary><b>Linux</b></summary>
| Linux | Build status |
|--------|--------|
|Linux SDL Build|[![Linux-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml)
|Linux Qt Build|[![Linux-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux-qt.yml)
</details>
<details>
<summary><b>macOS</b></summary>
| macOS | Build status |
|--------|--------|
|macOS SDL Build|[![macOS-sdl](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos.yml)
|macOS Qt Build|[![macOS-qt](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos-qt.yml/badge.svg)](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos-qt.yml)
</details>
# Debugging and reporting issues # Debugging and reporting issues
For more information on how to test, debug and report issues with the emulator or games, read the [Debugging documentation](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md). For more information on how to test, debug and report issues with the emulator or games, read the [**Debugging documentation**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md).
# Keyboard Mapping # Keyboard mapping
| Controller button | Keyboard | > [!NOTE]
> Xbox and DualShock controllers work out of the box.
| Controller button | Keyboard equivelant |
|-------------|-------------| |-------------|-------------|
LEFT AXIS UP | W | LEFT AXIS UP | W |
LEFT AXIS DOWN | S | LEFT AXIS DOWN | S |
@ -116,7 +98,7 @@ PAD DOWN | DOWN |
PAD LEFT | LEFT | PAD LEFT | LEFT |
PAD RIGHT | RIGHT | PAD RIGHT | RIGHT |
OPTIONS | RETURN | OPTIONS | RETURN |
TOUCH PAD | SPACE | BACK BUTTON / TOUCH PAD | SPACE |
L1 | Q | L1 | Q |
R1 | U | R1 | U |
L2 | E | L2 | E |
@ -137,8 +119,7 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
# Contributing # Contributing
If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file. If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
Open a PR and we'll check it :) Open a PR and we'll check it :)
# Contributors # Contributors
@ -147,11 +128,19 @@ Open a PR and we'll check it :)
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=15"> <img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=15">
</a> </a>
# Sister Projects
- [**Panda3DS**](https://github.com/wheremyfoodat/Panda3DS): A multiplatform 3DS emulator from our co-author wheremyfoodat. # Special Thanks
A few noteworthy teams/projects who've helped us along the way are:
- [**Panda3DS**](https://github.com/wheremyfoodat/Panda3DS): A multiplatform 3DS emulator from our co-author wheremyfoodat. They have been incredibly helpful in understanding and solving problems that came up from natively executing the x64 code of PS4 binaries
- [**fpPS4**](https://github.com/red-prig/fpPS4): The fpPS4 team has assisted massively with understanding some of the more complex parts of the PS4 operating system and libraries, by helping with reverse engineering work and research.
- **yuzu**: Our shader compiler has been designed with yuzu's Hades compiler as a blueprint. This allowed us to focus on the challenges of emulating a modern AMD GPU while having a high-quality optimizing shader compiler implementation as a base.
- [**hydra**](https://github.com/hydra-emu/hydra): A multisystem, multiplatform emulator (chip-8, GB, NES, N64) from Paris. - [**hydra**](https://github.com/hydra-emu/hydra): A multisystem, multiplatform emulator (chip-8, GB, NES, N64) from Paris.
# License # License
- [**GPL-2.0 license**](https://github.com/shadps4-emu/shadPS4/blob/main/LICENSE) - [**GPL-2.0 license**](https://github.com/shadps4-emu/shadPS4/blob/main/LICENSE)

87
REUSE.toml Normal file
View File

@ -0,0 +1,87 @@
version = 1
[[annotations]]
path = [
"REUSE.toml",
"CMakeSettings.json",
".github/FUNDING.yml",
".github/shadps4.desktop",
".github/shadps4.png",
".gitmodules",
"documents/changelog.txt",
"documents/Quickstart/2.png",
"documents/Screenshots/*",
"scripts/ps4_names.txt",
"src/images/about_icon.png",
"src/images/controller_icon.png",
"src/images/dump_icon.png",
"src/images/exit_icon.png",
"src/images/file_icon.png",
"src/images/flag_china.png",
"src/images/flag_eu.png",
"src/images/flag_jp.png",
"src/images/flag_unk.png",
"src/images/flag_us.png",
"src/images/flag_world.png",
"src/images/folder_icon.png",
"src/images/grid_icon.png",
"src/images/iconsize_icon.png",
"src/images/list_icon.png",
"src/images/list_mode_icon.png",
"src/images/pause_icon.png",
"src/images/play_icon.png",
"src/images/refresh_icon.png",
"src/images/settings_icon.png",
"src/images/stop_icon.png",
"src/images/shadPS4.icns",
"src/images/shadps4.ico",
"src/images/themes_icon.png",
"src/images/update_icon.png",
"src/shadps4.qrc",
"src/shadps4.rc",
]
precedence = "aggregate"
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
SPDX-License-Identifier = "GPL-2.0-or-later"
[[annotations]]
path = "externals/cmake-modules/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2009-2010 Iowa State University"
SPDX-License-Identifier = "BSL-1.0"
[[annotations]]
path = "externals/renderdoc/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2019-2024 Baldur Karlsson"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "externals/stb_image.h"
precedence = "aggregate"
SPDX-FileCopyrightText = "2017 Sean Barrett"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "externals/tracy/**"
precedence = "aggregate"
SPDX-FileCopyrightText = "2017-2024 Bartosz Taudul <wolf@nereid.pl>"
SPDX-License-Identifier = "BSD-3-Clause"
[[annotations]]
path = "src/imgui/renderer/fonts/NotoSansJP-Regular.ttf"
precedence = "aggregate"
SPDX-FileCopyrightText = "2012 Google Inc. All Rights Reserved."
SPDX-License-Identifier = "OFL-1.1"
[[annotations]]
path = "src/imgui/renderer/fonts/ProggyVector-Regular.ttf"
precedence = "aggregate"
SPDX-FileCopyrightText = "Copyright (c) 2004, 2005 Tristan Grimmer"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "externals/gcn/include/**"
SPDX-FileCopyrightText = "NONE"
SPDX-License-Identifier = "CC0-1.0"

28
cmake/Findhalf.cmake Normal file
View File

@ -0,0 +1,28 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
find_path(half_INCLUDE_DIR NAMES half.hpp PATH_SUFFIXES half)
if (half_INCLUDE_DIR)
file(STRINGS "${half_INCLUDE_DIR}/half.hpp" _ver_line
REGEX "^// Version [0-9.]+$"
LIMIT_COUNT 1
)
string(REGEX MATCH "[0-9.]+" half_VERSION "${_ver_line}")
unset(_ver_line)
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(half
REQUIRED_VARS half_INCLUDE_DIR
VERSION_VAR half_VERSION
)
if (half_FOUND AND NOT TARGET half::half)
add_library(half::half INTERFACE IMPORTED)
set_target_properties(half::half PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${half_INCLUDE_DIR}"
)
endif()
mark_as_advanced(half_INCLUDE_DIR)

View File

@ -7,21 +7,22 @@ SPDX-License-Identifier: GPL-2.0-or-later
## Summary ## Summary
- [PC Requirements](#pc-requirements) - [**PC Requirements**](#minimum-pc-requirements)
- [CPU](#cpu) - [**CPU**](#cpu)
- [GPU](#gpu) - [**GPU**](#gpu)
- [RAM](#ram) - [**RAM**](#ram)
- [OS](#os) - [**OS**](#os)
- [Have the latest WIP version](#have-the-latest-wip-version) - [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
- [Install PKG files (Games and Updates)](#install-pkg-files) - [**Install PKG files (Games and Updates)**](#install-pkg-files)
- [Configure the emulator](#configure-the-emulator) - [**Configure the emulator**](#configure-the-emulator)
## PC Requirements ## Minimum PC requirements
### CPU ### CPU
- A processor with at least 4 cores and 6 threads - A processor with at least 4 cores and 6 threads
- Above 2.5 GHz frequency - Above 2.5 GHz frequency
- required support AVX2 extension or Rosetta 2 on ARM
### GPU ### GPU
@ -37,45 +38,25 @@ SPDX-License-Identifier: GPL-2.0-or-later
- Windows 10 or Ubuntu 22.04 - Windows 10 or Ubuntu 22.04
## How to run the latest Work-in-Progress builds of ShadPS4 ## How to run the latest Work-in-Progress builds of shadPS4
1. Go to <https://github.com/shadps4-emu/shadPS4/actions> and make sure you are logged into your GitHub account (important!) 1. Go to <https://github.com/shadps4-emu/shadPS4/releases> In the release identified as 'pre-release' click on the down arrow(Assets), select your operating system of choice (the "**qt**" versions have a user interface, which is probably the one you want. The others are SDL versions, which can only be run via command line).
2. On the left side of the page, select your operating system of choice (the "**qt**" versions have a user interface, which is probably the one you want. The others are SDL versions, which can only be run via command line). ![image](https://github.com/user-attachments/assets/43f01bbf-236c-4d6d-98ac-f5a5badd4ce8) ![image](https://github.com/user-attachments/assets/af520c77-797c-41a0-8f67-d87f5de3e3df)
3. In the workflow list, select the latest entry with a green :white_check_mark: icon in front of it. (or the latest entry for whatever pull request you wish to test). ![image](https://github.com/user-attachments/assets/6365f407-867c-44ae-bf00-944f8d84a349) 2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
4. On the bottom of this page, select the name of the file, and it should start downloading. (If there is no file here, double check that you are indeed logged into a GitHub account, and that there is a green :white_check_mark: icon. ![image](https://github.com/user-attachments/assets/97924500-3911-4f90-ab63-ffae7e52700b) 3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to.
5. Once downloaded, extract to its own folder, and run ShadPS4's executable from the extracted folder.
6. Upon first launch, ShadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that ShadPS4 can use to install your PKG files to.
## Install PKG files ## Install PKG files
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application. To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800"></a> <img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
## Configure the emulator ## Configure the emulator
You can configure the emulator by editing the `config.toml` file found in the `user` folder created after starting the application.\ To configure the emulator, you can go through the interface and go to "settings".
Some settings may be related to more technical development and debugging. For more information on those, see [Debugging](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
Here's a list of configuration entries that are worth changing: You can also configure the emulator by editing the `config.toml` file located in the `user` folder created after the application is started (Mostly useful if you are using the SDL version).
Some settings may be related to more technical development and debugging.\
- `[General]` For more information on this, see [**Debugging**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#configuration).
- `Fullscreen`: Display the game in a full screen borderless window.
- `logType`: Configures logging synchronization (`sync`/`async`)
- It can be beneficial to set this to `sync` in order for the log to accurately maintain message order, at the cost of performance.
- Use when sending logs to developers. See more about [reporting issues](https://github.com/shadps4-emu/shadPS4/blob/main/documents/Debugging/Debugging.md#reporting-and-communicating-about-issues).
- `logFilter`: Sets the logging category for various logging classes.
- Format: `<class>:<level> ...`, `<class.*>:<level> <*:level> ...`
- Valid log levels: `Trace, Debug, Info, Warning, Error, Critical` - in this order, setting a level silences all levels preceding it and logs every level after it.
- Examples:
- If the log is being spammed with messages coming from Lib.Pad, you can use `Lib.Pad:Critical` to only log critical-level messages.
- If you'd like to mute everything, but still want to receive messages from Vulkan rendering: `*:Error Render.Vulkan:Info`
- `[GPU]`
- `screenWidth` and `screenHeight`: Configures the game window width and height.

BIN
documents/Screenshots/1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

BIN
documents/Screenshots/2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

BIN
documents/Screenshots/3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
documents/Screenshots/4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 350 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 850 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

View File

@ -3,28 +3,28 @@ SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later
--> -->
## Build shadPS4 for Linux ## Build shadPS4 for Linux
### Install the necessary tools to build shadPS4: ### Install the necessary tools to build shadPS4:
#### Debian & Ubuntu #### Debian & Ubuntu
``` ```
sudo apt-get install build-essential libasound2-dev libpulse-dev libopenal-dev zlib1g-dev libedit-dev libvulkan-dev libudev-dev git libevdev-dev libsdl2-2.0 libsdl2-dev libjack-dev libsndio-dev sudo apt install build-essential clang git cmake libasound2-dev libpulse-dev libopenal-dev libssl-dev zlib1g-dev libedit-dev libudev-dev libevdev-dev libsdl2-dev libjack-dev libsndio-dev qt6-base-dev qt6-tools-dev qt6-multimedia-dev libvulkan-dev vulkan-validationlayers
``` ```
#### Fedora #### Fedora
``` ```
sudo dnf install alsa-lib-devel cmake libatomic libevdev-devel libudev-devel openal-devel qt6-qtbase-devel qt6-qtbase-private-devel vulkan-devel pipewire-jack-audio-connection-kit-devel qt6-qtmultimedia-devel qt6-qtsvg-devel sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel libXext-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers
``` ```
#### Arch Linux #### Arch Linux
``` ```
sudo pacman -S openal cmake vulkan-validation-layers qt6-base qt6-declarative qt6-multimedia sdl2 sndio jack2 base-devel sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers
``` ```
#### OpenSUSE #### OpenSUSE
``` ```
sudo zypper install git cmake libasound2 libpulse-devel openal-soft-devel zlib-devel libedit-devel vulkan-devel libudev-devel libqt6-qtbase-devel libqt6-qtmultimedia-devel libqt6-qtsvg-devel libQt6Gui-private-headers-devel libevdev-devel libsndio7_1 libjack-devel sudo zypper install clang git cmake libasound2 libpulse-devel libsndio7 libjack-devel openal-soft-devel libopenssl-devel zlib-devel libedit-devel systemd-devel libevdev-devel qt6-base-devel qt6-multimedia-devel qt6-svg-devel qt6-linguist-devel qt6-gui-private-devel vulkan-devel vulkan-validationlayers
``` ```
### Cloning and compiling: ### Cloning and compiling:
@ -34,9 +34,11 @@ git clone --recursive https://github.com/shadps4-emu/shadPS4.git
cd shadPS4 cd shadPS4
``` ```
Generate the build directory in the shadPS4 directory: Generate the build directory in the shadPS4 directory. To disable the QT GUI, remove the ```-DENABLE_QT_GUI=ON``` flag:
**Note**: Clang is the compiler used for official builds and CI. If you build with GCC, you might encounter issues—please report any you find. If you choose to use GCC, we recommend building with Clang at least once before submitting a pull request.
``` ```
cmake -S . -B build/ cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
``` ```
Enter the directory: Enter the directory:
@ -49,8 +51,11 @@ Use make to build the project:
cmake --build . --parallel$(nproc) cmake --build . --parallel$(nproc)
``` ```
Now run the emulator: Now run the emulator. If QT is enabled:
```
./shadps4
```
Otherwise, specify the path to your PKG's boot file:
``` ```
./shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin ./shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
``` ```

View File

@ -0,0 +1,73 @@
<!--
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later
-->
## Build shadPS4 for macOS
### Install the necessary tools to build shadPS4:
First, make sure you have **Xcode 16.0 or newer** installed.
For installing other tools and library dependencies we will be using [Homebrew](https://brew.sh/).
On an ARM system, we will need the native ARM Homebrew to install tools and x86_64 Homebrew to install libraries.
First, install native Homebrew and tools:
```
# Installs native Homebrew to /opt/homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Adds Homebrew to your path
echo 'eval $(/opt/homebrew/bin/brew shellenv)' >> ~/.zprofile
eval $(/opt/homebrew/bin/brew shellenv)
# Installs tools.
brew install clang-format cmake
```
Next, install x86_64 Homebrew and libraries.
**If you are on an ARM Mac:**
```
# Installs x86_64 Homebrew to /usr/local
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# Installs libraries.
arch -x86_64 /usr/local/bin/brew install molten-vk qt@6
```
**If you are on an x86_64 Mac:**
```
brew install molten-vk qt@6
```
If you don't need the Qt GUI you can remove `qt@6` from the last command.
### Cloning and compiling:
Clone the repository recursively:
```
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
cd shadPS4
```
Generate the build directory in the shadPS4 directory:
```
cmake -S . -B build/ -DCMAKE_OSX_ARCHITECTURES=x86_64
```
If you want to build the Qt GUI, add `-DENABLE_QT_GUI=ON` to the end of this command as well.
Enter the directory:
```
cd build/
```
Use make to build the project:
```
cmake --build . --parallel$(sysctl -n hw.ncpu)
```
Now run the emulator:
```
./shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
```

View File

@ -6,7 +6,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
# Build shadPS4 for Windows # Build shadPS4 for Windows
This tutorial reads as if you have none of the prerequisites already installed. If you do, just ignore the steps regarding installation. This tutorial reads as if you have none of the prerequisites already installed. If you do, just ignore the steps regarding installation.
If you are building to contribute to the project, please omit `--depth 1` from the git invokations. If you are building to contribute to the project, please omit `--depth 1` from the git invocations.
Note: **ARM64 is not supported!** As of writing, it will not build nor run. The instructions with respect to ARM64 are for developers only. Note: **ARM64 is not supported!** As of writing, it will not build nor run. The instructions with respect to ARM64 are for developers only.
@ -15,36 +15,57 @@ Note: **ARM64 is not supported!** As of writing, it will not build nor run. The
### (Prerequisite) Download the Community edition from [**Visual Studio 2022**](https://visualstudio.microsoft.com/vs/) ### (Prerequisite) Download the Community edition from [**Visual Studio 2022**](https://visualstudio.microsoft.com/vs/)
Once you are within the installer: Once you are within the installer:
1. Select `Desktop development with C++` 1. Select `Desktop development with C++`
2. Go to "Individual Components" tab 2. Go to "Individual Components" tab
3. Make sure `C++ Clang Compiler for Windows`, `MSBuild support for LLVM` and `C++ CMake Tools for Windows` are selected 3. Search and select `C++ Clang Compiler for Windows` and `MSBuild support for LLVM`
4. Continue the installation 4. Continue the installation
### (Prerequisite) Download [**Qt**](https://doc.qt.io/qt-6/get-and-install-qt.html) ### (Prerequisite) Download [**Qt**](https://doc.qt.io/qt-6/get-and-install-qt.html)
Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead. Beware, this requires you to create a Qt account. If you do not want to do this, please follow the MSYS2/MinGW compilation method instead.
1. Select Qt for Visual Studio plugin 1. Under the current, non beta version of Qt (at the time of writing 6.7.2), select the option `MSVC 2019 64-bit` or similar.
2. Select `msvc2019_64` option or similar. If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `msvc2019_arm64` If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2019 ARM64` instead.
Go through the installation normally. If you do not know what components to select, just select the newest Qt version it gives you. Go through the installation normally. If you know what you are doing, you may unselect individual components that eat up too much disk space.
If you know what you are doing, you may unselect individual components that eat up too much disk space.
2. Download and install [Qt Visual Studio Tools](https://marketplace.visualstudio.com/items?itemName=TheQtCompany.QtVisualStudioTools2022)
Once you are finished, you will have to configure Qt within Visual Studio: Once you are finished, you will have to configure Qt within Visual Studio:
1. Tools -> Options -> Qt -> Versions 1. Tools -> Options -> Qt -> Versions
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.7.1\msvc2019_64` 2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.7.2\msvc2019_64`
3. Enable the default checkmark on the new version you just created. 3. Enable the default checkmark on the new version you just created.
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win) ### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
Go through the Git for Windows installation as normal Go through the Git for Windows installation as normal
### Compiling with Visual Studio GUI ### Cloning the source code
1. Open Git for Windows, navigate to a place where you want to store the shadPS4 source code folder 1. Open Git for Windows, navigate to a place where you want to store the shadPS4 source code folder
2. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4` 2. Clone the repository by running
3. Open up Visual Studio, select `Open a local folder` and select the folder with the shadPS4 source code. The folder should contain `CMakeLists.txt` `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
4. Build -> Build All
### Compiling with Visual Studio GUI
1. Open up Visual Studio, select `Open a local folder` and select the folder with the shadPS4 source code. The folder should contain `CMakeLists.txt`
2. Change x64-Clang-Debug to x64-Clang-Release if you want a regular, non-debug build.
3. If you want to build shadPS4 with the Qt Gui:
1. Click x64-Clang-Release and select "Manage Configurations"
2. Look for "CMake command arguments" and add to the text field
`-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.7.2\msvc2019_64`
(Change Qt path if you've installed it to non-default path)
3. Press CTRL+S to save and wait a moment for CMake generation
4. Change the project to build to shadps4.exe
5. Build -> Build All
Your shadps4.exe will be in `c:\path\to\source\Build\x64-Clang-Release\`
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
`C:\Qt\6.7.2\msvc2019_64\bin\windeployqt.exe "c:\path\to\shadps4.exe"`
(Change Qt path if you've installed it to non-default path)
## Option 2: MSYS2/MinGW ## Option 2: MSYS2/MinGW
@ -55,27 +76,35 @@ Go through the MSYS2 installation as normal
If you are building to distribute, please omit `-DCMAKE_CXX_FLAGS="-O2 -march=native"` within the build configuration step. If you are building to distribute, please omit `-DCMAKE_CXX_FLAGS="-O2 -march=native"` within the build configuration step.
Normal x86-based computers, follow: Normal x86-based computers, follow:
1. Open "MSYS2 MINGW64" from your new applications 1. Open "MSYS2 MINGW64" from your new applications
2. Run `pacman -Syu`, let it complete; 2. Run `pacman -Syu`, let it complete;
3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-qt6-base` 3. Run `pacman -S --needed git mingw-w64-x86_64-binutils mingw-w64-x86_64-clang mingw-w64-x86_64-cmake mingw-w64-x86_64-ninja mingw-w64-x86_64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-x86_64-qt6-base mingw-w64-x86_64-qt6-tools mingw-w64-x86_64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4` 4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4` 5. Run `cd shadPS4`
6. Run `cmake -S . -B build -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"` 6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
1. Optional (Qt only): add `-DENABLE_QT_GUI=ON`
7. Run `cmake --build build` 7. Run `cmake --build build`
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
8. To run the finished product, run `./build/shadPS4.exe` 8. To run the finished product, run `./build/shadPS4.exe`
ARM64-based computers, follow: ARM64-based computers, follow:
1. Open "MSYS2 CLANGARM64" from your new applications 1. Open "MSYS2 CLANGARM64" from your new applications
2. Run `pacman -Syu`, let it complete; 2. Run `pacman -Syu`, let it complete;
3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-qt6-base` 3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools mingw-w64-clang-aarch64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4` 4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4` 5. Run `cd shadPS4`
6. Run `cmake -S . -B build -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"` 6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
1. Optional (Qt only): add `-DENABLE_QT_GUI=ON`
7. Run `cmake --build build` 7. Run `cmake --build build`
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
8. To run the finished product, run `./build/shadPS4.exe` 8. To run the finished product, run `./build/shadPS4.exe`
## Note on MSYS2 builds ## Note on MSYS2 builds
These builds may not be easily copyable to people who do not also have a MSYS2 installation. These builds may not be easily copyable to people who do not also have a MSYS2 installation.
If you want to distribute these builds, you need to copy over the correct DLLs into a distribution folder. If you want to distribute these builds, you need to copy over the correct DLLs into a distribution folder.
In order to run them, you must be within the MSYS2 shell environment. In order to run them, you must be within the MSYS2 shell environment.

View File

@ -1,3 +1,14 @@
v0.3.0 23/09/2024 - codename broamic
=================
- Cheat/Patching support
- DLC support
- New translations support (26 languages)
- Support for unlocking trophies
- Support for more controllers (Dualshock and Xbox)
- Many GUI improvements
- AVplayer
v0.2.0 15/08/2024 - codename validptr v0.2.0 15/08/2024 - codename validptr
================= =================
- Adding macOS support - Adding macOS support

View File

@ -3,7 +3,10 @@
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
set(BUILD_TESTING OFF) set(BUILD_TESTING OFF)
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) set_directory_properties(PROPERTIES
EXCLUDE_FROM_ALL ON
SYSTEM ON
)
if (MSVC) if (MSVC)
# Silence "deprecation" warnings # Silence "deprecation" warnings
@ -13,11 +16,8 @@ endif()
# Boost # Boost
if (NOT TARGET Boost::headers) if (NOT TARGET Boost::headers)
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "") set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
set(Boost_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "") set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
add_library(boost INTERFACE) add_subdirectory(ext-boost)
target_include_directories(boost SYSTEM INTERFACE ${Boost_INCLUDE_DIR})
add_library(Boost::headers ALIAS boost)
endif() endif()
# fmtlib # fmtlib
@ -43,7 +43,6 @@ else()
endif() endif()
if (NOT TARGET FFmpeg::ffmpeg) if (NOT TARGET FFmpeg::ffmpeg)
set(ARCHITECTURE "x86_64")
add_subdirectory(ffmpeg-core) add_subdirectory(ffmpeg-core)
add_library(FFmpeg::ffmpeg ALIAS ffmpeg) add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
endif() endif()
@ -78,7 +77,7 @@ endif()
# RenderDoc # RenderDoc
if (NOT TARGET RenderDoc::API) if (NOT TARGET RenderDoc::API)
add_library(renderdoc INTERFACE) add_library(renderdoc INTERFACE)
target_include_directories(renderdoc SYSTEM INTERFACE ./renderdoc) target_include_directories(renderdoc INTERFACE ./renderdoc)
add_library(RenderDoc::API ALIAS renderdoc) add_library(RenderDoc::API ALIAS renderdoc)
endif() endif()
@ -142,13 +141,33 @@ if (WIN32)
target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument") target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument")
endif() endif()
# date # half
if (APPLE AND NOT TARGET date::date-tz) if (NOT TARGET half::half)
option(BUILD_TZ_LIB "" ON) add_library(half INTERFACE)
option(USE_SYSTEM_TZ_DB "" ON) target_include_directories(half INTERFACE half/include)
add_subdirectory(date) add_library(half::half ALIAS half)
endif() endif()
if (APPLE)
# date
if (NOT TARGET date::date-tz)
option(BUILD_TZ_LIB "" ON)
option(USE_SYSTEM_TZ_DB "" ON)
add_subdirectory(date)
endif()
endif()
# Dear ImGui
add_library(Dear_ImGui
dear_imgui/imgui.cpp
dear_imgui/imgui_demo.cpp
dear_imgui/imgui_draw.cpp
dear_imgui/imgui_internal.h
dear_imgui/imgui_tables.cpp
dear_imgui/imgui_widgets.cpp
)
target_include_directories(Dear_ImGui INTERFACE dear_imgui/)
# Tracy # Tracy
option(TRACY_ENABLE "" ON) option(TRACY_ENABLE "" ON)
option(TRACY_NO_CRASH_HANDLER "" ON) # Otherwise texture cache exceptions will be treaten as a crash option(TRACY_NO_CRASH_HANDLER "" ON) # Otherwise texture cache exceptions will be treaten as a crash
@ -162,3 +181,16 @@ option(TRACY_NO_SAMPLING "" ON)
option(TRACY_ONLY_LOCALHOST "" ON) option(TRACY_ONLY_LOCALHOST "" ON)
option(TRACY_NO_CONTEXT_SWITCH "" ON) option(TRACY_NO_CONTEXT_SWITCH "" ON)
add_subdirectory(tracy) add_subdirectory(tracy)
# pugixml
if (NOT TARGET pugixml::pugixml)
add_subdirectory(pugixml)
endif()
# Discord RPC
set(BUILD_EXAMPLES OFF)
add_subdirectory(discord-rpc/)
target_include_directories(discord-rpc INTERFACE discord-rpc/include)
# GCN Headers
add_subdirectory(gcn)

2
externals/date vendored

@ -1 +1 @@
Subproject commit 1ead6715dec030d340a316c927c877a3c4e5a00c Subproject commit dd8affc6de5755e07638bf0a14382d29549d6ee9

1
externals/dear_imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit 636cd4a7d623a2bc9bf59bb3acbb4ca075befba3

1
externals/discord-rpc vendored Submodule

@ -0,0 +1 @@
Subproject commit 4ec218155d73bcb8022f8f7ca72305d801f84beb

2
externals/ext-boost vendored

@ -1 +1 @@
Subproject commit a04136add1e469f46d8ae8d3e8307779240a5c53 Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a

2
externals/fmt vendored

@ -1 +1 @@
Subproject commit c98518351efd5a46f5d448e947e0b7242d197d07 Subproject commit 8ee89546ffcf046309d1f0d38c0393f02fde56c8

8
externals/gcn/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,8 @@
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later
project(gcn LANGUAGES CXX)
add_library(gcn dummy.cpp)
target_include_directories(gcn INTERFACE include)

2
externals/gcn/dummy.cpp vendored Normal file
View File

@ -0,0 +1,2 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,117 @@
/*
***********************************************************************************************************************
*
* Copyright (c) 2015-2021 Advanced Micro Devices, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
**********************************************************************************************************************/
#ifndef PM4_IT_OPCODES_H
#define PM4_IT_OPCODES_H
enum IT_OpCodeType {
IT_NOP = 0x10,
IT_SET_BASE = 0x11,
IT_CLEAR_STATE = 0x12,
IT_INDEX_BUFFER_SIZE = 0x13,
IT_DISPATCH_DIRECT = 0x15,
IT_DISPATCH_INDIRECT = 0x16,
IT_ATOMIC_GDS = 0x1D,
IT_ATOMIC = 0x1E,
IT_OCCLUSION_QUERY = 0x1F,
IT_SET_PREDICATION = 0x20,
IT_REG_RMW = 0x21,
IT_COND_EXEC = 0x22,
IT_PRED_EXEC = 0x23,
IT_DRAW_INDIRECT = 0x24,
IT_DRAW_INDEX_INDIRECT = 0x25,
IT_INDEX_BASE = 0x26,
IT_DRAW_INDEX_2 = 0x27,
IT_CONTEXT_CONTROL = 0x28,
IT_INDEX_TYPE = 0x2A,
IT_DRAW_INDIRECT_MULTI = 0x2C,
IT_DRAW_INDEX_AUTO = 0x2D,
IT_NUM_INSTANCES = 0x2F,
IT_DRAW_INDEX_MULTI_AUTO = 0x30,
IT_INDIRECT_BUFFER_CNST = 0x33,
IT_STRMOUT_BUFFER_UPDATE = 0x34,
IT_DRAW_INDEX_OFFSET_2 = 0x35,
IT_WRITE_DATA = 0x37,
IT_DRAW_INDEX_INDIRECT_MULTI = 0x38,
IT_MEM_SEMAPHORE = 0x39,
IT_COPY_DW__SI__CI = 0x3B,
IT_WAIT_REG_MEM = 0x3C,
IT_INDIRECT_BUFFER = 0x3F,
IT_COND_INDIRECT_BUFFER = 0x3F,
IT_COPY_DATA = 0x40,
IT_CP_DMA = 0x41,
IT_PFP_SYNC_ME = 0x42,
IT_SURFACE_SYNC = 0x43,
IT_COND_WRITE = 0x45,
IT_EVENT_WRITE = 0x46,
IT_EVENT_WRITE_EOP = 0x47,
IT_EVENT_WRITE_EOS = 0x48,
IT_PREAMBLE_CNTL = 0x4A,
IT_CONTEXT_REG_RMW = 0x51,
IT_LOAD_SH_REG = 0x5F,
IT_LOAD_CONFIG_REG = 0x60,
IT_LOAD_CONTEXT_REG = 0x61,
IT_SET_CONFIG_REG = 0x68,
IT_SET_CONTEXT_REG = 0x69,
IT_SET_CONTEXT_REG_INDIRECT = 0x73,
IT_SET_SH_REG = 0x76,
IT_SET_SH_REG_OFFSET = 0x77,
IT_SCRATCH_RAM_WRITE = 0x7D,
IT_SCRATCH_RAM_READ = 0x7E,
IT_LOAD_CONST_RAM = 0x80,
IT_WRITE_CONST_RAM = 0x81,
IT_DUMP_CONST_RAM = 0x83,
IT_INCREMENT_CE_COUNTER = 0x84,
IT_INCREMENT_DE_COUNTER = 0x85,
IT_WAIT_ON_CE_COUNTER = 0x86,
IT_WAIT_ON_DE_COUNTER__SI = 0x87,
IT_WAIT_ON_DE_COUNTER_DIFF = 0x88,
IT_SWITCH_BUFFER = 0x8B,
IT_DRAW_PREAMBLE__CI__VI = 0x36,
IT_RELEASE_MEM__CI__VI = 0x49,
IT_DMA_DATA__CI__VI = 0x50,
IT_ACQUIRE_MEM__CI__VI = 0x58,
IT_REWIND__CI__VI = 0x59,
IT_LOAD_UCONFIG_REG__CI__VI = 0x5E,
IT_SET_QUEUE_REG__CI__VI = 0x78,
IT_SET_UCONFIG_REG__CI__VI = 0x79,
IT_INDEX_ATTRIBUTES_INDIRECT__CI__VI = 0x91,
IT_SET_SH_REG_INDEX__CI__VI = 0x9B,
IT_SET_RESOURCES__CI__VI = 0xA0,
IT_MAP_PROCESS__CI__VI = 0xA1,
IT_MAP_QUEUES__CI__VI = 0xA2,
IT_UNMAP_QUEUES__CI__VI = 0xA3,
IT_QUERY_STATUS__CI__VI = 0xA4,
IT_RUN_LIST__CI__VI = 0xA5,
IT_LOAD_SH_REG_INDEX__VI = 0x63,
IT_LOAD_CONTEXT_REG_INDEX__VI = 0x9F,
IT_DUMP_CONST_RAM_OFFSET__VI = 0x9E,
};
#define PM4_TYPE_0 0
#define PM4_TYPE_2 2
#define PM4_TYPE_3 3
#endif

2
externals/glslang vendored

@ -1 +1 @@
Subproject commit d59c84d388c805022e2bddea08aa41cbe7e43e55 Subproject commit e61d7bb3006f451968714e2f653412081871e1ee

1
externals/half vendored Submodule

@ -0,0 +1 @@
Subproject commit 1ddada225144cac0de8f6b5c0dd9acffd99a2e68

@ -1 +1 @@
Subproject commit dae6bbf16c363e9ead4e628a47fdb02956a634f3 Subproject commit 126539e13cccdc2e75ce770e94f3c26403099fa5

1
externals/pugixml vendored Submodule

@ -0,0 +1 @@
Subproject commit 3b17184379fcaaeb7f1fbe08018b7fedf2640b3b

2
externals/robin-map vendored

@ -1 +1 @@
Subproject commit 1115dad3ffa0994e3f43b693d9b9cc99944c64c1 Subproject commit fe845fd7852ef541c5479ae23b3d36b57f8608ee

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit 4cc3410dce50cefce98d3cf3cf1bc8eca83b862a Subproject commit 54e622c2e6af456bfef382fae44c17682d5ac88a

2
externals/sirit vendored

@ -1 +1 @@
Subproject commit 8db09231c448b913ae905d5237ce2eca46e3fe87 Subproject commit 6cecb95d679c82c413d1f989e0b7ad9af130600d

2
externals/toml11 vendored

@ -1 +1 @@
Subproject commit cc0bee4fd46ea1f5db147d63ea545208cc9e8405 Subproject commit f925e7f287c0008813c2294798cf9ca167fd9ffd

2
externals/vma vendored

@ -1 +1 @@
Subproject commit e1bdbca9baf4d682fb6066b380f4aa4a7bdbb58a Subproject commit 1c35ba99ce775f8342d87a83a3f0f696f99c2a39

@ -1 +1 @@
Subproject commit d205aff40b4e15d4c568523ee6a26f85138126d9 Subproject commit d91597a82f881d473887b560a03a7edf2720b72c

2
externals/xbyak vendored

@ -1 +1 @@
Subproject commit aabb091ae37068498751fd58202a9854408ecb0e Subproject commit d067f0d3f55696ae8bc9a25ad7012ee80f221d54

2
externals/xxhash vendored

@ -1 +1 @@
Subproject commit dbea33e47e7c0fe0b7c8592cd931c7430c1f130d Subproject commit d4ad85e4afaad5c780f54db1dc967fff5a869ffd

2
externals/zydis vendored

@ -1 +1 @@
Subproject commit bd73bc03b0aacaa89c9c203b9b43cd08f1b1843b Subproject commit 9d298eb8067ff62a237203d1e1470785033e185c

View File

@ -114108,7 +114108,7 @@ STUB(
_ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_7Matches2V124RequestCompetitiveResultEE7add_refEv) _ZN3sce2Np9CppWebApi6Common12IntrusivePtrINS1_7Matches2V124RequestCompetitiveResultEE7add_refEv)
STUB("efPahl2FufA", STUB("efPahl2FufA",
_ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V35Error8fromJsonERKNS_4Json5ValueE) _ZN3sce2Np9CppWebApi30CommunicationRestrictionStatus2V35Error8fromJsonERKNS_4Json5ValueE)
STUB("efX3lrPwdKA", sceAppContentAddcontMountByEntitlemetId) STUB("efX3lrPwdKA", sceAppContentAddcontMountByEntitlementId)
STUB("efXnxYFN5oE", _ZNSt11range_errorD0Ev) STUB("efXnxYFN5oE", _ZNSt11range_errorD0Ev)
STUB("efcwuDLsAM0", _ZThn120_NK7WebCore16HTMLMediaElement5mutedEv) STUB("efcwuDLsAM0", _ZThn120_NK7WebCore16HTMLMediaElement5mutedEv)
STUB("efhGArzWdxE", _ZN7bmalloc6IsoTLS15s_didInitializeE) STUB("efhGArzWdxE", _ZN7bmalloc6IsoTLS15s_didInitializeE)
@ -129493,7 +129493,7 @@ STUB(
STUB("kJlYH5uMAWI", sceNetResolverDestroy) STUB("kJlYH5uMAWI", sceNetResolverDestroy)
STUB("kJmdxo4uM+8", STUB("kJmdxo4uM+8",
_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_InitERKSt8_Locinfo) _ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE5_InitERKSt8_Locinfo)
STUB("kJmjt81mXKQ", sceAppContentAddcontEnqueueDownloadByEntitlemetId) STUB("kJmjt81mXKQ", sceAppContentAddcontEnqueueDownloadByEntitlementId)
STUB( STUB(
"kJoY9lMIFzY", "kJoY9lMIFzY",
_ZN3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_21AdvancedPlayerProfile2V138MatchCompletionRateDisconnectedMetricsEEEEmmEi) _ZN3sce2Np9CppWebApi6Common8IteratorINS2_12IntrusivePtrINS1_21AdvancedPlayerProfile2V138MatchCompletionRateDisconnectedMetricsEEEEmmEi)

View File

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
import std.io;
import std.sys;
struct Header {
u32 magic;
u32 version;
u32 key_table_offset;
u32 data_table_offset;
u32 index_table_entries;
};
struct KeyEntry {
char name[];
} [[inline]];
struct DataEntry<auto fmt, auto size> {
if (fmt == 0x0404) {
u32 int_value;
} else if(fmt == 0x0004) {
char bin_value[size];
} else if(fmt == 0x0204) {
char str_value[size];
} else {
std::warning("unknown fmt type");
}
} [[inline]];
struct IndexEntry {
u16 key_offset;
u16 param_fmt;
u32 param_len;
u32 param_max_len;
u32 data_offset;
};
struct Entry<auto KeyTableOffset, auto DataTableOffset> {
u64 begin = $;
IndexEntry index;
KeyEntry key @ KeyTableOffset + index.key_offset;
DataEntry<index.param_fmt, index.param_len> data @ DataTableOffset + index.data_offset;
u8 data_empty[index.param_max_len - index.param_len] @ DataTableOffset + index.data_offset + index.param_len;
$ = begin + sizeof(IndexEntry);
};
Header header @ 0;
std::assert(header.magic == 0x46535000, "Miss match magic");
std::assert(header.version == 0x00000101, "Miss match version");
Entry<header.key_table_offset, header.data_table_offset> list[header.index_table_entries] @ 0x14;

View File

@ -80897,10 +80897,10 @@ sceAppCheckerExecute
sceAppCheckerExecuteEx sceAppCheckerExecuteEx
sceAppContentAddcontDelete sceAppContentAddcontDelete
sceAppContentAddcontEnqueueDownload sceAppContentAddcontEnqueueDownload
sceAppContentAddcontEnqueueDownloadByEntitlemetId sceAppContentAddcontEnqueueDownloadByEntitlementId
sceAppContentAddcontEnqueueDownloadSp sceAppContentAddcontEnqueueDownloadSp
sceAppContentAddcontMount sceAppContentAddcontMount
sceAppContentAddcontMountByEntitlemetId sceAppContentAddcontMountByEntitlementId
sceAppContentAddcontShrink sceAppContentAddcontShrink
sceAppContentAddcontUnmount sceAppContentAddcontUnmount
sceAppContentAppParamGetInt sceAppContentAppParamGetInt

View File

@ -14,7 +14,9 @@
namespace Audio { namespace Audio {
int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq, constexpr int AUDIO_STREAM_BUFFER_THRESHOLD = 65536; // Define constant for buffer threshold
s32 SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
Libraries::AudioOut::OrbisAudioOutParamFormat format) { Libraries::AudioOut::OrbisAudioOutParamFormat format) {
using Libraries::AudioOut::OrbisAudioOutParamFormat; using Libraries::AudioOut::OrbisAudioOutParamFormat;
std::unique_lock lock{m_mutex}; std::unique_lock lock{m_mutex};
@ -80,7 +82,7 @@ int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
SDL_zero(fmt); SDL_zero(fmt);
fmt.format = sampleFormat; fmt.format = sampleFormat;
fmt.channels = port.channels_num; fmt.channels = port.channels_num;
fmt.freq = 48000; fmt.freq = freq; // Set frequency from the argument
port.stream = port.stream =
SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL); SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &fmt, NULL, NULL);
SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port.stream)); SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(port.stream));
@ -88,7 +90,8 @@ int SDLAudio::AudioOutOpen(int type, u32 samples_num, u32 freq,
} }
} }
return -1; // all ports are used LOG_ERROR(Lib_AudioOut, "Audio ports are full");
return ORBIS_AUDIO_OUT_ERROR_PORT_FULL; // all ports are used
} }
s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) { s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
@ -97,27 +100,28 @@ s32 SDLAudio::AudioOutOutput(s32 handle, const void* ptr) {
if (!port.isOpen) { if (!port.isOpen) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
if (ptr == nullptr) {
return 0; const size_t data_size = port.samples_num * port.sample_size * port.channels_num;
}
// TODO mixing channels bool result = SDL_PutAudioStreamData(port.stream, ptr, data_size);
int result = SDL_PutAudioStreamData(port.stream, ptr,
port.samples_num * port.sample_size * port.channels_num); lock.unlock(); // Unlock only after necessary operations
// TODO find a correct value 8192 is estimated
while (SDL_GetAudioStreamAvailable(port.stream) > 65536) { while (SDL_GetAudioStreamAvailable(port.stream) > AUDIO_STREAM_BUFFER_THRESHOLD) {
SDL_Delay(0); SDL_Delay(0);
} }
return result; return result ? ORBIS_OK : -1;
} }
bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) { s32 SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
using Libraries::AudioOut::OrbisAudioOutParamFormat; using Libraries::AudioOut::OrbisAudioOutParamFormat;
std::shared_lock lock{m_mutex}; std::shared_lock lock{m_mutex};
auto& port = portsOut[handle - 1]; auto& port = portsOut[handle - 1];
if (!port.isOpen) { if (!port.isOpen) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT; return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
} }
for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) { for (int i = 0; i < port.channels_num; i++, bitflag >>= 1u) {
auto bit = bitflag & 0x1u; auto bit = bitflag & 0x1u;
@ -147,16 +151,16 @@ bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
} }
} }
return true; return ORBIS_OK;
} }
bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) { s32 SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
std::shared_lock lock{m_mutex}; std::shared_lock lock{m_mutex};
auto& port = portsOut[handle - 1]; auto& port = portsOut[handle - 1];
*type = port.type; *type = port.type;
*channels_num = port.channels_num; *channels_num = port.channels_num;
return true; return ORBIS_OK;
} }
} // namespace Audio } // namespace Audio

View File

@ -14,27 +14,26 @@ public:
SDLAudio() = default; SDLAudio() = default;
virtual ~SDLAudio() = default; virtual ~SDLAudio() = default;
int AudioOutOpen(int type, u32 samples_num, u32 freq, s32 AudioOutOpen(int type, u32 samples_num, u32 freq,
Libraries::AudioOut::OrbisAudioOutParamFormat format); Libraries::AudioOut::OrbisAudioOutParamFormat format);
s32 AudioOutOutput(s32 handle, const void* ptr); s32 AudioOutOutput(s32 handle, const void* ptr);
bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume); s32 AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume);
bool AudioOutGetStatus(s32 handle, int* type, int* channels_num); s32 AudioOutGetStatus(s32 handle, int* type, int* channels_num);
private: private:
struct PortOut { struct PortOut {
bool isOpen = false; SDL_AudioStream* stream = nullptr;
int type = 0;
u32 samples_num = 0; u32 samples_num = 0;
u8 sample_size = 0;
u32 freq = 0; u32 freq = 0;
u32 format = -1; u32 format = -1;
int type = 0;
int channels_num = 0; int channels_num = 0;
int volume[8] = {}; int volume[8] = {};
SDL_AudioStream* stream = nullptr; u8 sample_size = 0;
bool isOpen = false;
}; };
std::shared_mutex m_mutex; std::shared_mutex m_mutex;
std::array<PortOut, 22> portsOut; // main up to 8 ports , BGM 1 port , voice up to 4 ports , std::array<PortOut, Libraries::AudioOut::SCE_AUDIO_OUT_NUM_PORTS> portsOut;
// personal up to 4 ports , padspk up to 5 ports , aux 1 port
}; };
} // namespace Audio } // namespace Audio

View File

@ -28,4 +28,16 @@ template <typename T>
return (value & 0x3FFF) == 0; return (value & 0x3FFF) == 0;
} }
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Is64KBAligned(T value) {
return (value & 0xFFFF) == 0;
}
template <typename T>
requires std::is_integral_v<T>
[[nodiscard]] constexpr bool Is2MBAligned(T value) {
return (value & 0x1FFFFF) == 0;
}
} // namespace Common } // namespace Common

10
src/common/arch.h Normal file
View File

@ -0,0 +1,10 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#if defined(__x86_64__) || defined(_M_X64)
#define ARCH_X86_64 1
#elif defined(__aarch64__) || defined(_M_ARM64)
#define ARCH_ARM64 1
#endif

View File

@ -1,10 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/arch.h"
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/backend.h" #include "common/logging/backend.h"
#if defined(ARCH_X86_64)
#define Crash() __asm__ __volatile__("int $3") #define Crash() __asm__ __volatile__("int $3")
#elif defined(ARCH_ARM64)
#define Crash() __asm__ __volatile__("brk 0")
#else
#error "Missing Crash() implementation for target CPU architecture."
#endif
void assert_fail_impl() { void assert_fail_impl() {
Common::Log::Stop(); Common::Log::Stop();
@ -18,3 +25,8 @@ void assert_fail_impl() {
Crash(); Crash();
throw std::runtime_error("Unreachable code"); throw std::runtime_error("Unreachable code");
} }
void assert_fail_debug_msg(const char* msg) {
LOG_CRITICAL(Debug, "Assertion Failed!\n{}", msg);
assert_fail_impl();
}

View File

@ -81,7 +81,9 @@
#pragma pack(1) #pragma pack(1)
template <std::size_t Position, std::size_t Bits, typename T> template <std::size_t Position, std::size_t Bits, typename T>
struct BitField { struct BitField {
private:
using Type = T;
// UnderlyingType is T for non-enum types and the underlying type of T if // UnderlyingType is T for non-enum types and the underlying type of T if
// T is an enumeration. Note that T is wrapped within an enable_if in the // T is an enumeration. Note that T is wrapped within an enable_if in the
// former case to workaround compile errors which arise when using // former case to workaround compile errors which arise when using
@ -92,7 +94,6 @@ private:
// We store the value as the unsigned type to avoid undefined behaviour on value shifting // We store the value as the unsigned type to avoid undefined behaviour on value shifting
using StorageType = std::make_unsigned_t<UnderlyingType>; using StorageType = std::make_unsigned_t<UnderlyingType>;
public:
/// Constants to allow limited introspection of fields if needed /// Constants to allow limited introspection of fields if needed
static constexpr std::size_t position = Position; static constexpr std::size_t position = Position;
static constexpr std::size_t bits = Bits; static constexpr std::size_t bits = Bits;

View File

@ -3,33 +3,68 @@
#include <fstream> #include <fstream>
#include <string> #include <string>
#include <common/version.h>
#include <fmt/core.h> #include <fmt/core.h>
#include <fmt/xchar.h> // for wstring support
#include <toml.hpp> #include <toml.hpp>
#include "common/logging/formatter.h"
#include "common/path_util.h"
#include "config.h" #include "config.h"
namespace toml {
template <typename TC, typename K>
std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
std::filesystem::path opt) {
try {
auto str = find<std::string>(v, ky);
if (str.empty()) {
return opt;
}
std::u8string u8str{(char8_t*)&str.front(), (char8_t*)&str.back() + 1};
return std::filesystem::path{u8str};
} catch (...) {
return opt;
}
}
} // namespace toml
namespace Config { namespace Config {
static bool isNeo = false; static bool isNeo = false;
static bool isFullscreen = false; static bool isFullscreen = false;
static bool playBGM = false;
static int BGMvolume = 50;
static bool enableDiscordRPC = false;
static u32 screenWidth = 1280; static u32 screenWidth = 1280;
static u32 screenHeight = 720; static u32 screenHeight = 720;
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
static std::string logFilter; static std::string logFilter;
static std::string logType = "async"; static std::string logType = "async";
static std::string userName = "shadPS4"; static std::string userName = "shadPS4";
static std::string updateChannel;
static std::string backButtonBehavior = "left";
static bool useSpecialPad = false;
static int specialPadClass = 1;
static bool isDebugDump = false; static bool isDebugDump = false;
static bool isShowSplash = false; static bool isShowSplash = false;
static bool isAutoUpdate = false;
static bool isNullGpu = false; static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false; static bool shouldDumpShaders = false;
static bool shouldDumpPM4 = false;
static u32 vblankDivider = 1; static u32 vblankDivider = 1;
static bool vkValidation = false; static bool vkValidation = false;
static bool vkValidationSync = false; static bool vkValidationSync = false;
static bool vkValidationGpu = false; static bool vkValidationGpu = false;
static bool rdocEnable = false; static bool rdocEnable = false;
static bool rdocMarkersEnable = false; static bool vkMarkers = false;
static bool vkCrashDiagnostic = false;
static s16 cursorState = HideCursorState::Idle;
static int cursorHideTimeout = 5; // 5 seconds (default)
static bool separateupdatefolder = false;
// Gui // Gui
std::string settings_install_dir = ""; std::vector<std::filesystem::path> settings_install_dirs = {};
std::filesystem::path settings_addon_install_dir = {};
u32 main_window_geometry_x = 400; u32 main_window_geometry_x = 400;
u32 main_window_geometry_y = 400; u32 main_window_geometry_y = 400;
u32 main_window_geometry_w = 1280; u32 main_window_geometry_w = 1280;
@ -45,6 +80,7 @@ u32 m_window_size_H = 720;
std::vector<std::string> m_pkg_viewer; std::vector<std::string> m_pkg_viewer;
std::vector<std::string> m_elf_viewer; std::vector<std::string> m_elf_viewer;
std::vector<std::string> m_recent_files; std::vector<std::string> m_recent_files;
std::string emulator_language = "en";
// Settings // Settings
u32 m_language = 1; // english u32 m_language = 1; // english
@ -56,6 +92,26 @@ bool isFullscreenMode() {
return isFullscreen; return isFullscreen;
} }
bool getPlayBGM() {
return playBGM;
}
int getBGMvolume() {
return BGMvolume;
}
bool getEnableDiscordRPC() {
return enableDiscordRPC;
}
s16 getCursorState() {
return cursorState;
}
int getCursorHideTimeout() {
return cursorHideTimeout;
}
u32 getScreenWidth() { u32 getScreenWidth() {
return screenWidth; return screenWidth;
} }
@ -80,6 +136,22 @@ std::string getUserName() {
return userName; return userName;
} }
std::string getUpdateChannel() {
return updateChannel;
}
std::string getBackButtonBehavior() {
return backButtonBehavior;
}
bool getUseSpecialPad() {
return useSpecialPad;
}
int getSpecialPadClass() {
return specialPadClass;
}
bool debugDump() { bool debugDump() {
return isDebugDump; return isDebugDump;
} }
@ -88,16 +160,20 @@ bool showSplash() {
return isShowSplash; return isShowSplash;
} }
bool autoUpdate() {
return isAutoUpdate;
}
bool nullGpu() { bool nullGpu() {
return isNullGpu; return isNullGpu;
} }
bool dumpShaders() { bool copyGPUCmdBuffers() {
return shouldDumpShaders; return shouldCopyGPUBuffers;
} }
bool dumpPM4() { bool dumpShaders() {
return shouldDumpPM4; return shouldDumpShaders;
} }
bool isRdocEnabled() { bool isRdocEnabled() {
@ -105,7 +181,7 @@ bool isRdocEnabled() {
} }
bool isMarkersEnabled() { bool isMarkersEnabled() {
return rdocMarkersEnable; return vkMarkers;
} }
u32 vblankDiv() { u32 vblankDiv() {
@ -124,6 +200,18 @@ bool vkValidationGpuEnabled() {
return vkValidationGpu; return vkValidationGpu;
} }
bool vkMarkersEnabled() {
return vkMarkers || vkCrashDiagnostic; // Crash diagnostic forces markers on
}
bool vkCrashDiagnosticEnabled() {
return vkCrashDiagnostic;
}
bool getSeparateUpdateEnabled() {
return separateupdatefolder;
}
void setGpuId(s32 selectedGpuId) { void setGpuId(s32 selectedGpuId) {
gpuId = selectedGpuId; gpuId = selectedGpuId;
} }
@ -144,16 +232,20 @@ void setShowSplash(bool enable) {
isShowSplash = enable; isShowSplash = enable;
} }
void setAutoUpdate(bool enable) {
isAutoUpdate = enable;
}
void setNullGpu(bool enable) { void setNullGpu(bool enable) {
isNullGpu = enable; isNullGpu = enable;
} }
void setDumpShaders(bool enable) { void setCopyGPUCmdBuffers(bool enable) {
shouldDumpShaders = enable; shouldCopyGPUBuffers = enable;
} }
void setDumpPM4(bool enable) { void setDumpShaders(bool enable) {
shouldDumpPM4 = enable; shouldDumpShaders = enable;
} }
void setVkValidation(bool enable) { void setVkValidation(bool enable) {
@ -176,6 +268,26 @@ void setFullscreenMode(bool enable) {
isFullscreen = enable; isFullscreen = enable;
} }
void setPlayBGM(bool enable) {
playBGM = enable;
}
void setBGMvolume(int volume) {
BGMvolume = volume;
}
void setEnableDiscordRPC(bool enable) {
enableDiscordRPC = enable;
}
void setCursorState(s16 newCursorState) {
cursorState = newCursorState;
}
void setCursorHideTimeout(int newcursorHideTimeout) {
cursorHideTimeout = newcursorHideTimeout;
}
void setLanguage(u32 language) { void setLanguage(u32 language) {
m_language = language; m_language = language;
} }
@ -196,14 +308,48 @@ void setUserName(const std::string& type) {
userName = type; userName = type;
} }
void setUpdateChannel(const std::string& type) {
updateChannel = type;
}
void setBackButtonBehavior(const std::string& type) {
backButtonBehavior = type;
}
void setUseSpecialPad(bool use) {
useSpecialPad = use;
}
void setSpecialPadClass(int type) {
specialPadClass = type;
}
void setSeparateUpdateEnabled(bool use) {
separateupdatefolder = use;
}
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) { void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_x = x; main_window_geometry_x = x;
main_window_geometry_y = y; main_window_geometry_y = y;
main_window_geometry_w = w; main_window_geometry_w = w;
main_window_geometry_h = h; main_window_geometry_h = h;
} }
void setGameInstallDir(const std::string& dir) { bool addGameInstallDir(const std::filesystem::path& dir) {
settings_install_dir = dir; if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
settings_install_dirs.end()) {
settings_install_dirs.push_back(dir);
return true;
}
return false;
}
void removeGameInstallDir(const std::filesystem::path& dir) {
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
if (iterator != settings_install_dirs.end()) {
settings_install_dirs.erase(iterator);
}
}
void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir;
} }
void setMainWindowTheme(u32 theme) { void setMainWindowTheme(u32 theme) {
mw_themes = theme; mw_themes = theme;
@ -214,10 +360,10 @@ void setIconSize(u32 size) {
void setIconSizeGrid(u32 size) { void setIconSizeGrid(u32 size) {
m_icon_size_grid = size; m_icon_size_grid = size;
} }
void setSliderPositon(u32 pos) { void setSliderPosition(u32 pos) {
m_slider_pos = pos; m_slider_pos = pos;
} }
void setSliderPositonGrid(u32 pos) { void setSliderPositionGrid(u32 pos) {
m_slider_pos_grid = pos; m_slider_pos_grid = pos;
} }
void setTableMode(u32 mode) { void setTableMode(u32 mode) {
@ -242,6 +388,10 @@ void setRecentFiles(const std::vector<std::string>& recentFiles) {
m_recent_files = recentFiles; m_recent_files = recentFiles;
} }
void setEmulatorLanguage(std::string language) {
emulator_language = language;
}
u32 getMainWindowGeometryX() { u32 getMainWindowGeometryX() {
return main_window_geometry_x; return main_window_geometry_x;
} }
@ -254,8 +404,15 @@ u32 getMainWindowGeometryW() {
u32 getMainWindowGeometryH() { u32 getMainWindowGeometryH() {
return main_window_geometry_h; return main_window_geometry_h;
} }
std::string getGameInstallDir() { const std::vector<std::filesystem::path>& getGameInstallDirs() {
return settings_install_dir; return settings_install_dirs;
}
std::filesystem::path getAddonInstallDir() {
if (settings_addon_install_dir.empty()) {
// Default for users without a config file or a config file from before this option existed
return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "addcont";
}
return settings_addon_install_dir;
} }
u32 getMainWindowTheme() { u32 getMainWindowTheme() {
return mw_themes; return mw_themes;
@ -266,10 +423,10 @@ u32 getIconSize() {
u32 getIconSizeGrid() { u32 getIconSizeGrid() {
return m_icon_size_grid; return m_icon_size_grid;
} }
u32 getSliderPositon() { u32 getSliderPosition() {
return m_slider_pos; return m_slider_pos;
} }
u32 getSliderPositonGrid() { u32 getSliderPositionGrid() {
return m_slider_pos_grid; return m_slider_pos_grid;
} }
u32 getTableMode() { u32 getTableMode() {
@ -291,6 +448,10 @@ std::vector<std::string> getRecentFiles() {
return m_recent_files; return m_recent_files;
} }
std::string getEmulatorLanguage() {
return emulator_language;
}
u32 GetLanguage() { u32 GetLanguage() {
return m_language; return m_language;
} }
@ -305,7 +466,10 @@ void load(const std::filesystem::path& path) {
toml::value data; toml::value data;
try { try {
data = toml::parse(path); std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ifs.open(path, std::ios_base::binary);
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
} catch (std::exception& ex) { } catch (std::exception& ex) {
fmt::print("Got exception trying to load config file. Exception: {}\n", ex.what()); fmt::print("Got exception trying to load config file. Exception: {}\n", ex.what());
return; return;
@ -315,10 +479,30 @@ void load(const std::filesystem::path& path) {
isNeo = toml::find_or<bool>(general, "isPS4Pro", false); isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false); isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
playBGM = toml::find_or<bool>(general, "playBGM", false);
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
logFilter = toml::find_or<std::string>(general, "logFilter", ""); logFilter = toml::find_or<std::string>(general, "logFilter", "");
logType = toml::find_or<std::string>(general, "logType", "sync"); logType = toml::find_or<std::string>(general, "logType", "sync");
userName = toml::find_or<std::string>(general, "userName", "shadPS4"); userName = toml::find_or<std::string>(general, "userName", "shadPS4");
if (Common::isRelease) {
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Release");
} else {
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Nightly");
}
isShowSplash = toml::find_or<bool>(general, "showSplash", true); isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
}
if (data.contains("Input")) {
const toml::value& input = data.at("Input");
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
} }
if (data.contains("GPU")) { if (data.contains("GPU")) {
@ -327,8 +511,8 @@ void load(const std::filesystem::path& path) {
screenWidth = toml::find_or<int>(gpu, "screenWidth", screenWidth); screenWidth = toml::find_or<int>(gpu, "screenWidth", screenWidth);
screenHeight = toml::find_or<int>(gpu, "screenHeight", screenHeight); screenHeight = toml::find_or<int>(gpu, "screenHeight", screenHeight);
isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false); isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false);
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false);
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false); shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
shouldDumpPM4 = toml::find_or<bool>(gpu, "dumpPM4", false);
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1); vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1);
} }
@ -340,7 +524,8 @@ void load(const std::filesystem::path& path) {
vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false); vkValidationSync = toml::find_or<bool>(vk, "validation_sync", false);
vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true); vkValidationGpu = toml::find_or<bool>(vk, "validation_gpu", true);
rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false); rdocEnable = toml::find_or<bool>(vk, "rdocEnable", false);
rdocMarkersEnable = toml::find_or<bool>(vk, "rdocMarkersEnable", false); vkMarkers = toml::find_or<bool>(vk, "rdocMarkersEnable", false);
vkCrashDiagnostic = toml::find_or<bool>(vk, "crashDiagnostic", false);
} }
if (data.contains("Debug")) { if (data.contains("Debug")) {
@ -359,7 +544,20 @@ void load(const std::filesystem::path& path) {
mw_themes = toml::find_or<int>(gui, "theme", 0); mw_themes = toml::find_or<int>(gui, "theme", 0);
m_window_size_W = toml::find_or<int>(gui, "mw_width", 0); m_window_size_W = toml::find_or<int>(gui, "mw_width", 0);
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0); m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
settings_install_dir = toml::find_or<std::string>(gui, "installDir", "");
// TODO Migration code, after a major release this should be removed.
auto old_game_install_dir = toml::find_fs_path_or(gui, "installDir", {});
if (!old_game_install_dir.empty()) {
addGameInstallDir(std::filesystem::path{old_game_install_dir});
} else {
const auto install_dir_array =
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
for (const auto& dir : install_dir_array) {
addGameInstallDir(std::filesystem::path{dir});
}
}
settings_addon_install_dir = toml::find_fs_path_or(gui, "addonInstallDir", {});
main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0); main_window_geometry_x = toml::find_or<int>(gui, "geometry_x", 0);
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0); main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0); main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
@ -368,6 +566,7 @@ void load(const std::filesystem::path& path) {
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {}); m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {}); m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0); m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
emulator_language = toml::find_or<std::string>(gui, "emulatorLanguage", "en");
} }
if (data.contains("Settings")) { if (data.contains("Settings")) {
@ -382,37 +581,51 @@ void save(const std::filesystem::path& path) {
std::error_code error; std::error_code error;
if (std::filesystem::exists(path, error)) { if (std::filesystem::exists(path, error)) {
try { try {
data = toml::parse(path); std::ifstream ifs;
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
ifs.open(path, std::ios_base::binary);
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what()); fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
return; return;
} }
} else { } else {
if (error) { if (error) {
fmt::print("Filesystem error accessing {} (error: {})\n", path.string(), fmt::print("Filesystem error: {}\n", error.message());
error.message().c_str());
} }
fmt::print("Saving new configuration file {}\n", path.string()); fmt::print("Saving new configuration file {}\n", fmt::UTF(path.u8string()));
} }
data["General"]["isPS4Pro"] = isNeo; data["General"]["isPS4Pro"] = isNeo;
data["General"]["Fullscreen"] = isFullscreen; data["General"]["Fullscreen"] = isFullscreen;
data["General"]["playBGM"] = playBGM;
data["General"]["BGMvolume"] = BGMvolume;
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
data["General"]["logFilter"] = logFilter; data["General"]["logFilter"] = logFilter;
data["General"]["logType"] = logType; data["General"]["logType"] = logType;
data["General"]["userName"] = userName; data["General"]["userName"] = userName;
data["General"]["updateChannel"] = updateChannel;
data["General"]["showSplash"] = isShowSplash; data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["Input"]["cursorState"] = cursorState;
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
data["Input"]["backButtonBehavior"] = backButtonBehavior;
data["Input"]["useSpecialPad"] = useSpecialPad;
data["Input"]["specialPadClass"] = specialPadClass;
data["GPU"]["screenWidth"] = screenWidth; data["GPU"]["screenWidth"] = screenWidth;
data["GPU"]["screenHeight"] = screenHeight; data["GPU"]["screenHeight"] = screenHeight;
data["GPU"]["nullGpu"] = isNullGpu; data["GPU"]["nullGpu"] = isNullGpu;
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
data["GPU"]["dumpShaders"] = shouldDumpShaders; data["GPU"]["dumpShaders"] = shouldDumpShaders;
data["GPU"]["dumpPM4"] = shouldDumpPM4;
data["GPU"]["vblankDivider"] = vblankDivider; data["GPU"]["vblankDivider"] = vblankDivider;
data["Vulkan"]["gpuId"] = gpuId; data["Vulkan"]["gpuId"] = gpuId;
data["Vulkan"]["validation"] = vkValidation; data["Vulkan"]["validation"] = vkValidation;
data["Vulkan"]["validation_sync"] = vkValidationSync; data["Vulkan"]["validation_sync"] = vkValidationSync;
data["Vulkan"]["validation_gpu"] = vkValidationGpu; data["Vulkan"]["validation_gpu"] = vkValidationGpu;
data["Vulkan"]["rdocEnable"] = rdocEnable; data["Vulkan"]["rdocEnable"] = rdocEnable;
data["Vulkan"]["rdocMarkersEnable"] = rdocMarkersEnable; data["Vulkan"]["rdocMarkersEnable"] = vkMarkers;
data["Vulkan"]["crashDiagnostic"] = vkCrashDiagnostic;
data["Debug"]["DebugDump"] = isDebugDump; data["Debug"]["DebugDump"] = isDebugDump;
data["GUI"]["theme"] = mw_themes; data["GUI"]["theme"] = mw_themes;
data["GUI"]["iconSize"] = m_icon_size; data["GUI"]["iconSize"] = m_icon_size;
@ -422,7 +635,15 @@ void save(const std::filesystem::path& path) {
data["GUI"]["gameTableMode"] = m_table_mode; data["GUI"]["gameTableMode"] = m_table_mode;
data["GUI"]["mw_width"] = m_window_size_W; data["GUI"]["mw_width"] = m_window_size_W;
data["GUI"]["mw_height"] = m_window_size_H; data["GUI"]["mw_height"] = m_window_size_H;
data["GUI"]["installDir"] = settings_install_dir;
std::vector<std::string> install_dirs;
for (const auto& dirString : settings_install_dirs) {
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
}
data["GUI"]["installDirs"] = install_dirs;
data["GUI"]["addonInstallDir"] =
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
data["GUI"]["geometry_x"] = main_window_geometry_x; data["GUI"]["geometry_x"] = main_window_geometry_x;
data["GUI"]["geometry_y"] = main_window_geometry_y; data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w; data["GUI"]["geometry_w"] = main_window_geometry_w;
@ -430,9 +651,13 @@ void save(const std::filesystem::path& path) {
data["GUI"]["pkgDirs"] = m_pkg_viewer; data["GUI"]["pkgDirs"] = m_pkg_viewer;
data["GUI"]["elfDirs"] = m_elf_viewer; data["GUI"]["elfDirs"] = m_elf_viewer;
data["GUI"]["recentFiles"] = m_recent_files; data["GUI"]["recentFiles"] = m_recent_files;
data["GUI"]["emulatorLanguage"] = emulator_language;
data["Settings"]["consoleLanguage"] = m_language; data["Settings"]["consoleLanguage"] = m_language;
// TODO Migration code, after a major release this should be removed.
data.at("GUI").as_table().erase("installDir");
std::ofstream file(path, std::ios::out); std::ofstream file(path, std::ios::out);
file << data; file << data;
file.close(); file.close();
@ -441,19 +666,37 @@ void save(const std::filesystem::path& path) {
void setDefaultValues() { void setDefaultValues() {
isNeo = false; isNeo = false;
isFullscreen = false; isFullscreen = false;
playBGM = false;
BGMvolume = 50;
enableDiscordRPC = true;
screenWidth = 1280; screenWidth = 1280;
screenHeight = 720; screenHeight = 720;
logFilter = ""; logFilter = "";
logType = "async"; logType = "async";
userName = "shadPS4"; userName = "shadPS4";
if (Common::isRelease) {
updateChannel = "Release";
} else {
updateChannel = "Nightly";
}
cursorState = HideCursorState::Idle;
cursorHideTimeout = 5;
backButtonBehavior = "left";
useSpecialPad = false;
specialPadClass = 1;
isDebugDump = false; isDebugDump = false;
isShowSplash = false; isShowSplash = false;
isAutoUpdate = false;
isNullGpu = false; isNullGpu = false;
shouldDumpShaders = false; shouldDumpShaders = false;
shouldDumpPM4 = false;
vblankDivider = 1; vblankDivider = 1;
vkValidation = false; vkValidation = false;
vkValidationSync = false;
vkValidationGpu = false;
rdocEnable = false; rdocEnable = false;
vkMarkers = false;
vkCrashDiagnostic = false;
emulator_language = "en";
m_language = 1; m_language = 1;
gpuId = -1; gpuId = -1;
} }

View File

@ -8,14 +8,29 @@
#include "types.h" #include "types.h"
namespace Config { namespace Config {
enum HideCursorState : s16 { Never, Idle, Always };
void load(const std::filesystem::path& path); void load(const std::filesystem::path& path);
void save(const std::filesystem::path& path); void save(const std::filesystem::path& path);
bool isNeoMode(); bool isNeoMode();
bool isFullscreenMode(); bool isFullscreenMode();
bool getPlayBGM();
int getBGMvolume();
bool getEnableDiscordRPC();
bool getSeparateUpdateEnabled();
std::string getLogFilter(); std::string getLogFilter();
std::string getLogType(); std::string getLogType();
std::string getUserName(); std::string getUserName();
std::string getUpdateChannel();
s16 getCursorState();
int getCursorHideTimeout();
std::string getBackButtonBehavior();
bool getUseSpecialPad();
int getSpecialPadClass();
u32 getScreenWidth(); u32 getScreenWidth();
u32 getScreenHeight(); u32 getScreenHeight();
@ -23,26 +38,38 @@ s32 getGpuId();
bool debugDump(); bool debugDump();
bool showSplash(); bool showSplash();
bool autoUpdate();
bool nullGpu(); bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders(); bool dumpShaders();
bool dumpPM4();
bool isRdocEnabled(); bool isRdocEnabled();
bool isMarkersEnabled();
u32 vblankDiv(); u32 vblankDiv();
void setDebugDump(bool enable); void setDebugDump(bool enable);
void setShowSplash(bool enable); void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setNullGpu(bool enable); void setNullGpu(bool enable);
void setCopyGPUCmdBuffers(bool enable);
void setDumpShaders(bool enable); void setDumpShaders(bool enable);
void setDumpPM4(bool enable);
void setVblankDiv(u32 value); void setVblankDiv(u32 value);
void setGpuId(s32 selectedGpuId); void setGpuId(s32 selectedGpuId);
void setScreenWidth(u32 width); void setScreenWidth(u32 width);
void setScreenHeight(u32 height); void setScreenHeight(u32 height);
void setFullscreenMode(bool enable); void setFullscreenMode(bool enable);
void setPlayBGM(bool enable);
void setBGMvolume(int volume);
void setEnableDiscordRPC(bool enable);
void setLanguage(u32 language); void setLanguage(u32 language);
void setNeoMode(bool enable); void setNeoMode(bool enable);
void setUserName(const std::string& type); void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type);
void setSeparateUpdateEnabled(bool use);
void setCursorState(s16 cursorState);
void setCursorHideTimeout(int newcursorHideTimeout);
void setBackButtonBehavior(const std::string& type);
void setUseSpecialPad(bool use);
void setSpecialPadClass(int type);
void setLogType(const std::string& type); void setLogType(const std::string& type);
void setLogFilter(const std::string& type); void setLogFilter(const std::string& type);
@ -54,38 +81,45 @@ void setRdocEnabled(bool enable);
bool vkValidationEnabled(); bool vkValidationEnabled();
bool vkValidationSyncEnabled(); bool vkValidationSyncEnabled();
bool vkValidationGpuEnabled(); bool vkValidationGpuEnabled();
bool vkMarkersEnabled();
bool vkCrashDiagnosticEnabled();
// Gui // Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h); void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
void setGameInstallDir(const std::string& dir); bool addGameInstallDir(const std::filesystem::path& dir);
void removeGameInstallDir(const std::filesystem::path& dir);
void setAddonInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme); void setMainWindowTheme(u32 theme);
void setIconSize(u32 size); void setIconSize(u32 size);
void setIconSizeGrid(u32 size); void setIconSizeGrid(u32 size);
void setSliderPositon(u32 pos); void setSliderPosition(u32 pos);
void setSliderPositonGrid(u32 pos); void setSliderPositionGrid(u32 pos);
void setTableMode(u32 mode); void setTableMode(u32 mode);
void setMainWindowWidth(u32 width); void setMainWindowWidth(u32 width);
void setMainWindowHeight(u32 height); void setMainWindowHeight(u32 height);
void setPkgViewer(const std::vector<std::string>& pkgList); void setPkgViewer(const std::vector<std::string>& pkgList);
void setElfViewer(const std::vector<std::string>& elfList); void setElfViewer(const std::vector<std::string>& elfList);
void setRecentFiles(const std::vector<std::string>& recentFiles); void setRecentFiles(const std::vector<std::string>& recentFiles);
void setEmulatorLanguage(std::string language);
u32 getMainWindowGeometryX(); u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY(); u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW(); u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH(); u32 getMainWindowGeometryH();
std::string getGameInstallDir(); const std::vector<std::filesystem::path>& getGameInstallDirs();
std::filesystem::path getAddonInstallDir();
u32 getMainWindowTheme(); u32 getMainWindowTheme();
u32 getIconSize(); u32 getIconSize();
u32 getIconSizeGrid(); u32 getIconSizeGrid();
u32 getSliderPositon(); u32 getSliderPosition();
u32 getSliderPositonGrid(); u32 getSliderPositionGrid();
u32 getTableMode(); u32 getTableMode();
u32 getMainWindowWidth(); u32 getMainWindowWidth();
u32 getMainWindowHeight(); u32 getMainWindowHeight();
std::vector<std::string> getPkgViewer(); std::vector<std::string> getPkgViewer();
std::vector<std::string> getElfViewer(); std::vector<std::string> getElfViewer();
std::vector<std::string> getRecentFiles(); std::vector<std::string> getRecentFiles();
std::string getEmulatorLanguage();
void setDefaultValues(); void setDefaultValues();

171
src/common/cstring.h Normal file
View File

@ -0,0 +1,171 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include "assert.h"
namespace Common {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-undefined-compare"
/**
* @brief A null-terminated string with a fixed maximum length
* This class is not meant to be used as a general-purpose string class
* It is meant to be used as `char[N]` where memory layout is fixed
* @tparam N Maximum length of the string
* @tparam T Type of character
*/
template <size_t N, typename T = char>
class CString {
T data[N]{};
public:
class Iterator;
CString() = default;
template <size_t M>
explicit CString(const CString<M>& other)
requires(M <= N)
{
if (this == nullptr) {
return;
}
std::ranges::copy(other.begin(), other.end(), data);
}
void FromString(const std::basic_string_view<T>& str) {
if (this == nullptr) {
return;
}
size_t p = str.copy(data, N - 1);
data[p] = '\0';
}
void Zero() {
if (this == nullptr) {
return;
}
std::ranges::fill(data, 0);
}
explicit(false) operator std::basic_string_view<T>() const {
if (this == nullptr) {
return {};
}
return std::basic_string_view<T>{data};
}
explicit operator std::basic_string<T>() const {
if (this == nullptr) {
return {};
}
return std::basic_string<T>{data};
}
std::basic_string<T> to_string() const {
if (this == nullptr) {
return {};
}
return std::basic_string<T>{data};
}
std::basic_string_view<T> to_view() const {
if (this == nullptr) {
return {};
}
return std::basic_string_view<T>{data};
}
T* begin() {
if (this == nullptr) {
return nullptr;
}
return data;
}
const T* begin() const {
if (this == nullptr) {
return nullptr;
}
return data;
}
T* end() {
if (this == nullptr) {
return nullptr;
}
return data + N;
}
const T* end() const {
if (this == nullptr) {
return nullptr;
}
return data + N;
}
constexpr std::size_t capacity() const {
return N;
}
std::size_t size() const {
return std::char_traits<T>::length(data);
}
T& operator[](size_t idx) {
return data[idx];
}
const T& operator[](size_t idx) const {
return data[idx];
}
class Iterator {
T* ptr;
T* end;
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
using iterator_category = std::random_access_iterator_tag;
Iterator() = default;
explicit Iterator(T* ptr) : ptr(ptr), end(ptr + N) {}
Iterator& operator++() {
++ptr;
return *this;
}
Iterator operator++(int) {
Iterator tmp = *this;
++ptr;
return tmp;
}
operator T*() {
ASSERT_MSG(ptr >= end, "CString iterator out of bounds");
return ptr;
}
};
};
static_assert(sizeof(CString<13>) == sizeof(char[13])); // Ensure size still matches a simple array
static_assert(std::weakly_incrementable<CString<13>::Iterator>);
template <size_t N>
using CWString = CString<N, wchar_t>;
template <size_t N>
using CU16String = CString<N, char16_t>;
#pragma clang diagnostic pop
} // namespace Common

View File

@ -29,7 +29,7 @@ static inline bool IsProfilerConnected() {
#define TRACK_ALLOC(ptr, size, pool) TracyAllocN(std::bit_cast<void*>(ptr), (size), (pool)) #define TRACK_ALLOC(ptr, size, pool) TracyAllocN(std::bit_cast<void*>(ptr), (size), (pool))
#define TRACK_FREE(ptr, pool) TracyFreeN(std::bit_cast<void*>(ptr), (pool)) #define TRACK_FREE(ptr, pool) TracyFreeN(std::bit_cast<void*>(ptr), (pool))
enum MarkersPallete : int { enum MarkersPalette : int {
EmulatorMarkerColor = 0x264653, EmulatorMarkerColor = 0x264653,
RendererMarkerColor = 0x2a9d8f, RendererMarkerColor = 0x2a9d8f,
HleMarkerColor = 0xe9c46a, HleMarkerColor = 0xe9c46a,

View File

@ -2,18 +2,18 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <fmt/format.h> #include <fmt/format.h>
#include "common/disassembler.h" #include "common/decoder.h"
namespace Common { namespace Common {
Disassembler::Disassembler() { DecoderImpl::DecoderImpl() {
ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64); ZydisDecoderInit(&m_decoder, ZYDIS_MACHINE_MODE_LONG_64, ZYDIS_STACK_WIDTH_64);
ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL); ZydisFormatterInit(&m_formatter, ZYDIS_FORMATTER_STYLE_INTEL);
} }
Disassembler::~Disassembler() = default; DecoderImpl::~DecoderImpl() = default;
void Disassembler::printInstruction(void* code, u64 address) { void DecoderImpl::printInstruction(void* code, u64 address) {
ZydisDecodedInstruction instruction; ZydisDecodedInstruction instruction;
ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE]; ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT_VISIBLE];
ZyanStatus status = ZyanStatus status =
@ -25,8 +25,8 @@ void Disassembler::printInstruction(void* code, u64 address) {
} }
} }
void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, void DecoderImpl::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,
u64 address) { u64 address) {
const int bufLen = 256; const int bufLen = 256;
char szBuffer[bufLen]; char szBuffer[bufLen];
ZydisFormatterFormatInstruction(&m_formatter, &inst, operands, inst.operand_count_visible, ZydisFormatterFormatInstruction(&m_formatter, &inst, operands, inst.operand_count_visible,
@ -34,4 +34,9 @@ void Disassembler::printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand*
fmt::print("instruction: {}\n", szBuffer); fmt::print("instruction: {}\n", szBuffer);
} }
ZyanStatus DecoderImpl::decodeInstruction(ZydisDecodedInstruction& inst,
ZydisDecodedOperand* operands, void* data, u64 size) {
return ZydisDecoderDecodeFull(&m_decoder, data, size, &inst, operands);
}
} // namespace Common } // namespace Common

View File

@ -4,21 +4,26 @@
#pragma once #pragma once
#include <Zydis/Zydis.h> #include <Zydis/Zydis.h>
#include "common/singleton.h"
#include "common/types.h" #include "common/types.h"
namespace Common { namespace Common {
class Disassembler { class DecoderImpl {
public: public:
Disassembler(); DecoderImpl();
~Disassembler(); ~DecoderImpl();
void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address); void printInst(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands, u64 address);
void printInstruction(void* code, u64 address); void printInstruction(void* code, u64 address);
ZyanStatus decodeInstruction(ZydisDecodedInstruction& inst, ZydisDecodedOperand* operands,
void* data, u64 size = 15);
private: private:
ZydisDecoder m_decoder; ZydisDecoder m_decoder;
ZydisFormatter m_formatter; ZydisFormatter m_formatter;
}; };
using Decoder = Common::Singleton<DecoderImpl>;
} // namespace Common } // namespace Common

View File

@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include <ctime>
#include "common/discord.h"
namespace Discord {
void RPC::init() {
DiscordEventHandlers handlers{};
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
startTimestamp = time(nullptr);
enabled = true;
}
void RPC::update(Discord::RPCStatus status, const std::string& game) {
DiscordRichPresence rpc{};
if (status == Discord::RPCStatus::Playing) {
rpc.details = "Playing a game";
rpc.state = game.c_str();
} else {
rpc.details = "Idle";
}
rpc.largeImageKey = "shadps4";
rpc.largeImageText = "ShadPS4 is a PS4 emulator";
rpc.startTimestamp = startTimestamp;
Discord_UpdatePresence(&rpc);
}
void RPC::stop() {
if (enabled) {
enabled = false;
Discord_ClearPresence();
Discord_Shutdown();
}
}
} // namespace Discord

View File

@ -0,0 +1,57 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include <ctime>
#include "src/common/discord_rpc_handler.h"
namespace DiscordRPCHandler {
void RPC::init() {
DiscordEventHandlers handlers{};
Discord_Initialize("1139939140494971051", &handlers, 1, nullptr);
startTimestamp = time(nullptr);
rpcEnabled = true;
}
void RPC::setStatusIdling() {
DiscordRichPresence rpc{};
rpc.largeImageKey = "https://github.com/shadps4-emu/shadPS4/raw/main/.github/shadps4.png";
rpc.largeImageText = "shadPS4 is a PS4 emulator";
rpc.startTimestamp = startTimestamp;
rpc.details = "Idle";
status = RPCStatus::Idling;
Discord_UpdatePresence(&rpc);
}
void RPC::setStatusPlaying(const std::string& game_name, const std::string& game_id) {
DiscordRichPresence rpc{};
rpc.details = "Playing";
rpc.state = game_name.c_str();
std::string largeImageUrl =
"https://store.playstation.com/store/api/chihiro/00_09_000/titlecontainer/US/en/999/" +
game_id + "_00/image";
rpc.largeImageKey = largeImageUrl.c_str();
rpc.largeImageText = game_name.c_str();
rpc.startTimestamp = startTimestamp;
status = RPCStatus::Playing;
Discord_UpdatePresence(&rpc);
}
void RPC::shutdown() {
if (rpcEnabled) {
rpcEnabled = false;
Discord_ClearPresence();
Discord_Shutdown();
}
}
bool RPC::getRPCEnabled() {
return rpcEnabled;
}
} // namespace DiscordRPCHandler

View File

@ -7,7 +7,7 @@
#include <string> #include <string>
#include <discord_rpc.h> #include <discord_rpc.h>
namespace Discord { namespace DiscordRPCHandler {
enum class RPCStatus { enum class RPCStatus {
Idling, Idling,
@ -16,12 +16,15 @@ enum class RPCStatus {
class RPC { class RPC {
std::uint64_t startTimestamp; std::uint64_t startTimestamp;
bool enabled = false; bool rpcEnabled = false;
RPCStatus status;
public: public:
void init(); void init();
void update(RPCStatus status, const std::string& title); void setStatusIdling();
void stop(); void setStatusPlaying(const std::string& game_name, const std::string& game_id);
void shutdown();
bool getRPCEnabled();
}; };
} // namespace Discord } // namespace DiscordRPCHandler

72
src/common/elf_info.h Normal file
View File

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <string_view>
#include "assert.h"
#include "singleton.h"
#include "types.h"
namespace Core {
class Emulator;
}
namespace Common {
class ElfInfo {
friend class Core::Emulator;
bool initialized = false;
std::string game_serial{};
std::string title{};
std::string app_ver{};
u32 firmware_ver = 0;
u32 raw_firmware_ver = 0;
public:
static constexpr u32 FW_15 = 0x1500000;
static constexpr u32 FW_16 = 0x1600000;
static constexpr u32 FW_17 = 0x1700000;
static constexpr u32 FW_20 = 0x2000000;
static constexpr u32 FW_25 = 0x2500000;
static constexpr u32 FW_30 = 0x3000000;
static constexpr u32 FW_40 = 0x4000000;
static constexpr u32 FW_45 = 0x4500000;
static constexpr u32 FW_50 = 0x5000000;
static constexpr u32 FW_80 = 0x8000000;
static ElfInfo& Instance() {
return *Singleton<ElfInfo>::Instance();
}
[[nodiscard]] std::string_view GameSerial() const {
ASSERT(initialized);
return Instance().game_serial;
}
[[nodiscard]] std::string_view Title() const {
ASSERT(initialized);
return title;
}
[[nodiscard]] std::string_view AppVer() const {
ASSERT(initialized);
return app_ver;
}
[[nodiscard]] u32 FirmwareVer() const {
ASSERT(initialized);
return firmware_ver;
}
[[nodiscard]] u32 RawFirmwareVer() const {
ASSERT(initialized);
return raw_firmware_ver;
}
};
} // namespace Common

35
src/common/fixed_value.h Normal file
View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
/**
* @brief A template class that encapsulates a fixed, compile-time constant value.
*
* @tparam T The type of the value.
* @tparam Value The fixed value of type T.
*
* This class provides a way to encapsulate a value that is constant and known at compile-time.
* The value is stored as a private member and cannot be changed. Any attempt to assign a new
* value to an object of this class will reset it to the fixed value.
*/
template <typename T, T Value>
class FixedValue {
T m_value{Value};
public:
constexpr FixedValue() = default;
constexpr explicit(false) operator T() const {
return m_value;
}
FixedValue& operator=(const T&) {
m_value = Value;
return *this;
}
FixedValue& operator=(T&&) noexcept {
m_value = {Value};
return *this;
}
};

View File

@ -192,8 +192,9 @@ int IOFile::Open(const fs::path& path, FileAccessMode mode, FileType type, FileS
#endif #endif
if (!IsOpen()) { if (!IsOpen()) {
LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}", const auto ec = std::error_code{result, std::generic_category()};
PathToUTF8String(file_path)); LOG_ERROR(Common_Filesystem, "Failed to open the file at path={}, error_message={}",
PathToUTF8String(file_path), ec.message());
} }
return result; return result;
@ -230,7 +231,7 @@ void IOFile::Unlink() {
// Mark the file for deletion // Mark the file for deletion
// TODO: Also remove the file path? // TODO: Also remove the file path?
#if _WIN64 #ifdef _WIN64
FILE_DISPOSITION_INFORMATION disposition; FILE_DISPOSITION_INFORMATION disposition;
IO_STATUS_BLOCK iosb; IO_STATUS_BLOCK iosb;
@ -241,7 +242,11 @@ void IOFile::Unlink() {
NtSetInformationFile(hfile, &iosb, &disposition, sizeof(disposition), NtSetInformationFile(hfile, &iosb, &disposition, sizeof(disposition),
FileDispositionInformation); FileDispositionInformation);
#else #else
UNREACHABLE_MSG("Missing Linux implementation"); if (unlink(file_path.c_str()) != 0) {
const auto ec = std::error_code{errno, std::generic_category()};
LOG_ERROR(Common_Filesystem, "Failed to unlink the file at path={}, ec_message={}",
PathToUTF8String(file_path), ec.message());
}
#endif #endif
} }
@ -372,6 +377,18 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false; return false;
} }
u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
errno = 0; errno = 0;
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0; const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;
@ -396,4 +413,18 @@ s64 IOFile::Tell() const {
return ftello(file); return ftello(file);
} }
u64 GetDirectorySize(const std::filesystem::path& path) {
if (!fs::exists(path)) {
return 0;
}
u64 total = 0;
for (const auto& entry : fs::recursive_directory_iterator(path)) {
if (fs::is_regular_file(entry.path())) {
total += fs::file_size(entry.path());
}
}
return total;
}
} // namespace Common::FS } // namespace Common::FS

View File

@ -205,9 +205,9 @@ public:
return WriteSpan(string); return WriteSpan(string);
} }
static void WriteBytes(const std::filesystem::path path, std::span<const u8> data) { static size_t WriteBytes(const std::filesystem::path path, std::span<const u8> data) {
IOFile out(path, FileAccessMode::Write); IOFile out(path, FileAccessMode::Write);
out.Write(data); return out.Write(data);
} }
private: private:
@ -219,4 +219,6 @@ private:
uintptr_t file_mapping = 0; uintptr_t file_mapping = 0;
}; };
u64 GetDirectorySize(const std::filesystem::path& path);
} // namespace Common::FS } // namespace Common::FS

View File

@ -144,6 +144,10 @@ public:
initialization_in_progress_suppress_logging = false; initialization_in_progress_suppress_logging = false;
} }
static bool IsActive() {
return instance != nullptr;
}
static void Start() { static void Start() {
instance->StartBackendThread(); instance->StartBackendThread();
} }
@ -275,6 +279,10 @@ void Initialize(std::string_view log_file) {
Impl::Initialize(log_file.empty() ? LOG_FILE : log_file); Impl::Initialize(log_file.empty() ? LOG_FILE : log_file);
} }
bool IsActive() {
return Impl::IsActive();
}
void Start() { void Start() {
Impl::Start(); Impl::Start();
} }

View File

@ -13,6 +13,8 @@ class Filter;
/// Initializes the logging system. This should be the first thing called in main. /// Initializes the logging system. This should be the first thing called in main.
void Initialize(std::string_view log_file = ""); void Initialize(std::string_view log_file = "");
bool IsActive();
/// Starts the logging threads. /// Starts the logging threads.
void Start(); void Start();

View File

@ -113,10 +113,17 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, ImeDialog) \ SUB(Lib, ImeDialog) \
SUB(Lib, AvPlayer) \ SUB(Lib, AvPlayer) \
SUB(Lib, Ngs2) \ SUB(Lib, Ngs2) \
SUB(Lib, Audio3d) \
SUB(Lib, Ime) \
SUB(Lib, GameLiveStreaming) \
SUB(Lib, Remoteplay) \
SUB(Lib, SharePlay) \
SUB(Lib, Fiber) \
CLS(Frontend) \ CLS(Frontend) \
CLS(Render) \ CLS(Render) \
SUB(Render, Vulkan) \ SUB(Render, Vulkan) \
SUB(Render, Recompiler) \ SUB(Render, Recompiler) \
CLS(ImGui) \
CLS(Input) \ CLS(Input) \
CLS(Tty) \ CLS(Tty) \
CLS(Loader) CLS(Loader)

View File

@ -19,3 +19,24 @@ struct fmt::formatter<T, std::enable_if_t<std::is_enum_v<T>, char>>
} }
}; };
#endif #endif
namespace fmt {
template <typename T = std::string_view>
struct UTF {
T data;
explicit UTF(const std::u8string_view view) {
data = view.empty() ? T{} : T{(const char*)&view.front(), (const char*)&view.back() + 1};
}
explicit UTF(const std::u8string& str) : UTF(std::u8string_view{str}) {}
};
} // namespace fmt
template <>
struct fmt::formatter<fmt::UTF<std::string_view>, char> : formatter<std::string_view> {
template <typename FormatContext>
auto format(const UTF<std::string_view>& wrapper, FormatContext& ctx) const {
return formatter<std::string_view>::format(wrapper.data, ctx);
}
};

View File

@ -29,65 +29,72 @@ enum class Level : u8 {
* filter.cpp. * filter.cpp.
*/ */
enum class Class : u8 { enum class Class : u8 {
Log, ///< Messages about the log system itself Log, ///< Messages about the log system itself
Common, ///< Library routines Common, ///< Library routines
Common_Filesystem, ///< Filesystem interface library Common_Filesystem, ///< Filesystem interface library
Common_Memory, ///< Memory mapping and management functions Common_Memory, ///< Memory mapping and management functions
Core, ///< LLE emulation core Core, ///< LLE emulation core
Core_Linker, ///< The module linker Core_Linker, ///< The module linker
Config, ///< Emulator configuration (including commandline) Config, ///< Emulator configuration (including commandline)
Debug, ///< Debugging tools Debug, ///< Debugging tools
Kernel, ///< The HLE implementation of the PS4 kernel. Kernel, ///< The HLE implementation of the PS4 kernel.
Kernel_Pthread, ///< The pthread implementation of the kernel. Kernel_Pthread, ///< The pthread implementation of the kernel.
Kernel_Fs, ///< The filesystem implementation of the kernel. Kernel_Fs, ///< The filesystem implementation of the kernel.
Kernel_Vmm, ///< The virtual memory implementation of the kernel. Kernel_Vmm, ///< The virtual memory implementation of the kernel.
Kernel_Event, ///< The event management implementation of the kernel. Kernel_Event, ///< The event management implementation of the kernel.
Kernel_Sce, ///< The sony specific interfaces provided by the kernel. Kernel_Sce, ///< The sony specific interfaces provided by the kernel.
Lib, ///< HLE implementation of system library. Each major library Lib, ///< HLE implementation of system library. Each major library
///< should have its own subclass. ///< should have its own subclass.
Lib_LibC, ///< The LibC implementation. Lib_LibC, ///< The LibC implementation.
Lib_Kernel, ///< The LibKernel implementation. Lib_Kernel, ///< The LibKernel implementation.
Lib_Pad, ///< The LibScePad implementation. Lib_Pad, ///< The LibScePad implementation.
Lib_GnmDriver, ///< The LibSceGnmDriver implementation. Lib_GnmDriver, ///< The LibSceGnmDriver implementation.
Lib_SystemService, ///< The LibSceSystemService implementation. Lib_SystemService, ///< The LibSceSystemService implementation.
Lib_UserService, ///< The LibSceUserService implementation. Lib_UserService, ///< The LibSceUserService implementation.
Lib_VideoOut, ///< The LibSceVideoOut implementation. Lib_VideoOut, ///< The LibSceVideoOut implementation.
Lib_CommonDlg, ///< The LibSceCommonDialog implementation. Lib_CommonDlg, ///< The LibSceCommonDialog implementation.
Lib_MsgDlg, ///< The LibSceMsgDialog implementation. Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
Lib_AudioOut, ///< The LibSceAudioOut implementation. Lib_AudioOut, ///< The LibSceAudioOut implementation.
Lib_AudioIn, ///< The LibSceAudioIn implementation. Lib_AudioIn, ///< The LibSceAudioIn implementation.
Lib_Net, ///< The LibSceNet implementation. Lib_Net, ///< The LibSceNet implementation.
Lib_NetCtl, ///< The LibSecNetCtl implementation. Lib_NetCtl, ///< The LibSecNetCtl implementation.
Lib_SaveData, ///< The LibSceSaveData implementation. Lib_SaveData, ///< The LibSceSaveData implementation.
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation. Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
Lib_Ssl, ///< The LibSceSsl implementation. Lib_Ssl, ///< The LibSceSsl implementation.
Lib_Http, ///< The LibSceHttp implementation. Lib_Http, ///< The LibSceHttp implementation.
Lib_SysModule, ///< The LibSceSysModule implementation Lib_SysModule, ///< The LibSceSysModule implementation
Lib_NpManager, ///< The LibSceNpManager implementation Lib_NpManager, ///< The LibSceNpManager implementation
Lib_NpScore, ///< The LibSceNpScore implementation Lib_NpScore, ///< The LibSceNpScore implementation
Lib_NpTrophy, ///< The LibSceNpTrophy implementation Lib_NpTrophy, ///< The LibSceNpTrophy implementation
Lib_Screenshot, ///< The LibSceScreenshot implementation Lib_Screenshot, ///< The LibSceScreenshot implementation
Lib_LibCInternal, ///< The LibCInternal implementation. Lib_LibCInternal, ///< The LibCInternal implementation.
Lib_AppContent, ///< The LibSceAppContent implementation. Lib_AppContent, ///< The LibSceAppContent implementation.
Lib_Rtc, ///< The LibSceRtc implementation. Lib_Rtc, ///< The LibSceRtc implementation.
Lib_DiscMap, ///< The LibSceDiscMap implementation. Lib_DiscMap, ///< The LibSceDiscMap implementation.
Lib_Png, ///< The LibScePng implementation. Lib_Png, ///< The LibScePng implementation.
Lib_PlayGo, ///< The LibScePlayGo implementation. Lib_PlayGo, ///< The LibScePlayGo implementation.
Lib_Random, ///< The libSceRandom implementation. Lib_Random, ///< The libSceRandom implementation.
Lib_Usbd, ///< The LibSceUsbd implementation. Lib_Usbd, ///< The LibSceUsbd implementation.
Lib_Ajm, ///< The LibSceAjm implementation. Lib_Ajm, ///< The LibSceAjm implementation.
Lib_ErrorDialog, ///< The LibSceErrorDialog implementation. Lib_ErrorDialog, ///< The LibSceErrorDialog implementation.
Lib_ImeDialog, ///< The LibSceImeDialog implementation. Lib_ImeDialog, ///< The LibSceImeDialog implementation.
Lib_AvPlayer, ///< The LibSceAvPlayer implementation. Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
Lib_Ngs2, ///< The LibSceNgs2 implementation. Lib_Ngs2, ///< The LibSceNgs2 implementation.
Frontend, ///< Emulator UI Lib_Audio3d, ///< The LibSceAudio3d implementation.
Render, ///< Video Core Lib_Ime, ///< The LibSceIme implementation
Render_Vulkan, ///< Vulkan backend Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
Render_Recompiler, ///< Shader recompiler Lib_Remoteplay, ///< The LibSceRemotePlay implementation
Loader, ///< ROM loader Lib_SharePlay, ///< The LibSceSharePlay implemenation
Input, ///< Input emulation Lib_Fiber, ///< The LibSceFiber implementation.
Tty, ///< Debug output from emu Frontend, ///< Emulator UI
Count ///< Total number of logging classes Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
Render_Recompiler, ///< Shader recompiler
ImGui, ///< ImGui
Loader, ///< ROM loader
Input, ///< Input emulation
Tty, ///< Debug output from emu
Count ///< Total number of logging classes
}; };
} // namespace Common::Log } // namespace Common::Log

View File

@ -0,0 +1,446 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <codecvt>
#include <sstream>
#include <string>
#include <pugixml.hpp>
#ifdef ENABLE_QT_GUI
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QListView>
#include <QMessageBox>
#include <QString>
#include <QXmlStreamReader>
#endif
#include "common/logging/log.h"
#include "common/path_util.h"
#include "memory_patcher.h"
namespace MemoryPatcher {
uintptr_t g_eboot_address;
uint64_t g_eboot_image_size;
std::string g_game_serial;
std::string patchFile;
std::vector<patchInfo> pending_patches;
std::string toHex(unsigned long long value, size_t byteSize) {
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(byteSize * 2) << value;
return ss.str();
}
std::string convertValueToHex(const std::string type, const std::string valueStr) {
std::string result;
if (type == "byte") {
unsigned int value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 1);
} else if (type == "bytes16") {
unsigned int value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 2);
} else if (type == "bytes32") {
unsigned long value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 4);
} else if (type == "bytes64") {
unsigned long long value = std::stoull(valueStr, nullptr, 16);
result = toHex(value, 8);
} else if (type == "float32") {
union {
float f;
uint32_t i;
} floatUnion;
floatUnion.f = std::stof(valueStr);
result = toHex(floatUnion.i, sizeof(floatUnion.i));
} else if (type == "float64") {
union {
double d;
uint64_t i;
} doubleUnion;
doubleUnion.d = std::stod(valueStr);
result = toHex(doubleUnion.i, sizeof(doubleUnion.i));
} else if (type == "utf8") {
std::vector<unsigned char> byteArray =
std::vector<unsigned char>(valueStr.begin(), valueStr.end());
byteArray.push_back('\0');
std::stringstream ss;
for (unsigned char c : byteArray) {
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(c);
}
result = ss.str();
} else if (type == "utf16") {
std::wstring wide_str(valueStr.size(), L'\0');
std::mbstowcs(&wide_str[0], valueStr.c_str(), valueStr.size());
wide_str.resize(std::wcslen(wide_str.c_str()));
std::u16string valueStringU16;
for (wchar_t wc : wide_str) {
if (wc <= 0xFFFF) {
valueStringU16.push_back(static_cast<char16_t>(wc));
} else {
wc -= 0x10000;
valueStringU16.push_back(static_cast<char16_t>(0xD800 | (wc >> 10)));
valueStringU16.push_back(static_cast<char16_t>(0xDC00 | (wc & 0x3FF)));
}
}
std::vector<unsigned char> byteArray;
// convert to little endian
for (char16_t ch : valueStringU16) {
unsigned char low_byte = static_cast<unsigned char>(ch & 0x00FF);
unsigned char high_byte = static_cast<unsigned char>((ch >> 8) & 0x00FF);
byteArray.push_back(low_byte);
byteArray.push_back(high_byte);
}
byteArray.push_back('\0');
byteArray.push_back('\0');
std::stringstream ss;
for (unsigned char ch : byteArray) {
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(ch);
}
result = ss.str();
} else if (type == "bytes") {
result = valueStr;
} else if (type == "mask" || type == "mask_jump32") {
result = valueStr;
} else {
LOG_INFO(Loader, "Error applying Patch, unknown type: {}", type);
}
return result;
}
void OnGameLoaded() {
if (!patchFile.empty()) {
std::filesystem::path patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
auto filePath = (patchDir / patchFile).native();
pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filePath.c_str());
if (result) {
auto patchXML = doc.child("Patch");
for (pugi::xml_node_iterator it = patchXML.children().begin();
it != patchXML.children().end(); ++it) {
if (std::string(it->name()) == "Metadata") {
if (std::string(it->attribute("isEnabled").value()) == "true") {
auto patchList = it->first_child();
std::string currentPatchName = it->attribute("Name").value();
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
patchLineIt != patchList.children().end(); ++patchLineIt) {
std::string type = patchLineIt->attribute("Type").value();
std::string address = patchLineIt->attribute("Address").value();
std::string patchValue = patchLineIt->attribute("Value").value();
std::string maskOffsetStr = patchLineIt->attribute("type").value();
patchValue = convertValueToHex(type, patchValue);
bool littleEndian = false;
if (type == "bytes16") {
littleEndian = true;
} else if (type == "bytes32") {
littleEndian = true;
} else if (type == "bytes64") {
littleEndian = true;
}
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;
if (type == "mask") {
patchMask = MemoryPatcher::PatchMask::Mask;
// im not sure if this works, there is no games to test the mask
// offset on yet
if (!maskOffsetStr.empty())
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, false,
littleEndian, patchMask);
}
}
}
}
} else
LOG_ERROR(Loader, "couldnt patch parse xml : {}", result.description());
ApplyPendingPatches();
return;
}
#ifdef ENABLE_QT_GUI
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
QString patchDir;
Common::FS::PathToQString(patchDir, Common::FS::GetUserPath(Common::FS::PathType::PatchesDir));
QString repositories[] = {"GoldHEN", "shadPS4"};
for (const QString& repository : repositories) {
QString filesJsonPath = patchDir + "/" + repository + "/files.json";
QFile jsonFile(filesJsonPath);
if (!jsonFile.open(QIODevice::ReadOnly)) {
LOG_ERROR(Loader, "Unable to open files.json for reading.");
continue;
}
QByteArray jsonData = jsonFile.readAll();
jsonFile.close();
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
QJsonObject jsonObject = jsonDoc.object();
QString selectedFileName;
QString serial = QString::fromStdString(g_game_serial);
for (auto it = jsonObject.constBegin(); it != jsonObject.constEnd(); ++it) {
QString filePath = it.key();
QJsonArray idsArray = it.value().toArray();
if (idsArray.contains(QJsonValue(serial))) {
selectedFileName = filePath;
break;
}
}
if (selectedFileName.isEmpty()) {
LOG_ERROR(Loader, "No patch file found for the current serial.");
continue;
}
QString filePath = patchDir + "/" + repository + "/" + selectedFileName;
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
LOG_ERROR(Loader, "Unable to open the file for reading.");
continue;
}
QByteArray xmlData = file.readAll();
file.close();
QString newXmlData;
QXmlStreamReader xmlReader(xmlData);
bool insideMetadata = false;
bool isEnabled = false;
std::string currentPatchName;
while (!xmlReader.atEnd()) {
xmlReader.readNext();
if (xmlReader.isStartElement()) {
QJsonArray patchLines;
if (xmlReader.name() == QStringLiteral("Metadata")) {
insideMetadata = true;
QString name = xmlReader.attributes().value("Name").toString();
currentPatchName = name.toStdString();
// Check and update the isEnabled attribute
for (const QXmlStreamAttribute& attr : xmlReader.attributes()) {
if (attr.name() == QStringLiteral("isEnabled")) {
if (attr.value().toString() == "true") {
isEnabled = true;
} else
isEnabled = false;
}
}
} else if (xmlReader.name() == QStringLiteral("PatchList")) {
QJsonArray linesArray;
while (!xmlReader.atEnd() &&
!(xmlReader.tokenType() == QXmlStreamReader::EndElement &&
xmlReader.name() == QStringLiteral("PatchList"))) {
xmlReader.readNext();
if (xmlReader.tokenType() == QXmlStreamReader::StartElement &&
xmlReader.name() == QStringLiteral("Line")) {
QXmlStreamAttributes attributes = xmlReader.attributes();
QJsonObject lineObject;
lineObject["Type"] = attributes.value("Type").toString();
lineObject["Address"] = attributes.value("Address").toString();
lineObject["Value"] = attributes.value("Value").toString();
linesArray.append(lineObject);
}
}
patchLines = linesArray;
if (isEnabled) {
foreach (const QJsonValue& value, patchLines) {
QJsonObject lineObject = value.toObject();
QString type = lineObject["Type"].toString();
QString address = lineObject["Address"].toString();
QString patchValue = lineObject["Value"].toString();
QString maskOffsetStr = lineObject["Offset"].toString();
patchValue = QString::fromStdString(
convertValueToHex(type.toStdString(), patchValue.toStdString()));
bool littleEndian = false;
if (type == "bytes16") {
littleEndian = true;
} else if (type == "bytes32") {
littleEndian = true;
} else if (type == "bytes64") {
littleEndian = true;
}
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;
if (type == "mask") {
patchMask = MemoryPatcher::PatchMask::Mask;
// im not sure if this works, there is no games to test the mask
// offset on yet
if (!maskOffsetStr.toStdString().empty())
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
}
if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
MemoryPatcher::PatchMemory(currentPatchName, address.toStdString(),
patchValue.toStdString(), false,
littleEndian, patchMask);
}
}
}
}
}
if (xmlReader.hasError()) {
LOG_ERROR(Loader, "Failed to parse XML for {}", g_game_serial);
} else {
LOG_INFO(Loader, "Patches loaded successfully");
}
ApplyPendingPatches();
}
#endif
}
void AddPatchToQueue(patchInfo patchToAdd) {
pending_patches.push_back(patchToAdd);
}
void ApplyPendingPatches() {
for (size_t i = 0; i < pending_patches.size(); ++i) {
patchInfo currentPatch = pending_patches[i];
if (currentPatch.gameSerial != g_game_serial)
continue;
PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr,
currentPatch.isOffset, currentPatch.littleEndian, currentPatch.patchMask,
currentPatch.maskOffset);
}
pending_patches.clear();
}
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
bool littleEndian, PatchMask patchMask, int maskOffset) {
// Send a request to modify the process memory.
void* cheatAddress = nullptr;
if (patchMask == PatchMask::None) {
if (isOffset) {
cheatAddress = reinterpret_cast<void*>(g_eboot_address + std::stoi(offsetStr, 0, 16));
} else {
cheatAddress =
reinterpret_cast<void*>(g_eboot_address + (std::stoi(offsetStr, 0, 16) - 0x400000));
}
}
if (patchMask == PatchMask::Mask) {
cheatAddress = reinterpret_cast<void*>(PatternScan(offsetStr) + maskOffset);
}
// TODO: implement mask_jump32
if (cheatAddress == nullptr) {
LOG_ERROR(Loader, "Failed to get address for patch {}", modNameStr);
return;
}
std::vector<unsigned char> bytePatch;
for (size_t i = 0; i < valueStr.length(); i += 2) {
unsigned char byte =
static_cast<unsigned char>(std::strtol(valueStr.substr(i, 2).c_str(), nullptr, 16));
bytePatch.push_back(byte);
}
if (littleEndian) {
std::reverse(bytePatch.begin(), bytePatch.end());
}
std::memcpy(cheatAddress, bytePatch.data(), bytePatch.size());
LOG_INFO(Loader, "Applied patch: {}, Offset: {}, Value: {}", modNameStr,
(uintptr_t)cheatAddress, valueStr);
}
static std::vector<int32_t> PatternToByte(const std::string& pattern) {
std::vector<int32_t> bytes;
const char* start = pattern.data();
const char* end = start + pattern.size();
for (const char* current = start; current < end; ++current) {
if (*current == '?') {
++current;
if (*current == '?')
++current;
bytes.push_back(-1);
} else {
bytes.push_back(strtoul(current, const_cast<char**>(&current), 16));
}
}
return bytes;
}
uintptr_t PatternScan(const std::string& signature) {
std::vector<int32_t> patternBytes = PatternToByte(signature);
const auto scanBytes = static_cast<uint8_t*>((void*)g_eboot_address);
const int32_t* sigPtr = patternBytes.data();
const size_t sigSize = patternBytes.size();
uint32_t foundResults = 0;
for (uint32_t i = 0; i < g_eboot_image_size - sigSize; ++i) {
bool found = true;
for (uint32_t j = 0; j < sigSize; ++j) {
if (scanBytes[i + j] != sigPtr[j] && sigPtr[j] != -1) {
found = false;
break;
}
}
if (found) {
foundResults++;
return reinterpret_cast<uintptr_t>(&scanBytes[i]);
}
}
return 0;
}
} // namespace MemoryPatcher

View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cstring>
#include <string>
#include <vector>
namespace MemoryPatcher {
extern uintptr_t g_eboot_address;
extern uint64_t g_eboot_image_size;
extern std::string g_game_serial;
extern std::string patchFile;
enum PatchMask : uint8_t {
None,
Mask,
Mask_Jump32,
};
struct patchInfo {
std::string gameSerial;
std::string modNameStr;
std::string offsetStr;
std::string valueStr;
bool isOffset;
bool littleEndian;
PatchMask patchMask;
int maskOffset;
};
extern std::vector<patchInfo> pending_patches;
std::string convertValueToHex(const std::string type, const std::string valueStr);
void OnGameLoaded();
void AddPatchToQueue(patchInfo patchToAdd);
void ApplyPendingPatches();
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
bool littleEndian, PatchMask patchMask = PatchMask::None, int maskOffset = 0);
static std::vector<int32_t> PatternToByte(const std::string& pattern);
uintptr_t PatternScan(const std::string& signature);
} // namespace MemoryPatcher

View File

@ -18,16 +18,16 @@ NativeClock::NativeClock()
us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)}, us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)},
ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {} ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {}
u64 NativeClock::GetTimeNS() const { u64 NativeClock::GetTimeNS(u64 base_ptc /*= 0*/) const {
return MultiplyHigh(GetUptime(), ns_rdtsc_factor); return MultiplyHigh(GetUptime() - base_ptc, ns_rdtsc_factor);
} }
u64 NativeClock::GetTimeUS() const { u64 NativeClock::GetTimeUS(u64 base_ptc /*= 0*/) const {
return MultiplyHigh(GetUptime(), us_rdtsc_factor); return MultiplyHigh(GetUptime() - base_ptc, us_rdtsc_factor);
} }
u64 NativeClock::GetTimeMS() const { u64 NativeClock::GetTimeMS(u64 base_ptc /*= 0*/) const {
return MultiplyHigh(GetUptime(), ms_rdtsc_factor); return MultiplyHigh(GetUptime() - base_ptc, ms_rdtsc_factor);
} }
u64 NativeClock::GetUptime() const { u64 NativeClock::GetUptime() const {

View File

@ -16,9 +16,9 @@ public:
return rdtsc_frequency; return rdtsc_frequency;
} }
u64 GetTimeNS() const; u64 GetTimeNS(u64 base_ptc = 0) const;
u64 GetTimeUS() const; u64 GetTimeUS(u64 base_ptc = 0) const;
u64 GetTimeMS() const; u64 GetTimeMS(u64 base_ptc = 0) const;
u64 GetUptime() const; u64 GetUptime() const;
u64 GetProcessTimeUS() const; u64 GetProcessTimeUS() const;

161
src/common/number_utils.cpp Normal file
View File

@ -0,0 +1,161 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <half.hpp>
#include "common/number_utils.h"
#include "video_core/amdgpu/pixel_format.h"
#include "video_core/amdgpu/types.h"
#define UF11_EXPONENT_SHIFT 6
#define UF10_EXPONENT_SHIFT 5
#define RGB9E5_MANTISSA_BITS 9
#define RGB9E5_EXP_BIAS 1
#define F32_INFINITY 0x7f800000
namespace NumberUtils {
float Uf11ToF32(u16 val) {
union {
float f;
u32 ui;
} f32;
int exponent = (val & 0x07c0) >> UF11_EXPONENT_SHIFT;
int mantissa = (val & 0x003f);
f32.f = 0.0;
if (exponent == 0) {
if (mantissa != 0) {
const float scale = 1.0 / (1 << 20);
f32.f = scale * mantissa;
}
} else if (exponent == 31) {
f32.ui = F32_INFINITY | mantissa;
} else {
float scale, decimal;
exponent -= 15;
if (exponent < 0) {
scale = 1.0f / (1 << -exponent);
} else {
scale = (float)(1 << exponent);
}
decimal = 1.0f + (float)mantissa / 64;
f32.f = scale * decimal;
}
return f32.f;
}
float Uf10ToF32(u16 val) {
union {
float f;
u32 ui;
} f32;
int exponent = (val & 0x03e0) >> UF10_EXPONENT_SHIFT;
int mantissa = (val & 0x001f);
f32.f = 0.0;
if (exponent == 0) {
if (mantissa != 0) {
const float scale = 1.0 / (1 << 19);
f32.f = scale * mantissa;
}
} else if (exponent == 31) {
f32.ui = F32_INFINITY | mantissa;
} else {
float scale, decimal;
exponent -= 15;
if (exponent < 0) {
scale = 1.0f / (1 << -exponent);
} else {
scale = (float)(1 << exponent);
}
decimal = 1.0f + (float)mantissa / 32;
f32.f = scale * decimal;
}
return f32.f;
}
float Uf16ToF32(u16 val) {
return half_float::half_cast<float>(reinterpret_cast<half_float::half&>(val));
}
float U2ToUnorm(u8 val) {
static constexpr auto c = 1.0f / 3.0f;
return float(val * c);
}
float S2ToSnorm(s8 val) {
static constexpr auto c = 1.0f / 1.0f;
return float(val * c);
}
float U4ToUnorm(u8 val) {
static constexpr auto c = 1.0f / 15.0f;
return float(val * c);
}
float S4ToSnorm(s8 val) {
static constexpr auto c = 1.0f / 7.0f;
return float(val * c);
}
float U5ToUnorm(u8 val) {
static constexpr auto c = 1.0f / 31.0f;
return float(val * c);
}
float S5ToSnorm(s8 val) {
static constexpr auto c = 1.0f / 15.0f;
return float(val * c);
}
float U6ToUnorm(u8 val) {
static constexpr auto c = 1.0f / 63.0f;
return float(val * c);
}
float S6ToSnorm(s8 val) {
static constexpr auto c = 1.0f / 31.0f;
return float(val * c);
}
float U8ToUnorm(u8 val) {
static constexpr auto c = 1.0f / 255.0f;
return float(val * c);
}
float S8ToSnorm(s8 val) {
static constexpr auto c = 1.0f / 127.0f;
return float(val * c);
}
float U10ToUnorm(u16 val) {
static constexpr auto c = 1.0f / 1023.0f;
return float(val * c);
}
float S10ToSnorm(s16 val) {
static constexpr auto c = 1.0f / 511.0f;
return float(val * c);
}
float U16ToUnorm(u16 val) {
static constexpr auto c = 1.0f / 65535.0f;
return float(val * c);
}
float S16ToSnorm(s16 val) {
static constexpr auto c = 1.0f / 32767.0f;
return float(val * c);
}
} // namespace NumberUtils

28
src/common/number_utils.h Normal file
View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace NumberUtils {
float Uf11ToF32(u16 val);
float Uf10ToF32(u16 val);
float Uf16ToF32(u16 val);
float U2ToUnorm(u8 val);
float S2ToSnorm(s8 val);
float U4ToUnorm(u8 val);
float S4ToSnorm(s8 val);
float U5ToUnorm(u8 val);
float S5ToSnorm(s8 val);
float U6ToUnorm(u8 val);
float S6ToSnorm(s8 val);
float U8ToUnorm(u8 val);
float S8ToSnorm(s8 val);
float U10ToUnorm(u16 val);
float S10ToSnorm(s16 val);
float U16ToUnorm(u16 val);
float S16ToSnorm(s16 val);
} // namespace NumberUtils

View File

@ -22,6 +22,10 @@
#endif #endif
#endif #endif
#ifdef ENABLE_QT_GUI
#include <QString>
#endif
namespace Common::FS { namespace Common::FS {
namespace fs = std::filesystem; namespace fs = std::filesystem;
@ -82,11 +86,32 @@ static std::filesystem::path GetBundleParentDirectory() {
static auto UserPaths = [] { static auto UserPaths = [] {
#ifdef __APPLE__ #ifdef __APPLE__
std::filesystem::current_path(GetBundleParentDirectory()); // Start by assuming the base directory is the bundle's parent directory.
std::filesystem::path base_dir = GetBundleParentDirectory();
std::filesystem::path user_dir = base_dir / PORTABLE_DIR;
// Check if the "user" directory exists in the current path:
if (!std::filesystem::exists(user_dir)) {
// If it doesn't exist, use the new hardcoded path:
user_dir =
std::filesystem::path(getenv("HOME")) / "Library" / "Application Support" / "shadPS4";
}
#elif defined(__linux__)
auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
// Check if the "user" directory exists in the current path:
if (!std::filesystem::exists(user_dir)) {
// If it doesn't exist, use XDG_DATA_HOME if it is set, and provide a standard default
const char* xdg_data_home = getenv("XDG_DATA_HOME");
if (xdg_data_home != nullptr && strlen(xdg_data_home) > 0) {
user_dir = std::filesystem::path(xdg_data_home) / "shadPS4";
} else {
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
}
}
#else
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
#endif #endif
std::unordered_map<PathType, fs::path> paths; std::unordered_map<PathType, fs::path> paths;
const auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
const auto create_path = [&](PathType shad_path, const fs::path& new_path) { const auto create_path = [&](PathType shad_path, const fs::path& new_path) {
std::filesystem::create_directory(new_path); std::filesystem::create_directory(new_path);
@ -97,13 +122,15 @@ static auto UserPaths = [] {
create_path(PathType::LogDir, user_dir / LOG_DIR); create_path(PathType::LogDir, user_dir / LOG_DIR);
create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR); create_path(PathType::ScreenshotsDir, user_dir / SCREENSHOTS_DIR);
create_path(PathType::ShaderDir, user_dir / SHADER_DIR); create_path(PathType::ShaderDir, user_dir / SHADER_DIR);
create_path(PathType::PM4Dir, user_dir / PM4_DIR);
create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR); create_path(PathType::SaveDataDir, user_dir / SAVEDATA_DIR);
create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR); create_path(PathType::GameDataDir, user_dir / GAMEDATA_DIR);
create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR); create_path(PathType::TempDataDir, user_dir / TEMPDATA_DIR);
create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR); create_path(PathType::SysModuleDir, user_dir / SYSMODULES_DIR);
create_path(PathType::DownloadDir, user_dir / DOWNLOAD_DIR); create_path(PathType::DownloadDir, user_dir / DOWNLOAD_DIR);
create_path(PathType::CapturesDir, user_dir / CAPTURES_DIR); create_path(PathType::CapturesDir, user_dir / CAPTURES_DIR);
create_path(PathType::CheatsDir, user_dir / CHEATS_DIR);
create_path(PathType::PatchesDir, user_dir / PATCHES_DIR);
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
return paths; return paths;
}(); }();
@ -152,4 +179,22 @@ void SetUserPath(PathType shad_path, const fs::path& new_path) {
UserPaths.insert_or_assign(shad_path, new_path); UserPaths.insert_or_assign(shad_path, new_path);
} }
} // namespace Common::FS #ifdef ENABLE_QT_GUI
void PathToQString(QString& result, const std::filesystem::path& path) {
#ifdef _WIN32
result = QString::fromStdWString(path.wstring());
#else
result = QString::fromStdString(path.string());
#endif
}
std::filesystem::path PathFromQString(const QString& path) {
#ifdef _WIN32
return std::filesystem::path(path.toStdWString());
#else
return std::filesystem::path(path.toStdString());
#endif
}
#endif
} // namespace Common::FS

View File

@ -6,6 +6,10 @@
#include <filesystem> #include <filesystem>
#include <vector> #include <vector>
#ifdef ENABLE_QT_GUI
class QString; // to avoid including <QString> in this header
#endif
namespace Common::FS { namespace Common::FS {
enum class PathType { enum class PathType {
@ -13,13 +17,15 @@ enum class PathType {
LogDir, // Where log files are stored. LogDir, // Where log files are stored.
ScreenshotsDir, // Where screenshots are stored. ScreenshotsDir, // Where screenshots are stored.
ShaderDir, // Where shaders are stored. ShaderDir, // Where shaders are stored.
PM4Dir, // Where command lists are stored.
SaveDataDir, // Where guest save data is stored. SaveDataDir, // Where guest save data is stored.
TempDataDir, // Where game temp data is stored. TempDataDir, // Where game temp data is stored.
GameDataDir, // Where game data is stored. GameDataDir, // Where game data is stored.
SysModuleDir, // Where system modules are stored. SysModuleDir, // Where system modules are stored.
DownloadDir, // Where downloads/temp files are stored. DownloadDir, // Where downloads/temp files are stored.
CapturesDir, // Where rdoc captures are stored. CapturesDir, // Where rdoc captures are stored.
CheatsDir, // Where cheats are stored.
PatchesDir, // Where patches are stored.
MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored.
}; };
constexpr auto PORTABLE_DIR = "user"; constexpr auto PORTABLE_DIR = "user";
@ -28,13 +34,15 @@ constexpr auto PORTABLE_DIR = "user";
constexpr auto LOG_DIR = "log"; constexpr auto LOG_DIR = "log";
constexpr auto SCREENSHOTS_DIR = "screenshots"; constexpr auto SCREENSHOTS_DIR = "screenshots";
constexpr auto SHADER_DIR = "shader"; constexpr auto SHADER_DIR = "shader";
constexpr auto PM4_DIR = "pm4";
constexpr auto SAVEDATA_DIR = "savedata"; constexpr auto SAVEDATA_DIR = "savedata";
constexpr auto GAMEDATA_DIR = "data"; constexpr auto GAMEDATA_DIR = "data";
constexpr auto TEMPDATA_DIR = "temp"; constexpr auto TEMPDATA_DIR = "temp";
constexpr auto SYSMODULES_DIR = "sys_modules"; constexpr auto SYSMODULES_DIR = "sys_modules";
constexpr auto DOWNLOAD_DIR = "download"; constexpr auto DOWNLOAD_DIR = "download";
constexpr auto CAPTURES_DIR = "captures"; constexpr auto CAPTURES_DIR = "captures";
constexpr auto CHEATS_DIR = "cheats";
constexpr auto PATCHES_DIR = "patches";
constexpr auto METADATA_DIR = "game_data";
// Filenames // Filenames
constexpr auto LOG_FILE = "shad_log.txt"; constexpr auto LOG_FILE = "shad_log.txt";
@ -88,4 +96,23 @@ constexpr auto LOG_FILE = "shad_log.txt";
*/ */
void SetUserPath(PathType user_path, const std::filesystem::path& new_path); void SetUserPath(PathType user_path, const std::filesystem::path& new_path);
#ifdef ENABLE_QT_GUI
/**
* Converts an std::filesystem::path to a QString.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param result The resulting QString
* @param path The path to convert
*/
void PathToQString(QString& result, const std::filesystem::path& path);
/**
* Converts a QString to an std::filesystem::path.
* The native underlying string of a path is wstring on Windows and string on POSIX.
*
* @param path The path to convert
*/
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
#endif
} // namespace Common::FS } // namespace Common::FS

View File

@ -3,6 +3,8 @@
#pragma once #pragma once
#include "common/arch.h"
#ifdef _MSC_VER #ifdef _MSC_VER
#include <intrin.h> #include <intrin.h>
#endif #endif
@ -13,15 +15,20 @@ namespace Common {
#ifdef _MSC_VER #ifdef _MSC_VER
__forceinline static u64 FencedRDTSC() { __forceinline static u64 FencedRDTSC() {
#ifdef ARCH_X86_64
_mm_lfence(); _mm_lfence();
_ReadWriteBarrier(); _ReadWriteBarrier();
const u64 result = __rdtsc(); const u64 result = __rdtsc();
_mm_lfence(); _mm_lfence();
_ReadWriteBarrier(); _ReadWriteBarrier();
return result; return result;
#else
#error "Missing FencedRDTSC() implementation for target CPU architecture."
#endif
} }
#else #else
static inline u64 FencedRDTSC() { static inline u64 FencedRDTSC() {
#ifdef ARCH_X86_64
u64 eax; u64 eax;
u64 edx; u64 edx;
asm volatile("lfence\n\t" asm volatile("lfence\n\t"
@ -29,6 +36,16 @@ static inline u64 FencedRDTSC() {
"lfence\n\t" "lfence\n\t"
: "=a"(eax), "=d"(edx)); : "=a"(eax), "=d"(edx));
return (edx << 32) | eax; return (edx << 32) | eax;
#elif defined(ARCH_ARM64)
u64 ret;
asm volatile("isb\n\t"
"mrs %0, cntvct_el0\n\t"
"isb\n\t"
: "=r"(ret)::"memory");
return ret;
#else
#error "Missing FencedRDTSC() implementation for target CPU architecture."
#endif
} }
#endif #endif

View File

@ -6,12 +6,14 @@
#define GIT_REV "@GIT_REV@" #define GIT_REV "@GIT_REV@"
#define GIT_BRANCH "@GIT_BRANCH@" #define GIT_BRANCH "@GIT_BRANCH@"
#define GIT_DESC "@GIT_DESC@" #define GIT_DESC "@GIT_DESC@"
#define BUILD_DATE "@BUILD_DATE@"
namespace Common { namespace Common {
const char g_scm_rev[] = GIT_REV; const char g_scm_rev[] = GIT_REV;
const char g_scm_branch[] = GIT_BRANCH; const char g_scm_branch[] = GIT_BRANCH;
const char g_scm_desc[] = GIT_DESC; const char g_scm_desc[] = GIT_DESC;
const char g_scm_date[] = BUILD_DATE;
} // namespace } // namespace

View File

@ -8,5 +8,6 @@ namespace Common {
extern const char g_scm_rev[]; extern const char g_scm_rev[];
extern const char g_scm_branch[]; extern const char g_scm_branch[];
extern const char g_scm_desc[]; extern const char g_scm_desc[];
extern const char g_scm_date[];
} // namespace Common } // namespace Common

View File

@ -0,0 +1,92 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/arch.h"
#include "common/assert.h"
#include "common/signal_context.h"
#ifdef _WIN32
#include <windows.h>
#else
#include <sys/ucontext.h>
#endif
namespace Common {
void* GetXmmPointer(void* ctx, u8 index) {
#if defined(_WIN32)
#define CASE(index) \
case index: \
return (void*)(&((EXCEPTION_POINTERS*)ctx)->ContextRecord->Xmm##index.Low)
#elif defined(__APPLE__)
#define CASE(index) \
case index: \
return (void*)(&((ucontext_t*)ctx)->uc_mcontext->__fs.__fpu_xmm##index);
#else
#define CASE(index) \
case index: \
return (void*)(&((ucontext_t*)ctx)->uc_mcontext.fpregs->_xmm[index].element[0])
#endif
switch (index) {
CASE(0);
CASE(1);
CASE(2);
CASE(3);
CASE(4);
CASE(5);
CASE(6);
CASE(7);
CASE(8);
CASE(9);
CASE(10);
CASE(11);
CASE(12);
CASE(13);
CASE(14);
CASE(15);
default: {
UNREACHABLE_MSG("Invalid XMM register index: {}", index);
return nullptr;
}
}
#undef CASE
}
void* GetRip(void* ctx) {
#if defined(_WIN32)
return (void*)((EXCEPTION_POINTERS*)ctx)->ContextRecord->Rip;
#elif defined(__APPLE__)
return (void*)((ucontext_t*)ctx)->uc_mcontext->__ss.__rip;
#else
return (void*)((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RIP];
#endif
}
void IncrementRip(void* ctx, u64 length) {
#if defined(_WIN32)
((EXCEPTION_POINTERS*)ctx)->ContextRecord->Rip += length;
#elif defined(__APPLE__)
((ucontext_t*)ctx)->uc_mcontext->__ss.__rip += length;
#else
((ucontext_t*)ctx)->uc_mcontext.gregs[REG_RIP] += length;
#endif
}
bool IsWriteError(void* ctx) {
#if defined(_WIN32)
return ((EXCEPTION_POINTERS*)ctx)->ExceptionRecord->ExceptionInformation[0] == 1;
#elif defined(__APPLE__)
#if defined(ARCH_X86_64)
return ((ucontext_t*)ctx)->uc_mcontext->__es.__err & 0x2;
#elif defined(ARCH_ARM64)
return ((ucontext_t*)ctx)->uc_mcontext->__es.__esr & 0x40;
#endif
#else
#if defined(ARCH_X86_64)
return ((ucontext_t*)ctx)->uc_mcontext.gregs[REG_ERR] & 0x2;
#else
#error "Unsupported architecture"
#endif
#endif
}
} // namespace Common

View File

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Common {
void* GetXmmPointer(void* ctx, u8 index);
void* GetRip(void* ctx);
void IncrementRip(void* ctx, u64 length);
bool IsWriteError(void* ctx);
} // namespace Common

View File

@ -28,9 +28,13 @@ struct SlotId {
template <class T> template <class T>
class SlotVector { class SlotVector {
constexpr static std::size_t InitialCapacity = 1024; constexpr static std::size_t InitialCapacity = 2048;
public: public:
SlotVector() {
Reserve(InitialCapacity);
}
~SlotVector() noexcept { ~SlotVector() noexcept {
std::size_t index = 0; std::size_t index = 0;
for (u64 bits : stored_bitset) { for (u64 bits : stored_bitset) {
@ -67,19 +71,6 @@ public:
return SlotId{index}; return SlotId{index};
} }
template <typename... Args>
[[nodiscard]] SlotId swap_and_insert(SlotId existing_id, Args&&... args) noexcept {
const u32 index = FreeValueIndex();
T& existing_value = values[existing_id.index].object;
new (&values[index].object) T(std::move(existing_value));
existing_value.~T();
new (&values[existing_id.index].object) T(std::forward<Args>(args)...);
SetStorageBit(index);
return SlotId{index};
}
void erase(SlotId id) noexcept { void erase(SlotId id) noexcept {
values[id.index].object.~T(); values[id.index].object.~T();
free_list.push_back(id.index); free_list.push_back(id.index);
@ -151,7 +142,8 @@ private:
const std::size_t old_free_size = free_list.size(); const std::size_t old_free_size = free_list.size();
free_list.resize(old_free_size + (new_capacity - values_capacity)); free_list.resize(old_free_size + (new_capacity - values_capacity));
std::iota(free_list.begin() + old_free_size, free_list.end(), const std::size_t new_free_size = free_list.size();
std::iota(free_list.rbegin(), free_list.rbegin() + new_free_size - old_free_size,
static_cast<u32>(values_capacity)); static_cast<u32>(values_capacity));
delete[] values; delete[] values;

View File

@ -14,12 +14,17 @@
namespace Common { namespace Common {
std::string ToLower(std::string str) { std::string ToLower(std::string_view input) {
std::transform(str.begin(), str.end(), str.begin(), std::string str;
[](unsigned char c) { return static_cast<char>(std::tolower(c)); }); str.resize(input.size());
std::ranges::transform(input, str.begin(), tolower);
return str; return str;
} }
void ToLowerInPlace(std::string& str) {
std::ranges::transform(str, str.begin(), tolower);
}
std::vector<std::string> SplitString(const std::string& str, char delimiter) { std::vector<std::string> SplitString(const std::string& str, char delimiter) {
std::istringstream iss(str); std::istringstream iss(str);
std::vector<std::string> output(1); std::vector<std::string> output(1);

View File

@ -10,7 +10,9 @@
namespace Common { namespace Common {
/// Make a string lowercase /// Make a string lowercase
[[nodiscard]] std::string ToLower(std::string str); [[nodiscard]] std::string ToLower(std::string_view str);
void ToLowerInPlace(std::string& str);
std::vector<std::string> SplitString(const std::string& str, char delimiter); std::vector<std::string> SplitString(const std::string& str, char delimiter);

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