Merge branch 'main' into refactor
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
ko_fi: shadps4
|
9
.github/linux-appimage-qt.sh
vendored
@ -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
@ -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
|
17
.github/workflows/ci.yml
vendored
@ -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
|
|
28
.github/workflows/format.yml
vendored
@ -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
|
|
41
.github/workflows/linux-qt.yml
vendored
@ -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
|
|
48
.github/workflows/linux.yml
vendored
@ -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
|
|
60
.github/workflows/macos-qt.yml
vendored
@ -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
|
|
52
.github/workflows/macos.yml
vendored
@ -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
|
|
49
.github/workflows/windows-qt.yml
vendored
@ -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
|
|
34
.github/workflows/windows.yml
vendored
@ -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
@ -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
@ -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
|
60
.reuse/dep5
@ -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
@ -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()
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -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
@ -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.
|
93
README.md
@ -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|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows.yml)
|
|
||||||
|Windows Qt Build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/windows-qt.yml)
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>Linux</b></summary>
|
|
||||||
|
|
||||||
| Linux | Build status |
|
|
||||||
|--------|--------|
|
|
||||||
|Linux SDL Build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux.yml)
|
|
||||||
|Linux Qt Build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/linux-qt.yml)
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary><b>macOS</b></summary>
|
|
||||||
|
|
||||||
| macOS | Build status |
|
|
||||||
|--------|--------|
|
|
||||||
|macOS SDL Build|[](https://github.com/shadps4-emu/shadPS4/actions/workflows/macos.yml)
|
|
||||||
|macOS Qt Build|[](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
@ -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
@ -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)
|
@ -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). 
|

|
||||||
|
|
||||||
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). 
|
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. 
|
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
After Width: | Height: | Size: 1.3 MiB |
BIN
documents/Screenshots/2.png
Normal file
After Width: | Height: | Size: 2.3 MiB |
BIN
documents/Screenshots/3.png
Normal file
After Width: | Height: | Size: 1.2 MiB |
BIN
documents/Screenshots/4.png
Normal file
After Width: | Height: | Size: 1.8 MiB |
Before Width: | Height: | Size: 350 KiB |
Before Width: | Height: | Size: 850 KiB |
Before Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 175 KiB |
@ -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
|
||||||
```
|
```
|
||||||
|
73
documents/building-macos.md
Normal 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
|
||||||
|
```
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
56
externals/CMakeLists.txt
vendored
@ -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
@ -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
@ -0,0 +1,2 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
15339
externals/gcn/include/gcn/si_ci_vi_merged_offset.h
vendored
Normal file
117
externals/gcn/include/gcn/si_ci_vi_merged_pm4_it_opcodes.h
vendored
Normal 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
|
2
externals/magic_enum
vendored
@ -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
|
2
externals/vulkan-headers
vendored
@ -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
|
@ -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)
|
||||||
|
52
scripts/file_formats/sfo.hexpat
Normal 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;
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
@ -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
|
@ -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();
|
||||||
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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
|
@ -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,
|
||||||
|
@ -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
|
@ -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
|
@ -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
|
|
57
src/common/discord_rpc_handler.cpp
Normal 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
|
@ -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
@ -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
@ -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;
|
||||||
|
}
|
||||||
|
};
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
|
};
|
@ -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
|
||||||
|
446
src/common/memory_patcher.cpp
Normal 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**>(¤t), 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
|
47
src/common/memory_patcher.h
Normal 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
|
@ -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 {
|
||||||
|
@ -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
@ -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
@ -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
|
@ -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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
92
src/common/signal_context.cpp
Normal 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
|
18
src/common/signal_context.h
Normal 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
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|