mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-28 21:38:03 +03:00
Compare commits
374 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
beb9c86749 | ||
![]() |
81fa9b7fff | ||
![]() |
385c5a4507 | ||
![]() |
59d060bc16 | ||
![]() |
83fd0683fa | ||
![]() |
81ad31ce31 | ||
![]() |
ff984d3cde | ||
![]() |
b505829e16 | ||
![]() |
254375ef0c | ||
![]() |
cef795b80b | ||
![]() |
410313ca87 | ||
![]() |
c09fff2da6 | ||
![]() |
e816bc4b99 | ||
![]() |
632ed99ee7 | ||
![]() |
15d6a45dcd | ||
![]() |
d370ea32f4 | ||
![]() |
c01590175a | ||
![]() |
a12d447bd6 | ||
![]() |
ce3aded3e5 | ||
![]() |
4ecdcf77d1 | ||
![]() |
3f4249084c | ||
![]() |
aeee7706ee | ||
![]() |
5db162cbcd | ||
![]() |
354a2e6946 | ||
![]() |
53ca64f6ff | ||
![]() |
ee7fe305c9 | ||
![]() |
b1ebb2fec5 | ||
![]() |
96bee58d0f | ||
![]() |
0297aee3f4 | ||
![]() |
5b0205bc59 | ||
![]() |
cda421434b | ||
![]() |
0c86c54d48 | ||
![]() |
5be726ca3b | ||
![]() |
69777e2ffa | ||
![]() |
111ff2bedd | ||
![]() |
d188510e59 | ||
![]() |
d0dbb737d9 | ||
![]() |
e11ffe242b | ||
![]() |
6e963a7f71 | ||
![]() |
81ada41baa | ||
![]() |
0feb2e7211 | ||
![]() |
23c616c647 | ||
![]() |
20b11f2d63 | ||
![]() |
df89241eb8 | ||
![]() |
703620c7cd | ||
![]() |
b1b7538afd | ||
![]() |
ddc05e8a5f | ||
![]() |
62a4182aca | ||
![]() |
aa8dab5371 | ||
![]() |
ddf3df7f56 | ||
![]() |
243ee04b1c | ||
![]() |
04e4ce0775 | ||
![]() |
52ab1ed04b | ||
![]() |
3bc876ca78 | ||
![]() |
247e935353 | ||
![]() |
4bea00135d | ||
![]() |
683a223c1b | ||
![]() |
2b633fd3c5 | ||
![]() |
cd8e2c4e79 | ||
![]() |
7d32efbd31 | ||
![]() |
b8884d9591 | ||
![]() |
bec1b9056f | ||
![]() |
657073b9e2 | ||
![]() |
fb146f2a20 | ||
![]() |
ec515ad113 | ||
![]() |
d188d14e19 | ||
![]() |
14fad28a9b | ||
![]() |
aec6e330dc | ||
![]() |
6c2574364b | ||
![]() |
8ed82712a0 | ||
![]() |
b0fe1532f7 | ||
![]() |
6ebed7ce69 | ||
![]() |
37d4cd091c | ||
![]() |
5abec2a291 | ||
![]() |
e3b1c041d0 | ||
![]() |
2965656325 | ||
![]() |
03b1fef331 | ||
![]() |
08731303d8 | ||
![]() |
7fee289b66 | ||
![]() |
040fd79ef7 | ||
![]() |
473b66649f | ||
![]() |
b8f6ef1c0b | ||
![]() |
9d2175180e | ||
![]() |
0c6f2b470f | ||
![]() |
54b4d7fc78 | ||
![]() |
1ee2016902 | ||
![]() |
7bb49d85d3 | ||
![]() |
806b2ddc89 | ||
![]() |
afd0251dd2 | ||
![]() |
eb300d0aa7 | ||
![]() |
f6cc245e40 | ||
![]() |
9ee5d066a2 | ||
![]() |
01243fb8e5 | ||
![]() |
a2a1ecde0a | ||
![]() |
a5958bf7f0 | ||
![]() |
7533206d89 | ||
![]() |
b0a12c02e1 | ||
![]() |
374b66ad8e | ||
![]() |
f85d8df71e | ||
![]() |
a707d31a4c | ||
![]() |
f1e0a096d5 | ||
![]() |
3f33d218b3 | ||
![]() |
99b90cbd5c | ||
![]() |
bad82e7204 | ||
![]() |
faae1218fa | ||
![]() |
064c3161c3 | ||
![]() |
8122f8ecbf | ||
![]() |
9dbc79dc96 | ||
![]() |
df9151481c | ||
![]() |
be7d646e83 | ||
![]() |
78c8bca2bb | ||
![]() |
751a23af0f | ||
![]() |
501f46e515 | ||
![]() |
31e1d4f839 | ||
![]() |
be22674f8c | ||
![]() |
d339b3f7d6 | ||
![]() |
602de0c370 | ||
![]() |
c96853816a | ||
![]() |
437af93201 | ||
![]() |
ae2c9a745e | ||
![]() |
5caab76a45 | ||
![]() |
9c37aa039b | ||
![]() |
3abe5b0d57 | ||
![]() |
90b949b8ce | ||
![]() |
69cb4d5787 | ||
![]() |
d8204641fa | ||
![]() |
7d0631cf26 | ||
![]() |
a1ec8b0a88 | ||
![]() |
5c72030fb8 | ||
![]() |
1908d26093 | ||
![]() |
16a68d78eb | ||
![]() |
4f8e5dfd7c | ||
![]() |
10bf3d383c | ||
![]() |
99332e4ec2 | ||
![]() |
6f944ab117 | ||
![]() |
1f9ac53c28 | ||
![]() |
a80c4a7f48 | ||
![]() |
0fa1220eca | ||
![]() |
d7b947dd79 | ||
![]() |
3b2c012723 | ||
![]() |
2e54afb295 | ||
![]() |
c19b692a66 | ||
![]() |
b1885badda | ||
![]() |
2a05af22e1 | ||
![]() |
4eb6304076 | ||
![]() |
9298b074fc | ||
![]() |
b520994960 | ||
![]() |
171f755c13 | ||
![]() |
5691046dcc | ||
![]() |
36927a7bbd | ||
![]() |
4d0c03fd4a | ||
![]() |
f663176a5d | ||
![]() |
ba1eb298de | ||
![]() |
8bcdd9c068 | ||
![]() |
46b1bafa17 | ||
![]() |
a711f4d86e | ||
![]() |
20ea0ee190 | ||
![]() |
74c2c6c74f | ||
![]() |
aa22d80c3f | ||
![]() |
0e315cbd8f | ||
![]() |
6b3746f3a6 | ||
![]() |
bfb8b46d7d | ||
![]() |
b5029ab940 | ||
![]() |
8b7eed3ffc | ||
![]() |
eaa18d4e3c | ||
![]() |
f4dc8dca8d | ||
![]() |
0efe9a4d0f | ||
![]() |
f1aea5176d | ||
![]() |
96560ed3ca | ||
![]() |
dc52cfb9bc | ||
![]() |
f62884ffda | ||
![]() |
f4bf53402f | ||
![]() |
ba109a4c53 | ||
![]() |
3a9633f553 | ||
![]() |
7bef4a5c70 | ||
![]() |
e82c8d2f70 | ||
![]() |
367f08c1b5 | ||
![]() |
a4b35f275c | ||
![]() |
c2adaf41c0 | ||
![]() |
517d7f04c6 | ||
![]() |
c59d5eef45 | ||
![]() |
951128389d | ||
![]() |
a583a9abe0 | ||
![]() |
7a4244ac8b | ||
![]() |
d59536a71c | ||
![]() |
f4110c43a7 | ||
![]() |
76483f9c7b | ||
![]() |
4c7c703ea2 | ||
![]() |
9061028ce5 | ||
![]() |
0bdd21b4e4 | ||
![]() |
636a90386b | ||
![]() |
db868ea400 | ||
![]() |
99c7fc4049 | ||
![]() |
75db253370 | ||
![]() |
6331eb1d8a | ||
![]() |
169cbe90a5 | ||
![]() |
f5c75a5f55 | ||
![]() |
3b5d9459f3 | ||
![]() |
bf995d659b | ||
![]() |
5e5ca2138e | ||
![]() |
63b50ff92c | ||
![]() |
927f398658 | ||
![]() |
f0cc8c0d54 | ||
![]() |
be6840f6a9 | ||
![]() |
15d10e47ea | ||
![]() |
eac1daa5f7 | ||
![]() |
b8aac357cb | ||
![]() |
fd3bfdae80 | ||
![]() |
0a23072938 | ||
![]() |
76b4da6212 | ||
![]() |
0885d8fce7 | ||
![]() |
f975c0603c | ||
![]() |
ad68318515 | ||
![]() |
c9ba8e989e | ||
![]() |
47ac8b6c03 | ||
![]() |
bc0b42ee53 | ||
![]() |
07baf17c2a | ||
![]() |
229740f557 | ||
![]() |
42dd79a32d | ||
![]() |
c38e1635ea | ||
![]() |
84a614dddc | ||
![]() |
f1c70ce53c | ||
![]() |
02f9d03f57 | ||
![]() |
bc85357235 | ||
![]() |
e1e697a3ff | ||
![]() |
10486db091 | ||
![]() |
e1ae052185 | ||
![]() |
22ca57b1f2 | ||
![]() |
4f1baece33 | ||
![]() |
0aaeea4837 | ||
![]() |
8a793f64bf | ||
![]() |
9424047214 | ||
![]() |
6860bb7349 | ||
![]() |
5b3e156197 | ||
![]() |
745cdd89fd | ||
![]() |
6f5dfc576f | ||
![]() |
54a1694a2b | ||
![]() |
14717b8ecb | ||
![]() |
3ed1c31678 | ||
![]() |
b6baf78812 | ||
![]() |
2af20b0d83 | ||
![]() |
cc583b6189 | ||
![]() |
da0ab005c7 | ||
![]() |
50aa0f5564 | ||
![]() |
f686b1df98 | ||
![]() |
48c621532c | ||
![]() |
7d756e79ae | ||
![]() |
8447412c77 | ||
![]() |
e67263cc0e | ||
![]() |
41496e035a | ||
![]() |
e40451a3f7 | ||
![]() |
154473d3b3 | ||
![]() |
fd3d3c4158 | ||
![]() |
b06790dfe5 | ||
![]() |
195b94c1f1 | ||
![]() |
90c01f8d92 | ||
![]() |
679f8f1f36 | ||
![]() |
e9b44af469 | ||
![]() |
0425bd0fd6 | ||
![]() |
e13fb2e366 | ||
![]() |
26bb3d40d9 | ||
![]() |
7af9de353b | ||
![]() |
b0169de7c4 | ||
![]() |
e042710eaa | ||
![]() |
2b9a8e5605 | ||
![]() |
bdf4a5249d | ||
![]() |
82cacec8eb | ||
![]() |
290e127a4f | ||
![]() |
32763b7af6 | ||
![]() |
1781fcb9ef | ||
![]() |
16451b01e8 | ||
![]() |
bb6cca3056 | ||
![]() |
b48975f116 | ||
![]() |
1cc9e0d37f | ||
![]() |
ad43ba5ec7 | ||
![]() |
57bdb6cac2 | ||
![]() |
1dca54c165 | ||
![]() |
67a74a9357 | ||
![]() |
7db30d12cb | ||
![]() |
0f8bd509b2 | ||
![]() |
d1e88c40d8 | ||
![]() |
46ef678f55 | ||
![]() |
d76210d24f | ||
![]() |
4dfe05db24 | ||
![]() |
3634026436 | ||
![]() |
455b23c6f1 | ||
![]() |
b2fb004414 | ||
![]() |
1e7f651b1b | ||
![]() |
c94cd531f0 | ||
![]() |
40cd5c57c5 | ||
![]() |
753a3072ee | ||
![]() |
43191ff426 | ||
![]() |
7728db0dd3 | ||
![]() |
6e12642151 | ||
![]() |
ebe2aadb4c | ||
![]() |
c9d425dc08 | ||
![]() |
5f2467b453 | ||
![]() |
3b1840b7a9 | ||
![]() |
50b27bebd8 | ||
![]() |
7624e9482c | ||
![]() |
642c0bc367 | ||
![]() |
98eb8cb741 | ||
![]() |
2188895b40 | ||
![]() |
40eef6a066 | ||
![]() |
b51c767296 | ||
![]() |
843cd01308 | ||
![]() |
22357f70c2 | ||
![]() |
04fe3a79b9 | ||
![]() |
34a4f6e60e | ||
![]() |
15b520f4a2 | ||
![]() |
5d4812d1a6 | ||
![]() |
f3afbfbcec | ||
![]() |
0e238c87cb | ||
![]() |
89d349ae1c | ||
![]() |
95d5343eb4 | ||
![]() |
214eab2c52 | ||
![]() |
8f2883a388 | ||
![]() |
fb0871dbc8 | ||
![]() |
9dc3e39fc2 | ||
![]() |
a7a8ebcd77 | ||
![]() |
d98face501 | ||
![]() |
cb14431ee5 | ||
![]() |
3c5cb093de | ||
![]() |
cfe249debe | ||
![]() |
78b4f10cc6 | ||
![]() |
46cbee1585 | ||
![]() |
78ea536c95 | ||
![]() |
1a00b1af24 | ||
![]() |
1eb0affdea | ||
![]() |
0d498f12b9 | ||
![]() |
f111395044 | ||
![]() |
0c3260b1b4 | ||
![]() |
e1f0cd65af | ||
![]() |
e972a8805d | ||
![]() |
f5d64239cb | ||
![]() |
00465d5e41 | ||
![]() |
126cb824ea | ||
![]() |
ecfc940381 | ||
![]() |
e757063d31 | ||
![]() |
131b6f90e0 | ||
![]() |
b879dd59c6 | ||
![]() |
b6ad512e34 | ||
![]() |
363604c6f0 | ||
![]() |
e4598e8821 | ||
![]() |
fffd373652 | ||
![]() |
f8f732e78c | ||
![]() |
e0d85a7e58 | ||
![]() |
97441b62d1 | ||
![]() |
8ad650582a | ||
![]() |
02ad2b78fa | ||
![]() |
cef7edaea9 | ||
![]() |
83abaafdfa | ||
![]() |
a55acae5ee | ||
![]() |
8d4261efba | ||
![]() |
56b2f6c4cf | ||
![]() |
0d65ef6f6e | ||
![]() |
c5cd4bc5cf | ||
![]() |
460c266e04 | ||
![]() |
831903799b | ||
![]() |
1d8c607c15 | ||
![]() |
83671ebf76 | ||
![]() |
84c27eea2a | ||
![]() |
e1550c9091 | ||
![]() |
259d5ef60b | ||
![]() |
9aa6c5b951 | ||
![]() |
c4bfaa6031 | ||
![]() |
f3810cebea | ||
![]() |
fda8f1afa3 | ||
![]() |
eed4de1da9 | ||
![]() |
8aea0fc7ee | ||
![]() |
ec0cf25097 | ||
![]() |
49fc210833 | ||
![]() |
f3c33b29dd | ||
![]() |
8057ed408c |
437 changed files with 93261 additions and 49065 deletions
|
@ -10,7 +10,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
|||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-18
|
||||
CLANG_FORMAT=clang-format-19
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$GITHUB_EVENT_NAME" = "pull_request" ]; then
|
||||
|
|
21
.github/ISSUE_TEMPLATE/app-bug-report.yaml
vendored
21
.github/ISSUE_TEMPLATE/app-bug-report.yaml
vendored
|
@ -53,3 +53,24 @@ body:
|
|||
placeholder: "Example: Windows 11, Arch Linux, MacOS 15"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: cpu
|
||||
attributes:
|
||||
label: CPU
|
||||
placeholder: "Example: Intel Core i7-8700"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: gpu
|
||||
attributes:
|
||||
label: GPU
|
||||
placeholder: "Example: nVidia GTX 1650"
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: ram
|
||||
attributes:
|
||||
label: Amount of RAM in GB
|
||||
placeholder: "Example: 16 GB"
|
||||
validations:
|
||||
required: true
|
||||
|
|
58
.github/workflows/build.yml
vendored
58
.github/workflows/build.yml
vendored
|
@ -30,9 +30,9 @@ jobs:
|
|||
- name: Install
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main'
|
||||
sudo add-apt-repository 'deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main'
|
||||
sudo apt update
|
||||
sudo apt install clang-format-18
|
||||
sudo apt install clang-format-19
|
||||
- name: Build
|
||||
env:
|
||||
COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
|
||||
|
@ -76,7 +76,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
|
@ -111,10 +111,10 @@ jobs:
|
|||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.7.3
|
||||
version: 6.9.0
|
||||
host: windows
|
||||
target: desktop
|
||||
arch: win64_msvc2019_64
|
||||
arch: win64_msvc2022_64
|
||||
archives: qtbase qttools
|
||||
modules: qtmultimedia
|
||||
|
||||
|
@ -130,7 +130,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-cache-cmake-build
|
||||
with:
|
||||
|
@ -186,7 +186,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{runner.os}}-sdl-cache-cmake-build
|
||||
with:
|
||||
|
@ -205,12 +205,12 @@ jobs:
|
|||
run: |
|
||||
mkdir upload
|
||||
mv ${{github.workspace}}/build/shadps4 upload
|
||||
cp ${{github.workspace}}/build/externals/MoltenVK/libMoltenVK.dylib upload
|
||||
tar cf shadps4-macos-sdl.tar.gz -C upload .
|
||||
mv ${{github.workspace}}/build/MoltenVK_icd.json upload
|
||||
mv ${{github.workspace}}/build/libMoltenVK.dylib upload
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
|
||||
path: shadps4-macos-sdl.tar.gz
|
||||
path: upload/
|
||||
|
||||
macos-qt:
|
||||
runs-on: macos-15
|
||||
|
@ -228,7 +228,7 @@ jobs:
|
|||
- name: Setup Qt
|
||||
uses: jurplel/install-qt-action@v4
|
||||
with:
|
||||
version: 6.7.3
|
||||
version: 6.9.0
|
||||
host: mac
|
||||
target: desktop
|
||||
arch: clang_64
|
||||
|
@ -247,7 +247,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{runner.os}}-qt-cache-cmake-build
|
||||
with:
|
||||
|
@ -281,8 +281,13 @@ jobs:
|
|||
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 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
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 libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
|
@ -296,7 +301,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-cache-cmake-build
|
||||
with:
|
||||
|
@ -304,7 +309,7 @@ jobs:
|
|||
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 -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
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" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||
|
@ -337,8 +342,13 @@ jobs:
|
|||
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 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
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
|
||||
|
@ -352,7 +362,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-cache-cmake-build
|
||||
with:
|
||||
|
@ -360,7 +370,7 @@ jobs:
|
|||
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 -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
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)
|
||||
|
@ -385,7 +395,7 @@ jobs:
|
|||
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 build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
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 libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
|
||||
- name: Cache CMake Configuration
|
||||
uses: actions/cache@v4
|
||||
|
@ -399,7 +409,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-sdl-gcc-cache-cmake-build
|
||||
with:
|
||||
|
@ -407,7 +417,7 @@ jobs:
|
|||
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_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
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" -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
|
||||
|
@ -421,7 +431,7 @@ jobs:
|
|||
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 build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev
|
||||
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
|
||||
|
@ -435,7 +445,7 @@ jobs:
|
|||
${{ env.cache-name }}-
|
||||
|
||||
- name: Cache CMake Build
|
||||
uses: hendrikmuhs/ccache-action@v1.2.14
|
||||
uses: hendrikmuhs/ccache-action@v1.2.17
|
||||
env:
|
||||
cache-name: ${{ runner.os }}-qt-gcc-cache-cmake-build
|
||||
with:
|
||||
|
@ -443,7 +453,7 @@ jobs:
|
|||
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 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
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)
|
||||
|
|
11
.github/workflows/scripts/update_translation.sh
vendored
Executable file
11
.github/workflows/scripts/update_translation.sh
vendored
Executable file
|
@ -0,0 +1,11 @@
|
|||
#!/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
Normal file
30
.github/workflows/update_translation.yml
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
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
|
15
.gitmodules
vendored
15
.gitmodules
vendored
|
@ -1,15 +1,3 @@
|
|||
[submodule "externals/cryptopp-cmake"]
|
||||
path = externals/cryptopp-cmake
|
||||
url = https://github.com/shadps4-emu/ext-cryptopp-cmake.git
|
||||
shallow = true
|
||||
[submodule "externals/cryptopp"]
|
||||
path = externals/cryptopp
|
||||
url = https://github.com/shadps4-emu/ext-cryptopp.git
|
||||
shallow = true
|
||||
[submodule "externals/cryptoppwin"]
|
||||
path = externals/cryptoppwin
|
||||
url = https://github.com/shadps4-emu/ext-cryptoppwin.git
|
||||
shallow = true
|
||||
[submodule "externals/zlib-ng"]
|
||||
path = externals/zlib-ng
|
||||
url = https://github.com/shadps4-emu/ext-zlib-ng.git
|
||||
|
@ -119,3 +107,6 @@
|
|||
path = externals/MoltenVK/cereal
|
||||
url = https://github.com/USCiLab/cereal
|
||||
shallow = true
|
||||
[submodule "externals/libusb"]
|
||||
path = externals/libusb
|
||||
url = https://github.com/libusb/libusb-cmake.git
|
||||
|
|
256
CMakeLists.txt
256
CMakeLists.txt
|
@ -8,15 +8,16 @@ set(CMAKE_CXX_STANDARD 23)
|
|||
set(CMAKE_CXX_STANDARD_REQUIRED True)
|
||||
|
||||
if(APPLE)
|
||||
enable_language(OBJC)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 14)
|
||||
list(APPEND ADDITIONAL_LANGUAGES OBJC)
|
||||
# Starting with 15.4, Rosetta 2 has support for all the necessary instruction sets.
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET 15.4 CACHE STRING "")
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release)
|
||||
endif()
|
||||
|
||||
project(shadPS4 CXX C ASM)
|
||||
project(shadPS4 CXX C ASM ${ADDITIONAL_LANGUAGES})
|
||||
|
||||
# Forcing PIE makes sure that the base address is high enough so that it doesn't clash with the PS4 memory.
|
||||
if(UNIX AND NOT APPLE)
|
||||
|
@ -37,8 +38,10 @@ option(ENABLE_UPDATER "Enables the options to updater" ON)
|
|||
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
|
||||
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
|
||||
set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
|
||||
else()
|
||||
elseif (CMAKE_SYSTEM_PROCESSOR)
|
||||
set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
|
||||
else()
|
||||
set(BASE_ARCHITECTURE "${CMAKE_HOST_SYSTEM_PROCESSOR}")
|
||||
endif()
|
||||
|
||||
# Next, match common architecture strings down to a known common value.
|
||||
|
@ -50,7 +53,13 @@ else()
|
|||
message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}")
|
||||
endif()
|
||||
|
||||
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
if (ARCHITECTURE STREQUAL "x86_64")
|
||||
# Target the same CPU architecture as the PS4, to maintain the same level of compatibility.
|
||||
# Exclude SSE4a as it is only available on AMD CPUs.
|
||||
add_compile_options(-march=btver2 -mtune=generic -mno-sse4a)
|
||||
endif()
|
||||
|
||||
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
# Exclude ARM homebrew path to avoid conflicts when cross compiling.
|
||||
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
|
||||
|
||||
|
@ -96,28 +105,82 @@ if (CLANG_FORMAT)
|
|||
unset(CCOMMENT)
|
||||
endif()
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
|
||||
# generate git revision information
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/")
|
||||
include(GetGitRevisionDescription)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules/GetGitRevisionDescription.cmake")
|
||||
get_git_head_revision(GIT_REF_SPEC GIT_REV)
|
||||
git_describe(GIT_DESC --always --long --dirty)
|
||||
git_branch_name(GIT_BRANCH)
|
||||
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
|
||||
|
||||
message("start git things")
|
||||
|
||||
# Try to get the upstream remote and branch
|
||||
message("check for remote and branch")
|
||||
execute_process(
|
||||
COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u}
|
||||
OUTPUT_VARIABLE GIT_REMOTE_NAME
|
||||
RESULT_VARIABLE GIT_BRANCH_RESULT
|
||||
RESULT_VARIABLE GIT_REMOTE_RESULT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Default to origin if there's no upstream set or if the command failed
|
||||
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
# If there's no upstream set or the command failed, check remote.pushDefault
|
||||
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
message("check default push")
|
||||
execute_process(
|
||||
COMMAND git config --get remote.pushDefault
|
||||
OUTPUT_VARIABLE GIT_REMOTE_NAME
|
||||
RESULT_VARIABLE GIT_REMOTE_RESULT
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
endif()
|
||||
|
||||
# If running in GitHub Actions and the above fails
|
||||
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
|
||||
message("check github")
|
||||
set(GIT_REMOTE_NAME "origin")
|
||||
|
||||
# Retrieve environment variables
|
||||
if (DEFINED ENV{GITHUB_HEAD_REF} AND NOT "$ENV{GITHUB_HEAD_REF}" STREQUAL "")
|
||||
message("github head ref: $ENV{GITHUB_HEAD_REF}")
|
||||
set(GITHUB_HEAD_REF "$ENV{GITHUB_HEAD_REF}")
|
||||
else()
|
||||
set(GITHUB_HEAD_REF "")
|
||||
endif()
|
||||
|
||||
if (DEFINED ENV{GITHUB_REF} AND NOT "$ENV{GITHUB_REF}" STREQUAL "")
|
||||
message("github ref: $ENV{GITHUB_REF}")
|
||||
string(REGEX REPLACE "^refs/[^/]*/" "" GITHUB_BRANCH "$ENV{GITHUB_REF}")
|
||||
string(REGEX MATCH "refs/pull/([0-9]+)/merge" MATCHED_REF "$ENV{GITHUB_REF}")
|
||||
if (MATCHED_REF)
|
||||
set(PR_NUMBER "${CMAKE_MATCH_1}")
|
||||
set(GITHUB_BRANCH "")
|
||||
message("PR number: ${PR_NUMBER}")
|
||||
else()
|
||||
set(PR_NUMBER "")
|
||||
endif()
|
||||
else()
|
||||
set(GITHUB_BRANCH "")
|
||||
set(PR_NUMBER "")
|
||||
endif()
|
||||
|
||||
if (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
|
||||
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_HEAD_REF}")
|
||||
elseif (NOT "${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
|
||||
set(GIT_BRANCH "pr-${PR_NUMBER}-${GITHUB_BRANCH}")
|
||||
elseif (NOT "${PR_NUMBER}" STREQUAL "")
|
||||
set(GIT_BRANCH "pr-${PR_NUMBER}")
|
||||
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_HEAD_REF}" STREQUAL "")
|
||||
set(GIT_BRANCH "${GITHUB_HEAD_REF}")
|
||||
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_BRANCH}" STREQUAL "")
|
||||
set(GIT_BRANCH "${GITHUB_BRANCH}")
|
||||
elseif ("${PR_NUMBER}" STREQUAL "" AND NOT "${GITHUB_REF}" STREQUAL "")
|
||||
set(GIT_BRANCH "${GITHUB_REF}")
|
||||
else()
|
||||
message("couldn't find branch")
|
||||
set(GIT_BRANCH "detached-head")
|
||||
endif()
|
||||
else()
|
||||
# Extract remote name if the output contains a remote/branch format
|
||||
string(FIND "${GIT_REMOTE_NAME}" "/" INDEX)
|
||||
|
@ -130,14 +193,27 @@ else()
|
|||
endif()
|
||||
|
||||
# Get remote link
|
||||
message("getting remote link")
|
||||
execute_process(
|
||||
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
|
||||
OUTPUT_VARIABLE GIT_REMOTE_URL
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# Set Version
|
||||
set(EMULATOR_VERSION_MAJOR "0")
|
||||
set(EMULATOR_VERSION_MINOR "8")
|
||||
set(EMULATOR_VERSION_PATCH "1")
|
||||
|
||||
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} 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}")
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||
find_package(Boost 1.84.0 CONFIG)
|
||||
find_package(FFmpeg 5.1.2 MODULE)
|
||||
find_package(fmt 10.2.0 CONFIG)
|
||||
|
@ -150,21 +226,18 @@ find_package(SDL3 3.1.2 CONFIG)
|
|||
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.305 CONFIG)
|
||||
find_package(VulkanHeaders 1.4.309 CONFIG)
|
||||
find_package(VulkanMemoryAllocator 3.1.0 CONFIG)
|
||||
find_package(xbyak 7.07 CONFIG)
|
||||
find_package(xxHash 0.8.2 MODULE)
|
||||
find_package(ZLIB 1.3 MODULE)
|
||||
find_package(Zydis 5.0.0 CONFIG)
|
||||
find_package(pugixml 1.14 CONFIG)
|
||||
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR NOT MSVC)
|
||||
find_package(cryptopp 8.9.0 MODULE)
|
||||
endif()
|
||||
|
||||
find_package(libusb 1.0.27 MODULE)
|
||||
if (APPLE)
|
||||
find_package(date 3.0.1 CONFIG)
|
||||
endif()
|
||||
list(POP_BACK CMAKE_MODULE_PATH)
|
||||
|
||||
# Note: Windows always has these functions through winpthreads
|
||||
include(CheckSymbolExists)
|
||||
|
@ -184,6 +257,7 @@ endif()
|
|||
|
||||
add_subdirectory(externals)
|
||||
include_directories(src)
|
||||
include_directories(Resources)
|
||||
|
||||
if(ENABLE_QT_GUI)
|
||||
find_package(Qt6 REQUIRED COMPONENTS Widgets Concurrent LinguistTools Network Multimedia)
|
||||
|
@ -266,6 +340,8 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
|
|||
src/core/libraries/kernel/threads/thread_state.h
|
||||
src/core/libraries/kernel/process.cpp
|
||||
src/core/libraries/kernel/process.h
|
||||
src/core/libraries/kernel/debug.cpp
|
||||
src/core/libraries/kernel/debug.h
|
||||
src/core/libraries/kernel/equeue.cpp
|
||||
src/core/libraries/kernel/equeue.h
|
||||
src/core/libraries/kernel/file_system.cpp
|
||||
|
@ -286,6 +362,7 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
|
|||
|
||||
set(NETWORK_LIBS src/core/libraries/network/http.cpp
|
||||
src/core/libraries/network/http.h
|
||||
src/core/libraries/network/http_error.h
|
||||
src/core/libraries/network/http2.cpp
|
||||
src/core/libraries/network/http2.h
|
||||
src/core/libraries/network/net.cpp
|
||||
|
@ -358,12 +435,28 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
|
|||
src/core/libraries/ngs2/ngs2_error.h
|
||||
src/core/libraries/ngs2/ngs2_impl.cpp
|
||||
src/core/libraries/ngs2/ngs2_impl.h
|
||||
src/core/libraries/ngs2/ngs2_custom.cpp
|
||||
src/core/libraries/ngs2/ngs2_custom.h
|
||||
src/core/libraries/ngs2/ngs2_reverb.cpp
|
||||
src/core/libraries/ngs2/ngs2_reverb.h
|
||||
src/core/libraries/ngs2/ngs2_geom.cpp
|
||||
src/core/libraries/ngs2/ngs2_geom.h
|
||||
src/core/libraries/ngs2/ngs2_pan.cpp
|
||||
src/core/libraries/ngs2/ngs2_pan.h
|
||||
src/core/libraries/ngs2/ngs2_report.cpp
|
||||
src/core/libraries/ngs2/ngs2_report.h
|
||||
src/core/libraries/ngs2/ngs2_eq.cpp
|
||||
src/core/libraries/ngs2/ngs2_eq.h
|
||||
src/core/libraries/ngs2/ngs2_mastering.cpp
|
||||
src/core/libraries/ngs2/ngs2_mastering.h
|
||||
src/core/libraries/ngs2/ngs2_sampler.cpp
|
||||
src/core/libraries/ngs2/ngs2_sampler.h
|
||||
src/core/libraries/ngs2/ngs2_submixer.cpp
|
||||
src/core/libraries/ngs2/ngs2_submixer.h
|
||||
src/core/libraries/ajm/ajm_error.h
|
||||
src/core/libraries/audio3d/audio3d.cpp
|
||||
src/core/libraries/audio3d/audio3d.h
|
||||
src/core/libraries/audio3d/audio3d_error.h
|
||||
src/core/libraries/audio3d/audio3d_impl.cpp
|
||||
src/core/libraries/audio3d/audio3d_impl.h
|
||||
src/core/libraries/game_live_streaming/gamelivestreaming.cpp
|
||||
src/core/libraries/game_live_streaming/gamelivestreaming.h
|
||||
src/core/libraries/remote_play/remoteplay.cpp
|
||||
|
@ -386,8 +479,17 @@ set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
|
|||
src/core/libraries/videoout/videoout_error.h
|
||||
)
|
||||
|
||||
set(LIBC_SOURCES src/core/libraries/libc_internal/libc_internal.cpp
|
||||
set(HLE_LIBC_INTERNAL_LIB src/core/libraries/libc_internal/libc_internal.cpp
|
||||
src/core/libraries/libc_internal/libc_internal.h
|
||||
src/core/libraries/libc_internal/libc_internal_io.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_io.h
|
||||
src/core/libraries/libc_internal/libc_internal_memory.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_memory.h
|
||||
src/core/libraries/libc_internal/libc_internal_str.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_str.h
|
||||
src/core/libraries/libc_internal/libc_internal_math.cpp
|
||||
src/core/libraries/libc_internal/libc_internal_math.h
|
||||
src/core/libraries/libc_internal/printf.h
|
||||
)
|
||||
|
||||
set(IME_LIB src/core/libraries/ime/error_dialog.cpp
|
||||
|
@ -468,6 +570,8 @@ set(NP_LIBS src/core/libraries/np_common/np_common.cpp
|
|||
src/core/libraries/np_web_api/np_web_api.h
|
||||
src/core/libraries/np_party/np_party.cpp
|
||||
src/core/libraries/np_party/np_party.h
|
||||
src/core/libraries/np_auth/np_auth.cpp
|
||||
src/core/libraries/np_auth/np_auth.h
|
||||
)
|
||||
|
||||
set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
||||
|
@ -475,10 +579,16 @@ set(ZLIB_LIB src/core/libraries/zlib/zlib.cpp
|
|||
src/core/libraries/zlib/zlib_error.h
|
||||
)
|
||||
|
||||
set(VR_LIBS src/core/libraries/hmd/hmd.cpp
|
||||
src/core/libraries/hmd/hmd.h
|
||||
)
|
||||
|
||||
set(MISC_LIBS src/core/libraries/screenshot/screenshot.cpp
|
||||
src/core/libraries/screenshot/screenshot.h
|
||||
src/core/libraries/move/move.cpp
|
||||
src/core/libraries/move/move.h
|
||||
src/core/libraries/ulobjmgr/ulobjmgr.cpp
|
||||
src/core/libraries/ulobjmgr/ulobjmgr.h
|
||||
)
|
||||
|
||||
set(DEV_TOOLS src/core/devtools/layer.cpp
|
||||
|
@ -518,6 +628,7 @@ set(COMMON src/common/logging/backend.cpp
|
|||
src/common/logging/text_formatter.cpp
|
||||
src/common/logging/text_formatter.h
|
||||
src/common/logging/types.h
|
||||
src/common/aes.h
|
||||
src/common/alignment.h
|
||||
src/common/arch.h
|
||||
src/common/assert.cpp
|
||||
|
@ -549,6 +660,7 @@ set(COMMON src/common/logging/backend.cpp
|
|||
src/common/polyfill_thread.h
|
||||
src/common/rdtsc.cpp
|
||||
src/common/rdtsc.h
|
||||
src/common/sha1.h
|
||||
src/common/signal_context.h
|
||||
src/common/signal_context.cpp
|
||||
src/common/singleton.h
|
||||
|
@ -558,6 +670,7 @@ set(COMMON src/common/logging/backend.cpp
|
|||
src/common/spin_lock.h
|
||||
src/common/stb.cpp
|
||||
src/common/stb.h
|
||||
src/common/string_literal.h
|
||||
src/common/string_util.cpp
|
||||
src/common/string_util.h
|
||||
src/common/thread.cpp
|
||||
|
@ -566,7 +679,6 @@ set(COMMON src/common/logging/backend.cpp
|
|||
src/common/uint128.h
|
||||
src/common/unique_function.h
|
||||
src/common/va_ctx.h
|
||||
src/common/version.h
|
||||
src/common/ntapi.h
|
||||
src/common/ntapi.cpp
|
||||
src/common/number_utils.h
|
||||
|
@ -587,9 +699,6 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
src/core/aerolib/aerolib.h
|
||||
src/core/address_space.cpp
|
||||
src/core/address_space.h
|
||||
src/core/crypto/crypto.cpp
|
||||
src/core/crypto/crypto.h
|
||||
src/core/crypto/keys.h
|
||||
src/core/devices/base_device.cpp
|
||||
src/core/devices/base_device.h
|
||||
src/core/devices/ioccom.h
|
||||
|
@ -607,22 +716,14 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
src/core/devices/srandom_device.cpp
|
||||
src/core/devices/srandom_device.h
|
||||
src/core/file_format/pfs.h
|
||||
src/core/file_format/pkg.cpp
|
||||
src/core/file_format/pkg.h
|
||||
src/core/file_format/pkg_type.cpp
|
||||
src/core/file_format/pkg_type.h
|
||||
src/core/file_format/psf.cpp
|
||||
src/core/file_format/psf.h
|
||||
src/core/file_format/playgo_chunk.cpp
|
||||
src/core/file_format/playgo_chunk.h
|
||||
src/core/file_format/trp.cpp
|
||||
src/core/file_format/trp.h
|
||||
src/core/file_format/splash.h
|
||||
src/core/file_format/splash.cpp
|
||||
src/core/file_sys/fs.cpp
|
||||
src/core/file_sys/fs.h
|
||||
src/core/loader.cpp
|
||||
src/core/loader.h
|
||||
src/core/loader/dwarf.cpp
|
||||
src/core/loader/dwarf.h
|
||||
src/core/loader/elf.cpp
|
||||
|
@ -638,7 +739,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
${KERNEL_LIB}
|
||||
${NETWORK_LIBS}
|
||||
${SYSTEM_LIBS}
|
||||
${LIBC_SOURCES}
|
||||
${HLE_LIBC_INTERNAL_LIB}
|
||||
${PAD_LIB}
|
||||
${VIDEOOUT_LIB}
|
||||
${NP_LIBS}
|
||||
|
@ -652,6 +753,7 @@ set(CORE src/core/aerolib/stubs.cpp
|
|||
${IME_LIB}
|
||||
${FIBER_LIB}
|
||||
${VDEC_LIB}
|
||||
${VR_LIBS}
|
||||
${DEV_TOOLS}
|
||||
src/core/debug_state.cpp
|
||||
src/core/debug_state.h
|
||||
|
@ -737,11 +839,14 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
|
|||
src/shader_recompiler/ir/passes/hull_shader_transform.cpp
|
||||
src/shader_recompiler/ir/passes/identity_removal_pass.cpp
|
||||
src/shader_recompiler/ir/passes/ir_passes.h
|
||||
src/shader_recompiler/ir/passes/lower_shared_mem_to_registers.cpp
|
||||
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
|
||||
src/shader_recompiler/ir/passes/lower_fp64_to_fp32.cpp
|
||||
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
|
||||
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
|
||||
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
|
||||
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
|
||||
src/shader_recompiler/ir/passes/shared_memory_barrier_pass.cpp
|
||||
src/shader_recompiler/ir/passes/shared_memory_to_storage_pass.cpp
|
||||
src/shader_recompiler/ir/passes/ssa_rewrite_pass.cpp
|
||||
src/shader_recompiler/ir/abstract_syntax_list.h
|
||||
src/shader_recompiler/ir/attribute.cpp
|
||||
|
@ -817,6 +922,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
|
|||
src/video_core/renderer_vulkan/vk_shader_util.h
|
||||
src/video_core/renderer_vulkan/vk_swapchain.cpp
|
||||
src/video_core/renderer_vulkan/vk_swapchain.h
|
||||
src/video_core/renderer_vulkan/host_passes/fsr_pass.cpp
|
||||
src/video_core/renderer_vulkan/host_passes/fsr_pass.h
|
||||
src/video_core/renderer_vulkan/host_passes/pp_pass.cpp
|
||||
src/video_core/renderer_vulkan/host_passes/pp_pass.h
|
||||
src/video_core/texture_cache/image.cpp
|
||||
src/video_core/texture_cache/image.h
|
||||
src/video_core/texture_cache/image_info.cpp
|
||||
|
@ -854,6 +963,10 @@ set(IMGUI src/imgui/imgui_config.h
|
|||
|
||||
set(INPUT src/input/controller.cpp
|
||||
src/input/controller.h
|
||||
src/input/input_handler.cpp
|
||||
src/input/input_handler.h
|
||||
src/input/input_mouse.cpp
|
||||
src/input/input_mouse.h
|
||||
)
|
||||
|
||||
set(EMULATOR src/emulator.cpp
|
||||
|
@ -882,6 +995,12 @@ set(QT_GUI src/qt_gui/about_dialog.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
|
||||
|
@ -895,14 +1014,14 @@ set(QT_GUI src/qt_gui/about_dialog.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/install_dir_select.cpp
|
||||
src/qt_gui/install_dir_select.h
|
||||
src/qt_gui/pkg_viewer.cpp
|
||||
src/qt_gui/pkg_viewer.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/settings_dialog.cpp
|
||||
|
@ -950,7 +1069,7 @@ 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)
|
||||
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)
|
||||
|
||||
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")
|
||||
|
@ -965,30 +1084,39 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND ENABLE_USERFAULTFD)
|
|||
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)
|
||||
# Include MoltenVK in the app bundle, along with an ICD file so it can be found by the system Vulkan loader if used for loading layers.
|
||||
set(MVK_ICD ${CMAKE_CURRENT_SOURCE_DIR}/externals/MoltenVK/MoltenVK_icd.json)
|
||||
target_sources(shadps4 PRIVATE ${MVK_ICD})
|
||||
set_source_files_properties(${MVK_ICD} PROPERTIES MACOSX_PACKAGE_LOCATION Resources/vulkan/icd.d)
|
||||
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})
|
||||
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(MVK_DYLIB_DST ${CMAKE_CURRENT_BINARY_DIR}/shadps4.app/Contents/Frameworks/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_DST ${MVK_DST}/MoltenVK_icd.json)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${MVK_DST})
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_ICD_DST}
|
||||
DEPENDS ${MVK_ICD_SRC} ${MVK_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_ICD_SRC} ${MVK_ICD_DST})
|
||||
add_custom_command(
|
||||
OUTPUT ${MVK_DYLIB_DST}
|
||||
DEPENDS ${MVK_DYLIB_SRC}
|
||||
COMMAND cmake -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
|
||||
add_custom_target(CopyMoltenVK DEPENDS ${MVK_DYLIB_DST})
|
||||
DEPENDS ${MVK_DYLIB_SRC} ${MVK_DST}
|
||||
COMMAND ${CMAKE_COMMAND} -E copy ${MVK_DYLIB_SRC} ${MVK_DYLIB_DST})
|
||||
add_custom_target(CopyMoltenVK DEPENDS ${MVK_ICD_DST} ${MVK_DYLIB_DST})
|
||||
add_dependencies(CopyMoltenVK MoltenVK)
|
||||
add_dependencies(shadps4 CopyMoltenVK)
|
||||
set_property(TARGET shadps4 APPEND PROPERTY BUILD_RPATH "@executable_path/../Frameworks")
|
||||
else()
|
||||
# For non-bundled SDL build, just do a normal library link.
|
||||
target_link_libraries(shadps4 PRIVATE MoltenVK)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE STREQUAL "x86_64")
|
||||
# Reserve system-managed memory space.
|
||||
target_link_options(shadps4 PRIVATE -Wl,-no_pie,-no_fixup_chains,-no_huge,-pagezero_size,0x4000,-segaddr,TCB_SPACE,0x4000,-segaddr,GUEST_SYSTEM,0x400000,-image_base,0x20000000000)
|
||||
target_link_options(shadps4 PRIVATE -Wl,-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)
|
||||
endif()
|
||||
|
||||
# Replacement for std::chrono::time_zone
|
||||
|
@ -999,12 +1127,6 @@ if (NOT ENABLE_QT_GUI)
|
|||
target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
|
||||
target_link_libraries(shadps4 PRIVATE cryptoppwin)
|
||||
else()
|
||||
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
|
||||
endif()
|
||||
|
||||
if (ENABLE_QT_GUI)
|
||||
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
|
||||
add_definitions(-DENABLE_QT_GUI)
|
||||
|
@ -1065,6 +1187,18 @@ add_subdirectory(${HOST_SHADERS_INCLUDE})
|
|||
add_dependencies(shadps4 host_shaders)
|
||||
target_include_directories(shadps4 PRIVATE ${HOST_SHADERS_INCLUDE})
|
||||
|
||||
# embed resources
|
||||
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake")
|
||||
cmrc_add_resource_library(embedded-resources
|
||||
ALIAS res::embedded
|
||||
NAMESPACE res
|
||||
src/images/bronze.png
|
||||
src/images/gold.png
|
||||
src/images/platinum.png
|
||||
src/images/silver.png)
|
||||
target_link_libraries(shadps4 PRIVATE res::embedded)
|
||||
|
||||
# ImGui resources
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src/imgui/renderer)
|
||||
add_dependencies(shadps4 ImGui_Resources)
|
||||
|
@ -1076,7 +1210,7 @@ if (ENABLE_QT_GUI)
|
|||
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 "0.4.1"
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING "${APP_VERSION}"
|
||||
)
|
||||
|
||||
set_source_files_properties(src/images/shadPS4.icns PROPERTIES
|
||||
|
|
44
README.md
44
README.md
|
@ -13,7 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
||||
<h1 align="center">
|
||||
<a href="https://discord.gg/bFJxfftGW6">
|
||||
<img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4 Discord&logo=Discord&logoColor=white" width="240">
|
||||
<img src="https://img.shields.io/discord/1080089157554155590?color=5865F2&label=shadPS4%20Discord&logo=Discord&logoColor=white" width="275">
|
||||
<a href="https://github.com/shadps4-emu/shadPS4/releases/latest">
|
||||
<img src="https://img.shields.io/github/downloads/shadps4-emu/shadPS4/total.svg" width="140">
|
||||
<a href="https://shadps4.net/">
|
||||
|
@ -71,13 +71,13 @@ Check the build instructions for [**Linux**](https://github.com/shadps4-emu/shad
|
|||
Check the build instructions for [**macOS**](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-macos.md).
|
||||
|
||||
> [!IMPORTANT]
|
||||
> macOS users need at least macOS 15 on Apple Silicon-based Mac devices and at least macOS 14 on Intel-based Mac devices.
|
||||
> macOS users need at least macOS 15.4 to run shadPS4. Due to GPU issues there are currently heavy bugs on Intel Macs.
|
||||
|
||||
# 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).
|
||||
|
||||
# Keyboard mapping
|
||||
# Keyboard and Mouse Mappings
|
||||
|
||||
> [!NOTE]
|
||||
> Some keyboards may also require you to hold the Fn key to use the F\* keys. Mac users should use the Command key instead of Control, and need to use Command+F11 for full screen to avoid conflicting with system key bindings.
|
||||
|
@ -119,19 +119,40 @@ R2 | O |
|
|||
L3 | X |
|
||||
R3 | M |
|
||||
|
||||
Keyboard and mouse inputs can be customized in the settings menu by clicking the Controller button, and further details and help on controls are also found there. Custom bindings are saved per-game. Inputs support up to three keys per binding, mouse buttons, mouse movement mapped to joystick input, and more.
|
||||
|
||||
|
||||
# Firmware files
|
||||
|
||||
shadPS4 can load some PlayStation 4 firmware files, these must be dumped from your legally owned PlayStation 4 console.\
|
||||
The following firmware modules are supported and must be placed in shadPS4's `user/sys_modules` folder.
|
||||
|
||||
<div align="center">
|
||||
|
||||
| Modules | Modules | Modules | Modules |
|
||||
|-------------------------|-------------------------|-------------------------|-------------------------|
|
||||
| libSceCesCs.sprx | libSceFont.sprx | libSceFontFt.sprx | libSceFreeTypeOt.sprx |
|
||||
| libSceJson.sprx | libSceJson2.sprx | libSceLibcInternal.sprx | libSceNgs2.sprx |
|
||||
| libSceRtc.sprx | libSceUlt.sprx | | |
|
||||
|
||||
</div>
|
||||
|
||||
> [!Caution]
|
||||
> The above modules are required to run the games properly and must be extracted from your PlayStation 4.\
|
||||
> **We do not provide any information or support on how to do this**.
|
||||
|
||||
|
||||
|
||||
# Main team
|
||||
|
||||
- [**georgemoralis**](https://github.com/georgemoralis)
|
||||
- [**raphaelthegreat**](https://github.com/raphaelthegreat)
|
||||
- [**psucien**](https://github.com/psucien)
|
||||
- [**skmp**](https://github.com/skmp)
|
||||
- [**wheremyfoodat**](https://github.com/wheremyfoodat)
|
||||
- [**raziel1000**](https://github.com/raziel1000)
|
||||
- [**viniciuslrangel**](https://github.com/viniciuslrangel)
|
||||
- [**roamic**](https://github.com/vladmikhalin)
|
||||
- [**poly**](https://github.com/polybiusproxy)
|
||||
- [**squidbus**](https://github.com/squidbus)
|
||||
- [**frodo**](https://github.com/baggins183)
|
||||
- [**Stephen Miller**](https://github.com/StevenMiller123)
|
||||
- [**kalaposfos13**](https://github.com/kalaposfos13)
|
||||
|
||||
Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
||||
|
||||
|
@ -140,10 +161,13 @@ Logo is done by [**Xphalnos**](https://github.com/Xphalnos)
|
|||
If you want to contribute, please look the [**CONTRIBUTING.md**](https://github.com/shadps4-emu/shadPS4/blob/main/CONTRIBUTING.md) file.\
|
||||
Open a PR and we'll check it :)
|
||||
|
||||
# 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=15">
|
||||
<img src="https://contrib.rocks/image?repo=shadps4-emu/shadPS4&max=24">
|
||||
</a>
|
||||
|
||||
|
||||
|
@ -157,7 +181,7 @@ A few noteworthy teams/projects who've helped us along the way are:
|
|||
|
||||
- **yuzu**: Our shader compiler has been designed with yuzu's Hades compiler as a blueprint. This allowed us to focus on the challenges of emulating a modern AMD GPU while having a high-quality optimizing shader compiler implementation as a base.
|
||||
|
||||
- [**hydra**](https://github.com/hydra-emu/hydra): A multisystem, multiplatform emulator (chip-8, GB, NES, N64) from Paris.
|
||||
- [**felix86**](https://github.com/OFFTKP/felix86): A new x86-64 → RISC-V Linux userspace emulator
|
||||
|
||||
# License
|
||||
|
||||
|
|
32
REUSE.toml
32
REUSE.toml
|
@ -3,9 +3,12 @@ version = 1
|
|||
[[annotations]]
|
||||
path = [
|
||||
"REUSE.toml",
|
||||
"crowdin.yml",
|
||||
"CMakeSettings.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",
|
||||
|
@ -17,12 +20,17 @@ path = [
|
|||
"documents/Screenshots/Linux/*",
|
||||
"externals/MoltenVK/MoltenVK_icd.json",
|
||||
"scripts/ps4_names.txt",
|
||||
"src/images/bronze.png",
|
||||
"src/images/gold.png",
|
||||
"src/images/platinum.png",
|
||||
"src/images/silver.png",
|
||||
"src/images/about_icon.png",
|
||||
"src/images/controller_icon.png",
|
||||
"src/images/discord.png",
|
||||
"src/images/dump_icon.png",
|
||||
"src/images/exit_icon.png",
|
||||
"src/images/file_icon.png",
|
||||
"src/images/trophy_icon.png",
|
||||
"src/images/flag_china.png",
|
||||
"src/images/flag_eu.png",
|
||||
"src/images/flag_jp.png",
|
||||
|
@ -32,25 +40,38 @@ path = [
|
|||
"src/images/folder_icon.png",
|
||||
"src/images/github.png",
|
||||
"src/images/grid_icon.png",
|
||||
"src/images/keyboard_icon.png",
|
||||
"src/images/iconsize_icon.png",
|
||||
"src/images/KBM.png",
|
||||
"src/images/ko-fi.png",
|
||||
"src/images/list_icon.png",
|
||||
"src/images/list_mode_icon.png",
|
||||
"src/images/pause_icon.png",
|
||||
"src/images/play_icon.png",
|
||||
"src/images/refresh_icon.png",
|
||||
"src/images/ps4_controller.png",
|
||||
"src/images/restart_game_icon.png",
|
||||
"src/images/refreshlist_icon.png",
|
||||
"src/images/settings_icon.png",
|
||||
"src/images/fullscreen_icon.png",
|
||||
"src/images/stop_icon.png",
|
||||
"src/images/utils_icon.png",
|
||||
"src/images/shadPS4.icns",
|
||||
"src/images/shadps4.ico",
|
||||
"src/images/shadps4.png",
|
||||
"src/images/net.shadps4.shadPS4.svg",
|
||||
"src/images/themes_icon.png",
|
||||
"src/images/update_icon.png",
|
||||
"src/images/youtube.png",
|
||||
"src/images/website.png",
|
||||
"src/images/discord.svg",
|
||||
"src/images/github.svg",
|
||||
"src/images/ko-fi.svg",
|
||||
"src/images/shadps4.svg",
|
||||
"src/images/website.svg",
|
||||
"src/images/youtube.svg",
|
||||
"src/shadps4.qrc",
|
||||
"src/shadps4.rc",
|
||||
"src/qt_gui/translations/update_translation.sh",
|
||||
]
|
||||
precedence = "aggregate"
|
||||
SPDX-FileCopyrightText = "shadPS4 Emulator Project"
|
||||
|
@ -97,3 +118,12 @@ path = "externals/gcn/include/**"
|
|||
SPDX-FileCopyrightText = "NONE"
|
||||
SPDX-License-Identifier = "CC0-1.0"
|
||||
|
||||
[[annotations]]
|
||||
path = "cmake/CMakeRC.cmake"
|
||||
SPDX-FileCopyrightText = "Copyright (c) 2017 vector-of-bool <vectorofbool@gmail.com>"
|
||||
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"
|
||||
|
|
666
cmake/CMakeRC.cmake
Normal file
666
cmake/CMakeRC.cmake
Normal file
|
@ -0,0 +1,666 @@
|
|||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2017 vector-of-bool <vectorofbool@gmail.com>
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
# This block is executed when generating an intermediate resource file, not when
|
||||
# running in CMake configure mode
|
||||
if(_CMRC_GENERATE_MODE)
|
||||
# Read in the digits
|
||||
file(READ "${INPUT_FILE}" bytes HEX)
|
||||
# Format each pair into a character literal. Heuristics seem to favor doing
|
||||
# the conversion in groups of five for fastest conversion
|
||||
string(REGEX REPLACE "(..)(..)(..)(..)(..)" "'\\\\x\\1','\\\\x\\2','\\\\x\\3','\\\\x\\4','\\\\x\\5'," chars "${bytes}")
|
||||
# Since we did this in groups, we have some leftovers to clean up
|
||||
string(LENGTH "${bytes}" n_bytes2)
|
||||
math(EXPR n_bytes "${n_bytes2} / 2")
|
||||
math(EXPR remainder "${n_bytes} % 5") # <-- '5' is the grouping count from above
|
||||
set(cleanup_re "$")
|
||||
set(cleanup_sub )
|
||||
while(remainder)
|
||||
set(cleanup_re "(..)${cleanup_re}")
|
||||
set(cleanup_sub "'\\\\x\\${remainder}',${cleanup_sub}")
|
||||
math(EXPR remainder "${remainder} - 1")
|
||||
endwhile()
|
||||
if(NOT cleanup_re STREQUAL "$")
|
||||
string(REGEX REPLACE "${cleanup_re}" "${cleanup_sub}" chars "${chars}")
|
||||
endif()
|
||||
string(CONFIGURE [[
|
||||
namespace { const char file_array[] = { @chars@ 0 }; }
|
||||
namespace cmrc { namespace @NAMESPACE@ { namespace res_chars {
|
||||
extern const char* const @SYMBOL@_begin = file_array;
|
||||
extern const char* const @SYMBOL@_end = file_array + @n_bytes@;
|
||||
}}}
|
||||
]] code)
|
||||
file(WRITE "${OUTPUT_FILE}" "${code}")
|
||||
# Exit from the script. Nothing else needs to be processed
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_version 2.0.0)
|
||||
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
include(CMakeParseArguments)
|
||||
|
||||
if(COMMAND cmrc_add_resource_library)
|
||||
if(NOT DEFINED _CMRC_VERSION OR NOT (_version STREQUAL _CMRC_VERSION))
|
||||
message(WARNING "More than one CMakeRC version has been included in this project.")
|
||||
endif()
|
||||
# CMakeRC has already been included! Don't do anything
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(_CMRC_VERSION "${_version}" CACHE INTERNAL "CMakeRC version. Used for checking for conflicts")
|
||||
|
||||
set(_CMRC_SCRIPT "${CMAKE_CURRENT_LIST_FILE}" CACHE INTERNAL "Path to CMakeRC script")
|
||||
|
||||
function(_cmrc_normalize_path var)
|
||||
set(path "${${var}}")
|
||||
file(TO_CMAKE_PATH "${path}" path)
|
||||
while(path MATCHES "//")
|
||||
string(REPLACE "//" "/" path "${path}")
|
||||
endwhile()
|
||||
string(REGEX REPLACE "/+$" "" path "${path}")
|
||||
set("${var}" "${path}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
get_filename_component(_inc_dir "${CMAKE_BINARY_DIR}/_cmrc/include" ABSOLUTE)
|
||||
set(CMRC_INCLUDE_DIR "${_inc_dir}" CACHE INTERNAL "Directory for CMakeRC include files")
|
||||
# Let's generate the primary include file
|
||||
file(MAKE_DIRECTORY "${CMRC_INCLUDE_DIR}/cmrc")
|
||||
set(hpp_content [==[
|
||||
#ifndef CMRC_CMRC_HPP_INCLUDED
|
||||
#define CMRC_CMRC_HPP_INCLUDED
|
||||
|
||||
#include <cassert>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
|
||||
#if !(defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) || defined(CMRC_NO_EXCEPTIONS))
|
||||
#define CMRC_NO_EXCEPTIONS 1
|
||||
#endif
|
||||
|
||||
namespace cmrc { namespace detail { struct dummy; } }
|
||||
|
||||
#define CMRC_DECLARE(libid) \
|
||||
namespace cmrc { namespace detail { \
|
||||
struct dummy; \
|
||||
static_assert(std::is_same<dummy, ::cmrc::detail::dummy>::value, "CMRC_DECLARE() must only appear at the global namespace"); \
|
||||
} } \
|
||||
namespace cmrc { namespace libid { \
|
||||
cmrc::embedded_filesystem get_filesystem(); \
|
||||
} } static_assert(true, "")
|
||||
|
||||
namespace cmrc {
|
||||
|
||||
class file {
|
||||
const char* _begin = nullptr;
|
||||
const char* _end = nullptr;
|
||||
|
||||
public:
|
||||
using iterator = const char*;
|
||||
using const_iterator = iterator;
|
||||
iterator begin() const noexcept { return _begin; }
|
||||
iterator cbegin() const noexcept { return _begin; }
|
||||
iterator end() const noexcept { return _end; }
|
||||
iterator cend() const noexcept { return _end; }
|
||||
std::size_t size() const { return static_cast<std::size_t>(std::distance(begin(), end())); }
|
||||
|
||||
file() = default;
|
||||
file(iterator beg, iterator end) noexcept : _begin(beg), _end(end) {}
|
||||
};
|
||||
|
||||
class directory_entry;
|
||||
|
||||
namespace detail {
|
||||
|
||||
class directory;
|
||||
class file_data;
|
||||
|
||||
class file_or_directory {
|
||||
union _data_t {
|
||||
class file_data* file_data;
|
||||
class directory* directory;
|
||||
} _data;
|
||||
bool _is_file = true;
|
||||
|
||||
public:
|
||||
explicit file_or_directory(file_data& f) {
|
||||
_data.file_data = &f;
|
||||
}
|
||||
explicit file_or_directory(directory& d) {
|
||||
_data.directory = &d;
|
||||
_is_file = false;
|
||||
}
|
||||
bool is_file() const noexcept {
|
||||
return _is_file;
|
||||
}
|
||||
bool is_directory() const noexcept {
|
||||
return !is_file();
|
||||
}
|
||||
const directory& as_directory() const noexcept {
|
||||
assert(!is_file());
|
||||
return *_data.directory;
|
||||
}
|
||||
const file_data& as_file() const noexcept {
|
||||
assert(is_file());
|
||||
return *_data.file_data;
|
||||
}
|
||||
};
|
||||
|
||||
class file_data {
|
||||
public:
|
||||
const char* begin_ptr;
|
||||
const char* end_ptr;
|
||||
file_data(const file_data&) = delete;
|
||||
file_data(const char* b, const char* e) : begin_ptr(b), end_ptr(e) {}
|
||||
};
|
||||
|
||||
inline std::pair<std::string, std::string> split_path(const std::string& path) {
|
||||
auto first_sep = path.find("/");
|
||||
if (first_sep == path.npos) {
|
||||
return std::make_pair(path, "");
|
||||
} else {
|
||||
return std::make_pair(path.substr(0, first_sep), path.substr(first_sep + 1));
|
||||
}
|
||||
}
|
||||
|
||||
struct created_subdirectory {
|
||||
class directory& directory;
|
||||
class file_or_directory& index_entry;
|
||||
};
|
||||
|
||||
class directory {
|
||||
std::list<file_data> _files;
|
||||
std::list<directory> _dirs;
|
||||
std::map<std::string, file_or_directory> _index;
|
||||
|
||||
using base_iterator = std::map<std::string, file_or_directory>::const_iterator;
|
||||
|
||||
public:
|
||||
|
||||
directory() = default;
|
||||
directory(const directory&) = delete;
|
||||
|
||||
created_subdirectory add_subdir(std::string name) & {
|
||||
_dirs.emplace_back();
|
||||
auto& back = _dirs.back();
|
||||
auto& fod = _index.emplace(name, file_or_directory{back}).first->second;
|
||||
return created_subdirectory{back, fod};
|
||||
}
|
||||
|
||||
file_or_directory* add_file(std::string name, const char* begin, const char* end) & {
|
||||
assert(_index.find(name) == _index.end());
|
||||
_files.emplace_back(begin, end);
|
||||
return &_index.emplace(name, file_or_directory{_files.back()}).first->second;
|
||||
}
|
||||
|
||||
const file_or_directory* get(const std::string& path) const {
|
||||
auto pair = split_path(path);
|
||||
auto child = _index.find(pair.first);
|
||||
if (child == _index.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
auto& entry = child->second;
|
||||
if (pair.second.empty()) {
|
||||
// We're at the end of the path
|
||||
return &entry;
|
||||
}
|
||||
|
||||
if (entry.is_file()) {
|
||||
// We can't traverse into a file. Stop.
|
||||
return nullptr;
|
||||
}
|
||||
// Keep going down
|
||||
return entry.as_directory().get(pair.second);
|
||||
}
|
||||
|
||||
class iterator {
|
||||
base_iterator _base_iter;
|
||||
base_iterator _end_iter;
|
||||
public:
|
||||
using value_type = directory_entry;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
iterator() = default;
|
||||
explicit iterator(base_iterator iter, base_iterator end) : _base_iter(iter), _end_iter(end) {}
|
||||
|
||||
iterator begin() const noexcept {
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator end() const noexcept {
|
||||
return iterator(_end_iter, _end_iter);
|
||||
}
|
||||
|
||||
inline value_type operator*() const noexcept;
|
||||
|
||||
bool operator==(const iterator& rhs) const noexcept {
|
||||
return _base_iter == rhs._base_iter;
|
||||
}
|
||||
|
||||
bool operator!=(const iterator& rhs) const noexcept {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
iterator& operator++() noexcept {
|
||||
++_base_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator operator++(int) noexcept {
|
||||
auto cp = *this;
|
||||
++_base_iter;
|
||||
return cp;
|
||||
}
|
||||
};
|
||||
|
||||
using const_iterator = iterator;
|
||||
|
||||
iterator begin() const noexcept {
|
||||
return iterator(_index.begin(), _index.end());
|
||||
}
|
||||
|
||||
iterator end() const noexcept {
|
||||
return iterator();
|
||||
}
|
||||
};
|
||||
|
||||
inline std::string normalize_path(std::string path) {
|
||||
while (path.find("/") == 0) {
|
||||
path.erase(path.begin());
|
||||
}
|
||||
while (!path.empty() && (path.rfind("/") == path.size() - 1)) {
|
||||
path.pop_back();
|
||||
}
|
||||
auto off = path.npos;
|
||||
while ((off = path.find("//")) != path.npos) {
|
||||
path.erase(path.begin() + static_cast<std::string::difference_type>(off));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
using index_type = std::map<std::string, const cmrc::detail::file_or_directory*>;
|
||||
|
||||
} // detail
|
||||
|
||||
class directory_entry {
|
||||
std::string _fname;
|
||||
const detail::file_or_directory* _item;
|
||||
|
||||
public:
|
||||
directory_entry() = delete;
|
||||
explicit directory_entry(std::string filename, const detail::file_or_directory& item)
|
||||
: _fname(filename)
|
||||
, _item(&item)
|
||||
{}
|
||||
|
||||
const std::string& filename() const & {
|
||||
return _fname;
|
||||
}
|
||||
std::string filename() const && {
|
||||
return std::move(_fname);
|
||||
}
|
||||
|
||||
bool is_file() const {
|
||||
return _item->is_file();
|
||||
}
|
||||
|
||||
bool is_directory() const {
|
||||
return _item->is_directory();
|
||||
}
|
||||
};
|
||||
|
||||
directory_entry detail::directory::iterator::operator*() const noexcept {
|
||||
assert(begin() != end());
|
||||
return directory_entry(_base_iter->first, _base_iter->second);
|
||||
}
|
||||
|
||||
using directory_iterator = detail::directory::iterator;
|
||||
|
||||
class embedded_filesystem {
|
||||
// Never-null:
|
||||
const cmrc::detail::index_type* _index;
|
||||
const detail::file_or_directory* _get(std::string path) const {
|
||||
path = detail::normalize_path(path);
|
||||
auto found = _index->find(path);
|
||||
if (found == _index->end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
return found->second;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit embedded_filesystem(const detail::index_type& index)
|
||||
: _index(&index)
|
||||
{}
|
||||
|
||||
file open(const std::string& path) const {
|
||||
auto entry_ptr = _get(path);
|
||||
if (!entry_ptr || !entry_ptr->is_file()) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
|
||||
#endif
|
||||
}
|
||||
auto& dat = entry_ptr->as_file();
|
||||
return file{dat.begin_ptr, dat.end_ptr};
|
||||
}
|
||||
|
||||
bool is_file(const std::string& path) const noexcept {
|
||||
auto entry_ptr = _get(path);
|
||||
return entry_ptr && entry_ptr->is_file();
|
||||
}
|
||||
|
||||
bool is_directory(const std::string& path) const noexcept {
|
||||
auto entry_ptr = _get(path);
|
||||
return entry_ptr && entry_ptr->is_directory();
|
||||
}
|
||||
|
||||
bool exists(const std::string& path) const noexcept {
|
||||
return !!_get(path);
|
||||
}
|
||||
|
||||
directory_iterator iterate_directory(const std::string& path) const {
|
||||
auto entry_ptr = _get(path);
|
||||
if (!entry_ptr) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error no such file or directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::no_such_file_or_directory), path);
|
||||
#endif
|
||||
}
|
||||
if (!entry_ptr->is_directory()) {
|
||||
#ifdef CMRC_NO_EXCEPTIONS
|
||||
fprintf(stderr, "Error not a directory: %s\n", path.c_str());
|
||||
abort();
|
||||
#else
|
||||
throw std::system_error(make_error_code(std::errc::not_a_directory), path);
|
||||
#endif
|
||||
}
|
||||
return entry_ptr->as_directory().begin();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // CMRC_CMRC_HPP_INCLUDED
|
||||
]==])
|
||||
|
||||
set(cmrc_hpp "${CMRC_INCLUDE_DIR}/cmrc/cmrc.hpp" CACHE INTERNAL "")
|
||||
set(_generate 1)
|
||||
if(EXISTS "${cmrc_hpp}")
|
||||
file(READ "${cmrc_hpp}" _current)
|
||||
if(_current STREQUAL hpp_content)
|
||||
set(_generate 0)
|
||||
endif()
|
||||
endif()
|
||||
file(GENERATE OUTPUT "${cmrc_hpp}" CONTENT "${hpp_content}" CONDITION ${_generate})
|
||||
|
||||
add_library(cmrc-base INTERFACE)
|
||||
target_include_directories(cmrc-base INTERFACE $<BUILD_INTERFACE:${CMRC_INCLUDE_DIR}>)
|
||||
# Signal a basic C++11 feature to require C++11.
|
||||
target_compile_features(cmrc-base INTERFACE cxx_nullptr)
|
||||
set_property(TARGET cmrc-base PROPERTY INTERFACE_CXX_EXTENSIONS OFF)
|
||||
add_library(cmrc::base ALIAS cmrc-base)
|
||||
|
||||
function(cmrc_add_resource_library name)
|
||||
set(args ALIAS NAMESPACE TYPE)
|
||||
cmake_parse_arguments(ARG "" "${args}" "" "${ARGN}")
|
||||
# Generate the identifier for the resource library's namespace
|
||||
set(ns_re "[a-zA-Z_][a-zA-Z0-9_]*")
|
||||
if(NOT DEFINED ARG_NAMESPACE)
|
||||
# Check that the library name is also a valid namespace
|
||||
if(NOT name MATCHES "${ns_re}")
|
||||
message(SEND_ERROR "Library name is not a valid namespace. Specify the NAMESPACE argument")
|
||||
endif()
|
||||
set(ARG_NAMESPACE "${name}")
|
||||
else()
|
||||
if(NOT ARG_NAMESPACE MATCHES "${ns_re}")
|
||||
message(SEND_ERROR "NAMESPACE for ${name} is not a valid C++ namespace identifier (${ARG_NAMESPACE})")
|
||||
endif()
|
||||
endif()
|
||||
set(libname "${name}")
|
||||
# Check that type is either "STATIC" or "OBJECT", or default to "STATIC" if
|
||||
# not set
|
||||
if(NOT DEFINED ARG_TYPE)
|
||||
set(ARG_TYPE STATIC)
|
||||
elseif(NOT "${ARG_TYPE}" MATCHES "^(STATIC|OBJECT)$")
|
||||
message(SEND_ERROR "${ARG_TYPE} is not a valid TYPE (STATIC and OBJECT are acceptable)")
|
||||
set(ARG_TYPE STATIC)
|
||||
endif()
|
||||
# Generate a library with the compiled in character arrays.
|
||||
string(CONFIGURE [=[
|
||||
#include <cmrc/cmrc.hpp>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace cmrc {
|
||||
namespace @ARG_NAMESPACE@ {
|
||||
|
||||
namespace res_chars {
|
||||
// These are the files which are available in this resource library
|
||||
$<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_EXTERN_DECLS>,
|
||||
>
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const cmrc::detail::index_type&
|
||||
get_root_index() {
|
||||
static cmrc::detail::directory root_directory_;
|
||||
static cmrc::detail::file_or_directory root_directory_fod{root_directory_};
|
||||
static cmrc::detail::index_type root_index;
|
||||
root_index.emplace("", &root_directory_fod);
|
||||
struct dir_inl {
|
||||
class cmrc::detail::directory& directory;
|
||||
};
|
||||
dir_inl root_directory_dir{root_directory_};
|
||||
(void)root_directory_dir;
|
||||
$<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_MAKE_DIRS>,
|
||||
>
|
||||
$<JOIN:$<TARGET_PROPERTY:@libname@,CMRC_MAKE_FILES>,
|
||||
>
|
||||
return root_index;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
cmrc::embedded_filesystem get_filesystem() {
|
||||
static auto& index = get_root_index();
|
||||
return cmrc::embedded_filesystem{index};
|
||||
}
|
||||
|
||||
} // @ARG_NAMESPACE@
|
||||
} // cmrc
|
||||
]=] cpp_content @ONLY)
|
||||
get_filename_component(libdir "${CMAKE_CURRENT_BINARY_DIR}/__cmrc_${name}" ABSOLUTE)
|
||||
get_filename_component(lib_tmp_cpp "${libdir}/lib_.cpp" ABSOLUTE)
|
||||
string(REPLACE "\n " "\n" cpp_content "${cpp_content}")
|
||||
file(GENERATE OUTPUT "${lib_tmp_cpp}" CONTENT "${cpp_content}")
|
||||
get_filename_component(libcpp "${libdir}/lib.cpp" ABSOLUTE)
|
||||
add_custom_command(OUTPUT "${libcpp}"
|
||||
DEPENDS "${lib_tmp_cpp}" "${cmrc_hpp}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${lib_tmp_cpp}" "${libcpp}"
|
||||
COMMENT "Generating ${name} resource loader"
|
||||
)
|
||||
# Generate the actual static library. Each source file is just a single file
|
||||
# with a character array compiled in containing the contents of the
|
||||
# corresponding resource file.
|
||||
add_library(${name} ${ARG_TYPE} ${libcpp})
|
||||
set_property(TARGET ${name} PROPERTY CMRC_LIBDIR "${libdir}")
|
||||
set_property(TARGET ${name} PROPERTY CMRC_NAMESPACE "${ARG_NAMESPACE}")
|
||||
target_link_libraries(${name} PUBLIC cmrc::base)
|
||||
set_property(TARGET ${name} PROPERTY CMRC_IS_RESOURCE_LIBRARY TRUE)
|
||||
if(ARG_ALIAS)
|
||||
add_library("${ARG_ALIAS}" ALIAS ${name})
|
||||
endif()
|
||||
cmrc_add_resources(${name} ${ARG_UNPARSED_ARGUMENTS})
|
||||
endfunction()
|
||||
|
||||
function(_cmrc_register_dirs name dirpath)
|
||||
if(dirpath STREQUAL "")
|
||||
return()
|
||||
endif()
|
||||
# Skip this dir if we have already registered it
|
||||
get_target_property(registered "${name}" _CMRC_REGISTERED_DIRS)
|
||||
if(dirpath IN_LIST registered)
|
||||
return()
|
||||
endif()
|
||||
# Register the parent directory first
|
||||
get_filename_component(parent "${dirpath}" DIRECTORY)
|
||||
if(NOT parent STREQUAL "")
|
||||
_cmrc_register_dirs("${name}" "${parent}")
|
||||
endif()
|
||||
# Now generate the registration
|
||||
set_property(TARGET "${name}" APPEND PROPERTY _CMRC_REGISTERED_DIRS "${dirpath}")
|
||||
_cm_encode_fpath(sym "${dirpath}")
|
||||
if(parent STREQUAL "")
|
||||
set(parent_sym root_directory)
|
||||
else()
|
||||
_cm_encode_fpath(parent_sym "${parent}")
|
||||
endif()
|
||||
get_filename_component(leaf "${dirpath}" NAME)
|
||||
set_property(
|
||||
TARGET "${name}"
|
||||
APPEND PROPERTY CMRC_MAKE_DIRS
|
||||
"static auto ${sym}_dir = ${parent_sym}_dir.directory.add_subdir(\"${leaf}\")\;"
|
||||
"root_index.emplace(\"${dirpath}\", &${sym}_dir.index_entry)\;"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(cmrc_add_resources name)
|
||||
get_target_property(is_reslib ${name} CMRC_IS_RESOURCE_LIBRARY)
|
||||
if(NOT TARGET ${name} OR NOT is_reslib)
|
||||
message(SEND_ERROR "cmrc_add_resources called on target '${name}' which is not an existing resource library")
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(options)
|
||||
set(args WHENCE PREFIX)
|
||||
set(list_args)
|
||||
cmake_parse_arguments(ARG "${options}" "${args}" "${list_args}" "${ARGN}")
|
||||
|
||||
if(NOT ARG_WHENCE)
|
||||
set(ARG_WHENCE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
_cmrc_normalize_path(ARG_WHENCE)
|
||||
get_filename_component(ARG_WHENCE "${ARG_WHENCE}" ABSOLUTE)
|
||||
|
||||
# Generate the identifier for the resource library's namespace
|
||||
get_target_property(lib_ns "${name}" CMRC_NAMESPACE)
|
||||
|
||||
get_target_property(libdir ${name} CMRC_LIBDIR)
|
||||
get_target_property(target_dir ${name} SOURCE_DIR)
|
||||
file(RELATIVE_PATH reldir "${target_dir}" "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
if(reldir MATCHES "^\\.\\.")
|
||||
message(SEND_ERROR "Cannot call cmrc_add_resources in a parent directory from the resource library target")
|
||||
return()
|
||||
endif()
|
||||
|
||||
foreach(input IN LISTS ARG_UNPARSED_ARGUMENTS)
|
||||
_cmrc_normalize_path(input)
|
||||
get_filename_component(abs_in "${input}" ABSOLUTE)
|
||||
# Generate a filename based on the input filename that we can put in
|
||||
# the intermediate directory.
|
||||
file(RELATIVE_PATH relpath "${ARG_WHENCE}" "${abs_in}")
|
||||
if(relpath MATCHES "^\\.\\.")
|
||||
# For now we just error on files that exist outside of the soure dir.
|
||||
message(SEND_ERROR "Cannot add file '${input}': File must be in a subdirectory of ${ARG_WHENCE}")
|
||||
continue()
|
||||
endif()
|
||||
if(DEFINED ARG_PREFIX)
|
||||
_cmrc_normalize_path(ARG_PREFIX)
|
||||
endif()
|
||||
if(ARG_PREFIX AND NOT ARG_PREFIX MATCHES "/$")
|
||||
set(ARG_PREFIX "${ARG_PREFIX}/")
|
||||
endif()
|
||||
get_filename_component(dirpath "${ARG_PREFIX}${relpath}" DIRECTORY)
|
||||
_cmrc_register_dirs("${name}" "${dirpath}")
|
||||
get_filename_component(abs_out "${libdir}/intermediate/${ARG_PREFIX}${relpath}.cpp" ABSOLUTE)
|
||||
# Generate a symbol name relpath the file's character array
|
||||
_cm_encode_fpath(sym "${relpath}")
|
||||
# Get the symbol name for the parent directory
|
||||
if(dirpath STREQUAL "")
|
||||
set(parent_sym root_directory)
|
||||
else()
|
||||
_cm_encode_fpath(parent_sym "${dirpath}")
|
||||
endif()
|
||||
# Generate the rule for the intermediate source file
|
||||
_cmrc_generate_intermediate_cpp(${lib_ns} ${sym} "${abs_out}" "${abs_in}")
|
||||
target_sources(${name} PRIVATE "${abs_out}")
|
||||
set_property(TARGET ${name} APPEND PROPERTY CMRC_EXTERN_DECLS
|
||||
"// Pointers to ${input}"
|
||||
"extern const char* const ${sym}_begin\;"
|
||||
"extern const char* const ${sym}_end\;"
|
||||
)
|
||||
get_filename_component(leaf "${relpath}" NAME)
|
||||
set_property(
|
||||
TARGET ${name}
|
||||
APPEND PROPERTY CMRC_MAKE_FILES
|
||||
"root_index.emplace("
|
||||
" \"${ARG_PREFIX}${relpath}\","
|
||||
" ${parent_sym}_dir.directory.add_file("
|
||||
" \"${leaf}\","
|
||||
" res_chars::${sym}_begin,"
|
||||
" res_chars::${sym}_end"
|
||||
" )"
|
||||
")\;"
|
||||
)
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
function(_cmrc_generate_intermediate_cpp lib_ns symbol outfile infile)
|
||||
add_custom_command(
|
||||
# This is the file we will generate
|
||||
OUTPUT "${outfile}"
|
||||
# These are the primary files that affect the output
|
||||
DEPENDS "${infile}" "${_CMRC_SCRIPT}"
|
||||
COMMAND
|
||||
"${CMAKE_COMMAND}"
|
||||
-D_CMRC_GENERATE_MODE=TRUE
|
||||
-DNAMESPACE=${lib_ns}
|
||||
-DSYMBOL=${symbol}
|
||||
"-DINPUT_FILE=${infile}"
|
||||
"-DOUTPUT_FILE=${outfile}"
|
||||
-P "${_CMRC_SCRIPT}"
|
||||
COMMENT "Generating intermediate file for ${infile}"
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(_cm_encode_fpath var fpath)
|
||||
string(MAKE_C_IDENTIFIER "${fpath}" ident)
|
||||
string(MD5 hash "${fpath}")
|
||||
string(SUBSTRING "${hash}" 0 4 hash)
|
||||
set(${var} f_${hash}_${ident} PARENT_SCOPE)
|
||||
endfunction()
|
|
@ -1,15 +0,0 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(CRYPTOPP QUIET IMPORTED_TARGET libcryptopp)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(cryptopp
|
||||
REQUIRED_VARS CRYPTOPP_LINK_LIBRARIES
|
||||
VERSION_VAR CRYPTOPP_VERSION
|
||||
)
|
||||
|
||||
if (cryptopp_FOUND AND NOT TARGET cryptopp::cryptopp)
|
||||
add_library(cryptopp::cryptopp ALIAS PkgConfig::CRYPTOPP)
|
||||
endif()
|
15
cmake/Findlibusb.cmake
Normal file
15
cmake/Findlibusb.cmake
Normal file
|
@ -0,0 +1,15 @@
|
|||
# SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_search_module(LIBUSB QUIET IMPORTED_TARGET libusb-1.0)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(libusb
|
||||
REQUIRED_VARS LIBUSB_LINK_LIBRARIES
|
||||
VERSION_VAR LIBUSB_VERSION
|
||||
)
|
||||
|
||||
if (libusb_FOUND AND NOT TARGET libusb::usb)
|
||||
add_library(libusb::usb ALIAS PkgConfig::LIBUSB)
|
||||
endif()
|
3
crowdin.yml
Normal file
3
crowdin.yml
Normal file
|
@ -0,0 +1,3 @@
|
|||
files:
|
||||
- source: /src/qt_gui/translations/en_US.ts
|
||||
translation: /%original_path%/%locale_with_underscore%.ts
|
2
dist/net.shadps4.shadPS4.desktop
vendored
2
dist/net.shadps4.shadPS4.desktop
vendored
|
@ -5,5 +5,5 @@ Terminal=false
|
|||
Type=Application
|
||||
Icon=net.shadps4.shadPS4
|
||||
Comment=PlayStation 4 emulator
|
||||
Categories=Game;
|
||||
Categories=Game;Emulator;
|
||||
StartupWMClass=shadps4;
|
||||
|
|
9
dist/net.shadps4.shadPS4.metainfo.xml
vendored
9
dist/net.shadps4.shadPS4.metainfo.xml
vendored
|
@ -37,6 +37,15 @@
|
|||
<category translate="no">Game</category>
|
||||
</categories>
|
||||
<releases>
|
||||
<release version="0.8.0" date="2025-05-23">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.8.0</url>
|
||||
</release>
|
||||
<release version="0.7.0" date="2025-03-23">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.7.0</url>
|
||||
</release>
|
||||
<release version="0.6.0" date="2025-01-31">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url>
|
||||
</release>
|
||||
<release version="0.5.0" date="2024-12-25">
|
||||
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.5.0</url>
|
||||
</release>
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 658 KiB |
|
@ -13,7 +13,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
- [**RAM**](#ram)
|
||||
- [**OS**](#os)
|
||||
- [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
|
||||
- [**Install PKG files (Games and Updates)**](#install-pkg-files)
|
||||
- [**Configure the emulator**](#configure-the-emulator)
|
||||
|
||||
## Minimum PC requirements
|
||||
|
@ -25,13 +24,13 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
- A CPU supporting the following instruction sets: MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, AVX, F16C, CLMUL, AES, BMI1, MOVBE, XSAVE, ABM
|
||||
- **Intel**: Haswell generation or newer
|
||||
- **AMD**: Jaguar generation or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15 or newer
|
||||
- **Apple**: Rosetta 2 on macOS 15.4 or newer
|
||||
|
||||
### GPU
|
||||
|
||||
- A graphics card with at least 1GB of VRAM
|
||||
- Keep your graphics drivers up to date
|
||||
- Vulkan 1.3 support (required)
|
||||
- Up-to-date graphics drivers
|
||||
- Vulkan 1.3 with the `VK_KHR_swapchain` and `VK_KHR_push_descriptor` extensions
|
||||
|
||||
### RAM
|
||||
|
||||
|
@ -48,13 +47,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
||||
2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
|
||||
|
||||
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to.
|
||||
|
||||
## Install PKG files
|
||||
|
||||
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
|
||||
|
||||
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
|
||||
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that contains your dumped games.
|
||||
|
||||
## Configure the emulator
|
||||
|
||||
|
|
|
@ -13,28 +13,50 @@ First and foremost, Clang 18 is the **recommended compiler** as it is used for o
|
|||
|
||||
#### Debian & Ubuntu
|
||||
|
||||
```
|
||||
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
|
||||
```bash
|
||||
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
|
||||
```
|
||||
|
||||
#### Fedora
|
||||
|
||||
```
|
||||
sudo dnf install clang git cmake libatomic alsa-lib-devel pipewire-jack-audio-connection-kit-devel openal-devel openssl-devel libevdev-devel libudev-devel libXext-devel qt6-qtbase-devel qt6-qtbase-private-devel qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel vulkan-devel vulkan-validation-layers
|
||||
```bash
|
||||
sudo dnf install clang git cmake libatomic alsa-lib-devel \
|
||||
pipewire-jack-audio-connection-kit-devel openal-devel \
|
||||
openssl-devel libevdev-devel libudev-devel libXext-devel \
|
||||
qt6-qtbase-devel qt6-qtbase-private-devel \
|
||||
qt6-qtmultimedia-devel qt6-qtsvg-devel qt6-qttools-devel \
|
||||
vulkan-devel vulkan-validation-layers libpng-devel
|
||||
```
|
||||
|
||||
#### Arch Linux
|
||||
|
||||
```
|
||||
sudo pacman -S base-devel clang git cmake sndio jack2 openal qt6-base qt6-declarative qt6-multimedia sdl2 vulkan-validation-layers
|
||||
```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
|
||||
```
|
||||
|
||||
**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.
|
||||
|
||||
#### OpenSUSE
|
||||
|
||||
```bash
|
||||
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
|
||||
```
|
||||
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
|
||||
|
||||
#### NixOS
|
||||
|
||||
```bash
|
||||
nix-shell shell.nix
|
||||
```
|
||||
|
||||
#### Other Linux distributions
|
||||
|
@ -44,16 +66,16 @@ You can try one of two methods:
|
|||
- Search the packages by name and install them with your package manager, or
|
||||
- Install [distrobox](https://distrobox.it/), create a container using any of the distributions cited above as a base, for Arch Linux you'd do:
|
||||
|
||||
```
|
||||
```bash
|
||||
distrobox create --name archlinux --init --image archlinux:latest
|
||||
```
|
||||
|
||||
and install the dependencies on that container as cited above.
|
||||
This option is **highly recommended** for NixOS and distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
|
||||
This option is **highly recommended** for distributions with immutable/atomic filesystems (example: Fedora Kinoite, SteamOS).
|
||||
|
||||
### Cloning
|
||||
|
||||
```
|
||||
```bash
|
||||
git clone --recursive https://github.com/shadps4-emu/shadPS4.git
|
||||
cd shadPS4
|
||||
```
|
||||
|
@ -66,7 +88,7 @@ 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++
|
||||
```
|
||||
|
||||
|
@ -74,7 +96,7 @@ To disable the Qt GUI, remove the `-DENABLE_QT_GUI=ON` flag. To change the build
|
|||
|
||||
2. Use CMake to build the project:
|
||||
|
||||
```
|
||||
```bash
|
||||
cmake --build ./build --parallel$(nproc)
|
||||
```
|
||||
|
||||
|
@ -82,13 +104,13 @@ If your computer freezes during this step, this could be caused by excessive sys
|
|||
|
||||
Now run the emulator. If Qt was enabled at configure time:
|
||||
|
||||
```
|
||||
```bash
|
||||
./build/shadps4
|
||||
```
|
||||
|
||||
Otherwise, specify the path to your PKG's boot file:
|
||||
Otherwise, specify the path to your game's boot file:
|
||||
|
||||
```
|
||||
```bash
|
||||
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin
|
||||
```
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ Once you are within the installer:
|
|||
|
||||
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 (at the time of writing 6.7.3), select the option `MSVC 2022 64-bit` or similar, as well as `QT Multimedia`.
|
||||
1. Under the current, non beta version of Qt (at the time of writing 6.8.2), 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.
|
||||
|
@ -35,7 +35,7 @@ Beware, this requires you to create a Qt account. If you do not want to do this,
|
|||
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\6.7.3\msvc2022_64`
|
||||
2. Add a new Qt version and navigate it to the correct folder. Should look like so: `C:\Qt\6.8.2\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)
|
||||
|
@ -55,7 +55,7 @@ Go through the Git for Windows installation as normal
|
|||
3. If you want to build shadPS4 with the Qt Gui:
|
||||
1. Click x64-Clang-Release and select "Manage Configurations"
|
||||
2. Look for "CMake command arguments" and add to the text field
|
||||
`-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.7.3\msvc2022_64`
|
||||
`-DENABLE_QT_GUI=ON -DCMAKE_PREFIX_PATH=C:\Qt\6.8.2\msvc2022_64`
|
||||
(Change Qt path if you've installed it to non-default path)
|
||||
3. Press CTRL+S to save and wait a moment for CMake generation
|
||||
4. Change the project to build to shadps4.exe
|
||||
|
@ -64,11 +64,14 @@ Go through the Git for Windows installation as normal
|
|||
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
|
||||
|
||||
To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
|
||||
`C:\Qt\6.7.3\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
|
||||
`C:\Qt\6.8.2\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]
|
||||
> Building with MSYS2 is broken as of right now, the only way to build on Windows is to use [Option 1: Visual Studio 2022](https://github.com/shadps4-emu/shadPS4/blob/main/documents/building-windows.md#option-1-visual-studio-2022).
|
||||
|
||||
### (Prerequisite) Download [**MSYS2**](https://www.msys2.org/)
|
||||
|
||||
Go through the MSYS2 installation as normal
|
||||
|
|
36
externals/CMakeLists.txt
vendored
36
externals/CMakeLists.txt
vendored
|
@ -18,8 +18,6 @@ endif()
|
|||
|
||||
# Boost
|
||||
if (NOT TARGET Boost::headers)
|
||||
set(BOOST_ROOT "${CMAKE_SOURCE_DIR}/externals/ext-boost" CACHE STRING "")
|
||||
set(Boost_NO_SYSTEM_PATHS ON CACHE BOOL "")
|
||||
add_subdirectory(ext-boost)
|
||||
endif()
|
||||
|
||||
|
@ -28,24 +26,7 @@ if (NOT TARGET fmt::fmt)
|
|||
add_subdirectory(fmt)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
|
||||
# If it is clang and MSVC we will add a static lib
|
||||
# CryptoPP
|
||||
add_subdirectory(cryptoppwin)
|
||||
target_include_directories(cryptoppwin INTERFACE cryptoppwin/include)
|
||||
else()
|
||||
# CryptoPP
|
||||
if (NOT TARGET cryptopp::cryptopp)
|
||||
set(CRYPTOPP_INSTALL OFF)
|
||||
set(CRYPTOPP_BUILD_TESTING OFF)
|
||||
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
|
||||
add_subdirectory(cryptopp-cmake)
|
||||
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
|
||||
# remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
|
||||
set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# FFmpeg
|
||||
if (NOT TARGET FFmpeg::ffmpeg)
|
||||
add_subdirectory(ffmpeg-core)
|
||||
add_library(FFmpeg::ffmpeg ALIAS ffmpeg)
|
||||
|
@ -77,6 +58,7 @@ endif()
|
|||
|
||||
# SDL3
|
||||
if (NOT TARGET SDL3::SDL3)
|
||||
set(SDL_TEST_LIBRARY OFF)
|
||||
set(SDL_PIPEWIRE OFF)
|
||||
add_subdirectory(sdl3)
|
||||
endif()
|
||||
|
@ -131,6 +113,14 @@ endif()
|
|||
# Toml11
|
||||
if (NOT TARGET toml11::toml11)
|
||||
add_subdirectory(toml11)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
|
||||
get_target_property(_toml11_compile_options toml11 INTERFACE_COMPILE_OPTIONS)
|
||||
list(REMOVE_ITEM _toml11_compile_options "/Zc:preprocessor")
|
||||
set_target_properties(toml11 PROPERTIES INTERFACE_COMPILE_OPTIONS ${_toml11_compile_options})
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# xxHash
|
||||
|
@ -211,6 +201,12 @@ if (NOT TARGET pugixml::pugixml)
|
|||
add_subdirectory(pugixml)
|
||||
endif()
|
||||
|
||||
# libusb
|
||||
if (NOT TARGET libusb::usb)
|
||||
add_subdirectory(libusb)
|
||||
add_library(libusb::usb ALIAS usb-1.0)
|
||||
endif()
|
||||
|
||||
# Discord RPC
|
||||
if (ENABLE_DISCORD_RPC)
|
||||
add_subdirectory(discord-rpc)
|
||||
|
|
2
externals/LibAtrac9
vendored
2
externals/LibAtrac9
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 9640129dc6f2afbca6ceeca3019856e8653a5fb2
|
||||
Subproject commit ec8899dadf393f655f2871a94e0fe4b3d6220c9a
|
2
externals/MoltenVK/MoltenVK
vendored
2
externals/MoltenVK/MoltenVK
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 0c090001cb42997031cfe43914340e2639944972
|
||||
Subproject commit 87a8e8b13d4ad8835367fea1ebad1896d0460946
|
8
externals/MoltenVK/MoltenVK_icd.json
vendored
8
externals/MoltenVK/MoltenVK_icd.json
vendored
|
@ -1,8 +0,0 @@
|
|||
{
|
||||
"file_format_version": "1.0.0",
|
||||
"ICD": {
|
||||
"library_path": "../../../Frameworks/libMoltenVK.dylib",
|
||||
"api_version": "1.2.0",
|
||||
"is_portability_driver": true
|
||||
}
|
||||
}
|
2
externals/MoltenVK/SPIRV-Cross
vendored
2
externals/MoltenVK/SPIRV-Cross
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 1a7b7ef6de02cf6767e42b10ddad217c45e90d47
|
||||
Subproject commit 7918775748c5e2f5c40d9918ce68825035b5a1e1
|
2
externals/MoltenVK/cereal
vendored
2
externals/MoltenVK/cereal
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d1fcec807b372f04e4c1041b3058e11c12853e6e
|
||||
Subproject commit a56bad8bbb770ee266e930c95d37fff2a5be7fea
|
1
externals/cryptopp
vendored
1
externals/cryptopp
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit 60f81a77e0c9a0e7ffc1ca1bc438ddfa2e43b78e
|
1
externals/cryptopp-cmake
vendored
1
externals/cryptopp-cmake
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit 2c384c28265a93358a2455e610e76393358794df
|
1
externals/cryptoppwin
vendored
1
externals/cryptoppwin
vendored
|
@ -1 +0,0 @@
|
|||
Subproject commit bc3441dd2d6a9728e747dc0180bc8b9065a2923c
|
2
externals/date
vendored
2
externals/date
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 28b7b232521ace2c8ef3f2ad4126daec3569c14f
|
||||
Subproject commit a45ea7c17b4a7f320e199b71436074bd624c9e15
|
2
externals/dear_imgui
vendored
2
externals/dear_imgui
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 636cd4a7d623a2bc9bf59bb3acbb4ca075befba3
|
||||
Subproject commit f4d9359095eff3eb03f685921edc1cf0e37b1687
|
2
externals/discord-rpc
vendored
2
externals/discord-rpc
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 51b09d426a4a1bcfa6ee6d4894e57d669f4a2e65
|
||||
Subproject commit 19f66e6dcabb2268965f453db9e5774ede43238f
|
2
externals/ffmpeg-core
vendored
2
externals/ffmpeg-core
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 27de97c826b6b40c255891c37ac046a25836a575
|
||||
Subproject commit b0de1dcca26c0ebfb8011b8e59dd17fc399db0ff
|
2
externals/fmt
vendored
2
externals/fmt
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 8ee89546ffcf046309d1f0d38c0393f02fde56c8
|
||||
Subproject commit 64db979e38ec644b1798e41610b28c8d2c8a2739
|
6
externals/gcn/CMakeLists.txt
vendored
6
externals/gcn/CMakeLists.txt
vendored
|
@ -3,6 +3,10 @@
|
|||
|
||||
project(gcn LANGUAGES CXX)
|
||||
|
||||
add_library(gcn dummy.cpp)
|
||||
add_library(gcn INTERFACE)
|
||||
target_sources(gcn PRIVATE
|
||||
"include/gcn/si_ci_vi_merged_offset.h"
|
||||
"include/gcn/si_ci_vi_merged_pm4_it_opcodes.h"
|
||||
)
|
||||
|
||||
target_include_directories(gcn INTERFACE include)
|
||||
|
|
2
externals/gcn/dummy.cpp
vendored
2
externals/gcn/dummy.cpp
vendored
|
@ -1,2 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
2
externals/glslang
vendored
2
externals/glslang
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a0995c49ebcaca2c6d3b03efbabf74f3843decdb
|
||||
Subproject commit ba1640446f3826a518721d1f083f3a8cca1120c3
|
1
externals/libusb
vendored
Submodule
1
externals/libusb
vendored
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit a63a7e43e0950a595cf4b98a0eaf4051749ace5f
|
2
externals/magic_enum
vendored
2
externals/magic_enum
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 1a1824df7ac798177a521eed952720681b0bf482
|
||||
Subproject commit a413fcc9c46a020a746907136a384c227f3cd095
|
2
externals/pugixml
vendored
2
externals/pugixml
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4bc14418d12d289dd9978fdce9490a45deeb653e
|
||||
Subproject commit caade5a28aad86b92a4b5337a9dc70c4ba73c5eb
|
2
externals/robin-map
vendored
2
externals/robin-map
vendored
|
@ -1 +1 @@
|
|||
Subproject commit fe845fd7852ef541c5479ae23b3d36b57f8608ee
|
||||
Subproject commit 4ec1bf19c6a96125ea22062f38c2cf5b958e448e
|
2
externals/sdl3
vendored
2
externals/sdl3
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a336b62d8b0b97b09214e053203e442e2b6e2be5
|
||||
Subproject commit 4093e4a193971ef1d4928158e0a1832be42e4599
|
2
externals/sirit
vendored
2
externals/sirit
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d6f3c0d99862ab2ff8f95e9ac221560f1f97e29a
|
||||
Subproject commit 427a42c9ed99b38204d9107bc3dc14e92458acf1
|
2
externals/toml11
vendored
2
externals/toml11
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 7f6c574ff5aa1053534e7e19c0a4f22bf4c6aaca
|
||||
Subproject commit a01fe3b4c14c6d7b99ee3f07c9e80058c6403097
|
2
externals/vma
vendored
2
externals/vma
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 5a53a198945ba8260fbc58fadb788745ce6aa263
|
||||
Subproject commit f378e7b3f18f6e2b06b957f6ba7b1c7207d2a536
|
2
externals/vulkan-headers
vendored
2
externals/vulkan-headers
vendored
|
@ -1 +1 @@
|
|||
Subproject commit a03d2f6d5753b365d704d58161825890baad0755
|
||||
Subproject commit 5ceb9ed481e58e705d0d9b5326537daedd06b97d
|
2
externals/winpthreads
vendored
2
externals/winpthreads
vendored
|
@ -1 +1 @@
|
|||
Subproject commit f00c973a6ab2a23573708568b8ef4acc20a9d36b
|
||||
Subproject commit f35b0948d36a736e6a2d052ae295a3ffde09703f
|
2
externals/xbyak
vendored
2
externals/xbyak
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 4e44f4614ddbf038f2a6296f5b906d5c72691e0f
|
||||
Subproject commit 44a72f369268f7d552650891b296693e91db86bb
|
2
externals/xxhash
vendored
2
externals/xxhash
vendored
|
@ -1 +1 @@
|
|||
Subproject commit 2bf8313b934633b2a5b7e8fd239645b85e10c852
|
||||
Subproject commit 953a09abc39096da9e216b6eb0002c681cdc1199
|
2
externals/zlib-ng
vendored
2
externals/zlib-ng
vendored
|
@ -1 +1 @@
|
|||
Subproject commit d54e3769be0c522015b784eca2af258b1c026107
|
||||
Subproject commit fd0d263cedab1a136f40d65199987e3eaeecfcbd
|
2
externals/zydis
vendored
2
externals/zydis
vendored
|
@ -1 +1 @@
|
|||
Subproject commit bffbb610cfea643b98e87658b9058382f7522807
|
||||
Subproject commit 120e0e705f8e3b507dc49377ac2879979f0d545c
|
71
shell.nix
Normal file
71
shell.nix
Normal file
|
@ -0,0 +1,71 @@
|
|||
# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
|
||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
with import (fetchTarball "https://github.com/nixos/nixpkgs/archive/cfd19cdc54680956dc1816ac577abba6b58b901c.tar.gz") { };
|
||||
|
||||
pkgs.mkShell {
|
||||
name = "shadps4-build-env";
|
||||
|
||||
nativeBuildInputs = [
|
||||
pkgs.llvmPackages_18.clang
|
||||
pkgs.cmake
|
||||
pkgs.pkg-config
|
||||
pkgs.git
|
||||
];
|
||||
|
||||
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
|
||||
|
||||
pkgs.vulkan-headers
|
||||
pkgs.vulkan-utility-libraries
|
||||
pkgs.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
|
||||
];
|
||||
|
||||
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
|
||||
export LD_LIBRARY_PATH="${
|
||||
pkgs.lib.makeLibraryPath [
|
||||
pkgs.libglvnd
|
||||
pkgs.vulkan-tools
|
||||
]
|
||||
}:$LD_LIBRARY_PATH"
|
||||
|
||||
export LDFLAGS="-L${pkgs.llvmPackages_18.libcxx}/lib -lc++"
|
||||
export LC_ALL="C.UTF-8"
|
||||
export XAUTHORITY=${builtins.getEnv "XAUTHORITY"}
|
||||
'';
|
||||
}
|
1195
src/common/aes.h
Normal file
1195
src/common/aes.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,10 +7,10 @@
|
|||
#include <fmt/xchar.h> // for wstring support
|
||||
#include <toml.hpp>
|
||||
|
||||
#include "common/config.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "common/path_util.h"
|
||||
#include "config.h"
|
||||
#include "logging/formatter.h"
|
||||
#include "version.h"
|
||||
#include "common/scm_rev.h"
|
||||
|
||||
namespace toml {
|
||||
template <typename TC, typename K>
|
||||
|
@ -32,8 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
|
|||
namespace Config {
|
||||
|
||||
static bool isNeo = false;
|
||||
static bool isFullscreen = false;
|
||||
static std::string fullscreenMode = "borderless";
|
||||
static bool isDevKit = false;
|
||||
static bool playBGM = false;
|
||||
static bool isTrophyPopupDisabled = false;
|
||||
static int BGMvolume = 50;
|
||||
|
@ -42,12 +41,10 @@ static u32 screenWidth = 1280;
|
|||
static u32 screenHeight = 720;
|
||||
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
|
||||
static std::string logFilter;
|
||||
static std::string logType = "async";
|
||||
static std::string logType = "sync";
|
||||
static std::string userName = "shadPS4";
|
||||
static std::string updateChannel;
|
||||
static std::string chooseHomeTab;
|
||||
static u16 deadZoneLeft = 2.0;
|
||||
static u16 deadZoneRight = 2.0;
|
||||
static std::string backButtonBehavior = "left";
|
||||
static bool useSpecialPad = false;
|
||||
static int specialPadClass = 1;
|
||||
|
@ -56,6 +53,8 @@ static bool isDebugDump = false;
|
|||
static bool isShaderDebug = false;
|
||||
static bool isShowSplash = false;
|
||||
static bool isAutoUpdate = false;
|
||||
static bool isAlwaysShowChangelog = false;
|
||||
static std::string isSideTrophy = "right";
|
||||
static bool isNullGpu = false;
|
||||
static bool shouldCopyGPUBuffers = false;
|
||||
static bool shouldDumpShaders = false;
|
||||
|
@ -68,16 +67,22 @@ static bool vkCrashDiagnostic = false;
|
|||
static bool vkHostMarkers = false;
|
||||
static bool vkGuestMarkers = false;
|
||||
static bool rdocEnable = false;
|
||||
static bool isFpsColor = true;
|
||||
static bool isSeparateLogFilesEnabled = false;
|
||||
static s16 cursorState = HideCursorState::Idle;
|
||||
static int cursorHideTimeout = 5; // 5 seconds (default)
|
||||
static bool separateupdatefolder = false;
|
||||
static double trophyNotificationDuration = 6.0;
|
||||
static bool useUnifiedInputConfig = true;
|
||||
static bool overrideControllerColor = false;
|
||||
static int controllerCustomColorRGB[3] = {0, 0, 255};
|
||||
static bool compatibilityData = false;
|
||||
static bool checkCompatibilityOnStartup = false;
|
||||
static std::string trophyKey;
|
||||
|
||||
// Gui
|
||||
static bool load_game_size = true;
|
||||
std::vector<std::filesystem::path> settings_install_dirs = {};
|
||||
static std::vector<GameInstallDir> settings_install_dirs = {};
|
||||
std::vector<bool> install_dirs_enabled = {};
|
||||
std::filesystem::path settings_addon_install_dir = {};
|
||||
std::filesystem::path save_data_path = {};
|
||||
u32 main_window_geometry_x = 400;
|
||||
|
@ -92,14 +97,49 @@ u32 m_slider_pos_grid = 0;
|
|||
u32 m_table_mode = 0;
|
||||
u32 m_window_size_W = 1280;
|
||||
u32 m_window_size_H = 720;
|
||||
std::vector<std::string> m_pkg_viewer;
|
||||
std::vector<std::string> m_elf_viewer;
|
||||
std::vector<std::string> m_recent_files;
|
||||
std::string emulator_language = "en";
|
||||
std::string emulator_language = "en_US";
|
||||
static int backgroundImageOpacity = 50;
|
||||
static bool showBackgroundImage = true;
|
||||
static bool isFullscreen = false;
|
||||
static std::string fullscreenMode = "Windowed";
|
||||
static bool isHDRAllowed = false;
|
||||
static bool showLabelsUnderIcons = true;
|
||||
|
||||
// Language
|
||||
u32 m_language = 1; // english
|
||||
|
||||
bool allowHDR() {
|
||||
return isHDRAllowed;
|
||||
}
|
||||
|
||||
bool GetUseUnifiedInputConfig() {
|
||||
return useUnifiedInputConfig;
|
||||
}
|
||||
|
||||
void SetUseUnifiedInputConfig(bool use) {
|
||||
useUnifiedInputConfig = use;
|
||||
}
|
||||
|
||||
bool GetOverrideControllerColor() {
|
||||
return overrideControllerColor;
|
||||
}
|
||||
|
||||
void SetOverrideControllerColor(bool enable) {
|
||||
overrideControllerColor = enable;
|
||||
}
|
||||
|
||||
int* GetControllerCustomColor() {
|
||||
return controllerCustomColorRGB;
|
||||
}
|
||||
|
||||
void SetControllerCustomColor(int r, int b, int g) {
|
||||
controllerCustomColorRGB[0] = r;
|
||||
controllerCustomColorRGB[1] = b;
|
||||
controllerCustomColorRGB[2] = g;
|
||||
}
|
||||
|
||||
std::string getTrophyKey() {
|
||||
return trophyKey;
|
||||
}
|
||||
|
@ -127,10 +167,22 @@ bool isNeoModeConsole() {
|
|||
return isNeo;
|
||||
}
|
||||
|
||||
bool isDevKitConsole() {
|
||||
return isDevKit;
|
||||
}
|
||||
|
||||
bool getIsFullscreen() {
|
||||
return isFullscreen;
|
||||
}
|
||||
|
||||
bool getShowLabelsUnderIcons() {
|
||||
return showLabelsUnderIcons;
|
||||
}
|
||||
|
||||
bool setShowLabelsUnderIcons() {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string getFullscreenMode() {
|
||||
return fullscreenMode;
|
||||
}
|
||||
|
@ -151,14 +203,6 @@ bool getEnableDiscordRPC() {
|
|||
return enableDiscordRPC;
|
||||
}
|
||||
|
||||
u16 leftDeadZone() {
|
||||
return deadZoneLeft;
|
||||
}
|
||||
|
||||
u16 rightDeadZone() {
|
||||
return deadZoneRight;
|
||||
}
|
||||
|
||||
s16 getCursorState() {
|
||||
return cursorState;
|
||||
}
|
||||
|
@ -167,6 +211,10 @@ int getCursorHideTimeout() {
|
|||
return cursorHideTimeout;
|
||||
}
|
||||
|
||||
double getTrophyNotificationDuration() {
|
||||
return trophyNotificationDuration;
|
||||
}
|
||||
|
||||
u32 getScreenWidth() {
|
||||
return screenWidth;
|
||||
}
|
||||
|
@ -231,6 +279,14 @@ bool autoUpdate() {
|
|||
return isAutoUpdate;
|
||||
}
|
||||
|
||||
bool alwaysShowChangelog() {
|
||||
return isAlwaysShowChangelog;
|
||||
}
|
||||
|
||||
std::string sideTrophy() {
|
||||
return isSideTrophy;
|
||||
}
|
||||
|
||||
bool nullGpu() {
|
||||
return isNullGpu;
|
||||
}
|
||||
|
@ -251,6 +307,10 @@ bool isRdocEnabled() {
|
|||
return rdocEnable;
|
||||
}
|
||||
|
||||
bool fpsColor() {
|
||||
return isFpsColor;
|
||||
}
|
||||
|
||||
u32 vblankDiv() {
|
||||
return vblankDivider;
|
||||
}
|
||||
|
@ -291,10 +351,6 @@ void setVkGuestMarkersEnabled(bool enable) {
|
|||
vkGuestMarkers = enable;
|
||||
}
|
||||
|
||||
bool getSeparateUpdateEnabled() {
|
||||
return separateupdatefolder;
|
||||
}
|
||||
|
||||
bool getCompatibilityEnabled() {
|
||||
return compatibilityData;
|
||||
}
|
||||
|
@ -331,10 +387,22 @@ void setAutoUpdate(bool enable) {
|
|||
isAutoUpdate = enable;
|
||||
}
|
||||
|
||||
void setAlwaysShowChangelog(bool enable) {
|
||||
isAlwaysShowChangelog = enable;
|
||||
}
|
||||
|
||||
void setSideTrophy(std::string side) {
|
||||
isSideTrophy = side;
|
||||
}
|
||||
|
||||
void setNullGpu(bool enable) {
|
||||
isNullGpu = enable;
|
||||
}
|
||||
|
||||
void setAllowHDR(bool enable) {
|
||||
isHDRAllowed = enable;
|
||||
}
|
||||
|
||||
void setCopyGPUCmdBuffers(bool enable) {
|
||||
shouldCopyGPUBuffers = enable;
|
||||
}
|
||||
|
@ -362,6 +430,9 @@ void setVblankDiv(u32 value) {
|
|||
void setIsFullscreen(bool enable) {
|
||||
isFullscreen = enable;
|
||||
}
|
||||
static void setShowLabelsUnderIcons(bool enable) {
|
||||
showLabelsUnderIcons = enable;
|
||||
}
|
||||
|
||||
void setFullscreenMode(std::string mode) {
|
||||
fullscreenMode = mode;
|
||||
|
@ -390,6 +461,9 @@ void setCursorState(s16 newCursorState) {
|
|||
void setCursorHideTimeout(int newcursorHideTimeout) {
|
||||
cursorHideTimeout = newcursorHideTimeout;
|
||||
}
|
||||
void setTrophyNotificationDuration(double newTrophyNotificationDuration) {
|
||||
trophyNotificationDuration = newTrophyNotificationDuration;
|
||||
}
|
||||
|
||||
void setLanguage(u32 language) {
|
||||
m_language = language;
|
||||
|
@ -407,6 +481,10 @@ void setLogFilter(const std::string& type) {
|
|||
logFilter = type;
|
||||
}
|
||||
|
||||
void setSeparateLogFilesEnabled(bool enabled) {
|
||||
isSeparateLogFilesEnabled = enabled;
|
||||
}
|
||||
|
||||
void setUserName(const std::string& type) {
|
||||
userName = type;
|
||||
}
|
||||
|
@ -434,10 +512,6 @@ void setIsMotionControlsEnabled(bool use) {
|
|||
isMotionControlsEnabled = use;
|
||||
}
|
||||
|
||||
void setSeparateUpdateEnabled(bool use) {
|
||||
separateupdatefolder = use;
|
||||
}
|
||||
|
||||
void setCompatibilityEnabled(bool use) {
|
||||
compatibilityData = use;
|
||||
}
|
||||
|
@ -453,22 +527,34 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
|
|||
main_window_geometry_h = h;
|
||||
}
|
||||
|
||||
bool addGameInstallDir(const std::filesystem::path& dir) {
|
||||
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
|
||||
settings_install_dirs.end()) {
|
||||
settings_install_dirs.push_back(dir);
|
||||
return true;
|
||||
}
|
||||
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
|
||||
for (const auto& install_dir : settings_install_dirs) {
|
||||
if (install_dir.path == dir) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
settings_install_dirs.push_back({dir, enabled});
|
||||
return true;
|
||||
}
|
||||
|
||||
void removeGameInstallDir(const std::filesystem::path& dir) {
|
||||
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
|
||||
auto iterator =
|
||||
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
|
||||
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
|
||||
if (iterator != settings_install_dirs.end()) {
|
||||
settings_install_dirs.erase(iterator);
|
||||
}
|
||||
}
|
||||
|
||||
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled) {
|
||||
auto iterator =
|
||||
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
|
||||
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
|
||||
if (iterator != settings_install_dirs.end()) {
|
||||
iterator->enabled = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
void setAddonInstallDir(const std::filesystem::path& dir) {
|
||||
settings_addon_install_dir = dir;
|
||||
}
|
||||
|
@ -505,11 +591,6 @@ void setMainWindowHeight(u32 height) {
|
|||
m_window_size_H = height;
|
||||
}
|
||||
|
||||
void setPkgViewer(const std::vector<std::string>& pkgList) {
|
||||
m_pkg_viewer.resize(pkgList.size());
|
||||
m_pkg_viewer = pkgList;
|
||||
}
|
||||
|
||||
void setElfViewer(const std::vector<std::string>& elfList) {
|
||||
m_elf_viewer.resize(elfList.size());
|
||||
m_elf_viewer = elfList;
|
||||
|
@ -524,8 +605,15 @@ void setEmulatorLanguage(std::string language) {
|
|||
emulator_language = language;
|
||||
}
|
||||
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config) {
|
||||
settings_install_dirs = settings_install_dirs_config;
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) {
|
||||
settings_install_dirs.clear();
|
||||
for (const auto& dir : dirs_config) {
|
||||
settings_install_dirs.push_back({dir, true});
|
||||
}
|
||||
}
|
||||
|
||||
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config) {
|
||||
settings_install_dirs = dirs_config;
|
||||
}
|
||||
|
||||
void setSaveDataPath(const std::filesystem::path& path) {
|
||||
|
@ -548,8 +636,22 @@ u32 getMainWindowGeometryH() {
|
|||
return main_window_geometry_h;
|
||||
}
|
||||
|
||||
const std::vector<std::filesystem::path>& getGameInstallDirs() {
|
||||
return settings_install_dirs;
|
||||
const std::vector<std::filesystem::path> getGameInstallDirs() {
|
||||
std::vector<std::filesystem::path> enabled_dirs;
|
||||
for (const auto& dir : settings_install_dirs) {
|
||||
if (dir.enabled) {
|
||||
enabled_dirs.push_back(dir.path);
|
||||
}
|
||||
}
|
||||
return enabled_dirs;
|
||||
}
|
||||
|
||||
const std::vector<bool> getGameInstallDirsEnabled() {
|
||||
std::vector<bool> enabled_dirs;
|
||||
for (const auto& dir : settings_install_dirs) {
|
||||
enabled_dirs.push_back(dir.enabled);
|
||||
}
|
||||
return enabled_dirs;
|
||||
}
|
||||
|
||||
std::filesystem::path getAddonInstallDir() {
|
||||
|
@ -592,10 +694,6 @@ u32 getMainWindowHeight() {
|
|||
return m_window_size_H;
|
||||
}
|
||||
|
||||
std::vector<std::string> getPkgViewer() {
|
||||
return m_pkg_viewer;
|
||||
}
|
||||
|
||||
std::vector<std::string> getElfViewer() {
|
||||
return m_elf_viewer;
|
||||
}
|
||||
|
@ -612,6 +710,26 @@ u32 GetLanguage() {
|
|||
return m_language;
|
||||
}
|
||||
|
||||
bool getSeparateLogFilesEnabled() {
|
||||
return isSeparateLogFilesEnabled;
|
||||
}
|
||||
|
||||
int getBackgroundImageOpacity() {
|
||||
return backgroundImageOpacity;
|
||||
}
|
||||
|
||||
void setBackgroundImageOpacity(int opacity) {
|
||||
backgroundImageOpacity = std::clamp(opacity, 0, 100);
|
||||
}
|
||||
|
||||
bool getShowBackgroundImage() {
|
||||
return showBackgroundImage;
|
||||
}
|
||||
|
||||
void setShowBackgroundImage(bool show) {
|
||||
showBackgroundImage = show;
|
||||
}
|
||||
|
||||
void load(const std::filesystem::path& path) {
|
||||
// If the configuration file does not exist, create it and return
|
||||
std::error_code error;
|
||||
|
@ -635,23 +753,25 @@ void load(const std::filesystem::path& path) {
|
|||
const toml::value& general = data.at("General");
|
||||
|
||||
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
|
||||
isFullscreen = toml::find_or<bool>(general, "Fullscreen", false);
|
||||
fullscreenMode = toml::find_or<std::string>(general, "FullscreenMode", "borderless");
|
||||
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
|
||||
playBGM = toml::find_or<bool>(general, "playBGM", false);
|
||||
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
|
||||
trophyNotificationDuration =
|
||||
toml::find_or<double>(general, "trophyNotificationDuration", 5.0);
|
||||
BGMvolume = toml::find_or<int>(general, "BGMvolume", 50);
|
||||
enableDiscordRPC = toml::find_or<bool>(general, "enableDiscordRPC", true);
|
||||
logFilter = toml::find_or<std::string>(general, "logFilter", "");
|
||||
logType = toml::find_or<std::string>(general, "logType", "sync");
|
||||
userName = toml::find_or<std::string>(general, "userName", "shadPS4");
|
||||
if (Common::isRelease) {
|
||||
if (Common::g_is_release) {
|
||||
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Release");
|
||||
} else {
|
||||
updateChannel = toml::find_or<std::string>(general, "updateChannel", "Nightly");
|
||||
}
|
||||
isShowSplash = toml::find_or<bool>(general, "showSplash", true);
|
||||
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
|
||||
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
|
||||
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false);
|
||||
isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right");
|
||||
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
|
||||
checkCompatibilityOnStartup =
|
||||
toml::find_or<bool>(general, "checkCompatibilityOnStartup", false);
|
||||
|
@ -661,14 +781,13 @@ void load(const std::filesystem::path& path) {
|
|||
if (data.contains("Input")) {
|
||||
const toml::value& input = data.at("Input");
|
||||
|
||||
deadZoneLeft = toml::find_or<float>(input, "deadZoneLeft", 2.0);
|
||||
deadZoneRight = toml::find_or<float>(input, "deadZoneRight", 2.0);
|
||||
cursorState = toml::find_or<int>(input, "cursorState", HideCursorState::Idle);
|
||||
cursorHideTimeout = toml::find_or<int>(input, "cursorHideTimeout", 5);
|
||||
backButtonBehavior = toml::find_or<std::string>(input, "backButtonBehavior", "left");
|
||||
useSpecialPad = toml::find_or<bool>(input, "useSpecialPad", false);
|
||||
specialPadClass = toml::find_or<int>(input, "specialPadClass", 1);
|
||||
isMotionControlsEnabled = toml::find_or<bool>(input, "isMotionControlsEnabled", true);
|
||||
useUnifiedInputConfig = toml::find_or<bool>(input, "useUnifiedInputConfig", true);
|
||||
}
|
||||
|
||||
if (data.contains("GPU")) {
|
||||
|
@ -681,6 +800,9 @@ void load(const std::filesystem::path& path) {
|
|||
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
|
||||
shouldPatchShaders = toml::find_or<bool>(gpu, "patchShaders", true);
|
||||
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1);
|
||||
isFullscreen = toml::find_or<bool>(gpu, "Fullscreen", false);
|
||||
fullscreenMode = toml::find_or<std::string>(gpu, "FullscreenMode", "Windowed");
|
||||
isHDRAllowed = toml::find_or<bool>(gpu, "allowHDR", false);
|
||||
}
|
||||
|
||||
if (data.contains("Vulkan")) {
|
||||
|
@ -700,7 +822,9 @@ void load(const std::filesystem::path& path) {
|
|||
const toml::value& debug = data.at("Debug");
|
||||
|
||||
isDebugDump = toml::find_or<bool>(debug, "DebugDump", false);
|
||||
isSeparateLogFilesEnabled = toml::find_or<bool>(debug, "isSeparateLogFilesEnabled", false);
|
||||
isShaderDebug = toml::find_or<bool>(debug, "CollectShader", false);
|
||||
isFpsColor = toml::find_or<bool>(debug, "FPSColor", true);
|
||||
}
|
||||
|
||||
if (data.contains("GUI")) {
|
||||
|
@ -716,9 +840,23 @@ void load(const std::filesystem::path& path) {
|
|||
m_window_size_H = toml::find_or<int>(gui, "mw_height", 0);
|
||||
|
||||
const auto install_dir_array =
|
||||
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
|
||||
for (const auto& dir : install_dir_array) {
|
||||
addGameInstallDir(std::filesystem::path{dir});
|
||||
toml::find_or<std::vector<std::u8string>>(gui, "installDirs", {});
|
||||
|
||||
try {
|
||||
install_dirs_enabled = toml::find<std::vector<bool>>(gui, "installDirsEnabled");
|
||||
} catch (...) {
|
||||
// If it does not exist, assume that all are enabled.
|
||||
install_dirs_enabled.resize(install_dir_array.size(), true);
|
||||
}
|
||||
|
||||
if (install_dirs_enabled.size() < install_dir_array.size()) {
|
||||
install_dirs_enabled.resize(install_dir_array.size(), true);
|
||||
}
|
||||
|
||||
settings_install_dirs.clear();
|
||||
for (size_t i = 0; i < install_dir_array.size(); i++) {
|
||||
settings_install_dirs.push_back(
|
||||
{std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]});
|
||||
}
|
||||
|
||||
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
|
||||
|
@ -728,11 +866,12 @@ void load(const std::filesystem::path& path) {
|
|||
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
|
||||
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
|
||||
main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0);
|
||||
m_pkg_viewer = toml::find_or<std::vector<std::string>>(gui, "pkgDirs", {});
|
||||
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
|
||||
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
|
||||
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
|
||||
emulator_language = toml::find_or<std::string>(gui, "emulatorLanguage", "en");
|
||||
emulator_language = toml::find_or<std::string>(gui, "emulatorLanguage", "en_US");
|
||||
backgroundImageOpacity = toml::find_or<int>(gui, "backgroundImageOpacity", 50);
|
||||
showBackgroundImage = toml::find_or<bool>(gui, "showBackgroundImage", true);
|
||||
}
|
||||
|
||||
if (data.contains("Settings")) {
|
||||
|
@ -745,10 +884,53 @@ void load(const std::filesystem::path& path) {
|
|||
const toml::value& keys = data.at("Keys");
|
||||
trophyKey = toml::find_or<std::string>(keys, "TrophyKey", "");
|
||||
}
|
||||
|
||||
// Check if the loaded language is in the allowed list
|
||||
const std::vector<std::string> allowed_languages = {
|
||||
"ar_SA", "da_DK", "de_DE", "el_GR", "en_US", "es_ES", "fa_IR", "fi_FI", "fr_FR", "hu_HU",
|
||||
"id_ID", "it_IT", "ja_JP", "ko_KR", "lt_LT", "nb_NO", "nl_NL", "pl_PL", "pt_BR", "pt_PT",
|
||||
"ro_RO", "ru_RU", "sq_AL", "sv_SE", "tr_TR", "uk_UA", "vi_VN", "zh_CN", "zh_TW"};
|
||||
|
||||
if (std::find(allowed_languages.begin(), allowed_languages.end(), emulator_language) ==
|
||||
allowed_languages.end()) {
|
||||
emulator_language = "en_US"; // Default to en_US if not in the list
|
||||
save(path);
|
||||
}
|
||||
}
|
||||
|
||||
void sortTomlSections(toml::ordered_value& data) {
|
||||
toml::ordered_value ordered_data;
|
||||
std::vector<std::string> section_order = {"General", "Input", "GPU", "Vulkan",
|
||||
"Debug", "Keys", "GUI", "Settings"};
|
||||
|
||||
for (const auto& section : section_order) {
|
||||
if (data.contains(section)) {
|
||||
std::vector<std::string> keys;
|
||||
for (const auto& item : data.at(section).as_table()) {
|
||||
keys.push_back(item.first);
|
||||
}
|
||||
|
||||
std::sort(keys.begin(), keys.end(), [](const std::string& a, const std::string& b) {
|
||||
return std::lexicographical_compare(
|
||||
a.begin(), a.end(), b.begin(), b.end(), [](char a_char, char b_char) {
|
||||
return std::tolower(a_char) < std::tolower(b_char);
|
||||
});
|
||||
});
|
||||
|
||||
toml::ordered_value ordered_section;
|
||||
for (const auto& key : keys) {
|
||||
ordered_section[key] = data.at(section).at(key);
|
||||
}
|
||||
|
||||
ordered_data[section] = ordered_section;
|
||||
}
|
||||
}
|
||||
|
||||
data = ordered_data;
|
||||
}
|
||||
|
||||
void save(const std::filesystem::path& path) {
|
||||
toml::value data;
|
||||
toml::ordered_value data;
|
||||
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(path, error)) {
|
||||
|
@ -756,7 +938,8 @@ void save(const std::filesystem::path& path) {
|
|||
std::ifstream ifs;
|
||||
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
ifs.open(path, std::ios_base::binary);
|
||||
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
|
||||
data = toml::parse<toml::ordered_type_config>(
|
||||
ifs, std::string{fmt::UTF(path.filename().u8string()).data});
|
||||
} catch (const std::exception& ex) {
|
||||
fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
|
||||
return;
|
||||
|
@ -769,9 +952,9 @@ void save(const std::filesystem::path& path) {
|
|||
}
|
||||
|
||||
data["General"]["isPS4Pro"] = isNeo;
|
||||
data["General"]["Fullscreen"] = isFullscreen;
|
||||
data["General"]["FullscreenMode"] = fullscreenMode;
|
||||
data["General"]["isDevKit"] = isDevKit;
|
||||
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
|
||||
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
|
||||
data["General"]["playBGM"] = playBGM;
|
||||
data["General"]["BGMvolume"] = BGMvolume;
|
||||
data["General"]["enableDiscordRPC"] = enableDiscordRPC;
|
||||
|
@ -782,17 +965,17 @@ void save(const std::filesystem::path& path) {
|
|||
data["General"]["chooseHomeTab"] = chooseHomeTab;
|
||||
data["General"]["showSplash"] = isShowSplash;
|
||||
data["General"]["autoUpdate"] = isAutoUpdate;
|
||||
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
|
||||
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
|
||||
data["General"]["sideTrophy"] = isSideTrophy;
|
||||
data["General"]["compatibilityEnabled"] = compatibilityData;
|
||||
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
|
||||
data["Input"]["deadZoneLeft"] = deadZoneLeft;
|
||||
data["Input"]["deadZoneRight"] = deadZoneRight;
|
||||
data["Input"]["cursorState"] = cursorState;
|
||||
data["Input"]["cursorHideTimeout"] = cursorHideTimeout;
|
||||
data["Input"]["backButtonBehavior"] = backButtonBehavior;
|
||||
data["Input"]["useSpecialPad"] = useSpecialPad;
|
||||
data["Input"]["specialPadClass"] = specialPadClass;
|
||||
data["Input"]["isMotionControlsEnabled"] = isMotionControlsEnabled;
|
||||
data["Input"]["useUnifiedInputConfig"] = useUnifiedInputConfig;
|
||||
data["GPU"]["screenWidth"] = screenWidth;
|
||||
data["GPU"]["screenHeight"] = screenHeight;
|
||||
data["GPU"]["nullGpu"] = isNullGpu;
|
||||
|
@ -800,6 +983,9 @@ void save(const std::filesystem::path& path) {
|
|||
data["GPU"]["dumpShaders"] = shouldDumpShaders;
|
||||
data["GPU"]["patchShaders"] = shouldPatchShaders;
|
||||
data["GPU"]["vblankDivider"] = vblankDivider;
|
||||
data["GPU"]["Fullscreen"] = isFullscreen;
|
||||
data["GPU"]["FullscreenMode"] = fullscreenMode;
|
||||
data["GPU"]["allowHDR"] = isHDRAllowed;
|
||||
data["Vulkan"]["gpuId"] = gpuId;
|
||||
data["Vulkan"]["validation"] = vkValidation;
|
||||
data["Vulkan"]["validation_sync"] = vkValidationSync;
|
||||
|
@ -810,30 +996,61 @@ void save(const std::filesystem::path& path) {
|
|||
data["Vulkan"]["rdocEnable"] = rdocEnable;
|
||||
data["Debug"]["DebugDump"] = isDebugDump;
|
||||
data["Debug"]["CollectShader"] = isShaderDebug;
|
||||
|
||||
data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled;
|
||||
data["Debug"]["FPSColor"] = isFpsColor;
|
||||
data["Keys"]["TrophyKey"] = trophyKey;
|
||||
|
||||
std::vector<std::string> install_dirs;
|
||||
for (const auto& dirString : settings_install_dirs) {
|
||||
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
|
||||
std::vector<bool> install_dirs_enabled;
|
||||
|
||||
// temporary structure for ordering
|
||||
struct DirEntry {
|
||||
std::string path_str;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
std::vector<DirEntry> sorted_dirs;
|
||||
for (const auto& dirInfo : settings_install_dirs) {
|
||||
sorted_dirs.push_back(
|
||||
{std::string{fmt::UTF(dirInfo.path.u8string()).data}, dirInfo.enabled});
|
||||
}
|
||||
|
||||
// Sort directories alphabetically
|
||||
std::sort(sorted_dirs.begin(), sorted_dirs.end(), [](const DirEntry& a, const DirEntry& b) {
|
||||
return std::lexicographical_compare(
|
||||
a.path_str.begin(), a.path_str.end(), b.path_str.begin(), b.path_str.end(),
|
||||
[](char a_char, char b_char) { return std::tolower(a_char) < std::tolower(b_char); });
|
||||
});
|
||||
|
||||
for (const auto& entry : sorted_dirs) {
|
||||
install_dirs.push_back(entry.path_str);
|
||||
install_dirs_enabled.push_back(entry.enabled);
|
||||
}
|
||||
|
||||
data["GUI"]["installDirs"] = install_dirs;
|
||||
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
|
||||
data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data};
|
||||
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
|
||||
|
||||
data["GUI"]["addonInstallDir"] =
|
||||
std::string{fmt::UTF(settings_addon_install_dir.u8string()).data};
|
||||
data["GUI"]["emulatorLanguage"] = emulator_language;
|
||||
data["GUI"]["backgroundImageOpacity"] = backgroundImageOpacity;
|
||||
data["GUI"]["showBackgroundImage"] = showBackgroundImage;
|
||||
data["Settings"]["consoleLanguage"] = m_language;
|
||||
|
||||
// Sorting of TOML sections
|
||||
sortTomlSections(data);
|
||||
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
file << data;
|
||||
file.close();
|
||||
|
||||
saveMainWindow(path);
|
||||
}
|
||||
|
||||
void saveMainWindow(const std::filesystem::path& path) {
|
||||
toml::value data;
|
||||
toml::ordered_value data;
|
||||
|
||||
std::error_code error;
|
||||
if (std::filesystem::exists(path, error)) {
|
||||
|
@ -841,7 +1058,8 @@ void saveMainWindow(const std::filesystem::path& path) {
|
|||
std::ifstream ifs;
|
||||
ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
|
||||
ifs.open(path, std::ios_base::binary);
|
||||
data = toml::parse(ifs, std::string{fmt::UTF(path.filename().u8string()).data});
|
||||
data = toml::parse<toml::ordered_type_config>(
|
||||
ifs, std::string{fmt::UTF(path.filename().u8string()).data});
|
||||
} catch (const std::exception& ex) {
|
||||
fmt::print("Exception trying to parse config file. Exception: {}\n", ex.what());
|
||||
return;
|
||||
|
@ -865,17 +1083,21 @@ void saveMainWindow(const std::filesystem::path& path) {
|
|||
data["GUI"]["geometry_y"] = main_window_geometry_y;
|
||||
data["GUI"]["geometry_w"] = main_window_geometry_w;
|
||||
data["GUI"]["geometry_h"] = main_window_geometry_h;
|
||||
data["GUI"]["pkgDirs"] = m_pkg_viewer;
|
||||
data["GUI"]["elfDirs"] = m_elf_viewer;
|
||||
data["GUI"]["recentFiles"] = m_recent_files;
|
||||
|
||||
// Sorting of TOML sections
|
||||
sortTomlSections(data);
|
||||
|
||||
std::ofstream file(path, std::ios::binary);
|
||||
file << data;
|
||||
file.close();
|
||||
}
|
||||
|
||||
void setDefaultValues() {
|
||||
isHDRAllowed = false;
|
||||
isNeo = false;
|
||||
isDevKit = false;
|
||||
isFullscreen = false;
|
||||
isTrophyPopupDisabled = false;
|
||||
playBGM = false;
|
||||
|
@ -884,9 +1106,9 @@ void setDefaultValues() {
|
|||
screenWidth = 1280;
|
||||
screenHeight = 720;
|
||||
logFilter = "";
|
||||
logType = "async";
|
||||
logType = "sync";
|
||||
userName = "shadPS4";
|
||||
if (Common::isRelease) {
|
||||
if (Common::g_is_release) {
|
||||
updateChannel = "Release";
|
||||
} else {
|
||||
updateChannel = "Nightly";
|
||||
|
@ -894,6 +1116,7 @@ void setDefaultValues() {
|
|||
chooseHomeTab = "General";
|
||||
cursorState = HideCursorState::Idle;
|
||||
cursorHideTimeout = 5;
|
||||
trophyNotificationDuration = 6.0;
|
||||
backButtonBehavior = "left";
|
||||
useSpecialPad = false;
|
||||
specialPadClass = 1;
|
||||
|
@ -901,6 +1124,8 @@ void setDefaultValues() {
|
|||
isShaderDebug = false;
|
||||
isShowSplash = false;
|
||||
isAutoUpdate = false;
|
||||
isAlwaysShowChangelog = false;
|
||||
isSideTrophy = "right";
|
||||
isNullGpu = false;
|
||||
shouldDumpShaders = false;
|
||||
vblankDivider = 1;
|
||||
|
@ -911,12 +1136,123 @@ void setDefaultValues() {
|
|||
vkHostMarkers = false;
|
||||
vkGuestMarkers = false;
|
||||
rdocEnable = false;
|
||||
emulator_language = "en";
|
||||
emulator_language = "en_US";
|
||||
m_language = 1;
|
||||
gpuId = -1;
|
||||
separateupdatefolder = false;
|
||||
compatibilityData = false;
|
||||
checkCompatibilityOnStartup = false;
|
||||
backgroundImageOpacity = 50;
|
||||
showBackgroundImage = true;
|
||||
}
|
||||
|
||||
constexpr std::string_view GetDefaultKeyboardConfig() {
|
||||
return R"(#Feeling lost? Check out the Help section!
|
||||
|
||||
# Keyboard bindings
|
||||
|
||||
triangle = kp8
|
||||
circle = kp6
|
||||
cross = kp2
|
||||
square = kp4
|
||||
# Alternatives for users without a keypad
|
||||
triangle = c
|
||||
circle = b
|
||||
cross = n
|
||||
square = v
|
||||
|
||||
l1 = q
|
||||
r1 = u
|
||||
l2 = e
|
||||
r2 = o
|
||||
l3 = x
|
||||
r3 = m
|
||||
|
||||
options = enter
|
||||
touchpad = space
|
||||
|
||||
pad_up = up
|
||||
pad_down = down
|
||||
pad_left = left
|
||||
pad_right = right
|
||||
|
||||
axis_left_x_minus = a
|
||||
axis_left_x_plus = d
|
||||
axis_left_y_minus = w
|
||||
axis_left_y_plus = s
|
||||
|
||||
axis_right_x_minus = j
|
||||
axis_right_x_plus = l
|
||||
axis_right_y_minus = i
|
||||
axis_right_y_plus = k
|
||||
|
||||
# Controller bindings
|
||||
|
||||
triangle = triangle
|
||||
cross = cross
|
||||
square = square
|
||||
circle = circle
|
||||
|
||||
l1 = l1
|
||||
l2 = l2
|
||||
l3 = l3
|
||||
r1 = r1
|
||||
r2 = r2
|
||||
r3 = r3
|
||||
|
||||
options = options
|
||||
touchpad = back
|
||||
|
||||
pad_up = pad_up
|
||||
pad_down = pad_down
|
||||
pad_left = pad_left
|
||||
pad_right = pad_right
|
||||
|
||||
axis_left_x = axis_left_x
|
||||
axis_left_y = axis_left_y
|
||||
axis_right_x = axis_right_x
|
||||
axis_right_y = axis_right_y
|
||||
|
||||
# Range of deadzones: 1 (almost none) to 127 (max)
|
||||
analog_deadzone = leftjoystick, 2, 127
|
||||
analog_deadzone = rightjoystick, 2, 127
|
||||
|
||||
override_controller_color = false, 0, 0, 255
|
||||
)";
|
||||
}
|
||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id) {
|
||||
// Read configuration file of the game, and if it doesn't exist, generate it from default
|
||||
// If that doesn't exist either, generate that from getDefaultConfig() and try again
|
||||
// If even the folder is missing, we start with that.
|
||||
|
||||
const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir) / "input_config";
|
||||
const auto config_file = config_dir / (game_id + ".ini");
|
||||
const auto default_config_file = config_dir / "default.ini";
|
||||
|
||||
// Ensure the config directory exists
|
||||
if (!std::filesystem::exists(config_dir)) {
|
||||
std::filesystem::create_directories(config_dir);
|
||||
}
|
||||
|
||||
// Check if the default config exists
|
||||
if (!std::filesystem::exists(default_config_file)) {
|
||||
// If the default config is also missing, create it from getDefaultConfig()
|
||||
const auto default_config = GetDefaultKeyboardConfig();
|
||||
std::ofstream default_config_stream(default_config_file);
|
||||
if (default_config_stream) {
|
||||
default_config_stream << default_config;
|
||||
}
|
||||
}
|
||||
|
||||
// if empty, we only need to execute the function up until this point
|
||||
if (game_id.empty()) {
|
||||
return default_config_file;
|
||||
}
|
||||
|
||||
// If game-specific config doesn't exist, create it from the default config
|
||||
if (!std::filesystem::exists(config_file)) {
|
||||
std::filesystem::copy(default_config_file, config_file);
|
||||
}
|
||||
return config_file;
|
||||
}
|
||||
|
||||
} // namespace Config
|
|
@ -9,6 +9,11 @@
|
|||
|
||||
namespace Config {
|
||||
|
||||
struct GameInstallDir {
|
||||
std::filesystem::path path;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
enum HideCursorState : s16 { Never, Idle, Always };
|
||||
|
||||
void load(const std::filesystem::path& path);
|
||||
|
@ -21,15 +26,19 @@ bool GetLoadGameSizeEnabled();
|
|||
std::filesystem::path GetSaveDataPath();
|
||||
void setLoadGameSizeEnabled(bool enable);
|
||||
bool getIsFullscreen();
|
||||
bool getShowLabelsUnderIcons();
|
||||
bool setShowLabelsUnderIcons();
|
||||
std::string getFullscreenMode();
|
||||
bool isNeoModeConsole();
|
||||
bool isDevKitConsole();
|
||||
bool getPlayBGM();
|
||||
int getBGMvolume();
|
||||
bool getisTrophyPopupDisabled();
|
||||
bool getEnableDiscordRPC();
|
||||
bool getSeparateUpdateEnabled();
|
||||
bool getCompatibilityEnabled();
|
||||
bool getCheckCompatibilityOnStartup();
|
||||
int getBackgroundImageOpacity();
|
||||
bool getShowBackgroundImage();
|
||||
|
||||
std::string getLogFilter();
|
||||
std::string getLogType();
|
||||
|
@ -37,35 +46,47 @@ std::string getUserName();
|
|||
std::string getUpdateChannel();
|
||||
std::string getChooseHomeTab();
|
||||
|
||||
u16 leftDeadZone();
|
||||
u16 rightDeadZone();
|
||||
s16 getCursorState();
|
||||
int getCursorHideTimeout();
|
||||
double getTrophyNotificationDuration();
|
||||
std::string getBackButtonBehavior();
|
||||
bool getUseSpecialPad();
|
||||
int getSpecialPadClass();
|
||||
bool getIsMotionControlsEnabled();
|
||||
bool GetUseUnifiedInputConfig();
|
||||
void SetUseUnifiedInputConfig(bool use);
|
||||
bool GetOverrideControllerColor();
|
||||
void SetOverrideControllerColor(bool enable);
|
||||
int* GetControllerCustomColor();
|
||||
void SetControllerCustomColor(int r, int b, int g);
|
||||
|
||||
u32 getScreenWidth();
|
||||
u32 getScreenHeight();
|
||||
s32 getGpuId();
|
||||
bool allowHDR();
|
||||
|
||||
bool debugDump();
|
||||
bool collectShadersForDebug();
|
||||
bool showSplash();
|
||||
bool autoUpdate();
|
||||
bool alwaysShowChangelog();
|
||||
std::string sideTrophy();
|
||||
bool nullGpu();
|
||||
bool copyGPUCmdBuffers();
|
||||
bool dumpShaders();
|
||||
bool patchShaders();
|
||||
bool isRdocEnabled();
|
||||
bool fpsColor();
|
||||
u32 vblankDiv();
|
||||
|
||||
void setDebugDump(bool enable);
|
||||
void setCollectShaderForDebug(bool enable);
|
||||
void setShowSplash(bool enable);
|
||||
void setAutoUpdate(bool enable);
|
||||
void setAlwaysShowChangelog(bool enable);
|
||||
void setSideTrophy(std::string side);
|
||||
void setNullGpu(bool enable);
|
||||
void setAllowHDR(bool enable);
|
||||
void setCopyGPUCmdBuffers(bool enable);
|
||||
void setDumpShaders(bool enable);
|
||||
void setVblankDiv(u32 value);
|
||||
|
@ -83,14 +104,17 @@ void setNeoMode(bool enable);
|
|||
void setUserName(const std::string& type);
|
||||
void setUpdateChannel(const std::string& type);
|
||||
void setChooseHomeTab(const std::string& type);
|
||||
void setSeparateUpdateEnabled(bool use);
|
||||
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
|
||||
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);
|
||||
void setBackgroundImageOpacity(int opacity);
|
||||
void setShowBackgroundImage(bool show);
|
||||
|
||||
void setCursorState(s16 cursorState);
|
||||
void setCursorHideTimeout(int newcursorHideTimeout);
|
||||
void setTrophyNotificationDuration(double newTrophyNotificationDuration);
|
||||
void setBackButtonBehavior(const std::string& type);
|
||||
void setUseSpecialPad(bool use);
|
||||
void setSpecialPadClass(int type);
|
||||
|
@ -98,7 +122,8 @@ void setIsMotionControlsEnabled(bool use);
|
|||
|
||||
void setLogType(const std::string& type);
|
||||
void setLogFilter(const std::string& type);
|
||||
|
||||
void setSeparateLogFilesEnabled(bool enabled);
|
||||
bool getSeparateLogFilesEnabled();
|
||||
void setVkValidation(bool enable);
|
||||
void setVkSyncValidation(bool enable);
|
||||
void setRdocEnabled(bool enable);
|
||||
|
@ -115,8 +140,9 @@ void setVkGuestMarkersEnabled(bool enable);
|
|||
|
||||
// Gui
|
||||
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
|
||||
bool addGameInstallDir(const std::filesystem::path& dir);
|
||||
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
|
||||
void removeGameInstallDir(const std::filesystem::path& dir);
|
||||
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
|
||||
void setAddonInstallDir(const std::filesystem::path& dir);
|
||||
void setMainWindowTheme(u32 theme);
|
||||
void setIconSize(u32 size);
|
||||
|
@ -126,7 +152,6 @@ void setSliderPositionGrid(u32 pos);
|
|||
void setTableMode(u32 mode);
|
||||
void setMainWindowWidth(u32 width);
|
||||
void setMainWindowHeight(u32 height);
|
||||
void setPkgViewer(const std::vector<std::string>& pkgList);
|
||||
void setElfViewer(const std::vector<std::string>& elfList);
|
||||
void setRecentFiles(const std::vector<std::string>& recentFiles);
|
||||
void setEmulatorLanguage(std::string language);
|
||||
|
@ -135,7 +160,8 @@ u32 getMainWindowGeometryX();
|
|||
u32 getMainWindowGeometryY();
|
||||
u32 getMainWindowGeometryW();
|
||||
u32 getMainWindowGeometryH();
|
||||
const std::vector<std::filesystem::path>& getGameInstallDirs();
|
||||
const std::vector<std::filesystem::path> getGameInstallDirs();
|
||||
const std::vector<bool> getGameInstallDirsEnabled();
|
||||
std::filesystem::path getAddonInstallDir();
|
||||
u32 getMainWindowTheme();
|
||||
u32 getIconSize();
|
||||
|
@ -145,13 +171,15 @@ u32 getSliderPositionGrid();
|
|||
u32 getTableMode();
|
||||
u32 getMainWindowWidth();
|
||||
u32 getMainWindowHeight();
|
||||
std::vector<std::string> getPkgViewer();
|
||||
std::vector<std::string> getElfViewer();
|
||||
std::vector<std::string> getRecentFiles();
|
||||
std::string getEmulatorLanguage();
|
||||
|
||||
void setDefaultValues();
|
||||
|
||||
// todo: name and function location pending
|
||||
std::filesystem::path GetFoolproofKbmConfigFile(const std::string& game_id = "");
|
||||
|
||||
// settings
|
||||
u32 GetLanguage();
|
||||
}; // namespace Config
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
|
@ -69,6 +70,8 @@ class ElfInfo {
|
|||
u32 raw_firmware_ver = 0;
|
||||
PSFAttributes psf_attributes{};
|
||||
|
||||
std::filesystem::path splash_path{};
|
||||
|
||||
public:
|
||||
static constexpr u32 FW_15 = 0x1500000;
|
||||
static constexpr u32 FW_16 = 0x1600000;
|
||||
|
@ -116,6 +119,10 @@ public:
|
|||
ASSERT(initialized);
|
||||
return psf_attributes;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
|
||||
return splash_path;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
|
|
@ -125,12 +125,15 @@ namespace {
|
|||
[[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) {
|
||||
switch (origin) {
|
||||
case SeekOrigin::SetOrigin:
|
||||
default:
|
||||
return SEEK_SET;
|
||||
case SeekOrigin::CurrentPosition:
|
||||
return SEEK_CUR;
|
||||
case SeekOrigin::End:
|
||||
return SEEK_END;
|
||||
default:
|
||||
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
|
||||
static_cast<u32>(origin));
|
||||
return SEEK_SET;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -377,20 +380,6 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
|
||||
u64 size = GetSize();
|
||||
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
|
||||
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
|
||||
return false;
|
||||
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
|
||||
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
|
||||
return false;
|
||||
} else if (origin == SeekOrigin::End && offset > 0) {
|
||||
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
|
||||
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;
|
||||
|
|
|
@ -61,6 +61,8 @@ enum class SeekOrigin : u32 {
|
|||
SetOrigin, // Seeks from the start of the file.
|
||||
CurrentPosition, // Seeks from the current file pointer position.
|
||||
End, // Seeks from the end of the file.
|
||||
SeekHole, // Seeks from the start of the next hole in the file.
|
||||
SeekData, // Seeks from the start of the next non-hole region in the file.
|
||||
};
|
||||
|
||||
class IOFile final {
|
||||
|
|
|
@ -139,8 +139,9 @@ public:
|
|||
std::filesystem::create_directory(log_dir);
|
||||
Filter filter;
|
||||
filter.ParseFilterString(Config::getLogFilter());
|
||||
instance = std::unique_ptr<Impl, decltype(&Deleter)>(new Impl(log_dir / LOG_FILE, filter),
|
||||
Deleter);
|
||||
const auto& log_file_path = log_file.empty() ? LOG_FILE : log_file;
|
||||
instance = std::unique_ptr<Impl, decltype(&Deleter)>(
|
||||
new Impl(log_dir / log_file_path, filter), Deleter);
|
||||
initialization_in_progress_suppress_logging = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Kernel, Sce) \
|
||||
CLS(Lib) \
|
||||
SUB(Lib, LibC) \
|
||||
SUB(Lib, LibcInternal) \
|
||||
SUB(Lib, Kernel) \
|
||||
SUB(Lib, Pad) \
|
||||
SUB(Lib, GnmDriver) \
|
||||
|
@ -100,6 +101,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, Ssl2) \
|
||||
SUB(Lib, SysModule) \
|
||||
SUB(Lib, Move) \
|
||||
SUB(Lib, NpAuth) \
|
||||
SUB(Lib, NpCommon) \
|
||||
SUB(Lib, NpManager) \
|
||||
SUB(Lib, NpScore) \
|
||||
|
@ -134,6 +136,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
|
|||
SUB(Lib, WebBrowserDialog) \
|
||||
SUB(Lib, NpParty) \
|
||||
SUB(Lib, Zlib) \
|
||||
SUB(Lib, Hmd) \
|
||||
CLS(Frontend) \
|
||||
CLS(Render) \
|
||||
SUB(Render, Vulkan) \
|
||||
|
|
|
@ -23,8 +23,8 @@ std::string FormatLogMessage(const Entry& entry) {
|
|||
const char* class_name = GetLogClassName(entry.log_class);
|
||||
const char* level_name = GetLevelName(entry.log_level);
|
||||
|
||||
return fmt::format("[{}] <{}> {}:{}:{}: {}", class_name, level_name, entry.filename,
|
||||
entry.function, entry.line_num, entry.message);
|
||||
return fmt::format("[{}] <{}> {}:{} {}: {}", class_name, level_name, entry.filename,
|
||||
entry.line_num, entry.function, entry.message);
|
||||
}
|
||||
|
||||
void PrintMessage(const Entry& entry) {
|
||||
|
|
|
@ -47,6 +47,7 @@ enum class Class : u8 {
|
|||
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_GnmDriver, ///< The LibSceGnmDriver implementation.
|
||||
|
@ -68,6 +69,7 @@ enum class Class : u8 {
|
|||
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
|
||||
|
@ -101,6 +103,7 @@ enum class Class : u8 {
|
|||
Lib_WebBrowserDialog, ///< The LibSceWebBrowserDialog implementation
|
||||
Lib_NpParty, ///< The LibSceNpParty implementation
|
||||
Lib_Zlib, ///< The LibSceZlib implementation.
|
||||
Lib_Hmd, ///< The LibSceHmd implementation.
|
||||
Frontend, ///< Emulator UI
|
||||
Render, ///< Video Core
|
||||
Render_Vulkan, ///< Vulkan backend
|
||||
|
|
|
@ -144,37 +144,39 @@ void OnGameLoaded() {
|
|||
std::string type = patchLineIt->attribute("Type").value();
|
||||
std::string address = patchLineIt->attribute("Address").value();
|
||||
std::string patchValue = patchLineIt->attribute("Value").value();
|
||||
std::string maskOffsetStr = patchLineIt->attribute("type").value();
|
||||
|
||||
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") {
|
||||
littleEndian = true;
|
||||
} else if (type == "bytes32") {
|
||||
littleEndian = true;
|
||||
} else if (type == "bytes64") {
|
||||
if (type == "bytes16" || type == "bytes32" || type == "bytes64") {
|
||||
littleEndian = true;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask") {
|
||||
if (type == "mask")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
// im not sure if this works, there is no games to test the mask
|
||||
// offset on yet
|
||||
if (!maskOffsetStr.empty())
|
||||
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
|
||||
}
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, false,
|
||||
littleEndian, patchMask);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -278,6 +280,11 @@ void OnGameLoaded() {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
@ -291,37 +298,39 @@ void OnGameLoaded() {
|
|||
QString patchValue = lineObject["Value"].toString();
|
||||
QString maskOffsetStr = lineObject["Offset"].toString();
|
||||
|
||||
patchValue = QString::fromStdString(
|
||||
convertValueToHex(type.toStdString(), patchValue.toStdString()));
|
||||
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") {
|
||||
if (type == "bytes16" || type == "bytes32" || type == "bytes64")
|
||||
littleEndian = true;
|
||||
} else if (type == "bytes32") {
|
||||
littleEndian = true;
|
||||
} else if (type == "bytes64") {
|
||||
littleEndian = true;
|
||||
}
|
||||
|
||||
MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
|
||||
int maskOffsetValue = 0;
|
||||
|
||||
if (type == "mask") {
|
||||
if (type == "mask")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask;
|
||||
|
||||
// im not sure if this works, there is no games to test the mask
|
||||
// offset on yet
|
||||
if (!maskOffsetStr.toStdString().empty())
|
||||
maskOffsetValue = std::stoi(maskOffsetStr.toStdString(), 0, 10);
|
||||
}
|
||||
|
||||
if (type == "mask_jump32")
|
||||
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;
|
||||
|
||||
MemoryPatcher::PatchMemory(currentPatchName, address.toStdString(),
|
||||
patchValue.toStdString(), false,
|
||||
littleEndian, patchMask);
|
||||
if (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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -350,7 +359,7 @@ void ApplyPendingPatches() {
|
|||
if (currentPatch.gameSerial != g_game_serial)
|
||||
continue;
|
||||
|
||||
PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr,
|
||||
PatchMemory(currentPatch.modNameStr, currentPatch.offsetStr, currentPatch.valueStr, "", "",
|
||||
currentPatch.isOffset, currentPatch.littleEndian, currentPatch.patchMask,
|
||||
currentPatch.maskOffset);
|
||||
}
|
||||
|
@ -358,8 +367,9 @@ void ApplyPendingPatches() {
|
|||
pending_patches.clear();
|
||||
}
|
||||
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
|
||||
bool littleEndian, PatchMask patchMask, int maskOffset) {
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
|
||||
std::string targetStr, std::string sizeStr, bool isOffset, bool littleEndian,
|
||||
PatchMask patchMask, int maskOffset) {
|
||||
// Send a request to modify the process memory.
|
||||
void* cheatAddress = nullptr;
|
||||
|
||||
|
@ -376,7 +386,83 @@ void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valu
|
|||
cheatAddress = reinterpret_cast<void*>(PatternScan(offsetStr) + maskOffset);
|
||||
}
|
||||
|
||||
// TODO: implement mask_jump32
|
||||
if (patchMask == PatchMask::Mask_Jump32) {
|
||||
int jumpSize = std::stoi(sizeStr);
|
||||
|
||||
constexpr int MAX_PATTERN_LENGTH = 256;
|
||||
if (jumpSize < 5) {
|
||||
LOG_ERROR(Loader, "Jump size must be at least 5 bytes");
|
||||
return;
|
||||
}
|
||||
if (jumpSize > MAX_PATTERN_LENGTH) {
|
||||
LOG_ERROR(Loader, "Jump size must be no more than {} bytes.", MAX_PATTERN_LENGTH);
|
||||
return;
|
||||
}
|
||||
|
||||
// Find the base address using "Address"
|
||||
uintptr_t baseAddress = PatternScan(offsetStr);
|
||||
if (baseAddress == 0) {
|
||||
LOG_ERROR(Loader, "PatternScan failed for mask_jump32 with pattern: {}", offsetStr);
|
||||
return;
|
||||
}
|
||||
uintptr_t patchAddress = baseAddress + maskOffset;
|
||||
|
||||
// Fills the original region (jumpSize bytes) with NOPs
|
||||
std::vector<u8> nopBytes(jumpSize, 0x90);
|
||||
std::memcpy(reinterpret_cast<void*>(patchAddress), nopBytes.data(), nopBytes.size());
|
||||
|
||||
// Use "Target" to locate the start of the code cave
|
||||
uintptr_t jump_target = PatternScan(targetStr);
|
||||
if (jump_target == 0) {
|
||||
LOG_ERROR(Loader, "PatternScan failed to Target with pattern: {}", targetStr);
|
||||
return;
|
||||
}
|
||||
|
||||
// Converts the Value attribute to a byte array (payload)
|
||||
std::vector<u8> payload;
|
||||
for (size_t i = 0; i < valueStr.length(); i += 2) {
|
||||
|
||||
std::string tempStr = valueStr.substr(i, 2);
|
||||
const char* byteStr = tempStr.c_str();
|
||||
char* endPtr;
|
||||
unsigned int byteVal = std::strtoul(byteStr, &endPtr, 16);
|
||||
|
||||
if (endPtr != byteStr + 2) {
|
||||
LOG_ERROR(Loader, "Invalid byte in Value: {}", valueStr.substr(i, 2));
|
||||
return;
|
||||
}
|
||||
payload.push_back(static_cast<u8>(byteVal));
|
||||
}
|
||||
|
||||
// Calculates the end of the code cave (where the return jump will be inserted)
|
||||
uintptr_t code_cave_end = jump_target + payload.size();
|
||||
|
||||
// Write the payload to the code cave, from jump_target
|
||||
std::memcpy(reinterpret_cast<void*>(jump_target), payload.data(), payload.size());
|
||||
|
||||
// Inserts the initial jump in the original region to divert to the code cave
|
||||
u8 jumpInstruction[5];
|
||||
jumpInstruction[0] = 0xE9;
|
||||
s32 relJump = static_cast<s32>(jump_target - patchAddress - 5);
|
||||
std::memcpy(&jumpInstruction[1], &relJump, sizeof(relJump));
|
||||
std::memcpy(reinterpret_cast<void*>(patchAddress), jumpInstruction,
|
||||
sizeof(jumpInstruction));
|
||||
|
||||
// Inserts jump back at the end of the code cave to resume execution after patching
|
||||
u8 jumpBack[5];
|
||||
jumpBack[0] = 0xE9;
|
||||
// Calculates the relative offset to return to the instruction immediately following the
|
||||
// overwritten region
|
||||
s32 target_return = static_cast<s32>((patchAddress + jumpSize) - (code_cave_end + 5));
|
||||
std::memcpy(&jumpBack[1], &target_return, sizeof(target_return));
|
||||
std::memcpy(reinterpret_cast<void*>(code_cave_end), jumpBack, sizeof(jumpBack));
|
||||
|
||||
LOG_INFO(Loader,
|
||||
"Applied Patch mask_jump32: {}, PatchAddress: {:#x}, JumpTarget: {:#x}, "
|
||||
"CodeCaveEnd: {:#x}, JumpSize: {}",
|
||||
modNameStr, patchAddress, jump_target, code_cave_end, jumpSize);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cheatAddress == nullptr) {
|
||||
LOG_ERROR(Loader, "Failed to get address for patch {}", modNameStr);
|
||||
|
|
|
@ -38,8 +38,9 @@ void OnGameLoaded();
|
|||
void AddPatchToQueue(patchInfo patchToAdd);
|
||||
void ApplyPendingPatches();
|
||||
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr, bool isOffset,
|
||||
bool littleEndian, PatchMask patchMask = PatchMask::None, int maskOffset = 0);
|
||||
void PatchMemory(std::string modNameStr, std::string offsetStr, std::string valueStr,
|
||||
std::string targetStr, std::string sizeStr, bool isOffset, bool littleEndian,
|
||||
PatchMask patchMask = PatchMask::None, int maskOffset = 0);
|
||||
|
||||
static std::vector<int32_t> PatternToByte(const std::string& pattern);
|
||||
uintptr_t PatternScan(const std::string& signature);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
#include <unordered_map>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
|
@ -16,6 +17,8 @@
|
|||
#ifdef _WIN32
|
||||
// This is the maximum number of UTF-16 code units permissible in Windows file paths
|
||||
#define MAX_PATH 260
|
||||
#include <Shlobj.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
|
||||
#define MAX_PATH 1024
|
||||
|
@ -57,7 +60,7 @@ static CFURLRef UntranslocateBundlePath(const CFURLRef bundle_path) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
static std::filesystem::path GetBundleParentDirectory() {
|
||||
static std::optional<std::filesystem::path> GetBundleParentDirectory() {
|
||||
if (CFBundleRef bundle_ref = CFBundleGetMainBundle()) {
|
||||
if (CFURLRef bundle_url_ref = CFBundleCopyBundleURL(bundle_ref)) {
|
||||
SCOPE_EXIT {
|
||||
|
@ -80,14 +83,16 @@ static std::filesystem::path GetBundleParentDirectory() {
|
|||
}
|
||||
}
|
||||
}
|
||||
return std::filesystem::current_path();
|
||||
return std::nullopt;
|
||||
}
|
||||
#endif
|
||||
|
||||
static auto UserPaths = [] {
|
||||
#ifdef __APPLE__
|
||||
#if defined(__APPLE__) && defined(ENABLE_QT_GUI)
|
||||
// Set the current path to the directory containing the app bundle.
|
||||
std::filesystem::current_path(GetBundleParentDirectory());
|
||||
if (const auto bundle_dir = GetBundleParentDirectory()) {
|
||||
std::filesystem::current_path(*bundle_dir);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Try the portable user directory first.
|
||||
|
@ -105,6 +110,10 @@ static auto UserPaths = [] {
|
|||
} else {
|
||||
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
|
||||
}
|
||||
#elif _WIN32
|
||||
TCHAR appdata[MAX_PATH] = {0};
|
||||
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, appdata);
|
||||
user_dir = std::filesystem::path(appdata) / "shadPS4";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -128,6 +137,22 @@ static auto UserPaths = [] {
|
|||
create_path(PathType::CheatsDir, user_dir / CHEATS_DIR);
|
||||
create_path(PathType::PatchesDir, user_dir / PATCHES_DIR);
|
||||
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
|
||||
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY);
|
||||
|
||||
std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt");
|
||||
if (notice_file.is_open()) {
|
||||
notice_file
|
||||
<< "++++++++++++++++++++++++++++++++\n+ Custom Trophy Images / Sound "
|
||||
"+\n++++++++++++++++++++++++++++++++\n\nYou can add custom images to the "
|
||||
"trophies.\n*We recommend a square resolution image, for example 200x200, 500x500, "
|
||||
"the same size as the height and width.\nIn this folder ('user\\custom_trophy'), "
|
||||
"add the files with the following "
|
||||
"names:\n\nbronze.png\nsilver.png\ngold.png\nplatinum.png\n\nYou can add a custom "
|
||||
"sound for trophy notifications.\n*By default, no audio is played unless it is in "
|
||||
"this folder and you are using the QT version.\nIn this folder "
|
||||
"('user\\custom_trophy'), add the files with the following names:\n\ntrophy.mp3";
|
||||
notice_file.close();
|
||||
}
|
||||
|
||||
return paths;
|
||||
}();
|
||||
|
@ -176,6 +201,34 @@ void SetUserPath(PathType shad_path, const fs::path& new_path) {
|
|||
UserPaths.insert_or_assign(shad_path, new_path);
|
||||
}
|
||||
|
||||
std::optional<fs::path> FindGameByID(const fs::path& dir, const std::string& game_id,
|
||||
int max_depth) {
|
||||
if (max_depth < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Check if this is the game we're looking for
|
||||
if (dir.filename() == game_id && fs::exists(dir / "sce_sys" / "param.sfo")) {
|
||||
auto eboot_path = dir / "eboot.bin";
|
||||
if (fs::exists(eboot_path)) {
|
||||
return eboot_path;
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively search subdirectories
|
||||
std::error_code ec;
|
||||
for (const auto& entry : fs::directory_iterator(dir, ec)) {
|
||||
if (!entry.is_directory()) {
|
||||
continue;
|
||||
}
|
||||
if (auto found = FindGameByID(entry.path(), game_id, max_depth - 1)) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
void PathToQString(QString& result, const std::filesystem::path& path) {
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#ifdef ENABLE_QT_GUI
|
||||
|
@ -26,6 +27,7 @@ enum class PathType {
|
|||
CheatsDir, // Where cheats are stored.
|
||||
PatchesDir, // Where patches are stored.
|
||||
MetaDataDir, // Where game metadata (e.g. trophies and menu backgrounds) is stored.
|
||||
CustomTrophy, // Where custom files for trophies are stored.
|
||||
};
|
||||
|
||||
constexpr auto PORTABLE_DIR = "user";
|
||||
|
@ -43,6 +45,7 @@ constexpr auto CAPTURES_DIR = "captures";
|
|||
constexpr auto CHEATS_DIR = "cheats";
|
||||
constexpr auto PATCHES_DIR = "patches";
|
||||
constexpr auto METADATA_DIR = "game_data";
|
||||
constexpr auto CUSTOM_TROPHY = "custom_trophy";
|
||||
|
||||
// Filenames
|
||||
constexpr auto LOG_FILE = "shad_log.txt";
|
||||
|
@ -115,4 +118,18 @@ void PathToQString(QString& result, const std::filesystem::path& path);
|
|||
[[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.
|
||||
*
|
||||
* @param dir Base directory to start the search from
|
||||
* @param game_id The game ID to search for
|
||||
* @param max_depth Maximum directory depth to search
|
||||
*
|
||||
* @returns Path to eboot.bin if found, std::nullopt otherwise
|
||||
*/
|
||||
[[nodiscard]] std::optional<std::filesystem::path> FindGameByID(const std::filesystem::path& dir,
|
||||
const std::string& game_id,
|
||||
int max_depth);
|
||||
|
||||
} // namespace Common::FS
|
||||
|
|
|
@ -339,7 +339,9 @@ void CondvarWait(Condvar& cv, std::unique_lock<Lock>& lk, std::stop_token token,
|
|||
}
|
||||
|
||||
std::stop_callback callback(token, [&] {
|
||||
{ std::scoped_lock lk2{*lk.mutex()}; }
|
||||
{
|
||||
std::scoped_lock lk2{*lk.mutex()};
|
||||
}
|
||||
cv.notify_all();
|
||||
});
|
||||
|
||||
|
|
|
@ -3,21 +3,17 @@
|
|||
|
||||
#include "common/scm_rev.h"
|
||||
|
||||
#define GIT_REV "@GIT_REV@"
|
||||
#define GIT_BRANCH "@GIT_BRANCH@"
|
||||
#define GIT_DESC "@GIT_DESC@"
|
||||
#define GIT_REMOTE_NAME "@GIT_REMOTE_NAME@"
|
||||
#define GIT_REMOTE_URL "@GIT_REMOTE_URL@"
|
||||
#define BUILD_DATE "@BUILD_DATE@"
|
||||
|
||||
namespace Common {
|
||||
|
||||
const char g_scm_rev[] = GIT_REV;
|
||||
const char g_scm_branch[] = GIT_BRANCH;
|
||||
const char g_scm_desc[] = GIT_DESC;
|
||||
const char g_scm_remote_name[] = GIT_REMOTE_NAME;
|
||||
const char g_scm_remote_url[] = GIT_REMOTE_URL;
|
||||
const char g_scm_date[] = BUILD_DATE;
|
||||
constexpr char g_version[] = "@APP_VERSION@";
|
||||
constexpr bool g_is_release = @APP_IS_RELEASE@;
|
||||
|
||||
constexpr char g_scm_rev[] = "@GIT_REV@";
|
||||
constexpr char g_scm_branch[] = "@GIT_BRANCH@";
|
||||
constexpr char g_scm_desc[] = "@GIT_DESC@";
|
||||
constexpr char g_scm_remote_name[] = "@GIT_REMOTE_NAME@";
|
||||
constexpr char g_scm_remote_url[] = "@GIT_REMOTE_URL@";
|
||||
constexpr char g_scm_date[] = "@BUILD_DATE@";
|
||||
|
||||
} // namespace
|
||||
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
|
||||
namespace Common {
|
||||
|
||||
extern const char g_version[];
|
||||
extern const bool g_is_release;
|
||||
|
||||
extern const char g_scm_rev[];
|
||||
extern const char g_scm_branch[];
|
||||
extern const char g_scm_desc[];
|
||||
|
|
180
src/common/sha1.h
Normal file
180
src/common/sha1.h
Normal file
|
@ -0,0 +1,180 @@
|
|||
// SPDX-FileCopyrightText: 2012 SAURAV MOHAPATRA <mohaps@gmail.com>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace sha1 {
|
||||
class SHA1 {
|
||||
public:
|
||||
typedef uint32_t digest32_t[5];
|
||||
typedef uint8_t digest8_t[20];
|
||||
inline static uint32_t LeftRotate(uint32_t value, size_t count) {
|
||||
return (value << count) ^ (value >> (32 - count));
|
||||
}
|
||||
SHA1() {
|
||||
reset();
|
||||
}
|
||||
virtual ~SHA1() {}
|
||||
SHA1(const SHA1& s) {
|
||||
*this = s;
|
||||
}
|
||||
const SHA1& operator=(const SHA1& s) {
|
||||
memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t));
|
||||
memcpy(m_block, s.m_block, 64);
|
||||
m_blockByteIndex = s.m_blockByteIndex;
|
||||
m_byteCount = s.m_byteCount;
|
||||
return *this;
|
||||
}
|
||||
SHA1& reset() {
|
||||
m_digest[0] = 0x67452301;
|
||||
m_digest[1] = 0xEFCDAB89;
|
||||
m_digest[2] = 0x98BADCFE;
|
||||
m_digest[3] = 0x10325476;
|
||||
m_digest[4] = 0xC3D2E1F0;
|
||||
m_blockByteIndex = 0;
|
||||
m_byteCount = 0;
|
||||
return *this;
|
||||
}
|
||||
SHA1& processByte(uint8_t octet) {
|
||||
this->m_block[this->m_blockByteIndex++] = octet;
|
||||
++this->m_byteCount;
|
||||
if (m_blockByteIndex == 64) {
|
||||
this->m_blockByteIndex = 0;
|
||||
processBlock();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBlock(const void* const start, const void* const end) {
|
||||
const uint8_t* begin = static_cast<const uint8_t*>(start);
|
||||
const uint8_t* finish = static_cast<const uint8_t*>(end);
|
||||
while (begin != finish) {
|
||||
processByte(*begin);
|
||||
begin++;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
SHA1& processBytes(const void* const data, size_t len) {
|
||||
const uint8_t* block = static_cast<const uint8_t*>(data);
|
||||
processBlock(block, block + len);
|
||||
return *this;
|
||||
}
|
||||
const uint32_t* getDigest(digest32_t digest) {
|
||||
size_t bitCount = this->m_byteCount * 8;
|
||||
processByte(0x80);
|
||||
if (this->m_blockByteIndex > 56) {
|
||||
while (m_blockByteIndex != 0) {
|
||||
processByte(0);
|
||||
}
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
} else {
|
||||
while (m_blockByteIndex < 56) {
|
||||
processByte(0);
|
||||
}
|
||||
}
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(0);
|
||||
processByte(static_cast<unsigned char>((bitCount >> 24) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount >> 16) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount >> 8) & 0xFF));
|
||||
processByte(static_cast<unsigned char>((bitCount) & 0xFF));
|
||||
|
||||
memcpy(digest, m_digest, 5 * sizeof(uint32_t));
|
||||
return digest;
|
||||
}
|
||||
const uint8_t* getDigestBytes(digest8_t digest) {
|
||||
digest32_t d32;
|
||||
getDigest(d32);
|
||||
size_t di = 0;
|
||||
digest[di++] = ((d32[0] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[0] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[0]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[1] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[1] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[1]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[2] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[2] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[2]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[3] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[3] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[3]) & 0xFF);
|
||||
|
||||
digest[di++] = ((d32[4] >> 24) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 16) & 0xFF);
|
||||
digest[di++] = ((d32[4] >> 8) & 0xFF);
|
||||
digest[di++] = ((d32[4]) & 0xFF);
|
||||
return digest;
|
||||
}
|
||||
|
||||
protected:
|
||||
void processBlock() {
|
||||
uint32_t w[80];
|
||||
for (size_t i = 0; i < 16; i++) {
|
||||
w[i] = (m_block[i * 4 + 0] << 24);
|
||||
w[i] |= (m_block[i * 4 + 1] << 16);
|
||||
w[i] |= (m_block[i * 4 + 2] << 8);
|
||||
w[i] |= (m_block[i * 4 + 3]);
|
||||
}
|
||||
for (size_t i = 16; i < 80; i++) {
|
||||
w[i] = LeftRotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1);
|
||||
}
|
||||
|
||||
uint32_t a = m_digest[0];
|
||||
uint32_t b = m_digest[1];
|
||||
uint32_t c = m_digest[2];
|
||||
uint32_t d = m_digest[3];
|
||||
uint32_t e = m_digest[4];
|
||||
|
||||
for (std::size_t i = 0; i < 80; ++i) {
|
||||
uint32_t f = 0;
|
||||
uint32_t k = 0;
|
||||
|
||||
if (i < 20) {
|
||||
f = (b & c) | (~b & d);
|
||||
k = 0x5A827999;
|
||||
} else if (i < 40) {
|
||||
f = b ^ c ^ d;
|
||||
k = 0x6ED9EBA1;
|
||||
} else if (i < 60) {
|
||||
f = (b & c) | (b & d) | (c & d);
|
||||
k = 0x8F1BBCDC;
|
||||
} else {
|
||||
f = b ^ c ^ d;
|
||||
k = 0xCA62C1D6;
|
||||
}
|
||||
uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i];
|
||||
e = d;
|
||||
d = c;
|
||||
c = LeftRotate(b, 30);
|
||||
b = a;
|
||||
a = temp;
|
||||
}
|
||||
|
||||
m_digest[0] += a;
|
||||
m_digest[1] += b;
|
||||
m_digest[2] += c;
|
||||
m_digest[3] += d;
|
||||
m_digest[4] += e;
|
||||
}
|
||||
|
||||
private:
|
||||
digest32_t m_digest;
|
||||
uint8_t m_block[64];
|
||||
size_t m_blockByteIndex;
|
||||
size_t m_byteCount;
|
||||
};
|
||||
} // namespace sha1
|
15
src/common/string_literal.h
Normal file
15
src/common/string_literal.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
template <size_t N, typename C = char>
|
||||
struct StringLiteral {
|
||||
static constexpr size_t len = N;
|
||||
|
||||
constexpr StringLiteral(const C (&str)[N]) {
|
||||
std::copy_n(str, N, value);
|
||||
}
|
||||
|
||||
C value[N]{};
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
namespace Common {
|
||||
|
||||
constexpr char VERSION[] = "0.6.0";
|
||||
constexpr bool isRelease = true;
|
||||
|
||||
} // namespace Common
|
|
@ -21,7 +21,8 @@
|
|||
|
||||
#if defined(__APPLE__) && defined(ARCH_X86_64)
|
||||
// Reserve space for the system address space using a zerofill section.
|
||||
asm(".zerofill GUEST_SYSTEM,GUEST_SYSTEM,__guest_system,0xFBFC00000");
|
||||
asm(".zerofill SYSTEM_MANAGED,SYSTEM_MANAGED,__SYSTEM_MANAGED,0x7FFBFC000");
|
||||
asm(".zerofill SYSTEM_RESERVED,SYSTEM_RESERVED,__SYSTEM_RESERVED,0x7C0004000");
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
|
|
|
@ -22,10 +22,6 @@
|
|||
#include <windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#ifdef __APPLE__
|
||||
#include <half.hpp>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
using namespace Xbyak::util;
|
||||
|
@ -81,469 +77,6 @@ static Xbyak::Address ZydisToXbyakMemoryOperand(const ZydisDecodedOperand& opera
|
|||
return ptr[expression];
|
||||
}
|
||||
|
||||
static u64 ZydisToXbyakImmediateOperand(const ZydisDecodedOperand& operand) {
|
||||
ASSERT_MSG(operand.type == ZYDIS_OPERAND_TYPE_IMMEDIATE,
|
||||
"Expected immediate operand, got type: {}", static_cast<u32>(operand.type));
|
||||
return operand.imm.value.u;
|
||||
}
|
||||
|
||||
static std::unique_ptr<Xbyak::Operand> ZydisToXbyakOperand(const ZydisDecodedOperand& operand) {
|
||||
switch (operand.type) {
|
||||
case ZYDIS_OPERAND_TYPE_REGISTER: {
|
||||
return std::make_unique<Xbyak::Reg>(ZydisToXbyakRegisterOperand(operand));
|
||||
}
|
||||
case ZYDIS_OPERAND_TYPE_MEMORY: {
|
||||
return std::make_unique<Xbyak::Address>(ZydisToXbyakMemoryOperand(operand));
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Unsupported operand type: {}", static_cast<u32>(operand.type));
|
||||
}
|
||||
}
|
||||
|
||||
static bool OperandUsesRegister(const Xbyak::Operand* operand, int index) {
|
||||
if (operand->isREG()) {
|
||||
return operand->getIdx() == index;
|
||||
}
|
||||
if (operand->isMEM()) {
|
||||
const Xbyak::RegExp& reg_exp = operand->getAddress().getRegExp();
|
||||
return reg_exp.getBase().getIdx() == index || reg_exp.getIndex().getIdx() == index;
|
||||
}
|
||||
UNREACHABLE_MSG("Unsupported operand kind: {}", static_cast<u32>(operand->getKind()));
|
||||
}
|
||||
|
||||
static bool IsRegisterAllocated(
|
||||
const std::initializer_list<const Xbyak::Operand*>& allocated_registers, const int index) {
|
||||
return std::ranges::find_if(allocated_registers.begin(), allocated_registers.end(),
|
||||
[index](const Xbyak::Operand* operand) {
|
||||
return OperandUsesRegister(operand, index);
|
||||
}) != allocated_registers.end();
|
||||
}
|
||||
|
||||
static Xbyak::Reg AllocateScratchRegister(
|
||||
const std::initializer_list<const Xbyak::Operand*> allocated_registers, const u32 bits) {
|
||||
for (int index = Xbyak::Operand::R8; index <= Xbyak::Operand::R15; index++) {
|
||||
if (!IsRegisterAllocated(allocated_registers, index)) {
|
||||
return Xbyak::Reg32e(index, static_cast<int>(bits));
|
||||
}
|
||||
}
|
||||
UNREACHABLE_MSG("Out of scratch registers!");
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
static pthread_key_t stack_pointer_slot;
|
||||
static pthread_key_t patch_stack_slot;
|
||||
static std::once_flag patch_context_slots_init_flag;
|
||||
static constexpr u32 patch_stack_size = 0x1000;
|
||||
|
||||
static_assert(sizeof(void*) == sizeof(u64),
|
||||
"Cannot fit a register inside a thread local storage slot.");
|
||||
|
||||
static void FreePatchStack(void* patch_stack) {
|
||||
// Subtract back to the bottom of the stack for free.
|
||||
std::free(static_cast<u8*>(patch_stack) - patch_stack_size);
|
||||
}
|
||||
|
||||
static void InitializePatchContextSlots() {
|
||||
ASSERT_MSG(pthread_key_create(&stack_pointer_slot, nullptr) == 0,
|
||||
"Unable to allocate thread-local register for stack pointer.");
|
||||
ASSERT_MSG(pthread_key_create(&patch_stack_slot, FreePatchStack) == 0,
|
||||
"Unable to allocate thread-local register for patch stack.");
|
||||
}
|
||||
|
||||
void InitializeThreadPatchStack() {
|
||||
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
|
||||
|
||||
pthread_setspecific(patch_stack_slot,
|
||||
static_cast<u8*>(std::malloc(patch_stack_size)) + patch_stack_size);
|
||||
}
|
||||
|
||||
/// Saves the stack pointer to thread local storage and loads the patch stack.
|
||||
static void SaveStack(Xbyak::CodeGenerator& c) {
|
||||
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
|
||||
|
||||
// Save original stack pointer and load patch stack.
|
||||
c.putSeg(gs);
|
||||
c.mov(qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))], rsp);
|
||||
c.putSeg(gs);
|
||||
c.mov(rsp, qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))]);
|
||||
}
|
||||
|
||||
/// Restores the stack pointer from thread local storage.
|
||||
static void RestoreStack(Xbyak::CodeGenerator& c) {
|
||||
std::call_once(patch_context_slots_init_flag, InitializePatchContextSlots);
|
||||
|
||||
// Save patch stack pointer and load original stack.
|
||||
c.putSeg(gs);
|
||||
c.mov(qword[reinterpret_cast<void*>(patch_stack_slot * sizeof(void*))], rsp);
|
||||
c.putSeg(gs);
|
||||
c.mov(rsp, qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))]);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// These utilities are not implemented as we can't save anything to thread local storage without
|
||||
// temporary registers.
|
||||
void InitializeThreadPatchStack() {
|
||||
// No-op
|
||||
}
|
||||
|
||||
/// Saves the stack pointer to thread local storage and loads the patch stack.
|
||||
static void SaveStack(Xbyak::CodeGenerator& c) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
/// Restores the stack pointer from thread local storage.
|
||||
static void RestoreStack(Xbyak::CodeGenerator& c) {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// Switches to the patch stack, saves registers, and restores the original stack.
|
||||
static void SaveRegisters(Xbyak::CodeGenerator& c, const std::initializer_list<Xbyak::Reg> regs) {
|
||||
SaveStack(c);
|
||||
for (const auto& reg : regs) {
|
||||
c.push(reg.cvt64());
|
||||
}
|
||||
RestoreStack(c);
|
||||
}
|
||||
|
||||
/// Switches to the patch stack, restores registers, and restores the original stack.
|
||||
static void RestoreRegisters(Xbyak::CodeGenerator& c,
|
||||
const std::initializer_list<Xbyak::Reg> regs) {
|
||||
SaveStack(c);
|
||||
for (const auto& reg : regs) {
|
||||
c.pop(reg.cvt64());
|
||||
}
|
||||
RestoreStack(c);
|
||||
}
|
||||
|
||||
/// Switches to the patch stack and stores all registers.
|
||||
static void SaveContext(Xbyak::CodeGenerator& c, bool save_flags = false) {
|
||||
SaveStack(c);
|
||||
for (int reg = Xbyak::Operand::RAX; reg <= Xbyak::Operand::R15; reg++) {
|
||||
c.push(Xbyak::Reg64(reg));
|
||||
}
|
||||
for (int reg = 0; reg <= 7; reg++) {
|
||||
c.lea(rsp, ptr[rsp - 32]);
|
||||
c.vmovdqu(ptr[rsp], Xbyak::Ymm(reg));
|
||||
}
|
||||
if (save_flags) {
|
||||
c.pushfq();
|
||||
}
|
||||
}
|
||||
|
||||
/// Restores all registers and restores the original stack.
|
||||
/// If the destination is a register, it is not restored to preserve the output.
|
||||
static void RestoreContext(Xbyak::CodeGenerator& c, const Xbyak::Operand& dst,
|
||||
bool restore_flags = false) {
|
||||
if (restore_flags) {
|
||||
c.popfq();
|
||||
}
|
||||
for (int reg = 7; reg >= 0; reg--) {
|
||||
if ((!dst.isXMM() && !dst.isYMM()) || dst.getIdx() != reg) {
|
||||
c.vmovdqu(Xbyak::Ymm(reg), ptr[rsp]);
|
||||
}
|
||||
c.lea(rsp, ptr[rsp + 32]);
|
||||
}
|
||||
for (int reg = Xbyak::Operand::R15; reg >= Xbyak::Operand::RAX; reg--) {
|
||||
if (!dst.isREG() || dst.getIdx() != reg) {
|
||||
c.pop(Xbyak::Reg64(reg));
|
||||
} else {
|
||||
c.lea(rsp, ptr[rsp + 8]);
|
||||
}
|
||||
}
|
||||
RestoreStack(c);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
|
||||
static void GenerateANDN(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src1 = ZydisToXbyakRegisterOperand(operands[1]);
|
||||
const auto src2 = ZydisToXbyakOperand(operands[2]);
|
||||
|
||||
const auto scratch = AllocateScratchRegister({&dst, &src1, src2.get()}, dst.getBit());
|
||||
|
||||
SaveRegisters(c, {scratch});
|
||||
|
||||
c.mov(scratch, src1);
|
||||
c.not_(scratch);
|
||||
c.and_(scratch, *src2);
|
||||
c.mov(dst, scratch);
|
||||
|
||||
RestoreRegisters(c, {scratch});
|
||||
}
|
||||
|
||||
static void GenerateBEXTR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakOperand(operands[1]);
|
||||
const auto start_len = ZydisToXbyakRegisterOperand(operands[2]);
|
||||
|
||||
const Xbyak::Reg32e shift(Xbyak::Operand::RCX, static_cast<int>(start_len.getBit()));
|
||||
const auto scratch1 =
|
||||
AllocateScratchRegister({&dst, src.get(), &start_len, &shift}, dst.getBit());
|
||||
const auto scratch2 =
|
||||
AllocateScratchRegister({&dst, src.get(), &start_len, &shift, &scratch1}, dst.getBit());
|
||||
|
||||
if (dst.getIdx() == shift.getIdx()) {
|
||||
SaveRegisters(c, {scratch1, scratch2});
|
||||
} else {
|
||||
SaveRegisters(c, {scratch1, scratch2, shift});
|
||||
}
|
||||
|
||||
c.mov(scratch1, *src);
|
||||
if (shift.getIdx() != start_len.getIdx()) {
|
||||
c.mov(shift, start_len);
|
||||
}
|
||||
|
||||
c.shr(scratch1, shift.cvt8());
|
||||
c.shr(shift, 8);
|
||||
c.mov(scratch2, 1);
|
||||
c.shl(scratch2, shift.cvt8());
|
||||
c.dec(scratch2);
|
||||
|
||||
c.mov(dst, scratch1);
|
||||
c.and_(dst, scratch2);
|
||||
|
||||
if (dst.getIdx() == shift.getIdx()) {
|
||||
RestoreRegisters(c, {scratch2, scratch1});
|
||||
} else {
|
||||
RestoreRegisters(c, {shift, scratch2, scratch1});
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateBLSI(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakOperand(operands[1]);
|
||||
|
||||
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
|
||||
|
||||
SaveRegisters(c, {scratch});
|
||||
|
||||
// BLSI sets CF to zero if source is zero, otherwise it sets CF to one.
|
||||
Xbyak::Label clear_carry, end;
|
||||
|
||||
c.mov(scratch, *src);
|
||||
c.neg(scratch); // NEG, like BLSI, clears CF if the source is zero and sets it otherwise
|
||||
c.jnc(clear_carry);
|
||||
|
||||
c.and_(scratch, *src);
|
||||
c.stc(); // setting/clearing carry needs to happen after the AND because that clears CF
|
||||
c.jmp(end);
|
||||
|
||||
c.L(clear_carry);
|
||||
c.and_(scratch, *src);
|
||||
// We don't need to clear carry here since AND does that for us
|
||||
|
||||
c.L(end);
|
||||
c.mov(dst, scratch);
|
||||
|
||||
RestoreRegisters(c, {scratch});
|
||||
}
|
||||
|
||||
static void GenerateBLSMSK(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakOperand(operands[1]);
|
||||
|
||||
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
|
||||
|
||||
SaveRegisters(c, {scratch});
|
||||
|
||||
Xbyak::Label clear_carry, end;
|
||||
|
||||
// BLSMSK sets CF to zero if source is NOT zero, otherwise it sets CF to one.
|
||||
c.mov(scratch, *src);
|
||||
c.test(scratch, scratch);
|
||||
c.jnz(clear_carry);
|
||||
|
||||
c.dec(scratch);
|
||||
c.xor_(scratch, *src);
|
||||
c.stc();
|
||||
c.jmp(end);
|
||||
|
||||
c.L(clear_carry);
|
||||
c.dec(scratch);
|
||||
c.xor_(scratch, *src);
|
||||
// We don't need to clear carry here since XOR does that for us
|
||||
|
||||
c.L(end);
|
||||
c.mov(dst, scratch);
|
||||
|
||||
RestoreRegisters(c, {scratch});
|
||||
}
|
||||
|
||||
static void GenerateBLSR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakOperand(operands[1]);
|
||||
|
||||
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
|
||||
|
||||
SaveRegisters(c, {scratch});
|
||||
|
||||
Xbyak::Label clear_carry, end;
|
||||
|
||||
// BLSR sets CF to zero if source is NOT zero, otherwise it sets CF to one.
|
||||
c.mov(scratch, *src);
|
||||
c.test(scratch, scratch);
|
||||
c.jnz(clear_carry);
|
||||
|
||||
c.dec(scratch);
|
||||
c.and_(scratch, *src);
|
||||
c.stc();
|
||||
c.jmp(end);
|
||||
|
||||
c.L(clear_carry);
|
||||
c.dec(scratch);
|
||||
c.and_(scratch, *src);
|
||||
// We don't need to clear carry here since AND does that for us
|
||||
|
||||
c.L(end);
|
||||
c.mov(dst, scratch);
|
||||
|
||||
RestoreRegisters(c, {scratch});
|
||||
}
|
||||
|
||||
static __attribute__((sysv_abi)) void PerformVCVTPH2PS(float* out, const half_float::half* in,
|
||||
const u32 count) {
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
out[i] = half_float::half_cast<float>(in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateVCVTPH2PS(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakOperand(operands[1]);
|
||||
|
||||
const auto float_count = dst.getBit() / 32;
|
||||
const auto byte_count = float_count * 4;
|
||||
|
||||
SaveContext(c, true);
|
||||
|
||||
// Allocate stack space for outputs and load into first parameter.
|
||||
c.sub(rsp, byte_count);
|
||||
c.mov(rdi, rsp);
|
||||
|
||||
if (src->isXMM()) {
|
||||
// Allocate stack space for inputs and load into second parameter.
|
||||
c.sub(rsp, byte_count);
|
||||
c.mov(rsi, rsp);
|
||||
|
||||
// Move input to the allocated space.
|
||||
c.movdqu(ptr[rsp], *reinterpret_cast<Xbyak::Xmm*>(src.get()));
|
||||
} else {
|
||||
c.lea(rsi, src->getAddress());
|
||||
}
|
||||
|
||||
// Load float count into third parameter.
|
||||
c.mov(rdx, float_count);
|
||||
|
||||
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPH2PS));
|
||||
c.call(rax);
|
||||
|
||||
if (src->isXMM()) {
|
||||
// Clean up after inputs space.
|
||||
c.add(rsp, byte_count);
|
||||
}
|
||||
|
||||
// Load outputs into destination register and clean up space.
|
||||
if (dst.isYMM()) {
|
||||
c.vmovdqu(*reinterpret_cast<const Xbyak::Ymm*>(&dst), ptr[rsp]);
|
||||
} else {
|
||||
c.movdqu(*reinterpret_cast<const Xbyak::Xmm*>(&dst), ptr[rsp]);
|
||||
}
|
||||
c.add(rsp, byte_count);
|
||||
|
||||
RestoreContext(c, dst, true);
|
||||
}
|
||||
|
||||
using SingleToHalfFloatConverter = half_float::half (*)(float);
|
||||
static const SingleToHalfFloatConverter SingleToHalfFloatConverters[4] = {
|
||||
half_float::half_cast<half_float::half, std::round_to_nearest, float>,
|
||||
half_float::half_cast<half_float::half, std::round_toward_neg_infinity, float>,
|
||||
half_float::half_cast<half_float::half, std::round_toward_infinity, float>,
|
||||
half_float::half_cast<half_float::half, std::round_toward_zero, float>,
|
||||
};
|
||||
|
||||
static __attribute__((sysv_abi)) void PerformVCVTPS2PH(half_float::half* out, const float* in,
|
||||
const u32 count, const u8 rounding_mode) {
|
||||
const auto conversion_func = SingleToHalfFloatConverters[rounding_mode];
|
||||
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
out[i] = conversion_func(in[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateVCVTPS2PH(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
|
||||
const auto dst = ZydisToXbyakOperand(operands[0]);
|
||||
const auto src = ZydisToXbyakRegisterOperand(operands[1]);
|
||||
const auto ctrl = ZydisToXbyakImmediateOperand(operands[2]);
|
||||
|
||||
const auto float_count = src.getBit() / 32;
|
||||
const auto byte_count = float_count * 4;
|
||||
|
||||
SaveContext(c, true);
|
||||
|
||||
if (dst->isXMM()) {
|
||||
// Allocate stack space for outputs and load into first parameter.
|
||||
c.sub(rsp, byte_count);
|
||||
c.mov(rdi, rsp);
|
||||
} else {
|
||||
c.lea(rdi, dst->getAddress());
|
||||
}
|
||||
|
||||
// Allocate stack space for inputs and load into second parameter.
|
||||
c.sub(rsp, byte_count);
|
||||
c.mov(rsi, rsp);
|
||||
|
||||
// Move input to the allocated space.
|
||||
if (src.isYMM()) {
|
||||
c.vmovdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Ymm*>(&src));
|
||||
} else {
|
||||
c.movdqu(ptr[rsp], *reinterpret_cast<const Xbyak::Xmm*>(&src));
|
||||
}
|
||||
|
||||
// Load float count into third parameter.
|
||||
c.mov(rdx, float_count);
|
||||
|
||||
// Load rounding mode into fourth parameter.
|
||||
if (ctrl & 4) {
|
||||
// Load from MXCSR.RC.
|
||||
c.stmxcsr(ptr[rsp - 4]);
|
||||
c.mov(rcx, ptr[rsp - 4]);
|
||||
c.shr(rcx, 13);
|
||||
c.and_(rcx, 3);
|
||||
} else {
|
||||
c.mov(rcx, ctrl & 3);
|
||||
}
|
||||
|
||||
c.mov(rax, reinterpret_cast<u64>(PerformVCVTPS2PH));
|
||||
c.call(rax);
|
||||
|
||||
// Clean up after inputs space.
|
||||
c.add(rsp, byte_count);
|
||||
|
||||
if (dst->isXMM()) {
|
||||
// Load outputs into destination register and clean up space.
|
||||
c.movdqu(*reinterpret_cast<Xbyak::Xmm*>(dst.get()), ptr[rsp]);
|
||||
c.add(rsp, byte_count);
|
||||
}
|
||||
|
||||
RestoreContext(c, *dst, true);
|
||||
}
|
||||
|
||||
static bool FilterRosetta2Only(const ZydisDecodedOperand*) {
|
||||
int ret = 0;
|
||||
size_t size = sizeof(ret);
|
||||
if (sysctlbyname("sysctl.proc_translated", &ret, &size, nullptr, 0) != 0) {
|
||||
return false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else // __APPLE__
|
||||
|
||||
static bool FilterTcbAccess(const ZydisDecodedOperand* operands) {
|
||||
const auto& dst_op = operands[0];
|
||||
const auto& src_op = operands[1];
|
||||
|
@ -588,8 +121,6 @@ static void GenerateTcbAccess(const ZydisDecodedOperand* operands, Xbyak::CodeGe
|
|||
#endif
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
|
||||
Cpu cpu;
|
||||
return !cpu.has(Cpu::tSSE4a);
|
||||
|
@ -866,28 +397,16 @@ struct PatchInfo {
|
|||
};
|
||||
|
||||
static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
|
||||
// SSE4a
|
||||
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
|
||||
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Windows needs a trampoline.
|
||||
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, true}},
|
||||
#elif !defined(__APPLE__)
|
||||
{ZYDIS_MNEMONIC_MOV, {FilterTcbAccess, GenerateTcbAccess, false}},
|
||||
#endif
|
||||
|
||||
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
|
||||
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
|
||||
|
||||
#ifdef __APPLE__
|
||||
// Patches for instruction sets not supported by Rosetta 2.
|
||||
// BMI1
|
||||
{ZYDIS_MNEMONIC_ANDN, {FilterRosetta2Only, GenerateANDN, true}},
|
||||
{ZYDIS_MNEMONIC_BEXTR, {FilterRosetta2Only, GenerateBEXTR, true}},
|
||||
{ZYDIS_MNEMONIC_BLSI, {FilterRosetta2Only, GenerateBLSI, true}},
|
||||
{ZYDIS_MNEMONIC_BLSMSK, {FilterRosetta2Only, GenerateBLSMSK, true}},
|
||||
{ZYDIS_MNEMONIC_BLSR, {FilterRosetta2Only, GenerateBLSR, true}},
|
||||
// F16C
|
||||
{ZYDIS_MNEMONIC_VCVTPH2PS, {FilterRosetta2Only, GenerateVCVTPH2PS, true}},
|
||||
{ZYDIS_MNEMONIC_VCVTPS2PH, {FilterRosetta2Only, GenerateVCVTPS2PH, true}},
|
||||
#endif
|
||||
};
|
||||
|
||||
static std::once_flag init_flag;
|
||||
|
@ -1041,7 +560,7 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
|
|||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_WARNING(Core,
|
||||
LOG_TRACE(Core,
|
||||
"extrq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
|
@ -1101,7 +620,7 @@ static bool TryExecuteIllegalInstruction(void* ctx, void* code_address) {
|
|||
if (length + index > 64) {
|
||||
// Undefined behavior if length + index is bigger than 64 according to the spec,
|
||||
// we'll warn and continue execution.
|
||||
LOG_WARNING(Core,
|
||||
LOG_TRACE(Core,
|
||||
"insertq at {} with length {} and index {} is bigger than 64, "
|
||||
"undefined behavior",
|
||||
fmt::ptr(code_address), length, index);
|
||||
|
@ -1204,18 +723,7 @@ void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_are
|
|||
}
|
||||
|
||||
void PrePatchInstructions(u64 segment_addr, u64 segment_size) {
|
||||
#if defined(__APPLE__)
|
||||
// HACK: For some reason patching in the signal handler at the start of a page does not work
|
||||
// under Rosetta 2. Patch any instructions at the start of a page ahead of time.
|
||||
if (!Patches.empty()) {
|
||||
auto* code_page = reinterpret_cast<u8*>(Common::AlignUp(segment_addr, 0x1000));
|
||||
const auto* end_page = code_page + Common::AlignUp(segment_size, 0x1000);
|
||||
while (code_page < end_page) {
|
||||
TryPatchJit(code_page);
|
||||
code_page += 0x1000;
|
||||
}
|
||||
}
|
||||
#elif !defined(_WIN32)
|
||||
#if !defined(_WIN32) && !defined(__APPLE__)
|
||||
// Linux and others have an FS segment pointing to valid memory, so continue to do full
|
||||
// ahead-of-time patching for now until a better solution is worked out.
|
||||
if (!Patches.empty()) {
|
||||
|
|
|
@ -7,12 +7,6 @@
|
|||
|
||||
namespace Core {
|
||||
|
||||
/// Initializes a stack for the current thread for use by patch implementations.
|
||||
void InitializeThreadPatchStack();
|
||||
|
||||
/// Cleans up the patch stack for the current thread.
|
||||
void CleanupThreadPatchStack();
|
||||
|
||||
/// Registers a module for patching, providing an area to generate trampoline code.
|
||||
void RegisterPatchModule(void* module_ptr, u64 module_size, void* trampoline_area_ptr,
|
||||
u64 trampoline_area_size);
|
||||
|
|
|
@ -1,215 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "crypto.h"
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
|
||||
params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
|
||||
|
||||
params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
|
||||
|
||||
params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
|
||||
params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
|
||||
params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
|
||||
|
||||
params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
|
||||
|
||||
params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
|
||||
params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
|
||||
CryptoPP::InvertibleRSAFunction params;
|
||||
params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
|
||||
params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
|
||||
|
||||
params.SetPublicExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
|
||||
params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
|
||||
sizeof(DebugRifKeyset::PrivateExponent)));
|
||||
|
||||
params.SetModPrime1PrivateExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
|
||||
params.SetModPrime2PrivateExponent(
|
||||
CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
|
||||
|
||||
params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
|
||||
params.SetMultiplicativeInverseOfPrime2ModPrime1(
|
||||
CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
|
||||
|
||||
CryptoPP::RSA::PrivateKey privateKey(params);
|
||||
|
||||
return privateKey;
|
||||
}
|
||||
|
||||
void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
bool is_dk3) { // RSAES_PKCS1v15_
|
||||
// Create an RSA decryptor
|
||||
CryptoPP::RSA::PrivateKey privateKey;
|
||||
if (is_dk3) {
|
||||
privateKey = key_pkg_derived_key3_keyset_init();
|
||||
} else {
|
||||
privateKey = FakeKeyset_keyset_init();
|
||||
}
|
||||
|
||||
CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
|
||||
|
||||
// Allocate memory for the decrypted data
|
||||
std::array<CryptoPP::byte, 256> decrypted;
|
||||
|
||||
// Perform the decryption
|
||||
CryptoPP::AutoSeededRandomPool rng;
|
||||
CryptoPP::DecodingResult result =
|
||||
rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
|
||||
std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
|
||||
}
|
||||
|
||||
void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
|
||||
std::span<CryptoPP::byte, 32> ivkey_result) {
|
||||
CryptoPP::SHA256 sha256;
|
||||
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
|
||||
auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
|
||||
auto filter = new CryptoPP::HashFilter(sha256, array_sink);
|
||||
CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
|
||||
std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
|
||||
}
|
||||
|
||||
void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
std::span<CryptoPP::byte, 256> decrypted) {
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
|
||||
|
||||
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
|
||||
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
|
||||
|
||||
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
|
||||
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
|
||||
CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted) {
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
|
||||
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
|
||||
|
||||
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
|
||||
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
|
||||
|
||||
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
|
||||
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
|
||||
CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
|
||||
std::span<CryptoPP::byte, 16> NPcommID,
|
||||
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted) {
|
||||
|
||||
// step 1: Encrypt NPcommID
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
|
||||
|
||||
std::vector<CryptoPP::byte> trophyIv(16, 0);
|
||||
std::vector<CryptoPP::byte> trpKey(16);
|
||||
|
||||
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
|
||||
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
|
||||
|
||||
// step 2: decrypt efsm.
|
||||
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
|
||||
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
|
||||
|
||||
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
|
||||
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||
std::span<const CryptoPP::byte, 16> seed,
|
||||
std::span<CryptoPP::byte, 16> dataKey,
|
||||
std::span<CryptoPP::byte, 16> tweakKey) {
|
||||
CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
|
||||
|
||||
CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
|
||||
|
||||
// Copy the bytes of 'index' to the 'd' array
|
||||
uint32_t index = 1;
|
||||
std::memcpy(d, &index, sizeof(uint32_t));
|
||||
|
||||
// Copy the bytes of 'seed' to the 'd' array starting from index 4
|
||||
std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
|
||||
|
||||
// Allocate memory for 'u64' using new
|
||||
std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
|
||||
|
||||
// Calculate the HMAC
|
||||
hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
|
||||
std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
|
||||
std::copy(data_tweak_key.begin() + tweakKey.size(),
|
||||
data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
|
||||
}
|
||||
|
||||
void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
|
||||
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
|
||||
std::span<CryptoPP::byte> dst_image, u64 sector) {
|
||||
// Start at 0x10000 to keep the header when decrypting the whole pfs_image.
|
||||
for (int i = 0; i < src_image.size(); i += 0x1000) {
|
||||
const u64 current_sector = sector + (i / 0x1000);
|
||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
|
||||
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
|
||||
|
||||
std::array<CryptoPP::byte, 16> tweak{};
|
||||
std::array<CryptoPP::byte, 16> encryptedTweak;
|
||||
std::array<CryptoPP::byte, 16> xorBuffer;
|
||||
std::memcpy(tweak.data(), ¤t_sector, sizeof(u64));
|
||||
|
||||
// Encrypt the tweak for each sector.
|
||||
encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
|
||||
|
||||
for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
|
||||
xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
|
||||
encryptedTweak.data()); // x, c, t
|
||||
decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
|
||||
xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
|
||||
encryptedTweak.data()); //(p) c, x , t
|
||||
xtsMult(encryptedTweak);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <cryptopp/aes.h>
|
||||
#include <cryptopp/filters.h>
|
||||
#include <cryptopp/modes.h>
|
||||
#include <cryptopp/oaep.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/rsa.h>
|
||||
#include <cryptopp/sha.h>
|
||||
|
||||
#include "common/types.h"
|
||||
#include "keys.h"
|
||||
|
||||
class Crypto {
|
||||
public:
|
||||
CryptoPP::RSA::PrivateKey key_pkg_derived_key3_keyset_init();
|
||||
CryptoPP::RSA::PrivateKey FakeKeyset_keyset_init();
|
||||
CryptoPP::RSA::PrivateKey DebugRifKeyset_init();
|
||||
|
||||
void RSA2048Decrypt(std::span<CryptoPP::byte, 32> dk3,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
bool is_dk3); // RSAES_PKCS1v15_
|
||||
void ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
|
||||
std::span<CryptoPP::byte, 32> ivkey_result);
|
||||
void aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<const CryptoPP::byte, 256> ciphertext,
|
||||
std::span<CryptoPP::byte, 256> decrypted);
|
||||
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
|
||||
std::span<CryptoPP::byte> ciphertext,
|
||||
std::span<CryptoPP::byte> decrypted);
|
||||
void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
|
||||
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
|
||||
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
|
||||
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
|
||||
std::span<const CryptoPP::byte, 16> seed,
|
||||
std::span<CryptoPP::byte, 16> dataKey,
|
||||
std::span<CryptoPP::byte, 16> tweakKey);
|
||||
void decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
|
||||
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
|
||||
std::span<CryptoPP::byte> dst_image, u64 sector);
|
||||
|
||||
void xtsXorBlock(CryptoPP::byte* x, const CryptoPP::byte* a, const CryptoPP::byte* b) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
x[i] = a[i] ^ b[i];
|
||||
}
|
||||
}
|
||||
|
||||
void xtsMult(std::span<CryptoPP::byte, 16> encryptedTweak) {
|
||||
int feedback = 0;
|
||||
for (int k = 0; k < encryptedTweak.size(); k++) {
|
||||
const auto tmp = (encryptedTweak[k] >> 7) & 1;
|
||||
encryptedTweak[k] = ((encryptedTweak[k] << 1) + feedback) & 0xFF;
|
||||
feedback = tmp;
|
||||
}
|
||||
if (feedback != 0) {
|
||||
encryptedTweak[0] ^= 0x87;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -1,305 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
#include <cryptopp/rsa.h>
|
||||
|
||||
class FakeKeyset {
|
||||
public:
|
||||
// Constructor
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0x6D, 0x48, 0xE0, 0x54, 0x40, 0x25, 0xC8, 0x41, 0x29, 0x52, 0x42, 0x27, 0xEB, 0xD2, 0xC7,
|
||||
0xAB, 0x6B, 0x9C, 0x27, 0x0A, 0xB4, 0x1F, 0x94, 0x4E, 0xFA, 0x42, 0x1D, 0xB7, 0xBC, 0xB9,
|
||||
0xAE, 0xBC, 0x04, 0x6F, 0x75, 0x8F, 0x10, 0x5F, 0x89, 0xAC, 0xAB, 0x9C, 0xD2, 0xFA, 0xE6,
|
||||
0xA4, 0x13, 0x83, 0x68, 0xD4, 0x56, 0x38, 0xFE, 0xE5, 0x2B, 0x78, 0x44, 0x9C, 0x34, 0xE6,
|
||||
0x5A, 0xA0, 0xBE, 0x05, 0x70, 0xAD, 0x15, 0xC3, 0x2D, 0x31, 0xAC, 0x97, 0x5D, 0x88, 0xFC,
|
||||
0xC1, 0x62, 0x3D, 0xE2, 0xED, 0x11, 0xDB, 0xB6, 0x9E, 0xFC, 0x5A, 0x5A, 0x03, 0xF6, 0xCF,
|
||||
0x08, 0xD4, 0x5D, 0x90, 0xC9, 0x2A, 0xB9, 0x9B, 0xCF, 0xC8, 0x1A, 0x65, 0xF3, 0x5B, 0xE8,
|
||||
0x7F, 0xCF, 0xA5, 0xA6, 0x4C, 0x5C, 0x2A, 0x12, 0x0F, 0x92, 0xA5, 0xE3, 0xF0, 0x17, 0x1E,
|
||||
0x9A, 0x97, 0x45, 0x86, 0xFD, 0xDB, 0x54, 0x25};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0x2A, 0x51, 0xCE, 0x02, 0x44, 0x28, 0x50, 0xE8, 0x30, 0x20, 0x7C, 0x9C, 0x55, 0xBF, 0x60,
|
||||
0x39, 0xBC, 0xD1, 0xF0, 0xE7, 0x68, 0xF8, 0x08, 0x5B, 0x61, 0x1F, 0xA7, 0xBF, 0xD0, 0xE8,
|
||||
0x8B, 0xB5, 0xB1, 0xD5, 0xD9, 0x16, 0xAC, 0x75, 0x0C, 0x6D, 0xF2, 0xE0, 0xB5, 0x97, 0x75,
|
||||
0xD2, 0x68, 0x16, 0x1F, 0x00, 0x7D, 0x8B, 0x17, 0xE8, 0x78, 0x48, 0x41, 0x71, 0x2B, 0x18,
|
||||
0x96, 0x80, 0x11, 0xDB, 0x68, 0x39, 0x9C, 0xD6, 0xE0, 0x72, 0x42, 0x86, 0xF0, 0x1B, 0x16,
|
||||
0x0D, 0x3E, 0x12, 0x94, 0x3D, 0x25, 0xA8, 0xA9, 0x30, 0x9E, 0x54, 0x5A, 0xD6, 0x36, 0x6C,
|
||||
0xD6, 0x8C, 0x20, 0x62, 0x8F, 0xA1, 0x6B, 0x1F, 0x7C, 0x6D, 0xB2, 0xB1, 0xC1, 0x2E, 0xAD,
|
||||
0x36, 0x02, 0x9C, 0x3A, 0xCA, 0x2F, 0x09, 0xD2, 0x45, 0x9E, 0xEB, 0xF2, 0xBC, 0x6C, 0xAA,
|
||||
0x3B, 0x3E, 0x90, 0xBC, 0x38, 0x67, 0x35, 0x4D};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0x0B, 0x67, 0x1C, 0x0D, 0x6C, 0x57, 0xD3, 0xE7, 0x05, 0x65, 0x94, 0x31, 0x56, 0x55, 0xFD,
|
||||
0x28, 0x08, 0xFA, 0x05, 0x8A, 0xCC, 0x55, 0x39, 0x61, 0x97, 0x63, 0xA0, 0x16, 0x27, 0x3D,
|
||||
0xED, 0xC1, 0x16, 0x40, 0x2A, 0x12, 0xEA, 0x6F, 0xD9, 0xD8, 0x58, 0x56, 0xA8, 0x56, 0x8B,
|
||||
0x0D, 0x38, 0x5E, 0x1E, 0x80, 0x3B, 0x5F, 0x40, 0x80, 0x6F, 0x62, 0x4F, 0x28, 0xA2, 0x69,
|
||||
0xF3, 0xD3, 0xF7, 0xFD, 0xB2, 0xC3, 0x52, 0x43, 0x20, 0x92, 0x9D, 0x97, 0x8D, 0xA0, 0x15,
|
||||
0x07, 0x15, 0x6E, 0xA4, 0x0D, 0x56, 0xD3, 0x37, 0x1A, 0xC4, 0x9E, 0xDF, 0x02, 0x49, 0xB8,
|
||||
0x0A, 0x84, 0x62, 0xF5, 0xFA, 0xB9, 0x3F, 0xA4, 0x09, 0x76, 0xCC, 0xAA, 0xB9, 0x9B, 0xA6,
|
||||
0x4F, 0xC1, 0x6A, 0x64, 0xCE, 0xD8, 0x77, 0xAB, 0x4B, 0xF9, 0xA0, 0xAE, 0xDA, 0xF1, 0x67,
|
||||
0x87, 0x7C, 0x98, 0x5C, 0x7E, 0xB8, 0x73, 0xF5};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xC6, 0xCF, 0x71, 0xE7, 0xE5, 0x9A, 0xF0, 0xD1, 0x2A, 0x2C, 0x45, 0x8B, 0xF9, 0x2A, 0x0E,
|
||||
0xC1, 0x43, 0x05, 0x8B, 0xC3, 0x71, 0x17, 0x80, 0x1D, 0xCD, 0x49, 0x7D, 0xDE, 0x35, 0x9D,
|
||||
0x25, 0x9B, 0xA0, 0xD7, 0xA0, 0xF2, 0x7D, 0x6C, 0x08, 0x7E, 0xAA, 0x55, 0x02, 0x68, 0x2B,
|
||||
0x23, 0xC6, 0x44, 0xB8, 0x44, 0x18, 0xEB, 0x56, 0xCF, 0x16, 0xA2, 0x48, 0x03, 0xC9, 0xE7,
|
||||
0x4F, 0x87, 0xEB, 0x3D, 0x30, 0xC3, 0x15, 0x88, 0xBF, 0x20, 0xE7, 0x9D, 0xFF, 0x77, 0x0C,
|
||||
0xDE, 0x1D, 0x24, 0x1E, 0x63, 0xA9, 0x4F, 0x8A, 0xBF, 0x5B, 0xBE, 0x60, 0x19, 0x68, 0x33,
|
||||
0x3B, 0xFC, 0xED, 0x9F, 0x47, 0x4E, 0x5F, 0xF8, 0xEA, 0xCB, 0x3D, 0x00, 0xBD, 0x67, 0x01,
|
||||
0xF9, 0x2C, 0x6D, 0xC6, 0xAC, 0x13, 0x64, 0xE7, 0x67, 0x14, 0xF3, 0xDC, 0x52, 0x69, 0x6A,
|
||||
0xB9, 0x83, 0x2C, 0x42, 0x30, 0x13, 0x1B, 0xB2, 0xD8, 0xA5, 0x02, 0x0D, 0x79, 0xED, 0x96,
|
||||
0xB1, 0x0D, 0xF8, 0xCC, 0x0C, 0xDF, 0x81, 0x95, 0x4F, 0x03, 0x58, 0x09, 0x57, 0x0E, 0x80,
|
||||
0x69, 0x2E, 0xFE, 0xFF, 0x52, 0x77, 0xEA, 0x75, 0x28, 0xA8, 0xFB, 0xC9, 0xBE, 0xBF, 0x9F,
|
||||
0xBB, 0xB7, 0x79, 0x8E, 0x18, 0x05, 0xE1, 0x80, 0xBD, 0x50, 0x34, 0x94, 0x81, 0xD3, 0x53,
|
||||
0xC2, 0x69, 0xA2, 0xD2, 0x4C, 0xCF, 0x6C, 0xF4, 0x57, 0x2C, 0x10, 0x4A, 0x3F, 0xFB, 0x22,
|
||||
0xFD, 0x8B, 0x97, 0xE2, 0xC9, 0x5B, 0xA6, 0x2B, 0xCD, 0xD6, 0x1B, 0x6B, 0xDB, 0x68, 0x7F,
|
||||
0x4B, 0xC2, 0xA0, 0x50, 0x34, 0xC0, 0x05, 0xE5, 0x8D, 0xEF, 0x24, 0x67, 0xFF, 0x93, 0x40,
|
||||
0xCF, 0x2D, 0x62, 0xA2, 0xA0, 0x50, 0xB1, 0xF1, 0x3A, 0xA8, 0x3D, 0xFD, 0x80, 0xD1, 0xF9,
|
||||
0xB8, 0x05, 0x22, 0xAF, 0xC8, 0x35, 0x45, 0x90, 0x58, 0x8E, 0xE3, 0x3A, 0x7C, 0xBD, 0x3E,
|
||||
0x27};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xFE, 0xF6, 0xBF, 0x1D, 0x69, 0xAB, 0x16, 0x25, 0x08, 0x47, 0x55, 0x6B, 0x86, 0xE4, 0x35,
|
||||
0x88, 0x72, 0x2A, 0xB1, 0x3D, 0xF8, 0xB6, 0x44, 0xCA, 0xB3, 0xAB, 0x19, 0xD1, 0x04, 0x24,
|
||||
0x28, 0x0A, 0x74, 0x55, 0xB8, 0x15, 0x45, 0x09, 0xCC, 0x13, 0x1C, 0xF2, 0xBA, 0x37, 0xA9,
|
||||
0x03, 0x90, 0x8F, 0x02, 0x10, 0xFF, 0x25, 0x79, 0x86, 0xCC, 0x18, 0x50, 0x9A, 0x10, 0x5F,
|
||||
0x5B, 0x4C, 0x1C, 0x4E, 0xB0, 0xA7, 0xE3, 0x59, 0xB1, 0x2D, 0xA0, 0xC6, 0xB0, 0x20, 0x2C,
|
||||
0x21, 0x33, 0x12, 0xB3, 0xAF, 0x72, 0x34, 0x83, 0xCD, 0x52, 0x2F, 0xAF, 0x0F, 0x20, 0x5A,
|
||||
0x1B, 0xC0, 0xE2, 0xA3, 0x76, 0x34, 0x0F, 0xD7, 0xFC, 0xC1, 0x41, 0xC9, 0xF9, 0x79, 0x40,
|
||||
0x17, 0x42, 0x21, 0x3E, 0x9D, 0xFD, 0xC7, 0xC1, 0x50, 0xDE, 0x44, 0x5A, 0xC9, 0x31, 0x89,
|
||||
0x6A, 0x78, 0x05, 0xBE, 0x65, 0xB4, 0xE8, 0x2D};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xC7, 0x9E, 0x47, 0x58, 0x00, 0x7D, 0x62, 0x82, 0xB0, 0xD2, 0x22, 0x81, 0xD4, 0xA8, 0x97,
|
||||
0x1B, 0x79, 0x0C, 0x3A, 0xB0, 0xD7, 0xC9, 0x30, 0xE3, 0xC3, 0x53, 0x8E, 0x57, 0xEF, 0xF0,
|
||||
0x9B, 0x9F, 0xB3, 0x90, 0x52, 0xC6, 0x94, 0x22, 0x36, 0xAA, 0xE6, 0x4A, 0x5F, 0x72, 0x1D,
|
||||
0x70, 0xE8, 0x76, 0x58, 0xC8, 0xB2, 0x91, 0xCE, 0x9C, 0xC3, 0xE9, 0x09, 0x7F, 0x2E, 0x47,
|
||||
0x97, 0xCC, 0x90, 0x39, 0x15, 0x35, 0x31, 0xDE, 0x1F, 0x0C, 0x8C, 0x0D, 0xC1, 0xC2, 0x92,
|
||||
0xBE, 0x97, 0xBF, 0x2F, 0x91, 0xA1, 0x8C, 0x7D, 0x50, 0xA8, 0x21, 0x2F, 0xD7, 0xA2, 0x9A,
|
||||
0x7E, 0xB5, 0xA7, 0x2A, 0x90, 0x02, 0xD9, 0xF3, 0x3D, 0xD1, 0xEB, 0xB8, 0xE0, 0x5A, 0x79,
|
||||
0x9E, 0x7D, 0x8D, 0xCA, 0x18, 0x6D, 0xBD, 0x9E, 0xA1, 0x80, 0x28, 0x6B, 0x2A, 0xFE, 0x51,
|
||||
0x24, 0x9B, 0x6F, 0x4D, 0x84, 0x77, 0x80, 0x23};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x7F, 0x76, 0xCD, 0x0E, 0xE2, 0xD4, 0xDE, 0x05, 0x1C, 0xC6, 0xD9, 0xA8, 0x0E, 0x8D, 0xFA,
|
||||
0x7B, 0xCA, 0x1E, 0xAA, 0x27, 0x1A, 0x40, 0xF8, 0xF1, 0x22, 0x87, 0x35, 0xDD, 0xDB, 0xFD,
|
||||
0xEE, 0xF8, 0xC2, 0xBC, 0xBD, 0x01, 0xFB, 0x8B, 0xE2, 0x3E, 0x63, 0xB2, 0xB1, 0x22, 0x5C,
|
||||
0x56, 0x49, 0x6E, 0x11, 0xBE, 0x07, 0x44, 0x0B, 0x9A, 0x26, 0x66, 0xD1, 0x49, 0x2C, 0x8F,
|
||||
0xD3, 0x1B, 0xCF, 0xA4, 0xA1, 0xB8, 0xD1, 0xFB, 0xA4, 0x9E, 0xD2, 0x21, 0x28, 0x83, 0x09,
|
||||
0x8A, 0xF6, 0xA0, 0x0B, 0xA3, 0xD6, 0x0F, 0x9B, 0x63, 0x68, 0xCC, 0xBC, 0x0C, 0x4E, 0x14,
|
||||
0x5B, 0x27, 0xA4, 0xA9, 0xF4, 0x2B, 0xB9, 0xB8, 0x7B, 0xC0, 0xE6, 0x51, 0xAD, 0x1D, 0x77,
|
||||
0xD4, 0x6B, 0xB9, 0xCE, 0x20, 0xD1, 0x26, 0x66, 0x7E, 0x5E, 0x9E, 0xA2, 0xE9, 0x6B, 0x90,
|
||||
0xF3, 0x73, 0xB8, 0x52, 0x8F, 0x44, 0x11, 0x03, 0x0C, 0x13, 0x97, 0x39, 0x3D, 0x13, 0x22,
|
||||
0x58, 0xD5, 0x43, 0x82, 0x49, 0xDA, 0x6E, 0x7C, 0xA1, 0xC5, 0x8C, 0xA5, 0xB0, 0x09, 0xE0,
|
||||
0xCE, 0x3D, 0xDF, 0xF4, 0x9D, 0x3C, 0x97, 0x15, 0xE2, 0x6A, 0xC7, 0x2B, 0x3C, 0x50, 0x93,
|
||||
0x23, 0xDB, 0xBA, 0x4A, 0x22, 0x66, 0x44, 0xAC, 0x78, 0xBB, 0x0E, 0x1A, 0x27, 0x43, 0xB5,
|
||||
0x71, 0x67, 0xAF, 0xF4, 0xAB, 0x48, 0x46, 0x93, 0x73, 0xD0, 0x42, 0xAB, 0x93, 0x63, 0xE5,
|
||||
0x6C, 0x9A, 0xDE, 0x50, 0x24, 0xC0, 0x23, 0x7D, 0x99, 0x79, 0x3F, 0x22, 0x07, 0xE0, 0xC1,
|
||||
0x48, 0x56, 0x1B, 0xDF, 0x83, 0x09, 0x12, 0xB4, 0x2D, 0x45, 0x6B, 0xC9, 0xC0, 0x68, 0x85,
|
||||
0x99, 0x90, 0x79, 0x96, 0x1A, 0xD7, 0xF5, 0x4D, 0x1F, 0x37, 0x83, 0x40, 0x4A, 0xEC, 0x39,
|
||||
0x37, 0xA6, 0x80, 0x92, 0x7D, 0xC5, 0x80, 0xC7, 0xD6, 0x6F, 0xFE, 0x8A, 0x79, 0x89, 0xC6,
|
||||
0xB1};
|
||||
};
|
||||
|
||||
class DebugRifKeyset {
|
||||
public:
|
||||
// std::uint8_t* PrivateExponent;
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0xCD, 0x9A, 0x61, 0xB0, 0xB8, 0xD5, 0xB4, 0xE4, 0xE4, 0xF6, 0xAB, 0xF7, 0x27, 0xB7, 0x56,
|
||||
0x59, 0x6B, 0xB9, 0x11, 0xE7, 0xF4, 0x83, 0xAF, 0xB9, 0x73, 0x99, 0x7F, 0x49, 0xA2, 0x9C,
|
||||
0xF0, 0xB5, 0x6D, 0x37, 0x82, 0x14, 0x15, 0xF1, 0x04, 0x8A, 0xD4, 0x8E, 0xEB, 0x2E, 0x1F,
|
||||
0xE2, 0x81, 0xA9, 0x62, 0x6E, 0xB1, 0x68, 0x75, 0x62, 0xF3, 0x0F, 0xFE, 0xD4, 0x91, 0x87,
|
||||
0x98, 0x78, 0xBF, 0x26, 0xB5, 0x07, 0x58, 0xD0, 0xEE, 0x3F, 0x21, 0xE8, 0xC8, 0x0F, 0x5F,
|
||||
0xFA, 0x1C, 0x64, 0x74, 0x49, 0x52, 0xEB, 0xE7, 0xEE, 0xDE, 0xBA, 0x23, 0x26, 0x4A, 0xF6,
|
||||
0x9C, 0x1A, 0x09, 0x3F, 0xB9, 0x0B, 0x36, 0x26, 0x1A, 0xBE, 0xA9, 0x76, 0xE6, 0xF2, 0x69,
|
||||
0xDE, 0xFF, 0xAF, 0xCC, 0x0C, 0x9A, 0x66, 0x03, 0x86, 0x0A, 0x1F, 0x49, 0xA4, 0x10, 0xB6,
|
||||
0xBC, 0xC3, 0x7C, 0x88, 0xE8, 0xCE, 0x4B, 0xD9};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0xB3, 0x73, 0xA3, 0x59, 0xE6, 0x97, 0xC0, 0xAB, 0x3B, 0x68, 0xFC, 0x39, 0xAC, 0xDB, 0x44,
|
||||
0xB1, 0xB4, 0x9E, 0x35, 0x4D, 0xBE, 0xC5, 0x36, 0x69, 0x6C, 0x3D, 0xC5, 0xFC, 0xFE, 0x4B,
|
||||
0x2F, 0xDC, 0x86, 0x80, 0x46, 0x96, 0x40, 0x1A, 0x0D, 0x6E, 0xFA, 0x8C, 0xE0, 0x47, 0x91,
|
||||
0xAC, 0xAD, 0x95, 0x2B, 0x8E, 0x1F, 0xF2, 0x0A, 0x45, 0xF8, 0x29, 0x95, 0x70, 0xC6, 0x88,
|
||||
0x5F, 0x71, 0x03, 0x99, 0x79, 0xBC, 0x84, 0x71, 0xBD, 0xE8, 0x84, 0x8C, 0x0E, 0xD4, 0x7B,
|
||||
0x30, 0x74, 0x57, 0x1A, 0x95, 0xE7, 0x90, 0x19, 0x8D, 0xAD, 0x8B, 0x4C, 0x4E, 0xC3, 0xE7,
|
||||
0x6B, 0x23, 0x86, 0x01, 0xEE, 0x9B, 0xE0, 0x2F, 0x15, 0xA2, 0x2C, 0x4C, 0x39, 0xD3, 0xDF,
|
||||
0x9C, 0x39, 0x01, 0xF1, 0x8C, 0x44, 0x4A, 0x15, 0x44, 0xDC, 0x51, 0xF7, 0x22, 0xD7, 0x7F,
|
||||
0x41, 0x7F, 0x68, 0xFA, 0xEE, 0x56, 0xE8, 0x05};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0x00, 0x01, 0x00, 0x01};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0xC0, 0x32, 0x43, 0xD3, 0x8C, 0x3D, 0xB4, 0xD2, 0x48, 0x8C, 0x42, 0x41, 0x24, 0x94, 0x6C,
|
||||
0x80, 0xC9, 0xC1, 0x79, 0x36, 0x7F, 0xAC, 0xC3, 0xFF, 0x6A, 0x25, 0xEB, 0x2C, 0xFB, 0xD4,
|
||||
0x2B, 0xA0, 0xEB, 0xFE, 0x25, 0xE9, 0xC6, 0x77, 0xCE, 0xFE, 0x2D, 0x23, 0xFE, 0xD0, 0xF4,
|
||||
0x0F, 0xD9, 0x7E, 0xD5, 0xA5, 0x7D, 0x1F, 0xC0, 0xE8, 0xE8, 0xEC, 0x80, 0x5B, 0xC7, 0xFD,
|
||||
0xE2, 0xBD, 0x94, 0xA6, 0x2B, 0xDD, 0x6A, 0x60, 0x45, 0x54, 0xAB, 0xCA, 0x42, 0x9C, 0x6A,
|
||||
0x6C, 0xBF, 0x3C, 0x84, 0xF9, 0xA5, 0x0E, 0x63, 0x0C, 0x51, 0x58, 0x62, 0x6D, 0x5A, 0xB7,
|
||||
0x3C, 0x3F, 0x49, 0x1A, 0xD0, 0x93, 0xB8, 0x4F, 0x1A, 0x6C, 0x5F, 0xC5, 0xE5, 0xA9, 0x75,
|
||||
0xD4, 0x86, 0x9E, 0xDF, 0x87, 0x0F, 0x27, 0xB0, 0x26, 0x78, 0x4E, 0xFB, 0xC1, 0x8A, 0x4A,
|
||||
0x24, 0x3F, 0x7F, 0x8F, 0x9A, 0x12, 0x51, 0xCB};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xC2, 0xD2, 0x44, 0xBC, 0xDD, 0x84, 0x3F, 0xD9, 0xC5, 0x22, 0xAF, 0xF7, 0xFC, 0x88, 0x8A,
|
||||
0x33, 0x80, 0xED, 0x8E, 0xE2, 0xCC, 0x81, 0xF7, 0xEC, 0xF8, 0x1C, 0x79, 0xBF, 0x02, 0xBB,
|
||||
0x12, 0x8E, 0x61, 0x68, 0x29, 0x1B, 0x15, 0xB6, 0x5E, 0xC6, 0xF8, 0xBF, 0x5A, 0xE0, 0x3B,
|
||||
0x6A, 0x6C, 0xD9, 0xD6, 0xF5, 0x75, 0xAB, 0xA0, 0x6F, 0x34, 0x81, 0x34, 0x9A, 0x5B, 0xAD,
|
||||
0xED, 0x31, 0xE3, 0xC6, 0xEA, 0x1A, 0xD1, 0x13, 0x22, 0xBB, 0xB3, 0xDA, 0xB3, 0xB2, 0x53,
|
||||
0xBD, 0x45, 0x79, 0x87, 0xAD, 0x0A, 0x01, 0x72, 0x18, 0x10, 0x29, 0x49, 0xF4, 0x41, 0x7F,
|
||||
0xD6, 0x47, 0x0C, 0x72, 0x92, 0x9E, 0xE9, 0xBB, 0x95, 0xA9, 0x5D, 0x79, 0xEB, 0xE4, 0x30,
|
||||
0x76, 0x90, 0x45, 0x4B, 0x9D, 0x9C, 0xCF, 0x92, 0x03, 0x60, 0x8C, 0x4B, 0x6C, 0xB3, 0x7A,
|
||||
0x3A, 0x05, 0x39, 0xA0, 0x66, 0xA9, 0x35, 0xCF, 0xB9, 0xFA, 0xAD, 0x9C, 0xAB, 0xEB, 0xE4,
|
||||
0x6A, 0x8C, 0xE9, 0x3B, 0xCC, 0x72, 0x12, 0x62, 0x63, 0xBD, 0x80, 0xC4, 0xEE, 0x37, 0x2B,
|
||||
0x32, 0x03, 0xA3, 0x09, 0xF7, 0xA0, 0x61, 0x57, 0xAD, 0x0D, 0xCF, 0x15, 0x98, 0x9E, 0x4E,
|
||||
0x49, 0xF8, 0xB5, 0xA3, 0x5C, 0x27, 0xEE, 0x45, 0x04, 0xEA, 0xE4, 0x4B, 0xBC, 0x8F, 0x87,
|
||||
0xED, 0x19, 0x1E, 0x46, 0x75, 0x63, 0xC4, 0x5B, 0xD5, 0xBC, 0x09, 0x2F, 0x02, 0x73, 0x19,
|
||||
0x3C, 0x58, 0x55, 0x49, 0x66, 0x4C, 0x11, 0xEC, 0x0F, 0x09, 0xFA, 0xA5, 0x56, 0x0A, 0x5A,
|
||||
0x63, 0x56, 0xAD, 0xA0, 0x0D, 0x86, 0x08, 0xC1, 0xE6, 0xB6, 0x13, 0x22, 0x49, 0x2F, 0x7C,
|
||||
0xDB, 0x4C, 0x56, 0x97, 0x0E, 0xC2, 0xD9, 0x2E, 0x87, 0xBC, 0x0E, 0x67, 0xC0, 0x1B, 0x58,
|
||||
0xBC, 0x64, 0x2B, 0xC2, 0x6E, 0xE2, 0x93, 0x2E, 0xB5, 0x6B, 0x70, 0xA4, 0x42, 0x9F, 0x64,
|
||||
0xC1};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xE5, 0x62, 0xE1, 0x7F, 0x9F, 0x86, 0x08, 0xE2, 0x61, 0xD3, 0xD0, 0x42, 0xE2, 0xC4, 0xB6,
|
||||
0xA8, 0x51, 0x09, 0x19, 0x14, 0xA4, 0x3A, 0x11, 0x4C, 0x33, 0xA5, 0x9C, 0x01, 0x5E, 0x34,
|
||||
0xB6, 0x3F, 0x02, 0x1A, 0xCA, 0x47, 0xF1, 0x4F, 0x3B, 0x35, 0x2A, 0x07, 0x20, 0xEC, 0xD8,
|
||||
0xC1, 0x15, 0xD9, 0xCA, 0x03, 0x4F, 0xB8, 0xE8, 0x09, 0x73, 0x3F, 0x85, 0xB7, 0x41, 0xD5,
|
||||
0x51, 0x3E, 0x7B, 0xE3, 0x53, 0x2B, 0x48, 0x8B, 0x8E, 0xCB, 0xBA, 0xF7, 0xE0, 0x60, 0xF5,
|
||||
0x35, 0x0E, 0x6F, 0xB0, 0xD9, 0x2A, 0x99, 0xD0, 0xFF, 0x60, 0x14, 0xED, 0x40, 0xEA, 0xF8,
|
||||
0xD7, 0x0B, 0xC3, 0x8D, 0x8C, 0xE8, 0x81, 0xB3, 0x75, 0x93, 0x15, 0xB3, 0x7D, 0xF6, 0x39,
|
||||
0x60, 0x1A, 0x00, 0xE7, 0xC3, 0x27, 0xAD, 0xA4, 0x33, 0xD5, 0x3E, 0xA4, 0x35, 0x48, 0x6F,
|
||||
0x22, 0xEF, 0x5D, 0xDD, 0x7D, 0x7B, 0x61, 0x05};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xD9, 0x6C, 0xC2, 0x0C, 0xF7, 0xAE, 0xD1, 0xF3, 0x3B, 0x3B, 0x49, 0x1E, 0x9F, 0x12, 0x9C,
|
||||
0xA1, 0x78, 0x1F, 0x35, 0x1D, 0x98, 0x26, 0x13, 0x71, 0xF9, 0x09, 0xFD, 0xF0, 0xAD, 0x38,
|
||||
0x55, 0xB7, 0xEE, 0x61, 0x04, 0x72, 0x51, 0x87, 0x2E, 0x05, 0x84, 0xB1, 0x1D, 0x0C, 0x0D,
|
||||
0xDB, 0xD4, 0x25, 0x3E, 0x26, 0xED, 0xEA, 0xB8, 0xF7, 0x49, 0xFE, 0xA2, 0x94, 0xE6, 0xF2,
|
||||
0x08, 0x92, 0xA7, 0x85, 0xF5, 0x30, 0xB9, 0x84, 0x22, 0xBF, 0xCA, 0xF0, 0x5F, 0xCB, 0x31,
|
||||
0x20, 0x34, 0x49, 0x16, 0x76, 0x34, 0xCC, 0x7A, 0xCB, 0x96, 0xFE, 0x78, 0x7A, 0x41, 0xFE,
|
||||
0x9A, 0xA2, 0x23, 0xF7, 0x68, 0x80, 0xD6, 0xCE, 0x4A, 0x78, 0xA5, 0xB7, 0x05, 0x77, 0x81,
|
||||
0x1F, 0xDE, 0x5E, 0xA8, 0x6E, 0x3E, 0x87, 0xEC, 0x44, 0xD2, 0x69, 0xC6, 0x54, 0x91, 0x6B,
|
||||
0x5E, 0x13, 0x8A, 0x03, 0x87, 0x05, 0x31, 0x8D};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x01, 0x61, 0xAD, 0xD8, 0x9C, 0x06, 0x89, 0xD0, 0x60, 0xC8, 0x41, 0xF0, 0xB3, 0x83, 0x01,
|
||||
0x5D, 0xE3, 0xA2, 0x6B, 0xA2, 0xBA, 0x9A, 0x0A, 0x58, 0xCD, 0x1A, 0xA0, 0x97, 0x64, 0xEC,
|
||||
0xD0, 0x31, 0x1F, 0xCA, 0x36, 0x0E, 0x69, 0xDD, 0x40, 0xF7, 0x4E, 0xC0, 0xC6, 0xA3, 0x73,
|
||||
0xF0, 0x69, 0x84, 0xB2, 0xF4, 0x4B, 0x29, 0x14, 0x2A, 0x6D, 0xB8, 0x23, 0xD8, 0x1B, 0x61,
|
||||
0xD4, 0x9E, 0x87, 0xB3, 0xBB, 0xA9, 0xC4, 0x85, 0x4A, 0xF8, 0x03, 0x4A, 0xBF, 0xFE, 0xF9,
|
||||
0xFE, 0x8B, 0xDD, 0x54, 0x83, 0xBA, 0xE0, 0x2F, 0x3F, 0xB1, 0xEF, 0xA5, 0x05, 0x5D, 0x28,
|
||||
0x8B, 0xAB, 0xB5, 0xD0, 0x23, 0x2F, 0x8A, 0xCF, 0x48, 0x7C, 0xAA, 0xBB, 0xC8, 0x5B, 0x36,
|
||||
0x27, 0xC5, 0x16, 0xA4, 0xB6, 0x61, 0xAC, 0x0C, 0x28, 0x47, 0x79, 0x3F, 0x38, 0xAE, 0x5E,
|
||||
0x25, 0xC6, 0xAF, 0x35, 0xAE, 0xBC, 0xB0, 0xF3, 0xBC, 0xBD, 0xFD, 0xA4, 0x87, 0x0D, 0x14,
|
||||
0x3D, 0x90, 0xE4, 0xDE, 0x5D, 0x1D, 0x46, 0x81, 0xF1, 0x28, 0x6D, 0x2F, 0x2C, 0x5E, 0x97,
|
||||
0x2D, 0x89, 0x2A, 0x51, 0x72, 0x3C, 0x20, 0x02, 0x59, 0xB1, 0x98, 0x93, 0x05, 0x1E, 0x3F,
|
||||
0xA1, 0x8A, 0x69, 0x30, 0x0E, 0x70, 0x84, 0x8B, 0xAE, 0x97, 0xA1, 0x08, 0x95, 0x63, 0x4C,
|
||||
0xC7, 0xE8, 0x5D, 0x59, 0xCA, 0x78, 0x2A, 0x23, 0x87, 0xAC, 0x6F, 0x04, 0x33, 0xB1, 0x61,
|
||||
0xB9, 0xF0, 0x95, 0xDA, 0x33, 0xCC, 0xE0, 0x4C, 0x82, 0x68, 0x82, 0x14, 0x51, 0xBE, 0x49,
|
||||
0x1C, 0x58, 0xA2, 0x8B, 0x05, 0x4E, 0x98, 0x37, 0xEB, 0x94, 0x0B, 0x01, 0x22, 0xDC, 0xB3,
|
||||
0x19, 0xCA, 0x77, 0xA6, 0x6E, 0x97, 0xFF, 0x8A, 0x53, 0x5A, 0xC5, 0x24, 0xE4, 0xAF, 0x6E,
|
||||
0xA8, 0x2B, 0x53, 0xA4, 0xBE, 0x96, 0xA5, 0x7B, 0xCE, 0x22, 0x56, 0xA3, 0xF1, 0xCF, 0x14,
|
||||
0xA5};
|
||||
};
|
||||
|
||||
class PkgDerivedKey3Keyset {
|
||||
public:
|
||||
// std::uint8_t* PrivateExponent;
|
||||
static constexpr CryptoPP::byte Exponent1[] = {
|
||||
0x52, 0xCC, 0x2D, 0xA0, 0x9C, 0x9E, 0x75, 0xE7, 0x28, 0xEE, 0x3D, 0xDE, 0xE3, 0x45, 0xD1,
|
||||
0x4F, 0x94, 0x1C, 0xCC, 0xC8, 0x87, 0x29, 0x45, 0x3B, 0x8D, 0x6E, 0xAB, 0x6E, 0x2A, 0xA7,
|
||||
0xC7, 0x15, 0x43, 0xA3, 0x04, 0x8F, 0x90, 0x5F, 0xEB, 0xF3, 0x38, 0x4A, 0x77, 0xFA, 0x36,
|
||||
0xB7, 0x15, 0x76, 0xB6, 0x01, 0x1A, 0x8E, 0x25, 0x87, 0x82, 0xF1, 0x55, 0xD8, 0xC6, 0x43,
|
||||
0x2A, 0xC0, 0xE5, 0x98, 0xC9, 0x32, 0xD1, 0x94, 0x6F, 0xD9, 0x01, 0xBA, 0x06, 0x81, 0xE0,
|
||||
0x6D, 0x88, 0xF2, 0x24, 0x2A, 0x25, 0x01, 0x64, 0x5C, 0xBF, 0xF2, 0xD9, 0x99, 0x67, 0x3E,
|
||||
0xF6, 0x72, 0xEE, 0xE4, 0xE2, 0x33, 0x5C, 0xF8, 0x00, 0x40, 0xE3, 0x2A, 0x9A, 0xF4, 0x3D,
|
||||
0x22, 0x86, 0x44, 0x3C, 0xFB, 0x0A, 0xA5, 0x7C, 0x3F, 0xCC, 0xF5, 0xF1, 0x16, 0xC4, 0xAC,
|
||||
0x88, 0xB4, 0xDE, 0x62, 0x94, 0x92, 0x6A, 0x13};
|
||||
// exponent2 = d mod (q - 1)
|
||||
static constexpr CryptoPP::byte Exponent2[] = {
|
||||
0x7C, 0x9D, 0xAD, 0x39, 0xE0, 0xD5, 0x60, 0x14, 0x94, 0x48, 0x19, 0x7F, 0x88, 0x95, 0xD5,
|
||||
0x8B, 0x80, 0xAD, 0x85, 0x8A, 0x4B, 0x77, 0x37, 0x85, 0xD0, 0x77, 0xBB, 0xBF, 0x89, 0x71,
|
||||
0x4A, 0x72, 0xCB, 0x72, 0x68, 0x38, 0xEC, 0x02, 0xC6, 0x7D, 0xC6, 0x44, 0x06, 0x33, 0x51,
|
||||
0x1C, 0xC0, 0xFF, 0x95, 0x8F, 0x0D, 0x75, 0xDC, 0x25, 0xBB, 0x0B, 0x73, 0x91, 0xA9, 0x6D,
|
||||
0x42, 0xD8, 0x03, 0xB7, 0x68, 0xD4, 0x1E, 0x75, 0x62, 0xA3, 0x70, 0x35, 0x79, 0x78, 0x00,
|
||||
0xC8, 0xF5, 0xEF, 0x15, 0xB9, 0xFC, 0x4E, 0x47, 0x5A, 0xC8, 0x70, 0x70, 0x5B, 0x52, 0x98,
|
||||
0xC0, 0xC2, 0x58, 0x4A, 0x70, 0x96, 0xCC, 0xB8, 0x10, 0xE1, 0x2F, 0x78, 0x8B, 0x2B, 0xA1,
|
||||
0x7F, 0xF9, 0xAC, 0xDE, 0xF0, 0xBB, 0x2B, 0xE2, 0x66, 0xE3, 0x22, 0x92, 0x31, 0x21, 0x57,
|
||||
0x92, 0xC4, 0xB8, 0xF2, 0x3E, 0x76, 0x20, 0x37};
|
||||
// e
|
||||
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
|
||||
// (InverseQ)(q) = 1 mod p
|
||||
static constexpr CryptoPP::byte Coefficient[] = {
|
||||
0x45, 0x97, 0x55, 0xD4, 0x22, 0x08, 0x5E, 0xF3, 0x5C, 0xB4, 0x05, 0x7A, 0xFD, 0xAA, 0x42,
|
||||
0x42, 0xAD, 0x9A, 0x8C, 0xA0, 0x6C, 0xBB, 0x1D, 0x68, 0x54, 0x54, 0x6E, 0x3E, 0x32, 0xE3,
|
||||
0x53, 0x73, 0x76, 0xF1, 0x3E, 0x01, 0xEA, 0xD3, 0xCF, 0xEB, 0xEB, 0x23, 0x3E, 0xC0, 0xBE,
|
||||
0xCE, 0xEC, 0x2C, 0x89, 0x5F, 0xA8, 0x27, 0x3A, 0x4C, 0xB7, 0xE6, 0x74, 0xBC, 0x45, 0x4C,
|
||||
0x26, 0xC8, 0x25, 0xFF, 0x34, 0x63, 0x25, 0x37, 0xE1, 0x48, 0x10, 0xC1, 0x93, 0xA6, 0xAF,
|
||||
0xEB, 0xBA, 0xE3, 0xA2, 0xF1, 0x3D, 0xEF, 0x63, 0xD8, 0xF4, 0xFD, 0xD3, 0xEE, 0xE2, 0x5D,
|
||||
0xE9, 0x33, 0xCC, 0xAD, 0xBA, 0x75, 0x5C, 0x85, 0xAF, 0xCE, 0xA9, 0x3D, 0xD1, 0xA2, 0x17,
|
||||
0xF3, 0xF6, 0x98, 0xB3, 0x50, 0x8E, 0x5E, 0xF6, 0xEB, 0x02, 0x8E, 0xA1, 0x62, 0xA7, 0xD6,
|
||||
0x2C, 0xEC, 0x91, 0xFF, 0x15, 0x40, 0xD2, 0xE3};
|
||||
// n = p * q
|
||||
static constexpr CryptoPP::byte Modulus[] = {
|
||||
0xd2, 0x12, 0xfc, 0x33, 0x5f, 0x6d, 0xdb, 0x83, 0x16, 0x09, 0x62, 0x8b, 0x03, 0x56, 0x27,
|
||||
0x37, 0x82, 0xd4, 0x77, 0x85, 0x35, 0x29, 0x39, 0x2d, 0x52, 0x6b, 0x8c, 0x4c, 0x8c, 0xfb,
|
||||
0x06, 0xc1, 0x84, 0x5b, 0xe7, 0xd4, 0xf7, 0xbc, 0xd2, 0x4e, 0x62, 0x45, 0xcd, 0x2a, 0xbb,
|
||||
0xd7, 0x77, 0x76, 0x45, 0x36, 0x55, 0x27, 0x3f, 0xb3, 0xf5, 0xf9, 0x8e, 0xda, 0x4b, 0xef,
|
||||
0xaa, 0x59, 0xae, 0xb3, 0x9b, 0xea, 0x54, 0x98, 0xd2, 0x06, 0x32, 0x6a, 0x58, 0x31, 0x2a,
|
||||
0xe0, 0xd4, 0x4f, 0x90, 0xb5, 0x0a, 0x7d, 0xec, 0xf4, 0x3a, 0x9c, 0x52, 0x67, 0x2d, 0x99,
|
||||
0x31, 0x8e, 0x0c, 0x43, 0xe6, 0x82, 0xfe, 0x07, 0x46, 0xe1, 0x2e, 0x50, 0xd4, 0x1f, 0x2d,
|
||||
0x2f, 0x7e, 0xd9, 0x08, 0xba, 0x06, 0xb3, 0xbf, 0x2e, 0x20, 0x3f, 0x4e, 0x3f, 0xfe, 0x44,
|
||||
0xff, 0xaa, 0x50, 0x43, 0x57, 0x91, 0x69, 0x94, 0x49, 0x15, 0x82, 0x82, 0xe4, 0x0f, 0x4c,
|
||||
0x8d, 0x9d, 0x2c, 0xc9, 0x5b, 0x1d, 0x64, 0xbf, 0x88, 0x8b, 0xd4, 0xc5, 0x94, 0xe7, 0x65,
|
||||
0x47, 0x84, 0x1e, 0xe5, 0x79, 0x10, 0xfb, 0x98, 0x93, 0x47, 0xb9, 0x7d, 0x85, 0x12, 0xa6,
|
||||
0x40, 0x98, 0x2c, 0xf7, 0x92, 0xbc, 0x95, 0x19, 0x32, 0xed, 0xe8, 0x90, 0x56, 0x0d, 0x65,
|
||||
0xc1, 0xaa, 0x78, 0xc6, 0x2e, 0x54, 0xfd, 0x5f, 0x54, 0xa1, 0xf6, 0x7e, 0xe5, 0xe0, 0x5f,
|
||||
0x61, 0xc1, 0x20, 0xb4, 0xb9, 0xb4, 0x33, 0x08, 0x70, 0xe4, 0xdf, 0x89, 0x56, 0xed, 0x01,
|
||||
0x29, 0x46, 0x77, 0x5f, 0x8c, 0xb8, 0xa9, 0xf5, 0x1e, 0x2e, 0xb3, 0xb9, 0xbf, 0xe0, 0x09,
|
||||
0xb7, 0x8d, 0x28, 0xd4, 0xa6, 0xc3, 0xb8, 0x1e, 0x1f, 0x07, 0xeb, 0xb4, 0x12, 0x0b, 0x95,
|
||||
0xb8, 0x85, 0x30, 0xfd, 0xdc, 0x39, 0x13, 0xd0, 0x7c, 0xdc, 0x8f, 0xed, 0xf9, 0xc9, 0xa3,
|
||||
0xc1};
|
||||
// p
|
||||
static constexpr CryptoPP::byte Prime1[] = {
|
||||
0xF9, 0x67, 0xAD, 0x99, 0x12, 0x31, 0x0C, 0x56, 0xA2, 0x2E, 0x16, 0x1C, 0x46, 0xB3, 0x4D,
|
||||
0x5B, 0x43, 0xBE, 0x42, 0xA2, 0xF6, 0x86, 0x96, 0x80, 0x42, 0xC3, 0xC7, 0x3F, 0xC3, 0x42,
|
||||
0xF5, 0x87, 0x49, 0x33, 0x9F, 0x07, 0x5D, 0x6E, 0x2C, 0x04, 0xFD, 0xE3, 0xE1, 0xB2, 0xAE,
|
||||
0x0A, 0x0C, 0xF0, 0xC7, 0xA6, 0x1C, 0xA1, 0x63, 0x50, 0xC8, 0x09, 0x9C, 0x51, 0x24, 0x52,
|
||||
0x6C, 0x5E, 0x5E, 0xBD, 0x1E, 0x27, 0x06, 0xBB, 0xBC, 0x9E, 0x94, 0xE1, 0x35, 0xD4, 0x6D,
|
||||
0xB3, 0xCB, 0x3C, 0x68, 0xDD, 0x68, 0xB3, 0xFE, 0x6C, 0xCB, 0x8D, 0x82, 0x20, 0x76, 0x23,
|
||||
0x63, 0xB7, 0xE9, 0x68, 0x10, 0x01, 0x4E, 0xDC, 0xBA, 0x27, 0x5D, 0x01, 0xC1, 0x2D, 0x80,
|
||||
0x5E, 0x2B, 0xAF, 0x82, 0x6B, 0xD8, 0x84, 0xB6, 0x10, 0x52, 0x86, 0xA7, 0x89, 0x8E, 0xAE,
|
||||
0x9A, 0xE2, 0x89, 0xC6, 0xF7, 0xD5, 0x87, 0xFB};
|
||||
// q
|
||||
static constexpr CryptoPP::byte Prime2[] = {
|
||||
0xD7, 0xA1, 0x0F, 0x9A, 0x8B, 0xF2, 0xC9, 0x11, 0x95, 0x32, 0x9A, 0x8C, 0xF0, 0xD9, 0x40,
|
||||
0x47, 0xF5, 0x68, 0xA0, 0x0D, 0xBD, 0xC1, 0xFC, 0x43, 0x2F, 0x65, 0xF9, 0xC3, 0x61, 0x0F,
|
||||
0x25, 0x77, 0x54, 0xAD, 0xD7, 0x58, 0xAC, 0x84, 0x40, 0x60, 0x8D, 0x3F, 0xF3, 0x65, 0x89,
|
||||
0x75, 0xB5, 0xC6, 0x2C, 0x51, 0x1A, 0x2F, 0x1F, 0x22, 0xE4, 0x43, 0x11, 0x54, 0xBE, 0xC9,
|
||||
0xB4, 0xC7, 0xB5, 0x1B, 0x05, 0x0B, 0xBC, 0x56, 0x9A, 0xCD, 0x4A, 0xD9, 0x73, 0x68, 0x5E,
|
||||
0x5C, 0xFB, 0x92, 0xB7, 0x8B, 0x0D, 0xFF, 0xF5, 0x07, 0xCA, 0xB4, 0xC8, 0x9B, 0x96, 0x3C,
|
||||
0x07, 0x9E, 0x3E, 0x6B, 0x2A, 0x11, 0xF2, 0x8A, 0xB1, 0x8A, 0xD7, 0x2E, 0x1B, 0xA5, 0x53,
|
||||
0x24, 0x06, 0xED, 0x50, 0xB8, 0x90, 0x67, 0xB1, 0xE2, 0x41, 0xC6, 0x92, 0x01, 0xEE, 0x10,
|
||||
0xF0, 0x61, 0xBB, 0xFB, 0xB2, 0x7D, 0x4A, 0x73};
|
||||
static constexpr CryptoPP::byte PrivateExponent[] = {
|
||||
0x32, 0xD9, 0x03, 0x90, 0x8F, 0xBD, 0xB0, 0x8F, 0x57, 0x2B, 0x28, 0x5E, 0x0B, 0x8D, 0xB3,
|
||||
0xEA, 0x5C, 0xD1, 0x7E, 0xA8, 0x90, 0x88, 0x8C, 0xDD, 0x6A, 0x80, 0xBB, 0xB1, 0xDF, 0xC1,
|
||||
0xF7, 0x0D, 0xAA, 0x32, 0xF0, 0xB7, 0x7C, 0xCB, 0x88, 0x80, 0x0E, 0x8B, 0x64, 0xB0, 0xBE,
|
||||
0x4C, 0xD6, 0x0E, 0x9B, 0x8C, 0x1E, 0x2A, 0x64, 0xE1, 0xF3, 0x5C, 0xD7, 0x76, 0x01, 0x41,
|
||||
0x5E, 0x93, 0x5C, 0x94, 0xFE, 0xDD, 0x46, 0x62, 0xC3, 0x1B, 0x5A, 0xE2, 0xA0, 0xBC, 0x2D,
|
||||
0xEB, 0xC3, 0x98, 0x0A, 0xA7, 0xB7, 0x85, 0x69, 0x70, 0x68, 0x2B, 0x64, 0x4A, 0xB3, 0x1F,
|
||||
0xCC, 0x7D, 0xDC, 0x7C, 0x26, 0xF4, 0x77, 0xF6, 0x5C, 0xF2, 0xAE, 0x5A, 0x44, 0x2D, 0xD3,
|
||||
0xAB, 0x16, 0x62, 0x04, 0x19, 0xBA, 0xFB, 0x90, 0xFF, 0xE2, 0x30, 0x50, 0x89, 0x6E, 0xCB,
|
||||
0x56, 0xB2, 0xEB, 0xC0, 0x91, 0x16, 0x92, 0x5E, 0x30, 0x8E, 0xAE, 0xC7, 0x94, 0x5D, 0xFD,
|
||||
0x35, 0xE1, 0x20, 0xF8, 0xAD, 0x3E, 0xBC, 0x08, 0xBF, 0xC0, 0x36, 0x74, 0x9F, 0xD5, 0xBB,
|
||||
0x52, 0x08, 0xFD, 0x06, 0x66, 0xF3, 0x7A, 0xB3, 0x04, 0xF4, 0x75, 0x29, 0x5D, 0xE9, 0x5F,
|
||||
0xAA, 0x10, 0x30, 0xB2, 0x0F, 0x5A, 0x1A, 0xC1, 0x2A, 0xB3, 0xFE, 0xCB, 0x21, 0xAD, 0x80,
|
||||
0xEC, 0x8F, 0x20, 0x09, 0x1C, 0xDB, 0xC5, 0x58, 0x94, 0xC2, 0x9C, 0xC6, 0xCE, 0x82, 0x65,
|
||||
0x3E, 0x57, 0x90, 0xBC, 0xA9, 0x8B, 0x06, 0xB4, 0xF0, 0x72, 0xF6, 0x77, 0xDF, 0x98, 0x64,
|
||||
0xF1, 0xEC, 0xFE, 0x37, 0x2D, 0xBC, 0xAE, 0x8C, 0x08, 0x81, 0x1F, 0xC3, 0xC9, 0x89, 0x1A,
|
||||
0xC7, 0x42, 0x82, 0x4B, 0x2E, 0xDC, 0x8E, 0x8D, 0x73, 0xCE, 0xB1, 0xCC, 0x01, 0xD9, 0x08,
|
||||
0x70, 0x87, 0x3C, 0x44, 0x08, 0xEC, 0x49, 0x8F, 0x81, 0x5A, 0xE2, 0x40, 0xFF, 0x77, 0xFC,
|
||||
0x0D};
|
||||
};
|
|
@ -158,6 +158,10 @@ public:
|
|||
float Framerate = 1.0f / 60.0f;
|
||||
float FrameDeltaTime;
|
||||
|
||||
std::pair<u32, u32> game_resolution{};
|
||||
std::pair<u32, u32> output_resolution{};
|
||||
bool is_using_fsr{};
|
||||
|
||||
void ShowDebugMessage(std::string message) {
|
||||
if (message.empty()) {
|
||||
return;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "SDL3/SDL_log.h"
|
||||
#include "common/config.h"
|
||||
#include "common/singleton.h"
|
||||
#include "common/types.h"
|
||||
|
@ -21,8 +22,8 @@
|
|||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||
|
||||
using namespace ImGui;
|
||||
using namespace Core::Devtools;
|
||||
using L = Core::Devtools::Layer;
|
||||
using namespace ::Core::Devtools;
|
||||
using L = ::Core::Devtools::Layer;
|
||||
|
||||
static bool show_simple_fps = false;
|
||||
static bool visibility_toggled = false;
|
||||
|
@ -81,8 +82,24 @@ void L::DrawMenuBar() {
|
|||
ImGui::EndMenu();
|
||||
}
|
||||
if (BeginMenu("Display")) {
|
||||
auto& pp_settings = presenter->GetPPSettingsRef();
|
||||
if (BeginMenu("Brightness")) {
|
||||
SliderFloat("Gamma", &presenter->GetGammaRef(), 0.1f, 2.0f);
|
||||
SliderFloat("Gamma", &pp_settings.gamma, 0.1f, 2.0f);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (BeginMenu("FSR")) {
|
||||
auto& fsr = presenter->GetFsrSettingsRef();
|
||||
Checkbox("FSR Enabled", &fsr.enable);
|
||||
BeginDisabled(!fsr.enable);
|
||||
{
|
||||
Checkbox("RCAS", &fsr.use_rcas);
|
||||
BeginDisabled(!fsr.use_rcas);
|
||||
{
|
||||
SliderFloat("RCAS Attenuation", &fsr.rcas_attenuation, 0.0, 3.0);
|
||||
}
|
||||
EndDisabled();
|
||||
}
|
||||
EndDisabled();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
|
@ -101,22 +118,6 @@ void L::DrawMenuBar() {
|
|||
|
||||
EndMainMenuBar();
|
||||
}
|
||||
|
||||
if (IsKeyPressed(ImGuiKey_F9, false)) {
|
||||
if (io.KeyCtrl && io.KeyAlt) {
|
||||
if (!DebugState.ShouldPauseInSubmit()) {
|
||||
DebugState.RequestFrameDump(dump_frame_count);
|
||||
}
|
||||
}
|
||||
if (!io.KeyCtrl && !io.KeyAlt) {
|
||||
if (isSystemPaused) {
|
||||
DebugState.ResumeGuestThreads();
|
||||
} else {
|
||||
DebugState.PauseGuestThreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (open_popup_options) {
|
||||
OpenPopup("GPU Tools Options");
|
||||
just_opened_options = true;
|
||||
|
@ -259,7 +260,19 @@ void L::DrawAdvanced() {
|
|||
|
||||
void L::DrawSimple() {
|
||||
const float frameRate = DebugState.Framerate;
|
||||
if (Config::fpsColor()) {
|
||||
if (frameRate < 10) {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f)); // Red
|
||||
} else if (frameRate >= 10 && frameRate < 20) {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.5f, 0.0f, 1.0f)); // Orange
|
||||
} else {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); // White
|
||||
}
|
||||
} else {
|
||||
PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)); // White
|
||||
}
|
||||
Text("%d FPS (%.1f ms)", static_cast<int>(std::round(frameRate)), 1000.0f / frameRate);
|
||||
PopStyleColor();
|
||||
}
|
||||
|
||||
static void LoadSettings(const char* line) {
|
||||
|
@ -353,6 +366,32 @@ void L::Draw() {
|
|||
visibility_toggled = true;
|
||||
}
|
||||
|
||||
if (IsKeyPressed(ImGuiKey_F9, false)) {
|
||||
if (io.KeyCtrl && io.KeyAlt) {
|
||||
if (!DebugState.ShouldPauseInSubmit()) {
|
||||
DebugState.RequestFrameDump(dump_frame_count);
|
||||
}
|
||||
} else {
|
||||
if (DebugState.IsGuestThreadsPaused()) {
|
||||
DebugState.ResumeGuestThreads();
|
||||
SDL_Log("Game resumed from Keyboard");
|
||||
show_pause_status = false;
|
||||
} else {
|
||||
DebugState.PauseGuestThreads();
|
||||
SDL_Log("Game paused from Keyboard");
|
||||
show_pause_status = true;
|
||||
}
|
||||
visibility_toggled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_pause_status) {
|
||||
ImVec2 pos = ImVec2(10, 10);
|
||||
ImU32 color = IM_COL32(255, 255, 255, 255);
|
||||
|
||||
ImGui::GetForegroundDrawList()->AddText(pos, color, "Game Paused Press F9 to Resume");
|
||||
}
|
||||
|
||||
if (show_simple_fps) {
|
||||
if (Begin("Video Info", nullptr,
|
||||
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |
|
||||
|
|
|
@ -19,6 +19,7 @@ public:
|
|||
static void SetupSettings();
|
||||
|
||||
void Draw() override;
|
||||
bool show_pause_status = false;
|
||||
};
|
||||
|
||||
} // namespace Core::Devtools
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "options.h"
|
||||
|
||||
#include <memory>
|
||||
#include <imgui.h>
|
||||
|
||||
#include "options.h"
|
||||
#include "video_core/renderer_vulkan/vk_presenter.h"
|
||||
|
||||
extern std::unique_ptr<Vulkan::Presenter> presenter;
|
||||
|
||||
namespace Core::Devtools {
|
||||
|
||||
|
@ -12,6 +17,7 @@ TOptions Options;
|
|||
void LoadOptionsConfig(const char* line) {
|
||||
char str[512];
|
||||
int i;
|
||||
float f;
|
||||
if (sscanf(line, "disassembler_cli_isa=%511[^\n]", str) == 1) {
|
||||
Options.disassembler_cli_isa = str;
|
||||
return;
|
||||
|
@ -24,12 +30,26 @@ void LoadOptionsConfig(const char* line) {
|
|||
Options.frame_dump_render_on_collapse = i != 0;
|
||||
return;
|
||||
}
|
||||
if (sscanf(line, "fsr_enabled=%d", &i) == 1) {
|
||||
presenter->GetFsrSettingsRef().enable = i != 0;
|
||||
return;
|
||||
}
|
||||
if (sscanf(line, "fsr_rcas_enabled=%d", &i) == 1) {
|
||||
presenter->GetFsrSettingsRef().use_rcas = i != 0;
|
||||
return;
|
||||
}
|
||||
if (sscanf(line, "fsr_rcas_attenuation=%f", &f) == 1) {
|
||||
presenter->GetFsrSettingsRef().rcas_attenuation = f;
|
||||
}
|
||||
}
|
||||
|
||||
void SerializeOptionsConfig(ImGuiTextBuffer* buf) {
|
||||
buf->appendf("disassembler_cli_isa=%s\n", Options.disassembler_cli_isa.c_str());
|
||||
buf->appendf("disassembler_cli_spv=%s\n", Options.disassembler_cli_spv.c_str());
|
||||
buf->appendf("frame_dump_render_on_collapse=%d\n", Options.frame_dump_render_on_collapse);
|
||||
buf->appendf("fsr_enabled=%d\n", presenter->GetFsrSettingsRef().enable);
|
||||
buf->appendf("fsr_rcas_enabled=%d\n", presenter->GetFsrSettingsRef().use_rcas);
|
||||
buf->appendf("fsr_rcas_attenuation=%f\n", presenter->GetFsrSettingsRef().rcas_attenuation);
|
||||
}
|
||||
|
||||
} // namespace Core::Devtools
|
||||
|
|
|
@ -74,7 +74,7 @@ void FrameGraph::Draw() {
|
|||
if (!is_open) {
|
||||
return;
|
||||
}
|
||||
SetNextWindowSize({340.0, 185.0f}, ImGuiCond_FirstUseEver);
|
||||
SetNextWindowSize({308.0, 270.0f}, ImGuiCond_FirstUseEver);
|
||||
if (Begin("Video debug info", &is_open)) {
|
||||
const auto& ctx = *GImGui;
|
||||
const auto& io = ctx.IO;
|
||||
|
@ -88,13 +88,20 @@ void FrameGraph::Draw() {
|
|||
frameRate = 1000.0f / deltaTime;
|
||||
}
|
||||
|
||||
SeparatorText("Frame graph");
|
||||
DrawFrameGraph();
|
||||
|
||||
SeparatorText("Renderer info");
|
||||
|
||||
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
|
||||
Text("Presenter time: %.3f ms (%.1f FPS)", io.DeltaTime * 1000.0f, 1.0f / io.DeltaTime);
|
||||
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
|
||||
DebugState.gnm_frame_count.load());
|
||||
|
||||
SeparatorText("Frame graph");
|
||||
DrawFrameGraph();
|
||||
Text("Game Res: %dx%d", DebugState.game_resolution.first,
|
||||
DebugState.game_resolution.second);
|
||||
Text("Output Res: %dx%d", DebugState.output_resolution.first,
|
||||
DebugState.output_resolution.second);
|
||||
Text("FSR: %s", DebugState.is_using_fsr ? "on" : "off");
|
||||
}
|
||||
End();
|
||||
}
|
||||
|
|
|
@ -627,65 +627,56 @@ void TextEditor::HandleKeyboardInputs() {
|
|||
io.WantCaptureKeyboard = true;
|
||||
io.WantTextInput = true;
|
||||
|
||||
if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Z)))
|
||||
if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Z))
|
||||
Undo();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && alt && ImGui::IsKeyPressed(ImGuiKey_Backspace))
|
||||
Undo();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Y)))
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Y))
|
||||
Redo();
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_UpArrow))
|
||||
MoveUp(1, shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_DownArrow))
|
||||
MoveDown(1, shift);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_LeftArrow))
|
||||
MoveLeft(1, shift, ctrl);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_RightArrow))
|
||||
MoveRight(1, shift, ctrl);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageUp))
|
||||
MoveUp(GetPageSize() - 4, shift);
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)))
|
||||
else if (!alt && ImGui::IsKeyPressed(ImGuiKey_PageDown))
|
||||
MoveDown(GetPageSize() - 4, shift);
|
||||
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
|
||||
else if (!alt && ctrl && ImGui::IsKeyPressed(ImGuiKey_Home))
|
||||
MoveTop(shift);
|
||||
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
|
||||
else if (ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
|
||||
MoveBottom(shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Home))
|
||||
MoveHome(shift);
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)))
|
||||
else if (!ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_End))
|
||||
MoveEnd(shift);
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
|
||||
Delete();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Backspace)))
|
||||
ImGui::IsKeyPressed(ImGuiKey_Backspace))
|
||||
Backspace();
|
||||
else if (!ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (!ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
mOverwrite ^= true;
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
Copy();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_C)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_C))
|
||||
Copy();
|
||||
else if (!IsReadOnly() && !ctrl && shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Insert)))
|
||||
else if (!IsReadOnly() && !ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Insert))
|
||||
Paste();
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_V)))
|
||||
else if (!IsReadOnly() && ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_V))
|
||||
Paste();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_X)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_X))
|
||||
Cut();
|
||||
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete)))
|
||||
else if (!ctrl && shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Delete))
|
||||
Cut();
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_A)))
|
||||
else if (ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_A))
|
||||
SelectAll();
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Enter)))
|
||||
else if (!IsReadOnly() && !ctrl && !shift && !alt && ImGui::IsKeyPressed(ImGuiKey_Enter))
|
||||
EnterCharacter('\n', false);
|
||||
else if (!IsReadOnly() && !ctrl && !alt &&
|
||||
ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Tab)))
|
||||
else if (!IsReadOnly() && !ctrl && !alt && ImGui::IsKeyPressed(ImGuiKey_Tab))
|
||||
EnterCharacter('\t', shift);
|
||||
|
||||
if (!IsReadOnly() && !io.InputQueueCharacters.empty()) {
|
||||
|
|
|
@ -1,473 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <zlib.h>
|
||||
#include "common/io_file.h"
|
||||
#include "common/logging/formatter.h"
|
||||
#include "core/file_format/pkg.h"
|
||||
#include "core/file_format/pkg_type.h"
|
||||
|
||||
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
|
||||
z_stream decompressStream;
|
||||
decompressStream.zalloc = Z_NULL;
|
||||
decompressStream.zfree = Z_NULL;
|
||||
decompressStream.opaque = Z_NULL;
|
||||
|
||||
if (inflateInit(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error initializing zlib for deflation." << std::endl;
|
||||
}
|
||||
|
||||
decompressStream.avail_in = compressed_data.size();
|
||||
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
|
||||
decompressStream.avail_out = decompressed_data.size();
|
||||
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
|
||||
|
||||
if (inflate(&decompressStream, Z_FINISH)) {
|
||||
}
|
||||
if (inflateEnd(&decompressStream) != Z_OK) {
|
||||
// std::cerr << "Error ending zlib inflate" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
u32 GetPFSCOffset(std::span<const u8> pfs_image) {
|
||||
static constexpr u32 PfscMagic = 0x43534650;
|
||||
u32 value;
|
||||
for (u32 i = 0x20000; i < pfs_image.size(); i += 0x10000) {
|
||||
std::memcpy(&value, &pfs_image[i], sizeof(u32));
|
||||
if (value == PfscMagic)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PKG::PKG() = default;
|
||||
|
||||
PKG::~PKG() = default;
|
||||
|
||||
bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) {
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.GetSize();
|
||||
|
||||
file.Read(pkgheader);
|
||||
if (pkgheader.magic != 0x7F434E54)
|
||||
return false;
|
||||
|
||||
for (const auto& flag : flagNames) {
|
||||
if (isFlagSet(pkgheader.pkg_content_flags, flag.first)) {
|
||||
if (!pkgFlags.empty())
|
||||
pkgFlags += (", ");
|
||||
pkgFlags += (flag.second);
|
||||
}
|
||||
}
|
||||
|
||||
// Find title id it is part of pkg_content_id starting at offset 0x40
|
||||
file.Seek(0x47); // skip first 7 characters of content_id
|
||||
file.Read(pkgTitleID);
|
||||
|
||||
u32 offset = pkgheader.pkg_table_entry_offset;
|
||||
u32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
if (!file.Seek(offset)) {
|
||||
failreason = "Failed to seek to PKG table entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_files; i++) {
|
||||
PKGEntry entry{};
|
||||
file.Read(entry.id);
|
||||
file.Read(entry.filename_offset);
|
||||
file.Read(entry.flags1);
|
||||
file.Read(entry.flags2);
|
||||
file.Read(entry.offset);
|
||||
file.Read(entry.size);
|
||||
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
|
||||
|
||||
// Try to figure out the name
|
||||
const auto name = GetEntryNameByType(entry.id);
|
||||
if (name == "param.sfo") {
|
||||
sfo.clear();
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to param.sfo offset";
|
||||
return false;
|
||||
}
|
||||
sfo.resize(entry.size);
|
||||
file.ReadRaw<u8>(sfo.data(), entry.size);
|
||||
}
|
||||
}
|
||||
file.Close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
|
||||
std::string& failreason) {
|
||||
extract_path = extract;
|
||||
pkgpath = filepath;
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
pkgSize = file.GetSize();
|
||||
file.ReadRaw<u8>(&pkgheader, sizeof(PKGHeader));
|
||||
|
||||
if (pkgheader.magic != 0x7F434E54)
|
||||
return false;
|
||||
|
||||
if (pkgheader.pkg_size > pkgSize) {
|
||||
failreason = "PKG file size is different";
|
||||
return false;
|
||||
}
|
||||
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size) {
|
||||
failreason = "Content size is bigger than pkg size";
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 offset = pkgheader.pkg_table_entry_offset;
|
||||
u32 n_files = pkgheader.pkg_table_entry_count;
|
||||
|
||||
std::array<u8, 64> concatenated_ivkey_dk3;
|
||||
std::array<u8, 32> seed_digest;
|
||||
std::array<std::array<u8, 32>, 7> digest1;
|
||||
std::array<std::array<u8, 256>, 7> key1;
|
||||
std::array<u8, 256> imgkeydata;
|
||||
|
||||
if (!file.Seek(offset)) {
|
||||
failreason = "Failed to seek to PKG table entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n_files; i++) {
|
||||
PKGEntry entry{};
|
||||
file.Read(entry.id);
|
||||
file.Read(entry.filename_offset);
|
||||
file.Read(entry.flags1);
|
||||
file.Read(entry.flags2);
|
||||
file.Read(entry.offset);
|
||||
file.Read(entry.size);
|
||||
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
|
||||
|
||||
auto currentPos = file.Tell();
|
||||
|
||||
// Try to figure out the name
|
||||
const auto name = GetEntryNameByType(entry.id);
|
||||
const auto filepath = extract_path / "sce_sys" / name;
|
||||
std::filesystem::create_directories(filepath.parent_path());
|
||||
|
||||
if (name.empty()) {
|
||||
// Just print with id
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id),
|
||||
Common::FS::FileAccessMode::Write);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
out.WriteRaw<u8>(data.data(), entry.size);
|
||||
out.Close();
|
||||
|
||||
file.Seek(currentPos);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.id == 0x1) { // DIGESTS, seek;
|
||||
// file.Seek(entry.offset, fsSeekSet);
|
||||
} else if (entry.id == 0x10) { // ENTRY_KEYS, seek;
|
||||
file.Seek(entry.offset);
|
||||
file.Read(seed_digest);
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
file.Read(digest1[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 7; i++) {
|
||||
file.Read(key1[i]);
|
||||
}
|
||||
|
||||
PKG::crypto.RSA2048Decrypt(dk3_, key1[3], true); // decrypt DK3
|
||||
} else if (entry.id == 0x20) { // IMAGE_KEY, seek; IV_KEY
|
||||
file.Seek(entry.offset);
|
||||
file.Read(imgkeydata);
|
||||
|
||||
// The Concatenated iv + dk3 imagekey for HASH256
|
||||
std::memcpy(concatenated_ivkey_dk3.data(), &entry, sizeof(entry));
|
||||
std::memcpy(concatenated_ivkey_dk3.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
|
||||
|
||||
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3, ivKey); // ivkey_
|
||||
// imgkey_ to use for last step to get ekpfs
|
||||
PKG::crypto.aesCbcCfb128Decrypt(ivKey, imgkeydata, imgKey);
|
||||
// ekpfs key to get data and tweak keys.
|
||||
PKG::crypto.RSA2048Decrypt(ekpfsKey, imgKey, false);
|
||||
} else if (entry.id == 0x80) {
|
||||
// GENERAL_DIGESTS, seek;
|
||||
// file.Seek(entry.offset, fsSeekSet);
|
||||
}
|
||||
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
out.WriteRaw<u8>(data.data(), entry.size);
|
||||
out.Close();
|
||||
|
||||
// Decrypt Np stuff and overwrite.
|
||||
if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 ||
|
||||
entry.id == 0x403) { // somehow 0x401 is not decrypting
|
||||
decNp.resize(entry.size);
|
||||
if (!file.Seek(entry.offset)) {
|
||||
failreason = "Failed to seek to PKG entry offset";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> data;
|
||||
data.resize(entry.size);
|
||||
file.ReadRaw<u8>(data.data(), entry.size);
|
||||
|
||||
std::span<u8> cipherNp(data.data(), entry.size);
|
||||
std::array<u8, 64> concatenated_ivkey_dk3_;
|
||||
std::memcpy(concatenated_ivkey_dk3_.data(), &entry, sizeof(entry));
|
||||
std::memcpy(concatenated_ivkey_dk3_.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
|
||||
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3_, ivKey);
|
||||
PKG::crypto.aesCbcCfb128DecryptEntry(ivKey, cipherNp, decNp);
|
||||
|
||||
Common::FS::IOFile out(extract_path / "sce_sys" / name,
|
||||
Common::FS::FileAccessMode::Write);
|
||||
out.Write(decNp);
|
||||
out.Close();
|
||||
}
|
||||
|
||||
file.Seek(currentPos);
|
||||
}
|
||||
|
||||
// Read the seed
|
||||
std::array<u8, 16> seed;
|
||||
if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) {
|
||||
failreason = "Failed to seek to PFS image offset";
|
||||
return false;
|
||||
}
|
||||
file.Read(seed);
|
||||
|
||||
// Get data and tweak keys.
|
||||
PKG::crypto.PfsGenCryptoKey(ekpfsKey, seed, dataKey, tweakKey);
|
||||
const u32 length = pkgheader.pfs_cache_size * 0x2; // Seems to be ok.
|
||||
|
||||
int num_blocks = 0;
|
||||
std::vector<u8> pfsc(length);
|
||||
if (length != 0) {
|
||||
// Read encrypted pfs_image
|
||||
std::vector<u8> pfs_encrypted(length);
|
||||
file.Seek(pkgheader.pfs_image_offset);
|
||||
file.Read(pfs_encrypted);
|
||||
file.Close();
|
||||
// Decrypt the pfs_image.
|
||||
std::vector<u8> pfs_decrypted(length);
|
||||
PKG::crypto.decryptPFS(dataKey, tweakKey, pfs_encrypted, pfs_decrypted, 0);
|
||||
|
||||
// Retrieve PFSC from decrypted pfs_image.
|
||||
pfsc_offset = GetPFSCOffset(pfs_decrypted);
|
||||
std::memcpy(pfsc.data(), pfs_decrypted.data() + pfsc_offset, length - pfsc_offset);
|
||||
|
||||
PFSCHdr pfsChdr;
|
||||
std::memcpy(&pfsChdr, pfsc.data(), sizeof(pfsChdr));
|
||||
|
||||
num_blocks = (int)(pfsChdr.data_length / pfsChdr.block_sz2);
|
||||
sectorMap.resize(num_blocks + 1); // 8 bytes, need extra 1 to get the last offset.
|
||||
|
||||
for (int i = 0; i < num_blocks + 1; i++) {
|
||||
std::memcpy(§orMap[i], pfsc.data() + pfsChdr.block_offsets + i * 8, 8);
|
||||
}
|
||||
}
|
||||
|
||||
u32 ent_size = 0;
|
||||
u32 ndinode = 0;
|
||||
int ndinode_counter = 0;
|
||||
bool dinode_reached = false;
|
||||
bool uroot_reached = false;
|
||||
std::vector<char> compressedData;
|
||||
std::vector<char> decompressedData(0x10000);
|
||||
|
||||
// Get iNdoes and Dirents.
|
||||
for (int i = 0; i < num_blocks; i++) {
|
||||
const u64 sectorOffset = sectorMap[i];
|
||||
const u64 sectorSize = sectorMap[i + 1] - sectorOffset;
|
||||
|
||||
compressedData.resize(sectorSize);
|
||||
std::memcpy(compressedData.data(), pfsc.data() + sectorOffset, sectorSize);
|
||||
|
||||
if (sectorSize == 0x10000) // Uncompressed data
|
||||
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
|
||||
else if (sectorSize < 0x10000) // Compressed data
|
||||
DecompressPFSC(compressedData, decompressedData);
|
||||
|
||||
if (i == 0) {
|
||||
std::memcpy(&ndinode, decompressedData.data() + 0x30, 4); // number of folders and files
|
||||
}
|
||||
|
||||
int occupied_blocks =
|
||||
(ndinode * 0xA8) / 0x10000; // how many blocks(0x10000) are taken by iNodes.
|
||||
if (((ndinode * 0xA8) % 0x10000) != 0)
|
||||
occupied_blocks += 1;
|
||||
|
||||
if (i >= 1 && i <= occupied_blocks) { // Get all iNodes, gives type, file size and location.
|
||||
for (int p = 0; p < 0x10000; p += 0xA8) {
|
||||
Inode node;
|
||||
std::memcpy(&node, &decompressedData[p], sizeof(node));
|
||||
if (node.Mode == 0) {
|
||||
break;
|
||||
}
|
||||
iNodeBuf.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
// let's deal with the root/uroot entries here.
|
||||
// Sometimes it's more than 2 entries (Tomb Raider Remastered)
|
||||
const std::string_view flat_path_table(&decompressedData[0x10], 15);
|
||||
if (flat_path_table == "flat_path_table") {
|
||||
uroot_reached = true;
|
||||
}
|
||||
|
||||
if (uroot_reached) {
|
||||
for (int i = 0; i < 0x10000; i += ent_size) {
|
||||
Dirent dirent;
|
||||
std::memcpy(&dirent, &decompressedData[i], sizeof(dirent));
|
||||
ent_size = dirent.entsize;
|
||||
if (dirent.ino != 0) {
|
||||
ndinode_counter++;
|
||||
} else {
|
||||
// Set the the folder according to the current inode.
|
||||
// Can be 2 or more (rarely)
|
||||
auto parent_path = extract_path.parent_path();
|
||||
auto title_id = GetTitleID();
|
||||
|
||||
if (parent_path.filename() != title_id &&
|
||||
!fmt::UTF(extract_path.u8string()).data.ends_with("-UPDATE")) {
|
||||
extractPaths[ndinode_counter] = parent_path / title_id;
|
||||
} else {
|
||||
// DLCs path has different structure
|
||||
extractPaths[ndinode_counter] = extract_path;
|
||||
}
|
||||
uroot_reached = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char dot = decompressedData[0x10];
|
||||
const std::string_view dotdot(&decompressedData[0x28], 2);
|
||||
if (dot == '.' && dotdot == "..") {
|
||||
dinode_reached = true;
|
||||
}
|
||||
|
||||
// Get folder and file names.
|
||||
bool end_reached = false;
|
||||
if (dinode_reached) {
|
||||
for (int j = 0; j < 0x10000; j += ent_size) { // Skip the first parent and child.
|
||||
Dirent dirent;
|
||||
std::memcpy(&dirent, &decompressedData[j], sizeof(dirent));
|
||||
|
||||
// Stop here and continue the main loop
|
||||
if (dirent.ino == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ent_size = dirent.entsize;
|
||||
auto& table = fsTable.emplace_back();
|
||||
table.name = std::string(dirent.name, dirent.namelen);
|
||||
table.inode = dirent.ino;
|
||||
table.type = dirent.type;
|
||||
|
||||
if (table.type == PFS_CURRENT_DIR) {
|
||||
current_dir = extractPaths[table.inode];
|
||||
}
|
||||
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
|
||||
|
||||
if (table.type == PFS_FILE || table.type == PFS_DIR) {
|
||||
if (table.type == PFS_DIR) { // Create dirs.
|
||||
std::filesystem::create_directory(extractPaths[table.inode]);
|
||||
}
|
||||
ndinode_counter++;
|
||||
if ((ndinode_counter + 1) == ndinode) // 1 for the image itself (root).
|
||||
end_reached = true;
|
||||
}
|
||||
}
|
||||
if (end_reached) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PKG::ExtractFiles(const int index) {
|
||||
int inode_number = fsTable[index].inode;
|
||||
int inode_type = fsTable[index].type;
|
||||
std::string inode_name = fsTable[index].name;
|
||||
|
||||
if (inode_type == PFS_FILE) {
|
||||
int sector_loc = iNodeBuf[inode_number].loc;
|
||||
int nblocks = iNodeBuf[inode_number].Blocks;
|
||||
int bsize = iNodeBuf[inode_number].Size;
|
||||
|
||||
Common::FS::IOFile inflated;
|
||||
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
|
||||
|
||||
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
|
||||
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);
|
||||
|
||||
int size_decompressed = 0;
|
||||
std::vector<char> compressedData;
|
||||
std::vector<char> decompressedData(0x10000);
|
||||
|
||||
u64 pfsc_buf_size = 0x11000; // extra 0x1000
|
||||
std::vector<u8> pfsc(pfsc_buf_size);
|
||||
std::vector<u8> pfs_decrypted(pfsc_buf_size);
|
||||
|
||||
for (int j = 0; j < nblocks; j++) {
|
||||
u64 sectorOffset =
|
||||
sectorMap[sector_loc + j]; // offset into PFSC_image and not pfs_image.
|
||||
u64 sectorSize = sectorMap[sector_loc + j + 1] -
|
||||
sectorOffset; // indicates if data is compressed or not.
|
||||
u64 fileOffset = (pkgheader.pfs_image_offset + pfsc_offset + sectorOffset);
|
||||
u64 currentSector1 =
|
||||
(pfsc_offset + sectorOffset) / 0x1000; // block size is 0x1000 for xts decryption.
|
||||
|
||||
int sectorOffsetMask = (sectorOffset + pfsc_offset) & 0xFFFFF000;
|
||||
int previousData = (sectorOffset + pfsc_offset) - sectorOffsetMask;
|
||||
|
||||
pkgFile.Seek(fileOffset - previousData);
|
||||
pkgFile.Read(pfsc);
|
||||
|
||||
PKG::crypto.decryptPFS(dataKey, tweakKey, pfsc, pfs_decrypted, currentSector1);
|
||||
|
||||
compressedData.resize(sectorSize);
|
||||
std::memcpy(compressedData.data(), pfs_decrypted.data() + previousData, sectorSize);
|
||||
|
||||
if (sectorSize == 0x10000) // Uncompressed data
|
||||
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
|
||||
else if (sectorSize < 0x10000) // Compressed data
|
||||
DecompressPFSC(compressedData, decompressedData);
|
||||
|
||||
size_decompressed += 0x10000;
|
||||
|
||||
if (j < nblocks - 1) {
|
||||
inflated.WriteRaw<u8>(decompressedData.data(), decompressedData.size());
|
||||
} else {
|
||||
// This is to remove the zeros at the end of the file.
|
||||
const u32 write_size = decompressedData.size() - (size_decompressed - bsize);
|
||||
inflated.WriteRaw<u8>(decompressedData.data(), write_size);
|
||||
}
|
||||
}
|
||||
pkgFile.Close();
|
||||
inflated.Close();
|
||||
}
|
||||
}
|
|
@ -1,174 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include "common/endian.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "pfs.h"
|
||||
#include "trp.h"
|
||||
|
||||
struct PKGHeader {
|
||||
u32_be magic; // Magic
|
||||
u32_be pkg_type;
|
||||
u32_be pkg_0x8; // unknown field
|
||||
u32_be pkg_file_count;
|
||||
u32_be pkg_table_entry_count;
|
||||
u16_be pkg_sc_entry_count;
|
||||
u16_be pkg_table_entry_count_2; // same as pkg_entry_count
|
||||
u32_be pkg_table_entry_offset; // file table offset
|
||||
u32_be pkg_sc_entry_data_size;
|
||||
u64_be pkg_body_offset; // offset of PKG entries
|
||||
u64_be pkg_body_size; // length of all PKG entries
|
||||
u64_be pkg_content_offset;
|
||||
u64_be pkg_content_size;
|
||||
u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
|
||||
u8 pkg_padding[0xC]; // padding
|
||||
u32_be pkg_drm_type; // DRM type
|
||||
u32_be pkg_content_type; // Content type
|
||||
u32_be pkg_content_flags; // Content flags
|
||||
u32_be pkg_promote_size;
|
||||
u32_be pkg_version_date;
|
||||
u32_be pkg_version_hash;
|
||||
u32_be pkg_0x088;
|
||||
u32_be pkg_0x08C;
|
||||
u32_be pkg_0x090;
|
||||
u32_be pkg_0x094;
|
||||
u32_be pkg_iro_tag;
|
||||
u32_be pkg_drm_type_version;
|
||||
|
||||
u8 pkg_zeroes_1[0x60];
|
||||
|
||||
/* Digest table */
|
||||
u8 digest_entries1[0x20]; // sha256 digest for main entry 1
|
||||
u8 digest_entries2[0x20]; // sha256 digest for main entry 2
|
||||
u8 digest_table_digest[0x20]; // sha256 digest for digest table
|
||||
u8 digest_body_digest[0x20]; // sha256 digest for main table
|
||||
|
||||
u8 pkg_zeroes_2[0x280];
|
||||
|
||||
u32_be pkg_0x400;
|
||||
|
||||
u32_be pfs_image_count; // count of PFS images
|
||||
u64_be pfs_image_flags; // PFS flags
|
||||
u64_be pfs_image_offset; // offset to start of external PFS image
|
||||
u64_be pfs_image_size; // size of external PFS image
|
||||
u64_be mount_image_offset;
|
||||
u64_be mount_image_size;
|
||||
u64_be pkg_size;
|
||||
u32_be pfs_signed_size;
|
||||
u32_be pfs_cache_size;
|
||||
u8 pfs_image_digest[0x20];
|
||||
u8 pfs_signed_digest[0x20];
|
||||
u64_be pfs_split_size_nth_0;
|
||||
u64_be pfs_split_size_nth_1;
|
||||
|
||||
u8 pkg_zeroes_3[0xB50];
|
||||
|
||||
u8 pkg_digest[0x20];
|
||||
};
|
||||
|
||||
enum class PKGContentFlag {
|
||||
FIRST_PATCH = 0x100000,
|
||||
PATCHGO = 0x200000,
|
||||
REMASTER = 0x400000,
|
||||
PS_CLOUD = 0x800000,
|
||||
GD_AC = 0x2000000,
|
||||
NON_GAME = 0x4000000,
|
||||
UNKNOWN_0x8000000 = 0x8000000,
|
||||
SUBSEQUENT_PATCH = 0x40000000,
|
||||
DELTA_PATCH = 0x41000000,
|
||||
CUMULATIVE_PATCH = 0x60000000
|
||||
};
|
||||
|
||||
struct PKGEntry {
|
||||
u32_be id; // File ID, useful for files without a filename entry
|
||||
u32_be filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is
|
||||
// located
|
||||
u32_be flags1; // Flags including encrypted flag, etc
|
||||
u32_be flags2; // Flags including encryption key index, etc
|
||||
u32_be offset; // Offset into PKG to find the file
|
||||
u32_be size; // Size of the file
|
||||
u64_be padding; // blank padding
|
||||
};
|
||||
static_assert(sizeof(PKGEntry) == 32);
|
||||
|
||||
class PKG {
|
||||
public:
|
||||
PKG();
|
||||
~PKG();
|
||||
|
||||
bool Open(const std::filesystem::path& filepath, std::string& failreason);
|
||||
void ExtractFiles(const int index);
|
||||
bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
|
||||
std::string& failreason);
|
||||
|
||||
std::vector<u8> sfo;
|
||||
|
||||
u32 GetNumberOfFiles() {
|
||||
return fsTable.size();
|
||||
}
|
||||
|
||||
u64 GetPkgSize() {
|
||||
return pkgSize;
|
||||
}
|
||||
|
||||
std::string GetPkgFlags() {
|
||||
return pkgFlags;
|
||||
}
|
||||
|
||||
std::string_view GetTitleID() {
|
||||
return std::string_view(pkgTitleID, 9);
|
||||
}
|
||||
|
||||
PKGHeader GetPkgHeader() {
|
||||
return pkgheader;
|
||||
}
|
||||
|
||||
static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
|
||||
return (variable) & static_cast<u32>(flag);
|
||||
}
|
||||
|
||||
static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10> flagNames = {
|
||||
{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
|
||||
{PKGContentFlag::PATCHGO, "PATCHGO"},
|
||||
{PKGContentFlag::REMASTER, "REMASTER"},
|
||||
{PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
|
||||
{PKGContentFlag::GD_AC, "GD_AC"},
|
||||
{PKGContentFlag::NON_GAME, "NON_GAME"},
|
||||
{PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
|
||||
{PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
|
||||
{PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
|
||||
{PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
|
||||
|
||||
private:
|
||||
Crypto crypto;
|
||||
TRP trp;
|
||||
u64 pkgSize = 0;
|
||||
char pkgTitleID[9];
|
||||
PKGHeader pkgheader;
|
||||
std::string pkgFlags;
|
||||
|
||||
std::unordered_map<int, std::filesystem::path> extractPaths;
|
||||
std::vector<pfs_fs_table> fsTable;
|
||||
std::vector<Inode> iNodeBuf;
|
||||
std::vector<u64> sectorMap;
|
||||
u64 pfsc_offset;
|
||||
|
||||
std::array<u8, 32> dk3_;
|
||||
std::array<u8, 32> ivKey;
|
||||
std::array<u8, 256> imgKey;
|
||||
std::array<u8, 32> ekpfsKey;
|
||||
std::array<u8, 16> dataKey;
|
||||
std::array<u8, 16> tweakKey;
|
||||
std::vector<u8> decNp;
|
||||
|
||||
std::filesystem::path pkgpath;
|
||||
std::filesystem::path current_dir;
|
||||
std::filesystem::path extract_path;
|
||||
};
|
|
@ -1,638 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include "pkg_type.h"
|
||||
|
||||
struct PkgEntryValue {
|
||||
u32 type;
|
||||
std::string_view name;
|
||||
|
||||
operator u32() const noexcept {
|
||||
return type;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr static std::array<PkgEntryValue, 611> PkgEntries = {{
|
||||
{0x0001, "digests"},
|
||||
{0x0010, "entry_keys"},
|
||||
{0x0020, "image_key"},
|
||||
{0x0080, "general_digests"},
|
||||
{0x0100, "metas"},
|
||||
{0x0200, "entry_names"},
|
||||
{0x0400, "license.dat"},
|
||||
{0x0401, "license.info"},
|
||||
{0x0402, "nptitle.dat"},
|
||||
{0x0403, "npbind.dat"},
|
||||
{0x0404, "selfinfo.dat"},
|
||||
{0x0406, "imageinfo.dat"},
|
||||
{0x0407, "target-deltainfo.dat"},
|
||||
{0x0408, "origin-deltainfo.dat"},
|
||||
{0x0409, "psreserved.dat"},
|
||||
{0x1000, "param.sfo"},
|
||||
{0x1001, "playgo-chunk.dat"},
|
||||
{0x1002, "playgo-chunk.sha"},
|
||||
{0x1003, "playgo-manifest.xml"},
|
||||
{0x1004, "pronunciation.xml"},
|
||||
{0x1005, "pronunciation.sig"},
|
||||
{0x1006, "pic1.png"},
|
||||
{0x1007, "pubtoolinfo.dat"},
|
||||
{0x1008, "app/playgo-chunk.dat"},
|
||||
{0x1009, "app/playgo-chunk.sha"},
|
||||
{0x100A, "app/playgo-manifest.xml"},
|
||||
{0x100B, "shareparam.json"},
|
||||
{0x100C, "shareoverlayimage.png"},
|
||||
{0x100D, "save_data.png"},
|
||||
{0x100E, "shareprivacyguardimage.png"},
|
||||
{0x1200, "icon0.png"},
|
||||
{0x1201, "icon0_00.png"},
|
||||
{0x1202, "icon0_01.png"},
|
||||
{0x1203, "icon0_02.png"},
|
||||
{0x1204, "icon0_03.png"},
|
||||
{0x1205, "icon0_04.png"},
|
||||
{0x1206, "icon0_05.png"},
|
||||
{0x1207, "icon0_06.png"},
|
||||
{0x1208, "icon0_07.png"},
|
||||
{0x1209, "icon0_08.png"},
|
||||
{0x120A, "icon0_09.png"},
|
||||
{0x120B, "icon0_10.png"},
|
||||
{0x120C, "icon0_11.png"},
|
||||
{0x120D, "icon0_12.png"},
|
||||
{0x120E, "icon0_13.png"},
|
||||
{0x120F, "icon0_14.png"},
|
||||
{0x1210, "icon0_15.png"},
|
||||
{0x1211, "icon0_16.png"},
|
||||
{0x1212, "icon0_17.png"},
|
||||
{0x1213, "icon0_18.png"},
|
||||
{0x1214, "icon0_19.png"},
|
||||
{0x1215, "icon0_20.png"},
|
||||
{0x1216, "icon0_21.png"},
|
||||
{0x1217, "icon0_22.png"},
|
||||
{0x1218, "icon0_23.png"},
|
||||
{0x1219, "icon0_24.png"},
|
||||
{0x121A, "icon0_25.png"},
|
||||
{0x121B, "icon0_26.png"},
|
||||
{0x121C, "icon0_27.png"},
|
||||
{0x121D, "icon0_28.png"},
|
||||
{0x121E, "icon0_29.png"},
|
||||
{0x121F, "icon0_30.png"},
|
||||
{0x1220, "pic0.png"},
|
||||
{0x1240, "snd0.at9"},
|
||||
{0x1241, "pic1_00.png"},
|
||||
{0x1242, "pic1_01.png"},
|
||||
{0x1243, "pic1_02.png"},
|
||||
{0x1244, "pic1_03.png"},
|
||||
{0x1245, "pic1_04.png"},
|
||||
{0x1246, "pic1_05.png"},
|
||||
{0x1247, "pic1_06.png"},
|
||||
{0x1248, "pic1_07.png"},
|
||||
{0x1249, "pic1_08.png"},
|
||||
{0x124A, "pic1_09.png"},
|
||||
{0x124B, "pic1_10.png"},
|
||||
{0x124C, "pic1_11.png"},
|
||||
{0x124D, "pic1_12.png"},
|
||||
{0x124E, "pic1_13.png"},
|
||||
{0x124F, "pic1_14.png"},
|
||||
{0x1250, "pic1_15.png"},
|
||||
{0x1251, "pic1_16.png"},
|
||||
{0x1252, "pic1_17.png"},
|
||||
{0x1253, "pic1_18.png"},
|
||||
{0x1254, "pic1_19.png"},
|
||||
{0x1255, "pic1_20.png"},
|
||||
{0x1256, "pic1_21.png"},
|
||||
{0x1257, "pic1_22.png"},
|
||||
{0x1258, "pic1_23.png"},
|
||||
{0x1259, "pic1_24.png"},
|
||||
{0x125A, "pic1_25.png"},
|
||||
{0x125B, "pic1_26.png"},
|
||||
{0x125C, "pic1_27.png"},
|
||||
{0x125D, "pic1_28.png"},
|
||||
{0x125E, "pic1_29.png"},
|
||||
{0x125F, "pic1_30.png"},
|
||||
{0x1260, "changeinfo/changeinfo.xml"},
|
||||
{0x1261, "changeinfo/changeinfo_00.xml"},
|
||||
{0x1262, "changeinfo/changeinfo_01.xml"},
|
||||
{0x1263, "changeinfo/changeinfo_02.xml"},
|
||||
{0x1264, "changeinfo/changeinfo_03.xml"},
|
||||
{0x1265, "changeinfo/changeinfo_04.xml"},
|
||||
{0x1266, "changeinfo/changeinfo_05.xml"},
|
||||
{0x1267, "changeinfo/changeinfo_06.xml"},
|
||||
{0x1268, "changeinfo/changeinfo_07.xml"},
|
||||
{0x1269, "changeinfo/changeinfo_08.xml"},
|
||||
{0x126A, "changeinfo/changeinfo_09.xml"},
|
||||
{0x126B, "changeinfo/changeinfo_10.xml"},
|
||||
{0x126C, "changeinfo/changeinfo_11.xml"},
|
||||
{0x126D, "changeinfo/changeinfo_12.xml"},
|
||||
{0x126E, "changeinfo/changeinfo_13.xml"},
|
||||
{0x126F, "changeinfo/changeinfo_14.xml"},
|
||||
{0x1270, "changeinfo/changeinfo_15.xml"},
|
||||
{0x1271, "changeinfo/changeinfo_16.xml"},
|
||||
{0x1272, "changeinfo/changeinfo_17.xml"},
|
||||
{0x1273, "changeinfo/changeinfo_18.xml"},
|
||||
{0x1274, "changeinfo/changeinfo_19.xml"},
|
||||
{0x1275, "changeinfo/changeinfo_20.xml"},
|
||||
{0x1276, "changeinfo/changeinfo_21.xml"},
|
||||
{0x1277, "changeinfo/changeinfo_22.xml"},
|
||||
{0x1278, "changeinfo/changeinfo_23.xml"},
|
||||
{0x1279, "changeinfo/changeinfo_24.xml"},
|
||||
{0x127A, "changeinfo/changeinfo_25.xml"},
|
||||
{0x127B, "changeinfo/changeinfo_26.xml"},
|
||||
{0x127C, "changeinfo/changeinfo_27.xml"},
|
||||
{0x127D, "changeinfo/changeinfo_28.xml"},
|
||||
{0x127E, "changeinfo/changeinfo_29.xml"},
|
||||
{0x127F, "changeinfo/changeinfo_30.xml"},
|
||||
{0x1280, "icon0.dds"},
|
||||
{0x1281, "icon0_00.dds"},
|
||||
{0x1282, "icon0_01.dds"},
|
||||
{0x1283, "icon0_02.dds"},
|
||||
{0x1284, "icon0_03.dds"},
|
||||
{0x1285, "icon0_04.dds"},
|
||||
{0x1286, "icon0_05.dds"},
|
||||
{0x1287, "icon0_06.dds"},
|
||||
{0x1288, "icon0_07.dds"},
|
||||
{0x1289, "icon0_08.dds"},
|
||||
{0x128A, "icon0_09.dds"},
|
||||
{0x128B, "icon0_10.dds"},
|
||||
{0x128C, "icon0_11.dds"},
|
||||
{0x128D, "icon0_12.dds"},
|
||||
{0x128E, "icon0_13.dds"},
|
||||
{0x128F, "icon0_14.dds"},
|
||||
{0x1290, "icon0_15.dds"},
|
||||
{0x1291, "icon0_16.dds"},
|
||||
{0x1292, "icon0_17.dds"},
|
||||
{0x1293, "icon0_18.dds"},
|
||||
{0x1294, "icon0_19.dds"},
|
||||
{0x1295, "icon0_20.dds"},
|
||||
{0x1296, "icon0_21.dds"},
|
||||
{0x1297, "icon0_22.dds"},
|
||||
{0x1298, "icon0_23.dds"},
|
||||
{0x1299, "icon0_24.dds"},
|
||||
{0x129A, "icon0_25.dds"},
|
||||
{0x129B, "icon0_26.dds"},
|
||||
{0x129C, "icon0_27.dds"},
|
||||
{0x129D, "icon0_28.dds"},
|
||||
{0x129E, "icon0_29.dds"},
|
||||
{0x129F, "icon0_30.dds"},
|
||||
{0x12A0, "pic0.dds"},
|
||||
{0x12C0, "pic1.dds"},
|
||||
{0x12C1, "pic1_00.dds"},
|
||||
{0x12C2, "pic1_01.dds"},
|
||||
{0x12C3, "pic1_02.dds"},
|
||||
{0x12C4, "pic1_03.dds"},
|
||||
{0x12C5, "pic1_04.dds"},
|
||||
{0x12C6, "pic1_05.dds"},
|
||||
{0x12C7, "pic1_06.dds"},
|
||||
{0x12C8, "pic1_07.dds"},
|
||||
{0x12C9, "pic1_08.dds"},
|
||||
{0x12CA, "pic1_09.dds"},
|
||||
{0x12CB, "pic1_10.dds"},
|
||||
{0x12CC, "pic1_11.dds"},
|
||||
{0x12CD, "pic1_12.dds"},
|
||||
{0x12CE, "pic1_13.dds"},
|
||||
{0x12CF, "pic1_14.dds"},
|
||||
{0x12D0, "pic1_15.dds"},
|
||||
{0x12D1, "pic1_16.dds"},
|
||||
{0x12D2, "pic1_17.dds"},
|
||||
{0x12D3, "pic1_18.dds"},
|
||||
{0x12D4, "pic1_19.dds"},
|
||||
{0x12D5, "pic1_20.dds"},
|
||||
{0x12D6, "pic1_21.dds"},
|
||||
{0x12D7, "pic1_22.dds"},
|
||||
{0x12D8, "pic1_23.dds"},
|
||||
{0x12D9, "pic1_24.dds"},
|
||||
{0x12DA, "pic1_25.dds"},
|
||||
{0x12DB, "pic1_26.dds"},
|
||||
{0x12DC, "pic1_27.dds"},
|
||||
{0x12DD, "pic1_28.dds"},
|
||||
{0x12DE, "pic1_29.dds"},
|
||||
{0x12DF, "pic1_30.dds"},
|
||||
{0x1400, "trophy/trophy00.trp"},
|
||||
{0x1401, "trophy/trophy01.trp"},
|
||||
{0x1402, "trophy/trophy02.trp"},
|
||||
{0x1403, "trophy/trophy03.trp"},
|
||||
{0x1404, "trophy/trophy04.trp"},
|
||||
{0x1405, "trophy/trophy05.trp"},
|
||||
{0x1406, "trophy/trophy06.trp"},
|
||||
{0x1407, "trophy/trophy07.trp"},
|
||||
{0x1408, "trophy/trophy08.trp"},
|
||||
{0x1409, "trophy/trophy09.trp"},
|
||||
{0x140A, "trophy/trophy10.trp"},
|
||||
{0x140B, "trophy/trophy11.trp"},
|
||||
{0x140C, "trophy/trophy12.trp"},
|
||||
{0x140D, "trophy/trophy13.trp"},
|
||||
{0x140E, "trophy/trophy14.trp"},
|
||||
{0x140F, "trophy/trophy15.trp"},
|
||||
{0x1410, "trophy/trophy16.trp"},
|
||||
{0x1411, "trophy/trophy17.trp"},
|
||||
{0x1412, "trophy/trophy18.trp"},
|
||||
{0x1413, "trophy/trophy19.trp"},
|
||||
{0x1414, "trophy/trophy20.trp"},
|
||||
{0x1415, "trophy/trophy21.trp"},
|
||||
{0x1416, "trophy/trophy22.trp"},
|
||||
{0x1417, "trophy/trophy23.trp"},
|
||||
{0x1418, "trophy/trophy24.trp"},
|
||||
{0x1419, "trophy/trophy25.trp"},
|
||||
{0x141A, "trophy/trophy26.trp"},
|
||||
{0x141B, "trophy/trophy27.trp"},
|
||||
{0x141C, "trophy/trophy28.trp"},
|
||||
{0x141D, "trophy/trophy29.trp"},
|
||||
{0x141E, "trophy/trophy30.trp"},
|
||||
{0x141F, "trophy/trophy31.trp"},
|
||||
{0x1420, "trophy/trophy32.trp"},
|
||||
{0x1421, "trophy/trophy33.trp"},
|
||||
{0x1422, "trophy/trophy34.trp"},
|
||||
{0x1423, "trophy/trophy35.trp"},
|
||||
{0x1424, "trophy/trophy36.trp"},
|
||||
{0x1425, "trophy/trophy37.trp"},
|
||||
{0x1426, "trophy/trophy38.trp"},
|
||||
{0x1427, "trophy/trophy39.trp"},
|
||||
{0x1428, "trophy/trophy40.trp"},
|
||||
{0x1429, "trophy/trophy41.trp"},
|
||||
{0x142A, "trophy/trophy42.trp"},
|
||||
{0x142B, "trophy/trophy43.trp"},
|
||||
{0x142C, "trophy/trophy44.trp"},
|
||||
{0x142D, "trophy/trophy45.trp"},
|
||||
{0x142E, "trophy/trophy46.trp"},
|
||||
{0x142F, "trophy/trophy47.trp"},
|
||||
{0x1430, "trophy/trophy48.trp"},
|
||||
{0x1431, "trophy/trophy49.trp"},
|
||||
{0x1432, "trophy/trophy50.trp"},
|
||||
{0x1433, "trophy/trophy51.trp"},
|
||||
{0x1434, "trophy/trophy52.trp"},
|
||||
{0x1435, "trophy/trophy53.trp"},
|
||||
{0x1436, "trophy/trophy54.trp"},
|
||||
{0x1437, "trophy/trophy55.trp"},
|
||||
{0x1438, "trophy/trophy56.trp"},
|
||||
{0x1439, "trophy/trophy57.trp"},
|
||||
{0x143A, "trophy/trophy58.trp"},
|
||||
{0x143B, "trophy/trophy59.trp"},
|
||||
{0x143C, "trophy/trophy60.trp"},
|
||||
{0x143D, "trophy/trophy61.trp"},
|
||||
{0x143E, "trophy/trophy62.trp"},
|
||||
{0x143F, "trophy/trophy63.trp"},
|
||||
{0x1440, "trophy/trophy64.trp"},
|
||||
{0x1441, "trophy/trophy65.trp"},
|
||||
{0x1442, "trophy/trophy66.trp"},
|
||||
{0x1443, "trophy/trophy67.trp"},
|
||||
{0x1444, "trophy/trophy68.trp"},
|
||||
{0x1445, "trophy/trophy69.trp"},
|
||||
{0x1446, "trophy/trophy70.trp"},
|
||||
{0x1447, "trophy/trophy71.trp"},
|
||||
{0x1448, "trophy/trophy72.trp"},
|
||||
{0x1449, "trophy/trophy73.trp"},
|
||||
{0x144A, "trophy/trophy74.trp"},
|
||||
{0x144B, "trophy/trophy75.trp"},
|
||||
{0x144C, "trophy/trophy76.trp"},
|
||||
{0x144D, "trophy/trophy77.trp"},
|
||||
{0x144E, "trophy/trophy78.trp"},
|
||||
{0x144F, "trophy/trophy79.trp"},
|
||||
{0x1450, "trophy/trophy80.trp"},
|
||||
{0x1451, "trophy/trophy81.trp"},
|
||||
{0x1452, "trophy/trophy82.trp"},
|
||||
{0x1453, "trophy/trophy83.trp"},
|
||||
{0x1454, "trophy/trophy84.trp"},
|
||||
{0x1455, "trophy/trophy85.trp"},
|
||||
{0x1456, "trophy/trophy86.trp"},
|
||||
{0x1457, "trophy/trophy87.trp"},
|
||||
{0x1458, "trophy/trophy88.trp"},
|
||||
{0x1459, "trophy/trophy89.trp"},
|
||||
{0x145A, "trophy/trophy90.trp"},
|
||||
{0x145B, "trophy/trophy91.trp"},
|
||||
{0x145C, "trophy/trophy92.trp"},
|
||||
{0x145D, "trophy/trophy93.trp"},
|
||||
{0x145E, "trophy/trophy94.trp"},
|
||||
{0x145F, "trophy/trophy95.trp"},
|
||||
{0x1460, "trophy/trophy96.trp"},
|
||||
{0x1461, "trophy/trophy97.trp"},
|
||||
{0x1462, "trophy/trophy98.trp"},
|
||||
{0x1463, "trophy/trophy99.trp"},
|
||||
{0x1600, "keymap_rp/001.png"},
|
||||
{0x1601, "keymap_rp/002.png"},
|
||||
{0x1602, "keymap_rp/003.png"},
|
||||
{0x1603, "keymap_rp/004.png"},
|
||||
{0x1604, "keymap_rp/005.png"},
|
||||
{0x1605, "keymap_rp/006.png"},
|
||||
{0x1606, "keymap_rp/007.png"},
|
||||
{0x1607, "keymap_rp/008.png"},
|
||||
{0x1608, "keymap_rp/009.png"},
|
||||
{0x1609, "keymap_rp/010.png"},
|
||||
{0x1610, "keymap_rp/00/001.png"},
|
||||
{0x1611, "keymap_rp/00/002.png"},
|
||||
{0x1612, "keymap_rp/00/003.png"},
|
||||
{0x1613, "keymap_rp/00/004.png"},
|
||||
{0x1614, "keymap_rp/00/005.png"},
|
||||
{0x1615, "keymap_rp/00/006.png"},
|
||||
{0x1616, "keymap_rp/00/007.png"},
|
||||
{0x1617, "keymap_rp/00/008.png"},
|
||||
{0x1618, "keymap_rp/00/009.png"},
|
||||
{0x1619, "keymap_rp/00/010.png"},
|
||||
{0x1620, "keymap_rp/01/001.png"},
|
||||
{0x1621, "keymap_rp/01/002.png"},
|
||||
{0x1622, "keymap_rp/01/003.png"},
|
||||
{0x1623, "keymap_rp/01/004.png"},
|
||||
{0x1624, "keymap_rp/01/005.png"},
|
||||
{0x1625, "keymap_rp/01/006.png"},
|
||||
{0x1626, "keymap_rp/01/007.png"},
|
||||
{0x1627, "keymap_rp/01/008.png"},
|
||||
{0x1628, "keymap_rp/01/009.png"},
|
||||
{0x1629, "keymap_rp/01/010.png"},
|
||||
{0x1630, "keymap_rp/02/001.png"},
|
||||
{0x1631, "keymap_rp/02/002.png"},
|
||||
{0x1632, "keymap_rp/02/003.png"},
|
||||
{0x1633, "keymap_rp/02/004.png"},
|
||||
{0x1634, "keymap_rp/02/005.png"},
|
||||
{0x1635, "keymap_rp/02/006.png"},
|
||||
{0x1636, "keymap_rp/02/007.png"},
|
||||
{0x1637, "keymap_rp/02/008.png"},
|
||||
{0x1638, "keymap_rp/02/009.png"},
|
||||
{0x1639, "keymap_rp/02/010.png"},
|
||||
{0x1640, "keymap_rp/03/001.png"},
|
||||
{0x1641, "keymap_rp/03/002.png"},
|
||||
{0x1642, "keymap_rp/03/003.png"},
|
||||
{0x1643, "keymap_rp/03/004.png"},
|
||||
{0x1644, "keymap_rp/03/005.png"},
|
||||
{0x1645, "keymap_rp/03/006.png"},
|
||||
{0x1646, "keymap_rp/03/007.png"},
|
||||
{0x1647, "keymap_rp/03/008.png"},
|
||||
{0x1648, "keymap_rp/03/0010.png"},
|
||||
{0x1650, "keymap_rp/04/001.png"},
|
||||
{0x1651, "keymap_rp/04/002.png"},
|
||||
{0x1652, "keymap_rp/04/003.png"},
|
||||
{0x1653, "keymap_rp/04/004.png"},
|
||||
{0x1654, "keymap_rp/04/005.png"},
|
||||
{0x1655, "keymap_rp/04/006.png"},
|
||||
{0x1656, "keymap_rp/04/007.png"},
|
||||
{0x1657, "keymap_rp/04/008.png"},
|
||||
{0x1658, "keymap_rp/04/009.png"},
|
||||
{0x1659, "keymap_rp/04/010.png"},
|
||||
{0x1660, "keymap_rp/05/001.png"},
|
||||
{0x1661, "keymap_rp/05/002.png"},
|
||||
{0x1662, "keymap_rp/05/003.png"},
|
||||
{0x1663, "keymap_rp/05/004.png"},
|
||||
{0x1664, "keymap_rp/05/005.png"},
|
||||
{0x1665, "keymap_rp/05/006.png"},
|
||||
{0x1666, "keymap_rp/05/007.png"},
|
||||
{0x1667, "keymap_rp/05/008.png"},
|
||||
{0x1668, "keymap_rp/05/009.png"},
|
||||
{0x1669, "keymap_rp/05/010.png"},
|
||||
{0x1670, "keymap_rp/06/001.png"},
|
||||
{0x1671, "keymap_rp/06/002.png"},
|
||||
{0x1672, "keymap_rp/06/003.png"},
|
||||
{0x1673, "keymap_rp/06/004.png"},
|
||||
{0x1674, "keymap_rp/06/005.png"},
|
||||
{0x1675, "keymap_rp/06/006.png"},
|
||||
{0x1676, "keymap_rp/06/007.png"},
|
||||
{0x1677, "keymap_rp/06/008.png"},
|
||||
{0x1678, "keymap_rp/06/009.png"},
|
||||
{0x1679, "keymap_rp/06/010.png"},
|
||||
{0x1680, "keymap_rp/07/001.png"},
|
||||
{0x1681, "keymap_rp/07/002.png"},
|
||||
{0x1682, "keymap_rp/07/003.png"},
|
||||
{0x1683, "keymap_rp/07/004.png"},
|
||||
{0x1684, "keymap_rp/07/005.png"},
|
||||
{0x1685, "keymap_rp/07/006.png"},
|
||||
{0x1686, "keymap_rp/07/007.png"},
|
||||
{0x1687, "keymap_rp/07/008.png"},
|
||||
{0x1688, "keymap_rp/07/009.png"},
|
||||
{0x1689, "keymap_rp/07/010.png"},
|
||||
{0x1690, "keymap_rp/08/001.png"},
|
||||
{0x1691, "keymap_rp/08/002.png"},
|
||||
{0x1692, "keymap_rp/08/003.png"},
|
||||
{0x1693, "keymap_rp/08/004.png"},
|
||||
{0x1694, "keymap_rp/08/005.png"},
|
||||
{0x1695, "keymap_rp/08/006.png"},
|
||||
{0x1696, "keymap_rp/08/007.png"},
|
||||
{0x1697, "keymap_rp/08/008.png"},
|
||||
{0x1698, "keymap_rp/08/009.png"},
|
||||
{0x1699, "keymap_rp/08/010.png"},
|
||||
{0x16A0, "keymap_rp/09/001.png"},
|
||||
{0x16A1, "keymap_rp/09/002.png"},
|
||||
{0x16A2, "keymap_rp/09/003.png"},
|
||||
{0x16A3, "keymap_rp/09/004.png"},
|
||||
{0x16A4, "keymap_rp/09/005.png"},
|
||||
{0x16A5, "keymap_rp/09/006.png"},
|
||||
{0x16A6, "keymap_rp/09/007.png"},
|
||||
{0x16A7, "keymap_rp/09/008.png"},
|
||||
{0x16A8, "keymap_rp/09/009.png"},
|
||||
{0x16A9, "keymap_rp/09/010.png"},
|
||||
{0x16B0, "keymap_rp/10/001.png"},
|
||||
{0x16B1, "keymap_rp/10/002.png"},
|
||||
{0x16B2, "keymap_rp/10/003.png"},
|
||||
{0x16B3, "keymap_rp/10/004.png"},
|
||||
{0x16B4, "keymap_rp/10/005.png"},
|
||||
{0x16B5, "keymap_rp/10/006.png"},
|
||||
{0x16B6, "keymap_rp/10/007.png"},
|
||||
{0x16B7, "keymap_rp/10/008.png"},
|
||||
{0x16B8, "keymap_rp/10/009.png"},
|
||||
{0x16B9, "keymap_rp/10/010.png"},
|
||||
{0x16C0, "keymap_rp/11/001.png"},
|
||||
{0x16C1, "keymap_rp/11/002.png"},
|
||||
{0x16C2, "keymap_rp/11/003.png"},
|
||||
{0x16C3, "keymap_rp/11/004.png"},
|
||||
{0x16C4, "keymap_rp/11/005.png"},
|
||||
{0x16C5, "keymap_rp/11/006.png"},
|
||||
{0x16C6, "keymap_rp/11/007.png"},
|
||||
{0x16C7, "keymap_rp/11/008.png"},
|
||||
{0x16C8, "keymap_rp/11/009.png"},
|
||||
{0x16C9, "keymap_rp/11/010.png"},
|
||||
{0x16D0, "keymap_rp/12/001.png"},
|
||||
{0x16D1, "keymap_rp/12/002.png"},
|
||||
{0x16D2, "keymap_rp/12/003.png"},
|
||||
{0x16D3, "keymap_rp/12/004.png"},
|
||||
{0x16D4, "keymap_rp/12/005.png"},
|
||||
{0x16D5, "keymap_rp/12/006.png"},
|
||||
{0x16D6, "keymap_rp/12/007.png"},
|
||||
{0x16D7, "keymap_rp/12/008.png"},
|
||||
{0x16D8, "keymap_rp/12/009.png"},
|
||||
{0x16D9, "keymap_rp/12/010.png"},
|
||||
{0x16E0, "keymap_rp/13/001.png"},
|
||||
{0x16E1, "keymap_rp/13/002.png"},
|
||||
{0x16E2, "keymap_rp/13/003.png"},
|
||||
{0x16E3, "keymap_rp/13/004.png"},
|
||||
{0x16E4, "keymap_rp/13/005.png"},
|
||||
{0x16E5, "keymap_rp/13/006.png"},
|
||||
{0x16E6, "keymap_rp/13/007.png"},
|
||||
{0x16E7, "keymap_rp/13/008.png"},
|
||||
{0x16E8, "keymap_rp/13/009.png"},
|
||||
{0x16E9, "keymap_rp/13/010.png"},
|
||||
{0x16F0, "keymap_rp/14/001.png"},
|
||||
{0x16F1, "keymap_rp/14/002.png"},
|
||||
{0x16F2, "keymap_rp/14/003.png"},
|
||||
{0x16F3, "keymap_rp/14/004.png"},
|
||||
{0x16F4, "keymap_rp/14/005.png"},
|
||||
{0x16F5, "keymap_rp/14/006.png"},
|
||||
{0x16F6, "keymap_rp/14/007.png"},
|
||||
{0x16F7, "keymap_rp/14/008.png"},
|
||||
{0x16F8, "keymap_rp/14/009.png"},
|
||||
{0x16F9, "keymap_rp/14/010.png"},
|
||||
{0x1700, "keymap_rp/15/001.png"},
|
||||
{0x1701, "keymap_rp/15/002.png"},
|
||||
{0x1702, "keymap_rp/15/003.png"},
|
||||
{0x1703, "keymap_rp/15/004.png"},
|
||||
{0x1704, "keymap_rp/15/005.png"},
|
||||
{0x1705, "keymap_rp/15/006.png"},
|
||||
{0x1706, "keymap_rp/15/007.png"},
|
||||
{0x1707, "keymap_rp/15/008.png"},
|
||||
{0x1708, "keymap_rp/15/009.png"},
|
||||
{0x1709, "keymap_rp/15/010.png"},
|
||||
{0x1710, "keymap_rp/16/001.png"},
|
||||
{0x1711, "keymap_rp/16/002.png"},
|
||||
{0x1712, "keymap_rp/16/003.png"},
|
||||
{0x1713, "keymap_rp/16/004.png"},
|
||||
{0x1714, "keymap_rp/16/005.png"},
|
||||
{0x1715, "keymap_rp/16/006.png"},
|
||||
{0x1716, "keymap_rp/16/007.png"},
|
||||
{0x1717, "keymap_rp/16/008.png"},
|
||||
{0x1718, "keymap_rp/16/009.png"},
|
||||
{0x1719, "keymap_rp/16/010.png"},
|
||||
{0x1720, "keymap_rp/17/001.png"},
|
||||
{0x1721, "keymap_rp/17/002.png"},
|
||||
{0x1722, "keymap_rp/17/003.png"},
|
||||
{0x1723, "keymap_rp/17/004.png"},
|
||||
{0x1724, "keymap_rp/17/005.png"},
|
||||
{0x1725, "keymap_rp/17/006.png"},
|
||||
{0x1726, "keymap_rp/17/007.png"},
|
||||
{0x1727, "keymap_rp/17/008.png"},
|
||||
{0x1728, "keymap_rp/17/009.png"},
|
||||
{0x1729, "keymap_rp/17/010.png"},
|
||||
{0x1730, "keymap_rp/18/001.png"},
|
||||
{0x1731, "keymap_rp/18/002.png"},
|
||||
{0x1732, "keymap_rp/18/003.png"},
|
||||
{0x1733, "keymap_rp/18/004.png"},
|
||||
{0x1734, "keymap_rp/18/005.png"},
|
||||
{0x1735, "keymap_rp/18/006.png"},
|
||||
{0x1736, "keymap_rp/18/007.png"},
|
||||
{0x1737, "keymap_rp/18/008.png"},
|
||||
{0x1738, "keymap_rp/18/009.png"},
|
||||
{0x1739, "keymap_rp/18/010.png"},
|
||||
{0x1740, "keymap_rp/19/001.png"},
|
||||
{0x1741, "keymap_rp/19/002.png"},
|
||||
{0x1742, "keymap_rp/19/003.png"},
|
||||
{0x1743, "keymap_rp/19/004.png"},
|
||||
{0x1744, "keymap_rp/19/005.png"},
|
||||
{0x1745, "keymap_rp/19/006.png"},
|
||||
{0x1746, "keymap_rp/19/007.png"},
|
||||
{0x1747, "keymap_rp/19/008.png"},
|
||||
{0x1748, "keymap_rp/19/009.png"},
|
||||
{0x1749, "keymap_rp/19/010.png"},
|
||||
{0x1750, "keymap_rp/20/001.png"},
|
||||
{0x1751, "keymap_rp/20/002.png"},
|
||||
{0x1752, "keymap_rp/20/003.png"},
|
||||
{0x1753, "keymap_rp/20/004.png"},
|
||||
{0x1754, "keymap_rp/20/005.png"},
|
||||
{0x1755, "keymap_rp/20/006.png"},
|
||||
{0x1756, "keymap_rp/20/007.png"},
|
||||
{0x1757, "keymap_rp/20/008.png"},
|
||||
{0x1758, "keymap_rp/20/009.png"},
|
||||
{0x1759, "keymap_rp/20/010.png"},
|
||||
{0x1760, "keymap_rp/21/001.png"},
|
||||
{0x1761, "keymap_rp/21/002.png"},
|
||||
{0x1762, "keymap_rp/21/003.png"},
|
||||
{0x1763, "keymap_rp/21/004.png"},
|
||||
{0x1764, "keymap_rp/21/005.png"},
|
||||
{0x1765, "keymap_rp/21/006.png"},
|
||||
{0x1766, "keymap_rp/21/007.png"},
|
||||
{0x1767, "keymap_rp/21/008.png"},
|
||||
{0x1768, "keymap_rp/21/009.png"},
|
||||
{0x1769, "keymap_rp/21/010.png"},
|
||||
{0x1770, "keymap_rp/22/001.png"},
|
||||
{0x1771, "keymap_rp/22/002.png"},
|
||||
{0x1772, "keymap_rp/22/003.png"},
|
||||
{0x1773, "keymap_rp/22/004.png"},
|
||||
{0x1774, "keymap_rp/22/005.png"},
|
||||
{0x1775, "keymap_rp/22/006.png"},
|
||||
{0x1776, "keymap_rp/22/007.png"},
|
||||
{0x1777, "keymap_rp/22/008.png"},
|
||||
{0x1778, "keymap_rp/22/009.png"},
|
||||
{0x1779, "keymap_rp/22/010.png"},
|
||||
{0x1780, "keymap_rp/23/001.png"},
|
||||
{0x1781, "keymap_rp/23/002.png"},
|
||||
{0x1782, "keymap_rp/23/003.png"},
|
||||
{0x1783, "keymap_rp/23/004.png"},
|
||||
{0x1784, "keymap_rp/23/005.png"},
|
||||
{0x1785, "keymap_rp/23/006.png"},
|
||||
{0x1786, "keymap_rp/23/007.png"},
|
||||
{0x1787, "keymap_rp/23/008.png"},
|
||||
{0x1788, "keymap_rp/23/009.png"},
|
||||
{0x1789, "keymap_rp/23/010.png"},
|
||||
{0x1790, "keymap_rp/24/001.png"},
|
||||
{0x1791, "keymap_rp/24/002.png"},
|
||||
{0x1792, "keymap_rp/24/003.png"},
|
||||
{0x1793, "keymap_rp/24/004.png"},
|
||||
{0x1794, "keymap_rp/24/005.png"},
|
||||
{0x1795, "keymap_rp/24/006.png"},
|
||||
{0x1796, "keymap_rp/24/007.png"},
|
||||
{0x1797, "keymap_rp/24/008.png"},
|
||||
{0x1798, "keymap_rp/24/009.png"},
|
||||
{0x1799, "keymap_rp/24/010.png"},
|
||||
{0x17A0, "keymap_rp/25/001.png"},
|
||||
{0x17A1, "keymap_rp/25/002.png"},
|
||||
{0x17A2, "keymap_rp/25/003.png"},
|
||||
{0x17A3, "keymap_rp/25/004.png"},
|
||||
{0x17A4, "keymap_rp/25/005.png"},
|
||||
{0x17A5, "keymap_rp/25/006.png"},
|
||||
{0x17A6, "keymap_rp/25/007.png"},
|
||||
{0x17A7, "keymap_rp/25/008.png"},
|
||||
{0x17A8, "keymap_rp/25/009.png"},
|
||||
{0x17A9, "keymap_rp/25/010.png"},
|
||||
{0x17B0, "keymap_rp/26/001.png"},
|
||||
{0x17B1, "keymap_rp/26/002.png"},
|
||||
{0x17B2, "keymap_rp/26/003.png"},
|
||||
{0x17B3, "keymap_rp/26/004.png"},
|
||||
{0x17B4, "keymap_rp/26/005.png"},
|
||||
{0x17B5, "keymap_rp/26/006.png"},
|
||||
{0x17B6, "keymap_rp/26/007.png"},
|
||||
{0x17B7, "keymap_rp/26/008.png"},
|
||||
{0x17B8, "keymap_rp/26/009.png"},
|
||||
{0x17B9, "keymap_rp/26/010.png"},
|
||||
{0x17C0, "keymap_rp/27/001.png"},
|
||||
{0x17C1, "keymap_rp/27/002.png"},
|
||||
{0x17C2, "keymap_rp/27/003.png"},
|
||||
{0x17C3, "keymap_rp/27/004.png"},
|
||||
{0x17C4, "keymap_rp/27/005.png"},
|
||||
{0x17C5, "keymap_rp/27/006.png"},
|
||||
{0x17C6, "keymap_rp/27/007.png"},
|
||||
{0x17C7, "keymap_rp/27/008.png"},
|
||||
{0x17C8, "keymap_rp/27/009.png"},
|
||||
{0x17C9, "keymap_rp/27/010.png"},
|
||||
{0x17D0, "keymap_rp/28/001.png"},
|
||||
{0x17D1, "keymap_rp/28/002.png"},
|
||||
{0x17D2, "keymap_rp/28/003.png"},
|
||||
{0x17D3, "keymap_rp/28/004.png"},
|
||||
{0x17D4, "keymap_rp/28/005.png"},
|
||||
{0x17D5, "keymap_rp/28/006.png"},
|
||||
{0x17D6, "keymap_rp/28/007.png"},
|
||||
{0x17D7, "keymap_rp/28/008.png"},
|
||||
{0x17D8, "keymap_rp/28/009.png"},
|
||||
{0x17D9, "keymap_rp/28/010.png"},
|
||||
{0x17E0, "keymap_rp/29/001.png"},
|
||||
{0x17E1, "keymap_rp/29/002.png"},
|
||||
{0x17E2, "keymap_rp/29/003.png"},
|
||||
{0x17E3, "keymap_rp/29/004.png"},
|
||||
{0x17E4, "keymap_rp/29/005.png"},
|
||||
{0x17E5, "keymap_rp/29/006.png"},
|
||||
{0x17E6, "keymap_rp/29/007.png"},
|
||||
{0x17E7, "keymap_rp/29/008.png"},
|
||||
{0x17E8, "keymap_rp/29/009.png"},
|
||||
{0x17E9, "keymap_rp/29/010.png"},
|
||||
{0x17F0, "keymap_rp/30/001.png"},
|
||||
{0x17F1, "keymap_rp/30/002.png"},
|
||||
{0x17F2, "keymap_rp/30/003.png"},
|
||||
{0x17F3, "keymap_rp/30/004.png"},
|
||||
{0x17F4, "keymap_rp/30/005.png"},
|
||||
{0x17F5, "keymap_rp/30/006.png"},
|
||||
{0x17F6, "keymap_rp/30/007.png"},
|
||||
{0x17F7, "keymap_rp/30/008.png"},
|
||||
{0x17F8, "keymap_rp/30/009.png"},
|
||||
{0x17F9, "keymap_rp/30/010.png"},
|
||||
}};
|
||||
|
||||
std::string_view GetEntryNameByType(u32 type) {
|
||||
const auto key = PkgEntryValue{type};
|
||||
const auto it = std::ranges::lower_bound(PkgEntries, key);
|
||||
if (it != PkgEntries.end() && it->type == type) {
|
||||
return it->name;
|
||||
}
|
||||
return "";
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include "common/types.h"
|
||||
|
||||
/// Retrieves the PKG entry name from its type identifier.
|
||||
std::string_view GetEntryNameByType(u32 type);
|
|
@ -1,38 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/stb.h"
|
||||
#include "splash.h"
|
||||
|
||||
bool Splash::Open(const std::filesystem::path& filepath) {
|
||||
ASSERT_MSG(filepath.extension().string() == ".png", "Unexpected file format passed");
|
||||
|
||||
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
|
||||
if (!file.IsOpen()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<u8> png_file{};
|
||||
const auto png_size = file.GetSize();
|
||||
png_file.resize(png_size);
|
||||
file.Seek(0);
|
||||
file.Read(png_file);
|
||||
|
||||
auto* img_mem = stbi_load_from_memory(png_file.data(), png_file.size(),
|
||||
reinterpret_cast<int*>(&img_info.width),
|
||||
reinterpret_cast<int*>(&img_info.height),
|
||||
reinterpret_cast<int*>(&img_info.num_channels), 4);
|
||||
if (!img_mem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto img_size = img_info.GetSizeBytes();
|
||||
img_data.resize(img_size);
|
||||
std::memcpy(img_data.data(), img_mem, img_size);
|
||||
stbi_image_free(img_mem);
|
||||
return true;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "common/types.h"
|
||||
|
||||
class Splash {
|
||||
public:
|
||||
struct ImageInfo {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 num_channels;
|
||||
|
||||
u32 GetSizeBytes() const {
|
||||
return width * height * 4; // we always forcing rgba8 for simplicity
|
||||
}
|
||||
};
|
||||
|
||||
Splash() = default;
|
||||
~Splash() = default;
|
||||
|
||||
bool Open(const std::filesystem::path& filepath);
|
||||
[[nodiscard]] bool IsLoaded() const {
|
||||
return img_data.size();
|
||||
}
|
||||
|
||||
const auto& GetImageData() const {
|
||||
return img_data;
|
||||
}
|
||||
|
||||
ImageInfo GetImageInfo() const {
|
||||
return img_info;
|
||||
}
|
||||
|
||||
private:
|
||||
ImageInfo img_info{};
|
||||
std::vector<u8> img_data{};
|
||||
};
|
|
@ -1,10 +1,25 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/aes.h"
|
||||
#include "common/config.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/path_util.h"
|
||||
#include "trp.h"
|
||||
#include "core/file_format/trp.h"
|
||||
|
||||
static void DecryptEFSM(std::span<u8, 16> trophyKey, std::span<u8, 16> NPcommID,
|
||||
std::span<u8, 16> efsmIv, std::span<u8> ciphertext,
|
||||
std::span<u8> decrypted) {
|
||||
// Step 1: Encrypt NPcommID
|
||||
std::array<u8, 16> trophyIv{};
|
||||
std::array<u8, 16> trpKey;
|
||||
aes::encrypt_cbc(NPcommID.data(), NPcommID.size(), trophyKey.data(), trophyKey.size(),
|
||||
trophyIv.data(), trpKey.data(), trpKey.size(), false);
|
||||
|
||||
// Step 2: Decrypt EFSM
|
||||
aes::decrypt_cbc(ciphertext.data(), ciphertext.size(), trpKey.data(), trpKey.size(),
|
||||
efsmIv.data(), decrypted.data(), decrypted.size(), nullptr);
|
||||
}
|
||||
|
||||
TRP::TRP() = default;
|
||||
TRP::~TRP() = default;
|
||||
|
@ -54,7 +69,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
|||
return false;
|
||||
}
|
||||
|
||||
std::array<CryptoPP::byte, 16> user_key{};
|
||||
std::array<u8, 16> user_key{};
|
||||
hexToBytes(user_key_str.c_str(), user_key.data());
|
||||
|
||||
for (int index = 0; const auto& it : std::filesystem::directory_iterator(gameSysDir)) {
|
||||
|
@ -115,7 +130,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
|
|||
return false;
|
||||
}
|
||||
file.Read(ESFM);
|
||||
crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
|
||||
DecryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
|
||||
removePadding(XML);
|
||||
std::string xml_name = entry.entry_name;
|
||||
size_t pos = xml_name.find("ESFM");
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#include "common/endian.h"
|
||||
#include "common/io_file.h"
|
||||
#include "common/types.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
|
||||
struct TrpHeader {
|
||||
u32_be magic; // (0xDCA24D00)
|
||||
|
@ -37,7 +36,6 @@ public:
|
|||
void GetNPcommID(const std::filesystem::path& trophyPath, int index);
|
||||
|
||||
private:
|
||||
Crypto crypto;
|
||||
std::vector<u8> NPcommID = std::vector<u8>(12);
|
||||
std::array<u8, 16> np_comm_id{};
|
||||
std::array<u8, 16> esfmIv{};
|
||||
|
|
|
@ -70,6 +70,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
|
|||
std::filesystem::path host_path = mount->host_path / rel_path;
|
||||
std::filesystem::path patch_path = mount->host_path;
|
||||
patch_path += "-UPDATE";
|
||||
if (!std::filesystem::exists(patch_path)) {
|
||||
patch_path = mount->host_path;
|
||||
patch_path += "-patch";
|
||||
}
|
||||
patch_path /= rel_path;
|
||||
|
||||
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&
|
||||
|
|
|
@ -141,7 +141,12 @@ int AjmContext::BatchStartBuffer(u8* p_batch, u32 batch_size, const int priority
|
|||
*out_batch_id = batch_id.value();
|
||||
batch_info->id = *out_batch_id;
|
||||
|
||||
if (!batch_info->jobs.empty()) {
|
||||
batch_queue.EmplaceWait(batch_info);
|
||||
} else {
|
||||
// Empty batches are not submitted to the processor and are marked as finished
|
||||
batch_info->finished.release();
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
|||
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");
|
||||
|
@ -89,6 +90,10 @@ void AjmInstance::ExecuteJob(AjmJob& job) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!job.input.buffer.empty() && !job.output.buffers.empty()) {
|
||||
std::span<u8> in_buf(job.input.buffer);
|
||||
SparseOutputBuffer out_buf(job.output.buffers);
|
||||
|
|
|
@ -96,6 +96,7 @@ private:
|
|||
AjmSidebandResampleParameters m_resample_parameters{};
|
||||
u32 m_total_samples{};
|
||||
std::unique_ptr<AjmCodec> m_codec;
|
||||
bool is_initialized = false;
|
||||
};
|
||||
|
||||
} // namespace Libraries::Ajm
|
||||
|
|
|
@ -323,7 +323,7 @@ int PS4_SYSV_ABI sceAppContentTemporaryDataMount2(OrbisAppContentTemporaryDataOp
|
|||
return ORBIS_APP_CONTENT_ERROR_PARAMETER;
|
||||
}
|
||||
static constexpr std::string_view TmpMount = "/temp0";
|
||||
TmpMount.copy(mountPoint->data, sizeof(mountPoint->data));
|
||||
TmpMount.copy(mountPoint->data, TmpMount.size());
|
||||
LOG_INFO(Lib_AppContent, "sceAppContentTemporaryDataMount2: option = {}, mountPoint = {}",
|
||||
option, mountPoint->data);
|
||||
return ORBIS_OK;
|
||||
|
|
|
@ -89,6 +89,9 @@ int PS4_SYSV_ABI sceAudioOutChangeAppModuleState() {
|
|||
|
||||
int PS4_SYSV_ABI sceAudioOutClose(s32 handle) {
|
||||
LOG_INFO(Lib_AudioOut, "handle = {}", handle);
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -171,6 +174,9 @@ int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
|
|||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -185,6 +191,7 @@ int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* sta
|
|||
case OrbisAudioOutPort::Main:
|
||||
case OrbisAudioOutPort::Bgm:
|
||||
case OrbisAudioOutPort::Voice:
|
||||
case OrbisAudioOutPort::Audio3d:
|
||||
state->output = 1;
|
||||
state->channel = port.format_info.num_channels > 2 ? 2 : port.format_info.num_channels;
|
||||
break;
|
||||
|
@ -305,8 +312,12 @@ s32 PS4_SYSV_ABI sceAudioOutOpen(UserService::OrbisUserServiceUserId user_id,
|
|||
user_id, magic_enum::enum_name(port_type), index, length, sample_rate,
|
||||
magic_enum::enum_name(param_type.data_format.Value()),
|
||||
magic_enum::enum_name(param_type.attributes.Value()));
|
||||
if (audio == nullptr) {
|
||||
LOG_ERROR(Lib_AudioOut, "Audio out not initialized");
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if ((port_type < OrbisAudioOutPort::Main || port_type > OrbisAudioOutPort::Padspk) &&
|
||||
(port_type != OrbisAudioOutPort::Aux)) {
|
||||
(port_type != OrbisAudioOutPort::Audio3d && port_type != OrbisAudioOutPort::Aux)) {
|
||||
LOG_ERROR(Lib_AudioOut, "Invalid port type");
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT_TYPE;
|
||||
}
|
||||
|
@ -368,6 +379,9 @@ int PS4_SYSV_ABI sceAudioOutOpenEx() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudioOutOutput(s32 handle, void* ptr) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
@ -489,6 +503,9 @@ int PS4_SYSV_ABI sceAudioOutSetUsbVolume() {
|
|||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudioOutSetVolume(s32 handle, s32 flag, s32* vol) {
|
||||
if (audio == nullptr) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_NOT_INIT;
|
||||
}
|
||||
if (handle < 1 || handle > SCE_AUDIO_OUT_NUM_PORTS) {
|
||||
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,15 @@ class PortBackend;
|
|||
constexpr s32 SCE_AUDIO_OUT_NUM_PORTS = 22;
|
||||
constexpr s32 SCE_AUDIO_OUT_VOLUME_0DB = 32768; // max volume value
|
||||
|
||||
enum class OrbisAudioOutPort { Main = 0, Bgm = 1, Voice = 2, Personal = 3, Padspk = 4, Aux = 127 };
|
||||
enum class OrbisAudioOutPort {
|
||||
Main = 0,
|
||||
Bgm = 1,
|
||||
Voice = 2,
|
||||
Personal = 3,
|
||||
Padspk = 4,
|
||||
Audio3d = 126,
|
||||
Aux = 127,
|
||||
};
|
||||
|
||||
enum class OrbisAudioOutParamFormat : u32 {
|
||||
S16Mono = 0,
|
||||
|
|
|
@ -1,8 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <SDL3/SDL_audio.h>
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
#include "core/libraries/audio/audioout_error.h"
|
||||
#include "core/libraries/audio3d/audio3d.h"
|
||||
#include "core/libraries/audio3d/audio3d_error.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
@ -10,331 +15,577 @@
|
|||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dInitialize(s64 iReserved) {
|
||||
LOG_INFO(Lib_Audio3d, "iReserved = {}", iReserved);
|
||||
return ORBIS_OK;
|
||||
static constexpr u32 AUDIO3D_SAMPLE_RATE = 48000;
|
||||
|
||||
static constexpr AudioOut::OrbisAudioOutParamFormat AUDIO3D_OUTPUT_FORMAT =
|
||||
AudioOut::OrbisAudioOutParamFormat::S16Stereo;
|
||||
static constexpr u32 AUDIO3D_OUTPUT_NUM_CHANNELS = 2;
|
||||
static constexpr u32 AUDIO3D_OUTPUT_BUFFER_FRAMES = 0x100;
|
||||
|
||||
static std::unique_ptr<Audio3dState> state;
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(const s32 handle) {
|
||||
LOG_INFO(Lib_Audio3d, "called, handle = {}", handle);
|
||||
return AudioOut::sceAudioOutClose(handle);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dTerminate() {
|
||||
// TODO: When not initialized or some ports still open, return ORBIS_AUDIO3D_ERROR_NOT_READY
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* parameters) {
|
||||
if (parameters == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "Invalid OpenParameters ptr");
|
||||
return;
|
||||
}
|
||||
|
||||
parameters->size_this = sizeof(OrbisAudio3dOpenParameters);
|
||||
parameters->granularity = 256;
|
||||
parameters->rate = OrbisAudio3dRate::Rate48000;
|
||||
parameters->max_objects = 512;
|
||||
parameters->queue_depth = 2;
|
||||
parameters->buffer_mode = OrbisAudio3dBufferMode::AdvanceAndPush;
|
||||
parameters->num_beds = 2;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId iUserId,
|
||||
const OrbisAudio3dOpenParameters* pParameters,
|
||||
OrbisAudio3dPortId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "iUserId = {}", iUserId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortClose(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dAttributeId uiAttributeId,
|
||||
const void* pAttribute, size_t szAttribute) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiAttributeId = {}, szAttribute = {}", uiPortId,
|
||||
uiAttributeId, szAttribute);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortFlush(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId uiPortId, OrbisAudio3dBlocking eBlocking) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dAttributeId* pCapabilities,
|
||||
u32* pNumCapabilities) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId uiPortId, u32* pQueueLevel,
|
||||
u32* pQueueAvailable) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId uiPortId, OrbisAudio3dObjectId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectUnreserve(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dObjectId uiObjectId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}", uiPortId, uiObjectId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId uiPortId,
|
||||
OrbisAudio3dObjectId uiObjectId,
|
||||
size_t szNumAttributes,
|
||||
const OrbisAudio3dAttribute* pAttributeArray) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiObjectId = {}, szNumAttributes = {}", uiPortId,
|
||||
uiObjectId, szNumAttributes);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
u32 uiNumSamples) {
|
||||
LOG_TRACE(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}", uiPortId,
|
||||
uiNumChannels, uiNumSamples);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId uiPortId, u32 uiNumChannels,
|
||||
OrbisAudio3dFormat eFormat, const void* pBuffer,
|
||||
u32 uiNumSamples, OrbisAudio3dOutputRoute eOutputRoute,
|
||||
bool bRestricted) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}, uiNumChannels = {}, uiNumSamples = {}, bRestricted = {}",
|
||||
uiPortId, uiNumChannels, uiNumSamples, bRestricted);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
size_t PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize(u32 uiNumSpeakers, bool bIs3d) {
|
||||
LOG_INFO(Lib_Audio3d, "uiNumSpeakers = {}, bIs3d = {}", uiNumSpeakers, bIs3d);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI
|
||||
sceAudio3dCreateSpeakerArray(OrbisAudio3dSpeakerArrayHandle* pHandle,
|
||||
const OrbisAudio3dSpeakerArrayParameters* pParameters) {
|
||||
if (pHandle == nullptr || pParameters == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArray parameters");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray(OrbisAudio3dSpeakerArrayHandle handle) {
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
LOG_INFO(Lib_Audio3d, "called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
u32 uiNumCoefficients) {
|
||||
LOG_INFO(Lib_Audio3d, "fSpread = {}, uiNumCoefficients = {}", fSpread, uiNumCoefficients);
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2(OrbisAudio3dSpeakerArrayHandle handle,
|
||||
OrbisAudio3dPosition pos, float fSpread,
|
||||
float* pCoefficients,
|
||||
u32 uiNumCoefficients, bool bHeightAware,
|
||||
float fDownmixSpreadRadius) {
|
||||
s32 PS4_SYSV_ABI
|
||||
sceAudio3dAudioOutOpen(const OrbisAudio3dPortId port_id, const OrbisUserServiceUserId user_id,
|
||||
s32 type, const s32 index, const u32 len, const u32 freq,
|
||||
const AudioOut::OrbisAudioOutParamExtendedInformation param) {
|
||||
LOG_INFO(Lib_Audio3d,
|
||||
"fSpread = {}, uiNumCoefficients = {}, bHeightAware = {}, fDownmixSpreadRadius = {}",
|
||||
fSpread, uiNumCoefficients, bHeightAware, fDownmixSpreadRadius);
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid SpeakerArrayHandle");
|
||||
"called, port_id = {}, user_id = {}, type = {}, index = {}, len = {}, freq = {}",
|
||||
port_id, user_id, type, index, len, freq);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (len != state->ports[port_id].parameters.granularity) {
|
||||
LOG_ERROR(Lib_Audio3d, "len != state->ports[port_id].parameters.granularity");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return sceAudioOutOpen(user_id, static_cast<AudioOut::OrbisAudioOutPort>(type), index, len,
|
||||
freq, param);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(const s32 handle, void* ptr) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, handle = {}, ptr = {}", handle, ptr);
|
||||
|
||||
if (!ptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "!ptr");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (handle < 0 || (handle & 0xFFFF) > 25) {
|
||||
LOG_ERROR(Lib_Audio3d, "handle < 0 || (handle & 0xFFFF) > 25");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
return AudioOut::sceAudioOutOutput(handle, ptr);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param,
|
||||
const u32 num) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, param = {}, num = {}", static_cast<void*>(param), num);
|
||||
|
||||
if (!param || !num) {
|
||||
LOG_ERROR(Lib_Audio3d, "!param || !num");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
return AudioOut::sceAudioOutOutputs(param, num);
|
||||
}
|
||||
|
||||
static s32 PortQueueAudio(Port& port, const OrbisAudio3dPcm& pcm, const u32 num_channels) {
|
||||
// Audio3d output is configured for stereo signed 16-bit PCM. Convert the data to match.
|
||||
const SDL_AudioSpec src_spec = {
|
||||
.format = pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? SDL_AUDIO_S16LE
|
||||
: SDL_AUDIO_F32LE,
|
||||
.channels = static_cast<int>(num_channels),
|
||||
.freq = AUDIO3D_SAMPLE_RATE,
|
||||
};
|
||||
constexpr SDL_AudioSpec dst_spec = {
|
||||
.format = SDL_AUDIO_S16LE,
|
||||
.channels = AUDIO3D_OUTPUT_NUM_CHANNELS,
|
||||
.freq = AUDIO3D_SAMPLE_RATE,
|
||||
};
|
||||
const auto src_size = pcm.num_samples *
|
||||
(pcm.format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16 ? 2 : 4) *
|
||||
num_channels;
|
||||
|
||||
u8* dst_data;
|
||||
int dst_len;
|
||||
if (!SDL_ConvertAudioSamples(&src_spec, static_cast<u8*>(pcm.sample_buffer),
|
||||
static_cast<int>(src_size), &dst_spec, &dst_data, &dst_len)) {
|
||||
LOG_ERROR(Lib_Audio3d, "SDL_ConvertAudioSamples failed: {}", SDL_GetError());
|
||||
return ORBIS_AUDIO3D_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
port.queue.emplace_back(AudioData{
|
||||
.sample_buffer = dst_data,
|
||||
.num_samples = pcm.num_samples,
|
||||
});
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
||||
const OrbisAudio3dFormat format, void* buffer,
|
||||
const u32 num_samples) {
|
||||
return sceAudio3dBedWrite2(port_id, num_channels, format, buffer, num_samples,
|
||||
OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH, false);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(const OrbisAudio3dPortId port_id, const u32 num_channels,
|
||||
const OrbisAudio3dFormat format, void* buffer,
|
||||
const u32 num_samples,
|
||||
const OrbisAudio3dOutputRoute output_route,
|
||||
const bool restricted) {
|
||||
LOG_DEBUG(
|
||||
Lib_Audio3d,
|
||||
"called, port_id = {}, num_channels = {}, format = {}, num_samples = {}, output_route "
|
||||
"= {}, restricted = {}",
|
||||
port_id, num_channels, magic_enum::enum_name(format), num_samples,
|
||||
magic_enum::enum_name(output_route), restricted);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (output_route > OrbisAudio3dOutputRoute::ORBIS_AUDIO3D_OUTPUT_BOTH) {
|
||||
LOG_ERROR(Lib_Audio3d, "output_route > ORBIS_AUDIO3D_OUTPUT_BOTH");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (format > OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
|
||||
LOG_ERROR(Lib_Audio3d, "format > ORBIS_AUDIO3D_FORMAT_FLOAT");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (num_channels != 2 && num_channels != 8) {
|
||||
LOG_ERROR(Lib_Audio3d, "num_channels != 2 && num_channels != 8");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!buffer || !num_samples) {
|
||||
LOG_ERROR(Lib_Audio3d, "!buffer || !num_samples");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_FLOAT) {
|
||||
if ((reinterpret_cast<uintptr_t>(buffer) & 3) != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "buffer & 3 != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
} else if (format == OrbisAudio3dFormat::ORBIS_AUDIO3D_FORMAT_S16) {
|
||||
if ((reinterpret_cast<uintptr_t>(buffer) & 1) != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "buffer & 1 != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
return PortQueueAudio(state->ports[port_id],
|
||||
OrbisAudio3dPcm{
|
||||
.format = format,
|
||||
.sample_buffer = buffer,
|
||||
.num_samples = num_samples,
|
||||
},
|
||||
num_channels);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called");
|
||||
if (params) {
|
||||
*params = OrbisAudio3dOpenParameters{
|
||||
.size_this = 0x20,
|
||||
.granularity = 0x100,
|
||||
.rate = OrbisAudio3dRate::ORBIS_AUDIO3D_RATE_48000,
|
||||
.max_objects = 512,
|
||||
.queue_depth = 2,
|
||||
.buffer_mode = OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH,
|
||||
};
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId uiPortId, OrbisUserServiceUserId userId,
|
||||
s32 type, s32 index, u32 len, u32 freq, u32 param) {
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dInitialize(const s64 reserved) {
|
||||
LOG_INFO(Lib_Audio3d, "called, reserved = {}", reserved);
|
||||
|
||||
if (reserved != 0) {
|
||||
LOG_ERROR(Lib_Audio3d, "reserved != 0");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
LOG_ERROR(Lib_Audio3d, "already initialized");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
state = std::make_unique<Audio3dState>();
|
||||
|
||||
if (const auto init_ret = AudioOut::sceAudioOutInit();
|
||||
init_ret < 0 && init_ret != ORBIS_AUDIO_OUT_ERROR_ALREADY_INIT) {
|
||||
return init_ret;
|
||||
}
|
||||
|
||||
AudioOut::OrbisAudioOutParamExtendedInformation ext_info{};
|
||||
ext_info.data_format.Assign(AUDIO3D_OUTPUT_FORMAT);
|
||||
state->audio_out_handle =
|
||||
AudioOut::sceAudioOutOpen(0xFF, AudioOut::OrbisAudioOutPort::Audio3d, 0,
|
||||
AUDIO3D_OUTPUT_BUFFER_FRAMES, AUDIO3D_SAMPLE_RATE, ext_info);
|
||||
if (state->audio_out_handle < 0) {
|
||||
return state->audio_out_handle;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(const OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId* object_id) {
|
||||
LOG_INFO(Lib_Audio3d, "called, port_id = {}, object_id = {}", port_id,
|
||||
static_cast<void*>(object_id));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (!object_id) {
|
||||
LOG_ERROR(Lib_Audio3d, "!object_id");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
static int last_id = 0;
|
||||
*object_id = ++last_id;
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(const OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId object_id,
|
||||
const u64 num_attributes,
|
||||
const OrbisAudio3dAttribute* attribute_array) {
|
||||
LOG_DEBUG(Lib_Audio3d,
|
||||
"called, port_id = {}, object_id = {}, num_attributes = {}, attribute_array = {}",
|
||||
port_id, object_id, num_attributes, fmt::ptr(attribute_array));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
auto& port = state->ports[port_id];
|
||||
|
||||
for (u64 i = 0; i < num_attributes; i++) {
|
||||
const auto& attribute = attribute_array[i];
|
||||
|
||||
switch (attribute.attribute_id) {
|
||||
case OrbisAudio3dAttributeId::ORBIS_AUDIO3D_ATTRIBUTE_PCM: {
|
||||
const auto pcm = static_cast<OrbisAudio3dPcm*>(attribute.value);
|
||||
// Object audio has 1 channel.
|
||||
if (const auto ret = PortQueueAudio(port, *pcm, 1); ret != ORBIS_OK) {
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Lib_Audio3d, "Unsupported attribute ID: {:#x}",
|
||||
static_cast<u32>(attribute.attribute_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(const OrbisAudio3dPortId port_id) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}", port_id);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (state->ports[port_id].parameters.buffer_mode ==
|
||||
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_NO_ADVANCE) {
|
||||
LOG_ERROR(Lib_Audio3d, "port doesn't have advance capability");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
auto& port = state->ports[port_id];
|
||||
if (port.current_buffer.has_value()) {
|
||||
// Free existing buffer before replacing.
|
||||
SDL_free(port.current_buffer->sample_buffer);
|
||||
}
|
||||
|
||||
if (!port.queue.empty()) {
|
||||
port.current_buffer = port.queue.front();
|
||||
port.queue.pop_front();
|
||||
} else {
|
||||
// Nothing to advance to.
|
||||
LOG_DEBUG(Lib_Audio3d, "Port advance with no buffer queued");
|
||||
port.current_buffer = std::nullopt;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortClose() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortCreate() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortDestroy() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFlush() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFreeState() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetList() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(const OrbisAudio3dPortId port_id, u32* queue_level,
|
||||
u32* queue_available) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, queue_level = {}, queue_available = {}", port_id,
|
||||
static_cast<void*>(queue_level), static_cast<void*>(queue_available));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
if (!queue_level && !queue_available) {
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const auto port = state->ports[port_id];
|
||||
const size_t size = port.queue.size();
|
||||
|
||||
if (queue_level) {
|
||||
*queue_level = size;
|
||||
}
|
||||
|
||||
if (queue_available) {
|
||||
*queue_available = port.parameters.queue_depth - size;
|
||||
}
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetState() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortOpen(const OrbisUserServiceUserId user_id,
|
||||
const OrbisAudio3dOpenParameters* parameters,
|
||||
OrbisAudio3dPortId* port_id) {
|
||||
LOG_INFO(Lib_Audio3d, "called, user_id = {}, parameters = {}, id = {}", user_id,
|
||||
static_cast<const void*>(parameters), static_cast<void*>(port_id));
|
||||
|
||||
if (!state) {
|
||||
LOG_ERROR(Lib_Audio3d, "!initialized");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_READY;
|
||||
}
|
||||
|
||||
if (!parameters || !port_id) {
|
||||
LOG_ERROR(Lib_Audio3d, "!parameters || !id");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
const int id = static_cast<int>(state->ports.size()) + 1;
|
||||
|
||||
if (id > 3) {
|
||||
LOG_ERROR(Lib_Audio3d, "id > 3");
|
||||
return ORBIS_AUDIO3D_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
*port_id = id;
|
||||
std::memcpy(&state->ports[id].parameters, parameters, sizeof(OrbisAudio3dOpenParameters));
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortPush(const OrbisAudio3dPortId port_id,
|
||||
const OrbisAudio3dBlocking blocking) {
|
||||
LOG_DEBUG(Lib_Audio3d, "called, port_id = {}, blocking = {}", port_id,
|
||||
magic_enum::enum_name(blocking));
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
const auto& port = state->ports[port_id];
|
||||
if (port.parameters.buffer_mode !=
|
||||
OrbisAudio3dBufferMode::ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH) {
|
||||
LOG_ERROR(Lib_Audio3d, "port doesn't have push capability");
|
||||
return ORBIS_AUDIO3D_ERROR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
if (!port.current_buffer.has_value()) {
|
||||
// Nothing to push.
|
||||
LOG_DEBUG(Lib_Audio3d, "Port push with no buffer ready");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// TODO: Implement asynchronous blocking mode.
|
||||
const auto& [sample_buffer, num_samples] = port.current_buffer.value();
|
||||
return AudioOut::sceAudioOutOutput(state->audio_out_handle, sample_buffer);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(const OrbisAudio3dPortId port_id,
|
||||
const OrbisAudio3dAttributeId attribute_id,
|
||||
void* attribute, const u64 attribute_size) {
|
||||
LOG_INFO(Lib_Audio3d,
|
||||
"uiPortId = {}, userId = {}, type = {}, index = {}, len = {}, freq = {}, param = {}",
|
||||
uiPortId, userId, type, index, len, freq, param);
|
||||
return ORBIS_OK;
|
||||
"called, port_id = {}, attribute_id = {}, attribute = {}, attribute_size = {}",
|
||||
port_id, static_cast<u32>(attribute_id), attribute, attribute_size);
|
||||
|
||||
if (!state->ports.contains(port_id)) {
|
||||
LOG_ERROR(Lib_Audio3d, "!state->ports.contains(port_id)");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PORT;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle) {
|
||||
LOG_INFO(Lib_Audio3d, "handle = {}", handle);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, const void* ptr) {
|
||||
LOG_TRACE(Lib_Audio3d, "handle = {}", handle);
|
||||
if (ptr == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid Output ptr");
|
||||
if (!attribute) {
|
||||
LOG_ERROR(Lib_Audio3d, "!attribute");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(::Libraries::AudioOut::OrbisAudioOutOutputParam* param,
|
||||
s32 num) {
|
||||
LOG_INFO(Lib_Audio3d, "num = {}", num);
|
||||
if (param == nullptr) {
|
||||
LOG_ERROR(Lib_Audio3d, "invalid OutputParam ptr");
|
||||
return ORBIS_AUDIO3D_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortCreate(u32 uiGranularity, OrbisAudio3dRate eRate, s64 iReserved,
|
||||
OrbisAudio3dPortId* pId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiGranularity = {}, iReserved = {}", uiGranularity, iReserved);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortDestroy(OrbisAudio3dPortId uiPortId) {
|
||||
LOG_INFO(Lib_Audio3d, "uiPortId = {}", uiPortId);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// Audio3dPrivate
|
||||
|
||||
const char* PS4_SYSV_ABI sceAudio3dStrError(int iErrorCode) {
|
||||
LOG_ERROR(Lib_Audio3d, "(PRIVATE) called, iErrorCode = {}", iErrorCode);
|
||||
return "NOT_IMPLEMENTED";
|
||||
}
|
||||
|
||||
// Audio3dDebug
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortQueryDebug() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortQueryDebug called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetList() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetList called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetParameters() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetParameters called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetState() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortGetState called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortFreeState() {
|
||||
LOG_WARNING(Lib_Audio3d, "(DEBUG) sceAudio3dPortFreeState called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
// Unknown
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetBufferLevel() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dPortGetStatus() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dReportRegisterHandler() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dReportUnregisterHandler() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dStrError() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudio3dSetGpuRenderer() {
|
||||
s32 PS4_SYSV_ABI sceAudio3dTerminate() {
|
||||
LOG_ERROR(Lib_Audio3d, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
|
||||
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
|
||||
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutput);
|
||||
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutputs);
|
||||
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
|
||||
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
|
||||
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dCreateSpeakerArray);
|
||||
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dDeleteSpeakerArray);
|
||||
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetDefaultOpenParameters);
|
||||
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMemorySize);
|
||||
LIB_FUNCTION("-R1DukFq7Dk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMixCoefficients);
|
||||
LIB_FUNCTION("-Re+pCWvwjQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMixCoefficients2);
|
||||
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortQueryDebug);
|
||||
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectUnreserve);
|
||||
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
|
||||
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
|
||||
LIB_FUNCTION("4uyHN9q4ZeU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectSetAttributes);
|
||||
LIB_FUNCTION("7NYEzJ9SJbM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutput);
|
||||
LIB_FUNCTION("8hm6YdoQgwg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dDeleteSpeakerArray);
|
||||
LIB_FUNCTION("1HXxo-+1qCw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dObjectUnreserve);
|
||||
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
|
||||
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
|
||||
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
|
||||
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
|
||||
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
|
||||
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
|
||||
LIB_FUNCTION("9ZA23Ia46Po", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetAttributesSupported);
|
||||
LIB_FUNCTION("9tEwE0GV0qo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite);
|
||||
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
|
||||
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
|
||||
LIB_FUNCTION("HbxYY27lK6E", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dAudioOutOutputs);
|
||||
LIB_FUNCTION("Im+jOoa5WAI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetDefaultOpenParameters);
|
||||
LIB_FUNCTION("Mw9mRQtWepY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortDestroy);
|
||||
LIB_FUNCTION("OyVqOeVNtSk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortClose);
|
||||
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportRegisterHandler);
|
||||
LIB_FUNCTION("QqgTQQdzEMY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetBufferLevel);
|
||||
LIB_FUNCTION("SEggctIeTcI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetList);
|
||||
LIB_FUNCTION("UHFOgVNz0kk", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortCreate);
|
||||
LIB_FUNCTION("UmCvjSmuZIw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dInitialize);
|
||||
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
|
||||
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
|
||||
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
|
||||
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetQueueLevel);
|
||||
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortSetAttribute);
|
||||
LIB_FUNCTION("ZOGrxWLgQzE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFlush);
|
||||
LIB_FUNCTION("flPcUaXVXcw", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetParameters);
|
||||
LIB_FUNCTION("YaaDbDwKpFM", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortGetQueueLevel);
|
||||
LIB_FUNCTION("CKHlRW2E9dA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetState);
|
||||
LIB_FUNCTION("iRX6GJs9tvE", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortGetStatus);
|
||||
LIB_FUNCTION("jO2tec4dJ2M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dObjectReserve);
|
||||
LIB_FUNCTION("kEqqyDkmgdI", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dGetSpeakerArrayMemorySize);
|
||||
LIB_FUNCTION("lvWMW6vEqFU", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dCreateSpeakerArray);
|
||||
LIB_FUNCTION("lw0qrdSjZt8", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortAdvance);
|
||||
LIB_FUNCTION("pZlOm1aF3aA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutClose);
|
||||
LIB_FUNCTION("XeDDK0xJWQA", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortOpen);
|
||||
LIB_FUNCTION("VEVhZ9qd4ZY", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortPush);
|
||||
LIB_FUNCTION("-pzYDZozm+M", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortQueryDebug);
|
||||
LIB_FUNCTION("Yq9bfUQ0uJg", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dPortSetAttribute);
|
||||
LIB_FUNCTION("QfNXBrKZeI0", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportRegisterHandler);
|
||||
LIB_FUNCTION("psv2gbihC1A", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dReportUnregisterHandler);
|
||||
LIB_FUNCTION("uJ0VhGcxCTQ", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dPortFreeState);
|
||||
LIB_FUNCTION("ucEsi62soTo", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dAudioOutOpen);
|
||||
LIB_FUNCTION("xH4Q9UILL3o", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dBedWrite2);
|
||||
LIB_FUNCTION("yEYXcbAGK14", "libSceAudio3d", 1, "libSceAudio3d", 1, 1,
|
||||
sceAudio3dSetGpuRenderer);
|
||||
LIB_FUNCTION("Aacl5qkRU6U", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dStrError);
|
||||
LIB_FUNCTION("WW1TS2iz5yc", "libSceAudio3d", 1, "libSceAudio3d", 1, 1, sceAudio3dTerminate);
|
||||
};
|
||||
|
||||
} // namespace Libraries::Audio3d
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include <optional>
|
||||
#include <queue>
|
||||
|
||||
#include <stddef.h>
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/audio/audioout.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
|
@ -13,123 +15,131 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Audio3d {
|
||||
|
||||
class Audio3d;
|
||||
|
||||
using OrbisUserServiceUserId = s32;
|
||||
using OrbisAudio3dPortId = u32;
|
||||
using OrbisAudio3dObjectId = u32;
|
||||
using OrbisAudio3dAttributeId = u32;
|
||||
|
||||
enum class OrbisAudio3dFormat {
|
||||
S16 = 0,
|
||||
Float = 1,
|
||||
enum class OrbisAudio3dRate : u32 {
|
||||
ORBIS_AUDIO3D_RATE_48000 = 0,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dRate {
|
||||
Rate48000 = 0,
|
||||
enum class OrbisAudio3dBufferMode : u32 {
|
||||
ORBIS_AUDIO3D_BUFFER_NO_ADVANCE = 0,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_NO_PUSH = 1,
|
||||
ORBIS_AUDIO3D_BUFFER_ADVANCE_AND_PUSH = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dBufferMode { NoAdvance = 0, AdvanceNoPush = 1, AdvanceAndPush = 2 };
|
||||
|
||||
enum class OrbisAudio3dBlocking {
|
||||
Async = 0,
|
||||
Sync = 1,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dPassthrough {
|
||||
None = 0,
|
||||
Left = 1,
|
||||
Right = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dOutputRoute {
|
||||
Both = 0,
|
||||
HmuOnly = 1,
|
||||
TvOnly = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dAmbisonics : u32 {
|
||||
None = ~0U,
|
||||
W = 0,
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Z = 3,
|
||||
R = 4,
|
||||
S = 5,
|
||||
T = 6,
|
||||
U = 7,
|
||||
V = 8,
|
||||
K = 9,
|
||||
L = 10,
|
||||
M = 11,
|
||||
N = 12,
|
||||
O = 13,
|
||||
P = 14,
|
||||
Q = 15
|
||||
};
|
||||
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePcm = 0x00000001;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePriority = 0x00000002;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePosition = 0x00000003;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeSpread = 0x00000004;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeGain = 0x00000005;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributePassthrough = 0x00000006;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeResetState = 0x00000007;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeApplicationSpecific = 0x00000008;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeAmbisonics = 0x00000009;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeRestricted = 0x0000000A;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeOutputRoute = 0x0000000B;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeLateReverbLevel = 0x00010001;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadRadius = 0x00010002;
|
||||
static const OrbisAudio3dAttributeId s_sceAudio3dAttributeDownmixSpreadHeightAware = 0x00010003;
|
||||
|
||||
struct OrbisAudio3dSpeakerArray;
|
||||
using OrbisAudio3dSpeakerArrayHandle = OrbisAudio3dSpeakerArray*; // head
|
||||
|
||||
struct OrbisAudio3dOpenParameters {
|
||||
size_t size_this;
|
||||
u64 size_this;
|
||||
u32 granularity;
|
||||
OrbisAudio3dRate rate;
|
||||
u32 max_objects;
|
||||
u32 queue_depth;
|
||||
OrbisAudio3dBufferMode buffer_mode;
|
||||
char padding[32];
|
||||
int : 32;
|
||||
u32 num_beds;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dAttribute {
|
||||
OrbisAudio3dAttributeId attribute_id;
|
||||
char padding[32];
|
||||
const void* p_value;
|
||||
size_t value;
|
||||
enum class OrbisAudio3dFormat : u32 {
|
||||
ORBIS_AUDIO3D_FORMAT_S16 = 0,
|
||||
ORBIS_AUDIO3D_FORMAT_FLOAT = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPosition {
|
||||
float fX;
|
||||
float fY;
|
||||
float fZ;
|
||||
enum class OrbisAudio3dOutputRoute : u32 {
|
||||
ORBIS_AUDIO3D_OUTPUT_BOTH = 0,
|
||||
ORBIS_AUDIO3D_OUTPUT_HMU_ONLY = 1,
|
||||
ORBIS_AUDIO3D_OUTPUT_TV_ONLY = 2,
|
||||
};
|
||||
|
||||
enum class OrbisAudio3dBlocking : u32 {
|
||||
ORBIS_AUDIO3D_BLOCKING_ASYNC = 0,
|
||||
ORBIS_AUDIO3D_BLOCKING_SYNC = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dPcm {
|
||||
OrbisAudio3dFormat format;
|
||||
const void* sample_buffer;
|
||||
void* sample_buffer;
|
||||
u32 num_samples;
|
||||
};
|
||||
|
||||
struct OrbisAudio3dSpeakerArrayParameters {
|
||||
OrbisAudio3dPosition* speaker_position;
|
||||
u32 num_speakers;
|
||||
bool is_3d;
|
||||
void* buffer;
|
||||
size_t size;
|
||||
enum class OrbisAudio3dAttributeId : u32 {
|
||||
ORBIS_AUDIO3D_ATTRIBUTE_PCM = 1,
|
||||
};
|
||||
|
||||
struct OrbisAudio3dApplicationSpecific {
|
||||
size_t size_this;
|
||||
u8 application_specific[32];
|
||||
using OrbisAudio3dPortId = u32;
|
||||
using OrbisAudio3dObjectId = u32;
|
||||
|
||||
struct OrbisAudio3dAttribute {
|
||||
OrbisAudio3dAttributeId attribute_id;
|
||||
int : 32;
|
||||
void* value;
|
||||
u64 value_size;
|
||||
};
|
||||
|
||||
void PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* sParameters);
|
||||
struct AudioData {
|
||||
u8* sample_buffer;
|
||||
u32 num_samples;
|
||||
};
|
||||
|
||||
struct Port {
|
||||
OrbisAudio3dOpenParameters parameters{};
|
||||
std::deque<AudioData> queue; // Only stores PCM buffers for now
|
||||
std::optional<AudioData> current_buffer{};
|
||||
};
|
||||
|
||||
struct Audio3dState {
|
||||
std::unordered_map<OrbisAudio3dPortId, Port> ports;
|
||||
s32 audio_out_handle;
|
||||
};
|
||||
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutClose(s32 handle);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOpen(OrbisAudio3dPortId port_id, OrbisUserServiceUserId user_id,
|
||||
s32 type, s32 index, u32 len, u32 freq,
|
||||
AudioOut::OrbisAudioOutParamExtendedInformation param);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutput(s32 handle, void* ptr);
|
||||
s32 PS4_SYSV_ABI sceAudio3dAudioOutOutputs(AudioOut::OrbisAudioOutOutputParam* param, u32 num);
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite(OrbisAudio3dPortId port_id, u32 num_channels,
|
||||
OrbisAudio3dFormat format, void* buffer, u32 num_samples);
|
||||
s32 PS4_SYSV_ABI sceAudio3dBedWrite2(OrbisAudio3dPortId port_id, u32 num_channels,
|
||||
OrbisAudio3dFormat format, void* buffer, u32 num_samples,
|
||||
OrbisAudio3dOutputRoute output_route, bool restricted);
|
||||
s32 PS4_SYSV_ABI sceAudio3dCreateSpeakerArray();
|
||||
s32 PS4_SYSV_ABI sceAudio3dDeleteSpeakerArray();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetDefaultOpenParameters(OrbisAudio3dOpenParameters* params);
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMemorySize();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients();
|
||||
s32 PS4_SYSV_ABI sceAudio3dGetSpeakerArrayMixCoefficients2();
|
||||
s32 PS4_SYSV_ABI sceAudio3dInitialize(s64 reserved);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectReserve(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId* object_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectSetAttributes(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dObjectId object_id, u64 num_attributes,
|
||||
const OrbisAudio3dAttribute* attribute_array);
|
||||
s32 PS4_SYSV_ABI sceAudio3dObjectUnreserve();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortAdvance(OrbisAudio3dPortId port_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortClose();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortCreate();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortDestroy();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFlush();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortFreeState();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetAttributesSupported();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetList();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetParameters();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetQueueLevel(OrbisAudio3dPortId port_id, u32* queue_level,
|
||||
u32* queue_available);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetState();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortGetStatus();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortOpen(OrbisUserServiceUserId user_id,
|
||||
const OrbisAudio3dOpenParameters* parameters,
|
||||
OrbisAudio3dPortId* port_id);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortPush(OrbisAudio3dPortId port_id, OrbisAudio3dBlocking blocking);
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortQueryDebug();
|
||||
s32 PS4_SYSV_ABI sceAudio3dPortSetAttribute(OrbisAudio3dPortId port_id,
|
||||
OrbisAudio3dAttributeId attribute_id, void* attribute,
|
||||
u64 attribute_size);
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportRegisterHandler();
|
||||
s32 PS4_SYSV_ABI sceAudio3dReportUnregisterHandler();
|
||||
s32 PS4_SYSV_ABI sceAudio3dSetGpuRenderer();
|
||||
s32 PS4_SYSV_ABI sceAudio3dStrError();
|
||||
s32 PS4_SYSV_ABI sceAudio3dTerminate();
|
||||
|
||||
void RegisterlibSceAudio3d(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::Audio3d
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue