mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-09 05:08:43 +00:00
Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de6c5bbb83 | ||
|
|
65f0b07c34 | ||
|
|
2a5910ed51 | ||
|
|
391d30cbb1 | ||
|
|
d3ad728ac0 | ||
|
|
5183cbe686 | ||
|
|
9e80cde60d | ||
|
|
98fd0689ac | ||
|
|
9db4642f66 | ||
|
|
b135a056ba | ||
|
|
dc6013cf0e | ||
|
|
e5ea55e425 | ||
|
|
c3f7a4301c | ||
|
|
a5f9280841 | ||
|
|
cf866ab294 | ||
|
|
052f3260f3 | ||
|
|
78e301c3db | ||
|
|
a9f8eaf778 | ||
|
|
f9ef57f74b | ||
|
|
1394852791 | ||
|
|
6295c32e5c | ||
|
|
14d71a155a | ||
|
|
2577dfde7e | ||
|
|
8123c44ad1 | ||
|
|
f1a8b7d85e | ||
|
|
f6ae5544fd | ||
|
|
4922d526fe | ||
|
|
56109a1331 | ||
|
|
544a22a431 | ||
|
|
6612a32523 | ||
|
|
3f86c2e94a | ||
|
|
5b699090e6 | ||
|
|
aa5c045555 | ||
|
|
ed14359c87 | ||
|
|
6a9f9abda0 | ||
|
|
2f55636626 | ||
|
|
94d0f2e7ed | ||
|
|
f557c6ac64 | ||
|
|
93c340c6e1 | ||
|
|
25344a3b89 | ||
|
|
bbd985fe4b | ||
|
|
ee2bc97248 | ||
|
|
bebfee58d6 | ||
|
|
5ddabda2b8 | ||
|
|
3ce1ac5e86 | ||
|
|
b4628b80e2 | ||
|
|
2f022a462d | ||
|
|
f5505daaca | ||
|
|
8c1ec863da | ||
|
|
604f8d9398 | ||
|
|
19e974bf21 | ||
|
|
7031f5968e | ||
|
|
ff8869262f | ||
|
|
683e5f3b04 | ||
|
|
08fe66a97f | ||
|
|
bc44865cda | ||
|
|
a42ae46553 | ||
|
|
a4c3c665fe | ||
|
|
caccc05fb2 | ||
|
|
8238ecf88a | ||
|
|
8bbb3956a2 | ||
|
|
f466352dde | ||
|
|
430f2e4700 | ||
|
|
6c7c5eb59c | ||
|
|
493cda07c0 | ||
|
|
eda6be746f | ||
|
|
ed9ffbfb64 | ||
|
|
5cabd6ddd8 | ||
|
|
f06e126330 | ||
|
|
715eb512c9 | ||
|
|
87e09b613b | ||
|
|
6c08c6983b | ||
|
|
6bd74ef769 | ||
|
|
bf34665a8f | ||
|
|
2d17ab8e4b | ||
|
|
db9921baf2 | ||
|
|
17fab7fdf1 | ||
|
|
0cd6248eee | ||
|
|
a1973438db | ||
|
|
a7376dd41f | ||
|
|
6b6294a750 | ||
|
|
999960a6e6 | ||
|
|
6805baffb2 | ||
|
|
109b239ddf | ||
|
|
1714647343 | ||
|
|
794d593a02 | ||
|
|
b34556702e | ||
|
|
a0e7f7fb65 | ||
|
|
8f37cfb739 | ||
|
|
d17a4fb8cc | ||
|
|
4fa435490c | ||
|
|
11229c1dc0 | ||
|
|
455cd37aae | ||
|
|
e7194af881 | ||
|
|
08878385e1 | ||
|
|
81098da509 | ||
|
|
5fedf9daea | ||
|
|
23d0fc6493 | ||
|
|
5c7f802233 | ||
|
|
54b5520c1a | ||
|
|
02f9aef34a | ||
|
|
8de385a4f1 | ||
|
|
110a735a04 | ||
|
|
74c0ea8432 | ||
|
|
af147debc6 | ||
|
|
1020c3150f | ||
|
|
0134b8c3a8 | ||
|
|
6fb64a8054 | ||
|
|
6d0b179d24 | ||
|
|
68fca2552f | ||
|
|
0e6dea1059 | ||
|
|
8a8ee395c5 | ||
|
|
a8f4a20b24 | ||
|
|
505e80e756 | ||
|
|
ad99bda08d | ||
|
|
a35c9f3586 | ||
|
|
cad027845f | ||
|
|
6c5a84dc99 | ||
|
|
937d50cb00 | ||
|
|
905c536ef4 | ||
|
|
528a060709 | ||
|
|
6e27842562 | ||
|
|
71f343d2d6 | ||
|
|
a6f5e4c7dc | ||
|
|
98ceb6e43e | ||
|
|
eeee6ad0ee | ||
|
|
5d8027f0c0 | ||
|
|
1eead6a5ee | ||
|
|
419ea140ab | ||
|
|
976d12f4e6 | ||
|
|
50a3081084 | ||
|
|
525d24a7fc | ||
|
|
51c96b8ee6 | ||
|
|
2b1c0b4f82 | ||
|
|
eb18382396 | ||
|
|
fa489c023e | ||
|
|
f01b6295dd | ||
|
|
be80276ec3 | ||
|
|
71e81c836c | ||
|
|
ddb59edd3e | ||
|
|
7bd3eb485f | ||
|
|
0eff74223a | ||
|
|
1e949c5813 |
2
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
2
.github/ISSUE_TEMPLATE/game-bug-report.yaml
vendored
@@ -35,7 +35,7 @@ body:
|
||||
required: true
|
||||
- label: I have disabled all patches and cheats and the issue is still present.
|
||||
required: true
|
||||
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D#4-adding-modules) installed.
|
||||
- label: I have all the required [system modules](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D#4-dumping-firmware-modules) installed.
|
||||
required: true
|
||||
- type: textarea
|
||||
id: desc
|
||||
|
||||
33
.github/linux-appimage-qt.sh
vendored
33
.github/linux-appimage-qt.sh
vendored
@@ -1,33 +0,0 @@
|
||||
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
if [[ -z $GITHUB_WORKSPACE ]]; then
|
||||
GITHUB_WORKSPACE="${PWD%/*}"
|
||||
fi
|
||||
|
||||
export Qt6_DIR="/usr/lib/qt6"
|
||||
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
|
||||
wget -q https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
|
||||
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
wget -q https://github.com/linuxdeploy/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt-x86_64.sh
|
||||
|
||||
chmod a+x linuxdeploy-x86_64.AppImage
|
||||
chmod a+x linuxdeploy-plugin-qt-x86_64.AppImage
|
||||
chmod a+x linuxdeploy-plugin-checkrt-x86_64.sh
|
||||
|
||||
# Build AppImage
|
||||
./linuxdeploy-x86_64.AppImage --appdir AppDir
|
||||
./linuxdeploy-plugin-checkrt-x86_64.sh --appdir AppDir
|
||||
|
||||
cp -a "$GITHUB_WORKSPACE/build/translations" AppDir/usr/bin
|
||||
|
||||
./linuxdeploy-x86_64.AppImage --appdir AppDir -d "$GITHUB_WORKSPACE"/dist/net.shadps4.shadPS4.desktop -e "$GITHUB_WORKSPACE"/build/shadps4 -i "$GITHUB_WORKSPACE"/src/images/net.shadps4.shadPS4.svg --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
|
||||
238
.github/workflows/build.yml
vendored
238
.github/workflows/build.yml
vendored
@@ -17,14 +17,14 @@ jobs:
|
||||
runs-on: ubuntu-24.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- uses: fsfe/reuse-action@v5
|
||||
|
||||
clang-format:
|
||||
runs-on: ubuntu-24.04
|
||||
continue-on-error: true
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Install
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
shorthash: ${{ steps.vars.outputs.shorthash }}
|
||||
fullhash: ${{ steps.vars.outputs.fullhash }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
- name: Get date and git hash
|
||||
id: vars
|
||||
run: |
|
||||
@@ -60,7 +60,7 @@ jobs:
|
||||
runs-on: windows-2025
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -76,7 +76,7 @@ jobs:
|
||||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
uses: hendrikmuhs/ccache-action@v1.2.19
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
@@ -95,69 +95,11 @@ jobs:
|
||||
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-2025
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.9.2
|
||||
host: windows
|
||||
target: desktop
|
||||
arch: win64_msvc2022_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.18
|
||||
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 -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=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 $env:NUMBER_OF_PROCESSORS
|
||||
|
||||
- name: Deploy and Package
|
||||
run: |
|
||||
mkdir upload
|
||||
mkdir upload/qtplugins
|
||||
move build/shadPS4.exe upload
|
||||
cp dist/qt.conf upload/qt.conf
|
||||
windeployqt --plugindir upload/qtplugins --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-15
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -178,7 +120,7 @@ jobs:
|
||||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
uses: hendrikmuhs/ccache-action@v1.2.19
|
||||
env:
|
||||
cache-name: ${{runner.os}}-sdl-cache-cmake-build
|
||||
with:
|
||||
@@ -204,72 +146,11 @@ jobs:
|
||||
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
|
||||
path: upload/
|
||||
|
||||
macos-qt:
|
||||
runs-on: macos-15
|
||||
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: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.9.2
|
||||
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.18
|
||||
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 -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=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
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -293,7 +174,7 @@ jobs:
|
||||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
uses: hendrikmuhs/ccache-action@v1.2.19
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
@@ -326,63 +207,11 @@ jobs:
|
||||
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: Add LLVM repository
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
|
||||
|
||||
- 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-19 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-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.18
|
||||
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_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-19 -DCMAKE_CXX_COMPILER=clang++-19 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||
|
||||
- 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
|
||||
|
||||
linux-sdl-gcc:
|
||||
runs-on: ubuntu-24.04
|
||||
needs: get-info
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v5
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
@@ -401,7 +230,7 @@ jobs:
|
||||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.18
|
||||
uses: hendrikmuhs/ccache-action@v1.2.19
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
|
||||
with:
|
||||
@@ -414,51 +243,20 @@ jobs:
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||
|
||||
linux-qt-gcc:
|
||||
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 gcc-14 mold build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-gcc-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.18
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-gcc-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_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=gcc-14 -DCMAKE_CXX_COMPILER=g++-14 -DCMAKE_EXE_LINKER_FLAGS="-fuse-ld=mold" -DCMAKE_SHARED_LINKER_FLAGS="-fuse-ld=mold" -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||
|
||||
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]
|
||||
needs: [get-info, windows-sdl, macos-sdl, linux-sdl]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
uses: actions/download-artifact@v5
|
||||
with:
|
||||
path: ./artifacts
|
||||
|
||||
- name: Make SDL artifacts executable
|
||||
run: |
|
||||
chmod -R a+x ./artifacts/shadps4-linux-sdl-*
|
||||
chmod -R a+x ./artifacts/shadps4-macos-sdl-*
|
||||
|
||||
- name: Compress individual directories (without parent directory)
|
||||
run: |
|
||||
|
||||
11
.github/workflows/scripts/update_translation.sh
vendored
11
.github/workflows/scripts/update_translation.sh
vendored
@@ -1,11 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
sudo apt-get -y install qt6-l10n-tools python3
|
||||
|
||||
SCRIPT_PATH="src/qt_gui/translations/update_translation.sh"
|
||||
|
||||
chmod +x "$SCRIPT_PATH"
|
||||
|
||||
PATH=/usr/lib/qt6/bin:$PATH "$SCRIPT_PATH"
|
||||
30
.github/workflows/update_translation.yml
vendored
30
.github/workflows/update_translation.yml
vendored
@@ -1,30 +0,0 @@
|
||||
name: Update Translation
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 0 * * *" # Every day at 12am UTC.
|
||||
workflow_dispatch: # As well as manually.
|
||||
|
||||
jobs:
|
||||
update:
|
||||
if: github.repository == 'shadps4-emu/shadPS4'
|
||||
name: "Update Translation"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set execution permissions for the script
|
||||
run: chmod +x ./.github/workflows/scripts/update_translation.sh
|
||||
|
||||
- name: Update Base Translation
|
||||
run: ./.github/workflows/scripts/update_translation.sh
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
with:
|
||||
token: ${{ secrets.SHADPS4_TOKEN_REPO }}
|
||||
title: "Qt GUI: Update Translation"
|
||||
commit-message: "[ci skip] Qt GUI: Update Translation."
|
||||
body: "Daily update of translation sources."
|
||||
branch: update-translation
|
||||
delete-branch: true
|
||||
31
.gitmodules
vendored
31
.gitmodules
vendored
@@ -91,18 +91,6 @@
|
||||
path = externals/libpng
|
||||
url = https://github.com/pnggroup/libpng
|
||||
shallow = true
|
||||
[submodule "externals/MoltenVK/SPIRV-Cross"]
|
||||
path = externals/MoltenVK/SPIRV-Cross
|
||||
url = https://github.com/KhronosGroup/SPIRV-Cross
|
||||
shallow = true
|
||||
[submodule "externals/MoltenVK/MoltenVK"]
|
||||
path = externals/MoltenVK/MoltenVK
|
||||
url = https://github.com/KhronosGroup/MoltenVK
|
||||
shallow = true
|
||||
[submodule "externals/MoltenVK/cereal"]
|
||||
path = externals/MoltenVK/cereal
|
||||
url = https://github.com/USCiLab/cereal
|
||||
shallow = true
|
||||
[submodule "externals/ext-libusb"]
|
||||
path = externals/ext-libusb
|
||||
url = https://github.com/shadps4-emu/ext-libusb.git
|
||||
@@ -113,3 +101,22 @@
|
||||
path = externals/hwinfo
|
||||
url = https://github.com/shadps4-emu/ext-hwinfo
|
||||
shallow = true
|
||||
[submodule "externals/ext-wepoll"]
|
||||
path = externals/ext-wepoll
|
||||
url = https://github.com/shadps4-emu/ext-wepoll.git
|
||||
shallow = true
|
||||
branch = dist
|
||||
[submodule "externals/MoltenVK"]
|
||||
path = externals/MoltenVK
|
||||
url = https://github.com/shadPS4-emu/ext-MoltenVK.git
|
||||
shallow = true
|
||||
[submodule "externals/json"]
|
||||
path = externals/json
|
||||
url = https://github.com/nlohmann/json.git
|
||||
[submodule "externals/sdl3_mixer"]
|
||||
path = externals/sdl3_mixer
|
||||
url = https://github.com/libsdl-org/SDL_mixer
|
||||
shallow = true
|
||||
[submodule "externals/miniz"]
|
||||
path = externals/miniz
|
||||
url = https://github.com/richgel999/miniz
|
||||
|
||||
22
CMakeDarwinPresets.json
Normal file
22
CMakeDarwinPresets.json
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"version": 9,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 30,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "x64-Clang-Base",
|
||||
"hidden": true,
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/Build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/Build/${presetName}",
|
||||
"CMAKE_OSX_ARCHITECTURES": "x86_64"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
293
CMakeLists.txt
293
CMakeLists.txt
@@ -31,7 +31,6 @@ if(UNIX AND NOT APPLE)
|
||||
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_DISCORD_RPC "Enable the Discord RPC integration" ON)
|
||||
option(ENABLE_UPDATER "Enables the options to updater" ON)
|
||||
|
||||
@@ -203,27 +202,23 @@ execute_process(
|
||||
|
||||
# Set Version
|
||||
set(EMULATOR_VERSION_MAJOR "0")
|
||||
set(EMULATOR_VERSION_MINOR "11")
|
||||
set(EMULATOR_VERSION_PATCH "0")
|
||||
set(EMULATOR_VERSION_MINOR "12")
|
||||
set(EMULATOR_VERSION_PATCH "6")
|
||||
|
||||
set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}")
|
||||
|
||||
set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH}")
|
||||
set(APP_IS_RELEASE true)
|
||||
set(APP_VERSION "${EMULATOR_VERSION_MAJOR}.${EMULATOR_VERSION_MINOR}.${EMULATOR_VERSION_PATCH} WIP")
|
||||
set(APP_IS_RELEASE false)
|
||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
|
||||
|
||||
message("-- end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}, link: ${GIT_REMOTE_URL}")
|
||||
|
||||
string(TOLOWER "${GIT_REMOTE_URL}" GIT_REMOTE_URL_LOWER)
|
||||
if(NOT GIT_REMOTE_URL_LOWER MATCHES "shadps4-emu/shadps4" OR NOT GIT_BRANCH STREQUAL "main")
|
||||
if(NOT (GIT_REMOTE_URL_LOWER MATCHES "shadps4-emu/shadps4" AND (GIT_BRANCH STREQUAL "main" OR "$ENV{GITHUB_REF}" MATCHES "refs/tags/")))
|
||||
message(STATUS "not main, disabling auto update")
|
||||
set(ENABLE_UPDATER OFF)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND ENABLE_QT_GUI AND NOT CMAKE_PREFIX_PATH)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/DetectQtInstallation.cmake")
|
||||
endif ()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
find_package(Boost 1.84.0 CONFIG)
|
||||
find_package(FFmpeg 5.1.2 MODULE)
|
||||
@@ -233,11 +228,14 @@ find_package(half 1.12.0 MODULE)
|
||||
find_package(magic_enum 0.9.7 CONFIG)
|
||||
find_package(PNG 1.6 MODULE)
|
||||
find_package(RenderDoc 1.6.0 MODULE)
|
||||
find_package(SDL3 3.1.2 CONFIG)
|
||||
find_package(SDL3_mixer 2.8.1 CONFIG)
|
||||
if (SDL3_mixer_FOUND)
|
||||
find_package(SDL3 3.1.2 CONFIG)
|
||||
endif()
|
||||
find_package(stb MODULE)
|
||||
find_package(toml11 4.2.0 CONFIG)
|
||||
find_package(tsl-robin-map 1.3.0 CONFIG)
|
||||
find_package(VulkanHeaders 1.4.324 CONFIG)
|
||||
find_package(VulkanHeaders 1.4.329 CONFIG)
|
||||
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
|
||||
find_package(xbyak 7.07 CONFIG)
|
||||
find_package(xxHash 0.8.2 MODULE)
|
||||
@@ -262,30 +260,6 @@ endif()
|
||||
add_subdirectory(externals)
|
||||
include_directories(src)
|
||||
|
||||
if(ENABLE_QT_GUI)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
|
||||
qt_standard_project_setup()
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOMOC 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()
|
||||
|
||||
set(AJM_LIB src/core/libraries/ajm/ajm.cpp
|
||||
src/core/libraries/ajm/ajm.h
|
||||
src/core/libraries/ajm/ajm_at9.cpp
|
||||
@@ -380,6 +354,10 @@ set(NETWORK_LIBS src/core/libraries/network/http.cpp
|
||||
src/core/libraries/network/net_ctl_codes.h
|
||||
src/core/libraries/network/net_util.cpp
|
||||
src/core/libraries/network/net_util.h
|
||||
src/core/libraries/network/net_epoll.cpp
|
||||
src/core/libraries/network/net_epoll.h
|
||||
src/core/libraries/network/net_resolver.cpp
|
||||
src/core/libraries/network/net_resolver.h
|
||||
src/core/libraries/network/net_error.h
|
||||
src/core/libraries/network/net.h
|
||||
src/core/libraries/network/ssl.cpp
|
||||
@@ -486,6 +464,12 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
||||
src/core/libraries/mouse/mouse.h
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
|
||||
src/core/libraries/web_browser_dialog/webbrowserdialog.h
|
||||
src/core/libraries/font/font.cpp
|
||||
src/core/libraries/font/font.h
|
||||
src/core/libraries/font/fontft.cpp
|
||||
src/core/libraries/font/fontft.h
|
||||
src/core/libraries/font/font_error.h
|
||||
|
||||
)
|
||||
|
||||
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
||||
@@ -528,7 +512,7 @@ set(PAD_LIB src/core/libraries/pad/pad.cpp
|
||||
src/core/libraries/pad/pad_errors.h
|
||||
)
|
||||
|
||||
set(SYSTEM_GESTURE_LIB
|
||||
set(SYSTEM_GESTURE_LIB
|
||||
src/core/libraries/system_gesture/system_gesture.cpp
|
||||
src/core/libraries/system_gesture/system_gesture.h
|
||||
)
|
||||
@@ -557,6 +541,13 @@ set(RANDOM_LIB src/core/libraries/random/random.cpp
|
||||
|
||||
set(USBD_LIB src/core/libraries/usbd/usbd.cpp
|
||||
src/core/libraries/usbd/usbd.h
|
||||
src/core/libraries/usbd/usb_backend.h
|
||||
src/core/libraries/usbd/emulated/dimensions.cpp
|
||||
src/core/libraries/usbd/emulated/dimensions.h
|
||||
src/core/libraries/usbd/emulated/infinity.cpp
|
||||
src/core/libraries/usbd/emulated/infinity.h
|
||||
src/core/libraries/usbd/emulated/skylander.cpp
|
||||
src/core/libraries/usbd/emulated/skylander.h
|
||||
)
|
||||
|
||||
set(FIBER_LIB src/core/libraries/fiber/fiber_context.s
|
||||
@@ -565,6 +556,8 @@ set(FIBER_LIB src/core/libraries/fiber/fiber_context.s
|
||||
src/core/libraries/fiber/fiber_error.h
|
||||
)
|
||||
|
||||
set_source_files_properties(src/core/libraries/fiber/fiber_context.s PROPERTIES COMPILE_OPTIONS -Wno-unused-command-line-argument)
|
||||
|
||||
set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
|
||||
src/core/libraries/videodec/videodec2_impl.h
|
||||
src/core/libraries/videodec/videodec2.cpp
|
||||
@@ -580,6 +573,8 @@ set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp
|
||||
set(NP_LIBS src/core/libraries/np/np_error.h
|
||||
src/core/libraries/np/np_common.cpp
|
||||
src/core/libraries/np/np_common.h
|
||||
src/core/libraries/np/np_commerce.cpp
|
||||
src/core/libraries/np/np_commerce.h
|
||||
src/core/libraries/np/np_manager.cpp
|
||||
src/core/libraries/np/np_manager.h
|
||||
src/core/libraries/np/np_score.cpp
|
||||
@@ -596,6 +591,8 @@ set(NP_LIBS src/core/libraries/np/np_error.h
|
||||
src/core/libraries/np/np_auth.h
|
||||
src/core/libraries/np/np_profile_dialog.cpp
|
||||
src/core/libraries/np/np_profile_dialog.h
|
||||
src/core/libraries/np/np_sns_facebook_dialog.cpp
|
||||
src/core/libraries/np/np_sns_facebook_dialog.h
|
||||
)
|
||||
|
||||
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
||||
@@ -637,6 +634,7 @@ set(COMPANION_LIBS src/core/libraries/companion/companion_httpd.cpp
|
||||
)
|
||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||
src/core/devtools/layer.h
|
||||
src/core/devtools/layer_extra.cpp
|
||||
src/core/devtools/options.cpp
|
||||
src/core/devtools/options.h
|
||||
src/core/devtools/gcn/gcn_context_regs.cpp
|
||||
@@ -697,7 +695,6 @@ set(COMMON src/common/logging/backend.cpp
|
||||
src/common/lru_cache.h
|
||||
src/common/error.cpp
|
||||
src/common/error.h
|
||||
src/common/scope_exit.h
|
||||
src/common/fixed_value.h
|
||||
src/common/func_traits.h
|
||||
src/common/native_clock.cpp
|
||||
@@ -711,6 +708,8 @@ set(COMMON src/common/logging/backend.cpp
|
||||
src/common/rdtsc.h
|
||||
src/common/recursive_lock.cpp
|
||||
src/common/recursive_lock.h
|
||||
src/common/scope_exit.h
|
||||
src/common/serdes.h
|
||||
src/common/sha1.h
|
||||
src/common/shared_first_mutex.h
|
||||
src/common/signal_context.h
|
||||
@@ -763,6 +762,8 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||
src/core/file_sys/devices/deci_tty6_device.h
|
||||
src/core/file_sys/devices/random_device.cpp
|
||||
src/core/file_sys/devices/random_device.h
|
||||
src/core/file_sys/devices/rng_device.cpp
|
||||
src/core/file_sys/devices/rng_device.h
|
||||
src/core/file_sys/devices/urandom_device.cpp
|
||||
src/core/file_sys/devices/urandom_device.h
|
||||
src/core/file_sys/devices/srandom_device.cpp
|
||||
@@ -820,6 +821,8 @@ set(CORE src/core/aerolib/stubs.cpp
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
src/core/debugger.cpp
|
||||
src/core/debugger.h
|
||||
src/core/linker.cpp
|
||||
src/core/linker.h
|
||||
src/core/memory.cpp
|
||||
@@ -841,10 +844,10 @@ if (ARCHITECTURE STREQUAL "x86_64")
|
||||
src/core/cpu_patches.h)
|
||||
endif()
|
||||
|
||||
set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
||||
src/shader_recompiler/profile.h
|
||||
set(SHADER_RECOMPILER src/shader_recompiler/profile.h
|
||||
src/shader_recompiler/recompiler.cpp
|
||||
src/shader_recompiler/recompiler.h
|
||||
src/shader_recompiler/resource.h
|
||||
src/shader_recompiler/info.h
|
||||
src/shader_recompiler/params.h
|
||||
src/shader_recompiler/runtime_info.h
|
||||
@@ -942,21 +945,30 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
||||
src/shader_recompiler/ir/value.h
|
||||
)
|
||||
|
||||
set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
||||
set(VIDEO_CORE src/video_core/amdgpu/cb_db_extent.h
|
||||
src/video_core/amdgpu/liverpool.cpp
|
||||
src/video_core/amdgpu/liverpool.h
|
||||
src/video_core/amdgpu/pixel_format.cpp
|
||||
src/video_core/amdgpu/pixel_format.h
|
||||
src/video_core/amdgpu/pm4_cmds.h
|
||||
src/video_core/amdgpu/pm4_opcodes.h
|
||||
src/video_core/amdgpu/regs_color.h
|
||||
src/video_core/amdgpu/regs_depth.h
|
||||
src/video_core/amdgpu/regs.cpp
|
||||
src/video_core/amdgpu/regs.h
|
||||
src/video_core/amdgpu/regs_primitive.h
|
||||
src/video_core/amdgpu/regs_shader.h
|
||||
src/video_core/amdgpu/regs_texture.h
|
||||
src/video_core/amdgpu/regs_vertex.h
|
||||
src/video_core/amdgpu/resource.h
|
||||
src/video_core/amdgpu/tiling.cpp
|
||||
src/video_core/amdgpu/tiling.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.h
|
||||
src/video_core/buffer_cache/buffer_cache.cpp
|
||||
src/video_core/buffer_cache/buffer_cache.h
|
||||
src/video_core/buffer_cache/fault_manager.cpp
|
||||
src/video_core/buffer_cache/fault_manager.h
|
||||
src/video_core/buffer_cache/memory_tracker.h
|
||||
src/video_core/buffer_cache/range_set.h
|
||||
src/video_core/buffer_cache/region_definitions.h
|
||||
@@ -977,6 +989,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
||||
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_pipeline_serialization.cpp
|
||||
src/video_core/renderer_vulkan/vk_pipeline_serialization.h
|
||||
src/video_core/renderer_vulkan/vk_platform.cpp
|
||||
src/video_core/renderer_vulkan/vk_platform.h
|
||||
src/video_core/renderer_vulkan/vk_presenter.cpp
|
||||
@@ -1014,6 +1028,8 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
||||
src/video_core/texture_cache/tile_manager.cpp
|
||||
src/video_core/texture_cache/tile_manager.h
|
||||
src/video_core/texture_cache/types.h
|
||||
src/video_core/cache_storage.cpp
|
||||
src/video_core/cache_storage.h
|
||||
src/video_core/page_manager.cpp
|
||||
src/video_core/page_manager.h
|
||||
src/video_core/multi_level_page_table.h
|
||||
@@ -1049,112 +1065,27 @@ set(EMULATOR src/emulator.cpp
|
||||
src/sdl_window.cpp
|
||||
)
|
||||
|
||||
# The above is shared in SDL and Qt version (TODO share them all)
|
||||
|
||||
if(ENABLE_QT_GUI)
|
||||
qt_add_resources(RESOURCE_FILES src/shadps4.qrc)
|
||||
|
||||
if (ENABLE_UPDATER)
|
||||
set(UPDATER src/qt_gui/check_update.cpp
|
||||
src/qt_gui/check_update.h
|
||||
)
|
||||
endif()
|
||||
|
||||
set(QT_GUI src/qt_gui/about_dialog.cpp
|
||||
src/qt_gui/about_dialog.h
|
||||
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/compatibility_info.cpp
|
||||
src/qt_gui/compatibility_info.h
|
||||
src/qt_gui/control_settings.cpp
|
||||
src/qt_gui/control_settings.h
|
||||
src/qt_gui/control_settings.ui
|
||||
src/qt_gui/kbm_gui.cpp
|
||||
src/qt_gui/kbm_gui.h
|
||||
src/qt_gui/kbm_gui.ui
|
||||
src/qt_gui/main_window_ui.h
|
||||
src/qt_gui/main_window.cpp
|
||||
src/qt_gui/main_window.h
|
||||
src/qt_gui/gui_context_menus.h
|
||||
src/qt_gui/game_list_utils.h
|
||||
src/qt_gui/game_info.cpp
|
||||
src/qt_gui/game_info.h
|
||||
src/qt_gui/game_list_frame.cpp
|
||||
src/qt_gui/game_list_frame.h
|
||||
src/qt_gui/game_grid_frame.cpp
|
||||
src/qt_gui/game_grid_frame.h
|
||||
src/qt_gui/game_install_dialog.cpp
|
||||
src/qt_gui/game_install_dialog.h
|
||||
src/qt_gui/trophy_viewer.cpp
|
||||
src/qt_gui/trophy_viewer.h
|
||||
src/qt_gui/elf_viewer.cpp
|
||||
src/qt_gui/elf_viewer.h
|
||||
src/qt_gui/kbm_config_dialog.cpp
|
||||
src/qt_gui/kbm_config_dialog.h
|
||||
src/qt_gui/kbm_help_dialog.cpp
|
||||
src/qt_gui/kbm_help_dialog.h
|
||||
src/qt_gui/main_window_themes.cpp
|
||||
src/qt_gui/main_window_themes.h
|
||||
src/qt_gui/log_presets_dialog.cpp
|
||||
src/qt_gui/log_presets_dialog.h
|
||||
src/qt_gui/settings_dialog.cpp
|
||||
src/qt_gui/settings_dialog.h
|
||||
src/qt_gui/settings_dialog.ui
|
||||
src/qt_gui/main.cpp
|
||||
src/qt_gui/gui_settings.cpp
|
||||
src/qt_gui/gui_settings.h
|
||||
src/qt_gui/settings.cpp
|
||||
src/qt_gui/settings.h
|
||||
src/qt_gui/sdl_event_wrapper.cpp
|
||||
src/qt_gui/sdl_event_wrapper.h
|
||||
src/qt_gui/hotkeys.h
|
||||
src/qt_gui/hotkeys.cpp
|
||||
src/qt_gui/hotkeys.ui
|
||||
${EMULATOR}
|
||||
${RESOURCE_FILES}
|
||||
${TRANSLATIONS}
|
||||
${UPDATER}
|
||||
add_executable(shadps4
|
||||
${AUDIO_CORE}
|
||||
${IMGUI}
|
||||
${INPUT}
|
||||
${COMMON}
|
||||
${CORE}
|
||||
${SHADER_RECOMPILER}
|
||||
${VIDEO_CORE}
|
||||
${EMULATOR}
|
||||
src/main.cpp
|
||||
src/emulator.cpp
|
||||
src/emulator.h
|
||||
src/sdl_window.h
|
||||
src/sdl_window.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT_GUI)
|
||||
qt_add_executable(shadps4
|
||||
${AUDIO_CORE}
|
||||
${IMGUI}
|
||||
${INPUT}
|
||||
${QT_GUI}
|
||||
${COMMON}
|
||||
${CORE}
|
||||
${SHADER_RECOMPILER}
|
||||
${VIDEO_CORE}
|
||||
${EMULATOR}
|
||||
src/images/shadPS4.icns
|
||||
)
|
||||
else()
|
||||
add_executable(shadps4
|
||||
${AUDIO_CORE}
|
||||
${IMGUI}
|
||||
${INPUT}
|
||||
${COMMON}
|
||||
${CORE}
|
||||
${SHADER_RECOMPILER}
|
||||
${VIDEO_CORE}
|
||||
${EMULATOR}
|
||||
src/main.cpp
|
||||
src/emulator.cpp
|
||||
src/emulator.h
|
||||
src/sdl_window.h
|
||||
src/sdl_window.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
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 Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
|
||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers libusb::usb lfreist-hwinfo::hwinfo)
|
||||
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml)
|
||||
target_link_libraries(shadps4 PRIVATE stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json miniz)
|
||||
|
||||
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")
|
||||
@@ -1174,22 +1105,11 @@ endif()
|
||||
|
||||
if (APPLE)
|
||||
# Include MoltenVK, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
|
||||
if (ENABLE_QT_GUI)
|
||||
set(MVK_BUNDLE_PATH "Resources/vulkan/icd.d")
|
||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../${MVK_BUNDLE_PATH}")
|
||||
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/${MVK_BUNDLE_PATH})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
|
||||
else()
|
||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
|
||||
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/libMoltenVK.dylib)
|
||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path")
|
||||
set(MVK_DST ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(MVK_DYLIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/externals/MoltenVK/MoltenVK/libMoltenVK.dylib)
|
||||
set(MVK_DYLIB_DST ${MVK_DST}/libMoltenVK.dylib)
|
||||
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
|
||||
set(MVK_ICD_SRC ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK/icd/MoltenVK_icd.json)
|
||||
set(MVK_ICD_DST ${MVK_DST}/MoltenVK_icd.json)
|
||||
|
||||
add_custom_command(
|
||||
@@ -1206,38 +1126,30 @@ if (APPLE)
|
||||
|
||||
if (ARCHITECTURE STREQUAL "x86_64")
|
||||
# Reserve system-managed memory space.
|
||||
target_link_options(shadps4 PRIVATE -Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-image_base,0x20000000000)
|
||||
target_link_options(shadps4 PRIVATE -Wl,-ld_classic,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,SYSTEM_MANAGED,0x400000,-segaddr,SYSTEM_RESERVED,0x7FFFFC000,-segaddr,USER_AREA,0x7000000000,-image_base,0x700000000000)
|
||||
endif()
|
||||
|
||||
# Replacement for std::chrono::time_zone
|
||||
target_link_libraries(shadps4 PRIVATE date::date-tz epoll-shim)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT_GUI)
|
||||
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
|
||||
add_definitions(-DENABLE_QT_GUI)
|
||||
if (ENABLE_UPDATER)
|
||||
add_definitions(-DENABLE_UPDATER)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(shadps4 PRIVATE mincore)
|
||||
target_link_libraries(shadps4 PRIVATE mincore wepoll wbemuuid)
|
||||
|
||||
if (MSVC)
|
||||
# MSVC likes putting opinions on what people can use, disable:
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS)
|
||||
add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN)
|
||||
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN)
|
||||
|
||||
if (MSVC)
|
||||
# Needed for conflicts with time.h of windows.h
|
||||
add_definitions(-D_TIMESPEC_DEFINED)
|
||||
add_compile_definitions(_TIMESPEC_DEFINED)
|
||||
endif()
|
||||
|
||||
# Target Windows 10 RS5
|
||||
add_definitions(-DNTDDI_VERSION=0x0A000006 -D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00)
|
||||
add_compile_definitions(NTDDI_VERSION=0x0A000006 _WIN32_WINNT=0x0A00 WINVER=0x0A00)
|
||||
|
||||
if (MSVC)
|
||||
target_link_libraries(shadps4 PRIVATE clang_rt.builtins-x86_64.lib)
|
||||
@@ -1256,13 +1168,20 @@ if (WIN32)
|
||||
else()
|
||||
target_link_options(shadps4 PRIVATE -Wl,--stack,2097152)
|
||||
endif()
|
||||
|
||||
# Change base image address
|
||||
if (MSVC)
|
||||
target_link_options(shadps4 PRIVATE /BASE:0x700000000000)
|
||||
else()
|
||||
target_link_options(shadps4 PRIVATE -Wl,--image-base=0x700000000000)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
target_sources(shadps4 PRIVATE src/shadps4.rc)
|
||||
endif()
|
||||
|
||||
add_definitions(-DBOOST_ASIO_STANDALONE)
|
||||
add_compile_definitions(BOOST_ASIO_STANDALONE)
|
||||
|
||||
target_include_directories(shadps4 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
@@ -1291,25 +1210,6 @@ 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)
|
||||
set_target_properties(shadps4 PROPERTIES
|
||||
# WIN32_EXECUTABLE ON
|
||||
MACOSX_BUNDLE ON
|
||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/dist/MacOSBundleInfo.plist.in"
|
||||
MACOSX_BUNDLE_ICON_FILE "shadPS4.icns"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}"
|
||||
)
|
||||
|
||||
set_source_files_properties(src/images/shadPS4.icns PROPERTIES
|
||||
MACOSX_PACKAGE_LOCATION Resources)
|
||||
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
|
||||
if (ENABLE_DISCORD_RPC)
|
||||
@@ -1318,10 +1218,3 @@ endif()
|
||||
|
||||
# Install rules
|
||||
install(TARGETS shadps4 BUNDLE DESTINATION .)
|
||||
|
||||
if (ENABLE_QT_GUI AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
install(FILES "dist/net.shadps4.shadPS4.desktop" DESTINATION "share/applications")
|
||||
install(FILES "dist/net.shadps4.shadPS4.metainfo.xml" DESTINATION "share/metainfo")
|
||||
install(FILES ".github/shadps4.png" DESTINATION "share/icons/hicolor/512x512/apps" RENAME "net.shadps4.shadPS4.png")
|
||||
install(FILES "src/images/net.shadps4.shadPS4.svg" DESTINATION "share/icons/hicolor/scalable/apps")
|
||||
endif()
|
||||
|
||||
@@ -15,15 +15,6 @@
|
||||
"CMAKE_BUILD_TYPE": "Debug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Debug-Qt",
|
||||
"displayName": "Clang x64 Debug with Qt",
|
||||
"inherits": ["x64-Clang-Base"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"ENABLE_QT_GUI": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Release",
|
||||
"displayName": "Clang x64 Release",
|
||||
@@ -32,15 +23,6 @@
|
||||
"CMAKE_BUILD_TYPE": "Release"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Release-Qt",
|
||||
"displayName": "Clang x64 Release with Qt",
|
||||
"inherits": ["x64-Clang-Base"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"ENABLE_QT_GUI": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-RelWithDebInfo",
|
||||
"displayName": "Clang x64 RelWithDebInfo",
|
||||
@@ -48,15 +30,6 @@
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-RelWithDebInfo-Qt",
|
||||
"displayName": "Clang x64 RelWithDebInfo with Qt",
|
||||
"inherits": ["x64-Clang-Base"],
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "RelWithDebInfo",
|
||||
"ENABLE_QT_GUI": "ON"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,18 +12,6 @@
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Release-Qt",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Release",
|
||||
"buildRoot": "${projectDir}\\Build\\${name}",
|
||||
"installRoot": "${projectDir}\\Install\\${name}",
|
||||
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Debug",
|
||||
"generator": "Ninja",
|
||||
@@ -36,18 +24,6 @@
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-Debug-Qt",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${projectDir}\\Build\\${name}",
|
||||
"installRoot": "${projectDir}\\Install\\${name}",
|
||||
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-RelWithDebInfo",
|
||||
"generator": "Ninja",
|
||||
@@ -59,18 +35,6 @@
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
},
|
||||
{
|
||||
"name": "x64-Clang-RelWithDebInfo-Qt",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "RelWithDebInfo",
|
||||
"buildRoot": "${projectDir}\\Build\\${name}",
|
||||
"installRoot": "${projectDir}\\Install\\${name}",
|
||||
"cmakeCommandArgs": "-DENABLE_QT_GUI=ON",
|
||||
"buildCommandArgs": "",
|
||||
"ctestCommandArgs": "",
|
||||
"inheritEnvironments": [ "clang_cl_x64_x64" ],
|
||||
"intelliSenseMode": "windows-clang-x64"
|
||||
}
|
||||
]
|
||||
}
|
||||
31
README.md
31
README.md
@@ -36,6 +36,9 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
**shadPS4** is an early **PlayStation 4** emulator for **Windows**, **Linux** and **macOS** written in C++.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This is the emulator core, which does not include a GUI. If you just want to use the emulator as an end user, download the [**QtLauncher**](https://github.com/shadps4-emu/shadps4-qtlauncher/releases) instead.
|
||||
|
||||
If you encounter problems or have doubts, do not hesitate to look at the [**Quickstart**](https://github.com/shadps4-emu/shadPS4/wiki/I.-Quick-start-%5BUsers%5D).\
|
||||
To verify that a game works, you can look at [**shadPS4 Game Compatibility**](https://github.com/shadps4-compatibility/shadps4-game-compatibility).\
|
||||
To discuss shadPS4 development, suggest ideas or to ask for help, join our [**Discord server**](https://discord.gg/bFJxfftGW6).\
|
||||
@@ -55,9 +58,6 @@ This project began for fun. Given our limited free time, it may take some time b
|
||||
|
||||
# Building
|
||||
|
||||
> [!IMPORTANT]
|
||||
> If you want to use shadPS4 to play your games, you don't have to follow the build instructions, you can simply download the emulator from either the [**release tab**](https://github.com/shadps4-emu/shadPS4/releases) or the [**action tab**](https://github.com/shadps4-emu/shadPS4/actions).
|
||||
|
||||
## Windows
|
||||
|
||||
Check the build instructions for [**Windows**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md).
|
||||
@@ -73,6 +73,22 @@ Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shad
|
||||
> [!IMPORTANT]
|
||||
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
|
||||
|
||||
# Usage examples
|
||||
|
||||
> [!IMPORTANT]
|
||||
> For a user-friendly GUI, download the [**QtLauncher**](https://github.com/shadps4-emu/shadps4-qtlauncher/releases).
|
||||
|
||||
To get the list of all available commands and also a more detailed description of what each command does, please refer to the `--help` flag's output.
|
||||
|
||||
Below is a list of commonly used command patterns:
|
||||
```sh
|
||||
shadPS4 CUSA00001 # Searches for a game folder called CUSA00001 in the list of game install folders, and boots it.
|
||||
shadPS4 --fullscreen true --config-clean CUSA00001 # the game argument is always the last one,
|
||||
shadPS4 -g CUSA00001 --fullscreen true --config-clean # ...unless manually specified otherwise.
|
||||
shadPS4 /path/to/game.elf # Boots a PS4 ELF file directly. Useful if you want to boot an executable that is not named eboot.bin.
|
||||
shadPS4 CUSA00001 -- -flag1 -flag2 # Passes '-flag1' and '-flag2' to the game executable in argv.
|
||||
```
|
||||
|
||||
# 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).
|
||||
@@ -160,15 +176,6 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
||||
If you want to contribute, please read the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
|
||||
Open a PR and we'll check it :)
|
||||
|
||||
# Translations
|
||||
|
||||
If you want to translate shadPS4 to your language we use [**Crowdin**](https://crowdin.com/project/shadps4-emulator).
|
||||
# Contributors
|
||||
|
||||
<a href="https://github.com/shadps4-emu/shadPS4/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=24">
|
||||
</a>
|
||||
|
||||
|
||||
# Special Thanks
|
||||
|
||||
|
||||
12
REUSE.toml
12
REUSE.toml
@@ -5,13 +5,12 @@ path = [
|
||||
"REUSE.toml",
|
||||
"crowdin.yml",
|
||||
"CMakeSettings.json",
|
||||
"CMakeDarwinPresets.json",
|
||||
"CMakeLinuxPresets.json",
|
||||
"CMakeWindowsPresets.json",
|
||||
"CMakePresets.json",
|
||||
".github/FUNDING.yml",
|
||||
".github/shadps4.png",
|
||||
".github/workflows/scripts/update_translation.sh",
|
||||
".github/workflows/update_translation.yml",
|
||||
".gitmodules",
|
||||
"dist/MacOSBundleInfo.plist.in",
|
||||
"dist/net.shadps4.shadPS4.desktop",
|
||||
@@ -75,9 +74,7 @@ path = [
|
||||
"src/images/trophy.wav",
|
||||
"src/images/hotkey.png",
|
||||
"src/images/game_settings.png",
|
||||
"src/shadps4.qrc",
|
||||
"src/shadps4.rc",
|
||||
"src/qt_gui/translations/update_translation.sh",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
|
||||
@@ -132,9 +129,4 @@ SPDX-License-Identifier = "MIT"
|
||||
[[annotations]]
|
||||
path = "src/video_core/host_shaders/fsr/*"
|
||||
SPDX-FileCopyrightText = "Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved."
|
||||
SPDX-License-Identifier = "MIT"
|
||||
|
||||
[[annotations]]
|
||||
path = "dist/qt.conf"
|
||||
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
|
||||
SPDX-License-Identifier = "GPL-2.0-or-later"
|
||||
SPDX-License-Identifier = "MIT"
|
||||
@@ -1,28 +0,0 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
set(highest_version "0")
|
||||
set(CANDIDATE_DRIVES A B C D E F G H I J K L M N O P Q R S T U V W X Y Z)
|
||||
|
||||
foreach(drive ${CANDIDATE_DRIVES})
|
||||
file(GLOB kits LIST_DIRECTORIES true CONFIGURE_DEPENDS "${drive}:/Qt/*/msvc*_64")
|
||||
foreach(kit IN LISTS kits)
|
||||
get_filename_component(version_dir "${kit}" DIRECTORY)
|
||||
get_filename_component(kit_version "${version_dir}" NAME)
|
||||
|
||||
message(STATUS "DetectQtInstallation.cmake: Detected Qt: ${kit}")
|
||||
|
||||
if (kit_version VERSION_GREATER highest_version)
|
||||
set(highest_version "${kit_version}")
|
||||
set(QT_PREFIX "${kit}")
|
||||
|
||||
endif()
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
if(QT_PREFIX)
|
||||
set(CMAKE_PREFIX_PATH "${QT_PREFIX}" CACHE PATH "Qt prefix auto‑detected" FORCE)
|
||||
message(STATUS "DetectQtInstallation.cmake: Choose newest Qt: ${QT_PREFIX}")
|
||||
else()
|
||||
message(STATUS "DetectQtInstallation.cmake: No Qt‑Directory found in <drive>:/Qt – please set CMAKE_PREFIX_PATH manually")
|
||||
endif()
|
||||
@@ -1,3 +0,0 @@
|
||||
files:
|
||||
- source: /src/qt_gui/translations/en_US.ts
|
||||
translation: /%original_path%/%locale_with_underscore%.ts
|
||||
14
dist/net.shadps4.shadPS4.metainfo.xml
vendored
14
dist/net.shadps4.shadPS4.metainfo.xml
vendored
@@ -18,25 +18,31 @@
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image type="source" translate="no" >https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/1.png</image>
|
||||
<caption>Bloodborne</caption>
|
||||
<caption>Bloodborne by From Software</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/2.png</image>
|
||||
<caption>Hatsune Miku: Project DIVA Future Tone</caption>
|
||||
<caption>Hatsune Miku Project DIVA Future Tone by SEGA</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/3.png</image>
|
||||
<caption>Yakuza 0</caption>
|
||||
<caption>Yakuza 0 by SEGA</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image type="source" translate="no">https://cdn.jsdelivr.net/gh/shadps4-emu/shadps4@main/documents/Screenshots/4.png</image>
|
||||
<caption>Persona 4 Golden</caption>
|
||||
<caption>DRIVECLUB™ by Evolution Studios</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<categories>
|
||||
<category translate="no">Game</category>
|
||||
</categories>
|
||||
<releases>
|
||||
<release version="0.12.5" date="2025-11-07">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.5</url>
|
||||
</release>
|
||||
<release version="0.12.0" date="2025-10-31">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.0</url>
|
||||
</release>
|
||||
<release version="0.11.0" date="2025-09-18">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.11.0</url>
|
||||
</release>
|
||||
|
||||
2
dist/qt.conf
vendored
2
dist/qt.conf
vendored
@@ -1,2 +0,0 @@
|
||||
[Paths]
|
||||
plugins = "./qtplugins"
|
||||
@@ -11,6 +11,13 @@ This document covers information about debugging, troubleshooting and reporting
|
||||
|
||||
This section will guide you through setting up tools for debugging the emulator. This list will likely expand as more tools and platforms receive consistent setups.
|
||||
|
||||
<details>
|
||||
<summary>Linux</summary>
|
||||
|
||||
RenderDoc doesn't work with Wayland, so to use it you have to run the emulator with `SDL_VIDEODRIVER=x11` set.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Windows and Visual Studio</summary>
|
||||
|
||||
|
||||
@@ -17,8 +17,7 @@ First and foremost, Clang 18 is the **recommended compiler** as it is used for o
|
||||
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 libpng-dev
|
||||
libvulkan-dev vulkan-validationlayers libpng-dev
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
@@ -27,8 +26,6 @@ sudo apt install build-essential clang git cmake libasound2-dev \
|
||||
sudo dnf install clang git cmake libatomic alsa-lib-devel \
|
||||
pipewire-jack-audio-connection-kit-devel openal-soft-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 libpng-devel libuuid-devel
|
||||
```
|
||||
|
||||
@@ -36,8 +33,7 @@ sudo dnf install clang git cmake libatomic alsa-lib-devel \
|
||||
|
||||
```bash
|
||||
sudo pacman -S base-devel clang git cmake sndio jack2 openal \
|
||||
qt6-base qt6-declarative qt6-multimedia qt6-tools sdl2 \
|
||||
vulkan-validation-layers libpng
|
||||
sdl2 vulkan-validation-layers libpng
|
||||
```
|
||||
|
||||
**Note**: The `shadps4-git` AUR package is not maintained by any of the developers, and it uses the default compiler, which is often set to GCC. Use at your own discretion.
|
||||
@@ -48,9 +44,7 @@ sudo pacman -S base-devel clang git cmake sndio jack2 openal \
|
||||
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 libpng-devel
|
||||
vulkan-devel vulkan-validationlayers libpng-devel
|
||||
```
|
||||
|
||||
#### NixOS
|
||||
@@ -90,12 +84,12 @@ There are 3 options you can choose from. Option 1 is **highly recommended**.
|
||||
1. Generate the build directory in the shadPS4 directory.
|
||||
|
||||
```bash
|
||||
cmake -S . -B build/ -DENABLE_QT_GUI=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
cmake -S . -B build/ -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++
|
||||
```
|
||||
|
||||
To disable the Qt GUI, remove the `-DENABLE_QT_GUI=ON` flag. To change the build type (for debugging), add `-DCMAKE_BUILD_TYPE=Debug`.
|
||||
To change the build type (for debugging), add `-DCMAKE_BUILD_TYPE=Debug`.
|
||||
|
||||
2. Use CMake to build the project:
|
||||
1. Use CMake to build the project:
|
||||
|
||||
```bash
|
||||
cmake --build ./build --parallel$(nproc)
|
||||
@@ -103,18 +97,12 @@ cmake --build ./build --parallel$(nproc)
|
||||
|
||||
If your computer freezes during this step, this could be caused by excessive system resource usage. In that case, remove `--parallel$(nproc)`.
|
||||
|
||||
Now run the emulator. If Qt was enabled at configure time:
|
||||
Now run the emulator to get the list of options:
|
||||
|
||||
```bash
|
||||
./build/shadps4
|
||||
```
|
||||
|
||||
Otherwise, specify the path to your game's boot file:
|
||||
|
||||
```bash
|
||||
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
|
||||
```
|
||||
|
||||
You can also specify the Game ID as an argument for which game to boot, as long as the folder containing the games is specified in config.toml (example: Bloodborne (US) is CUSA00900).
|
||||
#### Option 2: Configuring with cmake-gui
|
||||
|
||||
@@ -142,10 +130,6 @@ Go to Settings, filter by `@ext:ms-vscode.cmake-tools configure` and disable thi
|
||||
|
||||

|
||||
|
||||
If you wish to build with the Qt GUI, add `-DENABLE_QT_GUI=ON` to the configure arguments:
|
||||
|
||||

|
||||
|
||||
On the CMake tab, change the options as you wish, but make sure that it looks similar to or exactly like this:
|
||||
|
||||

|
||||
|
||||
@@ -24,21 +24,6 @@ eval $(/opt/homebrew/bin/brew shellenv)
|
||||
brew install clang-format cmake
|
||||
```
|
||||
|
||||
Next, install x86_64 Qt. You can skip these steps and move on to **Cloning and compiling** if you do not intend to build the Qt GUI.
|
||||
|
||||
**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 qt@6
|
||||
```
|
||||
|
||||
**If you are on an x86_64 Mac:**
|
||||
```
|
||||
brew install qt@6
|
||||
```
|
||||
|
||||
### Cloning and compiling:
|
||||
|
||||
Clone the repository recursively:
|
||||
@@ -52,8 +37,6 @@ 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/
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
<!--
|
||||
SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
||||
SPDX-FileCopyrightText: 2025 shadPS4 Emulator Project
|
||||
SPDX-License-Identifier: GPL-2.0-or-later
|
||||
-->
|
||||
|
||||
# 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.
|
||||
If you are building to contribute to the project, please omit `--depth 1` from the git invocations.
|
||||
> [!WARNING]
|
||||
> If you are trying to compile older builds for testing, do not provide the `--depth 1` flag in `git clone`.
|
||||
> This flag omits the commit history from your clone, saving storage space while preventing you from testing older commits.
|
||||
|
||||
Note: **ARM64 is not supported!** As of writing, it will not build nor run. The instructions with respect to ARM64 are for developers only.
|
||||
|
||||
@@ -20,23 +22,6 @@ Once you are within the installer:
|
||||
2. Go to "Individual Components" tab then search and select both `C++ Clang Compiler for Windows` and `MSBuild support for LLVM`
|
||||
3. Continue the installation
|
||||
|
||||
### (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.
|
||||
|
||||
1. Under the current, non beta version of Qt, select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
|
||||
If you are on Windows on ARM / Qualcomm Snapdragon Elite X, select `MSVC 2022 ARM64` instead.
|
||||
|
||||
Go through the installation normally. 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:
|
||||
|
||||
1. Tools -> Options -> Qt -> Versions
|
||||
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\<QtVersion>\msvc2022_64`
|
||||
3. Enable the default checkmark on the new version you just created.
|
||||
|
||||
### (Prerequisite) Download [**Git for Windows**](https://git-scm.com/download/win)
|
||||
|
||||
Go through the Git for Windows installation as normal
|
||||
@@ -51,16 +36,11 @@ Go through the Git for Windows installation as normal
|
||||
|
||||
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 Clang x64 Debug to Clang x64 Release if you want a regular, non-debug build.
|
||||
3. If you want to build shadPS4 with the Qt Gui, simply select Clang x64 Release with Qt instead.
|
||||
4. Change the project to build to shadps4.exe
|
||||
5. Build -> Build All
|
||||
3. Change the project to build to shadps4.exe
|
||||
4. 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\<QtVersion>\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
|
||||
(Change Qt path if you've installed it to non-default path)
|
||||
|
||||
## Option 2: MSYS2/MinGW
|
||||
|
||||
> [!IMPORTANT]
|
||||
@@ -77,13 +57,10 @@ Normal x86-based computers, follow:
|
||||
1. Open "MSYS2 MINGW64" from your new applications
|
||||
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-rapidjson 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`
|
||||
5. Run `cd shadPS4`
|
||||
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`
|
||||
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
|
||||
8. To run the finished product, run `./build/shadPS4.exe`
|
||||
|
||||
ARM64-based computers, follow:
|
||||
@@ -91,13 +68,10 @@ ARM64-based computers, follow:
|
||||
1. Open "MSYS2 CLANGARM64" from your new applications
|
||||
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-rapidjson 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`
|
||||
5. Run `cd shadPS4`
|
||||
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`
|
||||
1. Optional (Qt only): run `windeployqt6 build/shadps4.exe`
|
||||
8. To run the finished product, run `./build/shadPS4.exe`
|
||||
|
||||
## Note on MSYS2 builds
|
||||
|
||||
28
externals/CMakeLists.txt
vendored
28
externals/CMakeLists.txt
vendored
@@ -63,6 +63,18 @@ if (NOT TARGET SDL3::SDL3)
|
||||
add_subdirectory(sdl3)
|
||||
endif()
|
||||
|
||||
# SDL3_mixer
|
||||
if (NOT TARGET SDL3_mixer::SDL3_mixer)
|
||||
set(SDLMIXER_FLAC OFF)
|
||||
set(SDLMIXER_OGG OFF)
|
||||
set(SDLMIXER_MOD OFF)
|
||||
set(SDLMIXER_MIDI OFF)
|
||||
set(SDLMIXER_OPUS OFF)
|
||||
set(SDLMIXER_WAVPACK OFF)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
add_subdirectory(sdl3_mixer)
|
||||
endif()
|
||||
|
||||
# vulkan-headers
|
||||
if (NOT TARGET Vulkan::Headers)
|
||||
set(VULKAN_HEADERS_ENABLE_MODULE OFF)
|
||||
@@ -140,7 +152,7 @@ endif()
|
||||
# sirit
|
||||
add_subdirectory(sirit)
|
||||
if (WIN32)
|
||||
target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument")
|
||||
target_compile_options(sirit PRIVATE "-Wno-error=unused-command-line-argument")
|
||||
endif()
|
||||
|
||||
# half
|
||||
@@ -231,6 +243,8 @@ if (APPLE)
|
||||
|
||||
# MoltenVK
|
||||
if (NOT TARGET MoltenVK)
|
||||
set(MVK_EXCLUDE_SPIRV_TOOLS ON)
|
||||
set(MVK_USE_METAL_PRIVATE_API ON)
|
||||
add_subdirectory(MoltenVK)
|
||||
endif()
|
||||
|
||||
@@ -238,3 +252,15 @@ if (APPLE)
|
||||
add_subdirectory(epoll-shim)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#windows only
|
||||
if (WIN32)
|
||||
add_subdirectory(ext-wepoll)
|
||||
endif()
|
||||
|
||||
#nlohmann json
|
||||
set(JSON_BuildTests OFF CACHE INTERNAL "")
|
||||
add_subdirectory(json)
|
||||
|
||||
# miniz
|
||||
add_subdirectory(miniz)
|
||||
|
||||
1
externals/MoltenVK
vendored
Submodule
1
externals/MoltenVK
vendored
Submodule
Submodule externals/MoltenVK added at f168dec059
93
externals/MoltenVK/CMakeLists.txt
vendored
93
externals/MoltenVK/CMakeLists.txt
vendored
@@ -1,93 +0,0 @@
|
||||
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
# Prepare MoltenVK Git revision
|
||||
find_package(Git)
|
||||
if(GIT_FOUND)
|
||||
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --short HEAD
|
||||
OUTPUT_VARIABLE MVK_GIT_REV
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
endif()
|
||||
set(MVK_GENERATED_INCLUDES ${CMAKE_CURRENT_BINARY_DIR}/Generated)
|
||||
file(WRITE ${MVK_GENERATED_INCLUDES}/mvkGitRevDerived.h "static const char* mvkRevString = \"${MVK_GIT_REV}\";")
|
||||
message(STATUS "MoltenVK revision: ${MVK_GIT_REV}")
|
||||
|
||||
# Prepare MoltenVK version
|
||||
file(READ ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK/MoltenVK/API/mvk_private_api.h MVK_PRIVATE_API)
|
||||
string(REGEX MATCH "#define MVK_VERSION_MAJOR [0-9]+" MVK_VERSION_MAJOR_LINE "${MVK_PRIVATE_API}")
|
||||
string(REGEX MATCH "[0-9]+" MVK_VERSION_MAJOR "${MVK_VERSION_MAJOR_LINE}")
|
||||
string(REGEX MATCH "#define MVK_VERSION_MINOR [0-9]+" MVK_VERSION_MINOR_LINE "${MVK_PRIVATE_API}")
|
||||
string(REGEX MATCH "[0-9]+" MVK_VERSION_MINOR "${MVK_VERSION_MINOR_LINE}")
|
||||
string(REGEX MATCH "#define MVK_VERSION_PATCH [0-9]+" MVK_VERSION_PATCH_LINE "${MVK_PRIVATE_API}")
|
||||
string(REGEX MATCH "[0-9]+" MVK_VERSION_PATCH "${MVK_VERSION_PATCH_LINE}")
|
||||
set(MVK_VERSION "${MVK_VERSION_MAJOR}.${MVK_VERSION_MINOR}.${MVK_VERSION_PATCH}")
|
||||
message(STATUS "MoltenVK version: ${MVK_VERSION}")
|
||||
|
||||
# Find required system libraries
|
||||
find_library(APPKIT_LIBRARY AppKit REQUIRED)
|
||||
find_library(FOUNDATION_LIBRARY Foundation REQUIRED)
|
||||
find_library(IOKIT_LIBRARY IOKit REQUIRED)
|
||||
find_library(IOSURFACE_LIBRARY IOSurface REQUIRED)
|
||||
find_library(METAL_LIBRARY Metal REQUIRED)
|
||||
find_library(QUARTZCORE_LIBRARY QuartzCore REQUIRED)
|
||||
|
||||
# cereal
|
||||
option(SKIP_PORTABILITY_TEST "" ON)
|
||||
option(BUILD_DOC "" OFF)
|
||||
option(BUILD_SANDBOX "" OFF)
|
||||
option(SKIP_PERFORMANCE_COMPARISON "" ON)
|
||||
option(SPIRV_CROSS_SKIP_INSTALL "" ON)
|
||||
add_subdirectory(cereal)
|
||||
|
||||
# SPIRV-Cross
|
||||
option(SPIRV_CROSS_CLI "" OFF)
|
||||
option(SPIRV_CROSS_ENABLE_TESTS "" OFF)
|
||||
option(SPIRV_CROSS_ENABLE_HLSL "" OFF)
|
||||
option(SPIRV_CROSS_ENABLE_CPP "" OFF)
|
||||
option(SPIRV_CROSS_SKIP_INSTALL "" ON)
|
||||
add_subdirectory(SPIRV-Cross)
|
||||
|
||||
# Common
|
||||
set(MVK_COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/Common)
|
||||
file(GLOB_RECURSE MVK_COMMON_SOURCES CONFIGURE_DEPENDS
|
||||
${MVK_COMMON_DIR}/*.cpp
|
||||
${MVK_COMMON_DIR}/*.m
|
||||
${MVK_COMMON_DIR}/*.mm)
|
||||
set(MVK_COMMON_INCLUDES ${MVK_COMMON_DIR})
|
||||
|
||||
add_library(MoltenVKCommon STATIC ${MVK_COMMON_SOURCES})
|
||||
target_include_directories(MoltenVKCommon PUBLIC ${MVK_COMMON_INCLUDES})
|
||||
target_compile_options(MoltenVKCommon PRIVATE -w)
|
||||
|
||||
# MoltenVKShaderConverter
|
||||
set(MVK_SHADER_CONVERTER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVKShaderConverter)
|
||||
file(GLOB_RECURSE MVK_SHADER_CONVERTER_SOURCES CONFIGURE_DEPENDS
|
||||
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.cpp
|
||||
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.m
|
||||
${MVK_SHADER_CONVERTER_DIR}/MoltenVKShaderConverter/*.mm)
|
||||
set(MVK_SHADER_CONVERTER_INCLUDES ${MVK_SHADER_CONVERTER_DIR} ${MVK_SHADER_CONVERTER_DIR}/include)
|
||||
|
||||
add_library(MoltenVKShaderConverter STATIC ${MVK_SHADER_CONVERTER_SOURCES})
|
||||
target_include_directories(MoltenVKShaderConverter PUBLIC ${MVK_SHADER_CONVERTER_INCLUDES})
|
||||
target_compile_options(MoltenVKShaderConverter PRIVATE -w)
|
||||
target_link_libraries(MoltenVKShaderConverter PRIVATE spirv-cross-msl spirv-cross-reflect MoltenVKCommon)
|
||||
target_compile_definitions(MoltenVKShaderConverter PRIVATE MVK_EXCLUDE_SPIRV_TOOLS=1)
|
||||
|
||||
# MoltenVK
|
||||
set(MVK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/MoltenVK/MoltenVK)
|
||||
file(GLOB_RECURSE MVK_SOURCES CONFIGURE_DEPENDS
|
||||
${MVK_DIR}/MoltenVK/*.cpp
|
||||
${MVK_DIR}/MoltenVK/*.m
|
||||
${MVK_DIR}/MoltenVK/*.mm)
|
||||
file(GLOB MVK_SRC_INCLUDES LIST_DIRECTORIES ON ${MVK_DIR}/MoltenVK/*)
|
||||
set(MVK_INCLUDES ${MVK_SRC_INCLUDES} ${MVK_GENERATED_INCLUDES} ${MVK_DIR}/include)
|
||||
|
||||
add_library(MoltenVK SHARED ${MVK_SOURCES})
|
||||
target_include_directories(MoltenVK PRIVATE ${MVK_INCLUDES})
|
||||
target_compile_options(MoltenVK PRIVATE -w)
|
||||
target_link_libraries(MoltenVK PRIVATE
|
||||
${APPKIT_LIBRARY} ${FOUNDATION_LIBRARY} ${IOKIT_LIBRARY} ${IOSURFACE_LIBRARY} ${METAL_LIBRARY} ${QUARTZCORE_LIBRARY}
|
||||
Vulkan::Headers cereal::cereal spirv-cross-msl MoltenVKCommon MoltenVKShaderConverter)
|
||||
target_compile_definitions(MoltenVK PRIVATE MVK_FRAMEWORK_VERSION=${MVK_VERSION} MVK_USE_METAL_PRIVATE_API=1)
|
||||
1
externals/MoltenVK/MoltenVK
vendored
1
externals/MoltenVK/MoltenVK
vendored
Submodule externals/MoltenVK/MoltenVK deleted from 712fbb808d
1
externals/MoltenVK/SPIRV-Cross
vendored
1
externals/MoltenVK/SPIRV-Cross
vendored
Submodule externals/MoltenVK/SPIRV-Cross deleted from 0a88b2d5c0
1
externals/MoltenVK/cereal
vendored
1
externals/MoltenVK/cereal
vendored
Submodule externals/MoltenVK/cereal deleted from a56bad8bbb
1
externals/ext-wepoll
vendored
Submodule
1
externals/ext-wepoll
vendored
Submodule
Submodule externals/ext-wepoll added at d3bb810353
1
externals/json
vendored
Submodule
1
externals/json
vendored
Submodule
Submodule externals/json added at 55f93686c0
1
externals/miniz
vendored
Submodule
1
externals/miniz
vendored
Submodule
Submodule externals/miniz added at 174573d602
1
externals/sdl3_mixer
vendored
Submodule
1
externals/sdl3_mixer
vendored
Submodule
Submodule externals/sdl3_mixer added at 4182794ea4
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
Submodule externals/vulkan-headers updated: a01329f307...33d7f51258
73
shell.nix
73
shell.nix
@@ -6,54 +6,47 @@ with import (fetchTarball "https://github.com/nixos/nixpkgs/archive/cfd19cdc5468
|
||||
pkgs.mkShell {
|
||||
name = "shadps4-build-env";
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.llvmPackages_18.clang
|
||||
pkgs.cmake
|
||||
pkgs.pkg-config
|
||||
pkgs.git
|
||||
nativeBuildInputs = with pkgs; [
|
||||
llvmPackages_18.clang
|
||||
cmake
|
||||
pkg-config
|
||||
git
|
||||
util-linux
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
pkgs.alsa-lib
|
||||
pkgs.libpulseaudio
|
||||
pkgs.openal
|
||||
pkgs.openssl
|
||||
pkgs.zlib
|
||||
pkgs.libedit
|
||||
pkgs.udev
|
||||
pkgs.libevdev
|
||||
pkgs.SDL2
|
||||
pkgs.jack2
|
||||
pkgs.sndio
|
||||
pkgs.qt6.qtbase
|
||||
pkgs.qt6.qttools
|
||||
pkgs.qt6.qtmultimedia
|
||||
buildInputs = with pkgs; [
|
||||
alsa-lib
|
||||
libpulseaudio
|
||||
openal
|
||||
zlib
|
||||
libedit
|
||||
udev
|
||||
libevdev
|
||||
SDL2
|
||||
jack2
|
||||
sndio
|
||||
|
||||
pkgs.vulkan-headers
|
||||
pkgs.vulkan-utility-libraries
|
||||
pkgs.vulkan-tools
|
||||
vulkan-headers
|
||||
vulkan-utility-libraries
|
||||
vulkan-tools
|
||||
|
||||
pkgs.ffmpeg
|
||||
pkgs.fmt
|
||||
pkgs.glslang
|
||||
pkgs.libxkbcommon
|
||||
pkgs.wayland
|
||||
pkgs.xorg.libxcb
|
||||
pkgs.xorg.xcbutil
|
||||
pkgs.xorg.xcbutilkeysyms
|
||||
pkgs.xorg.xcbutilwm
|
||||
pkgs.sdl3
|
||||
pkgs.stb
|
||||
pkgs.qt6.qtwayland
|
||||
pkgs.wayland-protocols
|
||||
pkgs.libpng
|
||||
ffmpeg
|
||||
fmt
|
||||
glslang
|
||||
libxkbcommon
|
||||
wayland
|
||||
xorg.libxcb
|
||||
xorg.xcbutil
|
||||
xorg.xcbutilkeysyms
|
||||
xorg.xcbutilwm
|
||||
sdl3
|
||||
stb
|
||||
wayland-protocols
|
||||
libpng
|
||||
];
|
||||
|
||||
shellHook = ''
|
||||
echo "Entering shadPS4 dev shell"
|
||||
export QT_QPA_PLATFORM="wayland"
|
||||
export QT_PLUGIN_PATH="${pkgs.qt6.qtwayland}/lib/qt-6/plugins:${pkgs.qt6.qtbase}/lib/qt-6/plugins"
|
||||
export QML2_IMPORT_PATH="${pkgs.qt6.qtbase}/lib/qt-6/qml"
|
||||
export CMAKE_PREFIX_PATH="${pkgs.vulkan-headers}:$CMAKE_PREFIX_PATH"
|
||||
|
||||
# OpenGL
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <fmt/xchar.h> // for wstring support
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "common/path_util.h"
|
||||
@@ -74,18 +75,34 @@ std::optional<T> get_optional(const toml::value& v, const std::string& key) {
|
||||
|
||||
namespace Config {
|
||||
|
||||
ConfigMode config_mode = ConfigMode::Default;
|
||||
|
||||
void setConfigMode(ConfigMode mode) {
|
||||
config_mode = mode;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class ConfigEntry {
|
||||
public:
|
||||
const T default_value;
|
||||
T base_value;
|
||||
optional<T> game_specific_value;
|
||||
ConfigEntry(const T& t = T()) : base_value(t), game_specific_value(nullopt) {}
|
||||
ConfigEntry(const T& t = T()) : default_value(t), base_value(t), game_specific_value(nullopt) {}
|
||||
ConfigEntry operator=(const T& t) {
|
||||
base_value = t;
|
||||
return *this;
|
||||
}
|
||||
const T get() const {
|
||||
return game_specific_value.has_value() ? *game_specific_value : base_value;
|
||||
switch (config_mode) {
|
||||
case ConfigMode::Default:
|
||||
return game_specific_value.value_or(base_value);
|
||||
case ConfigMode::Global:
|
||||
return base_value;
|
||||
case ConfigMode::Clean:
|
||||
return default_value;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
void setFromToml(const toml::value& v, const std::string& key, bool is_game_specific = false) {
|
||||
if (is_game_specific) {
|
||||
@@ -115,19 +132,18 @@ public:
|
||||
static ConfigEntry<int> volumeSlider(100);
|
||||
static ConfigEntry<bool> isNeo(false);
|
||||
static ConfigEntry<bool> isDevKit(false);
|
||||
static ConfigEntry<int> extraDmemInMbytes(0);
|
||||
static ConfigEntry<bool> isPSNSignedIn(false);
|
||||
static ConfigEntry<bool> isTrophyPopupDisabled(false);
|
||||
static ConfigEntry<double> trophyNotificationDuration(6.0);
|
||||
static ConfigEntry<string> logFilter("");
|
||||
static ConfigEntry<string> logType("sync");
|
||||
static ConfigEntry<string> userName("shadPS4");
|
||||
static ConfigEntry<string> chooseHomeTab("General");
|
||||
static ConfigEntry<bool> isShowSplash(false);
|
||||
static ConfigEntry<string> isSideTrophy("right");
|
||||
static ConfigEntry<bool> isConnectedToNetwork(false);
|
||||
static bool enableDiscordRPC = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
static bool compatibilityData = false;
|
||||
static std::filesystem::path sys_modules_path = {};
|
||||
|
||||
// Input
|
||||
static ConfigEntry<int> cursorState(HideCursorState::Idle);
|
||||
@@ -161,29 +177,32 @@ static ConfigEntry<bool> isFullscreen(false);
|
||||
static ConfigEntry<string> fullscreenMode("Windowed");
|
||||
static ConfigEntry<string> presentMode("Mailbox");
|
||||
static ConfigEntry<bool> isHDRAllowed(false);
|
||||
static ConfigEntry<bool> fsrEnabled(true);
|
||||
static ConfigEntry<bool> fsrEnabled(false);
|
||||
static ConfigEntry<bool> rcasEnabled(true);
|
||||
static ConfigEntry<int> rcasAttenuation(250);
|
||||
|
||||
// Vulkan
|
||||
static ConfigEntry<s32> gpuId(-1);
|
||||
static ConfigEntry<bool> vkValidation(false);
|
||||
static ConfigEntry<bool> vkValidationCore(true);
|
||||
static ConfigEntry<bool> vkValidationSync(false);
|
||||
static ConfigEntry<bool> vkValidationGpu(false);
|
||||
static ConfigEntry<bool> vkCrashDiagnostic(false);
|
||||
static ConfigEntry<bool> vkHostMarkers(false);
|
||||
static ConfigEntry<bool> vkGuestMarkers(false);
|
||||
static ConfigEntry<bool> rdocEnable(false);
|
||||
static ConfigEntry<bool> pipelineCacheEnable(false);
|
||||
static ConfigEntry<bool> pipelineCacheArchive(false);
|
||||
|
||||
// Debug
|
||||
static ConfigEntry<bool> isDebugDump(false);
|
||||
static ConfigEntry<bool> isShaderDebug(false);
|
||||
static ConfigEntry<bool> isSeparateLogFilesEnabled(false);
|
||||
static ConfigEntry<bool> isFpsColor(true);
|
||||
static ConfigEntry<bool> showFpsCounter(false);
|
||||
static ConfigEntry<bool> logEnabled(true);
|
||||
|
||||
// GUI
|
||||
static bool load_game_size = true;
|
||||
static std::vector<GameInstallDir> settings_install_dirs = {};
|
||||
std::vector<bool> install_dirs_enabled = {};
|
||||
std::filesystem::path settings_addon_install_dir = {};
|
||||
@@ -192,15 +211,39 @@ std::filesystem::path save_data_path = {};
|
||||
// Settings
|
||||
ConfigEntry<u32> m_language(1); // english
|
||||
|
||||
// USB Device
|
||||
static ConfigEntry<int> usbDeviceBackend(UsbBackendType::Real);
|
||||
|
||||
// Keys
|
||||
static string trophyKey = "";
|
||||
|
||||
// Config version, used to determine if a user's config file is outdated.
|
||||
static string config_version = Common::g_scm_rev;
|
||||
|
||||
// These two entries aren't stored in the config
|
||||
// These entries aren't stored in the config
|
||||
static bool overrideControllerColor = false;
|
||||
static int controllerCustomColorRGB[3] = {0, 0, 255};
|
||||
static bool isGameRunning = false;
|
||||
static bool load_auto_patches = true;
|
||||
|
||||
bool getGameRunning() {
|
||||
return isGameRunning;
|
||||
}
|
||||
|
||||
void setGameRunning(bool running) {
|
||||
isGameRunning = running;
|
||||
}
|
||||
|
||||
std::filesystem::path getSysModulesPath() {
|
||||
if (sys_modules_path.empty()) {
|
||||
return Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
|
||||
}
|
||||
return sys_modules_path;
|
||||
}
|
||||
|
||||
void setSysModulesPath(const std::filesystem::path& path) {
|
||||
sys_modules_path = path;
|
||||
}
|
||||
|
||||
int getVolumeSlider() {
|
||||
return volumeSlider.get();
|
||||
@@ -247,10 +290,6 @@ void setTrophyKey(string key) {
|
||||
trophyKey = key;
|
||||
}
|
||||
|
||||
bool GetLoadGameSizeEnabled() {
|
||||
return load_game_size;
|
||||
}
|
||||
|
||||
std::filesystem::path GetSaveDataPath() {
|
||||
if (save_data_path.empty()) {
|
||||
return Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "savedata";
|
||||
@@ -262,10 +301,6 @@ void setVolumeSlider(int volumeValue, bool is_game_specific) {
|
||||
volumeSlider.set(volumeValue, is_game_specific);
|
||||
}
|
||||
|
||||
void setLoadGameSizeEnabled(bool enable) {
|
||||
load_game_size = enable;
|
||||
}
|
||||
|
||||
bool isNeoModeConsole() {
|
||||
return isNeo.get();
|
||||
}
|
||||
@@ -274,6 +309,16 @@ bool isDevKitConsole() {
|
||||
return isDevKit.get();
|
||||
}
|
||||
|
||||
int getExtraDmemInMbytes() {
|
||||
return extraDmemInMbytes.get();
|
||||
}
|
||||
|
||||
void setExtraDmemInMbytes(int value, bool is_game_specific) {
|
||||
// Disable setting in global config
|
||||
is_game_specific ? extraDmemInMbytes.game_specific_value = value
|
||||
: extraDmemInMbytes.base_value = 0;
|
||||
}
|
||||
|
||||
bool getIsFullscreen() {
|
||||
return isFullscreen.get();
|
||||
}
|
||||
@@ -350,10 +395,6 @@ string getUserName() {
|
||||
return userName.get();
|
||||
}
|
||||
|
||||
string getChooseHomeTab() {
|
||||
return chooseHomeTab.get();
|
||||
}
|
||||
|
||||
bool getUseSpecialPad() {
|
||||
return useSpecialPad.get();
|
||||
}
|
||||
@@ -414,10 +455,26 @@ bool isRdocEnabled() {
|
||||
return rdocEnable.get();
|
||||
}
|
||||
|
||||
bool isPipelineCacheEnabled() {
|
||||
return pipelineCacheEnable.get();
|
||||
}
|
||||
|
||||
bool isPipelineCacheArchived() {
|
||||
return pipelineCacheArchive.get();
|
||||
}
|
||||
|
||||
bool fpsColor() {
|
||||
return isFpsColor.get();
|
||||
}
|
||||
|
||||
bool getShowFpsCounter() {
|
||||
return showFpsCounter.get();
|
||||
}
|
||||
|
||||
void setShowFpsCounter(bool enable, bool is_game_specific) {
|
||||
showFpsCounter.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
bool isLoggingEnabled() {
|
||||
return logEnabled.get();
|
||||
}
|
||||
@@ -433,6 +490,10 @@ bool vkValidationEnabled() {
|
||||
return vkValidation.get();
|
||||
}
|
||||
|
||||
bool vkValidationCoreEnabled() {
|
||||
return vkValidationCore.get();
|
||||
}
|
||||
|
||||
bool vkValidationSyncEnabled() {
|
||||
return vkValidationSync.get();
|
||||
}
|
||||
@@ -465,14 +526,6 @@ void setVkGuestMarkersEnabled(bool enable, bool is_game_specific) {
|
||||
vkGuestMarkers.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
bool getCompatibilityEnabled() {
|
||||
return compatibilityData;
|
||||
}
|
||||
|
||||
bool getCheckCompatibilityOnStartup() {
|
||||
return checkCompatibilityOnStartup;
|
||||
}
|
||||
|
||||
bool getIsConnectedToNetwork() {
|
||||
return isConnectedToNetwork.get();
|
||||
}
|
||||
@@ -557,10 +610,26 @@ void setVkSyncValidation(bool enable, bool is_game_specific) {
|
||||
vkValidationSync.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setVkCoreValidation(bool enable, bool is_game_specific) {
|
||||
vkValidationCore.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setVkGpuValidation(bool enable, bool is_game_specific) {
|
||||
vkValidationGpu.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setRdocEnabled(bool enable, bool is_game_specific) {
|
||||
rdocEnable.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setPipelineCacheEnabled(bool enable, bool is_game_specific) {
|
||||
pipelineCacheEnable.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setPipelineCacheArchived(bool enable, bool is_game_specific) {
|
||||
pipelineCacheArchive.set(enable, is_game_specific);
|
||||
}
|
||||
|
||||
void setVblankFreq(u32 value, bool is_game_specific) {
|
||||
vblankFrequency.set(value, is_game_specific);
|
||||
}
|
||||
@@ -637,10 +706,6 @@ void setUserName(const string& name, bool is_game_specific) {
|
||||
userName.set(name, is_game_specific);
|
||||
}
|
||||
|
||||
void setChooseHomeTab(const string& type, bool is_game_specific) {
|
||||
chooseHomeTab.set(type, is_game_specific);
|
||||
}
|
||||
|
||||
void setUseSpecialPad(bool use) {
|
||||
useSpecialPad.base_value = use;
|
||||
}
|
||||
@@ -653,14 +718,6 @@ void setIsMotionControlsEnabled(bool use, bool is_game_specific) {
|
||||
isMotionControlsEnabled.set(use, is_game_specific);
|
||||
}
|
||||
|
||||
void setCompatibilityEnabled(bool use) {
|
||||
compatibilityData = use;
|
||||
}
|
||||
|
||||
void setCheckCompatibilityOnStartup(bool use) {
|
||||
checkCompatibilityOnStartup = use;
|
||||
}
|
||||
|
||||
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
|
||||
for (const auto& install_dir : settings_install_dirs) {
|
||||
if (install_dir.path == dir) {
|
||||
@@ -790,6 +847,21 @@ void setRcasAttenuation(int value, bool is_game_specific) {
|
||||
rcasAttenuation.set(value, is_game_specific);
|
||||
}
|
||||
|
||||
int getUsbDeviceBackend() {
|
||||
return usbDeviceBackend.get();
|
||||
}
|
||||
|
||||
void setUsbDeviceBackend(int value, bool is_game_specific) {
|
||||
usbDeviceBackend.set(value, is_game_specific);
|
||||
}
|
||||
|
||||
bool getLoadAutoPatches() {
|
||||
return load_auto_patches;
|
||||
}
|
||||
void setLoadAutoPatches(bool enable) {
|
||||
load_auto_patches = enable;
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
// If the configuration file does not exist, create it and return, unless it is game specific
|
||||
std::error_code error;
|
||||
@@ -818,6 +890,9 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
volumeSlider.setFromToml(general, "volumeSlider", is_game_specific);
|
||||
isNeo.setFromToml(general, "isPS4Pro", is_game_specific);
|
||||
isDevKit.setFromToml(general, "isDevKit", is_game_specific);
|
||||
if (is_game_specific) { // do not get this value from the base config
|
||||
extraDmemInMbytes.setFromToml(general, "extraDmemInMbytes", is_game_specific);
|
||||
}
|
||||
isPSNSignedIn.setFromToml(general, "isPSNSignedIn", is_game_specific);
|
||||
isTrophyPopupDisabled.setFromToml(general, "isTrophyPopupDisabled", is_game_specific);
|
||||
trophyNotificationDuration.setFromToml(general, "trophyNotificationDuration",
|
||||
@@ -828,13 +903,10 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
userName.setFromToml(general, "userName", is_game_specific);
|
||||
isShowSplash.setFromToml(general, "showSplash", is_game_specific);
|
||||
isSideTrophy.setFromToml(general, "sideTrophy", is_game_specific);
|
||||
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", compatibilityData);
|
||||
checkCompatibilityOnStartup = toml::find_or<bool>(general, "checkCompatibilityOnStartup",
|
||||
checkCompatibilityOnStartup);
|
||||
|
||||
isConnectedToNetwork.setFromToml(general, "isConnectedToNetwork", is_game_specific);
|
||||
chooseHomeTab.setFromToml(general, "chooseHomeTab", is_game_specific);
|
||||
defaultControllerID.setFromToml(general, "defaultControllerID", is_game_specific);
|
||||
sys_modules_path = toml::find_fs_path_or(general, "sysModulesPath", sys_modules_path);
|
||||
}
|
||||
|
||||
if (data.contains("Input")) {
|
||||
@@ -847,6 +919,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
isMotionControlsEnabled.setFromToml(input, "isMotionControlsEnabled", is_game_specific);
|
||||
useUnifiedInputConfig.setFromToml(input, "useUnifiedInputConfig", is_game_specific);
|
||||
backgroundControllerInput.setFromToml(input, "backgroundControllerInput", is_game_specific);
|
||||
usbDeviceBackend.setFromToml(input, "usbDeviceBackend", is_game_specific);
|
||||
}
|
||||
|
||||
if (data.contains("Audio")) {
|
||||
@@ -886,12 +959,15 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
|
||||
gpuId.setFromToml(vk, "gpuId", is_game_specific);
|
||||
vkValidation.setFromToml(vk, "validation", is_game_specific);
|
||||
vkValidationCore.setFromToml(vk, "validation_core", is_game_specific);
|
||||
vkValidationSync.setFromToml(vk, "validation_sync", is_game_specific);
|
||||
vkValidationGpu.setFromToml(vk, "validation_gpu", is_game_specific);
|
||||
vkCrashDiagnostic.setFromToml(vk, "crashDiagnostic", is_game_specific);
|
||||
vkHostMarkers.setFromToml(vk, "hostMarkers", is_game_specific);
|
||||
vkGuestMarkers.setFromToml(vk, "guestMarkers", is_game_specific);
|
||||
rdocEnable.setFromToml(vk, "rdocEnable", is_game_specific);
|
||||
pipelineCacheEnable.setFromToml(vk, "pipelineCacheEnable", is_game_specific);
|
||||
pipelineCacheArchive.setFromToml(vk, "pipelineCacheArchive", is_game_specific);
|
||||
}
|
||||
|
||||
string current_version = {};
|
||||
@@ -902,6 +978,7 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
isSeparateLogFilesEnabled.setFromToml(debug, "isSeparateLogFilesEnabled", is_game_specific);
|
||||
isShaderDebug.setFromToml(debug, "CollectShader", is_game_specific);
|
||||
isFpsColor.setFromToml(debug, "FPSColor", is_game_specific);
|
||||
showFpsCounter.setFromToml(debug, "showFpsCounter", is_game_specific);
|
||||
logEnabled.setFromToml(debug, "logEnabled", is_game_specific);
|
||||
current_version = toml::find_or<std::string>(debug, "ConfigVersion", current_version);
|
||||
}
|
||||
@@ -909,8 +986,6 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
if (data.contains("GUI")) {
|
||||
const toml::value& gui = data.at("GUI");
|
||||
|
||||
load_game_size = toml::find_or<bool>(gui, "loadGameSizeEnabled", load_game_size);
|
||||
|
||||
const auto install_dir_array =
|
||||
toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
|
||||
|
||||
@@ -955,8 +1030,8 @@ void load(const std::filesystem::path& path, bool is_game_specific) {
|
||||
|
||||
void sortTomlSections(toml::ordered_value& data) {
|
||||
toml::ordered_value ordered_data;
|
||||
std::vector<string> section_order = {"General", "Input", "GPU", "Vulkan",
|
||||
"Debug", "Keys", "GUI", "Settings"};
|
||||
std::vector<string> section_order = {"General", "Input", "Audio", "GPU", "Vulkan",
|
||||
"Debug", "Keys", "GUI", "Settings"};
|
||||
|
||||
for (const auto& section : section_order) {
|
||||
if (data.contains(section)) {
|
||||
@@ -1014,11 +1089,13 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
|
||||
logFilter.setTomlValue(data, "General", "logFilter", is_game_specific);
|
||||
logType.setTomlValue(data, "General", "logType", is_game_specific);
|
||||
userName.setTomlValue(data, "General", "userName", is_game_specific);
|
||||
chooseHomeTab.setTomlValue(data, "General", "chooseHomeTab", is_game_specific);
|
||||
isShowSplash.setTomlValue(data, "General", "showSplash", is_game_specific);
|
||||
isSideTrophy.setTomlValue(data, "General", "sideTrophy", is_game_specific);
|
||||
isNeo.setTomlValue(data, "General", "isPS4Pro", is_game_specific);
|
||||
isDevKit.setTomlValue(data, "General", "isDevKit", is_game_specific);
|
||||
if (is_game_specific) {
|
||||
extraDmemInMbytes.setTomlValue(data, "General", "extraDmemInMbytes", is_game_specific);
|
||||
}
|
||||
isPSNSignedIn.setTomlValue(data, "General", "isPSNSignedIn", is_game_specific);
|
||||
isConnectedToNetwork.setTomlValue(data, "General", "isConnectedToNetwork", is_game_specific);
|
||||
|
||||
@@ -1028,6 +1105,7 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
|
||||
is_game_specific);
|
||||
backgroundControllerInput.setTomlValue(data, "Input", "backgroundControllerInput",
|
||||
is_game_specific);
|
||||
usbDeviceBackend.setTomlValue(data, "Input", "usbDeviceBackend", is_game_specific);
|
||||
|
||||
micDevice.setTomlValue(data, "Audio", "micDevice", is_game_specific);
|
||||
mainOutputDevice.setTomlValue(data, "Audio", "mainOutputDevice", is_game_specific);
|
||||
@@ -1053,10 +1131,14 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
|
||||
gpuId.setTomlValue(data, "Vulkan", "gpuId", is_game_specific);
|
||||
vkValidation.setTomlValue(data, "Vulkan", "validation", is_game_specific);
|
||||
vkValidationSync.setTomlValue(data, "Vulkan", "validation_sync", is_game_specific);
|
||||
vkValidationCore.setTomlValue(data, "Vulkan", "validation_core", is_game_specific);
|
||||
vkValidationGpu.setTomlValue(data, "Vulkan", "validation_gpu", is_game_specific);
|
||||
vkCrashDiagnostic.setTomlValue(data, "Vulkan", "crashDiagnostic", is_game_specific);
|
||||
vkHostMarkers.setTomlValue(data, "Vulkan", "hostMarkers", is_game_specific);
|
||||
vkGuestMarkers.setTomlValue(data, "Vulkan", "guestMarkers", is_game_specific);
|
||||
rdocEnable.setTomlValue(data, "Vulkan", "rdocEnable", is_game_specific);
|
||||
pipelineCacheEnable.setTomlValue(data, "Vulkan", "pipelineCacheEnable", is_game_specific);
|
||||
pipelineCacheArchive.setTomlValue(data, "Vulkan", "pipelineCacheArchive", is_game_specific);
|
||||
|
||||
isDebugDump.setTomlValue(data, "Debug", "DebugDump", is_game_specific);
|
||||
isShaderDebug.setTomlValue(data, "Debug", "CollectShader", is_game_specific);
|
||||
@@ -1098,12 +1180,10 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
|
||||
|
||||
// Non game-specific entries
|
||||
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||
data["General"]["sysModulesPath"] = string{fmt::UTF(sys_modules_path.u8string()).data};
|
||||
data["GUI"]["installDirs"] = install_dirs;
|
||||
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
|
||||
data["GUI"]["saveDataPath"] = string{fmt::UTF(save_data_path.u8string()).data};
|
||||
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
|
||||
data["GUI"]["addonInstallDir"] =
|
||||
string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||
data["Debug"]["ConfigVersion"] = config_version;
|
||||
@@ -1117,8 +1197,8 @@ void save(const std::filesystem::path& path, bool is_game_specific) {
|
||||
data["GPU"]["internalScreenWidth"] = internalScreenWidth.base_value;
|
||||
data["GPU"]["internalScreenHeight"] = internalScreenHeight.base_value;
|
||||
data["GPU"]["patchShaders"] = shouldPatchShaders.base_value;
|
||||
data["Vulkan"]["validation_gpu"] = vkValidationGpu.base_value;
|
||||
data["Debug"]["FPSColor"] = isFpsColor.base_value;
|
||||
data["Debug"]["showFpsCounter"] = showFpsCounter.base_value;
|
||||
}
|
||||
|
||||
// Sorting of TOML sections
|
||||
@@ -1141,6 +1221,7 @@ void setDefaultValues(bool is_game_specific) {
|
||||
isPSNSignedIn.set(false, is_game_specific);
|
||||
isConnectedToNetwork.set(false, is_game_specific);
|
||||
directMemoryAccessEnabled.set(false, is_game_specific);
|
||||
extraDmemInMbytes.set(0, is_game_specific);
|
||||
}
|
||||
|
||||
// Entries with game-specific settings that are in both the game-specific and global GUI
|
||||
@@ -1151,7 +1232,6 @@ void setDefaultValues(bool is_game_specific) {
|
||||
logFilter.set("", is_game_specific);
|
||||
logType.set("sync", is_game_specific);
|
||||
userName.set("shadPS4", is_game_specific);
|
||||
chooseHomeTab.set("General", is_game_specific);
|
||||
isShowSplash.set(false, is_game_specific);
|
||||
isSideTrophy.set("right", is_game_specific);
|
||||
|
||||
@@ -1160,6 +1240,7 @@ void setDefaultValues(bool is_game_specific) {
|
||||
cursorHideTimeout.set(5, is_game_specific);
|
||||
isMotionControlsEnabled.set(true, is_game_specific);
|
||||
backgroundControllerInput.set(false, is_game_specific);
|
||||
usbDeviceBackend.set(UsbBackendType::Real, is_game_specific);
|
||||
|
||||
// GS - Audio
|
||||
micDevice.set("Default Device", is_game_specific);
|
||||
@@ -1182,12 +1263,15 @@ void setDefaultValues(bool is_game_specific) {
|
||||
// GS - Vulkan
|
||||
gpuId.set(-1, is_game_specific);
|
||||
vkValidation.set(false, is_game_specific);
|
||||
vkValidationCore.set(true, is_game_specific);
|
||||
vkValidationSync.set(false, is_game_specific);
|
||||
vkValidationGpu.set(false, is_game_specific);
|
||||
vkCrashDiagnostic.set(false, is_game_specific);
|
||||
vkHostMarkers.set(false, is_game_specific);
|
||||
vkGuestMarkers.set(false, is_game_specific);
|
||||
rdocEnable.set(false, is_game_specific);
|
||||
pipelineCacheEnable.set(false, is_game_specific);
|
||||
pipelineCacheArchive.set(false, is_game_specific);
|
||||
|
||||
// GS - Debug
|
||||
isDebugDump.set(false, is_game_specific);
|
||||
@@ -1203,8 +1287,6 @@ void setDefaultValues(bool is_game_specific) {
|
||||
|
||||
// General
|
||||
enableDiscordRPC = false;
|
||||
compatibilityData = false;
|
||||
checkCompatibilityOnStartup = false;
|
||||
|
||||
// Input
|
||||
useSpecialPad.base_value = false;
|
||||
@@ -1223,11 +1305,9 @@ void setDefaultValues(bool is_game_specific) {
|
||||
internalScreenWidth.base_value = 1280;
|
||||
internalScreenHeight.base_value = 720;
|
||||
|
||||
// GUI
|
||||
load_game_size = true;
|
||||
|
||||
// Debug
|
||||
isFpsColor.base_value = true;
|
||||
showFpsCounter.base_value = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,6 +1322,7 @@ hotkey_pause = f9
|
||||
hotkey_reload_inputs = f8
|
||||
hotkey_toggle_mouse_to_joystick = f7
|
||||
hotkey_toggle_mouse_to_gyro = f6
|
||||
hotkey_toggle_mouse_to_touchpad = delete
|
||||
hotkey_quit = lctrl, lshift, end
|
||||
)";
|
||||
}
|
||||
|
||||
@@ -9,6 +9,13 @@
|
||||
|
||||
namespace Config {
|
||||
|
||||
enum class ConfigMode {
|
||||
Default,
|
||||
Global,
|
||||
Clean,
|
||||
};
|
||||
void setConfigMode(ConfigMode mode);
|
||||
|
||||
struct GameInstallDir {
|
||||
std::filesystem::path path;
|
||||
bool enabled;
|
||||
@@ -20,6 +27,8 @@ void load(const std::filesystem::path& path, bool is_game_specific = false);
|
||||
void save(const std::filesystem::path& path, bool is_game_specific = false);
|
||||
void resetGameSpecificValue(std::string entry);
|
||||
|
||||
bool getGameRunning();
|
||||
void setGameRunning(bool running);
|
||||
int getVolumeSlider();
|
||||
void setVolumeSlider(int volumeValue, bool is_game_specific = false);
|
||||
std::string getTrophyKey();
|
||||
@@ -72,6 +81,10 @@ bool vkValidationEnabled();
|
||||
void setVkValidation(bool enable, bool is_game_specific = false);
|
||||
bool vkValidationSyncEnabled();
|
||||
void setVkSyncValidation(bool enable, bool is_game_specific = false);
|
||||
bool vkValidationGpuEnabled();
|
||||
void setVkGpuValidation(bool enable, bool is_game_specific = false);
|
||||
bool vkValidationCoreEnabled();
|
||||
void setVkCoreValidation(bool enable, bool is_game_specific = false);
|
||||
bool getVkCrashDiagnosticEnabled();
|
||||
void setVkCrashDiagnosticEnabled(bool enable, bool is_game_specific = false);
|
||||
bool getVkHostMarkersEnabled();
|
||||
@@ -81,7 +94,11 @@ void setVkGuestMarkersEnabled(bool enable, bool is_game_specific = false);
|
||||
bool getEnableDiscordRPC();
|
||||
void setEnableDiscordRPC(bool enable);
|
||||
bool isRdocEnabled();
|
||||
bool isPipelineCacheEnabled();
|
||||
bool isPipelineCacheArchived();
|
||||
void setRdocEnabled(bool enable, bool is_game_specific = false);
|
||||
void setPipelineCacheEnabled(bool enable, bool is_game_specific = false);
|
||||
void setPipelineCacheArchived(bool enable, bool is_game_specific = false);
|
||||
std::string getLogType();
|
||||
void setLogType(const std::string& type, bool is_game_specific = false);
|
||||
std::string getLogFilter();
|
||||
@@ -90,11 +107,10 @@ double getTrophyNotificationDuration();
|
||||
void setTrophyNotificationDuration(double newTrophyNotificationDuration,
|
||||
bool is_game_specific = false);
|
||||
int getCursorHideTimeout();
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
std::string getMainOutputDevice();
|
||||
void setMainOutputDevice(std::string device);
|
||||
void setMainOutputDevice(std::string device, bool is_game_specific = false);
|
||||
std::string getPadSpkOutputDevice();
|
||||
void setPadSpkOutputDevice(std::string device);
|
||||
void setPadSpkOutputDevice(std::string device, bool is_game_specific = false);
|
||||
std::string getMicDevice();
|
||||
void setCursorHideTimeout(int newcursorHideTimeout, bool is_game_specific = false);
|
||||
void setMicDevice(std::string device, bool is_game_specific = false);
|
||||
@@ -110,12 +126,15 @@ bool getPSNSignedIn();
|
||||
void setPSNSignedIn(bool sign, bool is_game_specific = false);
|
||||
bool patchShaders(); // no set
|
||||
bool fpsColor(); // no set
|
||||
bool getShowFpsCounter();
|
||||
void setShowFpsCounter(bool enable, bool is_game_specific = false);
|
||||
bool isNeoModeConsole();
|
||||
void setNeoMode(bool enable, bool is_game_specific = false);
|
||||
bool isDevKitConsole();
|
||||
void setDevKitConsole(bool enable, bool is_game_specific = false);
|
||||
|
||||
bool vkValidationGpuEnabled(); // no set
|
||||
int getExtraDmemInMbytes();
|
||||
void setExtraDmemInMbytes(int value, bool is_game_specific = false);
|
||||
bool getIsMotionControlsEnabled();
|
||||
void setIsMotionControlsEnabled(bool use, bool is_game_specific = false);
|
||||
std::string getDefaultControllerID();
|
||||
@@ -133,16 +152,18 @@ void setRcasAttenuation(int value, bool is_game_specific = false);
|
||||
bool getIsConnectedToNetwork();
|
||||
void setConnectedToNetwork(bool enable, bool is_game_specific = false);
|
||||
void setUserName(const std::string& name, bool is_game_specific = false);
|
||||
void setChooseHomeTab(const std::string& type, bool is_game_specific = false);
|
||||
std::filesystem::path getSysModulesPath();
|
||||
void setSysModulesPath(const std::filesystem::path& path);
|
||||
bool getLoadAutoPatches();
|
||||
void setLoadAutoPatches(bool enable);
|
||||
|
||||
enum UsbBackendType : int { Real, SkylandersPortal, InfinityBase, DimensionsToypad };
|
||||
int getUsbDeviceBackend();
|
||||
void setUsbDeviceBackend(int value, bool is_game_specific = false);
|
||||
|
||||
// TODO
|
||||
bool GetLoadGameSizeEnabled();
|
||||
std::filesystem::path GetSaveDataPath();
|
||||
void setLoadGameSizeEnabled(bool enable);
|
||||
bool getCompatibilityEnabled();
|
||||
bool getCheckCompatibilityOnStartup();
|
||||
std::string getUserName();
|
||||
std::string getChooseHomeTab();
|
||||
bool GetUseUnifiedInputConfig();
|
||||
void SetUseUnifiedInputConfig(bool use);
|
||||
bool GetOverrideControllerColor();
|
||||
@@ -152,8 +173,6 @@ void SetControllerCustomColor(int r, int b, int g);
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
|
||||
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
|
||||
void setSaveDataPath(const std::filesystem::path& path);
|
||||
void setCompatibilityEnabled(bool use);
|
||||
void setCheckCompatibilityOnStartup(bool use);
|
||||
// Gui
|
||||
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
|
||||
void removeGameInstallDir(const std::filesystem::path& dir);
|
||||
|
||||
@@ -68,6 +68,7 @@ class ElfInfo {
|
||||
std::string app_ver{};
|
||||
u32 firmware_ver = 0;
|
||||
u32 raw_firmware_ver = 0;
|
||||
u32 sdk_ver = 0;
|
||||
PSFAttributes psf_attributes{};
|
||||
|
||||
std::filesystem::path splash_path{};
|
||||
@@ -117,6 +118,11 @@ public:
|
||||
return raw_firmware_ver;
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 CompiledSdkVer() const {
|
||||
ASSERT(initialized);
|
||||
return sdk_ver;
|
||||
}
|
||||
|
||||
[[nodiscard]] const PSFAttributes& GetPSFAttributes() const {
|
||||
ASSERT(initialized);
|
||||
return psf_attributes;
|
||||
|
||||
@@ -40,28 +40,30 @@ namespace {
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return L"rb";
|
||||
case FileAccessMode::Write:
|
||||
return L"wb";
|
||||
case FileAccessMode::Append:
|
||||
return L"ab";
|
||||
case FileAccessMode::Write:
|
||||
case FileAccessMode::ReadWrite:
|
||||
return L"r+b";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return L"a+b";
|
||||
case FileAccessMode::Create:
|
||||
return L"wb";
|
||||
}
|
||||
break;
|
||||
case FileType::TextFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return L"r";
|
||||
case FileAccessMode::Write:
|
||||
return L"w";
|
||||
case FileAccessMode::Append:
|
||||
return L"a";
|
||||
case FileAccessMode::Write:
|
||||
case FileAccessMode::ReadWrite:
|
||||
return L"r+";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return L"a+";
|
||||
case FileAccessMode::Create:
|
||||
return L"w";
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -91,28 +93,30 @@ namespace {
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return "rb";
|
||||
case FileAccessMode::Write:
|
||||
return "wb";
|
||||
case FileAccessMode::Append:
|
||||
return "ab";
|
||||
case FileAccessMode::Write:
|
||||
case FileAccessMode::ReadWrite:
|
||||
return "r+b";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return "a+b";
|
||||
case FileAccessMode::Create:
|
||||
return "wb";
|
||||
}
|
||||
break;
|
||||
case FileType::TextFile:
|
||||
switch (mode) {
|
||||
case FileAccessMode::Read:
|
||||
return "r";
|
||||
case FileAccessMode::Write:
|
||||
return "w";
|
||||
case FileAccessMode::Append:
|
||||
return "a";
|
||||
case FileAccessMode::Write:
|
||||
case FileAccessMode::ReadWrite:
|
||||
return "r+";
|
||||
case FileAccessMode::ReadAppend:
|
||||
return "a+";
|
||||
case FileAccessMode::Create:
|
||||
return "w";
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,8 @@ enum class FileAccessMode {
|
||||
*/
|
||||
Read = 1 << 0,
|
||||
/**
|
||||
* If the file at path exists, the existing contents of the file are erased.
|
||||
* The empty file is then opened for writing.
|
||||
* If the file at path does not exist, it creates and opens a new empty file for writing.
|
||||
* If the file at path exists, it opens the file for writing.
|
||||
* If the file at path does not exist, it fails to open the file.
|
||||
*/
|
||||
Write = 1 << 1,
|
||||
/**
|
||||
@@ -42,6 +41,12 @@ enum class FileAccessMode {
|
||||
* reading and appending.
|
||||
*/
|
||||
ReadAppend = Read | Append,
|
||||
/**
|
||||
* If the file at path exists, the existing contents of the file are erased.
|
||||
* The empty file is then opened for writing.
|
||||
* If the file at path does not exist, it creates and opens a new empty file for writing.
|
||||
*/
|
||||
Create = 1 << 3,
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
|
||||
|
||||
@@ -102,6 +107,11 @@ public:
|
||||
return file != nullptr;
|
||||
}
|
||||
|
||||
bool IsWriteOnly() const {
|
||||
return file_access_mode == FileAccessMode::Append ||
|
||||
file_access_mode == FileAccessMode::Write;
|
||||
}
|
||||
|
||||
uintptr_t GetFileMapping();
|
||||
|
||||
int Open(const std::filesystem::path& path, FileAccessMode mode,
|
||||
@@ -210,7 +220,7 @@ public:
|
||||
}
|
||||
|
||||
static size_t WriteBytes(const std::filesystem::path path, const auto& data) {
|
||||
IOFile out(path, FileAccessMode::Write);
|
||||
IOFile out(path, FileAccessMode::Create);
|
||||
return out.Write(data);
|
||||
}
|
||||
std::FILE* file = nullptr;
|
||||
|
||||
@@ -61,8 +61,9 @@ private:
|
||||
*/
|
||||
class FileBackend {
|
||||
public:
|
||||
explicit FileBackend(const std::filesystem::path& filename)
|
||||
: file{filename, FS::FileAccessMode::Write, FS::FileType::TextFile} {}
|
||||
explicit FileBackend(const std::filesystem::path& filename, bool should_append = false)
|
||||
: file{filename, should_append ? FS::FileAccessMode::Append : FS::FileAccessMode::Create,
|
||||
FS::FileType::TextFile} {}
|
||||
|
||||
~FileBackend() = default;
|
||||
|
||||
@@ -145,6 +146,11 @@ public:
|
||||
initialization_in_progress_suppress_logging = false;
|
||||
}
|
||||
|
||||
static void ResetInstance() {
|
||||
initialization_in_progress_suppress_logging = true;
|
||||
instance.reset();
|
||||
}
|
||||
|
||||
static bool IsActive() {
|
||||
return instance != nullptr;
|
||||
}
|
||||
@@ -157,6 +163,10 @@ public:
|
||||
instance->StopBackendThread();
|
||||
}
|
||||
|
||||
static void SetAppend() {
|
||||
should_append = true;
|
||||
}
|
||||
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
|
||||
@@ -172,7 +182,13 @@ public:
|
||||
}
|
||||
|
||||
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
|
||||
const char* function, std::string message) {
|
||||
const char* function, const char* format, const fmt::format_args& args) {
|
||||
if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto message = fmt::vformat(format, args);
|
||||
|
||||
// Propagate important log messages to the profiler
|
||||
if (IsProfilerConnected()) {
|
||||
const auto& msg_str = fmt::format("[{}] {}", GetLogClassName(log_class), message);
|
||||
@@ -191,10 +207,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::steady_clock;
|
||||
@@ -218,7 +230,7 @@ public:
|
||||
|
||||
private:
|
||||
Impl(const std::filesystem::path& file_backend_filename, const Filter& filter_)
|
||||
: filter{filter_}, file_backend{file_backend_filename} {}
|
||||
: filter{filter_}, file_backend{file_backend_filename, should_append} {}
|
||||
|
||||
~Impl() = default;
|
||||
|
||||
@@ -264,6 +276,7 @@ private:
|
||||
}
|
||||
|
||||
static inline std::unique_ptr<Impl, decltype(&Deleter)> instance{nullptr, Deleter};
|
||||
static inline bool should_append{false};
|
||||
|
||||
Filter filter;
|
||||
DebuggerBackend debugger_backend{};
|
||||
@@ -292,6 +305,11 @@ void Stop() {
|
||||
Impl::Stop();
|
||||
}
|
||||
|
||||
void Denitializer() {
|
||||
Impl::Stop();
|
||||
Impl::ResetInstance();
|
||||
}
|
||||
|
||||
void SetGlobalFilter(const Filter& filter) {
|
||||
Impl::Instance().SetGlobalFilter(filter);
|
||||
}
|
||||
@@ -300,12 +318,16 @@ void SetColorConsoleBackendEnabled(bool enabled) {
|
||||
Impl::Instance().SetColorConsoleBackendEnabled(enabled);
|
||||
}
|
||||
|
||||
void SetAppend() {
|
||||
Impl::SetAppend();
|
||||
}
|
||||
|
||||
void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
|
||||
unsigned int line_num, const char* function, const char* format,
|
||||
const fmt::format_args& args) {
|
||||
if (!initialization_in_progress_suppress_logging) [[likely]] {
|
||||
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,
|
||||
fmt::vformat(format, args));
|
||||
Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, format,
|
||||
args);
|
||||
}
|
||||
}
|
||||
} // namespace Common::Log
|
||||
|
||||
@@ -21,9 +21,14 @@ void Start();
|
||||
/// Explictily stops the logger thread and flushes the buffers
|
||||
void Stop();
|
||||
|
||||
/// Closes log files and stops the logger
|
||||
void Denitializer();
|
||||
|
||||
/// The global filter will prevent any messages from even being processed if they are filtered.
|
||||
void SetGlobalFilter(const Filter& filter);
|
||||
|
||||
void SetColorConsoleBackendEnabled(bool enabled);
|
||||
|
||||
void SetAppend();
|
||||
|
||||
} // namespace Common::Log
|
||||
|
||||
@@ -104,11 +104,13 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Lib, Move) \
|
||||
SUB(Lib, NpAuth) \
|
||||
SUB(Lib, NpCommon) \
|
||||
SUB(Lib, NpCommerce) \
|
||||
SUB(Lib, NpManager) \
|
||||
SUB(Lib, NpScore) \
|
||||
SUB(Lib, NpTrophy) \
|
||||
SUB(Lib, NpWebApi) \
|
||||
SUB(Lib, NpProfileDialog) \
|
||||
SUB(Lib, NpSnsFacebookDialog) \
|
||||
SUB(Lib, Screenshot) \
|
||||
SUB(Lib, LibCInternal) \
|
||||
SUB(Lib, AppContent) \
|
||||
@@ -139,6 +141,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
||||
SUB(Lib, NpParty) \
|
||||
SUB(Lib, Zlib) \
|
||||
SUB(Lib, Hmd) \
|
||||
SUB(Lib, Font) \
|
||||
SUB(Lib, FontFt) \
|
||||
SUB(Lib, HmdSetupDialog) \
|
||||
SUB(Lib, SigninDialog) \
|
||||
SUB(Lib, Camera) \
|
||||
|
||||
@@ -29,99 +29,103 @@ enum class Level : u8 {
|
||||
* filter.cpp.
|
||||
*/
|
||||
enum class Class : u8 {
|
||||
Log, ///< Messages about the log system itself
|
||||
Common, ///< Library routines
|
||||
Common_Filesystem, ///< Filesystem interface library
|
||||
Common_Memory, ///< Memory mapping and management functions
|
||||
Core, ///< LLE emulation core
|
||||
Core_Linker, ///< The module linker
|
||||
Core_Devices, ///< Devices emulation
|
||||
Config, ///< Emulator configuration (including commandline)
|
||||
Debug, ///< Debugging tools
|
||||
Kernel, ///< The HLE implementation of the PS4 kernel.
|
||||
Kernel_Pthread, ///< The pthread implementation of the kernel.
|
||||
Kernel_Fs, ///< The filesystem implementation of the kernel.
|
||||
Kernel_Vmm, ///< The virtual memory implementation of the kernel.
|
||||
Kernel_Event, ///< The event management implementation of the kernel.
|
||||
Kernel_Sce, ///< The sony specific interfaces provided by the kernel.
|
||||
Lib, ///< HLE implementation of system library. Each major library
|
||||
///< should have its own subclass.
|
||||
Lib_LibC, ///< The LibC implementation.
|
||||
Lib_LibcInternal, ///< The LibcInternal implementation.
|
||||
Lib_Kernel, ///< The LibKernel implementation.
|
||||
Lib_Pad, ///< The LibScePad implementation.
|
||||
Lib_SystemGesture, ///< The LibSceSystemGesture implementation.
|
||||
Lib_GnmDriver, ///< The LibSceGnmDriver implementation.
|
||||
Lib_SystemService, ///< The LibSceSystemService implementation.
|
||||
Lib_UserService, ///< The LibSceUserService implementation.
|
||||
Lib_VideoOut, ///< The LibSceVideoOut implementation.
|
||||
Lib_CommonDlg, ///< The LibSceCommonDialog implementation.
|
||||
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
|
||||
Lib_AudioOut, ///< The LibSceAudioOut implementation.
|
||||
Lib_AudioIn, ///< The LibSceAudioIn implementation.
|
||||
Lib_Move, ///< The LibSceMove implementation.
|
||||
Lib_Net, ///< The LibSceNet implementation.
|
||||
Lib_NetCtl, ///< The LibSceNetCtl implementation.
|
||||
Lib_SaveData, ///< The LibSceSaveData implementation.
|
||||
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
|
||||
Lib_Ssl, ///< The LibSceSsl implementation.
|
||||
Lib_Ssl2, ///< The LibSceSsl2 implementation.
|
||||
Lib_Http, ///< The LibSceHttp implementation.
|
||||
Lib_Http2, ///< The LibSceHttp2 implementation.
|
||||
Lib_SysModule, ///< The LibSceSysModule implementation
|
||||
Lib_NpCommon, ///< The LibSceNpCommon implementation
|
||||
Lib_NpAuth, ///< The LibSceNpAuth implementation
|
||||
Lib_NpManager, ///< The LibSceNpManager implementation
|
||||
Lib_NpScore, ///< The LibSceNpScore implementation
|
||||
Lib_NpTrophy, ///< The LibSceNpTrophy implementation
|
||||
Lib_NpWebApi, ///< The LibSceWebApi implementation
|
||||
Lib_NpProfileDialog, ///< The LibSceNpProfileDialog implementation
|
||||
Lib_Screenshot, ///< The LibSceScreenshot implementation
|
||||
Lib_LibCInternal, ///< The LibCInternal implementation.
|
||||
Lib_AppContent, ///< The LibSceAppContent implementation.
|
||||
Lib_Rtc, ///< The LibSceRtc implementation.
|
||||
Lib_DiscMap, ///< The LibSceDiscMap implementation.
|
||||
Lib_Png, ///< The LibScePng implementation.
|
||||
Lib_Jpeg, ///< The LibSceJpeg implementation.
|
||||
Lib_PlayGo, ///< The LibScePlayGo implementation.
|
||||
Lib_PlayGoDialog, ///< The LibScePlayGoDialog implementation.
|
||||
Lib_Random, ///< The LibSceRandom implementation.
|
||||
Lib_Usbd, ///< The LibSceUsbd implementation.
|
||||
Lib_Ajm, ///< The LibSceAjm implementation.
|
||||
Lib_ErrorDialog, ///< The LibSceErrorDialog implementation.
|
||||
Lib_ImeDialog, ///< The LibSceImeDialog implementation.
|
||||
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
||||
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
||||
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
||||
Lib_Ime, ///< The LibSceIme implementation
|
||||
Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
|
||||
Lib_Remoteplay, ///< The LibSceRemotePlay implementation
|
||||
Lib_SharePlay, ///< The LibSceSharePlay implemenation
|
||||
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
||||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||
Lib_Voice, ///< The LibSceVoice implementation.
|
||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||
Lib_Mouse, ///< The LibSceMouse implementation
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Lib_HmdSetupDialog, ///< The LibSceHmdSetupDialog implementation.
|
||||
Lib_SigninDialog, ///< The LibSigninDialog implementation.
|
||||
Lib_Camera, ///< The LibCamera implementation.
|
||||
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
|
||||
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
|
||||
Lib_VrTracker, ///< The LibSceVrTracker implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
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
|
||||
Log, ///< Messages about the log system itself
|
||||
Common, ///< Library routines
|
||||
Common_Filesystem, ///< Filesystem interface library
|
||||
Common_Memory, ///< Memory mapping and management functions
|
||||
Core, ///< LLE emulation core
|
||||
Core_Linker, ///< The module linker
|
||||
Core_Devices, ///< Devices emulation
|
||||
Config, ///< Emulator configuration (including commandline)
|
||||
Debug, ///< Debugging tools
|
||||
Kernel, ///< The HLE implementation of the PS4 kernel.
|
||||
Kernel_Pthread, ///< The pthread implementation of the kernel.
|
||||
Kernel_Fs, ///< The filesystem implementation of the kernel.
|
||||
Kernel_Vmm, ///< The virtual memory implementation of the kernel.
|
||||
Kernel_Event, ///< The event management implementation of the kernel.
|
||||
Kernel_Sce, ///< The sony specific interfaces provided by the kernel.
|
||||
Lib, ///< HLE implementation of system library. Each major library
|
||||
///< should have its own subclass.
|
||||
Lib_LibC, ///< The LibC implementation.
|
||||
Lib_LibcInternal, ///< The LibcInternal implementation.
|
||||
Lib_Kernel, ///< The LibKernel implementation.
|
||||
Lib_Pad, ///< The LibScePad implementation.
|
||||
Lib_SystemGesture, ///< The LibSceSystemGesture implementation.
|
||||
Lib_GnmDriver, ///< The LibSceGnmDriver implementation.
|
||||
Lib_SystemService, ///< The LibSceSystemService implementation.
|
||||
Lib_UserService, ///< The LibSceUserService implementation.
|
||||
Lib_VideoOut, ///< The LibSceVideoOut implementation.
|
||||
Lib_CommonDlg, ///< The LibSceCommonDialog implementation.
|
||||
Lib_MsgDlg, ///< The LibSceMsgDialog implementation.
|
||||
Lib_AudioOut, ///< The LibSceAudioOut implementation.
|
||||
Lib_AudioIn, ///< The LibSceAudioIn implementation.
|
||||
Lib_Move, ///< The LibSceMove implementation.
|
||||
Lib_Net, ///< The LibSceNet implementation.
|
||||
Lib_NetCtl, ///< The LibSceNetCtl implementation.
|
||||
Lib_SaveData, ///< The LibSceSaveData implementation.
|
||||
Lib_SaveDataDialog, ///< The LibSceSaveDataDialog implementation.
|
||||
Lib_Ssl, ///< The LibSceSsl implementation.
|
||||
Lib_Ssl2, ///< The LibSceSsl2 implementation.
|
||||
Lib_Http, ///< The LibSceHttp implementation.
|
||||
Lib_Http2, ///< The LibSceHttp2 implementation.
|
||||
Lib_SysModule, ///< The LibSceSysModule implementation
|
||||
Lib_NpCommon, ///< The LibSceNpCommon implementation
|
||||
Lib_NpCommerce, ///< The LibSceNpCommerce implementation
|
||||
Lib_NpAuth, ///< The LibSceNpAuth implementation
|
||||
Lib_NpManager, ///< The LibSceNpManager implementation
|
||||
Lib_NpScore, ///< The LibSceNpScore implementation
|
||||
Lib_NpTrophy, ///< The LibSceNpTrophy implementation
|
||||
Lib_NpWebApi, ///< The LibSceWebApi implementation
|
||||
Lib_NpProfileDialog, ///< The LibSceNpProfileDialog implementation
|
||||
Lib_NpSnsFacebookDialog, ///< The LibSceNpSnsFacebookDialog implementation
|
||||
Lib_Screenshot, ///< The LibSceScreenshot implementation
|
||||
Lib_LibCInternal, ///< The LibCInternal implementation.
|
||||
Lib_AppContent, ///< The LibSceAppContent implementation.
|
||||
Lib_Rtc, ///< The LibSceRtc implementation.
|
||||
Lib_DiscMap, ///< The LibSceDiscMap implementation.
|
||||
Lib_Png, ///< The LibScePng implementation.
|
||||
Lib_Jpeg, ///< The LibSceJpeg implementation.
|
||||
Lib_PlayGo, ///< The LibScePlayGo implementation.
|
||||
Lib_PlayGoDialog, ///< The LibScePlayGoDialog implementation.
|
||||
Lib_Random, ///< The LibSceRandom implementation.
|
||||
Lib_Usbd, ///< The LibSceUsbd implementation.
|
||||
Lib_Ajm, ///< The LibSceAjm implementation.
|
||||
Lib_ErrorDialog, ///< The LibSceErrorDialog implementation.
|
||||
Lib_ImeDialog, ///< The LibSceImeDialog implementation.
|
||||
Lib_AvPlayer, ///< The LibSceAvPlayer implementation.
|
||||
Lib_Ngs2, ///< The LibSceNgs2 implementation.
|
||||
Lib_Audio3d, ///< The LibSceAudio3d implementation.
|
||||
Lib_Ime, ///< The LibSceIme implementation
|
||||
Lib_GameLiveStreaming, ///< The LibSceGameLiveStreaming implementation
|
||||
Lib_Remoteplay, ///< The LibSceRemotePlay implementation
|
||||
Lib_SharePlay, ///< The LibSceSharePlay implemenation
|
||||
Lib_Fiber, ///< The LibSceFiber implementation.
|
||||
Lib_Vdec2, ///< The LibSceVideodec2 implementation.
|
||||
Lib_Videodec, ///< The LibSceVideodec implementation.
|
||||
Lib_Voice, ///< The LibSceVoice implementation.
|
||||
Lib_RazorCpu, ///< The LibRazorCpu implementation.
|
||||
Lib_Mouse, ///< The LibSceMouse implementation
|
||||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Lib_HmdSetupDialog, ///< The LibSceHmdSetupDialog implementation.
|
||||
Lib_SigninDialog, ///< The LibSigninDialog implementation.
|
||||
Lib_Camera, ///< The LibCamera implementation.
|
||||
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
|
||||
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
|
||||
Lib_VrTracker, ///< The LibSceVrTracker implementation.
|
||||
Lib_Font, ///< The libSceFont implementation.
|
||||
Lib_FontFt, ///< The libSceFontFt implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
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
|
||||
|
||||
@@ -3,20 +3,12 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <codecvt>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <pugixml.hpp>
|
||||
#ifdef ENABLE_QT_GUI
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QListView>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QXmlStreamReader>
|
||||
#endif
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
@@ -28,7 +20,7 @@ namespace MemoryPatcher {
|
||||
EXPORT uintptr_t g_eboot_address;
|
||||
uint64_t g_eboot_image_size;
|
||||
std::string g_game_serial;
|
||||
std::string patchFile;
|
||||
std::string patch_file;
|
||||
bool patches_applied = false;
|
||||
std::vector<patchInfo> pending_patches;
|
||||
|
||||
@@ -122,256 +114,104 @@ std::string convertValueToHex(const std::string type, const std::string valueStr
|
||||
|
||||
void ApplyPendingPatches();
|
||||
|
||||
void OnGameLoaded() {
|
||||
if (!patchFile.empty()) {
|
||||
std::filesystem::path patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
|
||||
void ApplyPatchesFromXML(std::filesystem::path path) {
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result result = doc.load_file(path.c_str());
|
||||
|
||||
auto filePath = (patchDir / patchFile).native();
|
||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||
|
||||
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) {
|
||||
|
||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||
if (std::string(it->name()) == "Metadata") {
|
||||
if (std::string(it->attribute("isEnabled").value()) == "true") {
|
||||
std::string currentPatchName = it->attribute("Name").value();
|
||||
std::string metadataAppVer = it->attribute("AppVer").value();
|
||||
bool versionMatches = metadataAppVer == app_version;
|
||||
|
||||
if (result) {
|
||||
auto patchXML = doc.child("Patch");
|
||||
for (pugi::xml_node_iterator it = patchXML.children().begin();
|
||||
it != patchXML.children().end(); ++it) {
|
||||
auto patchList = it->first_child();
|
||||
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
|
||||
patchLineIt != patchList.children().end(); ++patchLineIt) {
|
||||
|
||||
if (std::string(it->name()) == "Metadata") {
|
||||
if (std::string(it->attribute("isEnabled").value()) == "true") {
|
||||
std::string currentPatchName = it->attribute("Name").value();
|
||||
std::string metadataAppVer = it->attribute("AppVer").value();
|
||||
bool versionMatches = metadataAppVer == app_version;
|
||||
std::string type = patchLineIt->attribute("Type").value();
|
||||
if (!versionMatches && type != "mask" && type != "mask_jump32")
|
||||
continue;
|
||||
|
||||
auto patchList = it->first_child();
|
||||
for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
|
||||
patchLineIt != patchList.children().end(); ++patchLineIt) {
|
||||
|
||||
std::string type = patchLineIt->attribute("Type").value();
|
||||
if (!versionMatches && type != "mask" && type != "mask_jump32")
|
||||
continue;
|
||||
|
||||
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("Offset").value();
|
||||
std::string targetStr = "";
|
||||
std::string sizeStr = "";
|
||||
if (type == "mask_jump32") {
|
||||
targetStr = patchLineIt->attribute("Target").value();
|
||||
sizeStr = patchLineIt->attribute("Size").value();
|
||||
} else {
|
||||
patchValue = convertValueToHex(type, patchValue);
|
||||
}
|
||||
|
||||
bool littleEndian = false;
|
||||
|
||||
if (type == "bytes16" || type == "bytes32" || type == "bytes64") {
|
||||
littleEndian = true;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
if ((type == "mask" || type == "mask_jump32") &&
|
||||
!maskOffsetStr.empty()) {
|
||||
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue,
|
||||
targetStr, sizeStr, false, littleEndian,
|
||||
patchMask, maskOffsetValue);
|
||||
}
|
||||
std::string address = patchLineIt->attribute("Address").value();
|
||||
std::string patchValue = patchLineIt->attribute("Value").value();
|
||||
std::string maskOffsetStr = patchLineIt->attribute("Offset").value();
|
||||
std::string targetStr = "";
|
||||
std::string sizeStr = "";
|
||||
if (type == "mask_jump32") {
|
||||
targetStr = patchLineIt->attribute("Target").value();
|
||||
sizeStr = patchLineIt->attribute("Size").value();
|
||||
} else {
|
||||
patchValue = convertValueToHex(type, patchValue);
|
||||
}
|
||||
|
||||
bool littleEndian = false;
|
||||
if (type == "bytes16" || type == "bytes32" || type == "bytes64") {
|
||||
littleEndian = true;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
if ((type == "mask" || type == "mask_jump32") && !maskOffsetStr.empty()) {
|
||||
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, targetStr,
|
||||
sizeStr, false, littleEndian, patchMask,
|
||||
maskOffsetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR(Loader, "Could not parse patch XML: {}", result.description());
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameLoaded() {
|
||||
std::filesystem::path patch_dir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir);
|
||||
if (!patch_file.empty()) {
|
||||
|
||||
auto file_path = (patch_dir / patch_file).native();
|
||||
if (std::filesystem::exists(patch_file)) {
|
||||
ApplyPatchesFromXML(patch_file);
|
||||
} else {
|
||||
LOG_ERROR(Loader, "couldnt patch parse xml : {}", result.description());
|
||||
ApplyPatchesFromXML(file_path);
|
||||
}
|
||||
} else if (Config::getLoadAutoPatches()) {
|
||||
for (auto const& repo : std::filesystem::directory_iterator(patch_dir)) {
|
||||
if (!repo.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
std::ifstream json_file{repo.path() / "files.json"};
|
||||
nlohmann::json available_patches = nlohmann::json::parse(json_file);
|
||||
std::filesystem::path game_patch_file;
|
||||
for (auto const& [filename, serials] : available_patches.items()) {
|
||||
if (std::find(serials.begin(), serials.end(), g_game_serial) != serials.end()) {
|
||||
game_patch_file = repo.path() / filename;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (std::filesystem::exists(game_patch_file)) {
|
||||
ApplyPatchesFromXML(game_patch_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
ApplyPendingPatches();
|
||||
|
||||
#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));
|
||||
QDir dir(patchDir);
|
||||
QStringList folders = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||
|
||||
for (const QString& folder : folders) {
|
||||
QString filesJsonPath = patchDir + "/" + folder + "/files.json";
|
||||
|
||||
QFile jsonFile(filesJsonPath);
|
||||
if (!jsonFile.open(QIODevice::ReadOnly)) {
|
||||
LOG_ERROR(Loader, "Unable to open files.json for reading in repository {}",
|
||||
folder.toStdString());
|
||||
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 in repository {}",
|
||||
folder.toStdString());
|
||||
continue;
|
||||
}
|
||||
|
||||
QString filePath = patchDir + "/" + folder + "/" + 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 isEnabled = false;
|
||||
std::string currentPatchName;
|
||||
|
||||
auto* param_sfo = Common::Singleton<PSF>::Instance();
|
||||
auto app_version = param_sfo->GetString("APP_VER").value_or("Unknown version");
|
||||
bool versionMatches = true;
|
||||
|
||||
while (!xmlReader.atEnd()) {
|
||||
xmlReader.readNext();
|
||||
|
||||
if (xmlReader.isStartElement()) {
|
||||
QJsonArray patchLines;
|
||||
if (xmlReader.name() == QStringLiteral("Metadata")) {
|
||||
QString name = xmlReader.attributes().value("Name").toString();
|
||||
currentPatchName = name.toStdString();
|
||||
|
||||
QString appVer = xmlReader.attributes().value("AppVer").toString();
|
||||
|
||||
// Check and update the isEnabled attribute
|
||||
isEnabled = false;
|
||||
for (const QXmlStreamAttribute& attr : xmlReader.attributes()) {
|
||||
if (attr.name() == QStringLiteral("isEnabled")) {
|
||||
isEnabled = (attr.value().toString() == "true");
|
||||
}
|
||||
}
|
||||
versionMatches = (appVer.toStdString() == app_version);
|
||||
|
||||
} 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();
|
||||
lineObject["Offset"] = attributes.value("Offset").toString();
|
||||
if (lineObject["Type"].toString() == "mask_jump32") {
|
||||
lineObject["Target"] = attributes.value("Target").toString();
|
||||
lineObject["Size"] = attributes.value("Size").toString();
|
||||
}
|
||||
linesArray.append(lineObject);
|
||||
}
|
||||
}
|
||||
|
||||
patchLines = linesArray;
|
||||
if (isEnabled) {
|
||||
foreach (const QJsonValue& value, patchLines) {
|
||||
QJsonObject lineObject = value.toObject();
|
||||
QString type = lineObject["Type"].toString();
|
||||
|
||||
if ((type != "mask" && type != "mask_jump32") && !versionMatches)
|
||||
continue;
|
||||
|
||||
QString address = lineObject["Address"].toString();
|
||||
QString patchValue = lineObject["Value"].toString();
|
||||
QString maskOffsetStr = lineObject["Offset"].toString();
|
||||
|
||||
QString targetStr;
|
||||
QString sizeStr;
|
||||
|
||||
if (type == "mask_jump32") {
|
||||
targetStr = lineObject["Target"].toString();
|
||||
sizeStr = lineObject["Size"].toString();
|
||||
} else {
|
||||
patchValue = QString::fromStdString(convertValueToHex(
|
||||
type.toStdString(), patchValue.toStdString()));
|
||||
}
|
||||
|
||||
bool littleEndian = false;
|
||||
|
||||
if (type == "bytes16" || type == "bytes32" || type == "bytes64")
|
||||
littleEndian = true;
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
if ((type == "mask" || type == "mask_jump32") &&
|
||||
!maskOffsetStr.toStdString().empty()) {
|
||||
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMemory(
|
||||
currentPatchName, address.toStdString(), patchValue.toStdString(),
|
||||
targetStr.toStdString(), sizeStr.toStdString(), false, littleEndian,
|
||||
patchMask, maskOffsetValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlReader.hasError()) {
|
||||
LOG_ERROR(Loader, "Failed to parse XML for {}", g_game_serial);
|
||||
} else {
|
||||
LOG_INFO(Loader, "Patches loaded successfully, repository: {}", folder.toStdString());
|
||||
}
|
||||
ApplyPendingPatches();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void AddPatchToQueue(patchInfo patchToAdd) {
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MemoryPatcher {
|
||||
extern EXPORT uintptr_t g_eboot_address;
|
||||
extern uint64_t g_eboot_image_size;
|
||||
extern std::string g_game_serial;
|
||||
extern std::string patchFile;
|
||||
extern std::string patch_file;
|
||||
|
||||
enum PatchMask : uint8_t {
|
||||
None,
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
// 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
|
||||
constexpr u32 UF11_EXPONENT_SHIFT = 6;
|
||||
constexpr u32 UF10_EXPONENT_SHIFT = 5;
|
||||
constexpr u32 RGB9E5_MANTISSA_BITS = 9;
|
||||
constexpr u32 RGB9E5_EXP_BIAS = 1;
|
||||
constexpr u32 F32_INFINITY = 0x7f800000;
|
||||
|
||||
namespace NumberUtils {
|
||||
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
#include <QString>
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
@@ -88,13 +84,6 @@ static std::optional<std::filesystem::path> GetBundleParentDirectory() {
|
||||
#endif
|
||||
|
||||
static auto UserPaths = [] {
|
||||
#if defined(__APPLE__) && defined(ENABLE_QT_GUI)
|
||||
// Set the current path to the directory containing the app bundle.
|
||||
if (const auto bundle_dir = GetBundleParentDirectory()) {
|
||||
std::filesystem::current_path(*bundle_dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try the portable user directory first.
|
||||
auto user_dir = std::filesystem::current_path() / PORTABLE_DIR;
|
||||
if (!std::filesystem::exists(user_dir)) {
|
||||
@@ -138,6 +127,7 @@ static auto UserPaths = [] {
|
||||
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
|
||||
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY);
|
||||
create_path(PathType::CustomConfigs, user_dir / CUSTOM_CONFIGS);
|
||||
create_path(PathType::CacheDir, user_dir / CACHE_DIR);
|
||||
|
||||
std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt");
|
||||
if (notice_file.is_open()) {
|
||||
@@ -229,22 +219,4 @@ std::optional<fs::path> FindGameByID(const fs::path& dir, const std::string& gam
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
@@ -7,10 +7,6 @@
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
class QString; // to avoid including <QString> in this header
|
||||
#endif
|
||||
|
||||
namespace Common::FS {
|
||||
|
||||
enum class PathType {
|
||||
@@ -28,6 +24,7 @@ enum class PathType {
|
||||
MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored.
|
||||
CustomTrophy, // Where custom files for trophies are stored.
|
||||
CustomConfigs, // Where custom files for different games are stored.
|
||||
CacheDir, // Where pipeline and shader cache is stored.
|
||||
};
|
||||
|
||||
constexpr auto PORTABLE_DIR = "user";
|
||||
@@ -46,6 +43,7 @@ constexpr auto PATCHES_DIR = "patches";
|
||||
constexpr auto METADATA_DIR = "game_data";
|
||||
constexpr auto CUSTOM_TROPHY = "custom_trophy";
|
||||
constexpr auto CUSTOM_CONFIGS = "custom_configs";
|
||||
constexpr auto CACHE_DIR = "cache";
|
||||
|
||||
// Filenames
|
||||
constexpr auto LOG_FILE = "shad_log.txt";
|
||||
@@ -99,25 +97,6 @@ constexpr auto LOG_FILE = "shad_log.txt";
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
* Recursively searches for a game directory by its ID.
|
||||
* Limits search depth to prevent excessive filesystem traversal.
|
||||
|
||||
140
src/common/serdes.h
Normal file
140
src/common/serdes.h
Normal file
@@ -0,0 +1,140 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace Serialization {
|
||||
|
||||
template <typename T>
|
||||
concept Container = requires(T t) {
|
||||
typename T::iterator;
|
||||
{ t.begin() } -> std::same_as<typename T::iterator>;
|
||||
{ t.end() } -> std::same_as<typename T::iterator>;
|
||||
{ t.size() } -> std::convertible_to<std::size_t>;
|
||||
};
|
||||
|
||||
struct Archive {
|
||||
void Alloc(size_t size) {
|
||||
container.resize(size);
|
||||
}
|
||||
|
||||
void Grow(size_t size) {
|
||||
container.resize(container.size() + size);
|
||||
}
|
||||
|
||||
void Merge(const Archive& ar) {
|
||||
container.insert(container.end(), ar.container.cbegin(), ar.container.cend());
|
||||
offset = container.size();
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t SizeBytes() const {
|
||||
return container.size();
|
||||
}
|
||||
|
||||
u8* CurrPtr() {
|
||||
return container.data() + offset;
|
||||
}
|
||||
|
||||
void Advance(size_t size) {
|
||||
ASSERT(offset + size <= container.size());
|
||||
offset += size;
|
||||
}
|
||||
|
||||
std::vector<u8>&& TakeOff() {
|
||||
offset = 0;
|
||||
return std::move(container);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsEoS() const {
|
||||
return offset >= container.size();
|
||||
}
|
||||
|
||||
Archive() = default;
|
||||
explicit Archive(std::vector<u8>&& v) : container{v} {}
|
||||
|
||||
private:
|
||||
u32 offset{};
|
||||
std::vector<u8> container{};
|
||||
|
||||
friend struct Writer;
|
||||
friend struct Reader;
|
||||
};
|
||||
|
||||
struct Writer {
|
||||
template <typename T>
|
||||
void Write(const T* ptr, size_t size) {
|
||||
if (ar.offset + size >= ar.container.size()) {
|
||||
ar.Grow(size);
|
||||
}
|
||||
std::memcpy(ar.CurrPtr(), reinterpret_cast<const void*>(ptr), size);
|
||||
ar.Advance(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(!Container<T>)
|
||||
void Write(const T& value) {
|
||||
const auto size = sizeof(value);
|
||||
Write(&value, size);
|
||||
}
|
||||
|
||||
void Write(const auto& v) {
|
||||
Write(v.size());
|
||||
for (const auto& elem : v) {
|
||||
Write(elem);
|
||||
}
|
||||
}
|
||||
|
||||
void Write(const std::string& s) {
|
||||
Write(s.size());
|
||||
Write(s.c_str(), s.size());
|
||||
}
|
||||
|
||||
Writer() = delete;
|
||||
explicit Writer(Archive& ar_) : ar{ar_} {}
|
||||
|
||||
Archive& ar;
|
||||
};
|
||||
|
||||
struct Reader {
|
||||
template <typename T>
|
||||
void Read(T* ptr, size_t size) {
|
||||
ASSERT(ar.offset + size <= ar.container.size());
|
||||
std::memcpy(reinterpret_cast<void*>(ptr), ar.CurrPtr(), size);
|
||||
ar.Advance(size);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
requires(!Container<T>)
|
||||
void Read(T& value) {
|
||||
const auto size = sizeof(value);
|
||||
Read(&value, size);
|
||||
}
|
||||
|
||||
void Read(auto& v) {
|
||||
size_t num_elements{};
|
||||
Read(num_elements);
|
||||
for (int i = 0; i < num_elements; ++i) {
|
||||
v.emplace_back();
|
||||
Read(v.back());
|
||||
}
|
||||
}
|
||||
|
||||
void Read(std::string& s) {
|
||||
size_t length{};
|
||||
Read(length);
|
||||
s.resize(length);
|
||||
Read(s.data(), length);
|
||||
}
|
||||
|
||||
Reader() = delete;
|
||||
explicit Reader(Archive& ar_) : ar{ar_} {}
|
||||
|
||||
Archive& ar;
|
||||
};
|
||||
|
||||
} // namespace Serialization
|
||||
@@ -2,10 +2,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <map>
|
||||
#include <boost/icl/separate_interval_set.hpp>
|
||||
#include "common/alignment.h"
|
||||
#include "common/arch.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/error.h"
|
||||
#include "core/address_space.h"
|
||||
#include "core/libraries/kernel/memory.h"
|
||||
@@ -23,22 +24,70 @@
|
||||
// Reserve space for the system address space using a zerofill section.
|
||||
asm(".zerofill SYSTEM_MANAGED,SYSTEM_MANAGED,__SYSTEM_MANAGED,0x7FFBFC000");
|
||||
asm(".zerofill SYSTEM_RESERVED,SYSTEM_RESERVED,__SYSTEM_RESERVED,0x7C0004000");
|
||||
asm(".zerofill USER_AREA,USER_AREA,__USER_AREA,0x5F9000000000");
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
|
||||
static constexpr size_t BackingSize = SCE_KERNEL_TOTAL_MEM_PRO;
|
||||
// Constants used for mapping address space.
|
||||
constexpr VAddr SYSTEM_MANAGED_MIN = 0x400000ULL;
|
||||
constexpr VAddr SYSTEM_MANAGED_MAX = 0x7FFFFBFFFULL;
|
||||
constexpr VAddr SYSTEM_RESERVED_MIN = 0x7FFFFC000ULL;
|
||||
#if defined(__APPLE__) && defined(ARCH_X86_64)
|
||||
// Commpage ranges from 0xFC0000000 - 0xFFFFFFFFF, so decrease the system reserved maximum.
|
||||
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFBFFFFFFFULL;
|
||||
// GPU-reserved memory ranges from 0x1000000000 - 0x6FFFFFFFFF, so increase the user minimum.
|
||||
constexpr VAddr USER_MIN = 0x7000000000ULL;
|
||||
#else
|
||||
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFFFFFFFFFULL;
|
||||
constexpr VAddr USER_MIN = 0x1000000000ULL;
|
||||
#endif
|
||||
#if defined(__linux__)
|
||||
// Linux maps the shadPS4 executable around here, so limit the user maximum
|
||||
constexpr VAddr USER_MAX = 0x54FFFFFFFFFFULL;
|
||||
#else
|
||||
constexpr VAddr USER_MAX = 0x5FFFFFFFFFFFULL;
|
||||
#endif
|
||||
|
||||
// Constants for the sizes of the ranges in address space.
|
||||
static constexpr u64 SystemManagedSize = SYSTEM_MANAGED_MAX - SYSTEM_MANAGED_MIN + 1;
|
||||
static constexpr u64 SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_MIN + 1;
|
||||
static constexpr u64 UserSize = USER_MAX - USER_MIN + 1;
|
||||
|
||||
// Required backing file size for mapping physical address space.
|
||||
static u64 BackingSize = ORBIS_KERNEL_TOTAL_MEM_DEV_PRO;
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
[[nodiscard]] constexpr u64 ToWindowsProt(Core::MemoryProt prot) {
|
||||
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
|
||||
True(prot & Core::MemoryProt::GpuReadWrite)) {
|
||||
return PAGE_READWRITE;
|
||||
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
|
||||
return PAGE_READONLY;
|
||||
const bool read =
|
||||
True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead);
|
||||
const bool write =
|
||||
True(prot & Core::MemoryProt::CpuWrite) || True(prot & Core::MemoryProt::GpuWrite);
|
||||
const bool execute = True(prot & Core::MemoryProt::CpuExec);
|
||||
|
||||
if (write && !read) {
|
||||
// While write-only CPU mappings aren't possible, write-only GPU mappings are.
|
||||
LOG_WARNING(Core, "Converting write-only mapping to read-write");
|
||||
}
|
||||
|
||||
// All cases involving execute permissions have separate permissions.
|
||||
if (execute) {
|
||||
if (write) {
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
return PAGE_EXECUTE_READ;
|
||||
} else {
|
||||
return PAGE_EXECUTE;
|
||||
}
|
||||
} else {
|
||||
return PAGE_NOACCESS;
|
||||
if (write) {
|
||||
return PAGE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
return PAGE_READONLY;
|
||||
} else {
|
||||
return PAGE_NOACCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,70 +99,108 @@ struct MemoryRegion {
|
||||
|
||||
struct AddressSpace::Impl {
|
||||
Impl() : process{GetCurrentProcess()} {
|
||||
// Allocate virtual address placeholder for our address space.
|
||||
MEM_ADDRESS_REQUIREMENTS req{};
|
||||
MEM_EXTENDED_PARAMETER param{};
|
||||
req.LowestStartingAddress = reinterpret_cast<PVOID>(SYSTEM_MANAGED_MIN);
|
||||
// The ending address must align to page boundary - 1
|
||||
// https://stackoverflow.com/questions/54223343/virtualalloc2-with-memextendedparameteraddressrequirements-always-produces-error
|
||||
req.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MIN + UserSize - 1);
|
||||
req.Alignment = 0;
|
||||
param.Type = MemExtendedParameterAddressRequirements;
|
||||
param.Pointer = &req;
|
||||
// Determine the system's page alignment
|
||||
SYSTEM_INFO sys_info{};
|
||||
GetSystemInfo(&sys_info);
|
||||
u64 alignment = sys_info.dwAllocationGranularity;
|
||||
|
||||
// Typically, lower parts of system managed area is already reserved in windows.
|
||||
// If reservation fails attempt again by reducing the area size a little bit.
|
||||
// System managed is about 31GB in size so also cap the number of times we can reduce it
|
||||
// to a reasonable amount.
|
||||
static constexpr size_t ReductionOnFail = 1_GB;
|
||||
static constexpr size_t MaxReductions = 10;
|
||||
// Older Windows builds have a severe performance issue with VirtualAlloc2.
|
||||
// We need to get the host's Windows version, then determine if it needs a workaround.
|
||||
auto ntdll_handle = GetModuleHandleW(L"ntdll.dll");
|
||||
ASSERT_MSG(ntdll_handle, "Failed to retrieve ntdll handle");
|
||||
|
||||
size_t virtual_size = SystemManagedSize + SystemReservedSize + UserSize;
|
||||
for (u32 i = 0; i < MaxReductions; i++) {
|
||||
virtual_base = static_cast<u8*>(VirtualAlloc2(process, NULL, virtual_size,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||
PAGE_NOACCESS, ¶m, 1));
|
||||
if (virtual_base) {
|
||||
break;
|
||||
// Get the RtlGetVersion function
|
||||
s64(WINAPI * RtlGetVersion)(LPOSVERSIONINFOW);
|
||||
*(FARPROC*)&RtlGetVersion = GetProcAddress(ntdll_handle, "RtlGetVersion");
|
||||
ASSERT_MSG(RtlGetVersion, "failed to retrieve function pointer for RtlGetVersion");
|
||||
|
||||
// Call RtlGetVersion
|
||||
RTL_OSVERSIONINFOW os_version_info{};
|
||||
RtlGetVersion(&os_version_info);
|
||||
|
||||
u64 supported_user_max = USER_MAX;
|
||||
// This is the build number for Windows 11 22H2
|
||||
static constexpr s32 AffectedBuildNumber = 22621;
|
||||
|
||||
// Higher PS4 firmware versions prevent higher address mappings too.
|
||||
s32 sdk_ver = Common::ElfInfo::Instance().CompiledSdkVer();
|
||||
if (os_version_info.dwBuildNumber <= AffectedBuildNumber ||
|
||||
sdk_ver >= Common::ElfInfo::FW_30) {
|
||||
supported_user_max = 0x10000000000ULL;
|
||||
// Only log the message if we're restricting the user max due to operating system.
|
||||
// Since higher compiled SDK versions also get reduced max, we don't need to log there.
|
||||
if (sdk_ver < Common::ElfInfo::FW_30) {
|
||||
LOG_WARNING(
|
||||
Core,
|
||||
"Older Windows version detected, reducing user max to {:#x} to avoid problems",
|
||||
supported_user_max);
|
||||
}
|
||||
virtual_size -= ReductionOnFail;
|
||||
}
|
||||
ASSERT_MSG(virtual_base, "Unable to reserve virtual address space: {}",
|
||||
Common::GetLastErrorMsg());
|
||||
|
||||
// Determine the free address ranges we can access.
|
||||
VAddr next_addr = SYSTEM_MANAGED_MIN;
|
||||
MEMORY_BASIC_INFORMATION info{};
|
||||
while (next_addr <= supported_user_max) {
|
||||
ASSERT_MSG(VirtualQuery(reinterpret_cast<PVOID>(next_addr), &info, sizeof(info)),
|
||||
"Failed to query memory information for address {:#x}", next_addr);
|
||||
|
||||
// Ensure logic uses values aligned to bage boundaries.
|
||||
next_addr = reinterpret_cast<VAddr>(info.BaseAddress) + info.RegionSize;
|
||||
next_addr = Common::AlignUp(next_addr, alignment);
|
||||
|
||||
// Prevent size from going past supported_user_max
|
||||
u64 size = info.RegionSize;
|
||||
if (next_addr > supported_user_max) {
|
||||
size -= (next_addr - supported_user_max);
|
||||
}
|
||||
size = Common::AlignDown(size, alignment);
|
||||
|
||||
// Check for free memory areas
|
||||
// Restrict region size to avoid overly fragmenting the virtual memory space.
|
||||
if (info.State == MEM_FREE && info.RegionSize > 0x1000000) {
|
||||
VAddr addr = Common::AlignUp(reinterpret_cast<VAddr>(info.BaseAddress), alignment);
|
||||
regions.emplace(addr, MemoryRegion{addr, size, false});
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve all detected free regions.
|
||||
for (auto region : regions) {
|
||||
auto addr = static_cast<u8*>(VirtualAlloc2(
|
||||
process, reinterpret_cast<PVOID>(region.second.base), region.second.size,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, NULL, 0));
|
||||
// All marked regions should reserve fine since they're free.
|
||||
ASSERT_MSG(addr, "Unable to reserve virtual address space: {}",
|
||||
Common::GetLastErrorMsg());
|
||||
}
|
||||
|
||||
// Set these constants to ensure code relying on them works.
|
||||
// These do not fully encapsulate the state of the address space.
|
||||
system_managed_base = reinterpret_cast<u8*>(regions.begin()->first);
|
||||
system_managed_size = SystemManagedSize - (regions.begin()->first - SYSTEM_MANAGED_MIN);
|
||||
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
|
||||
system_reserved_size = SystemReservedSize;
|
||||
system_managed_base = virtual_base;
|
||||
system_managed_size = system_reserved_base - virtual_base;
|
||||
user_base = reinterpret_cast<u8*>(USER_MIN);
|
||||
user_size = virtual_base + virtual_size - user_base;
|
||||
user_size = supported_user_max - USER_MIN - 1;
|
||||
|
||||
LOG_INFO(Kernel_Vmm, "System managed virtual memory region: {} - {}",
|
||||
fmt::ptr(system_managed_base),
|
||||
fmt::ptr(system_managed_base + system_managed_size - 1));
|
||||
LOG_INFO(Kernel_Vmm, "System reserved virtual memory region: {} - {}",
|
||||
fmt::ptr(system_reserved_base),
|
||||
fmt::ptr(system_reserved_base + system_reserved_size - 1));
|
||||
LOG_INFO(Kernel_Vmm, "User virtual memory region: {} - {}", fmt::ptr(user_base),
|
||||
fmt::ptr(user_base + user_size - 1));
|
||||
|
||||
// Initializer placeholder tracker
|
||||
const uintptr_t system_managed_addr = reinterpret_cast<uintptr_t>(system_managed_base);
|
||||
regions.emplace(system_managed_addr,
|
||||
MemoryRegion{system_managed_addr, virtual_size, false});
|
||||
// Increase BackingSize to account for config options.
|
||||
BackingSize += Config::getExtraDmemInMbytes() * 1_MB;
|
||||
|
||||
// Allocate backing file that represents the total physical memory.
|
||||
backing_handle =
|
||||
CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_WRITE | FILE_MAP_READ,
|
||||
PAGE_READWRITE, SEC_COMMIT, BackingSize, nullptr, nullptr, 0);
|
||||
backing_handle = CreateFileMapping2(INVALID_HANDLE_VALUE, nullptr, FILE_MAP_ALL_ACCESS,
|
||||
PAGE_EXECUTE_READWRITE, SEC_COMMIT, BackingSize,
|
||||
nullptr, nullptr, 0);
|
||||
|
||||
ASSERT_MSG(backing_handle, "{}", Common::GetLastErrorMsg());
|
||||
// Allocate a virtual memory for the backing file map as placeholder
|
||||
backing_base = static_cast<u8*>(VirtualAlloc2(process, nullptr, BackingSize,
|
||||
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
|
||||
PAGE_NOACCESS, nullptr, 0));
|
||||
ASSERT_MSG(backing_base, "{}", Common::GetLastErrorMsg());
|
||||
|
||||
// Map backing placeholder. This will commit the pages
|
||||
void* const ret = MapViewOfFile3(backing_handle, process, backing_base, 0, BackingSize,
|
||||
MEM_REPLACE_PLACEHOLDER, PAGE_READWRITE, nullptr, 0);
|
||||
void* const ret =
|
||||
MapViewOfFile3(backing_handle, process, backing_base, 0, BackingSize,
|
||||
MEM_REPLACE_PLACEHOLDER, PAGE_EXECUTE_READWRITE, nullptr, 0);
|
||||
ASSERT_MSG(ret == backing_base, "{}", Common::GetLastErrorMsg());
|
||||
}
|
||||
|
||||
@@ -154,7 +241,12 @@ struct AddressSpace::Impl {
|
||||
ASSERT_MSG(ret, "VirtualProtect failed. {}", Common::GetLastErrorMsg());
|
||||
} else {
|
||||
ptr = MapViewOfFile3(backing, process, reinterpret_cast<PVOID>(virtual_addr),
|
||||
phys_addr, size, MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0);
|
||||
phys_addr, size, MEM_REPLACE_PLACEHOLDER,
|
||||
PAGE_EXECUTE_READWRITE, nullptr, 0);
|
||||
ASSERT_MSG(ptr, "MapViewOfFile3 failed. {}", Common::GetLastErrorMsg());
|
||||
DWORD resultvar;
|
||||
bool ret = VirtualProtect(ptr, size, prot, &resultvar);
|
||||
ASSERT_MSG(ret, "VirtualProtect failed. {}", Common::GetLastErrorMsg());
|
||||
}
|
||||
} else {
|
||||
ptr =
|
||||
@@ -296,17 +388,33 @@ struct AddressSpace::Impl {
|
||||
void Protect(VAddr virtual_addr, size_t size, bool read, bool write, bool execute) {
|
||||
DWORD new_flags{};
|
||||
|
||||
if (read && write && execute) {
|
||||
new_flags = PAGE_EXECUTE_READWRITE;
|
||||
} else if (read && write) {
|
||||
new_flags = PAGE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
new_flags = PAGE_READONLY;
|
||||
} else if (execute && !read && !write) {
|
||||
new_flags = PAGE_EXECUTE;
|
||||
} else if (!read && !write && !execute) {
|
||||
new_flags = PAGE_NOACCESS;
|
||||
if (write && !read) {
|
||||
// While write-only CPU protection isn't possible, write-only GPU protection is.
|
||||
LOG_WARNING(Core, "Converting write-only protection to read-write");
|
||||
}
|
||||
|
||||
// All cases involving execute permissions have separate permissions.
|
||||
if (execute) {
|
||||
// If there's some form of write protection requested, provide read-write permissions.
|
||||
if (write) {
|
||||
new_flags = PAGE_EXECUTE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
new_flags = PAGE_EXECUTE_READ;
|
||||
} else {
|
||||
new_flags = PAGE_EXECUTE;
|
||||
}
|
||||
} else {
|
||||
if (write) {
|
||||
new_flags = PAGE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
new_flags = PAGE_READONLY;
|
||||
} else {
|
||||
new_flags = PAGE_NOACCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// If no flags are assigned, then something's gone wrong.
|
||||
if (new_flags == 0) {
|
||||
LOG_CRITICAL(Common_Memory,
|
||||
"Unsupported protection flag combination for address {:#x}, size {}, "
|
||||
"read={}, write={}, execute={}",
|
||||
@@ -326,12 +434,20 @@ struct AddressSpace::Impl {
|
||||
DWORD old_flags{};
|
||||
if (!VirtualProtectEx(process, LPVOID(range_addr), range_size, new_flags, &old_flags)) {
|
||||
UNREACHABLE_MSG(
|
||||
"Failed to change virtual memory protection for address {:#x}, size {}",
|
||||
"Failed to change virtual memory protection for address {:#x}, size {:#x}",
|
||||
range_addr, range_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boost::icl::interval_set<VAddr> GetUsableRegions() {
|
||||
boost::icl::interval_set<VAddr> reserved_regions;
|
||||
for (auto region : regions) {
|
||||
reserved_regions.insert({region.second.base, region.second.base + region.second.size});
|
||||
}
|
||||
return reserved_regions;
|
||||
}
|
||||
|
||||
HANDLE process{};
|
||||
HANDLE backing_handle{};
|
||||
u8* backing_base{};
|
||||
@@ -356,62 +472,73 @@ enum PosixPageProtection {
|
||||
};
|
||||
|
||||
[[nodiscard]] constexpr PosixPageProtection ToPosixProt(Core::MemoryProt prot) {
|
||||
if (True(prot & Core::MemoryProt::CpuReadWrite) ||
|
||||
True(prot & Core::MemoryProt::GpuReadWrite)) {
|
||||
if (True(prot & Core::MemoryProt::CpuExec)) {
|
||||
const bool read =
|
||||
True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead);
|
||||
const bool write =
|
||||
True(prot & Core::MemoryProt::CpuWrite) || True(prot & Core::MemoryProt::GpuWrite);
|
||||
const bool execute = True(prot & Core::MemoryProt::CpuExec);
|
||||
|
||||
if (write && !read) {
|
||||
// While write-only CPU mappings aren't possible, write-only GPU mappings are.
|
||||
LOG_WARNING(Core, "Converting write-only mapping to read-write");
|
||||
}
|
||||
|
||||
// All cases involving execute permissions have separate permissions.
|
||||
if (execute) {
|
||||
if (write) {
|
||||
return PAGE_EXECUTE_READWRITE;
|
||||
} else {
|
||||
return PAGE_READWRITE;
|
||||
}
|
||||
} else if (True(prot & Core::MemoryProt::CpuRead) || True(prot & Core::MemoryProt::GpuRead)) {
|
||||
if (True(prot & Core::MemoryProt::CpuExec)) {
|
||||
} else if (read && !write) {
|
||||
return PAGE_EXECUTE_READ;
|
||||
} else {
|
||||
return PAGE_READONLY;
|
||||
return PAGE_EXECUTE;
|
||||
}
|
||||
} else {
|
||||
return PAGE_NOACCESS;
|
||||
if (write) {
|
||||
return PAGE_READWRITE;
|
||||
} else if (read && !write) {
|
||||
return PAGE_READONLY;
|
||||
} else {
|
||||
return PAGE_NOACCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AddressSpace::Impl {
|
||||
Impl() {
|
||||
BackingSize += Config::getExtraDmemInMbytes() * 1_MB;
|
||||
// Allocate virtual address placeholder for our address space.
|
||||
system_managed_size = SystemManagedSize;
|
||||
system_reserved_size = SystemReservedSize;
|
||||
user_size = UserSize;
|
||||
|
||||
constexpr int protection_flags = PROT_READ | PROT_WRITE;
|
||||
constexpr int base_map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE;
|
||||
constexpr int map_flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE | MAP_FIXED;
|
||||
#if defined(__APPLE__) && defined(ARCH_X86_64)
|
||||
// On ARM64 Macs under Rosetta 2, we run into limitations due to the commpage from
|
||||
// 0xFC0000000 - 0xFFFFFFFFF and the GPU carveout region from 0x1000000000 - 0x6FFFFFFFFF.
|
||||
// We can allocate the system managed region, as well as system reserved if reduced in size
|
||||
// slightly, but we cannot map the user region where we want, so we must let the OS put it
|
||||
// wherever possible and hope the game won't rely on its location.
|
||||
system_managed_base = reinterpret_cast<u8*>(
|
||||
mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN), system_managed_size, protection_flags,
|
||||
base_map_flags | MAP_FIXED, -1, 0));
|
||||
system_reserved_base = reinterpret_cast<u8*>(
|
||||
mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN), system_reserved_size,
|
||||
protection_flags, base_map_flags | MAP_FIXED, -1, 0));
|
||||
// Cannot guarantee enough space for these areas at the desired addresses, so not MAP_FIXED.
|
||||
user_base = reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(USER_MIN), user_size,
|
||||
protection_flags, base_map_flags, -1, 0));
|
||||
// On ARM64 Macs, we run into limitations due to the commpage from 0xFC0000000 - 0xFFFFFFFFF
|
||||
// and the GPU carveout region from 0x1000000000 - 0x6FFFFFFFFF. Because this creates gaps
|
||||
// in the available virtual memory region, we map memory space using three distinct parts.
|
||||
system_managed_base =
|
||||
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN),
|
||||
system_managed_size, protection_flags, map_flags, -1, 0));
|
||||
system_reserved_base =
|
||||
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_RESERVED_MIN),
|
||||
system_reserved_size, protection_flags, map_flags, -1, 0));
|
||||
user_base = reinterpret_cast<u8*>(
|
||||
mmap(reinterpret_cast<void*>(USER_MIN), user_size, protection_flags, map_flags, -1, 0));
|
||||
#else
|
||||
const auto virtual_size = system_managed_size + system_reserved_size + user_size;
|
||||
#if defined(ARCH_X86_64)
|
||||
const auto virtual_base =
|
||||
reinterpret_cast<u8*>(mmap(reinterpret_cast<void*>(SYSTEM_MANAGED_MIN), virtual_size,
|
||||
protection_flags, base_map_flags | MAP_FIXED, -1, 0));
|
||||
protection_flags, map_flags, -1, 0));
|
||||
system_managed_base = virtual_base;
|
||||
system_reserved_base = reinterpret_cast<u8*>(SYSTEM_RESERVED_MIN);
|
||||
user_base = reinterpret_cast<u8*>(USER_MIN);
|
||||
#else
|
||||
// Map memory wherever possible and instruction translation can handle offsetting to the
|
||||
// base.
|
||||
const auto virtual_base = reinterpret_cast<u8*>(
|
||||
mmap(nullptr, virtual_size, protection_flags, base_map_flags, -1, 0));
|
||||
const auto virtual_base =
|
||||
reinterpret_cast<u8*>(mmap(nullptr, virtual_size, protection_flags, map_flags, -1, 0));
|
||||
system_managed_base = virtual_base;
|
||||
system_reserved_base = virtual_base + SYSTEM_RESERVED_MIN - SYSTEM_MANAGED_MIN;
|
||||
user_base = virtual_base + USER_MIN - SYSTEM_MANAGED_MIN;
|
||||
@@ -579,9 +706,9 @@ void AddressSpace::Unmap(VAddr virtual_addr, size_t size, VAddr start_in_vma, VA
|
||||
// the entire allocation and remap the portions outside of the requested unmapping range.
|
||||
impl->Unmap(virtual_addr, size, has_backing && !readonly_file);
|
||||
|
||||
// TODO: Determine if any titles require partial unmapping support for flexible allocations.
|
||||
// TODO: Determine if any titles require partial unmapping support for un-backed allocations.
|
||||
ASSERT_MSG(has_backing || (start_in_vma == 0 && end_in_vma == size),
|
||||
"Partial unmapping of flexible allocations is not supported");
|
||||
"Partial unmapping of un-backed allocations is not supported");
|
||||
|
||||
if (start_in_vma != 0) {
|
||||
Map(virtual_addr, start_in_vma, 0, phys_base, is_exec);
|
||||
@@ -602,4 +729,22 @@ void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission per
|
||||
return impl->Protect(virtual_addr, size, read, write, execute);
|
||||
}
|
||||
|
||||
boost::icl::interval_set<VAddr> AddressSpace::GetUsableRegions() {
|
||||
#ifdef _WIN32
|
||||
// On Windows, we need to obtain the accessible intervals from the implementation's regions.
|
||||
return impl->GetUsableRegions();
|
||||
#else
|
||||
// On Linux and Mac, the memory space is fully represented by the three major regions
|
||||
boost::icl::interval_set<VAddr> reserved_regions;
|
||||
VAddr system_managed_addr = reinterpret_cast<VAddr>(system_managed_base);
|
||||
VAddr system_reserved_addr = reinterpret_cast<VAddr>(system_reserved_base);
|
||||
VAddr user_addr = reinterpret_cast<VAddr>(user_base);
|
||||
|
||||
reserved_regions.insert({system_managed_addr, system_managed_addr + system_managed_size});
|
||||
reserved_regions.insert({system_reserved_addr, system_reserved_addr + system_reserved_size});
|
||||
reserved_regions.insert({user_addr, user_addr + user_size});
|
||||
return reserved_regions;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/icl/separate_interval_set.hpp>
|
||||
#include "common/arch.h"
|
||||
#include "common/enum.h"
|
||||
#include "common/types.h"
|
||||
@@ -20,22 +21,6 @@ enum class MemoryPermission : u32 {
|
||||
};
|
||||
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
|
||||
|
||||
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
|
||||
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
|
||||
constexpr VAddr SYSTEM_RESERVED_MIN = 0x07FFFFC000ULL;
|
||||
#if defined(__APPLE__) && defined(ARCH_X86_64)
|
||||
// Can only comfortably reserve the first 0x7C0000000 of system reserved space.
|
||||
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFBFFFFFFFULL;
|
||||
#else
|
||||
constexpr VAddr SYSTEM_RESERVED_MAX = 0xFFFFFFFFFULL;
|
||||
#endif
|
||||
constexpr VAddr USER_MIN = 0x1000000000ULL;
|
||||
constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL;
|
||||
|
||||
static constexpr size_t SystemManagedSize = SYSTEM_MANAGED_MAX - SYSTEM_MANAGED_MIN + 1;
|
||||
static constexpr size_t SystemReservedSize = SYSTEM_RESERVED_MAX - SYSTEM_RESERVED_MIN + 1;
|
||||
static constexpr size_t UserSize = 1ULL << 40;
|
||||
|
||||
/**
|
||||
* Represents the user virtual address space backed by a dmem memory block
|
||||
*/
|
||||
@@ -100,6 +85,9 @@ public:
|
||||
|
||||
void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms);
|
||||
|
||||
// Returns an interval set containing all usable regions.
|
||||
boost::icl::interval_set<VAddr> GetUsableRegions();
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> impl;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <Zydis/Zydis.h>
|
||||
#include <xbyak/xbyak.h>
|
||||
#include <xbyak/xbyak_util.h>
|
||||
@@ -122,6 +123,30 @@ static void GenerateTcbAccess(void* /* address */, const ZydisDecodedOperand* op
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool FilterStackCheck(const ZydisDecodedOperand* operands) {
|
||||
const auto& dst_op = operands[0];
|
||||
const auto& src_op = operands[1];
|
||||
|
||||
// Some compilers emit stack checks by starting a function with
|
||||
// 'mov (64-bit register), fs:[0x28]', then checking with `xor (64-bit register), fs:[0x28]`
|
||||
return src_op.type == ZYDIS_OPERAND_TYPE_MEMORY && src_op.mem.segment == ZYDIS_REGISTER_FS &&
|
||||
src_op.mem.base == ZYDIS_REGISTER_NONE && src_op.mem.index == ZYDIS_REGISTER_NONE &&
|
||||
src_op.mem.disp.value == 0x28 && dst_op.reg.value >= ZYDIS_REGISTER_RAX &&
|
||||
dst_op.reg.value <= ZYDIS_REGISTER_R15;
|
||||
}
|
||||
|
||||
static void GenerateStackCheck(void* /* address */, const ZydisDecodedOperand* operands,
|
||||
Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
c.xor_(dst, 0);
|
||||
}
|
||||
|
||||
static void GenerateStackCanary(void* /* address */, const ZydisDecodedOperand* operands,
|
||||
Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
c.mov(dst, 0);
|
||||
}
|
||||
|
||||
static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
|
||||
Cpu cpu;
|
||||
return !cpu.has(Cpu::tSSE4a);
|
||||
@@ -440,18 +465,26 @@ struct PatchInfo {
|
||||
bool trampoline;
|
||||
};
|
||||
|
||||
static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
|
||||
static const std::unordered_map<ZydisMnemonic, std::vector<PatchInfo>> Patches = {
|
||||
// SSE4a
|
||||
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
|
||||
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
|
||||
{ZYDIS_MNEMONIC_MOVNTSS, {FilterNoSSE4a, ReplaceMOVNTSS, false}},
|
||||
{ZYDIS_MNEMONIC_MOVNTSD, {FilterNoSSE4a, ReplaceMOVNTSD, false}},
|
||||
{ZYDIS_MNEMONIC_EXTRQ, {{FilterNoSSE4a, GenerateEXTRQ, true}}},
|
||||
{ZYDIS_MNEMONIC_INSERTQ, {{FilterNoSSE4a, GenerateINSERTQ, true}}},
|
||||
{ZYDIS_MNEMONIC_MOVNTSS, {{FilterNoSSE4a, ReplaceMOVNTSS, false}}},
|
||||
{ZYDIS_MNEMONIC_MOVNTSD, {{FilterNoSSE4a, ReplaceMOVNTSD, false}}},
|
||||
|
||||
#if !defined(__APPLE__)
|
||||
// FS segment patches
|
||||
// These first two patches are for accesses to the stack canary, fs:[0x28]
|
||||
{ZYDIS_MNEMONIC_XOR, {{FilterStackCheck, GenerateStackCheck, false}}},
|
||||
{ZYDIS_MNEMONIC_MOV,
|
||||
{{FilterStackCheck, GenerateStackCanary, false},
|
||||
#if defined(_WIN32)
|
||||
// Windows needs a trampoline.
|
||||
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, true}},
|
||||
#elif !defined(__APPLE__)
|
||||
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, false}},
|
||||
// Windows needs a trampoline for Tcb accesses.
|
||||
{FilterTcbAccess, GenerateTcbAccess, true}
|
||||
#else
|
||||
{FilterTcbAccess, GenerateTcbAccess, false}
|
||||
#endif
|
||||
}},
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -503,51 +536,53 @@ static std::pair<bool, u64> TryPatch(u8* code, PatchModule* module) {
|
||||
}
|
||||
|
||||
if (Patches.contains(instruction.mnemonic)) {
|
||||
const auto& patch_info = Patches.at(instruction.mnemonic);
|
||||
bool needs_trampoline = patch_info.trampoline;
|
||||
if (patch_info.filter(operands)) {
|
||||
auto& patch_gen = module->patch_gen;
|
||||
const auto& patches = Patches.at(instruction.mnemonic);
|
||||
for (const auto& patch_info : patches) {
|
||||
bool needs_trampoline = patch_info.trampoline;
|
||||
if (patch_info.filter(operands)) {
|
||||
auto& patch_gen = module->patch_gen;
|
||||
|
||||
if (needs_trampoline && instruction.length < 5) {
|
||||
// Trampoline is needed but instruction is too short to patch.
|
||||
// Return false and length to signal to AOT compilation that this instruction
|
||||
// should be skipped and handled at runtime.
|
||||
return std::make_pair(false, instruction.length);
|
||||
}
|
||||
if (needs_trampoline && instruction.length < 5) {
|
||||
// Trampoline is needed but instruction is too short to patch.
|
||||
// Return false and length to signal to AOT compilation that this instruction
|
||||
// should be skipped and handled at runtime.
|
||||
return std::make_pair(false, instruction.length);
|
||||
}
|
||||
|
||||
// Reset state and move to current code position.
|
||||
patch_gen.reset();
|
||||
patch_gen.setSize(code - patch_gen.getCode());
|
||||
// Reset state and move to current code position.
|
||||
patch_gen.reset();
|
||||
patch_gen.setSize(code - patch_gen.getCode());
|
||||
|
||||
if (needs_trampoline) {
|
||||
auto& trampoline_gen = module->trampoline_gen;
|
||||
const auto trampoline_ptr = trampoline_gen.getCurr();
|
||||
if (needs_trampoline) {
|
||||
auto& trampoline_gen = module->trampoline_gen;
|
||||
const auto trampoline_ptr = trampoline_gen.getCurr();
|
||||
|
||||
patch_info.generator(code, operands, trampoline_gen);
|
||||
patch_info.generator(code, operands, trampoline_gen);
|
||||
|
||||
// Return to the following instruction at the end of the trampoline.
|
||||
trampoline_gen.jmp(code + instruction.length);
|
||||
// Return to the following instruction at the end of the trampoline.
|
||||
trampoline_gen.jmp(code + instruction.length);
|
||||
|
||||
// Replace instruction with near jump to the trampoline.
|
||||
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
|
||||
} else {
|
||||
patch_info.generator(code, operands, patch_gen);
|
||||
}
|
||||
// Replace instruction with near jump to the trampoline.
|
||||
patch_gen.jmp(trampoline_ptr, Xbyak::CodeGenerator::LabelType::T_NEAR);
|
||||
} else {
|
||||
patch_info.generator(code, operands, patch_gen);
|
||||
}
|
||||
|
||||
const auto patch_size = patch_gen.getCurr() - code;
|
||||
if (patch_size > 0) {
|
||||
ASSERT_MSG(instruction.length >= patch_size,
|
||||
"Instruction {} with length {} is too short to replace at: {}",
|
||||
ZydisMnemonicGetString(instruction.mnemonic), instruction.length,
|
||||
fmt::ptr(code));
|
||||
const auto patch_size = patch_gen.getCurr() - code;
|
||||
if (patch_size > 0) {
|
||||
ASSERT_MSG(instruction.length >= patch_size,
|
||||
"Instruction {} with length {} is too short to replace at: {}",
|
||||
ZydisMnemonicGetString(instruction.mnemonic), instruction.length,
|
||||
fmt::ptr(code));
|
||||
|
||||
// Fill remaining space with nops.
|
||||
patch_gen.nop(instruction.length - patch_size);
|
||||
// Fill remaining space with nops.
|
||||
patch_gen.nop(instruction.length - patch_size);
|
||||
|
||||
module->patched.insert(code);
|
||||
LOG_DEBUG(Core, "Patched instruction '{}' at: {}",
|
||||
ZydisMnemonicGetString(instruction.mnemonic), fmt::ptr(code));
|
||||
return std::make_pair(true, instruction.length);
|
||||
module->patched.insert(code);
|
||||
LOG_DEBUG(Core, "Patched instruction '{}' at: {}",
|
||||
ZydisMnemonicGetString(instruction.mnemonic), fmt::ptr(code));
|
||||
return std::make_pair(true, instruction.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ std::optional<RegDump*> DebugStateImpl::GetRegDump(uintptr_t base_addr, uintptr_
|
||||
}
|
||||
|
||||
void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
const AmdGpu::Liverpool::Regs& regs) {
|
||||
const AmdGpu::Regs& regs) {
|
||||
std::scoped_lock lock{frame_dump_list_mutex};
|
||||
|
||||
auto dump = GetRegDump(base_addr, header_addr);
|
||||
@@ -170,15 +170,14 @@ void DebugStateImpl::PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
for (int i = 0; i < RegDump::MaxShaderStages; i++) {
|
||||
if ((*dump)->regs.stage_enable.IsStageEnabled(i)) {
|
||||
auto stage = (*dump)->regs.ProgramForStage(i);
|
||||
if (stage->address_lo != 0) {
|
||||
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(stage->Address<u32*>());
|
||||
auto code = stage->Code();
|
||||
if (stage->address) {
|
||||
const auto params = AmdGpu::GetParams(*stage);
|
||||
(*dump)->stages[i] = PipelineShaderProgramDump{
|
||||
.name = Vulkan::PipelineCache::GetShaderName(Shader::StageFromIndex(i),
|
||||
info.shader_hash),
|
||||
.hash = info.shader_hash,
|
||||
params.hash),
|
||||
.hash = params.hash,
|
||||
.user_data = *stage,
|
||||
.code = std::vector<u32>{code.begin(), code.end()},
|
||||
.code = std::vector<u32>{params.code.begin(), params.code.end()},
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -198,12 +197,12 @@ void DebugStateImpl::PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_a
|
||||
auto& cs = (*dump)->regs.cs_program;
|
||||
cs = cs_state;
|
||||
|
||||
const auto& info = AmdGpu::Liverpool::SearchBinaryInfo(cs.Address<u32*>());
|
||||
const auto params = AmdGpu::GetParams(cs);
|
||||
(*dump)->cs_data = PipelineComputerProgramDump{
|
||||
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, info.shader_hash),
|
||||
.hash = info.shader_hash,
|
||||
.name = Vulkan::PipelineCache::GetShaderName(Shader::Stage::Compute, params.hash),
|
||||
.hash = params.hash,
|
||||
.cs_program = cs,
|
||||
.code = std::vector<u32>{cs.Code().begin(), cs.Code().end()},
|
||||
.code = std::vector<u32>{params.code.begin(), params.code.end()},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
#include <queue>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||
#include "shader_recompiler/runtime_info.h"
|
||||
#include "video_core/amdgpu/regs.h"
|
||||
#include "video_core/renderer_vulkan/vk_common.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
@@ -54,21 +56,21 @@ struct QueueDump {
|
||||
struct PipelineShaderProgramDump {
|
||||
std::string name;
|
||||
u64 hash;
|
||||
Vulkan::Liverpool::ShaderProgram user_data{};
|
||||
AmdGpu::ShaderProgram user_data{};
|
||||
std::vector<u32> code{};
|
||||
};
|
||||
|
||||
struct PipelineComputerProgramDump {
|
||||
std::string name;
|
||||
u64 hash;
|
||||
Vulkan::Liverpool::ComputeProgram cs_program{};
|
||||
AmdGpu::ComputeProgram cs_program{};
|
||||
std::vector<u32> code{};
|
||||
};
|
||||
|
||||
struct RegDump {
|
||||
bool is_compute{false};
|
||||
static constexpr size_t MaxShaderStages = 5;
|
||||
Vulkan::Liverpool::Regs regs{};
|
||||
AmdGpu::Regs regs;
|
||||
std::array<PipelineShaderProgramDump, MaxShaderStages> stages{};
|
||||
PipelineComputerProgramDump cs_data{};
|
||||
};
|
||||
@@ -219,9 +221,8 @@ public:
|
||||
|
||||
void PushQueueDump(QueueDump dump);
|
||||
|
||||
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr,
|
||||
const AmdGpu::Liverpool::Regs& regs);
|
||||
using CsState = AmdGpu::Liverpool::ComputeProgram;
|
||||
void PushRegsDump(uintptr_t base_addr, uintptr_t header_addr, const AmdGpu::Regs& regs);
|
||||
using CsState = AmdGpu::ComputeProgram;
|
||||
void PushRegsDumpCompute(uintptr_t base_addr, uintptr_t header_addr, const CsState& cs_state);
|
||||
|
||||
void CollectShader(const std::string& name, Shader::LogicalStage l_stage,
|
||||
|
||||
99
src/core/debugger.cpp
Normal file
99
src/core/debugger.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "debugger.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#include <debugapi.h>
|
||||
#elif defined(__linux__)
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#elif defined(__APPLE__)
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
bool Core::Debugger::IsDebuggerAttached() {
|
||||
#if defined(_WIN32)
|
||||
return IsDebuggerPresent();
|
||||
#elif defined(__linux__)
|
||||
std::ifstream status_file("/proc/self/status");
|
||||
std::string line;
|
||||
while (std::getline(status_file, line)) {
|
||||
if (line.starts_with("TracerPid:")) {
|
||||
std::string tracer_pid = line.substr(10);
|
||||
tracer_pid.erase(0, tracer_pid.find_first_not_of(" \t"));
|
||||
return tracer_pid != "0";
|
||||
}
|
||||
}
|
||||
return false;
|
||||
#elif defined(__APPLE__)
|
||||
int mib[4];
|
||||
struct kinfo_proc info;
|
||||
size_t size = sizeof(info);
|
||||
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PID;
|
||||
mib[3] = getpid();
|
||||
|
||||
if (sysctl(mib, 4, &info, &size, nullptr, 0) == 0) {
|
||||
return (info.kp_proc.p_flag & P_TRACED) != 0;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void Core::Debugger::WaitForDebuggerAttach() {
|
||||
int count = 0;
|
||||
while (!IsDebuggerAttached()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
if (--count <= 0) {
|
||||
count = 10;
|
||||
std::cerr << "Waiting for debugger to attach..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
int Core::Debugger::GetCurrentPid() {
|
||||
#if defined(_WIN32)
|
||||
return GetCurrentProcessId();
|
||||
#elif defined(__APPLE__) || defined(__linux__)
|
||||
return getpid();
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
|
||||
void Core::Debugger::WaitForPid(int pid) {
|
||||
#if defined(_WIN32)
|
||||
HANDLE process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
if (process_handle != nullptr) {
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
WaitForSingleObject(process_handle, INFINITE);
|
||||
CloseHandle(process_handle);
|
||||
}
|
||||
#elif defined(__linux__)
|
||||
std::string proc_path = "/proc/" + std::to_string(pid);
|
||||
|
||||
while (std::filesystem::exists(proc_path)) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
while (kill(pid, 0) == 0) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
std::cerr << "Waiting for process " << pid << " to exit..." << std::endl;
|
||||
}
|
||||
#else
|
||||
#error "Unsupported platform"
|
||||
#endif
|
||||
}
|
||||
16
src/core/debugger.h
Normal file
16
src/core/debugger.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core::Debugger {
|
||||
|
||||
bool IsDebuggerAttached();
|
||||
|
||||
void WaitForDebuggerAttach();
|
||||
|
||||
int GetCurrentPid();
|
||||
|
||||
void WaitForPid(int pid);
|
||||
|
||||
} // namespace Core::Debugger
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "layer.h"
|
||||
@@ -311,6 +311,7 @@ static void LoadSettings(const char* line) {
|
||||
|
||||
void L::SetupSettings() {
|
||||
frame_graph.is_open = true;
|
||||
show_simple_fps = Config::getShowFpsCounter();
|
||||
|
||||
using SettingLoader = void (*)(const char*);
|
||||
|
||||
@@ -460,12 +461,12 @@ void L::Draw() {
|
||||
}
|
||||
|
||||
void L::TextCentered(const std::string& text) {
|
||||
float window_width = ImGui::GetWindowSize().x;
|
||||
float text_width = ImGui::CalcTextSize(text.c_str()).x;
|
||||
float window_width = GetWindowSize().x;
|
||||
float text_width = CalcTextSize(text.c_str()).x;
|
||||
float text_indentation = (window_width - text_width) * 0.5f;
|
||||
|
||||
ImGui::SameLine(text_indentation);
|
||||
ImGui::Text("%s", text.c_str());
|
||||
SameLine(text_indentation);
|
||||
Text("%s", text.c_str());
|
||||
}
|
||||
|
||||
namespace Overlay {
|
||||
@@ -475,6 +476,11 @@ void ToggleSimpleFps() {
|
||||
visibility_toggled = true;
|
||||
}
|
||||
|
||||
void SetSimpleFps(bool enabled) {
|
||||
show_simple_fps = enabled;
|
||||
visibility_toggled = true;
|
||||
}
|
||||
|
||||
void ToggleQuitWindow() {
|
||||
show_quit_window = !show_quit_window;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
@@ -9,18 +9,20 @@
|
||||
namespace Core::Devtools {
|
||||
|
||||
class Layer final : public ImGui::Layer {
|
||||
|
||||
static void DrawMenuBar();
|
||||
|
||||
static void DrawAdvanced();
|
||||
|
||||
static void DrawSimple();
|
||||
|
||||
public:
|
||||
static void SetupSettings();
|
||||
|
||||
void Draw() override;
|
||||
void TextCentered(const std::string& text);
|
||||
|
||||
// Must be inside a window
|
||||
static void DrawNullGpuNotice();
|
||||
|
||||
private:
|
||||
static void DrawMenuBar();
|
||||
static void DrawAdvanced();
|
||||
static void DrawSimple();
|
||||
|
||||
static void TextCentered(const std::string& text);
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools
|
||||
@@ -28,6 +30,7 @@ public:
|
||||
namespace Overlay {
|
||||
|
||||
void ToggleSimpleFps();
|
||||
void SetSimpleFps(bool enabled);
|
||||
void ToggleQuitWindow();
|
||||
|
||||
} // namespace Overlay
|
||||
|
||||
95
src/core/devtools/layer_extra.cpp
Normal file
95
src/core/devtools/layer_extra.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "layer.h"
|
||||
|
||||
#include "imgui/imgui_std.h"
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <numbers>
|
||||
|
||||
namespace Core::Devtools {
|
||||
|
||||
void Layer::DrawNullGpuNotice() {
|
||||
|
||||
auto* window = ImGui::GetCurrentWindow();
|
||||
if (window->SkipItems) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr std::string_view mainNotice = "Null GPU is enabled";
|
||||
constexpr std::string_view detailsNotice =
|
||||
"Disable the nullGpu config to show the game display";
|
||||
|
||||
auto displaySize = window->Size;
|
||||
|
||||
ImVec2 targetSize = displaySize * 0.7f;
|
||||
|
||||
float minFontSize = 1.0f;
|
||||
float maxFontSize = 200.0f;
|
||||
float optimalFontSize = minFontSize;
|
||||
|
||||
static auto lastSize = ImVec2(-1, -1);
|
||||
static float lastFontSize = -1.0f;
|
||||
|
||||
auto* font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT_BIG];
|
||||
|
||||
if (lastSize != targetSize) {
|
||||
while (maxFontSize - minFontSize > 0.1f) {
|
||||
float testFontSize = (minFontSize + maxFontSize) / 2.0f;
|
||||
|
||||
ImVec2 textSize = font->CalcTextSizeA(testFontSize, FLT_MAX, 0.0f, &mainNotice.front(),
|
||||
&mainNotice.back() + 1);
|
||||
|
||||
if (textSize.x <= targetSize.x && textSize.y <= targetSize.y) {
|
||||
optimalFontSize = testFontSize;
|
||||
minFontSize = testFontSize;
|
||||
} else {
|
||||
maxFontSize = testFontSize;
|
||||
}
|
||||
}
|
||||
lastSize = targetSize;
|
||||
lastFontSize = optimalFontSize;
|
||||
} else {
|
||||
optimalFontSize = lastFontSize;
|
||||
}
|
||||
ImVec2 textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &mainNotice.front(),
|
||||
&mainNotice.back() + 1);
|
||||
|
||||
ImVec2 textPos = (displaySize - textSize) * 0.5f + window->Pos;
|
||||
|
||||
const float scale = optimalFontSize / font->FontSize;
|
||||
double timeAnim = -std::numbers::pi * ImGui::GetTime();
|
||||
int i = 0;
|
||||
for (auto ch : mainNotice) {
|
||||
double colorTime = sin(timeAnim + i * std::numbers::pi / 6.0) / 2.0 + 0.5;
|
||||
int color = (int)(200 * colorTime) + 55;
|
||||
|
||||
double posTime = sin(timeAnim + i * std::numbers::pi / 15.0) / 2.0 + 0.5;
|
||||
|
||||
auto pos = textPos;
|
||||
pos.y += 10.0 * (posTime < 0.5 ? std::pow(2.0, 20.0 * posTime - 10.0) / 2.0
|
||||
: (2.0 - std::pow(2.0, -20.0 * posTime + 10.0)) / 2.0);
|
||||
|
||||
window->DrawList->AddText(font, optimalFontSize, pos, IM_COL32(color, color, color, 255),
|
||||
&ch, &ch + 1);
|
||||
textPos.x += font->FindGlyph(ch)->AdvanceX * scale;
|
||||
i++;
|
||||
}
|
||||
|
||||
font = ImGui::GetIO().Fonts->Fonts[IMGUI_FONT_TEXT];
|
||||
|
||||
textPos.y += textSize.y + 1.0;
|
||||
|
||||
optimalFontSize *= 0.2;
|
||||
textSize = font->CalcTextSizeA(optimalFontSize, FLT_MAX, 0.0f, &detailsNotice.front(),
|
||||
&detailsNotice.back() + 1);
|
||||
textPos.x = window->Pos.x + (window->Size.x - textSize.x) * 0.5f;
|
||||
window->DrawList->AddText(font, optimalFontSize, textPos, IM_COL32(200, 200, 200, 255),
|
||||
&detailsNotice.front(), &detailsNotice.back() + 1);
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools
|
||||
@@ -65,7 +65,7 @@ static HdrType GetNext(HdrType this_pm4, uint32_t n) {
|
||||
}
|
||||
|
||||
void ParsePolygonControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<AmdGpu::Liverpool::PolygonControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::PolygonControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("PA_SU_SC_MODE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -73,80 +73,80 @@ void ParsePolygonControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("CULL_FRONT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.cull_front.Value());
|
||||
Text("%X", reg.cull_front);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("CULL_BACK");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.cull_back.Value());
|
||||
Text("%X", reg.cull_back);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FACE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.front_face.Value()).data());
|
||||
Text("%s", enum_name(reg.front_face).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLY_MODE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_polygon_mode.Value());
|
||||
Text("%X", reg.enable_polygon_mode);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLYMODE_FRONT_PTYPE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.polygon_mode_front.Value()).data());
|
||||
Text("%s", enum_name(reg.polygon_mode_front).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLYMODE_BACK_PTYPE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.polygon_mode_back.Value()).data());
|
||||
Text("%s", enum_name(reg.polygon_mode_back).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLY_OFFSET_FRONT_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_polygon_offset_front.Value());
|
||||
Text("%X", reg.enable_polygon_offset_front);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLY_OFFSET_BACK_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_polygon_offset_back.Value());
|
||||
Text("%X", reg.enable_polygon_offset_back);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("POLY_OFFSET_PARA_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_polygon_offset_para.Value());
|
||||
Text("%X", reg.enable_polygon_offset_para);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VTX_WINDOW_OFFSET_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_window_offset.Value());
|
||||
Text("%X", reg.enable_window_offset);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("PROVOKING_VTX_LAST");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.provoking_vtx_last.Value(),
|
||||
enum_name(reg.provoking_vtx_last.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.provoking_vtx_last),
|
||||
enum_name(reg.provoking_vtx_last).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("PERSP_CORR_DIS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.persp_corr_dis.Value());
|
||||
Text("%X", reg.persp_corr_dis);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("MULTI_PRIM_IB_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.multi_prim_ib_ena.Value());
|
||||
Text("%X", reg.multi_prim_ib_ena);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -155,7 +155,7 @@ void ParsePolygonControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseAaConfig(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::AaConfig const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::AaConfig const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("PA_SC_AA_CONFIG", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -163,31 +163,31 @@ void ParseAaConfig(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("MSAA_NUM_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.msaa_num_samples.Value());
|
||||
Text("%X", reg.msaa_num_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("AA_MASK_CENTROID_DTMN");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.aa_mask_centroid_dtmn.Value());
|
||||
Text("%X", reg.aa_mask_centroid_dtmn);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("MAX_SAMPLE_DIST");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.max_sample_dst.Value());
|
||||
Text("%X", reg.max_sample_dst);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("MSAA_EXPOSED_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.msaa_exposed_samples.Value());
|
||||
Text("%X", reg.msaa_exposed_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DETAIL_TO_EXPOSED_MODE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.detail_to_exposed_mode.Value());
|
||||
Text("%X", reg.detail_to_exposed_mode);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -196,7 +196,7 @@ void ParseAaConfig(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseViewportControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::ViewportControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::ViewportControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("PA_CL_VTE_CNTL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -204,61 +204,61 @@ void ParseViewportControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_X_SCALE_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.xscale_enable.Value());
|
||||
Text("%X", reg.xscale_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_X_OFFSET_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.yoffset_enable.Value());
|
||||
Text("%X", reg.yoffset_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_Y_SCALE_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.yscale_enable.Value());
|
||||
Text("%X", reg.yscale_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_Y_OFFSET_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.yoffset_enable.Value());
|
||||
Text("%X", reg.yoffset_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_Z_SCALE_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.zscale_enable.Value());
|
||||
Text("%X", reg.zscale_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VPORT_Z_OFFSET_ENA");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.zoffset_enable.Value());
|
||||
Text("%X", reg.zoffset_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VTX_XY_FMT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.xy_transformed.Value());
|
||||
Text("%X", reg.xy_transformed);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VTX_Z_FMT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.z_transformed.Value());
|
||||
Text("%X", reg.z_transformed);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("VTX_W0_FMT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.w_transformed.Value());
|
||||
Text("%X", reg.w_transformed);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("PERFCOUNTER_REF");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.perfcounter_ref.Value());
|
||||
Text("%X", reg.perfcounter_ref);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -267,7 +267,7 @@ void ParseViewportControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseColorControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::ColorControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::ColorControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("CB_COLOR_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -275,25 +275,25 @@ void ParseColorControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("DISABLE_DUAL_QUAD__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.disable_dual_quad.Value());
|
||||
Text("%X", reg.disable_dual_quad);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DEGAMMA_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.degamma_enable.Value());
|
||||
Text("%X", reg.degamma_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("MODE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.mode.Value(), enum_name(reg.mode.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.mode), enum_name(reg.mode).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ROP3");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", static_cast<u32>(reg.rop3.Value()));
|
||||
Text("%X", static_cast<u32>(reg.rop3));
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -302,7 +302,7 @@ void ParseColorControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseColor0Info(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Info const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::ColorBuffer::Color0Info const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("CB_COLOR_INFO", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -310,109 +310,109 @@ void ParseColor0Info(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("ENDIAN");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.endian.Value()).data());
|
||||
Text("%s", enum_name(reg.endian).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FORMAT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.format.Value()).data());
|
||||
Text("%s", enum_name(AmdGpu::DataFormat(reg.format)).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("LINEAR_GENERAL");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.linear_general.Value());
|
||||
Text("%X", reg.linear_general);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("NUMBER_TYPE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.number_type.Value()).data());
|
||||
Text("%s", enum_name(AmdGpu::NumberFormat(reg.number_type)).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COMP_SWAP");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.comp_swap.Value()).data());
|
||||
Text("%s", enum_name(reg.comp_swap).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FAST_CLEAR");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.fast_clear.Value());
|
||||
Text("%X", reg.fast_clear);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COMPRESSION");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.compression.Value());
|
||||
Text("%X", reg.compression);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("BLEND_CLAMP");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.blend_clamp.Value());
|
||||
Text("%X", reg.blend_clamp);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("BLEND_BYPASS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.blend_bypass.Value());
|
||||
Text("%X", reg.blend_bypass);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("SIMPLE_FLOAT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.simple_float.Value());
|
||||
Text("%X", reg.simple_float);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ROUND_MODE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.round_mode.Value(), enum_name(reg.round_mode.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.round_mode), enum_name(reg.round_mode).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("CMASK_IS_LINEAR");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.cmask_is_linear.Value());
|
||||
Text("%X", reg.cmask_is_linear);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("BLEND_OPT_DONT_RD_DST");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.blend_opt_dont_rd_dst.Value());
|
||||
Text("%X", reg.blend_opt_dont_rd_dst);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("BLEND_OPT_DISCARD_PIXEL");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.blend_opt_discard_pixel.Value());
|
||||
Text("%X", reg.blend_opt_discard_pixel);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FMASK_COMPRESSION_DISABLE__CI__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.fmask_compression_disable_ci.Value());
|
||||
Text("%X", reg.fmask_compression_disable_ci);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FMASK_COMPRESS_1FRAG_ONLY__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.fmask_compress_1frag_only.Value());
|
||||
Text("%X", reg.fmask_compress_1frag_only);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DCC_ENABLE__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.dcc_enable.Value());
|
||||
Text("%X", reg.dcc_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("CMASK_ADDR_TYPE__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.cmask_addr_type.Value());
|
||||
Text("%X", reg.cmask_addr_type);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -421,7 +421,7 @@ void ParseColor0Info(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseColor0Attrib(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::ColorBuffer::Color0Attrib const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::ColorBuffer::Color0Attrib const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("CB_COLOR_ATTRIB", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -429,37 +429,37 @@ void ParseColor0Attrib(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("TILE_MODE_INDEX");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%s", enum_name(reg.tile_mode_index.Value()).data());
|
||||
Text("%s", enum_name(reg.tile_mode_index).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FMASK_TILE_MODE_INDEX");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.fmask_tile_mode_index.Value());
|
||||
Text("%X", reg.fmask_tile_mode_index);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FMASK_BANK_HEIGHT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.fmask_bank_height.Value());
|
||||
Text("%X", reg.fmask_bank_height);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("NUM_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.num_samples_log2.Value());
|
||||
Text("%X", reg.num_samples_log2);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("NUM_FRAGMENTS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.num_fragments_log2.Value());
|
||||
Text("%X", reg.num_fragments_log2);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("FORCE_DST_ALPHA_1");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.force_dst_alpha_1.Value());
|
||||
Text("%X", reg.force_dst_alpha_1);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -468,7 +468,7 @@ void ParseColor0Attrib(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseBlendControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::BlendControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::BlendControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("CB_BLEND_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -476,59 +476,59 @@ void ParseBlendControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("COLOR_SRCBLEND");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.color_src_factor.Value(),
|
||||
enum_name(reg.color_src_factor.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.color_src_factor),
|
||||
enum_name(reg.color_src_factor).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COLOR_COMB_FCN");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.color_func.Value(), enum_name(reg.color_func.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.color_func), enum_name(reg.color_func).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COLOR_DESTBLEND");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.color_dst_factor.Value(),
|
||||
enum_name(reg.color_dst_factor.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.color_dst_factor),
|
||||
enum_name(reg.color_dst_factor).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALPHA_SRCBLEND");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.alpha_src_factor.Value(),
|
||||
enum_name(reg.alpha_src_factor.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.alpha_src_factor),
|
||||
enum_name(reg.alpha_src_factor).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALPHA_COMB_FCN");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.alpha_func.Value(), enum_name(reg.alpha_func.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.alpha_func), enum_name(reg.alpha_func).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALPHA_DESTBLEND");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.alpha_dst_factor.Value(),
|
||||
enum_name(reg.alpha_dst_factor.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.alpha_dst_factor),
|
||||
enum_name(reg.alpha_dst_factor).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("SEPARATE_ALPHA_BLEND");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.separate_alpha_blend.Value());
|
||||
Text("%X", reg.separate_alpha_blend);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable.Value());
|
||||
Text("%X", reg.enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DISABLE_ROP3");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.disable_rop3.Value());
|
||||
Text("%X", reg.disable_rop3);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -537,7 +537,7 @@ void ParseBlendControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseDepthRenderControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::DepthRenderControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::DepthRenderControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("DB_RENDER_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -545,61 +545,61 @@ void ParseDepthRenderControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("DEPTH_CLEAR_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_clear_enable.Value());
|
||||
Text("%X", reg.depth_clear_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCIL_CLEAR_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.stencil_clear_enable.Value());
|
||||
Text("%X", reg.stencil_clear_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DEPTH_COPY");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_clear_enable.Value());
|
||||
Text("%X", reg.depth_clear_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCIL_COPY");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.stencil_copy.Value());
|
||||
Text("%X", reg.stencil_copy);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("RESUMMARIZE_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.resummarize_enable.Value());
|
||||
Text("%X", reg.resummarize_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCIL_COMPRESS_DISABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.stencil_compress_disable.Value());
|
||||
Text("%X", reg.stencil_compress_disable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DEPTH_COMPRESS_DISABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_compress_disable.Value());
|
||||
Text("%X", reg.depth_compress_disable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COPY_CENTROID");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.copy_centroid.Value());
|
||||
Text("%X", reg.copy_centroid);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("COPY_SAMPLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.copy_sample.Value());
|
||||
Text("%X", reg.copy_sample);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DECOMPRESS_ENABLE__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.decompress_enable.Value());
|
||||
Text("%X", reg.decompress_enable);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -608,7 +608,7 @@ void ParseDepthRenderControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseDepthControl(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::DepthControl const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::DepthControl const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -616,63 +616,63 @@ void ParseDepthControl(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCIL_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.stencil_enable.Value());
|
||||
Text("%X", reg.stencil_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("Z_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_enable.Value());
|
||||
Text("%X", reg.depth_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("Z_WRITE_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_write_enable.Value());
|
||||
Text("%X", reg.depth_write_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DEPTH_BOUNDS_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.depth_bounds_enable.Value());
|
||||
Text("%X", reg.depth_bounds_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ZFUNC");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.depth_func.Value(), enum_name(reg.depth_func.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.depth_func), enum_name(reg.depth_func).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("BACKFACE_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.backface_enable.Value());
|
||||
Text("%X", reg.backface_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCILFUNC");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.stencil_ref_func.Value(),
|
||||
enum_name(reg.stencil_ref_func.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.stencil_ref_func),
|
||||
enum_name(reg.stencil_ref_func).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STENCILFUNC_BF");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.stencil_bf_func.Value(),
|
||||
enum_name(reg.stencil_bf_func.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.stencil_bf_func),
|
||||
enum_name(reg.stencil_bf_func).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ENABLE_COLOR_WRITES_ON_DEPTH_FAIL");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_color_writes_on_depth_fail.Value());
|
||||
Text("%X", reg.enable_color_writes_on_depth_fail);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DISABLE_COLOR_WRITES_ON_DEPTH_PASS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.disable_color_writes_on_depth_pass.Value());
|
||||
Text("%X", reg.disable_color_writes_on_depth_pass);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -681,7 +681,7 @@ void ParseDepthControl(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseEqaa(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::Eqaa const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::Eqaa const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -689,73 +689,73 @@ void ParseEqaa(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("MAX_ANCHOR_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.max_anchor_samples.Value());
|
||||
Text("%X", reg.max_anchor_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("PS_ITER_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.ps_iter_samples.Value());
|
||||
Text("%X", reg.ps_iter_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("MASK_EXPORT_NUM_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.mask_export_num_samples.Value());
|
||||
Text("%X", reg.mask_export_num_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALPHA_TO_MASK_NUM_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.alpha_to_mask_num_samples.Value());
|
||||
Text("%X", reg.alpha_to_mask_num_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("HIGH_QUALITY_INTERSECTIONS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.high_quality_intersections.Value());
|
||||
Text("%X", reg.high_quality_intersections);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("INCOHERENT_EQAA_READS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.incoherent_eqaa_reads.Value());
|
||||
Text("%X", reg.incoherent_eqaa_reads);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("INTERPOLATE_COMP_Z");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.interpolate_comp_z.Value());
|
||||
Text("%X", reg.interpolate_comp_z);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("INTERPOLATE_SRC_Z");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.interpolate_src_z.Value());
|
||||
Text("%X", reg.interpolate_src_z);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("STATIC_ANCHOR_ASSOCIATIONS");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.static_anchor_associations.Value());
|
||||
Text("%X", reg.static_anchor_associations);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALPHA_TO_MASK_EQAA_DISABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.alpha_to_mask_eqaa_disable.Value());
|
||||
Text("%X", reg.alpha_to_mask_eqaa_disable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("OVERRASTERIZATION_AMOUNT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.overrasterization_amount.Value());
|
||||
Text("%X", reg.overrasterization_amount);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ENABLE_POSTZ_OVERRASTERIZATION");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.enable_postz_overrasterization.Value());
|
||||
Text("%X", reg.enable_postz_overrasterization);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -764,7 +764,7 @@ void ParseEqaa(u32 value, bool begin_table) {
|
||||
}
|
||||
|
||||
void ParseZInfo(u32 value, bool begin_table) {
|
||||
auto const reg = reinterpret_cast<Liverpool::DepthBuffer::ZInfo const&>(value);
|
||||
auto const reg = reinterpret_cast<AmdGpu::DepthBuffer::ZInfo const&>(value);
|
||||
|
||||
if (!begin_table ||
|
||||
BeginTable("DB_DEPTH_CONTROL", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg)) {
|
||||
@@ -772,61 +772,61 @@ void ParseZInfo(u32 value, bool begin_table) {
|
||||
TableSetColumnIndex(0);
|
||||
Text("FORMAT");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X (%s)", (u32)reg.format.Value(), enum_name(reg.format.Value()).data());
|
||||
Text("%X (%s)", static_cast<u32>(reg.format), enum_name(reg.format).data());
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("NUM_SAMPLES");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.num_samples.Value());
|
||||
Text("%X", reg.num_samples);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("TILE_SPLIT__CI__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.tile_split.Value());
|
||||
Text("%X", reg.tile_split);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("TILE_MODE_INDEX");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", static_cast<u32>(reg.tile_mode_index.Value()));
|
||||
Text("%X", static_cast<u32>(reg.tile_mode_index));
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("DECOMPRESS_ON_N_ZPLANES__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.decompress_on_n_zplanes.Value());
|
||||
Text("%X", reg.decompress_on_n_zplanes);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ALLOW_EXPCLEAR");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.allow_expclear.Value());
|
||||
Text("%X", reg.allow_expclear);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("READ_SIZE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.read_size.Value());
|
||||
Text("%X", reg.read_size);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("TILE_SURFACE_ENABLE");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.tile_surface_en.Value());
|
||||
Text("%X", reg.tile_surface_enable);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("CLEAR_DISALLOWED__VI");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.clear_disallowed.Value());
|
||||
Text("%X", reg.clear_disallowed);
|
||||
|
||||
TableNextRow();
|
||||
TableSetColumnIndex(0);
|
||||
Text("ZRANGE_PRECISION");
|
||||
TableSetColumnIndex(1);
|
||||
Text("%X", reg.zrange_precision.Value());
|
||||
Text("%X", reg.zrange_precision);
|
||||
|
||||
if (begin_table) {
|
||||
EndTable();
|
||||
@@ -1515,4 +1515,4 @@ void CmdListViewer::Draw(bool only_batches_view, CmdListFilter& filter) {
|
||||
PopID();
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
||||
} // namespace Core::Devtools::Widget
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "common/types.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include "reg_view.h"
|
||||
#include "core/devtools/widget/imgui_memory_editor.h"
|
||||
#include "core/devtools/widget/reg_view.h"
|
||||
|
||||
namespace AmdGpu {
|
||||
union PM4Type3Header;
|
||||
|
||||
@@ -152,7 +152,7 @@ inline std::string RunDisassembler(const std::string& disassembler_cli, const T&
|
||||
}
|
||||
} else {
|
||||
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
|
||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
|
||||
Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Create);
|
||||
file.Write(shader_code);
|
||||
file.Close();
|
||||
|
||||
|
||||
@@ -118,11 +118,12 @@ void FrameDumpViewer::Draw() {
|
||||
SameLine();
|
||||
BeginDisabled(selected_cmd == -1);
|
||||
if (SmallButton("Dump cmd")) {
|
||||
auto now_time = fmt::localtime(std::time(nullptr));
|
||||
auto time = std::time(nullptr);
|
||||
auto now_time = *std::localtime(&time);
|
||||
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
|
||||
magic_enum::enum_name(selected_queue_type),
|
||||
selected_submit_num, selected_queue_num2);
|
||||
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
|
||||
Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Create);
|
||||
const auto& data = frame_dump->queues[selected_cmd].data;
|
||||
if (file.IsOpen()) {
|
||||
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
|
||||
|
||||
@@ -44,7 +44,7 @@ bool MemoryMapViewer::Iterator::DrawLine() {
|
||||
return false;
|
||||
}
|
||||
auto m = dmem.it->second;
|
||||
if (m.is_free) {
|
||||
if (m.dma_type == DMAType::Free) {
|
||||
++dmem.it;
|
||||
return DrawLine();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ bool MemoryMapViewer::Iterator::DrawLine() {
|
||||
auto type = static_cast<::Libraries::Kernel::MemoryTypes>(m.memory_type);
|
||||
Text("%s", magic_enum::enum_name(type).data());
|
||||
TableNextColumn();
|
||||
Text("%d", m.is_pooled);
|
||||
Text("%d", m.dma_type == DMAType::Pooled || m.dma_type == DMAType::Committed);
|
||||
++dmem.it;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/config.h"
|
||||
#include "common/elf_info.h"
|
||||
#include "common/path_util.h"
|
||||
|
||||
@@ -22,7 +23,7 @@ public:
|
||||
bool open = false;
|
||||
|
||||
static bool IsSystemModule(const std::filesystem::path& path) {
|
||||
const auto sys_modules_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
|
||||
const auto sys_modules_path = Config::getSysModulesPath();
|
||||
|
||||
const auto abs_path = std::filesystem::absolute(path).lexically_normal();
|
||||
const auto abs_sys_path = std::filesystem::absolute(sys_modules_path).lexically_normal();
|
||||
|
||||
@@ -16,7 +16,7 @@ using magic_enum::enum_name;
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
void RegPopup::DrawColorBuffer(const AmdGpu::ColorBuffer& buffer) {
|
||||
if (BeginTable("COLOR_BUFFER", 2, ImGuiTableFlags_Borders)) {
|
||||
TableNextRow();
|
||||
|
||||
@@ -36,7 +36,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
if (TreeNode("Color0Info")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Info(buffer.info.u32all, false);
|
||||
ParseColor0Info(buffer.info.raw, false);
|
||||
TreePop();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
if (TreeNode("Color0Attrib")) {
|
||||
TableNextRow();
|
||||
TableNextColumn();
|
||||
ParseColor0Attrib(buffer.attrib.u32all, false);
|
||||
ParseColor0Attrib(buffer.attrib.raw, false);
|
||||
TreePop();
|
||||
}
|
||||
|
||||
@@ -75,9 +75,8 @@ void RegPopup::DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer) {
|
||||
}
|
||||
}
|
||||
|
||||
void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||
const auto& [depth_buffer, depth_control] = depth_data;
|
||||
|
||||
void RegPopup::DrawDepthBuffer(const AmdGpu::DepthBuffer& buffer,
|
||||
const AmdGpu::DepthControl control) {
|
||||
SeparatorText("Depth buffer");
|
||||
|
||||
if (BeginTable("DEPTH_BUFFER", 2, ImGuiTableFlags_Borders)) {
|
||||
@@ -85,31 +84,31 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||
|
||||
// clang-format off
|
||||
DrawValueRowList(
|
||||
"Z_INFO.FORMAT", depth_buffer.z_info.format,
|
||||
"Z_INFO.NUM_SAMPLES", depth_buffer.z_info.num_samples,
|
||||
"Z_INFO.TILE_SPLIT", depth_buffer.z_info.tile_split,
|
||||
"Z_INFO.TILE_MODE_INDEX", depth_buffer.z_info.tile_mode_index,
|
||||
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", depth_buffer.z_info.decompress_on_n_zplanes,
|
||||
"Z_INFO.ALLOW_EXPCLEAR", depth_buffer.z_info.allow_expclear,
|
||||
"Z_INFO.READ_SIZE", depth_buffer.z_info.read_size,
|
||||
"Z_INFO.TILE_SURFACE_EN", depth_buffer.z_info.tile_surface_en,
|
||||
"Z_INFO.CLEAR_DISALLOWED", depth_buffer.z_info.clear_disallowed,
|
||||
"Z_INFO.ZRANGE_PRECISION", depth_buffer.z_info.zrange_precision,
|
||||
"STENCIL_INFO.FORMAT", depth_buffer.stencil_info.format,
|
||||
"Z_READ_BASE", depth_buffer.z_read_base,
|
||||
"STENCIL_READ_BASE", depth_buffer.stencil_read_base,
|
||||
"Z_WRITE_BASE", depth_buffer.z_write_base,
|
||||
"STENCIL_WRITE_BASE", depth_buffer.stencil_write_base,
|
||||
"DEPTH_SIZE.PITCH_TILE_MAX", depth_buffer.depth_size.pitch_tile_max,
|
||||
"DEPTH_SIZE.HEIGHT_TILE_MAX", depth_buffer.depth_size.height_tile_max,
|
||||
"DEPTH_SLICE.TILE_MAX", depth_buffer.depth_slice.tile_max,
|
||||
"Pitch()", depth_buffer.Pitch(),
|
||||
"Height()", depth_buffer.Height(),
|
||||
"DepthAddress()", depth_buffer.DepthAddress(),
|
||||
"StencilAddress()", depth_buffer.StencilAddress(),
|
||||
"NumSamples()", depth_buffer.NumSamples(),
|
||||
"NumBits()", depth_buffer.NumBits(),
|
||||
"GetDepthSliceSize()", depth_buffer.GetDepthSliceSize()
|
||||
"Z_INFO.FORMAT", buffer.z_info.format,
|
||||
"Z_INFO.NUM_SAMPLES", buffer.z_info.num_samples,
|
||||
"Z_INFO.TILE_SPLIT", buffer.z_info.tile_split,
|
||||
"Z_INFO.TILE_MODE_INDEX", buffer.z_info.tile_mode_index,
|
||||
"Z_INFO.DECOMPRESS_ON_N_ZPLANES", buffer.z_info.decompress_on_n_zplanes,
|
||||
"Z_INFO.ALLOW_EXPCLEAR", buffer.z_info.allow_expclear,
|
||||
"Z_INFO.READ_SIZE", buffer.z_info.read_size,
|
||||
"Z_INFO.TILE_SURFACE_ENABLE", buffer.z_info.tile_surface_enable,
|
||||
"Z_INFO.CLEAR_DISALLOWED", buffer.z_info.clear_disallowed,
|
||||
"Z_INFO.ZRANGE_PRECISION", buffer.z_info.zrange_precision,
|
||||
"STENCIL_INFO.FORMAT", buffer.stencil_info.format,
|
||||
"Z_READ_BASE", buffer.z_read_base,
|
||||
"STENCIL_READ_BASE", buffer.stencil_read_base,
|
||||
"Z_WRITE_BASE", buffer.z_write_base,
|
||||
"STENCIL_WRITE_BASE", buffer.stencil_write_base,
|
||||
"DEPTH_SIZE.PITCH_TILE_MAX", buffer.depth_size.pitch_tile_max,
|
||||
"DEPTH_SIZE.HEIGHT_TILE_MAX", buffer.depth_size.height_tile_max,
|
||||
"DEPTH_SLICE.TILE_MAX", buffer.depth_slice.tile_max,
|
||||
"Pitch()", buffer.Pitch(),
|
||||
"Height()", buffer.Height(),
|
||||
"DepthAddress()", buffer.DepthAddress(),
|
||||
"StencilAddress()", buffer.StencilAddress(),
|
||||
"NumSamples()", buffer.NumSamples(),
|
||||
"NumBits()", buffer.NumBits(),
|
||||
"GetDepthSliceSize()", buffer.GetDepthSliceSize()
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
@@ -121,16 +120,16 @@ void RegPopup::DrawDepthBuffer(const DepthBuffer& depth_data) {
|
||||
|
||||
// clang-format off
|
||||
DrawValueRowList(
|
||||
"STENCIL_ENABLE", depth_control.stencil_enable,
|
||||
"DEPTH_ENABLE", depth_control.depth_enable,
|
||||
"DEPTH_WRITE_ENABLE", depth_control.depth_write_enable,
|
||||
"DEPTH_BOUNDS_ENABLE", depth_control.depth_bounds_enable,
|
||||
"DEPTH_FUNC", depth_control.depth_func,
|
||||
"BACKFACE_ENABLE", depth_control.backface_enable,
|
||||
"STENCIL_FUNC", depth_control.stencil_ref_func,
|
||||
"STENCIL_FUNC_BF", depth_control.stencil_bf_func,
|
||||
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", depth_control.enable_color_writes_on_depth_fail,
|
||||
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", depth_control.disable_color_writes_on_depth_pass
|
||||
"STENCIL_ENABLE", control.stencil_enable,
|
||||
"DEPTH_ENABLE", control.depth_enable,
|
||||
"DEPTH_WRITE_ENABLE", control.depth_write_enable,
|
||||
"DEPTH_BOUNDS_ENABLE", control.depth_bounds_enable,
|
||||
"DEPTH_FUNC", control.depth_func,
|
||||
"BACKFACE_ENABLE", control.backface_enable,
|
||||
"STENCIL_FUNC", control.stencil_ref_func,
|
||||
"STENCIL_FUNC_BF", control.stencil_bf_func,
|
||||
"ENABLE_COLOR_WRITES_ON_DEPTH_FAIL", control.enable_color_writes_on_depth_fail,
|
||||
"DISABLE_COLOR_WRITES_ON_DEPTH_PASS", control.disable_color_writes_on_depth_pass
|
||||
);
|
||||
// clang-format on
|
||||
|
||||
@@ -143,15 +142,17 @@ RegPopup::RegPopup() {
|
||||
id = unique_id++;
|
||||
}
|
||||
|
||||
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
|
||||
u32 cb_id) {
|
||||
this->data = color_buffer;
|
||||
void RegPopup::SetData(const std::string& base_title, AmdGpu::ColorBuffer color_buffer, u32 cb_id) {
|
||||
this->type = DataType::Color;
|
||||
this->color = color_buffer;
|
||||
this->title = fmt::format("{}/CB #{}", base_title, cb_id);
|
||||
}
|
||||
|
||||
void RegPopup::SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||
AmdGpu::Liverpool::DepthControl depth_control) {
|
||||
this->data = std::make_tuple(depth_buffer, depth_control);
|
||||
void RegPopup::SetData(const std::string& base_title, AmdGpu::DepthBuffer depth_buffer,
|
||||
AmdGpu::DepthControl depth_control) {
|
||||
this->type = DataType::Depth;
|
||||
this->depth.buffer = depth_buffer;
|
||||
this->depth.control = depth_control;
|
||||
this->title = fmt::format("{}/Depth", base_title);
|
||||
}
|
||||
|
||||
@@ -161,10 +162,10 @@ void RegPopup::SetPos(ImVec2 pos, bool auto_resize) {
|
||||
Begin(name, &open, flags);
|
||||
SetWindowPos(pos);
|
||||
if (auto_resize) {
|
||||
if (std::holds_alternative<AmdGpu::Liverpool::ColorBuffer>(data)) {
|
||||
if (type == DataType::Color) {
|
||||
SetWindowSize({365.0f, 520.0f});
|
||||
KeepWindowInside();
|
||||
} else if (std::holds_alternative<DepthBuffer>(data)) {
|
||||
} else if (type == DataType::Depth) {
|
||||
SetWindowSize({404.0f, 543.0f});
|
||||
KeepWindowInside();
|
||||
}
|
||||
@@ -182,10 +183,10 @@ void RegPopup::Draw() {
|
||||
moved = true;
|
||||
}
|
||||
|
||||
if (const auto* buffer = std::get_if<AmdGpu::Liverpool::ColorBuffer>(&data)) {
|
||||
DrawColorBuffer(*buffer);
|
||||
} else if (const auto* depth_data = std::get_if<DepthBuffer>(&data)) {
|
||||
DrawDepthBuffer(*depth_data);
|
||||
if (type == DataType::Color) {
|
||||
DrawColorBuffer(color);
|
||||
} else if (type == DataType::Depth) {
|
||||
DrawDepthBuffer(depth.buffer, depth.control);
|
||||
}
|
||||
}
|
||||
End();
|
||||
|
||||
@@ -3,12 +3,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "video_core/renderer_vulkan/liverpool_to_vk.h"
|
||||
#include "video_core/amdgpu/regs_color.h"
|
||||
#include "video_core/amdgpu/regs_depth.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
@@ -16,15 +14,24 @@ class RegPopup {
|
||||
int id;
|
||||
ImGuiWindowFlags flags{ImGuiWindowFlags_NoSavedSettings};
|
||||
|
||||
using DepthBuffer = std::tuple<AmdGpu::Liverpool::DepthBuffer, AmdGpu::Liverpool::DepthControl>;
|
||||
|
||||
ImVec2 last_pos;
|
||||
std::variant<AmdGpu::Liverpool::ColorBuffer, DepthBuffer> data;
|
||||
AmdGpu::ColorBuffer color;
|
||||
struct {
|
||||
AmdGpu::DepthBuffer buffer;
|
||||
AmdGpu::DepthControl control;
|
||||
} depth;
|
||||
enum class DataType {
|
||||
None = 0,
|
||||
Color = 1,
|
||||
Depth = 2,
|
||||
};
|
||||
DataType type{};
|
||||
std::string title{};
|
||||
|
||||
static void DrawColorBuffer(const AmdGpu::Liverpool::ColorBuffer& buffer);
|
||||
static void DrawColorBuffer(const AmdGpu::ColorBuffer& buffer);
|
||||
|
||||
static void DrawDepthBuffer(const DepthBuffer& depth_data);
|
||||
static void DrawDepthBuffer(const AmdGpu::DepthBuffer& buffer,
|
||||
const AmdGpu::DepthControl control);
|
||||
|
||||
public:
|
||||
bool open = false;
|
||||
@@ -32,11 +39,10 @@ public:
|
||||
|
||||
RegPopup();
|
||||
|
||||
void SetData(const std::string& base_title, AmdGpu::Liverpool::ColorBuffer color_buffer,
|
||||
u32 cb_id);
|
||||
void SetData(const std::string& base_title, AmdGpu::ColorBuffer color_buffer, u32 cb_id);
|
||||
|
||||
void SetData(const std::string& base_title, AmdGpu::Liverpool::DepthBuffer depth_buffer,
|
||||
AmdGpu::Liverpool::DepthControl depth_control);
|
||||
void SetData(const std::string& base_title, AmdGpu::DepthBuffer depth_buffer,
|
||||
AmdGpu::DepthControl depth_control);
|
||||
|
||||
void SetPos(ImVec2 pos, bool auto_resize = false);
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Core::Devtools::Widget {
|
||||
|
||||
void RegView::ProcessShader(int shader_id) {
|
||||
std::vector<u32> shader_code;
|
||||
Vulkan::Liverpool::UserData user_data;
|
||||
AmdGpu::UserData user_data;
|
||||
if (data.is_compute) {
|
||||
shader_code = data.cs_data.code;
|
||||
user_data = data.cs_data.cs_program.user_data;
|
||||
@@ -129,7 +129,7 @@ void RegView::DrawGraphicsRegs() {
|
||||
}
|
||||
};
|
||||
|
||||
for (int cb = 0; cb < AmdGpu::Liverpool::NumColorBuffers; ++cb) {
|
||||
for (int cb = 0; cb < AmdGpu::NUM_COLOR_BUFFERS; ++cb) {
|
||||
PushID(cb);
|
||||
|
||||
TableNextRow();
|
||||
@@ -246,8 +246,7 @@ void RegView::SetData(DebugStateType::RegDump _data, const std::string& base_tit
|
||||
default_reg_popup.SetData(title, regs.depth_buffer, regs.depth_control);
|
||||
default_reg_popup.open = true;
|
||||
}
|
||||
} else if (last_selected_cb >= 0 &&
|
||||
last_selected_cb < AmdGpu::Liverpool::NumColorBuffers) {
|
||||
} else if (last_selected_cb >= 0 && last_selected_cb < AmdGpu::NUM_COLOR_BUFFERS) {
|
||||
const auto& buffer = regs.color_buffers[last_selected_cb];
|
||||
const bool has_cb = buffer && regs.color_target_mask.GetMask(last_selected_cb);
|
||||
if (has_cb) {
|
||||
@@ -348,7 +347,7 @@ void RegView::Draw() {
|
||||
} else {
|
||||
shader->hex_view.DrawContents(shader->user_data.data(),
|
||||
shader->user_data.size() *
|
||||
sizeof(Vulkan::Liverpool::UserData::value_type));
|
||||
sizeof(AmdGpu::UserData::value_type));
|
||||
}
|
||||
}
|
||||
End();
|
||||
@@ -392,4 +391,4 @@ void RegView::Draw() {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
||||
} // namespace Core::Devtools::Widget
|
||||
|
||||
@@ -2,17 +2,18 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/debug_state.h"
|
||||
#include "imgui_memory_editor.h"
|
||||
#include "reg_popup.h"
|
||||
#include "text_editor.h"
|
||||
#include "core/devtools/widget/imgui_memory_editor.h"
|
||||
#include "core/devtools/widget/reg_popup.h"
|
||||
#include "core/devtools/widget/text_editor.h"
|
||||
|
||||
namespace Core::Devtools::Widget {
|
||||
|
||||
struct ShaderCache {
|
||||
MemoryEditor hex_view;
|
||||
TextEditor dis_view;
|
||||
Vulkan::Liverpool::UserData user_data;
|
||||
AmdGpu::UserData user_data;
|
||||
};
|
||||
|
||||
class RegView {
|
||||
@@ -54,4 +55,4 @@ public:
|
||||
void Draw();
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools::Widget
|
||||
} // namespace Core::Devtools::Widget
|
||||
|
||||
@@ -36,6 +36,7 @@ bool PSF::Open(const std::filesystem::path& filepath) {
|
||||
}
|
||||
|
||||
const u64 psfSize = file.GetSize();
|
||||
ASSERT_MSG(psfSize != 0, "SFO file at {} is empty!", filepath.string());
|
||||
std::vector<u8> psf(psfSize);
|
||||
file.Seek(0);
|
||||
file.Read(psf);
|
||||
@@ -99,7 +100,7 @@ bool PSF::Open(const std::vector<u8>& psf_buffer) {
|
||||
}
|
||||
|
||||
bool PSF::Encode(const std::filesystem::path& filepath) const {
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Write);
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Create);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
||||
|
||||
const auto user_key_str = Config::getTrophyKey();
|
||||
if (user_key_str.size() != 32) {
|
||||
LOG_CRITICAL(Common_Filesystem, "Trophy decryption key is not specified");
|
||||
LOG_INFO(Common_Filesystem, "Trophy decryption key is not specified");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
||||
TrpEntry entry;
|
||||
file.Read(entry);
|
||||
std::string_view name(entry.entry_name);
|
||||
if (entry.flag == 0 && name.find("TROP") != std::string::npos) { // PNG
|
||||
if (entry.flag == 0) { // PNG
|
||||
if (!file.Seek(entry.entry_pos)) {
|
||||
LOG_CRITICAL(Common_Filesystem, "Failed to seek to TRP entry offset");
|
||||
return false;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <core/libraries/kernel/orbis_error.h>
|
||||
#include "common/types.h"
|
||||
#include "common/va_ctx.h"
|
||||
#include "core/libraries/kernel/orbis_error.h"
|
||||
|
||||
namespace Libraries::Kernel {
|
||||
struct OrbisKernelStat;
|
||||
@@ -20,27 +20,27 @@ public:
|
||||
|
||||
virtual ~BaseDevice() = 0;
|
||||
|
||||
virtual int ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
virtual s32 ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
return ORBIS_KERNEL_ERROR_ENOTTY;
|
||||
}
|
||||
|
||||
virtual s64 write(const void* buf, size_t nbytes) {
|
||||
virtual s64 write(const void* buf, u64 nbytes) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
virtual s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
virtual s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
virtual s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual size_t pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
virtual s64 pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
@@ -48,11 +48,11 @@ public:
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 read(void* buf, size_t nbytes) {
|
||||
virtual s64 read(void* buf, u64 nbytes) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
virtual s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
@@ -60,15 +60,15 @@ public:
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int ftruncate(s64 length) {
|
||||
virtual s32 ftruncate(s64 length) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual int getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
virtual s64 getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
virtual s64 pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,72 +2,71 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "console_device.h"
|
||||
#include "core/file_sys/devices/console_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> ConsoleDevice::Create(u32 handle, const char*, int, u16) {
|
||||
return std::shared_ptr<BaseDevice>(
|
||||
reinterpret_cast<Devices::BaseDevice*>(new ConsoleDevice(handle)));
|
||||
std::shared_ptr<BaseDevice> ConsoleDevice::Create(u32 handle, const char*, s32, u16) {
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<ConsoleDevice>(handle));
|
||||
}
|
||||
|
||||
int ConsoleDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 ConsoleDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 ConsoleDevice::write(const void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ConsoleDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t ConsoleDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 ConsoleDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 ConsoleDevice::lseek(s64 offset, int whence) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 ConsoleDevice::read(void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::read(void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConsoleDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 ConsoleDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 ConsoleDevice::fsync() {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConsoleDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 ConsoleDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConsoleDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 ConsoleDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 ConsoleDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class ConsoleDevice final : BaseDevice {
|
||||
class ConsoleDevice final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit ConsoleDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~ConsoleDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||
s64 lseek(s64 offset, int whence) override;
|
||||
s64 read(void* buf, size_t nbytes) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
int ftruncate(s64 length) override;
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
@@ -2,72 +2,71 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "deci_tty6_device.h"
|
||||
#include "core/file_sys/devices/deci_tty6_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> DeciTty6Device::Create(u32 handle, const char*, int, u16) {
|
||||
return std::shared_ptr<BaseDevice>(
|
||||
reinterpret_cast<Devices::BaseDevice*>(new DeciTty6Device(handle)));
|
||||
std::shared_ptr<BaseDevice> DeciTty6Device::Create(u32 handle, const char*, s32, u16) {
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<DeciTty6Device>(handle));
|
||||
}
|
||||
|
||||
int DeciTty6Device::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 DeciTty6Device::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 DeciTty6Device::write(const void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t DeciTty6Device::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t DeciTty6Device::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 DeciTty6Device::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 DeciTty6Device::lseek(s64 offset, int whence) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 DeciTty6Device::read(void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::read(void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeciTty6Device::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 DeciTty6Device::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 DeciTty6Device::fsync() {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeciTty6Device::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 DeciTty6Device::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeciTty6Device::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 DeciTty6Device::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 DeciTty6Device::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class DeciTty6Device final : BaseDevice {
|
||||
class DeciTty6Device final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit DeciTty6Device(u32 handle) : handle(handle) {}
|
||||
|
||||
~DeciTty6Device() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||
s64 lseek(s64 offset, int whence) override;
|
||||
s64 read(void* buf, size_t nbytes) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
int ftruncate(s64 length) override;
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/devices/logger.h"
|
||||
#include "core/libraries/kernel/file_system.h"
|
||||
#include "logger.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
@@ -11,13 +11,13 @@ Logger::Logger(std::string prefix, bool is_err) : prefix(std::move(prefix)), is_
|
||||
|
||||
Logger::~Logger() = default;
|
||||
|
||||
s64 Logger::write(const void* buf, size_t nbytes) {
|
||||
s64 Logger::write(const void* buf, u64 nbytes) {
|
||||
log(static_cast<const char*>(buf), nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
size_t Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
size_t total_written = 0;
|
||||
s64 Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
u64 total_written = 0;
|
||||
for (int i = 0; i < iovcnt; i++) {
|
||||
log(static_cast<const char*>(iov[i].iov_base), iov[i].iov_len);
|
||||
total_written += iov[i].iov_len;
|
||||
@@ -25,7 +25,7 @@ size_t Logger::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt
|
||||
return total_written;
|
||||
}
|
||||
|
||||
s64 Logger::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
s64 Logger::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
log(static_cast<const char*>(buf), nbytes);
|
||||
return nbytes;
|
||||
}
|
||||
@@ -35,7 +35,7 @@ s32 Logger::fsync() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Logger::log(const char* buf, size_t nbytes) {
|
||||
void Logger::log(const char* buf, u64 nbytes) {
|
||||
std::scoped_lock lock{mtx};
|
||||
const char* end = buf + nbytes;
|
||||
for (const char* it = buf; it < end; ++it) {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
@@ -23,14 +23,14 @@ public:
|
||||
|
||||
~Logger() override;
|
||||
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
|
||||
s32 fsync() override;
|
||||
|
||||
private:
|
||||
void log(const char* buf, size_t nbytes);
|
||||
void log(const char* buf, u64 nbytes);
|
||||
void log_flush();
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
@@ -14,35 +14,35 @@ public:
|
||||
|
||||
~NopDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override {
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 write(const void* buf, size_t nbytes) override {
|
||||
s64 write(const void* buf, u64 nbytes) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override {
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override {
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override {
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 lseek(s64 offset, int whence) override {
|
||||
s64 lseek(s64 offset, s32 whence) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 read(void* buf, size_t nbytes) override {
|
||||
s64 read(void* buf, u64 nbytes) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -50,15 +50,15 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ftruncate(s64 length) override {
|
||||
s32 ftruncate(s64 length) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override {
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override {
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4,75 +4,75 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "random_device.h"
|
||||
#include "core/file_sys/devices/random_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> RandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||
std::shared_ptr<BaseDevice> RandomDevice::Create(u32 handle, const char*, s32, u16) {
|
||||
std::srand(std::time(nullptr));
|
||||
return std::shared_ptr<BaseDevice>(
|
||||
reinterpret_cast<Devices::BaseDevice*>(new RandomDevice(handle)));
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<RandomDevice>(handle));
|
||||
}
|
||||
|
||||
int RandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 RandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RandomDevice::write(const void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t RandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t RandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RandomDevice::lseek(s64 offset, int whence) {
|
||||
s64 RandomDevice::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RandomDevice::read(void* buf, size_t nbytes) {
|
||||
auto rbuf = static_cast<char*>(buf);
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
s64 RandomDevice::read(void* buf, u64 nbytes) {
|
||||
auto rbuf = static_cast<s8*>(buf);
|
||||
for (u64 i = 0; i < nbytes; i++) {
|
||||
rbuf[i] = std::rand() & 0xFF;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
int RandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 RandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 RandomDevice::fsync() {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 RandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 RandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class RandomDevice final : BaseDevice {
|
||||
class RandomDevice final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit RandomDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~RandomDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||
s64 lseek(s64 offset, int whence) override;
|
||||
s64 read(void* buf, size_t nbytes) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
int ftruncate(s64 length) override;
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
87
src/core/file_sys/devices/rng_device.cpp
Normal file
87
src/core/file_sys/devices/rng_device.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/devices/rng_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> RngDevice::Create(u32 handle, const char*, s32, u16) {
|
||||
std::srand(std::time(nullptr));
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<RngDevice>(handle));
|
||||
}
|
||||
|
||||
s32 RngDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_INFO(Kernel_Pthread, "called, cmd = {:#x}", cmd);
|
||||
// Both commands are for generating a random number
|
||||
if (cmd == 0x40445301 || cmd == 0x40445302) {
|
||||
auto& data = *vaArgPtr<GetRandomArgs>(&args->va_list);
|
||||
data.result = 0;
|
||||
for (u64 i = 0; i < 64; i++) {
|
||||
data.buf[i] = std::rand();
|
||||
}
|
||||
} else {
|
||||
// ENOIOCTL
|
||||
return -3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::read(void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 RngDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 RngDevice::fsync() {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 RngDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 RngDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Core::Devices
|
||||
39
src/core/file_sys/devices/rng_device.h
Normal file
39
src/core/file_sys/devices/rng_device.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class RngDevice final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit RngDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~RngDevice() override = default;
|
||||
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
|
||||
private:
|
||||
struct GetRandomArgs {
|
||||
s32 result;
|
||||
s8 buf[64];
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
@@ -4,76 +4,75 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "srandom_device.h"
|
||||
#include "core/file_sys/devices/srandom_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> SRandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||
std::shared_ptr<BaseDevice> SRandomDevice::Create(u32 handle, const char*, s32, u16) {
|
||||
std::srand(std::time(nullptr));
|
||||
return std::shared_ptr<BaseDevice>(
|
||||
reinterpret_cast<Devices::BaseDevice*>(new SRandomDevice(handle)));
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<SRandomDevice>(handle));
|
||||
}
|
||||
|
||||
int SRandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 SRandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::write(const void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SRandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t SRandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::lseek(s64 offset, int whence) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::read(void* buf, size_t nbytes) {
|
||||
auto rbuf = static_cast<char*>(buf);
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
s64 SRandomDevice::read(void* buf, u64 nbytes) {
|
||||
auto rbuf = static_cast<s8*>(buf);
|
||||
for (u64 i = 0; i < nbytes; i++) {
|
||||
rbuf[i] = std::rand();
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
int SRandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 SRandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 SRandomDevice::fsync() {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
return s32();
|
||||
}
|
||||
|
||||
int SRandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SRandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 SRandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 SRandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 SRandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class SRandomDevice final : BaseDevice {
|
||||
class SRandomDevice final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit SRandomDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~SRandomDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||
s64 lseek(s64 offset, int whence) override;
|
||||
s64 read(void* buf, size_t nbytes) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
int ftruncate(s64 length) override;
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
@@ -4,76 +4,75 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "urandom_device.h"
|
||||
#include "core/file_sys/devices/urandom_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
std::shared_ptr<BaseDevice> URandomDevice::Create(u32 handle, const char*, int, u16) {
|
||||
std::shared_ptr<BaseDevice> URandomDevice::Create(u32 handle, const char*, s32, u16) {
|
||||
std::srand(std::time(nullptr));
|
||||
return std::shared_ptr<BaseDevice>(
|
||||
reinterpret_cast<Devices::BaseDevice*>(new URandomDevice(handle)));
|
||||
return std::static_pointer_cast<BaseDevice>(std::make_shared<URandomDevice>(handle));
|
||||
}
|
||||
|
||||
int URandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 URandomDevice::ioctl(u64 cmd, Common::VaCtx* args) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called, cmd = {:#x}", cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 URandomDevice::write(const void* buf, size_t nbytes) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::write(const void* buf, u64 nbytes) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t URandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t URandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 URandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 URandomDevice::lseek(s64 offset, int whence) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::lseek(s64 offset, s32 whence) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 URandomDevice::read(void* buf, size_t nbytes) {
|
||||
auto rbuf = static_cast<char*>(buf);
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
s64 URandomDevice::read(void* buf, u64 nbytes) {
|
||||
auto rbuf = static_cast<s8*>(buf);
|
||||
for (u64 i = 0; i < nbytes; i++) {
|
||||
rbuf[i] = std::rand() & 0xFF;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
int URandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 URandomDevice::fstat(Libraries::Kernel::OrbisKernelStat* sb) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s32 URandomDevice::fsync() {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int URandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s32 URandomDevice::ftruncate(s64 length) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int URandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::getdents(void* buf, u32 nbytes, s64* basep) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
s64 URandomDevice::pwrite(const void* buf, size_t nbytes, u64 offset) {
|
||||
LOG_ERROR(Kernel_Pthread, "(STUBBED) called");
|
||||
s64 URandomDevice::pwrite(const void* buf, u64 nbytes, s64 offset) {
|
||||
LOG_ERROR(Kernel_Fs, "(STUBBED) called");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,31 +3,31 @@
|
||||
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include "base_device.h"
|
||||
#include "core/file_sys/devices/base_device.h"
|
||||
|
||||
namespace Core::Devices {
|
||||
|
||||
class URandomDevice final : BaseDevice {
|
||||
class URandomDevice final : public BaseDevice {
|
||||
u32 handle;
|
||||
|
||||
public:
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, int, u16);
|
||||
static std::shared_ptr<BaseDevice> Create(u32 handle, const char*, s32, u16);
|
||||
explicit URandomDevice(u32 handle) : handle(handle) {}
|
||||
|
||||
~URandomDevice() override = default;
|
||||
|
||||
int ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, size_t nbytes) override;
|
||||
size_t readv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
size_t writev(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, int iovcnt, u64 offset) override;
|
||||
s64 lseek(s64 offset, int whence) override;
|
||||
s64 read(void* buf, size_t nbytes) override;
|
||||
int fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 ioctl(u64 cmd, Common::VaCtx* args) override;
|
||||
s64 write(const void* buf, u64 nbytes) override;
|
||||
s64 readv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) override;
|
||||
s64 preadv(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) override;
|
||||
s64 lseek(s64 offset, s32 whence) override;
|
||||
s64 read(void* buf, u64 nbytes) override;
|
||||
s32 fstat(Libraries::Kernel::OrbisKernelStat* sb) override;
|
||||
s32 fsync() override;
|
||||
int ftruncate(s64 length) override;
|
||||
int getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, size_t nbytes, u64 offset) override;
|
||||
s32 ftruncate(s64 length) override;
|
||||
s64 getdents(void* buf, u32 nbytes, s64* basep) override;
|
||||
s64 pwrite(const void* buf, u64 nbytes, s64 offset) override;
|
||||
};
|
||||
|
||||
} // namespace Core::Devices
|
||||
@@ -36,6 +36,18 @@ public:
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 write(const void* buf, u64 nbytes) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 writev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 pwritev(const Libraries::Kernel::OrbisKernelIovec* iov, s32 iovcnt, s64 offset) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
virtual s64 lseek(s64 offset, s32 whence) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
}
|
||||
|
||||
@@ -235,6 +235,30 @@ File* HandleTable::GetSocket(int d) {
|
||||
return file;
|
||||
}
|
||||
|
||||
File* HandleTable::GetEpoll(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (d < 0 || d >= m_files.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto file = m_files.at(d);
|
||||
if (file->type != Core::FileSys::FileType::Epoll) {
|
||||
return nullptr;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
File* HandleTable::GetResolver(int d) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
if (d < 0 || d >= m_files.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto file = m_files.at(d);
|
||||
if (file->type != Core::FileSys::FileType::Resolver) {
|
||||
return nullptr;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
File* HandleTable::GetFile(const std::filesystem::path& host_name) {
|
||||
for (auto* file : m_files) {
|
||||
if (file != nullptr && file->m_host_name == host_name) {
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
|
||||
namespace Libraries::Net {
|
||||
struct Socket;
|
||||
}
|
||||
struct Epoll;
|
||||
struct Resolver;
|
||||
} // namespace Libraries::Net
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
||||
@@ -78,6 +80,8 @@ enum class FileType {
|
||||
Directory,
|
||||
Device,
|
||||
Socket,
|
||||
Epoll,
|
||||
Resolver
|
||||
};
|
||||
|
||||
struct File {
|
||||
@@ -90,6 +94,8 @@ struct File {
|
||||
std::shared_ptr<Directories::BaseDirectory> directory; // only valid for type == Directory
|
||||
std::shared_ptr<Devices::BaseDevice> device; // only valid for type == Device
|
||||
std::shared_ptr<Libraries::Net::Socket> socket; // only valid for type == Socket
|
||||
std::shared_ptr<Libraries::Net::Epoll> epoll; // only valid for type == Epoll
|
||||
std::shared_ptr<Libraries::Net::Resolver> resolver; // only valid for type == Resolver
|
||||
};
|
||||
|
||||
class HandleTable {
|
||||
@@ -101,6 +107,8 @@ public:
|
||||
void DeleteHandle(int d);
|
||||
File* GetFile(int d);
|
||||
File* GetSocket(int d);
|
||||
File* GetEpoll(int d);
|
||||
File* GetResolver(int d);
|
||||
File* GetFile(const std::filesystem::path& host_name);
|
||||
int GetFileDescriptor(File* file);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "ipc.h"
|
||||
@@ -8,12 +8,19 @@
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/memory_patcher.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/types.h"
|
||||
#include "core/debug_state.h"
|
||||
#include "core/debugger.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "input/input_handler.h"
|
||||
#include "sdl_window.h"
|
||||
#include "src/core/libraries/usbd/usbd.h"
|
||||
#include "video_core/renderer_vulkan/vk_presenter.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||
|
||||
/**
|
||||
* Protocol summary:
|
||||
@@ -40,6 +47,7 @@
|
||||
* Command list:
|
||||
* - CAPABILITIES:
|
||||
* - ENABLE_MEMORY_PATCH: enables PATCH_MEMORY command
|
||||
* - ENABLE_EMU_CONTROL: enables PAUSE, RESUME, STOP, TOGGLE_FULLSCREEN commands
|
||||
* - INPUT CMD:
|
||||
* - RUN: start the emulator execution
|
||||
* - START: start the game execution
|
||||
@@ -53,7 +61,7 @@
|
||||
* - STOP: stop and quit the emulator
|
||||
* - TOGGLE_FULLSCREEN: enable / disable fullscreen
|
||||
* - OUTPUT CMD:
|
||||
* - N/A
|
||||
* - RESTART(argn: number, argv: ...string): Request restart of the emulator, must call STOP
|
||||
**/
|
||||
|
||||
void IPC::Init() {
|
||||
@@ -63,6 +71,8 @@ void IPC::Init() {
|
||||
return;
|
||||
}
|
||||
|
||||
Config::setLoadAutoPatches(false);
|
||||
|
||||
input_thread = std::jthread([this] {
|
||||
Common::SetCurrentThreadName("IPC Read thread");
|
||||
this->InputLoop();
|
||||
@@ -81,6 +91,15 @@ void IPC::Init() {
|
||||
}
|
||||
}
|
||||
|
||||
void IPC::SendRestart(const std::vector<std::string>& args) {
|
||||
std::cerr << ";RESTART\n";
|
||||
std::cerr << ";" << args.size() << "\n";
|
||||
for (const auto& arg : args) {
|
||||
std::cerr << ";" << arg << "\n";
|
||||
}
|
||||
std::cerr.flush();
|
||||
}
|
||||
|
||||
void IPC::InputLoop() {
|
||||
auto next_str = [&] -> const std::string& {
|
||||
static std::string line_buffer;
|
||||
@@ -130,8 +149,70 @@ void IPC::InputLoop() {
|
||||
SDL_memset(&event, 0, sizeof(event));
|
||||
event.type = SDL_EVENT_TOGGLE_FULLSCREEN;
|
||||
SDL_PushEvent(&event);
|
||||
} else if (cmd == "ADJUST_VOLUME") {
|
||||
int value = static_cast<int>(next_u64());
|
||||
bool is_game_specific = next_u64() != 0;
|
||||
Config::setVolumeSlider(value, is_game_specific);
|
||||
Libraries::AudioOut::AdjustVol();
|
||||
} else if (cmd == "SET_FSR") {
|
||||
bool use_fsr = next_u64() != 0;
|
||||
if (presenter) {
|
||||
presenter->GetFsrSettingsRef().enable = use_fsr;
|
||||
}
|
||||
} else if (cmd == "SET_RCAS") {
|
||||
bool use_rcas = next_u64() != 0;
|
||||
if (presenter) {
|
||||
presenter->GetFsrSettingsRef().use_rcas = use_rcas;
|
||||
}
|
||||
} else if (cmd == "SET_RCAS_ATTENUATION") {
|
||||
int value = static_cast<int>(next_u64());
|
||||
if (presenter) {
|
||||
presenter->GetFsrSettingsRef().rcas_attenuation =
|
||||
static_cast<float>(value / 1000.0f);
|
||||
}
|
||||
} else if (cmd == "USB_LOAD_FIGURE") {
|
||||
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
|
||||
if (ref) {
|
||||
ref->LoadFigure(next_str(), next_u64(), next_u64());
|
||||
}
|
||||
} else if (cmd == "USB_REMOVE_FIGURE") {
|
||||
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
|
||||
if (ref) {
|
||||
ref->RemoveFigure(next_u64(), next_u64(), next_u64() != 0);
|
||||
}
|
||||
} else if (cmd == "USB_MOVE_FIGURE") {
|
||||
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
|
||||
if (ref) {
|
||||
const u8 new_pad = next_u64();
|
||||
const u8 new_index = next_u64();
|
||||
const u8 old_pad = next_u64();
|
||||
const u8 old_index = next_u64();
|
||||
ref->MoveFigure(new_pad, new_index, old_pad, old_index);
|
||||
}
|
||||
} else if (cmd == "USB_TEMP_REMOVE_FIGURE") {
|
||||
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
|
||||
if (ref) {
|
||||
const u8 index = next_u64();
|
||||
ref->TempRemoveFigure(index);
|
||||
}
|
||||
} else if (cmd == "USB_CANCEL_REMOVE_FIGURE") {
|
||||
const auto ref = Libraries::Usbd::usb_backend->GetImplRef();
|
||||
if (ref) {
|
||||
const u8 index = next_u64();
|
||||
ref->CancelRemoveFigure(index);
|
||||
}
|
||||
} else if (cmd == "RELOAD_INPUTS") {
|
||||
std::string config = next_str();
|
||||
Input::ParseInputConfig(config);
|
||||
} else if (cmd == "SET_ACTIVE_CONTROLLER") {
|
||||
std::string active_controller = next_str();
|
||||
GamepadSelect::SetSelectedGamepad(active_controller);
|
||||
SDL_Event checkGamepad;
|
||||
SDL_memset(&checkGamepad, 0, sizeof(checkGamepad));
|
||||
checkGamepad.type = SDL_EVENT_CHANGE_CONTROLLER;
|
||||
SDL_PushEvent(&checkGamepad);
|
||||
} else {
|
||||
std::cerr << ";UNKNOWN CMD: " << cmd << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
#include "common/singleton.h"
|
||||
|
||||
#include <semaphore>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
class IPC {
|
||||
bool enabled{false};
|
||||
@@ -34,6 +36,8 @@ public:
|
||||
start_semaphore.acquire();
|
||||
}
|
||||
|
||||
void SendRestart(const std::vector<std::string>& args);
|
||||
|
||||
private:
|
||||
[[noreturn]] void InputLoop();
|
||||
};
|
||||
|
||||
@@ -10,15 +10,51 @@ extern "C" {
|
||||
#include <libatrac9.h>
|
||||
}
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace Libraries::Ajm {
|
||||
|
||||
struct ChunkHeader {
|
||||
u32 tag;
|
||||
u32 length;
|
||||
};
|
||||
static_assert(sizeof(ChunkHeader) == 8);
|
||||
|
||||
struct AudioFormat {
|
||||
u16 fmt_type;
|
||||
u16 num_channels;
|
||||
u32 avg_sample_rate;
|
||||
u32 avg_byte_rate;
|
||||
u16 block_align;
|
||||
u16 bits_per_sample;
|
||||
u16 ext_size;
|
||||
union {
|
||||
u16 valid_bits_per_sample;
|
||||
u16 samples_per_block;
|
||||
u16 reserved;
|
||||
};
|
||||
u32 channel_mask;
|
||||
u8 guid[16];
|
||||
u32 version;
|
||||
u8 config_data[4];
|
||||
u32 reserved2;
|
||||
};
|
||||
static_assert(sizeof(AudioFormat) == 52);
|
||||
|
||||
struct SampleData {
|
||||
u32 sample_length;
|
||||
u32 encoder_delay;
|
||||
u32 encoder_delay2;
|
||||
};
|
||||
static_assert(sizeof(SampleData) == 12);
|
||||
|
||||
struct RIFFHeader {
|
||||
u32 riff;
|
||||
u32 size;
|
||||
u32 wave;
|
||||
};
|
||||
static_assert(sizeof(RIFFHeader) == 12);
|
||||
|
||||
AjmAt9Decoder::AjmAt9Decoder(AjmFormatEncoding format, AjmAt9CodecFlags flags)
|
||||
: m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {
|
||||
ASSERT_MSG(m_handle, "Atrac9GetHandle failed");
|
||||
AjmAt9Decoder::Reset();
|
||||
}
|
||||
: m_format(format), m_flags(flags), m_handle(Atrac9GetHandle()) {}
|
||||
|
||||
AjmAt9Decoder::~AjmAt9Decoder() {
|
||||
Atrac9ReleaseHandle(m_handle);
|
||||
@@ -42,6 +78,7 @@ void AjmAt9Decoder::Initialize(const void* buffer, u32 buffer_size) {
|
||||
AjmAt9Decoder::Reset();
|
||||
m_pcm_buffer.resize(m_codec_info.frameSamples * m_codec_info.channels * GetPCMSize(m_format),
|
||||
0);
|
||||
m_is_initialized = true;
|
||||
}
|
||||
|
||||
void AjmAt9Decoder::GetInfo(void* out_info) const {
|
||||
@@ -52,8 +89,64 @@ void AjmAt9Decoder::GetInfo(void* out_info) const {
|
||||
info->next_frame_size = static_cast<Atrac9Handle*>(m_handle)->Config.FrameBytes;
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) {
|
||||
u8 g_at9_guid[] = {0xD2, 0x42, 0xE1, 0x47, 0xBA, 0x36, 0x8D, 0x4D,
|
||||
0x88, 0xFC, 0x61, 0x65, 0x4F, 0x8C, 0x83, 0x6C};
|
||||
|
||||
void AjmAt9Decoder::ParseRIFFHeader(std::span<u8>& in_buf, AjmInstanceGapless& gapless) {
|
||||
auto* header = reinterpret_cast<RIFFHeader*>(in_buf.data());
|
||||
in_buf = in_buf.subspan(sizeof(RIFFHeader));
|
||||
|
||||
ASSERT(header->riff == 'FFIR');
|
||||
ASSERT(header->wave == 'EVAW');
|
||||
|
||||
auto* chunk = reinterpret_cast<ChunkHeader*>(in_buf.data());
|
||||
in_buf = in_buf.subspan(sizeof(ChunkHeader));
|
||||
while (chunk->tag != 'atad') {
|
||||
switch (chunk->tag) {
|
||||
case ' tmf': {
|
||||
ASSERT(chunk->length == sizeof(AudioFormat));
|
||||
auto* fmt = reinterpret_cast<AudioFormat*>(in_buf.data());
|
||||
|
||||
ASSERT(fmt->fmt_type == 0xFFFE);
|
||||
ASSERT(memcmp(fmt->guid, g_at9_guid, 16) == 0);
|
||||
AjmDecAt9InitializeParameters init_params = {};
|
||||
std::memcpy(init_params.config_data, fmt->config_data, ORBIS_AT9_CONFIG_DATA_SIZE);
|
||||
Initialize(&init_params, sizeof(init_params));
|
||||
break;
|
||||
}
|
||||
case 'tcaf': {
|
||||
ASSERT(chunk->length == sizeof(SampleData));
|
||||
auto* samples = reinterpret_cast<SampleData*>(in_buf.data());
|
||||
|
||||
gapless.init.total_samples = samples->sample_length;
|
||||
gapless.init.skip_samples = samples->encoder_delay;
|
||||
gapless.Reset();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
in_buf = in_buf.subspan(chunk->length);
|
||||
|
||||
chunk = reinterpret_cast<ChunkHeader*>(in_buf.data());
|
||||
in_buf = in_buf.subspan(sizeof(ChunkHeader));
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<u32, u32, bool> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf,
|
||||
SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) {
|
||||
bool is_reset = false;
|
||||
if (True(m_flags & AjmAt9CodecFlags::ParseRiffHeader) &&
|
||||
*reinterpret_cast<u32*>(in_buf.data()) == 'FFIR') {
|
||||
ParseRIFFHeader(in_buf, gapless);
|
||||
is_reset = true;
|
||||
}
|
||||
|
||||
if (!m_is_initialized) {
|
||||
return {0, 0, is_reset};
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
int bytes_used = 0;
|
||||
switch (m_format) {
|
||||
@@ -118,7 +211,7 @@ std::tuple<u32, u32> AjmAt9Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
|
||||
m_num_frames = 0;
|
||||
}
|
||||
|
||||
return {1, samples_written};
|
||||
return {1, m_codec_info.frameSamples, is_reset};
|
||||
}
|
||||
|
||||
AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
|
||||
@@ -134,12 +227,13 @@ AjmSidebandFormat AjmAt9Decoder::GetFormat() const {
|
||||
}
|
||||
|
||||
u32 AjmAt9Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
|
||||
const auto max_samples =
|
||||
const auto skip_samples =
|
||||
std::min<u32>(gapless.current.skip_samples, m_codec_info.frameSamples);
|
||||
const auto samples =
|
||||
gapless.init.total_samples != 0
|
||||
? std::min(gapless.current.total_samples, u32(m_codec_info.frameSamples))
|
||||
? std::min<u32>(gapless.current.total_samples, m_codec_info.frameSamples - skip_samples)
|
||||
: m_codec_info.frameSamples;
|
||||
const auto skip_samples = std::min(u32(gapless.current.skip_samples), max_samples);
|
||||
return (max_samples - skip_samples) * m_codec_info.channels * GetPCMSize(m_format);
|
||||
return samples * m_codec_info.channels * GetPCMSize(m_format);
|
||||
}
|
||||
|
||||
} // namespace Libraries::Ajm
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "libatrac9.h"
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
namespace Libraries::Ajm {
|
||||
|
||||
@@ -36,8 +37,8 @@ struct AjmAt9Decoder final : AjmCodec {
|
||||
void GetInfo(void* out_info) const override;
|
||||
AjmSidebandFormat GetFormat() const override;
|
||||
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
|
||||
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) override;
|
||||
std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) override;
|
||||
|
||||
private:
|
||||
template <class T>
|
||||
@@ -49,8 +50,12 @@ private:
|
||||
return output.Write(pcm_data.subspan(0, pcm_size));
|
||||
}
|
||||
|
||||
void ParseRIFFHeader(std::span<u8>& input, AjmInstanceGapless& gapless);
|
||||
|
||||
const AjmFormatEncoding m_format;
|
||||
const AjmAt9CodecFlags m_flags;
|
||||
|
||||
bool m_is_initialized{};
|
||||
void* m_handle{};
|
||||
u8 m_config_data[ORBIS_AT9_CONFIG_DATA_SIZE]{};
|
||||
u32 m_superframe_bytes_remain{};
|
||||
|
||||
@@ -52,21 +52,22 @@ AjmInstance::AjmInstance(AjmCodecType codec_type, AjmInstanceFlags flags) : m_fl
|
||||
}
|
||||
}
|
||||
|
||||
void AjmInstance::Reset() {
|
||||
m_total_samples = 0;
|
||||
m_gapless.Reset();
|
||||
m_codec->Reset();
|
||||
}
|
||||
|
||||
void AjmInstance::ExecuteJob(AjmJob& job) {
|
||||
const auto control_flags = job.flags.control_flags;
|
||||
if (True(control_flags & AjmJobControlFlags::Reset)) {
|
||||
LOG_TRACE(Lib_Ajm, "Resetting instance {}", job.instance_id);
|
||||
m_format = {};
|
||||
m_gapless = {};
|
||||
m_resample_parameters = {};
|
||||
m_total_samples = 0;
|
||||
m_codec->Reset();
|
||||
Reset();
|
||||
}
|
||||
if (job.input.init_params.has_value()) {
|
||||
LOG_TRACE(Lib_Ajm, "Initializing instance {}", job.instance_id);
|
||||
auto& params = job.input.init_params.value();
|
||||
m_codec->Initialize(¶ms, sizeof(params));
|
||||
is_initialized = true;
|
||||
}
|
||||
if (job.input.resample_parameters.has_value()) {
|
||||
LOG_ERROR(Lib_Ajm, "Unimplemented: resample parameters");
|
||||
@@ -78,20 +79,37 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
||||
}
|
||||
if (job.input.gapless_decode.has_value()) {
|
||||
auto& params = job.input.gapless_decode.value();
|
||||
if (params.total_samples != 0) {
|
||||
const auto max = std::max(params.total_samples, m_gapless.init.total_samples);
|
||||
m_gapless.current.total_samples += max - m_gapless.init.total_samples;
|
||||
m_gapless.init.total_samples = max;
|
||||
}
|
||||
if (params.skip_samples != 0) {
|
||||
const auto max = std::max(params.skip_samples, m_gapless.init.skip_samples);
|
||||
m_gapless.current.skip_samples += max - m_gapless.init.skip_samples;
|
||||
m_gapless.init.skip_samples = max;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
const auto samples_processed =
|
||||
m_gapless.init.total_samples - m_gapless.current.total_samples;
|
||||
if (params.total_samples != 0 || params.skip_samples == 0) {
|
||||
if (params.total_samples >= samples_processed) {
|
||||
const auto sample_difference =
|
||||
s64(m_gapless.init.total_samples) - params.total_samples;
|
||||
|
||||
m_gapless.init.total_samples = params.total_samples;
|
||||
m_gapless.current.total_samples -= sample_difference;
|
||||
} else {
|
||||
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_INVALID_PARAMETER");
|
||||
job.output.p_result->result = ORBIS_AJM_RESULT_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const auto samples_skipped = m_gapless.init.skip_samples - m_gapless.current.skip_samples;
|
||||
if (params.skip_samples != 0 || params.total_samples == 0) {
|
||||
if (params.skip_samples >= samples_skipped) {
|
||||
const auto sample_difference =
|
||||
s32(m_gapless.init.skip_samples) - params.skip_samples;
|
||||
|
||||
m_gapless.init.skip_samples = params.skip_samples;
|
||||
m_gapless.current.skip_samples -= sample_difference;
|
||||
} else {
|
||||
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_INVALID_PARAMETER");
|
||||
job.output.p_result->result = ORBIS_AJM_RESULT_INVALID_PARAMETER;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!job.input.buffer.empty() && !job.output.buffers.empty()) {
|
||||
@@ -104,12 +122,23 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
||||
while (!in_buf.empty() && !out_buf.IsEmpty() && !m_gapless.IsEnd()) {
|
||||
if (!HasEnoughSpace(out_buf)) {
|
||||
if (job.output.p_mframe == nullptr || frames_decoded == 0) {
|
||||
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM ({} < {})",
|
||||
out_buf.Size(), m_codec->GetNextFrameSize(m_gapless));
|
||||
job.output.p_result->result = ORBIS_AJM_RESULT_NOT_ENOUGH_ROOM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const auto [nframes, nsamples] = m_codec->ProcessData(in_buf, out_buf, m_gapless);
|
||||
const auto [nframes, nsamples, reset] =
|
||||
m_codec->ProcessData(in_buf, out_buf, m_gapless);
|
||||
if (reset) {
|
||||
m_total_samples = 0;
|
||||
}
|
||||
if (!nframes) {
|
||||
LOG_WARNING(Lib_Ajm, "ORBIS_AJM_RESULT_NOT_INITIALIZED");
|
||||
job.output.p_result->result = ORBIS_AJM_RESULT_NOT_INITIALIZED;
|
||||
break;
|
||||
}
|
||||
frames_decoded += nframes;
|
||||
m_total_samples += nsamples;
|
||||
|
||||
@@ -118,10 +147,10 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
||||
}
|
||||
}
|
||||
|
||||
if (m_gapless.IsEnd()) {
|
||||
const auto total_decoded_samples = m_total_samples;
|
||||
if (m_flags.gapless_loop && m_gapless.IsEnd()) {
|
||||
in_buf = in_buf.subspan(in_buf.size());
|
||||
m_gapless.current.total_samples = m_gapless.init.total_samples;
|
||||
m_gapless.current.skip_samples = m_gapless.init.skip_samples;
|
||||
m_gapless.Reset();
|
||||
m_codec->Reset();
|
||||
}
|
||||
if (job.output.p_mframe) {
|
||||
@@ -130,7 +159,7 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
||||
if (job.output.p_stream) {
|
||||
job.output.p_stream->input_consumed = in_size - in_buf.size();
|
||||
job.output.p_stream->output_written = out_size - out_buf.Size();
|
||||
job.output.p_stream->total_decoded_samples = m_total_samples;
|
||||
job.output.p_stream->total_decoded_samples = total_decoded_samples;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,12 @@ struct AjmInstanceGapless {
|
||||
bool IsEnd() const {
|
||||
return init.total_samples != 0 && current.total_samples == 0;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
current.total_samples = init.total_samples;
|
||||
current.skip_samples = init.skip_samples;
|
||||
current.skipped_samples = 0;
|
||||
}
|
||||
};
|
||||
|
||||
class AjmCodec {
|
||||
@@ -76,8 +82,8 @@ public:
|
||||
virtual void GetInfo(void* out_info) const = 0;
|
||||
virtual AjmSidebandFormat GetFormat() const = 0;
|
||||
virtual u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const = 0;
|
||||
virtual std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) = 0;
|
||||
virtual std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) = 0;
|
||||
};
|
||||
|
||||
class AjmInstance {
|
||||
@@ -89,6 +95,7 @@ public:
|
||||
private:
|
||||
bool HasEnoughSpace(const SparseOutputBuffer& output) const;
|
||||
std::optional<u32> GetNumRemainingSamples() const;
|
||||
void Reset();
|
||||
|
||||
AjmInstanceFlags m_flags{};
|
||||
AjmSidebandFormat m_format{};
|
||||
@@ -96,7 +103,6 @@ private:
|
||||
AjmSidebandResampleParameters m_resample_parameters{};
|
||||
u32 m_total_samples{};
|
||||
std::unique_ptr<AjmCodec> m_codec;
|
||||
bool is_initialized = false;
|
||||
};
|
||||
|
||||
} // namespace Libraries::Ajm
|
||||
|
||||
@@ -138,8 +138,9 @@ void AjmMp3Decoder::GetInfo(void* out_info) const {
|
||||
}
|
||||
}
|
||||
|
||||
std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) {
|
||||
std::tuple<u32, u32, bool> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf,
|
||||
SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) {
|
||||
AVPacket* pkt = av_packet_alloc();
|
||||
|
||||
if ((!m_header.has_value() || m_frame_samples == 0) && in_buf.size() >= 4) {
|
||||
@@ -155,7 +156,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
|
||||
in_buf = in_buf.subspan(ret);
|
||||
|
||||
u32 frames_decoded = 0;
|
||||
u32 samples_written = 0;
|
||||
u32 samples_decoded = 0;
|
||||
|
||||
if (pkt->size) {
|
||||
// Send the packet with the compressed data to the decoder
|
||||
@@ -176,6 +177,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
|
||||
UNREACHABLE_MSG("Error during decoding");
|
||||
}
|
||||
frame = ConvertAudioFrame(frame);
|
||||
samples_decoded += u32(frame->nb_samples);
|
||||
|
||||
frames_decoded += 1;
|
||||
u32 skip_samples = 0;
|
||||
@@ -205,7 +207,6 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
|
||||
}
|
||||
|
||||
const auto samples = pcm_written / m_codec_context->ch_layout.nb_channels;
|
||||
samples_written += samples;
|
||||
gapless.current.skipped_samples += frame->nb_samples - samples;
|
||||
if (gapless.init.total_samples != 0) {
|
||||
gapless.current.total_samples -= samples;
|
||||
@@ -217,7 +218,7 @@ std::tuple<u32, u32> AjmMp3Decoder::ProcessData(std::span<u8>& in_buf, SparseOut
|
||||
|
||||
av_packet_free(&pkt);
|
||||
|
||||
return {frames_decoded, samples_written};
|
||||
return {frames_decoded, samples_decoded, false};
|
||||
}
|
||||
|
||||
u32 AjmMp3Decoder::GetNextFrameSize(const AjmInstanceGapless& gapless) const {
|
||||
|
||||
@@ -71,8 +71,8 @@ public:
|
||||
void GetInfo(void* out_info) const override;
|
||||
AjmSidebandFormat GetFormat() const override;
|
||||
u32 GetNextFrameSize(const AjmInstanceGapless& gapless) const override;
|
||||
std::tuple<u32, u32> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) override;
|
||||
std::tuple<u32, u32, bool> ProcessData(std::span<u8>& input, SparseOutputBuffer& output,
|
||||
AjmInstanceGapless& gapless) override;
|
||||
|
||||
static int ParseMp3Header(const u8* buf, u32 stream_size, int parse_ofl,
|
||||
AjmDecMp3ParseFrame* frame);
|
||||
|
||||
@@ -301,7 +301,7 @@ static void AudioOutputThread(PortOut* port, const std::stop_token& stop) {
|
||||
timer.Start();
|
||||
{
|
||||
std::unique_lock lock{port->mutex};
|
||||
if (port->output_cv.wait(lock, stop, [&] { return port->output_ready; })) {
|
||||
if (port->output_ready) {
|
||||
port->impl->Output(port->output_buffer);
|
||||
port->output_ready = false;
|
||||
}
|
||||
@@ -413,7 +413,6 @@ s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
samples_sent = port.buffer_frames * port.format_info.num_channels;
|
||||
}
|
||||
}
|
||||
port.output_cv.notify_one();
|
||||
return samples_sent;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,23 +9,22 @@
|
||||
|
||||
namespace Libraries::AvPlayer {
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerAddSource(SceAvPlayerHandle handle, const char* filename) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerAddSource(AvPlayerHandle handle, const char* filename) {
|
||||
LOG_TRACE(Lib_AvPlayer, "filename = {}", filename);
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->AddSource(filename);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->AddSource(filename);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(SceAvPlayerHandle handle, SceAvPlayerUriType uriType,
|
||||
SceAvPlayerSourceDetails* sourceDetails) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
if (handle == nullptr) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerAddSourceEx(AvPlayerHandle handle, AvPlayerUriType uri_type,
|
||||
AvPlayerSourceDetails* source_details) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr || uri_type != AvPlayerUriType::Source) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
const auto path = std::string_view(source_details->uri.name, source_details->uri.length);
|
||||
return handle->AddSourceEx(path, source_details->source_type);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAvPlayerChangeStream() {
|
||||
@@ -33,28 +32,24 @@ int PS4_SYSV_ABI sceAvPlayerChangeStream() {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerClose(SceAvPlayerHandle handle) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerClose(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS");
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
delete handle;
|
||||
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_OK");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(SceAvPlayerHandle handle) {
|
||||
u64 PS4_SYSV_ABI sceAvPlayerCurrentTime(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->CurrentTime();
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->CurrentTime();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_id) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerDisableStream(AvPlayerHandle handle, u32 stream_id) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
@@ -62,60 +57,49 @@ s32 PS4_SYSV_ABI sceAvPlayerDisableStream(SceAvPlayerHandle handle, u32 stream_i
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerEnableStream(SceAvPlayerHandle handle, u32 stream_id) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerEnableStream(AvPlayerHandle handle, u32 stream_id) {
|
||||
LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id);
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->EnableStream(stream_id);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->EnableStream(stream_id);
|
||||
}
|
||||
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetAudioData(SceAvPlayerHandle handle, SceAvPlayerFrameInfo* p_info) {
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetAudioData(AvPlayerHandle handle, AvPlayerFrameInfo* p_info) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr || p_info == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
return false;
|
||||
}
|
||||
const auto res = handle->GetAudioData(*p_info);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->GetAudioData(*p_info);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(SceAvPlayerHandle handle, u32 stream_id,
|
||||
SceAvPlayerStreamInfo* p_info) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerGetStreamInfo(AvPlayerHandle handle, u32 stream_id,
|
||||
AvPlayerStreamInfo* p_info) {
|
||||
LOG_TRACE(Lib_AvPlayer, "stream_id = {}", stream_id);
|
||||
if (handle == nullptr || p_info == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->GetStreamInfo(stream_id, *p_info);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->GetStreamInfo(stream_id, *p_info);
|
||||
}
|
||||
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetVideoData(SceAvPlayerHandle handle,
|
||||
SceAvPlayerFrameInfo* video_info) {
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetVideoData(AvPlayerHandle handle, AvPlayerFrameInfo* video_info) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr || video_info == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
return false;
|
||||
}
|
||||
const auto res = handle->GetVideoData(*video_info);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->GetVideoData(*video_info);
|
||||
}
|
||||
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(SceAvPlayerHandle handle,
|
||||
SceAvPlayerFrameInfoEx* video_info) {
|
||||
bool PS4_SYSV_ABI sceAvPlayerGetVideoDataEx(AvPlayerHandle handle,
|
||||
AvPlayerFrameInfoEx* video_info) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr || video_info == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
return false;
|
||||
}
|
||||
const auto res = handle->GetVideoData(*video_info);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->GetVideoData(*video_info);
|
||||
}
|
||||
|
||||
SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) {
|
||||
AvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(AvPlayerInitData* data) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
@@ -125,15 +109,14 @@ SceAvPlayerHandle PS4_SYSV_ABI sceAvPlayerInit(SceAvPlayerInitData* data) {
|
||||
data->memory_replacement.allocate_texture == nullptr ||
|
||||
data->memory_replacement.deallocate == nullptr ||
|
||||
data->memory_replacement.deallocate_texture == nullptr) {
|
||||
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation.");
|
||||
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new AvPlayer(*data);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
|
||||
SceAvPlayerHandle* p_player) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerInitEx(const AvPlayerInitDataEx* p_data, AvPlayerHandle* p_player) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (p_data == nullptr || p_player == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
@@ -143,11 +126,11 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
|
||||
p_data->memory_replacement.allocate_texture == nullptr ||
|
||||
p_data->memory_replacement.deallocate == nullptr ||
|
||||
p_data->memory_replacement.deallocate_texture == nullptr) {
|
||||
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AVPlayer Initialisation.");
|
||||
LOG_ERROR(Lib_AvPlayer, "All allocators are required for AvPlayer Initialisation.");
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
|
||||
SceAvPlayerInitData data = {};
|
||||
AvPlayerInitData data = {};
|
||||
data.memory_replacement = p_data->memory_replacement;
|
||||
data.file_replacement = p_data->file_replacement;
|
||||
data.event_replacement = p_data->event_replacement;
|
||||
@@ -159,18 +142,15 @@ s32 PS4_SYSV_ABI sceAvPlayerInitEx(const SceAvPlayerInitDataEx* p_data,
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
bool PS4_SYSV_ABI sceAvPlayerIsActive(SceAvPlayerHandle handle) {
|
||||
bool PS4_SYSV_ABI sceAvPlayerIsActive(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
LOG_TRACE(Lib_AvPlayer, "returning false");
|
||||
return false;
|
||||
}
|
||||
const auto res = handle->IsActive();
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->IsActive();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(AvPlayerHandle handle, uint64_t time) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called, time (msec) = {}", time);
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
@@ -178,22 +158,20 @@ s32 PS4_SYSV_ABI sceAvPlayerJumpToTime(SceAvPlayerHandle handle, uint64_t time)
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerPause(SceAvPlayerHandle handle) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceAvPlayerPause(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
return handle->Pause();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerPostInit(SceAvPlayerHandle handle, SceAvPlayerPostInitData* data) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerPostInit(AvPlayerHandle handle, AvPlayerPostInitData* data) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr || data == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->PostInit(*data);
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->PostInit(*data);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) {
|
||||
@@ -201,29 +179,28 @@ s32 PS4_SYSV_ABI sceAvPlayerPrintf(const char* format, ...) {
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerResume(SceAvPlayerHandle handle) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceAvPlayerResume(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
return handle->Resume();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(SceAvPlayerHandle handle,
|
||||
SceAvPlayerAvSyncMode sync_mode) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetAvSyncMode(AvPlayerHandle handle, AvPlayerAvSyncMode sync_mode) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
return handle->SetAvSyncMode(sync_mode);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(SceAvPlayerLogCallback log_cb, void* user_data) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetLogCallback(AvPlayerLogCallback log_cb, void* user_data) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetLooping(AvPlayerHandle handle, bool loop_flag) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called, looping = {}", loop_flag);
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
@@ -234,43 +211,36 @@ s32 PS4_SYSV_ABI sceAvPlayerSetLooping(SceAvPlayerHandle handle, bool loop_flag)
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(SceAvPlayerHandle handle, s32 trick_speed) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceAvPlayerSetTrickSpeed(AvPlayerHandle handle, s32 trick_speed) {
|
||||
LOG_ERROR(Lib_AvPlayer, "(STUBBED) called speed = {}", trick_speed);
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStart(SceAvPlayerHandle handle) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStart(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->Start();
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->Start();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStop(SceAvPlayerHandle handle) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStop(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
LOG_TRACE(Lib_AvPlayer, "returning ORBIS_AVPLAYER_ERROR_INVALID_PARAMS");
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->Stop();
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->Stop();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStreamCount(SceAvPlayerHandle handle) {
|
||||
s32 PS4_SYSV_ABI sceAvPlayerStreamCount(AvPlayerHandle handle) {
|
||||
LOG_TRACE(Lib_AvPlayer, "called");
|
||||
if (handle == nullptr) {
|
||||
return ORBIS_AVPLAYER_ERROR_INVALID_PARAMS;
|
||||
}
|
||||
const auto res = handle->GetStreamCount();
|
||||
LOG_TRACE(Lib_AvPlayer, "returning {}", res);
|
||||
return res;
|
||||
return handle->GetStreamCount();
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAvPlayerVprintf(const char* format, va_list args) {
|
||||
|
||||
@@ -16,38 +16,38 @@ namespace Libraries::AvPlayer {
|
||||
|
||||
class AvPlayer;
|
||||
|
||||
using SceAvPlayerHandle = AvPlayer*;
|
||||
using AvPlayerHandle = AvPlayer*;
|
||||
|
||||
enum class SceAvPlayerUriType : u32 {
|
||||
enum class AvPlayerUriType : u32 {
|
||||
Source = 0,
|
||||
};
|
||||
|
||||
struct SceAvPlayerUri {
|
||||
struct AvPlayerUri {
|
||||
const char* name;
|
||||
u32 length;
|
||||
};
|
||||
|
||||
enum class SceAvPlayerSourceType {
|
||||
enum class AvPlayerSourceType {
|
||||
Unknown = 0,
|
||||
FileMp4 = 1,
|
||||
Hls = 8,
|
||||
};
|
||||
|
||||
enum class SceAvPlayerStreamType : u32 {
|
||||
enum class AvPlayerStreamType : u32 {
|
||||
Video,
|
||||
Audio,
|
||||
TimedText,
|
||||
Unknown,
|
||||
};
|
||||
|
||||
struct SceAvPlayerSourceDetails {
|
||||
SceAvPlayerUri uri;
|
||||
struct AvPlayerSourceDetails {
|
||||
AvPlayerUri uri;
|
||||
u8 reserved1[64];
|
||||
SceAvPlayerSourceType source_type;
|
||||
AvPlayerSourceType source_type;
|
||||
u8 reserved2[44];
|
||||
};
|
||||
|
||||
struct SceAvPlayerAudio {
|
||||
struct AvPlayerAudio {
|
||||
u16 channel_count;
|
||||
u8 reserved1[2];
|
||||
u32 sample_rate;
|
||||
@@ -55,50 +55,50 @@ struct SceAvPlayerAudio {
|
||||
u8 language_code[4];
|
||||
};
|
||||
|
||||
struct SceAvPlayerVideo {
|
||||
struct AvPlayerVideo {
|
||||
u32 width;
|
||||
u32 height;
|
||||
f32 aspect_ratio;
|
||||
char language_code[4];
|
||||
};
|
||||
|
||||
struct SceAvPlayerTextPosition {
|
||||
struct AvPlayerTextPosition {
|
||||
u16 top;
|
||||
u16 left;
|
||||
u16 bottom;
|
||||
u16 right;
|
||||
};
|
||||
|
||||
struct SceAvPlayerTimedText {
|
||||
struct AvPlayerTimedText {
|
||||
u8 language_code[4];
|
||||
u16 text_size;
|
||||
u16 font_size;
|
||||
SceAvPlayerTextPosition position;
|
||||
AvPlayerTextPosition position;
|
||||
};
|
||||
|
||||
union SceAvPlayerStreamDetails {
|
||||
union AvPlayerStreamDetails {
|
||||
u8 reserved[16];
|
||||
SceAvPlayerAudio audio;
|
||||
SceAvPlayerVideo video;
|
||||
SceAvPlayerTimedText subs;
|
||||
AvPlayerAudio audio;
|
||||
AvPlayerVideo video;
|
||||
AvPlayerTimedText subs;
|
||||
};
|
||||
|
||||
struct SceAvPlayerFrameInfo {
|
||||
u8* pData;
|
||||
struct AvPlayerFrameInfo {
|
||||
u8* p_data;
|
||||
u8 reserved[4];
|
||||
u64 timestamp;
|
||||
SceAvPlayerStreamDetails details;
|
||||
AvPlayerStreamDetails details;
|
||||
};
|
||||
|
||||
struct SceAvPlayerStreamInfo {
|
||||
SceAvPlayerStreamType type;
|
||||
struct AvPlayerStreamInfo {
|
||||
AvPlayerStreamType type;
|
||||
u8 reserved[4];
|
||||
SceAvPlayerStreamDetails details;
|
||||
AvPlayerStreamDetails details;
|
||||
u64 duration;
|
||||
u64 start_time;
|
||||
};
|
||||
|
||||
struct SceAvPlayerAudioEx {
|
||||
struct AvPlayerAudioEx {
|
||||
u16 channel_count;
|
||||
u8 reserved[2];
|
||||
u32 sample_rate;
|
||||
@@ -107,7 +107,7 @@ struct SceAvPlayerAudioEx {
|
||||
u8 reserved1[64];
|
||||
};
|
||||
|
||||
struct SceAvPlayerVideoEx {
|
||||
struct AvPlayerVideoEx {
|
||||
u32 width;
|
||||
u32 height;
|
||||
f32 aspect_ratio;
|
||||
@@ -124,53 +124,53 @@ struct SceAvPlayerVideoEx {
|
||||
u8 reserved1[37];
|
||||
};
|
||||
|
||||
struct SceAvPlayerTimedTextEx {
|
||||
struct AvPlayerTimedTextEx {
|
||||
u8 language_code[4];
|
||||
u8 reserved[12];
|
||||
u8 reserved1[64];
|
||||
};
|
||||
|
||||
union SceAvPlayerStreamDetailsEx {
|
||||
SceAvPlayerAudioEx audio;
|
||||
SceAvPlayerVideoEx video;
|
||||
SceAvPlayerTimedTextEx subs;
|
||||
union AvPlayerStreamDetailsEx {
|
||||
AvPlayerAudioEx audio;
|
||||
AvPlayerVideoEx video;
|
||||
AvPlayerTimedTextEx subs;
|
||||
u8 reserved1[80];
|
||||
};
|
||||
|
||||
struct SceAvPlayerFrameInfoEx {
|
||||
void* pData;
|
||||
struct AvPlayerFrameInfoEx {
|
||||
void* p_data;
|
||||
u8 reserved[4];
|
||||
u64 timestamp;
|
||||
SceAvPlayerStreamDetailsEx details;
|
||||
AvPlayerStreamDetailsEx details;
|
||||
};
|
||||
|
||||
using SceAvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
|
||||
using SceAvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem);
|
||||
using SceAvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
|
||||
using SceAvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem);
|
||||
using AvPlayerAllocate = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
|
||||
using AvPlayerDeallocate = void PS4_SYSV_ABI (*)(void* p, void* mem);
|
||||
using AvPlayerAllocateTexture = void* PS4_SYSV_ABI (*)(void* p, u32 align, u32 size);
|
||||
using AvPlayerDeallocateTexture = void PS4_SYSV_ABI (*)(void* p, void* mem);
|
||||
|
||||
struct SceAvPlayerMemAllocator {
|
||||
struct AvPlayerMemAllocator {
|
||||
void* object_ptr;
|
||||
SceAvPlayerAllocate allocate;
|
||||
SceAvPlayerDeallocate deallocate;
|
||||
SceAvPlayerAllocateTexture allocate_texture;
|
||||
SceAvPlayerDeallocateTexture deallocate_texture;
|
||||
AvPlayerAllocate allocate;
|
||||
AvPlayerDeallocate deallocate;
|
||||
AvPlayerAllocateTexture allocate_texture;
|
||||
AvPlayerDeallocateTexture deallocate_texture;
|
||||
};
|
||||
|
||||
using SceAvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name);
|
||||
using SceAvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p);
|
||||
using SceAvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len);
|
||||
using SceAvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p);
|
||||
using AvPlayerOpenFile = s32 PS4_SYSV_ABI (*)(void* p, const char* name);
|
||||
using AvPlayerCloseFile = s32 PS4_SYSV_ABI (*)(void* p);
|
||||
using AvPlayerReadOffsetFile = s32 PS4_SYSV_ABI (*)(void* p, u8* buf, u64 pos, u32 len);
|
||||
using AvPlayerSizeFile = u64 PS4_SYSV_ABI (*)(void* p);
|
||||
|
||||
struct SceAvPlayerFileReplacement {
|
||||
struct AvPlayerFileReplacement {
|
||||
void* object_ptr;
|
||||
SceAvPlayerOpenFile open;
|
||||
SceAvPlayerCloseFile close;
|
||||
SceAvPlayerReadOffsetFile readOffset;
|
||||
SceAvPlayerSizeFile size;
|
||||
AvPlayerOpenFile open;
|
||||
AvPlayerCloseFile close;
|
||||
AvPlayerReadOffsetFile read_offset;
|
||||
AvPlayerSizeFile size;
|
||||
};
|
||||
|
||||
enum class SceAvPlayerEvents {
|
||||
enum class AvPlayerEvents {
|
||||
StateStop = 0x01,
|
||||
StateReady = 0x02,
|
||||
StatePlay = 0x03,
|
||||
@@ -182,26 +182,26 @@ enum class SceAvPlayerEvents {
|
||||
DrmError = 0x40,
|
||||
};
|
||||
|
||||
using SceAvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, SceAvPlayerEvents event, s32 src_id,
|
||||
void* data);
|
||||
using AvPlayerEventCallback = void PS4_SYSV_ABI (*)(void* p, AvPlayerEvents event, s32 src_id,
|
||||
void* data);
|
||||
|
||||
struct SceAvPlayerEventReplacement {
|
||||
struct AvPlayerEventReplacement {
|
||||
void* object_ptr;
|
||||
SceAvPlayerEventCallback event_callback;
|
||||
AvPlayerEventCallback event_callback;
|
||||
};
|
||||
|
||||
enum class SceAvPlayerDebuglevels {
|
||||
enum class AvPlayerDebuglevels {
|
||||
None,
|
||||
Info,
|
||||
Warnings,
|
||||
All,
|
||||
};
|
||||
|
||||
struct SceAvPlayerInitData {
|
||||
SceAvPlayerMemAllocator memory_replacement;
|
||||
SceAvPlayerFileReplacement file_replacement;
|
||||
SceAvPlayerEventReplacement event_replacement;
|
||||
SceAvPlayerDebuglevels debug_level;
|
||||
struct AvPlayerInitData {
|
||||
AvPlayerMemAllocator memory_replacement;
|
||||
AvPlayerFileReplacement file_replacement;
|
||||
AvPlayerEventReplacement event_replacement;
|
||||
AvPlayerDebuglevels debug_level;
|
||||
u32 base_priority;
|
||||
s32 num_output_video_framebuffers;
|
||||
bool auto_start;
|
||||
@@ -209,13 +209,13 @@ struct SceAvPlayerInitData {
|
||||
const char* default_language;
|
||||
};
|
||||
|
||||
struct SceAvPlayerInitDataEx {
|
||||
struct AvPlayerInitDataEx {
|
||||
size_t this_size;
|
||||
SceAvPlayerMemAllocator memory_replacement;
|
||||
SceAvPlayerFileReplacement file_replacement;
|
||||
SceAvPlayerEventReplacement event_replacement;
|
||||
AvPlayerMemAllocator memory_replacement;
|
||||
AvPlayerFileReplacement file_replacement;
|
||||
AvPlayerEventReplacement event_replacement;
|
||||
const char* default_language;
|
||||
SceAvPlayerDebuglevels debug_level;
|
||||
AvPlayerDebuglevels debug_level;
|
||||
u32 audio_decoder_priority;
|
||||
u32 audio_decoder_affinity;
|
||||
u32 video_decoder_priority;
|
||||
@@ -233,25 +233,25 @@ struct SceAvPlayerInitDataEx {
|
||||
u8 reserved[3];
|
||||
};
|
||||
|
||||
enum class SceAvPlayerVideoDecoderType {
|
||||
enum class AvPlayerVideoDecoderType {
|
||||
Default = 0,
|
||||
Reserved1,
|
||||
Software,
|
||||
Software2,
|
||||
};
|
||||
|
||||
enum class SceAvPlayerAudioDecoderType {
|
||||
enum class AvPlayerAudioDecoderType {
|
||||
Default = 0,
|
||||
Reserved1,
|
||||
Reserved2,
|
||||
};
|
||||
|
||||
struct SceAvPlayerDecoderInit {
|
||||
struct AvPlayerDecoderInit {
|
||||
union {
|
||||
SceAvPlayerVideoDecoderType video_type;
|
||||
SceAvPlayerAudioDecoderType audio_type;
|
||||
AvPlayerVideoDecoderType video_type;
|
||||
AvPlayerAudioDecoderType audio_type;
|
||||
u8 reserved[4];
|
||||
} decoderType;
|
||||
} decoder_type;
|
||||
union {
|
||||
struct {
|
||||
s32 cpu_affinity_mask;
|
||||
@@ -261,34 +261,34 @@ struct SceAvPlayerDecoderInit {
|
||||
u8 compute_queue_id;
|
||||
u8 enable_interlaced;
|
||||
u8 reserved[16];
|
||||
} avcSw2;
|
||||
} avc_sw2;
|
||||
struct {
|
||||
u8 audio_channel_order;
|
||||
u8 reserved[27];
|
||||
} aac;
|
||||
u8 reserved[28];
|
||||
} decoderParams;
|
||||
} decoder_params;
|
||||
};
|
||||
|
||||
struct SceAvPlayerHTTPCtx {
|
||||
struct AvPlayerHTTPCtx {
|
||||
u32 http_context_id;
|
||||
u32 ssl_context_id;
|
||||
};
|
||||
|
||||
struct SceAvPlayerPostInitData {
|
||||
struct AvPlayerPostInitData {
|
||||
u32 demux_video_buffer_size;
|
||||
SceAvPlayerDecoderInit video_decoder_init;
|
||||
SceAvPlayerDecoderInit audio_decoder_init;
|
||||
SceAvPlayerHTTPCtx http_context;
|
||||
AvPlayerDecoderInit video_decoder_init;
|
||||
AvPlayerDecoderInit audio_decoder_init;
|
||||
AvPlayerHTTPCtx http_context;
|
||||
u8 reserved[56];
|
||||
};
|
||||
|
||||
enum class SceAvPlayerAvSyncMode {
|
||||
enum class AvPlayerAvSyncMode {
|
||||
Default = 0,
|
||||
None,
|
||||
};
|
||||
|
||||
using SceAvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args);
|
||||
using AvPlayerLogCallback = int PS4_SYSV_ABI (*)(void* p, const char* format, va_list args);
|
||||
|
||||
void RegisterLib(Core::Loader::SymbolsResolver* sym);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user